Compare commits

...

2386 Commits

Author SHA1 Message Date
Philipp Oppermann
176d4a7783 Merge pull request #1386 from yo-goto/yo-goto-patch-1
Fix Japanese translation of "run in parallel"
2025-02-10 12:33:55 +01:00
Philipp Oppermann
b69f96e0ae Merge pull request #1393 from phil-opp/rustc-abi
Add `rustc-abi` field to target spec JSON
2025-02-10 12:32:28 +01:00
Philipp Oppermann
450afac4a1 Add rustc-abi field to target spec JSON
The Rust compiler now requires an explicit `rustc-abi: x86-softfloat` field when using the soft-float target feature. This was added in https://github.com/rust-lang/rust/pull/136146 and is part of the latest nightlies.

I updated the post branches in commit 688a21e4
2025-02-10 12:19:51 +01:00
PADAone
fba3bedf39 fix Japanese translation of "run in parallel" 2025-01-30 20:34:56 +09:00
Philipp Oppermann
8b341c96c1 Merge pull request #1377 from phil-opp/raw-const
Use new `&raw const` operator instead of `unsafe {& _}`
2025-01-15 19:59:04 +01:00
Philipp Oppermann
7f1f658358 Use new &raw const operator instead of unsafe {& _} 2025-01-15 19:57:38 +01:00
Philipp Oppermann
0417fd22ef Merge pull request #1376 from phil-opp/remove-const_mut_refs-feature
The `const_mut_refs` feature is stable now and no longer required
2025-01-15 19:43:08 +01:00
Philipp Oppermann
69a498c6a3 The const_mut_refs feature is stable now and no longer required 2025-01-15 19:40:20 +01:00
Philipp Oppermann
4de9527ef8 Merge pull request #1356 from GNITOAHC/GNITOAHC-patch-1
[translation]: Fix typo in index.zh-TW.md
2024-11-28 20:10:42 +01:00
Philipp Oppermann
c46922678e Use tracnslation_contributors section 2024-11-28 20:10:04 +01:00
Chao-Ting, Chen
146e694d08 docs: Update index.zh-TW.md 2024-11-12 02:53:44 +08:00
Philipp Oppermann
b797cc805f Merge pull request #1347 from elchukc/fix_typo_start_return_type
add return type on `_start()` in code block
2024-10-07 22:02:27 +02:00
Philipp Oppermann
63cd95b612 Merge pull request #1349 from EsotericDryad/patch-1
Update post 02 "Building our Kernel" section
2024-10-07 21:54:26 +02:00
Philipp Oppermann
28753d6a18 Merge branch 'main' into fix_typo_start_return_type 2024-10-07 21:52:25 +02:00
Philipp Oppermann
68698fde20 Merge pull request #1346 from HoKim98/main
Fix typo on `blog/content/edition-2/posts/04-testing/index.md`
2024-10-07 21:51:45 +02:00
Philipp Oppermann
3bb6671dd9 Merge branch 'main' into HoKim98/main 2024-10-07 21:50:40 +02:00
Philipp Oppermann
a16900efe4 Merge pull request #1345 from eltociear/patch-1
docs: update 09-paging-implementation/index.md
2024-10-07 21:49:50 +02:00
Philipp Oppermann
55b5cbaba3 Merge branch 'main' into patch-1 2024-10-07 21:49:08 +02:00
EsotericDryad
e0ab3f257d Update post 02 "Building our Kernel" section
Added an explanation for why the new target still uses Linux conventions
2024-10-06 01:18:16 -05:00
Philipp Oppermann
2b6fc68ad1 Fix: Download artifact to subdir 2024-10-04 14:12:14 +02:00
Philipp Oppermann
e2f2f4c533 Update upload-artifact and download-artifact actions to v4 2024-10-04 14:09:37 +02:00
Philipp Oppermann
6a27ab2c2d Update contact page 2024-10-04 14:04:40 +02:00
elchc
4d3b246ef6 add return type on _start() in code block 2024-09-25 10:53:15 -04:00
Ho Kim
e037dcfdae Fix typo on testing doc 2024-09-20 15:08:12 +02:00
Ikko Eltociear Ashimine
c87cff0cdd docs: update 09-paging-implementation/index.md
minor fix
2024-09-17 11:46:40 +09:00
Philipp Oppermann
e4dd739d72 Merge pull request #1340 from Fincap/patch-1
04-testing: Added panic-abort-tests flag note to "duplicate lang item" workaround
2024-08-26 07:59:56 +02:00
Matthew Archer
9a6039237d 04-testing: Added panic-abort-tests flag note to duplicate lang item workaround 2024-08-12 18:08:50 +10:00
Philipp Oppermann
94f1c4503a Merge pull request #1336 from phil-opp/ZAAFHachemrachid/main
Add Arabic translation
2024-07-25 22:23:19 +02:00
Philipp Oppermann
7095876dca Add category index file for Arabic 2024-07-25 22:17:20 +02:00
Philipp Oppermann
6d4c5c5c4e Fix markdown link 2024-07-25 22:17:02 +02:00
Philipp Oppermann
134e938c9d Add translation metadata 2024-07-25 22:16:51 +02:00
Philipp Oppermann
d10dbc19a4 Fix path 2024-07-25 22:16:38 +02:00
Philipp Oppermann
64cc41f49c Fix: Fill in latest post link 2024-07-25 22:16:27 +02:00
Philipp Oppermann
33d73cbdbc Fix front matter syntax 2024-07-25 22:16:12 +02:00
Philipp Oppermann
807fc91bf8 Add Arabic to config.toml 2024-07-25 22:16:01 +02:00
Philipp Oppermann
d67f9ee8ce Merge branch 'main' into ZAAFHachemrachid/main 2024-07-25 22:03:49 +02:00
Philipp Oppermann
0a9024f1bd Merge pull request #1328 from phil-opp/update-zola
Update to zola v0.19
2024-06-21 11:58:13 +02:00
Philipp Oppermann
b991afebac Update to zola v0.19 2024-06-21 11:54:33 +02:00
Zaaf Hachem rachid
7927beeffa Update index.ar.md 2024-06-03 11:40:11 -07:00
Zaaf Hachem rachid
cd348bbe3c Create _index.ar.md
create new file index.ar.md
2024-06-03 08:12:26 -07:00
Zaaf Hachem rachid
d2ee259bfd Update index.ar.md
fix some ui thing
2024-06-01 13:38:41 -07:00
Zaaf Hachem rachid
9150885e82 Update index.ar.md
Add Introduction , Disabling the Standard Library
2024-06-01 13:37:47 -07:00
Zaaf Hachem rachid
fcf63e42aa Create index.ar.md 2024-06-01 13:12:31 -07:00
Philipp Oppermann
087a464ed7 Merge pull request #1323 from phil-opp/fix-dead-links
Fix dead links
2024-05-30 12:19:37 +02:00
Philipp Oppermann
96dc9ed668 Remove dead docs.rs links from deprecated 'advanced-paging' post 2024-05-30 11:45:13 +02:00
Philipp Oppermann
e6486aad6d Remove dead link in 'building on Android' post and add deprecation notice 2024-05-30 11:44:47 +02:00
Philipp Oppermann
f578336cd7 Merge pull request #1322 from phil-opp/translation-improvements
Various translation improvements
2024-05-30 11:25:31 +02:00
Philipp Oppermann
1ba8a4b012 Remove chapter config from translated posts (they are not considered)
We only consider the chapter definitions on the original posts when generating the site.
2024-05-30 11:22:59 +02:00
Philipp Oppermann
69a0f31747 Move translation note behind <!--- more --> marker 2024-05-30 11:12:23 +02:00
Philipp Oppermann
e4c25a3612 Add translator for post-12-zh-TW 2024-05-30 11:10:43 +02:00
Philipp Oppermann
978fc6b174 Merge pull request #1291 from ssrlive/main
Translate Multitasking post to Chinese
2024-05-30 11:09:08 +02:00
Philipp Oppermann
f192d8ae4e Merge pull request #1321 from ds797/patch-1
Update crossbeam and pc_keyboard
2024-05-30 11:04:06 +02:00
ds797
1e108fba64 Update pc_keyboard
Updated pc_keyboard to 0.7.0 and fixed breaking changes.
2024-05-23 01:12:15 +00:00
ds797
9c05cc9bd5 Update crossbeam
Updated crossbeam to 0.3.11 and fixed breaking changes.
2024-05-22 17:48:43 -07:00
Philipp Oppermann
4d7b78069f Merge pull request #1312 from squirrel532/patch-zh-tw
Fix some minor error in zh-tw
2024-04-16 17:48:03 +02:00
Squirrel
56d66b6b24 Update wording, make it fluent 2024-04-13 23:36:50 +08:00
Squirrel
ed38ea1aa0 Update translation of name mangling
Translate "name mangling" to "名稱重整"
https://rust-lang.tw/book-tw/ch19-01-unsafe-rust.html
2024-04-13 22:27:42 +08:00
Squirrel
d8204b05cc Fix wording convention 2024-04-13 22:20:46 +08:00
Squirrel
5f00ca206d Fix typo 2024-04-13 22:09:48 +08:00
Philipp Oppermann
52856ea30e Merge pull request #1311 from phil-opp/cleanup
Remove old bors.toml config file
2024-04-10 18:38:54 +02:00
Philipp Oppermann
a611ca7bfe Remove old bors.toml config file 2024-04-10 18:37:39 +02:00
Philipp Oppermann
9b0a0a3fbb Add bootloader v0.9 note to Chinese translation 2024-04-10 12:46:02 +02:00
Philipp Oppermann
54010c3653 Merge pull request #1309 from phil-opp/bootloader-version-note
Add a note that only `bootloader v0.9` is compatible
2024-04-09 11:29:01 +02:00
Philipp Oppermann
b8be0c5a5d Add a note that only bootloader v0.9 is compatible 2024-04-09 11:27:15 +02:00
Philipp Oppermann
9271bb104c Merge pull request #1306 from phil-opp/add-alias
Add `.html` alias to 'Set Up GDB' post
2024-03-21 15:50:26 +01:00
Philipp Oppermann
5b5e541b1e Add .html alias to 'Set Up GDB' post
Some websites still link to the old `.html` URL.
2024-03-21 15:45:53 +01:00
Philipp Oppermann
6d20ba47fa Merge pull request #1298 from acyanbird/format
Format for two post
2024-02-28 19:03:48 +01:00
acyanbird
a3bbd5ab55 update
wrong code branch
2024-02-28 17:39:58 +00:00
ssrlive
88e473433b Merge branch 'phil-opp:main' into main 2024-02-16 22:12:18 +08:00
Philipp Oppermann
3527693aeb Merge pull request #1296 from phil-opp/update-bootloader-version
Specify bootloader version without a patch version
2024-02-16 13:29:45 +01:00
Philipp Oppermann
4376233ec3 Update bootloader docs.rs links to always point to latest v0.9 version 2024-02-16 13:26:05 +01:00
Philipp Oppermann
1f6402f746 Specify bootloader version as v0.9 (without patch version) in all posts
Cargo automatically chooses the latest patch version, but beginners might not know that. So this hopefully avoids some confusion.
2024-02-16 13:25:04 +01:00
Philipp Oppermann
3556211904 Merge pull request #1295 from phil-opp/update-data-layout
Update data layouts of custom targets to LLVM 18
2024-02-16 13:15:03 +01:00
Philipp Oppermann
c31dcb48e5 Update data layouts of custom targets to LLVM 18 2024-02-16 13:11:03 +01:00
ssrlive
1a0254b977 minor changes 2024-02-15 00:35:51 +08:00
ssrlive
05dadc1302 minor changes 2024-02-15 00:28:49 +08:00
ssrlive
6041d119db Merge branch 'phil-opp:main' into main 2024-02-15 00:15:31 +08:00
ssrlive
258426b787 minor changes 2024-02-15 00:14:14 +08:00
acyanbird
8e6c4caffc update 2024-02-13 19:32:41 +00:00
acyanbird
59f84c2a45 update (#1289) 2024-02-13 17:49:41 +01:00
Philipp Oppermann
6bc593be79 Merge pull request #1288 from acyanbird/main
fix typo and format
2024-02-13 09:39:40 +01:00
acyanbird
3d337e5f80 Update index.zh-CN.md 2024-02-13 00:44:58 +00:00
acyanbird
9691bd5dc8 Update index.zh-CN.md 2024-02-12 21:16:07 +00:00
acyanbird
c0fbb10907 Update index.zh-CN.md 2024-02-11 03:26:29 +00:00
acyanbird
f9f1b8e7b9 fix typo and format 2024-02-11 03:01:50 +00:00
Philipp Oppermann
bde9fd0262 Merge pull request #1287 from acyanbird/main
translate comment and support me to chinese
2024-02-10 12:39:59 +01:00
acyanbird
bd361ee25a translate comment and support me 2024-02-09 22:51:30 +00:00
Philipp Oppermann
f13ccee48b Merge pull request #1286 from phil-opp/translate-support-me
Enable translations of the 'Support Me' section and the comment note
2024-02-08 19:34:10 +01:00
Philipp Oppermann
e4316a8a16 Enable translations of the comment note 2024-02-08 19:31:34 +01:00
Philipp Oppermann
3eeb25c946 Enable translations of the 'Support Me' section 2024-02-08 19:27:16 +01:00
Philipp Oppermann
813f434ecd Merge pull request #1285 from phil-opp/fix-links
Fix links to Rust unstable book
2024-02-08 19:26:12 +01:00
Philipp Oppermann
71f5d220ee Fix links to Rust unstable book 2024-02-08 19:06:38 +01:00
Philipp Oppermann
71e5ea0268 Merge pull request #1283 from acyanbird/patch-1
fix formatting error
2024-02-08 10:47:51 +01:00
acyanbird
da82fe8a0f Update index.zh-CN.md 2024-02-08 00:54:14 +00:00
Philipp Oppermann
2b444d3262 Merge pull request #1274 from acyanbird/main
change some format errors for chinese edition minimal kernel
2024-01-30 18:03:55 +01:00
acyanbird
b118828956 change some format errors 2024-01-28 23:59:17 +00:00
Philipp Oppermann
4595872c6b Merge pull request #1271 from phil-opp/blog-update-data-layout
Update data layouts in target specifications
2024-01-28 11:52:43 +01:00
Philipp Oppermann
1dced13b29 Update data layouts in target specifications
The data layout changed in LLVM. Using the wrong data layout now leads to a build error.
2024-01-28 11:50:57 +01:00
Philipp Oppermann
4b023bb432 Merge pull request #1262 from acyanbird/main
fix testing and paging introduction chapter errors in zh-CN translation
2024-01-05 18:00:30 +01:00
acyanbird
b1b35833d6 fix zh-CN paging introduction 2024-01-05 16:27:14 +00:00
acyanbird
34120a0409 fix zh-CN testing code err 2024-01-05 16:16:08 +00:00
Philipp Oppermann
6367e931e5 Merge pull request #1082 from TornaxO7/post_04_pub_fn_test_runner
Adding fix to make the test_runner functions pub
2023-12-28 17:20:22 +01:00
Philipp Oppermann
02fe09d56f Merge pull request #1254 from swnakamura/change-translator-name
Change one of translator's github ID
2023-12-08 19:46:42 +01:00
woodyZootopia
f4ab296b8b Change one of translator's github id
woodyZootopia changed their github id to swnakamura. This commit changes
the translators section accordingly
2023-12-02 15:04:01 +09:00
Philipp Oppermann
db4068826b Merge pull request #1167 from swnakamura/translate-11allocatordesign-ja
Translate post 11 "allocator design" into Japanese
2023-11-27 14:40:47 +01:00
woodyZootopia
9b1791a48d Refine the translation of post 11 2023-11-26 13:22:08 +09:00
Philipp Oppermann
61d074cc6c Merge pull request #1253 from keith666666/main
Fix: broken link of generator
2023-11-25 18:16:44 +01:00
Your Name
417c22556d fix: broken link of generator 2023-11-25 18:15:03 +08:00
Philipp Oppermann
5b4d04e337 Fix datetime comparison error in before_build.py 2023-10-17 09:57:11 +02:00
Philipp Oppermann
684ef64767 Merge pull request #1242 from phil-opp/improve-comment-link
Add `in:title` qualifier for discussion links
2023-09-14 20:30:36 +02:00
Philipp Oppermann
87d0ce5fa2 Add in:title qualifier for discussion links
Reduces the number of false positives in search.
2023-09-14 20:23:53 +02:00
Philipp Oppermann
5b67cb05ff Merge pull request #1237 from xzmeng/issue-1199
minimal-rust-kernel: fix missing .toml in zh-CN translation
2023-09-06 20:04:10 +02:00
Meng Xiangzhuo
81b7829657 minimal-rust-kernel: fix missing .toml in zh-CN translation 2023-08-27 03:48:25 +08:00
Philipp Oppermann
1ddeb129ac Merge pull request #1235 from Connortsui20/post-02-beginner-cargo-tips
Grammar fix
2023-08-21 09:26:13 +02:00
woodyZootopia
53d181d57b Rebase to the latest main 2023-08-21 13:34:57 +09:00
woodyZootopia
b634a24f4b Finish translation 2023-08-21 13:33:14 +09:00
woodyZootopia
4ef59648be Add Japanese article 2023-08-21 13:33:14 +09:00
Connortsui20
73628c1d05 Grammar fix 2023-08-18 08:12:39 -04:00
Philipp Oppermann
2e3230eca2 Merge pull request #1234 from Connortsui20/post-02-beginner-cargo-tips
Update post 2 with beginner friendly cargo tips
2023-08-17 16:30:54 +02:00
Connortsui20
63dc179cc7 shorter .cargo explanation 2023-08-17 09:13:43 -04:00
Connortsui20
211544af00 Better clarification 2023-08-17 08:42:54 -04:00
Connortsui20
1ff26bb4b6 Update post 2 with beginner friendly cargo tips
As a relatively new person to Rust, I confused the `.cargo/config.toml` with the global cargo config in my home directory (`~/.cargo/config.toml). While this is pretty obviously wrong in hindsight, since I've never used the `[unstable]` options before, I didn't realize my mistake until this next thing that tripped me up.

For `cargo install bootimage`, I think it is reasonable to tell the reader to go into a different directory to execute the command, since it might be the case that the reader has never dealt with different targets before and would have no idea that running `cargo install` for the new target that they just made in a json would be wrong (at least this was me).

This could be worded differently than the changes I made, but I think that the addition of these could only benefit a confused reader.
2023-08-16 18:57:37 -04:00
Philipp Oppermann
e2a4464835 Merge pull request #1230 from phil-opp/fix-category-id
Fix: Use correct category ID for comment threads of translated posts
2023-06-25 14:22:38 +02:00
Philipp Oppermann
f0fe3929ab Fix: Use correct category ID for comment threads of translated posts 2023-06-25 14:12:40 +02:00
Philipp Oppermann
c728cf8225 Merge pull request #1218 from twilfredo/wilfred/fixup_deprecated_fn
posts/06-double-faults/index: fixup deprecated fn
2023-06-02 09:22:55 +02:00
Philipp Oppermann
f38c11ae8e Merge pull request #1219 from Firenezz/main
Correcting typos and errors in French translation of Post 1
2023-06-02 09:21:53 +02:00
Philipp Oppermann
a1b195ede0 Merge pull request #1226 from SPuntte/fix-post-06-ub-panic
Fix panics caused by misaligned pointer dereferences in "Double Faults" & "Introduction to Paging"
2023-06-02 09:21:06 +02:00
Pontus Lundström
cfd31a977d Repeat previous for post-08 2023-05-31 17:14:43 +03:00
Pontus Lundström
06dd5edb3f Fix panic caused by misaligned pointer dereference 2023-05-20 23:12:33 +03:00
Demelari
685f55dd31 Keep "fils d'exécution" 2023-05-05 14:40:12 -04:00
Demelari
0b6b053c54 Swap "bien-sûr" for "bien sûr" and "évidemment" 2023-05-05 14:04:49 -04:00
Demelari
e0464fbd44 Fix and use "autoporté" instead of "autonome" 2023-05-05 13:58:55 -04:00
Demelari
5e88b86d1e Fix some typos 2023-05-05 13:32:23 -04:00
Wilfred Mallawa
e6b507e6d2 posts/06-double-faults/index: fixup deprecated fn
The code segment from the example uses the newer function whilst the
text segment refers to the old/deprecated `set_cs` fn. Let's fix that.

Signed-off-by: Wilfred Mallawa <vindulawilfred@gmail.com>
2023-05-04 14:55:40 +10:00
Philipp Oppermann
5baf50a5b4 Merge pull request #1217 from phil-opp/remove-alloc-error-handler-text
Update 'Heap Allocation' post to remove `alloc_error_handler`
2023-04-29 12:35:07 +02:00
Philipp Oppermann
5d63300512 Fix markdown syntax 2023-04-29 12:30:50 +02:00
Philipp Oppermann
739d9e1a3c Update 'Heap Allocation' post to remove alloc_error_handler
The unstable feature was removed. Allocation errors are reported as normal panics now.
2023-04-29 12:30:08 +02:00
Philipp Oppermann
8a1063df5f Merge pull request #1211 from GNITOAHC/main
fix(translation zh-TW): typo
2023-04-17 18:57:59 +02:00
GINTOAHC
d2c6b281c8 fix(translation zh-TW): typo 2023-04-17 18:14:39 +08:00
Philipp Oppermann
3900ddeb2c Merge pull request #1210 from phil-opp/fix-links
Fix link syntax
2023-04-09 19:56:46 +02:00
Philipp Oppermann
a7f4647e73 Fix link syntax 2023-04-09 19:54:58 +02:00
Philipp Oppermann
a7cfc562e9 Fix: Add back title and description for translated sites 2023-04-09 19:49:35 +02:00
Philipp Oppermann
5f5320f8e0 Merge pull request #1209 from phil-opp/update-zola
Update `zola` to `v0.17.2`
2023-04-09 19:32:43 +02:00
Philipp Oppermann
6f6e6698c4 Update CI to use zola v0.17.2 2023-04-09 19:27:46 +02:00
Philipp Oppermann
1d0e7950fd Make blog compatible with zola v0.17.2 2023-04-09 19:26:43 +02:00
Philipp Oppermann
dd4e872f82 Remove outdated paragraph with dead link in first edition 2023-03-25 15:49:47 +01:00
Philipp Oppermann
d8ad83528d Merge pull request #1190 from somebodyLi/main
fix(edition-2-posts-01-zh-CN): translate issue
2023-03-09 18:08:14 +01:00
Jie Wei
7c1b57a663 [Translation][Chinese] post-09 (edition-2) (#1189) 2023-02-26 12:29:42 +01:00
Ritchie
559b2a195d fix(edition-2-posts-01-zh-CN): translate issue 2023-02-16 19:04:49 +08:00
Philipp Oppermann
e56c635c13 Merge pull request #1188 from phil-opp/fix-broken-links
Fix broken links
2023-01-26 10:30:14 +01:00
Kenny Strawn
6cf6e32ee9 Fix broken links 2023-01-26 10:14:21 +01:00
Philipp Oppermann
ac94309114 Merge pull request #1177 from JOE1994/ko_translate_ch07
[Translation][Korean] post-07 (edition-2)
2022-12-15 11:01:07 +01:00
Philipp Oppermann
3183dc92e9 Format markdown tables and add newline at end of file 2022-12-15 10:59:17 +01:00
Philipp Oppermann
19150682df Add dalinaum as translation contributor 2022-12-15 10:59:03 +01:00
JOE1994
912566167c [Translation][Korean] post-07: apply 1st round of feedback from @dalinaum
Special thank you to @dalinaum for the time & effort!

Co-authored-by: dalinaum <dalinaum@gmail.com>
2022-12-14 17:38:43 -05:00
Philipp Oppermann
82f205956a Merge pull request #1180 from JOE1994/add_zola_to_gitignore
Add `zola` to `blog/.gitignore`
2022-12-13 14:17:04 +01:00
Philipp Oppermann
d456410da2 Merge pull request #1175 from JOE1994/ko_translate_ch06
[Translation][Korean] post-06 (edition-2)
2022-12-13 14:13:39 +01:00
JOE1994
48c3532c40 [Translation][Korean] post-06: Apply feedback from @dalinaum
Special thank you to @dalinaum for providing feedback!

Co-authored-by: dalinaum <dalinaum@gmail.com>
2022-12-08 20:02:57 -05:00
JOE1994
0c79f42e39 Add zola to blog/.gitignore
Make git ignore 'zola' when contributors locally
build & test the blog with `./zola serve`.

Meant to be a small usability improvement for contributors.
2022-12-03 16:45:40 -05:00
JOE1994
399eee2e19 [Translation][Korean] Small formatting improvements
Minor improvements to improve readability on rendered page.
2022-11-27 14:45:51 -05:00
JOE1994
2a338cf045 [Translation][Korean] post-07 (edition-2)
Double checked translation and formatting on rendered page using Zola.

Some edits to previous articles are to fix my previous mistake of translating "data race" as "race condition" :(
2022-11-27 14:45:48 -05:00
Miata
31eb517b4d [Chinese] Translate posts 5-8 and improve translation of posts 1-4 (#1131) 2022-11-25 11:27:42 +01:00
Philipp Oppermann
2844d0fc8c Merge pull request #1176 from seewishnew/main
Fixes bootloader version
2022-11-25 11:16:16 +01:00
seewishnew
b63ce2dc3c Fixes bootloader version
Adds a note about using a custom physical memory offset and its caveats
2022-11-24 20:42:22 -08:00
JOE1994
184db36e7c [Translation][Korean] post-06 (edition-2)
Double checked the translation, and checked rendering using Zola.

Contains some fixes to Korean translations of previous posts (4, 5)
to ensure url points to proper sections from previous Korean translations.
2022-11-19 19:07:07 -05:00
Philipp Oppermann
a108367d71 Merge pull request #1166 from alaincao/main
French translation's links fixes
2022-11-07 11:02:23 +01:00
Alain CAO
c1639cb9c2 French translation's links fixes 2022-11-01 01:29:11 +01:00
Philipp Oppermann
2f1918bf71 Merge pull request #1144 from TheMimiCodes/main
Add French translation of post 2 ("A Minimal Rust Kernel")
2022-10-28 10:16:34 +02:00
Philipp Oppermann
7a44cd1f60 Add alaincao to translation contributors 2022-10-28 10:14:50 +02:00
TheMimiCodes
15421d988a Merge pull request #1 from alaincao/main
French translation fix suggestions
2022-10-27 12:57:02 -04:00
Philipp Oppermann
1e2ae0e2ee Add // new comment to highlight changed test_runner signature 2022-10-26 11:52:40 +02:00
Philipp Oppermann
56ec24cbe1 Merge pull request #1135 from JOE1994/korean_translate_ch04
[Translation][Korean] post-04 (edition-2)
2022-10-18 17:46:54 +02:00
JOE1994
c786f14b8a [Translation][Korean] post-04 (edition-2)
Thanks to @SNOOPYOF & @dalinaum for providing feedback!

Co-authored-by: SNOOPYOF <jeehun0719@gmail.com>
Co-authored-by: dalinaum <dalinaum@gmail.com>
2022-10-18 11:19:48 -04:00
Philipp Oppermann
4abdc3ea43 Merge pull request #1162 from JOE1994/ko_translate_ch05
[korean translation] chapter 05
2022-10-18 16:36:30 +02:00
Philipp Oppermann
f6546321a3 Auto-format markdown tables 2022-10-18 16:34:39 +02:00
Philipp Oppermann
98514773d0 Add KimWang906 as translation contributor 2022-10-18 16:34:11 +02:00
ykim837
b0884bd879 [korean translation] chapter 05
Tested with Zola to double check the translation and formatting.
Thanks to @KimWang906 for providing feedback!

Co-authored-by: KimWang906 <hyunbin06git@gmail.com>
2022-10-18 09:23:48 -04:00
Alain CAO
633bc2e032 French translation fix suggestions 2022-10-13 23:32:10 +02:00
Philipp Oppermann
745d12d7f5 Merge pull request #1151 from lovemeforareason/qem1
Remove warning output from QEMU command.
2022-10-10 09:16:15 +02:00
Philipp Oppermann
3fef39211e Merge pull request #1150 from phil-opp/zola-update
Fix dead links
2022-10-03 17:03:11 +02:00
lovemeforareason
f905e7aa2b Remove warning output from QEMU command. 2022-10-03 10:39:46 -04:00
Philipp Oppermann
d17048e054 Auto-format config.toml 2022-10-03 14:01:23 +02:00
Philipp Oppermann
e0db01a59d Skip anchor checking for Japanese nomicon too 2022-10-03 14:01:10 +02:00
Philipp Oppermann
cca2886907 Rename link check job 2022-10-03 13:50:07 +02:00
Philipp Oppermann
77221b833b Remove dead link from first edition 2022-10-03 13:48:46 +02:00
Philipp Oppermann
db64d2876d Disable anchor checking for Japanese Rust edition guide
Zola seems to have problems with Japanese anchors.
2022-10-03 13:48:38 +02:00
Philipp Oppermann
bde26a617e Merge pull request #1149 from phil-opp/zola-update
CI: Move link check to separate workflow
2022-10-03 13:33:08 +02:00
Philipp Oppermann
d70afb7ecc CI: Move link check to separate workflow
The job often fails temporarily, which can be confusing to contributors. By moving it to a separate 'Check Links' workflow, it hopefully becomes clearer that the failure is unrelated to a PR.
2022-10-03 13:32:10 +02:00
Philipp Oppermann
cc100920d8 Merge pull request #1148 from phil-opp/zola-update
Fixes for zola update
2022-10-03 13:25:15 +02:00
Philipp Oppermann
209fd7c312 Fix license file ignore 2022-10-03 13:24:04 +02:00
Philipp Oppermann
a86304d932 Fix prev/next links for old status update posts 2022-10-03 13:22:18 +02:00
Philipp Oppermann
7f5859f8ee Merge pull request #1147 from phil-opp/zola-update
Update zola to v0.16.1
2022-10-03 13:16:16 +02:00
Philipp Oppermann
09aa0347d1 Update zola to v0.16.1 2022-10-03 13:12:35 +02:00
seewishnew
bbc59d23e8 Fixes bad URL from post-09 address calculation section (#1146) 2022-10-03 12:32:07 +02:00
Maxime Vaillancourt
c2c6d64452 Translate "Putting it Together" section 2022-10-02 08:28:03 -04:00
Maxime Vaillancourt
1c66190ac2 Fix typos, reword 2022-10-02 08:26:16 -04:00
Maxime Vaillancourt
90a92f04a6 Translate "The build-std Option" section 2022-10-02 08:07:28 -04:00
Maxime Vaillancourt
7de8c2aa37 Translate "Building our Kernel" section 2022-10-02 08:01:31 -04:00
Maxime Vaillancourt
3f5c404609 Translate "Target Specification" paragraph 2022-10-02 07:53:05 -04:00
Maxime Vaillancourt
44eaeca650 Finish translating "Installing Rust Nightly" paragraph 2022-10-02 07:20:42 -04:00
Maxime Vaillancourt
d52116d446 Translate "Memory-Related Intrinsics" paragraph 2022-10-02 07:16:10 -04:00
Maxime Vaillancourt
0268d6b9c6 Translate "Set a Default Target" paragraph 2022-10-02 06:59:59 -04:00
TheMimiCodes
001231b53f translate "installing Rust Nightly" paragraph 2022-10-01 20:39:43 -04:00
Maxime Vaillancourt
a366cdf277 Translate "Printing to Screen" paragraph 2022-10-01 20:37:14 -04:00
TheMimiCodes
80be2f0a9e Translate "a minimal kernel" paragraph 2022-10-01 20:28:56 -04:00
Maxime Vaillancourt
4337df6236 Translate "Running our Kernel" paragraph 2022-10-01 20:15:41 -04:00
TheMimiCodes
f0ab5e01c7 Translate "Multiboot Standard" parapgrah 2022-10-01 20:14:58 -04:00
Maxime Vaillancourt
f339bca0bf Translate "Creating a bootimage" paragraph 2022-10-01 20:13:31 -04:00
Maxime Vaillancourt
a95c6d1745 Translate "How does it work" paragraph 2022-10-01 19:55:38 -04:00
TheMimiCodes
1030e82621 Translate "BIOS boot" paragraph 2022-10-01 19:50:54 -04:00
Maxime Vaillancourt
ea70ed128c Translate "Booting it in QEMU" paragraph 2022-10-01 19:48:16 -04:00
Maxime Vaillancourt
5b5e72425e Translate "Real machine" paragraph 2022-10-01 19:40:46 -04:00
TheMimiCodes
7332d3d332 translate the first two paragraphs 2022-10-01 19:25:40 -04:00
Maxime Vaillancourt
20b306d7a4 Translate the last two paragraphs 2022-10-01 19:21:47 -04:00
TheMimiCodes
dee0ee61fa Add french translation of post 002 2022-10-01 18:46:02 -04:00
Philipp Oppermann
c689ecf810 Merge pull request #1142 from Firenezz/main
Fix typo in french translation 01-freestanding-rust-binary
2022-09-25 10:56:51 +02:00
Demelary
a9c8b51c0e Fix typo post-fr 2022-09-23 09:12:45 -04:00
Philipp Oppermann
a9aa4219e6 Merge pull request #1129 from bolded/paging-introduction
Copyedit edition 2 paging-introduction/index.md
2022-09-20 09:39:05 +02:00
Philipp Oppermann
fe387b5fa6 Merge pull request #1141 from shimomura1004/post-07-ja
Translate post-07 to Japanese
2022-09-20 09:10:52 +02:00
shimomura
567ace4f8d Apply suggestions from code review
Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>
2022-09-20 09:08:08 +02:00
SHIMOMURA Sho
00b068a6eb add ja file for post-07 2022-09-17 22:37:03 +09:00
Philipp Oppermann
cfe743ad9e Merge branch 'main' into paging-introduction
I tried my best to resolve the conflicts manually but some sentences were modified in different ways in the two PRs.
2022-08-19 17:14:00 +02:00
Philipp Oppermann
81d4f49f15 Merge pull request #1123 from hecatia-elegua/main
Check writing of all posts in edition 2
2022-08-16 11:32:58 +02:00
no
9440629176 fix: check writing reviews 2022-08-16 09:48:21 +02:00
Philipp Oppermann
096c044b4f Merge pull request #1127 from ykomatsu/double-faults-ja
Fix Japanese translation of "Double Faults"
2022-07-31 17:57:02 +02:00
mostly documentation
987f8e7f17 Copyedit edition 2 paging-introduction/index.md
Many minor grammar and writing mistakes corrected.
2022-07-27 20:29:31 -07:00
Yoshito Komatsu
6060898753 Fix the typo 2022-07-26 22:54:12 +09:00
Yoshito Komatsu
c8688719ee Fix Japanese translation of "Double Faults" 2022-07-26 22:50:58 +09:00
hecatia-elegua
fcc20806a7 fix: check writing of 12
also update the outdated line 1063 about crossbeam-queue,
making it similar to line 1220 about futures-util
2022-07-14 13:48:07 +02:00
hecatia-elegua
3b6064bbe0 fix: check writing of 11
also update the "What's next?" section
2022-07-14 13:20:52 +02:00
hecatia-elegua
ba7ec89c35 fix: check writing of 10
also update the note about recent use-after-free vulnerabilities
2022-07-14 12:56:45 +02:00
hecatia-elegua
6680ecbfeb fix: check writing of 09 2022-07-14 12:46:49 +02:00
hecatia-elegua
9c7c62754b fix: check writing of 08 2022-07-14 12:33:09 +02:00
hecatia-elegua
9c5890d409 fix: check writing of 07 2022-07-14 12:22:49 +02:00
hecatia-elegua
f927a863f2 fix: check writing of 06 2022-07-14 12:18:03 +02:00
hecatia-elegua
4d178a2a35 fix: check writing of 05 2022-07-14 12:10:32 +02:00
hecatia-elegua
dabc17bc39 fix: check writing of 04 2022-07-14 11:57:07 +02:00
hecatia-elegua
1dd8ea1dba fix: check writing of 03 2022-07-14 11:51:44 +02:00
hecatia-elegua
9d079e6d3e fix: check writing of 02
also prepend the dd-command with the "be careful"-warning
2022-07-08 17:38:45 +02:00
Philipp Oppermann
d07b3d089e Merge pull request #1111 from woodyZootopia/translate_10heapallocation_ja
Translate heap allocation to Japanese
2022-07-06 22:26:10 +02:00
hecatia-elegua
cc68aaf453 fix: check writing of 01 2022-07-06 19:55:59 +02:00
woodyZootopia
410f1df3da Add garasubo as the co-translator 2022-07-03 18:22:50 +09:00
woodyZootopia
d915443930 Update 2022-07-03 11:43:43 +09:00
woodyZootopia
ff512edb54 Update translation (with @garasubo 's review) 2022-07-03 11:40:42 +09:00
Philipp Oppermann
aa389dae4b Merge pull request #1122 from KisaragiEffective/patch-1
fix typo
2022-06-28 11:30:38 +02:00
Kisaragi
4905a41af0 fix typo 2022-06-28 18:00:03 +09:00
Philipp Oppermann
ad89055521 Merge pull request #1121 from JOE1994/korean_translate_ch03
[Translation][Korean] post-03 (edition-2)
2022-06-28 10:03:31 +02:00
JOE1994
5d0f200b61 [Translation][Korean] post-03: Add @Quqqu to translators list
who reviewed the Korean translation draft
2022-06-27 18:57:59 -04:00
woodyZootopia
2f9836b407 Change links to Japanese counterparts if available 2022-06-21 14:41:36 +09:00
woodyZootopia
6dc78627f7 Add translation_based_on_commit 2022-06-21 14:14:55 +09:00
woodyZootopia
ef19dbce1d Fix translations 2022-06-21 14:14:55 +09:00
JOE1994
c0f111aaee [Translation][Korean] post-03 (edition-2) 2022-06-18 13:31:05 -04:00
Philipp Oppermann
1662aaaea7 Merge pull request #1120 from JOE1994/korean_translation_recognition
Add @Quqqu to Korean translators' list: post 1 & 2
2022-06-09 09:26:27 +02:00
JOE1994
1f27d18427 Add @Quqqu to Korean translators' list: post 1 & 2
@Quqqu helped with reviewing Korean translation drafts for
post-01 & post-02.
2022-06-08 20:29:02 -04:00
Philipp Oppermann
3c3a37a48c Merge pull request #1118 from phil-opp/translate-giscus
Translate the giscus comment system
2022-06-07 10:52:15 +02:00
Philipp Oppermann
87794f2240 Translate the giscus comment system 2022-06-07 10:50:35 +02:00
Philipp Oppermann
341e05b843 Merge pull request #1117 from phil-opp/remove-analytics
Remove goatcounter analytics again
2022-06-07 10:35:49 +02:00
Philipp Oppermann
01975be7ac Remove goatcounter analytics again
This commit removes the https://www.goatcounter.com/ script that we were using for basic, privacy-friendly analytics. I don't really need that data, so there is not much value in keeping it.
2022-06-07 10:25:19 +02:00
Philipp Oppermann
eeac9e880c Fix swapped if/else in comment thread selection 2022-06-07 10:14:12 +02:00
Philipp Oppermann
2eb5147675 Merge pull request #1116 from phil-opp/fix-comment-threads
Move comment threads for translated posts to separate category
2022-06-07 10:08:13 +02:00
Philipp Oppermann
b05c07d21c Move comment threads for translated posts to separate category
Avoids that a search for the post title returns a thread for a translated post.
2022-06-07 10:06:48 +02:00
woodyZootopia
385d0e1306 Translated to the end 2022-06-04 13:14:17 +09:00
Philipp Oppermann
1c9b5edd6a Merge pull request #1114 from phil-opp/fix-links
Fix Rust documentation links
2022-05-22 13:10:13 +02:00
Philipp Oppermann
eab9b70c68 Fix Rust documentation links 2022-05-22 12:54:22 +02:00
Philipp Oppermann
ad8e0b4783 Use gray font instead of reduced opacity for translation contributors list
This way the contributors are listed in link color with full opacity.
2022-05-22 12:44:37 +02:00
Philipp Oppermann
c2d3f2704c Merge pull request #1113 from phil-opp/japanese-correction
Merge correction for Japanese translation of post-12 and use `translation_contributors` field
2022-05-22 12:33:49 +02:00
Philipp Oppermann
9025695ebf Merge pull request #1112 from phil-opp/translation-contributors
Add a new `translation_contributors` front matter field
2022-05-22 12:32:44 +02:00
Philipp Oppermann
5a1b841711 Use new translation_contributors field 2022-05-22 12:29:16 +02:00
Philipp Oppermann
21c5b62c38 Add a new translation_contributors front matter field
This field should list people that contributed to the translation, e.g. by fixing errors. The idea behind this field is to properly acknowledge all contributors, while still keeping the list of the original translation authors separate.
2022-05-22 12:23:15 +02:00
woodyZootopia
884247cb1d Made the Japanese file, translated about 1/8 2022-05-20 21:23:15 +09:00
asami
d78dd1582b add translators 2022-05-17 21:12:40 +09:00
asami
1a750f5374 Japanese Correction 2022-05-17 21:05:54 +09:00
Philipp Oppermann
afeed7477b Merge pull request #1106 from asami-kawasaki/delete-unnecessary-brackets
Delete unnecessary brackets
2022-05-17 09:26:36 +02:00
asami
611698ec5f Delete unnecessary brackets 2022-05-17 14:57:54 +09:00
Philipp Oppermann
c34db52262 Merge pull request #1105 from MysticalUser/patch-1
Fix minor grammar mistakes
2022-05-16 17:42:54 +02:00
MysticalUser
71870a05b0 Fix minor grammar mistakes 2022-05-15 15:46:34 -04:00
Philipp Oppermann
1519a17803 Merge pull request #1101 from JOE1994/korean_translate_ch02
Korean translation for chapter 2
2022-04-29 12:06:04 +02:00
JOE1994
d8dc4f5395 Korean translation for chapter 2
Special thanks to @Quqqu for reviewing the translation!
2022-04-28 22:37:51 -04:00
Bruno
b13f261770 fix: typo (#1103) 2022-04-18 10:06:52 +00:00
Hofer-Julian
5217bc27b7 Add missing and (#1093) 2022-04-07 19:08:10 +02:00
Philipp Oppermann
f365ade976 Merge pull request #1096 from Programatic/patch-1
Set CS register with non-deprecated function
2022-04-07 19:07:17 +02:00
ruhuang
f6777e621d Replace deprecated inclusive pattern syntax (#1091)
I am currently using rustc 1.61.0-nightly (10913c000 2022-03-03). The original English blog is correct but this translation is deprecated.
2022-04-07 19:05:25 +02:00
SilensAngelusNex
ee893a7ba0 Fix typo (#1094)
I think you mean "voluntarily" here?
2022-04-07 17:04:43 +00:00
Julien
58eca98ae1 Fix typo in '04-testing' (#1095) 2022-04-07 17:04:38 +00:00
Ford Smith
f56b4a0a32 Fix formatting and remove commented use statements 2022-03-19 13:03:40 -04:00
Ford Smith
c393e4442d Update blog/content/edition-2/posts/06-double-faults/index.md
Accidentally forgot to update the use statements.

Co-authored-by: ruhuang <ruhuang2001@gmail.com>
2022-03-19 13:02:16 -04:00
Ford Smith
7954a9f424 Set CS register with non-deprecated function
set_cs is deprecated and CS::set_reg is preferred. Update the blog to reflect this change according to the docs.
2022-03-17 23:42:00 -04:00
Youngsuk Kim
0873c3ae1d Korean translation for ch-01 (#1079) 2022-03-09 22:05:15 +00:00
Alexandre
daafb244d9 Updated list of french translators (#1090) 2022-03-07 13:38:23 +01:00
alaincao
b8272b53cf Fix french in 01-freestanding-rust-binary (#1089) 2022-03-07 13:14:39 +01:00
TornaxO7
7ce356f99d Adding fix to make the test_runner functions pub 2022-02-23 02:26:05 +01:00
Max Desiatov
5b2c60ece3 Fix typo in 02-minimal-rust-kernel (#1080)
`rerun the our build command` -> `rerun our build command`
2022-02-16 10:37:31 +00:00
Aleksey R. (aka EreTIk)
c1af4e31b1 Fix link to MS Docs (#1077) 2022-02-06 10:29:29 +01:00
Philipp Oppermann
c7eced8b49 Use proper HTML escaping for GitHub discussions link 2022-01-23 17:53:12 +01:00
Philipp Oppermann
6b241de81b Fix HTML encoding of GitHub discussions link 2022-01-23 17:39:37 +01:00
Philipp Oppermann
09e0c5915b Link to license in footer 2022-01-23 17:34:57 +01:00
Philipp Oppermann
64c1130908 Fix HTML error: <b> tags should go inside <li> tags 2022-01-23 17:34:46 +01:00
Philipp Oppermann
b24122a604 Remove dark mode warning again
There weren't any problems reported, so I guess it looks okay.
2022-01-23 17:30:06 +01:00
Philipp Oppermann
a26eeae82e Don't minify html 2022-01-23 17:23:06 +01:00
Philipp Oppermann
0d42178666 Don't deploy license file 2022-01-23 16:51:18 +01:00
Philipp Oppermann
05acd376e9 Merge pull request #1061 from phil-opp/zola-update
Upgrade to zola 0.15.3
2022-01-23 16:41:53 +01:00
Philipp Oppermann
0d40ee3750 Fix interal links and work around errors for #comments links
Zola only checks the markdown source for link targets, so an error occurs if the target is in an template. This is the case for our `#comments` links, so we add a dummy target in a comment.
2022-01-23 16:40:54 +01:00
Philipp Oppermann
ce51e833a8 Update to zola v0.15.3 2022-01-23 16:38:21 +01:00
Tianxi Ku
c4f8477310 Add Chinese translation to _index.zh-CN.md (#1067) 2022-01-03 11:25:26 +01:00
Philipp Oppermann
44f51402f7 Upgrade to zola 0.14.1 2021-10-17 21:06:57 +02:00
Philipp Oppermann
5c750985a6 Wait 500ms before changing giscus theme on load to make sure that it's ready 2021-10-17 18:41:24 +02:00
Philipp Oppermann
d6bf1b2271 Revert "Use onload handler to set giscus theme as soon as it's loaded"
This reverts commit 7eb1426e1f.
2021-10-17 18:35:45 +02:00
Philipp Oppermann
7eb1426e1f Use onload handler to set giscus theme as soon as it's loaded 2021-10-17 18:31:40 +02:00
Philipp Oppermann
ebbc6381d7 Fix front matter syntax 2021-10-17 18:19:54 +02:00
Philipp Oppermann
456ed398e8 Merge pull request #1053 from Alekzus/main
Adding French translation for the first post
2021-10-17 18:17:28 +02:00
Philipp Oppermann
195d40080a Don't spellcheck french translations (lots of false positives) 2021-10-17 18:10:09 +02:00
Philipp Oppermann
18f7cb16b9 Merge branch 'main' into main 2021-10-17 18:07:57 +02:00
Philipp Oppermann
1095dc33f4 Merge pull request #1060 from phil-opp/ci-typo-check
Use `crate-ci/typos` action to check for typos
2021-10-17 17:38:43 +02:00
Philipp Oppermann
a41d3236b8 Check translated files too 2021-10-17 17:37:55 +02:00
Philipp Oppermann
53e3578e34 Use crate-ci/typos action to check for typos
The misspell tool that we used previously has no exclude switch for ignoring translated files. Also, it looks like it is not maintained anymore.

In addition to changing our spell checker, this commit renames the `Build Site` workflow to `Blog` (to be consistent with our `Code` workflow).
2021-10-17 17:31:43 +02:00
Philipp Oppermann
ac8f0175a7 Merge pull request #1059 from phil-opp/dark-mode
Remember chosen theme in `localStorage`, add a switch for going back to system theme, improve layout
2021-10-17 16:45:34 +02:00
Philipp Oppermann
0fa31a0e15 Fix: don't assume that light mode is active on initial theme switch 2021-10-17 16:34:59 +02:00
Philipp Oppermann
5ff1aab7b5 Improve layout on mobile and clean up sass code 2021-10-17 16:34:24 +02:00
Philipp Oppermann
76b6c445e4 Add a switch for going back to system theme 2021-10-17 15:40:48 +02:00
Philipp Oppermann
69917e234c Remember chosen theme in localStorage
This way, the selected theme is kept when changing pages, and for subsequent visits. To prevent flickering, we set the selected theme in a blocking script directly on load. To speed things up further, we now use a `data-theme` attribute instead of classes on the body tag, this way we don't need to wait until the body element is loaded.
2021-10-17 15:05:11 +02:00
Philipp Oppermann
3281df3a41 Merge pull request #1058 from phil-opp/dark-mode
Implement a switch for switching between light and dark mode
2021-10-17 14:21:18 +02:00
Philipp Oppermann
96ab77fd1e Implement a switch for switching between light and dark mode 2021-10-17 14:20:08 +02:00
Philipp Oppermann
9d7c0ead07 Merge pull request #1057 from phil-opp/dark-mode
Initial Dark Mode Support
2021-10-16 17:31:49 +02:00
Philipp Oppermann
adaaa3238a Add meta tag that we support both light and dark mode 2021-10-16 17:27:48 +02:00
Philipp Oppermann
d8c27c7fcc Add a note that dark mode is experimental 2021-10-16 17:27:33 +02:00
Philipp Oppermann
990169b631 Make the background less dark to be easier on the eyes 2021-10-16 17:27:13 +02:00
Philipp Oppermann
9b02a5e77a Force a white background for all images for now
Our current images with transparency assume a white background.
2021-10-16 17:26:55 +02:00
Philipp Oppermann
874f79a8f9 Change colors depending on preferred color scheme 2021-10-16 16:41:36 +02:00
Philipp Oppermann
faae44a477 Add fonts heading and autoformat 2021-10-16 16:25:12 +02:00
Philipp Oppermann
b16c0c861f Migrate CSS files to SASS to prepare for dark mode 2021-10-16 16:23:23 +02:00
Philipp Oppermann
a8a111c6ee Merge pull request #1056 from phil-opp/iosevka
Use Iosevka font for code blocks and inline code
2021-10-16 15:54:47 +02:00
Philipp Oppermann
5155e18ba1 Use Iosevka font for code blocks and inline code
The advantage of Iosevka is its narrow width that allows us to show more columns in code examples without reducing font size.
2021-10-16 15:51:47 +02:00
Philipp Oppermann
ff5ac93908 Merge pull request #1054 from phil-opp/giscus-improvements
Improve our integration of the giscus comment system
2021-10-16 15:27:02 +02:00
Philipp Oppermann
d3e8714a80 Rename utterances.json to giscus.json to enable origin checks again 2021-10-16 15:20:44 +02:00
Philipp Oppermann
5654201a09 Add note above comments and link to GitHub discussion 2021-10-16 15:20:12 +02:00
Alexandre
279ca5dad7 Apply suggestions from code review
Co-authored-by: Benoît Cortier <benoit.cortier@fried-world.eu>
2021-10-11 07:08:05 +02:00
Alexandre
ff10c51d11 Update index.fr.md 2021-10-08 22:56:42 +02:00
Alexandre
daf15c993e Update config.toml 2021-10-08 22:55:43 +02:00
Alexandre
fbff83e498 Apply suggestions from code review, removing typos
Co-authored-by: Guillaume DALLENNE <dallenneguillaume@gmail.com>
2021-10-08 22:54:05 +02:00
Alexandre
1bc5422049 Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.fr.md
Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
2021-10-08 08:35:30 +02:00
Alexandre
f5c111f649 Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.fr.md
Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
2021-10-08 08:35:19 +02:00
Philipp Oppermann
9dd6588edf Merge pull request #993 from woodyZootopia/translate_post_09_ja
Translate 09 paging implementation to Japanese
2021-10-08 08:07:14 +02:00
Alexandre
526c7a3dca Update blog/config.toml
Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
2021-10-08 07:27:01 +02:00
Shu W. Nakamura
893c1cf447 Update blog/content/edition-2/posts/09-paging-implementation/index.ja.md 2021-10-08 12:19:07 +09:00
woodyZootopia
f57bded691 Fix for the advice given by @garasubo 2021-10-07 22:41:09 +09:00
Alexandre
f30ebe878c Translated the first post 2021-09-23 15:35:25 +02:00
Alexandre
c987148dc2 Added translations
Up to the "Linker Errors" section
2021-09-23 12:40:38 +02:00
Alexandre
c430d1d113 Create _index.fr.md 2021-09-23 10:54:39 +02:00
Alexandre
68212e8bc4 Translated the "Disabling the Standard Library" section 2021-09-23 10:31:15 +02:00
Alexandre
ae72448f89 Translated the introduction 2021-09-23 10:02:37 +02:00
Alexandre
6622e583da Update _index.fr.md 2021-09-23 09:10:20 +02:00
Alexandre
8e506fc34a Rename _index_fr.md to _index.fr.md 2021-09-23 09:07:22 +02:00
Alexandre
38027670fd Create _index_fr.md 2021-09-23 09:07:03 +02:00
Alexandre
7d7130bc0f Translated "post" 2021-09-23 08:59:31 +02:00
Alexandre
f881645991 Update config.toml 2021-09-23 08:58:23 +02:00
Jon Gillham
3e87916b6c Fix typos (#1051) 2021-09-19 10:36:20 +00:00
Philipp Oppermann
dbe43c203d Remove "about me" section from sidebar 2021-09-16 19:14:48 +02:00
Shu W. Nakamura
4472eed23c Apply suggestions from code review
Co-authored-by: garasubo <garasubo@gmail.com>
2021-09-14 11:19:03 +09:00
Shu W. Nakamura
0fe6d6aaec Apply suggestions from code review and Add garasubo as a co-translator
Co-authored-by: garasubo <garasubo@gmail.com>
2021-09-11 16:43:57 +09:00
woodyZootopia
282ed23a99 翻訳をさらに校正 2021-08-24 12:09:28 +09:00
Dmitry Kozlovtsev
559f1fbecd Fix link typos for #1043 (#1046) 2021-08-22 18:32:31 +02:00
woodyZootopia
575547963d Fix links to Japanese articles 2021-08-15 15:15:20 +09:00
woodyZootopia
803d2e6c7a Translate till the end 2021-08-15 14:55:48 +09:00
woodyZootopia
ed14ee779d 翻訳を進めた 2021-08-13 13:33:55 +09:00
woodyZootopia
fcabba0751 rebase to current origin/main 2021-08-13 11:57:33 +09:00
woodyZootopia
21516fe821 Add file and translate a bit 2021-08-10 21:31:06 +09:00
woodyZootopia
841b9deea3 Add the translation file and translated a bit 2021-08-10 21:31:06 +09:00
Philipp Oppermann
27ab4518ac Replace fathom analytics with goatcounter 2021-08-08 20:05:36 +02:00
Philipp Oppermann
c1e6a66e35 Fix link: The const_fn unstable feature no longer exists
There is now a description of `const` functions in the Rust reference, so we can link there instead.
2021-08-07 10:25:17 +02:00
Philipp Oppermann
d8eff6ba3e Merge pull request #1031 from Foo-x/1030-update-versions
docs: update version of crates
2021-08-07 10:10:58 +02:00
Philipp Oppermann
eb1e22582b Merge pull request #1034 from adi-g15/patch-1
Replace MS doc link in german
2021-08-07 10:08:42 +02:00
Kalbiq
f9fb942ba8 fix: typo (#1040) 2021-08-04 11:00:31 +00:00
MrZlo
0edd05ccac Translate first two posts into Russian (#1029)
* preabule

* Introduction

* Introduction

* Disactivation

* Disablaing std

* no_std

* panic_handler

* eh_personality

* unwiding

* start

* entry point

* summary

* what's next

* Details

* fix:
title

* config

* next post fix

* tabs into spaces

* fix: correct link to 02 post

* fix: bad gateway

* fix: typo error

* TRANSITION TO SECOND POST

* HEADER

* PREAMBULE

* BOOT SEQUENCE

* BOOT BIOS

* MULTIBOOT

* UEFI

* MINIMAL KERNEL

* NIGHTLY INSTALL

* SPECIFICATION JSON

* BUILD

* INTRISICS

* DEFAULT TARGET

* PRINTING TO SCREEN

* BOOTIMAGE

* FIRST BOOT

* FINISH

* RED ZONE

* SIMD

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* FIX: CONTROVERSIAL MOMENTS

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/01-freestanding-rust-binary/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/disable-red-zone/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/disable-simd/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/disable-simd/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* Update blog/content/edition-2/posts/02-minimal-rust-kernel/index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* LANGUAGE ITEM

* ALL OTHER MOMENTS

* standarD

* ADDITIONAL SETUP FILES

* Update blog/content/_index.ru.md

Co-authored-by: SnejUgal <contact@snejugal.ru>

* WRONG LINKS

Co-authored-by: SnejUgal <contact@snejugal.ru>
2021-07-19 12:14:39 +02:00
Foo-x
6fbcd8527a docs: fix typo (#1036) 2021-07-14 14:57:50 +02:00
Aditya Gupta
906a0580d0 Merge branch 'mx/mx-psi/use-english-link' into patch-1 2021-07-14 01:19:03 +05:30
Pablo Baeyens
6ac7b5bb9d Use English Windows documentation 2021-07-13 20:06:39 +02:00
Foo-x
dcef701d04 fix: typo (#1035) 2021-07-13 13:46:01 +02:00
Aditya Gupta
3c0060dacf Replace MS german doc link 2021-07-08 20:36:27 +05:30
Foo-x
4653711620 fix: typo (#1032) 2021-07-06 07:29:33 +02:00
Philipp Oppermann
7f36fe6693 Don't check anchors on https://doc.rust-jp.rs/book-ja 2021-06-30 13:27:25 +02:00
Foo-x
8270e1e12e docs: remove &mut
Replace `&mut InterruptStackFrame` to `InterruptStackFrame` due to the version updating.

Closes #1030
2021-06-30 19:55:25 +09:00
Foo-x
ff9a7c10d3 docs: update version of crates
Closes #1030
2021-06-30 19:02:42 +09:00
Foo-x
c2d6645392 docs: fix link to next post (#1026)
Refs #906
2021-06-28 11:08:57 +00:00
Foo-x
8b2ee6a4b8 docs: clean indent of JSONs (#1028)
Closes #1027
2021-06-28 11:07:58 +00:00
Conor
4942a8e50e Fix typo (#1023) 2021-06-21 10:33:26 +02:00
ㄗㄠˋ ㄑㄧˊ
782d5d6d5e fix typo (#1021) 2021-06-17 14:23:41 +00:00
kahirokunn
218a2754c7 Translate post-12 to Japanese (#977)
* Added Japanese translation of Async/Await.

* This is a review response.

* This is a review response.

* This is a review response.

* Unified expression.

* This is a review response.

* This is a review response.

* This is a review response.

* This is a review response.

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Yuki Okushi <jtitor@2k36.org>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update index.ja.md

Added translators and reviewers

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* This is a review response.

* I've translated more

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: garasubo <garasubo@gmail.com>

* Apply suggestions from code review

Co-authored-by: garasubo <garasubo@gmail.com>

* Waker -> ウェイカー

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Update blog/content/edition-2/posts/12-async-await/index.ja.md

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>

Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>
Co-authored-by: Yuki Okushi <jtitor@2k36.org>
Co-authored-by: garasubo <garasubo@gmail.com>
2021-06-14 10:09:34 +02:00
Philipp Oppermann
c7743a23ed Move comments_notice on translated posts to end of comments 2021-06-12 17:11:25 +02:00
Philipp Oppermann
afb20aae74 Use original English title for mapping discussions to translated posts 2021-06-12 17:07:48 +02:00
Philipp Oppermann
27b1528a65 giscus: Append page lang code to search term for translated posts 2021-06-12 17:02:23 +02:00
Philipp Oppermann
03853d15f4 Merge pull request #1010 from phil-opp/giscus
Make it possible to set discussion thread manually per post
2021-06-12 16:53:30 +02:00
Philipp Oppermann
963eb3e659 Make it possible to set discussion thread manually per post 2021-06-12 16:52:18 +02:00
Philipp Oppermann
8eba8dab7c Merge pull request #1007 from phil-opp/giscus
giscus: Use specific search term instead of `og:title`
2021-06-12 16:36:05 +02:00
Philipp Oppermann
47292beaad giscus: Use specific search term instead of og:title
This makes us more flexible and gives us ways to avoid title collisions (e.g. when the title on an extra post is a substring of some post title).
2021-06-12 16:35:20 +02:00
Philipp Oppermann
90c4e2bb93 Merge pull request #996 from phil-opp/giscus
Switch comments from utterances to giscus
2021-06-12 16:14:12 +02:00
Philipp Oppermann
a46c20ef93 Switch comments from utterances to giscus
to use GitHub discussions instead of issues for comment threads.
2021-06-12 16:12:38 +02:00
Philipp Oppermann
762beaa59e Merge pull request #954 from woodyZootopia/translate_post_08_ja
translate post 08 to Japanese
2021-05-27 14:13:34 +02:00
woodyZootopia
b0f0a4c5e2 Add @JohnTitor as co-translator 2021-05-26 12:41:09 +09:00
woodyZootopia
b956c0c591 Refined translation slightly 2021-05-26 12:33:45 +09:00
woodyZootopia
8cb4cf16df Apply suggestions from code review 2021-05-26 12:32:40 +09:00
Shu W. Nakamura
7fb46ee069 Apply suggestions from code review
Co-authored-by: Yuki Okushi <jtitor@2k36.org>
2021-05-26 12:18:23 +09:00
Philipp Oppermann
54ca8bbe67 Update copyright year in footer 2021-05-17 16:03:08 +02:00
Philipp Oppermann
bbf3c03cce Adjust CI deploy job for rename of master branch 2021-05-17 15:58:43 +02:00
Philipp Oppermann
732014c148 Merge pull request #990 from phil-opp/blog-nightly-fixes
Update posts to fix build on latest nightly
2021-05-17 15:55:13 +02:00
Philipp Oppermann
7992ce6a21 Fix link 2021-05-17 15:53:23 +02:00
Philipp Oppermann
34a3066cae Update posts to linked_list_allocator v0.9.0 2021-05-17 15:38:50 +02:00
Philipp Oppermann
248bc1cf05 Switch Hardware Interrupts post to pic8259 crate
Fork of previous `pic8259_simple` crate.
2021-05-17 15:36:08 +02:00
Philipp Oppermann
5ef39591f6 Update posts to use x86_64 v0.14.2 2021-05-17 15:33:35 +02:00
HKalbasi
b070fa8ee6 Remove wrong suggestion part (#983) 2021-05-17 08:30:11 +00:00
woodyZootopia
01e254db8c Refine translation 2021-05-12 16:15:14 +09:00
Shu W. Nakamura
c85e40b9ab Update blog/content/edition-2/posts/08-paging-introduction/index.ja.md 2021-05-12 15:00:42 +09:00
woodyZootopia
c7deb06fe8 Translate to the end 2021-05-11 23:11:42 +09:00
woodyZootopia
178c90ad74 Translate about half of the article 2021-05-09 00:17:09 +09:00
Philipp Oppermann
bf4f881079 Fix typo (#978) 2021-05-04 11:29:13 +02:00
kahirokunn
5d5e51400e fix typo 2021-05-04 10:28:13 +09:00
Mostafa Elbannan
6d02874049 Suggestion for .cargo/config.toml Explanation (#974)
I was confused on what the 'unstable' section of my .cargo/config.toml file should look like once I started getting linking errors when going through the third post. It turned out it was because I overwrote the previous 'unstable' configuration with the latter one. 

In other words, I thought we were to overwrite "build-std = ["core", "compiler_builtins"]" under the "unstable" config, with "build-std-features = ["compiler-builtins-mem"]" and NOT have both present. 

I think this makes it more clear that both are supposed to be present.
2021-04-27 11:18:38 +02:00
Alexx Roche
d3f5bb5fcb wake_trait is now stable (#963)
You probably know: `wake_trait` has been stable since 1.51.0 and no longer requires an attribute to enable
2021-04-05 13:04:41 +02:00
Alexx Roche
f2ca9f282a Previously updated dependency (#964)
Previously, in https://os.phil-opp.com/testing/ we set the dependency to `x86_64 = "0.13.2"` so this advice seems redundant.
2021-04-04 09:56:34 +02:00
二手掉包工程师
fc81c27fec Fix typo (#965) 2021-04-04 09:50:52 +02:00
二手掉包工程师
02b80acbd7 Translate common texts into Chinese (#962) 2021-04-02 14:31:56 +02:00
Alexx Roche
2d6108dc2f missing word (#960)
minor omission of a definite article.
2021-04-01 10:37:57 +02:00
Alexx Roche
ff43048585 grammar (#957)
almost done with the proofreading first pass ;-)
2021-03-30 13:56:09 +02:00
Clément Nerma
3f1a451e2b Fix: missing word (#958) 2021-03-30 13:54:19 +02:00
Alexx Roche
51f401a56c missing word (#956) 2021-03-28 12:47:28 +02:00
Alexx Roche
8bcfc7043f typo (#955) 2021-03-27 15:25:47 +01:00
woodyZootopia
c515590c1b Add ja file 2021-03-27 10:33:59 +09:00
Alexx Roche
3315bfe2f6 x86_64::VirtAddr already imported on L415 (#953)
`error[E0252]: the name 'VirtAddr' is defined multiple times`
2021-03-24 13:50:06 +01:00
Alexx Roche
ec4863ff93 Example image does not match code output (#952)
The 2nd edition outputs "L4 " at the start of each line of the loop.
2021-03-24 13:16:45 +01:00
Alexx Roche
5577f19859 Inconsistent version and grammar change (#951)
Earlier in https://github.com/phil-opp/blog_os/blob/master/blog/content/edition-2/posts/02-minimal-rust-kernel/index.md bootloader = "0.9.8" and here we are effectively downgrading to bootloader = "0.9.3" (Maybe there is an earlier feature that has been dropped that I am unaware of.)
2021-03-24 12:48:26 +01:00
Alexx Roche
6a17e8a7f4 missing word (#950) 2021-03-22 09:36:55 +01:00
Alexx Roche
7ac5fc903b minor typo (#949)
I think this is missing a preposition.
2021-03-22 09:23:35 +01:00
Philipp Oppermann
05b22bfa69 Merge pull request #941 from woodyZootopia/translate_post_05_ja
Translate post-05 to Japanese
2021-03-21 13:59:39 +01:00
Shu W. Nakamura
bdf6f14b9e Apply suggestions from code review
Co-authored-by: Yuki Okushi <huyuumi.dev@gmail.com>
2021-03-21 07:47:52 +09:00
Philipp Oppermann
f87cc129fc Convert before_build.py to python3 2021-03-19 12:20:03 +01:00
Philipp Oppermann
3f29b7b582 Add urllib2 as python requirement (for before_build.py) 2021-03-19 12:07:04 +01:00
Philipp Oppermann
42c550fcde Clarify that we can remove the test_runner stub from basic_boot.rs
Fixes #945
2021-03-19 11:12:28 +01:00
Philipp Oppermann
e2ea67a826 Merge pull request #943 from woodyZootopia/fix_post_06
post-06: Add spaces around some "two asterisk" notations
2021-03-11 11:27:58 +01:00
Philipp Oppermann
a9df1f2ec2 Ci: Fix workflow name for schedule job 2021-03-11 08:57:03 +01:00
woodyZootopia
a0368be408 Fix minor mistake in the translation 2021-03-10 14:47:16 +09:00
woodyZootopia
5dbdd8c11d Add spaces around some "two asterisk" notations 2021-03-10 14:30:19 +09:00
woodyZootopia
2ce8169e64 Fix Double Faults article accordingly 2021-03-08 19:13:02 +09:00
woodyZootopia
be2e130de9 Refined translation 2021-03-08 19:10:21 +09:00
woodyZootopia
616376fbd7 Rebased to the current HEAD 2021-03-08 19:10:21 +09:00
woodyZootopia
0779767355 Finish translation 2021-03-08 19:10:06 +09:00
woodyZootopia
987d695ed2 Just copied the file 2021-03-08 15:38:41 +09:00
Hiroki Tokunaga
a8a6b725cf chore(ja): remove the description about the memory optimizations (#935)
Same as #932.
2021-02-27 16:02:10 +01:00
Philipp Oppermann
15ae425a6b Fix: month numbers should start with 1 2021-02-25 14:02:40 +01:00
garasubo
9d381723ed Add ja translation for double faults (#917) 2021-02-23 09:28:47 +01:00
Daniel Spencer
88f32ffcb5 Remove note on builtin memory optimizations (#932)
The referenced issue in compiler-builtins (https://github.com/rust-lang/compiler-builtins/pull/365) has been merged.
2021-02-23 09:24:09 +01:00
garasubo
54a0c2b0ad minor fix (#928) 2021-02-11 14:59:23 +01:00
16yuki0702
16cc7048b0 Fix typo (#927)
`ListNone::new` to `ListNode::new`
2021-02-08 14:32:33 +01:00
Philipp Oppermann
d4034ee3d9 Add some margin between list items of status updates 2021-02-08 10:46:17 +01:00
Philipp Oppermann
6e6d9cbe05 Update Rust book links
Fixes #918.
2021-02-02 12:30:58 +01:00
Philipp Oppermann
3c75f84581 Merge pull request #920 from phil-opp/update-x86_64
Update post to use x86_64 v0.13.2
2021-02-02 12:00:00 +01:00
Philipp Oppermann
563689dba5 Use EMPTY constant of removed const_in_array_repeat_expressions feature 2021-02-02 11:50:35 +01:00
Philipp Oppermann
6d648457b1 The enable_interrupts_and_hlt function was renamed to enable_and_hlt 2021-02-02 11:09:37 +01:00
Philipp Oppermann
00986e8876 The MapperAllSizes trait was renamed to Translate 2021-02-02 11:05:57 +01:00
Philipp Oppermann
c5eeea29e2 Update post to use x86_64 v0.13.2 2021-02-02 11:01:53 +01:00
Mohammad H. Bahrampour
18930ccad7 Translate post-08 to Persian (#913) 2021-02-02 09:41:21 +01:00
Philipp Oppermann
cd8e139ab0 Fix memory address in self-referential struct example 2021-01-30 17:37:24 +01:00
Komoriii096
27ac0e1acc Remove trailing comma in zh-CN (#912) 2021-01-27 09:46:52 +01:00
Nick Schmitt
c242563a13 Added note to specify version 0.2.6 of volatile (#910) 2021-01-16 19:16:24 +01:00
Philipp Oppermann
27b5f5ee83 Merge pull request #909 from hamidrezakp/persian-translation
Adding tracking issue for Persian
2021-01-14 13:51:44 +01:00
Hamid R. K. Pishghadam
749d9d3793 add tracking issue for Persian 2021-01-14 02:06:11 +03:30
Philipp Oppermann
904d203f36 Merge pull request #907 from woodyZootopia/translate_index_ja
Translate the index page to Japanese
2021-01-13 10:03:13 +01:00
Shu W. Nakamura
611bb91141 Update blog/content/_index.ja.md
Co-authored-by: Yuki Okushi <huyuumi.dev@gmail.com>
2021-01-13 00:02:49 +09:00
woodyZootopia
1839f98be2 Translate the index page to Japanese 2021-01-12 22:23:43 +09:00
Philipp Oppermann
ec0d60e6aa Merge pull request #905 from JohnTitor/common-text-ja
Translate common texts into Japanese
2021-01-12 14:00:29 +01:00
Yuki Okushi
0cb7977025 Apply suggestion from review
Co-authored-by: Shu W. Nakamura <30687489+woodyZootopia@users.noreply.github.com>
2021-01-12 21:42:12 +09:00
Yuki Okushi
a1b496fab5 Translate common texts into Japanese 2021-01-12 21:28:34 +09:00
Philipp Oppermann
16b9e30d5f Merge pull request #903 from woodyZootopia/translate_post_04_ja
Translate post-04 to Japnese
2021-01-12 12:48:57 +01:00
woodyZootopia
3efca6dbbc Add JohnTitor as the co-translator 2021-01-11 12:10:57 +09:00
Shu W. Nakamura
23e8cb3b5d Apply suggestions from code review
Co-authored-by: Yuki Okushi <huyuumi.dev@gmail.com>
2021-01-11 12:02:33 +09:00
Philipp Oppermann
70fa363658 Merge pull request #904 from hamidrezakp/persian-translation
Persian translation of chapter Interrupts
2021-01-08 17:32:07 +01:00
Mohammad H. Bahrampour
d697c6caf2 Translation of post-07 to Persian is done. 2021-01-08 19:16:43 +03:30
Mohammad H. Bahrampour
b7416af316 Translation of post-06 to Persian is done. 2021-01-08 19:16:22 +03:30
Mohammad H. Bahrampour
aa33626a03 Translation of post-05 to Persian is done. 2021-01-08 19:15:59 +03:30
woodyZootopia
761b5de93d Translated post-04 2021-01-08 18:45:54 +09:00
Philipp Oppermann
bb39724f72 Another case fix in translation text 2021-01-08 10:35:01 +01:00
Philipp Oppermann
a28ad5eba2 Minor casing fix 2021-01-08 10:33:59 +01:00
Philipp Oppermann
247965c1b7 Merge pull request #901 from hamidrezakp/improve-multilingual-support
Improve multilingual support and Persian translation
2021-01-08 10:27:05 +01:00
Hamid R. K. Pishghadam
f60883071e Fix typo and wrong indention using tabs 2021-01-04 17:50:02 +03:30
nanai
3ca2ef760f Fix typo (#900)
computer-builtins-mem -> compiler-builtins-mem
Learning a lot from this blog. Thank you 🌱
2021-01-04 12:21:29 +01:00
Hamid R. K. Pishghadam
f779303472 Add translation for post warning and some minor fix 2021-01-03 21:52:56 +03:30
Hamid R. K. Pishghadam
fad609f744 Fix wrong translations and add font for Persian 2021-01-03 20:53:29 +03:30
Hamid R. K. Pishghadam
478b4cb808 using trans for most common short texts 2021-01-03 19:00:14 +03:30
Hamid R. K. Pishghadam
63d9828213 translate index page to persian 2021-01-03 18:58:59 +03:30
Philipp Oppermann
c20d7b534d Add (english) description for translated index pages again 2021-01-03 14:35:38 +01:00
Philipp Oppermann
b9cc0a47c6 Merge pull request #899 from phil-opp/index-template
Make index page translatable
2021-01-03 14:30:35 +01:00
Philipp Oppermann
4d4a2e5ae8 Revert "Add example for a Persian translation of introduction"
This reverts commit 36c4e6a7fe.
2021-01-03 14:29:38 +01:00
Philipp Oppermann
36c4e6a7fe Add example for a Persian translation of introduction 2021-01-02 18:14:21 +01:00
Philipp Oppermann
d2daf9dc48 Move section template to edition-2 subfolder 2021-01-02 18:11:07 +01:00
Philipp Oppermann
5a86a715c9 Move introduction from index template to markdown file
To allow translations.
2021-01-02 18:09:47 +01:00
Philipp Oppermann
aa227c7dc6 Restructure macros
- Split macros.html in per-edition files
- Create new snippets.html macro file with utterances snippet
- Move support.html to snippets.html as new macro
- Create new `latest_post` macro in 2nd edition macros.html
2021-01-02 18:09:06 +01:00
Philipp Oppermann
ee1ca9fa61 Point index page directly to edition-2/index.html template 2021-01-02 18:05:01 +01:00
Philipp Oppermann
22255d12a9 Create a top-level _index.md file 2021-01-02 17:33:16 +01:00
Hamid R. K. Pishghadam
68d12a7839 Fix layout or rtl in homepage and tables (#896) 2021-01-02 17:21:24 +01:00
Byron Hambly
a3bb0d3469 Remove unused import in code example (#898) 2021-01-02 17:19:15 +01:00
Byron Hambly
924da318c0 Improve explanation for BootInfoFrameAllocator::usable_frames (#897) 2021-01-02 17:18:36 +01:00
Byron Hambly
ceb52ac411 Minor grammar fixes (#894)
2 small fixes 

"we don't have implemented" -> "we haven't implemented"  

and 

"We use lazy_static again, because Rust's const evaluator is not powerful enough yet" -> "As before, we use lazy_static again." 

just to remove what has already been said a few paragraphs up. 

Thank you for this amazing resource!
2020-12-31 12:53:41 +01:00
Philipp Oppermann
b6ff79ac32 Remove unused font-face 2020-12-30 15:39:06 +01:00
Philipp Oppermann
85d97bd362 Fix font-family for code blocks in first edition 2020-12-30 15:38:17 +01:00
Philipp Oppermann
d9f3558b34 Hide first edition posts in Readme by default 2020-12-27 15:27:11 +01:00
16yuki0702
3ef243f342 Add filepath to code blocks in Testing post (#893) 2020-12-23 11:50:17 +01:00
woodyZootopia
5f5fdaf902 Set configurations of the post to pass the compile 2020-12-19 23:47:53 +09:00
woodyZootopia
009d0ceaa5 Just copied the file 2020-12-19 23:45:50 +09:00
Philipp Oppermann
dce5c9825b The second-edition folder was renamed to edition-2 2020-12-17 12:41:48 +01:00
Philipp Oppermann
b5a1360a72 Merge pull request #887 from woodyZootopia/translate_post_03
Translate post-03 to Japanese
2020-12-17 12:40:17 +01:00
woodyZootopia
183872e362 Add JohnTitor as a co-translator 2020-12-17 11:53:57 +09:00
Philipp Oppermann
9279c75160 Merge pull request #890 from phil-opp/rename-edition-folders
Rename edition folders
2020-12-16 15:00:32 +01:00
Philipp Oppermann
f692c5b377 Rename second-edition subfolder to `edition-2 2020-12-16 14:56:36 +01:00
Philipp Oppermann
4a9ea6c503 Rename first-edition subfolder to edition-1 2020-12-16 14:38:59 +01:00
Shu W. Nakamura
e6c510cba6 Apply suggestions from code review by @JohnTitor
Co-authored-by: Yuki Okushi <huyuumi.dev@gmail.com>
2020-12-16 22:12:55 +09:00
woodyZootopia
d36c041a9c Translate post 03 2020-12-11 23:11:22 +09:00
Yuki Okushi
f6416c1e6b Fix broken QEMU link (#888) 2020-12-11 12:08:30 +01:00
Brian Kung
e8f5ee95c6 Emphasize moving code (#883)
This prevents people from having duplicate code and potentially encountering errors. If both copies are kept the compiler may complain `error: cannot find macro `serial_println` in this scope` in `main.rs`
2020-11-20 10:20:16 +01:00
Philipp Oppermann
a081faf3cc CI: Use environment files instead of deprecated set-env 2020-11-13 08:52:00 +01:00
Philipp Oppermann
8f023f8e70 Merge pull request #878 from hamidrezakp/persian-translation
Adding Persian translation for posts of `Bare Bone` Chapter
2020-11-13 08:42:58 +01:00
Hamid R. K. Pishghadam
165a83efae adding persian language name 2020-11-13 02:04:51 +03:30
Hamid R. K. Pishghadam
a6be039bdb Post 04 translation done 2020-11-13 02:03:39 +03:30
Hamid R. K. Pishghadam
6b0f9290ea Post 03 translation done 2020-11-13 02:03:39 +03:30
Hamid R. K. Pishghadam
1ba70ef398 Post 02 translation done 2020-11-13 02:03:38 +03:30
Hamid R. K. Pishghadam
c39b1e2b3c Post 01 translation done 2020-11-13 02:03:38 +03:30
Hamid R. K. Pishghadam
a1bb75850d Adding persian support 2020-11-13 02:03:24 +03:30
Philipp Oppermann
19bf93a59d Use languages names in language list 2020-11-11 13:31:04 +01:00
Philipp Oppermann
106be64a1a Provide language names for all lang codes 2020-11-11 13:17:18 +01:00
Philipp Oppermann
8fd8e42490 Remove margins in language selector list 2020-11-11 13:16:40 +01:00
Philipp Oppermann
656b1c1ab2 Merge pull request #880 from phil-opp/show-all-languages
Show all available languages
2020-11-11 11:51:02 +01:00
Philipp Oppermann
668c903c02 Show all available languages
Not just languages enabled in the browser. This makes the translations more discoverable.
2020-11-11 10:29:17 +01:00
Arseniy Pendryak
307916d1fe Fix some links in 02-minimal-rust-kernel (#877)
Previously:
"`mem` feature" led to wrong feature
"`memcpy` etc. implementations" had redundant parenthesis that prevented proper rendering
2020-11-01 20:33:10 +01:00
Hamid Reza
caecc2c98e Adding Right-to-Left support for template (#875) 2020-11-01 10:54:57 +01:00
Philipp Oppermann
b17b3d40da GitHub no longer matches sponsorships, but they still charge no fees 2020-10-31 21:27:49 +01:00
Shu W. Nakamura
85b7d4b5c1 translate post 02 to Japanese (#871)
Co-authored-by: Yuki Okushi <huyuumi.dev@gmail.com>
2020-10-23 12:18:03 +02:00
Motoki saito
c9fae31766 Remove apache license appendix (#873) 2020-10-21 12:45:02 +02:00
Philipp Oppermann
7212ffaa83 Add an example why it is dangerous to implement memcpy yourself 2020-10-10 11:58:20 +02:00
Toothbrush
a65bf32d57 Removed message about rustfmt (#870)
Removed message about recent Rust nightlies not containing `rustfmt`.
2020-10-08 18:06:38 +02:00
Brian Kung
5184a2f7ea Specify which file to change (#869)
The commented file path was removed in https://github.com/phil-opp/blog_os/pull/866
2020-10-08 08:11:44 +02:00
Brian Kung
fb8b03e82d Use shorthand initialization from earlier code (#864)
Minor change, but keep the shorthand struct initialization seen previously at line 201: https://github.com/phil-opp/blog_os/blame/master/blog/content/second-edition/posts/03-vga-text-buffer/index.md#L201
2020-10-03 10:35:09 +02:00
Philipp Oppermann
4213609b1e Merge pull request #866 from phil-opp/compiler-builtins-mem
Update blog to use `mem` feature of `compiler_builtins`
2020-10-02 23:39:25 +02:00
Philipp Oppermann
114140ab7c Fix typo 2020-10-02 23:13:08 +02:00
Philipp Oppermann
d007af4811 Update blog to use mem feature of compiler_builtins 2020-10-02 23:12:46 +02:00
Philipp Oppermann
1a63bbe28d Fix outdated linked_list_allocator links and description (#867) 2020-10-02 23:11:05 +02:00
Philipp Oppermann
80136cc047 Update to zola v0.12.1 (#861) 2020-09-27 15:56:13 +02:00
Philipp Oppermann
68d59147e7 Update feature gate name in 'Allocator Designs'
Code update in https://github.com/phil-opp/blog_os/pull/860.
2020-09-24 10:56:43 +02:00
Philipp Oppermann
3ac8291712 Update blog posts to x86_64 v0.12.1 (#859) 2020-09-24 10:26:07 +02:00
Brian Kung
8ff1aeb96d Add link to custom targets (#857)
This makes it slightly easier to find out more about the JSON file that specifies custom targets.
2020-09-21 15:20:00 +02:00
Hofer Julian
685b8a94ac Heap Allocation: Make wording of heap start prefix clearer (#854) 2020-09-11 10:56:53 +02:00
Philipp Oppermann
00ebabddc2 Add an 'about me' block in the sidebar 2020-09-07 12:24:04 +02:00
Philipp Oppermann
3c0e8dc56a Merge pull request #850 from phil-opp/zola-update
Update Zola to 0.11.0
2020-08-19 09:59:25 +02:00
Philipp Oppermann
b978c72e03 Zola 0.11.0 fixes anchor checking for uppercase HTML tags 2020-08-19 09:55:44 +02:00
Philipp Oppermann
f198d45a59 Update to Zola 0.11.0 2020-08-19 09:55:16 +02:00
Philipp Oppermann
10d84faa92 Mention required #![feature(const_fn)] attribute again for FixedSizeBlockAllocator
The post explicitly allows readers to skip the `LinkedListAllocator` implementation, so we should not rely that the reader already enabled the unstable `const_fn` function there.

Reported in https://github.com/phil-opp/blog_os/issues/720#issuecomment-672625377.
2020-08-19 09:29:46 +02:00
Philipp Oppermann
9b61e061a0 Merge pull request #846 from phil-opp/scheduled
Use workflow dispatch event to trigger scheduled builds of code branches
2020-08-16 18:24:55 +02:00
Philipp Oppermann
e159804492 Use workflow dispatch event to trigger scheduled builds of code branches 2020-08-16 18:06:54 +02:00
Philipp Oppermann
0425bd3c81 Increase double fault stack size in Double Faults post
Code update in 817e36c064.
2020-08-16 17:59:50 +02:00
Philipp Oppermann
e80864b64d Add a note on translation pages that English comments are preferred 2020-08-13 18:00:41 +02:00
Philipp Oppermann
90b5a958d3 Fix import in code example in Chinese translation of VGA text buffer post 2020-08-13 17:46:06 +02:00
Philipp Oppermann
30650ab52b Merge pull request #845 from JohnTitor/add-japanese
Add (initial) Japanese translation
2020-08-13 17:30:36 +02:00
Yuki Okushi
3cdf51aaca Fix minor issues 2020-08-05 10:07:12 +09:00
Yuki Okushi
bff9944b02 Follow upstream changes 2020-08-05 10:07:11 +09:00
Yuki Okushi
3650a48c51 Add Japanese translation for second-edition/01 2020-08-05 09:10:11 +09:00
Yuki Okushi
57855e23cb Enable Japanese translation 2020-08-05 09:10:10 +09:00
Philipp Oppermann
277368537b Fix dead link 2020-08-02 14:03:48 +02:00
Roberto Wesley Overdijk
3c070c6dc0 change rustup override add to rustup override set (#843) 2020-08-02 13:43:51 +02:00
Yuki Okushi
6233747299 Fix link in build-on-android (#842) 2020-07-25 19:30:46 +02:00
Martin Fibik
96edb8909f Fix small typo in add_scancode (#841) 2020-07-24 21:32:15 +02:00
Philipp Oppermann
4717834ad0 Add a note regarding https://github.com/rust-lang/cargo/issues/7359 2020-07-21 08:38:54 +02:00
Philipp Oppermann
06d235f8af Make 'This Month in Rust OSDev' links bold on index page 2020-07-17 19:53:17 +02:00
Philipp Oppermann
36a0ae4737 Merge pull request #838 from phil-opp/link-this-month-in-rust-osdev
Link 'This Month in Rust OSDev' posts in status updates section
2020-07-17 19:50:20 +02:00
Philipp Oppermann
4cde35b674 Link to actual post, not the pull request 2020-07-17 19:48:37 +02:00
Philipp Oppermann
68b2b7737b Link 'This Month in Rust OSDev' posts in status updates section 2020-07-17 19:00:27 +02:00
Philipp Oppermann
3096baf462 Fix: rustc-std-workpace-core is a dependency of compiler_builtins, not core 2020-07-17 16:00:17 +02:00
Philipp Oppermann
f0443b7bfe Remove duplicated note about requiring Rust nightly 2020-07-17 13:13:13 +02:00
Philipp Oppermann
e407ec0ee0 Merge pull request #836 from phil-opp/build-std
Update blog to use `build-std` feature instead of cargo-xbuild
2020-07-17 13:10:16 +02:00
Philipp Oppermann
ed339ee2ce Add a note about minimal required nightly version 2020-07-17 13:08:23 +02:00
Philipp Oppermann
1a52165e25 Update 'Heap Allocation' post to enable alloc crates in build-std cfg key 2020-07-17 12:53:35 +02:00
Philipp Oppermann
de07416085 Update all uses of cargo x* to cargo * 2020-07-17 12:46:28 +02:00
Philipp Oppermann
3c723b428e Update testing post for build-std feature 2020-07-17 12:42:06 +02:00
Philipp Oppermann
580f58f7ab Update bootloader version in 'Minimal Rust Kernel' post to 0.9.8 2020-07-17 12:37:24 +02:00
Philipp Oppermann
6e2edf03a9 Update 'Minimal Rust Kernel' for build-std feature 2020-07-17 12:37:00 +02:00
Philipp Oppermann
6f1f872158 Rename .cargo/config files to .cargo/config.toml
The latter makes it more clear what kind of file it is.
2020-07-17 11:57:17 +02:00
Philipp Oppermann
b7eb093b42 Fix dead links
Some links do no longer exist, so I tried to find good replacements for them.
2020-07-16 14:31:23 +02:00
Philipp Oppermann
797e87e169 Merge pull request #833 from AxlLind/master
chore: Update x86_64 crate links to latest version
2020-07-16 14:13:08 +02:00
Jk Jensen
9985e4a699 Fix grammar for freestanding-rust-binary (#834)
The grammar for MacOS linker arguments was clunky.
2020-07-13 10:27:50 +02:00
Axel Lindeberg
64501e46f5 chore: update dead links to PhysAddr and VirtAddr 2020-06-29 18:36:31 +02:00
Axel Lindeberg
ee33868068 chore: update x86_64 crate links to latest version 2020-06-29 18:27:00 +02:00
Han Han
4540a2e725 sync dependencies from origin article (#828) 2020-06-29 16:13:28 +02:00
Han Han
0b15229a5e sync dependencies from origin article (#827) 2020-06-29 16:13:05 +02:00
Gelez
7f9ff717b4 Fix a small typo (#826) 2020-06-19 13:00:43 +02:00
Han Han
aa895e271d docs: remove version lock (#822)
fix error `error: the legacy LLVM-style asm! syntax is no longer supported`
2020-06-15 12:34:54 +02:00
Rodrigo Valle
6194a43724 Update link to const evaluator documentation (#821) 2020-06-12 11:08:33 +02:00
Philipp Oppermann
ec90a6a958 Merge pull request #820 from phil-opp/prevent-tail-recursion-in-test
Update Double Faults post to prevent tail recursion in test
2020-06-08 12:30:41 +02:00
Philipp Oppermann
9980989f7f Update Double Faults post to prevent tail recursion in test
Adds a dummy volatile read in the stack_overflow test to ensure that it is not tail recursive. Thus, the compiler can't apply the tail call elimination optimization, which turns the recursive function into a loop and thus prevents the stack overflow from happening.

Code update in https://github.com/phil-opp/blog_os/pull/818.
2020-06-08 12:29:02 +02:00
Philipp Oppermann
e1228d8708 Merge pull request #819 from phil-opp/remove-superfluous-test-printing
Remove superfluous printing from tests
2020-06-08 12:12:26 +02:00
Philipp Oppermann
c081c3f51f Remove superfluous printing from tests
Our test_runner now prints these messages automatically (see #816 and #817).
2020-06-08 12:11:39 +02:00
Philipp Oppermann
0fa30e24c7 Merge pull request #817 from phil-opp/testable-trait
Update Testing post to use Testable trait for automatic printing
2020-06-08 11:50:47 +02:00
Philipp Oppermann
a3dcc3095e Update Testing post to use Testable trait for automatic printing
Updates the post for the changes in https://github.com/phil-opp/blog_os/pull/816.
2020-06-08 11:48:56 +02:00
二手掉包工程师
433fd26173 fix(post-11): refine typo and use assert_eq (#813) 2020-06-05 15:50:22 +02:00
Philipp Oppermann
59a7f96ae8 Update simple_allocation test in Heap Allocation post 2020-05-22 10:56:35 +02:00
Philipp Oppermann
788d6a7e22 Use the latest version of bootimage 2020-05-21 10:45:17 +02:00
Philipp Oppermann
1f8a388bdc Fix typo 2020-05-21 09:45:32 +02:00
Philipp Oppermann
524fa5330f Point bootloader docs.rs link to latest version 2020-05-21 09:39:14 +02:00
Philipp Oppermann
c7c7f64f79 Merge pull request #810 from phil-opp/update-pic8259
Update Hardware Interrupts post to use pic8259_simple v0.2.0
2020-05-21 09:38:13 +02:00
Philipp Oppermann
fddab6967d Update Hardware Interrupts post to use pic8259_simple v0.2.0 2020-05-21 09:34:05 +02:00
Philipp Oppermann
5e37a0ed5d Mention alternative names for bump/linked list allocator design 2020-05-20 15:19:00 +02:00
Philipp Oppermann
5caf136bc2 Merge pull request #809 from phil-opp/update-x86_64
Update x86_64 dependency to version 0.11.0
2020-05-20 15:12:50 +02:00
Philipp Oppermann
2cb6a0ffe7 Fix docs.rs anchor name 2020-05-20 14:57:57 +02:00
Philipp Oppermann
fbaa641841 Update Heap Allocation post for x86_64 v0.11.0 2020-05-20 14:46:14 +02:00
Philipp Oppermann
1a5d91be4b Update Paging Implementation post for x86_64 v0.11.0 2020-05-20 14:43:58 +02:00
Philipp Oppermann
ee09a70d40 Update x86_64 dependency to version 0.11.0 2020-05-20 14:35:06 +02:00
Philipp Oppermann
a8c85afeb0 Merge pull request #808 from phil-opp/update-bootloader
Update bootloader to v0.9.3
2020-05-20 14:23:01 +02:00
Philipp Oppermann
70b2f07694 Update bootloader to v0.9.3 2020-05-20 14:16:43 +02:00
Philipp Oppermann
a79cea1cd6 Update Allocator Designs post for #806 2020-05-20 10:54:52 +02:00
Philipp Oppermann
052fc405ad Merge pull request #805 from phil-opp/merge-task_queue-and-wake_queue
Update Async/Await post for simplified executor design
2020-05-19 14:34:50 +02:00
Philipp Oppermann
36e8c16a2c Update Async/Await post for simplified executor design
See https://github.com/phil-opp/blog_os/pull/804 for more information.
2020-05-19 14:25:24 +02:00
Philipp Oppermann
199c3b467c Fix file name in example 2020-05-18 11:40:06 +02:00
hg
516121b698 Add one more unsafe superpower (#802) 2020-05-17 12:45:10 +02:00
Lars Kloosterman
389b97f13e Fix a tiny typo (#799) 2020-05-03 21:24:03 +02:00
Philipp Oppermann
1adfacf21d Fix dead link 2020-04-29 14:46:30 +02:00
Philipp Oppermann
a7a57578e9 Fix memory address in self-referential struct example 2020-04-23 12:04:27 +02:00
韩朴宇
0b957688b7 Fix command line in Chinese translation of post 2 (#794) 2020-04-14 10:42:48 +02:00
ptrckd
ed3eaacb44 We no longer make entry points for Windows and macOS in post-01 (#789) 2020-04-13 11:24:08 +02:00
Julian
355d3f6681 Fix typo (#791) 2020-04-13 11:16:03 +02:00
Philipp Oppermann
e46d1f3455 Fix RSS link in <head> 2020-04-10 11:55:19 +02:00
Toothbrush
cf1e447d9c Remove note about rustfmt and clippy components (#788)
This note is no longer needed since 2020-04-06 (see https://rust-lang.github.io/rustup-components-history/).
2020-04-09 09:27:18 +02:00
Philipp Oppermann
b2b58278be Remove note about job search 2020-04-08 15:15:20 +02:00
Philipp Oppermann
a947956616 Add link tag for RSS feed 2020-04-07 15:42:14 +02:00
Stefan Gränitz
9b3ab1bba5 Some more fixes in Async/Await (#787) 2020-04-07 10:51:50 +02:00
Stefan Gränitz
cbfd467011 Fix 3 typos in Async/Await (#786) 2020-04-06 10:24:26 +02:00
Philipp Oppermann
a237cd2777 Truncate description of extra pages to 150 characters 2020-04-02 10:34:18 +02:00
Philipp Oppermann
f13fc3062a Remove duplicated <h1> tags on first edition index 2020-04-02 10:32:41 +02:00
Philipp Oppermann
392cbc2d41 Merge pull request #784 from phil-opp/status-update
Updates in March 2020
2020-04-01 16:48:07 +02:00
Philipp Oppermann
f8f9a02d56 Updates in March 2020 2020-04-01 14:49:18 +02:00
Philipp Oppermann
47969a618e Merge pull request #783 from phil-opp/task-id-counter
Update Async/Await post for new task ID implementation
2020-04-01 12:54:46 +02:00
Philipp Oppermann
a96a5ca8d7 Update Async/Await post for new task ID implementation
Updates the post to incorporate the changes from #782.
2020-04-01 12:51:20 +02:00
Philipp Oppermann
b6d09c8a70 Fix duplicate words 2020-04-01 12:19:48 +02:00
Philipp Oppermann
a98de2a76c Fix typo 2020-03-31 16:41:39 +02:00
Julian
8aea96a4e3 Fix typo (#781) 2020-03-31 15:41:08 +02:00
Philipp Oppermann
7cf7646ed0 Fix dead link 2020-03-31 13:18:55 +02:00
Neeraj Jaiswal
5c617f311a Fix queue name in keyboard::add_scancode (#780) 2020-03-31 12:56:13 +02:00
Rustin
023a18014e Also delete useless function translate_addr_inner (#778) 2020-03-30 14:24:00 +02:00
zeroed
c67da817b7 Fix typo: "s/sately/safely/" (#779) 2020-03-30 11:43:45 +02:00
Philipp Oppermann
0512a65c42 Fix link
Fixes #776
2020-03-29 12:33:22 +02:00
Ellis Hoag
101a0c8648 [typo] an => our (#775) 2020-03-28 18:20:05 +01:00
Philipp Oppermann
2966752b73 Fix duplicated 'the the' 2020-03-28 13:38:42 +01:00
Philipp Oppermann
a04926ae4d Discuss the approach of storing offsets for self-referential structs (#774) 2020-03-28 13:17:31 +01:00
kschibli
b82d0bdefb Fix typo 'compilicated' (#773) 2020-03-28 12:59:52 +01:00
Philipp Oppermann
f32ee7fbbb Fix collision of reference-styile markdown link
It seems like markdown does ignore casing for reference-style links, leading to a collision because both [`wake`] and [`Wake`] are defined. This commit fixes this by using a different name for the second link reference.
2020-03-28 11:47:14 +01:00
Philipp Oppermann
a83a946cda Merge pull request #771 from stensonowen/typos
Fix minor typos in post 12
2020-03-28 11:40:07 +01:00
Michel Boaventura
84f726edd6 Fix minor typo (#772) 2020-03-28 11:39:23 +01:00
Jonathan Klimt
1aa1a0c0d5 Fixed minor typo in example code (#769)
`WaitingOnFooTxt` -> `WaitingOnBarTxt`
2020-03-28 11:39:02 +01:00
owen
e7a35086f7 Fix trait name in example code (s/Fut/F/) 2020-03-27 20:24:22 -04:00
owen
8a7e8665d2 Fix 'uphelp' and s/and/an 2020-03-27 20:14:09 -04:00
Philipp Oppermann
74969cd1be Move toc_aside out of <main>
This way, we avoid that the table of contents is picked for link previews by third-party sites.
2020-03-27 18:02:46 +01:00
Philipp Oppermann
6163821401 Merge pull request #767 from phil-opp/async-await
New post about Async/Await
2020-03-27 17:34:42 +01:00
Philipp Oppermann
4f8858f75d Update Readme for new async/await post 2020-03-27 17:31:19 +01:00
Philipp Oppermann
fb2b6f3685 Update chapter name of post 2020-03-27 17:30:37 +01:00
Philipp Oppermann
5286828cb8 Set release date for post 2020-03-27 17:24:06 +01:00
Philipp Oppermann
d29a28591e Finish the post 2020-03-27 17:23:29 +01:00
Philipp Oppermann
da58c31ed4 Fill in required nightly version and note missing rustfmt 2020-03-26 18:23:21 +01:00
Philipp Oppermann
55bfb1d550 Minor improvements 2020-03-26 18:12:25 +01:00
Philipp Oppermann
4d326ef806 Ignore linkedin.com in link checking 2020-03-26 17:24:40 +01:00
Philipp Oppermann
117fcbddd4 Resolve remaining TODO-links 2020-03-26 17:18:22 +01:00
Philipp Oppermann
46fbd2454c Add TODO for updating release date before publishing 2020-03-26 17:02:20 +01:00
Philipp Oppermann
fe0c8ccb0c Add job seeking note 2020-03-26 17:02:01 +01:00
Philipp Oppermann
e76e71f285 Write introduction 2020-03-26 17:01:39 +01:00
Philipp Oppermann
358a05c0fa Fix some typos 2020-03-26 13:42:05 +01:00
Philipp Oppermann
1264a44aa0 Don't check links to github.com because of rate limiting 2020-03-26 13:42:05 +01:00
Philipp Oppermann
9c96651e70 Write summary and what's next sections 2020-03-26 13:42:05 +01:00
Philipp Oppermann
8e758c383c Finish implementation of executor with waker support 2020-03-26 13:42:05 +01:00
Philipp Oppermann
886d7411ae Begin working on executor with waker support 2020-03-26 13:42:05 +01:00
Philipp Oppermann
7600a763a2 Unregister keyboard waker when we can continue
Avoids that the waker stored in the waker_cache in the executor is dropped first. Thus, it avoids that the waker is deallocated inside interrupt handlers.
2020-03-26 13:42:05 +01:00
Philipp Oppermann
8d3cdf62e3 Add keyboard output gif 2020-03-26 13:42:05 +01:00
Philipp Oppermann
9e5e993a1b Fix typo 2020-03-26 13:42:05 +01:00
Philipp Oppermann
5a879058c9 Minor fixes 2020-03-26 13:42:05 +01:00
Philipp Oppermann
c26d36ebce Prevent deadlock by basing DummyWaker directly on RawWaker
Don't use Arc for DummyWaker. It causes a drop in the `add_scancode` function, which can easily lead to a deadlock because the function is called directly from the interrupt handler.
2020-03-26 13:42:05 +01:00
Philipp Oppermann
89f5350ac4 Start explaining the deadlock problem caused by Arc dealloc 2020-03-26 13:42:05 +01:00
Philipp Oppermann
c423363266 Small fixes to text and code examples 2020-03-26 13:42:05 +01:00
Philipp Oppermann
000adfb2be Create a keyboard task and use it with our SimpleExecutor 2020-03-26 13:42:05 +01:00
Philipp Oppermann
4f29fdea72 Add Waker support to the poll_next implementation on ScancodeStream 2020-03-26 13:42:05 +01:00
Philipp Oppermann
c3648e4b20 Implement Stream for ScancodeStream 2020-03-26 13:42:05 +01:00
Philipp Oppermann
dd83feec2d Add section about filling the scancode queue 2020-03-26 13:42:05 +01:00
Philipp Oppermann
45afd2032b Add section about scancode queue 2020-03-26 13:42:05 +01:00
Philipp Oppermann
744314cb3a Begin section about async keyboard interrupt 2020-03-26 13:41:25 +01:00
Philipp Oppermann
1907e5d3ce Summarize execution steps for the simple executor example 2020-03-26 13:41:25 +01:00
Philipp Oppermann
50db561774 Update implementation section 2020-03-26 13:41:25 +01:00
Philipp Oppermann
326a35939a Start implementation section 2020-03-26 13:41:25 +01:00
Philipp Oppermann
ae167faee5 Explain how async/await implements cooperative multitasking 2020-03-26 13:41:25 +01:00
Philipp Oppermann
fb0f30b9f0 Write section about executors and wakers 2020-03-26 13:41:25 +01:00
Philipp Oppermann
75e2626dc0 Some minor improvements 2020-03-26 13:41:25 +01:00
Philipp Oppermann
def0e6762d Add images for pinning section 2020-03-26 13:41:25 +01:00
Rob Gries
ba6452c5b0 Fix typos (#759) 2020-03-26 13:41:25 +01:00
Philipp Oppermann
817c0c56ab Fix typo 2020-03-26 13:41:25 +01:00
Philipp Oppermann
81f71982f4 Finish first draft of pinning section 2020-03-26 13:41:25 +01:00
Philipp Oppermann
bf07f26e73 Begin section about pinning 2020-03-26 13:41:25 +01:00
Philipp Oppermann
642ff0f27f Minor improvement 2020-03-26 13:41:25 +01:00
Philipp Oppermann
58faf5adf0 Remove old section 2020-03-26 13:41:25 +01:00
Philipp Oppermann
868a6f03ec Add explantion for state machine code 2020-03-26 13:41:25 +01:00
Philipp Oppermann
2ff011ffba Split code example into individual match cases; add code for example 2020-03-26 13:41:25 +01:00
Philipp Oppermann
7ce491df53 Start creating full state machine for example 2020-03-26 13:41:25 +01:00
Philipp Oppermann
3d89841a51 Update async/await sections and 'saving state' section 2020-03-26 13:41:25 +01:00
Philipp Oppermann
3cff5d0961 Small improvements 2020-03-26 13:41:25 +01:00
Philipp Oppermann
51a02a4064 Typo fix 2020-03-26 13:41:25 +01:00
Philipp Oppermann
752accdd33 Explain how to work with futures and introduce async/await 2020-03-26 13:41:25 +01:00
Philipp Oppermann
bdcd392dbf Start explaining futures in Rust 2020-03-26 13:40:34 +01:00
Philipp Oppermann
6f7c5a35dd Begin a new post about async/await 2020-03-26 13:40:34 +01:00
StackDoubleFlow
4feaffe102 Use a instead of an before a constant (#766) 2020-03-17 08:48:17 +01:00
Philipp Oppermann
e0686209f4 Fix cargo doc links that were moved
Move occured in https://github.com/rust-lang/cargo/pull/7733 and was just released together with Rust 1.42.
2020-03-13 13:47:26 +01:00
Philipp Oppermann
e061557eea Use <h2> for site title for first edition too 2020-03-11 13:51:22 +01:00
Patrick
aeafe57c5d Removed unnecessary word (#765)
Removed the word "executes" from "The CPU executes tries to write to `0xdeadbeef`, which causes a page fault."
2020-03-11 13:07:22 +01:00
Philipp Oppermann
e84b6f4084 Merge pull request #764 from phil-opp/x86_64-0.9.6
Update x86_64 dependency to version 0.9.6
2020-03-08 14:40:32 +01:00
Philipp Oppermann
82c6a5dd60 Update x86_64 dependency to version 0.9.6 2020-03-08 14:38:38 +01:00
Philipp Oppermann
f9002f9f9b Update Heap Allocation post for new spinlock type of linked_list_allocator 2020-03-06 14:56:07 +01:00
Philipp Oppermann
bf4c928214 Update Heap Allocation post for #763 2020-03-06 11:50:29 +01:00
Philipp Oppermann
bdf161aa7d Merge pull request #760 from phil-opp/status-update
Updates in February 2020
2020-03-02 11:49:06 +01:00
Philipp Oppermann
bfdc1e96a6 Create February status update 2020-03-02 11:42:19 +01:00
Philipp Oppermann
368b5445e4 Update 'thank you' text 2020-03-02 11:41:53 +01:00
Philipp Oppermann
6b76338407 Add a .gray css class for making things gray 2020-03-02 11:41:41 +01:00
Philipp Oppermann
6beedbdba9 Merge pull request #758 from phil-opp/pc-keyboard-0.5.0
Hardware Interrupts: Update pc-keyboard crate to v0.5.0
2020-02-26 12:20:01 +01:00
Philipp Oppermann
fb920af5dc Hardware Interrupts: Update pc-keyboard crate to v0.5.0 2020-02-26 12:17:35 +01:00
Philipp Oppermann
acea700708 Fix overlap of 'All Posts' and ToC; add comments to ToC
The 'All Posts' link used to overlap with the table of contents at the end of a post. This occured because the ToC is sticky to the `main` block, so it scrolled up before the `comments` section. The 'All Post' link, however, is fixed, so it does not scroll up.

This commit fixes the issue by moving the comment block to the main block (from the after_main block). This way, the ToC stays visible in the comment section. We also add the comment section to the ToC.
2020-02-25 14:26:41 +01:00
Philipp Oppermann
0619f3a9e7 Convert all external links to https (if supported) 2020-02-21 11:53:34 +01:00
Philipp Oppermann
361108b88e Move language selector to the top 2020-02-21 11:29:11 +01:00
Philipp Oppermann
b03a368191 Truncate site description to 150 characters
According to the Bing webmaster tools, this is recommended for SEO.
2020-02-21 11:24:45 +01:00
Philipp Oppermann
516bc38b2b Ensure that each page only has a single <h1>
According to Bing's webmaster tool multiple <h1> tags on a site are a SEO problem.
2020-02-21 11:17:31 +01:00
Philipp Oppermann
b532c052ad Double Faults: A missing handler leads to a #GP exception (not a #NP)
A IDT entry that is zero is not valid (e.g. the must-be-one bits are not set). For this reason, a general protection fault occurs instead of a segment-not-present fault.

See https://github.com/phil-opp/blog_os/issues/449#issuecomment-558906316 for more information.
2020-02-19 10:58:55 +01:00
Philipp Oppermann
a392065ca8 Merge pull request #732 from phil-opp/phil-opp-patch-1
Mention in "Paging Introduction" that a CPU with 5-level paging is available now
2020-02-18 14:58:21 +01:00
Philipp Oppermann
0195d2ec43 Don't escape permalink; emit less newlines 2020-02-17 15:07:43 +01:00
Philipp Oppermann
cc27cf5c24 Only emit language selector on pages that have translations 2020-02-17 15:07:09 +01:00
Philipp Oppermann
fa5b500751 Remove debug logging from javascript 2020-02-17 15:06:48 +01:00
Philipp Oppermann
2c9226e4b1 Merge pull request #752 from phil-opp/lang-selector
Add a language selector for browser-supported languages
2020-02-17 14:56:46 +01:00
Philipp Oppermann
6908e297f6 Make language selectors of browser supported languages visible 2020-02-17 14:52:15 +01:00
Philipp Oppermann
8ff09b3a62 Add hidden language selector to front page and post pages 2020-02-17 14:51:51 +01:00
Philipp Oppermann
ea3e89dd00 Select front page aside by class page-aside-right instead of id recent-updates 2020-02-17 14:51:19 +01:00
Philipp Oppermann
b8e8370a4c Merge pull request #751 from phil-opp/fix-zola-check
Use zola check to check for dead links; fix all dead links found
2020-02-17 13:49:56 +01:00
Philipp Oppermann
2cb6d2f3d0 Add a _index.md to prevent orphan pages 2020-02-17 13:45:49 +01:00
Philipp Oppermann
71dee66573 Make link_checker skip more sites 2020-02-17 13:43:33 +01:00
Philipp Oppermann
65da18d143 Fix dead links 2020-02-17 13:41:22 +01:00
Philipp Oppermann
f21bef93b1 Don't check anchors for github.com 2020-02-17 13:31:22 +01:00
Philipp Oppermann
3f43994766 Don't continue on error for zola check 2020-02-17 13:31:21 +01:00
Philipp Oppermann
06862d354e Merge pull request #750 from phil-opp/sort-recent-updates
Sort recent updates by merge date
2020-02-17 12:41:58 +01:00
Philipp Oppermann
06aded3ce4 Sort recent updates by merge date 2020-02-17 12:39:05 +01:00
Philipp Oppermann
cdb6aabdbf Consider the newest 100 pull requests in recent list
There might be old pull requests that were recently merged.
2020-02-17 12:33:45 +01:00
Philipp Oppermann
c23e8f8c65 Merge pull request #749 from phil-opp/translation-metadata
Add metadata to translations and list translators
2020-02-17 12:08:52 +01:00
Philipp Oppermann
db69d016a9 Add metadata to translations and list translators 2020-02-17 12:04:12 +01:00
Philipp Oppermann
9e5e3fba16 Remove some more whitespace to minimize diff 2020-02-17 11:39:24 +01:00
Philipp Oppermann
135d6e510e Merge pull request #748 from phil-opp/translations-fix
Some fixes to generated translations
2020-02-17 11:32:18 +01:00
Philipp Oppermann
0e3635f98b Remove some excessive newlines from generated HTML 2020-02-17 11:30:50 +01:00
Philipp Oppermann
127f446856 Don't show 'not translated yet' for default language 2020-02-17 11:30:47 +01:00
Philipp Oppermann
0ae8c972bb Specify a template for zh-TW posts 2020-02-17 11:18:09 +01:00
Philipp Oppermann
03d4cc43ec Merge pull request #692 from phil-opp/translations
Experimental Support for Community Translations
2020-02-17 11:09:18 +01:00
Philipp Oppermann
04fae1194f Remove stale link 2020-02-17 11:04:04 +01:00
Philipp Oppermann
f6867a914e Don't show 'not translated yet' message on english site 2020-02-17 11:01:25 +01:00
Philipp Oppermann
0f8bd7fab8 Fix internal link syntax in translation 2020-02-17 10:49:00 +01:00
Philipp Oppermann
7124ce742f Merge branch 'master' into translations 2020-02-17 10:38:43 +01:00
Philipp Oppermann
1ea72a0080 Merge pull request #694 from phil-opp/rustcc-translation
Add translations from rustcc/writing-an-os-in-rust
2020-02-17 10:37:17 +01:00
Philipp Oppermann
2b20528eee Merge pull request #747 from phil-opp/zola-0.10.0
Update to Zola 0.10
2020-02-17 10:26:32 +01:00
Philipp Oppermann
a3d73fa5ff Zola 0.10 was released 2020-02-17 10:23:42 +01:00
Philipp Oppermann
9547b0fc72 Revert "Use upcoming zola release on Github Actions"
This reverts commit c33c08392c.
2020-02-17 10:23:08 +01:00
Philipp Oppermann
bccfef77c9 Merge branch 'master' into zola-0.10.0 2020-02-17 10:22:11 +01:00
Jayanth Manklu
b01c6b68b6 Fix a grammatical miss in println macro section (#745) 2020-02-16 17:56:40 +01:00
Philipp Oppermann
9924ed0b13 Add styling for upcoming multitasking chapter 2020-02-11 10:31:44 +01:00
Philipp Oppermann
78f55a701f Use for loop on index page instead of hardcoding post numbers 2020-02-11 10:29:48 +01:00
Philipp Oppermann
7d27a2c4a4 Add chapter information to frontmatter 2020-02-11 10:29:48 +01:00
Philipp Oppermann
c1319ba34f Update Readme for Allocator Designs post 2020-02-10 15:05:07 +01:00
Philipp Oppermann
a3eeb1ded7 Clarify that x86-interrupt only saves registers that are overwritten 2020-02-07 18:18:33 +01:00
Philipp Oppermann
536a37aee9 Shorten site description a bit 2020-02-07 12:29:39 +01:00
Philipp Oppermann
4707ea617f Update Allocator Designs post to signal OOM instead of panicking on overflow (#739) 2020-02-04 09:47:43 +01:00
Philipp Oppermann
83239394dd Mention potential bump allocator extensions (#722)
These extensions make it possible to reuse freed memory in more cases. While they would fix the failing test, they are no general solutions.
2020-02-04 08:55:02 +01:00
Philipp Oppermann
5276972c67 Set meta.description tag correctly 2020-02-03 17:13:28 +01:00
Philipp Oppermann
174d695512 Merge pull request #735 from phil-opp/status-update
Updates in January 2020
2020-02-01 14:26:48 +01:00
Philipp Oppermann
e134914ef8 Updates in January 2020 2020-02-01 14:24:58 +01:00
Philipp Oppermann
e91567f637 Reword 'thank you' section 2020-02-01 14:24:41 +01:00
Maxim Zholobak
423ab3fa68 Make active section link more discreet (#734) 2020-01-31 16:20:13 +01:00
Philipp Oppermann
b569fcbc25 Fix typo in Javascript comment 2020-01-31 14:19:52 +01:00
Philipp Oppermann
728620b527 Mark active item in table of contents (#733) 2020-01-31 14:17:22 +01:00
Philipp Oppermann
e2ea963d5d Make 'All Posts' link fixed
Fixes #731
2020-01-31 12:12:54 +01:00
Philipp Oppermann
9c6cdff785 A CPU with 5-level paging is available now 2020-01-31 11:10:09 +01:00
Philipp Oppermann
670ac60e1b Update Allocator Designs post to use LinkedListAllocator::lock method 2020-01-30 13:04:56 +01:00
Philipp Oppermann
4f42826399 Update address on contact page 2020-01-30 12:42:13 +01:00
Philipp Oppermann
5f7437df8d Fix and improve generated HTML 2020-01-30 12:05:04 +01:00
Rustin
6d4f1d6c43 post-3 translation refactor (#725) 2020-01-30 10:37:40 +01:00
Philipp Oppermann
409c6de44a Add doc link for eh_personality language item 2020-01-29 13:29:01 +01:00
Philipp Oppermann
571c66c1b2 Merge pull request #729 from phil-opp/front-page-update
Some style updates to the front page
2020-01-28 17:45:18 +01:00
Philipp Oppermann
6a56ea242f Fix dummy allocator code example (#728)
We forgot to remove the `allocator::` prefix when moving the ALLOCATOR declaration into the `allocator` module.
2020-01-28 17:10:46 +01:00
Philipp Oppermann
c7af79f452 Remove '(Second Edition)' from title 2020-01-28 17:06:47 +01:00
Philipp Oppermann
578b03efcb Move and rewrite front page section about first edition 2020-01-28 16:59:47 +01:00
Philipp Oppermann
d351e48602 Adjust style of 'read more' link 2020-01-28 16:58:26 +01:00
Philipp Oppermann
f710404f10 Remove extra content section from front page
We only have a single extra post, which is about building on Android and possibly outdated.
2020-01-28 16:57:49 +01:00
Philipp Oppermann
007bf8a937 Move posts about red zone and disabling SIMD in second post folder
They are strongly related to the second post.
2020-01-28 16:57:00 +01:00
Philipp Oppermann
0c67111e68 Merge pull request #721 from phil-opp/align-up-performance
Provide multiple implementations of align_up and mention performance
2020-01-28 10:39:20 +01:00
Philipp Oppermann
16a6aca76a Use bitmask method instead of align_offset
See https://github.com/phil-opp/blog_os/issues/720#issuecomment-578874828
2020-01-28 10:21:20 +01:00
Philipp Oppermann
c0399b04db Update allocator designs post to use checked additions (#727) 2020-01-27 13:25:13 +01:00
Philipp Oppermann
4b8c902354 Fix typo 2020-01-27 12:46:33 +01:00
Philipp Oppermann
7070bb608d Fix typo
Accidentally introduced in 0b9ca84735.
2020-01-22 12:42:19 +01:00
Philipp Oppermann
3a6aa9834a Provide multiple implementations of align_up and mention performance 2020-01-22 11:36:54 +01:00
Philipp Oppermann
0346ec3111 Merge pull request #719 from phil-opp/allocator-designs
New post about allocator designs
2020-01-20 14:22:09 +01:00
Philipp Oppermann
2f926b601c Update release date 2020-01-20 14:18:10 +01:00
Philipp Oppermann
d6da1c8485 Typo fixes 2020-01-20 14:17:44 +01:00
Philipp Oppermann
6ecf2998ee Minor improvements 2020-01-20 14:00:52 +01:00
Philipp Oppermann
13d65e64b5 Improve post introduction 2020-01-20 13:09:46 +01:00
Philipp Oppermann
0b9a80684a Fix typo 2020-01-20 11:47:54 +01:00
Philipp Oppermann
bd94c52c36 What's next? 2020-01-20 11:45:29 +01:00
Philipp Oppermann
9d25a18f9e Write summary 2020-01-20 11:38:02 +01:00
Philipp Oppermann
987138f5bf Write discussion section for fixed-size block allocator 2020-01-20 11:04:21 +01:00
Philipp Oppermann
dc8d0a833b Add image 2020-01-20 10:09:08 +01:00
Philipp Oppermann
6368938b9e Link to free list wikipedia article 2020-01-20 10:08:33 +01:00
Philipp Oppermann
8500b480a9 Reword 'support me' text 2020-01-15 18:53:58 +01:00
Philipp Oppermann
deca65eb1f Break long line in code excerpt 2020-01-15 18:23:59 +01:00
Philipp Oppermann
2cfa13a48f Add missing imports 2020-01-15 18:13:43 +01:00
Philipp Oppermann
687c81eedb Array initialization using non-Copy types requires feature gate 2020-01-15 18:06:30 +01:00
Philipp Oppermann
658212c1f5 Add bullet points for discussion section 2020-01-15 17:17:27 +01:00
Philipp Oppermann
04857a063d Write short 'Using it' section 2020-01-15 15:42:16 +01:00
Philipp Oppermann
5d14722601 Store a Option<&mut ListNode in head array instead of a dummy ListNode 2020-01-15 15:34:13 +01:00
Philipp Oppermann
db20a40745 Write implementation section for fixed-size block allocator 2020-01-15 13:42:39 +01:00
Philipp Oppermann
07b1ee0199 Fix internal link 2020-01-15 13:42:08 +01:00
Philipp Oppermann
ad671a3a92 Continue fixed-size block allocator section 2020-01-14 12:34:26 +01:00
Philipp Oppermann
f042761ada Fix typo 2020-01-14 11:50:28 +01:00
Philipp Oppermann
64e5b67f35 Remove old content 2020-01-14 11:49:07 +01:00
Philipp Oppermann
c92b0d46dc Begin introduction for fixed-size block allocator 2020-01-14 11:48:28 +01:00
Philipp Oppermann
1915e6feb4 Minor improvements to linked list section 2020-01-14 11:48:09 +01:00
Philipp Oppermann
8f80378e65 Improve section about performance of linked list allocator 2020-01-14 10:50:32 +01:00
Philipp Oppermann
b34cad7c61 Improve example for merging freed blocks 2020-01-14 10:50:00 +01:00
Philipp Oppermann
e4c07e0356 Fill in images related to merging freed blocks 2020-01-13 13:21:58 +01:00
Philipp Oppermann
6a4fdf94fc Write discussion section 2020-01-13 10:07:25 +01:00
Philipp Oppermann
14c0cc7ece Fix typo 2020-01-10 13:09:31 +01:00
Philipp Oppermann
231b5d587b Update implementation section of linked list allocator 2020-01-10 13:09:20 +01:00
Philipp Oppermann
6cc3449183 Restructure headings 2020-01-09 16:52:47 +01:00
Philipp Oppermann
dda99166d9 Start rewriting linked list allocator section 2020-01-09 16:33:40 +01:00
Philipp Oppermann
f19b93eb34 Fixes and improvements to bump allocator section 2020-01-09 15:43:35 +01:00
Philipp Oppermann
e4652090a8 Finish rewrite of bump allocator section 2020-01-09 13:46:37 +01:00
Philipp Oppermann
8fb0a7c405 Update blog for #716 2020-01-09 13:01:25 +01:00
Philipp Oppermann
192923bd2a Fix typo in support template 2020-01-09 12:59:17 +01:00
Philipp Oppermann
851460fe12 Fix typos 2020-01-08 18:03:16 +01:00
Philipp Oppermann
37aa01958a Start rewriting bump allocator section
Remove the `Locked` wrapper type as we can just use `spin::Mutex` directly.
2020-01-08 17:39:26 +01:00
Philipp Oppermann
c3feb6a9e6 Reword design section 2020-01-08 17:38:06 +01:00
Philipp Oppermann
ed157c8a75 Write an introduction 2020-01-08 17:37:40 +01:00
Philipp Oppermann
26fc3ba626 Add a small abstract 2020-01-08 17:37:28 +01:00
Philipp Oppermann
06ea0caece Code will be available in post-11 branch 2020-01-08 12:41:12 +01:00
Philipp Oppermann
620958a8a2 Fix interal links 2020-01-08 12:41:12 +01:00
Philipp Oppermann
5937ec2e04 Reintroduce allocator designs post
The post was split off the Heap Allocations post because it became too large. To keep the tree clean, it was then temporarily removed. This commit restores the post by reverting the removal commit.

This reverts commit 029d77ef21.
2020-01-08 12:41:12 +01:00
Philipp Oppermann
4e5a757396 It is now possible to define allocators in submodules (#715) 2020-01-08 12:39:11 +01:00
Philipp Oppermann
581849098f Fix typo 2020-01-08 12:24:09 +01:00
Philipp Oppermann
dd5baca85d Updates in December 2019 (#712) 2020-01-07 13:11:07 +01:00
Philipp Oppermann
1bde324162 Remove azure pipelines and travis CI scripts 2020-01-07 13:10:51 +01:00
Philipp Oppermann
05ac04d30d Update copyright year in footer 2020-01-07 12:23:32 +01:00
Wu Yu Wei
4784ec9915 Add Traditional Chinese on chapter 1 (#699)
* Add traditional chinese on chapter 1

* Fix markdown typo

* Fix language tag

* Rename post name to right language tag

* Add commit data to front matter

* Update extra info in front matter
2020-01-07 10:54:49 +01:00
Philipp Oppermann
f1b13d7ed3 The LLVM error code bug was resolved (#711)
We already updated the other posts in https://github.com/phil-opp/blog_os/pull/644 but forgot to update this post
2020-01-05 20:02:39 +01:00
Rustin
55f19fdcdc post-2 translation refactor (#708) 2020-01-05 19:30:44 +01:00
Philipp Oppermann
6db4e34c48 Merge pull request #709 from pamolloy/pmolloy/minor-grammar
Reword sentence in first post
2019-12-29 17:51:56 +01:00
Philip Molloy
d9d204a6cd Remove superfluous adjective
"own" may be used as an adjective, but must follow a possessive word. Rather than add "our" just remove the adjective entirely since ownership is not significant.

Co-Authored-By: Philipp Oppermann <dev@phil-opp.com>
2019-12-29 11:47:06 -05:00
Philip Molloy
fdccda6b54 Add missing word to sentence 2019-12-27 16:25:23 -05:00
Philipp Oppermann
60ce0e0cd4 Show translated content directly on index page (#693)
instead of only providing a 'Community Translation' link
2019-12-19 13:31:12 +01:00
Philipp Oppermann
001e041855 Merge branch 'translations' into rustcc-translation 2019-12-19 13:19:00 +01:00
Philipp Oppermann
b31b2af58b Merge branch 'master' into translations 2019-12-18 12:13:47 +01:00
Philipp Oppermann
6e04648284 Merge pull request #700 from Rustin-Liu/rustcc-translation
refactor first post translation
2019-12-16 17:18:03 +01:00
Philipp Oppermann
bf5e2cf4dc Use <h1> instead of <h2> for 'Recent Updates'/'Repository' 2019-12-13 12:36:35 +01:00
Rustin-Liu
59fe01cef6 refactor to change word 2019-12-13 19:19:59 +08:00
Rustin-Liu
e0a823bf58 add space 2019-12-13 19:17:36 +08:00
Philipp Oppermann
f8a50cb752 Code examples are _additionally_ licensed under MIT/Apache2 2019-12-12 10:51:57 +01:00
Philipp Oppermann
44cefeec28 Improve rendering of "```" 2019-12-12 10:51:15 +01:00
Philipp Oppermann
2eeec2bfc6 Merge pull request #705 from phil-opp/license
License the `blog/content` folder under CC BY-NC
2019-12-12 10:48:52 +01:00
Philipp Oppermann
f53f09cea5 Clarify licensing of contributions to blog/content 2019-12-12 10:10:07 +01:00
Philipp Oppermann
7205b5f942 Remove azure pipelines CI script 2019-12-12 10:08:17 +01:00
Philipp Oppermann
5b7129acb7 Ignore README.md in zola processing 2019-12-12 10:06:39 +01:00
Philipp Oppermann
a7ae6519c7 Clarify licensing in root README 2019-12-12 09:55:23 +01:00
Philipp Oppermann
9406eb32f6 License blog content under CC BY-NC 2019-12-12 09:55:03 +01:00
Philipp Oppermann
ef1885d63e Update copyright year in MIT license 2019-12-12 09:54:30 +01:00
Philipp Oppermann
6d091df30c Merge pull request #704 from phil-opp/x86_64-0.8.0
Update blog to x86_64 version 0.8.1
2019-12-11 16:53:34 +01:00
Philipp Oppermann
b0317d0e4a Remove now unneeded unsafe block in Heap Allocation post
The `map_to` method is safe since x86_64 0.8.1.
2019-12-11 16:50:13 +01:00
Philipp Oppermann
b65825e99a Update docs.rs links to point to x86_64 0.8.1 2019-12-11 16:46:04 +01:00
Philipp Oppermann
5ad8df595c Update Paging Implementation post for new UnusedPhysFrame type 2019-12-11 16:46:04 +01:00
Philipp Oppermann
130fc3e075 Make double fault handler diverging 2019-12-11 16:37:16 +01:00
Philipp Oppermann
f02e3a23ee Update x86_64 version in Testing post 2019-12-11 16:37:16 +01:00
Rustin-Liu
3ec59540bd Merge branch 'rustcc-translation' of https://github.com/phil-opp/blog_os into rustcc-translation 2019-12-09 21:43:34 +08:00
Philipp Oppermann
01c887530b Apply suggestions from @Rustin-Liu
Co-Authored-By: Rustin <1196089730@qq.com>
2019-12-09 14:17:18 +01:00
Rustin-Liu
5824c9de52 first post translation refactor 2019-12-09 20:40:03 +08:00
Rustin-Liu
c3805b6b2f first post translation refactor and review 2019-12-09 20:23:15 +08:00
Philipp Oppermann
78ce5f3e6e Updates in October and November 2019 (#695) 2019-12-02 15:13:53 +01:00
Philipp Oppermann
3d25c27b11 Add message if recent update list is empty
Instead of showing an empty section, print 'No notable updates recently'.
2019-12-02 15:08:17 +01:00
luojia65
469add4b6b Add translations from rustcc/writing-an-os-in-rust
d5d1e6abc8
2019-11-28 13:11:25 +01:00
Philipp Oppermann
a66fe41977 Default to config.default_language if no lang is set (e.g. for 404 page) 2019-11-28 11:30:17 +01:00
Philipp Oppermann
63e53724c4 Zola does not make the lang variable available when rendering rss.xml
We only generate a RSS feed for the default language anyway.
2019-11-27 16:34:24 +01:00
Philipp Oppermann
85bd909af2 Update HTML language tag for translations 2019-11-27 16:02:35 +01:00
Philipp Oppermann
94a19f627b Change Chinese language tag to zh-CN (simplified Chinese) 2019-11-27 15:59:06 +01:00
Philipp Oppermann
e0d25951a2 Adjust translated post to zola multilingual naming scheme 2019-11-27 15:36:18 +01:00
Philipp Oppermann
c14adf700a Merge pull request #682 from TheBegining/master 2019-11-27 15:35:00 +01:00
Philipp Oppermann
8e2e4e7c30 Point 'All Posts' link to localized index page 2019-11-27 15:34:54 +01:00
Philipp Oppermann
a1020cde7d Show links to community translated posts 2019-11-27 15:34:54 +01:00
Philipp Oppermann
d1da7f4a47 Write a proper warning message for translated posts 2019-11-27 15:34:54 +01:00
Philipp Oppermann
55a45c7673 Start adding support for translations 2019-11-27 15:34:54 +01:00
Philipp Oppermann
e9361e74e8 The global toc was replaced by page.toc in upcoming zola version 2019-11-27 14:48:24 +01:00
Philipp Oppermann
c33c08392c Use upcoming zola release on Github Actions 2019-11-27 14:37:07 +01:00
Philipp Oppermann
bb2ac9c259 Add missing hlt_loop import in code listing
The hlt_loop import was missing when creating a page fault handler.
2019-11-25 13:32:38 +01:00
MarinPostma
6d95caec31 fixed repeated "the" typo (#691) 2019-11-23 15:41:31 +01:00
Philipp Oppermann
555b5aece1 Hardware Interrupts: Don't replace panic in double fault handler (#690) 2019-11-22 16:13:01 +01:00
Daniel Harper
537a070238 Clarified writing beyond the buffers end (#685) 2019-11-16 20:25:05 +01:00
cqh
dcacc7969f Update Chinese translate 2019-10-26 00:00:14 +08:00
cqh
63110b204d Add Chinese translate 2019-10-21 23:30:02 +08:00
Philipp Oppermann
a439f96384 Also deploy site on schedule event 2019-10-18 15:02:09 +02:00
Philipp Oppermann
8e0d70da8b Add a sponsor link to github box on front page 2019-10-18 14:58:26 +02:00
Philipp Oppermann
18ce0f4219 Update to new Github Sponsors URL 2019-10-18 14:55:59 +02:00
Philipp Oppermann
7f4fc340ad Fix escaping issues by adding safe filters in more places (#678) 2019-10-08 10:28:45 +02:00
Philipp Oppermann
50aaa206bf Reword support text 2019-10-06 18:28:02 +02:00
Philipp Oppermann
cbed5dae46 Updates in September 2019 (#677) 2019-10-06 18:25:47 +02:00
Philipp Oppermann
fd64bb9d36 Add status update posts to front page 2019-10-06 15:20:39 +02:00
Philipp Oppermann
945aaf02d8 Add support template 2019-10-06 15:05:33 +02:00
Philipp Oppermann
a93c0e424d Mention Github sponsors in status update posts 2019-10-06 14:02:11 +02:00
Philipp Oppermann
7ae2489153 Factor out support text into template and add it to pages too 2019-10-06 13:59:30 +02:00
Philipp Oppermann
78f014e74b Rewrite support section on frontpage; mention GitHub sponsors 2019-10-06 13:51:46 +02:00
Philipp Oppermann
dddabe2243 Fix some remaining internal links that used old syntax 2019-10-06 13:51:09 +02:00
Philipp Oppermann
0caf162825 Add Github Sponsors account 2019-10-06 13:10:16 +02:00
Bruno Flores
24d04e0e39 Fix minor typos. (#675) 2019-10-03 14:07:45 +02:00
Philipp Oppermann
d7ccea9cdb Merge pull request #674 from phil-opp/optional-zola-check
Don't fail job if `zola check` fails
2019-10-02 11:11:10 +02:00
Philipp Oppermann
69bfe311f9 Don't fail job if zola check fails
The external link checker of the `zola check` command has false positives, e.g. https://github.com/getzola/zola/issues/805.
2019-10-02 11:09:16 +02:00
Philipp Oppermann
f5ef5d3222 Fix master ref in if condition of deploy job 2019-10-02 11:03:48 +02:00
Philipp Oppermann
30752f53b8 Debug github actions deploy failure 2019-10-02 11:00:46 +02:00
Philipp Oppermann
76f00c3a08 Merge pull request #673 from phil-opp/gh-actions-job-if
Merge build/deploy workflows by using new job.if
2019-10-02 10:57:10 +02:00
Philipp Oppermann
3ffda44c39 Merge build/deploy workflows by using new job.if 2019-10-02 10:51:21 +02:00
Philipp Oppermann
fac3e7d3c7 Merge pull request #670 from phil-opp/zola-0.9.0
Update to Zola 0.9.0
2019-09-29 16:07:50 +02:00
Philipp Oppermann
46386c71a3 Add a new 'Zola Check' CI workflow
This also checks external links.

We add it as a separate job because it seems to be still buggy.
2019-09-29 16:06:12 +02:00
Philipp Oppermann
ffdd1abd47 Update CI scripts to use zola 0.9.0 2019-09-29 15:52:20 +02:00
Philipp Oppermann
032ea13c65 safe filter must be at the very end since zola 0.8.0 2019-09-29 15:48:12 +02:00
Philipp Oppermann
c76516db75 Fix anchor names of internal links 2019-09-29 15:44:44 +02:00
Philipp Oppermann
e5b4d501ed Remove dead links in first edition
It seems like the corresponding sections do not exist anymore.
2019-09-29 15:36:49 +02:00
Philipp Oppermann
a133ea82cf Update to new internal link syntax 2019-09-29 15:24:21 +02:00
Philipp Oppermann
0b971c9128 12KiB is 0x3000 in hex, not 0xc000 2019-09-29 15:10:17 +02:00
Philipp Oppermann
9877e4c84d Add missing import of serial_print in Testing post 2019-09-20 10:04:48 +02:00
Philipp Oppermann
94e2b7c351 Fix heap allocation test: memory::init expects a VirtAddr now 2019-09-15 10:56:37 +02:00
Philipp Oppermann
d4d853c26d Merge pull request #666 from phil-opp/offset_page_table
Improve Paging Implementation Post
2019-09-14 19:04:57 +02:00
Philipp Oppermann
841bf664fa Improve implementation section of Paging Implementation post 2019-09-14 17:48:07 +02:00
Philipp Oppermann
820bc0cab3 Map page 0 instead of page 0x1000 because of bootloader 0.8.0
Bootloader 0.8.0 maps the page at 0x1000 itself.
2019-09-14 17:41:01 +02:00
Philipp Oppermann
7104014c27 Require up-to-date x86_64 version instead of bootloader version 2019-09-14 10:46:22 +02:00
Philipp Oppermann
4546d40be1 Remove 'Another Paging Post' aside
It's been a while since we removed the old Advanced Paging post.
2019-09-14 10:45:59 +02:00
Philipp Oppermann
553b9723b3 Disable build workflow on staging.tmp branch 2019-09-13 10:48:39 +02:00
bors[bot]
b0aff929f5 Merge #665
665: Fix: Link to the old "Set up GDB" article r=phil-opp a=zzeroo



Co-authored-by: zzeroo <co@zzeroo.com>
2019-09-12 16:02:21 +00:00
zzeroo
a2364f9e59 Fix: Link to the old "Set up GDB" article 2019-09-12 15:35:56 +02:00
Philipp Oppermann
9136f81f78 Simplify Paging Implementation by using OffsetPageTable instead of MappedPageTable 2019-09-11 14:27:54 +02:00
Philipp Oppermann
9d8b55f6ee Update some more doc links to use x86_64 version 0.7.5 2019-09-11 13:48:16 +02:00
Philipp Oppermann
b9005f28f7 Update docs links to use version 0.5.2 of spin 2019-09-11 13:46:56 +02:00
Philipp Oppermann
ea1711fe06 Update docs link to use x86_64 version 0.7.5 2019-09-11 13:45:51 +02:00
Philipp Oppermann
bc738c8afc Update x86_64, volatile, and spin dependencies 2019-09-11 13:30:44 +02:00
Philipp Oppermann
1fc00669a6 Gate bors on Github Actions jobs 2019-09-11 11:19:49 +02:00
Philipp Oppermann
19f585d517 Remove x86_64 dependency update note in Paging Implementation post
We already introduce version 0.7.0 of `x86_64` in the Testing post for some time, so it's reasonable to expect that most people use a compatible version now. Therefore, we no longer need to mention it explicitly.
2019-09-11 11:17:47 +02:00
Philipp Oppermann
0744cc4471 Merge pull request #664 from phil-opp/update-deps
Update to bootloader 0.8.0
2019-09-11 11:10:53 +02:00
Philipp Oppermann
c4546f1e30 Use version 0.8.0 of bootloader 2019-09-11 10:55:29 +02:00
Philipp Oppermann
f124f2fc4d Use version 0.7.7 of bootimage 2019-09-11 10:54:22 +02:00
Philipp Oppermann
ff39b77c18 Use ::set-env command instead of repeating env variable 2019-09-10 19:25:39 +02:00
Philipp Oppermann
a640376d84 Pass SSH_AUTH_SOCK env variable to git push 2019-09-10 16:03:39 +02:00
Philipp Oppermann
529f59264c Merge pull request #660 from phil-opp/github-ci-zola
Use GitHub Actions to build and deploy blog
2019-09-10 15:59:36 +02:00
Philipp Oppermann
fa97ae36b5 Add a deploy workflow 2019-09-10 15:53:22 +02:00
Philipp Oppermann
c0af518121 Add a GitHub Actions workflow to build site using Zola 2019-09-10 15:53:22 +02:00
Philipp Oppermann
fdd8fa3f2a Create a status update post about the changes in August 2019 (#659) 2019-09-09 16:00:25 +02:00
Chris Smith
afdc269323 Fix minor typo (#658)
Found a minor typo while following along.

Thank you for publishing this series, it's great!
2019-09-08 00:47:07 +02:00
Philipp Oppermann
54ad8ae792 Show codepage 437 instead of 737 in Minimal Rust Kernel 2019-09-02 15:47:03 +02:00
Funfoolsuzi
c8b3583465 fix typo in 06-double-fault (#655) 2019-08-20 07:37:58 +02:00
Philipp Oppermann
c88d4d674f Remove pararaph 2019-08-12 19:27:20 +02:00
Philipp Oppermann
cd5dd17a99 Clarify that panic-strategy option is required in target json
The Cargo.toml option does not apply to the core library compiled by cargo-xbuild.
2019-08-12 19:23:57 +02:00
Nikos Fertakis
f4123dc011 Fix typo in 04-testing (#654) 2019-08-10 11:17:19 +02:00
Funfoolsuzi
4b3fbd27cc Fix typo in 05-cpu-exceptions (#653)
Thanks for the great tutorial. Here is a typo I found.
2019-08-09 09:26:39 +02:00
Philipp Oppermann
87c64cf255 Rewrite section about no-harness tests (#650) 2019-08-07 12:39:28 +02:00
Philipp Oppermann
f92f514254 Merge pull request #648 from phil-opp/status-update
Updates in July 2019
2019-08-02 11:15:59 +02:00
Philipp Oppermann
8ccb4bd6fe Update publish date 2019-08-02 11:12:48 +02:00
Philipp Oppermann
1846f75f81 Small grammar fix 2019-08-02 11:12:27 +02:00
William Mbotta
3d015be1fc Fix wrong location for bootimage (#647) 2019-07-30 11:14:12 +02:00
Alex Ozdemir
420d67f092 Fix grammar typo in "Red Zone" (#646)
Replace an adjective with an adverb.
2019-07-27 22:34:29 +02:00
Philipp Oppermann
f57f717f92 Updates in July 2019 2019-07-25 18:20:13 +02:00
Philipp Oppermann
af138542b7 Fix URL of june status update 2019-07-25 17:14:34 +02:00
Philipp Oppermann
f67e7bb128 Update paging introduction post to use page fault error code (#644)
We previously did not use the error code because of https://github.com/phil-opp/blog_os/issues/513, which is now fixed.
2019-07-22 10:47:33 +02:00
Philipp Oppermann
48974ec63e Update posts to bootloader 0.6.4 2019-07-18 10:21:08 +02:00
Philipp Oppermann
f8afce46a1 Minimal Rust Kernel: Only mention core in error message
The `OR` is confusing since the reader might think that it's part of the output. Also, the compiler_builtins error should no longer occur now that the library lives on crates.io.
2019-07-09 19:27:59 +02:00
Philipp Oppermann
c4ccf7303a Create FUNDING.yml 2019-07-07 12:31:59 +02:00
Philipp Oppermann
545b87b10e Update Readme for heap allocation post 2019-07-07 11:23:14 +02:00
Philipp Oppermann
323c0ff611 Fix two more dead links 2019-07-07 11:10:57 +02:00
Philipp Oppermann
7294471223 Fix remaining dead links 2019-07-07 11:03:13 +02:00
Philipp Oppermann
a74c65f8dc Merge pull request #638 from phil-opp/fix-dead-links
Fix lot of dead links in both the second and first edition
2019-07-07 10:39:21 +02:00
Philipp Oppermann
304eb179f1 Use rel="nofollow" for all old comments 2019-07-07 10:36:16 +02:00
Philipp Oppermann
bc5631d9a8 Fix lot of dead links in both the 2nd and 1st edition 2019-07-07 10:33:12 +02:00
Philipp Oppermann
265f9f9bd5 Add June status update post (#635) 2019-07-06 13:19:26 +02:00
Philipp Oppermann
67e780691c Clarifications for VGA text buffer format 2019-07-06 11:15:37 +02:00
Philipp Oppermann
85b83aed32 Merge pull request #634 from leocassarani/patch-1
Introduction to Paging: fix a couple of small typos
2019-07-04 22:51:28 +02:00
Leo Cassarani
41c9efd734 Introduction to Paging: fix typo (a -> an) 2019-07-04 21:38:07 +01:00
Leo Cassarani
7aec521fa8 Introduction to Paging: fix typo (sized -> size) 2019-07-04 21:35:43 +01:00
Donald Pinckney
a40b65a77d Fix small typo in heap allocation post (#628) 2019-06-27 09:55:21 +02:00
Philipp Oppermann
9c9ad4a172 Merge pull request #625 from phil-opp/heap-allocation
New post about heap allocation
2019-06-26 21:40:46 +02:00
Philipp Oppermann
fc2a0cd162 Resolve TODOs and update date 2019-06-26 21:11:59 +02:00
Philipp Oppermann
2209853abe Final edits 2019-06-26 21:11:26 +02:00
Philipp Oppermann
fc33c079a1 The heap size is 100 KiB (not 1 KiB) 2019-06-26 18:16:03 +02:00
Philipp Oppermann
3178be619e unsafe -> unstable 2019-06-26 18:14:33 +02:00
Philipp Oppermann
7abd49dc56 Add alt text to images 2019-06-26 18:05:28 +02:00
Philipp Oppermann
433cf1a974 Typo fixes 2019-06-26 18:00:41 +02:00
Philipp Oppermann
bb612298b9 Add an integration test 2019-06-26 17:55:53 +02:00
Philipp Oppermann
597bf6793d Write introduction 2019-06-26 17:55:53 +02:00
Philipp Oppermann
2acb3e1b65 Write remaining parts of post 2019-06-26 17:55:53 +02:00
Philipp Oppermann
55446928c2 Minor improvements 2019-06-26 13:18:57 +02:00
Philipp Oppermann
acada272c5 Add missing import 2019-06-26 13:15:10 +02:00
Philipp Oppermann
029d77ef21 Move Allocator Designs post into separate branch 2019-06-26 12:23:15 +02:00
Philipp Oppermann
5bc1e3cc72 Continue linked list allocator section 2019-06-25 19:26:49 +02:00
Philipp Oppermann
8acf687a97 Improve linked list allocator section 2019-06-25 19:25:59 +02:00
Philipp Oppermann
55b96f21b6 One _million_ boxes suffice 2019-06-25 19:25:08 +02:00
Philipp Oppermann
5f1d6aed2e Split off Allocator Designs section into its own post
The post is already long enough and this section is already large enough to fill its own post and far from finished.
2019-06-25 19:23:45 +02:00
Philipp Oppermann
0cb439b450 Begin implementation section of linked list allocator 2019-06-24 18:29:44 +02:00
Philipp Oppermann
925d228c7f Explain challanges of reusing freed memory 2019-06-24 16:34:18 +02:00
Philipp Oppermann
9842ede61c Minor improvements 2019-06-24 16:32:50 +02:00
Philipp Oppermann
2a0e5e4696 Fix wrong address in page table mapping example 2019-06-23 18:10:21 +02:00
Philipp Oppermann
a09357a484 Explain allocator design goals and user/kernel space differences 2019-06-21 13:04:05 +02:00
Philipp Oppermann
1022c3b6fa Remove BTreeMap from example code, list possible types instead 2019-06-21 12:43:00 +02:00
Philipp Oppermann
8282608d3a Make list elements paragraphs to increase spacing 2019-06-21 12:42:16 +02:00
Philipp Oppermann
2b78ad44be Revert "CSS: Improve formatting of list elements"
This reverts commit bfab946078.
2019-06-21 12:40:13 +02:00
Philipp Oppermann
2d16cce255 Add image alt text 2019-06-21 12:08:39 +02:00
Philipp Oppermann
518f5247c5 Write section about bump allocation 2019-06-20 16:28:00 +02:00
Philipp Oppermann
63b8b2c31d Minor improvements 2019-06-20 16:24:04 +02:00
Philipp Oppermann
bfab946078 CSS: Improve formatting of list elements 2019-06-19 16:45:01 +02:00
Philipp Oppermann
5d2f27f870 Create and map a heap memory region 2019-06-19 16:44:29 +02:00
Philipp Oppermann
79c827006d Remove duplicate word 2019-06-19 16:43:24 +02:00
Philipp Oppermann
5f4153c365 Fix markdown parsing problems 2019-06-19 15:38:05 +02:00
Philipp Oppermann
f6d2ac229f Add screenshot 2019-06-18 18:41:01 +02:00
Philipp Oppermann
572ff8fff6 Apply special formatting for code blocks in headings 2019-06-17 17:52:33 +02:00
Philipp Oppermann
3b86f8de2a Write section about allocator interface 2019-06-17 17:52:15 +02:00
Philipp Oppermann
684e21fcec Update VGA buffer post for commit fcd849f47
Commit fcd849f471
2019-06-17 17:30:09 +02:00
Philipp Oppermann
6e1e677316 Begin sections about allocator interface and dummy/bump allocator 2019-06-16 19:32:51 +02:00
Philipp Oppermann
608ec767f0 Typo fixes 2019-06-16 15:26:48 +02:00
Philipp Oppermann
4f6d62779d Heap Allocation is the 10th post now
(We combined the two testing posts into one.)
2019-06-16 15:18:09 +02:00
Philipp Oppermann
bdb87289d8 Minor improvements 2019-06-16 15:16:50 +02:00
Philipp Oppermann
6108c01fb5 Motivate dynamic memory and explain how it works in Rust 2019-06-15 13:56:14 +02:00
Philipp Oppermann
015ef5b960 Begin new Heap Allocation post 2019-06-15 13:56:14 +02:00
Philipp Oppermann
361ba0c32b Add a GitHub style repository card on index page (#620) 2019-06-15 12:30:11 +02:00
rybot666
00978bd6c9 Add Status Updates (#619)
Adds the status updates link to the extra content section of the blog
2019-06-15 11:15:37 +02:00
Philipp Oppermann
413ed1d914 Merge pull request #617 from phil-opp/typos
Use misspell tool to look for common typos
2019-06-03 18:23:47 +02:00
Philipp Oppermann
a61bcc62ed Run misspell on CI 2019-06-03 18:20:55 +02:00
Philipp Oppermann
bd6fbcb1c3 Use misspell to fix some typos 2019-06-03 18:02:20 +02:00
Philipp Oppermann
300510869b Merge pull request #616 from phil-opp/status-update
Updates in May 2019
2019-06-03 17:59:26 +02:00
Philipp Oppermann
ba0a610749 Fix typo: Mai -> May 2019-06-03 17:49:24 +02:00
Philipp Oppermann
0e185670ab Add may status update post 2019-06-03 17:41:15 +02:00
Philipp Oppermann
2adea53ae8 Use page.{earlier, later} in status update template 2019-06-03 17:37:51 +02:00
Philipp Oppermann
65e8b354d3 Typo fix 2019-05-26 16:00:44 +02:00
Philipp Oppermann
bd95ade626 Clarify that print_something needs to be called from _start 2019-05-26 15:58:08 +02:00
Philipp Oppermann
a8908acecc Fix typo: 1004 MiB -> 1004 KiB 2019-05-23 12:57:16 +02:00
Philipp Oppermann
99f8d2cfe7 Rewrite CompareMessage to check the whole string (#611)
Not just a single string component like before.
2019-05-23 12:40:14 +02:00
Philipp Oppermann
6db5ad78ab Add missing MemoryMap and MemoryRegionType imports 2019-05-13 12:30:22 +02:00
Joseph Richey
1ebe869e0e Always use spaces for code (if possible) (#609)
Almost all the code in the blog uses spaces instead of tabs.
This change fixes 3 places where there was inconsistancy.

This was causing some of the content to appear misaligned.

Now tabs are only used in:
  - Makefiles
  - Dockerfiles
  - Command output (from `objdump` and `diff`) containing tabs
  - `.fish` files
2019-05-12 14:39:31 +02:00
Philipp Oppermann
a770d09c0a Fix: Port needs to be mutable when reading from it
Required because of the update to x86_64 0.7.0 (#606).
2019-05-09 15:40:33 +02:00
Philipp Oppermann
f845b608c2 Update testing post to use -serial stdio instead of -serial mon:stdio (#605) 2019-05-09 15:01:09 +02:00
Philipp Oppermann
0632a0de80 Update posts for x86_64 version 0.7.0 (#607) 2019-05-09 15:00:49 +02:00
Philipp Oppermann
e2f0881701 Show only changes of last month in recent updates list 2019-05-06 11:40:56 +02:00
Philipp Oppermann
244d05ebff Merge pull request #600 from phil-opp/x86_64-0.6.0
Update to version 0.6.0 of x86_64
2019-05-03 19:36:23 +02:00
Philipp Oppermann
c1994c943f Show the 10 most recent changes (instead of 5) 2019-05-03 19:35:52 +02:00
Philipp Oppermann
4736ad27fd Update Paging Implementation for unsafe FrameAllocator trait 2019-05-03 19:32:48 +02:00
Philipp Oppermann
faf574621a Update to x86_64 0.6.0 2019-05-03 19:25:48 +02:00
Philipp Oppermann
af663942b6 Merge pull request #597 from phil-opp/news
Updates in April 2019
2019-05-01 19:41:05 +02:00
Philipp Oppermann
9fc786beca Add a Status Updates overview page 2019-05-01 19:31:32 +02:00
Philipp Oppermann
aac8e351f6 Add a status-update-page template 2019-05-01 19:23:38 +02:00
Philipp Oppermann
a9bdb5c56b Finish first status update post 2019-05-01 19:23:38 +02:00
Philipp Oppermann
d4ef8cb9ce Add draft for april status update post 2019-05-01 19:23:38 +02:00
Philipp Oppermann
4f557713ea Improve margins for news section 2019-04-30 14:50:17 +02:00
Philipp Oppermann
d10531f65d Use page_template for news section and sort it by date 2019-04-30 14:50:17 +02:00
Philipp Oppermann
eb76c67a44 Update Paging Implementation for new frame allocator implementation (#596) 2019-04-30 13:29:30 +02:00
Matej Stuchlik
11e1f0d787 Typo: iozize -> iosize (#594) 2019-04-29 14:40:08 +02:00
Philipp Oppermann
b8d3aa32e9 Testing: PANIC_INFO needs to be adjusted after adding attributes/imports 2019-04-28 13:44:42 +02:00
Philipp Oppermann
41c54f54da Update Zola to version 0.7.0 (#592) 2019-04-28 13:38:13 +02:00
Philipp Oppermann
1f9710308f Add missing core::fmt::{self, Write} imports in testing post 2019-04-28 12:59:27 +02:00
Sam Gluck
b7e98fa04a add missing "it" (#590) 2019-04-27 21:59:44 +02:00
bjorn3
7cbd985756 Update index.md (#588) 2019-04-27 19:28:20 +02:00
Philipp Oppermann
3bcb2eecd8 Merge pull request #584 from phil-opp/rewrite-test-post
New testing post
2019-04-27 14:24:51 +02:00
Philipp Oppermann
a8865e2277 Add deprecation notices to old testing posts and specify requirements 2019-04-27 13:40:15 +02:00
Philipp Oppermann
9995c69cc6 Mention deprecated Unit Testing and Integration Tests posts 2019-04-27 13:40:15 +02:00
Philipp Oppermann
e677e5d569 Set publish date 2019-04-27 13:40:15 +02:00
Philipp Oppermann
2286569694 Write summary section 2019-04-27 13:40:15 +02:00
Philipp Oppermann
c337840584 Typo fixes 2019-04-27 13:40:15 +02:00
Philipp Oppermann
3307cc6f66 Explain the timeout feature of bootimage 2019-04-27 13:40:15 +02:00
Philipp Oppermann
0509307d8f Mention test_main and blog_os::init in later posts 2019-04-27 13:40:15 +02:00
Philipp Oppermann
57a506e0fc Remove old cfg(not(test)) attributes from paging implementation post
The kernel_main function is now also the entry point in test mode.
2019-04-27 13:40:15 +02:00
Philipp Oppermann
2d61a463fc Use the entry point macro for lib.rs too 2019-04-27 13:40:15 +02:00
Philipp Oppermann
8d0293e647 Point x86_64 links to version 0.5.2 2019-04-27 13:40:15 +02:00
Philipp Oppermann
74783de318 Update to version 0.6.0 of bootloader 2019-04-27 13:40:15 +02:00
Philipp Oppermann
dce7adb210 Remove redundant import 2019-04-27 13:40:15 +02:00
Philipp Oppermann
8f14013e0a Hardware Interrupts: Use hlt_loop in lib.rs too 2019-04-27 13:40:15 +02:00
Philipp Oppermann
8db60d8e79 Hardware Interrupts: Fix a race condition in the test_println_output test 2019-04-27 13:40:15 +02:00
Philipp Oppermann
34bce0513c Explain new stack_overflow test in post 2019-04-27 13:40:15 +02:00
Philipp Oppermann
cd6223c0ab Fix internal links 2019-04-27 13:40:15 +02:00
Philipp Oppermann
8735bbefd4 Update some of the following posts to use blog_os::init 2019-04-27 13:40:15 +02:00
Philipp Oppermann
fd8fb3e581 Remove some old cfg(not(test)) attributes 2019-04-27 13:40:15 +02:00
Philipp Oppermann
fad4618de3 Update post numbers in Readme 2019-04-27 13:40:15 +02:00
Philipp Oppermann
e8901719fa Update post numbers
Renames the directories, updates the weights, and the post branch links
2019-04-27 13:40:15 +02:00
Philipp Oppermann
992b958414 Remove section about fixing cargo test on windows
This no longer applies since cargo xtest no also compiles for the target system
2019-04-27 13:40:15 +02:00
Philipp Oppermann
c10d2ef753 Add TODO 2019-04-27 13:40:15 +02:00
Philipp Oppermann
bda362a666 Panic in Double Fault handler instead of looping endlessly
The advantage of panicking is that it causes a QEMU exit in integration tests.
2019-04-27 13:40:15 +02:00
Philipp Oppermann
701542b40f Move Testing post to bare bones category and update post numbers 2019-04-27 13:40:15 +02:00
Philipp Oppermann
9437656d5c Update I/O Port links in hardware interrupts post 2019-04-27 13:40:15 +02:00
Philipp Oppermann
97bd58720e Update Double Faults post for new test system 2019-04-27 13:40:15 +02:00
Philipp Oppermann
38b904c6fb Update CPU Exceptions post for new test system 2019-04-27 13:40:15 +02:00
Philipp Oppermann
6f4383d004 Write requirements section 2019-04-27 13:40:15 +02:00
Philipp Oppermann
077b583eff Delete content from old unit testing post 2019-04-27 13:40:15 +02:00
Philipp Oppermann
22261d8303 Write section about testing the panic handler 2019-04-27 13:40:15 +02:00
Philipp Oppermann
00b3ded7d6 Add missing imports 2019-04-27 13:40:15 +02:00
Philipp Oppermann
028d31cc5b Make exit_qemu safe 2019-04-27 13:40:15 +02:00
Philipp Oppermann
6257baaea5 Some improvements 2019-04-27 13:40:15 +02:00
Philipp Oppermann
10718f2996 Continue post 2019-04-27 13:40:15 +02:00
Philipp Oppermann
736160a910 Some improvements 2019-04-27 13:40:15 +02:00
Philipp Oppermann
ade3e36856 Continue post 2019-04-27 13:40:15 +02:00
Philipp Oppermann
441ef21937 Continue post 2019-04-27 13:40:15 +02:00
Philipp Oppermann
f0c5326b19 Rename section 2019-04-27 13:40:15 +02:00
Philipp Oppermann
66102b3aba Use version 0.2.0 of uart_16550 2019-04-27 13:40:15 +02:00
Philipp Oppermann
ae46a98cdb Add introduciotn for printing to the console section 2019-04-27 13:40:15 +02:00
Philipp Oppermann
79ce3bd883 Deprecate the old testing posts 2019-04-27 13:40:15 +02:00
Philipp Oppermann
005dd7d951 Begin new testing post 2019-04-27 13:40:15 +02:00
Philipp Oppermann
5808aafb49 Merge pull request #582 from phil-opp/bootimage-runner
Minimal Rust Kernel: Use a runner to make cargo xrun work
2019-04-27 13:39:37 +02:00
Philipp Oppermann
82c499a8b9 Update mentions of bootimage run in other posts 2019-04-26 12:08:41 +02:00
Philipp Oppermann
52cbb1e756 Set up a cargo runner to make cargo xrun work 2019-04-26 12:08:41 +02:00
Philipp Oppermann
22bc414972 Use cargo bootimage instead of bootimage run 2019-04-26 12:08:41 +02:00
Philipp Oppermann
2377c0a579 Restructure: Create a new Running our Kernel section 2019-04-26 12:08:41 +02:00
Philipp Oppermann
24e06d8978 Create a .cargo/config file that sets the default target
Instead of setting a bootimage default target.
2019-04-25 13:12:29 +02:00
Philipp Oppermann
3a3a76466c Use bootimage 0.7.3 2019-04-25 12:27:27 +02:00
bors[bot]
719a8ef964 Merge #580
580: Use requirements.txt for PyGitHub r=phil-opp a=phil-opp

This is mostly a test PR for testing the new deploy process.

Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
2019-04-24 16:48:42 +00:00
Philipp Oppermann
646faffb4e Use requirements.txt for PyGitHub 2019-04-24 18:48:14 +02:00
Philipp Oppermann
ffb17617a1 Merge pull request #579 from phil-opp/azure-artifacts
Migrate from Netlify to Github Pages
2019-04-24 18:04:33 +02:00
Philipp Oppermann
65f48be964 Delete netlify.toml file 2019-04-24 17:54:21 +02:00
Philipp Oppermann
e4eee8c37f Revert "Mention GitHub, Zola, and Netlify in the footer"
This reverts commit 1ff397f568.
2019-04-24 17:54:21 +02:00
Philipp Oppermann
c1d7a7933b Link to base_url instead of /second-edition 2019-04-24 17:54:21 +02:00
Philipp Oppermann
e2504b1366 Build all branches 2019-04-24 17:54:21 +02:00
Philipp Oppermann
b17c06b47d Require azure pipelines for bors 2019-04-24 17:54:21 +02:00
Philipp Oppermann
5daa7269d6 Use Zola's aliases feature instead of Netlify redirects
Makes the project less dependent on Netlify.
2019-04-24 17:54:21 +02:00
Philipp Oppermann
5995948310 Add a CNAME file for GitHub Pages 2019-04-24 17:54:21 +02:00
Philipp Oppermann
dcac2d118d Run Zola build on azure pipelines
Produce generated site as artifact.
2019-04-24 15:58:18 +02:00
Philipp Oppermann
a6b8252946 Revert "Use Zola's aliases feature instead of Netlify redirects"
This reverts commit fd2ac6ef18.
2019-04-24 15:57:06 +02:00
Philipp Oppermann
fd2ac6ef18 Use Zola's aliases feature instead of Netlify redirects
Makes the project less dependent on Netlify.
2019-04-24 12:07:00 +02:00
Philipp Oppermann
1ff397f568 Mention GitHub, Zola, and Netlify in the footer 2019-04-23 14:27:00 +02:00
Philipp Oppermann
8e6e5f7dcc Update copyright to 2019 2019-04-23 14:18:44 +02:00
Philipp Oppermann
f2335e8e72 Add a note that there must be no spaces in features string 2019-04-17 18:49:23 +02:00
Philipp Oppermann
ac16f2ed55 Link if let and shadowing chapters under keyboard code 2019-04-15 14:10:34 +02:00
Philipp Oppermann
0b9ca84735 Rewrite "A Freestanding Rust Binary" (#577)
- solve linker errors by compiling for thumbv7em-none-eabihf
- make old section about linker arguments optional content
- use different linker arguments on Windows and macOS to use the `_start` entry point on all OSs
- Add an (optional) section that explains how to set linker arguments in .cargo/config
- Add an (optional) section that discourages the linker arguments approach and recommends the `#[start]` attribute instead
- reorganize section levels
2019-04-11 15:28:51 +02:00
Philipp Oppermann
4c01a96eb1 Merge pull request #575 from phil-opp/update-bootloader-bootimage
Update to new bootloader 0.5.1 and bootimage 0.7.2
2019-04-06 17:53:18 +02:00
Philipp Oppermann
6015feb511 Update 'Paging Implementation' post for bootloader 0.5.1 2019-04-06 17:49:31 +02:00
Philipp Oppermann
b8667c45dd Update "Minimal Rust Kernel" to new bootloader 0.5.1 and bootimage 0.7.2 2019-04-06 16:46:10 +02:00
Philipp Oppermann
beb1306a1d Move warnings before toc to fix toc placement
The placement was off for pages with warnings.
2019-04-04 13:59:07 +02:00
Philipp Oppermann
042c934c6e Remove badges, mention Gitter in the text 2019-04-04 12:24:59 +02:00
Philipp Oppermann
6eb9c83345 Spell out post-* branch names in posts 2019-04-03 12:12:48 +02:00
Philipp Oppermann
bbe2fe000d Use <div> instead of <article> for post list
The <article> tag is for self-contained content, which the post list isn't really. I hope that this change makes search engines display the blog's introduction instead of the first post's introduction in their results.
2019-03-27 19:26:59 +01:00
Philipp Oppermann
84c539df67 Update Readme: Advanced Paging was replaced by Paging Implementation 2019-03-26 12:36:20 +01:00
Philipp Oppermann
8397cae2be Update to zola 0.6.0 2019-03-26 12:34:36 +01:00
Philipp Oppermann
11ae72b2e2 Use toc-aside id in first edition too so that CSS is applied again 2019-03-26 12:34:05 +01:00
Philipp Oppermann
6a07fea2d7 Fix ToC resizing
The `#toc` id was renamed to `#toc-aside`.
2019-03-20 23:37:56 +01:00
Philipp Oppermann
5cd435b755 Add a small margin after the ToC Heading 2019-03-19 13:24:59 +01:00
Philipp Oppermann
0605fc54df Move the ToC of Paging Implementation after the aside 2019-03-19 13:24:41 +01:00
Philipp Oppermann
48d96243ea Add an inline table of contents to all posts 2019-03-19 13:01:25 +01:00
Philipp Oppermann
6055a2e342 Add an inline table of contents for small screens
This ToC is only shown when the screen is too small for the sticky sidebar ToC.

We use a `<!-- toc -->` comment and the `replace` function to allow inserting the ToC at well defined points of the page. We don't use the shortcode feature of Zola because of https://github.com/getzola/zola/issues/584.
2019-03-19 12:58:15 +01:00
Philipp Oppermann
d0c0cd8ed7 Use non-breaking spaces for subtitle 2019-03-19 12:52:59 +01:00
Philipp Oppermann
fe19af668d Make table of contents sticky instead of fixed
Fixed looks a bit strange with the new `All Posts` link.
2019-03-19 12:52:31 +01:00
Philipp Oppermann
06ec0dbf25 Rename id of ToC aside from toc to toc-aside 2019-03-19 12:51:43 +01:00
Philipp Oppermann
06b334396a Provide an All Posts link on posts that points back to the index page 2019-03-18 10:27:54 +01:00
Philipp Oppermann
cc0f68448b Fix swapped changelog links 2019-03-15 10:46:30 +01:00
Philipp Oppermann
fc5fd7f86b Remove unneeded into_iter call in Paging Implementation post 2019-03-14 13:21:02 +01:00
Philipp Oppermann
82256aaa2f Use zola's page_template feature 2019-03-14 12:58:10 +01:00
Philipp Oppermann
c655a61290 Point bootloader doc links to version 0.4.0 2019-03-14 11:20:48 +01:00
Philipp Oppermann
7b88ebcaf6 Update bootloader dependency in post to 0.4.0 2019-03-14 11:20:36 +01:00
Philipp Oppermann
2e9e8d7f45 Merge pull request #567 from phil-opp/paging-implementation
New Post: "Paging Implementation"
2019-03-14 10:51:33 +01:00
Philipp Oppermann
b496f835dc Set publish date 2019-03-14 10:13:04 +01:00
Philipp Oppermann
5ce8eabffb Fix code link to current HEAD of post-10 branch
The code in the post-10 branch will be replaced with the code of the new "Paging Implementation" post.
2019-03-13 15:10:32 +01:00
Philipp Oppermann
c069cdde69 Minor improvements 2019-03-13 15:01:07 +01:00
Philipp Oppermann
c734bc472f Link to the page table flag list of the previous post 2019-03-13 15:01:07 +01:00
Philipp Oppermann
42d94c3d50 Fix missing imports in code examples 2019-03-13 15:01:07 +01:00
Philipp Oppermann
154f10c3a0 Add missing unsafe in code example 2019-03-13 15:01:07 +01:00
Philipp Oppermann
1041754c71 Provide more context in code example 2019-03-13 15:01:07 +01:00
Philipp Oppermann
b8a3bb44df Simplify the active_level_4_table function 2019-03-13 15:01:07 +01:00
Philipp Oppermann
23e70e0e9c Add a second temporary mapping to figure to make things clearer 2019-03-13 15:01:07 +01:00
Philipp Oppermann
f34725de85 Fix grammar 2019-03-13 15:01:07 +01:00
Philipp Oppermann
15668849d2 Minor fixes 2019-03-13 15:01:07 +01:00
Philipp Oppermann
8efa53761e Cleanup: remove replaced content from Advanced Paging post 2019-03-13 15:01:07 +01:00
Philipp Oppermann
a72810e1ab Rewrite and extend introduction 2019-03-13 15:01:07 +01:00
Philipp Oppermann
409527caca Deprecate the Advanced Paging post 2019-03-13 15:01:07 +01:00
Philipp Oppermann
bf66b29225 Update images 2019-03-13 15:01:07 +01:00
Philipp Oppermann
96f543b2d4 Finish implementation section 2019-03-13 15:01:07 +01:00
Philipp Oppermann
053b2d3c23 Complete section about translating addresses 2019-03-13 15:01:07 +01:00
Philipp Oppermann
d09dd7ff1f Begin implementation section 2019-03-13 15:01:07 +01:00
Philipp Oppermann
4197382855 Resolve some TODOs and other minor improvements 2019-03-13 15:01:07 +01:00
Philipp Oppermann
d0e995d221 Update the Accessing Page Tables section 2019-03-13 15:01:07 +01:00
Philipp Oppermann
cb6d46a582 Require x86_64 0.5.0 and bootloader 0.4.0 2019-03-13 15:01:07 +01:00
Philipp Oppermann
fee3e34378 Create Bootloader Support section 2019-03-13 15:01:07 +01:00
Philipp Oppermann
c3abefd745 Begin restructuring the post
- Add page table access code from previous post
- Make each page table access technique its own subsection
- Make details of recursive paging optional
  - Add short codesnippets how to implement recursive paging
- Add disadvantages of recursive paging
2019-03-13 15:01:07 +01:00
Philipp Oppermann
b19e350dc4 Create a copy of the advanced paging post 2019-03-13 15:01:07 +01:00
Philipp Oppermann
7e4c8285dd Move images 2019-03-13 15:01:07 +01:00
Philipp Oppermann
8d54b92ded Update paging introduction post to not use the recursive address
The upcoming breaking version of the bootloader will not create a recursive mapping unless requested through a cargo feature. So we move the last section to the next post where we introduce these cargo features.
2019-03-13 15:01:07 +01:00
Philipp Oppermann
aa0a876e19 Add styling for details elements 2019-03-13 15:00:28 +01:00
Philipp Oppermann
ddbe36c0dc Update x86_64 to version 0.5.2
This is required for the upcomping _Paging Implementation_ post.
2019-03-12 17:47:58 +01:00
Philipp Oppermann
0b6564895e Merge pull request #566 from phil-opp/x86_64-0.5.0
Update to version 0.5.0 of x86_64
2019-03-09 13:51:39 +01:00
Philipp Oppermann
9011a8a123 Use the new MapperAllSizes::translate_addr function in Post 10 2019-03-09 13:46:55 +01:00
Philipp Oppermann
4c68f8a541 The int3 function was moved into the interrupts submodule 2019-03-09 13:18:46 +01:00
Philipp Oppermann
8ea576263c Update x86_64 to version 0.5.0 2019-03-09 13:16:46 +01:00
Philipp Oppermann
d2852ce966 ExceptionStackFrame was renamed to InterruptStackFrame 2019-03-09 13:13:40 +01:00
Philipp Oppermann
b95ec88e4f Update x86_64 doc links to version 0.5.0 2019-03-09 13:13:40 +01:00
Antoine
c14d1db833 🎨 format hex numbers to improve readability (#565) 2019-03-08 15:48:50 +01:00
Antoine
3a3bb7fb38 ✏️ fix typos (#563)
`create_example_mapping` was written `create_mapping` in several lines
2019-03-08 13:50:58 +01:00
Sergey Elantsev
23e2136e47 fixed Keyboard::process_keyevent link (#564) 2019-03-08 13:49:49 +01:00
Sergey Elantsev
715318707e double-faults misspell fixed (#561) 2019-03-03 11:51:22 +01:00
Philipp Oppermann
4fc9f569e2 Add scripts for updating the post-XX branches 2019-02-25 18:59:11 +01:00
Philipp Oppermann
c1428d92d5 Remove old first-edition scripts 2019-02-25 18:58:49 +01:00
Philipp Oppermann
fb02b0c340 Update Hardware Interrupts post for #557 2019-02-25 18:17:42 +01:00
esplo
a7f9477e95 fix typo: 'can used' -> 'can be used' (#559) 2019-02-18 16:30:54 +01:00
chenli
58165264c6 Fix outdated links in CPU Exceptions (#555) 2019-02-12 09:16:47 +01:00
Philipp Oppermann
746591430f [Fix] Don't run azure pipelines for PRs to master
Apply the previous commit to the right file.
2019-02-12 08:22:15 +01:00
Philipp Oppermann
b0d0dcad2c Don't run azure pipelines for PRs to master 2019-02-12 08:19:55 +01:00
Philipp Oppermann
9e090175a5 Fix level 2 table entry in figure 2019-02-11 10:31:26 +01:00
Tair Sabirgaliev
345726265b fix the integration test link (#554) 2019-02-10 00:15:23 +01:00
Philipp Oppermann
2c53bb0eb8 Merge pull request #552 from phil-opp/delete-code-from-master
Delete code from master branch
2019-02-08 10:34:17 +01:00
Philipp Oppermann
51ef14c71a Update bors.toml 2019-02-08 10:19:13 +01:00
Philipp Oppermann
df4b29acaf Don't run CI on master branch 2019-02-08 10:19:13 +01:00
Philipp Oppermann
3b23155fa4 Readme: Use bold text instead of h3 headings 2019-02-08 10:19:13 +01:00
Philipp Oppermann
59b99fa6b0 Reword Readme 2019-02-08 10:19:13 +01:00
Philipp Oppermann
381627bbbb Delete code from master branch
The code for each post now lives in the `post-XX` branches where `XX` is the post number.
2019-02-08 10:19:13 +01:00
Philipp Oppermann
aa09d2f719 The first post is now buildable on stable Rust (#551) 2019-02-07 16:24:00 +01:00
Philipp Oppermann
1f27ca5352 Clarify why we disable SSE for our kernel 2019-02-07 12:05:55 +01:00
Philipp Oppermann
131be53b1a Add missing [panic] link 2019-02-05 22:17:57 +01:00
Philipp Oppermann
cdc9448e93 Update code to current post-10 branch 2019-02-05 15:24:56 +01:00
Philipp Oppermann
47092acf8c Use repr(transparent) for vga_buffer::{ColorCode, Buffer} 2019-02-05 10:53:55 +01:00
Philipp Oppermann
87d542f7a1 Update code to current post-10 branch 2019-02-05 10:47:51 +01:00
Philipp Oppermann
403e67a795 Mention Patreon second 2019-02-04 12:52:04 +01:00
Philipp Oppermann
c8ee869941 Mention donorbox before liberapay 2019-02-04 12:36:06 +01:00
Steve Hess
82f249ca6f fix broken links in VGA buffer post (#546) 2019-02-04 11:46:32 +01:00
azure-pipelines[bot]
426cd9b6a6 Set up CI with Azure Pipelines (#548) 2019-02-03 15:37:43 +01:00
Philipp Oppermann
6fe331397c Update translate_addr code example
This makes the function safe again because no level 4 address is passed in. It also avoids bit-shifts which only work if the recursive index is 0o777.
2019-02-03 14:34:36 +01:00
Philipp Oppermann
8306f3e2da Note in Advanced Paging post that x86_64>=0.4.0 is required 2019-02-03 13:37:57 +01:00
Aaron Hill
0c5e303175 Make translate_addr unsafe (#544)
This function casts a usize argument to a pointer, and dereferences it.
This is undefined behavior unless level_4_table_addr is the address of a
valid PageTable, so the function should be marked 'unsafe'
2019-02-01 12:39:14 +01:00
Philipp Oppermann
b9ff59fd75 Add a note about the rename of FrameAllocator::allocate_frame 2019-01-29 08:52:17 +01:00
Philipp Oppermann
8b279bf34b Fix memory addresses in code example 2019-01-29 08:41:03 +01:00
Philipp Oppermann
a238fe99a9 Fix source code link for "Advanced Paging" post 2019-01-28 14:02:26 +01:00
Philipp Oppermann
2905fbe647 Merge pull request #539 from phil-opp/advanced-paging
New post: "Advanced Paging"
2019-01-28 13:16:36 +01:00
Philipp Oppermann
e349388372 Update code to current post-10 branch
Latest commit on post-10 branch: e5dfbd4b23
2019-01-28 12:01:11 +01:00
Philipp Oppermann
e5298ea8e6 Update CI scripts
- Build `post-*` branches
- Use `cargo install-latest` and `cargo cache`
- Always notify on failure
- Remove some comments
2019-01-28 11:57:46 +01:00
Philipp Oppermann
cc36ae536b Fix code snippets and improve their formatting 2019-01-28 11:31:45 +01:00
Philipp Oppermann
7744acd69c Link the post-10 branch in Readme 2019-01-28 11:16:44 +01:00
Philipp Oppermann
fa40f1a83f Resolve TODOs 2019-01-28 11:11:24 +01:00
Philipp Oppermann
196e5c4419 Spelling and grammar fixes 2019-01-28 11:11:24 +01:00
Philipp Oppermann
ffa25d1d9c Improve What's next? 2019-01-28 11:11:24 +01:00
Philipp Oppermann
ed649f0516 Improvements 2019-01-28 11:11:24 +01:00
Philipp Oppermann
df84c2b28d Link the post-10 branch 2019-01-28 11:11:24 +01:00
Philipp Oppermann
e8b5faf1d5 Add introduction 2019-01-28 11:11:24 +01:00
Philipp Oppermann
8c3b9e6508 Continue improving post 2019-01-28 11:11:24 +01:00
Philipp Oppermann
5e756c9fd3 Fixes, improvements, new content 2019-01-28 11:11:24 +01:00
Philipp Oppermann
a3e7ad1fa8 Fix typo in graphics and replace SVGs with PNGs
The SVG have rendering problems on some devices, e.g. when the text is zoomed.
2019-01-28 11:11:24 +01:00
Philipp Oppermann
bcc590e65f Create memory module in memory.rs instead of memory/mod.rs 2019-01-28 11:11:24 +01:00
Philipp Oppermann
7cb62ee7fe Make Recursive Page Tables a subsection 2019-01-28 11:11:24 +01:00
Philipp Oppermann
660528bb52 Minor rewordings 2019-01-28 11:11:24 +01:00
Philipp Oppermann
4cec9642ab Update from gutenberg to zola 2019-01-28 11:11:24 +01:00
Philipp Oppermann
257125b8c8 Various minor improvements to post 2019-01-28 11:11:24 +01:00
Philipp Oppermann
e46f8c5187 Introduce boot info later; continue post 2019-01-28 11:11:24 +01:00
Philipp Oppermann
41b21914be The page fault section was moved to the paging-introduction post 2019-01-28 11:11:24 +01:00
Philipp Oppermann
1ff102dc27 Continue post 2019-01-28 11:11:24 +01:00
Philipp Oppermann
47915fd4a0 Trim trailing whitespace 2019-01-28 11:11:24 +01:00
Philipp Oppermann
6d5ebf56a4 Revise post and add new introduction 2019-01-28 11:11:24 +01:00
Philipp Oppermann
c285ac7c4f Add post to Readme 2019-01-28 11:11:24 +01:00
Philipp Oppermann
7bb7efc705 Rename second paging post to 'Advanced Paging' 2019-01-28 11:11:06 +01:00
Philipp Oppermann
b570cad138 The first paging post was renamed 2019-01-28 11:11:06 +01:00
Philipp Oppermann
abd5082c56 Add second paging post to index page 2019-01-28 11:11:06 +01:00
Philipp Oppermann
d87c41fa6c Continue second paging post 2019-01-28 11:11:06 +01:00
Philipp Oppermann
2ad8de51de Begin second paging post 2019-01-28 11:11:06 +01:00
Philipp Oppermann
14f7e910cb Add comments label for comment issues 2019-01-28 10:51:17 +01:00
Philipp Oppermann
55d86b8d42 Spelling: Github -> GitHub 2019-01-27 18:00:08 +01:00
Philipp Oppermann
1034c884ac Add source code link to each post 2019-01-27 17:58:30 +01:00
Philipp Oppermann
04d3c134e2 Link post branches in Readme 2019-01-27 17:17:34 +01:00
Philipp Oppermann
2cbe44ecef Update to x86_64 0.4.0 2019-01-27 14:11:16 +01:00
Philipp Oppermann
dc86c88be5 Insert the testing code at the end of _start instead of at the beginning 2019-01-26 12:56:30 +01:00
Philipp Oppermann
bc2b3891d6 Rename code release tags for first edition 2019-01-26 12:39:59 +01:00
Philipp Oppermann
9cd801fd1f Fix old 2015 edition import path 2019-01-25 14:19:20 +01:00
Philipp Oppermann
c677103c5e Add another missing import in code example 2019-01-25 14:11:45 +01:00
Philipp Oppermann
d84127a7a8 Add missing import in code example 2019-01-25 14:08:44 +01:00
Philipp Oppermann
db2290e47a Fix import path in code example 2019-01-25 14:00:44 +01:00
Philipp Oppermann
441d2df46f Only allow(unused_imports) 2019-01-25 13:43:12 +01:00
Philipp Oppermann
0e4c13937b Use #![cfg_attr(not(test), no_std)] instead of #![no_std] 2019-01-25 13:41:07 +01:00
Philipp Oppermann
1d0bdad7d0 Remove wrong serial_println import 2019-01-25 13:36:04 +01:00
Philipp Oppermann
c0e0136349 Break long line in code example 2019-01-25 13:35:46 +01:00
Justin
90ac6bf3b4 Update links to point to current version of the rust book (#536) 2019-01-23 10:18:18 +01:00
Philipp Oppermann
d83acc0fc8 Merge pull request #534 from phil-opp/zola
Update from Gutenberg 0.3.3 to Zola 0.5.1
2019-01-22 18:48:15 +01:00
Philipp Oppermann
53e0749906 Fix post ordering
`reverse` is no longer needed with `weight`
2019-01-22 16:59:00 +01:00
Philipp Oppermann
ccc36b7d45 Replace 404.md with a 404.html template 2019-01-22 16:58:55 +01:00
Philipp Oppermann
a62ee6f35e Update netlify configuration 2019-01-22 16:58:55 +01:00
Philipp Oppermann
a6eb3f25ac The subsections field is now an iterator of paths 2019-01-22 15:52:22 +01:00
Philipp Oppermann
b96f73278d Gutenberg was renamed to Zola 2019-01-22 15:52:22 +01:00
Philipp Oppermann
ea7f4d74f6 Sort by order has been removed 2019-01-22 15:47:57 +01:00
sergio valverde
40806ceda0 Fix old links in freestanding Rust bin post. (#531) 2019-01-22 09:31:24 +01:00
Philipp Oppermann
b4238e93af Reduce cache size on travis (#532)
The Windows build fails often because it takes too long to store the build cache (timeout). This commit uses `cargo cache` to clean up the /home/philipp/.cargo directory before caching. It also removes caching of the `target` directory since it needs to be recompiled for each new nightly anyway.
2019-01-21 23:30:02 +01:00
bors[bot]
19b7fbc350 Merge #530
530: fix unreachable link r=phil-opp a=zyctree

seems rustc-guide already move to https://rust-lang.github.io/rustc-guide/

Co-authored-by: Pen Tree <appletree2479@outlook.com>
2019-01-21 13:31:37 +00:00
Pen Tree
ef2bf0ca0f fix unreachable link
seems rustc-guide already move to https://rust-lang.github.io/rustc-guide/
2019-01-21 21:12:59 +08:00
bors[bot]
cdbcb6b981 Merge #526 #529
526: Rewrite breakpoint test r=phil-opp a=phil-opp

The current test only tests the x86_64 crate, not any property of our kernel. This was reported in https://github.com/phil-opp/blog_os/issues/450#issuecomment-455771614.

529: Fixing typos in paging introduction r=phil-opp a=kolemannix

Love this series and thought I'd contribute in whatever way I could. Thanks for the great work.

Looking forward to the next post!

Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
Co-authored-by: Koleman Nix <kolemannix@gmail.com>
2019-01-21 08:08:34 +00:00
Koleman Nix
09789b5327 Fixing typos in paging introduction 2019-01-20 17:28:49 -05:00
Philipp Oppermann
9673c9dc2c Rewrite breakpoint test 2019-01-20 23:00:59 +01:00
Dato Simó
aa72396013 Add closing quote, missing in print! invocation. (#527) 2019-01-20 19:49:24 +01:00
Philipp Oppermann
ed3c4cced9 Revert caching changes as they lead to permission problems on Windows
This reverts commit 450099c13a.
2019-01-20 19:36:39 +01:00
Philipp Oppermann
450099c13a Only cache .cargo/bin to speed up CI
The target folder needs to be recompiled anyway with each new nightly.
2019-01-20 19:05:28 +01:00
Philipp Oppermann
2e16cc492a Add missing import in code example
Reported in https://github.com/phil-opp/blog_os/issues/480#issuecomment-455777535
2019-01-20 17:33:22 +01:00
Philipp Oppermann
f03463bd85 Rust 2018 allows foo.rs with foo/*.rs submodules
Fixes #525
2019-01-20 17:29:52 +01:00
bors[bot]
205cbce425 Merge #524
524: Mention `cargo test --lib` r=phil-opp a=phil-opp

Fixes #523 

Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
2019-01-18 10:56:15 +00:00
Philipp Oppermann
a147009dcd Mention cargo test --lib 2019-01-18 11:34:41 +01:00
Philipp Oppermann
7e5757e317 Fix link to AMD64 manual 2019-01-15 12:41:54 +01:00
Maximilian Goisser
0dd17a2603 Add missing "to" (#521) 2019-01-15 11:15:52 +01:00
Philipp Oppermann
f423c068fe Fix graphic: 24KiB -> 32KiB
Reported in https://news.ycombinator.com/item?id=18904875.
2019-01-14 21:40:39 +01:00
Matthew Klein
f28bed6436 Typo: vrtual -> virtual (#518)
Changed in blog post "Paging Introduction".
2019-01-14 16:35:19 +01:00
Philipp Oppermann
c478c7a90e Fix patreon link 2019-01-14 16:09:16 +01:00
Philipp Oppermann
6bf0bbfdfd Replace buttondown newsletter with tinyletter 2019-01-14 15:54:06 +01:00
Philipp Oppermann
d9f0baa987 Merge pull request #517 from phil-opp/paging-introduction
New Post: "Introduction to Paging"
2019-01-14 15:19:22 +01:00
Philipp Oppermann
9037941ddc Use PNG instead of SVG for address image
The SVG renders incorrectly in Chrome. See https://github.com/phil-opp/blog_os/pull/517#discussion_r247489190 .
2019-01-14 14:28:47 +01:00
Philipp Oppermann
bb7b599151 Set post date 2019-01-14 14:02:50 +01:00
Philipp Oppermann
4e54bb9841 Run rustfmt 2019-01-14 14:00:54 +01:00
Philipp Oppermann
dec8ec8a60 Final edits 2019-01-14 14:00:34 +01:00
Philipp Oppermann
8d6eab6b33 Add code for post 2019-01-13 16:26:56 +01:00
Philipp Oppermann
c1009715de Update x86_64 to version 0.3.5 2019-01-13 16:26:56 +01:00
Philipp Oppermann
62f7cfb82b Remove unused images 2019-01-13 16:26:56 +01:00
Philipp Oppermann
b35fa0adc7 Typo fixes 2019-01-13 16:26:56 +01:00
Philipp Oppermann
e8c7ec339e Don't mention APIC in 'What's next?' section of double faults post 2019-01-13 16:26:56 +01:00
Philipp Oppermann
2f1616fa40 Add section about provoking page faults 2019-01-13 16:26:56 +01:00
Philipp Oppermann
c4e3f86ebf Finish first draft of paging post and rename it 2019-01-10 13:09:01 +01:00
Philipp Oppermann
0c21ed01c2 Make graphic smaller 2019-01-10 13:09:01 +01:00
Philipp Oppermann
d158d39e1f Add margin after nested list if it's followed by a paragraph 2019-01-10 13:09:01 +01:00
Philipp Oppermann
aa55d2639a Fix alt text for image 2019-01-10 13:09:01 +01:00
Philipp Oppermann
7fbbaa6d60 Typo fixes 2019-01-10 13:09:01 +01:00
Philipp Oppermann
c47fff7bf5 Update Readme with new Paging post 2019-01-10 13:09:01 +01:00
Philipp Oppermann
b4d53f3aed Adjust section colors 2019-01-10 13:02:30 +01:00
Philipp Oppermann
cdd0328f03 Add paging post to index page 2019-01-10 13:02:30 +01:00
Philipp Oppermann
60e84bd659 Rewrite summary and what's next? section of previous post 2019-01-10 13:02:30 +01:00
Philipp Oppermann
164ae2ba32 Finish first draft of post 2019-01-10 13:02:30 +01:00
Philipp Oppermann
383ff21823 Begin new post about paging 2019-01-10 13:02:30 +01:00
Philipp Oppermann
78a936d21f Update cargo-xbuild output 2019-01-08 12:37:12 +01:00
Philipp Oppermann
c7c7a04e89 Bump bootloader version to 0.3.12 2019-01-08 12:36:28 +01:00
Philipp Oppermann
e9e4984643 Mention LLVM bug that leads to wrong error code
See https://github.com/phil-opp/blog_os/issues/513
2019-01-05 14:35:48 +01:00
Philipp Oppermann
ec377baa37 Link patreon 2019-01-05 14:35:48 +01:00
Philipp Oppermann
5a90015dc7 Clarify OS-specific entry points (#516)
Closes #515 
Closes #514
2019-01-03 17:27:21 +01:00
Philipp Oppermann
0554c5c5fb Link to LLVM docs for the data-layout field 2019-01-02 20:45:07 +01:00
OddCoincidence
37293b3f1b Grammar: trying to execut{ing => e} (#510) 2018-12-29 09:19:37 +01:00
Philipp Oppermann
651d4799d8 Remove piwik tracking script 2018-12-19 21:30:00 +01:00
Philipp Oppermann
2cec6ecbc0 Add Hardware Interrupts post to Readme 2018-12-13 18:08:46 +01:00
Philipp Oppermann
42f1ef0d6b Add Support Me section at the end of each post 2018-12-13 18:00:27 +01:00
Philipp Oppermann
ed062f2c64 Fix macro syntax 2018-12-10 11:09:07 +01:00
Philipp Oppermann
5aaee100c8 Archive comments of first edition (#504) 2018-12-09 17:31:37 +01:00
Philipp Oppermann
517e39f34a Update fathom tracking code 2018-12-09 13:00:22 +01:00
Philipp Oppermann
4a257c6bad Don't import println in main.rs 2018-12-09 12:24:30 +01:00
Philipp Oppermann
4fd5545e2d Add liberapay and donorbox links 2018-11-27 13:22:12 +01:00
Philipp Oppermann
08a40e10e7 Merge pull request #503 from phil-opp/travis_update
Update qemu installation in travis script
2018-11-25 13:51:11 +01:00
Philipp Oppermann
af61d11cc1 Install qemu on Windows through choco 2018-11-25 12:58:50 +01:00
Philipp Oppermann
c9aa0684bf Use travis homebrew addon for installing qemu 2018-11-25 12:58:34 +01:00
Toothbrush
eda4c08fc0 Bootloader is prepended, not appended(#502) 2018-11-24 10:58:34 +01:00
bors[bot]
3aa39bcd9a Merge #501
501: Update to the 2018 edition of Rust r=phil-opp a=phil-opp

This updates the blog to use the upcoming [2018 edition](https://rust-lang-nursery.github.io/edition-guide/rust-2018/index.html) of Rust, which is currently in beta and already the default on nightly. It changes a few local import paths (now with a `crate::` prefix) and removes all `extern crate` definitions and `macro_use` attributes.

This PR changes a lot of code across all posts, so there might be some things in the posts that I forgot to update. Please let me know if you see anything! [Preview of the changes](https://rust-2018--blog-os.netlify.com/)

Fixes #499 
Fixes #500

Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
2018-11-19 09:16:07 +00:00
Philipp Oppermann
ad7c11c0a3 Add #[doc(hidden)] to {vga_buffer, serial}::_print functions 2018-11-19 10:14:47 +01:00
Philipp Oppermann
dbfb732325 Fix remaining uses of {vga_buffer, serial}::print 2018-11-19 09:45:27 +01:00
Philipp Oppermann
8e292cc593 Fix typo: invokation -> invocation 2018-11-19 09:44:02 +01:00
Philipp Oppermann
0b5e89fbb7 Remove all the extern crate definitions 2018-11-18 15:30:19 +01:00
Philipp Oppermann
1d4cbdbe57 Update CPU exceptions post 2018-11-18 15:26:28 +01:00
Philipp Oppermann
f5aea8f015 Update testing posts 2018-11-18 15:26:21 +01:00
Philipp Oppermann
bf413d3baa Mention in the first post that our crate uses the 2018 edition 2018-11-18 15:01:55 +01:00
Philipp Oppermann
ba31b21661 Update the VGA buffer post to the new println macro and Rust 2018 2018-11-18 15:01:55 +01:00
Philipp Oppermann
767fd53d5f Remove macro_use and use explicit imports 2018-11-18 15:01:55 +01:00
Philipp Oppermann
24e7974d04 Update to a newer println definition 2018-11-18 14:30:40 +01:00
Philipp Oppermann
fc4542463b Rename vga_buffer::print function to avoid name clash with macro 2018-11-18 13:59:34 +01:00
Philipp Oppermann
6e5ebc4bd9 Transition the code to Rust 2018 2018-11-18 13:44:21 +01:00
bors[bot]
5091491a1f Merge #498
498: Use pc-keyboard crate for translating scancodes r=phil-opp a=phil-opp

This PR extends the "Hardware Interrupts" post to use the [`pc-keyboard`](https://docs.rs/pc-keyboard/0.3.1/pc_keyboard/index.html) crate for translating scancodes. This enables us to use all keys and not only 0-9 like before.

Thanks to @ZerothLaw for implementing scancode 1 support in `pc-keyboard` and of course @thejpster for writing the crate.

Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
2018-11-17 20:25:00 +00:00
Philipp Oppermann
231888eb4c Add gif of me typing Hello World 2018-11-17 21:22:44 +01:00
Philipp Oppermann
264a32f747 Update post to use pc-keyboard for scancode translation 2018-11-17 18:22:10 +01:00
Philipp Oppermann
6322bcce2a Use pc-keyboard crate for translating scancodes 2018-11-17 16:31:51 +01:00
Philipp Oppermann
0823c9f6c5 Use use imports for lazy_static in integration tests too 2018-11-13 11:42:15 +01:00
Philipp Oppermann
e7d4012653 Import lazy_static through normal use 2018-11-13 11:36:40 +01:00
Philipp Oppermann
21f3152dc0 Explictly mention in VGA buffer post in which file a code example belongs 2018-11-13 11:12:40 +01:00
Philipp Oppermann
298e71401b Update sections about panic_handler and eh_personality
The rust compiler no longer mentions the panic_impl language item.
2018-11-13 11:06:35 +01:00
Philipp Oppermann
d9f3b3d155 Remove wrong extern crate x86_64 from code example 2018-11-13 10:42:18 +01:00
Philipp Oppermann
f5b6b7a240 Typo: becaues -> because 2018-11-13 10:40:31 +01:00
Philipp Oppermann
a56112e789 The bootloader is now buildable on all platforms (#497)
It is now also linked with LLD, so it can be compiled out of the box on Linux, Windows, and macOS.
2018-11-09 08:56:19 +01:00
Noah Rinehart
b5b39d1b6e Fix minor url typo for System V ABI on cpu-exceptions page (#496) 2018-11-07 17:52:42 +01:00
Philipp Oppermann
442da8c9eb Remove wrong Option in code example 2018-11-05 13:34:04 +01:00
Will Gulian
24c6a85f18 Fix minor typo on cpu-exceptions page (#495) 2018-11-04 14:55:25 +01:00
Philipp Oppermann
68f8d238d8 Fix typo: 8259 APIC -> 8259 PIC 2018-10-31 12:42:33 +01:00
bors[bot]
ead49217c0 Merge #494
494: Fix typo in CPU exceptions post r=phil-opp a=jabedude

Fix a small typo in cpu-exceptions blog post.

Co-authored-by: Josh Abraham <sinisterpatrician@gmail.com>
2018-10-28 13:45:16 +00:00
Josh Abraham
8dbdefdfad Fix typo in CPU exceptions post
Fix a small typo in cpu-exceptions blog post.
2018-10-28 09:36:45 -04:00
Philipp Oppermann
7f36c84c0f Don't build non-master branches 2018-10-28 14:11:32 +01:00
bors[bot]
c9f721d4c9 Merge #493
493: Use a nightly Rust version from the beginning r=phil-opp a=phil-opp



Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
2018-10-28 12:06:09 +00:00
Philipp Oppermann
768f81aedc Use a nightly Rust version from the beginning 2018-10-28 13:04:35 +01:00
Philipp Oppermann
070e81964e Use cargo-update-installed instead of cargo-update (#491) 2018-10-27 16:37:42 +02:00
bors[bot]
92c27c6545 Merge #490
490: Don't compile the interrupts module on Windows to fix cargo test r=phil-opp a=phil-opp



Co-authored-by: Philipp Oppermann <dev@phil-opp.com>
2018-10-26 15:37:28 +00:00
Philipp Oppermann
b8206b895f Move PICS import into _start function 2018-10-26 17:07:47 +02:00
Philipp Oppermann
d802763867 Appveyor: Only run cargo test on x86_64
Many parts of the `x86_64` library are not available on 32-bit x86 and
we currently don't do much target dependent conditional compilation in
blog_os since we only support a single architecture at the moment.
2018-10-26 17:07:47 +02:00
Philipp Oppermann
b1c8df2a7f Don't compile the interrupts module on Windows to fix cargo test 2018-10-26 16:08:51 +02:00
Philipp Oppermann
1b52ff1acf Fix: standard library -> core library 2018-10-26 12:30:20 +02:00
Donald Pinckney
250a80dd77 Fix typo in hardware interrupts post (#489) 2018-10-25 17:10:12 +02:00
Donald Pinckney
d6c812ea28 Correct the filenames in comments for where _start() is. (#488) 2018-10-25 14:29:22 +02:00
Donald Pinckney
1ed19359b5 Fix typos in 06 and 07 posts. (#487) 2018-10-25 14:27:37 +02:00
Philipp Oppermann
7df441c014 Merge pull request #486 from phil-opp/building-on-android
Add extra post about building on Android
2018-10-24 15:42:46 +02:00
Philipp Oppermann
8330447463 Link extra content from the front page 2018-10-24 15:40:40 +02:00
Philipp Oppermann
ca9279e3f9 Add extra post about building on Android 2018-10-24 15:35:46 +02:00
Philipp Oppermann
bf59190406 Remove the second-edition warning from extra content 2018-10-24 15:35:15 +02:00
Philipp Oppermann
cefb137e1e The RSS feed now includes the full post content 2018-10-24 12:14:41 +02:00
Philipp Oppermann
4d85bde8d5 Provide alternative methods to subscribe: RSS + GitHub issue 2018-10-24 12:14:07 +02:00
Donald Pinckney
f6196a73be Bump spin version as 0.4.6 can't build on nightly (#485) 2018-10-24 09:31:42 +02:00
Steve Kemp
005551efc8 Fix typo (#484)
Fixed `interrups` -> `interrupts`.
2018-10-22 20:41:57 +02:00
Evan Martin
6465d6e68e fix typo (#483) 2018-10-22 19:55:40 +02:00
Connor E
cd44531822 Use shorthand struct initialization syntax (#482) 2018-10-22 19:49:24 +02:00
Philipp Oppermann
0aa59f3ab8 Fix typo
Fixes #481
2018-10-22 19:30:35 +02:00
Philipp Oppermann
9eef331df6 Bootimage file is named bootimage-blog_os.bin 2018-10-22 19:22:08 +02:00
Philipp Oppermann
e34804d23b Fix release date 2018-10-22 14:12:08 +02:00
Philipp Oppermann
dd2262fc88 Merge pull request #478 from phil-opp/hardware-interrupts
New post about hardware interrupts
2018-10-22 14:11:02 +02:00
Philipp Oppermann
75a7359ba5 Update to latest x86_64 crate 2018-10-20 19:29:44 +02:00
Philipp Oppermann
fb489a30ee Move hlt_loop import into function 2018-10-20 19:04:09 +02:00
Philipp Oppermann
678ea47cbe Merge branch 'master' into hardware-interrupts 2018-10-20 19:00:37 +02:00
Philipp Oppermann
b40e5bd7b2 Group imports 2018-10-20 18:57:17 +02:00
Philipp Oppermann
5035872ab6 Run rustfmt 2018-10-20 18:57:17 +02:00
Philipp Oppermann
4583936f0b Remove some temporary variables 2018-10-20 18:57:17 +02:00
Philipp Oppermann
16a727b3cc Set release date 2018-10-20 18:57:17 +02:00
Philipp Oppermann
66d940559f Avoid deadlocks in println/serial_println 2018-10-20 18:57:17 +02:00
acheronfail
68ffc3cd59 refactor interrupts (#476) 2018-10-20 18:57:17 +02:00
Philipp Oppermann
ac9582bd8b Minor improvements 2018-10-20 18:57:17 +02:00
acheronfail
5243ef874d add gifs for keyboard and fix source to compile 2018-10-20 18:55:04 +02:00
acheronfail
5b308be891 add screenshots and gif of hardware timer 2018-10-20 18:55:04 +02:00
acheronfail
7ad0ed9254 update source to match draft 2018-10-20 18:55:04 +02:00
Philipp Oppermann
7b95ded577 Merge pull request #477 from phil-opp/travis_windows
Enable Windows testing under travis
2018-10-20 18:34:27 +02:00
Philipp Oppermann
00d869952d Only use travis for bors 2018-10-20 18:33:41 +02:00
Philipp Oppermann
15c3925b1e Enable Windows testing under travis 2018-10-20 18:33:41 +02:00
Philipp Oppermann
a1dd6b2484 Merge pull request #475 from acheronfail/refactor-interrupts
Refactor exception code into new `interrupts` module
2018-10-18 14:20:59 +02:00
acheronfail
48f9e9c3f0 Merge pull request #3 from phil-opp/refactor-interrupts
Clarify that the exceptions tests use their own IDT
2018-10-18 22:59:46 +11:00
acheronfail
4f2bb34218 Merge branch 'refactor-interrupts' into refactor-interrupts 2018-10-18 22:58:42 +11:00
acheronfail
a80ae0d06a feedback: fix some typos 2018-10-18 22:57:37 +11:00
Philipp Oppermann
da09ad3362 Clarify that the exceptions tests use their own IDT 2018-10-18 13:50:00 +02:00
acheronfail
168e2b3d89 feedback: add explanation for adding #[macro_use] before import 2018-10-18 18:46:36 +11:00
acheronfail
e3d742c928 remove unused crate from main.rs 2018-10-18 14:16:17 +11:00
acheronfail
61397dbb07 feedback: mention creating a new interrupts module 2018-10-18 08:59:30 +11:00
acheronfail
206fb7cc8a refactor exception code into interrupts.rs 2018-10-18 08:21:58 +11:00
acheronfail
a198de6d1f fix minor typo (#474) 2018-10-17 13:40:29 +02:00
Tshepang Lekhonkhobe
36d56438a2 freestanding-rust-binary: small improves (#471) 2018-10-14 16:19:25 +02:00
Tshepang Lekhonkhobe
b30c3f653e minimal-rust-kernel: typo (#472) 2018-10-14 16:18:55 +02:00
Philipp Oppermann
87f6e734a9 Finish first draft 2018-10-10 18:57:21 +02:00
Philipp Oppermann
a619b8908d Add aside styling 2018-10-10 18:56:40 +02:00
Philipp Oppermann
9effe2b27b Master/slave -> primary/seondary 2018-10-10 18:56:16 +02:00
Philipp Oppermann
fa426fc633 Minor improvements 2018-10-10 14:48:07 +02:00
Philipp Oppermann
4e82b63816 Add fathom tracking script 2018-10-09 15:40:28 +02:00
Philipp Oppermann
4538b2fb21 Add rel=canonical link to all pages 2018-10-09 13:07:13 +02:00
Philipp Oppermann
23e35b8d9b Fix typo in code example
Closes #470
2018-10-07 15:26:53 +02:00
Philipp Oppermann
6f48a17ba4 Pub and no_mangle are no longer required for panic_handler (#468) 2018-10-01 13:11:39 +02:00
Philipp Oppermann
2dd925d34d Don't mention the deprecated panic_implementation
It existed only for a very short time, so I think that not many people will remember this attribute.
2018-10-01 10:39:09 +02:00
Ben
2a9075d642 Rfc 2070 panic implementation deprecated (#467)
* Make changes to code examples.

* Explain that panic_implementation has been deprecated

* Update attributes in source code.
2018-10-01 10:38:48 +02:00
Philipp Oppermann
0bd4fcd99e Run cargo update 2018-08-14 13:24:56 +02:00
Kazushige Tominaga
91001d9158 Use write_string instead of write_str in example code (#462) 2018-08-14 12:57:18 +02:00
Philipp Oppermann
81d3001c07 Fix QEMU URLs in appveyor build 2018-08-13 17:09:27 +02:00
Philipp Oppermann
812c981f9b Self-host math picture 2018-08-13 17:09:27 +02:00
Kenta
06011a6317 typo fix (#463) 2018-08-13 13:02:00 +02:00
Philipp Oppermann
ee7f0cecf8 Continue post 2018-07-27 12:37:58 +02:00
Philipp Oppermann
2209b580b5 Begin new post about hardware interrupts 2018-07-26 22:45:21 +02:00
Philipp Oppermann
a2d99bb52e Improve introductions of various posts 2018-07-26 19:15:50 +02:00
Philipp Oppermann
f551116714 Typo: deadbeaf -> deadbeef 2018-07-23 11:07:49 +02:00
Philipp Oppermann
71e35cef4d Merge pull request #460 from phil-opp/bootimage-0.5.0
Update to bootimage 0.5.0
2018-07-20 11:31:06 +02:00
Philipp Oppermann
f2d2c476f3 The bootloader_precompiled crate should be in lib.rs 2018-07-20 10:50:11 +02:00
Philipp Oppermann
c198d86538 Update bootimage test output 2018-07-20 10:32:40 +02:00
Philipp Oppermann
6eabcf1704 Add bootloader_precompiled as a dependency 2018-07-20 10:30:11 +02:00
Philipp Oppermann
42bfe4b357 Update “Minimal Rust Kernel” to bootimage 0.5.0 2018-07-20 10:27:08 +02:00
Philipp Oppermann
d2973e27da Merge pull request #458 from phil-opp/idt_rename
Update to x86_64 version 0.2.8
2018-07-14 14:47:13 +02:00
Philipp Oppermann
934c7f3413 Link to Github instead of gists 2018-07-14 14:34:21 +02:00
Philipp Oppermann
0f07341dea Update to x86_64 0.2.8: The Idt type was renamed to InterruptDescriptorTable 2018-07-14 14:32:33 +02:00
Philipp Oppermann
3faa0cfcad Don't ignore Cargo.lock since this is not a library 2018-07-14 14:05:47 +02:00
Philipp Oppermann
841684593f Clarify that we create a kernel for x86 2018-07-09 12:33:55 +02:00
Philipp Oppermann
0b98799673 The bundled LLD linker was renamed to rust-lld (#457) 2018-07-09 12:16:59 +02:00
Donald Pinckney
b0d18c735b Very small pluralization grammar fix in post 01 (#454) 2018-07-08 19:12:01 +02:00
Michael Noronha
9f6966d7f2 Add missing semicolon in integration tests post (#455) 2018-07-08 19:09:59 +02:00
Philipp Oppermann
bb85705fe9 Merge pull request #448 from slin31/master
Fix: should be `main.rs` instead of `lib.rs`
2018-07-02 15:44:59 +02:00
Nils Siemons
b4dd2de117 Update abi_x86_interrupt error message 2018-07-02 14:26:00 +02:00
Nils Siemons
dbb8575692 Fix: should be main.rs instead of lib.rs
The feature flag for `abi_x86_interrupt` needs to be in `main.rs`
2018-07-02 13:58:06 +02:00
Philipp Oppermann
41bd05586e Update Readme for second edition 2018-07-01 19:38:01 +02:00
Erlend
3e570a8cfb Fix links that pointed to a redirection page (#447) 2018-07-01 18:58:00 +02:00
Philipp Oppermann
3365a4f9ff Remove unneeded const_fn feature 2018-07-01 18:26:48 +02:00
skierpage
795b84a447 explain choice of 0xf4 for I/O port (#446)
based on issue 443 comment 400625857
2018-06-28 09:05:10 +02:00
Philipp Oppermann
0af14e1d51 Clarify that the entry point should be named _start, even on Windows and macOS 2018-06-27 13:12:32 +02:00
Philipp Oppermann
e8b6801de1 Fix typo 2018-06-27 12:22:08 +02:00
Philipp Oppermann
22470e7c87 Fix: should be “integration test” instead of “unit test” 2018-06-27 12:22:00 +02:00
Philipp Oppermann
56c9b0e41a Use post url for finding utterances issue 2018-06-27 12:07:11 +02:00
Erlend
83873ab54b Fix confusing wording (#444) 2018-06-25 16:22:42 +02:00
Philipp Oppermann
0bc3ebe3a5 Explain unsafe uses in double faults post 2018-06-20 12:42:41 +02:00
Philipp Oppermann
275ba7509f Remove TODO introduced by rebasing
(this already exists)
2018-06-20 12:06:12 +02:00
Philipp Oppermann
799e96c317 Merge pull request #442 from phil-opp/double-faults
Port double faults post to second edition
2018-06-19 00:30:59 +02:00
Philipp Oppermann
6a3e391f17 Cache homebrew cache on travis 2018-06-19 00:08:05 +02:00
Philipp Oppermann
deaf48e319 Update x86_64 to version 0.2.6 2018-06-18 23:48:56 +02:00
Philipp Oppermann
22bf95ac19 Run rustfmt 2018-06-18 23:48:17 +02:00
Philipp Oppermann
0b6174ace6 Use same import structure as in post 2018-06-18 23:48:17 +02:00
Philipp Oppermann
1ed7a4ceb8 Add missing } in code example 2018-06-18 23:48:17 +02:00
Philipp Oppermann
233e32b570 Update “what's next” section of previous post 2018-06-18 21:30:47 +02:00
Philipp Oppermann
18fadda280 Update and extend post 2018-06-18 21:30:47 +02:00
Philipp Oppermann
99c0fa5ebf Redesign code 2018-06-18 21:30:47 +02:00
Philipp Oppermann
5499471279 Begin porting the double faults post 2018-06-18 21:30:47 +02:00
Philipp Oppermann
803eafe632 Only build master and bors branches on appveyor 2018-06-18 21:30:29 +02:00
Philipp Oppermann
521ff876b9 Merge pull request #441 from phil-opp/cpu-exceptions
Port post about cpu exceptions to second edition
2018-06-17 21:49:48 +02:00
Philipp Oppermann
97a87728f7 Port cpu exceptions post to second edition 2018-06-17 20:16:41 +02:00
Philipp Oppermann
c39835e61e Extend explanation of lazy_static 2018-06-17 20:08:06 +02:00
Philipp Oppermann
01ac5b5ea0 Merge pull request #439 from phil-opp/integration-tests
New post about integration testing
2018-06-15 10:30:24 +02:00
Philipp Oppermann
837d1502e9 Update post date 2018-06-15 09:47:01 +02:00
Philipp Oppermann
30493e763b Last minute improvements 2018-06-15 09:47:01 +02:00
Philipp Oppermann
faf8521e9d Install QEMU on travis and appveyor 2018-06-15 09:47:01 +02:00
Philipp Oppermann
e585d72216 Fix typo: _start_ -> _start 2018-06-15 09:47:01 +02:00
Philipp Oppermann
2ed8d94c67 Allow unused imports for cargo test 2018-06-15 09:47:01 +02:00
Philipp Oppermann
3372966664 Add missing core::panic::PanicInfo imports in code snippets (#440) 2018-06-14 08:24:37 +02:00
刘冲
34f5733114 remove redundant code in _start (#438)
"as *const u8" seems to be not needed
2018-06-13 11:48:11 +02:00
Philipp Oppermann
76ff956eb9 Add bootimage test to CI 2018-06-12 19:39:40 +02:00
Philipp Oppermann
6529cbc674 Run rustfmt 2018-06-12 19:26:17 +02:00
Philipp Oppermann
8b5be6ebc0 Implement code for integration test post 2018-06-12 19:25:53 +02:00
Philipp Oppermann
40eb19b613 Fix code snippets and resolve some todos 2018-06-12 19:23:12 +02:00
Philipp Oppermann
955fc795da Remove margin-bottom for nested lists 2018-06-12 17:44:46 +02:00
Philipp Oppermann
4fd26d7784 Finish post 2018-06-12 17:44:32 +02:00
Philipp Oppermann
85e199b27b Minor improvements 2018-06-12 17:43:45 +02:00
Philipp Oppermann
79211ac4a9 Update for new panic_implementation attribute 2018-06-12 17:43:45 +02:00
Philipp Oppermann
99c3d86fa5 Fix some printlns that should be print_serials 2018-06-12 15:36:21 +02:00
Philipp Oppermann
1f03081002 Rename all instances of hprint! to serial_print! 2018-06-12 15:33:29 +02:00
Philipp Oppermann
84001f848f Improve wording 2018-06-12 15:30:25 +02:00
Philipp Oppermann
66b49bcf31 Add section about port I/O 2018-06-12 15:18:41 +02:00
Philipp Oppermann
fb0dd53ba5 Write section about test organization 2018-06-10 13:30:33 +02:00
Philipp Oppermann
15c0e7551e Improve the serial section 2018-06-10 13:30:33 +02:00
Philipp Oppermann
38fe338029 Add a TODO about panic messages to vga buffer post 2018-06-10 13:30:33 +02:00
Philipp Oppermann
6b5076bbfe Update minimal kernel post to bootimage 0.4.0 2018-06-10 13:30:33 +02:00
Philipp Oppermann
a180d71e72 Remove VirtualBox instructions since they don't work currently
See https://github.com/phil-opp/blog_os/issues/403#issuecomment-375785477 and following comments
2018-06-10 13:30:33 +02:00
Philipp Oppermann
0c9d4386fb Write sections about the serial port and QEMU shutdown 2018-06-10 13:30:33 +02:00
Philipp Oppermann
591eb5411f Various minor improvements 2018-06-10 13:30:33 +02:00
Philipp Oppermann
5cffdc4d8c Move testing posts to their own section 2018-06-10 13:30:33 +02:00
Philipp Oppermann
e293fbdb07 Begin new post about integration testing 2018-06-10 13:30:33 +02:00
Philipp Oppermann
97ce17925e Make second edition the default (#437) 2018-06-10 13:29:57 +02:00
Philipp Oppermann
3e3778d982 Import PanicInfo only in non(test) environment 2018-06-05 11:11:25 +02:00
Philipp Oppermann
cc6396ec56 Run cargo test on CI 2018-06-05 11:06:38 +02:00
Philipp Oppermann
c33811ae3d Update unit testing post for new panic handler 2018-06-05 11:06:17 +02:00
Philipp Oppermann
ee07901388 Typo fixes 2018-06-04 14:05:34 +02:00
Philipp Oppermann
d9d836fe2c Print panic message to vga buffer 2018-06-04 13:48:39 +02:00
Philipp Oppermann
3f61050387 Define panic handler using new panic_implementation attribute (#435) 2018-06-04 13:19:44 +02:00
Philipp Oppermann
3b8f9c7d36 Add 2018 HTWG talk to talks page 2018-06-04 10:34:08 +02:00
ccesare
9b94bdffed Small typo in second edition VGA buffer chapter (#434) 2018-05-27 16:19:46 +02:00
Philipp Oppermann
c566ad8456 Merge pull request #432 from phil-opp/design
Design Improvements
2018-05-23 10:59:24 +02:00
Philipp Oppermann
40cfef3115 Update gutenberg to 0.3.3 2018-05-22 19:51:37 +02:00
Philipp Oppermann
a860ca76b5 Change syntax highlighting theme to visual-studio-dark 2018-05-22 19:45:01 +02:00
Philipp Oppermann
b613c8e0ff Delete unused syntax.css 2018-05-22 19:45:01 +02:00
Philipp Oppermann
3de9c85065 Use system font size; make site a bit wider 2018-05-22 19:45:01 +02:00
Philipp Oppermann
92f4969cd9 Use non-breaking space for “read more” 2018-05-22 19:45:01 +02:00
Philipp Oppermann
1b9ec290a7 Merge pull request #431 from phil-opp/no-more-rust-target-path
No more RUST_TARGET_PATH
2018-05-07 16:04:13 +02:00
Philipp Oppermann
ab8a224b06 Add a code block for the bootimage build command 2018-05-07 13:02:07 +02:00
Philipp Oppermann
65211f85a5 Use cargo-xbuild instead of xargo and pass paths to --target 2018-05-07 12:59:24 +02:00
Philipp Oppermann
cb1fa395b1 Fix syntax errors in first construct_buffer() version 2018-05-04 18:12:08 +02:00
Philipp Oppermann
ba266f31c5 ColorCode::new does not need to be a const fn 2018-05-01 17:28:16 +02:00
Philipp Oppermann
0aaeb52581 Use correct array-init version 2018-05-01 16:00:26 +02:00
Philipp Oppermann
1242eabb55 Merge pull request #428 from phil-opp/unit-tests
Create a new post about unit testing
2018-04-29 23:27:03 +02:00
Philipp Oppermann
94c3b63ff6 Update release date 2018-04-29 22:52:38 +02:00
Philipp Oppermann
547943bb94 Fix typos 2018-04-26 11:41:08 +02:00
Philipp Oppermann
c1961ec61c Depend on the master branch of array-init for now
Until a new crates.io version is released
2018-04-25 20:39:16 +02:00
Philipp Oppermann
b278b9ec76 Update “What's next?” section of vga buffer post 2018-04-25 20:39:16 +02:00
Philipp Oppermann
573e1ed40c Derive PartialEq/Eq for vga buffer types 2018-04-25 20:39:16 +02:00
Philipp Oppermann
44ffa1d046 Create new post about unit testing 2018-04-25 20:39:16 +02:00
Philipp Oppermann
d7efdf013a Mention bootimage run in the Minial Rust Kernel post 2018-04-13 18:57:18 +02:00
Philipp Oppermann
5f12cd8fea Use CONSOLE entry points consistently 2018-04-09 01:20:22 +02:00
Philipp Oppermann
2a00afaab5 Update to xargo 0.3.12 (#427) 2018-04-08 17:47:43 +02:00
Philipp Oppermann
7a1c38a4ad Fix 32bit GNU appveyor build too 2018-04-08 13:49:37 +02:00
Philipp Oppermann
8a5ad66616 Fix undefined references related to cargo install-update on appveyor 2018-04-08 11:54:59 +02:00
Philipp Oppermann
81ed946515 Don't cache .cargo/{config, env} since it's empty anyway 2018-04-08 11:52:53 +02:00
Philipp Oppermann
dcf8b7767c A dependency on compiler_builtins is now automatically injected (#426) 2018-04-08 11:51:16 +02:00
Philipp Oppermann
6d0f103c16 Handle non-printable characters in vga buffer module (#425) 2018-04-07 19:45:28 +02:00
Philipp Oppermann
21fb890328 Run rustfmt 2018-04-02 17:34:37 +02:00
Philipp Oppermann
5d0503e250 Use explicit extern "C" 2018-04-02 17:31:04 +02:00
Philipp Oppermann
549dfd362b Mark _start as extern; fix wrong entry point name 2018-04-02 17:24:00 +02:00
Philipp Oppermann
0bd0c70c8f Update for bootimage 0.2.0 (#424) 2018-03-31 23:09:21 +02:00
SomeAnotherDude
e1338bb53e Add an empty branch to println!() macro to be consistent with std (#423) 2018-03-31 10:44:59 +02:00
Philipp Oppermann
5f195a869c Mention that libssl-dev is required for building bootimage 2018-03-23 14:32:50 +01:00
Philipp Oppermann
9a108026e6 Add a netlify.toml file 2018-03-18 17:24:28 +01:00
Philipp Oppermann
05b68e21f4 Add and describe rust-toolchain file 2018-03-17 18:20:08 +01:00
Philipp Oppermann
6599a6935f Use CONSOLE subsystem entry points; update link 2018-03-14 18:22:13 +01:00
Philipp Oppermann
8d312293b1 Use $(shell pwd) instead of $(pwd) in Makefile 2018-03-14 17:01:20 +01:00
bors[bot]
ed06b77864 Merge #417
417: Separate Writer::write_string and fmt::Write::write_str methods r=phil-opp a=phil-opp

Avoids confusion by using different names for the two methods (and keeping them both) instead of naming both `write_str` as before.
2018-03-14 14:39:59 +00:00
Lin
8a83c611eb Added more specific instructions for nightly (#415) 2018-03-14 15:38:44 +01:00
Philipp Oppermann
78bd186003 Separate Writer::write_string and fmt::Write::write_str methods 2018-03-13 21:16:22 +01:00
Philipp Oppermann
7a14fe6a90 Retry the rustup download on appveyor if it fails 2018-03-13 20:39:19 +01:00
Philipp Oppermann
424e9c4aaa Bors: Remove netlify from required status set
Netlify does not push status information for commits, only for pull requests.
2018-03-13 16:41:59 +01:00
Philipp Oppermann
59f5e4fe17 Mention RUST_TARGET_PATH in Set Up Rust post (first edition) (#416) 2018-03-13 16:39:32 +01:00
Aaron Hill
af151a2d45 Fix 'pwd' command substitution (#413) 2018-03-13 16:00:34 +01:00
Philipp Oppermann
77522e79c6 Remove old uses of x86_64-unknown-blog_os target
Reported in #406.
2018-03-11 11:46:19 +01:00
Philipp Oppermann
ace131cd4e Fix #410 2018-03-11 11:36:53 +01:00
Paul
b7b8c5ff61 fix #411 (#412) 2018-03-11 11:08:14 +01:00
Brian Campbell
558e9237fd Remove extra "the" (#407)
There is an extra word in "the entry point is _the_ called `main`".

It's possible that "the entry point is _then_ called `main`" was intended,
but it works without the word just as well, so just remove it.
2018-03-10 16:39:33 +01:00
Redrield
f4acd176b8 Switch (possible) typo, arcane --> archaic (#402) 2018-03-10 01:10:42 +01:00
Philipp Oppermann
2c2bd0a973 Add link for VGA write details and two minor fixes
Addresses the review comments at https://github.com/phil-opp/blog_os/pull/394#pullrequestreview-102511735.
2018-03-10 00:43:26 +01:00
Philipp Oppermann
ffbf030a3d Fix typo: cargo -> xargo 2018-03-10 00:03:52 +01:00
Philipp Oppermann
f82e46ed1d Merge pull request #401 from phil-opp/pure-rust
Add a “Writing an OS in pure Rust” news post
2018-03-09 23:55:53 +01:00
Philipp Oppermann
b0a7795cf0 Create a “Writing an OS in pure Rust” news post 2018-03-09 23:50:27 +01:00
Philipp Oppermann
7d2b5b6c07 Add a “news” category 2018-03-09 23:50:27 +01:00
Philipp Oppermann
a02a6b0b92 Promote the second edition from the front page 2018-03-09 23:50:27 +01:00
Philipp Oppermann
4c6edec787 Merge pull request #400 from phil-opp/bundled-lld
Use bundled lld for linking (this time for real)
2018-03-09 23:49:42 +01:00
Philipp Oppermann
fcb074bbd8 Mention the minimum required xargo version 2018-03-09 23:26:43 +01:00
Steve Klabnik
e120e49efb adjust blog post to reflect json changes 2018-03-09 11:13:41 +01:00
Steve Klabnik
b106ed8fc0 re-organize order of target spec to match blog post 2018-03-09 11:13:41 +01:00
Philipp Oppermann
844f0f0051 Reapply usage of LLD shipped with Rust
This reverts commit f24ba8b799.
2018-03-09 11:13:41 +01:00
Josh Backstein
02941fe5d3 Add information on rust-toolchain file to set-up-rust (#399) 2018-03-08 06:12:28 +01:00
Philipp Oppermann
8bd66bf06f Add missing name mangling link 2018-03-07 11:49:24 +01:00
Philipp Oppermann
ae085404d3 Adjust copyright year 2018-03-07 11:25:48 +01:00
Philipp Oppermann
1c4e6ecac6 Add subscribe form to second edition index page 2018-03-07 11:25:39 +01:00
Philipp Oppermann
f24ba8b799 Revert "LLD is now shipped with Rust!" (#397) 2018-03-06 18:26:57 +01:00
Philipp Oppermann
c810448fc8 Merge pull request #395 from phil-opp/builtin-lld
LLD is now shipped with Rust!
2018-03-06 11:55:45 +01:00
Philipp Oppermann
db812fe7c8 Remove “Installing LLD” guide 2018-03-06 11:20:32 +01:00
Philipp Oppermann
d7e17b2f56 Set linker-flavor to ld.lld, leave linker at default 2018-03-06 11:20:32 +01:00
Philipp Oppermann
033144fd9c No need to install LLD on travis/appveyor anymore
Rust now ships a LLD binary.
2018-03-06 11:20:32 +01:00
Philipp Oppermann
4c909d5cfc Merge pull request #394 from phil-opp/vga-text-mode
Add post about VGA text mode
2018-03-05 21:06:24 +01:00
Philipp Oppermann
70889544d1 Add rlibc dependency in minimal rust kernel post 2018-03-04 23:32:57 +01:00
Philipp Oppermann
557b869aa4 Update the VGA buffer post for the second edition 2018-03-04 23:19:07 +01:00
Philipp Oppermann
2f30a0df56 Delete old heap allocator 2018-03-04 23:18:01 +01:00
Philipp Oppermann
fab439d6a3 Add the Printing to Screen post to the second edition 2018-03-04 23:18:01 +01:00
Philipp Oppermann
73663150f8 Make image alt texts grey and italic 2018-03-04 23:18:01 +01:00
Philipp Oppermann
21f409625b Add "read more" links on frontpage 2018-03-04 23:18:01 +01:00
Philipp Oppermann
fe472d3412 Adjust order number of first two posts 2018-02-26 19:02:31 +01:00
Philipp Oppermann
2671fac8c2 Rename first first-edition post to “Minimal Multiboot Kernel“ 2018-02-26 18:57:35 +01:00
Philipp Oppermann
c157c91075 Merge pull request #393 from phil-opp/improvements
Wording improvements; Explain the bootimage tool
2018-02-25 16:59:56 +01:00
Philipp Oppermann
9208ae18ce Explain shortly how the bootimage tool works 2018-02-25 16:00:14 +01:00
Philipp Oppermann
4281f0e261 Minor improvements 2018-02-25 15:59:43 +01:00
Philipp Oppermann
7d04bdea1b Reformulate the drawbacks of the multiboot standard 2018-02-25 15:05:09 +01:00
Philipp Oppermann
bd1cf20f05 Improve wording 2018-02-25 14:46:35 +01:00
Toothbrush
1cdc010446 Fix: Change "panic" to "panic-strategy" (#392) 2018-02-20 22:10:05 +01:00
Andre Richter
07553ed219 Nitpicks for second article (#390)
Some nitpick corrections.
2018-02-14 11:39:08 +01:00
Philipp Oppermann
3a8de6cdec Bors: Add netlify to required status set and delete merged branches 2018-02-12 12:59:57 +01:00
Philipp Oppermann
71778d7a42 Remove BootInfo parameter from second post code example
Fixes #388
2018-02-12 12:46:44 +01:00
Andre Richter
384f6c2420 Corrections from proof read (#389)
Some minor corrections while proof-reading.

Changed Max OS X to macOS, since it's the official Apple speak since 2016.
2018-02-12 12:37:26 +01:00
bors[bot]
65c63a77b2 Merge #387
387: Minor fixes for second edition r=phil-opp a=phil-opp
2018-02-10 18:22:17 +00:00
Philipp Oppermann
325f1f2756 Fix date of new post 2018-02-10 18:03:34 +01:00
Philipp Oppermann
8848f4c139 Git ignore bootimage.bin 2018-02-10 18:03:34 +01:00
bors[bot]
00b3adfe82 Merge #385
385: First bits of the second edition r=phil-opp a=phil-opp

This PR adds the first two posts for the second edition, “A Freestanding Rust Binary” and “A Minimal Rust Kernel”. The largest changes in comparison to the first edition are:

- Instead of GRUB, we use our own [bootloader](https://github.com/rust-osdev/bootloader) (written in Rust) and our [bootimage](https://github.com/rust-osdev/bootimage) tool. This removes the dependencies on GRUB and `nasm`. Note that both tools are still experimental and might contain bugs.
- Support for Windows and Mac: Without GRUB, there's nothing preventing us from building on Windows or Mac OS anymore! We added additional CI jobs at travis and appveyor to ensure that the project always builds on all three platforms. (At the moment, users still need to install LLD, but with the [LLVM 6 update of rustc](https://github.com/rust-lang/rust/pull/47828) we should have a builtin LLD soon.)
- No assembly in the main posts. Instead, we're creating a `no_std` _executable_ and relying on our custom bootloader to perform the initial page mapping and the switch to long mode.
- No linker script: Our bootloader loads the kernel in a clean address space, so we can just use the default executable layout and don't need a linker script. (This also means that users that want a higher half kernel just need to update the mapping in their linker script. However, I'm not sure if it's a good idea to add this to the blog. Maybe later, when we begin to run user programs.)

These changes only land in “beta mode” with this PR, which means that they're not linked from the front page yet. We will do that in a follow up PR.
2018-02-10 15:58:25 +00:00
Philipp Oppermann
b2285f762c Add a “first-edition” section
The first edition will live there after the second edition is published.
2018-02-10 16:52:29 +01:00
Philipp Oppermann
dc50747c78 Link to the github issue from the UEFI section 2018-02-10 16:49:09 +01:00
Philipp Oppermann
56be17ab80 Add paragraph about Multiboot 2018-02-10 16:49:09 +01:00
Philipp Oppermann
254d5476b1 Update Linux/Windows/Mac entry points 2018-02-10 16:48:48 +01:00
Philipp Oppermann
5e96335c23 Add instructions for running in QEMU, VirtualBox, and on real hardware 2018-02-10 16:48:30 +01:00
Philipp Oppermann
7be59b571d Use static and for loop for printing Hello World 2018-02-10 16:47:21 +01:00
Philipp Oppermann
cef44163bc Remove/resolve some todos 2018-02-10 16:47:21 +01:00
Philipp Oppermann
7d55dda917 Add extra posts about disabling red zone and SIMD and installing LLD 2018-02-10 16:47:02 +01:00
Philipp Oppermann
8a75c2828e More work on minimal kernel post 2018-02-10 16:46:54 +01:00
Philipp Oppermann
9bb456ed2f Add support for bors.ng 2018-02-10 16:45:53 +01:00
Philipp Oppermann
bff0c4401c Print “Hello” instead of “OK” 2018-02-10 16:43:17 +01:00
Philipp Oppermann
9fc0a07453 Fix offset typo 2018-02-10 16:43:17 +01:00
Philipp Oppermann
eb688962a1 Rewrite first post to work on Windows too 2018-02-10 16:43:17 +01:00
Philipp Oppermann
c266193a34 We do not need separate “Intoduction” and “Booting” posts 2018-02-10 16:43:17 +01:00
Philipp Oppermann
244dd16819 Add appveyor configuration
Don't cache ~/.cargo/git and ~/.cargo/registry, because appveyor has a hard cache limit of 1GB (per account!). So we want to cache as few as possible without giving up the speed gains.
2018-02-10 16:42:51 +01:00
Philipp Oppermann
7d7b94804b Rewrite .travis.yml for second edition 2018-02-10 16:42:51 +01:00
Philipp Oppermann
8f69dfa6a2 Use lld for linking 2018-02-10 16:42:51 +01:00
Philipp Oppermann
734310ff0d Allow executables for x86_64-blog_os target 2018-02-10 16:42:51 +01:00
Philipp Oppermann
5823bcb7ab Initial code for second edition 2018-02-10 16:42:51 +01:00
Philipp Oppermann
2629945c72 Delete code from first edition 2018-02-10 16:42:51 +01:00
Philipp Oppermann
f5797b7fd2 Begin post about creating a minimal Rust kernel 2018-02-10 16:42:51 +01:00
Philipp Oppermann
082c9f0f4f New favicon 2018-02-10 16:42:51 +01:00
Philipp Oppermann
7f3de8dcb4 Update to gutenberg 0.3.0 2018-02-10 16:42:51 +01:00
Philipp Oppermann
abc9f350d2 Use utterances for comments on second edition posts 2018-02-10 16:42:50 +01:00
Philipp Oppermann
d38e97ee0b Link to #id instead of permalink in TOC
This makes table of content links also work in deploy previews.
2018-02-10 16:42:50 +01:00
Philipp Oppermann
25441a8773 Use absolute paths instead of permalink
This makes links also work in deploy previews.
2018-02-10 16:42:50 +01:00
Philipp Oppermann
7a263355f3 Add custom templates for second edition posts 2018-02-10 16:42:50 +01:00
Philipp Oppermann
75b4e09c4e Make page title an h1 for semantics 2018-02-10 16:42:50 +01:00
Philipp Oppermann
9d32d49488 Begin new post about freestanding executables 2018-02-10 16:42:50 +01:00
Philipp Oppermann
3f4a4bf2e1 Create utterances.json 2018-01-19 14:49:04 +01:00
Philipp Oppermann
8ce22720c6 Try to fix travis build by also caching .xargo directory 2018-01-09 19:26:15 +01:00
bissonex
651a33a98d Fix eh_personality reference error (#383)
Fix issue with undefined reference to `rust_eh_personality' when compiling
2018-01-09 19:07:19 +01:00
Rob Gries
b188e8a617 Allow users to use latest nightly compiler without manually setting environment variable (#381)
* Workaround for latest rust compiler

* Remove unnecessary travis environment variable
2018-01-02 18:11:38 +01:00
Rob Gries
3523fdfbb5 Workaround for xargo issue (#380) 2017-12-27 12:48:02 +01:00
Rob Gries
f7868a1bd8 Use proper size for heap init (#376) 2017-12-15 10:06:57 +01:00
Rob Gries
5e937e6e20 Panic on alloc::oom instead of calling intrinsics::abort (#375) 2017-12-15 09:20:50 +01:00
Patrik
2e8da22b32 Docker: Add a Dockerfile and Makefile targets (#373)
* add docker build option

* add docker section in makefile

* add bash_aliases to get different prompt
2017-12-09 17:34:22 +01:00
Isaac Woods
cf2c5550aa Fix sign extension bug in next_table_address (#372)
Fixes #362

Fix an issue where the left shift of the old table address would overwrite the sign extension, making the address non-canonical and leading to #GPs. This calculates the correct sign extension for the new table address.
2017-12-05 20:22:29 +01:00
Philipp Oppermann
0a583ca73b Add fish script for helping with rebasing of post_* tags 2017-11-19 15:53:08 +01:00
Philipp Oppermann
5ad167c45d Merge pull request #367 from phil-opp/allocator-post-update
Update the “Kernel Heap” post to use new allocator API
2017-11-19 15:35:09 +01:00
Philipp Oppermann
e89e4f5277 Rewrite bump allocator and integrate it in main crate 2017-11-19 15:29:36 +01:00
Philipp Oppermann
8fb813a09d Rewrite “Kernel Heap” to use the new allocator API 2017-11-19 15:29:36 +01:00
Wesley Aptekar-Cassels
bed57b03ce Add missing semicolon in double-fault post (#366) 2017-11-18 09:22:57 +01:00
Will
3e7aea0d51 Fix eh_personality linker errors (#364) 2017-11-14 15:21:14 +01:00
johanmon
30fcae9dce A rewrite of the bump allocator to conform to the new API (#361) 2017-10-24 08:31:08 +02:00
Philipp Oppermann
f499b6378c Toc.js was removed 2017-10-10 09:39:14 +02:00
Philipp Oppermann
e23479bd9e Make “Recent Updates” a h2 instead of h1 2017-10-10 09:37:41 +02:00
Philipp Oppermann
087371d7b0 Fix html (incorrect </datetime>) 2017-10-10 09:35:41 +02:00
Philipp Oppermann
ff240ed264 Use absolute permalinks instead of relative paths for links
Fixes links in subfolders. See https://github.com/Keats/gutenberg/issues/128 for a detailed description of the problems with `page.path`.
2017-10-10 09:30:22 +02:00
Philipp Oppermann
7590050ffe Front matter: insert_anchor was renamed to insert_achor_links 2017-10-05 16:01:02 +02:00
Philipp Oppermann
3c6b0b89ac Front matter: url key was renamed to path 2017-10-05 15:52:40 +02:00
Philipp Oppermann
f1ffa242c2 Don't escape titles (e.g. they might contain <code>) 2017-10-05 15:49:10 +02:00
Philipp Oppermann
36eccdd102 Re-indent table of content code 2017-10-05 11:50:51 +02:00
Philipp Oppermann
1c9c20c810 Remove empty toc asides from posts 2017-10-05 11:50:32 +02:00
Philipp Oppermann
dae2edfbf5 Let gutenberg generate the table of contents
Remove the javascript toc code.
2017-10-05 11:37:23 +02:00
Philipp Oppermann
bba3c52ff3 Reverse posts array for increasing post numbers
This should make it much easier to add a new post at the end.
2017-10-05 11:25:10 +02:00
Philipp Oppermann
a85794df1b Get_url paths should start with ./ for internal links 2017-10-05 10:55:37 +02:00
Philipp Oppermann
df0a6fa3ab Argument of get_url was renamed to path 2017-10-05 10:17:13 +02:00
Philipp Oppermann
c5cde79130 Use get_section instead of deprecated `sections argument 2017-10-05 10:14:52 +02:00
Philipp Oppermann
b58ee1e52b Add new const_unique_new feature gate (#355) 2017-10-03 13:29:22 +02:00
Philipp Oppermann
82c4a6f0a0 Add new required target-c-int-width field to target json (#354) 2017-10-03 13:11:22 +02:00
Will
0175e83387 Update to use the new API for custom allocators (#348)
* Update to new allocator API

* Change linked_list_allocator dependency to link directly to git repository

* Add Cargo.lock to gitignore
2017-08-20 19:36:30 +07:00
Tim Crawford
2ebd4ed954 Use new Unique API (#346)
Change Unique to use `new_unchecked`. Fixes #345.
2017-08-05 12:47:15 +08:00
Tim Crawford
e54cfa4378 Update bitflags to 0.9.1 (#347)
Signed-off-by: Tim Crawford <crawfxrd@gmail.com>
2017-08-05 12:33:56 +08:00
Philipp Oppermann
7b04934cab Fix dead internal link 2017-07-05 23:44:44 +02:00
Philipp Oppermann
970aeb1e20 Merge pull request #340 from phil-opp/markdown-fixes
Fix markdown links
2017-06-25 21:16:15 +02:00
Philipp Oppermann
54ab56aec5 Move links down to avoid splitting list items 2017-06-25 21:12:49 +02:00
Philipp Oppermann
d5fe84e1c6 Fix broken link 2017-06-25 21:12:49 +02:00
Philipp Oppermann
bfe0d12a60 Markdown links require a blank line before them 2017-06-25 21:12:49 +02:00
skierpage
a06f074bc8 Minor error in 01-multiboot-kernel.md (#336)
Fixes #335
2017-06-25 13:38:15 +02:00
skierpage
1f0e1f0e21 Two minor English fixes (#338)
Garbled sentence, no word "everytime".
2017-06-25 13:32:55 +02:00
skierpage
ab8b40a9d1 Explain and motivate "ISO"
This change to 01-multiboot-kernel/index.md fixes issue #337
2017-06-25 13:28:32 +02:00
Philipp Oppermann
557c6a58ea Make subtitle non-wrapping 2017-06-20 20:28:00 +02:00
Philipp Oppermann
3263f412fd Remove unneeded installation of rustfmt on travis 2017-06-20 18:09:09 +02:00
Philipp Oppermann
559a90ad8b Format using rustfmt-nightly 2017-06-20 18:09:09 +02:00
Philipp Oppermann
ff8e8e0f8b The collections crate was merged into the alloc crate (#333) 2017-06-20 17:41:28 +02:00
Philipp Oppermann
7d584818ff Fix CI by avoiding duplicate rustup installation (#330)
Travis uses rustup by default now
2017-06-19 14:05:54 +02:00
Philipp Oppermann
31806c7e92 Add redirect from /handling-exceptions-with-naked-fns.html 2017-06-14 15:15:04 +02:00
Philipp Oppermann
ee6a4ecc53 Add missing redirect from /modifying-page-tables.html 2017-06-13 23:08:20 +02:00
Philipp Oppermann
b5a271191d Make table of content JS async 2017-06-13 22:10:44 +02:00
Philipp Oppermann
076b4e132f Use a cdn for piwik.js 2017-06-13 21:52:45 +02:00
Philipp Oppermann
4df59060fb Move favicon to /favicon.ico 2017-06-13 21:42:16 +02:00
Philipp Oppermann
0048d3bcd3 Use js/ instead of piwik.js/php for caching and compression 2017-06-13 21:33:23 +02:00
Philipp Oppermann
f807eaa95e Merge pull request #326 from phil-opp/gutenberg
Switch from hugo to gutenberg
2017-06-13 21:03:00 +02:00
Philipp Oppermann
ab0d27e398 Redirect from /atom.xml to /rss.xml 2017-06-13 20:35:03 +02:00
Philipp Oppermann
487e4c18fc Add isso comments 2017-06-13 20:34:15 +02:00
Philipp Oppermann
1794a94fa9 Introduce an (arbitrary) ordering for extra pages 2017-06-13 17:47:07 +02:00
Philipp Oppermann
e84c8ac638 Display date of last update for posts 2017-06-13 17:35:08 +02:00
Philipp Oppermann
6f8999ada5 Display date for posts 2017-06-13 17:30:36 +02:00
Philipp Oppermann
ca96cae9cc Use a plain template for pages 2017-06-13 17:30:06 +02:00
Philipp Oppermann
1530cfe55f Include javascript table of content 2017-06-13 17:07:36 +02:00
Philipp Oppermann
918f9045d3 Rename naked exception handling section 2017-06-13 14:27:24 +02:00
Philipp Oppermann
d83dc719cf Add piwik tracking code 2017-06-13 13:39:04 +02:00
Philipp Oppermann
a1ed273f7f Add redirects from old URLs 2017-06-09 18:55:26 +02:00
Philipp Oppermann
c104445880 Remove sections from URLs 2017-06-09 18:08:10 +02:00
Philipp Oppermann
e11d838189 Add a 404 page 2017-06-09 17:54:05 +02:00
Philipp Oppermann
8140eb0e7c Don't render section pages for posts,pages,extra 2017-06-09 17:43:58 +02:00
Philipp Oppermann
4c09e9792b Remove python requirements we no longer need 2017-06-09 15:57:17 +02:00
Philipp Oppermann
6f14cc83af Adjust recent-updates generation for gutenberg 2017-06-09 15:57:17 +02:00
Philipp Oppermann
88d81461e2 Fix dead internal links 2017-06-09 15:18:25 +02:00
Philipp Oppermann
f1ce61263c Move talks page to extra section 2017-06-09 14:58:48 +02:00
Philipp Oppermann
59594b8622 Replace unsupported highlight syntax with normal code blocks 2017-06-09 14:51:37 +02:00
Philipp Oppermann
945a766f0c Fix internal links 2017-06-09 14:51:37 +02:00
Philipp Oppermann
66e10facc1 Move images next to their corresponding posts 2017-06-09 14:51:37 +02:00
Philipp Oppermann
11de9b4c07 Update templates for new page sections 2017-06-09 14:51:36 +02:00
Philipp Oppermann
d5a3b48d62 Make posts, pages, and extra sections 2017-06-09 14:51:36 +02:00
Philipp Oppermann
8289bc7d5b The css class for anchors was changed 2017-06-09 14:51:36 +02:00
Philipp Oppermann
c6cd132de9 Sort naked exception handling posts correctly 2017-06-09 14:51:36 +02:00
Philipp Oppermann
a80017cf6c Remove index section 2017-06-09 14:51:36 +02:00
Philipp Oppermann
c2dcd29d81 Fix and update gutenberg config file 2017-06-09 14:51:36 +02:00
Philipp Oppermann
3f51f3c61d Use gutenberg's syntax for internal links 2017-06-09 14:51:36 +02:00
Philipp Oppermann
7744a08212 Move footnotes to the bottom 2017-06-09 14:51:36 +02:00
Philipp Oppermann
7e63bf08ff Move posts to their own subfolder
This allows us to move the images right next to the posts
2017-06-09 14:51:36 +02:00
Philipp Oppermann
2ebc323cdb Don't underline the anchor link symbol 2017-06-09 14:51:36 +02:00
Philipp Oppermann
c4f9b28b41 Add styling to heading anchors 2017-06-09 14:51:36 +02:00
Philipp Oppermann
c5622c864e Add a “neutral” border style for post lists 2017-06-09 14:51:36 +02:00
Philipp Oppermann
76c0c4f1da Add slug for contact page 2017-06-09 14:51:36 +02:00
Philipp Oppermann
186ce23e11 Move additional-resources/old-posts to a section named extra 2017-06-09 14:51:36 +02:00
Philipp Oppermann
68453f7374 Use manual ordering for posts 2017-06-09 14:51:36 +02:00
Philipp Oppermann
168b598901 Create gutenberg templates 2017-06-09 14:51:36 +02:00
Philipp Oppermann
d109912798 Remove hugo layout files 2017-06-09 14:51:36 +02:00
Philipp Oppermann
55b3378e8c Description field is optional now 2017-06-09 14:51:36 +02:00
Philipp Oppermann
1f5cca2779 Fix syntax of <!-- more --> marker 2017-06-09 14:51:36 +02:00
Philipp Oppermann
f525541969 Fix front matter: Add description field and set slug 2017-06-09 14:51:35 +02:00
Philipp Oppermann
9940a598ab Create new config.toml for gutenberg 2017-06-09 14:51:35 +02:00
Philipp Oppermann
4f0fa4e1b3 Pluralize content folder names (“post” -> “posts”, etc.) 2017-06-09 14:51:35 +02:00
Philipp Oppermann
b7ca881bed Add missing front matter 2017-05-22 10:55:14 +02:00
Philipp Oppermann
03fc9d2e4e Create a “Talks” page 2017-05-22 10:53:23 +02:00
Philipp Oppermann
f3829346bc Unique::get/get_mut were renamed to as_ref/as_mut (#325) 2017-05-12 21:32:38 +02:00
Philipp Oppermann
160b986322 The Makefile uses xargo instead of cargo now 2017-05-09 19:01:05 +02:00
Philipp Oppermann
6ef85ecd69 Add required linket-flavor field to target specification 2017-04-20 19:29:23 +02:00
Philipp Oppermann
fd11d71f08 Link to new post_X tags (#320) 2017-04-19 12:50:47 +02:00
Philipp Oppermann
4634149084 Merge pull request #319 from phil-opp/double-faults-fixes
Some small improvements for the “Double Faults” post
2017-04-19 12:23:32 +02:00
Philipp Oppermann
92566fcdc4 Fix highlight line numbers 2017-04-19 12:17:57 +02:00
Philipp Oppermann
44758f46fb Describe how to add a dependency on the bit_field crate 2017-04-18 18:34:32 +02:00
Philipp Oppermann
aac958a119 Fix module file name (interrupts.rs -> interrupts/mod.rs) 2017-04-18 18:27:26 +02:00
Philipp Oppermann
559e85a597 Mention that we need to enable the abi_x86_interrupt feature (#318) 2017-04-18 15:23:22 +02:00
Philipp Oppermann
f94062a9d5 Merge pull request #317 from phil-opp/kernel-heap-fixes
Kernel Heap: Mention Xargo.toml and add missing unsafe in code example
2017-04-18 15:09:47 +02:00
Philipp Oppermann
f5d9766868 Add missing unsafe 2017-04-18 14:58:52 +02:00
Philipp Oppermann
538cc32766 A Xargo.toml is required as soon as we use alloc/collections 2017-04-18 14:58:41 +02:00
Philipp Oppermann
f2c8b792d6 Minor fixes in code examples 2017-04-18 12:36:04 +02:00
Philipp Oppermann
1ad30d488c Merge pull request #311 from phil-opp/page-table-post-updates
Bring “Page Tables” post up to date again
2017-04-13 19:52:45 +02:00
Philipp Oppermann
493dede919 The x86_64 crate requires no unsafe for tlb flushing 2017-04-13 19:43:38 +02:00
Philipp Oppermann
9f0995c4b7 Update x86_64 crate to 0.1.2 2017-04-13 19:35:32 +02:00
Philipp Oppermann
df048c9922 The stack overflow no longer occurs since we're using a 16kb stack now 2017-04-13 19:34:34 +02:00
Philipp Oppermann
e48aa7e68e Fix updated date of “Set Up Rust” 2017-04-12 20:52:24 +02:00
Philipp Oppermann
d0e3a93672 Merge pull request #310 from phil-opp/set-up-rust-xargo
Update “Set Up Rust” to use a custom target and xargo
2017-04-12 20:49:37 +02:00
Philipp Oppermann
c202937302 Add the new linker-flavor field to target json
See https://github.com/rust-lang/rust/pull/40018
2017-04-12 20:45:59 +02:00
Philipp Oppermann
239e96e8f2 Link to the new post_n tags 2017-04-11 19:42:40 +02:00
Philipp Oppermann
f72cfbff34 Disable unwinding in the target config file 2017-04-11 19:40:57 +02:00
Philipp Oppermann
388f014fc3 Use rlibc 1.0 2017-04-11 19:40:06 +02:00
Philipp Oppermann
42c6ad56bb Fix Todos, improve wording, and update console output 2017-04-11 19:38:00 +02:00
Philipp Oppermann
04dcedbc38 Add link targets 2017-04-10 09:20:48 +02:00
Philipp Oppermann
f58ec094ab Minor wording improvements 2017-04-10 09:20:35 +02:00
Philipp Oppermann
553fac369e Introduce our custom target (and xargo) already in “Set Up Rust” 2017-04-10 08:39:49 +02:00
Philipp Oppermann
47455021ee Revert "Create yandex_b2ebe30f3e30e19e.html"
This reverts commit 5cb96ce440.
2017-04-09 10:26:12 +02:00
Philipp Oppermann
5cb96ce440 Create yandex_b2ebe30f3e30e19e.html 2017-04-09 10:22:47 +02:00
Philipp Oppermann
b7b9097557 Update Readme for “Handling Exceptions” post (#307)
* Update Readme for “Handling Exceptions” post

* Fix typo
2017-04-03 09:54:44 +02:00
Ahmed Charles
657f34ae5e Fix typo. (#306) 2017-04-01 11:38:33 +02:00
Gil Mendes
38c6561252 Fix SegmentSelector::empty() on double-fault post (#305)
The “Double Fault“ post still use the old `SegmentSelector::empty()` on
the x86 crate. This commit update it to the new x86_64 crate.
2017-03-31 11:08:56 +02:00
Philipp Oppermann
de45b55cf8 Fix wrong include paths x86_64::shared 2017-03-28 16:36:40 +02:00
Philipp Oppermann
d02b89c626 Remove duplicate word 2017-03-27 13:47:05 +02:00
Philipp Oppermann
9e79c6bd97 Fix release date 2017-03-26 18:43:09 +02:00
Philipp Oppermann
1cc5f055f7 Merge pull request #292 from phil-opp/handling-exceptions
Create a new “Handling Exceptions” post
2017-03-26 13:23:39 +02:00
Philipp Oppermann
67739e4020 Add post templates for old-posts 2017-03-25 18:14:38 +01:00
Philipp Oppermann
97ef518895 Rewrite “Double Faults” post based on new “Handling Exceptions” post 2017-03-25 18:10:25 +01:00
Philipp Oppermann
260b416ae4 Create a index page for handling exceptions using naked fns 2017-03-25 18:10:20 +01:00
Philipp Oppermann
26417cc670 Keep original URLs for old-posts 2017-03-25 17:00:36 +01:00
Philipp Oppermann
43a41233b2 Add notes on old posts 2017-03-25 17:00:16 +01:00
Philipp Oppermann
3e5eceb1b3 Move old exception posts to old_posts folder 2017-03-25 16:39:50 +01:00
Philipp Oppermann
839cf7fba4 The double faults post is the 10th post now 2017-03-25 16:38:35 +01:00
Philipp Oppermann
d3a0684014 Hack: Put “Handling Exceptions” before “Double Faults” 2017-03-25 16:37:16 +01:00
Philipp Oppermann
3b1f795714 The Handling Exceptions post will be the 9th post 2017-03-25 16:28:26 +01:00
Philipp Oppermann
129ce4ca25 Add an aside for resolving stack overflow errors 2017-03-25 16:27:46 +01:00
Philipp Oppermann
09b5e7b136 Fix stack size in posts (it was increased to 16kB) 2017-03-25 16:23:37 +01:00
Philipp Oppermann
531a069a6e Create a new “Handling Exceptions” post
This post combines the previous exception handling posts “Catching Exceptions”, “Better Exception Messages” and “Returning from Exceptions” into a single post by using the `x86-interrupt` calling convention and the `Idt` type of the `x86_64` crate.
2017-03-25 16:22:33 +01:00
Gil Mendes
0cb9be7c08 Merge pull request #296 from gil0mendes/expand-stack
Expand stack to 16k
2017-03-24 13:06:42 +01:00
Philipp Oppermann
e20a48712b Increase opacity of table of contents to 0.5 2017-03-21 19:38:31 +01:00
Philipp Oppermann
2afa815b2f inline-block instead of inline 2017-03-19 14:30:18 +01:00
Philipp Oppermann
3765d2337b Color <code> elements inside <a> 2017-03-19 14:30:18 +01:00
Philipp Oppermann
37911358ac Merge pull request #289 from phil-opp/x86_64-crate
Use the `x86_64` crate instead of `x86`
2017-03-19 13:25:17 +01:00
Philipp Oppermann
31aab55ace Remove rustfmt check for now due to rust-lang-nursery/rustfmt#1375 2017-03-19 13:22:35 +01:00
Philipp Oppermann
4853baaabc Update posts to use x86_64 crate 2017-03-15 16:58:15 +01:00
Philipp Oppermann
02eaeb7af1 Switch to x86_64 crate and use its idt module 2017-03-15 16:58:15 +01:00
Philipp Oppermann
7ef97adb9c CI: Remove hugo build and deploy 2017-03-12 00:25:45 +01:00
Philipp Oppermann
24a4c57deb Remove Rust codegen crate 2017-03-12 00:19:46 +01:00
Philipp Oppermann
cfa93f1c46 Add before_build script 2017-03-12 00:14:14 +01:00
Philipp Oppermann
0fc98f2a92 Remove files that were only needed for github pages 2017-03-11 19:21:45 +01:00
Philipp Oppermann
74f84c16fa Disable section and taxonomy pages 2017-03-11 14:02:55 +01:00
Philipp Oppermann
71d5a1d9dc Move “diagrams” one level up 2017-03-11 13:55:50 +01:00
Philipp Oppermann
fc4d296dc7 Add a requirements.txt file 2017-03-11 13:50:17 +01:00
Philipp Oppermann
cb84c5c152 Remove .RSSlink (deprecation error) 2017-03-11 13:50:17 +01:00
Philipp Oppermann
495bee0480 Use standard “content” directory 2017-03-11 12:51:40 +01:00
Philipp Oppermann
7dbc7dc885 Merge branch 'hugo' 2017-03-11 12:45:27 +01:00
Philipp Oppermann
ce36e25da9 Move everything into a “blog” directory 2017-03-11 12:41:53 +01:00
Philipp Oppermann
68dc7447f4 Run rustfmt 2017-03-09 17:50:44 +01:00
Ahmed Charles
844d739379 Fix typo in “Returning from Exceptions” (#285) 2017-02-13 14:24:59 +01:00
Ahmed Charles
cb98f1a4de Remove unneeded read/write flag in post (#282) 2017-01-30 14:21:53 +01:00
Philipp Oppermann
419d000897 Merge pull request #281 from phil-opp/update-bit_field
Update to latest bit_field version
2017-01-25 13:49:49 +01:00
Philipp Oppermann
8b807a7d25 Update posts to latest bit_field version 2017-01-25 13:46:21 +01:00
Philipp Oppermann
46100ba24b Update to latest bit_field version 2017-01-25 13:45:57 +01:00
Philipp Oppermann
fce85e68ee The ReadWrite flag isn't needed for code segments (#279) 2017-01-18 13:12:28 +01:00
Philipp Oppermann
0ec93fc6fe Merge pull request #278 from phil-opp/gdt-without-data-segment
Remove the data segment from assembly 64-bit GDT
2017-01-14 16:56:14 +01:00
Philipp Oppermann
ebb3e413dd Update GDT code in post (no data segments anymore)
We also load 0 into all data segment registers to avoid future problems with iretq. Also: minor wording improvements.
2017-01-14 16:42:18 +01:00
Philipp Oppermann
8f8b46a9b6 Load null selectors to all data registers
This is required for some instructions such as iretq (ss must be valid or 0).
2017-01-14 16:38:33 +01:00
Philipp Oppermann
e179dadf70 Data segments aren't needed for 64-bit mode 2017-01-12 17:23:50 +01:00
Philipp Oppermann
a8847c22ef Fix broken links 2017-01-04 16:36:25 +01:00
Philipp Oppermann
ae1c9b3739 Merge pull request #276 from phil-opp/p
Make panic_fmt public to fix private_no_mangle_fns warning
2017-01-04 16:21:19 +01:00
Philipp Oppermann
64cbabd1c2 make panic_fmt public in posts 2017-01-04 16:15:59 +01:00
Philipp Oppermann
1be2f42791 Make panic_fmt public to fix private_no_mangle_fns warning 2017-01-04 16:13:27 +01:00
Philipp Oppermann
f6a1faab96 Fix broken links in “Double Faults” (#275) 2017-01-02 19:39:19 +01:00
Philipp Oppermann
1549e318a5 Merge pull request #270 from phil-opp/new-post
New post about double faults
2017-01-02 19:19:29 +01:00
Philipp Oppermann
c39070da4a “Double Faults” is the 12th post 2017-01-02 19:15:50 +01:00
Philipp Oppermann
a43b23b619 Catch double faults on a separate stack 2017-01-02 19:11:56 +01:00
Philipp Oppermann
006619920e Reload code segment register and load TSS 2017-01-02 19:11:56 +01:00
Philipp Oppermann
c0d7206249 Make TSS and GDT statics by using spin::Once 2017-01-02 19:11:56 +01:00
Philipp Oppermann
31ffe60052 Add a new GDT module 2017-01-02 19:11:56 +01:00
Philipp Oppermann
d330a67659 Create a new TaskStateSegment
(that contains the double fault stack in its IST)
2017-01-02 19:11:56 +01:00
Philipp Oppermann
e08bd375ae Allocate a new double fault stack in interrupts::init 2017-01-02 19:11:56 +01:00
Philipp Oppermann
8ad76ba496 Create a new MemoryAllocator (and initialize it) 2017-01-02 19:11:56 +01:00
Philipp Oppermann
4347ff235f Add a new stack_allocator module 2017-01-02 19:11:56 +01:00
Philipp Oppermann
47755d541d Trigger a stack overflow (still causes a triple fault) 2017-01-02 19:11:56 +01:00
Philipp Oppermann
dfa1cc48c9 Add a double fault handler (and trigger it) 2017-01-02 19:11:56 +01:00
Philipp Oppermann
9090bf0c06 Set correct release date 2017-01-02 19:11:56 +01:00
Philipp Oppermann
7db15cf892 Reset source code to master again
(in order to follow the post and test the exact code from it)
2017-01-02 19:11:56 +01:00
Philipp Oppermann
055c534b4e Add a section about possible safety problems 2017-01-02 19:11:56 +01:00
Philipp Oppermann
80354c8a72 Multiple code corrections in post 2017-01-02 19:11:56 +01:00
Philipp Oppermann
02b3ebcd27 Add another image for double fault post 2017-01-02 19:10:58 +01:00
Philipp Oppermann
cce40a1d67 Many small improvements 2016-12-30 14:54:46 +01:00
Philipp Oppermann
e121edced2 Change the GDT push logic
Instead of looking for a zero field, we now keep track of the next free index in a separate field. This avoids the bug that the high u64 of a pushed TSS descriptor is treated as empty.
2016-12-30 14:54:46 +01:00
Philipp Oppermann
1e45ddd79c Link double fault post and source in Readme 2016-12-30 14:52:04 +01:00
Philipp Oppermann
ec358321da Finish first draft of double faults post 2016-12-30 14:52:04 +01:00
Philipp Oppermann
c3bfcbcd8d Silence dead code warning 2016-12-30 14:52:04 +01:00
Philipp Oppermann
58e7cc77d0 Data segment descriptors are not needed in 64-bit mode 2016-12-30 14:52:04 +01:00
Philipp Oppermann
0b03c18b06 Rewrite interrupts::init using a lazy_static IDT again 2016-12-30 14:52:04 +01:00
Philipp Oppermann
3e6b1a8a35 Rewrite gdt module using an array instead of Vec 2016-12-30 14:52:04 +01:00
Philipp Oppermann
ceb44d9c2e Use x86's TaskStateSegment and use usize for stack pointers 2016-12-30 14:52:04 +01:00
Philipp Oppermann
d1fb1516fa Minor improvements to post 2016-12-30 14:52:04 +01:00
Philipp Oppermann
ef786e1fe8 Update post and code 2016-12-30 14:52:04 +01:00
Philipp Oppermann
038fd097b6 Update post 2016-12-30 14:52:04 +01:00
Philipp Oppermann
5f8de6e871 Create TSS and GDT modules and use a double fault stack 2016-12-30 14:52:04 +01:00
Philipp Oppermann
b4bc47d5d9 Add a new section about the causes of double faults
(+ many other improvements)
2016-12-30 14:51:47 +01:00
Philipp Oppermann
0cd2577abe Some code for double faults post 2016-12-30 14:50:53 +01:00
Philipp Oppermann
8eba47816f Begin new post about double faults 2016-12-30 14:50:52 +01:00
Philipp Oppermann
c33f01d8f7 Update printing-to-screen post to use spin 0.4.5 2016-12-30 14:47:39 +01:00
Philipp Oppermann
89abbf1038 Update to spin 0.4.5
Fixes #274
2016-12-30 14:40:57 +01:00
Philipp Oppermann
14babd8c2a Add a Xargo.toml for xargo 0.3.0 and update the corresponding post (#272) 2016-12-29 16:45:24 +01:00
Philipp Oppermann
8685cc602f Add images for double fault post 2016-12-29 15:25:58 +01:00
Philipp Oppermann
02697891e2 Update x86 crate to version 0.8.0 (#266) 2016-12-21 14:59:57 +01:00
Philipp Oppermann
a7a9aabce7 Remove workspace from post as well (#267) 2016-12-21 14:55:09 +01:00
Philipp Oppermann
fcd453ac29 Remove cargo workspace (#265) 2016-12-21 00:19:30 +01:00
Philipp Oppermann
00452c2302 Revert "map the P4 table recursively before setting paging" (#259) 2016-12-19 11:34:21 +01:00
Philipp Oppermann
c5dd983949 Mark panic_fmt as no_mangle to work around rust-lang/rust#38281 (#262) 2016-12-19 11:32:20 +01:00
Philipp Oppermann
f4ff2b0000 Keep installed tools up-to-date using cargo-update 2016-12-19 11:01:21 +01:00
Philipp Oppermann
9583cdea28 Test for rustfmt/xargo instead of using || true (#257) 2016-11-30 16:29:01 +01:00
Anton Strömkvist
bef61116fd Minor grammatical error fix (#258)
In `02-entering-longmode.md`
2016-11-30 16:28:45 +01:00
Philipp Oppermann
c76f7b8b98 Merge pull request #256 from phil-opp/p1
Fix panic_fmt arguments: file is a &'static str
2016-11-26 12:27:42 +01:00
Philipp Oppermann
f4c9c12047 Fix panic_fmt arguments in post 2016-11-26 12:17:12 +01:00
Philipp Oppermann
e9735738f7 Fix panic_fmt arguments: file is a &'static str 2016-11-26 12:15:34 +01:00
Philipp Oppermann
c7268cff3b Fix CI for xargo 0.2.0 2016-11-19 10:46:07 +01:00
Philipp Oppermann
a1fccc12b6 Set date of last update correctly for posts (#254) 2016-11-08 17:45:36 +01:00
Philipp Oppermann
e304b8ee21 Update images for #252 2016-11-01 17:56:31 +01:00
Philipp Oppermann
571f1d2fbf Merge pull request #252 from phil-opp/stack_frame-reference
Exceptions: Take the ExceptionStackFrame per reference
2016-11-01 17:56:25 +01:00
Philipp Oppermann
9963961f35 Test the handler_with_error_code macro in a different way
We now take stack_frame as a immutable reference and we shouldn't write to a &. So the old test example (page faults as breakpoints) becomes even more hacky. Instead, we're now deliberately entering an endless page fault loop to check our iretq logic.
2016-11-01 17:50:51 +01:00
Philipp Oppermann
67857bde2f Returning from Exceptions: Take stack_frame as reference 2016-11-01 17:46:57 +01:00
Philipp Oppermann
e129da8cc2 Better Exception Messages: Take stack_frame argument as reference 2016-11-01 17:46:57 +01:00
Philipp Oppermann
15feb9a120 Use references for the ExceptionStackFrame argument
We require/assume that these pointers are correct. Using references is cleaner than blindly dereferencing raw pointers.

Important: The Rust book guarantees that: “At runtime, a raw pointer * and a reference pointing to the same piece of data have an identical representation.”
2016-11-01 16:56:11 +01:00
Philipp Oppermann
f737c302e7 therefor -> for that 2016-10-31 15:31:32 +01:00
Philipp Oppermann
7a0bb1ff7b Print an empty line before exception error messages 2016-10-31 01:37:37 +01:00
Philipp Oppermann
a6d52f8244 Merge pull request #250 from phil-opp/println-screenshots
New screenshots with println (green) instead of print_error (red)
2016-10-31 01:12:40 +01:00
Philipp Oppermann
7254528d53 Merge pull request #249 from phil-opp/fix-println-deadlock
Update `print` macro to avoid deadlock; remove hacky `print_error` function
2016-10-31 01:12:34 +01:00
Philipp Oppermann
f300afe139 New screenshots with println instead of print_error 2016-10-31 01:07:06 +01:00
Philipp Oppermann
3bfa5a8178 Update “Returning from Exceptions” to use println 2016-10-31 01:04:53 +01:00
Philipp Oppermann
25fca59248 Update “Better Exception Messages” to use println 2016-10-30 20:06:51 +01:00
Philipp Oppermann
f14baa218e Fix typo 2016-10-30 19:12:55 +01:00
Philipp Oppermann
ca522db7bf Exceptions inside printlns are no longer a problem
The recent update to the vga driver evaluates the arguments before locking the global stdout writer
2016-10-30 17:32:04 +01:00
Philipp Oppermann
9e7ea0b65f Remove images that are no longer needed 2016-10-30 17:30:28 +01:00
Philipp Oppermann
beba773e52 Add some more QEMU screenshots for “Printing to Screen” 2016-10-30 17:24:12 +01:00
Philipp Oppermann
41c87636e0 Improve wording and add some more QEMU screenshots 2016-10-30 17:23:17 +01:00
Philipp Oppermann
cfccffca39 Trigger and fix the deadlock for nested printlns 2016-10-30 16:54:03 +01:00
Philipp Oppermann
c69f73b9b2 Improve some explanations in the section about fomatting macros 2016-10-30 16:53:24 +01:00
Philipp Oppermann
9b83b2853e Remove print_error and use normal println in exception handlers 2016-10-30 16:51:59 +01:00
Philipp Oppermann
212dcfa592 Make print_error safe by using the global writer
This is now possible since we fixed the deadlock problem.
2016-10-30 16:51:59 +01:00
Philipp Oppermann
d96df500a7 Create a new print function and use it in the print macro
This fixes the deadlock problem, because the format_args is now evaluated before locking the screen writer. So `println!("{:?}", {println!("");})` no longer triggers a deadlock.
2016-10-30 16:51:59 +01:00
Dentosal
1fe9e87ead Remap the Kernel: Fixed broken link (#247) 2016-10-24 00:06:58 +02:00
Matanel Levi
f35ea9430c Page Tables: clarify that we need to map the P4 table recursively before enabling paging (#246)
We have to map the P4 table recursively before setting paging - can't do this wherever we'd like.
2016-10-23 16:04:09 +02:00
Philipp Oppermann
92b04dfba7 Remove old “Update” sections (#244)
Most of these updates are quite old and thus distracting. Instead, we now have a “Recent Changes” box in the sidebar of the front page.
2016-10-15 17:10:43 +02:00
Philipp Oppermann
941fca8b0d Better Exception Messages: Add example code that triggers the triple fault again (#242) 2016-10-12 16:56:25 +02:00
Philipp Oppermann
8bec3b42b0 Merge pull request #239 from phil-opp/vga_volatile
Printing to Screen: Use volatile operations for accessing the VGA Buffer
2016-10-08 15:49:00 +02:00
Philipp Oppermann
7db50a1a62 Fine-tune the section about volatiles 2016-10-08 15:41:59 +02:00
Philipp Oppermann
895cab981b Rewrite post to use and explain volatiles
Also extends some other explanations.
2016-10-06 23:57:26 +02:00
Philipp Oppermann
d7a445b1bb Use volatile operations for accessing the VGA buffer 2016-10-06 23:57:26 +02:00
Philipp Oppermann
a55a144a26 Use absolute times instead of durations (#236) 2016-10-04 20:16:39 +02:00
Philipp Oppermann
83ce5d2d4d Use non-breaking spaces when formatting durations 2016-10-04 19:39:55 +02:00
Philipp Oppermann
1829509800 Merge pull request #235 from phil-opp/recent-updates
Add a “Recent Updates” section on the front page
2016-10-04 19:32:57 +02:00
Philipp Oppermann
6a5b3c9d1a Cache cargo target folder 2016-10-04 19:29:08 +02:00
Philipp Oppermann
f10982aa7d Put “Recent Updates” to the right sidebar on large displays 2016-10-04 19:18:57 +02:00
Philipp Oppermann
9ec3914aa3 Add “Recent Updates” to index.html 2016-10-04 19:18:35 +02:00
Philipp Oppermann
b7351b0f69 Remove X-Frame-Options meta tag 2016-10-04 19:18:12 +02:00
Philipp Oppermann
12b66968dc Call codegen crate in build script 2016-10-04 19:17:46 +02:00
Philipp Oppermann
eef00ff35c Refactor: Move build commands into a new travis-build.sh 2016-10-04 19:15:19 +02:00
Philipp Oppermann
9d5728cdcd Create a cargo workspace 2016-10-04 19:11:32 +02:00
Philipp Oppermann
b22c1f8113 Add a codegen crate for generating an “Recent Updates” section 2016-10-04 19:10:04 +02:00
Philipp Oppermann
620c4858a3 Switch travis to language:rust (we're using binary hugo releases now) 2016-10-04 15:31:57 +02:00
Philipp Oppermann
cd93924159 Add a footnote that userspace programs can still use SSE
Fixes #227
2016-10-02 18:49:20 +02:00
Philipp Oppermann
0f4d1ce303 Add missing license headers (#233) 2016-10-02 18:28:35 +02:00
Philipp Oppermann
a04924955a Add missing license headers and update copyright year (#232) 2016-10-02 18:20:48 +02:00
Philipp Oppermann
51e19d104b Merge pull request #230 from phil-opp/multiboot2-crates.io
Use crates.io version of multiboot2
2016-09-27 13:49:36 +02:00
Philipp Oppermann
2b07d88b62 Update post to use multiboot2 from crates.io 2016-09-27 13:46:29 +02:00
Philipp Oppermann
c6b1346956 Use crates.io version of multiboot2 2016-09-27 13:43:53 +02:00
Philipp Oppermann
05c537d1e7 Merge pull request #229 from phil-opp/update-bitfield
Update bit_field to 0.5.0 and use new trait based API
2016-09-27 13:36:29 +02:00
Philipp Oppermann
4db15a7e80 Update post to new bit_field code 2016-09-27 13:25:03 +02:00
Philipp Oppermann
2639a46a5e Reorder items to cargo-edit format 2016-09-27 13:24:43 +02:00
Philipp Oppermann
6eba03dd58 Update bit_field to 0.5.0 and use new API 2016-09-27 13:24:01 +02:00
Philipp Oppermann
f73006a24f Fix link syntax (#228) 2016-09-25 21:48:43 +02:00
Philipp Oppermann
3315f54978 Merge pull request #223 from 4e554c4c/master
Fix for #220: BumpAllocator overflow

Fixes #220
2016-09-23 01:17:23 +02:00
Calvin Lee
5b9a45674d Minor wording change
"so that the calling code cannot overflow `heap_start`" -> "so that `alloc_end` cannot overflow"
2016-09-22 16:03:32 -06:00
Calvin Lee
54e02fd6b5 Fixes #220: BumpAllocator overflow
I also fixed a spelling error and replaced a tab with a space
in the blog post where `allocate()` was created.
2016-09-22 12:25:59 -06:00
Philipp Oppermann
379ca660ae Merge pull request #221 from phil-opp/cross-compile-core
Use rustup for cross compiling and also explain xargo
2016-09-22 15:59:20 +02:00
Philipp Oppermann
901ca7f2ed Rewrite “Cross Compile Libcore” guide using rustup and xargo
Rustup replaces the “Download it” solution and xargo the “Build it using cargo” solution.
2016-09-22 15:34:24 +02:00
Philipp Oppermann
2e013397e3 Use rustup for cross compiling libcore 2016-09-22 15:15:46 +02:00
Philipp Oppermann
fce2da691d Remove diagram sources 2016-09-21 15:47:06 +02:00
Philipp Oppermann
f8151580de Fix date of new post 2016-09-21 15:39:43 +02:00
Philipp Oppermann
3a82be2c1f Merge pull request #219 from phil-opp/returning-from-exceptions
“Returning from Exceptions”
2016-09-21 15:26:16 +02:00
Philipp Oppermann
9f7994772b Add ~/.cargo/bin to PATH 2016-09-21 15:17:39 +02:00
Philipp Oppermann
bd285b1731 Use kalakris-cmake for cmake 2.8.11 2016-09-21 14:54:49 +02:00
Philipp Oppermann
43ed189b35 Fix travis: Install xargo in before_script 2016-09-21 14:45:03 +02:00
Philipp Oppermann
5c05f7c438 Add new post to README 2016-09-21 14:41:47 +02:00
Philipp Oppermann
e9128e8c54 Update images for “Returning from Exceptions” 2016-09-21 14:35:02 +02:00
Philipp Oppermann
00701ca474 Add code for “Returning from Exceptions” 2016-09-21 14:34:32 +02:00
Philipp Oppermann
a4054c478c We require xargo now 2016-09-21 14:33:09 +02:00
Philipp Oppermann
f38805c3d3 Final improvements 2016-09-21 14:32:42 +02:00
Philipp Oppermann
706c48a410 Add source files for the diagrams 2016-09-20 17:35:39 +02:00
Philipp Oppermann
5a00bddd7c Write introduction 2016-09-20 17:31:28 +02:00
Philipp Oppermann
626763d452 Write “What's next?” 2016-09-20 17:16:13 +02:00
Philipp Oppermann
bdebc1525f Add images for “Returning from Exceptions” post 2016-09-20 16:35:33 +02:00
Philipp Oppermann
e75881c501 Increase .container width 2016-09-20 16:34:02 +02:00
Philipp Oppermann
e4ae45e863 Write “Exceptions with Error Codes” section 2016-09-20 16:17:22 +02:00
Philipp Oppermann
0bb7f1a53e New post about returning from exceptions 2016-09-20 02:47:55 +02:00
Philipp Oppermann
8cee4161de Update to hugo 0.16 2016-09-18 19:26:45 +02:00
Philipp Oppermann
9b842e9578 Rename posts: Use ascending numbers instead of date 2016-09-18 19:25:08 +02:00
Philipp Oppermann
3d8dca0588 Merge pull request #218 from phil-opp/use-hugo-release
Use latest hugo release instead of github master
2016-09-18 19:22:07 +02:00
Philipp Oppermann
0b08caf16d Disable success notifications 2016-09-18 19:18:30 +02:00
Philipp Oppermann
5cd4ff8641 Use latest release instead of github master 2016-09-18 19:18:08 +02:00
Philipp Oppermann
f948f8cb98 Revert "Use new .Authors instead of deprecated .Author (#216)"
This reverts commit 555d24698b.
2016-09-18 18:37:06 +02:00
Philipp Oppermann
113ad1c6f9 Decrease font size to 17px (#217) 2016-09-18 18:24:30 +02:00
Philipp Oppermann
555d24698b Use new .Authors instead of deprecated .Author (#216)
This fixes the breaking change introduced by https://github.com/spf13/hugo/issues/2464
2016-09-18 18:16:11 +02:00
dns2utf8
917eb78255 Add mtools to readme (#213) 2016-09-12 11:22:42 +02:00
Philipp Oppermann
ee48c2ee3b Use main rss with new rss template (#212) 2016-08-29 11:29:07 +02:00
Philipp Oppermann
9830f4ef48 Check rustfmt formatting in travis builds (#210)
* Install rustfmt

* Check formatting in travis builds
2016-08-27 13:45:18 +02:00
Philipp Oppermann
68921b625d Cache cargo directories (#209) 2016-08-27 13:11:44 +02:00
Philipp Oppermann
18d02e01e1 Merge pull request #208 from KarboniteKream/master
Fix various typos
2016-08-20 14:05:19 +02:00
Klemen Košir
30a8c06295 reexport -> re-export 2016-08-20 13:04:26 +02:00
Klemen Košir
e56df793d4 Fix an incorrect function name 2016-08-20 13:03:54 +02:00
Klemen Košir
02ef52c677 Fix an incorrect year of update in post title 2016-08-20 13:03:25 +02:00
Klemen Košir
a33bf9c889 Fix a function name typo 2016-08-20 13:02:41 +02:00
Philipp Oppermann
7c0082ecb4 Fix broken unwinding link (link to nomicon now) (#207) 2016-08-17 14:35:42 +02:00
Jeremy Ruten
c6f35a953a Fix code to trigger memcpy linker errors (#206)
Fixes #205
2016-08-16 12:49:36 +02:00
Leon Loopik
98c3b2a4a1 Fix incorrect uses of therefor (#204)
* Fix typo (therefor -> therefore)

* Rephrased a sentence

* Added backticks back in
2016-08-10 12:22:53 +02:00
Philipp Oppermann
462a38d0ca Merge pull request #203 from phil-opp/kernel-heap-improvements
Various improvements to “Kernel Heap”
2016-08-05 11:25:06 +02:00
Philipp Oppermann
72199bb7d7 Fix link and link to both “page tables” and “remap the kernel” 2016-08-05 11:22:20 +02:00
Philipp Oppermann
86efbda8d8 Remove panic=abort note 2016-08-05 11:22:20 +02:00
Philipp Oppermann
a5acfee7c3 Improve some heading levels 2016-08-05 11:22:20 +02:00
Philipp Oppermann
9603ac1ccc Create a cargo workspace for subcrates (#202) 2016-08-05 11:21:57 +02:00
Philipp Oppermann
a01034cbfc Merge pull request #201 from phil-opp/lazy_static
Use upstream lazy_static and upgrade `once` to latest version
2016-08-04 20:14:55 +02:00
Philipp Oppermann
4a1fa3a65a Explain how to add lazy_static to the main crate 2016-08-04 20:09:25 +02:00
Philipp Oppermann
3bd5e56e3f Use upstream lazy_static and update once crate 2016-08-04 20:09:25 +02:00
Mark Schmale
74cadb15a3 removed extra "use" (#197)
I'm not a native speaker so I'm not 100% sure but I guess this "use" shouldn't be there.
2016-08-04 13:58:49 +02:00
Philipp Oppermann
9ec1860f02 Merge pull request #196 from phil-opp/p1
Fix clobber syntax and add missing rsi clobber in code
2016-08-04 01:12:50 +02:00
Philipp Oppermann
46d41d9c3d Add missing rsi clobber in code as well 2016-08-04 01:07:51 +02:00
Philipp Oppermann
cde3f535c7 Fix clobber syntax in post 2016-08-04 01:07:39 +02:00
Philipp Oppermann
3a62b42414 Link to nightly docs as stable still has wrong clobber syntax
See #195
2016-08-04 01:00:55 +02:00
Leon Loopik
ca925c49e0 Add rsi to the clobber list (#195)
In the second macro (handler_with_error_code), we pop the error code into rsi, this means we are changing the value of rsi in the assembly block, so we should add it to the clobbers.

I am quite new to this, so please close this request if I am completely wrong.

(Side question: An other thing I came across while trying to figure out if this was correct, is that every documentation says you should add curly brackets around register names, can someone tell me why this is not done here?)
2016-08-04 00:19:12 +02:00
Philipp Oppermann
5e6a8cb69b Link gitter chat 2016-08-03 20:48:24 +02:00
Philipp Oppermann
88fe633b87 Merge pull request #194 from phil-opp/better-exception-messages
New post: Better Exception Messages
2016-08-03 17:03:13 +02:00
Philipp Oppermann
3312478f71 Include “Better Exception Messages” in README 2016-08-03 17:00:18 +02:00
Philipp Oppermann
60a58a8c9c Fix github tag link 2016-08-03 17:00:18 +02:00
Philipp Oppermann
2b629415a4 Final improvements 2016-08-03 17:00:18 +02:00
Philipp Oppermann
d13460812d Run rustfmt 2016-08-03 17:00:18 +02:00
Philipp Oppermann
a9319ea83e Translate error code and print cr2 register 2016-08-03 17:00:18 +02:00
Philipp Oppermann
69f1b58bb0 Add and test a handler_with_error_code macro and a page fault handler 2016-08-03 17:00:18 +02:00
Philipp Oppermann
df1e39edb2 Add and test an invalid opcode handler function 2016-08-03 17:00:18 +02:00
Philipp Oppermann
71ebb23ec3 Add a handler macro that creates wrapper functions 2016-08-03 17:00:18 +02:00
Philipp Oppermann
e7ee1faaba Add a wrapper function and print the exception stack frame 2016-08-03 17:00:18 +02:00
Philipp Oppermann
d97a8a3210 Silence dead code warnings 2016-08-03 17:00:18 +02:00
Philipp Oppermann
297f8442b9 Reset src to master to be able to follow step-by-step 2016-08-03 17:00:18 +02:00
Philipp Oppermann
398ba7a424 Provoke a page fault 2016-08-03 17:00:18 +02:00
Philipp Oppermann
261f92e2e5 Print cr2 in page_fault_handler 2016-08-03 17:00:18 +02:00
Philipp Oppermann
1ba595aab3 Rename to better-exception-messages 2016-08-03 17:00:18 +02:00
Philipp Oppermann
710cebe695 Finish exceptions diagnostics post 2016-08-03 17:00:18 +02:00
Philipp Oppermann
e9d2d594ab Add handler! macros 2016-08-03 17:00:18 +02:00
Philipp Oppermann
f14876dfff Next section: Debug the failure on real hardware 2016-08-03 17:00:18 +02:00
Philipp Oppermann
b1de7a9100 Add a ToC 2016-08-03 17:00:18 +02:00
Philipp Oppermann
40b565947b Test the two-stage exception handler in code 2016-08-03 17:00:18 +02:00
Philipp Oppermann
e8220b3781 Describe the two-stage exception handler 2016-08-03 17:00:18 +02:00
Philipp Oppermann
2e0f4f9161 Begin code for upcoming post 2016-08-03 17:00:11 +02:00
Philipp Oppermann
8d27acd15a Add images for “Better Exception Messages” post 2016-08-03 16:45:32 +02:00
Philipp Oppermann
95c0452bcb Begin new post 2016-08-03 14:44:52 +02:00
Philipp Oppermann
68e2495d9c Rename modifying-page-tables.md to page-tables.md 2016-08-03 14:43:01 +02:00
Philipp Oppermann
3b515229bb Center images 2016-07-30 15:07:22 +02:00
Philipp Oppermann
439aa861e7 Merge pull request #191 from phil-opp/hugo-toc
Display a Table of Contents on large displays
2016-07-28 20:18:28 +02:00
Philipp Oppermann
35c083122e Add function to automatically add/rm the coarse class
Based on viewport height. Automatically adjusted onresize.
2016-07-28 19:53:27 +02:00
Philipp Oppermann
46bb485621 Don't do anything if there's no #toc 2016-07-28 19:52:43 +02:00
Philipp Oppermann
226c0ccdfc Hide sublists of coarse in CSS instead of JS 2016-07-28 19:52:43 +02:00
Philipp Oppermann
fda5851e7c Fade out ToC when it's not hovered 2016-07-28 19:52:43 +02:00
Philipp Oppermann
7e2878aba7 Reposition Toc and tweak width and line-height 2016-07-28 19:52:43 +02:00
Philipp Oppermann
9469dc5891 Remove coarse class from ToCs
We will add it dynamically via javascript when the Toc is higher than the viewport.
2016-07-28 19:42:37 +02:00
Anton Strömkvist
6b2f1281ae Fix hex constant (#193)
I assume these were in the wrong order since all the others looked this way :)
2016-07-28 18:01:42 +02:00
Philipp Oppermann
826e303ed0 Merge pull request #192 from phil-opp/post-toc
Add tables of contents to all blog posts
2016-07-17 17:14:50 +02:00
Philipp Oppermann
d4e82b0aa4 Improve heading levels 2016-07-17 17:10:42 +02:00
Philipp Oppermann
bc6f496eb5 Add tables of contents to all blog posts 2016-07-17 17:10:23 +02:00
Philipp Oppermann
05d74786f9 Move ToC initialization code into own js file 2016-07-17 16:44:45 +02:00
Philipp Oppermann
0f72384ed9 Create the “Table of Contents” heading in javascript 2016-07-17 16:42:21 +02:00
Philipp Oppermann
f4b84d55e2 Fixate the ToC on the left side and show only on wide screens 2016-07-17 16:23:42 +02:00
Philipp Oppermann
4000c990f0 Add and initialize toc.js 2016-07-17 16:23:13 +02:00
Philipp Oppermann
62dd13b2e7 Merge pull request #190 from phil-opp/p1
Add aligned .got and .got.plt sections to linker script
2016-07-16 17:22:25 +02:00
Philipp Oppermann
68c1e42356 Update linker script in post (add .got and .got.plt) 2016-07-14 18:11:58 +02:00
Philipp Oppermann
2445b47661 Add aligned .got and .got.plt sections to linker script 2016-07-14 18:07:26 +02:00
Philipp Oppermann
a8534a7bd7 Remove additional-resource page and feed as well 2016-07-14 11:47:36 +02:00
Philipp Oppermann
03bdf35dd3 Add section page template because hugo requires it
We don't want these pages and delete them in our update script anyway. We just use the error 404 template in case the deletion doesn't work.
2016-07-14 11:37:20 +02:00
Philipp Oppermann
d64e4ba2fc Update x86 crate to 0.7.1 (#189) 2016-07-14 11:21:04 +02:00
Aaron Hill
48e7faa521 Add ENTRY(start) to 'Allocating Frames' blog post linker script (#188) 2016-06-29 09:19:08 +02:00
Philipp Oppermann
8ca12286f6 Replace page fault screenshots with divide-by-zero error screenshots 2016-06-25 17:30:26 +02:00
Philipp Oppermann
f8c5bc5dec Merge pull request #187 from phil-opp/divide_by_zero
Catch divide error instead of page fault
2016-06-25 17:13:29 +02:00
Philipp Oppermann
ca438d9740 Revise plans for the upcoming post 2016-06-25 17:12:04 +02:00
Philipp Oppermann
702e49eaf7 Catch divide-by-zero errors and introduce inline assembly
This commit updates the “Catching Exceptions” post to catch divide-by-zero errors instead of page faults. The reason is a subtle stack alignment bug, which is somehow caused by the additional error code on a page fault. This commit also adds a short introduction to inline assembly.
2016-06-25 17:12:04 +02:00
Philipp Oppermann
e8b3a1fff1 Catch divide error instead of page fault
The divide error pushes no error code. Thus we avoid stack misalignment (see #184).
2016-06-25 17:12:04 +02:00
Philipp Oppermann
c9d8afe434 Run rustfmt 2016-06-25 17:08:26 +02:00
Philipp Oppermann
2f9e6cc0d0 Minor improvements to catching exceptions post 2016-06-25 17:06:57 +02:00
Philipp Oppermann
84ba085a0a The section will be only about exceptions (#186) 2016-06-24 13:59:17 +02:00
Philipp Oppermann
b7a47ee001 Add gitter badge (#183) 2016-06-24 13:54:35 +02:00
Philipp Oppermann
e4cc5b84f1 Merge pull request #185 from phil-opp/unwind_resume
Create dummy _Unwind_Resume function to fix libcore linker errors
2016-06-24 13:44:54 +02:00
Philipp Oppermann
f00360d553 Add and explain dummy _Unwind_Resume function in “Set Up Rust” post 2016-06-24 13:37:03 +02:00
Philipp Oppermann
952f7ed5e3 Create dummy _Unwind_Resume function to fix libcore linker errors 2016-06-24 13:37:02 +02:00
Philipp Oppermann
7bd6030185 Rename “Interrupts” section to “Exceptions”
There will be some more posts about exceptions, so they get their own section.
2016-06-14 11:51:51 +02:00
Philipp Oppermann
76b83c623e Revert "Remove unneeded gcc_except_table section" (#180) 2016-06-13 18:36:01 +02:00
Philipp Oppermann
20d9037740 Merge pull request #178 from phil-opp/patch5
Remove unneeded gcc_except_table section
2016-06-12 16:36:00 +02:00
Philipp Oppermann
1fb6369f61 Remove unneeded gcc_except_table section from blog post 2016-06-12 16:33:55 +02:00
Philipp Oppermann
1083ac9bac Remove unneeded gcc_except_table section 2016-06-12 16:32:34 +02:00
Ryan Campbell
793eeebfb3 Add missing open brace (#177) 2016-06-10 20:36:33 +02:00
Steve Klabnik
1183f5d1e1 Update section header to reflect changes in the text (#176) 2016-06-07 21:48:54 +02:00
Philipp Oppermann
bddf35f365 Add missing link to bit_field crate (#174) 2016-06-01 01:21:16 +02:00
Jordan Danford
bf0e70746d Change 'boot load' to 'boot loop' in 'Remap the Kernel' section (#173) 2016-05-31 09:11:14 +02:00
Homu
c22e1e8bb1 Auto merge of #172 - phil-opp:phil-opp-patch-1, r=phil-opp
Recommend rustup instead of multirust
2016-05-30 23:58:02 +09:00
Philipp Oppermann
4fae6e4731 Recommend rustup instead of multirust 2016-05-30 16:57:28 +02:00
Philipp Oppermann
c52ba54077 Render additional resources at the end of index.html (#171) 2016-05-29 20:00:08 +02:00
Philipp Oppermann
c2336ceece Make cross-compile-* and set-up-gdb pages additional resourses 2016-05-29 19:58:44 +02:00
Philipp Oppermann
01f8d382e4 Add new addional-recourse content type, which is rendered with comments 2016-05-29 19:53:22 +02:00
Philipp Oppermann
2f0a3459ad Merge pull request #170 from phil-opp/cargo-panic-abort
Use the `panic=abort` option instead of `-Z no-landing-pads`
2016-05-29 18:49:30 +02:00
Philipp Oppermann
0f5ec6f129 Update “Kernel Heap”: The _Unwind_Resume linker error shouldn't occur anymore 2016-05-29 18:47:38 +02:00
Philipp Oppermann
5d13ff7c3a Add update note 2016-05-29 18:38:14 +02:00
Philipp Oppermann
d7b05bc6b4 Update “Set Up Rust” post to use the cargo panic option 2016-05-29 18:35:16 +02:00
Philipp Oppermann
f4eb589f19 We don't need _Unwind_Resume anymore 2016-05-29 18:00:58 +02:00
Philipp Oppermann
725c452157 Use the panic=abort option instead of -Z no-landing-pads 2016-05-29 18:00:29 +02:00
Philipp Oppermann
01f9f1056c Merge pull request #169 from phil-opp/missing-pub
Make methods of EntryOptions public
2016-05-29 17:26:48 +02:00
Philipp Oppermann
9ea7ee6f57 Make methods of EntryOptions public in post 2016-05-29 17:25:11 +02:00
Philipp Oppermann
480265872d Make methods of EntryOptions public 2016-05-29 17:24:21 +02:00
Philipp Oppermann
929e72c8a7 Add new “interrupts” section to index page (#165) 2016-05-28 16:03:42 +02:00
Philipp Oppermann
165bf096a7 Merge pull request #164 from phil-opp/catching-exceptions
Add new post about “Catching Exceptions”
2016-05-28 16:00:31 +02:00
Philipp Oppermann
11cc57b59d Add images for “Catching Exceptions” (#166) 2016-05-28 15:53:04 +02:00
Philipp Oppermann
8d7f3ab284 Use the “Consolas” font instead of “Courier New” for code blocks (#163) 2016-05-25 10:18:53 +02:00
Philipp Oppermann
4bb23e9687 Use latest go version (#157)
Use go 1.6
2016-05-07 15:01:20 +02:00
Philipp Oppermann
01f32ba33e Add missing anchorjs partial 2016-05-02 17:30:12 +02:00
Philipp Oppermann
5ec5a5828d Add automatic anchor symbols using anchorjs 2016-05-02 17:26:19 +02:00
Philipp Oppermann
e30f50019d Redirect from phil-opp.github.io 2016-05-02 17:19:19 +02:00
Philipp Oppermann
2d463d103a Use passed commit hash for update message (if any) 2016-05-02 16:08:48 +02:00
Philipp Oppermann
2dfbf77de9 Move update script to ci folder and add encrypted key 2016-05-02 15:08:50 +02:00
Philipp Oppermann
5f62015c2d Use post feed as main feed 2016-05-01 15:52:07 +02:00
Philipp Oppermann
3004d8d43d Add travis blog update script 2016-05-01 15:42:13 +02:00
Philipp Oppermann
b2e1f9bfdc Recreate CNAME 2016-05-01 15:26:35 +02:00
Philipp Oppermann
a5ed209fe9 Add prev/next links 2016-05-01 12:53:03 +02:00
Philipp Oppermann
6a4dbe8446 Revert "Remove `plainIDAnchors option"
This reverts commit 7343fc7a50.
2016-05-01 12:33:56 +02:00
Philipp Oppermann
a5c1a2da88 Update gitignore for hugo 2016-05-01 11:59:45 +02:00
Philipp Oppermann
a4b623d734 Add .nojekyll 2016-05-01 11:58:48 +02:00
Philipp Oppermann
66a588efd6 Add RSS link 2016-04-30 14:31:24 +02:00
Philipp Oppermann
e0ce3a6774 Add disqus comments 2016-04-30 14:30:43 +02:00
Philipp Oppermann
4c42c961ac Add google analytics 2016-04-30 14:30:11 +02:00
Philipp Oppermann
1c01e74d3a Set base url 2016-04-30 14:29:43 +02:00
Philipp Oppermann
2d128620c6 Recreate bare-bones and memory-management sections 2016-04-30 13:32:13 +02:00
Philipp Oppermann
4e0ce25794 Add updated date 2016-04-30 13:31:21 +02:00
Philipp Oppermann
87e21bf6e7 Remove date from post teasers 2016-04-30 13:30:37 +02:00
Philipp Oppermann
885b39acf0 Fix footer (missing </div>) and add link to contact page 2016-04-30 13:28:41 +02:00
Philipp Oppermann
d447d2cad9 Add favicon 2016-04-30 13:25:43 +02:00
Philipp Oppermann
cba4c16fb6 Fix travis build (provide content dir) 2016-04-30 13:16:33 +02:00
Philipp Oppermann
7343fc7a50 Remove `plainIDAnchors option 2016-04-30 13:15:25 +02:00
Philipp Oppermann
60c7f51747 Move allocator images to correct directory 2016-04-25 23:46:09 +02:00
Philipp Oppermann
cb3ed425c8 Display only posts on front page and start category separation 2016-04-25 23:42:51 +02:00
Philipp Oppermann
7e05690ad8 Add page layout and url format 2016-04-25 23:41:50 +02:00
Philipp Oppermann
aa3d53f800 Use slug instead of filename 2016-04-25 23:07:24 +02:00
Philipp Oppermann
fc3d445c3f Use blog directory in main folder as contentdir 2016-04-25 23:07:24 +02:00
Philipp Oppermann
e8520b665c Images should not be wider than the main container 2016-04-25 23:07:23 +02:00
Philipp Oppermann
97c3680013 Use plain ID anchors 2016-04-25 23:07:23 +02:00
Philipp Oppermann
ea7f21a392 Experimental travis file 2016-04-25 23:07:23 +02:00
Philipp Oppermann
c65e98fd86 Add images again 2016-04-25 23:07:23 +02:00
Philipp Oppermann
e0d966ffdd Use ugly URLs to fit old ULR scheme 2016-04-25 23:07:23 +02:00
Philipp Oppermann
3fa7a72e9d Revert "Add lorem ipsum post for testing"
This reverts commit 090fb773b2f7ff1ac161c62988a6d381ee472f66.
2016-04-25 23:07:23 +02:00
Philipp Oppermann
50f4657c0a Add a 404 page 2016-04-25 23:07:23 +02:00
Philipp Oppermann
d905f5209b Don't wrap code blocks 2016-04-25 23:07:23 +02:00
Philipp Oppermann
dc099ae621 Add syntax highlighting using pygments 2016-04-25 23:07:23 +02:00
Philipp Oppermann
5f3ff4904e Order posts by date (ascending) 2016-04-25 23:07:23 +02:00
Philipp Oppermann
f6d3494d66 Fix css links (.RSSlink seems to be broken)
See spf13/hugo#1147
2016-04-25 23:07:23 +02:00
Philipp Oppermann
05ae323d0f Include author email and copyright in config (for rss) 2016-04-25 23:07:23 +02:00
Philipp Oppermann
93bed0a54a Add margin to subtitle 2016-04-25 23:07:23 +02:00
Philipp Oppermann
24a65dc8ff Use variable for year in footer 2016-04-25 23:07:23 +02:00
Philipp Oppermann
269fd36df4 Fix margings for introduction 2016-04-25 23:07:23 +02:00
Philipp Oppermann
a708ffd037 Make the main container a bit wider 2016-04-25 23:07:23 +02:00
Philipp Oppermann
5aaab11022 Make text a bit smaller 2016-04-25 23:07:23 +02:00
Philipp Oppermann
6c01e8039c Add poole css 2016-04-25 23:07:23 +02:00
Philipp Oppermann
6c5b577b88 Add teaser layout for posts 2016-04-25 23:07:23 +02:00
Philipp Oppermann
6be428b248 Add index.html 2016-04-25 23:07:23 +02:00
Philipp Oppermann
840ed0097a Add layout for post 2016-04-25 23:07:23 +02:00
Philipp Oppermann
fc6653d780 Add partial layouts for header and footer 2016-04-25 23:07:23 +02:00
Philipp Oppermann
bccf9f9166 Add lorem ipsum post for testing 2016-04-25 23:07:23 +02:00
Philipp Oppermann
f740789dba Set some configuration variables 2016-04-25 23:07:23 +02:00
Philipp Oppermann
7059b2f6a6 Replace jekyll site with new hugo site 2016-04-25 23:07:23 +02:00
travis-update-bot
298c9dc694 Update blog to 0d539a6dae 2016-04-25 14:52:58 +00:00
travis-update-bot
c1f1121512 Update blog to 9e74969732 2016-04-12 07:45:16 +00:00
Philipp Oppermann
5cb498856b Include “Kernel Heap” post in memory management section 2016-04-11 18:25:48 +02:00
Philipp Oppermann
08f2fee638 Add graphics for “Kernel Heap” post 2016-04-11 18:13:44 +02:00
travis-update-bot
236f120cba Update blog to 05f76f525c 2016-03-06 14:05:13 +00:00
travis-update-bot
00a6697680 Update blog to 23df363136 2016-02-24 16:42:48 +00:00
travis-update-bot
adc401206d Update blog to c145f9f1d1 2016-02-24 16:25:13 +00:00
travis-update-bot
54c4f674c8 Update blog to 3b7638bb1d 2016-02-24 16:05:02 +00:00
travis-update-bot
b32aab82db Update blog to 75aa669cdb 2016-02-22 06:32:10 +00:00
travis-update-bot
a6d9988151 Update blog to ac9044bd96 2016-02-13 21:48:40 +00:00
travis-update-bot
5c12fc6cde Update blog to d321982755 2016-02-05 09:54:57 +00:00
travis-update-bot
21708b3a15 Update blog to 75bd3c8785 2016-02-04 16:11:35 +00:00
travis-update-bot
79ec86489b Update blog to 937224a2c7 2016-02-02 22:14:23 +00:00
Philipp Oppermann
d127ee9954 Remove deprecated relative_permalinks option 2016-02-02 22:22:19 +01:00
Philipp Oppermann
21f862b325 Redirect from phil-opp.github.io/blog_os 2016-02-02 21:04:01 +01:00
travis-update-bot
e431e59d78 Update blog to 7b16d80d98 2016-01-27 16:45:19 +00:00
travis-update-bot
5221d4a4cf Update blog to df72565933 2016-01-20 13:44:06 +00:00
travis-update-bot
ed41966300 Update blog to 954ec78a44 2016-01-19 23:16:49 +00:00
travis-update-bot
f61e070d88 Update blog to 23ee000f70 2016-01-19 22:56:42 +00:00
travis-update-bot
ca3a71a4dc Update blog to 49b78f59e2 2016-01-19 22:28:04 +00:00
Philipp Oppermann
38e0eedcc6 Merge pull request #119 from phil-opp/introduction
Add an introduction to the front page
2016-01-19 22:23:10 +01:00
Philipp Oppermann
230668fa05 Revert "Add bing webmaster authentication code"
This reverts commit 771cfd76b1.
2016-01-19 22:20:32 +01:00
Philipp Oppermann
771cfd76b1 Add bing webmaster authentication code 2016-01-19 22:19:59 +01:00
Philipp Oppermann
5a4e5288f0 Formatting 2016-01-19 22:05:00 +01:00
Philipp Oppermann
d47af70e51 Shorten the introduction 2016-01-19 22:03:01 +01:00
travis-update-bot
fc95bf1ac9 Update blog to 86d27933ff 2016-01-19 12:09:28 +00:00
Philipp Oppermann
0f334f5da2 Add an introduction to the front page 2016-01-19 00:56:05 +01:00
Philipp Oppermann
23523189cb Decrease the maximal page width for readability 2016-01-19 00:55:26 +01:00
Philipp Oppermann
1d7b913a1a Add automatic anchor symbols using anchorjs 2016-01-17 15:22:42 +01:00
travis-update-bot
82e230c257 Update blog to a6632af0b6 2016-01-17 12:27:53 +00:00
travis-update-bot
f3f5a901a5 Update blog to 1284ea3657 2016-01-14 13:57:55 +00:00
travis-update-bot
9c5773d94d Update blog to 0c45cf1b97 2016-01-14 13:45:48 +00:00
travis-update-bot
618866234e Update blog to 16eef8e945 2016-01-14 08:38:44 +00:00
travis-update-bot
8d00795640 Update blog to e320e4d1d9 2016-01-10 11:54:43 +00:00
travis-update-bot
90aded2bad Update blog to 43a86e7b86 2016-01-04 23:15:43 +00:00
Philipp Oppermann
2f72b0d173 Update qemu screenshot for qemu -cdrom
See #103
2016-01-02 16:52:21 +01:00
travis-update-bot
aa91bf7f2d Update blog to a338bf5d98 2016-01-02 15:36:55 +00:00
travis-update-bot
6c81a67a65 Update blog to d57657ac29 2016-01-02 15:12:00 +00:00
Philipp Oppermann
15873b8448 Include Remap the Kernel post in memory management category 2016-01-01 18:41:06 +01:00
travis-update-bot
cf7a19adef Update blog to 980c94202f 2016-01-01 17:36:24 +00:00
Philipp Oppermann
6ad00195f5 Add more images for upcoming post 2015-12-31 15:01:27 +01:00
travis-update-bot
262aec97ae Update blog to 9bad9020f6 2015-12-30 23:07:52 +00:00
travis-update-bot
66417a1b72 Update blog to b11ed7bd46 2015-12-30 01:23:26 +00:00
Philipp Oppermann
9c193d432c Add gdb tui screenshot 2015-12-30 02:20:01 +01:00
Philipp Oppermann
4df4fab08f Add image for recursive mapping of inactive tables 2015-12-27 13:19:33 +01:00
Philipp Oppermann
30414dccf5 Highlight doc comments as well 2015-12-26 17:32:23 +01:00
Philipp Oppermann
b02b6144ac Add local config to disable disqus and analytics 2015-12-26 15:38:08 +01:00
travis-update-bot
0ba1cab5a0 Update blog to 6f3daa8a2a 2015-12-26 12:42:47 +00:00
travis-update-bot
790717db9a Update blog to 97d381198b 2015-12-26 03:38:35 +00:00
travis-update-bot
7bcd730c5f Update blog to 65d2f7e013 2015-12-25 12:19:31 +00:00
travis-update-bot
af2897fe12 Update blog to d28548fa10 2015-12-24 02:28:28 +00:00
Philipp Oppermann
935126b14c Add new set up gdb post to archive 2015-12-24 03:08:37 +01:00
travis-update-bot
64f45b3743 Update blog to d9eff3e50a 2015-12-24 02:08:04 +00:00
travis-update-bot
cf6b6ca787 Update blog to ad8e9da766 2015-12-23 11:52:19 +00:00
travis-update-bot
606211a8d5 Update blog to c19d176aa0 2015-12-20 15:07:15 +00:00
travis-update-bot
ec215ff4df Update blog to 74e84c7ea4 2015-12-20 15:00:35 +00:00
Philipp Oppermann
d162a1a930 Use darker colors again 2015-12-18 14:53:30 +01:00
Philipp Oppermann
a8f3712d12 Make category posts wider 2015-12-17 12:13:31 +01:00
Philipp Oppermann
0bdc4795a8 Make main area a bit wider 2015-12-17 12:12:53 +01:00
Philipp Oppermann
1eb62e8380 Revert "Make post categories wider again"
This reverts commit 653c87e145.
2015-12-17 12:05:22 +01:00
Philipp Oppermann
653c87e145 Make post categories wider again 2015-12-17 11:55:00 +01:00
Philipp Oppermann
aa06cd8bbd Change color for memory management category 2015-12-17 11:51:39 +01:00
Philipp Oppermann
d137b1e5fa Use lighter colors 2015-12-17 11:37:49 +01:00
Philipp Oppermann
99e026a7e0 Merge pull request #77 from phil-opp/categories
Add categories to front page
2015-12-17 11:27:49 +01:00
Philipp Oppermann
6cccace846 Tweak margins 2015-12-17 11:05:17 +01:00
Philipp Oppermann
5f8b058cd3 Add bare bones and memory management categories 2015-12-17 11:01:39 +01:00
Philipp Oppermann
f0cf691229 Disable pagination 2015-12-17 10:57:12 +01:00
travis-update-bot
2f5f122053 Update blog to 52f239e5b4 2015-12-16 13:12:19 +00:00
travis-update-bot
ff38d2aec9 Update blog to f00366d09f 2015-12-16 11:38:43 +00:00
Philipp Oppermann
5ee4fd1e4b Use Writing an OS in Rust title in atom feed 2015-12-14 01:40:53 +01:00
travis-update-bot
34b126b370 Update blog to bb0bd73584 2015-12-14 00:10:28 +00:00
Philipp Oppermann
2c6b8aed4f Delete old setup rust post 2015-12-14 00:25:45 +01:00
travis-update-bot
5e94142e7c Update blog to 3c6057dd76 2015-12-13 23:16:29 +00:00
travis-update-bot
14f2f1a967 Update blog to 7675a08ebe 2015-12-13 23:10:42 +00:00
travis-update-bot
2f637887e3 Update blog to 87b8fc6a29 2015-12-13 23:05:06 +00:00
travis-update-bot
fb4669eaca Update blog to 807e8110be 2015-12-13 18:42:35 +00:00
travis-update-bot
6f62dc6709 Update blog to 26fc76fbda 2015-12-12 14:05:05 +00:00
Philipp Oppermann
9c76819466 Fix numbering of bits
Closes #63
2015-12-10 20:24:05 +01:00
travis-update-bot
a605b9f822 Update blog to e272cc9257 2015-12-10 16:01:40 +00:00
travis-update-bot
4461e9c3c7 Update blog to 5cc6f9ec4b 2015-12-09 15:28:11 +00:00
Philipp Oppermann
d07fd8798b Add graphic for x86 address structure 2015-12-07 16:47:53 +01:00
Philipp Oppermann
3e0a08c2ee Update recursive map graphics 2015-12-07 01:38:56 +01:00
Philipp Oppermann
b7b8fff4d5 Fix image 2015-12-06 19:57:01 +01:00
Philipp Oppermann
d904b31783 Add another recursive mapping graphic 2015-12-06 19:50:56 +01:00
Philipp Oppermann
d1d9eaa14e Zoom image 2015-12-06 19:47:34 +01:00
Philipp Oppermann
dd6db1a571 Resize image 2015-12-06 19:35:33 +01:00
Philipp Oppermann
4d6613736d Add recursive mapping graphic 2015-12-06 19:33:05 +01:00
travis-update-bot
67146f2096 Update blog to f1f1e66dce 2015-12-03 17:45:37 +00:00
travis-update-bot
53d53bb648 Update blog to 0cfb38ee6e 2015-11-28 17:07:30 +00:00
travis-update-bot
f615b75d6b Update blog to 0a6a174e54 2015-11-23 23:20:42 +00:00
travis-update-bot
1e4beda09a Update blog to 9b6bb7f895 2015-11-23 23:11:13 +00:00
travis-update-bot
02a1eb4e27 Update blog to 43924afbbf 2015-11-23 22:45:43 +00:00
Philipp Oppermann
66d7cf802e Use relative links in archive 2015-11-23 23:38:55 +01:00
Philipp Oppermann
9def164db3 Add disqus to standard pages, too 2015-11-23 23:38:55 +01:00
travis-update-bot
7f5e356132 Update blog to 5137ad103a 2015-11-22 22:08:00 +00:00
travis-update-bot
cd83d97091 Update blog to cefe95dc88 2015-11-19 18:58:22 +00:00
travis-update-bot
8a75b88abd Update blog to 4e0071cf3d 2015-11-19 14:30:11 +00:00
travis-update-bot
3468c2378b Update blog to f4c61f7634 2015-11-19 14:25:26 +00:00
travis-update-bot
ec6b02ab95 Update blog to 25122bc05c 2015-11-16 14:18:36 +00:00
travis-update-bot
eab586b73b Update blog to fc856a55a6 2015-11-15 19:19:58 +00:00
travis-update-bot
7c952d83ac Update blog to eb93c94d6d 2015-11-15 19:14:44 +00:00
travis-update-bot
7c2bd760dd Update blog to f08b2cb340 2015-11-15 16:17:50 +00:00
travis-update-bot
4e2e94770c Update blog to e380129fde 2015-11-15 11:04:04 +00:00
travis-update-bot
ce170cad74 Update blog to b8d1dfd84d 2015-11-15 10:00:32 +00:00
Philipp Oppermann
0d15f92487 Add image for remapping-the-kernel post 2015-11-13 19:54:53 +01:00
travis-update-bot
ef8f4e2dac Update blog to 86d1ff145d 2015-11-13 17:07:48 +00:00
Philipp Oppermann
f7e3136845 Update code style to manni 2015-11-13 14:36:12 +01:00
Philipp Oppermann
1d35df58eb Revert _drafts symlink as github pages does not like invalid symlinks
This reverts commit cb85eca708.
2015-11-12 18:08:53 +01:00
Philipp Oppermann
cb85eca708 Add _drafts as a symbolic link to ../posts/
Allows to create a gh-pages worktree [1] in a subfolder and preview changes through `jekyll serve --drafts`. Note that already published posts are displayed twice.

[1]: https://git-scm.com/docs/git-worktree
2015-11-12 18:05:26 +01:00
Philipp Oppermann
2089c893fe Remove contact page from sitemap 2015-11-09 18:09:18 +01:00
Philipp Oppermann
835601fd48 Add a sitemap 2015-11-09 18:07:52 +01:00
Philipp Oppermann
4666e25404 Specify blog URL (for feed) 2015-11-07 15:44:08 +01:00
travis-update-bot
7b235adab2 Update blog to b9a35036e3 2015-11-07 00:15:50 +00:00
travis-update-bot
cb463cc70f Update blog to e8b6947555 2015-11-06 23:41:33 +00:00
Philipp Oppermann
ef0bdc6986 Change the title to “Writing an OS in Rust” 2015-11-06 19:59:03 +01:00
Philipp Oppermann
8a4ae0751d Change URL to os.phil-opp.com 2015-11-06 19:53:36 +01:00
Philipp Oppermann
237b0e8e6a Add a CNAME for rust-os.phil-opp.com 2015-11-06 19:48:03 +01:00
Philipp Oppermann
7ffaf1cac8 Update links to blog repository 2015-11-06 19:46:27 +01:00
Philipp Oppermann
ba5550aebb Remove rust-os category 2015-11-06 19:43:02 +01:00
Philipp Oppermann
870d858018 Remove CNAME 2015-11-06 19:33:57 +01:00
Philipp Oppermann
514bad2cbd Fix row/column number 2015-11-01 06:45:06 +01:00
Philipp Oppermann
dbce597de7 Suggest --verbose on grub-mkrescue problems 2015-10-31 14:31:13 +01:00
Philipp Oppermann
765e22db47 Add notes about required unstable features
Fixes phil-opp/blog_os#19
2015-10-31 14:19:05 +01:00
Philipp Oppermann
175ed545b1 Emphazise that we're using 512 2MiB pages 2015-10-31 14:07:11 +01:00
Philipp Oppermann
7cfa96b72d Use mul instead of imul
See phil-opp/blog_os#21
2015-10-31 14:00:13 +01:00
Philipp Oppermann
44a8f72c28 Merge pull request phil-opp/phil-opp.github.io#13 from InPermutation/master
Fix typo and update line number of zip function
2015-10-31 13:43:03 +01:00
Jacob Krall
243abbe280 fn zip moved around in the latest nightly
line 654 is current as of 2e07996a9
2015-10-30 23:39:12 -04:00
Jacob Krall
8c45ffff6a Setup Rust: fix typo in attribute name 2015-10-30 22:08:20 -04:00
Philipp Oppermann
3453fbfa2f Fix non-breaking spaces 2015-10-30 12:10:20 +01:00
Philipp Oppermann
8ff462f831 typo 2015-10-30 11:56:16 +01:00
Philipp Oppermann
cb2a90ef2b typo 2015-10-29 19:36:04 +01:00
Philipp Oppermann
99be56f9b8 Display updated on for Entering Long Mode post 2015-10-29 19:28:32 +01:00
Philipp Oppermann
5dde1afc38 Merge pull request phil-opp/phil-opp.github.io#10 from phil-opp/2mib_pages
Update article to use 2MiB pages instead of 1GiB pages
2015-10-29 19:17:06 +01:00
Philipp Oppermann
77b766d669 Use 2MiB pages instead of 1GiB pages 2015-10-29 19:12:41 +01:00
Philipp Oppermann
cc10ea92c1 Refer to comments on grub-mkrescue issues 2015-10-29 15:01:29 +01:00
Philipp Oppermann
934e8369b6 Add a note about a xorriso version error on grub-mkrescue
fixes phil-opp/blog_os#16
2015-10-28 18:34:15 +01:00
Philipp Oppermann
5e60f6708e Link to cross-compile-binutils post in the other projects section 2015-10-27 23:37:54 +01:00
Philipp Oppermann
c5d459bd10 Clear screen before printing Hello World 2015-10-27 23:30:51 +01:00
Philipp Oppermann
e0955c6019 Add missing Copy explanation 2015-10-27 23:20:02 +01:00
Philipp Oppermann
f9325f5811 Some small improvements to sync post and code 2015-10-27 20:45:41 +01:00
Philipp Oppermann
592bae3f87 Rename multiboot section to multiboot_header
See phil-opp/blog_os#14
2015-10-27 18:45:37 +01:00
Philipp Oppermann
ba938a2aeb Merge pull request #8 from InPermutation/patch-1
“A minimal x86 kernel” fixes
2015-10-26 11:12:49 +01:00
Jacob Krall
3e59075d53 Explicitly rename copied kernel to kernel.bin
Otherwise your `grub.cfg` from earlier in the article will be out of date (we're producing `kernel-x86_64.bin`, but grub expects `kernel.bin`).
2015-10-26 00:54:30 -04:00
Jacob Krall
0a165becfe make iso depends on grub.cfg
This way, if you fix a typo in grub.cfg, you don't have to `make clean` to get `make iso` to pick it up.
2015-10-26 00:52:12 -04:00
Jacob Krall
93f042da4c typo 2015-10-25 23:51:55 -04:00
Philipp Oppermann
1b6d39f998 Update contact page 2015-10-25 16:56:56 +01:00
Philipp Oppermann
daa2bcc1fe Merge pull request phil-opp/phil-opp.github.io#6 from phil-opp/printing_to_screen_repr_c
Add repr(C) attribute to ScreenChar
2015-10-25 15:55:13 +01:00
Philipp Oppermann
07fdd581d8 Add repr(C) attribute to ScreenChar
see phil-opp/blog_os#8
2015-10-25 15:52:22 +01:00
Philipp Oppermann
d017999722 Add a RSS link 2015-10-25 15:05:04 +01:00
Philipp Oppermann
8aaa0105c3 Include subtitle in RSS feed 2015-10-25 15:04:44 +01:00
Philipp Oppermann
d8746e116d Remove redirect for /contact 2015-10-25 14:30:08 +01:00
Philipp Oppermann
a2cebb7fcb Don't break subtitle partially 2015-10-25 14:22:16 +01:00
Philipp Oppermann
f48ebb3961 Add a subtitle: Writing an OS in Rust 2015-10-25 14:07:40 +01:00
Philipp Oppermann
76ea95acf5 Fix test_long_mode (closes #4) 2015-10-25 01:55:31 +02:00
Philipp Oppermann
ca9c3fdcf4 Don't crawl the contact page 2015-10-25 01:36:22 +02:00
Philipp Oppermann
145c7a2285 Include cross compiling posts in archive + redesign 2015-10-24 21:12:04 +02:00
Philipp Oppermann
955f30a2a4 Merge pull request phil-opp/phil-opp.github.io#5 from phil-opp/cross-compile-libcore
Add page about libcore for cross compiling
2015-10-24 21:02:32 +02:00
Philipp Oppermann
edfe60d416 Add page about libcore for cross compiling 2015-10-24 17:21:54 +02:00
Philipp Oppermann
76372f82f4 Use target parameter when invoking cargo build/rustc
See phil-opp/blogOS#5.
2015-10-24 16:36:12 +02:00
Philipp Oppermann
a57d769687 Use non-breaking hyphens and emphasize not 2015-10-24 15:59:47 +02:00
Philipp Oppermann
01798b717f Some syntactical and whitespace fixes 2015-10-24 15:55:30 +02:00
Philipp Oppermann
710fa81c27 Add and link article about cross compiling binutils 2015-10-24 15:54:59 +02:00
Philipp Oppermann
2f64af811e Switch to none permalinks and setup redirects 2015-10-24 14:53:48 +02:00
Philipp Oppermann
9497fc853e Update contact page 2015-10-23 18:04:31 +02:00
Philipp Oppermann
c223ae604a Remove ads 2015-10-23 17:51:53 +02:00
Philipp Oppermann
cad0065e74 Fix wording 2015-10-23 13:03:58 +02:00
Philipp Oppermann
29fa352663 Merge pull request phil-opp/phil-opp.github.io#3 from phil-opp/printing_wip
Finish and publish post about printing to screen
2015-10-23 12:48:18 +02:00
Philipp Oppermann
4efb3c1eae Publish poist about printing to screen 2015-10-23 01:47:26 +02:00
Philipp Oppermann
44f512a90c Add section about other Rust OS projects 2015-10-23 01:44:05 +02:00
Philipp Oppermann
9b61ace59d Rework What's next? 2015-10-23 01:43:47 +02:00
Philipp Oppermann
47ffda304d Use println to print hello world 2015-10-23 01:43:05 +02:00
Philipp Oppermann
cc73673305 Improve macro subsection 2015-10-23 01:42:40 +02:00
Philipp Oppermann
6602332094 Update introduction 2015-10-23 01:42:03 +02:00
Philipp Oppermann
8d90933c01 Update introduction 2015-10-22 16:06:30 +02:00
Philipp Oppermann
fd889d8613 Add an introduction for the VGA buffer post 2015-10-14 10:46:55 +02:00
Philipp Oppermann
4fd71fc295 Increase updated highlight to 2s 2015-10-07 16:09:22 +02:00
Philipp Oppermann
ec053b2586 Revise and extend post about printing to screen 2015-10-06 18:15:10 +02:00
Philipp Oppermann
61908ce94f Revise rust setup post 2015-10-06 17:07:08 +02:00
Philipp Oppermann
282206e3ff Update repository URL (it was renamed to blog_os) 2015-10-06 16:18:44 +02:00
Philipp Oppermann
99a3979c68 Point repository directly to subdirectory 2015-10-06 15:46:52 +02:00
Philipp Oppermann
7ddb202d70 Revise and reformat long mode post 2015-10-06 15:40:36 +02:00
Philipp Oppermann
ae339d3c59 Don't use upper case for long mode etc. 2015-10-06 14:29:45 +02:00
Philipp Oppermann
db18395f48 Revise first post 2015-10-06 12:48:24 +02:00
Philipp Oppermann
bc30771243 Use correct exception number 2015-10-06 00:30:14 +02:00
Philipp Oppermann
427ad8dcf1 Tweak latest post highlight
Tweak JS to work on a 2nd click, too. Tweak CSS for shorter highlight and linear transition.
2015-10-06 00:17:22 +02:00
Philipp Oppermann
e24f30d86c Highlight latest post when link is clicked 2015-10-04 20:21:26 +02:00
Philipp Oppermann
445b50ce77 Update title and tagline 2015-10-04 20:20:25 +02:00
Philipp Oppermann
0c7100ca7d Add subsection for stack creation 2015-10-03 19:05:48 +02:00
Philipp Oppermann
0324241ea1 Merge pull request phil-opp/phil-opp.github.io#2 from phil-opp/better_hello_world
Rewrite Hello World section and update its code
2015-10-03 19:01:26 +02:00
Philipp Oppermann
5c4bb91592 Use new Hello World! code and rewrite its section
See phil-opp/blogOS#4 for the new `Hello World!`.
2015-10-03 18:52:51 +02:00
Philipp Oppermann
4bfd933522 Improve phrasing 2015-10-03 18:50:48 +02:00
Philipp Oppermann
93a7bb6333 many improvements 2015-09-27 18:05:43 +02:00
Philipp Oppermann
517c5eab0d Some wording improvements 2015-09-26 13:25:33 +02:00
Philipp Oppermann
9d34da7c13 WIP 2015-09-15 15:26:31 +02:00
Philipp Oppermann
6b29a31ae9 Rename main to rust_main
See phil-opp/blogOS#1.
2015-09-15 15:21:18 +02:00
Philipp Oppermann
4523352e05 Add missing links 2015-09-15 15:11:38 +02:00
Philipp Oppermann
d34c7a5730 Rename file for setup rust post 2015-09-10 15:35:34 +02:00
Philipp Oppermann
faf04f65c6 Many wording improvements 2015-09-10 15:34:43 +02:00
Philipp Oppermann
76d21f0e99 replace wrong uses of like 2015-09-10 14:48:09 +02:00
Philipp Oppermann
b021fe49bf replace e.g. with for example 2015-09-10 14:47:39 +02:00
Philipp Oppermann
5aabcfa38d Many wording improvements 2015-09-10 14:19:14 +02:00
Philipp Oppermann
d0c7d4d3d1 Wording: replace check with test 2015-09-10 12:50:00 +02:00
Philipp Oppermann
47b21253ec Add newline code and println! section 2015-08-30 10:36:19 +02:00
Philipp Oppermann
73377ca504 Improve code and fix headings 2015-08-30 10:35:02 +02:00
Philipp Oppermann
ce16d32e81 Add draft about printing to screen 2015-08-26 18:11:50 +02:00
Philipp Oppermann
a4bcdefbd5 Pre-publish rust setup post 2015-08-25 17:40:49 +02:00
Philipp Oppermann
41d04687d9 Shorten titles 2015-08-25 17:39:43 +02:00
Philipp Oppermann
d83a2eb130 Redesign index page to show posts in chronological order 2015-08-25 17:22:07 +02:00
Philipp Oppermann
589f540b28 Add posts to rust-os category 2015-08-25 17:09:14 +02:00
Philipp Oppermann
87f36584c2 Use jekyll features to link to next/previous posts 2015-08-25 17:07:40 +02:00
Philipp Oppermann
1e831e2266 Publish long mode post 2015-08-25 15:43:15 +02:00
Philipp Oppermann
79ac1effd6 Add hello world section 2015-08-25 15:35:33 +02:00
Philipp Oppermann
2a58061641 Many small improvements 2015-08-25 15:35:05 +02:00
Philipp Oppermann
ce26218d1f Add section about the _Unwind_Resume issue 2015-08-25 15:33:54 +02:00
Philipp Oppermann
997c8ef8f9 Create an introduction and the rust setup section 2015-08-25 15:31:51 +02:00
Philipp Oppermann
0503c59198 Move 64-bit assembly to own file 2015-08-22 15:25:12 +02:00
Philipp Oppermann
5b09bda567 Remove debugging section again
This post is long enough and it fits better in the next post.
2015-08-22 15:23:08 +02:00
Philipp Oppermann
e4c1acec4e Add rust setup draft 2015-08-22 15:21:54 +02:00
Philipp Oppermann
9198e224ef Updated date of long mode post 2015-08-19 00:59:58 +02:00
Philipp Oppermann
57a156d9bd Add QEMU debugging section 2015-08-19 00:57:40 +02:00
Philipp Oppermann
952452aa38 Many additional explanations, rewordings, and fixes 2015-08-19 00:56:34 +02:00
Philipp Oppermann
08d9c7da5b Small wording improvements 2015-08-18 20:33:25 +02:00
Philipp Oppermann
9447a054a3 Publish first post (minimal multiboot kernel) 2015-08-18 20:20:55 +02:00
Philipp Oppermann
003b9d347c Add links to next and previous post 2015-08-18 20:05:25 +02:00
Philipp Oppermann
ed5ace118b Some small improvements 2015-08-13 11:58:17 +02:00
Philipp Oppermann
726b8b65b6 Add virtual address translation graphic 2015-08-13 11:34:02 +02:00
Philipp Oppermann
f064d4415f Shorten the link text for the Wikipedia image source. 2015-08-12 19:55:12 +02:00
Philipp Oppermann
f3f78697f5 Add draft for Long Mode post 2015-08-12 19:35:23 +02:00
Philipp Oppermann
333c95faac Link to specific tag in repository 2015-08-10 13:25:00 +02:00
Philipp Oppermann
2e0fa08605 Uncapitalize BITS for consistency (and move it after section) 2015-08-10 13:07:52 +02:00
Philipp Oppermann
e38f3cfe52 Fix markdown: Add required newline before list 2015-08-06 12:02:34 +02:00
Philipp Oppermann
002c97402c Add link to source repository 2015-08-06 12:01:49 +02:00
Philipp Oppermann
826e489fe1 Delete example post 2015-08-02 19:15:33 +02:00
Philipp Oppermann
fdb6ef2edf Improve wording and extend some explanations 2015-07-31 19:40:11 +02:00
Philipp Oppermann
4bf8f08a55 Add section about build automation 2015-07-31 19:37:44 +02:00
Philipp Oppermann
6895314ae0 Add an indroduction and a real title 2015-07-31 19:37:21 +02:00
Philipp Oppermann
6ee4267be6 Move footnotes and link targets to associated sections
Improve some wording on the way
2015-07-31 19:36:23 +02:00
Philipp Oppermann
de7113b428 add hr after post and ad 2015-07-28 17:53:34 +02:00
Philipp Oppermann
3aea2c209f add disqus and show adsense only on posts 2015-07-28 17:48:03 +02:00
Philipp Oppermann
fe9e7e9eae extend booting section 2015-07-31 19:22:21 +02:00
Philipp Oppermann
5b0a8cf468 Improve wording and code 2015-07-31 19:20:46 +02:00
Philipp Oppermann
ee38c185ce Add Boot Code and building sections 2015-07-31 19:19:56 +02:00
Philipp Oppermann
0e73acda14 Improve naming and wording 2015-07-31 19:18:52 +02:00
Philipp Oppermann
9588bbe5ff add multiboot section 2015-07-23 16:00:43 +02:00
Philipp Oppermann
72f8e122fa add draft for testing 2015-07-23 15:50:34 +02:00
Philipp Oppermann
ea4d8f0056 remove related posts 2015-07-22 19:29:56 +02:00
Philipp Oppermann
c8d4693fea remove two example posts 2015-07-22 19:10:50 +02:00
Philipp Oppermann
5004c2cbe3 new site generated by poole 2015-07-22 14:38:46 +02:00
Philipp Oppermann
5afd95a22d ignore _site directory 2015-07-19 14:27:53 +02:00
Philipp Oppermann
a1368cd51a add example post 2015-07-19 14:27:02 +02:00
Philipp Oppermann
4d618ac374 add style for navigation list 2015-07-19 14:26:37 +02:00
Philipp Oppermann
8cf1bd68bc add and use default layout 2015-07-19 14:26:01 +02:00
Philipp Oppermann
ba22982704 add test advertising block 2015-07-18 20:09:55 +02:00
Philipp Oppermann
c1b8aa2161 Replace master branch with page content via GitHub 2015-07-18 17:46:34 +02:00
Philipp Oppermann
bb304bb66f Merge pull request phil-opp/phil-opp.github.io#1 from phil-opp/cname
add CNAME for blog.phil-opp.com
2015-07-17 11:38:15 +02:00
Philipp Oppermann
4d1f47308b Replace master branch with page content via GitHub 2015-07-17 01:46:48 +02:00
Philipp Oppermann
2afe2add5f add CNAME for blog.phil-opp.com 2015-07-17 00:45:16 +02:00
Philipp Oppermann
34edd3497e Initial commit 2015-07-17 00:41:44 +02:00
379 changed files with 65815 additions and 3415 deletions

13
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
# These are supported funding model platforms
github: [phil-opp] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
custom: ['https://donorbox.org/phil-opp'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
patreon: phil_opp # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: phil-opp # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username

107
.github/workflows/blog.yml vendored Normal file
View File

@@ -0,0 +1,107 @@
name: Blog
on:
push:
branches:
- '*'
- '!staging.tmp'
tags:
- '*'
pull_request:
schedule:
- cron: '0 0 1/4 * *' # every 4 days
jobs:
build_site:
name: "Zola Build"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: 'Download Zola'
run: curl -sL https://github.com/getzola/zola/releases/download/v0.19.0/zola-v0.19.0-x86_64-unknown-linux-gnu.tar.gz | tar zxv
- name: 'Install Python Libraries'
run: python -m pip install --user -r requirements.txt
working-directory: "blog"
- name: "Run before_build.py script"
run: python before_build.py
working-directory: "blog"
- name: "Build Site"
run: ../zola build
working-directory: "blog"
- name: Upload Generated Site
uses: actions/upload-artifact@v4
with:
name: generated_site
path: blog/public
check_spelling:
name: "Check Spelling"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Typo Check
uses: crate-ci/typos@v1.1.9
with:
files: blog
deploy_site:
name: "Deploy Generated Site"
runs-on: ubuntu-latest
needs: [build_site, check_spelling]
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')
steps:
- name: "Download Generated Site"
uses: actions/download-artifact@v4
with:
name: generated_site
path: generated_site
- name: Setup SSH Keys and known_hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan github.com >> ~/.ssh/known_hosts
ssh-agent -a $SSH_AUTH_SOCK > /dev/null
ssh-add - <<< "$deploy_key"
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK" >> $GITHUB_ENV
env:
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
deploy_key: ${{ secrets.DEPLOY_SSH_KEY }}
- name: "Clone blog_os_deploy Repo"
run: git clone git@github.com:phil-opp/blog_os_deploy.git --branch gh-pages
- name: "Set Up Git Identity"
run: |
git config --local user.name "GitHub Actions Deploy"
git config --local user.email "github-actions-deploy@phil-opp.com"
working-directory: "blog_os_deploy"
- name: "Delete Old Content"
run: "rm -r ./*"
working-directory: "blog_os_deploy"
- name: "Add New Content"
run: cp -r generated_site/* blog_os_deploy
- name: "Commit New Content"
run: |
git add .
git commit --allow-empty -m "Deploy ${GITHUB_SHA}
Deploy of commit https://github.com/phil-opp/blog_os/commit/${GITHUB_SHA}"
working-directory: "blog_os_deploy"
- name: "Show Changes"
run: "git show"
working-directory: "blog_os_deploy"
- name: "Push Changes"
run: "git push"
working-directory: "blog_os_deploy"

27
.github/workflows/check-links.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Check Links
on:
push:
branches:
- "*"
- "!staging.tmp"
tags:
- "*"
pull_request:
schedule:
- cron: "0 0 1/4 * *" # every 4 days
jobs:
zola_check:
name: "Zola Link Check"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: "Download Zola"
run: curl -sL https://github.com/getzola/zola/releases/download/v0.19.0/zola-v0.19.0-x86_64-unknown-linux-gnu.tar.gz | tar zxv
- name: "Run zola check"
run: ../zola check
working-directory: "blog"

33
.github/workflows/scheduled-builds.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Build code on schedule
on:
schedule:
- cron: '40 1 * * *' # every day at 1:40
jobs:
trigger-build:
name: Trigger Build
strategy:
matrix:
branch: [
post-01,
post-02,
post-03,
post-04,
post-05,
post-06,
post-07,
post-08,
post-09,
post-10,
post-11,
post-12,
]
runs-on: ubuntu-latest
steps:
- name: Invoke workflow
uses: benc-uk/workflow-dispatch@v1.1
with:
workflow: Code
token: ${{ secrets.SCHEDULED_BUILDS_TOKEN }}
ref: ${{ matrix.branch }}

15
.gitignore vendored
View File

@@ -1,14 +1 @@
# Compiled files
*.o
*.so
*.rlib
*.dll
# Executables
*.exe
# Generated by Cargo
/target/
# Build directory
/build/
code

View File

@@ -1,24 +0,0 @@
language: rust
rust:
- nightly
sudo: false
notifications:
email:
on_success: never
on_failure: change
addons:
apt:
packages:
- nasm
script: bash scripts/travis-build.sh
after_success: bash scripts/travis-trigger-hugo-build.sh
env:
global:
secure: YQvZpLe32k8N+vLMa8PB80LKJdiD4WEUuw2lPFk3AJLSK6dojWq8MKjGuedxLvtmjURu401m7D06NFCjwd6j0dpR4L2xmVJ/EgufP2Wc62BUa2XvIIU/zURv0dFpGvaOTyHKl4j46SIk2LDugIzB1WyYRqeYTCpiN0xHuWsywXjPpCCJ04ftxHwrjYjzA8vvtyehjMeN4HC3J9r6anFlN9Ka7RFVSQ0Bun79pd6Xa/OPIxTsZuw24Ru4v458e4QxVh0atJif0lqmu5tZAeR/S0FTnG3XlKqfIYDmDWKJVKUwk6AHnsgaYAFASQhi9XOcr+cMir38/8k8FQpx80hjqkWXCZafUWuypgQnZOKS8K1oZLmMAQnrssM8HbMZEIYH40I8G5MqcpgPUvdwFO2PMGRNimMk6bEvrtheNwZn1XBTxgNOW4huCBoR0/E95FFGiTH5HL2kZi5N5+1EGJMdhPGjybIdJgawsAY2SOdw6rvHgf+ZMkJFBU2R9ftS88DHygMhkOifLDUq3GFPiFePNrE97LBFH3WN48fxPTcske00tAPTMcMGvw8zDBH4tZAHQikH6oMZFzKNQ0GvBTiKNvLMl1HaCcM/h1QmGXho4HtVD6PNrgOocdVxxXBcntQMVewkcr3hwDwaAZ/7+AqjeG9M+V2wEkI20Y4XYiq24HY=

View File

@@ -1,24 +0,0 @@
[package]
authors = ["Philipp Oppermann <dev@phil-opp.com>"]
name = "blog_os"
version = "0.1.0"
[dependencies]
bit_field = "0.1.0"
bitflags = "0.7.0"
once = "0.2.1"
rlibc = "0.1.4"
spin = "0.3.4"
[dependencies.hole_list_allocator]
path = "libs/hole_list_allocator"
[dependencies.multiboot2]
git = "https://github.com/phil-opp/multiboot2-elf64"
[dependencies.x86]
default-features = false
version = "0.7.0"
[lib]
crate-type = ["staticlib"]

View File

@@ -1,6 +1,6 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -174,28 +174,3 @@
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 Philipp Oppermann
Copyright (c) 2019 Philipp Oppermann
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View File

@@ -1,57 +0,0 @@
# Copyright 2015 Philipp Oppermann. See the README.md
# file at the top-level directory of this distribution.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
arch ?= x86_64
target ?= $(arch)-unknown-linux-gnu
kernel := build/kernel-$(arch).bin
iso := build/os-$(arch).iso
rust_os := target/$(target)/debug/libblog_os.a
linker_script := src/arch/$(arch)/linker.ld
grub_cfg := src/arch/$(arch)/grub.cfg
assembly_source_files := $(wildcard src/arch/$(arch)/*.asm)
assembly_object_files := $(patsubst src/arch/$(arch)/%.asm, \
build/arch/$(arch)/%.o, $(assembly_source_files))
.PHONY: all clean run debug iso cargo gdb
all: $(kernel)
clean:
@cargo clean
@rm -rf build
run: $(iso)
@qemu-system-x86_64 -cdrom $(iso) -s
debug: $(iso)
@qemu-system-x86_64 -cdrom $(iso) -s -S
gdb:
@rust-os-gdb/bin/rust-gdb "build/kernel-x86_64.bin" -ex "target remote :1234"
iso: $(iso)
$(iso): $(kernel) $(grub_cfg)
@mkdir -p build/isofiles/boot/grub
@cp $(kernel) build/isofiles/boot/kernel.bin
@cp $(grub_cfg) build/isofiles/boot/grub
@grub-mkrescue -o $(iso) build/isofiles 2> /dev/null
@rm -r build/isofiles
$(kernel): cargo $(rust_os) $(assembly_object_files) $(linker_script)
@ld -n --gc-sections -T $(linker_script) -o $(kernel) $(assembly_object_files) $(rust_os)
cargo:
@cargo rustc --target $(target) -- -Z no-landing-pads
# compile assembly files
build/arch/$(arch)/%.o: src/arch/$(arch)/%.asm
@mkdir -p $(shell dirname $@)
@nasm -felf64 $< -o $@

152
README.md
View File

@@ -1,41 +1,131 @@
# Blog OS
[![Build Status](https://travis-ci.org/phil-opp/blog_os.svg?branch=master)](https://travis-ci.org/phil-opp/blog_os)
This repository contains the source code for the _Writing an OS in Rust_ series at [os.phil-opp.com](http://os.phil-opp.com).
This repository contains the source code for the _Writing an OS in Rust_ series at [os.phil-opp.com](https://os.phil-opp.com).
## Bare Bones
- [A Minimal x86 Kernel](http://os.phil-opp.com/multiboot-kernel.html)
([source code](https://github.com/phil-opp/blog_os/tree/multiboot_bootstrap))
- [Entering Long Mode](http://os.phil-opp.com/entering-longmode.html)
([source code](https://github.com/phil-opp/blog_os/tree/entering_longmode))
- [Set Up Rust](http://os.phil-opp.com/set-up-rust.html)
([source code](https://github.com/phil-opp/blog_os/tree/set_up_rust))
- [Printing to Screen](http://os.phil-opp.com/printing-to-screen.html)
([source code](https://github.com/phil-opp/blog_os/tree/printing_to_screen))
If you have questions, open an issue or chat with us [on Gitter](https://gitter.im/phil-opp/blog_os).
## Memory Management
- [Allocating Frames](http://os.phil-opp.com/allocating-frames.html)
([source code](https://github.com/phil-opp/blog_os/tree/allocating_frames))
- [Page Tables](http://os.phil-opp.com/modifying-page-tables.html)
([source code](https://github.com/phil-opp/blog_os/tree/page_tables))
- [Remap the Kernel](http://os.phil-opp.com/remap-the-kernel.html)
([source code](https://github.com/phil-opp/blog_os/tree/remap_the_kernel))
- [Kernel Heap](http://os.phil-opp.com/kernel-heap.html)
([source code](https://github.com/phil-opp/blog_os/tree/kernel_heap))
## Where is the code?
## Interrupts
- [Catching Exceptions](http://os.phil-opp.com/catching-exceptions.html)
([source code](https://github.com/phil-opp/blog_os/tree/catching_exceptions))
The code for each post lives in a separate git branch. This makes it possible to see the intermediate state after each post.
## Additional Resources
- [Cross Compile Binutils](http://os.phil-opp.com/cross-compile-binutils.html)
- [Cross Compile libcore](http://os.phil-opp.com/cross-compile-libcore.html)
- [Set Up GDB](http://os.phil-opp.com/set-up-gdb.html)
**The code for the latest post is available [here][latest-post].**
## Building
You need to have `nasm`, `grub-mkrescue`, `xorriso`, `qemu` and a nighly Rust compiler installed. Then you can run it using `make run`.
[latest-post]: https://github.com/phil-opp/blog_os/tree/post-12
Please file an issue if you run into any problems.
You can find the branch for each post by following the `(source code)` link in the [post list](#posts) below. The branches are named `post-XX` where `XX` is the post number, for example `post-03` for the _VGA Text Mode_ post or `post-07` for the _Hardware Interrupts_ post. For build instructions, see the Readme of the respective branch.
You can check out a branch in a subdirectory using [git worktree]:
[git worktree]: https://git-scm.com/docs/git-worktree
```
git worktree add code post-10
```
The above command creates a subdirectory named `code` that contains the code for the 10th post ("Heap Allocation").
## Posts
The goal of this project is to provide step-by-step tutorials in individual blog posts. We currently have the following set of posts:
**Bare Bones:**
- [A Freestanding Rust Binary](https://os.phil-opp.com/freestanding-rust-binary/)
([source code](https://github.com/phil-opp/blog_os/tree/post-01))
- [A Minimal Rust Kernel](https://os.phil-opp.com/minimal-rust-kernel/)
([source code](https://github.com/phil-opp/blog_os/tree/post-02))
- [VGA Text Mode](https://os.phil-opp.com/vga-text-mode/)
([source code](https://github.com/phil-opp/blog_os/tree/post-03))
- [Testing](https://os.phil-opp.com/testing/)
([source code](https://github.com/phil-opp/blog_os/tree/post-04))
**Interrupts:**
- [CPU Exceptions](https://os.phil-opp.com/cpu-exceptions/)
([source code](https://github.com/phil-opp/blog_os/tree/post-05))
- [Double Faults](https://os.phil-opp.com/double-fault-exceptions/)
([source code](https://github.com/phil-opp/blog_os/tree/post-06))
- [Hardware Interrupts](https://os.phil-opp.com/hardware-interrupts/)
([source code](https://github.com/phil-opp/blog_os/tree/post-07))
**Memory Management:**
- [Introduction to Paging](https://os.phil-opp.com/paging-introduction/)
([source code](https://github.com/phil-opp/blog_os/tree/post-08))
- [Paging Implementation](https://os.phil-opp.com/paging-implementation/)
([source code](https://github.com/phil-opp/blog_os/tree/post-09))
- [Heap Allocation](https://os.phil-opp.com/heap-allocation/)
([source code](https://github.com/phil-opp/blog_os/tree/post-10))
- [Allocator Designs](https://os.phil-opp.com/allocator-designs/)
([source code](https://github.com/phil-opp/blog_os/tree/post-11))
**Multitasking**:
- [Async/Await](https://os.phil-opp.com/async-await/)
([source code](https://github.com/phil-opp/blog_os/tree/post-12))
## First Edition Posts
The current version of the blog is already the second edition. The first edition is outdated and no longer maintained, but might still be useful. The posts of the first edition are:
<details><summary><i>Click to expand</i></summary>
**Bare Bones:**
- [A Minimal x86 Kernel](https://os.phil-opp.com/multiboot-kernel.html)
([source code](https://github.com/phil-opp/blog_os/tree/first_edition_post_1))
- [Entering Long Mode](https://os.phil-opp.com/entering-longmode.html)
([source code](https://github.com/phil-opp/blog_os/tree/first_edition_post_2))
- [Set Up Rust](https://os.phil-opp.com/set-up-rust.html)
([source code](https://github.com/phil-opp/blog_os/tree/first_edition_post_3))
- [Printing to Screen](https://os.phil-opp.com/printing-to-screen.html)
([source code](https://github.com/phil-opp/blog_os/tree/first_edition_post_4))
**Memory Management:**
- [Allocating Frames](https://os.phil-opp.com/allocating-frames.html)
([source code](https://github.com/phil-opp/blog_os/tree/first_edition_post_5))
- [Page Tables](https://os.phil-opp.com/modifying-page-tables.html)
([source code](https://github.com/phil-opp/blog_os/tree/first_edition_post_6))
- [Remap the Kernel](https://os.phil-opp.com/remap-the-kernel.html)
([source code](https://github.com/phil-opp/blog_os/tree/first_edition_post_7))
- [Kernel Heap](https://os.phil-opp.com/kernel-heap.html)
([source code](https://github.com/phil-opp/blog_os/tree/first_edition_post_8))
**Exceptions:**
- [Handling Exceptions](https://os.phil-opp.com/handling-exceptions.html)
([source code](https://github.com/phil-opp/blog_os/tree/first_edition_post_9))
- [Double Faults](https://os.phil-opp.com/double-faults.html)
([source code](https://github.com/phil-opp/blog_os/tree/first_edition_post_10))
**Additional Resources:**
- [Cross Compile Binutils](https://os.phil-opp.com/cross-compile-binutils.html)
- [Cross Compile libcore](https://os.phil-opp.com/cross-compile-libcore.html)
- [Set Up GDB](https://os.phil-opp.com/set-up-gdb)
- [Handling Exceptions using Naked Functions](https://os.phil-opp.com/handling-exceptions-with-naked-fns.html)
- [Catching Exceptions](https://os.phil-opp.com/catching-exceptions.html)
([source code](https://github.com/phil-opp/blog_os/tree/catching_exceptions))
- [Better Exception Messages](https://os.phil-opp.com/better-exception-messages.html)
([source code](https://github.com/phil-opp/blog_os/tree/better_exception_messages))
- [Returning from Exceptions](https://os.phil-opp.com/returning-from-exceptions.html)
([source code](https://github.com/phil-opp/blog_os/tree/returning_from_exceptions))
</details>
## License
The source code is dual-licensed under MIT or the Apache License (Version 2.0). This excludes the `blog` directory.
This project, with exception of the `blog/content` folder, is licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
https://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
at your option.
For licensing of the `blog/content` folder, see the [`blog/content/README.md`](blog/content/README.md).
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

2
blog/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/public
zola

89
blog/before_build.py Normal file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import io
import urllib
import datetime
from github import Github
g = Github()
one_month_ago = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=32)
def filter_date(issue):
return issue.closed_at > one_month_ago
def format_number(number):
if number > 1000:
return u"{:.1f}k".format(float(number) / 1000)
else:
return u"{}".format(number)
with io.open("templates/auto/recent-updates.html", 'w', encoding='utf8') as recent_updates:
recent_updates.truncate()
relnotes_issues = g.search_issues("is:merged", repo="phil-opp/blog_os", type="pr", label="relnotes")[:100]
recent_relnotes_issues = list(filter(filter_date, relnotes_issues))
if len(recent_relnotes_issues) == 0:
recent_updates.write(u"No notable updates recently.")
else:
recent_updates.write(u"<ul>\n")
for pr in sorted(recent_relnotes_issues, key=lambda issue: issue.closed_at, reverse=True):
link = '<a href="' + pr.html_url + '">' + pr.title + "</a> "
iso_date = pr.closed_at.isoformat()
readable_date = pr.closed_at.strftime("%b&nbsp;%d")
datetime_str = '<time datetime="' + iso_date + '">' + readable_date + '</time>'
recent_updates.write(u" <li>" + link + datetime_str + "</li>\n")
recent_updates.write(u"</ul>")
repo = g.get_repo("phil-opp/blog_os")
with io.open("templates/auto/stars.html", 'w', encoding='utf8') as stars:
stars.truncate()
stars.write(format_number(repo.stargazers_count))
with io.open("templates/auto/forks.html", 'w', encoding='utf8') as forks:
forks.truncate()
forks.write(format_number(repo.forks_count))
# query "This week in Rust OSDev posts"
lines = []
year = 2020
month = 4
while True:
url = "https://rust-osdev.com/this-month/" + str(year) + "-" + str(month).zfill(2) + "/"
try:
urllib.request.urlopen(url)
except urllib.error.HTTPError as e:
break
month_str = datetime.date(1900, month, 1).strftime('%B')
link = '<a href="' + url + '">This Month in Rust OSDev (' + month_str + " " + str(year) + ")</a> "
lines.append(u" <li><b>" + link + "</b></li>\n")
month = month + 1
if month > 12:
month = 1
year = year + 1
lines.reverse()
with io.open("templates/auto/status-updates.html", 'w', encoding='utf8') as status_updates:
status_updates.truncate()
for line in lines:
status_updates.write(line)
with io.open("templates/auto/status-updates-truncated.html", 'w', encoding='utf8') as status_updates:
status_updates.truncate()
for index, line in enumerate(lines):
if index == 5:
break
status_updates.write(line)

256
blog/config.toml Normal file
View File

@@ -0,0 +1,256 @@
base_url = "https://os.phil-opp.com"
title = "Writing an OS in Rust"
description = "This blog series creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code."
generate_feeds = true
feed_filenames = ["rss.xml"]
compile_sass = true
minify_html = false
ignored_content = ["*/README.md", "*/LICENSE-CC-BY-NC"]
[markdown]
highlight_code = true
highlight_theme = "visual-studio-dark"
smart_punctuation = true
[link_checker]
skip_prefixes = [
"https://crates.io/crates", # see https://github.com/rust-lang/crates.io/issues/788
"https://www.amd.com/system/files/TechDocs/", # seems to have problems with PDFs
"https://developer.apple.com/library/archive/qa/qa1118/_index.html", # results in a 401 (I don't know why)
"https://github.com", # rate limiting often leads to "Error 429 Too Many Requests"
"https://www.linkedin.com/", # seems to send invalid HTTP status codes
]
skip_anchor_prefixes = [
"https://github.com/", # see https://github.com/getzola/zola/issues/805
"https://docs.rs/x86_64/0.1.2/src/", # source code highlight
"https://doc.rust-jp.rs/book-ja/", # seems like Zola has problems with Japanese anchor names
"https://doc.rust-jp.rs/edition-guide/rust-2018", # seems like Zola has problems with Japanese anchor names
"https://doc.rust-jp.rs/rust-nomicon-ja/", # seems like Zola has problems with Japanese anchor names
]
[extra]
subtitle = "Philipp Oppermann's blog"
author = { name = "Philipp Oppermann" }
default_language = "en"
languages = ["en", "zh-CN", "zh-TW", "fr", "ja", "fa", "ru", "ko", "ar"]
[translations]
lang_name = "English (original)"
toc = "Table of Contents"
all_posts = "« All Posts"
comments = "Comments"
comments_notice = "Please leave your comments in English if possible."
readmore = "read&nbsp;more&nbsp;»"
not_translated = "(This post is not translated yet.)"
translated_content = "Translated Content:"
translated_content_notice = "This is a community translation of the <strong><a href=\"_original.permalink_\">_original.title_</a></strong> post. It might be incomplete, outdated or contain errors. Please report any issues!"
translated_by = "Translation by"
translation_contributors = "With contributions from"
word_separator = "and"
support_me = """
<h2>Support Me</h2>
<p>Creating and maintaining this blog and the associated libraries is a lot of work, but I really enjoy doing it. By supporting me, you allow me to invest more time in new content, new features, and continuous maintenance. The best way to support me is to <a href="https://github.com/sponsors/phil-opp"><em>sponsor me on GitHub</em></a>. Thank you!</p>
"""
comment_note = """
Do you have a problem, want to share feedback, or discuss further ideas? Feel free to leave a comment here! Please stick to English and follow Rust's <a href="https://www.rust-lang.org/policies/code-of-conduct">code of conduct</a>. This comment thread directly maps to a <a href="_discussion_url_"><em>discussion on GitHub</em></a>, so you can also comment there if you prefer.
"""
# Chinese (simplified)
[languages.zh-CN]
title = "Writing an OS in Rust"
description = "This blog series creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code."
[languages.zh-CN.translations]
lang_name = "Chinese (simplified)"
toc = "目录"
all_posts = "« 所有文章"
comments = "评论"
comments_notice = "请尽可能使用英语评论。"
readmore = "更多 »"
not_translated = "(该文章还没有被翻译。)"
translated_content = "翻译内容:"
translated_content_notice = "这是对原文章 <strong><a href=\"_original.permalink_\">_original.title_</a></strong> 的社区中文翻译。它可能不完整,过时或者包含错误。可以在 <a href=\"https://github.com/phil-opp/blog_os/issues/961\">这个 Issue</a> 上评论和提问!"
translated_by = "翻译者:"
translation_contributors = "With contributions from"
word_separator = "和"
support_me = """
<h2>支持我</h2>
<p>创建和维护这个博客以及相关的库带来了十分庞大的工作量,即便我十分热爱它们,仍然需要你们的支持。通过赞助我,可以让我有能投入更多时间与精力在创造新内容,开发新功能上。赞助我最好的办法是通过<a href="https://github.com/sponsors/phil-opp"><em>sponsor me on GitHub</em></a>. 十分感谢各位!</p>
"""
comment_note = """
你有问题需要解决,想要分享反馈,或者讨论更多的想法吗?请随时在这里留下评论!请使用尽量使用英文并遵循 Rust 的 <a href="https://www.rust-lang.org/policies/code-of-conduct">code of conduct</a>. 这个讨论串将与 <a href="_discussion_url_"><em>discussion on GitHub</em></a> 直接连接,所以你也可以直接在那边发表评论
"""
# Chinese (traditional)
[languages.zh-TW]
title = "Writing an OS in Rust"
description = "This blog series creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code."
[languages.zh-TW.translations]
lang_name = "Chinese (traditional)"
toc = "目錄"
all_posts = "« 所有文章"
comments = "評論"
comments_notice = "請儘可能使用英語評論。"
readmore = "更多 »"
not_translated = "(該文章還沒有被翻譯。)"
translated_content = "翻譯內容:"
translated_content_notice = "這是對原文章 <strong><a href=\"_original.permalink_\">_original.title_</a></strong> 的社區中文翻譯。它可能不完整,過時或者包含錯誤。可以在 <a href=\"https://github.com/phil-opp/blog_os/issues/961\">這個 Issue</a> 上評論和提問!"
translated_by = "翻譯者:"
translation_contributors = "With contributions from"
word_separator = "和"
support_me = """
<h2>Support Me</h2>
<p>Creating and maintaining this blog and the associated libraries is a lot of work, but I really enjoy doing it. By supporting me, you allow me to invest more time in new content, new features, and continuous maintenance. The best way to support me is to <a href="https://github.com/sponsors/phil-opp"><em>sponsor me on GitHub</em></a>. Thank you!</p>
"""
comment_note = """
Do you have a problem, want to share feedback, or discuss further ideas? Feel free to leave a comment here! Please stick to English and follow Rust's <a href="https://www.rust-lang.org/policies/code-of-conduct">code of conduct</a>. This comment thread directly maps to a <a href="_discussion_url_"><em>discussion on GitHub</em></a>, so you can also comment there if you prefer.
"""
# Japanese
[languages.ja]
title = "Writing an OS in Rust"
description = "This blog series creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code."
[languages.ja.translations]
lang_name = "Japanese"
toc = "目次"
all_posts = "« すべての記事へ"
comments = "コメント"
comments_notice = "可能な限りコメントは英語で残すようにしてください。"
readmore = "もっと読む »"
not_translated = "(この記事はまだ翻訳されていません。)"
translated_content = "この記事は翻訳されたものです:"
translated_content_notice = "この記事は<strong><a href=\"_original.permalink_\">_original.title_</a></strong>をコミュニティの手により翻訳したものです。そのため、翻訳が完全・最新でなかったり、原文にない誤りを含んでいる可能性があります。問題があれば<a href=\"https://github.com/phil-opp/blog_os/issues/906\">このissue</a>上で報告してください!"
translated_by = "翻訳者:"
translation_contributors = "With contributions from"
word_separator = "及び"
support_me = """
<h2>Support Me</h2>
<p>Creating and maintaining this blog and the associated libraries is a lot of work, but I really enjoy doing it. By supporting me, you allow me to invest more time in new content, new features, and continuous maintenance. The best way to support me is to <a href="https://github.com/sponsors/phil-opp"><em>sponsor me on GitHub</em></a>. Thank you!</p>
"""
comment_note = """
Do you have a problem, want to share feedback, or discuss further ideas? Feel free to leave a comment here! Please stick to English and follow Rust's <a href="https://www.rust-lang.org/policies/code-of-conduct">code of conduct</a>. This comment thread directly maps to a <a href="_discussion_url_"><em>discussion on GitHub</em></a>, so you can also comment there if you prefer.
"""
# Persian
[languages.fa]
title = "Writing an OS in Rust"
description = "This blog series creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code."
[languages.fa.translations]
lang_name = "Persian"
toc = "فهرست مطالب"
all_posts = "« همه پست‌ها"
comments = "نظرات"
comments_notice = "لطفا نظرات خود را در صورت امکان به انگلیسی بنویسید."
readmore = "ادامه‌مطلب»"
not_translated = "(.این پست هنوز ترجمه نشده است)"
translated_content = "محتوای ترجمه شده:"
translated_content_notice = "این یک ترجمه از جامعه کاربران برای پست <strong><a href=\"_original.permalink_\">_original.title_</a></strong> است. ممکن است ناقص، منسوخ شده یا دارای خطا باشد. لطفا هر گونه مشکل را در <a href=\"https://github.com/phil-opp/blog_os/issues/908\">این ایشو</a> گزارش دهید!"
translated_by = "ترجمه توسط"
translation_contributors = "With contributions from"
word_separator = "و"
support_me = """
<h2>Support Me</h2>
<p>Creating and maintaining this blog and the associated libraries is a lot of work, but I really enjoy doing it. By supporting me, you allow me to invest more time in new content, new features, and continuous maintenance. The best way to support me is to <a href="https://github.com/sponsors/phil-opp"><em>sponsor me on GitHub</em></a>. Thank you!</p>
"""
comment_note = """
Do you have a problem, want to share feedback, or discuss further ideas? Feel free to leave a comment here! Please stick to English and follow Rust's <a href="https://www.rust-lang.org/policies/code-of-conduct">code of conduct</a>. This comment thread directly maps to a <a href="_discussion_url_"><em>discussion on GitHub</em></a>, so you can also comment there if you prefer.
"""
# Russian
[languages.ru]
title = "Writing an OS in Rust"
description = "This blog series creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code."
[languages.ru.translations]
lang_name = "Russian"
toc = "Содержание"
all_posts = Все посты"
comments = "Комментарии"
comments_notice = "Пожалуйста, оставляйте комментарии на английском по возможности."
readmore = "читать&nbsp;дальше&nbsp;»"
not_translated = "(Этот пост еще не переведен.)"
translated_content = "Переведенное содержание:"
translated_content_notice = "Это перевод сообщества поста <strong><a href=\"_original.permalink_\">_original.title_</a></strong>. Он может быть неполным, устаревшим или содержать ошибки. Пожалуйста, сообщайте о любых проблемах!"
translated_by = "Перевод сделан"
translation_contributors = "With contributions from"
word_separator = "и"
support_me = """
<h2>Support Me</h2>
<p>Creating and maintaining this blog and the associated libraries is a lot of work, but I really enjoy doing it. By supporting me, you allow me to invest more time in new content, new features, and continuous maintenance. The best way to support me is to <a href="https://github.com/sponsors/phil-opp"><em>sponsor me on GitHub</em></a>. Thank you!</p>
"""
comment_note = """
Do you have a problem, want to share feedback, or discuss further ideas? Feel free to leave a comment here! Please stick to English and follow Rust's <a href="https://www.rust-lang.org/policies/code-of-conduct">code of conduct</a>. This comment thread directly maps to a <a href="_discussion_url_"><em>discussion on GitHub</em></a>, so you can also comment there if you prefer.
"""
# French
[languages.fr]
title = "Writing an OS in Rust"
description = "This blog series creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code."
[languages.fr.translations]
lang_name = "French"
toc = "Table des matières"
all_posts = "« Tous les articles"
comments = "Commentaires"
comments_notice = "Veuillez commenter en Anglais si possible."
readmore = "Voir&nbsp;plus&nbsp;»"
not_translated = "(Cet article n'est pas encore traduit.)"
translated_content = "Contenu traduit : "
translated_content_notice = "Ceci est une traduction communautaire de l'article <strong><a href=\"_original.permalink_\">_original.title_</a></strong>. Il peut être incomplet, obsolète ou contenir des erreurs. Veuillez signaler les quelconques problèmes !"
translated_by = "Traduit par : "
translation_contributors = "With contributions from"
word_separator = "et"
support_me = """
<h2>Support Me</h2>
<p>Creating and maintaining this blog and the associated libraries is a lot of work, but I really enjoy doing it. By supporting me, you allow me to invest more time in new content, new features, and continuous maintenance. The best way to support me is to <a href="https://github.com/sponsors/phil-opp"><em>sponsor me on GitHub</em></a>. Thank you!</p>
"""
comment_note = """
Do you have a problem, want to share feedback, or discuss further ideas? Feel free to leave a comment here! Please stick to English and follow Rust's <a href="https://www.rust-lang.org/policies/code-of-conduct">code of conduct</a>. This comment thread directly maps to a <a href="_discussion_url_"><em>discussion on GitHub</em></a>, so you can also comment there if you prefer.
"""
# Korean
[languages.ko]
title = "Writing an OS in Rust"
description = "This blog series creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code."
[languages.ko.translations]
lang_name = "Korean"
toc = "목차"
all_posts = "« 모든 게시글"
comments = "댓글"
comments_notice = "댓글은 가능하면 영어로 작성해주세요."
readmore = "더&nbsp;읽기&nbsp;»"
not_translated = "(아직 번역이 완료되지 않은 게시글입니다)"
translated_content = "번역된 내용 : "
translated_content_notice = "이것은 커뮤니티 멤버가 <strong><a href=\"_original.permalink_\">_original.title_</a></strong> 포스트를 번역한 글입니다. 부족한 설명이나 오류, 혹은 시간이 지나 더 이상 유효하지 않은 정보를 발견하시면 제보해주세요!"
translated_by = "번역한 사람 : "
translation_contributors = "With contributions from"
word_separator = "와"
support_me = """
<h2>Support Me</h2>
<p>Creating and maintaining this blog and the associated libraries is a lot of work, but I really enjoy doing it. By supporting me, you allow me to invest more time in new content, new features, and continuous maintenance. The best way to support me is to <a href="https://github.com/sponsors/phil-opp"><em>sponsor me on GitHub</em></a>. Thank you!</p>
"""
comment_note = """
Do you have a problem, want to share feedback, or discuss further ideas? Feel free to leave a comment here! Please stick to English and follow Rust's <a href="https://www.rust-lang.org/policies/code-of-conduct">code of conduct</a>. This comment thread directly maps to a <a href="_discussion_url_"><em>discussion on GitHub</em></a>, so you can also comment there if you prefer.
"""
[languages.ar]
title = "Writing an OS in Rust"
[languages.ar.translations]
lang_name = "Arabic"
toc = "Table of Contents"
all_posts = "« All Posts"
comments = "Comments"
comments_notice = "Please leave your comments in English if possible."
readmore = "read&nbsp;more&nbsp;»"
not_translated = "(This post is not translated yet.)"
translated_content = "Translated Content:"
translated_content_notice = "This is a community translation of the <strong><a href=\"_original.permalink_\">_original.title_</a></strong> post. It might be incomplete, outdated or contain errors. Please report any issues!"
translated_by = "Translation by"
translation_contributors = "With contributions from"
word_separator = "and"
support_me = """
<h2>Support Me</h2>
<p>Creating and maintaining this blog and the associated libraries is a lot of work, but I really enjoy doing it. By supporting me, you allow me to invest more time in new content, new features, and continuous maintenance. The best way to support me is to <a href="https://github.com/sponsors/phil-opp"><em>sponsor me on GitHub</em></a>. Thank you!</p>
"""
comment_note = """
Do you have a problem, want to share feedback, or discuss further ideas? Feel free to leave a comment here! Please stick to English and follow Rust's <a href="https://www.rust-lang.org/policies/code-of-conduct">code of conduct</a>. This comment thread directly maps to a <a href="_discussion_url_"><em>discussion on GitHub</em></a>, so you can also comment there if you prefer.
"""

View File

@@ -0,0 +1,96 @@
Creative Commons Attribution-NonCommercial 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
Section 1 Definitions.
Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
Licensor means the individual(s) or entity(ies) granting rights under this Public License.
NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange.
Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
Section 2 Scope.
License grant.
Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and
produce, reproduce, and Share Adapted Material for NonCommercial purposes only.
Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
Term. The term of this Public License is specified in Section 6(a).
Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
Downstream recipients.
Offer from the Licensor Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
Other rights.
Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
Patent and trademark rights are not licensed under this Public License.
To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes.
Section 3 License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
Attribution.
If You Share the Licensed Material (including in modified form), You must:
retain the following if it is supplied by the Licensor with the Licensed Material:
identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
a copyright notice;
a notice that refers to this Public License;
a notice that refers to the disclaimer of warranties;
a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License.
Section 4 Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only;
if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and
You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
Section 5 Disclaimer of Warranties and Limitation of Liability.
Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.
To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.
The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
Section 6 Term and Termination.
This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.
For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
Section 7 Other Terms and Conditions.
The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
Section 8 Interpretation.
For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.

19
blog/content/README.md Normal file
View File

@@ -0,0 +1,19 @@
# Blog Content
This folder contains the content for the _"Writing an OS in Rust"_ blog.
## License
This folder is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License, available in [LICENSE-CC-BY-NC](LICENSE-CC-BY-NC) or under <https://creativecommons.org/licenses/by-nc/4.0/>.
All _code examples_ between markdown code blocks denoted by three backticks (<code>\`\`\`</code>) are additionally licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or
https://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or https://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be licensed as above, without any additional terms or conditions.

12
blog/content/_index.ar.md Normal file
View File

@@ -0,0 +1,12 @@
+++
template = "edition-2/index.html"
+++
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">كتابة نظام تشغيل بلغة Rust </h1>
<div class="front-page-introduction">
تنشئ سلسلة المدونات هذه نظام تشغيل صغير بلغة البرمجة [Rust ](https://www.rust-lang.org/). كل منشور هو عبارة عن برنامج تعليمي صغير ويتضمن كل الشيفرة المطلوبة، لذا يمكنك المتابعة إذا أردت. الكود المصدري متاح أيضًا في مستودع [Github ](https://github.com/phil-opp/blog_os) المقابل.
آخر منشور: <!-- latest-post -->
</div>

13
blog/content/_index.fa.md Normal file
View File

@@ -0,0 +1,13 @@
+++
template = "edition-2/index.html"
+++
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">نوشتن یک سیستم عامل با راست</h1>
<div class="front-page-introduction right-to-left">
این مجموعه بلاگ یک سیستم عامل کوچک در [زبان برنامه نویسی Rust](https://www.rust-lang.org/) ایجاد می کند. هر پست یک آموزش کوچک است و شامل تمام کدهای مورد نیاز است ، بنابراین اگر دوست دارید می توانید آن را دنبال کنید. کد منبع نیز در [مخزن گیت‌هاب](https://github.com/phil-opp/blog_os) مربوطه موجود است.
اخرین پست: <!-- latest-post -->
</div>

13
blog/content/_index.fr.md Normal file
View File

@@ -0,0 +1,13 @@
+++
template = "edition-2/index.html"
+++
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">Écrire un OS en Rust</h1>
<div class="front-page-introduction">
L'objectif de ce blog est de créer un petit système d'exploitation avec le [langage de programmation Rust](https://www.rust-lang.org/). Chaque article est un petit tutoriel et comprend tout le code nécessaire, vous pouvez donc essayer en même temps si vous le souhaitez. Le code source est aussi disponible dans le [dépôt GitHub](https://github.com/phil-opp/blog_os) correspondant.
Dernier article : <!-- latest-post -->
</div>

13
blog/content/_index.ja.md Normal file
View File

@@ -0,0 +1,13 @@
+++
template = "edition-2/index.html"
+++
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">RustでOSを書く</h1>
<div class="front-page-introduction">
このブログシリーズでは、ちょっとしたオペレーティングシステムを[Rustプログラミング言語](https://www.rust-lang.org/)を使って作ります。それぞれの記事が小さなチュートリアルになっており、必要なコードも全て記事内に記されているので、一つずつ読み進めて行けば理解できるでしょう。対応した[Githubリポジトリ](https://github.com/phil-opp/blog_os)でソースコードを見ることもできます。
最新記事: <!-- latest-post -->
</div>

14
blog/content/_index.ko.md Normal file
View File

@@ -0,0 +1,14 @@
+++
template = "edition-2/index.html"
+++
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">Rust로 OS 구현하기</h1>
<div class="front-page-introduction">
이 블로그 시리즈는 [Rust 프로그래밍 언어](https://www.rust-lang.org/)로 작은 OS를 구현하는 것을 주제로 합니다.
각 포스트는 구현에 필요한 소스 코드를 포함한 작은 튜토리얼 형식으로 구성되어 있습니다. 소스 코드는 이 블로그의 [Github 저장소](https://github.com/phil-opp/blog_os)에서도 확인하실 수 있습니다.
최신 포스트: <!-- latest-post -->
</div>

13
blog/content/_index.md Normal file
View File

@@ -0,0 +1,13 @@
+++
template = "edition-2/index.html"
+++
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">Writing an OS in Rust</h1>
<div class="front-page-introduction">
This blog series creates a small operating system in the [Rust programming language](https://www.rust-lang.org/). Each post is a small tutorial and includes all needed code, so you can follow along if you like. The source code is also available in the corresponding [Github repository](https://github.com/phil-opp/blog_os).
Latest post: <!-- latest-post -->
</div>

13
blog/content/_index.ru.md Normal file
View File

@@ -0,0 +1,13 @@
+++
template = "edition-2/index.html"
+++
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">Собственная операционная система на Rust</h1>
<div class="front-page-introduction">
Этот блог посвящен написанию маленькой операционной системы на [языке программирования Rust](https://www.rust-lang.org/). Каждый пост &mdash; это маленькое руководство, включающее в себя весь необходимый код, &mdash; вы сможете следовать ему, если пожелаете. Исходный код также доступен в соотвестующем [репозитории на Github](https://github.com/phil-opp/blog_os).
Последний пост: <!-- latest-post -->
</div>

View File

@@ -0,0 +1,13 @@
+++
template = "edition-2/index.html"
+++
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">用Rust写一个操作系统</h1>
<div class="front-page-introduction">
这个博客系列用[Rust编程语言](https://www.rust-lang.org/)编写了一个小操作系统。每篇文章都是一个小教程,并且包含了所有代码,你可以跟着一起学习。源代码也放在了[Github 仓库](https://github.com/phil-opp/blog_os)。
最新文章: <!-- latest-post -->
</div>

View File

@@ -0,0 +1,13 @@
+++
template = "edition-2/index.html"
+++
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">Writing an OS in Rust</h1>
<div class="front-page-introduction">
This blog series creates a small operating system in the [Rust programming language](https://www.rust-lang.org/). Each post is a small tutorial and includes all needed code, so you can follow along if you like. The source code is also available in the corresponding [Github repository](https://github.com/phil-opp/blog_os).
Latest post: <!-- latest-post -->
</div>

View File

@@ -0,0 +1,5 @@
+++
title = "First Edition"
template = "edition-1/index.html"
aliases = ["first-edition/index.html"]
+++

View File

@@ -0,0 +1,6 @@
+++
title = "Extra Content"
insert_anchor_links = "left"
render = false
sort_by = "weight"
+++

View File

@@ -1,12 +1,17 @@
+++
title = "Cross Compile Binutils"
template = "plain.html"
path = "cross-compile-binutils"
weight = 2
+++
The [GNU Binutils] are a collection of various binary tools such as `ld`, `as`, `objdump`, or `readelf`. These tools are platform-specific, so you need to compile them again if your host system and target system are different. In our case, we need `ld` and `objdump` for the x86_64 architecture.
[GNU Binutils]: https://www.gnu.org/software/binutils/
## Building Setup
First, you need to download a current binutils version from [here][download] \(the latest one is near the bottom). After extracting, you should have a folder named `binutils-2.X` where `X` is for example `25.1`. Now can create and switch to a new folder for building (recommended):
[download]: ftp://sourceware.org/pub/binutils/snapshots
```bash

View File

@@ -0,0 +1,36 @@
+++
title = "Cross Compiling: libcore"
template = "plain.html"
path = "cross-compile-libcore"
weight = 3
+++
If you get an `error: can't find crate for 'core'`, you're probably compiling for a different target (e.g. you're passing the `target` option to `cargo build`). Now the compiler complains that it can't find the `core` library. This document gives a quick overview how to fix this problem. For more details, see the [rust-cross] project.
[rust-cross]: https://github.com/japaric/rust-cross
## Libcore
The core library is a dependency-free library that is added implicitly when using `#![no_std]`. It provides basic standard library features like Option or Iterator. The core library is installed together with the rust compiler (just like the std library). But the installed libcore is specific to your architecture. If you aren't working on x86_64 Linux and pass `target x86_64unknownlinuxgnu` to cargo, it can't find a x86_64 libcore. To fix this, you can either use `rustup` or `xargo`.
## rustup
Thanks to [rustup], cross-compilation for [official target triples] is pretty easy today: Just execute `rustup target add x86_64-unknown-linux-gnu`.
[rustup]: https://rustup.rs
[official target triples]: https://github.com/japaric/rust-cross#the-target-triple
## xargo
If you're using a _custom target specification_, the `rustup` method doesn't work. Instead, you can use [xargo]. Xargo is a wrapper for cargo that eases cross compilation. We can install it by executing:
```
cargo install xargo
```
If the installation fails, make sure that you have `cmake` and the OpenSSL headers installed. For more details, see the xargo's [dependency section].
[xargo]: https://github.com/japaric/xargo
[dependency section]: https://github.com/japaric/xargo#dependencies
Xargo is “a drop-in replacement for cargo”, so every cargo command also works with `xargo`. You can do e.g. `xargo --help`, `xargo clean`, or `xargo doc`. However, the `build` command gains additional functionality: `xargo build` will automatically cross compile the `core` library (and a few other libraries such as `alloc`) when compiling for custom targets.
[xargo]: https://github.com/japaric/xargo
So if your custom target file is named `your-cool-target.json`, you can compile your code using xargo through `xargo build --target your-cool-target` (note the omitted extension).

View File

@@ -1,17 +1,28 @@
+++
title = "Catching Exceptions"
date = "2016-05-28"
weight = 1
path = "catching-exceptions"
aliases = ["catching-exceptions.html"]
date = 2016-05-28
template = "edition-1/page.html"
[extra]
updated = "2016-06-25"
+++
In this post, we start exploring exceptions. We set up an interrupt descriptor table and add handler functions. At the end of this post, our kernel will be able to catch page faults.
In this post, we start exploring exceptions. We set up an interrupt descriptor table and add handler functions. At the end of this post, our kernel will be able to catch divide-by-zero faults.
<!--more-->
<!-- more -->
As always, the complete source code is on [Github]. Please file [issues] for any problems, questions, or improvement suggestions. There is also a comment section at the end of this page.
As always, the complete source code is on [GitHub]. Please file [issues] for any problems, questions, or improvement suggestions. There is also a comment section at the end of this page.
[Github]: https://github.com/phil-opp/blog_os/tree/catching_exceptions
[GitHub]: https://github.com/phil-opp/blog_os/tree/catching_exceptions
[issues]: https://github.com/phil-opp/blog_os/issues
> **Note**: This post describes how to handle exceptions using naked functions (see [“Handling Exceptions with Naked Functions”] for an overview). Our new way of handling exceptions can be found in the [“Handling Exceptions”] post.
[“Handling Exceptions with Naked Functions”]: @/edition-1/extra/naked-exceptions/_index.md
[“Handling Exceptions”]: @/edition-1/posts/09-handling-exceptions/index.md
## Exceptions
An exception signals that something is wrong with the current instruction. For example, the CPU issues an exception if the current instruction tries to divide by 0. When an exception occurs, the CPU interrupts its current work and immediately calls a specific exception handler function, depending on the exception type.
@@ -24,7 +35,7 @@ We've already seen several types of exceptions in our kernel:
For the full list of exceptions check out the [OSDev wiki][exceptions].
[exceptions]: http://wiki.osdev.org/Exceptions
[exceptions]: https://wiki.osdev.org/Exceptions
### The Interrupt Descriptor Table
In order to catch and handle exceptions, we have to set up a so-called _Interrupt Descriptor Table_ (IDT). In this table we can specify a handler function for each CPU exception. The hardware uses this table directly, so we need to follow a predefined format. Each entry must have the following 16-byte structure:
@@ -83,7 +94,9 @@ Now we create types for the IDT and its entries:
```rust
// src/interrupts/idt.rs
use x86::segmentation::{self, SegmentSelector};
use x86_64::instructions::segmentation;
use x86_64::structures::gdt::SegmentSelector;
use x86_64::PrivilegeLevel;
pub struct Idt([Entry; 16]);
@@ -113,13 +126,13 @@ pub struct EntryOptions(u16);
impl EntryOptions {
fn new() -> Self {...}
fn set_present(&mut self, present: bool) {...}
pub fn set_present(&mut self, present: bool) {...}
fn disable_interrupts(&mut self, disable: bool) {...}
pub fn disable_interrupts(&mut self, disable: bool) {...}
fn set_privilege_level(&mut self, dpl: u16) {...}
pub fn set_privilege_level(&mut self, dpl: u16) {...}
fn set_stack_index(&mut self, index: u16) {...}
pub fn set_stack_index(&mut self, index: u16) {...}
}
```
@@ -141,17 +154,19 @@ Or:
self.0 = ((self.0 >> 3) << 3) | stack_index;
```
Well, none of these variants is really _readable_ and it's very easy to make mistakes somewhere. Therefore I created a `BitField` type with the following API:
Well, none of these variants is really _readable_ and it's very easy to make mistakes somewhere. Therefore I created a `BitField` trait that provides the following [Range]-based API:
[Range]: https://doc.rust-lang.org/nightly/core/ops/struct.Range.html
``` rust
self.0.set_range(0..3, stack_index);
self.0.set_bits(0..3, stack_index);
```
I think it is much more readable, since we abstracted away all bit-masking details. The `BitField` type is contained in the [bit_field] crate. (It's pretty new, so it might still contain bugs.) To add it as dependency, we run `cargo add bit_field` and add `extern crate bit_field;` to our `src/lib.rs`.
I think it is much more readable, since we abstracted away all bit-masking details. The `BitField` trait is contained in the [bit_field] crate. (It's pretty new, so it might still contain bugs.) To add it as dependency, we run `cargo add bit_field` and add `extern crate bit_field;` to our `src/lib.rs`.
[bit_field]: TODO
[bit_field]: https://crates.io/crates/bit_field
Now we can use the crate to implement the methods of `EntryOptions`:
Now we can use the trait to implement the methods of `EntryOptions`:
```rust
// in src/interrupts/idt.rs
@@ -159,12 +174,12 @@ Now we can use the crate to implement the methods of `EntryOptions`:
use bit_field::BitField;
#[derive(Debug, Clone, Copy)]
pub struct EntryOptions(BitField<u16>);
pub struct EntryOptions(u16);
impl EntryOptions {
fn minimal() -> Self {
let mut options = BitField::new(0);
options.set_range(9..12, 0b111); // 'must-be-one' bits
let mut options = 0;
options.set_bits(9..12, 0b111); // 'must-be-one' bits
EntryOptions(options)
}
@@ -174,23 +189,23 @@ impl EntryOptions {
options
}
fn set_present(&mut self, present: bool) -> &mut Self {
pub fn set_present(&mut self, present: bool) -> &mut Self {
self.0.set_bit(15, present);
self
}
fn disable_interrupts(&mut self, disable: bool) -> &mut Self {
pub fn disable_interrupts(&mut self, disable: bool) -> &mut Self {
self.0.set_bit(8, !disable);
self
}
fn set_privilege_level(&mut self, dpl: u16) -> &mut Self {
self.0.set_range(13..15, dpl);
pub fn set_privilege_level(&mut self, dpl: u16) -> &mut Self {
self.0.set_bits(13..15, dpl);
self
}
fn set_stack_index(&mut self, index: u16) -> &mut Self {
self.0.set_range(0..3, index);
pub fn set_stack_index(&mut self, index: u16) -> &mut Self {
self.0.set_bits(0..3, index);
self
}
}
@@ -230,9 +245,9 @@ It needs to be a function with a defined [calling convention], as it called dire
It is important that the function is [diverging], i.e. it must never return. The reason is that the hardware doesn't _call_ the handler functions, it just _jumps_ to them after pushing some values to the stack. So our stack might look different:
[diverging]: https://doc.rust-lang.org/book/functions.html#diverging-functions
[diverging]: https://doc.rust-lang.org/rust-by-example/fn/diverging.html
![normal function return vs interrupt function return](/images/normal-vs-interrupt-function-return.svg)
![normal function return vs interrupt function return](normal-vs-interrupt-function-return.svg)
If our handler function returned normally, it would try to pop the return address from the stack. But it might get some completely different value then. For example, the CPU pushes an error code for some exceptions. Bad things would happen if we interpreted this error code as return address and jumped to it. Therefore interrupt handler functions must diverge[^fn-must-diverge].
@@ -251,7 +266,7 @@ impl Idt {
impl Entry {
fn missing() -> Self {
Entry {
gdt_selector: SegmentSelector::new(0),
gdt_selector: SegmentSelector::new(0, PrivilegeLevel::Ring0),
pointer_low: 0,
pointer_middle: 0,
pointer_high: 0,
@@ -275,17 +290,16 @@ impl Idt {
}
}
```
The method overwrites the specified entry with the given handler function. We use the `segmentation::cs`[^fn-segmentation-cs] function of the [x86 crate] to get the current code segment descriptor. There's no need for different kernel code segments in long mode, so the current `cs` value should be always the right choice.
The method overwrites the specified entry with the given handler function. We use the `segmentation::cs` function of the [x86_64 crate] to get the current code segment descriptor. There's no need for different kernel code segments in long mode, so the current `cs` value should be always the right choice.
[x86 crate]: https://github.com/gz/rust-x86
[^fn-segmentation-cs]: The `segmentation::cs` function was [added](https://github.com/gz/rust-x86/pull/12) in version 0.7.0, so you might need to update your `x86` version in your `Cargo.toml`.
[x86_64 crate]: https://docs.rs/x86_64
By returning a mutual reference to the entry's options, we allow the caller to override the default settings. For example, the caller could add a non-present entry by executing: `idt.set_handler(11, handler_fn).set_present(false)`.
### Loading the IDT
Now we're able to create new interrupt descriptor tables with registered handler functions. We just need a way to load an IDT, so that the CPU uses it. The x86 architecture uses a special register to store the active IDT and its length. In order to load a new IDT we need to update this register through the [lidt] instruction.
[lidt]: http://x86.renejeschke.de/html/file_module_x86_id_156.html
[lidt]: https://www.felixcloutier.com/x86/lgdt:lidt
The `lidt` instruction expects a pointer to a special data structure, which specifies the start address of the IDT and its length:
@@ -295,15 +309,15 @@ Type | Name | Description
u16 | Limit | The maximum addressable byte in the table. Equal to the table size in bytes minus 1.
u64 | Offset | Virtual start address of the table.
This structure is already contained [in the x86 crate], so we don't need to create it ourselves. The same is true for the [lidt function]. So we just need to put the pieces together to create a `load` method:
This structure is already contained [in the x86_64 crate], so we don't need to create it ourselves. The same is true for the [lidt function]. So we just need to put the pieces together to create a `load` method:
[in the x86 crate]: http://gz.github.io/rust-x86/x86/dtables/struct.DescriptorTablePointer.html
[lidt function]: http://gz.github.io/rust-x86/x86/dtables/fn.lidt.html
[in the x86_64 crate]: https://docs.rs/x86_64/0.1.0/x86_64/instructions/tables/struct.DescriptorTablePointer.html
[lidt function]: https://docs.rs/x86_64/0.1.0/x86_64/instructions/tables/fn.lidt.html
```rust
impl Idt {
pub fn load(&self) {
use x86::dtables::{DescriptorTablePointer, lidt};
use x86_64::instructions::tables::{DescriptorTablePointer, lidt};
use core::mem::size_of;
let ptr = DescriptorTablePointer {
@@ -315,13 +329,11 @@ impl Idt {
}
}
```
The method does not need to modify the IDT, so it takes `self` by immutable reference. We convert this reference to an u64 and calculate the table size using [mem::size_of]. The additional `-1` is needed because the limit field has to be the maximum addressable byte.
The method does not need to modify the IDT, so it takes `self` by immutable reference. First, we create a `DescriptorTablePointer` and then we pass it to `lidt`. The `lidt` function expects that the `base` field has the type `u64`, therefore we need to cast the `self` pointer. For calculating the `limit` we use [mem::size_of]. The additional `-1` is needed because the limit field has to be the maximum addressable byte (inclusive bound). We need an unsafe block around `lidt`, because the function assumes that the specified handler addresses are valid.
[mem::size_of]: https://doc.rust-lang.org/nightly/core/mem/fn.size_of.html
Then we pass a pointer to our `ptr` structure to the `lidt` function, which calls the `lidt` assembly instruction in order to reload the IDT register. We need an unsafe block here, because the `lidt` assumes that the specified handler addresses are valid.
### Safety
#### Safety
But can we really guarantee that handler addresses are always valid? Let's see:
- The `Idt::new` function creates a new table populated with non-present entries. There's no way to set these entries to present from outside of this module, so this function is fine.
@@ -354,7 +366,7 @@ Well, we construct an IDT _on the stack_ and load it. It is perfectly valid unti
Now imagine that the `cause_page_fault` function declared an array of pointers instead. If the present was coincidentally set, the CPU would jump to some random pointer and interpret random memory as code. This would be a clear violation of memory safety.
### Fixing the load method
#### Fixing the load method
So how do we fix it? We could make the load function itself `unsafe` and push the unsafety to the caller. However, there is a much better solution in this case. In order to see it, we formulate the requirement for the `load` method:
> The referenced IDT must be valid until a new IDT is loaded.
@@ -365,7 +377,7 @@ We can't know when the next IDT will be loaded. Maybe never. So in the worst cas
This is exactly the definition of a [static lifetime]. So we can easily ensure that the IDT lives long enough by adding a `'static` requirement to the signature of the `load` function:
[static lifetime]: http://rustbyexample.com/scope/lifetime/static_lifetime.html
[static lifetime]: https://doc.rust-lang.org/rust-by-example/scope/lifetime/static_lifetime.html
```rust
pub fn load(&'static self) {...}
@@ -398,17 +410,21 @@ So a valid IDT needs to have the `'static` lifetime. We can either create a `sta
static IDT: idt::Idt = {
let mut idt = idt::Idt::new();
idt.set_handler(14, page_fault_handler);
idt.set_handler(0, divide_by_zero_handler);
idt
};
extern "C" fn page_fault_handler() -> ! {
println!("EXCEPTION: PAGE FAULT");
extern "C" fn divide_by_zero_handler() -> ! {
println!("EXCEPTION: DIVIDE BY ZERO");
loop {}
}
```
We register a single handler function for a page fault (index 14). The handler function just prints an error message and enters a `loop`. However, it doesn't work this way:
We register a single handler function for a [divide by zero error] \(index 0). Like the name says, this exception occurs when dividing a number by 0. Thus we have an easy way to test our new exception handler.
[divide by zero error]: https://wiki.osdev.org/Exceptions#Division_Error
However, it doesn't work this way:
```
error: calls in statics are limited to constant functions, struct and enum
@@ -421,9 +437,27 @@ error: references in statics may only refer to immutable values [E0017]
```
The reason is that the Rust compiler is not able to evaluate the value of the `static` at compile time. Maybe it will work someday when `const` functions become more powerful. But until then, we have to find another solution.
### Lazy Statics to the Rescue
#### Lazy Statics to the Rescue
Fortunately the `lazy_static` macro exists. Instead of evaluating a `static` at compile time, the macro performs the initialization when the `static` is referenced the first time. Thus, we can do almost everything in the initialization block and are even able to read runtime values.
Let's add the `lazy_static` crate to our project:
```rust
// in src/lib.rs
#[macro_use]
extern crate lazy_static;
```
```toml
# in Cargo.toml
[dependencies.lazy_static]
version = "0.2.1"
features = ["spin_no_std"]
```
We need the `spin_no_std` feature, since we don't link the standard library.
With `lazy_static`, we can define our IDT without problems:
```rust
@@ -433,7 +467,7 @@ lazy_static! {
static ref IDT: idt::Idt = {
let mut idt = idt::Idt::new();
idt.set_handler(14, page_fault_handler);
idt.set_handler(0, divide_by_zero_handler);
idt
};
@@ -464,157 +498,65 @@ pub extern "C" fn rust_main(...) {
// initialize our IDT
interrupts::init();
// provoke a page fault by writing to some random address
unsafe{ *(0xdeadbeaf as *mut u64) = 42 };
// provoke a divide-by-zero fault
42 / 0;
println!("It did not crash!");
loop {}
}
```
It works! We see a `EXCEPTION: PAGE FAULT` message at the bottom of our screen:
When we run it, we get a runtime panic:
![QEMU screenshot with `EXCEPTION: PAGE FAULT` message](images/qemu-page-fault-println.png)
```
PANIC in src/lib.rs at line 57:
attempted to divide by zero
```
Let's try something else:
That's a not our exception handler. The reason is that Rust itself checks for a possible division by zero and panics in that case. So in order to raise a divide-by-zero error in the CPU, we need to bypass the Rust compiler somehow.
### Inline Assembly
In order to cause a divide-by-zero exception, we need to execute a [div] or [idiv] assembly instruction with operand 0. We could write a small assembly function and call it from our Rust code. An easier way is to use Rust's [inline assembly] macro.
[div]: https://www.felixcloutier.com/x86/div
[idiv]: https://www.felixcloutier.com/x86/idiv
[inline assembly]: https://doc.rust-lang.org/1.10.0/book/inline-assembly.html
Inline assembly allows us to write raw x86 assembly within a Rust function. The feature is unstable, so we need to add `#![feature(asm)]` to our `src/lib.rs`. Then we're able to write a `divide_by_zero` function:
```rust
fn divide_by_zero() {
unsafe {
asm!("mov dx, 0; div dx" ::: "ax", "dx" : "volatile", "intel")
}
}
```
Let's try to decode it:
- The `asm!` macro emits raw assembly instructions, so it's `unsafe` to use it.
- We insert two assembly instructions here: `mov dx, 0` and `div dx`. The former loads a 0 into the `dx` register (a subset of `rdx`) and the latter divides the `ax` register by `dx`. (The `div` instruction always implicitly operates on the `ax` register).
- The colons are separators. After the first `:` we could specify output operands and after the second `:` we could specify input operands. We need neither, so we leave these areas empty.
- After the third colon, we specify the so-called _clobbers_. These tell the compiler that our assembly modifies the values of some registers. Otherwise, the compiler assumes that the registers preserve their value. In our case, we clobber `dx` (we load 0 to it) and `ax` (the `div` instruction places the result in it).
- The last block (after the 4th colon) specifies some options. The `volatile` option tells the compiler: “This code has side effects. Do not delete it and do not move it elsewhere”. In our case, the “side effect” is the divide-by-zero exception. Finally, the `intel` option allows us to use the Intel assembly syntax instead of the default AT&T syntax.
Let's use our new `divide_by_zero` function to raise a CPU exception:
```rust
// in src/lib.rs
pub extern "C" fn rust_main(...) {
...
interrupts::init();
// provoke a page fault inside println
println!("{:?}", unsafe{ *(0xdeadbeaf as *mut u64) = 42 });
// provoke a divide-by-zero fault
divide_by_zero();
println!("It did not crash!");
loop {}
}
```
Now the output ends on the `guard page` line. No `EXCEPTION` message and no `It did not crash` message either. What's happening?
### Debugging
Let's debug it using [GDB]. It is a console debugger and works with nearly everything, including QEMU. To make QEMU listen for a debugger connection, we start it with the `-s` flag:
It works! We see a `EXCEPTION: DIVIDE BY ZERO` message at the bottom of our screen:
[GDB]: https://www.gnu.org/software/gdb/
```Makefile
# in `Makefile`
run: $(iso)
@qemu-system-x86_64 -cdrom $(iso) -s
```
Then we can launch GDB in another console window:
```
> gdb build/kernel-x86_64.bin
[some version, copyright, and usage information]
Reading symbols from build/kernel-x86_64.bin...done.
(gdb)
```
Now we can connect to our running QEMU instance on port `1234`:
```
(gdb) target remote :1234
Remote debugging using :1234
0x00000000001031bd in spin::mutex::cpu_relax ()
at /home/.../spin-0.3.5/src/mutex.rs:102
102 unsafe { asm!("pause" :::: "volatile"); }
```
So we're locked in a function named `mutex::cpu_relax` inside the `spin` crate. Let's try a backtrace:
```
(gdb) backtrace
#0 0x00000000001031bd in spin::mutex::cpu_relax ()
at /home/.../spin-0.3.5/src/mutex.rs:102
#1 spin::mutex::{{impl}}::obtain_lock<blog_os::vga_buffer::Writer> (
self=0x111230 <blog_os::vga_buffer::WRITER::h702c3f466147ac3b>)
at /home/.../spin-0.3.5/src/mutex.rs:142
#2 0x0000000000103143 in spin::mutex::{{impl}}::lock<blog_os::vga_buffer::
Writer> (
self=0x111230 <blog_os::vga_buffer::WRITER::h702c3f466147ac3b>)
at /home/.../spin-0.3.5/src/mutex.rs:163
#3 0x000000000010da59 in blog_os::interrupts::page_fault_handler ()
at src/vga_buffer.rs:31
...
```
Pretty verbose… but very useful. Let's clean it up a bit:
- `spin::mutex::cpu_relax`
- `spin::mutex::obtain_lock<vga_buffer::Writer>`
- `spin::mutex::lock<vga_buffer::Writer>`
- `blog_os::interrupts::page_fault_handler`
- ...
It's a _back_-trace, so it goes from the innermost function to the outermost function. We see that our page fault handler was called successfully. It then tried to write its error message. Therefore, it tried to `lock` the static `WRITER`, which in turn called `obtain_lock` and `cpu_relax`.
So our kernel tries to lock the output `WRITER`, which is already locked by the interrupted `println`. Thus, our exception handler waits forever and we don't see what error occurred. Yay, that's our first deadlock! :)
(As you see, GDB can be very useful sometimes. For more GDB information check out our [Set Up GDB] page.)
[Set Up GDB]: {{% relref "set-up-gdb.md" %}}
## Printing Errors Reliably
In order to guarantee that we always see error messages, we add a `print_error` function to our `vga_buffer` module:
```rust
// in src/vga_buffer.rs
pub unsafe fn print_error(fmt: fmt::Arguments) {
use core::fmt::Write;
let mut writer = Writer {
column_position: 0,
color_code: ColorCode::new(Color::Red, Color::Black),
buffer: Unique::new(0xb8000 as *mut _),
};
writer.new_line();
writer.write_fmt(fmt);
}
```
Instead of using the static `WRITER`, this function creates a new `Writer` on each invocation. Thereby it ignores the mutex and is always able to print to the screen without deadlocking. We print in red to highlight the error and add a newline to avoid overwriting unfinished lines.
### Safety
This function clearly violates the invariants of the `vga_buffer` module, as it creates another `Unique` pointing to `0xb8000`. Thus, we deliberately introduce a data race on the VGA buffer. For this reason, the function is marked as `unsafe` and should only be used if absolutely necessary.
However, the situation is not _that_ bad. The VGA buffer only stores characters (no pointers) and we never rely on the buffer's values. So the function might cause mangled output, but should never be able to violate memory safety.
### Using print_error
Let's use the new `print_error` function to print the page fault error:
```rust
// in src/interrupts/mod.rs
use vga_buffer::print_error;
extern "C" fn page_fault_handler() -> ! {
unsafe { print_error(format_args!("EXCEPTION: PAGE FAULT")) };
loop {}
}
```
We use the built-in [format_args] macro to translate the error string to a `fmt::Arguments` type. Now we should always see the error message, even if the exception occurred inside `println`:
[format_args]: https://doc.rust-lang.org/nightly/std/macro.format_args!.html
![QEMU screenshot with new red `EXCEPTION: PAGE FAULT` message](images/qemu-page-fault-red.png)
![QEMU screenshot with `EXCEPTION: DIVIDE BY ZERO` message](qemu-divide-error-println.png)
## What's next?
Now we're able to catch _almost_ all page faults. However, some page faults still cause a triple fault and a bootloop. For example, try the following code:
```rust
pub extern "C" fn rust_main(...) {
...
interrupts::init();
// provoke a kernel stack overflow, which hits the guard page
fn recursive() {
recursive();
}
recursive();
println!("It did not crash!");
loop {}
}
```
The next post will explore and fix this triple fault by creating a double fault handler. After that, we should never again experience a triple fault in our kernel.
We've successfully caught our first exception! However, our `EXCEPTION: DIVIDE BY ZERO` message doesn't contain much information about the cause of the exception. The next post improves the situation by printing i.a. the current stack pointer and address of the causing instruction. We will also explore other exceptions such as page faults, for which the CPU pushes an _error code_ on the stack.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,664 @@
+++
title = "Better Exception Messages"
weight = 2
path = "better-exception-messages"
aliases = ["better-exception-messages.html"]
date = 2016-08-03
template = "edition-1/page.html"
[extra]
updated = "2016-11-01"
+++
In this post, we explore exceptions in more detail. Our goal is to print additional information when an exception occurs, for example the values of the instruction and stack pointer. In the course of this, we will explore inline assembly and naked functions. We will also add a handler function for page faults and read the associated error code.
<!-- more -->
As always, the complete source code is on [GitHub]. Please file [issues] for any problems, questions, or improvement suggestions. There is also a [gitter chat] and a comment section at the end of this page.
[GitHub]: https://github.com/phil-opp/blog_os/tree/better_exception_messages
[issues]: https://github.com/phil-opp/blog_os/issues
[gitter chat]: https://gitter.im/phil-opp/blog_os
> **Note**: This post describes how to handle exceptions using naked functions (see [“Handling Exceptions with Naked Functions”] for an overview). Our new way of handling exceptions can be found in the [“Handling Exceptions”] post.
[“Handling Exceptions with Naked Functions”]: @/edition-1/extra/naked-exceptions/_index.md
[“Handling Exceptions”]: @/edition-1/posts/09-handling-exceptions/index.md
## Exceptions in Detail
An exception signals that something is wrong with the currently-executed instruction. Whenever an exception occurs, the CPU interrupts its current work and starts an internal exception routine.
This routine involves reading the interrupt descriptor table and invoking the registered handler function. But first, the CPU pushes various information onto the stack, which describe the current state and provide information about the cause of the exception:
![exception stack frame](exception-stack-frame.svg)
The pushed information contain the instruction and stack pointer, the current CPU flags, and (for some exceptions) an error code, which contains further information about the cause of the exception. Let's look at the fields in detail:
- First, the CPU aligns the stack pointer on a 16-byte boundary. This allows the handler function to use SSE instructions, which partly expect such an alignment.
- After that, the CPU pushes the stack segment descriptor (SS) and the old stack pointer (from before the alignment) onto the stack. This allows us to restore the previous stack pointer when we want to resume the interrupted program.
- Then the CPU pushes the contents of the [RFLAGS] register. This register contains various state information of the interrupted program. For example, it indicates if interrupts were enabled and whether the last executed instruction returned zero.
- Next the CPU pushes the instruction pointer and its code segment descriptor onto the stack. This tells us the address of the last executed instruction, which caused the exception.
- Finally, the CPU pushes an error code for some exceptions. This error code only exists for exceptions such as page faults or general protection faults and provides additional information. For example, it tells us whether a page fault was caused by a read or a write request.
[RFLAGS]: https://en.wikipedia.org/wiki/FLAGS_register
## Printing the Exception Stack Frame
Let's create a struct that represents the exception stack frame:
```rust
// in src/interrupts/mod.rs
#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
instruction_pointer: u64,
code_segment: u64,
cpu_flags: u64,
stack_pointer: u64,
stack_segment: u64,
}
```
The divide-by-zero fault pushes no error code, so we leave it out for now. Note that the stack grows downwards in memory, so we need to declare the fields in reverse order (compared to the figure above).
Now we need a way to find the memory address of this stack frame. When we look at the above graphic again, we see that the start address of the exception stack frame is the new stack pointer. So we just need to read the value of `rsp` at the very beginning of our handler function:
```rust
// in src/interrupts/mod.rs
extern "C" fn divide_by_zero_handler() -> ! {
let stack_frame: &ExceptionStackFrame;
unsafe {
asm!("mov $0, rsp" : "=r"(stack_frame) ::: "intel");
}
println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame);
loop {}
}
```
We're using [inline assembly] here to load the value from the `rsp` register into `stack_frame`. The syntax is a bit strange, so here's a quick explanation:
[inline assembly]: https://doc.rust-lang.org/1.10.0/book/inline-assembly.html
- The `asm!` macro emits raw assembly instructions. This is the only way to read raw register values in Rust.
- We insert a single assembly instruction: `mov $0, rsp`. It moves the value of `rsp` to some register (the `$0` is a placeholder for an arbitrary register, which gets filled by the compiler).
- The colons are separators. After the first colon, the `asm!` macro expects output operands. We're specifying our `stack_frame` variable as a single output operand here. The `=r` tells the compiler that it should use any register for the first placeholder `$0`.
- After the second colon, we can specify input operands. We don't need any, therefore we leave it empty.
- After the third colon, the macro expects so called [clobbers]. We don't change any register values, so we leave it empty too.
- The last block (after the 4th colon) specifies options. The `intel` option tells the compiler that our code is in Intel assembly syntax (instead of the default AT&T syntax).
[clobbers]: https://doc.rust-lang.org/1.10.0/book/inline-assembly.html#clobbers
So the inline assembly loads the stack pointer value to `stack_frame` at the very beginning of our function. Thus we have a pointer to the exception stack frame and are able to pretty-print its `Debug` formatting through the `{:#?}` argument.
### Testing it
Let's try it by executing `make run`:
![qemu printing an ExceptionStackFrame with strange values](qemu-print-stack-frame-try.png)
Those `ExceptionStackFrame` values look very wrong. The instruction pointer definitely shouldn't be 1 and the code segment should be `0x8` instead of some big number. So what's going on here?
### Debugging
It seems like we somehow got the pointer wrong. The `ExceptionStackFrame` type and our inline assembly seem correct, so something must be modifying `rsp` before we load it into `stack_frame`.
Let's see what's happening by looking at the disassembly of our function:
```
> objdump -d build/kernel-x86_64.bin | grep -A20 "divide_by_zero_handler"
[...]
000000000010ced0 <_ZN7blog_os10interrupts22divide_by_zero_handler17h62189e8E>:
10ced0: 55 push %rbp
10ced1: 48 89 e5 mov %rsp,%rbp
10ced4: 48 81 ec b0 00 00 00 sub $0xb0,%rsp
10cedb: 48 8d 45 98 lea -0x68(%rbp),%rax
10cedf: 48 b9 1d 1d 1d 1d 1d movabs $0x1d1d1d1d1d1d1d1d,%rcx
10cee6: 1d 1d 1d
10cee9: 48 89 4d 98 mov %rcx,-0x68(%rbp)
10ceed: 48 89 4d f8 mov %rcx,-0x8(%rbp)
10cef1: 48 89 e1 mov %rsp,%rcx
10cef4: 48 89 4d f8 mov %rcx,-0x8(%rbp)
10cef8: ...
[...]
```
Our `divide_by_zero_handler` starts at address `0x10ced0`. Let's look at the instruction at address `0x10cef1`:
```
mov %rsp,%rcx
```
This is our inline assembly instruction, which loads the stack pointer into the `stack_frame` variable. It just looks a bit different, since it's in AT&T syntax and contains `rcx` instead of our `$0` placeholder. It moves `rsp` to `rcx`, and then the next instruction (`mov %rcx,-0x8(%rbp)`) moves `rcx` to the variable on the stack.
We can clearly see the problem here: The compiler inserted various other instructions before our inline assembly. These instructions modify the stack pointer so that we don't read the original `rsp` value and get a wrong pointer. But why is the compiler doing this?
The reason is that we need some place on the stack to store things like variables. Therefore the compiler inserts a so-called _[function prologue]_, which prepares the stack and reserves space for all variables. In our case, the compiler subtracts from the stack pointer to make room for i.a. our `stack_frame` variable. This prologue is the first thing in every function and comes before every other code.
So in order to correctly load the exception frame pointer, we need some way to circumvent the automatic prologue generation.
[function prologue]: https://en.wikipedia.org/wiki/Function_prologue
### Naked Functions
Fortunately there is a way to disable the prologue: [naked functions]. A naked function has no prologue and immediately starts with the first instruction of its body. However, most Rust code requires the prologue. Therefore naked functions should only contain inline assembly.
[naked functions]: https://github.com/rust-lang/rfcs/blob/master/text/1201-naked-fns.md
A naked function looks like this (note the `#[naked]` attribute):
```rust
#[naked]
extern "C" fn naked_function_example() {
unsafe {
asm!("mov rax, 0x42" ::: "rax" : "intel");
};
}
```
Naked functions are highly unstable, so we need to add `#![feature(naked_functions)]` to our `src/lib.rs`.
If you want to try it, insert it in `src/lib.rs` and call it from `rust_main`. When we inspect the disassembly, we see that the function prologue is missing:
```
> objdump -d build/kernel-x86_64.bin | grep -A5 "naked_function_example"
[...]
000000000010df90 <_ZN7blog_os22naked_function_example17ha9f733dfe42b595dE>:
10df90: 48 c7 c0 2a 00 00 00 mov $0x42,%rax
10df97: c3 retq
10df98: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
10df9f: 00
```
It contains just the specified inline assembly and a return instruction (you can ignore the junk values after the return statement). So let's try to use a naked function to retrieve the exception frame pointer.
### A Naked Exception Handler
We can't use Rust code in naked functions, but we still want to use Rust in our exception handler. Therefore we split our handler function in two parts. A main exception handler in Rust and a small naked wrapper function, which just loads the exception frame pointer and then calls the main handler.
Our new two-stage exception handler looks like this:
```rust
// in src/interrupts/mod.rs
#[naked]
extern "C" fn divide_by_zero_wrapper() -> ! {
unsafe {
asm!(/* load exception frame pointer and call main handler */);
}
}
extern "C" fn divide_by_zero_handler(stack_frame: &ExceptionStackFrame)
-> !
{
println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}",
unsafe { &*stack_frame });
loop {}
}
```
The naked wrapper function retrieves the exception stack frame pointer and then calls the `divide_by_zero_handler` with the pointer as argument. We can't use Rust code in naked functions, so we need to do both things in inline assembly.
Retrieving the pointer to the exception stack frame is easy: We just need to load it from the `rsp` register. Our wrapper function has no prologue (it's naked), so we can be sure that nothing modifies the register before.
Calling the main handler is a bit more complicated, since we need to pass the argument correctly. Our main handler uses the C calling convention, which specifies that the the first argument is passed in the `rdi` register. So we need to load the pointer value into `rdi` and then use the `call` instruction to call `divide_by_zero_handler`.
Translated to assembly, it looks like this:
```nasm
mov rdi, rsp
call divide_by_zero_handler
```
It moves the exception stack frame pointer from `rsp` to `rdi`, where the first argument is expected, and then calls the main handler. Let's create the corresponding inline assembly to complete our wrapper function:
```rust
#[naked]
extern "C" fn divide_by_zero_wrapper() -> ! {
unsafe {
asm!("mov rdi, rsp; call $0"
:: "i"(divide_by_zero_handler as extern "C" fn(_) -> !)
: "rdi" : "intel");
}
}
```
Instead of `call divide_by_zero_handler`, we use a placeholder again. The reason is Rust's name mangling, which changes the name of the `divide_by_zero_handler` function. To circumvent this, we pass a function pointer as input parameter (after the second colon). The `"i"` tells the compiler that it is an immediate value, which can be directly inserted for the placeholder. We also specify a clobber after the third colon, which tells the compiler that we change the value of the `rdi` register.
### Intrinsics::Unreachable
When we try to compile it, we get the following error:
```
error: computation may converge in a function marked as diverging
--> src/interrupts/mod.rs:23:1
|>
23 |> extern "C" fn divide_by_zero_wrapper() -> ! {
|> ^
```
The reason is that we marked our `divide_by_zero_wrapper` function as diverging (the `!`). We call another diverging function in inline assembly, so it is clear that the function diverges. However, the Rust compiler doesn't understand inline assembly, so it doesn't know that. To fix this, we tell the compiler that all code after the `asm!` macro is unreachable:
```rust
#[naked]
extern "C" fn divide_by_zero_wrapper() -> ! {
unsafe {
asm!("mov rdi, rsp; call $0"
:: "i"(divide_by_zero_handler as extern "C" fn(_) -> !)
: "rdi" : "intel");
::core::intrinsics::unreachable();
}
}
```
The [intrinsics::unreachable] function is unstable, so we need to add `#![feature(core_intrinsics)]` to our `src/lib.rs`. It is just an annotation for the compiler and produces no real code. (Not to be confused with the [unreachable!] macro, which is completely different!)
[intrinsics::unreachable]: https://doc.rust-lang.org/nightly/core/intrinsics/fn.unreachable.html
[unreachable!]: https://doc.rust-lang.org/nightly/core/macro.unreachable!.html
### It works!
The last step is to update the interrupt descriptor table (IDT) to use our new wrapper function:
```rust
// in src/interrupts/mod.rs
lazy_static! {
static ref IDT: idt::Idt = {
let mut idt = idt::Idt::new();
idt.set_handler(0, divide_by_zero_wrapper); // changed
idt
};
}
```
Now we see a correct exception stack frame when we execute `make run`:
![QEMU showing correct divide by zero stack frame](qemu-divide-by-zero-stack-frame.png)
## Testing on real Hardware
Virtual machines such as QEMU are very convenient to quickly test our kernel. However, they might behave a bit different than real hardware in some situations. So we should test our kernel on real hardware, too.
Let's do it by burning it to an USB stick:
```
> sudo dd if=build/os-x86_64.iso of=/dev/sdX; and sync
```
Replace `sdX` by the device name of your USB stick. But **be careful**! The command will erase everything on that device.
Now we should be able to boot from this USB stick. When we do it, we see that it works fine on real hardware, too. Great!
However, this section wouldn't exist if there weren't a problem. To trigger this problem, we add some example code to the start of our `divide_by_zero_handler`:
```rust
// in src/interrupts/mod.rs
extern "C" fn divide_by_zero_handler(...) {
let x = (1u64, 2u64, 3u64);
let y = Some(x);
for i in (0..100).map(|z| (z, z - 1)) {}
println!(...);
loop {}
}
```
This is just some garbage code that doesn't do anything useful. When we try it in QEMU using `make run`, it still works fine. However, when we burn it to an USB stick again and boot from it on real hardware, we see that our computer reboots just before printing the exception message.
So our code, which worked well in QEMU, _causes a triple fault_ on real hardware. What's happening?
### Reproducing the Bug in QEMU
Debugging on a real machine is difficult. Fortunately there is a way to reproduce this bug in QEMU: We use Linux's [Kernel-based Virtual Machine] \(KVM) by passing the `enable-kvm` flag:
[Kernel-based Virtual Machine]: https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine
```
> qemu-system-x86_64 -cdrom build/os-x86_64.iso -enable-kvm
```
Now QEMU triple faults as well. This should make debugging much easier.
### Debugging
QEMU's `-d int`, which prints every exception, doesn't seem to work in KVM mode. However `-d cpu_reset` still works. It prints the complete CPU state whenever the CPU resets. Let's try it:
```
> qemu-system-x86_64 -cdrom build/os-x86_64.iso -enable-kvm -d cpu_reset
CPU Reset (CPU 0)
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
EIP=00000000 EFL=00000000 [-------] CPL=0 II=0 A20=0 SMM=0 HLT=0
[...]
CPU Reset (CPU 0)
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000663
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
EIP=0000fff0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
[...]
CPU Reset (CPU 0)
RAX=0000000000118cb8 RBX=0000000000000800 RCX=1d1d1d1d1d1d1d1d RDX=0..0000000
RSI=0000000000112cd0 RDI=0000000000118d38 RBP=0000000000118d28 RSP=0..0118c68
R8 =0000000000000000 R9 =0000000000000100 R10=0000000000118700 R11=0..0118a00
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0..0000000
RIP=000000000010cf08 RFL=00210002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
[...]
```
The first two resets occur while the CPU is still in 32-bit mode (`EAX` instead of `RAX`), so we ignore them. The third reset is the interesting one, because it occurs in 64-bit mode. The register dump tells us that the instruction pointer (`rip`) was `0x10cf08` just before the reset. This might be the address of the instruction that caused the triple fault.
We can find the corresponding instruction by disassembling our kernel:
```
objdump -d build/kernel-x86_64.bin | grep "10cf08:"
10cf08: 0f 29 45 b0 movaps %xmm0,-0x50(%rbp)
```
The [movaps] instruction is an [SSE] instruction that moves aligned 128bit values. It can fail for a number of reasons:
[movaps]: https://www.felixcloutier.com/x86/movaps
[SSE]: https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions
1. For an illegal memory operand effective address in the CS, DS, ES, FS or GS segments.
2. For an illegal address in the SS segment.
3. If a memory operand is not aligned on a 16-byte boundary.
4. For a page fault.
5. If TS in CR0 is set.
The segment registers contain no meaningful values in long mode, so they can't contain illegal addresses. We did not change the TS bit in [CR0] and there is no reason for a page fault either. So it has to be option 3.
[CR0]: https://en.wikipedia.org/wiki/Control_register#CR0
### 16-byte Alignment
Some SSE instructions such as `movaps` require that memory operands are 16-byte aligned. In our case, the instruction is `movaps %xmm0,-0x50(%rbp)`, which writes to address `rbp - 0x50`. Therefore `rbp` needs to be 16-byte aligned.
Let's look at the above `-d cpu_reset` dump again and check the value of `rbp`:
```
CPU Reset (CPU 0)
RAX=[...] RBX=[...] RCX=[...] RDX=[...]
RSI=[...] RDI=[...] RBP=0000000000118d28 RSP=[...]
...
```
`RBP` is `0x118d28`, which is _not_ 16-byte aligned. So this is the reason for the triple fault. (It seems like QEMU doesn't check the alignment for `movaps`, but real hardware of course does.)
But how did we end up with a misaligned `rbp` register?
### The Base Pointer
In order to solve this mystery, we need to look at the disassembly of the preceding code:
```
> objdump -d build/kernel-x86_64.bin | grep -B10 "10cf08:"
000000000010cee0 <_ZN7blog_os10interrupts22divide_by_zero_handler17hE>:
10cee0: 55 push %rbp
10cee1: 48 89 e5 mov %rsp,%rbp
10cee4: 48 81 ec c0 00 00 00 sub $0xc0,%rsp
10ceeb: 48 8d 45 90 lea -0x70(%rbp),%rax
10ceef: 48 b9 1d 1d 1d 1d 1d movabs $0x1d1d1d1d1d1d1d1d,%rcx
10cef6: 1d 1d 1d
10cef9: 48 89 4d 90 mov %rcx,-0x70(%rbp)
10cefd: 48 89 7d f8 mov %rdi,-0x8(%rbp)
10cf01: 0f 10 05 a8 51 00 00 movups 0x51a8(%rip),%xmm0
10cf08: 0f 29 45 b0 movaps %xmm0,-0x50(%rbp)
```
At the last line we have the `movaps` instruction, which caused the triple fault. The exception occurs inside our `divide_by_zero_handler` function. We see that `rbp` is loaded with the value of `rsp` at the beginning (at `0x10cee1`). The `rbp` register holds the so-called _base pointer_, which points to the beginning of the stack frame. It is used in the rest of the function to address variables and other values on the stack.
The base pointer is initialized directly from the stack pointer (`rsp`) after pushing the old base pointer. There is no special alignment code, so the compiler blindly assumes that `(rsp - 8)`[^fn-rsp-8] is always 16-byte aligned. This seems to be wrong in our case. But why does the compiler assume this?
[^fn-rsp-8]: By pushing the old base pointer, `rsp` is updated to `rsp-8`.
### Calling Conventions
The reason is that our exception handler is defined as `extern "C" function`, which specifies that it's using the C [calling convention]. On x86_64 Linux, the C calling convention is specified by the System V AMD64 ABI ([PDF][system v abi]). Section 3.2.2 defines the following:
[calling convention]: https://en.wikipedia.org/wiki/X86_calling_conventions
[system v abi]: https://web.archive.org/web/20160801075139/https://www.x86-64.org/documentation/abi.pdf
> The end of the input argument area shall be aligned on a 16 byte boundary. In other words, the value (%rsp + 8) is always a multiple of 16 when control is transferred to the function entry point.
The “end of the input argument area” refers to the last stack-passed argument (in our case there aren't any). So the stack pointer must be 16 byte aligned whenever we `call` a C-compatible function. The `call` instruction then pushes the return value on the stack so that “the value (%rsp + 8) is a multiple of 16 when control is transferred to the function entry point”.
_Summary_: The calling convention requires a 16 byte aligned stack pointer before `call` instructions. The compiler relies on this requirement, but we broke it somehow. Thus the generated code triple faults due to a misaligned memory address in the `movaps` instruction.
### Fixing the Alignment
In order to fix this bug, we need to make sure that the stack pointer is correctly aligned before calling `extern "C"` functions. Let's summarize the stack pointer modifications that occur before the exception handler is called:
1. The CPU aligns the stack pointer to a 16 byte boundary.
2. The CPU pushes `ss`, `rsp`, `rflags`, `cs`, and `rip`. So it pushes five 8 byte registers, which makes `rsp` misaligned.
3. The wrapper function calls `divide_by_zero_handler` with a misaligned stack pointer.
The problem is that we're pushing an uneven number of 8 byte registers. Thus we need to align the stack pointer again before the `call` instruction:
```rust
#[naked]
extern "C" fn divide_by_zero_wrapper() -> ! {
unsafe {
asm!("mov rdi, rsp
sub rsp, 8 // align the stack pointer
call $0"
:: "i"(divide_by_zero_handler as extern "C" fn(_) -> !)
: "rdi" : "intel");
::core::intrinsics::unreachable();
}
}
```
The additional `sub rsp, 8` instruction aligns the stack pointer to a 16 byte boundary. Now it should work on real hardware (and in QEMU KVM mode) again.
## A Handler Macro
The next step is to add handlers for other exceptions. However, we would need wrapper functions for them too. To avoid this code duplication, we create a `handler` macro that creates the wrapper functions for us:
```rust
// in src/interrupts/mod.rs
macro_rules! handler {
($name: ident) => {{
#[naked]
extern "C" fn wrapper() -> ! {
unsafe {
asm!("mov rdi, rsp
sub rsp, 8 // align the stack pointer
call $0"
:: "i"($name as extern "C" fn(
&ExceptionStackFrame) -> !)
: "rdi" : "intel");
::core::intrinsics::unreachable();
}
}
wrapper
}}
}
```
The macro takes a single Rust identifier (`ident`) as argument and expands to a `{}` block (hence the double braces). The block defines a new wrapper function that calls the function `$name` and passes a pointer to the exception stack frame. Note that we're fixing the argument type to `&ExceptionStackFrame`. If we used a `_` like before, the passed function could accept an arbitrary argument, which would lead to ugly bugs at runtime.
Now we can remove the `divide_by_zero_wrapper` and use our new `handler!` macro instead:
```rust
// in src/interrupts/mod.rs
lazy_static! {
static ref IDT: idt::Idt = {
let mut idt = idt::Idt::new();
idt.set_handler(0, handler!(divide_by_zero_handler)); // new
idt
};
}
```
Note that the `handler!` macro needs to be defined above the static `IDT`, because macros are only available after their definition.
### Invalid Opcode Exception
With the `handler!` macro we can create new handler functions easily. For example, we can add a handler for the invalid opcode exception as follows:
```rust
// in src/interrupts/mod.rs
lazy_static! {
static ref IDT: idt::Idt = {
let mut idt = idt::Idt::new();
idt.set_handler(0, handler!(divide_by_zero_handler));
idt.set_handler(6, handler!(invalid_opcode_handler)); // new
idt
};
}
extern "C" fn invalid_opcode_handler(stack_frame: &ExceptionStackFrame)
-> !
{
let stack_frame = unsafe { &*stack_frame };
println!("\nEXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
stack_frame.instruction_pointer, stack_frame);
loop {}
}
```
Invalid opcode faults have the vector number 6, so we set the 6th IDT entry. This time we additionally print the address of the invalid instruction.
We can test our new handler with the special [ud2] instruction, which generates a invalid opcode:
[ud2]: https://www.felixcloutier.com/x86/ud
```rust
// in src/lib.rs
#[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) {
...
// initialize our IDT
interrupts::init();
// provoke a invalid opcode exception
unsafe { asm!("ud2") };
println!("It did not crash!");
loop {}
}
```
## Exceptions with Error Codes
When a divide-by-zero exception occurs, we immediately know the reason: Someone tried to divide by zero. In contrast, there are faults with many possible causes. For example, a page fault occurs in many occasions: When accessing a non-present page, when writing to a read-only page, when the page table is malformed, etc. In order to differentiate these causes, the CPU pushes an additional error code onto the stack for such exceptions, which gives additional information.
### A new Macro
Since the CPU pushes an additional error code, the stack frame is different and our `handler!` macro is not applicable. Therefore we create a new `handler_with_error_code!` macro for them:
```rust
// in src/interrupts/mod.rs
macro_rules! handler_with_error_code {
($name: ident) => {{
#[naked]
extern "C" fn wrapper() -> ! {
unsafe {
asm!("pop rsi // pop error code into rsi
mov rdi, rsp
sub rsp, 8 // align the stack pointer
call $0"
:: "i"($name as extern "C" fn(
&ExceptionStackFrame, u64) -> !)
: "rdi","rsi" : "intel");
::core::intrinsics::unreachable();
}
}
wrapper
}}
}
```
The difference to the `handler!` macro is the additional error code argument. The CPU pushes the error code last, so we pop it right at the beginning of the wrapper function. We pop it into `rsi` because the C calling convention expects the second argument in it.
### A Page Fault Handler
Let's write a page fault handler which analyzes and prints the error code:
```rust
// in src/interrupts/mod.rs
extern "C" fn page_fault_handler(stack_frame: &ExceptionStackFrame,
error_code: u64) -> !
{
println!(
"\nEXCEPTION: PAGE FAULT with error code {:?}\n{:#?}",
error_code, unsafe { &*stack_frame });
loop {}
}
```
We need to register our new handler function in the static interrupt descriptor table (IDT):
```rust
// in src/interrupts/mod.rs
lazy_static! {
static ref IDT: idt::Idt = {
let mut idt = idt::Idt::new();
idt.set_handler(0, handler!(divide_by_zero_handler));
idt.set_handler(6, handler!(invalid_opcode_handler));
// new
idt.set_handler(14, handler_with_error_code!(page_fault_handler));
idt
};
}
```
Page faults have the vector number 14, so we set the 14th IDT entry.
#### Testing it
Let's test our new page fault handler by provoking a page fault in our main function:
```rust
// in src/lib.rs
#[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) {
...
// initialize our IDT
interrupts::init();
// provoke a page fault
unsafe { *(0xdeadbeaf as *mut u64) = 42 };
println!("It did not crash!");
loop {}
}
```
We get the following output:
![QEMU: page fault with error code 2 and stack frame dump](qemu-page-fault-handler.png)
### The Page Fault Error Code
“Error code 2” is not really an useful error message. Let's improve this by creating a `PageFaultErrorCode` type:
```rust
// in src/interrupts/mod.rs
bitflags! {
struct PageFaultErrorCode: u64 {
const PROTECTION_VIOLATION = 1 << 0;
const CAUSED_BY_WRITE = 1 << 1;
const USER_MODE = 1 << 2;
const MALFORMED_TABLE = 1 << 3;
const INSTRUCTION_FETCH = 1 << 4;
}
}
```
- When the `PROTECTION_VIOLATION` flag is set, the page fault was caused e.g. by a write to a read-only page. If it's not set, it was caused by accessing a non-present page.
- The `CAUSED_BY_WRITE` flag specifies if the fault was caused by a write (if set) or a read (if not set).
- The `USER_MODE` flag is set when the fault occurred in non-privileged mode.
- The `MALFORMED_TABLE` flag is set when the page table entry has a 1 in a reserved field.
- When the `INSTRUCTION_FETCH` flag is set, the page fault occurred while fetching the next instruction.
Now we can improve our page fault error message by using the new `PageFaultErrorCode`. We also print the accessed memory address:
```rust
extern "C" fn page_fault_handler(stack_frame: &ExceptionStackFrame,
error_code: u64) -> !
{
use x86_64::registers::control_regs;
println!(
"\nEXCEPTION: PAGE FAULT while accessing {:#x}\
\nerror code: {:?}\n{:#?}",
unsafe { control_regs::cr2() },
PageFaultErrorCode::from_bits(error_code).unwrap(),
unsafe { &*stack_frame });
loop {}
}
```
The `from_bits` function tries to convert the `u64` into a `PageFaultErrorCode`. We use `unwrap` to panic if the error code has invalid bits set, since this indicates an error in our `PageFaultErrorCode` definition or a stack corruption. We also print the contents of the `cr2` register. It contains the accessed memory address, which was the cause of the page fault.
Now we get a useful error message when a page fault occurs, which allows us to debug it more easily:
![QEMU: output is now `PAGE FAULT with error code CAUSED_BY_WRITE`](qemu-page-fault-error-code.png)
As expected, the page fault was caused by write to `0xdeadbeaf`. The `PROTECTION_VIOLATION` flag is not set, so the accessed page was not present.
## What's next?
Now we're able to catch and analyze various exceptions. The next step is to _resolve_ exceptions, if possible. An example is [demand paging]: The OS swaps out memory pages to disk so that a page fault occurs when the page is accessed the next time. In that case, the OS can resolve the exception by bringing the page back into memory. Afterwards, the OS resumes the interrupted program as if nothing had happened.
[demand paging]: https://en.wikipedia.org/wiki/Demand_paging
The next post will implement the first portion of demand paging: saving and restoring the complete state of an program. This will allow us to transparently interrupt and resume programs in the future.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -0,0 +1,905 @@
+++
title = "Returning from Exceptions"
weight = 3
path = "returning-from-exceptions"
aliases = ["returning-from-exceptions.html"]
date = 2016-09-21
template = "edition-1/page.html"
[extra]
updated = "2016-11-01"
+++
In this post, we learn how to return from exceptions correctly. In the course of this, we will explore the `iretq` instruction, the C calling convention, multimedia registers, and the red zone.
<!-- more -->
As always, the complete source code is on [GitHub]. Please file [issues] for any problems, questions, or improvement suggestions. There is also a [gitter chat] and a comment section at the end of this page.
[GitHub]: https://github.com/phil-opp/blog_os/tree/returning_from_exceptions
[issues]: https://github.com/phil-opp/blog_os/issues
[gitter chat]: https://gitter.im/phil-opp/blog_os
> **Note**: This post describes how to handle exceptions using naked functions (see [“Handling Exceptions with Naked Functions”] for an overview). Our new way of handling exceptions can be found in the [“Handling Exceptions”] post.
[“Handling Exceptions with Naked Functions”]: @/edition-1/extra/naked-exceptions/_index.md
[“Handling Exceptions”]: @/edition-1/posts/09-handling-exceptions/index.md
## Introduction
Most exceptions are fatal and can't be resolved. For example, we can't return from a divide-by-zero exception in a reasonable way. However, there are some exceptions that we can resolve:
Imagine a system that uses [memory mapped files]: We map a file into the virtual address space without loading it into memory. Whenever we access a part of the file for the first time, a page fault occurs. However, this page fault is not fatal. We can resolve it by loading the corresponding page from disk into memory and setting the `present` flag in the page table. Then we can return from the page fault handler and restart the failed instruction, which now successfully accesses the file data.
[memory mapped files]: https://en.wikipedia.org/wiki/Memory-mapped_file
Memory mapped files are completely out of scope for us right now (we have neither a file concept nor a hard disk driver). So we need an exception that we can resolve easily so that we can return from it in a reasonable way. Fortunately, there is an exception that needs no resolution at all: the breakpoint exception.
## The Breakpoint Exception
The breakpoint exception is the perfect exception to test our upcoming return-from-exception logic. Its only purpose is to temporary pause a program when the breakpoint instruction `int3` is executed.
The breakpoint exception is commonly used in debuggers: When the user sets a breakpoint, the debugger overwrites the corresponding instruction with the `int3` instruction so that the CPU throws the breakpoint exception when it reaches that line. When the user wants to continue the program, the debugger replaces the `int3` instruction with the original instruction again and continues the program. For more details, see the [How debuggers work] series.
[How debuggers work]: https://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints
For our use case, we don't need to overwrite any instructions (it wouldn't even be possible since we [set the page table flags] to read-only). Instead, we just want to print a message when the breakpoint instruction is executed and then continue the program.
[set the page table flags]: @/edition-1/posts/07-remap-the-kernel/index.md#using-the-correct-flags
### Catching Breakpoints
Let's start by defining a handler function for the breakpoint exception:
```rust
// in src/interrupts/mod.rs
extern "C" fn breakpoint_handler(stack_frame: &ExceptionStackFrame) -> !
{
let stack_frame = unsafe { &*stack_frame };
println!("\nEXCEPTION: BREAKPOINT at {:#x}\n{:#?}",
stack_frame.instruction_pointer, stack_frame);
loop {}
}
```
We print an error message and also output the instruction pointer and the rest of the stack frame. Note that this function does _not_ return yet, since our `handler!` macro still requires a diverging function.
We need to register our new handler function in the interrupt descriptor table (IDT):
```rust
// in src/interrupts/mod.rs
lazy_static! {
static ref IDT: idt::Idt = {
let mut idt = idt::Idt::new();
idt.set_handler(0, handler!(divide_by_zero_handler));
idt.set_handler(3, handler!(breakpoint_handler)); // new
idt.set_handler(6, handler!(invalid_opcode_handler));
idt.set_handler(14, handler_with_error_code!(page_fault_handler));
idt
};
}
```
We set the IDT entry with number 3 since it's the vector number of the breakpoint exception.
#### Testing it
In order to test it, we insert an `int3` instruction in our `rust_main`:
```rust
// in src/lib.rs
...
#[macro_use] // needed for the `int!` macro
extern crate x86_64;
...
#[no_mangle]
pub extern "C" fn rust_main(...) {
...
interrupts::init();
// trigger a breakpoint exception
unsafe { int!(3) };
println!("It did not crash!");
loop {}
}
```
When we execute `make run`, we see the following:
![QEMU showing `EXCEPTION: BREAKPOINT at 0x110970` and a dump of the exception stack frame](qemu-breakpoint-handler.png)
It works! Now we “just” need to return from the breakpoint handler somehow so that we see the `It did not crash` message again.
## Returning from Exceptions
So how do we return from exceptions? To make it easier, we look at a normal function return first:
![function stack frame](function-stack-frame.svg)
When calling a function, the `call` instruction pushes the return address on the stack. When the called function is finished, it can return to the parent function through the `ret` instruction, which pops the return address from the stack and then jumps to it.
The exception stack frame, in contrast, looks a bit different:
![exception stack frame](exception-stack-frame.svg)
Instead of pushing a return address, the CPU pushes the stack and instruction pointers (with their segment descriptors), the RFLAGS register, and an optional error code. It also aligns the stack pointer to a 16 byte boundary before pushing values.
So we can't use a normal `ret` instruction, since it expects a different stack frame layout. Instead, there is a special instruction for returning from exceptions: `iretq`.
### The `iretq` Instruction
The `iretq` instruction is the one and only way to return from exceptions and is specifically designed for this purpose. The AMD64 instruction manual ([PDF][amd-manual]) even demands that `iretq` “_must_ be used to terminate the exception or interrupt handler associated with the exception”.
[amd-manual]: https://www.amd.com/system/files/TechDocs/24594.pdf
IRETQ restores `rip`, `cs`, `rflags`, `rsp`, and `ss` from the values saved on the stack and thus continues the interrupted program. The instruction does not handle the optional error code, so it must be popped from the stack before.
We see that `iretq` treats the stored instruction pointer as return address. For most exceptions, the stored `rip` points to the instruction that caused the fault. So by executing `iretq`, we restart the failing instruction. This makes sense because we should have resolved the exception when returning from it, so the instruction should no longer fail (e.g. the accessed part of the memory mapped file is now present in memory).
The situation is a bit different for the breakpoint exception, since it needs no resolution. Restarting the `int3` instruction wouldn't make sense, since it would cause a new breakpoint exception and we would enter an endless loop. For this reason the hardware designers decided that the stored `rip` should point to the next instruction after the `int3` instruction.
Let's check this for our breakpoint handler. Remember, the handler printed the following message (see the image above):
```
EXCEPTION: BREAKPOINT at 0x110970
```
So let's disassemble the instruction at `0x110970` and its predecessor:
```bash
> objdump -d build/kernel-x86_64.bin | grep -B1 "110970:"
11096f: cc int3
110970: 48 c7 01 2a 00 00 00 movq $0x2a,(%rcx)
```
We see that `0x110970` indeed points to the next instruction after `int3`. So we can simply jump to the stored instruction pointer when we want to return from the breakpoint exception.
### Implementation
Let's update our `handler!` macro to support non-diverging exception handlers:
```rust
// in src/interrupts/mod.rs
macro_rules! handler {
($name: ident) => {{
#[naked]
extern "C" fn wrapper() -> ! {
unsafe {
asm!("mov rdi, rsp
sub rsp, 8 // align the stack pointer
call $0"
:: "i"($name as extern "C" fn(
&ExceptionStackFrame)) // no longer diverging
: "rdi" : "intel", "volatile");
// new
asm!("add rsp, 8 // undo stack pointer alignment
iretq"
:::: "intel", "volatile");
::core::intrinsics::unreachable();
}
}
wrapper
}}
}
```
When an exception handler returns from the `call` instruction, we use the `iretq` instruction to continue the interrupted program. Note that we need to undo the stack pointer alignment before, so that `rsp` points to the end of the exception stack frame again.
We've changed the handler function type, so we need to adjust our existing exception handlers:
```diff
// in src/interrupts/mod.rs
extern "C" fn divide_by_zero_handler(
- stack_frame: &ExceptionStackFrame) -> ! {...}
+ stack_frame: &ExceptionStackFrame) {...}
extern "C" fn invalid_opcode_handler(
- stack_frame: &ExceptionStackFrame) -> ! {...}
+ stack_frame: &ExceptionStackFrame) {...}
extern "C" fn breakpoint_handler(
- stack_frame: &ExceptionStackFrame) -> ! {
+ stack_frame: &ExceptionStackFrame) {
println!(...);
- loop {}
}
```
Note that we also removed the `loop {}` at the end of our `breakpoint_handler` so that it no longer diverges. The `divide_by_zero_handler` and the `invalid_opcode_handler` still diverge (albeit the new function type would allow a return).
### Testing
Let's try our new `iretq` logic:
![QEMU output with `EXCEPTION BREAKPOINT` and `EXCEPTION PAGE FAULT` but no `It did not crash`](qemu-breakpoint-return-page-fault.png)
Instead of the expected _“It did not crash”_ message after the breakpoint exception, we get a page fault. The strange thing is that our kernel tried to access address `0x1`, which should never happen. So it seems like we messed up something important.
### Debugging
Let's debug it using GDB. For that we execute `make debug` in one terminal (which starts QEMU with the `-s -S` flags) and then `make gdb` (which starts and connects GDB) in a second terminal. For more information about GDB debugging, check out our [Set Up GDB] guide.
[Set Up GDB]: @/edition-1/extra/set-up-gdb/index.md
First we want to check if our `iretq` was successful. Therefore we set a breakpoint on the `println!("It did not crash line!")` statement in `src/lib.rs`. Let's assume that it's on line 61:
```
(gdb) break blog_os/src/lib.rs:61
Breakpoint 1 at 0x110a95: file /home/.../blog_os/src/lib.rs, line 61.
```
This line is after the `int3` instruction, so we know that the `iretq` succeeded when the breakpoint is hit. To test this, we continue the execution:
```
(gdb) continue
Continuing.
Breakpoint 1, blog_os::rust_main (multiboot_information_address=1539136)
at /home/.../blog_os/src/lib.rs:61
61 println!("It did not crash!");
```
It worked! So our kernel successfully returned from the `int3` instruction, which means that the `iretq` itself works.
However, when we `continue` the execution again, we get the page fault. So the exception occurs somewhere in the `println` logic. This means that it occurs in code generated by the compiler (and not e.g. in inline assembly). But the compiler should never access `0x1`, so how is this happening?
The answer is that we've used the wrong _calling convention_ for our exception handlers. Thus, we violate some compiler invariants so that the code that works fine without intermediate exceptions starts to violate memory safety when it's executed after a breakpoint exception.
## Calling Conventions
Exceptions are quite similar to function calls: The CPU jumps to the first instruction of the (handler) function and executes the function. Afterwards, if the function is not diverging, the CPU jumps to the return address and continues the execution of the parent function.
However, there is a major difference between exceptions and function calls: A function call is invoked voluntary by a compiler inserted `call` instruction, while an exception might occur at _any_ instruction. In order to understand the consequences of this difference, we need to examine function calls in more detail.
[Calling conventions] specify the details of a function call. For example, they specify where function parameters are placed (e.g. in registers or on the stack) and how results are returned. On x86_64 Linux, the following rules apply for C functions (specified in the [System V ABI]):
[Calling conventions]: https://en.wikipedia.org/wiki/Calling_convention
[System V ABI]: https://refspecs.linuxbase.org/elf/gabi41.pdf
- the first six integer arguments are passed in registers `rdi`, `rsi`, `rdx`, `rcx`, `r8`, `r9`
- additional arguments are passed on the stack
- results are returned in `rax` and `rdx`
Note that Rust does not follow the C ABI (in fact, [there isn't even a Rust ABI yet][rust abi]). So these rules apply only to functions declared as `extern "C" fn`.
[rust abi]: https://github.com/rust-lang/rfcs/issues/600
### Preserved and Scratch Registers
The calling convention divides the registers in two parts: _preserved_ and _scratch_ registers.
The values of the preserved register must remain unchanged across function calls. So a called function (the _“callee”_) is only allowed to overwrite these registers if it restores their original values before returning. Therefore these registers are called _“callee-saved”_. A common pattern is to save these registers to the stack at the function's beginning and restore them just before returning.
In contrast, a called function is allowed to overwrite scratch registers without restrictions. If the caller wants to preserve the value of a scratch register across a function call, it needs to backup and restore it (e.g. by pushing it to the stack before the function call). So the scratch registers are _caller-saved_.
On x86_64, the C calling convention specifies the following preserved and scratch registers:
preserved registers | scratch registers
---|---
`rbp`, `rbx`, `rsp`, `r12`, `r13`, `r14`, `r15` | `rax`, `rcx`, `rdx`, `rsi`, `rdi`, `r8`, `r9`, `r10`, `r11`
_callee-saved_ | _caller-saved_
The compiler knows these rules, so it generates the code accordingly. For example, most functions begin with a `push rbp`, which backups `rbp` on the stack (because it's a callee-saved register).
### The Exception Calling Convention
In contrast to function calls, exceptions can occur on _any_ instruction. In most cases we don't even know at compile time if the generated code will cause an exception. For example, the compiler can't know if an instruction causes a stack overflow or an other page fault.
Since we don't know when an exception occurs, we can't backup any registers before. This means that we can't use a calling convention that relies on caller-saved registers for our exception handlers. But we do so at the moment: Our exception handlers are declared as `extern "C" fn` and thus use the C calling convention.
So here is what happens:
- `rust_main` is executing; it writes some memory address into `rax`.
- The `int3` instruction causes a breakpoint exception.
- Our `breakpoint_handler` prints to the screen and assumes that it can overwrite `rax` freely (since it's a scratch register). Somehow the value `0` ends up in `rax`.
- We return from the breakpoint exception using `iretq`.
- `rust_main` continues and accesses the memory address in `rax`.
- The CPU tries to access address `0x1`, which causes a page fault.
So our exception handler erroneously assumes that the scratch registers were saved by the caller. But the caller (`rust_main`) couldn't save any registers since it didn't know that an exception occurs. So nobody saves `rax` and the other scratch registers, which leads to the page fault.
The problem is that we use a calling convention with caller-saved registers for our exception handlers. Instead, we need a calling convention means that preserves _all registers_. In other words, all registers must be callee-saved:
```rust
extern "all-registers-callee-saved" fn exception_handler() {...}
```
Unfortunately, Rust does not support such a calling convention. It was [proposed once][interrupt calling conventions], but did not get accepted for various reasons. The primary reason was that such calling conventions can be simulated by writing a naked wrapper function.
(Remember: [Naked functions] are functions without prologue and can contain only inline assembly. They were discussed in the [previous post][naked fn post].)
[interrupt calling conventions]: https://github.com/rust-lang/rfcs/pull/1275
[Naked functions]: https://github.com/rust-lang/rfcs/blob/master/text/1201-naked-fns.md
[naked fn post]: @/edition-1/extra/naked-exceptions/02-better-exception-messages/index.md#naked-functions
### A naked wrapper function
Such a naked wrapper function might look like this:
```rust
#[naked]
extern "C" fn calling_convention_wrapper() {
unsafe {
asm!("
push rax
push rcx
push rdx
push rsi
push rdi
push r8
push r9
push r10
push r11
// TODO: call exception handler with C calling convention
pop r11
pop r10
pop r9
pop r8
pop rdi
pop rsi
pop rdx
pop rcx
pop rax
" :::: "intel", "volatile");
}
}
```
This wrapper function saves all _scratch_ registers to the stack before calling the exception handler and restores them afterwards. Note that we `pop` the registers in reverse order.
We don't need to backup _preserved_ registers since they are callee-saved in the C calling convention. Thus, the compiler already takes care of preserving their values.
### Fixing our Handler Macro
Let's update our handler macro to fix the calling convention problem. Therefore we need to backup and restore all scratch registers. For that we create two new macros:
```rust
// in src/interrupts/mod.rs
macro_rules! save_scratch_registers {
() => {
asm!("push rax
push rcx
push rdx
push rsi
push rdi
push r8
push r9
push r10
push r11
" :::: "intel", "volatile");
}
}
macro_rules! restore_scratch_registers {
() => {
asm!("pop r11
pop r10
pop r9
pop r8
pop rdi
pop rsi
pop rdx
pop rcx
pop rax
" :::: "intel", "volatile");
}
}
```
We need to declare these macros _above_ our `handler` macro, since macros are only available after their declaration.
Now we can use these macros to fix our `handler!` macro:
```rust
// in src/interrupts/mod.rs
macro_rules! handler {
($name: ident) => {{
#[naked]
extern "C" fn wrapper() -> ! {
unsafe {
save_scratch_registers!();
asm!("mov rdi, rsp
add rdi, 9*8 // calculate exception stack frame pointer
// sub rsp, 8 (stack is aligned already)
call $0"
:: "i"($name as
extern "C" fn(&ExceptionStackFrame))
: "rdi" : "intel", "volatile");
restore_scratch_registers!();
asm!("
// add rsp, 8 (undo stack alignment; not needed anymore)
iretq"
:::: "intel", "volatile");
::core::intrinsics::unreachable();
}
}
wrapper
}}
}
```
It's important that we save the registers first, before we modify any of them. After the `call` instruction (but before `iretq`) we restore the registers again. Because we're now changing `rsp` (by pushing the register values) before we load it into `rdi`, we would get a wrong exception stack frame pointer. Therefore we need to adjust it by adding the number of bytes we push. We push 9 registers that are 8 bytes each, so `9 * 8` bytes in total.
Note that we no longer need to manually align the stack pointer, because we're pushing an uneven number of registers in `save_scratch_registers`. Thus the stack pointer already has the required 16-byte alignment.
### Testing it again
Let's test it again with our corrected `handler!` macro:
![QEMU output with `EXCEPTION BREAKPOINT` and `It did not crash`](qemu-breakpoint-return.png)
The page fault is gone and we see the _“It did not crash”_ message again!
So the page fault occurred because our exception handler didn't preserve the scratch register `rax`. Our new `handler!` macro fixes this problem by saving all scratch registers (including `rax`) before calling exception handlers. Thus, `rax` still contains the valid memory address when `rust-main` continues execution.
## Multimedia Registers
When we discussed calling conventions above, we assumed that a x86_64 CPU only has the following 16 registers: `rax`, `rbx`, `rcx`, `rdx`, `rsi`, `rdi`, `rsp`, `rbp`, `r8`, `r9`, `r10`, `r11`.`r12`, `r13`, `r14`, and `r15`. These registers are called _general purpose registers_ since each of them can be used for arithmetic and load/store instructions.
However, modern CPUs also have a set of _special purpose registers_, which can be used to improve performance in several use cases. On x86_64, the most important set of special purpose registers are the _multimedia registers_. These registers are larger than the general purpose registers and can be used to speed up audio/video processing or matrix calculations. For example, we could use them to add two 4-dimensional vectors _in a single CPU instruction_:
![`(1,2,3,4) + (5,6,7,8) = (6,8,10,12)`](vector-addition.png)
Such multimedia instructions are called [Single Instruction Multiple Data (SIMD)] instructions, because they simultaneously perform an operation (e.g. addition) on multiple data words. Good compilers are able to transform normal loops into such SIMD code automatically. This process is called [auto-vectorization] and can lead to huge performance improvements.
[Single Instruction Multiple Data (SIMD)]: https://en.wikipedia.org/wiki/SIMD
[auto-vectorization]: https://en.wikipedia.org/wiki/Automatic_vectorization
However, auto-vectorization causes a problem for us: Most of the multimedia registers are caller-saved. According to our discussion of calling conventions above, this means that our exception handlers erroneously assume that they are allowed to overwrite them without preserving their values.
We don't use any multimedia registers explicitly, but the Rust compiler might auto-vectorize our code (including the exception handlers). Thus we could silently clobber the multimedia registers, which leads to the same problems as above:
![example: program uses mm0, mm1, and mm2. Then the exception handler clobbers mm1.](xmm-overwrite.svg)
This example shows a program that is using the first three multimedia registers (`mm0` to `mm2`). At some point, an exception occurs and control is transferred to the exception handler. The exception handler uses `mm1` for its own data and thus overwrites the previous value. When the exception is resolved, the CPU continues the interrupted program again. However, the program is now corrupt since it relies on the original `mm1` value.
### Saving and Restoring Multimedia Registers
In order to fix this problem, we need to backup all caller-saved multimedia registers before we call the exception handler. The problem is that the set of multimedia registers varies between CPUs. There are different standards:
- [MMX]: The MMX instruction set was introduced in 1997 and defines eight 64 bit registers called `mm0` through `mm7`. These registers are just aliases for the registers of the [x87 floating point unit].
- [SSE]: The _Streaming SIMD Extensions_ instruction set was introduced in 1999. Instead of re-using the floating point registers, it adds a completely new register set. The sixteen new registers are called `xmm0` through `xmm15` and are 128 bits each.
- [AVX]: The _Advanced Vector Extensions_ are extensions that further increase the size of the multimedia registers. The new registers are called `ymm0` through `ymm15` and are 256 bits each. They extend the `xmm` registers, so e.g. `xmm0` is the lower (or upper?) half of `ymm0`.
[MMX]: https://en.wikipedia.org/wiki/MMX_(instruction_set)
[x87 floating point unit]: https://en.wikipedia.org/wiki/X87
[SSE]: https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions
[AVX]: https://en.wikipedia.org/wiki/Advanced_Vector_Extensions
The Rust compiler (and LLVM) assume that the `x86_64-unknown-linux-gnu` target supports only MMX and SSE, so we don't need to save the `ymm0` through `ymm15`. But we need to save `xmm0` through `xmm15` and also `mm0` through `mm7`. There is a special instruction to do this: [fxsave]. This instruction saves the floating point and multimedia state to a given address. It needs _512 bytes_ to store that state.
[fxsave]: https://www.felixcloutier.com/x86/fxsave
In order to save/restore the multimedia registers, we _could_ add new macros:
```rust
macro_rules! save_multimedia_registers {
() => {
asm!("sub rsp, 512
fxsave [rsp]
" :::: "intel", "volatile");
}
}
macro_rules! restore_multimedia_registers {
() => {
asm!("fxrstor [rsp]
add rsp, 512
" :::: "intel", "volatile");
}
}
```
First, we reserve the 512 bytes on the stack and then we use `fxsave` to backup the multimedia registers. In order to restore them later, we use the [fxrstor] instruction. Note that `fxsave` and `fxrstor` require a 16 byte aligned memory address.
[fxrstor]: https://www.felixcloutier.com/x86/fxrstor
However, _we won't do it that way_. The problem is the large amount of memory required. We will reuse the same code when we handle hardware interrupts in a future post. So for each mouse click, pressed key, or arrived network package we need to write 512 bytes to memory. This would be a huge performance problem.
Fortunately, there exists an alternative solution.
### Disabling Multimedia Extensions
We just disable MMX, SSE, and all the other fancy multimedia extensions in our kernel[^fn-userspace-sse]. This way, our exception handlers won't clobber the multimedia registers because they won't use them at all.
[^fn-userspace-sse]: Userspace programs will still be able to use the multimedia registers.
This solution has its own disadvantages, of course. For example, it leads to slower kernel code because the compiler can't perform any auto-vectorization optimizations. But it's still the faster solution (since we save many memory accesses) and most kernels do it this way (including Linux).
So how do we disable MMX and SSE? Well, we just tell the compiler that our target system doesn't support it. Since the very beginning, we're compiling our kernel for the `x86_64-unknown-linux-gnu` target. This worked fine so far, but now we want a different target without support for multimedia extensions. We can do so by creating a _target configuration file_.
### Target Specifications
In order to disable the multimedia extensions for our kernel, we need to compile for a custom target. We want a target that is equal to `x86_64-unknown-linux-gnu`, but without MMX and SSE support. Rust allows us to specify such a target using a JSON configuration file.
A minimal target specification that describes the `x86_64-unknown-linux-gnu` target looks like this:
```json
{
"llvm-target": "x86_64-unknown-linux-gnu",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"arch": "x86_64",
"os": "none"
}
```
The `llvm-target` field specifies the target triple that is passed to LLVM. We want to derive a 64-bit Linux target, so we choose `x86_64-unknown-linux-gnu`. The `data-layout` field is also passed to LLVM and specifies how data should be laid out in memory. It consists of various specifications separated by a `-` character. For example, the `e` means little endian and `S128` specifies that the stack should be 128 bits (= 16 byte) aligned. The format is described in detail in the [LLVM documentation][data layout] but there shouldn't be a reason to change this string.
The other fields are used for conditional compilation. This allows crate authors to use `cfg` variables to write special code for depending on the OS or the architecture. There isn't any up-to-date documentation about these fields but the [corresponding source code][target specification] is quite readable.
[data layout]: https://llvm.org/docs/LangRef.html#data-layout
[target specification]: https://github.com/rust-lang/rust/blob/c772948b687488a087356cb91432425662e034b9/src/librustc_back/target/mod.rs#L194-L214
#### Disabling MMX and SSE
In order to disable the multimedia extensions, we create a new target named `x86_64-blog_os`. To describe this target, we create a file named `x86_64-blog_os.json` in the project root with the following content:
```json
{
"llvm-target": "x86_64-unknown-linux-gnu",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"arch": "x86_64",
"os": "none",
"features": "-mmx,-sse"
}
```
It's equal to `x86_64-unknown-linux-gnu` target but has one additional option: `"features": "-mmx,-sse"`. So we added two target _features_: `-mmx` and `-sse`. The minus prefix defines that our target does _not_ support this feature. So by specifying `-mmx` and `-sse`, we disable the default `mmx` and `sse` features.
In order to compile for the new target, we need to adjust our Makefile:
```diff
# in `Makefile`
arch ?= x86_64
-target ?= $(arch)-unknown-linux-gnu
+target ?= $(arch)-blog_os
...
```
The new target name (`x86_64-blog_os`) is the file name of the JSON configuration file without the `.json` extension.
### Cross compilation
Let's try if our kernel still works with the new target:
```
> make run
Compiling raw-cpuid v2.0.1
Compiling rlibc v0.1.5
Compiling x86 v0.7.1
Compiling spin v0.3.5
error[E0463]: can't find crate for `core`
error: aborting due to previous error
Build failed, waiting for other jobs to finish...
...
Makefile:52: recipe for target 'cargo' failed
make: *** [cargo] Error 101
```
It doesn't compile anymore. The error tells us that the Rust compiler no longer finds the core library.
The [core library] is implicitly linked to all `no_std` crates and contains things such as `Result`, `Option`, and iterators. We've used that library without problems since [the very beginning], so why is it no longer available?
[core library]: https://doc.rust-lang.org/nightly/core/index.html
[the very beginning]: @/edition-1/posts/03-set-up-rust/index.md
The problem is that the core library is distributed together with the Rust compiler as a _precompiled_ library. So it is only valid for the host triple, which is `x86_64-unknown-linux-gnu` in our case. If we want to compile code for other targets, we need to recompile `core` for these targets first.
#### Xargo
That's where [xargo] comes in. It is a wrapper for cargo that eases cross compilation. We can install it by executing:
[xargo]: https://github.com/japaric/xargo
```
cargo install xargo
```
Xargo depends on the rust source code, which we can install with `rustup component add rust-src`.
Xargo is “a drop-in replacement for cargo”, so every cargo command also works with `xargo`. You can do e.g. `xargo --help`, `xargo clean`, or `xargo doc`. However, the `build` command gains additional functionality: `xargo build` will automatically cross compile the `core` library when compiling for custom targets.
That's exactly what we want, so we change one letter in our Makefile:
```diff
# in `Makefile`
...
cargo:
- @cargo build --target $(target)
+ @xargo build --target $(target)
...
```
Now the build goes through `xargo`, which should fix the compilation error. Let's try it out:
```
> make run
Compiling core v0.0.0 (file:///home/…/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore)
LLVM ERROR: SSE register return with SSE disabled
error: Could not compile `core`.
```
Well, we get a different error now, so it seems like we're making progress :). It seems like there is a “SSE register return” although SSE is disabled. But what's an “SSE register return”?
### SSE Register Return
Remember when we discussed calling conventions above? The calling convention defines which registers are used for return values. Well, the [System V ABI] defines that `xmm0` should be used for returning floating point values. So somewhere in the `core` library a function returns a float and LLVM doesn't know what to do. The ABI says “use `xmm0`” but the target specification says “don't use `xmm` registers”.
In order to fix this problem, we need to change our float ABI. The idea is to avoid normal hardware-supported floats and use a pure software implementation instead. We can do so by enabling the `soft-float` feature for our target. For that, we edit `x86_64-blog_os.json`:
```json
{
"llvm-target": "x86_64-unknown-linux-gnu",
...
"features": "-mmx,-sse,+soft-float"
}
```
The plus prefix tells LLVM to enable the `soft-float` feature.
Let's try `make run` again:
```
> make run
Compiling core v0.0.0 (file:///…/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore)
Finished release [optimized] target(s) in 21.95 secs
Compiling spin v0.4.5
Compiling once v0.3.2
Compiling x86 v0.8.0
Compiling bitflags v0.9.1
Compiling raw-cpuid v2.0.1
Compiling rlibc v0.1.5
Compiling linked_list_allocator v0.2.3
Compiling volatile v0.1.0
Compiling bitflags v0.4.0
Compiling bit_field v0.5.0
Compiling spin v0.3.5
Compiling multiboot2 v0.1.0
Compiling lazy_static v0.2.2
Compiling hole_list_allocator v0.1.0 (file:///…/libs/hole_list_allocator)
Compiling blog_os v0.1.0 (file:///…)
error[E0463]: can't find crate for `alloc`
--> src/lib.rs:33:1
|
33 | extern crate alloc;
| ^^^^^^^^^^^^^^^^^^^ can't find crate
error: aborting due to previous error
```
We see that `xargo` now compiles the `core` crate in release mode. Then it starts the normal cargo build. Cargo then recompiles all dependencies, since it needs to generate different code for the new target.
However, the build still fails. The reason is that xargo only installs `core` by default, but we also need the `alloc` crate. We can enable it by creating a file named `Xargo.toml` with the following contents:
```toml
# Xargo.toml
[target.x86_64-blog_os.dependencies]
alloc = {}
```
Now xargo compiles `alloc`, too:
```
> make run
Compiling core v0.0.0 (file:///…/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore)
Compiling std_unicode v0.0.0 (file:///…/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd_unicode)
Compiling alloc v0.0.0 (file:///…/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc)
Finished release [optimized] target(s) in 28.84 secs
Compiling blog_os v0.1.0 (file:///…/Documents/blog_os/master)
warning: unused variable: `allocator` […]
warning: unused variable: `frame` […]
Finished debug [unoptimized + debuginfo] target(s) in 1.75 secs
```
It worked! Now we have a kernel that never touches the multimedia registers! We can verify this by executing:
```
> objdump -d build/kernel-x86_64.bin | grep "mm[0-9]"
```
If the command produces no output, our kernel uses neither MMX (`mm0` `mm7`) nor SSE (`xmm0` `xmm15`) registers.
So now our return-from-exception logic works without problems in _most_ cases. However, there is still a pitfall hidden in the C calling convention, which might cause hideous bugs in some rare cases.
## The Red Zone
The [red zone] is an optimization of the [System V ABI] that allows functions to temporary use the 128 bytes below its stack frame without adjusting the stack pointer:
[red zone]: https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone
![stack frame with red zone](red-zone.svg)
The image shows the stack frame of a function with `n` local variables. On function entry, the stack pointer is adjusted to make room on the stack for the local variables.
The red zone is defined as the 128 bytes below the adjusted stack pointer. The function can use this area for temporary data that's not needed across function calls. Thus, the two instructions for adjusting the stack pointer can be avoided in some cases (e.g. in small leaf functions).
However, this optimization leads to huge problems with exceptions. Let's assume that an exception occurs while a function uses the red zone:
![red zone overwritten by exception handler](red-zone-overwrite.svg)
The CPU and the exception handler overwrite the data in red zone. But this data is still needed by the interrupted function. So the function won't work correctly anymore when we return from the exception handler. It might fail or cause another exception, but it could also lead to strange bugs that [take weeks to debug].
[take weeks to debug]: https://forum.osdev.org/viewtopic.php?t=21720
### Adjusting our Exception Handler?
The problem is that the [System V ABI] demands that the red zone _“shall not be modified by signal or interrupt handlers.”_ Our current exception handlers do not respect this. We could try to fix it by subtracting 128 from the stack pointer before pushing anything:
```nasm
sub rsp, 128
save_scratch_registers()
...
call ...
...
restore_scratch_registers()
add rsp, 128
iretq
```
_This will not work._ The problem is that the CPU pushes the exception stack frame before even calling our handler function. So the CPU itself will clobber the red zone and there is nothing we can do about that. So our only chance is to disable the red zone.
### Disabling the Red Zone
The red zone is a property of our target, so in order to disable it we edit our `x86_64-blog_os.json` a last time:
```json
{
"llvm-target": "x86_64-unknown-linux-gnu",
...
"features": "-mmx,-sse,+soft-float",
"disable-redzone": true
}
```
We add one additional option at the end: `"disable-redzone": true`. As you might guess, this option disables the red zone optimization.
Now we have a red zone free kernel!
## Exceptions with Error Codes
We're now able to correctly return from exceptions without error codes. However, we still can't return from exceptions that push an error code (e.g. page faults). Let's fix that by updating our `handler_with_error_code` macro:
```rust
// in src/interrupts/mod.rs
macro_rules! handler_with_error_code {
($name: ident) => {{
#[naked]
extern "C" fn wrapper() -> ! {
unsafe {
asm!("pop rsi // pop error code into rsi
mov rdi, rsp
sub rsp, 8 // align the stack pointer
call $0"
:: "i"($name as extern "C" fn(
&ExceptionStackFrame, u64))
: "rdi","rsi" : "intel");
asm!("iretq" :::: "intel", "volatile");
::core::intrinsics::unreachable();
}
}
wrapper
}}
}
```
First, we change the type of the handler function: no more `-> !`, so it no longer needs to diverge. We also add an `iretq` instruction at the end.
Now we can make our `page_fault_handler` non-diverging:
```diff
// in src/interrupts/mod.rs
extern "C" fn page_fault_handler(stack_frame: &ExceptionStackFrame,
- error_code: u64) -> ! { ... }
+ error_code: u64) { ... }
```
However, now we have the same problem as above: The handler function will overwrite the scratch registers and cause bugs when returning. Let's fix this by invoking `save_scratch_registers` at the beginning:
```rust
// in src/interrupts/mod.rs
macro_rules! handler_with_error_code {
($name: ident) => {{
#[naked]
extern "C" fn wrapper() -> ! {
unsafe {
save_scratch_registers!();
asm!("pop rsi // pop error code into rsi
mov rdi, rsp
add rdi, 10*8 // calculate exception stack frame pointer
sub rsp, 8 // align the stack pointer
call $0
add rsp, 8 // undo stack pointer alignment
" :: "i"($name as extern "C" fn(
&ExceptionStackFrame, u64))
: "rdi","rsi" : "intel");
restore_scratch_registers!();
asm!("iretq" :::: "intel", "volatile");
::core::intrinsics::unreachable();
}
}
wrapper
}}
}
```
Now we backup the scratch registers to the stack right at the beginning and restore them just before the `iretq`. Like in the `handler` macro, we now need to add `10*8` to `rdi` in order to get the correct exception stack frame pointer (`save_scratch_registers` pushes nine 8 byte registers, plus the error code). We also need to undo the stack pointer alignment after the `call` [^fn-stack-alignment].
[^fn-stack-alignment]: The stack alignment is actually wrong here, since we additionally pushed an uneven number of registers. However, the `pop rsi` is wrong too, since the error code is no longer at the top of the stack. When we fix that problem, the stack alignment becomes correct again. So I left it in to keep things simple.
Now we have one last bug: We `pop` the error code into `rsi`, but the error code is no longer at the top of the stack (since `save_scratch_registers` pushed 9 registers on top of it). So we need to do it differently:
```rust
// in src/interrupts/mod.rs
macro_rules! handler_with_error_code {
($name: ident) => {{
#[naked]
extern "C" fn wrapper() -> ! {
unsafe {
save_scratch_registers!();
asm!("mov rsi, [rsp + 9*8] // load error code into rsi
mov rdi, rsp
add rdi, 10*8 // calculate exception stack frame pointer
sub rsp, 8 // align the stack pointer
call $0
add rsp, 8 // undo stack pointer alignment
" :: "i"($name as extern "C" fn(
&ExceptionStackFrame, u64))
: "rdi","rsi" : "intel");
restore_scratch_registers!();
asm!("add rsp, 8 // pop error code
iretq" :::: "intel", "volatile");
::core::intrinsics::unreachable();
}
}
wrapper
}}
}
```
Instead of using `pop`, we're calculating the error code address manually (`save_scratch_registers` pushes nine 8 byte registers) and load it into `rsi` using a `mov`. So now the error code stays on the stack. But `iretq` doesn't handle the error code, so we need to pop it before invoking `iretq`.
Phew! That was a lot of fiddling with assembly. Let's test if it still works.
### Testing
First, we test if the exception stack frame pointer and the error code are still correct:
```rust
// in rust_main in src/lib.rs
...
unsafe { int!(3) };
// provoke a page fault
unsafe { *(0xdeadbeaf as *mut u64) = 42; }
println!("It did not crash!");
loop {}
```
This should cause the following error message:
```
EXCEPTION: PAGE FAULT while accessing 0xdeadbeaf
error code: CAUSED_BY_WRITE
ExceptionStackFrame {
instruction_pointer: 1114753,
code_segment: 8,
cpu_flags: 2097158,
stack_pointer: 1171104,
stack_segment: 16
}
```
The error code should still be `CAUSED_BY_WRITE` and the exception stack frame values should also be correct (e.g. `code_segment` should be 8 and `stack_segment` should be 16).
#### Returning from Page Faults
Let's see what happens if we comment out the trailing `loop` in our page fault handler:
![QEMU printing the same page fault message again and again](qemu-page-fault-return.png)
We see that the same error message is printed over and over again. Here is what happens:
- The CPU executes `rust_main` and tries to access `0xdeadbeaf`. This causes a page fault.
- The page fault handler prints an error message and returns without fixing the cause of the exception (`0xdeadbeaf` is still unaccessible).
- The CPU restarts the instruction that caused the page fault and thus tries to access `0xdeadbeaf` again. Of course, this causes a page fault again.
- The page fault handler prints the error message and returns.
… and so on. Thus, our code indefinitely jumps between the page fault handler and the instruction that accesses `0xdeadbeaf`.
This is a good thing! It means that our `iretq` logic is working correctly, since it returns to the correct instruction every time. So our `handler_with_error_code` macro seems to be correct.
## What's next?
We are now able to catch exceptions and to return from them. However, there are still exceptions that completely crash our kernel by causing a [triple fault]. In the next post, we will fix this issue by handling a special type of exception: the [double fault]. Thus, we will be able to avoid random reboots in our kernel.
[triple fault]: https://en.wikipedia.org/wiki/Triple_fault
[double fault]: https://en.wikipedia.org/wiki/Double_fault

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
<svg width="17cm" height="11cm" viewBox="-60 -21 340 212" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<text font-size="9.03111" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="90" y="65.9389">
<tspan x="90" y="65.9389"></tspan>
</text>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="204" y1="70" x2="176.236" y2="70"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="185.118,65 175.118,70 185.118,75 "/>
</g>
<text font-size="7.90222" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="208" y="72.75">
<tspan x="208" y="72.75">Old Stack Pointer</tspan>
</text>
<text font-size="7.90222" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="75" y="230">
<tspan x="75" y="230"></tspan>
</text>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="-20" y1="70" x2="-4" y2="70"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="-20" y1="190" x2="-4" y2="190"/>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="-12" y1="72.2361" x2="-12" y2="187.764"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="-7,81.118 -12,71.118 -17,81.118 "/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="-17,178.882 -12,188.882 -7,178.882 "/>
</g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="0" y1="-20" x2="0" y2="0"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="170" y1="-20" x2="170" y2="0"/>
<g>
<rect style="fill: #00ff00" x="0" y="0" width="170" height="20"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="0" width="170" height="20"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="85" y="13.125">
<tspan x="85" y="13.125">Return Address</tspan>
</text>
<text font-size="9.03097" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="84" y="4">
<tspan x="84" y="4"></tspan>
</text>
<g>
<rect style="fill: #dddddd" x="0" y="20" width="170" height="20"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="20" width="170" height="20"/>
</g>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="85" y="33.125">
<tspan x="85" y="33.125">Local Variable 1</tspan>
</text>
<g>
<rect style="fill: #cccccc" x="0" y="40" width="170" height="32"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x="0" y="40" width="170" height="32"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="85" y="59.125">
<tspan x="85" y="59.125">Local Variables 2..n</tspan>
</text>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="0" y1="40" x2="170" y2="40"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="0" y1="72" x2="120" y2="72"/>
<g>
<rect style="fill: #ff3333" x="0" y="70" width="170" height="120"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="70" width="170" height="120"/>
</g>
<text font-size="9.03111" style="fill: #ffffff;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="40" y="179.125">
<tspan x="40" y="179.125">Red Zone</tspan>
</text>
<text font-size="7.9021" style="fill: #000000;text-anchor:end;font-family:sans-serif;font-style:normal;font-weight:normal" x="-20" y="132.75">
<tspan x="-20" y="132.75">128 bytes</tspan>
</text>
<g>
<rect style="fill: #ffc200" x="30" y="70" width="140" height="30"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="30" y="70" width="140" height="30"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="100" y="88.125">
<tspan x="100" y="88.125">Exception Stack Frame</tspan>
</text>
<g>
<rect style="fill: #ffe000" x="30" y="100" width="140" height="30"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="30" y="100" width="140" height="30"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="100" y="118.125">
<tspan x="100" y="118.125">Register Backup</tspan>
</text>
<g>
<rect style="fill: #c6db97" x="30" y="130" width="140" height="30"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="30" y="130" width="140" height="30"/>
</g>
<text font-size="8.46654" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="100" y="147.925">
<tspan x="100" y="147.925">Handler Function Stack Frame</tspan>
</text>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #ff3333" x1="30" y1="70" x2="30" y2="160"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #ff3333" x1="30" y1="160" x2="170" y2="160"/>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="204" y1="160" x2="176.236" y2="160"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="185.118,155 175.118,160 185.118,165 "/>
</g>
<text font-size="7.90222" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="208" y="162.635">
<tspan x="208" y="162.635">New Stack Pointer</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
<svg width="14cm" height="9cm" viewBox="-60 -21 270 172" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<text font-size="9.03111" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="90" y="65.9389">
<tspan x="90" y="65.9389"></tspan>
</text>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="154" y1="70" x2="126.236" y2="70"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="135.118,65 125.118,70 135.118,75 "/>
</g>
<text font-size="7.90222" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="158" y="72.75">
<tspan x="158" y="72.75">Stack Pointer</tspan>
</text>
<text font-size="7.90222" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="75" y="230">
<tspan x="75" y="230"></tspan>
</text>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="-20" y1="70" x2="-4" y2="70"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="-20" y1="150" x2="-4" y2="150"/>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="-12" y1="72.2361" x2="-12" y2="147.764"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="-7,81.118 -12,71.118 -17,81.118 "/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="-17,138.882 -12,148.882 -7,138.882 "/>
</g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="0" y1="-20" x2="0" y2="0"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="120" y1="-20" x2="120" y2="0"/>
<g>
<rect style="fill: #00ff00" x="0" y="0" width="120" height="20"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="0" width="120" height="20"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="60" y="13.125">
<tspan x="60" y="13.125">Return Address</tspan>
</text>
<text font-size="9.03097" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="84" y="4">
<tspan x="84" y="4"></tspan>
</text>
<g>
<rect style="fill: #dddddd" x="0" y="20" width="120" height="20"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="20" width="120" height="20"/>
</g>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="60" y="33.125">
<tspan x="60" y="33.125">Local Variable 1</tspan>
</text>
<g>
<rect style="fill: #cccccc" x="0" y="40" width="120" height="32"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x="0" y="40" width="120" height="32"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="60" y="59.125">
<tspan x="60" y="59.125">Local Variables 2..n</tspan>
</text>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="0" y1="40" x2="120" y2="40"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="0" y1="72" x2="120" y2="72"/>
<g>
<rect style="fill: #ff3333" x="0" y="70" width="120" height="80"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="70" width="120" height="80"/>
</g>
<text font-size="9.03111" style="fill: #ffffff;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="60" y="113.125">
<tspan x="60" y="113.125">Red Zone</tspan>
</text>
<text font-size="7.9021" style="fill: #000000;text-anchor:end;font-family:sans-serif;font-style:normal;font-weight:normal" x="-20" y="112.75">
<tspan x="-20" y="112.75">128 bytes</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
<svg width="13cm" height="4cm" viewBox="-1 -23 252 63" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<rect style="fill: #00ff00" x="0" y="0" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="0" width="50" height="10"/>
</g>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="25" y="8.125">
<tspan x="25" y="8.125">mm0</tspan>
</text>
<g>
<rect style="fill: #00ff00" x="0" y="10" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="10" width="50" height="10"/>
</g>
<g>
<rect style="fill: #00ff00" x="0" y="20" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="20" width="50" height="10"/>
</g>
<g>
<rect style="fill: #dddddd" x="0" y="30" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="30" width="50" height="10"/>
</g>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="25" y="17.9931">
<tspan x="25" y="17.9931">mm1</tspan>
</text>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="25" y="28.125">
<tspan x="25" y="28.125">mm2</tspan>
</text>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="25" y="38.125">
<tspan x="25" y="38.125">mm3</tspan>
</text>
<g>
<rect style="fill: #00ff00" x="100" y="-4.44089e-15" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="100" y="-4.44089e-15" width="50" height="10"/>
</g>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="125" y="8.125">
<tspan x="125" y="8.125">mm0</tspan>
</text>
<g>
<rect style="fill: #ff0000" x="100" y="10" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="100" y="10" width="50" height="10"/>
</g>
<g>
<rect style="fill: #00ff00" x="100" y="20" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="100" y="20" width="50" height="10"/>
</g>
<g>
<rect style="fill: #dddddd" x="100" y="30" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="100" y="30" width="50" height="10"/>
</g>
<text font-size="9.03111" style="fill: #ffffff;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="125" y="18.125">
<tspan x="125" y="18.125">mm1</tspan>
</text>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="125" y="28.125">
<tspan x="125" y="28.125">mm2</tspan>
</text>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="125" y="38.125">
<tspan x="125" y="38.125">mm3</tspan>
</text>
<g>
<rect style="fill: #00ff00" x="200" y="0" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="200" y="0" width="50" height="10"/>
</g>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="225" y="8.125">
<tspan x="225" y="8.125">mm0</tspan>
</text>
<g>
<rect style="fill: #ff0000" x="200" y="10" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="200" y="10" width="50" height="10"/>
</g>
<g>
<rect style="fill: #00ff00" x="200" y="20" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="200" y="20" width="50" height="10"/>
</g>
<g>
<rect style="fill: #dddddd" x="200" y="30" width="50" height="10"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="200" y="30" width="50" height="10"/>
</g>
<text font-size="9.03111" style="fill: #ffffff;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="225" y="18.125">
<tspan x="225" y="18.125">mm1</tspan>
</text>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="225" y="28.125">
<tspan x="225" y="28.125">mm2</tspan>
</text>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="225" y="38.125">
<tspan x="225" y="38.125">mm3</tspan>
</text>
<text font-size="7.9021" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="25" y="-10.0787">
<tspan x="25" y="-10.0787">Program</tspan>
</text>
<text font-size="7.9021" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="125" y="-15.0175">
<tspan x="125" y="-15.0175">Exception</tspan>
<tspan x="125" y="-5.13977">Handler</tspan>
</text>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="50" y1="-12.8287" x2="97.7639" y2="-12.8287"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="94.882,-10.8287 98.882,-12.8287 94.882,-14.8287 "/>
</g>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="150" y1="-12.8287" x2="197.764" y2="-12.8287"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="194.882,-10.8287 198.882,-12.8287 194.882,-14.8287 "/>
</g>
<text font-size="7.9021" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="225" y="-10.0787">
<tspan x="225" y="-10.0787">Program</tspan>
</text>
<text font-size="6.77323" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="75" y="-14.737">
<tspan x="75" y="-14.737">Exception</tspan>
<tspan x="75" y="-6.27032">occurs</tspan>
</text>
<text font-size="6.77323" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="175" y="-14.737">
<tspan x="175" y="-14.737">Exception</tspan>
<tspan x="175" y="-6.27032">resolved</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,7 @@
+++
title = "Handling Exceptions using naked Functions"
sort_by = "weight"
template = "edition-1/handling-exceptions-with-naked-fns.html"
insert_anchor_links = "left"
aliases = ["first-edition/extra/naked-exceptions/index.html"]
+++

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -1,5 +1,9 @@
+++
title = "Set Up GDB"
template = "plain.html"
path = "set-up-gdb"
aliases = ["set-up-gdb.html"]
weight = 4
+++
There are a lot of things that can go wrong when developing an OS. So it's a good idea to add a debugger to our toolset, which allows us to set breakpoints and examine variables. We will use [GDB](https://www.gnu.org/software/gdb/) as QEMU supports it out of the box.
@@ -29,7 +33,7 @@ Remote 'g' packet reply is too long: [a very long number]
```
This issue is known [since 2012][gdb issue patch] but it is still not fixed. Maybe we find the reason in the [issue thread][gdb issue thread]:
[gdb issue patch]: http://www.cygwin.com/ml/gdb-patches/2012-03/msg00116.html
[gdb issue patch]: https://web.archive.org/web/20190114181420/https://www.cygwin.com/ml/gdb-patches/2012-03/msg00116.html
[gdb issue thread]: https://sourceware.org/bugzilla/show_bug.cgi?id=13984#c11
> from my (limited) experience, unless you ping the gdb-patches list weekly, this patch is more likely to remain forgotten :-)
@@ -66,9 +70,9 @@ After connecting to QEMU, you can use various gdb commands to control execution
- `print` or `p`: Prints the value of a variable. You can use Cs `*` and `&` operators. To print in hexadecimal, use `p/x`.
- `tui enable`: Enables the text user interface, which provides a graphical interface (see below). To disable it again, run `tui disable`.
![gdb text user interface](images/gdb-tui-screenshot.png)
![gdb text user interface](gdb-tui-screenshot.png)
Of course there are many more commands. Feel free to send a PR if you think this list is missing something important. For a more complete GDB overview, check out [Beej's Quick Guide][bggdb] or the [website for Harvard's CS161 course][CS161].
[bggdb]: http://beej.us/guide/bggdb/
[CS161]: http://www.eecs.harvard.edu/~cs161/resources/gdb.html
[bggdb]: https://beej.us/guide/bggdb/
[CS161]: https://www.eecs.harvard.edu/~cs161/resources/gdb.html

View File

@@ -0,0 +1,14 @@
+++
title = "Talks"
path = "talks"
template = "plain.html"
weight = 1
+++
## 2018
- “The Rust Way Of OS Development” at HTWG Konstanz, May 30, 2018: [slides](https://phil-opp.github.io/talk-konstanz-may-2018/) [pdf](https://phil-opp.github.io/talk-konstanz-may-2018/talk.pdf)
## 2017
- “Open Source OS Development in Rust” at HTWG Konstanz, May 22, 2017: [slides](https://phil-opp.github.io/talk-konstanz-may-2017/)

View File

@@ -1,23 +1,22 @@
+++
title = "A minimal x86 kernel"
slug = "multiboot-kernel"
date = "2015-08-18"
aliases = [
"/2015/08/18/multiboot-kernel/",
"/rust-os/multiboot-kernel.html",
]
title = "A minimal Multiboot Kernel"
weight = 1
path = "multiboot-kernel"
aliases = ["multiboot-kernel.html", "/2015/08/18/multiboot-kernel/", "/rust-os/multiboot-kernel.html"]
date = 2015-08-18
template = "edition-1/page.html"
+++
This post explains how to create a minimal x86 operating system kernel. In fact, it will just boot and print `OK` to the screen. The following blog posts we will extend it using the [Rust] programming language.
This post explains how to create a minimal x86 operating system kernel using the Multiboot standard. In fact, it will just boot and print `OK` to the screen. In subsequent blog posts we will extend it using the [Rust] programming language.
[Rust]: http://www.rust-lang.org/
[Rust]: https://www.rust-lang.org/
<!--more-->
<!-- more -->
I tried to explain everything in detail and to keep the code as simple as possible. If you have any questions, suggestions or other issues, please leave a comment or [create an issue] on Github. The source code is available in a [repository][source code], too.
[create an issue]: https://github.com/phil-opp/blog_os/issues
[source code]: https://github.com/phil-opp/blog_os/tree/multiboot_bootstrap/src/arch/x86_64
[source code]: https://github.com/phil-opp/blog_os/tree/first_edition_post_1/src/arch/x86_64
Note that this tutorial is written mainly for Linux. For some known problems on OS X see the comment section and [this issue][mac os issue]. If you want to use a virtual Linux machine, you can find instructions and a Vagrantfile in Ashley Willams's [x86-kernel repository].
@@ -29,19 +28,19 @@ When you turn on a computer, it loads the [BIOS] from some special flash memory.
[BIOS]: https://en.wikipedia.org/wiki/BIOS
[protected mode]: https://en.wikipedia.org/wiki/Protected_mode
[real mode]: http://wiki.osdev.org/Real_Mode
[real mode]: https://wiki.osdev.org/Real_Mode
We won't write a bootloader because that would be a complex project on its own (if you really want to do it, check out [_Rolling Your Own Bootloader_]). Instead we will use one of the [many well-tested bootloaders][bootloader comparison] out there. But which one?
We won't write a bootloader because that would be a complex project on its own (if you really want to do it, check out [_Rolling Your Own Bootloader_]). Instead we will use one of the [many well-tested bootloaders][bootloader comparison] out there to boot our kernel from a CD-ROM. But which one?
[_Rolling Your Own Bootloader_]: http://wiki.osdev.org/Rolling_Your_Own_Bootloader
[_Rolling Your Own Bootloader_]: https://wiki.osdev.org/Rolling_Your_Own_Bootloader
[bootloader comparison]: https://en.wikipedia.org/wiki/Comparison_of_boot_loaders
## Multiboot
Fortunately there is a bootloader standard: the [Multiboot Specification][multiboot]. Our kernel just needs to indicate that it supports Multiboot and every Multiboot-compliant bootloader can boot it. We will use the Multiboot 2 specification ([PDF][Multiboot 2]) together with the well-known [GRUB 2] bootloader.
[multiboot]: https://en.wikipedia.org/wiki/Multiboot_Specification
[multiboot 2]: http://nongnu.askapache.com/grub/phcoder/multiboot.pdf
[grub 2]: http://wiki.osdev.org/GRUB_2
[multiboot 2]: https://nongnu.askapache.com/grub/phcoder/multiboot.pdf
[grub 2]: https://wiki.osdev.org/GRUB_2
To indicate our Multiboot 2 support to the bootloader, our kernel must start with a _Multiboot Header_, which has the following format:
@@ -80,8 +79,6 @@ If you don't know x86 assembly, here is some quick guide:
- `dd` stands for `define double` (32bit) and `dw` stands for `define word` (16bit). They just output the specified 32bit/16bit constant.
- the additional `0x100000000` in the checksum calculation is a small hack[^fn-checksum_hack] to avoid a compiler warning
[^fn-checksum_hack]: The formula from the table, `-(magic + architecture + header_length)`, creates a negative value that doesn't fit into 32bit. By subtracting from `0x100000000` (= 2^(32)) instead, we keep the value positive without changing its truncated value. Without the additional sign bit(s) the result fits into 32bit and the compiler is happy :).
We can already _assemble_ this file (which I called `multiboot_header.asm`) using `nasm`. It produces a flat binary by default, so the resulting file just contains our 24 bytes (in little endian if you work on a x86 machine):
```
@@ -110,7 +107,7 @@ There are some new commands:
- `global` exports a label (makes it public). As `start` will be the entry point of our kernel, it needs to be public.
- the `.text` section is the default section for executable code
- `bits 32` specifies that the following lines are 32-bit instructions. It's needed because the CPU is still in [Protected mode] when GRUB starts our kernel. When we switch to [Long mode] in the [next post] we can use `bits 64` (64-bit instructions).
- the `mov dword` instruction moves the 32bit constant `0x2f4f2f4b` to the memory at address `b8000` (it prints `OK` to the screen, an explanation follows in the next posts)
- the `mov dword` instruction moves the 32bit constant `0x2f4b2f4f` to the memory at address `b8000` (it prints `OK` to the screen, an explanation follows in the next posts)
- `hlt` is the halt instruction and causes the CPU to stop
Through assembling, viewing and disassembling we can see the CPU [Opcodes] in action:
@@ -133,14 +130,14 @@ Through assembling, viewing and disassembling we can see the CPU [Opcodes] in ac
To boot our executable later through GRUB, it should be an [ELF] executable. So we want `nasm` to create ELF [object files] instead of plain binaries. To do that, we simply pass the `f elf64` argument to it.
[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
[object files]: http://wiki.osdev.org/Object_Files
[object files]: https://wiki.osdev.org/Object_Files
To create the ELF _executable_, we need to [link] the object files together. We use a custom [linker script] named `linker.ld`:
[link]: https://en.wikipedia.org/wiki/Linker_(computing)
[linker script]: https://sourceware.org/binutils/docs/ld/Scripts.html
```
```ld
ENTRY(start)
SECTIONS {
@@ -166,8 +163,6 @@ Let's translate it:
- the `.text` output section contains all input sections named `.text`
- Sections named `.multiboot_header` are added to the first output section (`.boot`) to ensure they are at the beginning of the executable. This is necessary because GRUB expects to find the Multiboot header very early in the file.
[^Linker 1M]: We don't want to load the kernel to e.g. `0x0` because there are many special memory areas below the 1MB mark (for example the so-called VGA buffer at `0xb8000`, that we use to print `OK` to the screen).
So let's create the ELF object files and link them using our new linker script:
```
@@ -191,10 +186,11 @@ Idx Name Size VMA LMA File off Algn
CONTENTS, ALLOC, LOAD, READONLY, CODE
```
_Note_: The `ld` and `objdump` commands are platform specific. If you're _not_ working on x86_64 architecture, you will need to [cross compile binutils]. Then use `x86_64elfld` and `x86_64elfobjdump` instead of `ld` and `objdump`.
[cross compile binutils]: {{% relref "cross-compile-binutils.md" %}}
[cross compile binutils]: @/edition-1/extra/cross-compile-binutils.md
## Creating the ISO
The last step is to create a bootable ISO image with GRUB. We need to create the following directory structure and copy the `kernel.bin` to the right place:
All PC BIOSes know how to boot from a CD-ROM, so we want to create a bootable CD-ROM image, containing our kernel and the GRUB bootloader's files, in a single file called an [ISO](https://en.wikipedia.org/wiki/ISO_image). Make the following directory structure and copy the `kernel.bin` to the right place:
```
isofiles
@@ -235,13 +231,13 @@ Now it's time to boot our OS. We will use [QEMU]:
```
qemu-system-x86_64 -cdrom os.iso
```
![qemu output](/images/qemu-ok.png)
![qemu output](qemu-ok.png)
Notice the green `OK` in the upper left corner. If it does not work for you, take a look at the comment section.
Let's summarize what happens:
1. the BIOS loads the bootloader (GRUB) from the virtual hard drive (the ISO)
1. the BIOS loads the bootloader (GRUB) from the virtual CD-ROM (the ISO)
2. the bootloader reads the kernel executable and finds the Multiboot header
3. it copies the `.boot` and `.text` sections to memory (to addresses `0x100000` and `0x100020`)
4. it jumps to the entry point (`0x100020`, you can obtain it through `objdump -f`)
@@ -251,9 +247,7 @@ You can test it on real hardware, too. Just burn the ISO to a disk or USB stick
## Build Automation
Right now we need to execute 4 commands in the right order everytime we change a file. That's bad. So let's automate the build using a [Makefile][Makefile tutorial]. But first we should create some clean directory structure for our source files to separate the architecture specific files:
[Makefile tutorial]: http://mrbook.org/blog/tutorials/make/
Right now we need to execute 4 commands in the right order every time we change a file. That's bad. So let's automate the build using a `Makefile`. But first we should create some clean directory structure for our source files to separate the architecture specific files:
```
@@ -321,5 +315,10 @@ Now we can invoke `make` and all updated assembly files are compiled and linked.
In the [next post] we will create a page table and do some CPU configuration to switch to the 64-bit [long mode].
[next post]: {{% relref "2015-08-25-entering-longmode.md" %}}
[next post]: @/edition-1/posts/02-entering-longmode/index.md
[long mode]: https://en.wikipedia.org/wiki/Long_mode
## Footnotes
[^fn-checksum_hack]: The formula from the table, `-(magic + architecture + header_length)`, creates a negative value that doesn't fit into 32bit. By subtracting from `0x100000000` (= 2^(32)) instead, we keep the value positive without changing its truncated value. Without the additional sign bit(s) the result fits into 32bit and the compiler is happy :).
[^Linker 1M]: We don't want to load the kernel to e.g. `0x0` because there are many special memory areas below the 1MB mark (for example the so-called VGA buffer at `0xb8000`, that we use to print `OK` to the screen).

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,929 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="7.2973523in"
height="4.1279249in"
viewBox="-2141 2141 8777.1352 4929.2808"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="X86_Paging_64bit.svg">
<metadata
id="metadata370">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs368" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1080"
inkscape:window-height="1868"
id="namedview366"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4404005"
inkscape:cx="383.13253"
inkscape:cy="73.778068"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g4" />
<g
style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="g4"
transform="translate(-2845,-286.64442)">
<rect
x="8503"
y="4015"
width="708"
height="3307"
rx="0"
style="fill:#dfdfdf"
id="rect8" />
<polyline
points="3365,2598 3365,3070"
id="polyline10" />
<polyline
points="3189,2598 3189,3070"
id="polyline12" />
<polyline
points="3012,2598 3012,3070"
id="polyline14" />
<polyline
points="2834,2598 2834,3070"
id="polyline16" />
<polyline
points="2657,2598 2657,3070"
id="polyline18" />
<polyline
points="2480,2598 2480,3070"
id="polyline20" />
<polyline
points="2303,2598 2303,3070"
id="polyline22" />
<polyline
points="2125,2456 2125,3070"
id="polyline24" />
<polyline
points="1948,2598 1948,3070"
id="polyline26" />
<polyline
points="1772,2598 1772,3070"
id="polyline28" />
<polyline
points="1594,2598 1594,3070"
id="polyline30" />
<polyline
points="1417,2598 1417,3070"
id="polyline32" />
<polyline
points="1239,2598 1239,3070"
id="polyline34" />
<polyline
points="1063,2598 1063,3070"
id="polyline36" />
<polyline
points="886,2598 886,3070"
id="polyline38" />
<polyline
points="708,2456 708,3070"
id="polyline40" />
<polyline
points="3543,2456 3543,3070"
id="polyline74" />
<polyline
points="-2125,2598 3543,2598"
id="polyline76"
transform="matrix(0.49978943,0,0,1,1772.2461,0)" />
<polyline
points="3543,3070 -1948,3070 -2125,3070"
id="polyline78"
transform="matrix(0.49786923,0,0,1,1779.0493,0)" />
<polyline
points="9035,2598 9035,3070"
id="polyline80" />
<polyline
points="8858,2598 8858,3070"
id="polyline82" />
<polyline
points="8681,2598 8681,3070"
id="polyline84" />
<polyline
points="8503,2598 8503,3070"
id="polyline86" />
<polyline
points="8326,2598 8326,3070"
id="polyline88" />
<polyline
points="8150,2598 8150,3070"
id="polyline90" />
<polyline
points="7972,2598 7972,3070"
id="polyline92" />
<polyline
points="7795,2456 7795,3070"
id="polyline94" />
<polyline
points="7617,2598 7617,3070"
id="polyline96" />
<polyline
points="7441,2598 7441,3070"
id="polyline98" />
<polyline
points="7264,2598 7264,3070"
id="polyline100" />
<polyline
points="7086,2598 7086,3070"
id="polyline102" />
<polyline
points="6909,2598 6909,3070"
id="polyline104" />
<polyline
points="6732,2598 6732,3070"
id="polyline106" />
<polyline
points="6555,2598 6555,3070"
id="polyline108" />
<polyline
points="6377,2456 6377,3070"
id="polyline110" />
<polyline
points="6200,2598 6200,3070"
id="polyline112" />
<polyline
points="6024,2598 6024,3070"
id="polyline114" />
<polyline
points="5846,2598 5846,3070"
id="polyline116" />
<polyline
points="5669,2598 5669,3070"
id="polyline118" />
<polyline
points="5491,2598 5491,3070"
id="polyline120" />
<polyline
points="5315,2598 5315,3070"
id="polyline122" />
<polyline
points="5138,2598 5138,3070"
id="polyline124" />
<polyline
points="4960,2409 4960,3070"
id="polyline126" />
<polyline
points="4783,2598 4783,3070"
id="polyline128" />
<polyline
points="4606,2598 4606,3070"
id="polyline130" />
<polyline
points="4429,2598 4429,3070"
id="polyline132" />
<polyline
points="4251,2598 4251,3070"
id="polyline134" />
<polyline
points="4074,2598 4074,3070"
id="polyline136" />
<polyline
points="3898,2598 3898,3070"
id="polyline138" />
<polyline
points="3720,2598 3720,3070"
id="polyline140" />
<polyline
points="9212,2456 9212,3070"
id="polyline142" />
<polyline
points="3543,2598 9212,2598"
id="polyline144" />
<polyline
points="9212,3070 3720,3070 0,3070"
id="polyline146"
transform="matrix(0.92335242,0,0,1,706.07747,0)" />
<rect
x="5102"
y="4488"
width="1181"
height="2362"
rx="0"
style="fill:#dfdfdf"
id="rect148" />
<rect
x="3307"
y="4251"
width="1181"
height="2362"
rx="0"
style="fill:#dfdfdf"
id="rect150" />
<rect
x="6897"
y="4724"
width="1181"
height="2362"
rx="0"
style="fill:#dfdfdf"
id="rect152" />
<rect
x="1511"
y="4015"
width="1181"
height="2362"
rx="0"
style="fill:#dfdfdf"
id="rect154" />
<rect
x="1417"
y="6850"
width="1417"
height="472"
rx="0"
id="rect156" />
<rect
x="8503"
y="5433"
width="708"
height="236"
rx="0"
style="fill:#dfdfdf"
id="rect158" />
<rect
x="5102"
y="5669"
width="1181"
height="472"
rx="0"
id="rect160" />
<rect
x="3307"
y="5433"
width="1181"
height="472"
rx="0"
id="rect162" />
<rect
x="6897"
y="5905"
width="1181"
height="472"
rx="0"
id="rect164" />
<rect
x="1511"
y="5196"
width="1181"
height="472"
rx="0"
id="rect166" />
<circle
cx="6141"
cy="5905"
r="47"
style="fill:#0000ff;stroke:#0000ff;stroke-width:32"
id="circle170" />
<circle
cx="4346"
cy="5669"
r="47"
style="fill:#0000ff;stroke:#0000ff;stroke-width:32"
id="circle172" />
<circle
cx="7937"
cy="6141"
r="47"
style="fill:#0000ff;stroke:#0000ff;stroke-width:32"
id="circle174" />
<circle
cx="2551"
cy="5433"
r="47"
style="fill:#0000ff;stroke:#0000ff;stroke-width:32"
id="circle176" />
<polyline
points="3118,3590 2834,3779"
style="stroke:#0000ff"
id="polyline178" />
<polyline
points="1322,3590 1039,3779"
style="stroke:#0000ff"
id="polyline180" />
<polyline
points="4913,3590 4629,3779"
style="stroke:#0000ff"
id="polyline184" />
<polyline
points="6519,3590 6236,3779"
style="stroke:#0000ff"
id="polyline186" />
<polyline
points="8314,3590 8031,3779"
style="stroke:#0000ff"
id="polyline188" />
<circle
cx="1653"
cy="7086"
r="47"
style="fill:#0000ff;stroke:#0000ff;stroke-width:32"
id="circle190" />
<polyline
points="1653,7086 1181,7086 1181,6377 1354,6377"
style="stroke:#0000ff"
id="polyline192" />
<polygon
points="1512,6377 1355,6330 1355,6425 1355,6425 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon194" />
<polyline
points="7937,6141 8173,6141 8173,7322 8346,7322"
style="stroke:#0000ff"
id="polyline196" />
<polygon
points="8504,7322 8347,7275 8347,7370 8347,7370 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon198" />
<polyline
points="8173,3543 8173,5669 8346,5669"
style="stroke:#0000ff"
id="polyline200" />
<polygon
points="8504,5669 8347,5622 8347,5716 8347,5716 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon202" />
<polyline
points="9212,3070 9070,3307 8314,3307 8173,3543 8031,3307 7228,3307 7086,3070"
style="stroke:#0000ff"
id="polyline204" />
<polyline
points="3898,3070 4015,3307 4629,3307 4771,3543 4913,3307 5385,3307 5491,3070"
style="stroke:#0000ff"
id="polyline206" />
<polyline
points="5491,3070 5622,3307 6236,3307 6377,3543 6519,3307 6909,3307 7086,3070"
style="stroke:#0000ff"
id="polyline208" />
<polyline
points="2303,3070 2409,3307 2834,3307 2976,3543 3118,3307 3779,3307 3898,3070"
style="stroke:#0000ff"
id="polyline210" />
<polyline
points="708,3070 850,3307 1039,3307 1181,3543 1322,3307 2173,3307 2303,3070"
style="stroke:#0000ff"
id="polyline212" />
<polyline
points="4771,3543 4771,6141 4944,6141"
style="stroke:#0000ff"
id="polyline214" />
<polygon
points="5103,6141 4945,6094 4945,6188 4945,6188 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon216" />
<polyline
points="6377,3543 6377,4015 6519,4157 6519,6377 6740,6377"
style="stroke:#0000ff"
id="polyline218" />
<polygon
points="6898,6377 6741,6330 6741,6425 6741,6425 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon220" />
<polyline
points="6141,5905 6377,5905 6377,7086 6740,7086"
style="stroke:#0000ff"
id="polyline222" />
<polygon
points="6898,7086 6741,7039 6741,7133 6741,7133 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon224" />
<polyline
points="4346,5669 4629,5669 4629,6850 4944,6850"
style="stroke:#0000ff"
id="polyline226" />
<polygon
points="5103,6850 4945,6803 4945,6897 4945,6897 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon228" />
<polyline
points="2598,5433 2834,5433 2834,6614 3149,6614"
style="stroke:#0000ff"
id="polyline230" />
<polygon
points="3308,6614 3150,6566 3150,6661 3150,6661 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon232" />
<polyline
points="1181,3543 1181,5669 1401,5669"
style="stroke:#0000ff"
id="polyline234" />
<polygon
points="1560,5669 1402,5622 1402,5716 1402,5716 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon236" />
<polyline
points="2976,3543 2976,5905 3149,5905"
style="stroke:#0000ff"
id="polyline238" />
<polygon
points="3308,5905 3150,5858 3150,5952 3150,5952 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon240" />
<g
style="fill:#000000;stroke-width:0"
id="g242">
<text
xml:space="preserve"
x="2281.8145"
y="7165"
font-style="normal"
font-weight="normal"
font-size="152"
id="text244"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle">CR3 register</text>
<text
xml:space="preserve"
x="3507"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text246"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">32</text>
<text
xml:space="preserve"
x="2161"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text248"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">39</text>
<text
xml:space="preserve"
x="2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text250"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">40</text>
<text
xml:space="preserve"
x="744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">47</text>
<text
xml:space="preserve"
x="672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text254"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text256"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="-744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text258"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text260"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="9176"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text262"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">0</text>
<text
xml:space="preserve"
x="7759"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text264"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">8</text>
<text
xml:space="preserve"
x="6342"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text266"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">16</text>
<text
xml:space="preserve"
x="4924"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text268"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">24</text>
<text
xml:space="preserve"
x="3579"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text270"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">31</text>
<text
xml:space="preserve"
x="6413"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text272"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">15</text>
<text
xml:space="preserve"
x="7830"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text274"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">7</text>
<text
xml:space="preserve"
x="4996"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text276"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">23</text>
<g
transform="matrix(0,-1,1,0,8976,4724)"
id="g278">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text280"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,8976,6614)"
id="g282">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text284"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,9448,5622)"
id="g286">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="152"
id="text288"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46390561px"
id="tspan3509">4K memory page</tspan></text>
</g>
<text
xml:space="preserve"
x="-2125"
y="2314"
font-style="normal"
font-weight="normal"
font-size="152"
id="text290"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
xml:space="preserve"
x="5622"
y="5958.457"
font-style="normal"
font-weight="normal"
font-size="152"
id="text292"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3497">P2 entry</tspan></text>
<g
transform="matrix(0,-1,1,0,5723,6614)"
id="g296">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text298"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,5723,5196)"
id="g300">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text302"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="5692"
y="4393"
font-style="normal"
font-weight="normal"
font-size="152"
id="text304"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46390561px"
id="tspan3505">P2 table</tspan></text>
<g
transform="matrix(0,-1,1,0,3928,6377)"
id="g306">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,3928,4960)"
id="g310">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text312"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3826"
y="5722.457"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3495">P3 entry</tspan></text>
<text
xml:space="preserve"
x="3874"
y="3968"
font-style="normal"
font-weight="normal"
font-size="152"
id="text318"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
xml:space="preserve"
x="3874"
y="4157"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46390561px"
id="tspan3503">P3 table</tspan></text>
<text
xml:space="preserve"
x="7417"
y="6194.457"
font-style="normal"
font-weight="normal"
font-size="152"
id="text322"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3499">P1 entry </tspan></text>
<g
transform="matrix(0,-1,1,0,7519,6850)"
id="g326">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text328"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,7519,5433)"
id="g330">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text332"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="7487"
y="4629"
font-style="normal"
font-weight="normal"
font-size="152"
id="text334"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46390561px"
id="tspan3507">P1 table</tspan></text>
<g
transform="matrix(0,-1,1,0,2133,6141)"
id="g336">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text338"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,2133,4724)"
id="g340">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text342"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
x="2004.2715"
y="5486.457"
font-style="normal"
font-weight="normal"
font-size="152"
id="text344"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle">
<tspan
style="font-size:200.46390561px"
id="tspan3493">P4 entry</tspan>
</text>
<text
x="2031"
y="5622"
font-style="normal"
font-weight="normal"
font-size="152"
id="text346"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="2078"
y="3941.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text348"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle">
<tspan
style="font-size:200.46391296px"
id="tspan3501">P4 table</tspan>
</text>
<text
x="3165"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text350"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="1370"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text352"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="1370"
y="6708"
font-style="normal"
font-weight="normal"
font-size="152"
id="text354"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff" />
<text
x="4960"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text356"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="6566"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text358"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="8362"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text360"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">12</text>
<text
x="1181"
y="7532.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text364"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -1,30 +1,27 @@
+++
title = "Entering Long Mode"
slug = "entering-longmode"
date = "2015-08-25"
weight = 2
path = "entering-longmode"
aliases = ["entering-longmode.html", "/2015/08/25/entering-longmode/", "/rust-os/entering-longmode.html"]
date = 2015-08-25
template = "edition-1/page.html"
[extra]
updated = "2015-10-29"
aliases = [
"/2015/08/25/entering-longmode/",
"/rust-os/entering-longmode.html",
]
+++
In the [previous post] we created a minimal multiboot kernel. It just prints `OK` and hangs. The goal is to extend it and call 64-bit [Rust] code. But the CPU is currently in [protected mode] and allows only 32-bit instructions and up to 4GiB memory. So we need to set up _Paging_ and switch to the 64-bit [long mode] first.
[previous post]: {{% relref "2015-08-18-multiboot-kernel.md" %}}
[Rust]: http://www.rust-lang.org/
[previous post]: @/edition-1/posts/01-multiboot-kernel/index.md
[Rust]: https://www.rust-lang.org/
[protected mode]: https://en.wikipedia.org/wiki/Protected_mode
[long mode]: https://en.wikipedia.org/wiki/Long_mode
<!--more-->
<!-- more -->
I tried to explain everything in detail and to keep the code as simple as possible. If you have any questions, suggestions, or issues, please leave a comment or [create an issue] on Github. The source code is available in a [repository][source code], too.
[create an issue]: https://github.com/phil-opp/blog_os/issues
[source code]: https://github.com/phil-opp/blog_os/tree/entering_longmode/src/arch/x86_64
_Notable Changes_: We don't use 1GiB pages anymore, since they have [compatibility problems][1GiB page problems]. The identity mapping is now done through 2MiB pages.
[1GiB page problems]: https://github.com/phil-opp/blog_os/issues/17
[source code]: https://github.com/phil-opp/blog_os/tree/first_edition_post_2/src/arch/x86_64
## Some Tests
To avoid bugs and strange errors on old CPUs we should check if the processor supports every needed feature. If not, the kernel should abort and display an error message. To handle errors easily, we create an error procedure in `boot.asm`. It prints a rudimentary `ERR: X` message, where X is an error code letter, and hangs:
@@ -42,7 +39,7 @@ error:
At address `0xb8000` begins the so-called [VGA text buffer]. It's an array of screen characters that are displayed by the graphics card. A [future post] will cover the VGA buffer in detail and create a Rust interface to it. But for now, manual bit-fiddling is the easiest option.
[VGA text buffer]: https://en.wikipedia.org/wiki/VGA-compatible_text_mode
[future post]: {{% relref "2015-10-23-printing-to-screen.md" %}}
[future post]: @/edition-1/posts/04-printing-to-screen/index.md
A screen character consists of a 8 bit color code and a 8 bit [ASCII] character. We used the color code `4f` for all characters, which means white text on red background. `0x52` is an ASCII `R`, `0x45` is an `E`, `0x3a` is a `:`, and `0x20` is a space. The second space is overwritten by the given ASCII byte. Finally the CPU is stopped with the `hlt` instruction.
@@ -50,7 +47,7 @@ A screen character consists of a 8 bit color code and a 8 bit [ASCII] character.
Now we can add some check _functions_. A function is just a normal label with an `ret` (return) instruction at the end. The `call` instruction can be used to call it. Unlike the `jmp` instruction that just jumps to a memory address, the `call` instruction will push a return address to the stack (and the `ret` will jump to this address). But we don't have a stack yet. The [stack pointer] in the esp register could point to some important data or even invalid memory. So we need to update it and point it to some valid stack memory.
[stack pointer]: http://stackoverflow.com/a/1464052/866447
[stack pointer]: https://stackoverflow.com/a/1464052/866447
### Creating a Stack
To create stack memory we reserve some bytes at the end of our `boot.asm`:
@@ -99,14 +96,14 @@ We use the `cmp` instruction to compare the value in `eax` to the magic value. I
In `no_multiboot`, we use the `jmp` (“jump”) instruction to jump to our error function. We could just as well use the `call` instruction, which additionally pushes the return address. But the return address is not needed because `error` never returns. To pass `0` as error code to the `error` function, we move it into `al` before the jump (`error` will read it from there).
[Multiboot specification]: http://nongnu.askapache.com/grub/phcoder/multiboot.pdf
[Multiboot specification]: https://nongnu.askapache.com/grub/phcoder/multiboot.pdf
[FLAGS register]: https://en.wikipedia.org/wiki/FLAGS_register
### CPUID check
[CPUID] is a CPU instruction that can be used to get various information about the CPU. But not every processor supports it. CPUID detection is quite laborious, so we just copy a detection function from the [OSDev wiki][CPUID detection]:
[CPUID]: http://wiki.osdev.org/CPUID
[CPUID detection]: http://wiki.osdev.org/Setting_Up_Long_Mode#Detection_of_CPUID
[CPUID]: https://wiki.osdev.org/CPUID
[CPUID detection]: https://wiki.osdev.org/Setting_Up_Long_Mode#Detection_of_CPUID
```nasm
check_cpuid:
@@ -154,7 +151,7 @@ Don't worry, you don't need to understand the details.
### Long Mode check
Now we can use CPUID to detect whether long mode can be used. I use code from [OSDev][long mode detection] again:
[long mode detection]: http://wiki.osdev.org/Setting_Up_Long_Mode#x86_or_x86-64
[long mode detection]: https://wiki.osdev.org/Setting_Up_Long_Mode#x86_or_x86-64
```nasm
check_long_mode:
@@ -174,7 +171,7 @@ check_long_mode:
mov al, "2"
jmp error
```
Like many low-level things, CPUID is a bit strange. Instead of taking a parameter, the `cpuid` instruction implicitely uses the `eax` register as argument. To test if long mode is available, we need to call `cpuid` with `0x80000001` in `eax`. This loads some information to the `ecx` and `edx` registers. Long mode is supported if the 29th bit in `edx` is set. [Wikipedia][cpuid long mode] has detailed information.
Like many low-level things, CPUID is a bit strange. Instead of taking a parameter, the `cpuid` instruction implicitly uses the `eax` register as argument. To test if long mode is available, we need to call `cpuid` with `0x80000001` in `eax`. This loads some information to the `ecx` and `edx` registers. Long mode is supported if the 29th bit in `edx` is set. [Wikipedia][cpuid long mode] has detailed information.
[cpuid long mode]: https://en.wikipedia.org/wiki/CPUID#EAX.3D80000001h:_Extended_Processor_Info_and_Feature_Bits
@@ -184,11 +181,11 @@ If you look at the assembly above, you'll probably notice that we call `cpuid` t
We just call these check functions right after start:
```nasm
global _start
global start
section .text
bits 32
_start:
start:
mov esp, stack_top
call check_multiboot
@@ -217,11 +214,7 @@ As I don't like these names, I will call them P4, P3, P2, and P1 from now on.
Each page table contains 512 entries and one entry is 8 bytes, so they fit exactly in one page (`512*8 = 4096`). To translate a virtual address to a physical address the CPU[^hardware_lookup] will do the following[^virtual_physical_translation_source]:
[^hardware_lookup]: In the x86 architecture, the page tables are _hardware walked_, so the CPU will look at the table on its own when it needs a translation. Other architectures, for example MIPS, just throw an exception and let the OS translate the virtual address.
[^virtual_physical_translation_source]: Image source: [Wikipedia](https://commons.wikimedia.org/wiki/File:X86_Paging_64bit.svg), with modified font size, page table naming, and removed sign extended bits. The modified file is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license.
![translation of virtual to physical addresses in 64 bit mode](/images/X86_Paging_64bit.svg)
![translation of virtual to physical addresses in 64 bit mode](X86_Paging_64bit.svg)
1. Get the address of the P4 table from the CR3 register
2. Use bits 39-47 (9 bits) as an index into P4 (`2^9 = 512 = number of entries`)
@@ -255,14 +248,13 @@ Bit(s) | Name | Meaning
When we switch to long mode, paging will be activated automatically. The CPU will then try to read the instruction at the following address, but this address is now a virtual address. So we need to do _identity mapping_, i.e. map a physical address to the same virtual address.
The `huge page` bit is now very useful to us. It creates a 2MiB (when used in P2) or even a 1GiB page (when used in P3). So we could map the first _gigabytes_ of the kernel with only one P4 and one P3 table by using 1GiB pages. Unfortunately 1GiB pages are relatively new feature, for example Intel introduced it 2010 in the [Westmere architecture]. Therefore we will use 2MiB pages instead to make our kernel compatible to older computers, too.
[Westmere architecture]: https://en.wikipedia.org/wiki/Westmere_(microarchitecture)#Technology
To identity map the first gigabyte of our kernel with 512 2MiB pages, we need one P4, one P3, and one P2 table. Of course we will replace them with finer-grained tables later. But now that we're stuck with assembly, we choose the easiest way.
We can add these two tables at the beginning[^page_table_alignment] of the `.bss` section:
[^page_table_alignment]: Page tables need to be page-aligned as the bits 0-11 are used for flags. By putting these tables at the beginning of `.bss`, the linker can just page align the whole section and we don't have unused padding bytes in between.
```nasm
...
@@ -320,7 +312,7 @@ set_up_page_tables:
ret
```
Maybe I first explain how an assembly loop works. We use the `ecx` register as a counter variable, just like `i` in a for loop. After mapping the `ecx-th` entry, we increase `ecx` by one and jump to `.map_p2_table` again if it's still smaller 512.
Maybe I should first explain how an assembly loop works. We use the `ecx` register as a counter variable, just like `i` in a for loop. After mapping the `ecx-th` entry, we increase `ecx` by one and jump to `.map_p2_table` again if it's still smaller than 512.
To map a P2 entry we first calculate the start address of its page in `eax`: The `ecx-th` entry needs to be mapped to `ecx * 2MiB`. We use the `mul` operation for that, which multiplies `eax` with the given register and stores the result in `eax`. Then we set the `present`, `writable`, and `huge page` bits and write it to the P2 entry. The address of the `ecx-th` entry in P2 is `p2_table + ecx * 8`, because each entry is 8 bytes large.
@@ -386,55 +378,47 @@ start:
To test it we execute `make run`. If the green OK is still printed, we have successfully enabled paging!
## The Global Descriptor Table
After enabling Paging, the processor is in long mode. So we can use 64-bit instructions now, right? Wrong. The processor is still in some 32-bit compatibility submode. To actually execute 64-bit code, we need to set up a new Global Descriptor Table.
After enabling Paging, the processor is in long mode. So we can use 64-bit instructions now, right? Wrong. The processor is still in a 32-bit compatibility submode. To actually execute 64-bit code, we need to set up a new Global Descriptor Table.
The Global Descriptor Table (GDT) was used for _Segmentation_ in old operating systems. I won't explain Segmentation but the [Three Easy Pieces] OS book has good introduction ([PDF][Segmentation chapter]) again.
[Segmentation chapter]: http://pages.cs.wisc.edu/~remzi/OSTEP/vm-segmentation.pdf
Today almost everyone uses Paging instead of Segmentation (and so do we). But on x86, a GDT is always required, even when you're not using Segmentation. GRUB has set up a valid 32-bit GDT for us but now we need to switch to a long mode GDT.
A GDT always starts with a 0-entry and contains an arbitrary number of segment entries afterwards. An entry has the following format:
A GDT always starts with a 0-entry and contains an arbitrary number of segment entries afterwards. A 64-bit entry has the following format:
Bit(s) | Name | Meaning
--------------------- | ------ | ----------------------------------
0-15 | limit 0-15 | the first 2 byte of the segment's limit
16-39 | base 0-23 | the first 3 byte of the segment's base address
40 | accessed | set by the CPU when the segment is accessed
41 | read/write | reads allowed for code segments / writes allowed for data segments
42 | direction/conforming | the segment grows down (i.e. base>limit) for data segments / the current privilege level can be higher than the specified level for code segments (else it must match exactly)
0-41 | ignored | ignored in 64-bit mode
42 | conforming | the current privilege level can be higher than the specified level for code segments (else it must match exactly)
43 | executable | if set, it's a code segment, else it's a data segment
44 | descriptor type | should be 1 for code and data segments
45-46 | privilege | the [ring level]: 0 for kernel, 3 for user
47 | present | must be 1 for valid selectors
48-51 | limit 16-19 | bits 16 to 19 of the segment's limit
52 | available | freely available to the OS
48-52 | ignored | ignored in 64-bit mode
53 | 64-bit | should be set for 64-bit code segments
54 | 32-bit | should be set for 32-bit segments
55 | granularity | if it's set, the limit is the number of pages, else it's a byte number
56-63 | base 24-31 | the last byte of the base address
54 | 32-bit | must be 0 for 64-bit segments
55-63 | ignored | ignored in 64-bit mode
[ring level]: http://wiki.osdev.org/Security#Rings
[ring level]: https://wiki.osdev.org/Security#Rings
We need one code and one data segment. They have the following bits set: _descriptor type_, _present_, and _read/write_. The code segment has additionally the _executable_ and the _64-bit_ flag. In Long mode, it's not possible to actually use the GDT entries for Segmentation and thus the base and limit fields must be 0. Translated to assembly the long mode GDT looks like this:
We need one code segment, a data segment is not necessary in 64-bit mode. Code segments have the following bits set: _descriptor type_, _present_, _executable_ and the _64-bit_ flag. Translated to assembly the long mode GDT looks like this:
```nasm
section .rodata
gdt64:
dq 0 ; zero entry
dq (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53) ; code segment
dq (1<<44) | (1<<47) | (1<<41) ; data segment
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
```
We chose the `.rodata` section here because it's initialized read-only data. The `dq` command stands for `define quad` and outputs a 64-bit constant (similar to `dw` and `dd`). And the `(1<<44)` is a [bit shift] that sets bit 44.
[bit shift]: http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/bitshift.html
We chose the `.rodata` section here because it's initialized read-only data. The `dq` command stands for `define quad` and outputs a 64-bit constant (similar to `dw` and `dd`). And the `(1<<43)` is a bit shift that sets bit 43.
### Loading the GDT
To load our new 64-bit GDT, we have to tell the CPU its address and length. We do this by passing the memory location of a special pointer structure to the `lgdt` (load GDT) instruction. The pointer structure looks like this:
```nasm
gdt64:
...
dq (1<<44) | (1<<47) | (1<<41) ; data segment
dq 0 ; zero entry
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
.pointer:
dw $ - gdt64 - 1
dq gdt64
@@ -454,39 +438,22 @@ start:
; print `OK` to screen
...
```
When you still see the green `OK`, everything went fine and the new GDT is loaded. But we still can't execute 64-bit code: The selector registers such as the code selector `cs` and the data selector `ds` still have the values from the old GDT. To update them, we need to load them with the GDT offset (in bytes) of the desired segment. In our case the code segment starts at byte 8 of the GDT and the data segment at byte 16. Let's try it:
```nasm
...
lgdt [gdt64.pointer]
; update selectors
mov ax, 16
mov ss, ax ; stack selector
mov ds, ax ; data selector
mov es, ax ; extra selector
; print `OK` to screen
...
```
It should still work. The segment selectors are only 16-bits large, so we use the 16-bit `ax` subregister. Notice that we didn't update the code selector `cs`. We will do that later. First we should replace this hardcoded `16` by adding some labels to our GDT:
When you still see the green `OK`, everything went fine and the new GDT is loaded. But we still can't execute 64-bit code: The code selector register `cs` still has the values from the old GDT. To update it, we need to load it with the GDT offset (in bytes) of the desired segment. In our case the code segment starts at byte 8 of the GDT, but we don't want to hardcode that 8 (in case we modify our GDT later). Instead, we add a `.code` label to our GDT, that calculates the offset directly from the GDT:
```nasm
section .rodata
gdt64:
dq 0 ; zero entry
.code: equ $ - gdt64 ; new
dq (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53) ; code segment
.data: equ $ - gdt64 ; new
dq (1<<44) | (1<<47) | (1<<41) ; data segment
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
.pointer:
...
```
We can't just use normal labels here, as we need the table offset. We calculate this offset using the current address `$` and set the labels to this value using [equ]. Now we can use `gdt64.data` instead of 16 and `gdt64.code` instead of 8 and these labels will still work if we modify the GDT.
We can't just use a normal label here, since we need the table _offset_. We calculate this offset using the current address `$` and set the label to this value using [equ]. Now we can use `gdt64.code` instead of 8 and this label will still work if we modify the GDT.
[equ]: http://www.nasm.us/doc/nasmdoc3.html#section-3.2.4
[equ]: https://www.nasm.us/doc/nasmdoc3.html#section-3.2.4
Now there is just one last step left to enter the true 64-bit mode: We need to load `cs` with `gdt64.code`. But we can't do it through `mov`. The only way to reload the code selector is a _far jump_ or a _far return_. These instructions work like a normal jump/return but change the code selector. We use a far jump to a long mode label:
In order to finally enter the true 64-bit mode, we need to load `cs` with `gdt64.code`. But we can't do it through `mov`. The only way to reload the code selector is a _far jump_ or a _far return_. These instructions work like a normal jump/return but change the code selector. We use a far jump to a long mode label:
```nasm
global start
@@ -496,12 +463,6 @@ start:
...
lgdt [gdt64.pointer]
; update selectors
mov ax, gdt64.data
mov ss, ax
mov ds, ax
mov es, ax
jmp gdt64.code:long_mode_start
...
```
@@ -528,10 +489,37 @@ You should see a green `OKAY` on the screen. Some notes on this last step:
_Congratulations_! You have successfully wrestled through this CPU configuration and compatibility mode mess :).
## What's next?
It's time to finally leave assembly behind[^leave_assembly_behind] and switch to some higher level language. We won't use C or C++ (not even a single line). Instead we will use the relatively new [Rust] language. It's a systems language without garbage collections but with guaranteed memory safety. Through a real type system and many abstractions it feels like a high-level language but can still be low-level enough for OS development. The [next post] describes the Rust setup.
#### One Last Thing
Above, we reloaded the code segment register `cs` with the new GDT offset. However, the data segment registers `ss`, `ds`, `es`, `fs`, and `gs` still contain the data segment offsets of the old GDT. This isn't necessarily bad, since they're ignored by almost all instructions in 64-bit mode. However, there are a few instructions that expect a valid data segment descriptor _or the null descriptor_ in those registers. An example is the the [iretq] instruction that we'll need in the [_Returning from Exceptions_] post.
[^leave_assembly_behind]: Actually we will still need some assembly in the future, but I'll try to minimize it.
[iretq]: @/edition-1/extra/naked-exceptions/03-returning-from-exceptions/index.md#the-iretq-instruction
[_Returning from Exceptions_]: @/edition-1/extra/naked-exceptions/03-returning-from-exceptions/index.md
To avoid future problems, we reload all data segment registers with null:
```nasm
long_mode_start:
; load 0 into all data segment registers
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; print `OKAY` to screen
...
```
## What's next?
It's time to finally leave assembly behind and switch to [Rust]. Rust is a systems language without garbage collections that guarantees memory safety. Through a real type system and many abstractions it feels like a high-level language but can still be low-level enough for OS development. The [next post] describes the Rust setup.
[Rust]: https://www.rust-lang.org/
[next post]: {{% relref "2015-09-02-set-up-rust.md" %}}
[next post]: @/edition-1/posts/03-set-up-rust/index.md
## Footnotes
[^hardware_lookup]: In the x86 architecture, the page tables are _hardware walked_, so the CPU will look at the table on its own when it needs a translation. Other architectures, for example MIPS, just throw an exception and let the OS translate the virtual address.
[^virtual_physical_translation_source]: Image source: [Wikipedia](https://commons.wikimedia.org/wiki/File:X86_Paging_64bit.svg), with modified font size, page table naming, and removed sign extended bits. The modified file is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license.
[^page_table_alignment]: Page tables need to be page-aligned as the bits 0-11 are used for flags. By putting these tables at the beginning of `.bss`, the linker can just page align the whole section and we don't have unused padding bytes in between.

View File

@@ -0,0 +1,491 @@
+++
title = "Set Up Rust"
weight = 3
path = "set-up-rust"
aliases = ["set-up-rust.html", "setup-rust.html", "/2015/09/02/setup-rust/", "/rust-os/setup-rust.html"]
date = 2015-09-02
template = "edition-1/page.html"
[extra]
updated = "2017-04-12"
+++
In the previous posts we created a [minimal Multiboot kernel][multiboot post] and [switched to Long Mode][long mode post]. Now we can finally switch to [Rust] code. Rust is a high-level language without runtime. It allows us to not link the standard library and write bare metal code. Unfortunately the setup is not quite hassle-free yet.
[multiboot post]: @/edition-1/posts/01-multiboot-kernel/index.md
[long mode post]: @/edition-1/posts/02-entering-longmode/index.md
[Rust]: https://www.rust-lang.org/
<!-- more -->
This blog post tries to set up Rust step-by-step and point out the different problems. If you have any questions, problems, or suggestions please [file an issue] or create a comment at the bottom. The code from this post is in a [Github repository], too.
[file an issue]: https://github.com/phil-opp/blog_os/issues
[Github repository]: https://github.com/phil-opp/blog_os/tree/first_edition_post_3
## Installing Rust
We need a nightly compiler, as we will use many unstable features. To manage Rust installations I highly recommend [rustup]. It allows you to install nightly, beta, and stable compilers side-by-side and makes it easy to update them. To use a nightly compiler for the current directory, you can run `rustup override add nightly`. Alternatively, you can add a file called `rust-toolchain` to the project's root directory:
```
nightly
```
[rustup]: https://www.rustup.rs/
## Creating a Cargo project
[Cargo] is Rust's excellent package manager. Normally you would call `cargo new` when you want to create a new project folder. We can't use it because our folder already exists, so we need to do it manually. Fortunately we only need to add a cargo configuration file named `Cargo.toml`:
[Cargo]: https://doc.crates.io/guide.html
```toml
[package]
name = "blog_os"
version = "0.1.0"
authors = ["Philipp Oppermann <dev@phil-opp.com>"]
[lib]
crate-type = ["staticlib"]
```
The `package` section contains required project metadata such as the [semantic crate version]. The `lib` section specifies that we want to build a static library, i.e. a library that contains all of its dependencies. This is required to link the Rust project with our kernel.
[semantic crate version]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-package-section
Now we place our root source file in `src/lib.rs`:
```rust
#![feature(lang_items)]
#![no_std]
#[no_mangle]
pub extern fn rust_main() {}
#[lang = "eh_personality"] #[no_mangle] pub extern fn eh_personality() {}
#[lang = "panic_fmt"] #[no_mangle] pub extern fn panic_fmt() -> ! {loop{}}
```
Let's break it down:
- `#!` defines an [attribute] of the current module. Since we are at the root module, the attributes apply to the crate itself.
- The `feature` attribute is used to allow the specified _feature-gated_ attributes in this crate. You can't do that in a stable/beta compiler, so this is one reason we need a Rust nighly.
- The `no_std` attribute prevents the automatic linking of the standard library. We can't use `std` because it relies on operating system features like files, system calls, and various device drivers. Remember that currently the only “feature” of our OS is printing `OKAY` :).
- A `#` without a `!` afterwards defines an attribute for the _following_ item (a function in our case).
- The `no_mangle` attribute disables the automatic [name mangling] that Rust uses to get unique function names. We want to do a `call rust_main` from our assembly code, so this function name must stay as it is.
- We mark our main function as `extern` to make it compatible to the standard C [calling convention].
- The `lang` attribute defines a Rust [language item].
- The `eh_personality` function is used for Rust's [unwinding] on `panic!`. We can leave it empty since we don't have any unwinding support in our OS yet.
- The `panic_fmt` function is the entry point on panic. Right now we can't do anything useful, so we just make sure that it doesn't return (required by the `!` return type).
[attribute]: https://doc.rust-lang.org/book/attributes.html
[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
[calling convention]: https://en.wikipedia.org/wiki/Calling_convention
[language item]: https://doc.rust-lang.org/1.10.0/book/lang-items.html
[unwinding]: https://doc.rust-lang.org/nomicon/unwinding.html
## Building Rust
We can now build it using `cargo build`, which creates a static library at `target/debug/libblog_os.a`. However, the resulting library is specific to our _host_ operating system. This is undesirable, because our target system might be different.
Let's define some properties of our target system:
- **x86_64**: Our target CPU is a recent `x86_64` CPU.
- **No operating system**: Our target does not run any operating system (we're currently writing it), so the compiler should not assume any OS-specific functionality.
- **Handles hardware interrupts**: We're writing a kernel, so we'll need to handle asynchronous hardware interrupts at some point. This means that we have to disable a certain stack pointer optimization (the so-called [red zone]), because it would cause stack corruptions otherwise.
- **No SSE**: Our target might not have [SSE] support. Even if it does, we probably don't want to use SSE instructions in our kernel, because it makes interrupt handling much slower. We will explain this in detail in the [“Handling Exceptions”] post.
- **No hardware floats**: The `x86_64` architecture uses SSE instructions for floating point operations, which we don't want to use (see the previous point). So we also need to avoid hardware floating point operations in our kernel. Instead, we will use _soft floats_, which are basically software functions that emulate floating point operations using normal integers.
[“Handling Exceptions”]: @/edition-1/posts/09-handling-exceptions/index.md
### Target Specifications
Rust allows us to define [custom targets] through a JSON configuration file. A minimal target specification equal to `x86_64-unknown-linux-gnu` (the default 64-bit Linux target) looks like this:
```json
{
"llvm-target": "x86_64-unknown-linux-gnu",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"linker-flavor": "gcc",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"arch": "x86_64",
"os": "linux"
}
```
[custom targets]: https://doc.rust-lang.org/1.1.0/rustc_back/target/
The `llvm-target` field specifies the target triple that is passed to LLVM. [Target triples] are a naming convention that define the CPU architecture (e.g., `x86_64` or `arm`), the vendor (e.g., `apple` or `unknown`), the operating system (e.g., `windows` or `linux`), and the [ABI] \(e.g., `gnu` or `msvc`). For example, the target triple for 64-bit Linux is `x86_64-unknown-linux-gnu` and for 32-bit Windows the target triple is `i686-pc-windows-msvc`.
[Target triples]: https://llvm.org/docs/LangRef.html#target-triple
[ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
The `data-layout` field is also passed to LLVM and specifies how data should be laid out in memory. It consists of various specifications separated by a `-` character. For example, the `e` means little endian and `S128` specifies that the stack should be 128 bits (= 16 byte) aligned. The format is described in detail in the [LLVM documentation][data layout] but there shouldn't be a reason to change this string.
The `linker-flavor` field was recently introduced in [#40018] with the intention to add support for the LLVM linker [LLD], which is platform independent. In the future, this might allow easy cross compilation without the need to install a gcc cross compiler for linking.
[#40018]: https://github.com/rust-lang/rust/pull/40018
[LLD]: https://lld.llvm.org/
The other fields are used for conditional compilation. This allows crate authors to use `cfg` variables to write special code for depending on the OS or the architecture. There isn't any up-to-date documentation about these fields but the [corresponding source code][target specification] is quite readable.
[data layout]: https://llvm.org/docs/LangRef.html#data-layout
[target specification]: https://github.com/rust-lang/rust/blob/c772948b687488a087356cb91432425662e034b9/src/librustc_back/target/mod.rs#L194-L214
### A Kernel Target Specification
For our target system, we define the following JSON configuration in a file named `x86_64-blog_os.json`:
```json
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"linker-flavor": "gcc",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"arch": "x86_64",
"os": "none",
"disable-redzone": true,
"features": "-mmx,-sse,+soft-float"
}
```
As `llvm-target` we use `x86_64-unknown-none`, which defines the `x86_64` architecture, an `unknown` vendor, and no operating system (`none`). The ABI doesn't matter for us, so we just leave it off. The `data-layout` field is just copied from the `x86_64-unknown-linux-gnu` target. We also use the same values for the `target-endian`, `target-pointer-width`, `target-c-int-width`, and `arch` fields. For the `os` field we choose `none`, since our kernel runs on bare metal.
#### The Red Zone
The [red zone] is an optimization of the [System V ABI] that allows functions to temporary use the 128 bytes below its stack frame without adjusting the stack pointer:
[red zone]: https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone
[System V ABI]: https://wiki.osdev.org/System_V_ABI
![stack frame with red zone](red-zone.svg)
The image shows the stack frame of a function with `n` local variables. On function entry, the stack pointer is adjusted to make room on the stack for the local variables.
The red zone is defined as the 128 bytes below the adjusted stack pointer. The function can use this area for temporary data that's not needed across function calls. Thus, the two instructions for adjusting the stack pointer can be avoided in some cases (e.g. in small leaf functions).
However, this optimization leads to huge problems with exceptions or hardware interrupts. Let's assume that an exception occurs while a function uses the red zone:
![red zone overwritten by exception handler](red-zone-overwrite.svg)
The CPU and the exception handler overwrite the data in red zone. But this data is still needed by the interrupted function. So the function won't work correctly anymore when we return from the exception handler. This might lead to strange bugs that [take weeks to debug].
[take weeks to debug]: https://forum.osdev.org/viewtopic.php?t=21720
To avoid such bugs when we implement exception handling in the future, we disable the red zone right from the beginning. This is achieved by adding the `"disable-redzone": true` line to our target configuration file.
#### SIMD Extensions
The `features` field enables/disables target features. We disable the `mmx` and `sse` features by prefixing them with a minus and enable the `soft-float` feature by prefixing it with a plus. The `mmx` and `sse` features determine support for [Single Instruction Multiple Data (SIMD)] instructions, which simultaneously perform an operation (e.g. addition) on multiple data words. The `x86` architecture supports the following standards:
[Single Instruction Multiple Data (SIMD)]: https://en.wikipedia.org/wiki/SIMD
- [MMX]: The _Multi Media Extension_ instruction set was introduced in 1997 and defines eight 64 bit registers called `mm0` through `mm7`. These registers are just aliases for the registers of the [x87 floating point unit].
- [SSE]: The _Streaming SIMD Extensions_ instruction set was introduced in 1999. Instead of re-using the floating point registers, it adds a completely new register set. The sixteen new registers are called `xmm0` through `xmm15` and are 128 bits each.
- [AVX]: The _Advanced Vector Extensions_ are extensions that further increase the size of the multimedia registers. The new registers are called `ymm0` through `ymm15` and are 256 bits each. They extend the `xmm` registers, so e.g. `xmm0` is the lower half of `ymm0`.
[MMX]: https://en.wikipedia.org/wiki/MMX_(instruction_set)
[x87 floating point unit]: https://en.wikipedia.org/wiki/X87
[SSE]: https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions
[AVX]: https://en.wikipedia.org/wiki/Advanced_Vector_Extensions
By using such SIMD standards, programs can often speed up significantly. Good compilers are able to transform normal loops into such SIMD code automatically through a process called [auto-vectorization].
[auto-vectorization]: https://en.wikipedia.org/wiki/Automatic_vectorization
However, the large SIMD registers lead to problems in OS kernels. The reason is that the kernel has to backup all registers that it uses on each hardware interrupt (we will look into this in the [“Handling Exceptions”] post). So if the kernel uses SIMD registers, it has to backup a lot more data, which noticeably decreases performance. To avoid this performance loss, we disable the `sse` and `mmx` features (the `avx` feature is disabled by default).
As noted above, floating point operations on `x86_64` use SSE registers, so floats are no longer usable without SSE. Unfortunately, the Rust core library already uses floats (e.g., it implements traits for `f32` and `f64`), so we need an alternative way to implement float operations. The `soft-float` feature solves this problem by emulating all floating point operations through software functions based on normal integers.
### Compiling
To build our kernel for our new target, we pass the configuration file's name as `--target` argument. There is currently an [open bug][custom-target-bug] for custom target specifications, so you also need to set the `RUST_TARGET_PATH` environment variable to the current directory, otherwise Rust doesn't find your target. The full command is:
[custom-target-bug]: https://github.com/rust-lang/cargo/issues/4905
```
RUST_TARGET_PATH=$(pwd) cargo build --target x86_64-blog_os
```
However, the following error occurs:
```
error[E0463]: can't find crate for `core`
|
= note: the `x86_64-blog_os` target may not be installed
```
The error tells us that the Rust compiler no longer finds the core library. The [core library] is implicitly linked to all `no_std` crates and contains things such as `Result`, `Option`, and iterators.
[core library]: https://doc.rust-lang.org/nightly/core/index.html
The problem is that the core library is distributed together with the Rust compiler as a _precompiled_ library. So it is only valid for the host triple (e.g., `x86_64-unknown-linux-gnu`) but not for our custom target. If we want to compile code for other targets, we need to recompile `core` for these targets first.
#### Xargo
That's where [xargo] comes in. It is a wrapper for cargo that eases cross compilation. We can install it by executing:
[xargo]: https://github.com/japaric/xargo
```
cargo install xargo
```
Xargo depends on the rust source code, which we can install with `rustup component add rust-src`.
Xargo is “a drop-in replacement for cargo”, so every cargo command also works with `xargo`. You can do e.g. `xargo --help`, `xargo clean`, or `xargo doc`. However, the `build` command gains additional functionality: `xargo build` will automatically cross compile the `core` library when compiling for custom targets.
Let's try it:
```bash
> RUST_TARGET_PATH=$(pwd) xargo build --target=x86_64-blog_os
Compiling core v0.0.0 (file:///…/rust/src/libcore)
Finished release [optimized] target(s) in 22.87 secs
Compiling blog_os v0.1.0 (file:///…/blog_os/tags)
Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs
```
It worked! We see that `xargo` cross-compiled the `core` library for our new custom target and then continued to compile our `blog_os` crate. After compilation, we can find a static library at `target/x86_64-blog_os/debug/libblog_os.a`, which can be linked with our assembly kernel.
## Integrating Rust
Let's try to integrate our Rust library into our assembly kernel so that we can call the `rust_main` function. For that we need to pass the `libblog_os.a` file to the linker, together with the assembly object files.
### Adjusting the Makefile
To build and link the rust library on `make`, we extend our `Makefile`([full file][github makefile]):
```make
# ...
target ?= $(arch)-blog_os
rust_os := target/$(target)/debug/libblog_os.a
# ...
.PHONY: all clean run iso kernel
# ...
$(kernel): kernel $(rust_os) $(assembly_object_files) $(linker_script)
@ld -n -T $(linker_script) -o $(kernel) \
$(assembly_object_files) $(rust_os)
kernel:
@RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target)
```
We add a new `kernel` target that just executes `xargo build` and modify the `$(kernel)` target to link the created static lib. We also add the new `kernel` target to the `.PHONY` list, since it does not belong to a file with that name.
But now `xargo build` is executed on every `make`, even if no source file was changed. And the ISO is recreated on every `make iso`/`make run`, too. We could try to avoid this by adding dependencies on all rust source and cargo configuration files to the `kernel` target, but the ISO creation takes only half a second on my machine and most of the time we will have changed a Rust file when we run `make`. So we keep it simple for now and let cargo do the bookkeeping of changed files (it does it anyway).
[github makefile]: https://github.com/phil-opp/blog_os/blob/first_edition_post_3/Makefile
### Calling Rust
Now we can call the main method in `long_mode_start`:
```nasm
bits 64
long_mode_start:
...
; call the rust main
extern rust_main ; new
call rust_main ; new
; print `OKAY` to screen
mov rax, 0x2f592f412f4b2f4f
mov qword [0xb8000], rax
hlt
```
By defining `rust_main` as `extern` we tell nasm that the function is defined in another file. As the linker takes care of linking them together, we'll get a linker error if we have a typo in the name or forget to mark the rust function as `pub extern`.
If we've done everything right, we should still see the green `OKAY` when executing `make run`. That means that we successfully called the Rust function and returned back to assembly.
### Fixing Linker Errors
Now we can try some Rust code:
```rust
pub extern fn rust_main() {
let x = ["Hello", "World", "!"];
let y = x;
}
```
When we test it using `make run`, it fails with `undefined reference to 'memcpy'`. The `memcpy` function is one of the basic functions of the C library (`libc`). Usually the `libc` crate is linked to every Rust program together with the standard library, but we opted out through `#![no_std]`. We could try to fix this by adding the [libc crate] as `extern crate`. But `libc` is just a wrapper for the system `libc`, for example `glibc` on Linux, so this won't work for us. Instead we need to recreate the basic `libc` functions such as `memcpy`, `memmove`, `memset`, and `memcmp` in Rust.
[libc crate]: https://doc.rust-lang.org/1.10.0/libc/index.html
#### rlibc
Fortunately there already is a crate for that: [rlibc]. When we look at its [source code][rlibc source] we see that it contains no magic, just some [raw pointer] operations in a while loop. To add `rlibc` as a dependency we just need to add two lines to the `Cargo.toml`:
```toml
...
[dependencies]
rlibc = "1.0"
```
and an `extern crate` definition in our `src/lib.rs`:
```rust
...
extern crate rlibc;
#[no_mangle]
pub extern fn rust_main() {
...
```
Now `make run` doesn't complain about `memcpy` anymore. Instead it will show a pile of new ugly linker errors:
```
target/x86_64-blog_os/debug/libblog_os.a(core-92335f822fa6c9a6.0.o):
In function `_$LT$f32$u20$as$u20$core..num..dec2flt..
rawfp..RawFloat$GT$::from_int::h50f7952efac3fdca':
core.cgu-0.rs:(.text._ZN59_$LT$f32$u20$as$u20$core..num..dec2flt..
rawfp..RawFloat$GT$8from_int17h50f7952efac3fdcaE+0x2):
undefined reference to `__floatundisf'
target/x86_64-blog_os/debug/libblog_os.a(core-92335f822fa6c9a6.0.o):
In function `_$LT$f64$u20$as$u20$core..num..dec2flt..rawfp..
RawFloat$GT$::from_int::h12a81f175246914a':
core.cgu-0.rs:(.text._ZN59_$LT$f64$u20$as$u20$core..num..dec2flt..rawfp..
RawFloat$GT$8from_int17h12a81f175246914aE+0x2):
undefined reference to `__floatundidf'
target/x86_64-blog_os/debug/libblog_os.a(core-92335f822fa6c9a6.0.o):
In function `core::num::from_str_radix::h09b12650704e0508':
core.cgu-0.rs:(.text._ZN4core3num14from_str_radix
17h09b12650704e0508E+0xcf):
undefined reference to `__muloti4'
...
```
[rlibc]: https://crates.io/crates/rlibc
[rlibc source]: https://github.com/alexcrichton/rlibc/blob/defb486e765846417a8e73329e8c5196f1dca49a/src/lib.rs
[raw pointer]: https://doc.rust-lang.org/book/raw-pointers.html
[crates.io]: https://crates.io
#### --gc-sections
The new errors are linker errors about various missing functions such as `__floatundisf` or `__muloti4`. These functions are part of LLVM's [`compiler-rt` builtins] and are normally linked by the standard library. For `no_std` crates like ours, one has to link the `compiler-rt` library manually. Unfortunately, this library is implemented in C and the build process is a bit cumbersome. Alternatively, there is the [compiler-builtins] crate that tries to port the library to Rust, but it isn't complete yet.
[`compiler-rt` builtins]: https://compiler-rt.llvm.org/
[compiler-builtins]: https://github.com/rust-lang-nursery/compiler-builtins
In our case, there is a much simpler solution, since our kernel doesn't really need any of those functions yet. So we can just tell the linker to remove unused program sections and hopefully all references to these functions will disappear. Removing unused sections is generally a good idea as it reduces kernel size. The magic linker flag for this is `--gc-sections`, which stands for “garbage collect sections”. Let's add it to the `$(kernel)` target in our `Makefile`:
```make
$(kernel): xargo $(rust_os) $(assembly_object_files) $(linker_script)
@ld -n --gc-sections -T $(linker_script) -o $(kernel) \
$(assembly_object_files) $(rust_os)
```
Now we can do a `make run` again and it compiles without errors again. However, it doesn't boot anymore:
```
GRUB error: no multiboot header found.
```
What happened? Well, the linker removed unused sections. And since we don't use the Multiboot section anywhere, `ld` removes it, too. So we need to tell the linker explicitly that it should keep this section. The `KEEP` command does exactly that, so we add it to the linker script (`linker.ld`):
```
.boot :
{
/* ensure that the multiboot header is at the beginning */
KEEP(*(.multiboot_header))
}
```
Now everything should work again (the green `OKAY`). But there is another linking issue, which is triggered by some other example code.
#### panic = "abort"
The following snippet still fails:
```rust
...
let test = (0..3).flat_map(|x| 0..x).zip(0..);
```
The error is a linker error again (hence the ugly error message):
```
target/x86_64-blog_os/debug/libblog_os.a(blog_os-b5a29f28b14f1f1f.0.o):
In function `core::ptr::drop_in_place<core::iter::Zip<
core::iter::FlatMap<core::ops::Range<i32>, core::ops::Range<i32>,
closure>, core::ops::RangeFrom<i32>>>':
/…/rust/src/libcore/ptr.rs:66:
undefined reference to `_Unwind_Resume'
target/x86_64-blog_os/debug/libblog_os.a(blog_os-b5a29f28b14f1f1f.0.o):
In function `core::iter::iterator::Iterator::zip<core::iter::FlatMap<
core::ops::Range<i32>, core::ops::Range<i32>, closure>,
core::ops::RangeFrom<i32>>':
/…/rust/src/libcore/iter/iterator.rs:389:
undefined reference to `_Unwind_Resume'
...
```
So the linker can't find a function named `_Unwind_Resume` that is referenced e.g. in `iter/iterator.rs:389` in libcore. This reference is not really there at [line 389][iterator.rs:389] of libcore's `iterator.rs`. Instead, it is a compiler inserted _landing pad_, which is used for panic handling.
[iterator.rs:389]: https://github.com/rust-lang/rust/blob/c58c928e658d2e45f816fd05796a964aa83759da/src/libcore/iter/iterator.rs#L389
By default, the destructors of all stack variables are run when a `panic` occurs. This is called _unwinding_ and allows parent threads to recover from panics. However, it requires a platform specific gcc library, which isn't available in our kernel.
Fortunately, Rust allows us to disable unwinding for our target. For that we add the following line to our `x86_64-blog_os.json` file:
```json
{
"...",
"panic-strategy": "abort"
}
```
By setting the [panic strategy] to `abort` instead of the default `unwind`, we disable all unwinding in our kernel. Let's try `make run` again:
[panic strategy]: https://github.com/nox/rust-rfcs/blob/master/text/1513-less-unwinding.md
```
Compiling core v0.0.0 (file:///…/rust/src/libcore)
Finished release [optimized] target(s) in 22.24 secs
Finished dev [unoptimized + debuginfo] target(s) in 0.5 secs
target/x86_64-blog_os/debug/libblog_os.a(blog_os-b5a29f28b14f1f1f.0.o):
In function `core::ptr::drop_in_place<…>':
/…/src/libcore/ptr.rs:66:
undefined reference to `_Unwind_Resume'
...
```
We see that `xargo` recompiles the `core` crate, but the `_Unwind_Resume` error still occurs. This is because our `blog_os` crate was not recompiled somehow and thus still references the unwinding function. To fix this, we need to force a recompile using `cargo clean`:
```
> cargo clean
> make run
Compiling rlibc v1.0.0
Compiling blog_os v0.1.0 (file:///home/philipp/Documents/blog_os/tags)
warning: unused variable: `test` […]
Finished dev [unoptimized + debuginfo] target(s) in 0.60 secs
```
It worked! We no longer see linker errors and our kernel prints `OKAY` again.
## Hello World!
Finally, it's time for a `Hello World!` from Rust:
```rust
#[no_mangle]
pub extern fn rust_main() {
// ATTENTION: we have a very small stack and no guard page
let hello = b"Hello World!";
let color_byte = 0x1f; // white foreground, blue background
let mut hello_colored = [color_byte; 24];
for (i, char_byte) in hello.into_iter().enumerate() {
hello_colored[i*2] = *char_byte;
}
// write `Hello World!` to the center of the VGA text buffer
let buffer_ptr = (0xb8000 + 1988) as *mut _;
unsafe { *buffer_ptr = hello_colored };
loop{}
}
```
Some notes:
- The `b` prefix creates a [byte string], which is just an array of `u8`
- [enumerate] is an `Iterator` method that adds the current index `i` to elements
- `buffer_ptr` is a [raw pointer] that points to the center of the VGA text buffer
- Rust doesn't know the VGA buffer and thus can't guarantee that writing to the `buffer_ptr` is safe (it could point to important data). So we need to tell Rust that we know what we are doing by using an [unsafe block].
[byte string]: https://doc.rust-lang.org/reference/tokens.html#characters-and-strings
[enumerate]: https://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.enumerate
[unsafe block]: https://doc.rust-lang.org/book/unsafe.html
### Stack Overflows
Since we still use the small 64 byte [stack from the last post], we must be careful not to [overflow] it. Normally, Rust tries to avoid stack overflows through _guard pages_: The page below the stack isn't mapped and such a stack overflow triggers a page fault (instead of silently overwriting random memory). But we can't unmap the page below our stack right now since we currently use only a single big page. Fortunately the stack is located just above the page tables. So some important page table entry would probably get overwritten on stack overflow and then a page fault occurs, too.
[stack from the last post]: @/edition-1/posts/02-entering-longmode/index.md#creating-a-stack
[overflow]: https://en.wikipedia.org/wiki/Stack_overflow
## What's next?
Until now we write magic bits to some memory location when we want to print something to screen. In the [next post] we create a abstraction for the VGA text buffer that allows us to print strings in different colors and provides a simple interface.
[next post]: @/edition-1/posts/04-printing-to-screen/index.md

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
<svg width="17cm" height="11cm" viewBox="-60 -21 340 212" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<text font-size="9.03111" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="90" y="65.9389">
<tspan x="90" y="65.9389"></tspan>
</text>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="204" y1="70" x2="176.236" y2="70"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="185.118,65 175.118,70 185.118,75 "/>
</g>
<text font-size="7.90222" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="208" y="72.75">
<tspan x="208" y="72.75">Old Stack Pointer</tspan>
</text>
<text font-size="7.90222" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="75" y="230">
<tspan x="75" y="230"></tspan>
</text>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="-20" y1="70" x2="-4" y2="70"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="-20" y1="190" x2="-4" y2="190"/>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="-12" y1="72.2361" x2="-12" y2="187.764"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="-7,81.118 -12,71.118 -17,81.118 "/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="-17,178.882 -12,188.882 -7,178.882 "/>
</g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="0" y1="-20" x2="0" y2="0"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="170" y1="-20" x2="170" y2="0"/>
<g>
<rect style="fill: #00ff00" x="0" y="0" width="170" height="20"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="0" width="170" height="20"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="85" y="13.125">
<tspan x="85" y="13.125">Return Address</tspan>
</text>
<text font-size="9.03097" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="84" y="4">
<tspan x="84" y="4"></tspan>
</text>
<g>
<rect style="fill: #dddddd" x="0" y="20" width="170" height="20"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="20" width="170" height="20"/>
</g>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="85" y="33.125">
<tspan x="85" y="33.125">Local Variable 1</tspan>
</text>
<g>
<rect style="fill: #cccccc" x="0" y="40" width="170" height="32"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x="0" y="40" width="170" height="32"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="85" y="59.125">
<tspan x="85" y="59.125">Local Variables 2..n</tspan>
</text>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="0" y1="40" x2="170" y2="40"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="0" y1="72" x2="120" y2="72"/>
<g>
<rect style="fill: #ff3333" x="0" y="70" width="170" height="120"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="70" width="170" height="120"/>
</g>
<text font-size="9.03111" style="fill: #ffffff;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="40" y="179.125">
<tspan x="40" y="179.125">Red Zone</tspan>
</text>
<text font-size="7.9021" style="fill: #000000;text-anchor:end;font-family:sans-serif;font-style:normal;font-weight:normal" x="-20" y="132.75">
<tspan x="-20" y="132.75">128 bytes</tspan>
</text>
<g>
<rect style="fill: #ffc200" x="30" y="70" width="140" height="30"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="30" y="70" width="140" height="30"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="100" y="88.125">
<tspan x="100" y="88.125">Exception Stack Frame</tspan>
</text>
<g>
<rect style="fill: #ffe000" x="30" y="100" width="140" height="30"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="30" y="100" width="140" height="30"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="100" y="118.125">
<tspan x="100" y="118.125">Register Backup</tspan>
</text>
<g>
<rect style="fill: #c6db97" x="30" y="130" width="140" height="30"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="30" y="130" width="140" height="30"/>
</g>
<text font-size="8.46654" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="100" y="147.925">
<tspan x="100" y="147.925">Handler Function Stack Frame</tspan>
</text>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #ff3333" x1="30" y1="70" x2="30" y2="160"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #ff3333" x1="30" y1="160" x2="170" y2="160"/>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="204" y1="160" x2="176.236" y2="160"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="185.118,155 175.118,160 185.118,165 "/>
</g>
<text font-size="7.90222" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="208" y="162.635">
<tspan x="208" y="162.635">New Stack Pointer</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
<svg width="14cm" height="9cm" viewBox="-60 -21 270 172" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<text font-size="9.03111" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="90" y="65.9389">
<tspan x="90" y="65.9389"></tspan>
</text>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="154" y1="70" x2="126.236" y2="70"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="135.118,65 125.118,70 135.118,75 "/>
</g>
<text font-size="7.90222" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="158" y="72.75">
<tspan x="158" y="72.75">Stack Pointer</tspan>
</text>
<text font-size="7.90222" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="75" y="230">
<tspan x="75" y="230"></tspan>
</text>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="-20" y1="70" x2="-4" y2="70"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="-20" y1="150" x2="-4" y2="150"/>
<g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="-12" y1="72.2361" x2="-12" y2="147.764"/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="-7,81.118 -12,71.118 -17,81.118 "/>
<polyline style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" points="-17,138.882 -12,148.882 -7,138.882 "/>
</g>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="0" y1="-20" x2="0" y2="0"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x1="120" y1="-20" x2="120" y2="0"/>
<g>
<rect style="fill: #00ff00" x="0" y="0" width="120" height="20"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="0" width="120" height="20"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="60" y="13.125">
<tspan x="60" y="13.125">Return Address</tspan>
</text>
<text font-size="9.03097" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="84" y="4">
<tspan x="84" y="4"></tspan>
</text>
<g>
<rect style="fill: #dddddd" x="0" y="20" width="120" height="20"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="20" width="120" height="20"/>
</g>
<text font-size="9.03111" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="60" y="33.125">
<tspan x="60" y="33.125">Local Variable 1</tspan>
</text>
<g>
<rect style="fill: #cccccc" x="0" y="40" width="120" height="32"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke-dasharray: 4; stroke: #000000" x="0" y="40" width="120" height="32"/>
</g>
<text font-size="9.03097" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="60" y="59.125">
<tspan x="60" y="59.125">Local Variables 2..n</tspan>
</text>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="0" y1="40" x2="120" y2="40"/>
<line style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x1="0" y1="72" x2="120" y2="72"/>
<g>
<rect style="fill: #ff3333" x="0" y="70" width="120" height="80"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 1; stroke: #000000" x="0" y="70" width="120" height="80"/>
</g>
<text font-size="9.03111" style="fill: #ffffff;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="60" y="113.125">
<tspan x="60" y="113.125">Red Zone</tspan>
</text>
<text font-size="7.9021" style="fill: #000000;text-anchor:end;font-family:sans-serif;font-style:normal;font-weight:normal" x="-20" y="112.75">
<tspan x="-20" y="112.75">128 bytes</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -1,25 +1,27 @@
+++
title = "Printing to Screen"
date = "2015-10-23"
aliases = [
"/2015/10/23/printing-to-screen/",
"/rust-os/printing-to-screen.html",
]
weight = 4
path = "printing-to-screen"
aliases = ["printing-to-screen.html", "/2015/10/23/printing-to-screen/", "/rust-os/printing-to-screen.html"]
date = 2015-10-23
template = "edition-1/page.html"
[extra]
updated = "2016-10-31"
+++
In the [previous post] we switched from assembly to [Rust], a systems programming language that provides great safety. But so far we are using unsafe features like [raw pointers] whenever we want to print to screen. In this post we will create a Rust module that provides a safe and easy-to-use interface for the VGA text buffer. It will support Rust's [formatting macros], too.
[previous post]: {{% relref "2015-09-02-set-up-rust.md" %}}
[previous post]: @/edition-1/posts/03-set-up-rust/index.md
[Rust]: https://www.rust-lang.org/
[raw pointers]: https://doc.rust-lang.org/book/raw-pointers.html
[formatting macros]: https://doc.rust-lang.org/std/fmt/#related-macros
<!--more-->
<!-- more -->
This post uses recent unstable features, so you need an up-to-date nighly compiler. If you have any questions, problems, or suggestions please [file an issue] or create a comment at the bottom. The code from this post is also available on [Github][code repository].
This post uses recent unstable features, so you need an up-to-date nighly compiler. If you have any questions, problems, or suggestions please [file an issue] or create a comment at the bottom. The code from this post is also available on [GitHub][code repository].
[file an issue]: https://github.com/phil-opp/blog_os/issues
[code repository]: https://github.com/phil-opp/blog_os/tree/printing_to_screen
[code repository]: https://github.com/phil-opp/blog_os/tree/first_edition_post_4
## The VGA Text Buffer
The text buffer starts at physical address `0xb8000` and contains the characters displayed on screen. It has 25 rows and 80 columns. Each screen character has the following format:
@@ -87,13 +89,11 @@ pub enum Color {
```
We use a [C-like enum] here to explicitly specify the number for each color. Because of the `repr(u8)` attribute each enum variant is stored as an `u8`. Actually 4 bits would be sufficient, but Rust doesn't have an `u4` type.
[C-like enum]: http://rustbyexample.com/custom_types/enum/c_like.html
[C-like enum]: https://doc.rust-lang.org/rust-by-example/custom_types/enum/c_like.html
Normally the compiler would issue a warning for each unused variant. By using the `#[allow(dead_code)]` attribute we disable these warnings for the `Color` enum.
To represent a full color code that specifies foreground and background color, we create a [newtype] on top of `u8`:
[newtype]: https://aturon.github.io/features/types/newtype.html
To represent a full color code that specifies foreground and background color, we create a newtype on top of `u8`:
```rust
struct ColorCode(u8);
@@ -142,14 +142,14 @@ pub struct Writer {
```
The writer will always write to the last line and shift lines up when a line is full (or on `\n`). The `column_position` field keeps track of the current position in the last row. The current foreground and background colors are specified by `color_code` and a pointer to the VGA buffer is stored in `buffer`. To make it possible to create a `static` Writer later, the `buffer` field stores an `Unique<Buffer>` instead of a plain `*mut Buffer`. [Unique] is a wrapper that implements Send/Sync and is thus usable as a `static`. Since it's unstable, you may need to add the `unique` feature to `lib.rs`:
[Unique]: https://doc.rust-lang.org/nightly/core/ptr/struct.Unique.html
[Unique]: https://doc.rust-lang.org/1.10.0/core/ptr/struct.Unique.html
```rust
// in src/lib.rs
#![feature(unique)]
```
## Printing to Screen
## Printing Characters
Now we can use the `Writer` to modify the buffer's characters. First we create a method to write a single ASCII byte (it doesn't compile yet):
```rust
@@ -165,9 +165,10 @@ impl Writer {
let row = BUFFER_HEIGHT - 1;
let col = self.column_position;
let color_code = self.color_code;
self.buffer().chars[row][col] = ScreenChar {
ascii_character: byte,
color_code: self.color_code,
color_code: color_code,
};
self.column_position += 1;
}
@@ -175,7 +176,7 @@ impl Writer {
}
fn buffer(&mut self) -> &mut Buffer {
unsafe{ self.buffer.get_mut() }
unsafe{ self.buffer.as_mut() }
}
fn new_line(&mut self) {/* TODO */}
@@ -187,20 +188,56 @@ If the byte is the [newline] byte `\n`, the writer does not print anything. Inst
When printing a byte, the writer checks if the current line is full. In that case, a `new_line` call is required before to wrap the line. Then it writes a new `ScreenChar` to the buffer at the current position. Finally, the current column position is advanced.
The `buffer()` auxiliary method converts the raw pointer in the `buffer` field into a safe mutable buffer reference. The unsafe block is needed because the [get_mut()] method of `Unique` is unsafe. But our `buffer()` method itself isn't marked as unsafe, so it must not introduce any unsafety (e.g. cause segfaults). To guarantee that, it's very important that the `buffer` field always points to a valid `Buffer`. It's like a contract that we must stand to every time we create a `Writer`. To ensure that it's not possible to create an invalid `Writer` from outside of the module, the struct must have at least one private field and public creation functions are not allowed either.
[get_mut()]: https://doc.rust-lang.org/nightly/core/ptr/struct.Unique.html#method.get_mut
The `buffer()` auxiliary method converts the raw pointer in the `buffer` field into a safe mutable buffer reference. The unsafe block is needed because the [as_mut()] method of `Unique` is unsafe. But our `buffer()` method itself isn't marked as unsafe, so it must not introduce any unsafety (e.g. cause segfaults). To guarantee that, it's very important that the `buffer` field always points to a valid `Buffer`. It's like a contract that we must stand to every time we create a `Writer`. To ensure that it's not possible to create an invalid `Writer` from outside of the module, the struct must have at least one private field and public creation functions are not allowed either.
[as_mut()]: https://doc.rust-lang.org/1.26.0/core/ptr/struct.Unique.html#method.as_mut
### Cannot Move out of Borrowed Content
When we try to compile it, we get the following error:
```
error: cannot move out of borrowed content [E0507]
color_code: self.color_code,
^~~~
error[E0507]: cannot move out of borrowed content
--> src/vga_buffer.rs:79:34
|
79 | let color_code = self.color_code;
| ^^^^ cannot move out of borrowed content
```
The reason it that Rust _moves_ values by default instead of copying them like other languages. And we cannot move `color_code` out of `self` because we only borrowed `self`. For more information check out the [ownership section] in the Rust book. To fix it, we can implement the [Copy trait] for the `ColorCode` type by adding `#[derive(Clone, Copy)]` to its struct.
The reason it that Rust _moves_ values by default instead of copying them like other languages. And we cannot move `color_code` out of `self` because we only borrowed `self`. For more information check out the [ownership section] in the Rust book.
[ownership section]: https://doc.rust-lang.org/book/ownership.html
[Copy trait]: https://doc.rust-lang.org/nightly/core/marker/trait.Copy.html
[by reference]: https://rust-lang.github.io/book/ch04-02-references-and-borrowing.html
To fix it, we can implement the [Copy] trait for the `ColorCode` type. The easiest way to do this is to use the built-in [derive macro]:
[Copy]: https://doc.rust-lang.org/nightly/core/marker/trait.Copy.html
[derive macro]: https://doc.rust-lang.org/rust-by-example/custom_types/enum/c_like.html
```rust
#[derive(Debug, Clone, Copy)]
struct ColorCode(u8);
```
We also derive the [Clone] trait, since it's a requirement for `Copy`, and the [Debug] trait, which allows us to print this field for debugging purposes.
[Clone]: https://doc.rust-lang.org/nightly/core/clone/trait.Clone.html
[Debug]: https://doc.rust-lang.org/nightly/core/fmt/trait.Debug.html
Now our project should compile again.
However, the [documentation for Copy] says: _“if your type can implement Copy, it should”_. Therefore we also derive Copy for `Color` and `ScreenChar`:
[documentation for Copy]: https://doc.rust-lang.org/core/marker/trait.Copy.html#when-should-my-type-be-copy
```rust
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum Color {...}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct ScreenChar {...}
```
### Try it out!
To write some characters to the screen, you can create a temporary function:
@@ -210,17 +247,97 @@ pub fn print_something() {
let mut writer = Writer {
column_position: 0,
color_code: ColorCode::new(Color::LightGreen, Color::Black),
buffer: unsafe { Unique::new(0xb8000 as *mut _) },
buffer: unsafe { Unique::new_unchecked(0xb8000 as *mut _) },
};
writer.write_byte(b'H');
}
```
It just creates a new Writer that points to the VGA buffer at `0xb8000`. Then it writes the byte `b'H'` to it. The `b` prefix creates a [byte character], which represents an ASCII code point. When we call `vga_buffer::print_something` in main, a `H` should be printed in the _lower_ left corner of the screen in light green.
It just creates a new Writer that points to the VGA buffer at `0xb8000`. To use the unstable `Unique::new_unchecked` function, we need to add the feature flag `#![feature(const_unique_new)]` to the top of our `src/lib.rs`.
[byte character]: https://doc.rust-lang.org/reference.html#characters-and-strings
Then it writes the byte `b'H'` to it. The `b` prefix creates a [byte character], which represents an ASCII code point. When we call `vga_buffer::print_something` in main, a `H` should be printed in the _lower_ left corner of the screen in light green:
### Printing Strings
[byte character]: https://doc.rust-lang.org/reference/tokens.html#characters-and-strings
![QEMU output with a green `H` in the lower left corner](vga-H-lower-left.png)
### Volatile
We just saw that our `H` was printed correctly. However, it might not work with future Rust compilers that optimize more aggressively.
The problem is that we only write to the `Buffer` and never read from it again. The compiler doesn't know about the side effect that some characters appear on the screen. So it might decide that these writes are unnecessary and can be omitted.
To avoid this erroneous optimization, we need to specify these writes as _[volatile]_. This tells the compiler that the write has side effects and should not be optimized away.
[volatile]: https://en.wikipedia.org/wiki/Volatile_(computer_programming)
In order to use volatile writes for the VGA buffer, we use the [volatile][volatile crate] library. This _crate_ (this is how packages are called in the Rust world) provides a `Volatile` wrapper type with `read` and `write` methods. These methods internally use the [read_volatile] and [write_volatile] functions of the standard library and thus guarantee that the reads/writes are not optimized away.
[volatile crate]: https://docs.rs/volatile
[read_volatile]: https://doc.rust-lang.org/nightly/core/ptr/fn.read_volatile.html
[write_volatile]: https://doc.rust-lang.org/nightly/core/ptr/fn.write_volatile.html
We can add a dependency on the `volatile` crate by adding it to the `dependencies` section of our `Cargo.toml`:
```toml
# in Cargo.toml
[dependencies]
volatile = "0.1.0"
```
The `0.1.0` is the [semantic] version number. For more information, see the [Specifying Dependencies] guide of the cargo documentation.
[semantic]: https://semver.org/
[Specifying Dependencies]: https://doc.crates.io/specifying-dependencies.html
Now we've declared that our project depends on the `volatile` crate and are able to import it in `src/lib.rs`:
```rust
// in src/lib.rs
extern crate volatile;
```
Let's use it to make writes to the VGA buffer volatile. We update our `Buffer` type as follows:
```rust
// in src/vga_buffer.rs
use volatile::Volatile;
struct Buffer {
chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
```
Instead of a `ScreenChar`, we're now using a `Volatile<ScreenChar>`. (The `Volatile` type is [generic] and can wrap (almost) any type). This ensures that we can't accidentally write to it through a “normal” write. Instead, we have to use the `write` method now.
[generic]: https://doc.rust-lang.org/book/second-edition/ch10-00-generics.html
This means that we have to update our `Writer::write_byte` method:
```rust
impl Writer {
pub fn write_byte(&mut self, byte: u8) {
match byte {
b'\n' => self.new_line(),
byte => {
...
self.buffer().chars[row][col].write(ScreenChar {
ascii_character: byte,
color_code: color_code,
});
...
}
}
}
...
}
```
Instead of a normal assignment using `=`, we're now using the `write` method. This guarantees that the compiler will never optimize away this write.
## Printing Strings
To print whole strings, we can convert them to bytes and print them one-by-one:
@@ -237,14 +354,16 @@ You can try it yourself in the `print_something` function.
When you print strings with some special characters like `ä` or `λ`, you'll notice that they cause weird symbols on screen. That's because they are represented by multiple bytes in [UTF-8]. By converting them to bytes, we of course get strange results. But since the VGA buffer doesn't support UTF-8, it's not possible to display these characters anyway.
[core tracking issue]: https://github.com/rust-lang/rust/issues/27701
[UTF-8]: http://www.fileformat.info/info/unicode/utf8.htm
[UTF-8]: https://www.fileformat.info/info/unicode/utf8.htm
### Support Formatting Macros
It would be nice to support Rust's formatting macros, too. That way, we can easily print different types like integers or floats. To support them, we need to implement the [core::fmt::Write] trait. The only required method of this trait is `write_str` that looks quite similar to our `write_str` method. To implement the trait, we just need to move it into an `impl ::core::fmt::Write for Writer` block and add a return type:
It would be nice to support Rust's formatting macros, too. That way, we can easily print different types like integers or floats. To support them, we need to implement the [core::fmt::Write] trait. The only required method of this trait is `write_str` that looks quite similar to our `write_str` method. To implement the trait, we just need to move it into an `impl fmt::Write for Writer` block and add a return type:
```rust
impl ::core::fmt::Write for Writer {
fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
use core::fmt;
impl fmt::Write for Writer {
fn write_str(&mut self, s: &str) -> fmt::Result {
for byte in s.bytes() {
self.write_byte(byte)
}
@@ -264,7 +383,8 @@ writer.write_byte(b'H');
writer.write_str("ello! ");
write!(writer, "The numbers are {} and {}", 42, 1.0/3.0);
```
Now you should see a `Hello! The numbers are 42 and 0.3333333333333333` in strange colors at the bottom of the screen.
Now you should see a `Hello! The numbers are 42 and 0.3333333333333333` at the bottom of the screen.
[core::fmt::Write]: https://doc.rust-lang.org/nightly/core/fmt/trait.Write.html
@@ -275,9 +395,12 @@ Right now, we just ignore newlines and characters that don't fit into the line a
// in `impl Writer`
fn new_line(&mut self) {
for row in 0..(BUFFER_HEIGHT-1) {
let buffer = self.buffer();
buffer.chars[row] = buffer.chars[row + 1]
for row in 1..BUFFER_HEIGHT {
for col in 0..BUFFER_WIDTH {
let buffer = self.buffer();
let character = buffer.chars[row][col].read();
buffer.chars[row - 1][col].write(character);
}
}
self.clear_row(BUFFER_HEIGHT-1);
self.column_position = 0;
@@ -285,14 +408,7 @@ fn new_line(&mut self) {
fn clear_row(&mut self, row: usize) {/* TODO */}
```
We just move each line to the line above. Notice that the range notation (`..`) is exclusive the upper bound. But when we try to compile it, we get an borrow checker error again:
```
error: cannot move out of indexed content [E0507]
buffer.chars[row] = buffer.chars[row + 1]
^~~~~~~~~~~~~~~~~~~~~
```
It's because of Rust's move semantics again: We try to move out the `ScreenChar` at `row+1`. If Rust would allow that, the array would become invalid as it would contain some valid and some moved out values. Fortunately, the `ScreenChar` type meets all criteria for the [Copy trait], so we can fix the problem by adding `#[derive(Clone, Copy)]` to `ScreenChar`.
We iterate over all screen characters and move each characters one row up. Note that the range notation (`..`) is exclusive the upper bound. We also omit the 0th row (the first range starts at `1`) because it's the row that is shifted off screen.
Now we only need to implement the `clear_row` method to finish the newline code:
@@ -303,9 +419,12 @@ fn clear_row(&mut self, row: usize) {
ascii_character: b' ',
color_code: self.color_code,
};
self.buffer().chars[row] = [blank; BUFFER_WIDTH];
for col in 0..BUFFER_WIDTH {
self.buffer().chars[row][col].write(blank);
}
}
```
This method clears a row by overwriting all of its characters with a space character.
## Providing an Interface
To provide a global writer that can used as an interface from other modules, we can add a `static` writer:
@@ -314,7 +433,7 @@ To provide a global writer that can used as an interface from other modules, we
pub static WRITER: Writer = Writer {
column_position: 0,
color_code: ColorCode::new(Color::LightGreen, Color::Black),
buffer: unsafe { Unique::new(0xb8000 as *mut _) },
buffer: unsafe { Unique::new_unchecked(0xb8000 as *mut _) },
};
```
@@ -322,14 +441,14 @@ But we can't use it to print anything! You can try it yourself in the `print_som
To resolve it, we could use a [mutable static]. But then every read and write to it would be unsafe since it could easily introduce data races and other bad things. Using `static mut` is highly discouraged, there are even proposals to [remove it][remove static mut].
[mutable static]: https://doc.rust-lang.org/book/const-and-static.html#mutability
[mutable static]: https://doc.rust-lang.org/1.30.0/book/second-edition/ch19-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable
[remove static mut]: https://internals.rust-lang.org/t/pre-rfc-remove-static-mut/1437
But what are the alternatives? We could try to use a cell type like [RefCell] or even [UnsafeCell] to provide [interior mutability]. But these types aren't [Sync] \(with good reason), so we can't use them in statics.
[RefCell]: https://doc.rust-lang.org/nightly/core/cell/struct.RefCell.html
[UnsafeCell]: https://doc.rust-lang.org/nightly/core/cell/struct.UnsafeCell.html
[interior mutability]: https://doc.rust-lang.org/book/mutability.html#interior-vs.-exterior-mutability
[interior mutability]: https://doc.rust-lang.org/1.30.0/book/first-edition/mutability.html#interior-vs-exterior-mutability
[Sync]: https://doc.rust-lang.org/nightly/core/marker/trait.Sync.html
To get synchronized interior mutability, users of the standard library can use [Mutex]. It provides mutual exclusion by blocking threads when the resource is already locked. But our basic kernel does not have any blocking support or even a concept of threads, so we can't use it either. However there is a really basic kind of mutex in computer science that requires no operating system features: the [spinlock]. Instead of blocking, the threads simply try to lock it again and again in a tight loop and thus burn CPU time until the mutex is free again.
@@ -345,7 +464,7 @@ To use a spinning mutex, we can add the [spin crate] as a dependency:
# in Cargo.toml
[dependencies]
rlibc = "0.1.4"
spin = "0.3.4"
spin = "0.4.5"
```
```rust
@@ -362,14 +481,14 @@ use spin::Mutex;
pub static WRITER: Mutex<Writer> = Mutex::new(Writer {
column_position: 0,
color_code: ColorCode::new(Color::LightGreen, Color::Black),
buffer: unsafe { Unique::new(0xb8000 as *mut _) },
buffer: unsafe { Unique::new_unchecked(0xb8000 as *mut _) },
});
```
[Mutex::new] is a const function, too, so it can be used in statics.
Now we can easily print from our main function:
[Mutex::new]: https://mvdnes.github.io/rust-docs/spinlock-rs/spin/struct.Mutex.html#method.new
[Mutex::new]: https://docs.rs/spin/0.4.5/spin/struct.Mutex.html#method.new
```rust
// in src/lib.rs
@@ -385,7 +504,7 @@ Note that we need to import the `Write` trait if we want to use its functions.
## A println macro
Rust's [macro syntax] is a bit strange, so we won't try to write a macro from scratch. Instead we look at the source of the [`println!` macro] in the standard library:
[macro syntax]: https://doc.rust-lang.org/nightly/book/macros.html
[macro syntax]: https://doc.rust-lang.org/nightly/book/second-edition/appendix-04-macros.html
[`println!` macro]: https://doc.rust-lang.org/nightly/std/macro.println!.html
```rust
@@ -394,7 +513,9 @@ macro_rules! println {
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
```
It just adds a `\n` and then invokes the [`print!` macro], which is defined as:
Macros are defined through one or more rules, which are similar to `match` arms. The `println` macro has two rules: The first rule is for invocations with a single argument (e.g. `println!("Hello")`) and the second rule is for invocations with additional parameters (e.g. `println!("{}{}", 4, 2)`).
Both rules simply append a newline character (`\n`) to the format string and then invoke the [`print!` macro], which is defined as:
[`print!` macro]: https://doc.rust-lang.org/nightly/std/macro.print!.html
@@ -403,9 +524,14 @@ macro_rules! print {
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
}
```
It calls the `_print` method in the `io` module of the current crate (`$crate`), which is `std`. The [`_print` function] in libstd is rather complicated, as it supports different `Stdout` devices.
The macro expands to a call of the [`_print` function] in the `io` module. The [`$crate` variable] ensures that the macro also works from outside the `std` crate. For example, it expands to `::std` when it's used in other crates.
[`_print` function]: https://doc.rust-lang.org/nightly/src/std/io/stdio.rs.html#578
The [`format_args` macro] builds a [fmt::Arguments] type from the passed arguments, which is passed to `_print`. The [`_print` function] of libstd is rather complicated, as it supports different `Stdout` devices. We don't need that complexity since we just want to print to the VGA buffer.
[`_print` function]: https://github.com/rust-lang/rust/blob/46d39f3329487115e7d7dcd37bc64eea6ef9ba4e/src/libstd/io/stdio.rs#L631
[`$crate` variable]: https://doc.rust-lang.org/1.30.0/book/first-edition/macros.html#the-variable-crate
[`format_args` macro]: https://doc.rust-lang.org/nightly/std/macro.format_args.html
[fmt::Arguments]: https://doc.rust-lang.org/nightly/core/fmt/struct.Arguments.html
To print to the VGA buffer, we just copy the `println!` macro and modify the `print!` macro to use our static `WRITER` instead of `_print`:
@@ -413,15 +539,15 @@ To print to the VGA buffer, we just copy the `println!` macro and modify the `pr
// in src/vga_buffer.rs
macro_rules! print {
($($arg:tt)*) => ({
use core::fmt::Write;
let mut writer = $crate::vga_buffer::WRITER.lock();
writer.write_fmt(format_args!($($arg)*)).unwrap();
use core::fmt::Write;
let mut writer = $crate::vga_buffer::WRITER.lock();
writer.write_fmt(format_args!($($arg)*)).unwrap();
});
}
```
Instead of a `_print` function, we call the `write_fmt` method of our static `Writer`. Since we're using a method from the `Write` trait, we need to import it before. The additional `unwrap()` at the end panics if printing isn't successful. But since we always return `Ok` in `write_str`, that should not happen.
Note the additional `{}` scope around the macro: I wrote `=> ({…})` instead of `=> (…)`. The additional `{}` avoids that the `Write` trait is silently imported when `print` is used.
Note the additional `{}` scope around the macro: We write `=> ({…})` instead of `=> (…)`. The additional `{}` avoids that the `Write` trait is silently imported to the parent scope when `print` is used.
### Clearing the screen
We can now use `println!` to add a rather trivial function to clear the screen:
@@ -452,31 +578,91 @@ pub extern fn rust_main() {
loop{}
}
```
Since we imported the macros at crate level, they are available in all modules and thus provide an easy and safe interface to the VGA buffer.
As expected, we now see a _“Hello World!”_ on a cleared screen:
![QEMU printing “Hello World!” on a cleared screen](vga-hello-world.png)
### Deadlocks
Whenever we use locks, we must be careful to not accidentally introduce _deadlocks_. A [deadlock] occurs when a thread/program waits for a lock that will never be released. Normally, this happens when multiple threads access multiple locks. For example, when thread A holds lock 1 and tries to acquire lock 2 and -- at the same time -- thread B holds lock 2 and tries to acquire lock 1.
[deadlock]: https://en.wikipedia.org/wiki/Deadlock
However, a deadlock can also occur when a thread tries to acquire the same lock twice. This way we can trigger a deadlock in our VGA driver:
```rust
// in rust_main in src/lib.rs
println!("{}", { println!("inner"); "outer" });
```
The argument passed to `println` is new block that resolves to the string _“outer”_ (a block always returns the result of the last expression). But before returning “outer”, the block tries to print the string _“inner”_.
When we try this code in QEMU, we see that neither of the strings are printed. To understand what's happening, we take a look at our `print` macro again:
```rust
macro_rules! print {
($($arg:tt)*) => ({
use core::fmt::Write;
let mut writer = $crate::vga_buffer::WRITER.lock();
writer.write_fmt(format_args!($($arg)*)).unwrap();
});
}
```
So we _first_ lock the `WRITER` and then we evaluate the arguments using `format_args`. The problem is that the argument in our code example contains another `println`, which tries to lock the `WRITER` again. So now the inner `println` waits for the outer `println` and vice versa. Thus, a deadlock occurs and the CPU spins endlessly.
### Fixing the Deadlock
In order to fix the deadlock, we need to evaluate the arguments _before_ locking the `WRITER`. We can do so by moving the locking and printing logic into a new `print` function (like it's done in the standard library):
```rust
// in src/vga_buffer.rs
macro_rules! print {
($($arg:tt)*) => ({
$crate::vga_buffer::print(format_args!($($arg)*));
});
}
pub fn print(args: fmt::Arguments) {
use core::fmt::Write;
WRITER.lock().write_fmt(args).unwrap();
}
```
Now the macro only evaluates the arguments (through `format_args!`) and passes them to the new `print` function. The `print` function then locks the `WRITER` and prints the formatting arguments using `write_fmt`. So now the arguments are evaluated before locking the `WRITER`.
Thus, we fixed the deadlock:
![QEMU printing “inner” and then “outer”](fixed-println-deadlock.png)
We see that both “inner” and “outer” are printed.
## What's next?
In the next posts we will map the kernel pages correctly so that accessing `0x0` or writing to `.rodata` is not possible anymore. To obtain the loaded kernel sections we will read the Multiboot information structure. Then we will create a paging module and use it to switch to a new page table where the kernel sections are mapped correctly.
The [next post] describes the Multiboot information structure and creates a frame allocator using the information about memory areas.
[next post]: {{% relref "2015-11-15-allocating-frames.md" %}}
[next post]: @/edition-1/posts/05-allocating-frames/index.md
## Other Rust OS Projects
Now that you know the very basics of OS development in Rust, you should also check out the following projects:
- [Rust Bare-Bones Kernel]: A basic kernel with roughly the same functionality as ours. Writes output to the serial port instead of the VGA buffer and maps the kernel to the [higher half] \(instead of our identity mapping).
_Note_: You need to [cross compile binutils] to build it (or you create some symbolic links[^fn-symlink] if you're on x86_64).
[Rust Bare-Bones Kernel]: https://github.com/thepowersgang/rust-barebones-kernel
[higher half]: http://wiki.osdev.org/Higher_Half_Kernel
[cross compile binutils]: {{% relref "cross-compile-binutils.md" %}}
[^fn-symlink]: You will need to symlink `x86_64-none_elf-XXX` to `/usr/bin/XXX` where `XXX` is in {`as`, `ld`, `objcopy`, `objdump`, `strip`}. The `x86_64-none_elf-XXX` files must be in some folder that is in your `$PATH`. But then you can only build for your x86_64 host architecture, so use this hack only for testing.
- [RustOS]: More advanced kernel that supports allocation, keyboard inputs, and threads. It also has a scheduler and a basic network driver.
[RustOS]: https://github.com/RustOS-Fork-Holding-Ground/RustOS
- ["Tifflin" Experimental Kernel]: Big kernel project by thepowersgang, that is actively developed and has over 650 commits. It has a separate userspace and supports multiple file systems, even a GUI is included. Needs a cross compiler.
["Tifflin" Experimental Kernel]:https://github.com/thepowersgang/rust_os
- [Redox]: Probably the most complete Rust OS today. It has an active community and over 1000 Github stars. File systems, network, an audio player, a picture viewer, and much more. Just take a look at the [screenshots][redox screenshots].
[Rust Bare-Bones Kernel]: https://github.com/thepowersgang/rust-barebones-kernel
[higher half]: https://wiki.osdev.org/Higher_Half_Kernel
[cross compile binutils]: @/edition-1/extra/cross-compile-binutils.md
[RustOS]: https://github.com/RustOS-Fork-Holding-Ground/RustOS
["Tifflin" Experimental Kernel]:https://github.com/thepowersgang/rust_os
[Redox]: https://github.com/redox-os/redox
[redox screenshots]: https://github.com/redox-os/redox#what-it-looks-like
## Footnotes
[^fn-symlink]: You will need to symlink `x86_64-none_elf-XXX` to `/usr/bin/XXX` where `XXX` is in {`as`, `ld`, `objcopy`, `objdump`, `strip`}. The `x86_64-none_elf-XXX` files must be in some folder that is in your `$PATH`. But then you can only build for your x86_64 host architecture, so use this hack only for testing.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -1,24 +1,28 @@
+++
title = "Allocating Frames"
date = "2015-11-15"
weight = 5
path = "allocating-frames"
aliases = ["allocating-frames.html"]
date = 2015-11-15
template = "edition-1/page.html"
+++
In this post we create an allocator that provides free physical frames for a future paging module. To get the required information about available and used memory we use the Multiboot information structure. Additionally, we improve the `panic` handler to print the corresponding message and source line.
<!--more-->
<!-- more -->
The full source code is available on [Github][source repo]. Feel free to open issues there if you have any problems or improvements. You can also leave a comment at the bottom.
The full source code is available on [GitHub][source repo]. Feel free to open issues there if you have any problems or improvements. You can also leave a comment at the bottom.
[source repo]: https://github.com/phil-opp/blog_os/tree/allocating_frames
[source repo]: https://github.com/phil-opp/blog_os/tree/first_edition_post_5
## Preparation
We still have a really tiny stack of 64 bytes, which won't suffice for this post. So we increase it to 4096 bytes (one page) in `boot.asm`:
We still have a really tiny stack of 64 bytes, which won't suffice for this post. So we increase it to 16kB (four pages) in `boot.asm`:
```asm
section .bss
...
stack_bottom:
resb 4096
resb 4096 * 4
stack_top:
```
@@ -44,17 +48,17 @@ Now we can add the argument to our `rust_main`:
pub extern fn rust_main(multiboot_information_address: usize) { ... }
```
Instead of writing an own Multiboot module, we use the [multiboot2-elf64] crate. It gives us some basic information about mapped kernel sections and available memory. I just wrote it for this blog post since I could not find any other Multiboot 2 crate. It's really ugly and incomplete, but it does its job[^fn-multiboot-crate].
Instead of writing an own Multiboot module, we use the [multiboot2] crate. It gives us some basic information about mapped kernel sections and available memory. I just wrote it for this blog post since I could not find any other Multiboot 2 crate. It's still incomplete, but it does its job.
[multiboot2-elf64]: https://github.com/phil-opp/multiboot2-elf64
[^fn-multiboot-crate]: All contributions are welcome! If you want to maintain it, please contact me!
[multiboot2]: https://docs.rs/multiboot2
So let's add a dependency on the git repository:
```toml
# in Cargo.toml
[dependencies.multiboot2]
git = "https://github.com/phil-opp/multiboot2-elf64"
[dependencies]
...
multiboot2 = "0.1.0"
```
```rust
@@ -67,7 +71,7 @@ Now we can use it to print available memory areas.
### Available Memory
The boot information structure consists of various _tags_. See section 3.4 of the Multiboot specification ([PDF][multiboot specification]) for a complete list. The _memory map_ tag contains a list of all available RAM areas. Special areas such as the VGA text buffer at `0xb8000` are not available. Note that some of the available memory is already used by our kernel and by the multiboot information structure itself.
[multiboot specification]: http://nongnu.askapache.com/grub/phcoder/multiboot.pdf
[multiboot specification]: https://nongnu.askapache.com/grub/phcoder/multiboot.pdf
To print all available memory areas, we can use the `multiboot2` crate in our `rust_main` as follows:
@@ -96,14 +100,15 @@ So we have one area from `0x0` to `0x9fc00`, which is a bit below the 1MiB mark.
If you give QEMU more than 4GiB of memory by passing `-m 5G`, you get another unusable area below the 4GiB mark. This memory is normally mapped to some hardware devices. See the [OSDev Wiki][Memory_map] for more information.
[Memory_map]: http://wiki.osdev.org/Memory_Map_(x86)
[Memory_map]: https://wiki.osdev.org/Memory_Map_(x86)
### Handling Panics
We used `expect` in the code above, which will panic if there is no memory map tag. But our current panic handler just loops without printing any error message. Of course we could replace `expect` by a `match`, but we should fix the panic handler nonetheless:
```rust
#[lang = "panic_fmt"]
extern fn panic_fmt() -> ! {
#[no_mangle]
pub extern fn panic_fmt() -> ! {
println!("PANIC");
loop{}
}
@@ -112,7 +117,10 @@ Now we get a `PANIC` message. But we can do even better. The `panic_fmt` functio
```rust
#[lang = "panic_fmt"]
extern fn panic_fmt(fmt: core::fmt::Arguments, file: &str, line: u32) -> ! {
#[no_mangle]
pub extern fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str,
line: u32) -> !
{
println!("\n\nPANIC in {} at line {}:", file, line);
println!(" {}", fmt);
loop{}
@@ -142,6 +150,8 @@ But when we execute it, tons of really small sections are printed. We can use th
To merge these subsections, we need to update our linker script:
```
ENTRY(start)
SECTIONS {
. = 1M;
@@ -169,7 +179,7 @@ These lines are taken from the default linker script of `ld`, which can be obtai
Now there are only 12 sections left and we get a much more useful output:
![qemu output](/images/qemu-memory-areas-and-kernel-sections.png)
![qemu output](qemu-memory-areas-and-kernel-sections.png)
If you like, you can compare this output to the `objdump -h build/kernel-x86_64.bin` output. You will see that the start addresses and sizes match exactly for each section. The sections with flags `0x0` are mostly debug sections, so they don't need to be loaded. And the last few sections of the QEMU output aren't in the `objdump` output because they are special sections such as string tables.
@@ -206,7 +216,8 @@ There are various ways to write such a frame allocator:
We could create some kind of linked list from the free frames. For example, each frame could begin with a pointer to the next free frame. Since the frames are free, this would not overwrite any data. Our allocator would just save the head of the list and could easily allocate and deallocate frames by updating pointers. Unfortunately, this approach has a problem: It requires reading and writing these free frames. So we would need to map all physical frames to some virtual address, at least temporary. Another disadvantage is that we need to create this linked list at startup. That implies that we need to set over one million pointers at startup if the machine has 4GiB of RAM.
Another approach is to create some kind of data structure such as a [bitmap or a stack] to manage free frames. We could place it in the already identity mapped area right behind the kernel or multiboot structure. That way we would not need to (temporary) map each free frame. But it has the same problem of the slow initial creating/filling. In fact, we will use this approach in a future post to manage frames that are freed again. But for the initial management of free frames, we use a different method.
[bitmap or a stack]: http://wiki.osdev.org/Page_Frame_Allocation#Physical_Memory_Allocators
[bitmap or a stack]: https://wiki.osdev.org/Page_Frame_Allocation#Physical_Memory_Allocators
In the following, we will use Multiboot's memory map directly. The idea is to maintain a simple counter that starts at frame 0 and is increased constantly. If the current frame is available (part of an available area in the memory map) and not used by the kernel or the multiboot structure (we know their start and end addresses), we know that it's free and return it. Else, we increase the counter to the next possibly free frame. That way, we don't need to create a data structure when booting and the physical frames can remain unmapped. The only problem is that we cannot reasonably free frames again, but we will solve that problem in a future post (by adding an intermediate frame stack that saves freed frames).
@@ -225,9 +236,6 @@ pub struct Frame {
```
(Don't forget to add the `mod memory` line to `src/lib.rs`.) Instead of e.g. the start address, we just store the frame number. We use `usize` here since the number of frames depends on the memory size. The long `derive` line makes frames printable and comparable.
_Update_: In a previous version, the `Clone` and `Copy` traits were derived, too. [This was removed][PR 52] to make the allocator interface safer.
[PR 52]: https://github.com/phil-opp/blog_os/pull/52
To make it easy to get the corresponding frame for a physical address, we add a `containing_address` method:
```rust
@@ -386,7 +394,7 @@ Note that we call `choose_next_area` manually here because `allocate_frame` retu
### Testing it
In order to test it in main, we need to [re-export] the `AreaFrameAllocator` in the `memory` module. Then we can create a new allocator:
[re-export]: https://doc.rust-lang.org/book/crates-and-modules.html#re-exporting-with-pub-use
[re-export]: https://doc.rust-lang.org/1.30.0/book/first-edition/crates-and-modules.html#re-exporting-with-pub-use
```rust
let mut frame_allocator = memory::AreaFrameAllocator::new(
@@ -413,7 +421,7 @@ for i in 0.. {
```
You can try different amounts of memory by passing e.g. `-m 500M` to QEMU. To compare these numbers, [WolframAlpha] can be very helpful.
[WolframAlpha]: http://www.wolframalpha.com/input/?i=%2832605+*+4096%29+bytes+in+MiB
[WolframAlpha]: https://www.wolframalpha.com/input/?i=%2832605+*+4096%29+bytes+in+MiB
## Conclusion
@@ -422,10 +430,10 @@ Now we have a working frame allocator. It is a bit rudimentary and cannot free f
## What's next?
The [next post] will be about paging again. We will use the frame allocator to create a safe module that allows us to switch page tables and map pages. Then we will use this module and the information from the Elf-sections tag to remap the kernel correctly.
[next post]: {{% relref "2015-12-09-modifying-page-tables.md" %}}
[next post]: @/edition-1/posts/06-page-tables/index.md
## Recommended Posts
Eric Kidd started the [Bare Metal Rust] series last week. Like this post, it builds upon the code from [Printing to Screen], but tries to support keyboard input instead of wrestling through memory management details.
[Bare Metal Rust]: http://www.randomhacks.net/bare-metal-rust/
[Printing to Screen]: {{% relref "2015-10-23-printing-to-screen.md" %}}
[Printing to Screen]: @/edition-1/posts/04-printing-to-screen/index.md

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,929 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="7.2973523in"
height="4.1279249in"
viewBox="-2141 2141 8777.1352 4929.2808"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="X86_Paging_64bit.svg">
<metadata
id="metadata370">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs368" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1080"
inkscape:window-height="1868"
id="namedview366"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4404005"
inkscape:cx="383.13253"
inkscape:cy="73.778068"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g4" />
<g
style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="g4"
transform="translate(-2845,-286.64442)">
<rect
x="8503"
y="4015"
width="708"
height="3307"
rx="0"
style="fill:#dfdfdf"
id="rect8" />
<polyline
points="3365,2598 3365,3070"
id="polyline10" />
<polyline
points="3189,2598 3189,3070"
id="polyline12" />
<polyline
points="3012,2598 3012,3070"
id="polyline14" />
<polyline
points="2834,2598 2834,3070"
id="polyline16" />
<polyline
points="2657,2598 2657,3070"
id="polyline18" />
<polyline
points="2480,2598 2480,3070"
id="polyline20" />
<polyline
points="2303,2598 2303,3070"
id="polyline22" />
<polyline
points="2125,2456 2125,3070"
id="polyline24" />
<polyline
points="1948,2598 1948,3070"
id="polyline26" />
<polyline
points="1772,2598 1772,3070"
id="polyline28" />
<polyline
points="1594,2598 1594,3070"
id="polyline30" />
<polyline
points="1417,2598 1417,3070"
id="polyline32" />
<polyline
points="1239,2598 1239,3070"
id="polyline34" />
<polyline
points="1063,2598 1063,3070"
id="polyline36" />
<polyline
points="886,2598 886,3070"
id="polyline38" />
<polyline
points="708,2456 708,3070"
id="polyline40" />
<polyline
points="3543,2456 3543,3070"
id="polyline74" />
<polyline
points="-2125,2598 3543,2598"
id="polyline76"
transform="matrix(0.49978943,0,0,1,1772.2461,0)" />
<polyline
points="3543,3070 -1948,3070 -2125,3070"
id="polyline78"
transform="matrix(0.49786923,0,0,1,1779.0493,0)" />
<polyline
points="9035,2598 9035,3070"
id="polyline80" />
<polyline
points="8858,2598 8858,3070"
id="polyline82" />
<polyline
points="8681,2598 8681,3070"
id="polyline84" />
<polyline
points="8503,2598 8503,3070"
id="polyline86" />
<polyline
points="8326,2598 8326,3070"
id="polyline88" />
<polyline
points="8150,2598 8150,3070"
id="polyline90" />
<polyline
points="7972,2598 7972,3070"
id="polyline92" />
<polyline
points="7795,2456 7795,3070"
id="polyline94" />
<polyline
points="7617,2598 7617,3070"
id="polyline96" />
<polyline
points="7441,2598 7441,3070"
id="polyline98" />
<polyline
points="7264,2598 7264,3070"
id="polyline100" />
<polyline
points="7086,2598 7086,3070"
id="polyline102" />
<polyline
points="6909,2598 6909,3070"
id="polyline104" />
<polyline
points="6732,2598 6732,3070"
id="polyline106" />
<polyline
points="6555,2598 6555,3070"
id="polyline108" />
<polyline
points="6377,2456 6377,3070"
id="polyline110" />
<polyline
points="6200,2598 6200,3070"
id="polyline112" />
<polyline
points="6024,2598 6024,3070"
id="polyline114" />
<polyline
points="5846,2598 5846,3070"
id="polyline116" />
<polyline
points="5669,2598 5669,3070"
id="polyline118" />
<polyline
points="5491,2598 5491,3070"
id="polyline120" />
<polyline
points="5315,2598 5315,3070"
id="polyline122" />
<polyline
points="5138,2598 5138,3070"
id="polyline124" />
<polyline
points="4960,2409 4960,3070"
id="polyline126" />
<polyline
points="4783,2598 4783,3070"
id="polyline128" />
<polyline
points="4606,2598 4606,3070"
id="polyline130" />
<polyline
points="4429,2598 4429,3070"
id="polyline132" />
<polyline
points="4251,2598 4251,3070"
id="polyline134" />
<polyline
points="4074,2598 4074,3070"
id="polyline136" />
<polyline
points="3898,2598 3898,3070"
id="polyline138" />
<polyline
points="3720,2598 3720,3070"
id="polyline140" />
<polyline
points="9212,2456 9212,3070"
id="polyline142" />
<polyline
points="3543,2598 9212,2598"
id="polyline144" />
<polyline
points="9212,3070 3720,3070 0,3070"
id="polyline146"
transform="matrix(0.92335242,0,0,1,706.07747,0)" />
<rect
x="5102"
y="4488"
width="1181"
height="2362"
rx="0"
style="fill:#dfdfdf"
id="rect148" />
<rect
x="3307"
y="4251"
width="1181"
height="2362"
rx="0"
style="fill:#dfdfdf"
id="rect150" />
<rect
x="6897"
y="4724"
width="1181"
height="2362"
rx="0"
style="fill:#dfdfdf"
id="rect152" />
<rect
x="1511"
y="4015"
width="1181"
height="2362"
rx="0"
style="fill:#dfdfdf"
id="rect154" />
<rect
x="1417"
y="6850"
width="1417"
height="472"
rx="0"
id="rect156" />
<rect
x="8503"
y="5433"
width="708"
height="236"
rx="0"
style="fill:#dfdfdf"
id="rect158" />
<rect
x="5102"
y="5669"
width="1181"
height="472"
rx="0"
id="rect160" />
<rect
x="3307"
y="5433"
width="1181"
height="472"
rx="0"
id="rect162" />
<rect
x="6897"
y="5905"
width="1181"
height="472"
rx="0"
id="rect164" />
<rect
x="1511"
y="5196"
width="1181"
height="472"
rx="0"
id="rect166" />
<circle
cx="6141"
cy="5905"
r="47"
style="fill:#0000ff;stroke:#0000ff;stroke-width:32"
id="circle170" />
<circle
cx="4346"
cy="5669"
r="47"
style="fill:#0000ff;stroke:#0000ff;stroke-width:32"
id="circle172" />
<circle
cx="7937"
cy="6141"
r="47"
style="fill:#0000ff;stroke:#0000ff;stroke-width:32"
id="circle174" />
<circle
cx="2551"
cy="5433"
r="47"
style="fill:#0000ff;stroke:#0000ff;stroke-width:32"
id="circle176" />
<polyline
points="3118,3590 2834,3779"
style="stroke:#0000ff"
id="polyline178" />
<polyline
points="1322,3590 1039,3779"
style="stroke:#0000ff"
id="polyline180" />
<polyline
points="4913,3590 4629,3779"
style="stroke:#0000ff"
id="polyline184" />
<polyline
points="6519,3590 6236,3779"
style="stroke:#0000ff"
id="polyline186" />
<polyline
points="8314,3590 8031,3779"
style="stroke:#0000ff"
id="polyline188" />
<circle
cx="1653"
cy="7086"
r="47"
style="fill:#0000ff;stroke:#0000ff;stroke-width:32"
id="circle190" />
<polyline
points="1653,7086 1181,7086 1181,6377 1354,6377"
style="stroke:#0000ff"
id="polyline192" />
<polygon
points="1512,6377 1355,6330 1355,6425 1355,6425 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon194" />
<polyline
points="7937,6141 8173,6141 8173,7322 8346,7322"
style="stroke:#0000ff"
id="polyline196" />
<polygon
points="8504,7322 8347,7275 8347,7370 8347,7370 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon198" />
<polyline
points="8173,3543 8173,5669 8346,5669"
style="stroke:#0000ff"
id="polyline200" />
<polygon
points="8504,5669 8347,5622 8347,5716 8347,5716 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon202" />
<polyline
points="9212,3070 9070,3307 8314,3307 8173,3543 8031,3307 7228,3307 7086,3070"
style="stroke:#0000ff"
id="polyline204" />
<polyline
points="3898,3070 4015,3307 4629,3307 4771,3543 4913,3307 5385,3307 5491,3070"
style="stroke:#0000ff"
id="polyline206" />
<polyline
points="5491,3070 5622,3307 6236,3307 6377,3543 6519,3307 6909,3307 7086,3070"
style="stroke:#0000ff"
id="polyline208" />
<polyline
points="2303,3070 2409,3307 2834,3307 2976,3543 3118,3307 3779,3307 3898,3070"
style="stroke:#0000ff"
id="polyline210" />
<polyline
points="708,3070 850,3307 1039,3307 1181,3543 1322,3307 2173,3307 2303,3070"
style="stroke:#0000ff"
id="polyline212" />
<polyline
points="4771,3543 4771,6141 4944,6141"
style="stroke:#0000ff"
id="polyline214" />
<polygon
points="5103,6141 4945,6094 4945,6188 4945,6188 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon216" />
<polyline
points="6377,3543 6377,4015 6519,4157 6519,6377 6740,6377"
style="stroke:#0000ff"
id="polyline218" />
<polygon
points="6898,6377 6741,6330 6741,6425 6741,6425 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon220" />
<polyline
points="6141,5905 6377,5905 6377,7086 6740,7086"
style="stroke:#0000ff"
id="polyline222" />
<polygon
points="6898,7086 6741,7039 6741,7133 6741,7133 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon224" />
<polyline
points="4346,5669 4629,5669 4629,6850 4944,6850"
style="stroke:#0000ff"
id="polyline226" />
<polygon
points="5103,6850 4945,6803 4945,6897 4945,6897 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon228" />
<polyline
points="2598,5433 2834,5433 2834,6614 3149,6614"
style="stroke:#0000ff"
id="polyline230" />
<polygon
points="3308,6614 3150,6566 3150,6661 3150,6661 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon232" />
<polyline
points="1181,3543 1181,5669 1401,5669"
style="stroke:#0000ff"
id="polyline234" />
<polygon
points="1560,5669 1402,5622 1402,5716 1402,5716 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon236" />
<polyline
points="2976,3543 2976,5905 3149,5905"
style="stroke:#0000ff"
id="polyline238" />
<polygon
points="3308,5905 3150,5858 3150,5952 3150,5952 "
style="fill:#0000ff;stroke:#0000ff"
id="polygon240" />
<g
style="fill:#000000;stroke-width:0"
id="g242">
<text
xml:space="preserve"
x="2281.8145"
y="7165"
font-style="normal"
font-weight="normal"
font-size="152"
id="text244"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle">CR3 register</text>
<text
xml:space="preserve"
x="3507"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text246"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">32</text>
<text
xml:space="preserve"
x="2161"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text248"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">39</text>
<text
xml:space="preserve"
x="2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text250"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">40</text>
<text
xml:space="preserve"
x="744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">47</text>
<text
xml:space="preserve"
x="672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text254"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text256"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="-744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text258"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text260"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="9176"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text262"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">0</text>
<text
xml:space="preserve"
x="7759"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text264"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">8</text>
<text
xml:space="preserve"
x="6342"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text266"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">16</text>
<text
xml:space="preserve"
x="4924"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text268"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">24</text>
<text
xml:space="preserve"
x="3579"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text270"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">31</text>
<text
xml:space="preserve"
x="6413"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text272"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">15</text>
<text
xml:space="preserve"
x="7830"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text274"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">7</text>
<text
xml:space="preserve"
x="4996"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text276"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">23</text>
<g
transform="matrix(0,-1,1,0,8976,4724)"
id="g278">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text280"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,8976,6614)"
id="g282">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text284"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,9448,5622)"
id="g286">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="152"
id="text288"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46390561px"
id="tspan3509">4K memory page</tspan></text>
</g>
<text
xml:space="preserve"
x="-2125"
y="2314"
font-style="normal"
font-weight="normal"
font-size="152"
id="text290"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
xml:space="preserve"
x="5622"
y="5958.457"
font-style="normal"
font-weight="normal"
font-size="152"
id="text292"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3497">P2 entry</tspan></text>
<g
transform="matrix(0,-1,1,0,5723,6614)"
id="g296">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text298"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,5723,5196)"
id="g300">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text302"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="5692"
y="4393"
font-style="normal"
font-weight="normal"
font-size="152"
id="text304"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46390561px"
id="tspan3505">P2 table</tspan></text>
<g
transform="matrix(0,-1,1,0,3928,6377)"
id="g306">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,3928,4960)"
id="g310">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text312"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3826"
y="5722.457"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3495">P3 entry</tspan></text>
<text
xml:space="preserve"
x="3874"
y="3968"
font-style="normal"
font-weight="normal"
font-size="152"
id="text318"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
xml:space="preserve"
x="3874"
y="4157"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46390561px"
id="tspan3503">P3 table</tspan></text>
<text
xml:space="preserve"
x="7417"
y="6194.457"
font-style="normal"
font-weight="normal"
font-size="152"
id="text322"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3499">P1 entry </tspan></text>
<g
transform="matrix(0,-1,1,0,7519,6850)"
id="g326">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text328"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,7519,5433)"
id="g330">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text332"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="7487"
y="4629"
font-style="normal"
font-weight="normal"
font-size="152"
id="text334"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46390561px"
id="tspan3507">P1 table</tspan></text>
<g
transform="matrix(0,-1,1,0,2133,6141)"
id="g336">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text338"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<g
transform="matrix(0,-1,1,0,2133,4724)"
id="g340">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text342"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
x="2004.2715"
y="5486.457"
font-style="normal"
font-weight="normal"
font-size="152"
id="text344"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle">
<tspan
style="font-size:200.46390561px"
id="tspan3493">P4 entry</tspan>
</text>
<text
x="2031"
y="5622"
font-style="normal"
font-weight="normal"
font-size="152"
id="text346"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="2078"
y="3941.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text348"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle">
<tspan
style="font-size:200.46391296px"
id="tspan3501">P4 table</tspan>
</text>
<text
x="3165"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text350"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="1370"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text352"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="1370"
y="6708"
font-style="normal"
font-weight="normal"
font-size="152"
id="text354"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff" />
<text
x="4960"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text356"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="6566"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text358"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="8362"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text360"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">12</text>
<text
x="1181"
y="7532.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text364"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -1,16 +1,19 @@
+++
title = "Page Tables"
slug = "modifying-page-tables"
date = "2015-12-09"
weight = 6
path = "page-tables"
aliases = ["page-tables.html", "modifying-page-tables.html"]
date = 2015-12-09
template = "edition-1/page.html"
+++
In this post we will create a paging module, which allows us to access and modify the 4-level page table. We will explore recursive page table mapping and use some Rust features to make it safe. Finally we will create functions to translate virtual addresses and to map and unmap pages.
<!--more-->
<!-- more -->
You can find the source code and this post itself on [Github][source repository]. Please file an issue there if you have any problems or improvement suggestions. There is also a comment section at the end of this page. Note that this post requires a current Rust nightly.
You can find the source code and this post itself on [GitHub][source repository]. Please file an issue there if you have any problems or improvement suggestions. There is also a comment section at the end of this page. Note that this post requires a current Rust nightly.
[source repository]: https://github.com/phil-opp/blog_os/tree/page_tables
[source repository]: https://github.com/phil-opp/blog_os/tree/first_edition_post_6
## Paging
_Paging_ is a memory management scheme that separates virtual and physical memory. The address space is split into equal sized _pages_ and _page tables_ specify which virtual page points to which physical frame. For an extensive paging introduction take a look at the paging chapter ([PDF][paging chapter]) of the [Three Easy Pieces] OS book.
@@ -20,7 +23,7 @@ _Paging_ is a memory management scheme that separates virtual and physical memor
The x86 architecture uses a 4-level page table in 64-bit mode. A virtual address has the following structure:
![structure of a virtual address on x86](/images/x86_address_structure.svg)
![structure of a virtual address on x86](x86_address_structure.svg)
The bits 4863 are so-called _sign extension_ bits and must be copies of bit 47. The following 36 bits define the page table indexes (9 bits per table) and the last 12 bits specify the offset in the 4KiB page.
@@ -28,7 +31,7 @@ Each table has 2^9 = 512 entries and each entry is 8 byte. Thus a page table fit
To translate an address, the CPU reads the P4 address from the CR3 register. Then it uses the indexes to walk the tables:
![translation of virtual to physical addresses in 64 bit mode](/images/X86_Paging_64bit.svg)
![translation of virtual to physical addresses in 64 bit mode](X86_Paging_64bit.svg)
The P4 entry points to a P3 table, where the next 9 bits of the address are used to select an entry. The P3 entry then points to a P2 table and the P2 entry points to a P1 table. The P1 entry, which is specified through bits 1220, finally points to the physical frame.
@@ -49,7 +52,7 @@ pub struct Page {
```
We import the `PAGE_SIZE` and define a constant for the number of entries per table. To make future function signatures more expressive, we can use the type aliases `PhysicalAddress` and `VirtualAddress`. The `Page` struct is similar to the `Frame` struct in the [previous post], but represents a virtual page instead of a physical frame.
[previous post]: {{% relref "2015-11-15-allocating-frames.md#a-memory-module" %}}
[previous post]: @/edition-1/posts/05-allocating-frames/index.md#a-memory-module
### Page Table Entries
To model page table entries, we create a new `entry` submodule:
@@ -96,7 +99,7 @@ To model the various flags, we will use the [bitflags] crate. To add it as a dep
```toml
[dependencies]
...
bitflags = "0.7.0"
bitflags = "0.9.1"
```
To import the macro, we need to use `#[macro_use]` above the `extern crate` definition:
@@ -111,23 +114,23 @@ Now we can model the various flags:
```rust
bitflags! {
pub flags EntryFlags: u64 {
const PRESENT = 1 << 0,
const WRITABLE = 1 << 1,
const USER_ACCESSIBLE = 1 << 2,
const WRITE_THROUGH = 1 << 3,
const NO_CACHE = 1 << 4,
const ACCESSED = 1 << 5,
const DIRTY = 1 << 6,
const HUGE_PAGE = 1 << 7,
const GLOBAL = 1 << 8,
const NO_EXECUTE = 1 << 63,
pub struct EntryFlags: u64 {
const PRESENT = 1 << 0;
const WRITABLE = 1 << 1;
const USER_ACCESSIBLE = 1 << 2;
const WRITE_THROUGH = 1 << 3;
const NO_CACHE = 1 << 4;
const ACCESSED = 1 << 5;
const DIRTY = 1 << 6;
const HUGE_PAGE = 1 << 7;
const GLOBAL = 1 << 8;
const NO_EXECUTE = 1 << 63;
}
}
```
To extract the flags from the entry we create an `Entry::flags` method that uses [from_bits_truncate]:
[from_bits_truncate]: https://doc.rust-lang.org/bitflags/bitflags/macro.bitflags!.html#methods
[from_bits_truncate]: https://docs.rs/bitflags/0.9.1/bitflags/example_generated/struct.Flags.html#method.from_bits_truncate
```rust
pub fn flags(&self) -> EntryFlags {
@@ -232,19 +235,19 @@ We will solve the problem in another way using a trick called _recursive mapping
### Recursive Mapping
The trick is to map the P4 table recursively: The last entry doesn't point to a P3 table, but to the P4 table itself. We can use this entry to remove a translation level so that we land on a page table instead. For example, we can “loop” once to access a P1 table:
![access P1 table through recursive paging](/images/recursive_mapping_access_p1.svg)
![access P1 table through recursive paging](recursive_mapping_access_p1.svg)
By selecting the 511th P4 entry, which points points to the P4 table itself, the P4 table is used as the P3 table. Similarly, the P3 table is used as a P2 table and the P2 table is treated like a P1 table. Thus the P1 table becomes the target page and can be accessed through the offset.
It's also possible to access P2 tables by looping twice. And if we select the 511th entry three times, we can access and modify P3 tables:
![access P3 table through recursive paging](/images/recursive_mapping_access_p3.svg)
![access P3 table through recursive paging](recursive_mapping_access_p3.svg)
So we just need to specify the desired P3 table in the address through the P1 index. By choosing the 511th entry multiple times, we stay on the P4 table until the address's P1 index becomes the actual P4 index.
To access the P4 table itself, we loop once more and thus never leave the frame:
![access P4 table through recursive paging](/images/recursive_mapping_access_p4.svg)
![access P4 table through recursive paging](recursive_mapping_access_p4.svg)
So we can access and modify page tables of all levels by just setting one P4 entry once. Most work is done by the CPU, we just the recursive entry to remove one or more translation levels. It may seem a bit strange at first, but it's a clean and simple solution once you wrapped your head around it.
@@ -320,7 +323,7 @@ We convert the address into raw pointers through `as` casts and then convert the
Note that `self` stays borrowed as long as the returned reference is valid. This is because of Rust's [lifetime elision] rules. Basically, these rules say that the lifetime of an output reference is the same as the lifetime of the input reference by default. So the above function signatures are expanded to:
[lifetime elision]: https://doc.rust-lang.org/book/lifetimes.html#lifetime-elision
[lifetime elision]: https://doc.rust-lang.org/1.30.0/book/first-edition/lifetimes.html#lifetime-elision
```rust
pub fn next_table<'a>(&'a self, index: usize) -> Option<&'a Table> {...}
@@ -345,8 +348,6 @@ _What happens if we call them on a P1 table?_
Well, they would calculate the address of the next table (which does not exist) and treat it as a page table. Either they construct an invalid address (if `XXX < 400`)[^fn-invalid-address] or access the mapped page itself. That way, we could easily corrupt memory or cause CPU exceptions by accident. So these two functions are not _safe_ in Rust terms. Thus we need to make them `unsafe` functions unless we find some clever solution.
[^fn-invalid-address]: If the `XXX` part of the address is smaller than `0o400`, it's binary representation doesn't start with `1`. But the sign extension bits, which should be a copy of that bit, are `1` instead of `0`. Thus the address is not valid.
## Some Clever Solution
We can use Rust's type system to statically guarantee that the `next_table` methods can only be called on P4, P3, and P2 tables, but not on a P1 table. The idea is to add a `Level` parameter to the `Table` type and implement the `next_table` methods only for level 4, 3, and 2.
@@ -598,9 +599,9 @@ pub fn map_to<A>(page: Page, frame: Frame, flags: EntryFlags,
p1[page.p1_index()].set(frame, flags | PRESENT);
}
```
We add an reexport for all `entry` types since they are required to call the function. We assert that the page is unmapped and always set the present flag (since it wouldn't make sense to map a page without setting it).
We add an re-export for all `entry` types since they are required to call the function. We assert that the page is unmapped and always set the present flag (since it wouldn't make sense to map a page without setting it).
The `Table::next_table_create` method doesn't exist yet. It should return the next table if it exists, or create a new one. Therefor we need the `FrameAllocator` from the [previous post] and the `Table::zero` method:
The `Table::next_table_create` method doesn't exist yet. It should return the next table if it exists, or create a new one. For the implementation we need the `FrameAllocator` from the [previous post] and the `Table::zero` method:
```rust
use memory::FrameAllocator;
@@ -651,8 +652,8 @@ pub struct ActivePageTable {
```
We can't store the `Table<Level4>` directly because it needs to be at a special memory location (like the [VGA text buffer]). We could use a raw pointer or `&mut` instead of [Unique], but Unique indicates ownership better.
[VGA text buffer]: {{% relref "2015-10-23-printing-to-screen.md#the-text-buffer" %}}
[Unique]: https://doc.rust-lang.org/nightly/core/ptr/struct.Unique.html
[VGA text buffer]: @/edition-1/posts/04-printing-to-screen/index.md#the-text-buffer
[Unique]: https://doc.rust-lang.org/1.10.0/core/ptr/struct.Unique.html
Because the `ActivePageTable` owns the unique recursive mapped P4 table, there must be only one `ActivePageTable` instance. Thus we make the constructor function unsafe:
@@ -660,7 +661,7 @@ Because the `ActivePageTable` owns the unique recursive mapped P4 table, there m
impl ActivePageTable {
pub unsafe fn new() -> ActivePageTable {
ActivePageTable {
p4: Unique::new(table::P4),
p4: Unique::new_unchecked(table::P4),
}
}
}
@@ -670,11 +671,11 @@ We add some methods to get P4 references:
```rust
fn p4(&self) -> &Table<Level4> {
unsafe { self.p4.get() }
unsafe { self.p4.as_ref() }
}
fn p4_mut(&mut self) -> &mut Table<Level4> {
unsafe { self.p4.get_mut() }
unsafe { self.p4.as_mut() }
}
```
@@ -776,12 +777,12 @@ To test it, we add a `test_paging` function in `memory/paging/mod.rs`:
pub fn test_paging<A>(allocator: &mut A)
where A: FrameAllocator
{
let page_table = unsafe { ActivePageTable::new() };
let mut page_table = unsafe { ActivePageTable::new() };
// test it
}
```
We borrow the frame allocator since we will need it for the mapping functions. To be able to call that function from main, we need to reexport it in `memory/mod.rs`:
We borrow the frame allocator since we will need it for the mapping functions. To be able to call that function from main, we need to re-export it in `memory/mod.rs`:
```rust
// in memory/mod.rs
@@ -792,63 +793,6 @@ let mut frame_allocator = ...;
memory::test_paging(&mut frame_allocator);
```
### translate
First, we translate some addresses:
```rust
// address 0 is mapped
println!("Some = {:?}", page_table.translate(0));
// second P1 entry
println!("Some = {:?}", page_table.translate(4096));
// second P2 entry
println!("Some = {:?}", page_table.translate(512 * 4096));
// 300th P2 entry
println!("Some = {:?}", page_table.translate(300 * 512 * 4096));
// second P3 entry
println!("None = {:?}", page_table.translate(512 * 512 * 4096));
// last mapped byte
println!("Some = {:?}", page_table.translate(512 * 512 * 4096 - 1));
```
Currently, the first GiB of the address space is identity-mapped. Thus all addresses in this area should translate to `Some(x)`, where `x` is the virtual address. Only the second last address, `512 * 512 * 4096`, is not in that area and should resolve to `None`.
But the output shows two `None` lines:
```
Some = Some(0)
Some = Some(4096)
Some = Some(2097152)
Some = Some(629145600)
None = None
Some = None
```
The last line is wrong. But why?
In fact, all addresses above `344 * 512 * 4096` seem to get translated to `None`. But even worse, there are some wrong translations, too. For example, on my machine `357 * 512 * 4096` translates to roughly `255TiB`:
```
Some(280735973961728)
```
Something is terribly wrong here. But it's not our code.
The reason for this bug is a silent stack overflow. Remember, our `.bss` section in the `boot.asm` file looks like this:
```nasm
section .bss
align 4096
p4_table:
resb 4096
p3_table:
resb 4096
p2_table:
resb 4096
stack_bottom:
resb 4096
stack_top:
```
So a stack overflow overwrites the P2 table, starting at the last entry. But the CPU still uses the memory as page table entries. And if the stack bytes contain the present byte, it seems to point to a frame and `translate` returns a (wrong) `Some`.
To fix it, we double the stack size to `4096 * 2`. Now the last byte gets translated to `Some(1073741823)` correctly. To avoid this kind of bug in the future, we need to add a guard page to the stack, which causes an exception on stack overflow. We will do that in the next post when we remap the kernel.
### map_to
Let's test the `map_to` function:
@@ -881,7 +825,7 @@ To test the `unmap` function, we unmap the test page so that it translates to `N
page_table.unmap(Page::containing_address(addr), allocator);
println!("None = {:?}", page_table.translate(addr));
```
It causes a panic since we call the unimplemented `deallocate_frame` method in `unwrap`. If we comment this call out, it works without problems. But there is some bug in this function nevertheless.
It causes a panic since we call the unimplemented `deallocate_frame` method in `unmap`. If we comment this call out, it works without problems. But there is some bug in this function nevertheless.
Let's read something from the mapped page (of course before we unmap it again):
@@ -898,29 +842,28 @@ An x86 processor has many different caches because always accessing the main mem
The translation lookaside buffer, or TLB, caches the translation of virtual to physical addresses. It's filled automatically when a page is accessed. But it's not updated transparently when the mapping of a page changes. This is the reason that we still can access the page even through we unmapped it in the page table.
So to fix our `unmap` function, we need to remove the cached translation from the TLB. We can use Gerd Zellweger's [x86][x86 crate] crate to do this easily. To add it, we append the following to our `Cargo.toml`:
So to fix our `unmap` function, we need to remove the cached translation from the TLB. We can use the [x86_64][x86_64 crate] crate to do this easily. To add it, we append the following to our `Cargo.toml`:
[x86 crate]: https://github.com/gz/rust-x86
[x86_64 crate]: https://docs.rs/x86_64
```toml
[dependencies.x86]
version = "0.6.0"
default-features = false
[dependencies]
...
x86_64 = "0.1.2"
```
It has a `performance-counter` feature that allows reading the CPU specific [performance counters] but increases compile times. We don't need it right now, so we disable it using `default-features = false`.
[performance counters]: http://gz.github.io/rust-x86/x86/perfcnt/index.html
Now we can use it to fix `unmap`:
```rust
...
p1[page.p1_index()].set_unused();
unsafe {
::x86::tlb::flush(page.start_address());
}
// TODO free p(1,2,3) table if empty
//allocator.deallocate_frame(frame);
p1[page.p1_index()].set_unused();
use x86_64::instructions::tlb;
use x86_64::VirtualAddress;
tlb::flush(VirtualAddress(page.start_address()));
// TODO free p(1,2,3) table if empty
//allocator.deallocate_frame(frame);
}
```
Now the desired page fault occurs even when we access the page before.
@@ -938,10 +881,13 @@ This post has become pretty long. So let's summarize what we've done:
## What's next?
In the [next post] we will extend this module and add a function to modify inactive page tables. Through that function, we will create a new page table hierarchy that maps the kernel correctly using 4KiB pages. Then we will switch to the new table to get a safer kernel environment.
[next post]: {{% relref "2016-01-01-remap-the-kernel.md" %}}
[next post]: @/edition-1/posts/07-remap-the-kernel/index.md
Afterwards, we will use this paging module to build a heap allocator. This will allow us to use allocation and collection types such as `Box` and `Vec`.
<small>Image sources: [^virtual_physical_translation_source]</small>
## Footnotes
[^fn-invalid-address]: If the `XXX` part of the address is smaller than `0o400`, it's binary representation doesn't start with `1`. But the sign extension bits, which should be a copy of that bit, are `1` instead of `0`. Thus the address is not valid.
[^virtual_physical_translation_source]: Image sources: Modified versions of an image from [Wikipedia](https://commons.wikimedia.org/wiki/File:X86_Paging_64bit.svg). The modified files are licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,819 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="900.00409"
height="530"
viewBox="-2141 2141 12027.89 7032.1014"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="recursive_mapping_access_p3.svg">
<metadata
id="metadata370">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs368" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="998"
id="namedview366"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="2.7755576e-17"
fit-margin-bottom="0"
inkscape:zoom="1"
inkscape:cx="236.56561"
inkscape:cy="267.91265"
inkscape:window-x="1080"
inkscape:window-y="568"
inkscape:window-maximized="1"
inkscape:current-layer="g4"
units="in" />
<g
style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="g4"
transform="translate(-1087.0637,717.51407)">
<polyline
points="3365,2598 3365,3070"
id="polyline10"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3189,2598 3189,3070"
id="polyline12"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3012,2598 3012,3070"
id="polyline14"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2834,2598 2834,3070"
id="polyline16"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2657,2598 2657,3070"
id="polyline18"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2480,2598 2480,3070"
id="polyline20"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2303,2598 2303,3070"
id="polyline22"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2125,2456 2125,3070"
id="polyline24"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1948,2598 1948,3070"
id="polyline26"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1772,2598 1772,3070"
id="polyline28"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1594,2598 1594,3070"
id="polyline30"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1417,2598 1417,3070"
id="polyline32"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1239,2598 1239,3070"
id="polyline34"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1063,2598 1063,3070"
id="polyline36"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="886,2598 886,3070"
id="polyline38"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="708,2456 708,3070"
id="polyline40"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3543,2456 3543,3070"
id="polyline74"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="-2125,2598 3543,2598"
id="polyline76"
transform="matrix(0.70622791,0,0,1.3955346,455.54989,-1956.6141)" />
<polyline
points="3543,3070 -1948,3070 -2125,3070"
id="polyline78"
transform="matrix(0.70351457,0,0,1.3955346,465.16321,-1956.6141)" />
<polyline
points="9035,2598 9035,3070"
id="polyline80"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8858,2598 8858,3070"
id="polyline82"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8681,2598 8681,3070"
id="polyline84"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8503,2598 8503,3070"
id="polyline86"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8326,2598 8326,3070"
id="polyline88"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8150,2598 8150,3070"
id="polyline90"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7972,2598 7972,3070"
id="polyline92"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7795,2456 7795,3070"
id="polyline94"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7617,2598 7617,3070"
id="polyline96"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7441,2598 7441,3070"
id="polyline98"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7264,2598 7264,3070"
id="polyline100"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7086,2598 7086,3070"
id="polyline102"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6909,2598 6909,3070"
id="polyline104"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6732,2598 6732,3070"
id="polyline106"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6555,2598 6555,3070"
id="polyline108"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6377,2456 6377,3070"
id="polyline110"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6200,2598 6200,3070"
id="polyline112"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6024,2598 6024,3070"
id="polyline114"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5846,2598 5846,3070"
id="polyline116"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5669,2598 5669,3070"
id="polyline118"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5491,2598 5491,3070"
id="polyline120"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5315,2598 5315,3070"
id="polyline122"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5138,2598 5138,3070"
id="polyline124"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4960,2409 4960,3070"
id="polyline126"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4783,2598 4783,3070"
id="polyline128"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4606,2598 4606,3070"
id="polyline130"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4429,2598 4429,3070"
id="polyline132"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4251,2598 4251,3070"
id="polyline134"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4074,2598 4074,3070"
id="polyline136"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3898,2598 3898,3070"
id="polyline138"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3720,2598 3720,3070"
id="polyline140"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,2456 9212,3070"
id="polyline142"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3543,2598 9212,2598"
id="polyline144"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,3070 3720,3070 0,3070"
id="polyline146"
transform="matrix(1.3047439,0,0,1.3955346,-1051.0007,-1956.6141)" />
<rect
x="4021.6787"
y="4311.5088"
width="1668.8131"
height="3296.2527"
rx="0"
style="fill:#dfdfdf;stroke-width:11.23412323"
id="rect150" />
<polyline
points="3118,3590 2834,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline178"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1322,3590 1039,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline180"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4913,3590 4629,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline184"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6519,3590 6236,3779"
style="stroke:#0000ff"
id="polyline186"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8314,3590 8031,3779"
style="stroke:#0000ff"
id="polyline188"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,3070 9070,3307 8314,3307 8173,3543 8031,3307 7228,3307 7086,3070"
style="stroke:#0000ff"
id="polyline204"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3898,3070 4015,3307 4629,3307 4771,3543 4913,3307 5385,3307 5491,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline206"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5491,3070 5622,3307 6236,3307 6377,3543 6519,3307 6909,3307 7086,3070"
style="stroke:#0000ff"
id="polyline208"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2303,3070 2409,3307 2834,3307 2976,3543 3118,3307 3779,3307 3898,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline210"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="708,3070 850,3307 1039,3307 1181,3543 1322,3307 2173,3307 2303,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline212"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<g
style="fill:#000000;stroke-width:0"
id="g242"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)">
<text
xml:space="preserve"
x="5546.7881"
y="6876.4409"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-5">0</tspan></text>
<text
xml:space="preserve"
x="3507"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text246"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">32</text>
<text
xml:space="preserve"
x="2161"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text248"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">39</text>
<text
xml:space="preserve"
x="2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text250"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">40</text>
<text
xml:space="preserve"
x="744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">47</text>
<text
xml:space="preserve"
x="672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text254"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text256"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="-744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text258"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text260"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="9176"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text262"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">0</text>
<text
xml:space="preserve"
x="7759"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text264"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">8</text>
<text
xml:space="preserve"
x="6342"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text266"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">16</text>
<text
xml:space="preserve"
x="4924"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text268"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">24</text>
<text
xml:space="preserve"
x="3579"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text270"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">31</text>
<text
xml:space="preserve"
x="6413"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text272"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">15</text>
<text
xml:space="preserve"
x="7830"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text274"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">7</text>
<text
xml:space="preserve"
x="4996"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text276"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">23</text>
<g
transform="matrix(0,-1,1,0,8976,6614)"
id="g282" />
<text
xml:space="preserve"
x="-2125"
y="2314"
font-style="normal"
font-weight="normal"
font-size="152"
id="text290"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<g
transform="matrix(0,-1,1,0,4916.9545,5254.403)"
id="g306">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3874"
y="3968"
font-style="normal"
font-weight="normal"
font-size="152"
id="text318"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
xml:space="preserve"
x="4862.9551"
y="4397.5566"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3503">P4 table</tspan></text>
<text
x="2031"
y="5622"
font-style="normal"
font-weight="normal"
font-size="152"
id="text346"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="3165"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text350"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1;">9</text>
<text
x="1370"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text352"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1;">9</text>
<text
x="1370"
y="6708"
font-style="normal"
font-weight="normal"
font-size="152"
id="text354"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff" />
<text
x="4960"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text356"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1;">9</text>
<text
x="6566"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text358"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="8362"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text360"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">12</text>
<text
x="1181"
y="7532.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text364"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
x="1946.0945"
y="6998.52"
font-style="normal"
font-weight="normal"
font-size="152"
id="text344-8-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.75857544px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:217.16923523px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3493-3-2" />
</text>
<rect
style="fill:none;stroke:#000000;stroke-width:7.99999952;stroke-linecap:butt;stroke-linejoin:miter"
x="4294.9473"
y="4493.6152"
width="1181"
height="471.99994"
rx="0"
id="rect162-5" />
<circle
cx="5335.9546"
cy="4720.2134"
style="fill:#008200;stroke:#008200;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
id="circle172-4"
r="46.999996" />
<text
xml:space="preserve"
x="4815.9546"
y="4773.6704"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6">P4 entry</tspan></text>
<text
xml:space="preserve"
x="4925.6357"
y="7173.5298"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-0"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6-4">Recursive</tspan></text>
<text
xml:space="preserve"
x="4925.6357"
y="7440.8149"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-0-9"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6-4-4">Mapping</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:6.53430033;stroke-linecap:butt;stroke-linejoin:miter"
x="4296.5396"
y="5560.2471"
width="1182.4656"
height="314.50067"
rx="0"
id="rect162-5-1" />
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-0.99999994,0.99999994,0,4915.3734,6277.1653)"
id="g306-2">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308-3"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3097.1609"
y="2954.5652"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:318.2364502px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
inkscape:transform-center-x="-789.14735"
inkscape:transform-center-y="1300.106"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:318.2364502px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3503-4">111111111111111111111111111</tspan></text>
<rect
x="8208.377"
y="4073.4419"
width="691.0863"
height="3268.5144"
rx="0"
style="fill:#dfdfdf;stroke:#000000;stroke-width:7.85773897;stroke-linecap:butt;stroke-linejoin:miter"
id="rect8" />
<rect
x="8208.377"
y="5474.9399"
width="691.0863"
height="233.25354"
rx="0"
style="fill:#dfdfdf;stroke:#000000;stroke-width:7.85773897;stroke-linecap:butt;stroke-linejoin:miter"
id="rect158" />
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-0.98836234,0.97611052,0,9106.1205,5822.055)"
id="g286">
<text
xml:space="preserve"
x="96.892052"
y="38.756821"
font-style="normal"
font-weight="normal"
font-size="152"
id="text288"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3509">P3 table </tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:14.53380773;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 2308.9448,-2797.8507 -483.0169,0 0,-2544.6425 -1879.786585,0 0,339.1222"
id="path8874"
inkscape:connector-curvature="0" />
</g>
<text
xml:space="preserve"
x="4809.9756"
y="5774.4951"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-5"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46392822px;stroke-width:0"
id="tspan3495-6-7">P4 entry</tspan></text>
<ellipse
ry="46.999996"
rx="46.999992"
cx="5336.855"
cy="5714.1816"
style="fill:#0000ff;stroke:#0000ff;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter"
id="circle172-4-4" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:9.55735683px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 5392.0276,5712.0004 1512.0496,0 0,1631.4957 1257.8109,0"
id="path9464"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:9.51690483px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 8173.2452,3542.5202 0,364.8071 -584.0141,0 0,1802.0952 528.0052,0"
id="path9466"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
x="5610.3569"
y="4990.1772"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5">511</tspan></text>
</g>
<polygon
points="3308,6614 3150,6566 3150,6661 3150,6661 "
style="fill:#008200;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;fill-opacity:1;stroke-opacity:1"
id="polygon232-2"
transform="matrix(1.4130509,0,0,1.3955346,-646.4618,-1622.6914)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.76697159px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 5574.5569,4637.287 719.9709,0 0,3526.7653 -2765.702,0 0,-560.545 294.8212,0"
id="path5354"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.52740288px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 3843.9848,5007.8363 -4223.58417,0 0,-2024.2908"
id="path5356"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.65159035px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 2156.7076,2986.8221 0,1988.2634 1691.863,0"
id="path5358"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.78581619px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 4696.351,2980.052 0,497.5653 -1975.7645,0 0,1464.6642 1128.3337,0"
id="path5360"
inkscape:connector-curvature="0" />
<polygon
points="3150,6661 3308,6614 3150,6566 3150,6661 "
style="fill:#0000ff;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polygon232-2-7"
transform="matrix(1.4130509,0,0,1.3955346,-625.83944,-2988.2046)" />
<polygon
points="3150,6661 3150,6661 3308,6614 3150,6566 "
style="fill:#0000ff;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polygon232-2-7-3"
transform="matrix(1.4130509,0,0,1.3955346,4891.7749,-3219.444)" />
<polygon
points="3150,6661 3150,6661 3308,6614 3150,6566 "
style="fill:#0000ff;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polygon232-2-7-3-5"
transform="matrix(1.4130509,0,0,1.3955346,4896.989,-940.27671)" />
<polygon
points="3150,6566 3150,6661 3150,6661 3308,6614 "
style="fill:#008200;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;fill-opacity:1;stroke-opacity:1"
id="polygon232-2-7-7"
transform="matrix(1.4130509,0,0,1.3955346,-628.09888,-4256.4264)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -0,0 +1,765 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="900.00409"
height="530"
viewBox="-2141 2141 12027.89 7032.1014"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="recursive_mapping_access_p4.svg">
<metadata
id="metadata370">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs368" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="998"
id="namedview366"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="2.7755576e-17"
fit-margin-bottom="0"
inkscape:zoom="0.5"
inkscape:cx="150.51041"
inkscape:cy="507.56343"
inkscape:window-x="1080"
inkscape:window-y="568"
inkscape:window-maximized="1"
inkscape:current-layer="g4"
units="in" />
<g
style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="g4"
transform="translate(-1087.0637,717.51407)">
<polyline
points="3365,2598 3365,3070"
id="polyline10"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3189,2598 3189,3070"
id="polyline12"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3012,2598 3012,3070"
id="polyline14"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2834,2598 2834,3070"
id="polyline16"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2657,2598 2657,3070"
id="polyline18"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2480,2598 2480,3070"
id="polyline20"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2303,2598 2303,3070"
id="polyline22"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2125,2456 2125,3070"
id="polyline24"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1948,2598 1948,3070"
id="polyline26"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1772,2598 1772,3070"
id="polyline28"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1594,2598 1594,3070"
id="polyline30"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1417,2598 1417,3070"
id="polyline32"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1239,2598 1239,3070"
id="polyline34"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1063,2598 1063,3070"
id="polyline36"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="886,2598 886,3070"
id="polyline38"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="708,2456 708,3070"
id="polyline40"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3543,2456 3543,3070"
id="polyline74"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="-2125,2598 3543,2598"
id="polyline76"
transform="matrix(0.70622791,0,0,1.3955346,455.54989,-1956.6141)" />
<polyline
points="3543,3070 -1948,3070 -2125,3070"
id="polyline78"
transform="matrix(0.70351457,0,0,1.3955346,465.16321,-1956.6141)" />
<polyline
points="9035,2598 9035,3070"
id="polyline80"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8858,2598 8858,3070"
id="polyline82"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8681,2598 8681,3070"
id="polyline84"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8503,2598 8503,3070"
id="polyline86"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8326,2598 8326,3070"
id="polyline88"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8150,2598 8150,3070"
id="polyline90"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7972,2598 7972,3070"
id="polyline92"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7795,2456 7795,3070"
id="polyline94"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7617,2598 7617,3070"
id="polyline96"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7441,2598 7441,3070"
id="polyline98"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7264,2598 7264,3070"
id="polyline100"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7086,2598 7086,3070"
id="polyline102"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6909,2598 6909,3070"
id="polyline104"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6732,2598 6732,3070"
id="polyline106"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6555,2598 6555,3070"
id="polyline108"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6377,2456 6377,3070"
id="polyline110"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6200,2598 6200,3070"
id="polyline112"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6024,2598 6024,3070"
id="polyline114"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5846,2598 5846,3070"
id="polyline116"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5669,2598 5669,3070"
id="polyline118"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5491,2598 5491,3070"
id="polyline120"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5315,2598 5315,3070"
id="polyline122"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5138,2598 5138,3070"
id="polyline124"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4960,2409 4960,3070"
id="polyline126"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4783,2598 4783,3070"
id="polyline128"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4606,2598 4606,3070"
id="polyline130"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4429,2598 4429,3070"
id="polyline132"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4251,2598 4251,3070"
id="polyline134"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4074,2598 4074,3070"
id="polyline136"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3898,2598 3898,3070"
id="polyline138"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3720,2598 3720,3070"
id="polyline140"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,2456 9212,3070"
id="polyline142"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3543,2598 9212,2598"
id="polyline144"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,3070 3720,3070 0,3070"
id="polyline146"
transform="matrix(1.3047439,0,0,1.3955346,-1051.0007,-1956.6141)" />
<rect
x="4021.6787"
y="4311.5088"
width="1668.8131"
height="3296.2527"
rx="0"
style="fill:#dfdfdf;stroke-width:11.23412323"
id="rect150" />
<polyline
points="3118,3590 2834,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline178"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1322,3590 1039,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline180"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4913,3590 4629,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline184"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6519,3590 6236,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline186"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8314,3590 8031,3779"
style="stroke:#0000ff"
id="polyline188"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,3070 9070,3307 8314,3307 8173,3543 8031,3307 7228,3307 7086,3070"
style="stroke:#0000ff"
id="polyline204"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3898,3070 4015,3307 4629,3307 4771,3543 4913,3307 5385,3307 5491,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline206"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5491,3070 5622,3307 6236,3307 6377,3543 6519,3307 6909,3307 7086,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline208"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2303,3070 2409,3307 2834,3307 2976,3543 3118,3307 3779,3307 3898,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline210"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="708,3070 850,3307 1039,3307 1181,3543 1322,3307 2173,3307 2303,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline212"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<g
style="fill:#000000;stroke-width:0"
id="g242"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)">
<text
xml:space="preserve"
x="3507"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text246"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">32</text>
<text
xml:space="preserve"
x="2161"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text248"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">39</text>
<text
xml:space="preserve"
x="2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text250"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">40</text>
<text
xml:space="preserve"
x="744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">47</text>
<text
xml:space="preserve"
x="672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text254"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text256"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="-744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text258"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text260"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="9176"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text262"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">0</text>
<text
xml:space="preserve"
x="7759"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text264"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">8</text>
<text
xml:space="preserve"
x="6342"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text266"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">16</text>
<text
xml:space="preserve"
x="4924"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text268"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">24</text>
<text
xml:space="preserve"
x="3579"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text270"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">31</text>
<text
xml:space="preserve"
x="6413"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text272"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">15</text>
<text
xml:space="preserve"
x="7830"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text274"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">7</text>
<text
xml:space="preserve"
x="4996"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text276"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">23</text>
<g
transform="matrix(0,-1,1,0,8976,6614)"
id="g282" />
<text
xml:space="preserve"
x="-2125"
y="2314"
font-style="normal"
font-weight="normal"
font-size="152"
id="text290"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<g
transform="matrix(0,-1,1,0,4916.9545,5254.403)"
id="g306">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3874"
y="3968"
font-style="normal"
font-weight="normal"
font-size="152"
id="text318"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
xml:space="preserve"
x="4862.9551"
y="4397.5566"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3503">P4 table</tspan></text>
<text
x="2031"
y="5622"
font-style="normal"
font-weight="normal"
font-size="152"
id="text346"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="3165"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text350"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1;">9</text>
<text
x="1370"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text352"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1;">9</text>
<text
x="1370"
y="6708"
font-style="normal"
font-weight="normal"
font-size="152"
id="text354"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff" />
<text
x="4960"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text356"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1;">9</text>
<text
x="6566"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text358"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1;">9</text>
<text
x="8362"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text360"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">12</text>
<text
x="1181"
y="7532.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text364"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
x="1946.0945"
y="6998.52"
font-style="normal"
font-weight="normal"
font-size="152"
id="text344-8-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.75857544px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:217.16923523px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3493-3-2" />
</text>
<rect
style="fill:none;stroke:#000000;stroke-width:7.99999952;stroke-linecap:butt;stroke-linejoin:miter"
x="4294.9473"
y="4493.6152"
width="1181"
height="471.99994"
rx="0"
id="rect162-5" />
<circle
cx="5335.9546"
cy="4720.2134"
style="fill:#008200;stroke:#008200;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;fill-opacity:1;stroke-opacity:1"
id="circle172-4"
r="46.999996" />
<text
xml:space="preserve"
x="4815.9546"
y="4773.6704"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6">P4 entry</tspan></text>
<text
xml:space="preserve"
x="4925.6357"
y="7173.5298"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-0"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6-4">Recursive</tspan></text>
<text
xml:space="preserve"
x="4925.6357"
y="7440.8149"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-0-9"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6-4-4">Mapping</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:6.53430033;stroke-linecap:butt;stroke-linejoin:miter"
x="4296.5396"
y="5560.2471"
width="1182.4656"
height="314.50067"
rx="0"
id="rect162-5-1" />
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-0.99999994,0.99999994,0,4915.3734,6277.1653)"
id="g306-2">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308-3"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3891.613"
y="2954.5652"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:318.2364502px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
inkscape:transform-center-x="-789.14735"
inkscape:transform-center-y="1300.106"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:318.2364502px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3503-4">111111111111111111111111111111111111</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:13.36426067px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 5603.8041,5874.9118 2568.0264,0 0,-2337.6838"
id="path5364"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
x="7481.9214"
y="6083.3872"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-0-6"
style="font-style:normal;font-weight:normal;font-size:151.99998474px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46389771px;stroke-width:0"
id="tspan3495-6-4-9">Offset in bytes</tspan></text>
<text
xml:space="preserve"
x="5622.4961"
y="5000.6953"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5">511</tspan></text>
<text
xml:space="preserve"
x="5548.4839"
y="6877.3652"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-1">0</tspan></text>
</g>
<polygon
transform="matrix(-1.4130475,-0.00314156,0.00318097,-1.395531,10325.825,15480.806)"
points="3150,6661 3308,6614 3150,6566 3150,6661 "
style="fill:#0000ff;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polygon232-0-6" />
<polygon
points="3308,6614 3150,6566 3150,6661 3150,6661 "
style="fill:#008200;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;fill-opacity:1;stroke-opacity:1"
id="polygon232-2"
transform="matrix(1.4130509,0,0,1.3955346,-646.4618,-1622.6914)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.76697159px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 5574.5569,4637.287 719.9709,0 0,3526.7653 -2765.702,0 0,-560.545 294.8212,0"
id="path5354"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.54883385px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 3842.7968,5013.0895 -4222.39215,0 0,-2029.5495"
id="path5356"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.67419624px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 2156.6937,2986.8005 0,2001.4832 1684.7642,0"
id="path5358"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.88186646px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 4696.3171,2980.021 0,502.6836 -1975.6967,0 0,1479.7303 1128.295,0"
id="path5360"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:19.05912971px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 6962.3822,2986.9474 0,745.9077 -3590.1899,0 0,1203.077 448.1838,0"
id="path5362"
inkscape:connector-curvature="0" />
<polygon
points="3150,6661 3308,6614 3150,6566 3150,6661 "
style="fill:#008200;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;fill-opacity:1;stroke-opacity:1"
id="polygon232-2-3"
transform="matrix(1.4130509,0,0,1.3955346,-639.67391,-4258.2588)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -0,0 +1,917 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="900.0036"
height="145.45076"
viewBox="-2141 2141 12027.883 1929.8575"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="x86_address_structure.svg">
<metadata
id="metadata370">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs368" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="716"
id="namedview366"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="2.8284271"
inkscape:cx="84.319072"
inkscape:cy="113.89333"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g242"
units="px" />
<g
style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="g4"
transform="translate(331.35503,-225.83102)">
<polyline
points="3365,2598 3365,3070"
id="polyline10"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="3189,2598 3189,3070"
id="polyline12"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="3012,2598 3012,3070"
id="polyline14"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="2834,2598 2834,3070"
id="polyline16"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="2657,2598 2657,3070"
id="polyline18"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="2480,2598 2480,3070"
id="polyline20"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="2303,2598 2303,3070"
id="polyline22"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="2125,2456 2125,3070"
id="polyline24"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:25.36408559;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="1948,2598 1948,3070"
id="polyline26"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="1772,2598 1772,3070"
id="polyline28"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="1594,2598 1594,3070"
id="polyline30"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="1417,2598 1417,3070"
id="polyline32"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="1239,2598 1239,3070"
id="polyline34"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="1063,2598 1063,3070"
id="polyline36"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="886,2598 886,3070"
id="polyline38"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="708,2456 708,3070"
id="polyline40"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:25.36408559;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="3543,2456 3543,3070"
id="polyline74"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:25.36408559;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="-2125,2598 3543,2598"
id="polyline76"
transform="matrix(0.52969427,0,0,1.0477876,1661.7387,-151.61082)"
style="stroke-width:17.93889427;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="3543,3070 -1948,3070 -2125,3070"
id="polyline78"
transform="matrix(0.52765919,0,0,1.0477876,1673.588,-157.78641)"
style="stroke-width:17.97345503;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="9035,2598 9035,3070"
id="polyline80"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="8858,2598 8858,3070"
id="polyline82"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="8681,2598 8681,3070"
id="polyline84"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="8503,2598 8503,3070"
id="polyline86"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="8326,2598 8326,3070"
id="polyline88"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="8150,2598 8150,3070"
id="polyline90"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="7972,2598 7972,3070"
id="polyline92"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="7795,2456 7795,3070"
id="polyline94"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:25.36408559;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="7617,2598 7617,3070"
id="polyline96"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="7441,2598 7441,3070"
id="polyline98"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="7264,2598 7264,3070"
id="polyline100"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="7086,2598 7086,3070"
id="polyline102"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="6909,2598 6909,3070"
id="polyline104"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="6732,2598 6732,3070"
id="polyline106"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="6555,2598 6555,3070"
id="polyline108"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="6377,2456 6377,3070"
id="polyline110"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:25.36408559;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="6200,2598 6200,3070"
id="polyline112"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="6024,2598 6024,3070"
id="polyline114"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="5846,2598 5846,3070"
id="polyline116"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="5669,2598 5669,3070"
id="polyline118"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="5491,2598 5491,3070"
id="polyline120"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="5315,2598 5315,3070"
id="polyline122"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="5138,2598 5138,3070"
id="polyline124"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="4960,2409 4960,3070"
id="polyline126"
transform="matrix(1.0598349,0,0,0.97582891,-211.91044,63.126762)"
style="stroke-width:25.36408615;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="4783,2598 4783,3070"
id="polyline128"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="4606,2598 4606,3070"
id="polyline130"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="4429,2598 4429,3070"
id="polyline132"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="4251,2598 4251,3070"
id="polyline134"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="4074,2598 4074,3070"
id="polyline136"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="3898,2598 3898,3070"
id="polyline138"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="3720,2598 3720,3070"
id="polyline140"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:12.6820428;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="9212,2456 9212,3070"
id="polyline142"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)"
style="stroke-width:25.36408559;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="3543,2598 9212,2598"
id="polyline144"
transform="matrix(1.0598349,0,0,1.0477876,-207.27136,-151.61082)"
style="stroke-width:17.75485992;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="9212,3070 3720,3070 0,3070"
id="polyline146"
transform="matrix(0.65314228,0,0,1.0477876,3541.5006,-157.82019)"
style="stroke-width:18.04502869;stroke-miterlimit:4;stroke-dasharray:none" />
<polyline
points="3118,3590 2834,3779"
style="stroke:#0000ff"
id="polyline178"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)" />
<polyline
points="1322,3590 1039,3779"
style="stroke:#0000ff"
id="polyline180"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)" />
<polyline
points="4913,3590 4629,3779"
style="stroke:#0000ff"
id="polyline184"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)" />
<polyline
points="6519,3590 6236,3779"
style="stroke:#0000ff"
id="polyline186"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)" />
<polyline
points="8314,3590 8031,3779"
style="stroke:#0000ff"
id="polyline188"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)" />
<polyline
points="9212,3070 9070,3307 8314,3307 8173,3543 8031,3307 7228,3307 7086,3070"
style="stroke:#0000ff"
id="polyline204"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)" />
<polyline
points="3898,3070 4015,3307 4629,3307 4771,3543 4913,3307 5385,3307 5491,3070"
style="stroke:#0000ff"
id="polyline206"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)" />
<polyline
points="5491,3070 5622,3307 6236,3307 6377,3543 6519,3307 6909,3307 7086,3070"
style="stroke:#0000ff"
id="polyline208"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)" />
<polyline
points="2303,3070 2409,3307 2834,3307 2976,3543 3118,3307 3779,3307 3898,3070"
style="stroke:#0000ff"
id="polyline210"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)" />
<polyline
points="708,3070 850,3307 1039,3307 1181,3543 1322,3307 2173,3307 2303,3070"
style="stroke:#0000ff"
id="polyline212"
transform="matrix(1.0598349,0,0,1.0477876,-211.91044,-157.78641)" />
<g
style="fill:#000000;stroke-width:0"
id="g242">
<text
xml:space="preserve"
x="3484.9529"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text246"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">32</text>
<text
xml:space="preserve"
x="2305.7319"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text248"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">39</text>
<text
xml:space="preserve"
x="1965.1508"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text250"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">40</text>
<text
xml:space="preserve"
x="480.46173"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">48</text>
<text
xml:space="preserve"
x="672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text254"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text256"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="-744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text258"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text260"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="9458.9111"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text262"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">0</text>
<text
xml:space="preserve"
x="7965.6851"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text264"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">8</text>
<text
xml:space="preserve"
x="6445.8828"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text266"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">16</text>
<text
xml:space="preserve"
x="4978.1792"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text268"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">24</text>
<text
xml:space="preserve"
x="3796.0706"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text270"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">31</text>
<text
xml:space="preserve"
x="6782.5229"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text272"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">15</text>
<text
xml:space="preserve"
x="8167.3521"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text274"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">7</text>
<text
xml:space="preserve"
x="5289.2969"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text276"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">23</text>
<text
xml:space="preserve"
x="-2125"
y="2314"
font-style="normal"
font-weight="normal"
font-size="152"
id="text290"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
xml:space="preserve"
x="3874"
y="3968"
font-style="normal"
font-weight="normal"
font-size="152"
id="text318"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="2031"
y="5622"
font-style="normal"
font-weight="normal"
font-size="152"
id="text346"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="1074.5779"
y="4269.3325"
font-style="normal"
font-weight="normal"
font-size="152"
id="text348"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3501">P4 index</tspan>
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan5052" />
</text>
<text
x="3124.5554"
y="3774.0684"
font-style="normal"
font-weight="normal"
font-size="152"
id="text350"
style="font-style:normal;font-weight:normal;font-size:160.17668152px;font-family:Helvetica;text-anchor:start;fill:#0000ff;stroke-width:0"
transform="scale(1.0057325,0.99430016)">9</text>
<text
x="1232.9951"
y="3774.0684"
font-style="normal"
font-weight="normal"
font-size="152"
id="text352"
style="font-style:normal;font-weight:normal;font-size:160.17668152px;font-family:Helvetica;text-anchor:start;fill:#0000ff;stroke-width:0"
transform="scale(1.0057325,0.99430016)">9</text>
<text
x="1370"
y="6708"
font-style="normal"
font-weight="normal"
font-size="152"
id="text354"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff" />
<text
x="5016.1157"
y="3774.0684"
font-style="normal"
font-weight="normal"
font-size="152"
id="text356"
style="font-style:normal;font-weight:normal;font-size:160.17668152px;font-family:Helvetica;text-anchor:start;fill:#0000ff;stroke-width:0"
transform="scale(1.0057325,0.99430016)">9</text>
<text
x="6708.5088"
y="3774.0684"
font-style="normal"
font-weight="normal"
font-size="152"
id="text358"
style="font-style:normal;font-weight:normal;font-size:160.17668152px;font-family:Helvetica;text-anchor:start;fill:#0000ff;stroke-width:0"
transform="scale(1.0057325,0.99430016)">9</text>
<text
x="8601.1221"
y="3774.0684"
font-style="normal"
font-weight="normal"
font-size="152"
id="text360"
style="font-style:normal;font-weight:normal;font-size:160.17668152px;font-family:Helvetica;text-anchor:start;fill:#0000ff;stroke-width:0"
transform="scale(1.0057325,0.99430016)">12</text>
<text
x="1181"
y="7532.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text364"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
xml:space="preserve"
x="809.5191"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">47</text>
<text
xml:space="preserve"
x="-684.95245"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">55</text>
<text
xml:space="preserve"
x="-1034.7118"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252-4-7"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">56</text>
<text
xml:space="preserve"
x="-2201.2915"
y="2529.5376"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252-4-7-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.7585907px;line-height:125%;font-family:'Helvetica Narrow';-inkscape-font-specification:'Helvetica Narrow, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">63</text>
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-2192.9027,-160.09714)"
points="1322,3590 1039,3779"
style="fill:none;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polyline180-0" />
<text
x="-736.70618"
y="3771.7437"
font-style="normal"
font-weight="normal"
font-size="152"
id="text352-2"
style="font-style:normal;font-weight:normal;font-size:160.17668152px;font-family:Helvetica;text-anchor:start;fill:#0000ff;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="scale(1.0057325,0.99430016)">16</text>
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:14.08317852px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -929.72072,3549.5659 0,431.3931"
id="path4175"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:14.08317852px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 1039.4204,3550.0043 0,431.3933"
id="path4175-3"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:14.08317852px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 2942.7798,3549.8477 0,431.3932"
id="path4175-3-8"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:14.08317852px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 4844.585,3551.0064 0,431.3933"
id="path4175-3-8-6"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:14.08317852px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 6546.975,3551.1192 0,431.3932"
id="path4175-3-8-6-3"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:14.08317852px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 8449.877,3550.1734 0,431.3931"
id="path4175-3-8-6-3-5"
inkscape:connector-curvature="0" />
<text
x="-980.58942"
y="4269.3325"
font-style="normal"
font-weight="normal"
font-size="152"
id="text348-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3501-0">Sign extension</tspan>
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan5052-5" />
</text>
<text
x="4862.6738"
y="4269.3325"
font-style="normal"
font-weight="normal"
font-size="152"
id="text348-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3501-5">P2 index</tspan>
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan5052-8" />
</text>
<text
x="2919.9609"
y="4269.3325"
font-style="normal"
font-weight="normal"
font-size="152"
id="text348-1-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3501-5-8">P3 index</tspan>
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan5052-8-0" />
</text>
<text
x="6532.3008"
y="4269.3325"
font-style="normal"
font-weight="normal"
font-size="152"
id="text348-1-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3501-5-9">P1 index</tspan>
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan5052-8-7" />
</text>
<text
x="8392.0518"
y="4269.3325"
font-style="normal"
font-weight="normal"
font-size="152"
id="text348-1-5-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="scale(1.0057325,0.99430017)"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:300.69586182px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3501-5-9-5">Offset</tspan>
</text>
</g>
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="3365,2598 3365,3070"
id="polyline10-3" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="3189,2598 3189,3070"
id="polyline12-5" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="3012,2598 3012,3070"
id="polyline14-6" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="2834,2598 2834,3070"
id="polyline16-9" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="2657,2598 2657,3070"
id="polyline18-9" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="2480,2598 2480,3070"
id="polyline20-8" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="2303,2598 2303,3070"
id="polyline22-2" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:25.36408559;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="2125,2456 2125,3070"
id="polyline24-5" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="1948,2598 1948,3070"
id="polyline26-2" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="1772,2598 1772,3070"
id="polyline28-1" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="1594,2598 1594,3070"
id="polyline30-5" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="1417,2598 1417,3070"
id="polyline32-9" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="1239,2598 1239,3070"
id="polyline34-3" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="1063,2598 1063,3070"
id="polyline36-9" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:12.6820428;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="886,2598 886,3070"
id="polyline38-2" />
<polyline
transform="matrix(1.0598349,0,0,1.0477876,-3218.4788,-157.56699)"
style="fill:none;stroke:#000000;stroke-width:25.36408559;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="708,2456 708,3070"
id="polyline40-6" />
<polyline
style="fill:none;stroke:#000000;stroke-width:17.93889618;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="-2125,2598 3543,2598"
id="polyline76-6"
transform="matrix(0.52969421,0,0,1.0477875,-1349.4687,-150.28545)" />
<polyline
style="fill:none;stroke:#000000;stroke-width:17.97345674;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
points="3543,3070 -1948,3070 -2125,3070"
id="polyline78-8"
transform="matrix(0.52765914,0,0,1.0477875,-1332.9803,-157.56699)" />
<polyline
transform="matrix(1.4116086,0,0,1.0450205,-12466.637,-150.55138)"
points="9212,3070 9070,3307 8314,3307 8173,3543 8031,3307 7228,3307 7086,3070"
style="fill:none;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polyline204-3" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -0,0 +1,404 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="617.39313"
height="215.65028"
viewBox="-2141 2141 8251.0033 2861.2729"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="cyclic_mapping_inactive_table.svg">
<metadata
id="metadata370">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs368" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="998"
id="namedview366"
showgrid="false"
fit-margin-top="1"
fit-margin-left="1"
fit-margin-right="1"
fit-margin-bottom="1"
inkscape:zoom="1.4142136"
inkscape:cx="345.80952"
inkscape:cy="50.097583"
inkscape:window-x="1080"
inkscape:window-y="413"
inkscape:window-maximized="1"
inkscape:current-layer="g242"
units="in" />
<g
style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="g4"
transform="translate(-1516.6308,-1533.1047)">
<g
style="fill:#000000;stroke-width:0"
id="g242"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)">
<text
xml:space="preserve"
x="672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text254"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text256"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="-744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text258"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text260"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<g
transform="matrix(0,-1,1,0,8976,6614)"
id="g282" />
<text
xml:space="preserve"
x="-2125"
y="2314"
font-style="normal"
font-weight="normal"
font-size="152"
id="text290"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
xml:space="preserve"
x="3874"
y="3968"
font-style="normal"
font-weight="normal"
font-size="152"
id="text318"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="2031"
y="5622"
font-style="normal"
font-weight="normal"
font-size="152"
id="text346"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="1370"
y="6708"
font-style="normal"
font-weight="normal"
font-size="152"
id="text354"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff" />
<text
x="1181"
y="7532.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text364"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
x="1946.0945"
y="6998.52"
font-style="normal"
font-weight="normal"
font-size="152"
id="text344-8-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.75857544px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:217.16923523px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3493-3-2" />
</text>
<rect
x="3090.1064"
y="4497.9272"
width="1182.895"
height="1367.9473"
rx="0"
style="fill:#dfdfdf;stroke:#000000;stroke-width:6.0930233;stroke-linecap:butt;stroke-linejoin:miter"
id="rect150-8" />
<text
xml:space="preserve"
x="4341.8867"
y="5887.8105"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-5-9"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-5-6">0</tspan></text>
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-1,1,0,3712.0549,5414.9455)"
id="g306-4">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308-1"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3676.9697"
y="4404.876"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-8"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46392822px;stroke-width:0"
id="tspan3503-3">P4 table</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:7.99999952;stroke-linecap:butt;stroke-linejoin:miter"
x="3090.0466"
y="4500.9346"
width="1181"
height="471.99997"
rx="0"
id="rect162-5-4" />
<text
xml:space="preserve"
x="3611.0537"
y="4780.9897"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-1"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46392822px;stroke-width:0"
id="tspan3495-6-41">P4 entry</tspan></text>
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-0.99999992,0.9999999,0,2296.6633,6284.4847)"
id="g306-2-3" />
<text
xml:space="preserve"
x="4405.4561"
y="4997.4966"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-8">511</tspan></text>
<ellipse
ry="46.999996"
rx="46.999992"
cx="4117.4102"
cy="4723.3125"
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="circle172-4-3" />
<text
xml:space="preserve"
x="3674.7217"
y="4178.6655"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-8-5"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3503-3-0">active</tspan></text>
<rect
x="5370.3823"
y="4498.0884"
width="1182.895"
height="1367.9473"
rx="0"
style="fill:#dfdfbe;fill-opacity:1;stroke:#000000;stroke-width:6.0930233;stroke-linecap:butt;stroke-linejoin:miter"
id="rect150-8-9" />
<text
xml:space="preserve"
x="6622.1631"
y="5887.9717"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-5-9-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-5-6-5">0</tspan></text>
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-1,1,0,5992.3314,5415.1068)"
id="g306-4-9">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308-1-8"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="5957.2456"
y="4405.0371"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-8-0"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3503-3-2">P4 table</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:7.99999952;stroke-linecap:butt;stroke-linejoin:miter"
x="5370.3228"
y="4501.0957"
width="1181"
height="472"
rx="0"
id="rect162-5-4-4" />
<text
xml:space="preserve"
x="5891.3296"
y="4781.1509"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-1-6"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3495-6-41-6">P4 entry</tspan></text>
<text
xml:space="preserve"
x="6685.7324"
y="4997.6577"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-6-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-8-1">511</tspan></text>
<polygon
points="3308,6614 3150,6566 3150,6661 3150,6661 "
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="polygon232-2-7-7-1-1"
transform="translate(2076.0084,-749.88898)" />
<ellipse
ry="46.999996"
rx="46.999992"
cx="6397.6865"
cy="4723.4736"
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="circle172-4-3-6" />
<text
xml:space="preserve"
x="5954.9976"
y="4178.8267"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-8-5-9"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3503-3-0-2">inactive</tspan></text>
<rect
x="1019.4597"
y="4821.9668"
width="1487.6132"
height="469.84174"
rx="0"
style="fill:#dfdfdf;stroke:#000000;stroke-width:4.0044775;stroke-linecap:butt;stroke-linejoin:miter"
id="rect150-8-0" />
<text
xml:space="preserve"
x="1642.8574"
y="5136.835"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-1-4"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3495-6-41-8">CR3 register</tspan></text>
<ellipse
ry="46.999996"
rx="46.999992"
cx="2349.6458"
cy="5076.04"
style="fill:#969696;fill-opacity:1;stroke:#969696;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="circle172-4-3-2" />
<path
style="fill:none;fill-rule:evenodd;stroke:#969696;stroke-width:9.42606354px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 2349.6459,5073.5559 359.3939,0 0,777.3949 255.3589,0"
id="path4612"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:9.51690483px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 4118.0344,4723.1182 672.1066,0 0,1137.6237 494.8846,0"
id="path4614"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:9.51690578px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 6398.2284,4730.6471 434.6959,0 0,1347.5425 -4005.8897,0 0,-197.3547 140.4403,0"
id="path4641"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<polygon
points="3308,6614 3150,6566 3150,6661 3150,6661 "
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="polygon232-2-7-7-1-1-7"
transform="translate(-214.18472,-748.49788)" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,45 +1,38 @@
+++
title = "Remap the Kernel"
date = "2016-01-01"
weight = 7
path = "remap-the-kernel"
aliases = ["remap-the-kernel.html"]
date = 2016-01-01
template = "edition-1/page.html"
[extra]
updated = "2016-03-06"
+++
In this post we will create a new page table to map the kernel sections correctly. Therefor we will extend the paging module to support modifications of _inactive_ page tables as well. Then we will switch to the new table and secure our kernel stack by creating a guard page.
In this post we will create a new page table to map the kernel sections correctly. Therefore we will extend the paging module to support modifications of _inactive_ page tables as well. Then we will switch to the new table and secure our kernel stack by creating a guard page.
<!--more-->
<!-- more -->
As always, you can find the source code on [Github]. Don't hesitate to file issues there if you have any problems or improvement suggestions. There is also a comment section at the end of this page. Note that this post requires a current Rust nightly.
As always, you can find the source code on [GitHub]. Don't hesitate to file issues there if you have any problems or improvement suggestions. There is also a comment section at the end of this page. Note that this post requires a current Rust nightly.
[Github]: https://github.com/phil-opp/blog_os/tree/remap_the_kernel
_Updates_:
- The `AreaFrameAllocator` [was broken][areaframeallocator broken] after switching to a new table. To fix this, we added the [Fixing the Frame Allocator] section and updated the [linker script][linker script update]. For a complete set of changes see [#131] and [this diff][#131-changes].
- We [fixed a bug][#141] in iterating over a section's frames. Therefor we added a `Frame::range_inclusive` function and updated the [Remapping the Kernel section]. For a complete list of changes check out [this diff][#141-changes].
[areaframeallocator broken]: https://github.com/phil-opp/blog_os/issues/126
[Fixing the Frame Allocator]: #fixing-the-frame-allocator
[linker script update]: #page-align-sections
[#131]: https://github.com/phil-opp/blog_os/pull/131
[#131-changes]: https://github.com/phil-opp/blog_os/compare/75aa669cdbb427c7bf0485c68692d243065cd3e9...635f7d3f9dced752f84d429e1d51f5c2b29854e3
[#141]: https://github.com/phil-opp/blog_os/pull/141
[Remapping the Kernel section]: #remapping-the-kernel
[#141-changes]: https://github.com/phil-opp/blog_os/commit/03ed3ce9a0758bf0d14a13144892c731216e25c6
[GitHub]: https://github.com/phil-opp/blog_os/tree/first_edition_post_7
## Motivation
In the [previous post], we had a strange bug in the `unmap` function. Its reason was a silent stack overflow, which corrupted the page tables. Fortunately, our kernel stack is right above the page tables so that we noticed the overflow relatively quickly. This won't be the case when we add threads with new stacks in the future. Then a silent stack overflow could overwrite some data without us noticing. But eventually some completely unrelated function fails because a variable changed its value.
[previous post]: {{% relref "2015-12-09-modifying-page-tables.md" %}}
[previous post]: @/edition-1/posts/06-page-tables/index.md
As you can imagine, these kinds of bugs are horrendous to debug. For that reason we will create a new hierarchical page table in this post, which has _guard page_ below the stack. A guard page is basically an unmapped page that causes a page fault when accessed. Thus we can catch stack overflows right when they happen.
Also, we will use the [information about kernel sections] to map the various sections individually instead of blindly mapping the first gigabyte. To improve safety even further, we will set the correct page table flags for the various sections. Thus it won't be possible to modify the contents of `.text` or to execute code from `.data` anymore.
[information about kernel sections]: {{% relref "2015-11-15-allocating-frames.md#kernel-elf-sections" %}}
[information about kernel sections]: @/edition-1/posts/05-allocating-frames/index.md#kernel-elf-sections
## Preparation
There are many things that can go wrong when we switch to a new table. Therefore it's a good idea to [set up a debugger][set up gdb]. You should not need it when you follow this post, but it's good to know how to debug a problem when it occurs[^fn-debug-notes].
[set up gdb]: {{% relref "set-up-gdb.md" %}}
[^fn-debug-notes]: For this post the most useful GDB command is probably `p/x *((long int*)0xfffffffffffff000)@512`. It prints all entries of the recursively mapped P4 table by interpreting it as an array of 512 long ints (the `@512` is GDB's array syntax). Of course you can also print other tables by adjusting the address.
[set up gdb]: @/edition-1/extra/set-up-gdb/index.md
We also update the `Page` and `Frame` types to make our lives easier. The `Page` struct gets some derived traits:
@@ -52,9 +45,11 @@ pub struct Page {
}
```
By making it [Copy][Copy trait], we can still use it after passing it to functions such as `map_to`. We also make the `Page::containing_address` public (if it isn't already).
[Copy trait]: https://doc.rust-lang.org/nightly/core/marker/trait.Copy.html
The `Frame` type gets a `clone` method too, but it does not implement the [Clone trait]:
[Clone trait]: https://doc.rust-lang.org/nightly/core/clone/trait.Clone.html
```rust
@@ -76,9 +71,7 @@ We can't do that for a `Frame`. If we wanted to be sure that a given frame is un
## Recap: The Paging Module
This post builds upon the post about [page tables][previous post], so let's start by quickly recapitulating what we've done there.
We created a `memory::paging` module, which reads and modifies the hierarchical page table through recursive mapping. The owner of the active P4 table and thus all subtables is an `ActivePageTable`[^fn-apt-renamed] struct, which must be instantiated only once.
[^fn-apt-renamed]: It was renamed in [#88](https://github.com/phil-opp/blog_os/pull/88). The previous name was `RecursivePageTable`.
We created a `memory::paging` module, which reads and modifies the hierarchical page table through recursive mapping. The owner of the active P4 table and thus all subtables is an `ActivePageTable` struct, which must be instantiated only once.
The `ActivePageTable` struct provides the following interface:
@@ -287,7 +280,8 @@ pub fn map_table_frame(&mut self,
}
```
This function interprets the given frame as a page table frame and returns a `Table` reference. We return a table of level 1 because it [forbids calling the `next_table` methods][some clever solution]. Calling `next_table` must not be possible since it's not a page of the recursive mapping. To be able to return a `Table<Level1>`, we need to make the `Level1` enum in `memory/paging/table.rs` public.
[some clever solution]: {{% relref "2015-12-09-modifying-page-tables.md#some-clever-solution" %}}
[some clever solution]: @/edition-1/posts/06-page-tables/index.md#some-clever-solution
The `unsafe` block is safe since the `VirtualAddress` returned by the `map` function is always valid and the type cast just reinterprets the frame's content.
@@ -333,7 +327,8 @@ impl InactivePageTable {
}
```
We added two new arguments, `active_table` and `temporary_page`. We need an [inner scope] to ensure that the `table` variable is dropped before we try to unmap the temporary page again. This is required since the `table` variable exclusively borrows `temporary_page` as long as it's alive.
[inner scope]: http://rustbyexample.com/variable_bindings/scope.html
[inner scope]: https://doc.rust-lang.org/rust-by-example/variable_bindings/scope.html
Now we are able to create valid inactive page tables, which are zeroed and recursively mapped. But we still can't modify them. To resolve this problem, we need to look at recursive mapping again.
@@ -342,11 +337,11 @@ Recursive mapping works by mapping the last P4 entry to the P4 table itself. Thu
For example, accessing a P3 table requires lopping three times:
![access active P3 table through recursive mapping](/images/recursive_mapping_access_p3.svg)
![access active P3 table through recursive mapping](recursive_mapping_access_p3.svg)
We can use the same mechanism to access inactive tables. The trick is to change the recursive mapping of the active P4 table to point to the inactive P4 table:
![access inactive P3 table through recursive mapping](/images/recursive_mapping_access_p3_inactive_table.svg)
![access inactive P3 table through recursive mapping](recursive_mapping_access_p3_inactive_table.svg)
Now the inactive table can be accessed exactly as the active table, even the magic addresses are the same. This allows us to use the `ActivePageTable` interface and the existing mapping methods for inactive tables, too. Note that everything besides the recursive mapping continues to work exactly as before since we've never changed the active table in the CPU.
@@ -359,12 +354,11 @@ pub fn with<F>(&mut self,
f: F)
where F: FnOnce(&mut ActivePageTable)
{
use x86::tlb;
let flush_tlb = || unsafe { tlb::flush_all() };
use x86_64::instructions::tlb;
// overwrite recursive mapping
self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE);
flush_tlb();
tlb::flush_all();
// execute f in the new context
f(self);
@@ -373,12 +367,13 @@ pub fn with<F>(&mut self,
}
```
It overwrites the 511th P4 entry and points it to the inactive table frame. Then it flushes the [translation lookaside buffer (TLB)][TLB], which still contains some old translations. We need to flush all pages that are part of the recursive mapping, so the easiest way is to flush the TLB completely.
[TLB]: http://wiki.osdev.org/TLB
[TLB]: https://wiki.osdev.org/TLB
Now that the recursive mapping points to the given inactive table, we execute the closure in the new context. The closure can call all active table methods such as `translate` or `map_to`. It could even call `with` again and chain another inactive table! Wait… that would not work:
![access inactive P3 table through recursive mapping](/images/recursive_mapping_access_p1_invalid_chaining.svg)
![access inactive P3 table through recursive mapping](recursive_mapping_access_p1_invalid_chaining.svg)
Here the closure called `with` again and thus changed the recursive mapping of the inactive table to point to a second inactive table. Now we want to modify the P1 of the _second_ inactive table, but instead we land on the P1 of the _first_ inactive table since we never follow the pointer to the second table. Only when modifying the P2, P3, or P4 table we really access the second inactive table. This inconsistency would break our mapping functions completely.
@@ -453,6 +448,7 @@ impl ActivePageTable {
}
```
The [Deref] and [DerefMut] implementations allow us to use the `ActivePageTable` exactly as before, for example we still can call `map_to` on it (because of [deref coercions]). But the closure called in the `with` function can no longer invoke `with` again. The reason is that we changed the type of the generic `F` parameter a bit: Instead of an `ActivePageTable`, the closure just gets a `Mapper` as argument.
[Deref]: https://doc.rust-lang.org/nightly/core/ops/trait.Deref.html
[DerefMut]: https://doc.rust-lang.org/nightly/core/ops/trait.DerefMut.html
[deref coercions]: https://doc.rust-lang.org/nightly/book/deref-coercions.html
@@ -463,24 +459,24 @@ Right now, the `with` function overwrites the recursive mapping and calls the cl
To backup the physical P4 frame of the active table, we can either read it from the 511th P4 entry (before we change it) or from the CR3 control register directly. We will do the latter as it should be faster and we already have a external crate that makes it easy:
```rust
use x86::controlregs;
use x86_64::registers::control_regs;
let backup = Frame::containing_address(
unsafe { controlregs::cr3() } as usize
unsafe { control_regs::cr3() } as usize
);
```
Why is it unsafe? Because reading the CR3 register leads to a CPU exception if the processor is not running in kernel mode ([Ring 0]). But this code will always run in kernel mode, so the `unsafe` block is completely safe here.
[Ring 0]: http://wiki.osdev.org/Security#Low-level_Protection_Mechanisms
[Ring 0]: https://wiki.osdev.org/Security#Low-level_Protection_Mechanisms
Now that we have a backup of the original P4 frame, we need a way to restore it after the closure has run. So we need to somehow modify the 511th entry of the original P4 frame, which is still the active table in the CPU. But we can't access it because the recursive mapping now points to the inactive table:
![it's not possible to access the original P4 through recursive mapping anymore](/images/recursive_mapping_inactive_table_scheme.svg)
![it's not possible to access the original P4 through recursive mapping anymore](recursive_mapping_inactive_table_scheme.svg)
It's just not possible to access the active P4 entry in 4 steps, so we can't reach it through the 4-level page table.
We could try to overwrite the recursive mapping of the _inactive_ P4 table and point it back to the original P4 frame:
![cyclic map active and inactive P4 tables](/images/cyclic_mapping_inactive_tables.svg)
![cyclic map active and inactive P4 tables](cyclic_mapping_inactive_tables.svg)
Now we can reach the active P4 entry in 4 steps and could restore the original mapping in the active table. But this hack has a drawback: The inactive table is now invalid since it is no longer recursive mapped. We would need to fix it by using a temporary page again (as above).
@@ -496,26 +492,26 @@ pub fn with<F>(&mut self,
f: F)
where F: FnOnce(&mut Mapper)
{
use x86::{controlregs, tlb};
let flush_tlb = || unsafe { tlb::flush_all() };
use x86_64::instructions::tlb;
use x86_64::registers::control_regs;
{
let backup = Frame::containing_address(
unsafe { controlregs::cr3() } as usize);
control_regs::cr3().0 as usize);
// map temporary_page to current p4 table
let p4_table = temporary_page.map_table_frame(backup.clone(), self);
// overwrite recursive mapping
self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE);
flush_tlb();
tlb::flush_all();
// execute f in the new context
f(self);
// restore recursive mapping to original p4 table
p4_table[511].set(backup, PRESENT | WRITABLE);
flush_tlb();
tlb::flush_all();
}
temporary_page.unmap(self);
@@ -557,7 +553,8 @@ pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
First, we create a temporary page at page number `0xcafebabe`. We could use `0xdeadbeaf` or `0x123456789` as well, as long as the page is unused. The `active_table` and the `new_table` are created using their constructor functions.
Then we use the `with` function to temporary change the recursive mapping and execute the closure as if the `new_table` were active. This allows us to map the sections in the new table without changing the active mapping. To get the kernel sections, we use the [Multiboot information structure].
[Multiboot information structure]: {{% relref "2015-11-15-allocating-frames.md#the-multiboot-information-structure" %}}
[Multiboot information structure]: @/edition-1/posts/05-allocating-frames/index.md#the-multiboot-information-structure
Let's resolve the above `TODO` by identity mapping the sections:
@@ -569,7 +566,7 @@ for section in elf_sections_tag.sections() {
// section is not loaded to memory
continue;
}
assert!(address % PAGE_SIZE == 0,
assert!(section.start_address() % PAGE_SIZE == 0,
"sections need to be page aligned");
println!("mapping section at addr: {:#x}, size: {:#x}",
@@ -579,7 +576,7 @@ for section in elf_sections_tag.sections() {
let start_frame = Frame::containing_address(section.start_address());
let end_frame = Frame::containing_address(section.end_address() - 1);
for frame in Frame::range_inclusive(start_frame, end_frame)
for frame in Frame::range_inclusive(start_frame, end_frame) {
mapper.identity_map(frame, flags, allocator);
}
}
@@ -625,7 +622,7 @@ impl Iterator for FrameIter {
Instead of creating a custom iterator, we could have used the [Range] struct of the standard library. But it requires that we implement the [One] and [Add] traits for `Frame`. Then every module could perform arithmetic operations on frames, for example `let frame3 = frame1 + frame2`. This would violate our safety invariants because `frame3` could be already in use. The `range_inclusive` function does not have these problems because it is only available inside the `memory` module.
[Range]: https://doc.rust-lang.org/nightly/core/ops/struct.Range.html
[One]: https://doc.rust-lang.org/nightly/core/num/trait.One.html
[One]: https://doc.rust-lang.org/1.10.0/core/num/trait.One.html
[Add]: https://doc.rust-lang.org/nightly/core/ops/trait.Add.html
### Page Align Sections
@@ -643,13 +640,16 @@ SECTIONS {
}
```
The `.` is the “current location counter” and represents the current virtual address. At the beginning of the `SECTIONS` tag we set it to `1M`, so our kernel starts at 1MiB. We use the [ALIGN][linker align] function to align the current location counter to the next `4K` boundary (`4K` is the page size). Thus the end of the `.text` section and the beginning of the next section are page aligned.
[linker align]: http://www.math.utah.edu/docs/info/ld_3.html#SEC12
[linker align]: https://www.math.utah.edu/docs/info/ld_3.html#SEC12
To put all sections on their own page, we add the `ALIGN` statement to all of them:
```
/* src/arch/x86_64/linker.ld */
ENTRY(start)
SECTIONS {
. = 1M;
@@ -679,6 +679,18 @@ SECTIONS {
. = ALIGN(4K);
}
.got :
{
*(.got)
. = ALIGN(4K);
}
.got.plt :
{
*(.got.plt)
. = ALIGN(4K);
}
.data.rel.ro : ALIGN(4K) {
*(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*)
. = ALIGN(4K);
@@ -693,7 +705,7 @@ SECTIONS {
Instead of page aligning the `.multiboot_header` section, we merge it into the `.rodata` section. That way, we don't waste a whole page for the few bytes of the Multiboot header. We could merge it into any section, but `.rodata` fits best because it has the same flags (neither writable nor executable). The Multiboot header still needs to be at the beginning of the file, so `.rodata` must be our first section now.
### Testing it
Time to test it! We reexport the `remap_the_kernel` function from the memory module and call it from `rust_main`:
Time to test it! We re-export the `remap_the_kernel` function from the memory module and call it from `rust_main`:
```rust
// in src/memory/mod.rs
@@ -755,21 +767,24 @@ We do this in a new `ActivePageTable::switch` method:
// in `impl ActivePageTable` in src/memory/paging/mod.rs
pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
use x86::controlregs;
use x86_64::PhysicalAddress;
use x86_64::registers::control_regs;
let old_table = InactivePageTable {
p4_frame: Frame::containing_address(
unsafe { controlregs::cr3() } as usize
control_regs::cr3().0 as usize
),
};
unsafe {
controlregs::cr3_write(new_table.p4_frame.start_address() as u64);
control_regs::cr3_write(PhysicalAddress(
new_table.p4_frame.start_address() as u64));
}
old_table
}
```
This function activates the given inactive table and returns the previous active table as a `InactivePageTable`. We don't need to flush the TLB here, as the CPU does it automatically when the P4 table is switched. In fact, the `tlb::flush_all` function, which we used above, does nothing more than [reloading the CR3 register].
[reloading the CR3 register]: https://github.com/gz/rust-x86/blob/master/src/tlb.rs#L19
[reloading the CR3 register]: https://docs.rs/x86_64/0.1.2/src/x86_64/instructions/tlb.rs.html#11-14
Now we are finally able to switch to the new table. We do it by adding the following lines to our `remap_the_kernel` function:
@@ -789,8 +804,7 @@ Let's cross our fingers and run it…
… and it fails with a boot loop.
### Debugging
A QEMU boot load indicates that some CPU exception occured. We can see all thrown CPU exception by starting QEMU with `-d int` (as described [here][qemu debugging]):
[qemu debugging]: {{% relref "2015-09-02-set-up-rust.md#debugging" %}}
A QEMU boot loop indicates that some CPU exception occurred. We can see all thrown CPU exception by starting QEMU with `-d int`:
```bash
> qemu-system-x86_64 -d int -no-reboot -cdrom build/os-x86_64.iso
@@ -803,26 +817,27 @@ check_exception old: 0xffffffff new 0xe
These lines are the important ones. We can read many useful information from them:
- `v=0e`: An exception with number `0xe` occurred, which is a page fault according to the [OSDev Wiki][osdev exception overview].
[osdev exception overview]: http://wiki.osdev.org/Exceptions
[page fault]: http://wiki.osdev.org/Exceptions#Page_Fault
- `e=0002`: The CPU set an [error code][page fault error code], which tells us why the exception occurred. The `0x2` bit tells us that it was caused by a write operation. And since the `0x1` bit is not set, the target page was not present.
[page fault error code]: http://wiki.osdev.org/Exceptions#Error_code
- `IP=0008:000000000010ab97` or `pc=000000000010ab97`: The program counter register tells us that the exception occurred when the CPU tried to execute the instruction at `0x10ab97`. We can disassemble this address to see the corresponding function. The `0008:` prefix in `IP` indicates the code [GDT segment].
[GDT segment]: {{% relref "2015-08-25-entering-longmode.md#loading-the-gdt" %}}
- `SP=0010:00000000001182d0`: The stack pointer was `0x1182d0` (the `0010:` prefix indicates the data [GDT segment]). This tells us if it the stack overflowed.
- `CR2=00000000000b8f00`: Finally the most useful register. It tells us which virtual address caused the page fault. In our case it's `0xb8f00`, which is part of the [VGA text buffer].
[VGA text buffer]: {{% relref "2015-10-23-printing-to-screen.md#the-vga-text-buffer" %}}
[osdev exception overview]: https://wiki.osdev.org/Exceptions
[page fault]: https://wiki.osdev.org/Exceptions#Page_Fault
[page fault error code]: https://wiki.osdev.org/Exceptions#Error_code
[GDT segment]: @/edition-1/posts/02-entering-longmode/index.md#loading-the-gdt
[VGA text buffer]: @/edition-1/posts/04-printing-to-screen/index.md#the-vga-text-buffer
So let's find out which function caused the exception:
```
objdump -d build/kernel-x86_64.bin | grep -B100 "10ab97"
```
We disassemble our kernel and search for `10ab97`. The `-B100` option prints the 100 preceeding lines too. The output tells us the responsible function:
We disassemble our kernel and search for `10ab97`. The `-B100` option prints the 100 preceding lines too. The output tells us the responsible function:
```
...
@@ -833,6 +848,7 @@ We disassemble our kernel and search for `10ab97`. The `-B100` option prints the
10ab97: 66 89 14 48 mov %dx,(%rax,%rcx,2)
```
The reason for the cryptical function name is Rust's [name mangling]. But we can identity the `vga_buffer::Writer::write_byte` function nonetheless.
[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
So the reason for the page fault is that the `write_byte` function tried to write to the VGA text buffer at `0xb8f00`. Of course this provokes a page fault: We forgot to identity map the VGA buffer in the new page table.
@@ -866,7 +882,7 @@ Now we should see the `NEW TABLE!!!` message (and also the `It did not crash!` l
### Fixing the Frame Allocator
The same problem as above occurs when we try to use our [AreaFrameAllocator] again. Try to add the following to `rust_main` after switching to the new table:
[AreaFrameAllocator]: http://os.phil-opp.com/allocating-frames.html#the-allocator
[AreaFrameAllocator]: @/edition-1/posts/05-allocating-frames/index.md#the-allocator
```rust
// in src/lib.rs
@@ -963,20 +979,22 @@ pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
But when we test it now, we get a page fault again. We can use the same technique as above to get the responsible function. I won't bother you with the QEMU output and just tell you the results:
This time the responsible function is `controlregs::cr3_write()` itself. From the [error code][page fault error code] we learn that it was a page protection violation and caused by “reading a 1 in a reserved field”. So the page table had some reserved bit set that should be always 0. It must be the `NO_EXECUTE` flag, since it's the only new bit that we set in the page table.
This time the responsible function is `control_regs::cr3_write()` itself. From the [error code][page fault error code] we learn that it was a page protection violation and caused by “reading a 1 in a reserved field”. So the page table had some reserved bit set that should be always 0. It must be the `NO_EXECUTE` flag, since it's the only new bit that we set in the page table.
### The NXE Bit
The reason is that the `NO_EXECUTE` bit must only be used when the `NXE` bit in the [Extended Feature Enable Register] \(EFER) is set. That register is similar to Rust's feature gating and can be used to enable all sorts of advanced CPU features. Since the `NXE` bit is off by default, we caused a page fault when we added the `NO_EXECUTE` bit to the page table.
[Extended Feature Enable Register]: https://en.wikipedia.org/wiki/Control_register#EFER
So we need to enable the `NXE` bit. Therefor we use Gerd Zellweger's awesome [x86][rust-x86] crate again:
[rust-x86]: https://github.com/gz/rust-x86
So we need to enable the `NXE` bit. For that we use the [x86_64 crate] again:
[x86_64 crate]: https://docs.rs/x86_64
```rust
// in lib.rs
fn enable_nxe_bit() {
use x86::msr::{IA32_EFER, rdmsr, wrmsr};
use x86_64::registers::msr::{IA32_EFER, rdmsr, wrmsr};
let nxe_bit = 1 << 11;
unsafe {
@@ -996,10 +1014,9 @@ Right now, we are still able to modify the `.code` and `.rodata` sections, even
// in lib.rs
fn enable_write_protect_bit() {
use x86::controlregs::{cr0, cr0_write};
use x86_64::registers::control_regs::{cr0, cr0_write, Cr0};
let wp_bit = 1 << 16;
unsafe { cr0_write(cr0() | wp_bit) };
unsafe { cr0_write(cr0() | Cr0::WRITE_PROTECT) };
}
```
The `cr0` functions are unsafe because accessing the `CR0` register is only allowed in kernel mode.
@@ -1010,7 +1027,8 @@ If we haven't forgotten to set the `WRITABLE` flag somewhere, it should still wo
The final step is to create a guard page for our kernel stack.
The decision to place the kernel stack right above the page tables was already useful to detect a silent stack overflow in the [previous post][silent stack overflow]. Now we profit from it again. Let's look at our assembly `.bss` section again to understand why:
[silent stack overflow]: {{% relref "2015-12-09-modifying-page-tables.md#translate" %}}
[silent stack overflow]: @/edition-1/posts/06-page-tables/index.md
```nasm
; in src/arch/x86_64/boot.asm
@@ -1024,7 +1042,7 @@ p3_table:
p2_table:
resb 4096
stack_bottom:
resb 4096 * 2
resb 4096 * 4
stack_top:
```
@@ -1070,7 +1088,11 @@ Unfortunately stack probes require compiler support. They already work on Window
## What's next?
Now that we have a (mostly) safe kernel stack and a working page table module, we can add a virtual memory allocator. The [next post] will explore Rust's allocator API and create a very basic allocator. At the end of that post, we will be able to use Rust's allocation and collections types such as [Box], [Vec], or even [BTreeMap].
[next post]: {{% relref "2016-04-11-kernel-heap.md" %}}
[next post]: @/edition-1/posts/08-kernel-heap/index.md
[Box]: https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html
[Vec]: https://doc.rust-lang.org/nightly/collections/vec/struct.Vec.html
[BTreeMap]: https://doc.rust-lang.org/nightly/collections/struct.BTreeMap.html
[Vec]: https://doc.rust-lang.org/1.10.0/collections/vec/struct.Vec.html
[BTreeMap]: https://doc.rust-lang.org/1.10.0/collections/btree_map/struct.BTreeMap.html
## Footnotes
[^fn-debug-notes]: For this post the most useful GDB command is probably `p/x *((long int*)0xfffffffffffff000)@512`. It prints all entries of the recursively mapped P4 table by interpreting it as an array of 512 long ints (the `@512` is GDB's array syntax). Of course you can also print other tables by adjusting the address.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1,819 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="900.00409"
height="530"
viewBox="-2141 2141 12027.89 7032.1014"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="recursive_mapping_access_p3.svg">
<metadata
id="metadata370">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs368" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="998"
id="namedview366"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="2.7755576e-17"
fit-margin-bottom="0"
inkscape:zoom="1"
inkscape:cx="236.56561"
inkscape:cy="267.91265"
inkscape:window-x="1080"
inkscape:window-y="568"
inkscape:window-maximized="1"
inkscape:current-layer="g4"
units="in" />
<g
style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="g4"
transform="translate(-1087.0637,717.51407)">
<polyline
points="3365,2598 3365,3070"
id="polyline10"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3189,2598 3189,3070"
id="polyline12"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3012,2598 3012,3070"
id="polyline14"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2834,2598 2834,3070"
id="polyline16"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2657,2598 2657,3070"
id="polyline18"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2480,2598 2480,3070"
id="polyline20"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2303,2598 2303,3070"
id="polyline22"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2125,2456 2125,3070"
id="polyline24"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1948,2598 1948,3070"
id="polyline26"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1772,2598 1772,3070"
id="polyline28"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1594,2598 1594,3070"
id="polyline30"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1417,2598 1417,3070"
id="polyline32"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1239,2598 1239,3070"
id="polyline34"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1063,2598 1063,3070"
id="polyline36"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="886,2598 886,3070"
id="polyline38"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="708,2456 708,3070"
id="polyline40"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3543,2456 3543,3070"
id="polyline74"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="-2125,2598 3543,2598"
id="polyline76"
transform="matrix(0.70622791,0,0,1.3955346,455.54989,-1956.6141)" />
<polyline
points="3543,3070 -1948,3070 -2125,3070"
id="polyline78"
transform="matrix(0.70351457,0,0,1.3955346,465.16321,-1956.6141)" />
<polyline
points="9035,2598 9035,3070"
id="polyline80"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8858,2598 8858,3070"
id="polyline82"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8681,2598 8681,3070"
id="polyline84"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8503,2598 8503,3070"
id="polyline86"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8326,2598 8326,3070"
id="polyline88"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8150,2598 8150,3070"
id="polyline90"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7972,2598 7972,3070"
id="polyline92"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7795,2456 7795,3070"
id="polyline94"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7617,2598 7617,3070"
id="polyline96"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7441,2598 7441,3070"
id="polyline98"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7264,2598 7264,3070"
id="polyline100"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7086,2598 7086,3070"
id="polyline102"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6909,2598 6909,3070"
id="polyline104"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6732,2598 6732,3070"
id="polyline106"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6555,2598 6555,3070"
id="polyline108"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6377,2456 6377,3070"
id="polyline110"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6200,2598 6200,3070"
id="polyline112"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6024,2598 6024,3070"
id="polyline114"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5846,2598 5846,3070"
id="polyline116"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5669,2598 5669,3070"
id="polyline118"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5491,2598 5491,3070"
id="polyline120"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5315,2598 5315,3070"
id="polyline122"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5138,2598 5138,3070"
id="polyline124"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4960,2409 4960,3070"
id="polyline126"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4783,2598 4783,3070"
id="polyline128"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4606,2598 4606,3070"
id="polyline130"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4429,2598 4429,3070"
id="polyline132"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4251,2598 4251,3070"
id="polyline134"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4074,2598 4074,3070"
id="polyline136"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3898,2598 3898,3070"
id="polyline138"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3720,2598 3720,3070"
id="polyline140"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,2456 9212,3070"
id="polyline142"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3543,2598 9212,2598"
id="polyline144"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,3070 3720,3070 0,3070"
id="polyline146"
transform="matrix(1.3047439,0,0,1.3955346,-1051.0007,-1956.6141)" />
<rect
x="4021.6787"
y="4311.5088"
width="1668.8131"
height="3296.2527"
rx="0"
style="fill:#dfdfdf;stroke-width:11.23412323"
id="rect150" />
<polyline
points="3118,3590 2834,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline178"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1322,3590 1039,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline180"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4913,3590 4629,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline184"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6519,3590 6236,3779"
style="stroke:#0000ff"
id="polyline186"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8314,3590 8031,3779"
style="stroke:#0000ff"
id="polyline188"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,3070 9070,3307 8314,3307 8173,3543 8031,3307 7228,3307 7086,3070"
style="stroke:#0000ff"
id="polyline204"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3898,3070 4015,3307 4629,3307 4771,3543 4913,3307 5385,3307 5491,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline206"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5491,3070 5622,3307 6236,3307 6377,3543 6519,3307 6909,3307 7086,3070"
style="stroke:#0000ff"
id="polyline208"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2303,3070 2409,3307 2834,3307 2976,3543 3118,3307 3779,3307 3898,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline210"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="708,3070 850,3307 1039,3307 1181,3543 1322,3307 2173,3307 2303,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline212"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<g
style="fill:#000000;stroke-width:0"
id="g242"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)">
<text
xml:space="preserve"
x="5546.7881"
y="6876.4409"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-5">0</tspan></text>
<text
xml:space="preserve"
x="3507"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text246"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">32</text>
<text
xml:space="preserve"
x="2161"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text248"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">39</text>
<text
xml:space="preserve"
x="2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text250"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">40</text>
<text
xml:space="preserve"
x="744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">47</text>
<text
xml:space="preserve"
x="672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text254"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text256"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="-744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text258"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text260"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="9176"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text262"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">0</text>
<text
xml:space="preserve"
x="7759"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text264"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">8</text>
<text
xml:space="preserve"
x="6342"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text266"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">16</text>
<text
xml:space="preserve"
x="4924"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text268"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">24</text>
<text
xml:space="preserve"
x="3579"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text270"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">31</text>
<text
xml:space="preserve"
x="6413"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text272"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">15</text>
<text
xml:space="preserve"
x="7830"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text274"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">7</text>
<text
xml:space="preserve"
x="4996"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text276"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">23</text>
<g
transform="matrix(0,-1,1,0,8976,6614)"
id="g282" />
<text
xml:space="preserve"
x="-2125"
y="2314"
font-style="normal"
font-weight="normal"
font-size="152"
id="text290"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<g
transform="matrix(0,-1,1,0,4916.9545,5254.403)"
id="g306">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3874"
y="3968"
font-style="normal"
font-weight="normal"
font-size="152"
id="text318"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
xml:space="preserve"
x="4862.9551"
y="4397.5566"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3503">P4 table</tspan></text>
<text
x="2031"
y="5622"
font-style="normal"
font-weight="normal"
font-size="152"
id="text346"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="3165"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text350"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1;">9</text>
<text
x="1370"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text352"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1;">9</text>
<text
x="1370"
y="6708"
font-style="normal"
font-weight="normal"
font-size="152"
id="text354"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff" />
<text
x="4960"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text356"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1;">9</text>
<text
x="6566"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text358"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="8362"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text360"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">12</text>
<text
x="1181"
y="7532.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text364"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
x="1946.0945"
y="6998.52"
font-style="normal"
font-weight="normal"
font-size="152"
id="text344-8-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.75857544px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:217.16923523px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3493-3-2" />
</text>
<rect
style="fill:none;stroke:#000000;stroke-width:7.99999952;stroke-linecap:butt;stroke-linejoin:miter"
x="4294.9473"
y="4493.6152"
width="1181"
height="471.99994"
rx="0"
id="rect162-5" />
<circle
cx="5335.9546"
cy="4720.2134"
style="fill:#008200;stroke:#008200;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
id="circle172-4"
r="46.999996" />
<text
xml:space="preserve"
x="4815.9546"
y="4773.6704"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6">P4 entry</tspan></text>
<text
xml:space="preserve"
x="4925.6357"
y="7173.5298"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-0"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6-4">Recursive</tspan></text>
<text
xml:space="preserve"
x="4925.6357"
y="7440.8149"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-0-9"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6-4-4">Mapping</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:6.53430033;stroke-linecap:butt;stroke-linejoin:miter"
x="4296.5396"
y="5560.2471"
width="1182.4656"
height="314.50067"
rx="0"
id="rect162-5-1" />
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-0.99999994,0.99999994,0,4915.3734,6277.1653)"
id="g306-2">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308-3"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3097.1609"
y="2954.5652"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:318.2364502px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
inkscape:transform-center-x="-789.14735"
inkscape:transform-center-y="1300.106"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:318.2364502px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3503-4">111111111111111111111111111</tspan></text>
<rect
x="8208.377"
y="4073.4419"
width="691.0863"
height="3268.5144"
rx="0"
style="fill:#dfdfdf;stroke:#000000;stroke-width:7.85773897;stroke-linecap:butt;stroke-linejoin:miter"
id="rect8" />
<rect
x="8208.377"
y="5474.9399"
width="691.0863"
height="233.25354"
rx="0"
style="fill:#dfdfdf;stroke:#000000;stroke-width:7.85773897;stroke-linecap:butt;stroke-linejoin:miter"
id="rect158" />
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-0.98836234,0.97611052,0,9106.1205,5822.055)"
id="g286">
<text
xml:space="preserve"
x="96.892052"
y="38.756821"
font-style="normal"
font-weight="normal"
font-size="152"
id="text288"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3509">P3 table </tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:14.53380773;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 2308.9448,-2797.8507 -483.0169,0 0,-2544.6425 -1879.786585,0 0,339.1222"
id="path8874"
inkscape:connector-curvature="0" />
</g>
<text
xml:space="preserve"
x="4809.9756"
y="5774.4951"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-5"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46392822px;stroke-width:0"
id="tspan3495-6-7">P4 entry</tspan></text>
<ellipse
ry="46.999996"
rx="46.999992"
cx="5336.855"
cy="5714.1816"
style="fill:#0000ff;stroke:#0000ff;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter"
id="circle172-4-4" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:9.55735683px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 5392.0276,5712.0004 1512.0496,0 0,1631.4957 1257.8109,0"
id="path9464"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:9.51690483px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 8173.2452,3542.5202 0,364.8071 -584.0141,0 0,1802.0952 528.0052,0"
id="path9466"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
x="5610.3569"
y="4990.1772"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5">511</tspan></text>
</g>
<polygon
points="3308,6614 3150,6566 3150,6661 3150,6661 "
style="fill:#008200;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;fill-opacity:1;stroke-opacity:1"
id="polygon232-2"
transform="matrix(1.4130509,0,0,1.3955346,-646.4618,-1622.6914)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.76697159px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 5574.5569,4637.287 719.9709,0 0,3526.7653 -2765.702,0 0,-560.545 294.8212,0"
id="path5354"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.52740288px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 3843.9848,5007.8363 -4223.58417,0 0,-2024.2908"
id="path5356"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.65159035px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 2156.7076,2986.8221 0,1988.2634 1691.863,0"
id="path5358"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.78581619px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 4696.351,2980.052 0,497.5653 -1975.7645,0 0,1464.6642 1128.3337,0"
id="path5360"
inkscape:connector-curvature="0" />
<polygon
points="3150,6661 3308,6614 3150,6566 3150,6661 "
style="fill:#0000ff;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polygon232-2-7"
transform="matrix(1.4130509,0,0,1.3955346,-625.83944,-2988.2046)" />
<polygon
points="3150,6661 3150,6661 3308,6614 3150,6566 "
style="fill:#0000ff;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polygon232-2-7-3"
transform="matrix(1.4130509,0,0,1.3955346,4891.7749,-3219.444)" />
<polygon
points="3150,6661 3150,6661 3308,6614 3150,6566 "
style="fill:#0000ff;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polygon232-2-7-3-5"
transform="matrix(1.4130509,0,0,1.3955346,4896.989,-940.27671)" />
<polygon
points="3150,6566 3150,6661 3150,6661 3308,6614 "
style="fill:#008200;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;fill-opacity:1;stroke-opacity:1"
id="polygon232-2-7-7"
transform="matrix(1.4130509,0,0,1.3955346,-628.09888,-4256.4264)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -0,0 +1,936 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="900.00409"
height="530.5"
viewBox="-2141 2141 12027.89 7038.7354"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="recursive_mapping_access_p3_inactive_table.svg">
<metadata
id="metadata370">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs368" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="998"
id="namedview366"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="1"
inkscape:zoom="1"
inkscape:cx="466.92372"
inkscape:cy="267.78109"
inkscape:window-x="1080"
inkscape:window-y="413"
inkscape:window-maximized="1"
inkscape:current-layer="g242"
units="in" />
<g
style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="g4"
transform="translate(-1087.0637,710.26871)">
<polyline
points="3365,2598 3365,3070"
id="polyline10"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3189,2598 3189,3070"
id="polyline12"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3012,2598 3012,3070"
id="polyline14"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2834,2598 2834,3070"
id="polyline16"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2657,2598 2657,3070"
id="polyline18"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2480,2598 2480,3070"
id="polyline20"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2303,2598 2303,3070"
id="polyline22"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2125,2456 2125,3070"
id="polyline24"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1948,2598 1948,3070"
id="polyline26"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1772,2598 1772,3070"
id="polyline28"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1594,2598 1594,3070"
id="polyline30"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1417,2598 1417,3070"
id="polyline32"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1239,2598 1239,3070"
id="polyline34"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1063,2598 1063,3070"
id="polyline36"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="886,2598 886,3070"
id="polyline38"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="708,2456 708,3070"
id="polyline40"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3543,2456 3543,3070"
id="polyline74"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="-2125,2598 3543,2598"
id="polyline76"
transform="matrix(0.70622791,0,0,1.3955346,455.54989,-1956.6141)" />
<polyline
points="3543,3070 -1948,3070 -2125,3070"
id="polyline78"
transform="matrix(0.70351457,0,0,1.3955346,465.16321,-1956.6141)" />
<polyline
points="9035,2598 9035,3070"
id="polyline80"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8858,2598 8858,3070"
id="polyline82"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8681,2598 8681,3070"
id="polyline84"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8503,2598 8503,3070"
id="polyline86"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8326,2598 8326,3070"
id="polyline88"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8150,2598 8150,3070"
id="polyline90"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7972,2598 7972,3070"
id="polyline92"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7795,2456 7795,3070"
id="polyline94"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7617,2598 7617,3070"
id="polyline96"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7441,2598 7441,3070"
id="polyline98"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7264,2598 7264,3070"
id="polyline100"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="7086,2598 7086,3070"
id="polyline102"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6909,2598 6909,3070"
id="polyline104"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6732,2598 6732,3070"
id="polyline106"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6555,2598 6555,3070"
id="polyline108"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6377,2456 6377,3070"
id="polyline110"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6200,2598 6200,3070"
id="polyline112"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6024,2598 6024,3070"
id="polyline114"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5846,2598 5846,3070"
id="polyline116"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5669,2598 5669,3070"
id="polyline118"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5491,2598 5491,3070"
id="polyline120"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5315,2598 5315,3070"
id="polyline122"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5138,2598 5138,3070"
id="polyline124"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4960,2409 4960,3070"
id="polyline126"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4783,2598 4783,3070"
id="polyline128"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4606,2598 4606,3070"
id="polyline130"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4429,2598 4429,3070"
id="polyline132"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4251,2598 4251,3070"
id="polyline134"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4074,2598 4074,3070"
id="polyline136"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3898,2598 3898,3070"
id="polyline138"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3720,2598 3720,3070"
id="polyline140"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,2456 9212,3070"
id="polyline142"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3543,2598 9212,2598"
id="polyline144"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,3070 3720,3070 0,3070"
id="polyline146"
transform="matrix(1.3047439,0,0,1.3955346,-1051.0007,-1956.6141)" />
<rect
x="5478.3828"
y="4304.8267"
width="1668.8131"
height="3296.2527"
rx="0"
style="fill:#dfdfc7;fill-opacity:1;stroke-width:11.23412323"
id="rect150" />
<polyline
points="3118,3590 2834,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline178"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="1322,3590 1039,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline180"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="4913,3590 4629,3779"
style="stroke:#008200;stroke-opacity:1"
id="polyline184"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="6519,3590 6236,3779"
style="stroke:#0000ff"
id="polyline186"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="8314,3590 8031,3779"
style="stroke:#0000ff"
id="polyline188"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="9212,3070 9070,3307 8314,3307 8173,3543 8031,3307 7228,3307 7086,3070"
style="stroke:#0000ff"
id="polyline204"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="3898,3070 4015,3307 4629,3307 4771,3543 4913,3307 5385,3307 5491,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline206"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="5491,3070 5622,3307 6236,3307 6377,3543 6519,3307 6909,3307 7086,3070"
style="stroke:#0000ff"
id="polyline208"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="2303,3070 2409,3307 2834,3307 2976,3543 3118,3307 3779,3307 3898,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline210"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<polyline
points="708,3070 850,3307 1039,3307 1181,3543 1322,3307 2173,3307 2303,3070"
style="stroke:#008200;stroke-opacity:1"
id="polyline212"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)" />
<g
style="fill:#000000;stroke-width:0"
id="g242"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)">
<text
xml:space="preserve"
x="6577.6826"
y="6866.8647"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-5">0</tspan></text>
<text
xml:space="preserve"
x="3507"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text246"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">32</text>
<text
xml:space="preserve"
x="2161"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text248"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">39</text>
<text
xml:space="preserve"
x="2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text250"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">40</text>
<text
xml:space="preserve"
x="744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text252"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">47</text>
<text
xml:space="preserve"
x="672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text254"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text256"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="-744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text258"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text260"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="9176"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text262"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">0</text>
<text
xml:space="preserve"
x="7759"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text264"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">8</text>
<text
xml:space="preserve"
x="6342"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text266"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">16</text>
<text
xml:space="preserve"
x="4924"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text268"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end">24</text>
<text
xml:space="preserve"
x="3579"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text270"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">31</text>
<text
xml:space="preserve"
x="6413"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text272"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">15</text>
<text
xml:space="preserve"
x="7830"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text274"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">7</text>
<text
xml:space="preserve"
x="4996"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text276"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start">23</text>
<g
transform="matrix(0,-1,1,0,8976,6614)"
id="g282" />
<text
xml:space="preserve"
x="-2125"
y="2314"
font-style="normal"
font-weight="normal"
font-size="152"
id="text290"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<g
transform="matrix(0,-1,1,0,5947.8484,5249.6147)"
id="g306">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3874"
y="3968"
font-style="normal"
font-weight="normal"
font-size="152"
id="text318"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
xml:space="preserve"
x="5912.7651"
y="4431.0742"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle"><tspan
style="font-size:200.46391296px"
id="tspan3503">P4 table</tspan></text>
<text
x="2031"
y="5622"
font-style="normal"
font-weight="normal"
font-size="152"
id="text346"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="3165"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text350"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1">9</text>
<text
x="1370"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text352"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1">9</text>
<text
x="1370"
y="6708"
font-style="normal"
font-weight="normal"
font-size="152"
id="text354"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff" />
<text
x="4960"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text356"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#008200;fill-opacity:1">9</text>
<text
x="6566"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text358"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">9</text>
<text
x="8362"
y="3732"
font-style="normal"
font-weight="normal"
font-size="152"
id="text360"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff">12</text>
<text
x="1181"
y="7532.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text364"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
x="1946.0945"
y="6998.52"
font-style="normal"
font-weight="normal"
font-size="152"
id="text344-8-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.75857544px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:217.16923523px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3493-3-2" />
</text>
<rect
style="fill:none;stroke:#000000;stroke-width:7.99999952;stroke-linecap:butt;stroke-linejoin:miter"
x="5325.8418"
y="4484.0391"
width="1181"
height="471.99994"
rx="0"
id="rect162-5" />
<circle
cx="6366.8491"
cy="4715.4253"
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="circle172-4"
r="46.999996" />
<text
xml:space="preserve"
x="5846.8491"
y="4768.8823"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6">P4 entry</tspan></text>
<text
xml:space="preserve"
x="5956.5303"
y="7168.7417"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-0"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6-4">Recursive</tspan></text>
<text
xml:space="preserve"
x="5956.5303"
y="7436.0269"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-0-9"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46391296px;stroke-width:0"
id="tspan3495-6-4-4">Mapping</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:6.53430033;stroke-linecap:butt;stroke-linejoin:miter"
x="5327.4341"
y="5550.6709"
width="1182.4656"
height="314.50067"
rx="0"
id="rect162-5-1" />
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-0.99999994,0.99999994,0,5946.2673,6272.377)"
id="g306-2">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308-3"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3097.1609"
y="2954.5652"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:318.2364502px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
inkscape:transform-center-x="-789.14735"
inkscape:transform-center-y="1300.106"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:318.2364502px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3503-4">111111111111111111111111111</tspan></text>
<rect
x="8208.377"
y="4073.4419"
width="691.0863"
height="3268.5144"
rx="0"
style="fill:#dfdfc7;fill-opacity:1;stroke:#000000;stroke-width:7.85773897;stroke-linecap:butt;stroke-linejoin:miter"
id="rect8" />
<rect
x="8208.377"
y="5474.9399"
width="691.0863"
height="233.25354"
rx="0"
style="fill:#dfdfc7;fill-opacity:1;stroke:#000000;stroke-width:7.85773897;stroke-linecap:butt;stroke-linejoin:miter"
id="rect158" />
<text
xml:space="preserve"
x="5840.8701"
y="5769.707"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-5"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46392822px;stroke-width:0"
id="tspan3495-6-7">P4 entry</tspan></text>
<ellipse
ry="46.999996"
rx="46.999992"
cx="6367.7495"
cy="5709.3936"
style="fill:#0000ff;stroke:#0000ff;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter"
id="circle172-4-4" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:9.51690483px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 8173.2452,3542.5202 0,364.8071 -584.0141,0 0,1802.0952 528.0052,0"
id="path9466"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
x="6641.2515"
y="4980.6011"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5">511</tspan></text>
<rect
x="1677.2448"
y="4498.876"
width="1181"
height="2361.9998"
rx="0"
style="fill:#dfdfdf;stroke:#000000;stroke-width:7.99999905;stroke-linecap:butt;stroke-linejoin:miter"
id="rect150-8" />
<text
xml:space="preserve"
x="2928.0776"
y="6883.7607"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-5-9"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-5-6">0</tspan></text>
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-1,1,0,2298.2444,5414.9455)"
id="g306-4">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308-1"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="2263.1606"
y="4404.876"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-8"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46392822px;stroke-width:0"
id="tspan3503-3">P4 table</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:7.99999952;stroke-linecap:butt;stroke-linejoin:miter"
x="1676.2374"
y="4500.9346"
width="1181"
height="471.99997"
rx="0"
id="rect162-5-4" />
<text
xml:space="preserve"
x="2197.2446"
y="4780.9897"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-1"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46392822px;stroke-width:0"
id="tspan3495-6-41">P4 entry</tspan></text>
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-0.99999992,0.9999999,0,2296.6633,6284.4847)"
id="g306-2-3" />
<text
xml:space="preserve"
x="2991.647"
y="4997.4966"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-8">511</tspan></text>
<polygon
points="3150,6661 3308,6614 3150,6566 3150,6661 "
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="polygon232-2-7-7-1"
transform="translate(-1613.3498,-1640.66)" />
<text
transform="matrix(0,-1.0062563,0.9937826,0,0,0)"
xml:space="preserve"
x="-5614.5532"
y="9191.6416"
font-style="normal"
font-weight="normal"
font-size="152"
id="text288"
style="font-style:normal;font-weight:normal;font-size:149.29702759px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:196.89912415px;stroke-width:0"
id="tspan3509">inactive P3 table </tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:11.42028618;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1180.4935,3543.3667 0,1428.1431 381.7959,0"
id="path6515"
inkscape:connector-curvature="0" />
<ellipse
ry="46.999996"
rx="46.999992"
cx="2703.6011"
cy="4723.3125"
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="circle172-4-3" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:14.74861526;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2716.9762,4721.7506 729.3182,0 0,2110.8251 1739.3012,0"
id="path6534"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:11.42028618;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 4771.7501,3542.097 0,1413.9884 417.9767,0"
id="path6542"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:11.42028618;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2975.9128,3541.8854 0,541.514 1015.0566,0 0,897.233 1213.8046,0"
id="path6544"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:11.42028618;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 6376.72,3540.8786 0,343.9797 -1325.7614,2.3941 0,1978.7627 172.2064,0"
id="path6546"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:11.42028618;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 6378.641,5717.2755 889.0271,0 0,1623.2076 851.1962,0"
id="path6548"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
x="2260.9126"
y="4178.6655"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-8-5"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3503-3-0">active</tspan></text>
<text
xml:space="preserve"
x="5915.9365"
y="4225.4873"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-0"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46392822px;stroke-width:0"
id="tspan3503-9">inactive</tspan></text>
</g>
<polygon
points="3150,6661 3150,6661 3308,6614 3150,6566 "
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="polygon232-2"
transform="matrix(1.4130509,0,0,1.3955346,810.24264,-1636.0556)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:18.76342201;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 7031.2608,4630.6049 719.9709,0 0,3526.7653 -2765.702,0 2.3625,-539.2826 285.3712,0"
id="path5354"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<polygon
points="3150,6661 3308,6614 3150,6566 3150,6661 "
style="fill:#0000ff;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polygon232-2-7"
transform="matrix(1.4130509,0,0,1.3955346,830.86496,-2994.8867)" />
<polygon
points="3150,6661 3150,6661 3308,6614 3150,6566 "
style="fill:#0000ff;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polygon232-2-7-3"
transform="matrix(1.4130509,0,0,1.3955346,4891.7749,-3219.444)" />
<polygon
points="3150,6661 3150,6661 3308,6614 3150,6566 "
style="fill:#0000ff;stroke:#0000ff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="polygon232-2-7-3-5"
transform="matrix(1.4130509,0,0,1.3955346,4896.989,-940.27671)" />
<polygon
points="3150,6566 3150,6661 3150,6661 3308,6614 "
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="polygon232-2-7-7"
transform="matrix(1.4130509,0,0,1.3955346,828.60556,-4263.1085)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -0,0 +1,403 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="617.77704"
height="216.27831"
viewBox="-2141 2141 8256.134 2869.6056"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="recursive_mapping_inactive_table_scheme.svg">
<metadata
id="metadata370">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs368" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="998"
id="namedview366"
showgrid="false"
fit-margin-top="1"
fit-margin-left="1"
fit-margin-right="1"
fit-margin-bottom="1"
inkscape:zoom="1.4142136"
inkscape:cx="523.64687"
inkscape:cy="50.722008"
inkscape:window-x="1080"
inkscape:window-y="413"
inkscape:window-maximized="1"
inkscape:current-layer="g242"
units="in" />
<g
style="fill:none;stroke:#000000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter"
id="g4"
transform="translate(-1516.6308,-1533.0567)">
<g
style="fill:#000000;stroke-width:0"
id="g242"
transform="matrix(1.4130509,0,0,1.3955346,-2048.7241,-1956.6141)">
<text
xml:space="preserve"
x="672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text254"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-672"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text256"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<text
xml:space="preserve"
x="-744"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text258"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:end" />
<text
xml:space="preserve"
x="-2090"
y="2551"
font-style="normal"
font-weight="normal"
font-size="152"
id="text260"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:'Helvetica Narrow';text-anchor:start" />
<g
transform="matrix(0,-1,1,0,8976,6614)"
id="g282" />
<text
xml:space="preserve"
x="-2125"
y="2314"
font-style="normal"
font-weight="normal"
font-size="152"
id="text290"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
xml:space="preserve"
x="3874"
y="3968"
font-style="normal"
font-weight="normal"
font-size="152"
id="text318"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="2031"
y="5622"
font-style="normal"
font-weight="normal"
font-size="152"
id="text346"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle" />
<text
x="1370"
y="6708"
font-style="normal"
font-weight="normal"
font-size="152"
id="text354"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start;fill:#0000ff" />
<text
x="1181"
y="7532.2715"
font-style="normal"
font-weight="normal"
font-size="152"
id="text364"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:start" />
<text
x="1946.0945"
y="6998.52"
font-style="normal"
font-weight="normal"
font-size="152"
id="text344-8-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.75857544px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%">
<tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:217.16923523px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0"
id="tspan3493-3-2" />
</text>
<rect
x="3090.1064"
y="4497.9272"
width="1182.895"
height="1367.9473"
rx="0"
style="fill:#dfdfdf;stroke:#000000;stroke-width:6.0930233;stroke-linecap:butt;stroke-linejoin:miter"
id="rect150-8" />
<text
xml:space="preserve"
x="4341.8867"
y="5887.8105"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-5-9"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-5-6">0</tspan></text>
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-1,1,0,3712.0549,5414.9455)"
id="g306-4">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308-1"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="3676.9697"
y="4404.876"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-8"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46392822px;stroke-width:0"
id="tspan3503-3">P4 table</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:7.99999952;stroke-linecap:butt;stroke-linejoin:miter"
x="3090.0466"
y="4500.9346"
width="1181"
height="471.99997"
rx="0"
id="rect162-5-4" />
<text
xml:space="preserve"
x="3611.0537"
y="4780.9897"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-1"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46392822px;stroke-width:0"
id="tspan3495-6-41">P4 entry</tspan></text>
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-0.99999992,0.9999999,0,2296.6633,6284.4847)"
id="g306-2-3" />
<text
xml:space="preserve"
x="4405.4561"
y="4997.4966"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-8">511</tspan></text>
<ellipse
ry="46.999996"
rx="46.999992"
cx="4117.4102"
cy="4723.3125"
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="circle172-4-3" />
<text
xml:space="preserve"
x="3674.7217"
y="4178.6655"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-8-5"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3503-3-0">active</tspan></text>
<rect
x="5370.3823"
y="4498.0884"
width="1182.895"
height="1367.9473"
rx="0"
style="fill:#dfdfbe;fill-opacity:1;stroke:#000000;stroke-width:6.0930233;stroke-linecap:butt;stroke-linejoin:miter"
id="rect150-8-9" />
<text
xml:space="preserve"
x="6622.1631"
y="5887.9717"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-5-9-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-5-6-5">0</tspan></text>
<g
style="fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
transform="matrix(0,-1,1,0,5992.3314,5415.1068)"
id="g306-4-9">
<text
xml:space="preserve"
x="0"
y="0"
font-style="normal"
font-weight="normal"
font-size="404"
id="text308-1-8"
style="font-style:normal;font-weight:normal;font-size:404px;font-family:Helvetica;text-anchor:middle">...</text>
</g>
<text
xml:space="preserve"
x="5957.2456"
y="4405.0371"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-8-0"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3503-3-2">P4 table</tspan></text>
<rect
style="fill:none;stroke:#000000;stroke-width:7.99999952;stroke-linecap:butt;stroke-linejoin:miter"
x="5370.3228"
y="4501.0957"
width="1181"
height="472"
rx="0"
id="rect162-5-4-4" />
<text
xml:space="preserve"
x="5891.3296"
y="4781.1509"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-1-6"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3495-6-41-6">P4 entry</tspan></text>
<text
xml:space="preserve"
x="6685.7324"
y="4997.6577"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-2-1-6-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:130.85745239px;line-height:125%;font-family:Helvetica;-inkscape-font-specification:'Helvetica, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#4d4d4d;stroke-width:0"
id="tspan3503-48-5-8-1">511</tspan></text>
<polygon
points="3150,6566 3150,6661 3150,6661 3308,6614 "
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="polygon232-2-7-7-1-1"
transform="translate(2076.0084,-749.88898)" />
<ellipse
ry="46.999996"
rx="46.999992"
cx="6397.6865"
cy="4723.4736"
style="fill:#008200;fill-opacity:1;stroke:#008200;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="circle172-4-3-6" />
<text
xml:space="preserve"
x="5954.9976"
y="4178.8267"
font-style="normal"
font-weight="normal"
font-size="152"
id="text320-8-5-9"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3503-3-0-2">inactive</tspan></text>
<rect
x="1019.4597"
y="4821.9668"
width="1487.6132"
height="469.84174"
rx="0"
style="fill:#dfdfdf;stroke:#000000;stroke-width:4.0044775;stroke-linecap:butt;stroke-linejoin:miter"
id="rect150-8-0" />
<text
xml:space="preserve"
x="1642.8574"
y="5136.835"
font-style="normal"
font-weight="normal"
font-size="152"
id="text314-5-1-4"
style="font-style:normal;font-weight:normal;font-size:152px;font-family:Helvetica;text-anchor:middle;fill:#000000;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter"><tspan
style="font-size:200.46394348px;stroke-width:0"
id="tspan3495-6-41-8">CR3 register</tspan></text>
<ellipse
ry="46.999996"
rx="46.999992"
cx="2349.6458"
cy="5076.04"
style="fill:#969696;fill-opacity:1;stroke:#969696;stroke-width:31.99999809;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="circle172-4-3-2" />
<polygon
points="3150,6566 3150,6661 3150,6661 3308,6614 "
style="fill:#969696;fill-opacity:1;stroke:#969696;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="polygon232-2-7-7-1-1-7"
transform="translate(-214.18472,-748.49788)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#969696;stroke-width:9.51690483px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 2349.6459,5073.646 359.3939,0 0,792.4508 255.3589,0"
id="path4612"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:9.51690483px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 4118.0344,4723.1182 672.1066,0 0,1137.6237 494.8846,0"
id="path4614"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#008200;stroke-width:9.51690483px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 6395.1719,4726.5039 441.3835,0 0,1357.6997 -1725.4081,0 0,-199.7613 127.0649,0"
id="path4620"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -1,95 +1,170 @@
+++
title = "Kernel Heap"
date = "2016-04-11"
weight = 8
path = "kernel-heap"
aliases = ["kernel-heap.html"]
date = 2016-04-11
template = "edition-1/page.html"
[extra]
updated = "2017-11-19"
+++
In the previous posts we have created a [frame allocator] and a [page table module]. Now we are ready to create a kernel heap and a memory allocator. Thus, we will unlock `Box`, `Vec`, `BTreeMap`, and the rest of the [alloc] and [collections] crates.
In the previous posts we created a [frame allocator] and a [page table module]. Now we are ready to create a kernel heap and a memory allocator. Thus, we will unlock `Box`, `Vec`, `BTreeMap`, and the rest of the [alloc] crate.
[frame allocator]: {{% relref "2015-11-15-allocating-frames.md" %}}
[page table module]: {{% relref "2015-12-09-modifying-page-tables.md" %}}
[frame allocator]: @/edition-1/posts/05-allocating-frames/index.md
[page table module]: @/edition-1/posts/06-page-tables/index.md
[alloc]: https://doc.rust-lang.org/nightly/alloc/index.html
[collections]: https://doc.rust-lang.org/nightly/collections/index.html
<!--more-->
<!-- more -->
As always, you can find the complete source code on [Github]. Please file [issues] for any problems, questions, or improvement suggestions. There is also a comment section at the end of this page.
As always, you can find the complete source code on [GitHub]. Please file [issues] for any problems, questions, or improvement suggestions. There is also a comment section at the end of this page.
[Github]: https://github.com/phil-opp/blog_os/tree/kernel_heap
[GitHub]: https://github.com/phil-opp/blog_os/tree/first_edition_post_8
[issues]: https://github.com/phil-opp/blog_os/issues
## Introduction
The _heap_ is the memory area for long-lived allocations. The programmer can access it by using types like [Box][Box rustbyexample] or [Vec]. Behind the scenes, the compiler manages that memory by inserting calls to some memory allocator. By default, Rust links to the [jemalloc] allocator (for binaries) or the system allocator (for libraries). However, both rely on [system calls] such as [sbrk] and are thus unusable in our kernel. So we need to create and link our own allocator.
[Box rustbyexample]: http://rustbyexample.com/std/box.html
[Box rustbyexample]: https://doc.rust-lang.org/rust-by-example/std/box.html
[Vec]: https://doc.rust-lang.org/book/vectors.html
[jemalloc]: http://www.canonware.com/jemalloc/
[jemalloc]: http://jemalloc.net/
[system calls]: https://en.wikipedia.org/wiki/System_call
[sbrk]: https://en.wikipedia.org/wiki/Sbrk
A good allocator is fast and reliable. It also effectively utilizes the available memory and keeps [fragmentation] low. Furthermore, it works well for concurrent applications and scales to any number of processors. It even optimizes the memory layout with respect to the CPU caches to improve [cache locality] and avoid [false sharing].
[cache locality]: http://docs.cray.com/books/S-2315-50/html-S-2315-50/qmeblljm.html
[cache locality]: https://www.geeksforgeeks.org/locality-of-reference-and-cache-operation-in-cache-memory/
[fragmentation]: https://en.wikipedia.org/wiki/Fragmentation_(computing)
[false sharing]: http://mechanical-sympathy.blogspot.de/2011/07/false-sharing.html
[false sharing]: https://mechanical-sympathy.blogspot.de/2011/07/false-sharing.html
These requirements make good allocators pretty complex. For example, [jemalloc] has over 30.000 lines of code. This complexity is out of scope for our kernel, so we will create a much simpler allocator. However, it should suffice for the foreseeable future, since we'll allocate only when it's absolutely necessary.
These requirements make good allocators pretty complex. For example, [jemalloc] has over 30.000 lines of code. This complexity is out of scope for our kernel, so we will create a much simpler allocator. Nevertheless, it should suffice for the foreseeable future, since we'll allocate only when it's absolutely necessary.
## The Allocator Interface
The allocator interface in Rust is defined through the [`Alloc` trait], which looks like this:
[`Alloc` trait]: https://doc.rust-lang.org/1.20.0/alloc/allocator/trait.Alloc.html
```rust
pub unsafe trait Alloc {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>;
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout);
[…] // about 13 methods with default implementations
}
```
The `alloc` method should allocate a memory block with the size and alignment given through `Layout` parameter. The `deallocate` method should free such memory blocks again. Both methods are `unsafe`, as is the trait itself. This has different reasons:
- Implementing the `Alloc` trait is unsafe, because the implementation must satisfy a set of contracts. Among other things, pointers returned by `alloc` must point to valid memory and adhere to the `Layout` requirements.
- Calling `alloc` is unsafe because the caller must ensure that the passed layout does not have size zero. I think this is because of compatibility reasons with existing C-allocators, where zero-sized allocations are undefined behavior.
- Calling `dealloc` is unsafe because the caller must guarantee that the passed parameters adhere to the contract. For example, `ptr` must denote a valid memory block allocated via this allocator.
To set the system allocator, the `global_allocator` attribute can be added to a `static` that implements `Alloc` for a shared reference of itself. For example:
```rust
#[global_allocator]
static MY_ALLOCATOR: MyAllocator = MyAllocator {...};
impl<'a> Alloc for &'a MyAllocator {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {...}
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {...}
}
```
Note that `Alloc` needs to be implemented for `&MyAllocator`, not for `MyAllocator`. The reason is that the `alloc` and `dealloc` methods require mutable `self` references, but there's no way to get such a reference safely from a `static`. By requiring implementations for `&MyAllocator`, the global allocator interface avoids this problem and pushes the burden of synchronization onto the user.
## Including the alloc crate
The `Alloc` trait is part of the `alloc` crate, which like `core` is a subset of Rust's standard library. Apart from the trait, the crate also contains the standard types that require allocations such as `Box`, `Vec` and `Arc`. We can include it through a simple `extern crate`:
```rust
// in src/lib.rs
#![feature(alloc)] // the alloc crate is still unstable
[...]
#[macro_use]
extern crate alloc;
```
We don't need to add anything to our Cargo.toml, since the `alloc` crate is part of the standard library and shipped with the Rust compiler. The `alloc` crate provides the [format!] and [vec!] macros, so we use `#[macro_use]` to import them.
[format!]: https://doc.rust-lang.org/1.10.0/collections/macro.format!.html
[vec!]: https://doc.rust-lang.org/1.10.0/collections/macro.vec!.html
When we try to compile our crate now, the following error occurs:
```
error[E0463]: can't find crate for `alloc`
--> src/lib.rs:10:1
|
16 | extern crate alloc;
| ^^^^^^^^^^^^^^^^^^^ can't find crate
```
The problem is that [`xargo`] only cross compiles `libcore` by default. To also cross compile the `alloc` crate, we need to create a file named `Xargo.toml` in our project root (right next to the `Cargo.toml`) with the following content:
[`xargo`]: https://github.com/japaric/xargo
```toml
[target.x86_64-blog_os.dependencies]
alloc = {}
```
This instructs `xargo` that we also need `alloc`. It still doesn't compile, since we need to define a global allocator in order to use the `alloc` crate:
```
error: no #[default_lib_allocator] found but one is required; is libstd not linked?
```
## A Bump Allocator
For our own allocator, we start simple. We create an allocator crate in a new `libs` subfolder:
For our first allocator, we start simple. We create a `memory::heap_allocator` module containing a so-called _bump allocator_:
``` shell
> mkdir libs
> cd libs
> cargo new bump_allocator
> cd bump_allocator
```
```rust
// in src/memory/mod.rs
Our allocator is very basic. It only keeps track of the next free address:
mod heap_allocator;
``` rust
// in libs/bump_allocator/src/lib.rs
// in src/memory/heap_allocator.rs
#![feature(const_fn)]
use alloc::heap::{Alloc, AllocErr, Layout};
/// A simple allocator that allocates memory linearly and ignores freed memory.
#[derive(Debug)]
struct BumpAllocator {
pub struct BumpAllocator {
heap_start: usize,
heap_size: usize,
heap_end: usize,
next: usize,
}
impl BumpAllocator {
/// Create a new allocator, which uses the memory in the
/// range [heap_start, heap_start + heap_size).
const fn new(heap_start: usize, heap_size: usize) -> BumpAllocator {
BumpAllocator {
heap_start: heap_start,
heap_size: heap_size,
next: heap_start,
pub const fn new(heap_start: usize, heap_end: usize) -> Self {
Self { heap_start, heap_end, next: heap_start }
}
}
unsafe impl Alloc for BumpAllocator {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
let alloc_start = align_up(self.next, layout.align());
let alloc_end = alloc_start.saturating_add(layout.size());
if alloc_end <= self.heap_end {
self.next = alloc_end;
Ok(alloc_start as *mut u8)
} else {
Err(AllocErr::Exhausted{ request: layout })
}
}
/// Allocates a block of memory with the given size and alignment.
fn allocate(&mut self, size: usize, align: usize) -> Option<*mut u8> {
let alloc_start = align_up(self.next, align);
let alloc_end = alloc_start + size;
if alloc_end <= self.heap_start + self.heap_size {
self.next = alloc_end;
Some(alloc_start as *mut u8)
} else {
None
}
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
// do nothing, leak memory
}
}
```
The `heap_start` and `heap_size` fields just contain the start address and size of our kernel heap. The `next` field contains the next free address and is increased after every allocation. To `allocate` a memory block we align the `next` address using the `align_up` function (decribed below). Then we add up the desired `size` and make sure that we don't exceed the end of the heap. If everything goes well, we update the `next` address and return a pointer to the start address of the allocation. Else, we return `None`.
We also need to add `#![feature(allocator_api)]` to our `lib.rs`, since the allocator API is still unstable.
Note that we need to add a feature flag at the beginning of the file, because we've marked the `new` function as `const`. [Const functions] are unstable, so we need to add the `#![feature(const_fn)]` flag.
[Const functions]: https://github.com/rust-lang/rust/issues/24111
The `heap_start` and `heap_end` fields contain the start and end address of our kernel heap. The `next` field contains the next free address and is increased after every allocation. To `allocate` a memory block we align the `next` address using the `align_up` function (described below). Then we add up the desired `size` and make sure that we don't exceed the end of the heap. We use a saturating add so that the `alloc_end` cannot overflow, which could lead to an invalid allocation. If everything goes well, we update the `next` address and return a pointer to the start address of the allocation. Else, we return `None`.
### Alignment
In order to simplify alignment, we add `align_down` and `align_up` functions:
@@ -114,7 +189,7 @@ pub fn align_up(addr: usize, align: usize) -> usize {
}
```
Let's start with `align_down`: If the alignment is a valid power of two (i.e. in `{1,2,4,8,…}`), we use some bit-fiddling to return the aligned address. It works because every power of two has exactly one bit set in its binary representation. For example, the numbers `{1,2,4,8,…}` are `{1,10,100,1000,…}` in binary. By subtracting 1 we get `{0,01,011,0111,…}`. These binary numbers have a `1` at exactly the positions that need to be zeroed in `addr`. For example, the last 3 bits need to be zeroed for a alignment of 8.
Let's start with `align_down`: If the alignment is a valid power of two (i.e. in `{1,2,4,8,…}`), we use some bitwise operations to return the aligned address. It works because every power of two has exactly one bit set in its binary representation. For example, the numbers `{1,2,4,8,…}` are `{1,10,100,1000,…}` in binary. By subtracting 1 we get `{0,01,011,0111,…}`. These binary numbers have a `1` at exactly the positions that need to be zeroed in `addr`. For example, the last 3 bits need to be zeroed for a alignment of 8.
To align `addr`, we create a [bitmask] from `align-1`. We want a `0` at the position of each `1`, so we invert it using `!`. After that, the binary numbers look like this: `{…11111,…11110,…11100,…11000,…}`. Finally, we zero the correct bits using a binary `AND`.
@@ -122,193 +197,132 @@ To align `addr`, we create a [bitmask] from `align-1`. We want a `0` at the posi
Aligning upwards is simple now. We just increase `addr` by `align-1` and call `align_down`. We add `align-1` instead of `align` because we would otherwise waste `align` bytes for already aligned addresses.
### Deallocate
But how do we deallocate memory in our bump allocator? Well, we don't ;). We just leak all freed memory for now. Thus our allocator quickly runs out of memory in a real system. On the other hand, it's as fast as an allocator can get: It just increases a single variable when allocating and does nothing at all when deallocating. And RAM is cheap nowadays, right? :)
### Reusing Freed Memory
The heap memory is limited, so we should reuse freed memory for new allocations. This sounds simple, but is not so easy in practice since allocations can live arbitrarily long (and can be freed in an arbitrary order). This means that we need some kind of data structure to keep track of which memory areas are free and which are in use. This data structure should be very optimized since it causes overheads in both space (i.e. it needs backing memory) and time (i.e. accessing and organizing it needs CPU cycles).
(Don't worry, we will introduce a better allocator later in this post.)
Our bump allocator only keeps track of the next free memory address, which doesn't suffice to keep track of freed memory areas. So our only choice is to ignore deallocations and leak the corresponding memory. Thus our allocator quickly runs out of memory in a real system, but it suffices for simple testing. Later in this post, we will introduce a better allocator that does not leak freed memory.
### Custom Allocators in Rust
In order to use our crate as system allocator, we add some attributes at the beginning of the file:
### Using it as System Allocator
``` rust
// in libs/bump_allocator/src/lib.rs
Above we saw that we can use a static allocator as system allocator through the `global_allocator` attribute:
#![feature(allocator)]
#![allocator]
#![no_std]
```
The `#![allocator]` attribute tells the compiler that it should not link a default allocator when this crate is linked. The attribute is unstable and feature-gated, so we need to add `#![feature(allocator)]` as well. Allocator crates must not depend on [liballoc], because this would introduce a circular dependency. Thus, allocator crates can't use the standard library either (as it depends on `liballoc`). Therefore all allocator crates must be marked as `#![no_std]`.
[liballoc]: https://doc.rust-lang.org/nightly/alloc/index.html
According to [the book][custom-allocators], an allocator crate needs to implement the following five functions:
[custom-allocators]: https://doc.rust-lang.org/book/custom-allocators.html
``` rust
#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {}
#[no_mangle]
pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {}
#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, size: usize, align: usize) {}
#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize,
align: usize) -> *mut u8 {}
#[no_mangle]
pub extern fn __rust_reallocate_inplace(ptr: *mut u8, size: usize,
new_size: usize, align: usize)
-> usize {}
```rust
#[global_allocator]
static ALLOCATOR: MyAllocator = MyAllocator {...};
```
These functions are highly unstable and the compiler does not check their types. So make sure that the type, number, and order of parameters are correct when you implement it.
This requires an implementation of `Alloc` for `&MyAllocator`, i.e. a shared reference. If we try to add such an implementation for our bump allocator (`unsafe impl<'a> Alloc for &'a BumpAllocator`), we have a problem: Our `alloc` method requires updating the `next` field, which is not possible for a shared reference.
Let's look at each function individually:
One solution could be to put the bump allocator behind a Mutex and wrap it into a new type, for which we can implement `Alloc` for a shared reference:
- The `__rust_allocate` function allocates a block of memory with the given size (in bytes) and alignment. _Alignment_ means that the start address of the allocation needs to be a multiple of the `align` parameter. This is required because some CPUs can only access e.g. 4 byte aligned addresses. The alignment is always a power of 2.
- The `__rust_usable_size` returns the usable size of an allocation created with the specified size and alignment. The usable size is at least `size`, but might be larger if the allocator uses fixed block sizes. For example, a [buddy allocator] rounds the size of each allocation to the next power of two.
- The `__rust_deallocate` function frees the memory block referenced `ptr` again. The `size` and `align` parameters contain the values that were used to create the allocation. Thus the allocator knows exactly how much memory it needs to free. In constrast, the [free function] of C only has a single `ptr` argument. So a C allocator needs to [maintain information][c free info] about the size of each block itself. In Rust, the compiler maintains this information for us.
- The `__rust_reallocate` function changes the size of the block referenced by `ptr` from `size` to `new_size`. If it's possible to do in in-place, the function resizes the block and returns `ptr` again. Else, it allocates a new block of `new_size` and copies the memory contents from the old block. Then it frees the old block and returns the pointer to the new block.
- The `__rust_reallocate_inplace` function tries to change the size of the block referenced by `ptr` from `size` to `new_size` without relocating the memory block. If it succeeds, it returns `usable_size(new_size, align)`, else it returns `usable_size(size, align)`.
```rust
struct LockedBumpAllocator(Mutex<BumpAllocator>);
[buddy allocator]: https://en.wikipedia.org/wiki/Buddy_memory_allocation
[free function]: http://www.cplusplus.com/reference/cstdlib/free/
[c free info]: http://stackoverflow.com/questions/1518711/how-does-free-know-how-much-to-free
impl<'a> Alloc for &'a LockedBumpAllocator {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
self.0.lock().alloc(layout)
}
A more detailed documentation for these functions can be found in the [API docs for alloc::heap][alloc::heap]. Note that all of these functions and custom allocators in general are _unstable_ (as indicated by the `allocator` feature gate).
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
self.0.lock().dealloc(ptr, layout)
}
}
```
[alloc::heap]: https://doc.rust-lang.org/nightly/alloc/heap/
However, there is a more interesting solution for our bump allocator that avoids locking altogether. The idea is to exploit that we only need to update a single `usize` field byusing an `AtomicUsize` type. This type uses special synchronized hardware instructions to ensure data race freedom without requiring locks.
### Implementation
Let's implement the allocation functions using our new allocator. First we need a way to access the allocator. The functions do not know anything about our allocator, so we can only access it through a `static`:
#### A lock-free Bump Allocator
A lock-free implementation looks like this:
``` rust
// in libs/bump_allocator/src/lib.rs
```rust
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::Mutex;
/// A simple allocator that allocates memory linearly and ignores freed memory.
#[derive(Debug)]
pub struct BumpAllocator {
heap_start: usize,
heap_end: usize,
next: AtomicUsize,
}
extern crate spin;
impl BumpAllocator {
pub const fn new(heap_start: usize, heap_end: usize) -> Self {
// NOTE: requires adding #![feature(const_atomic_usize_new)] to lib.rs
Self { heap_start, heap_end, next: AtomicUsize::new(heap_start) }
}
}
unsafe impl<'a> Alloc for &'a BumpAllocator {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
loop {
// load current state of the `next` field
let current_next = self.next.load(Ordering::Relaxed);
let alloc_start = align_up(current_next, layout.align());
let alloc_end = alloc_start.saturating_add(layout.size());
if alloc_end <= self.heap_end {
// update the `next` pointer if it still has the value `current_next`
let next_now = self.next.compare_and_swap(current_next, alloc_end,
Ordering::Relaxed);
if next_now == current_next {
// next address was successfully updated, allocation succeeded
return Ok(alloc_start as *mut u8);
}
} else {
return Err(AllocErr::Exhausted{ request: layout })
}
}
}
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
// do nothing, leak memory
}
}
```
The implementation is a bit more complicated now. First, there is now a `loop` around the whole method body, since we might need multiple tries until we succeed (e.g. if multiple threads try to allocate at the same time). Also, the loads operation is an explicit method call now, i.e. `self.next.load(Ordering::Relaxed)` instead of just `self.next`. The ordering parameter makes it possible to restrict the automatic instruction reordering performed by both the compiler and the CPU itself. For example, it is used when implementing locks to ensure that no write to the locked variable happens before the lock is acquired. We don't have such requirements, so we use the less restrictive `Relaxed` ordering.
The heart of this lock-free method is the `compare_and_swap` call that updates the `next` address:
```rust
...
let next_now = self.next.compare_and_swap(current_next, alloc_end,
Ordering::Relaxed);
if next_now == current_next {
// next address was successfully updated, allocation succeeded
return Ok(alloc_start as *mut u8);
}
...
```
Compare-and-swap is a special CPU instruction that updates a variable with a given value if it still contains the value we expect. If it doesn't, it means that another thread updated the value simultaneously, so we need to try again. The important feature is that this happens in a single uninteruptible operation (thus the name `atomic`), so no partial updates or intermediate states are possible.
In detail, `compare_and_swap` works by comparing `next` with the first argument and, in case they're equal, updates `next` with the second parameter (the previous value is returned). To find out whether a switch happened, we check the returned previous value of `next`. If it is equal to the first parameter, the values were swapped. Otherwise, we try again in the next loop iteration.
#### Setting the Global Allocator
Now we can define a static bump allocator, that we can set as system allocator:
```rust
pub const HEAP_START: usize = 0o_000_001_000_000_0000;
pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB
static BUMP_ALLOCATOR: Mutex<BumpAllocator> = Mutex::new(
BumpAllocator::new(HEAP_START, HEAP_SIZE));
#[global_allocator]
static HEAP_ALLOCATOR: BumpAllocator = BumpAllocator::new(HEAP_START,
HEAP_START + HEAP_SIZE);
```
We use `0o_000_001_000_000_0000` as heap start address, which is the address starting at the second `P3` entry. It doesn't really matter which address we choose here as long as it's unused. We use a heap size of 100 KiB, which should be large enough for the near future. The static allocator is protected by a spinlock since we need to able to modify it. Our allocator crate is distinct from our main crate, so we need to add the `spin` dependency to its `Cargo.toml` as well. The easiest way is to run `cargo add spin` (using the [cargo-edit] crate).
We use `0o_000_001_000_000_0000` as heap start address, which is the address starting at the second `P3` entry. It doesn't really matter which address we choose here as long as it's unused. We use a heap size of 100 KiB, which should be large enough for the near future.
[cargo-edit]: https://github.com/killercup/cargo-edit
Putting the above in the `memory::heap_allocator` module would make most sense, but unfortunately there is currently a [weird bug][global allocator bug] in the global allocator implementation that requires putting the global allocator in the root module. I hope it's fixed soon, but until then we need to put the above lines in `src/lib.rs`. For that, we need to make the `memory::heap_allocator` module public and add an import for `BumpAllocator`. We also need to add the `#![feature(global_allocator)]` at the top of our `lib.rs`, since the `global_allocator` attribute is still unstable.
Now we can easily implement the `__rust_allocate` and `__rust_deallocate` functions:
[global allocator bug]: https://github.com/rust-lang/rust/issues/44113
```rust
// in libs/bump_allocator/src/lib.rs
That's it! We have successfully created and linked a custom system allocator. Now we're ready to test it.
#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
BUMP_ALLOCATOR.lock().allocate(size, align).expect("out of memory")
}
### Testing
#[no_mangle]
pub extern fn __rust_deallocate(_ptr: *mut u8, _size: usize,
_align: usize)
{
// just leak it
}
```
We use `expect` to panic in out of memory (OOM) situations. We could alternatively return a null pointer, which indicates an OOM situation to the Rust runtime. However, the runtime would react by aborting the process. On Linux, the abort function intentionally raises an [invalid opcode] exception, which would lead to a boot loop for our kernel. So panickying is a better solution for our kernel.
[invalid opcode]: http://wiki.osdev.org/Exceptions#Invalid_Opcode
We never allocate more memory than requested, so the `__rust_usable_size` function is simple:
```rust
#[no_mangle]
pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
size
}
```
In order to keep things simple, we don't support the `__rust_reallocate_inplace` function and always return the old size:
```rust
#[no_mangle]
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, size: usize,
_new_size: usize, _align: usize) -> usize
{
size
}
```
Now only `__rust_reallocate` is left. It's a bit more difficult, since we need to copy the contents of the old allocation to the new allocation. However, we can just steal some code from the official [reallocate implementation for unix][unix realloc]:
[unix realloc]: https://github.com/rust-lang/rust/blob/c66d2380a810c9a2b3dbb4f93a830b101ee49cc2/src/liballoc_system/lib.rs#L98-L101
``` rust
#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize,
align: usize) -> *mut u8 {
use core::{ptr, cmp};
// from: https://github.com/rust-lang/rust/blob/
// c66d2380a810c9a2b3dbb4f93a830b101ee49cc2/
// src/liballoc_system/lib.rs#L98-L101
let new_ptr = __rust_allocate(new_size, align);
unsafe { ptr::copy(ptr, new_ptr, cmp::min(size, new_size)) };
__rust_deallocate(ptr, size, align);
new_ptr
}
```
That's it! We have successfully created a custom allocator. Now we're ready to test it.
## Box, Vec, and Friends
In order to use our new allocator we import it in our main project:
```rust
// in src/lib.rs of our main project
extern crate bump_allocator;
```
Additionally, we need to tell cargo where our `bump_allocator` crate lives:
``` toml
# in Cargo.toml of our main project
[dependencies.bump_allocator]
path = "libs/bump_allocator"
```
Now we're able to import the `alloc` and `collections` crates in order to unlock `Box`, `Vec`, `BTreeMap`, and friends:
```rust
// in src/lib.rs of our main project
#![feature(alloc, collections)]
extern crate bump_allocator;
extern crate alloc;
#[macro_use]
extern crate collections;
```
The `collections` crate provides the [format!] and [vec!] macros, so we use `#[macro_use]` to import them.
[format!]: //doc.rust-lang.org/nightly/collections/macro.format!.html
[vec!]: https://doc.rust-lang.org/nightly/collections/macro.vec!.html
## Testing
Now we should be able to allocate memory on the heap. Let's try it in our `rust_main`:
We should be able to allocate memory on the heap now. Let's try it in our `rust_main`:
```rust
// in rust_main in src/lib.rs
@@ -317,33 +331,9 @@ use alloc::boxed::Box;
let heap_test = Box::new(42);
```
When we try to compile it using `make run`, we get several linker errors about a function named `_Unwind_Resume`:
When we run it, a triple fault occurs and causes permanent rebooting. Let's try debug it using QEMU and objdump as described [in the previous post][qemu debugging]:
```
target/x86_64-unknown-linux-gnu/debug/libblog_os.a(bump_allocator-[…].0.o):
In function `bump_allocator::__rust_allocate':
/home/…/blog_os/libs/bump_allocator/src/lib.rs:19:
undefined reference to `_Unwind_Resume'
```
This function is part of Rust's unwinding machinery. We disabled most of by passing `-Z no-landing-pads` to rustc, but apparently our precompiled `libcollections` still links to it.
To work around this issue for now, we add a dummy function:
```rust
// in libs/bump_allocator/src/lib.rs
#[no_mangle]
pub extern fn _Unwind_Resume() -> ! {
loop{}
}
```
This is just a temporary fix to keep this post simple. We will resolve this issue in a better way in a future post.
Now our kernel compiles again. But when we run it, a triple fault occurs and causes permanent rebooting. We use QEMU for debugging as described [in the previous post][qemu debugging]:
[qemu debugging]: http://os.phil-opp.com/remap-the-kernel.html#debugging
[qemu debugging]: @/edition-1/posts/07-remap-the-kernel/index.md#debugging
```
> qemu-system-x86_64 -d int -no-reboot -cdrom build/os-x86_64.iso
@@ -353,9 +343,9 @@ check_exception old: 0xffffffff new 0xe
SP=0010:0000000000116af0 CR2=0000000040000000
```
Aha! It's a [page fault] (`v=0e`) and was caused by the code at `0x102860`. The code tried to write (`e=0002`) to address `0x40000000`. This address is `0o_000_001_000_000_0000` in octal, which is the `HEAP_START` address defined above. Of course it page-faults: We have forgotten to map the heap memory to some physical memory.
Aha! It's a [page fault] \(`v=0e`) and was caused by the code at `0x102860`. The code tried to write (`e=0002`) to address `0x40000000`. This address is `0o_000_001_000_000_0000` in octal, which is the `HEAP_START` address defined above. Of course it page-faults: We have forgotten to map the heap memory to some physical memory.
[page fault]: http://wiki.osdev.org/Exceptions#Page_Fault
[page fault]: https://wiki.osdev.org/Exceptions#Page_Fault
### Some Refactoring
In order to map the heap cleanly, we do a bit of refactoring first. We move all memory initialization from our `rust_main` to a new `memory::init` function. Now our `rust_main` looks like this:
@@ -363,6 +353,7 @@ In order to map the heap cleanly, we do a bit of refactoring first. We move all
```rust
// in src/lib.rs
#[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) {
// ATTENTION: we have a very small stack and no guard page
vga_buffer::clear_screen();
@@ -423,8 +414,8 @@ pub fn init(boot_info: &BootInformation) {
We've just moved the code to a new function. However, we've sneaked some improvements in:
- An additional `.filter(|s| s.is_allocated())` in the calculation of `kernel_start` and `kernel_end`. This ignores all sections that aren't loaded to memory (such as debug sections). Thus, the kernel end address is no longer artifically increased by such sections.
- We use the `start_address()` and `end_address()` methods of `boot_info` instead of calculating the adresses manually.
- An additional `.filter(|s| s.is_allocated())` in the calculation of `kernel_start` and `kernel_end`. This ignores all sections that aren't loaded to memory (such as debug sections). Thus, the kernel end address is no longer artificially increased by such sections.
- We use the `start_address()` and `end_address()` methods of `boot_info` instead of calculating the addresses manually.
- We use the alternate `{:#x}` form when printing kernel/multiboot addresses. Before, we used `0x{:x}`, which leads to the same result. For a complete list of these “alternate” formatting forms, check out the [std::fmt documentation].
[std::fmt documentation]: https://doc.rust-lang.org/nightly/std/fmt/index.html#sign0
@@ -451,7 +442,7 @@ extern crate once;
The crate provides an [assert_has_not_been_called!] macro (sorry for the long name :D). We can use it to fix the safety problem easily:
[assert_has_not_been_called!]: https://phil-opp.rustdocs.org/once/macro.assert_has_not_been_called!.html
[assert_has_not_been_called!]: https://docs.rs/once/0.3.2/once/macro.assert_has_not_been_called!.html
``` rust
// in src/memory/mod.rs
@@ -468,9 +459,10 @@ That's it. Now our `memory::init` function can only be called once. The macro wo
[AtomicBool]: https://doc.rust-lang.org/nightly/core/sync/atomic/struct.AtomicBool.html
### Mapping the Heap
Now we're ready to map the heap pages. In order to do it, we need access to the `ActivePageTable` or `Mapper` instance (see the [previous post]). Therefore we return it from the `paging::remap_the_kernel` function:
Now we're ready to map the heap pages. In order to do it, we need access to the `ActivePageTable` or `Mapper` instance (see the [page table] and [kernel remapping] posts). For that we return it from the `paging::remap_the_kernel` function:
[previous post]: {{ page.previous.url }}
[page table]: @/edition-1/posts/06-page-tables/index.md
[kernel remapping]: @/edition-1/posts/07-remap-the-kernel/index.md
```rust
// in src/memory/paging/mod.rs
@@ -502,7 +494,7 @@ pub fn init(boot_info: &BootInformation) {
boot_info);
use self::paging::Page;
use bump_allocator::{HEAP_START, HEAP_SIZE};
use {HEAP_START, HEAP_SIZE};
let heap_start_page = Page::containing_address(HEAP_START);
let heap_end_page = Page::containing_address(HEAP_START + HEAP_SIZE-1);
@@ -510,6 +502,7 @@ pub fn init(boot_info: &BootInformation) {
for page in Page::range_inclusive(heap_start_page, heap_end_page) {
active_table.map(page, paging::WRITABLE, &mut frame_allocator);
}
}
```
The `Page::range_inclusive` function is just a copy of the `Frame::range_inclusive` function:
@@ -572,7 +565,7 @@ for i in &vec_test {
}
```
We can also use all other types of the `alloc` and `collections` crates, including:
We can also use all other types of the `alloc` crate, including:
- the reference counted pointers [Rc] and [Arc]
- the owned string type [String] and the [format!] macro
@@ -581,14 +574,14 @@ We can also use all other types of the `alloc` and `collections` crates, includi
- [BinaryHeap]
- [BTreeMap] and [BTreeSet]
[Rc]: https://doc.rust-lang.org/nightly/alloc/rc/
[Arc]: https://doc.rust-lang.org/nightly/alloc/arc/
[String]: https://doc.rust-lang.org/nightly/collections/string/struct.String.html
[Linked List]: https://doc.rust-lang.org/nightly/collections/linked_list/struct.LinkedList.html
[VecDeque]: https://doc.rust-lang.org/nightly/collections/vec_deque/struct.VecDeque.html
[BinaryHeap]: https://doc.rust-lang.org/nightly/collections/binary_heap/struct.BinaryHeap.html
[BTreeMap]: https://doc.rust-lang.org/nightly/collections/btree_map/struct.BTreeMap.html
[BTreeSet]: https://doc.rust-lang.org/nightly/collections/btree_set/struct.BTreeSet.html
[Rc]: https://doc.rust-lang.org/1.10.0/alloc/rc/
[Arc]: https://doc.rust-lang.org/1.10.0/alloc/arc/
[String]: https://doc.rust-lang.org/1.10.0/collections/string/struct.String.html
[Linked List]: https://doc.rust-lang.org/1.10.0/collections/linked_list/struct.LinkedList.html
[VecDeque]: https://doc.rust-lang.org/1.10.0/collections/vec_deque/struct.VecDeque.html
[BinaryHeap]: https://doc.rust-lang.org/1.10.0/collections/binary_heap/struct.BinaryHeap.html
[BTreeMap]: https://doc.rust-lang.org/1.10.0/collections/btree_map/struct.BTreeMap.html
[BTreeSet]: https://doc.rust-lang.org/1.10.0/collections/btree_set/struct.BTreeSet.html
## A better Allocator
Right now, we leak every freed memory block. Thus, we run out of memory quickly, for example, by creating a new `String` in each iteration of a loop:
@@ -621,25 +614,25 @@ We will choose another solution with different tradoffs. It's not clearly “bet
A freed memory block is not used anymore and no one needs the stored information. It is still mapped to a virtual address and backed by a physical page. So we just store the information about the freed block _in the block itself_. We keep a pointer to the first block and store a pointer to the next block in each block. Thus, we create a single linked list:
![Linked List Allocator](/images/linked-list-allocator/overview.svg)
![Linked List Allocator](overview.svg)
In the following, we call a freed block a _hole_. Each hole stores its size and a pointer to the next hole. If a hole is larger than needed, we leave the remaining memory unused. By storing a pointer to the first hole, we are able to traverse the complete list.
#### Initialization
When the heap is created, all of its memory is unused. Thus, it forms a single large hole:
![Heap Initialization](/images/linked-list-allocator/initialization.svg)
![Heap Initialization](initialization.svg)
The optional pointer to the next hole is set to `None`.
#### Allocation
In order to allocate a block of memory, we need to find a hole that satisfies the size and alignment requirements. If the found hole is larger than required, we split it into two smaller holes. For example, when we allocate a 24 byte block right after initialization, we split the single hole into a hole of size 24 and a hole with the remaining size:
![split hole](/images/linked-list-allocator/split-hole.svg)
![split hole](split-hole.svg)
Then we use the new 24 byte hole to perform the allocation:
![24 bytes allocated](/images/linked-list-allocator/allocate.svg)
![24 bytes allocated](allocate.svg)
To find a suitable hole, we can use several search strategies:
@@ -658,11 +651,11 @@ However, both best fit and worst fit have a significant problem: They need to sc
#### Deallocation
To deallocate a block of memory, we can just insert its corresponding hole somewhere into the list. However, we need to merge adjacent holes. Otherwise, we are unable to reuse the freed memory for larger allocations. For example:
![deallocate memory, which leads to adjacent holes](/images/linked-list-allocator/deallocate.svg)
![deallocate memory, which leads to adjacent holes](deallocate.svg)
In order to use these adjacent holes for a large allocation, we need to merge them to a single large hole first:
![merge adjacent holes and allocate large block](/images/linked-list-allocator/merge-holes-and-allocate.svg)
![merge adjacent holes and allocate large block](merge-holes-and-allocate.svg)
The easiest way to ensure that adjacent holes are always merged, is to keep the hole list sorted by address. Thus, we only need to check the predecessor and the successor in the list when we free a memory block. If they are adjacent to the freed block, we merge the corresponding holes. Else, we insert the freed block as a new hole at the correct position.
@@ -673,167 +666,54 @@ The detailed implementation would go beyond the scope of this post, since it con
- We need to satisfy the alignment requirements, which requires additional splitting logic.
- The minimal hole size of 16 bytes: We must not create smaller holes when splitting a hole.
I created the [linked_list_allocator] crate to handle all of these cases. It consists of a [Heap struct] that provides an `allocate_first_fit` and a `deallocate` method. If you are interested in the implementation details, check out the [source code][linked_list_allocator source].
I created the [linked_list_allocator] crate to handle all of these cases. It consists of a [Heap struct] that provides an `allocate_first_fit` and a `deallocate` method. It also contains a [LockedHeap] type that wraps `Heap` into spinlock so that it's usable as a static system allocator. If you are interested in the implementation details, check out the [source code][linked_list_allocator source].
[linked_list_allocator]: https://crates.io/crates/linked_list_allocator
[Heap struct]: http://phil-opp.github.io/linked-list-allocator/linked_list_allocator/struct.Heap.html
[linked_list_allocator]: https://docs.rs/crate/linked_list_allocator/0.4.1
[Heap struct]: https://docs.rs/linked_list_allocator/0.4.1/linked_list_allocator/struct.Heap.html
[LockedHeap]: https://docs.rs/linked_list_allocator/0.4.1/linked_list_allocator/struct.LockedHeap.html
[linked_list_allocator source]: https://github.com/phil-opp/linked-list-allocator
So we just need to implement Rust's allocation modules and integrate it into our kernel. We start by creating a new `hole_list_allocator`[^1] crate inside the `libs` directory:
We need to add the extern crate to our `Cargo.toml` and our `lib.rs`:
[^1]: The name `linked_list_allocator` is already taken, sorry :P.
```shell
> cd libs
> cargo new hole_list_allocator
> cd hole_list_allocator
```
We add the `allocator` and `no_std` attributes to `src/lib.rs` like described above:
```rust
// in libs/hole_list_allocator/src/lib.rs
#![feature(allocator)]
#![allocator]
#![no_std]
```
We also add a static allocator protected by a spinlock, but this time we use the `Heap` type of the `linked_list_allocator` crate:
```rust
// in libs/hole_list_allocator/src/lib.rs
#![feature(const_fn)]
use spin::Mutex;
use linked_list_allocator::Heap;
extern crate spin;
extern crate linked_list_allocator;
pub const HEAP_START: usize = 0o_000_001_000_000_0000;
pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB
static HEAP: Mutex<Heap> = Mutex::new(Heap::new(HEAP_START, HEAP_SIZE));
```
Note that we use the same values for `HEAP_START` and `HEAP_SIZE` as in the `bump_allocator`.
We need to add the extern crates to our `Cargo.toml`:
``` shell
> cargo add spin
``` bash
> cargo add linked_list_allocator
```
However, we get an error when we try to compile it:
```rust
// in src/lib.rs
extern crate linked_list_allocator;
```
error: function calls in statics are limited to constant functions,
struct and enum constructors [E0015]
static HEAP: Mutex<Heap> = Mutex::new(Heap::new(HEAP_START, HEAP_SIZE));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
The reason is that the `Heap::new` function needs to initialize the first hole (like described [above](#initialization)). This can't be done at compile time, so the function can't be a `const` function. Therefore we can't use it to initialize a static.
There is an easy solution for crates with access to the standard library: [lazy_static]. It automatically initializes the static when it's used the first time. By default, it relies on the `std::sync::once` module and is thus unusable in our kernel. Fortunately it has a `spin_no_std` feature for `no_std` projects.
[lazy_static]: https://github.com/rust-lang-nursery/lazy-static.rs
So let's use the `lazy_static!` macro to fix our `hole_list_allocator`:
```toml
# in libs/hole_list_allocator/Cargo.toml
[dependencies.lazy_static]
version = "0.2.1"
features = ["spin_no_std"]
```
Now we can change our global allocator:
```rust
// in libs/hole_list_allocator/src/lib.rs
use linked_list_allocator::LockedHeap;
#[macro_use]
extern crate lazy_static;
lazy_static! {
static ref HEAP: Mutex<Heap> = Mutex::new(unsafe {
Heap::new(HEAP_START, HEAP_SIZE)
});
}
#[global_allocator]
static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty();
```
The `unsafe` block is required since `Heap::new` is `unsafe`. It's unsafe because it assumes that `HEAP_START` is a valid and unused address.
Now we can implement the allocation functions:
We can't initialize the linked list allocator statically, since it needs to initialize the first hole (like described [above](#initialization)). This can't be done at compile time, so the function can't be a `const` function. Therefore we can only create an empty heap and initialize it later at runtime. For that, we add the following lines to our `rust_main` function:
```rust
// in libs/hole_list_allocator/src/lib.rs
// in src/lib.rs
#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
HEAP.lock().allocate_first_fit(size, align).expect("out of memory")
}
pub extern "C" fn rust_main(multiboot_information_address: usize) {
[…]
#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, size: usize, align: usize) {
unsafe { HEAP.lock().deallocate(ptr, size, align) };
// set up guard page and map the heap pages
memory::init(boot_info);
// initialize the heap allocator
unsafe {
HEAP_ALLOCATOR.lock().init(HEAP_START, HEAP_START + HEAP_SIZE);
}
[…]
}
```
The remaining functions are implemented like above:
```rust
// in libs/hole_list_allocator/src/lib.rs
#[no_mangle]
pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
size
}
#[no_mangle]
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, size: usize,
_new_size: usize, _align: usize) -> usize
{
size
}
#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize,
align: usize) -> *mut u8 {
use core::{ptr, cmp};
// from: https://github.com/rust-lang/rust/blob/
// c66d2380a810c9a2b3dbb4f93a830b101ee49cc2/
// src/liballoc_system/lib.rs#L98-L101
let new_ptr = __rust_allocate(new_size, align);
unsafe { ptr::copy(ptr, new_ptr, cmp::min(size, new_size)) };
__rust_deallocate(ptr, size, align);
new_ptr
}
```
Now we just need to replace every use of `bump_allocator` with `hole_list_allocator` in our kernel:
```toml
# in Cargo.toml
[dependencies.hole_list_allocator]
path = "libs/hole_list_allocator"
```
```diff
in src/lib.rs:
-extern crate bump_allocator;
+extern crate hole_list_allocator;
in memory::init in src/memory/mod.rs:
-use bump_allocator::{HEAP_START, HEAP_SIZE};
+use hole_list_allocator::{HEAP_START, HEAP_SIZE};
```
It is important that we initialize the heap _after_ mapping the heap pages, since the init function writes to the heap memory (the first hole).
Our kernel uses the new allocator now, so we can deallocate memory without leaking it. The example from above should work now without causing an OOM situation:
@@ -857,4 +737,4 @@ Now we're able to use heap storage in our kernel without leaking memory. This al
## What's next?
This post concludes the section about memory management for now. We will revisit this topic eventually, but now it's time to explore other topics. The upcoming posts will be about CPU exceptions and interrupts. We will catch all page, double, and triple faults and create a driver to read keyboard input. The [next post] starts by setting up a so-called _Interrupt Descriptor Table_.
[next post]: {{% relref "2016-05-28-catching-exceptions.md" %}}
[next post]: @/edition-1/posts/09-handling-exceptions/index.md

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -0,0 +1,473 @@
+++
title = "Handling Exceptions"
weight = 9
path = "handling-exceptions"
aliases = ["handling-exceptions.html"]
date = 2017-03-26
template = "edition-1/page.html"
+++
In this post, we start exploring CPU exceptions. Exceptions occur in various erroneous situations, for example when accessing an invalid memory address or when dividing by zero. To catch them, we have to set up an _interrupt descriptor table_ that provides handler functions. At the end of this post, our kernel will be able to catch [breakpoint exceptions] and to resume normal execution afterwards.
[breakpoint exceptions]: https://wiki.osdev.org/Exceptions#Breakpoint
<!-- more -->
As always, the complete source code is available on [GitHub]. Please file [issues] for any problems, questions, or improvement suggestions. There is also a comment section at the end of this page.
[GitHub]: https://github.com/phil-opp/blog_os/tree/first_edition_post_9
[issues]: https://github.com/phil-opp/blog_os/issues
## Exceptions
An exception signals that something is wrong with the current instruction. For example, the CPU issues an exception if the current instruction tries to divide by 0. When an exception occurs, the CPU interrupts its current work and immediately calls a specific exception handler function, depending on the exception type.
We've already seen several types of exceptions in our kernel:
- **Invalid Opcode**: This exception occurs when the current instruction is invalid. For example, this exception occurred when we tried to use SSE instructions before enabling SSE. Without SSE, the CPU didn't know the `movups` and `movaps` instructions, so it throws an exception when it stumbles over them.
- **Page Fault**: A page fault occurs on illegal memory accesses. For example, if the current instruction tries to read from an unmapped page or tries to write to a read-only page.
- **Double Fault**: When an exception occurs, the CPU tries to call the corresponding handler function. If another exception occurs _while calling the exception handler_, the CPU raises a double fault exception. This exception also occurs when there is no handler function registered for an exception.
- **Triple Fault**: If an exception occurs while the CPU tries to call the double fault handler function, it issues a fatal _triple fault_. We can't catch or handle a triple fault. Most processors react by resetting themselves and rebooting the operating system. This causes the bootloops we experienced in the previous posts.
For the full list of exceptions check out the [OSDev wiki][exceptions].
[exceptions]: https://wiki.osdev.org/Exceptions
### The Interrupt Descriptor Table
In order to catch and handle exceptions, we have to set up a so-called _Interrupt Descriptor Table_ (IDT). In this table we can specify a handler function for each CPU exception. The hardware uses this table directly, so we need to follow a predefined format. Each entry must have the following 16-byte structure:
Type| Name | Description
----|--------------------------|-----------------------------------
u16 | Function Pointer [0:15] | The lower bits of the pointer to the handler function.
u16 | GDT selector | Selector of a code segment in the GDT.
u16 | Options | (see below)
u16 | Function Pointer [16:31] | The middle bits of the pointer to the handler function.
u32 | Function Pointer [32:63] | The remaining bits of the pointer to the handler function.
u32 | Reserved |
The options field has the following format:
Bits | Name | Description
------|-----------------------------------|-----------------------------------
0-2 | Interrupt Stack Table Index | 0: Don't switch stacks, 1-7: Switch to the n-th stack in the Interrupt Stack Table when this handler is called.
3-7 | Reserved |
8 | 0: Interrupt Gate, 1: Trap Gate | If this bit is 0, interrupts are disabled when this handler is called.
9-11 | must be one |
12 | must be zero |
1314 | Descriptor Privilege Level (DPL) | The minimal privilege level required for calling this handler.
15 | Present |
Each exception has a predefined IDT index. For example the invalid opcode exception has table index 6 and the page fault exception has table index 14. Thus, the hardware can automatically load the corresponding IDT entry for each exception. The [Exception Table][exceptions] in the OSDev wiki shows the IDT indexes of all exceptions in the “Vector nr.” column.
When an exception occurs, the CPU roughly does the following:
1. Push some registers on the stack, including the instruction pointer and the [RFLAGS] register. (We will use these values later in this post.)
2. Read the corresponding entry from the Interrupt Descriptor Table (IDT). For example, the CPU reads the 14-th entry when a page fault occurs.
3. Check if the entry is present. Raise a double fault if not.
4. Disable interrupts if the entry is an interrupt gate (bit 40 not set).
5. Load the specified GDT selector into the CS segment.
6. Jump to the specified handler function.
[RFLAGS]: https://en.wikipedia.org/wiki/FLAGS_register
## An IDT Type
Instead of creating our own IDT type, we will use the [`Idt` struct] of the `x86_64` crate, which looks like this:
[`Idt` struct]: https://docs.rs/x86_64/0.1.1/x86_64/structures/idt/struct.Idt.html
``` rust
#[repr(C)]
pub struct Idt {
pub divide_by_zero: IdtEntry<HandlerFunc>,
pub debug: IdtEntry<HandlerFunc>,
pub non_maskable_interrupt: IdtEntry<HandlerFunc>,
pub breakpoint: IdtEntry<HandlerFunc>,
pub overflow: IdtEntry<HandlerFunc>,
pub bound_range_exceeded: IdtEntry<HandlerFunc>,
pub invalid_opcode: IdtEntry<HandlerFunc>,
pub device_not_available: IdtEntry<HandlerFunc>,
pub double_fault: IdtEntry<HandlerFuncWithErrCode>,
pub invalid_tss: IdtEntry<HandlerFuncWithErrCode>,
pub segment_not_present: IdtEntry<HandlerFuncWithErrCode>,
pub stack_segment_fault: IdtEntry<HandlerFuncWithErrCode>,
pub general_protection_fault: IdtEntry<HandlerFuncWithErrCode>,
pub page_fault: IdtEntry<PageFaultHandlerFunc>,
pub x87_floating_point: IdtEntry<HandlerFunc>,
pub alignment_check: IdtEntry<HandlerFuncWithErrCode>,
pub machine_check: IdtEntry<HandlerFunc>,
pub simd_floating_point: IdtEntry<HandlerFunc>,
pub virtualization: IdtEntry<HandlerFunc>,
pub security_exception: IdtEntry<HandlerFuncWithErrCode>,
pub interrupts: [IdtEntry<HandlerFunc>; 224],
// some fields omitted
}
```
The fields have the type [`IdtEntry<F>`], which is a struct that represents the fields of an IDT entry (see the table above). The type parameter `F` defines the expected handler function type. We see that some entries require a [`HandlerFunc`] and some entries require a [`HandlerFuncWithErrCode`]. The page fault even has its own special type: [`PageFaultHandlerFunc`].
[`IdtEntry<F>`]: https://docs.rs/x86_64/0.1.1/x86_64/structures/idt/struct.IdtEntry.html
[`HandlerFunc`]: https://docs.rs/x86_64/0.1.1/x86_64/structures/idt/type.HandlerFunc.html
[`HandlerFuncWithErrCode`]: https://docs.rs/x86_64/0.1.1/x86_64/structures/idt/type.HandlerFuncWithErrCode.html
[`PageFaultHandlerFunc`]: https://docs.rs/x86_64/0.1.1/x86_64/structures/idt/type.PageFaultHandlerFunc.html
Let's look at the `HandlerFunc` type first:
```rust
type HandlerFunc = extern "x86-interrupt" fn(_: &mut ExceptionStackFrame);
```
It's a [type alias] for an `extern "x86-interrupt" fn` type. The `extern` keyword defines a function with a [foreign calling convention] and is often used to communicate with C code (`extern "C" fn`). But what is the `x86-interrupt` calling convention?
[type alias]: https://doc.rust-lang.org/book/type-aliases.html
[foreign calling convention]: https://doc.rust-lang.org/1.30.0/book/first-edition/ffi.html#foreign-calling-conventions
## The Interrupt Calling Convention
Exceptions are quite similar to function calls: The CPU jumps to the first instruction of the called function and executes it. Afterwards, if the function is not diverging, the CPU jumps to the return address and continues the execution of the parent function.
However, there is a major difference between exceptions and function calls: A function call is invoked voluntary by a compiler inserted `call` instruction, while an exception might occur at _any_ instruction. In order to understand the consequences of this difference, we need to examine function calls in more detail.
[Calling conventions] specify the details of a function call. For example, they specify where function parameters are placed (e.g. in registers or on the stack) and how results are returned. On x86_64 Linux, the following rules apply for C functions (specified in the [System V ABI]):
[Calling conventions]: https://en.wikipedia.org/wiki/Calling_convention
[System V ABI]: https://refspecs.linuxbase.org/elf/gabi41.pdf
- the first six integer arguments are passed in registers `rdi`, `rsi`, `rdx`, `rcx`, `r8`, `r9`
- additional arguments are passed on the stack
- results are returned in `rax` and `rdx`
Note that Rust does not follow the C ABI (in fact, [there isn't even a Rust ABI yet][rust abi]). So these rules apply only to functions declared as `extern "C" fn`.
[rust abi]: https://github.com/rust-lang/rfcs/issues/600
### Preserved and Scratch Registers
The calling convention divides the registers in two parts: _preserved_ and _scratch_ registers.
The values of _preserved_ registers must remain unchanged across function calls. So a called function (the _“callee”_) is only allowed to overwrite these registers if it restores their original values before returning. Therefore these registers are called _“callee-saved”_. A common pattern is to save these registers to the stack at the function's beginning and restore them just before returning.
In contrast, a called function is allowed to overwrite _scratch_ registers without restrictions. If the caller wants to preserve the value of a scratch register across a function call, it needs to backup and restore it before the function call (e.g. by pushing it to the stack). So the scratch registers are _caller-saved_.
On x86_64, the C calling convention specifies the following preserved and scratch registers:
preserved registers | scratch registers
---|---
`rbp`, `rbx`, `rsp`, `r12`, `r13`, `r14`, `r15` | `rax`, `rcx`, `rdx`, `rsi`, `rdi`, `r8`, `r9`, `r10`, `r11`
_callee-saved_ | _caller-saved_
The compiler knows these rules, so it generates the code accordingly. For example, most functions begin with a `push rbp`, which backups `rbp` on the stack (because it's a callee-saved register).
### Preserving all Registers
In contrast to function calls, exceptions can occur on _any_ instruction. In most cases we don't even know at compile time if the generated code will cause an exception. For example, the compiler can't know if an instruction causes a stack overflow or a page fault.
Since we don't know when an exception occurs, we can't backup any registers before. This means that we can't use a calling convention that relies on caller-saved registers for exception handlers. Instead, we need a calling convention means that preserves _all registers_. The `x86-interrupt` calling convention is such a calling convention, so it guarantees that all register values are restored to their original values on function return.
### The Exception Stack Frame
On a normal function call (using the `call` instruction), the CPU pushes the return address before jumping to the target function. On function return (using the `ret` instruction), the CPU pops this return address and jumps to it. So the stack frame of a normal function call looks like this:
![function stack frame](function-stack-frame.svg)
For exception and interrupt handlers, however, pushing a return address would not suffice, since interrupt handlers often run in a different context (stack pointer, CPU flags, etc.). Instead, the CPU performs the following steps when an interrupt occurs:
1. **Aligning the stack pointer**: An interrupt can occur at any instructions, so the stack pointer can have any value, too. However, some CPU instructions (e.g. some SSE instructions) require that the stack pointer is aligned on a 16 byte boundary, therefore the CPU performs such an alignment right after the interrupt.
2. **Switching stacks** (in some cases): A stack switch occurs when the CPU privilege level changes, for example when a CPU exception occurs in an user mode program. It is also possible to configure stack switches for specific interrupts using the so-called _Interrupt Stack Table_ (described in the next post).
3. **Pushing the old stack pointer**: The CPU pushes the values of the stack pointer (`rsp`) and the stack segment (`ss`) registers at the time when the interrupt occurred (before the alignment). This makes it possible to restore the original stack pointer when returning from an interrupt handler.
4. **Pushing and updating the `RFLAGS` register**: The [`RFLAGS`] register contains various control and status bits. On interrupt entry, the CPU changes some bits and pushes the old value.
5. **Pushing the instruction pointer**: Before jumping to the interrupt handler function, the CPU pushes the instruction pointer (`rip`) and the code segment (`cs`). This is comparable to the return address push of a normal function call.
6. **Pushing an error code** (for some exceptions): For some specific exceptions such as page faults, the CPU pushes an error code, which describes the cause of the exception.
7. **Invoking the interrupt handler**: The CPU reads the address and the segment descriptor of the interrupt handler function from the corresponding field in the IDT. It then invokes this handler by loading the values into the `rip` and `cs` registers.
[`RFLAGS`]: https://en.wikipedia.org/wiki/FLAGS_register
So the _exception stack frame_ looks like this:
![exception stack frame](exception-stack-frame.svg)
In the `x86_64` crate, the exception stack frame is represented by the [`ExceptionStackFrame`] struct. It is passed to interrupt handlers as `&mut` and can be used to retrieve additional information about the exception's cause. The struct contains no error code field, since only some few exceptions push an error code. These exceptions use the separate [`HandlerFuncWithErrCode`] function type, which has an additional `error_code` argument.
[`ExceptionStackFrame`]: https://docs.rs/x86_64/0.1.1/x86_64/structures/idt/struct.ExceptionStackFrame.html
### Behind the Scenes
The `x86-interrupt` calling convention is a powerful abstraction that hides almost all of the messy details of the exception handling process. However, sometimes it's useful to know what's happening behind the curtain. Here is a short overview of the things that the `x86-interrupt` calling convention takes care of:
- **Retrieving the arguments**: Most calling conventions expect that the arguments are passed in registers. This is not possible for exception handlers, since we must not overwrite any register values before backing them up on the stack. Instead, the `x86-interrupt` calling convention is aware that the arguments already lie on the stack at a specific offset.
- **Returning using `iretq`**: Since the exception stack frame completely differs from stack frames of normal function calls, we can't return from handlers functions through the normal `ret` instruction. Instead, the `iretq` instruction must be used.
- **Handling the error code**: The error code, which is pushed for some exceptions, makes things much more complex. It changes the stack alignment (see the next point) and needs to be popped off the stack before returning. The `x86-interrupt` calling convention handles all that complexity. However, it doesn't know which handler function is used for which exception, so it needs to deduce that information from the number of function arguments. That means that the programmer is still responsible to use the correct function type for each exception. Luckily, the `Idt` type defined by the `x86_64` crate ensures that the correct function types are used.
- **Aligning the stack**: There are some instructions (especially SSE instructions) that require a 16-byte stack alignment. The CPU ensures this alignment whenever an exception occurs, but for some exceptions it destroys it again later when it pushes an error code. The `x86-interrupt` calling convention takes care of this by realigning the stack in this case.
If you are interested in more details: We also have a series of posts that explains exception handling using [naked functions] linked [at the end of this post][too-much-magic].
[naked functions]: https://github.com/rust-lang/rfcs/blob/master/text/1201-naked-fns.md
[too-much-magic]: #too-much-magic
## Implementation
Now that we've understood the theory, it's time to handle CPU exceptions in our kernel. We start by creating a new `interrupts` module:
``` rust
// in src/lib.rs
...
mod interrupts;
...
```
In the new module, we create an `init` function, that creates a new `Idt`:
``` rust
// in src/interrupts.rs
use x86_64::structures::idt::Idt;
pub fn init() {
let mut idt = Idt::new();
}
```
Now we can add handler functions. We start by adding a handler for the [breakpoint exception]. The breakpoint exception is the perfect exception to test exception handling. Its only purpose is to temporary pause a program when the breakpoint instruction `int3` is executed.
[breakpoint exception]: https://wiki.osdev.org/Exceptions#Breakpoint
The breakpoint exception is commonly used in debuggers: When the user sets a breakpoint, the debugger overwrites the corresponding instruction with the `int3` instruction so that the CPU throws the breakpoint exception when it reaches that line. When the user wants to continue the program, the debugger replaces the `int3` instruction with the original instruction again and continues the program. For more details, see the ["_How debuggers work_"] series.
["_How debuggers work_"]: https://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints
For our use case, we don't need to overwrite any instructions (it wouldn't even be possible since we [set the page table flags] to read-only). Instead, we just want to print a message when the breakpoint instruction is executed and then continue the program.
[set the page table flags]: @/edition-1/posts/07-remap-the-kernel/index.md#using-the-correct-flags
So let's create a simple `breakpoint_handler` function and add it to our IDT:
```rust
/// in src/interrupts.rs
use x86_64::structures::idt::ExceptionStackFrame;
pub fn init() {
let mut idt = Idt::new();
idt.breakpoint.set_handler_fn(breakpoint_handler);
}
extern "x86-interrupt" fn breakpoint_handler(
stack_frame: &mut ExceptionStackFrame)
{
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
}
```
Our handler just outputs a message and pretty-prints the exception stack frame.
When we try to compile it, the following error occurs:
```
error: x86-interrupt ABI is experimental and subject to change (see issue #40180)
--> src/interrupts.rs:8:1
|
8 | extern "x86-interrupt" fn breakpoint_handler(
| _^ starting here...
9 | | stack_frame: &mut ExceptionStackFrame)
10 | | {
11 | | println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
12 | | }
| |_^ ...ending here
|
= help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable
```
This error occurs because the `x86-interrupt` calling convention is still unstable. To use it anyway, we have to explicitly enable it by adding `#![feature(abi_x86_interrupt)]` on the top of our `lib.rs`.
### Loading the IDT
In order that the CPU uses our new interrupt descriptor table, we need to load it using the [`lidt`] instruction. The `Idt` struct of the `x86_64` provides a [`load`][Idt::load] method function for that. Let's try to use it:
[`lidt`]: https://www.felixcloutier.com/x86/lgdt:lidt
[Idt::load]: https://docs.rs/x86_64/0.1.1/x86_64/structures/idt/struct.Idt.html#method.load
```rust
pub fn init() {
let mut idt = Idt::new();
idt.breakpoint.set_handler_fn(breakpoint_handler);
idt.load();
}
```
When we try to compile it now, the following error occurs:
```
error: `idt` does not live long enough
--> src/interrupts/mod.rs:43:5
|
43 | idt.load();
| ^^^ does not live long enough
44 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
```
So the `load` methods expects a `&'static self`, that is a reference that is valid for the complete runtime of the program. The reason is that the CPU will access this table on every interrupt until we load a different IDT. So using a shorter lifetime than `'static` could lead to use-after-free bugs.
In fact, this is exactly what happens here. Our `idt` is created on the stack, so it is only valid inside the `init` function. Afterwards the stack memory is reused for other functions, so the CPU would interpret random stack memory as IDT. Luckily, the `Idt::load` method encodes this lifetime requirement in its function definition, so that the Rust compiler is able to prevent this possible bug at compile time.
In order to fix this problem, we need to store our `idt` at a place where it has a `'static` lifetime. To achieve this, we could either allocate our IDT on the heap using `Box` and then convert it to a `'static` reference or we can store the IDT as a `static`. Let's try the latter:
```rust
static IDT: Idt = Idt::new();
pub fn init() {
IDT.breakpoint.set_handler_fn(breakpoint_handler);
IDT.load();
}
```
There are two problems with this. First, statics are immutable, so we can't modify the breakpoint entry from our `init` function. Second, the `Idt::new` function is not a [`const` function], so it can't be used to initialize a `static`. We could solve this problem by using a [`static mut`] of type `Option<Idt>`:
[`const` function]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
[`static mut`]: https://doc.rust-lang.org/1.30.0/book/second-edition/ch19-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable
```rust
static mut IDT: Option<Idt> = None;
pub fn init() {
unsafe {
let IDT = Some(Idt::new());
let idt = IDT.as_mut_ref().unwrap();
idt.breakpoint.set_handler_fn(breakpoint_handler);
idt.load();
}
}
```
This variant compiles without errors but it's far from idiomatic. `static mut`s are very prone to data races, so we need an [`unsafe` block] on each access. Also, we need to explicitly `unwrap` the `IDT` on each use, since might be `None`.
[`unsafe` block]: https://doc.rust-lang.org/1.30.0/book/second-edition/ch19-01-unsafe-rust.html#unsafe-superpowers
#### Lazy Statics to the Rescue
The one-time initialization of statics with non-const functions is a common problem in Rust. Fortunately, there already exists a good solution in a crate named [lazy_static]. This crate provides a `lazy_static!` macro that defines a lazily initialized `static`. Instead of computing its value at compile time, the `static` laziliy initializes itself when it's accessed the first time. Thus, the initialization happens at runtime so that arbitrarily complex initialization code is possible.
[lazy_static]: https://docs.rs/lazy_static/0.2.4/lazy_static/
Let's add the `lazy_static` crate to our project:
```rust
// in src/lib.rs
#[macro_use]
extern crate lazy_static;
```
```toml
# in Cargo.toml
[dependencies.lazy_static]
version = "0.2.4"
features = ["spin_no_std"]
```
We need the `spin_no_std` feature, since we don't link the standard library. We also need the `#[macro_use]` attribute on the `extern crate` line to import the `lazy_static!` macro.
Now we can create our static IDT using `lazy_static`:
```rust
lazy_static! {
static ref IDT: Idt = {
let mut idt = Idt::new();
idt.breakpoint.set_handler_fn(breakpoint_handler);
idt
};
}
pub fn init() {
IDT.load();
}
```
Note how this solution requires no `unsafe` blocks or `unwrap` calls.
> ##### Aside: How does the `lazy_static!` macro work?
>
> The macro generates a `static` of type `Once<Idt>`. The [`Once`][spin::Once] type is provided by the `spin` crate and allows deferred one-time initialization. It is implemented using an [`AtomicUsize`] for synchronization and an [`UnsafeCell`] for storing the (possibly uninitialized) value. So this solution also uses `unsafe` behind the scenes, but it is abstracted away in a safe interface.
[spin::Once]: https://docs.rs/spin/0.4.5/spin/struct.Once.html
[`AtomicUsize`]: https://doc.rust-lang.org/nightly/core/sync/atomic/struct.AtomicUsize.html
[`UnsafeCell`]: https://doc.rust-lang.org/nightly/core/cell/struct.UnsafeCell.html
### Testing it
Now we should be able to handle breakpoint exceptions! Let's try it in our `rust_main`:
```rust
// in src/lib.rs
pub extern "C" fn rust_main(...) {
...
memory::init(boot_info);
// initialize our IDT
interrupts::init();
// invoke a breakpoint exception
x86_64::instructions::interrupts::int3();
println!("It did not crash!");
loop {}
}
```
When we run it in QEMU now (using `make run`), we see the following:
![QEMU printing `EXCEPTION: BREAKPOINT` and the exception stack frame](qemu-breakpoint-exception.png)
It works! The CPU successfully invokes our breakpoint handler, which prints the message, and then returns back to the `rust_main` function, where the `It did not crash!` message is printed.
> **Aside**: If it doesn't work and a boot loop occurs, this might be caused by a kernel stack overflow. Try increasing the stack size to at least 16kB (4096 * 4 bytes) in the `boot.asm` file.
We see that the exception stack frame tells us the instruction and stack pointers at the time when the exception occurred. This information is very useful when debugging unexpected exceptions. For example, we can look at the corresponding assembly line using `objdump`:
```
> objdump -d build/kernel-x86_64.bin | grep -B5 "1140a6:"
00000000001140a0 <x86_64::instructions::interrupts::int3::h015bf61815bb8afe>:
1140a0: 55 push %rbp
1140a1: 48 89 e5 mov %rsp,%rbp
1140a4: 50 push %rax
1140a5: cc int3
1140a6: 48 83 c4 08 add $0x8,%rsp
```
The `-d` flags disassembles the `code` section and `-C` flag makes function names more readable by [demangling] them. The `-B` flag of `grep` specifies the number of preceding lines that should be shown (5 in our case).
[demangling]: https://en.wikipedia.org/wiki/Name_mangling
We clearly see the `int3` exception that caused the breakpoint exception at address `1140a5`. Wait… the stored instruction pointer was `1140a6`, which is a normal `add` operation. What's happening here?
### Faults, Aborts, and Traps
The answer is that the stored instruction pointer only points to the causing instruction for _fault_ type exceptions, but not for _trap_ or _abort_ type exceptions. The difference between these types is the following:
- **Faults** are exceptions that can be corrected so that the program can continue as if nothing happened. An example is the [page fault], which can often be resolved by loading the accessed page from the disk into memory.
- **Aborts** are fatal exceptions that can't be recovered. Examples are [machine check exception] or the [double fault].
- **Traps** are only reported to the kernel, but don't hinder the continuation of the program. Examples are the breakpoint exception and the [overflow exception].
[page fault]: https://wiki.osdev.org/Exceptions#Page_Fault
[machine check exception]: https://wiki.osdev.org/Exceptions#Machine_Check
[double fault]: https://wiki.osdev.org/Exceptions#Double_Fault
[overflow exception]: https://wiki.osdev.org/Exceptions#Overflow
The reason for the diffent instruction pointer values is that the stored value is also the return address. So for faults, the instruction that caused the exception is restarted and might cause the same exception again if it's not resolved. This would not make much sense for traps, since invoking the breakpoint exception again would just cause another breakpoint exception[^fn-breakpoint-restart-use-cases]. Thus the instruction pointer points to the _next_ instruction for these exceptions.
In some cases, the distinction between faults and traps is vague. For example, the [debug exception] behaves like a fault in some cases, but like a trap in others. So to find out the meaning of the saved instruction pointer, it is a good idea to read the official documentation for the exception, which can be found in the [AMD64 manual] in Section 8.2. For example, for the breakpoint exception it says:
[debug exception]: https://wiki.osdev.org/Exceptions#Debug
[AMD64 manual]: https://www.amd.com/system/files/TechDocs/24593.pdf
> `#BP` is a trap-type exception. The saved instruction pointer points to the byte after the `INT3` instruction.
The documentation of the [`Idt`] struct and the [OSDev Wiki][osdev wiki exceptions] also contain this information.
[`Idt`]: https://docs.rs/x86_64/0.1.1/x86_64/structures/idt/struct.Idt.html
[osdev wiki exceptions]: https://wiki.osdev.org/Exceptions
## Too much Magic?
The `x86-interrupt` calling convention and the [`Idt`] type made the exception handling process relatively straightforward and painless. If this was too much magic for you and you like to learn all the gory details of exception handling, we got you covered: Our [“Handling Exceptions with Naked Functions”] series shows how to handle exceptions without the `x86-interrupt` calling convention and also creates its own `Idt` type. Historically, these posts were the main exception handling posts before the `x86-interrupt` calling convention and the `x86_64` crate existed.
[“Handling Exceptions with Naked Functions”]: @/edition-1/extra/naked-exceptions/_index.md
## What's next?
We've successfully caught our first exception and returned from it! The next step is to add handlers for other common exceptions such as page faults. We also need to make sure that we never cause a [triple fault], since it causes a complete system reset. The next post explains how we can avoid this by correctly catching [double faults].
[triple fault]: https://wiki.osdev.org/Triple_Fault
[double faults]: https://wiki.osdev.org/Double_Fault#Double_Fault
## Footnotes
[^fn-breakpoint-restart-use-cases]: There are valid use cases for restarting an instruction that caused a breakpoint. The most common use case is a debugger: When setting a breakpoint on some code line, the debugger overwrites the corresponding instruction with an `int3` instruction, so that the CPU traps when that line is executed. When the user continues execution, the debugger swaps in the original instruction and continues the program from the replaced instruction.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -0,0 +1,920 @@
+++
title = "Double Faults"
weight = 10
path = "double-faults"
aliases = ["double-faults.html"]
date = 2017-01-02
template = "edition-1/page.html"
+++
In this post we explore double faults in detail. We also set up an _Interrupt Stack Table_ to catch double faults on a separate kernel stack. This way, we can completely prevent triple faults, even on kernel stack overflow.
<!-- more -->
As always, the complete source code is available on [GitHub]. Please file [issues] for any problems, questions, or improvement suggestions. There is also a [gitter chat] and a comment section at the end of this page.
[GitHub]: https://github.com/phil-opp/blog_os/tree/first_edition_post_10
[issues]: https://github.com/phil-opp/blog_os/issues
[gitter chat]: https://gitter.im/phil-opp/blog_os
## What is a Double Fault?
In simplified terms, a double fault is a special exception that occurs when the CPU fails to invoke an exception handler. For example, it occurs when a page fault is triggered but there is no page fault handler registered in the [Interrupt Descriptor Table][IDT] (IDT). So it's kind of similar to catch-all blocks in programming languages with exceptions, e.g. `catch(...)` in C++ or `catch(Exception e)` in Java or C#.
[IDT]: @/edition-1/posts/09-handling-exceptions/index.md#the-interrupt-descriptor-table
A double fault behaves like a normal exception. It has the vector number `8` and we can define a normal handler function for it in the IDT. It is really important to provide a double fault handler, because if a double fault is unhandled a fatal _triple fault_ occurs. Triple faults can't be caught and most hardware reacts with a system reset.
### Triggering a Double Fault
Let's provoke a double fault by triggering an exception for that we didn't define a handler function:
```rust
// in src/lib.rs
#[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) {
...
// initialize our IDT
interrupts::init();
// trigger a page fault
unsafe {
*(0xdeadbeaf as *mut u64) = 42;
};
println!("It did not crash!");
loop {}
}
```
We try to write to address `0xdeadbeaf`, but the corresponding page is not present in the page tables. Thus, a page fault occurs. We haven't registered a page fault handler in our [IDT], so a double fault occurs.
When we start our kernel now, we see that it enters an endless boot loop:
![boot loop](boot-loop.gif)
The reason for the boot loop is the following:
1. The CPU tries to write to `0xdeadbeaf`, which causes a page fault.
2. The CPU looks at the corresponding entry in the IDT and sees that the present bit isn't set. Thus, it can't call the page fault handler and a double fault occurs.
3. The CPU looks at the IDT entry of the double fault handler, but this entry is also non-present. Thus, a _triple_ fault occurs.
4. A triple fault is fatal. QEMU reacts to it like most real hardware and issues a system reset.
So in order to prevent this triple fault, we need to either provide a handler function for page faults or a double fault handler. Let's start with the latter, since we want to avoid triple faults in all cases.
### A Double Fault Handler
A double fault is a normal exception with an error code, so we can use our `handler_with_error_code` macro to create a wrapper function:
```rust
// in src/interrupts.rs
lazy_static! {
static ref IDT: idt::Idt = {
let mut idt = idt::Idt::new();
idt.breakpoint.set_handler_fn(breakpoint_handler);
idt.double_fault.set_handler_fn(double_fault_handler);
idt
};
}
// our new double fault handler
extern "x86-interrupt" fn double_fault_handler(
stack_frame: &mut ExceptionStackFrame, _error_code: u64)
{
println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
loop {}
}
```
Our handler prints a short error message and dumps the exception stack frame. The error code of the double fault handler is always zero, so there's no reason to print it.
When we start our kernel now, we should see that the double fault handler is invoked:
![QEMU printing `EXCEPTION: DOUBLE FAULT` and the exception stack frame](qemu-catch-double-fault.png)
It worked! Here is what happens this time:
1. The CPU executes tries to write to `0xdeadbeaf`, which causes a page fault.
2. Like before, the CPU looks at the corresponding entry in the IDT and sees that the present bit isn't set. Thus, a double fault occurs.
3. The CPU jumps to the now present double fault handler.
The triple fault (and the boot-loop) no longer occurs, since the CPU can now call the double fault handler.
That was quite straightforward! So why do we need a whole post for this topic? Well, we're now able to catch _most_ double faults, but there are some cases where our current approach doesn't suffice.
## Causes of Double Faults
Before we look at the special cases, we need to know the exact causes of double faults. Above, we used a pretty vague definition:
> A double fault is a special exception that occurs when the CPU fails to invoke an exception handler.
What does _“fails to invoke”_ mean exactly? The handler is not present? The handler is [swapped out]? And what happens if a handler causes exceptions itself?
[swapped out]: http://pages.cs.wisc.edu/~remzi/OSTEP/vm-beyondphys.pdf
For example, what happens if… :
1. a divide-by-zero exception occurs, but the corresponding handler function is swapped out?
2. a page fault occurs, but the page fault handler is swapped out?
3. a divide-by-zero handler causes a breakpoint exception, but the breakpoint handler is swapped out?
4. our kernel overflows its stack and the [guard page] is hit?
[guard page]: @/edition-1/posts/07-remap-the-kernel/index.md#creating-a-guard-page
Fortunately, the AMD64 manual ([PDF][AMD64 manual]) has an exact definition (in Section 8.2.9). According to it, a “double fault exception _can_ occur when a second exception occurs during the handling of a prior (first) exception handler”. The _“can”_ is important: Only very specific combinations of exceptions lead to a double fault. These combinations are:
First Exception | Second Exception
----------------|-----------------
[Divide-by-zero],<br>[Invalid TSS],<br>[Segment Not Present],<br>[Stack-Segment Fault],<br>[General Protection Fault] | [Invalid TSS],<br>[Segment Not Present],<br>[Stack-Segment Fault],<br>[General Protection Fault]
[Page Fault] | [Page Fault],<br>[Invalid TSS],<br>[Segment Not Present],<br>[Stack-Segment Fault],<br>[General Protection Fault]
[Divide-by-zero]: https://wiki.osdev.org/Exceptions#Division_Error
[Invalid TSS]: https://wiki.osdev.org/Exceptions#Invalid_TSS
[Segment Not Present]: https://wiki.osdev.org/Exceptions#Segment_Not_Present
[Stack-Segment Fault]: https://wiki.osdev.org/Exceptions#Stack-Segment_Fault
[General Protection Fault]: https://wiki.osdev.org/Exceptions#General_Protection_Fault
[Page Fault]: https://wiki.osdev.org/Exceptions#Page_Fault
[AMD64 manual]: https://www.amd.com/system/files/TechDocs/24593.pdf
So for example a divide-by-zero fault followed by a page fault is fine (the page fault handler is invoked), but a divide-by-zero fault followed by a general-protection fault leads to a double fault.
With the help of this table, we can answer the first three of the above questions:
1. If a divide-by-zero exception occurs and the corresponding handler function is swapped out, a _page fault_ occurs and the _page fault handler_ is invoked.
2. If a page fault occurs and the page fault handler is swapped out, a _double fault_ occurs and the _double fault handler_ is invoked.
3. If a divide-by-zero handler causes a breakpoint exception, the CPU tries to invoke the breakpoint handler. If the breakpoint handler is swapped out, a _page fault_ occurs and the _page fault handler_ is invoked.
In fact, even the case of a non-present handler follows this scheme: A non-present handler causes a _segment-not-present_ exception. We didn't define a segment-not-present handler, so another segment-not-present exception occurs. According to the table, this leads to a double fault.
### Kernel Stack Overflow
Let's look at the fourth question:
> What happens if our kernel overflows its stack and the [guard page] is hit?
When our kernel overflows its stack and hits the guard page, a _page fault_ occurs. The CPU looks up the page fault handler in the IDT and tries to push the [exception stack frame] onto the stack. However, our current stack pointer still points to the non-present guard page. Thus, a second page fault occurs, which causes a double fault (according to the above table).
[exception stack frame]: @/edition-1/posts/09-handling-exceptions/index.md#the-exception-stack-frame
So the CPU tries to call our _double fault handler_ now. However, on a double fault the CPU tries to push the exception stack frame, too. Our stack pointer still points to the guard page, so a _third_ page fault occurs, which causes a _triple fault_ and a system reboot. So our current double fault handler can't avoid a triple fault in this case.
Let's try it ourselves! We can easily provoke a kernel stack overflow by calling a function that recurses endlessly:
```rust
// in src/lib.rs
#[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) {
...
// initialize our IDT
interrupts::init();
fn stack_overflow() {
stack_overflow(); // for each recursion, the return address is pushed
}
// trigger a stack overflow
stack_overflow();
println!("It did not crash!");
loop {}
}
```
When we try this code in QEMU, we see that the system enters a boot-loop again.
So how can we avoid this problem? We can't omit the pushing of the exception stack frame, since the CPU itself does it. So we need to ensure somehow that the stack is always valid when a double fault exception occurs. Fortunately, the x86_64 architecture has a solution to this problem.
## Switching Stacks
The x86_64 architecture is able to switch to a predefined, known-good stack when an exception occurs. This switch happens at hardware level, so it can be performed before the CPU pushes the exception stack frame.
This switching mechanism is implemented as an _Interrupt Stack Table_ (IST). The IST is a table of 7 pointers to known-good stacks. In Rust-like pseudo code:
```rust
struct InterruptStackTable {
stack_pointers: [Option<StackPointer>; 7],
}
```
For each exception handler, we can choose a stack from the IST through the `options` field in the corresponding [IDT entry]. For example, we could use the first stack in the IST for our double fault handler. Then the CPU would automatically switch to this stack whenever a double fault occurs. This switch would happen before anything is pushed, so it would prevent the triple fault.
[IDT entry]: @/edition-1/posts/09-handling-exceptions/index.md#the-interrupt-descriptor-table
### Allocating a new Stack
In order to fill an Interrupt Stack Table later, we need a way to allocate new stacks. Therefore we extend our `memory` module with a new `stack_allocator` submodule:
```rust
// in src/memory/mod.rs
mod stack_allocator;
```
First, we create a new `StackAllocator` struct and a constructor function:
```rust
// in src/memory/stack_allocator.rs
use memory::paging::PageIter;
pub struct StackAllocator {
range: PageIter,
}
impl StackAllocator {
pub fn new(page_range: PageIter) -> StackAllocator {
StackAllocator { range: page_range }
}
}
```
We create a simple `StackAllocator` that allocates stacks from a given range of pages (`PageIter` is an Iterator over a range of pages; we introduced it [in the kernel heap post].).
[in the kernel heap post]: @/edition-1/posts/08-kernel-heap/index.md#mapping-the-heap
We add a `alloc_stack` method that allocates a new stack:
```rust
// in src/memory/stack_allocator.rs
use memory::paging::{self, Page, ActivePageTable};
use memory::{PAGE_SIZE, FrameAllocator};
impl StackAllocator {
pub fn alloc_stack<FA: FrameAllocator>(&mut self,
active_table: &mut ActivePageTable,
frame_allocator: &mut FA,
size_in_pages: usize)
-> Option<Stack> {
if size_in_pages == 0 {
return None; /* a zero sized stack makes no sense */
}
// clone the range, since we only want to change it on success
let mut range = self.range.clone();
// try to allocate the stack pages and a guard page
let guard_page = range.next();
let stack_start = range.next();
let stack_end = if size_in_pages == 1 {
stack_start
} else {
// choose the (size_in_pages-2)th element, since index
// starts at 0 and we already allocated the start page
range.nth(size_in_pages - 2)
};
match (guard_page, stack_start, stack_end) {
(Some(_), Some(start), Some(end)) => {
// success! write back updated range
self.range = range;
// map stack pages to physical frames
for page in Page::range_inclusive(start, end) {
active_table.map(page, paging::WRITABLE, frame_allocator);
}
// create a new stack
let top_of_stack = end.start_address() + PAGE_SIZE;
Some(Stack::new(top_of_stack, start.start_address()))
}
_ => None, /* not enough pages */
}
}
}
```
The method takes mutable references to the [ActivePageTable] and a [FrameAllocator], since it needs to map the new virtual stack pages to physical frames. We define that the stack size is a multiple of the page size.
[ActivePageTable]: @/edition-1/posts/06-page-tables/index.md#page-table-ownership
[FrameAllocator]: @/edition-1/posts/05-allocating-frames/index.md#a-frame-allocator
Instead of operating directly on `self.range`, we [clone] it and only write it back on success. This way, subsequent stack allocations can still succeed if there are pages left (e.g., a call with `size_in_pages = 3` can still succeed after a failed call with `size_in_pages = 100`).
In order to be able to clone `PageIter`, we add a `#[derive(Clone)]` to its definition in `src/memory/paging/mod.rs`. We also need to make the `start_address` method of the `Page` type public (in the same file).
[clone]: https://doc.rust-lang.org/nightly/core/clone/trait.Clone.html#tymethod.clone
The actual allocation is straightforward: First, we choose the next page as [guard page]. Then we choose the next `size_in_pages` pages as stack pages using [Iterator::nth]. If all three variables are `Some`, the allocation succeeded and we map the stack pages to physical frames using [ActivePageTable::map]. The guard page remains unmapped.
[Iterator::nth]: https://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.nth
[ActivePageTable::map]: @/edition-1/posts/06-page-tables/index.md#more-mapping-functions
Finally, we create and return a new `Stack`, which we define as follows:
```rust
// in src/memory/stack_allocator.rs
#[derive(Debug)]
pub struct Stack {
top: usize,
bottom: usize,
}
impl Stack {
fn new(top: usize, bottom: usize) -> Stack {
assert!(top > bottom);
Stack {
top: top,
bottom: bottom,
}
}
pub fn top(&self) -> usize {
self.top
}
pub fn bottom(&self) -> usize {
self.bottom
}
}
```
The `Stack` struct describes a stack though its top and bottom addresses.
#### The Memory Controller
Now we're able to allocate a new double fault stack. However, we add one more level of abstraction to make things easier. For that we add a new `MemoryController` type to our `memory` module:
```rust
// in src/memory/mod.rs
pub use self::stack_allocator::Stack;
pub struct MemoryController {
active_table: paging::ActivePageTable,
frame_allocator: AreaFrameAllocator,
stack_allocator: stack_allocator::StackAllocator,
}
impl MemoryController {
pub fn alloc_stack(&mut self, size_in_pages: usize) -> Option<Stack> {
let &mut MemoryController { ref mut active_table,
ref mut frame_allocator,
ref mut stack_allocator } = self;
stack_allocator.alloc_stack(active_table, frame_allocator,
size_in_pages)
}
}
```
The `MemoryController` struct holds the three types that are required for `alloc_stack` and provides a simpler interface (only one argument). The `alloc_stack` wrapper just takes the tree types as `&mut` through [destructuring] and forwards them to the `stack_allocator`. The [ref mut]-s are needed to take the inner fields by mutable reference. Note that we're re-exporting the `Stack` type since it is returned by `alloc_stack`.
[destructuring]: https://doc.rust-lang.org/1.10.0/book/patterns.html#destructuring
[ref mut]: https://doc.rust-lang.org/1.30.0/book/second-edition/ch18-03-pattern-syntax.html#creating-references-in-patterns-with-ref-and-ref-mut
The last step is to create a `StackAllocator` and return a `MemoryController` from `memory::init`:
```rust
// in src/memory/mod.rs
pub fn init(boot_info: &BootInformation) -> MemoryController {
...
let stack_allocator = {
let stack_alloc_start = heap_end_page + 1;
let stack_alloc_end = stack_alloc_start + 100;
let stack_alloc_range = Page::range_inclusive(stack_alloc_start,
stack_alloc_end);
stack_allocator::StackAllocator::new(stack_alloc_range)
};
MemoryController {
active_table: active_table,
frame_allocator: frame_allocator,
stack_allocator: stack_allocator,
}
}
```
We create a new `StackAllocator` with a range of 100 pages starting right after the last heap page.
In order to do arithmetic on pages (e.g. calculate the hundredth page after `stack_alloc_start`), we implement `Add<usize>` for `Page`:
```rust
// in src/memory/paging/mod.rs
use core::ops::Add;
impl Add<usize> for Page {
type Output = Page;
fn add(self, rhs: usize) -> Page {
Page { number: self.number + rhs }
}
}
```
#### Allocating a Double Fault Stack
Now we can allocate a new double fault stack by passing the memory controller to our `interrupts::init` function:
```rust
// in src/lib.rs
#[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) {
...
// set up guard page and map the heap pages
let mut memory_controller = memory::init(boot_info); // new return type
// initialize our IDT
interrupts::init(&mut memory_controller); // new argument
...
}
// in src/interrupts.rs
use memory::MemoryController;
pub fn init(memory_controller: &mut MemoryController) {
let double_fault_stack = memory_controller.alloc_stack(1)
.expect("could not allocate double fault stack");
IDT.load();
}
```
We allocate a 4096 bytes stack (one page) for our double fault handler. Now we just need some way to tell the CPU that it should use this stack for handling double faults.
### The IST and TSS
The Interrupt Stack Table (IST) is part of an old legacy structure called _[Task State Segment]_ \(TSS). The TSS used to hold various information (e.g. processor register state) about a task in 32-bit mode and was for example used for [hardware context switching]. However, hardware context switching is no longer supported in 64-bit mode and the format of the TSS changed completely.
[Task State Segment]: https://en.wikipedia.org/wiki/Task_state_segment
[hardware context switching]: https://wiki.osdev.org/Context_Switching#Hardware_Context_Switching
On x86_64, the TSS no longer holds any task specific information at all. Instead, it holds two stack tables (the IST is one of them). The only common field between the 32-bit and 64-bit TSS is the pointer to the [I/O port permissions bitmap].
[I/O port permissions bitmap]: https://en.wikipedia.org/wiki/Task_state_segment#I.2FO_port_permissions
The 64-bit TSS has the following format:
Field | Type
------ | ----------------
<span style="opacity: 0.5">(reserved)</span> | `u32`
Privilege Stack Table | `[u64; 3]`
<span style="opacity: 0.5">(reserved)</span> | `u64`
Interrupt Stack Table | `[u64; 7]`
<span style="opacity: 0.5">(reserved)</span> | `u64`
<span style="opacity: 0.5">(reserved)</span> | `u16`
I/O Map Base Address | `u16`
The _Privilege Stack Table_ is used by the CPU when the privilege level changes. For example, if an exception occurs while the CPU is in user mode (privilege level 3), the CPU normally switches to kernel mode (privilege level 0) before invoking the exception handler. In that case, the CPU would switch to the 0th stack in the Privilege Stack Table (since 0 is the target privilege level). We don't have any user mode programs yet, so we ignore this table for now.
#### Creating a TSS
Let's create a new TSS that contains our double fault stack in its interrupt stack table. For that we need a TSS struct. Fortunately, the `x86_64` crate already contains a [`TaskStateSegment` struct] that we can use:
[`TaskStateSegment` struct]: https://docs.rs/x86_64/0.1.1/x86_64/structures/tss/struct.TaskStateSegment.html
```rust
// in src/interrupts.rs
use x86_64::structures::tss::TaskStateSegment;
```
Let's create a new TSS in our `interrupts::init` function:
```rust
// in src/interrupts.rs
use x86_64::VirtualAddress;
const DOUBLE_FAULT_IST_INDEX: usize = 0;
pub fn init(memory_controller: &mut MemoryController) {
let double_fault_stack = memory_controller.alloc_stack(1)
.expect("could not allocate double fault stack");
let mut tss = TaskStateSegment::new();
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] = VirtualAddress(
double_fault_stack.top());
IDT.load();
}
```
We define that the 0th IST entry is the double fault stack (any other IST index would work too). We create a new TSS through the `TaskStateSegment::new` function and load the top address (stacks grow downwards) of the double fault stack into the 0th entry.
#### Loading the TSS
Now that we created a new TSS, we need a way to tell the CPU that it should use it. Unfortunately, this is a bit cumbersome, since the TSS is a Task State _Segment_ (for historical reasons). So instead of loading the table directly, we need to add a new segment descriptor to the [Global Descriptor Table] \(GDT). Then we can load our TSS invoking the [`ltr` instruction] with the respective GDT index.
[Global Descriptor Table]: https://web.archive.org/web/20190217233448/https://www.flingos.co.uk/docs/reference/Global-Descriptor-Table/
[`ltr` instruction]: https://www.felixcloutier.com/x86/ltr
### The Global Descriptor Table (again)
The Global Descriptor Table (GDT) is a relict that was used for [memory segmentation] before paging became the de facto standard. It is still needed in 64-bit mode for various things such as kernel/user mode configuration or TSS loading.
[memory segmentation]: https://en.wikipedia.org/wiki/X86_memory_segmentation
We already created a GDT [when switching to long mode]. Back then, we used assembly to create valid code and data segment descriptors, which were required to enter 64-bit mode. We could just edit that assembly file and add an additional TSS descriptor. However, we now have the expressiveness of Rust, so let's do it in Rust instead.
[when switching to long mode]: @/edition-1/posts/02-entering-longmode/index.md#the-global-descriptor-table
We start by creating a new `interrupts::gdt` submodule. For that we need to rename the `src/interrupts.rs` file to `src/interrupts/mod.rs`. Then we can create a new submodule:
```rust
// in src/interrupts/mod.rs
mod gdt;
```
```rust
// src/interrupts/gdt.rs
pub struct Gdt {
table: [u64; 8],
next_free: usize,
}
impl Gdt {
pub fn new() -> Gdt {
Gdt {
table: [0; 8],
next_free: 1,
}
}
}
```
We create a simple `Gdt` struct with two fields. The `table` field contains the actual GDT modeled as a `[u64; 8]`. Theoretically, a GDT can have up to 8192 entries, but this doesn't make much sense in 64-bit mode (since there is no real segmentation support). Eight entries should be more than enough for our system.
The `next_free` field stores the index of the next free entry. We initialize it with `1` since the 0th entry needs always needs to be 0 in a valid GDT.
#### User and System Segments
There are two types of GDT entries in long mode: user and system segment descriptors. Descriptors for code and data segment segments are user segment descriptors. They contain no addresses since segments always span the complete address space on x86_64 (real segmentation is no longer supported). Thus, user segment descriptors only contain a few flags (e.g. present or user mode) and fit into a single `u64` entry.
System descriptors such as TSS descriptors are different. They often contain a base address and a limit (e.g. TSS start and length) and thus need more than 64 bits. Therefore, system segments are 128 bits. They are stored as two consecutive entries in the GDT.
Consequently, we model a `Descriptor` as an `enum`:
```rust
// in src/interrupts/gdt.rs
pub enum Descriptor {
UserSegment(u64),
SystemSegment(u64, u64),
}
```
The flag bits are common between all descriptor types, so we create a general `DescriptorFlags` type (using the [bitflags] macro):
[bitflags]: https://docs.rs/bitflags/0.9.1/bitflags/macro.bitflags.html
```rust
// in src/interrupts/gdt.rs
bitflags! {
struct DescriptorFlags: u64 {
const CONFORMING = 1 << 42;
const EXECUTABLE = 1 << 43;
const USER_SEGMENT = 1 << 44;
const PRESENT = 1 << 47;
const LONG_MODE = 1 << 53;
}
}
```
We only add flags that are relevant in 64-bit mode. For example, we omit the read/write bit, since it is completely ignored by the CPU in 64-bit mode.
#### Code Segments
We add a function to create kernel mode code segments:
```rust
// in src/interrupts/gdt.rs
impl Descriptor {
pub fn kernel_code_segment() -> Descriptor {
let flags = USER_SEGMENT | PRESENT | EXECUTABLE | LONG_MODE;
Descriptor::UserSegment(flags.bits())
}
}
```
We set the `USER_SEGMENT` bit to indicate a 64 bit user segment descriptor (otherwise the CPU expects a 128 bit system segment descriptor). The `PRESENT`, `EXECUTABLE`, and `LONG_MODE` bits are also needed for a 64-bit mode code segment.
The data segment registers `ds`, `ss`, and `es` are completely ignored in 64-bit mode, so we don't need any data segment descriptors in our GDT.
#### TSS Segments
A TSS descriptor is a system segment descriptor with the following format:
Bit(s) | Name | Meaning
--------------------- | ------ | ----------------------------------
0-15 | **limit 0-15** | the first 2 byte of the TSS's limit
16-39 | **base 0-23** | the first 3 byte of the TSS's base address
40-43 | **type** | must be `0b1001` for an available 64-bit TSS
44 | zero | must be 0
45-46 | privilege | the [ring level]: 0 for kernel, 3 for user
47 | **present** | must be 1 for valid selectors
48-51 | limit 16-19 | bits 16 to 19 of the segment's limit
52 | available | freely available to the OS
53-54 | ignored |
55 | granularity | if it's set, the limit is the number of pages, else it's a byte number
56-63 | **base 24-31** | the fourth byte of the base address
64-95 | **base 32-63** | the last four bytes of the base address
96-127 | ignored/must be zero | bits 104-108 must be zero, the rest is ignored
[ring level]: https://wiki.osdev.org/Security#Rings
We only need the bold fields for our TSS descriptor. For example, we don't need the `limit 16-19` field since a TSS has a fixed size that is smaller than `2^16`.
Let's add a function to our descriptor that creates a TSS descriptor for a given TSS:
```rust
// in src/interrupts/gdt.rs
use x86_64::structures::tss::TaskStateSegment;
impl Descriptor {
pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor {
use core::mem::size_of;
use bit_field::BitField;
let ptr = tss as *const _ as u64;
let mut low = PRESENT.bits();
// base
low.set_bits(16..40, ptr.get_bits(0..24));
low.set_bits(56..64, ptr.get_bits(24..32));
// limit (the `-1` in needed since the bound is inclusive)
low.set_bits(0..16, (size_of::<TaskStateSegment>() - 1) as u64);
// type (0b1001 = available 64-bit tss)
low.set_bits(40..44, 0b1001);
let mut high = 0;
high.set_bits(0..32, ptr.get_bits(32..64));
Descriptor::SystemSegment(low, high)
}
}
```
The `set_bits` and `get_bits` methods are provided by the [`BitField` trait] of the `bit_fields` crate. They allow us to easily get or set specific bits in an integer without using bit masks or shift operations. For example, we can do `x.set_bits(8..12, 42)` instead of `x = (x & 0xfffff0ff) | (42 << 8)`.
[`BitField` trait]: https://docs.rs/bit_field/0.6.0/bit_field/trait.BitField.html#method.get_bit
To link the `bit_fields` crate, we modify our `Cargo.toml` and our `src/lib.rs`:
```toml
[dependencies]
bit_field = "0.7.0"
```
```rust
extern crate bit_field;
```
We require the `'static` lifetime for the `TaskStateSegment` reference, since the hardware might access it on every interrupt as long as the OS runs.
#### Adding Descriptors to the GDT
In order to add descriptors to the GDT, we add a `add_entry` method:
```rust
// in src/interrupts/gdt.rs
use x86_64::structures::gdt::SegmentSelector;
use x86_64::PrivilegeLevel;
impl Gdt {
pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
let index = match entry {
Descriptor::UserSegment(value) => self.push(value),
Descriptor::SystemSegment(value_low, value_high) => {
let index = self.push(value_low);
self.push(value_high);
index
}
};
SegmentSelector::new(index as u16, PrivilegeLevel::Ring0)
}
}
```
For an user segment we just push the `u64` and remember the index. For a system segment, we push the low and high `u64` and use the index of the low value. We then use this index to return a new [SegmentSelector].
[SegmentSelector]: https://docs.rs/x86/0.8.0/x86/shared/segmentation/struct.SegmentSelector.html#method.new
The `push` method looks like this:
```rust
// in src/interrupts/gdt.rs
impl Gdt {
fn push(&mut self, value: u64) -> usize {
if self.next_free < self.table.len() {
let index = self.next_free;
self.table[index] = value;
self.next_free += 1;
index
} else {
panic!("GDT full");
}
}
}
```
The method just writes to the `next_free` entry and returns the corresponding index. If there is no free entry left, we panic since this likely indicates a programming error (we should never need to create more than two or three GDT entries for our kernel).
#### Loading the GDT
To load the GDT, we add a new `load` method:
```rust
// in src/interrupts/gdt.rs
impl Gdt {
pub fn load(&'static self) {
use x86_64::instructions::tables::{DescriptorTablePointer, lgdt};
use core::mem::size_of;
let ptr = DescriptorTablePointer {
base: self.table.as_ptr() as u64,
limit: (self.table.len() * size_of::<u64>() - 1) as u16,
};
unsafe { lgdt(&ptr) };
}
}
```
We use the [`DescriptorTablePointer` struct] and the [`lgdt` function] provided by the `x86_64` crate to load our GDT. Again, we require a `'static` reference since the GDT possibly needs to live for the rest of the run time.
[`DescriptorTablePointer` struct]: https://docs.rs/x86_64/0.1.1/x86_64/instructions/tables/struct.DescriptorTablePointer.html
[`lgdt` function]: https://docs.rs/x86_64/0.1.1/x86_64/instructions/tables/fn.lgdt.html
### Putting it together
We now have a double fault stack and are able to create and load a TSS (which contains an IST). So let's put everything together to catch kernel stack overflows.
We already created a new TSS in our `interrupts::init` function. Now we can load this TSS by creating a new GDT:
```rust
// in src/interrupts/mod.rs
pub fn init(memory_controller: &mut MemoryController) {
let double_fault_stack = memory_controller.alloc_stack(1)
.expect("could not allocate double fault stack");
let mut tss = TaskStateSegment::new();
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] = VirtualAddress(
double_fault_stack.top());
let mut gdt = gdt::Gdt::new();
let code_selector = gdt.add_entry(gdt::Descriptor::kernel_code_segment());
let tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss));
gdt.load();
IDT.load();
}
```
However, when we try to compile it, the following errors occur:
```
error: `tss` does not live long enough
--> src/interrupts/mod.rs:118:68
|
118 | let tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss));
| does not live long enough ^^^
...
122 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error: `gdt` does not live long enough
--> src/interrupts/mod.rs:119:5
|
119 | gdt.load();
| ^^^ does not live long enough
...
122 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
```
The problem is that we require that the TSS and GDT are valid for the rest of the run time (i.e. for the `'static` lifetime). But our created `tss` and `gdt` live on the stack and are thus destroyed at the end of the `init` function. So how do we fix this problem?
We could allocate our TSS and GDT on the heap using `Box` and use [into_raw] and a bit of `unsafe` to convert it to `&'static` references ([RFC 1233] was closed unfortunately).
Alternatively, we could store them in a `static` somehow. The [`lazy_static` macro] doesn't work here, since we need access to the `MemoryController` for initialization. However, we can use its fundamental building block, the [`spin::Once` type].
[into_raw]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_raw
[RFC 1233]: https://github.com/rust-lang/rfcs/pull/1233
[`lazy_static` macro]: https://docs.rs/lazy_static/0.2.2/lazy_static/
[`spin::Once` type]: https://docs.rs/spin/0.4.5/spin/struct.Once.html
#### spin::Once
Let's try to solve our problem using [`spin::Once`][`spin::Once` type]:
```rust
// in src/interrupts/mod.rs
use spin::Once;
static TSS: Once<TaskStateSegment> = Once::new();
static GDT: Once<gdt::Gdt> = Once::new();
```
The `Once` type allows us to initialize a `static` at runtime. It is safe because the only way to access the static value is through the provided methods ([call_once][Once::call_once], [try][Once::try], and [wait][Once::wait]). Thus, no value can be read before initialization and the value can only be initialized once.
[Once::call_once]: https://docs.rs/spin/0.4.5/spin/struct.Once.html#method.call_once
[Once::try]: https://docs.rs/spin/0.4.5/spin/struct.Once.html#method.try
[Once::wait]: https://docs.rs/spin/0.4.5/spin/struct.Once.html#method.wait
(The `Once` was added in spin 0.4, so you're probably need to update your spin dependency.)
So let's rewrite our `interrupts::init` function to use the static `TSS` and `GDT`:
```rust
pub fn init(memory_controller: &mut MemoryController) {
let double_fault_stack = memory_controller.alloc_stack(1)
.expect("could not allocate double fault stack");
let tss = TSS.call_once(|| {
let mut tss = TaskStateSegment::new();
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] = VirtualAddress(
double_fault_stack.top());
tss
});
let gdt = GDT.call_once(|| {
let mut gdt = gdt::Gdt::new();
let code_selector = gdt.add_entry(gdt::Descriptor::
kernel_code_segment());
let tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss));
gdt
});
gdt.load();
IDT.load();
}
```
Now it should compile again!
#### The final Steps
We're almost done. We successfully loaded our new GDT, which contains a TSS descriptor. Now there are just a few steps left:
1. We changed our GDT, so we should reload the `cs`, the code segment register. This required since the old segment selector could point a different GDT descriptor now (e.g. a TSS descriptor).
2. We loaded a GDT that contains a TSS selector, but we still need to tell the CPU that it should use that TSS.
3. As soon as our TSS is loaded, the CPU has access to a valid interrupt stack table (IST). Then we can tell the CPU that it should use our new double fault stack by modifying our double fault IDT entry.
For the first two steps, we need access to the `code_selector` and `tss_selector` variables outside of the closure. We can achieve this by moving the `let` declarations out of the closure:
```rust
// in src/interrupts/mod.rs
pub fn init(memory_controller: &mut MemoryController) {
use x86_64::structures::gdt::SegmentSelector;
use x86_64::instructions::segmentation::set_cs;
use x86_64::instructions::tables::load_tss;
...
let mut code_selector = SegmentSelector(0);
let mut tss_selector = SegmentSelector(0);
let gdt = GDT.call_once(|| {
let mut gdt = gdt::Gdt::new();
code_selector = gdt.add_entry(gdt::Descriptor::kernel_code_segment());
tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss));
gdt
});
gdt.load();
unsafe {
// reload code segment register
set_cs(code_selector);
// load TSS
load_tss(tss_selector);
}
IDT.load();
}
```
We first set the descriptors to `empty` and then update them from inside the closure (which implicitly borrows them as `&mut`). Now we're able to reload the code segment register using [`set_cs`] and to load the TSS using [`load_tss`].
[`set_cs`]: https://docs.rs/x86_64/0.1.2/x86_64/instructions/segmentation/fn.set_cs.html
[`load_tss`]: https://docs.rs/x86_64/0.1.2/x86_64/instructions/tables/fn.load_tss.html
Now that we loaded a valid TSS and interrupt stack table, we can set the stack index for our double fault handler in the IDT:
```rust
// in src/interrupt/mod.rs
lazy_static! {
static ref IDT: idt::Idt = {
let mut idt = idt::Idt::new();
...
unsafe {
idt.double_fault.set_handler_fn(double_fault_handler)
.set_stack_index(DOUBLE_FAULT_IST_INDEX as u16);
}
...
};
}
```
The `set_stack_index` method is unsafe because the the caller must ensure that the used index is valid and not already used for another exception.
That's it! Now the CPU should switch to the double fault stack whenever a double fault occurs. Thus, we are able to catch _all_ double faults, including kernel stack overflows:
![QEMU printing `EXCEPTION: DOUBLE FAULT` and a dump of the exception stack frame](qemu-double-fault-on-stack-overflow.png)
From now on we should never see a triple fault again!
## What's next?
Now that we mastered exceptions, it's time to explore another kind of interrupts: interrupts from external devices such as timers, keyboards, or network controllers. These hardware interrupts are very similar to exceptions, e.g. they are also dispatched through the IDT.
However, unlike exceptions, they don't arise directly on the CPU. Instead, an _interrupt controller_ aggregates these interrupts and forwards them to CPU depending on their priority. In the next posts we will explore the two interrupt controller variants on x86: the [Intel 8259] \(“PIC”) and the [APIC]. This will allow us to react to keyboard and mouse input.
[Intel 8259]: https://en.wikipedia.org/wiki/Intel_8259
[APIC]: https://en.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,6 @@
+++
title = "Posts"
sort_by = "weight"
insert_anchor_links = "left"
render = false
+++

View File

@@ -0,0 +1,5 @@
+++
title = "Second Edition"
template = "redirect-to-frontpage.html"
aliases = ["second-edition/index.html"]
+++

View File

@@ -0,0 +1,7 @@
+++
title = "Extra Content"
insert_anchor_links = "left"
render = false
sort_by = "weight"
page_template = "edition-2/extra.html"
+++

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

View File

@@ -0,0 +1,115 @@
+++
title = "Building on Android"
weight = 3
aliases = ["second-edition/extra/building-on-android/index.html"]
+++
I finally managed to get `blog_os` building on my Android phone using [termux](https://termux.com/). This post explains the necessary steps to set it up.
<!-- more -->
<div class = "warning">
This post is outdated and the instructions provided here might not work anymore.
</div>
<img src="building-on-android.png" alt="Screenshot of the compilation output from android" style="height: 50rem;" >
### Install Termux and Nightly Rust
First, install [termux](https://termux.com/) from the [Google Play Store](https://play.google.com/store/apps/details?id=com.termux) or from F-Droid. After installing, open it and perform the following steps:
- Install fish shell, set as default shell, and launch it:
```
pkg install fish
chsh -s fish
fish
```
This step is of course optional. However, if you continue with bash you will need to adjust some of the following commands to bash syntax.
- Install some basic tools:
```
pkg install wget tar
```
- Add the [community repository by its-pointless](https://wiki.termux.com/wiki/Package_Management):
```
wget https://its-pointless.github.io/setup-pointless-repo.sh
bash setup-pointless-repo.sh
```
- Install cargo and a nightly version of rustc:
```
pkg install rustc cargo rustc-nightly
```
- Prepend the nightly rustc path to your `PATH` in order to use nightly (fish syntax):
```
set -U fish_user_paths $PREFIX/opt/rust-nightly/bin/ $fish_user_paths
```
Now `rustc --version` should work and output a nightly version number.
### Install Git and Clone blog_os
We need something to compile, so let's download the `blog_os` repository:
- Install git:
```
pkg install git
```
- Clone the `blog_os` repository:
```
git clone https://github.com/phil-opp/blog_os.git
```
If you want to clone/push via SSH, you need to install the `openssh` package: `pkg install openssh`.
### Install Xbuild and Bootimage
Now we're ready to install `cargo xbuild` and `bootimage`
- Run `cargo install`:
```
cargo install cargo-xbuild bootimage
```
- Add the cargo bin directory to your `PATH` (fish syntax):
```
set -U fish_user_paths ~/.cargo/bin/ $fish_user_paths
```
Now `cargo xbuild` and `bootimage` should be available. It does not work yet because `cargo xbuild` needs access to the rust source code. By default it tries to use rustup for this, but we have no rustup support so we need a different way.
### Providing the Rust Source Code
The Rust source code corresponding to our installed nightly is available in the [`its-pointless` repository](https://github.com/its-pointless/its-pointless.github.io):
- Download a tar containing the source code:
```
wget https://github.com/its-pointless/its-pointless.github.io/raw/master/rust-src-nightly.tar.xz
```
- Extract it:
```
tar xf rust-src-nightly.tar.xz
```
- Set the `XARGO_RUST_SRC` environment variable to tell cargo-xbuild the source path (fish syntax):
```
set -Ux XARGO_RUST_SRC ~/rust-src-nightly/rust-src/lib/rustlib/src/rust/src
```
Now cargo-xbuild should no longer complain about a missing `rust-src` component. However it will throw an I/O error after building the sysroot. The problem is that the downloaded Rust source code has a different structure than the source provided by rustup. We can fix this by adding a symbolic link:
```
ln -s ~/../usr/opt/rust-nightly/bin ~/../usr/opt/rust-nightly/lib/rustlib/aarch64-linux-android/bin
```
Now `cargo xbuild --target x86_64-blog_os.json` and `bootimage build` should both work!
I couldn't get QEMU to run yet, so you won't be able to run your kernel. If you manage to get it working, please tell me :).

View File

@@ -0,0 +1,129 @@
+++
title = "A Freestanding Rust Binary"
weight = 1
path = "ar/freestanding-rust-binary"
date = 2018-02-10
[extra]
# Please update this when updating the translation
translation_based_on_commit = "087a464ed77361cff6c459fb42fc655cb9eacbea"
# GitHub usernames of the people that translated this post
translators = ["ZAAFHachemrachid"]
+++
تتمثل الخطوة الأولى في إنشاء نواة نظام التشغيل الخاصة بنا في إنشاء ملف Rust قابل للتنفيذ لا يربط المكتبة القياسية. هذا يجعل من الممكن تشغيل شيفرة Rust على [bare metal] دون نظام تشغيل أساسي.
[bare metal]: https://en.wikipedia.org/wiki/Bare_machine
<!-- more -->
تم تطوير هذه المدونة بشكل مفتوح على [GitHub]. إذا كان لديك أي مشاكل أو أسئلة، يرجى فتح مشكلة هناك. يمكنك أيضًا ترك تعليقات [في الأسفل]. يمكن العثور على الشيفرة المصدرية الكاملة لهذا المنشور في فرع [post-01][post branch].
[GitHub]: https://github.com/phil-opp/blog_os
[at the bottom]: #comments
<!-- fix for zola anchor checker (target is in template): <a id="comments"> -->
[post branch]: https://github.com/phil-opp/blog_os/tree/post-01
<!-- toc -->
## مقدمة
لكتابة نواة نظام تشغيل، نحتاج إلى شيفرة لا تعتمد على أي ميزات نظام تشغيل. هذا يعني أنه لا يمكننا استخدام سلاسل الرسائل(threads) أو الملفات(File System) أو Heap ram أو الشبكة أو الأرقام العشوائية أو الإخراج القياسي(I/O) أو أي ميزات أخرى تتطلب تجريدات نظام التشغيل أو أجهزة معينة. وهذا منطقي، لأننا نحاول كتابة نظام التشغيل الخاص بنا (OS) وبرامج التشغيل الخاصة بنا (drivers).
هذا يعني أنه لا يمكننا استخدام معظم [Rust standard library]، ولكن هناك الكثير من ميزات Rust التي _يمكننا استخدامها. على سبيل المثال، يمكننا استخدام [iterators] و [closures] و [pattern matching] و [option] و [اresult] و [string formatting] وبالطبع [ownership system]. هذه الميزات تجعل من الممكن كتابة نواة بطريقة معبرة جدًا وعالية المستوى دون القلق بشأن [undefined behavior] أو [memory safety].
[option]: https://doc.rust-lang.org/core/option/
[result]:https://doc.rust-lang.org/core/result/
[Rust standard library]: https://doc.rust-lang.org/std/
[iterators]: https://doc.rust-lang.org/book/ch13-02-iterators.html
[closures]: https://doc.rust-lang.org/book/ch13-01-closures.html
[pattern matching]: https://doc.rust-lang.org/book/ch06-00-enums.html
[string formatting]: https://doc.rust-lang.org/core/macro.write.html
[ownership system]: https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html
[undefined behavior]: https://www.nayuki.io/page/undefined-behavior-in-c-and-cplusplus-programs
[memory safety]: https://tonyarcieri.com/it-s-time-for-a-memory-safety-intervention
من أجل إنشاء نواة نظام تشغيل في Rust، نحتاج إلى إنشاء ملف قابل للتنفيذ يمكن تشغيله بدون نظام تشغيل أساسي. غالبًا ما يُطلق على هذا الملف القابل للتنفيذ اسم الملف القابل للتنفيذ ”القائم بذاته“ أو ”المعدني العاري“.
يصف هذا المنشور الخطوات اللازمة لإنشاء ثنائي Rust قائم بذاته ويشرح سبب الحاجة إلى هذه الخطوات. إذا كنت مهتمًا بمثال بسيط فقط، يمكنك **[الانتقال إلى الملخص] (#ملخص)**.
## تعطيل المكتبة القياسية
بشكل افتراضي، تربط جميع صناديق Rust [standard library]، والتي تعتمد على نظام التشغيل لميزات (مثل threads, files, or networking). كما أنها تعتمد أيضًا على مكتبة C القياسية 'libc'، والتي تتفاعل بشكل وثيق مع خدمات نظام التشغيل. نظرًا لأن خطتنا هي كتابة نظام تشغيل، لا يمكننا استخدام أي مكتبات تعتمد على نظام التشغيل. لذا يجب علينا تعطيل التضمين التلقائي للمكتبة القياسية من خلال سمة [no_std].
[standard library]: https://doc.rust-lang.org/std/
[`no_std` attribute]: https://doc.rust-lang.org/1.30.0/book/first-edition/using-rust-without-the-standard-library.html
```
cargo new blog_os --bin --edition 2018
```
لقد أطلقتُ على المشروع اسم ”Blog_os“، ولكن بالطبع يمكنك اختيار اسمك الخاص. تُحدّد علامة ”bin“ أننا نريد إنشاء نسخة binary قابلة للتنفيذ (على عكس المكتبة) وتحدّد علامة ”--- Edition 2018“ أننا نريد استخدام [2018 edition] من Rust لصندوقنا. عندما نُشغّل الأمر، تُنشئ لنا الشحنة بنية الدليل التالية:
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
```
blog_os
├── Cargo.toml
└── src
└── main.rs
```
يحتوي ملف 'Cargo.toml' على تكوين الصندوق، على سبيل المثال اسم الصندوق، والمؤلف، ورقم [semantic version]، والتبعيات. يحتوي الملف 'src/main.rs' على الوحدة النمطية الجذرية للصندوق والدالة 'الرئيسية'. يمكنك تجميع قفصك من خلال 'cargo build' ثم تشغيل الملف الثنائي 'blog_os' المجمّع في المجلد الفرعي 'target/debug'.
[semantic version]: https://semver.org/
### السمة 'no_std'
يربط صندوقنا الآن المكتبة القياسية ضمنيًا بالمكتبة القياسية. دعونا نحاول تعطيل ذلك بإضافة سمة [no_std]:
```rust
// main.rs
#![no_std]
fn main() {
println!("Hello, world!");
}
```
عندما نحاول بناءه الآن (عن طريق تشغيل ”cargo build“)، يحدث الخطأ التالي:
```
error: cannot find macro `println!` in this scope
--> src/main.rs:4:5
|
4 | println!("Hello, world!");
| ^^^^^^^
```
والسبب في هذا الخطأ هو أن [`println` macro] هو جزء من المكتبة القياسية، والتي لم نعد نضمّنها. لذا لم يعد بإمكاننا طباعة الأشياء. هذا أمر منطقي، لأن 'println' يكتب إلى [standard output]، وهو واصف ملف خاص يوفره نظام التشغيل.
[`println` macro]: https://doc.rust-lang.org/std/macro.println.html
[standard output]: https://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29
لذا دعنا نحذف الطباعة ونحاول مرة أخرى بدالة رئيسية فارغة:
```rust
// main.rs
#![no_std]
fn main() {}
```
```
> cargo build
error: `#[panic_handler]` function required, but not found
error: language item required, but not found: `eh_personality`
```
يفتقد بناء المترجمات البرمجية الآن إلى `#[panic_handler]` دالة و _language item_.

View File

@@ -0,0 +1,526 @@
+++
title = " یک باینری مستقل Rust"
weight = 1
path = "fa/freestanding-rust-binary"
date = 2018-02-10
[extra]
# Please update this when updating the translation
translation_based_on_commit = "80136cc0474ae8d2da04f391b5281cfcda068c1a"
# GitHub usernames of the people that translated this post
translators = ["hamidrezakp", "MHBahrampour"]
rtl = true
+++
اولین قدم برای نوشتن سیستم‌عامل، ساخت یک باینری راست (کلمه: Rust) هست که به کتابخانه استاندارد نیازمند نباشد. این باعث می‌شود تا بتوانیم کد راست را بدون سیستم‌عامل زیرین، بر روی سخت افزار [bare metal] اجرا کنیم.
[bare metal]: https://en.wikipedia.org/wiki/Bare_machine
<!-- more -->
این بلاگ بصورت آزاد بر روی [گیت‌هاب] توسعه داده شده. اگر مشکل یا سوالی دارید، لطفاً آن‌جا یک ایشو باز کنید. همچنین می‌توانید [در زیر] این پست کامنت بگذارید. سورس کد کامل این پست را می‌توانید در بِرَنچ [`post-01`][post branch] پیدا کنید.
[گیت‌هاب]: https://github.com/phil-opp/blog_os
[در زیر]: #comments
<!-- fix for zola anchor checker (target is in template): <a id="comments"> -->
[post branch]: https://github.com/phil-opp/blog_os/tree/post-01
<!-- toc -->
## مقدمه
برای نوشتن هسته سیستم‌عامل، ما به کدی نیاز داریم که به هیچ یک از ویژگی‌های سیستم‌عامل نیازی نداشته باشد. یعنی نمی‌توانیم از نخ‌ها (ترجمه: Threads)، فایل‌ها، حافظه هیپ (کلمه: Heap)، شبکه، اعداد تصادفی، ورودی استاندارد، یا هر ویژگی دیگری که نیاز به انتزاعات سیستم‌عامل یا سخت‌افزار خاصی داشته، استفاده کنیم. منطقی هم به نظر می‌رسد، چون ما سعی داریم سیستم‌عامل و درایور‌های خودمان را بنویسیم.
نداشتن انتزاعات سیستم‌عامل به این معنی هست که نمی‌توانیم از بخش زیادی از [کتابخانه استاندارد راست] استفاده کنیم، اما هنوز بسیاری از ویژگی‌های راست هستند که می‌توانیم از آن‌ها استفاده کنیم. به عنوان مثال، می‌توانیم از [iterator] ها، [closure] ها، [pattern matching]، [option]، [result]، [string formatting] و البته [سیستم ownership] استفاده کنیم. این ویژگی‌ها به ما امکان نوشتن هسته به طور رسا، سطح بالا و بدون نگرانی درباره [رفتار تعریف نشده] و [امنیت حافظه] را میدهند.
[option]: https://doc.rust-lang.org/core/option/
[result]:https://doc.rust-lang.org/core/result/
[کتابخانه استاندارد راست]: https://doc.rust-lang.org/std/
[iterators]: https://doc.rust-lang.org/book/ch13-02-iterators.html
[closures]: https://doc.rust-lang.org/book/ch13-01-closures.html
[pattern matching]: https://doc.rust-lang.org/book/ch06-00-enums.html
[string formatting]: https://doc.rust-lang.org/core/macro.write.html
[سیستم ownership]: https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html
[رفتار تعریف نشده]: https://www.nayuki.io/page/undefined-behavior-in-c-and-cplusplus-programs
[امنیت حافظه]: https://tonyarcieri.com/it-s-time-for-a-memory-safety-intervention
برای ساختن یک هسته سیستم‌عامل به زبان راست، باید فایل اجرایی‌ای بسازیم که بتواند بدون سیستم‌عامل زیرین اجرا بشود. چنین فایل اجرایی، فایل اجرایی مستقل (ترجمه: freestanding) یا فایل اجرایی “bare-metal” نامیده می‌شود.
این پست قدم‌های لازم برای ساخت یک باینری مستقل راست و اینکه چرا این قدم‌ها نیاز هستند را توضیح می‌دهد. اگر علاقه‌ایی به خواندن کل توضیحات ندارید، می‌توانید **[به قسمت خلاصه مراجعه کنید](#summary)**.
## غیر فعال کردن کتابخانه استاندارد
به طور پیش‌فرض تمام کِرِیت‌های راست، از [کتابخانه استاندارد] استفاده می‌کنند(لینک به آن دارند)، که به سیستم‌عامل برای قابلیت‌هایی مثل نخ‌ها، فایل‌ها یا شبکه وابستگی دارد. همچنین به کتابخانه استاندارد زبان سی، `libc` هم وابسطه هست که با سرویس‌های سیستم‌عامل تعامل نزدیکی دارند. از آن‌جا که قصد داریم یک سیستم‌عامل بنویسیم، نمی‌توانیم از هیچ کتابخانه‌ایی که به سیستم‌عامل نیاز داشته باشد استفاده کنیم. بنابراین باید اضافه شدن خودکار کتابخانه استاندارد را از طریق [خاصیت `no_std`] غیر فعال کنیم.
[کتابخانه استاندارد]: https://doc.rust-lang.org/std/
[خاصیت `no_std`]: https://doc.rust-lang.org/1.30.0/book/first-edition/using-rust-without-the-standard-library.html
با ساخت یک اپلیکیشن جدید کارگو شروع می‌کنیم. ساده‌ترین راه برای انجام این کار از طریق خط فرمان است:
```
cargo new blog_os --bin --edition 2018
```
نام پروژه را `blog_os` گذاشتم، اما شما می‌توانید نام دلخواه خود را انتخاب کنید. پرچمِ (ترجمه: Flag) `bin--` مشخص می‌کند که ما می‌خواهیم یک فایل اجرایی ایجاد کنیم (به جای یک کتابخانه) و پرچمِ `edition 2018--` مشخص می‌کند که می‌خواهیم از [ویرایش 2018] زبان راست برای کریت خود استفاده کنیم. وقتی دستور را اجرا می‌کنیم، کارگو ساختار پوشه‌های زیر را برای ما ایجاد می‌کند:
[ویرایش 2018]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
```
blog_os
├── Cargo.toml
└── src
└── main.rs
```
فایل `Cargo.toml` شامل تنظیمات کریت می‌باشد، به عنوان مثال نام کریت، نام نویسنده، شماره [نسخه سمنتیک] و وابستگی‌ها. فایل `src/main.rs` شامل ماژول ریشه برای کریت ما و تابع `main` است. می‌توانید کریت خود را با دستور `cargo build` کامپایل کنید و سپس باینری کامپایل شده `blog_os` را در زیرپوشه `target/debug` اجرا کنید.
[نسخه سمنتیک]: https://semver.org/
### خاصیت `no_std`
در حال حاظر کریت ما بطور ضمنی به کتابخانه استاندارد لینک دارد. بیایید تا سعی کنیم آن را با اضافه کردن [خاصیت `no_std`] غیر فعال کنیم:
```rust
// main.rs
#![no_std]
fn main() {
println!("Hello, world!");
}
```
حالا وقتی سعی می‌کنیم تا بیلد کنیم (با اجرای دستور `cargo build`)، خطای زیر رخ می‌دهد:
```
error: cannot find macro `println!` in this scope
--> src/main.rs:4:5
|
4 | println!("Hello, world!");
| ^^^^^^^
```
دلیل این خطا این هست که [ماکروی `println`]\(ترجمه: macro) جزوی از کتابخانه استاندارد است، که ما دیگر آن را نداریم. بنابراین نمی‌توانیم چیزی را چاپ کنیم. منطقی هست زیرا `println` در [خروجی استاندارد] می‌نویسد، که یک توصیف کننده فایل (ترجمه: File Descriptor) خاص است که توسط سیستم‌عامل ارائه می‌شود.
[ماکروی `println`]: https://doc.rust-lang.org/std/macro.println.html
[خروجی استاندارد]: https://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29
پس بیایید قسمت مروبط به چاپ را پاک کرده و این‌ بار با یک تابع main خالی امتحان کنیم:
```rust
// main.rs
#![no_std]
fn main() {}
```
```
> cargo build
error: `#[panic_handler]` function required, but not found
error: language item required, but not found: `eh_personality`
```
حالا کامپایلر با کمبود یک تابع `#[panic_handler]` و یک _language item_ روبرو است.
## پیاده‌سازی پنیک (کلمه: Panic)
خاصیت `panic_handler` تابعی را تعریف می‌کند که کامپایلر باید در هنگام رخ دادن یک [پنیک] اجرا کند. کتابخانه استاندارد تابع مدیریت پنیک خود را ارائه می‌دهد، اما در یک محیط `no_std` ما باید خودمان آن را تعریف کنیم.
[پنیک]: https://doc.rust-lang.org/stable/book/ch09-01-unrecoverable-errors-with-panic.html
```rust
// in main.rs
use core::panic::PanicInfo;
/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
[پارامتر `PanicInfo`][PanicInfo] شامل فایل و شماره خطی که پنیک رخ داده و پیام پنیکِ اختیاری می‌باشد. تابع هیچ وقت نباید چیزی را برگرداند به همین دلیل به عنوان یک [تابع واگرا]\(ترجمه: diverging function) بوسیله نوع برگشتی `!` [نوع ”هرگز“] علامت‌گذاری شده است. فعلا کار زیادی نیست که بتوانیم در این تابع انجام دهیم، بنابراین فقط یک حلقه بی‌نهایت می‌نویسیم.
[PanicInfo]: https://doc.rust-lang.org/nightly/core/panic/struct.PanicInfo.html
[تابع واگرا]: https://doc.rust-lang.org/1.30.0/book/first-edition/functions.html#diverging-functions
[نوع ”هرگز“]: https://doc.rust-lang.org/nightly/std/primitive.never.html
## آیتم زبان `eh_personality`
آیتم‌های زبان، توابع و انواع خاصی هستند که برای استفاده درون کامپایلر ضروری‌اند. به عنوان مثال، تِرِیت [`Copy`]\(کلمه: Trait) یک آیتم زبان است که به کامپایلر می‌گوید کدام انواع دارای [_مفهوم کپی_][`Copy`] هستند. وقتی به [پیاده‌سازی][copy code] آن نگاه می‌کنیم، می‌بینیم که یک خاصیت ویژه `#[lang = "copy"]` دارد که آن را به عنوان یک آیتم زبان تعریف می‌کند.
[`Copy`]: https://doc.rust-lang.org/nightly/core/marker/trait.Copy.html
[copy code]: https://github.com/rust-lang/rust/blob/485397e49a02a3b7ff77c17e4a3f16c653925cb3/src/libcore/marker.rs#L296-L299
درحالی که می‌توان پیاده‌سازی خاص برای آیتم‌های زبان فراهم کرد، فقط باید به عنوان آخرین راه حل از آن استفاده کرد. زیرا آیتم‌های زبان بسیار در جزئیات پیاده‌سازی ناپایدار هستند و حتی انواع آن‌ها نیز چک نمی‌شود (بنابراین کامپایلر حتی چک نمی‌کند که آرگومان تابع نوع درست را دارد). خوشبختانه یک راه پایدارتر برای حل مشکل آیتم زبان بالا وجود دارد.
[آیتم زبان `eh_personality`] یک تابع را به عنوان تابعی که برای پیاده‌سازی [بازکردن پشته (Stack Unwinding)] استفاده شده، علامت‌گذاری می‌کند. راست بطور پیش‌فرض از _بازکردن_ (ترجمه: unwinding) برای اجرای نابودگرهای (ترجمه: Destructors) تمام متغیرهای زنده درون استک در مواقع [پنیک] استفاده می‌کند. این تضمین می‌کند که تمام حافظه استفاده شده آزاد می‌شود و به نخ اصلی اجازه می‌دهد پنیک را دریافت کرده و اجرا را ادامه دهد. باز کردن، یک فرآیند پیچیده است و به برخی از کتابخانه‌های خاص سیستم‌عامل (به عنوان مثال [libunwind] در لینوکس یا [مدیریت اکسپشن ساخت یافته] در ویندوز) نیاز دارد، بنابراین ما نمی‌خواهیم از آن برای سیستم‌عامل خود استفاده کنیم.
[آیتم زبان `eh_personality`]: https://github.com/rust-lang/rust/blob/edb368491551a77d77a48446d4ee88b35490c565/src/libpanic_unwind/gcc.rs#L11-L45
[بازکردن پشته (Stack Unwinding)]: https://www.bogotobogo.com/cplusplus/stackunwinding.php
[libunwind]: https://www.nongnu.org/libunwind/
[مدیریت اکسپشن ساخت یافته]: https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling
### غیرفعال کردن Unwinding
موارد استفاده دیگری نیز وجود دارد که باز کردن نامطلوب است، بنابراین راست به جای آن گزینه [قطع در پنیک] را فراهم می‌کند. این امر تولید اطلاعات نمادها (ترجمه: Symbol) را از بین می‌برد و بنابراین اندازه باینری را بطور قابل توجهی کاهش می‌دهد. چندین مکان وجود دارد که می توانیم باز کردن را غیرفعال کنیم. ساده‌ترین راه این است که خطوط زیر را به `Cargo.toml` اضافه کنید:
```toml
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
```
این استراتژی پنیک را برای دو پروفایل `dev` (در `cargo build` استفاده می‌شود) و پروفایل `release` (در ` cargo build --release` استفاده می‌شود) تنظیم می‌کند. اکنون آیتم زبان `eh_personality` نباید دیگر لازم باشد.
[قطع در پنیک]: https://github.com/rust-lang/rust/pull/32900
اکنون هر دو خطای فوق را برطرف کردیم. با این حال‌، اگر اکنون بخواهیم آن را کامپایل کنیم، خطای دیگری رخ می‌دهد:
```
> cargo build
error: requires `start` lang_item
```
برنامه ما آیتم زبان `start` که نقطه ورود را مشخص می‌کند، را ندارد.
## خاصیت `start`
ممکن است تصور شود که تابع `main` اولین تابعی است که هنگام اجرای یک برنامه فراخوانی می‌شود. با این حال، بیشتر زبان‌ها دارای [سیستم رانتایم] هستند که مسئول مواردی مانند جمع آوری زباله (به عنوان مثال در جاوا) یا نخ‌های نرم‌افزار (به عنوان مثال goroutines در Go) است. این رانتایم باید قبل از `main` فراخوانی شود، زیرا باید خود را مقداردهی اولیه و آماده کند.
[سیستم رانتایم]: https://en.wikipedia.org/wiki/Runtime_system
در یک باینری معمولی راست که از کتابخانه استاندارد استفاده می‌کند، اجرا در یک کتابخانه رانتایم C به نام `crt0` ("زمان اجرا صفر C") شروع می‌شود، که محیط را برای یک برنامه C تنظیم می‌کند. این شامل ایجاد یک پشته و قرار دادن آرگومان‌ها در رجیسترهای مناسب است. سپس رانتایم C [ورودی رانتایم راست][rt::lang_start] را فراخوانی می‌کند، که با آیتم زبان `start` مشخص شده است. راست فقط یک رانتایم بسیار کوچک دارد، که مواظب برخی از کارهای کوچک مانند راه‌اندازی محافظ‌های سرریز پشته یا چاپ backtrace با پنیک می‌باشد. رانتایم در نهایت تابع `main` را فراخوانی می‌کند.
[rt::lang_start]: https://github.com/rust-lang/rust/blob/bb4d1491466d8239a7a5fd68bd605e3276e97afb/src/libstd/rt.rs#L32-L73
برنامه اجرایی مستقل ما به رانتایم و `crt0` دسترسی ندارد، بنابراین باید نقطه ورود را مشخص کنیم. پیاده‌سازی آیتم زبان `start` کمکی نخواهد کرد، زیرا همچنان به `crt0` نیاز دارد. در عوض، باید نقطه ورود `crt0` را مستقیماً بازنویسی کنیم.
### بازنویسی نقطه ورود
برای اینکه به کامپایلر راست بگوییم که نمی‌خواهیم از زنجیره نقطه ورودی عادی استفاده کنیم، ویژگی `#![no_main]` را اضافه می‌کنیم.
```rust
#![no_std]
#![no_main]
use core::panic::PanicInfo;
/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
ممکن است متوجه شده باشید که ما تابع `main` را حذف کردیم. دلیل این امر این است که `main` بدون یک رانتایم اساسی که آن را صدا کند معنی ندارد. در عوض، ما در حال بازنویسی نقطه ورود سیستم‌عامل با تابع `start_` خود هستیم:
```rust
#[no_mangle]
pub extern "C" fn _start() -> ! {
loop {}
}
```
با استفاده از ویژگی `[no_mangle]#` ما [name mangling] را غیرفعال می کنیم تا اطمینان حاصل کنیم که کامپایلر راست تابعی با نام `start_` را خروجی می‌دهد. بدون این ویژگی، کامپایلر برخی از نمادهای رمزنگاری شده `ZN3blog_os4_start7hb173fedf945531caE_` را تولید می‌کند تا به هر تابع یک نام منحصر به فرد بدهد. این ویژگی لازم است زیرا در مرحله بعدی باید نام تایع نقطه ورود را به لینکر (کلمه: linker) بگوییم.
ما همچنین باید تابع را به عنوان `"extern "C` علامت‌گذاری کنیم تا به کامپایلر بگوییم که باید از [قرارداد فراخوانی C] برای این تابع استفاده کند (به جای قرارداد مشخص نشده فراخوانی راست). دلیل نامگذاری تابع `start_` این است که این نام نقطه پیش‌فرض ورودی برای اکثر سیستم‌ها است.
[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
[قرارداد فراخوانی C]: https://en.wikipedia.org/wiki/Calling_convention
نوع بازگشت `!` به این معنی است که تایع واگرا است، یعنی اجازه بازگشت ندارد. این مورد لازم است زیرا نقطه ورود توسط هیچ تابعی فراخوانی نمی‌شود، بلکه مستقیماً توسط سیستم‌عامل یا بوت‌لودر فراخوانی می‌شود. بنابراین به جای بازگشت، نقطه ورود باید به عنوان مثال [فراخوان سیستمی `exit`] از سیستم‌عامل را فراخوانی کند. در مورد ما، خاموش کردن دستگاه می‌تواند اقدامی منطقی باشد، زیرا در صورت بازگشت باینری مستقل دیگر کاری برای انجام دادن وجود ندارد. در حال حاضر، ما این نیاز را با حلقه‌های بی‌پایان انجام می‌دهیم.
[فراخوان سیستمی `exit`]: https://en.wikipedia.org/wiki/Exit_(system_call)
حالا وقتی `cargo build` را اجرا می‌کنیم، با یک خطای _لینکر_ زشت مواجه می‌شویم.
## خطا‌های لینکر (Linker)
لینکر برنامه‌ای است که کد تولید شده را ترکیب کرده و یک فایل اجرایی می‌سازد. از آن‌جا که فرمت اجرایی بین لینوکس، ویندوز و macOS متفاوت است، هر سیستم لینکر خود را دارد که خطای متفاوتی ایجاد می‌کند. علت اصلی خطاها یکسان است: پیکربندی پیش‌فرض لینکر فرض می‌کند که برنامه ما به رانتایم C وابسته است، که این طور نیست.
برای حل خطاها، باید به لینکر بگوییم که نباید رانتایم C را اضافه کند. ما می‌توانیم این کار را با اضافه کردن مجموعه‌ای از آرگمان‌ها به لینکر یا با ساختن یک هدف (ترجمه: Target) bare metal انجام دهیم.
### بیلد کردن برای یک هدف bare metal
راست به طور پیش‌فرض سعی در ایجاد یک اجرایی دارد که بتواند در محیط سیستم فعلی شما اجرا شود. به عنوان مثال، اگر از ویندوز در `x86_64` استفاده می‌کنید، راست سعی در ایجاد یک `exe.` اجرایی ویندوز دارد که از دستورالعمل‌های `x86_64` استفاده می‌کند. به این محیط سیستم "میزبان" شما گفته می‌شود.
راست برای توصیف محیط‌های مختلف، از رشته‌ای به نام [_target triple_]\(سه‌گانه هدف) استفاده می‌کند. با اجرای `rustc --version --verbose` می‌توانید target triple را برای سیستم میزبان خود مشاهده کنید:
[_target triple_]: https://clang.llvm.org/docs/CrossCompilation.html#target-triple
```
rustc 1.35.0-nightly (474e7a648 2019-04-07)
binary: rustc
commit-hash: 474e7a6486758ea6fc761893b1a49cd9076fb0ab
commit-date: 2019-04-07
host: x86_64-unknown-linux-gnu
release: 1.35.0-nightly
LLVM version: 8.0
```
خروجی فوق از یک سیستم لینوکس `x86_64` است. می‌بینیم که سه‌گانه میزبان `x86_64-unknown-linux-gnu` است که شامل معماری پردازنده (`x86_64`)، فروشنده (`ناشناخته`)، سیستم‌عامل (` linux`) و [ABI] (`gnu`) است.
[ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
با کامپایل کردن برای سه‌گانه میزبان‌مان، کامپایلر راست و لینکر فرض می‌کنند که یک سیستم‌عامل زیرین مانند Linux یا Windows وجود دارد که به طور پیش‌فرض از رانتایم C استفاده می‌کند، که باعث خطاهای لینکر می‌شود. بنابراین برای جلوگیری از خطاهای لینکر، می‌توانیم برای محیطی متفاوت و بدون سیستم‌عامل زیرین کامپایل کنیم.
یک مثال برای چنین محیطِ bare metal ی، سه‌گانه هدف `thumbv7em-none-eabihf` است، که یک سیستم [تعبیه شده][ARM] را توصیف می‌کند. جزئیات مهم نیستند، مهم این است که سه‌گانه هدف فاقد سیستم‌عامل زیرین باشد، که با `none` در سه‌گانه هدف نشان داده می‌شود. برای این که بتوانیم برای این هدف کامپایل کنیم، باید آن را به rustup اضافه کنیم:
[تعبیه شده]: https://en.wikipedia.org/wiki/Embedded_system
[ARM]: https://en.wikipedia.org/wiki/ARM_architecture
```
rustup target add thumbv7em-none-eabihf
```
با این کار نسخه‌ای از کتابخانه استاندارد (و core) برای سیستم بارگیری می‌شود. اکنون می‌توانیم برای این هدف اجرایی مستقل خود را بسازیم:
```
cargo build --target thumbv7em-none-eabihf
```
با استفاده از یک آرگومان `target--`، ما اجرایی خود را برای یک سیستم هدف bare metal [کراس کامپایل] می‌کنیم. از آن‌جا که سیستم هدف فاقد سیستم‌عامل است، لینکر سعی نمی‌کند رانتایم C را به آن پیوند دهد و بیلد ما بدون هیچ گونه خطای لینکر با موفقیت انجام می‌شود.
[کراس کامپایل]: https://en.wikipedia.org/wiki/Cross_compiler
این روشی است که ما برای ساخت هسته سیستم‌عامل خود استفاده خواهیم کرد. به جای `thumbv7em-none-eabihf`، ما از یک [هدف سفارشی] استفاده خواهیم کرد که یک محیط `x86_64` bare metal را توصیف می‌کند. جزئیات در پست بعدی توضیح داده خواهد شد.
[هدف سفارشی]: https://doc.rust-lang.org/rustc/targets/custom.html
### آرگومان‌های لینکر
به جای کامپایل کردن برای یک سیستم bare metal، می‌توان خطاهای لینکر را با استفاده از مجموعه خاصی از آرگومان‌ها به لینکر حل کرد. این روشی نیست که ما برای هسته خود استفاده کنیم، بنابراین این بخش اختیاری است و فقط برای کامل بودن ارائه می‌شود. برای نشان دادن محتوای اختیاری، روی _"آرگومان‌های لینکر"_ در زیر کلیک کنید.
<details>
<summary>آرگومان‌های لینکر</summary>
در این بخش، ما در مورد خطاهای لینکر که در لینوکس، ویندوز و macOS رخ می‌دهد بحث می‌کنیم و نحوه حل آن‌ها را با استفاده از آرگومان‌های اضافی به لینکر توضیح می‌دهیم. توجه داشته باشید که فرمت اجرایی و لینکر بین سیستم‌عامل‌ها متفاوت است، بنابراین برای هر سیستم مجموعه‌ای متفاوت از آرگومان‌ها مورد نیاز است.
#### لینوکس
در لینوکس خطای لینکر زیر رخ می‌دهد (کوتاه شده):
```
error: linking with `cc` failed: exit code: 1
|
= note: "cc" […]
= note: /usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x12): undefined reference to `__libc_csu_fini'
/usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x19): undefined reference to `__libc_csu_init'
/usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x25): undefined reference to `__libc_start_main'
collect2: error: ld returned 1 exit status
```
مشکل این است که لینکر به طور پیش‌فرض شامل روال راه‌اندازی رانتایم C است که به آن `start_` نیز گفته می‌شود. به برخی از نمادهای کتابخانه استاندارد C یعنی `libc` نیاز دارد که به دلیل ویژگی`no_std` آن‌ها را نداریم، بنابراین لینکر نمی‌تواند این مراجع را پیدا کند. برای حل این مسئله، با استفاده از پرچم `nostartfiles-` می‌توانیم به لینکر بگوییم که نباید روال راه‌اندازی C را لینک دهد.
یکی از راه‌های عبور صفات لینکر از طریق cargo، دستور `cargo rustc` است. این دستور دقیقاً مانند `cargo build` رفتار می‌کند، اما اجازه می‌دهد گزینه‌ها را به `rustc`، کامپایلر اصلی راست انتقال دهید. `rustc` دارای پرچم`C link-arg-` است که آرگومان را به لینکر منتقل می‌کند. با ترکیب همه این‌ها، دستور بیلد جدید ما به این شکل است:
```
cargo rustc -- -C link-arg=-nostartfiles
```
اکنون کریت ما بصورت اجرایی مستقل در لینوکس ساخته می‌شود!
لازم نیست که صریحاً نام تابع نقطه ورود را مشخص کنیم، زیرا لینکر به طور پیش‌فرض به دنبال تابعی با نام `start_` می‌گردد.
#### ویندوز
در ویندوز، یک خطای لینکر متفاوت رخ می‌دهد (کوتاه شده):
```
error: linking with `link.exe` failed: exit code: 1561
|
= note: "C:\\Program Files (x86)\\…\\link.exe" […]
= note: LINK : fatal error LNK1561: entry point must be defined
```
خطای "entry point must be defined" به این معنی است که لینکر نمی‌تواند نقطه ورود را پیدا کند. در ویندوز، نام پیش‌فرض نقطه ورود [بستگی به زیر سیستم استفاده شده دارد] [windows-subsystem]. برای زیر سیستم `CONSOLE` لینکر به دنبال تابعی به نام `mainCRTStartup` و برای زیر سیستم `WINDOWS` به دنبال تابعی به نام `WinMainCRTStartup` می‌گردد. برای بازنویسی این پیش‌فرض و به لینکر گفتن که در عوض به دنبال تابع `_start` ما باشد ، می توانیم یک آرگومان `ENTRY/` را به لینکر ارسال کنیم:
[windows-subsystems]: https://docs.microsoft.com/en-us/cpp/build/reference/entry-entry-point-symbol
```
cargo rustc -- -C link-arg=/ENTRY:_start
```
از متفاوت بودن فرمت آرگومان، به وضوح می‌فهمیم که لینکر ویندوز یک برنامه کاملاً متفاوت از لینکر Linux است.
اکنون یک خطای لینکر متفاوت رخ داده است:
```
error: linking with `link.exe` failed: exit code: 1221
|
= note: "C:\\Program Files (x86)\\…\\link.exe" […]
= note: LINK : fatal error LNK1221: a subsystem can't be inferred and must be
defined
```
این خطا به این دلیل رخ می‌دهد که برنامه‌های اجرایی ویندوز می‌توانند از [زیر سیستم های][windows-subsystems] مختلف استفاده کنند. برای برنامه‌های عادی، بسته به نام نقطه ورود استنباط می شوند: اگر نقطه ورود `main` نامگذاری شود، از زیر سیستم `CONSOLE` و اگر نقطه ورود `WinMain` نامگذاری شود، از زیر سیستم `WINDOWS` استفاده می‌شود. از آن‌جا که تابع `start_` ما نام دیگری دارد، باید زیر سیستم را صریحاً مشخص کنیم:
```
cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"
```
ما در اینجا از زیر سیستم `CONSOLE` استفاده می‌کنیم، اما زیر سیستم `WINDOWS` نیز کار خواهد کرد. به جای اینکه چند بار از `C link-arg-` استفاده کنیم، از`C link-args-` استفاده می‌کنیم که لیستی از آرگومان‌ها به صورت جدا شده با فاصله را دریافت می‌کند.
با استفاده از این دستور، اجرایی ما باید با موفقیت بر روی ویندوز ساخته شود.
#### macOS
در macOS، خطای لینکر زیر رخ می‌دهد (کوتاه شده):
```
error: linking with `cc` failed: exit code: 1
|
= note: "cc" […]
= note: ld: entry point (_main) undefined. for architecture x86_64
clang: error: linker command failed with exit code 1 […]
```
این پیام خطا به ما می‌گوید که لینکر نمی‌تواند یک تابع نقطه ورود را با نام پیش‌فرض `main` پیدا کند (به دلایلی همه توابع در macOS دارای پیشوند `_` هستند). برای تنظیم نقطه ورود به تابع `start_` ، آرگومان لینکر `e-` را استفاده می‌کنیم:
```
cargo rustc -- -C link-args="-e __start"
```
پرچم `e-` نام تابع نقطه ورود را مشخص می‌کند. از آن‌جا که همه توابع در macOS دارای یک پیشوند اضافی `_` هستند، ما باید به جای `start_` نقطه ورود را روی `start__` تنظیم کنیم.
اکنون خطای لینکر زیر رخ می‌دهد:
```
error: linking with `cc` failed: exit code: 1
|
= note: "cc" […]
= note: ld: dynamic main executables must link with libSystem.dylib
for architecture x86_64
clang: error: linker command failed with exit code 1 […]
```
سیستم‌عامل مک‌ [رسماً باینری‌هایی را که بطور استاتیک با هم پیوند دارند پشتیبانی نمی‌کند] و بطور پیش‌فرض به برنامه‌هایی برای پیوند دادن کتابخانه `libSystem` نیاز دارد. برای تغییر این حالت و پیوند دادن یک باینری استاتیک، پرچم `static-` را به لینکر ارسال می‌کنیم:
[باینری‌هایی را که بطور استاتیک با هم پیوند دارند پشتیبانی نمی‌کند]: https://developer.apple.com/library/archive/qa/qa1118/_index.html
```
cargo rustc -- -C link-args="-e __start -static"
```
این نیز کافی نیست، سومین خطای لینکر رخ می‌دهد:
```
error: linking with `cc` failed: exit code: 1
|
= note: "cc" […]
= note: ld: library not found for -lcrt0.o
clang: error: linker command failed with exit code 1 […]
```
این خطا رخ می‌دهد زیرا برنامه های موجود در macOS به طور پیش‌فرض به `crt0` ("رانتایم صفر C") پیوند دارند. این همان خطایی است که در لینوکس داشتیم و با افزودن آرگومان لینکر `nostartfiles-` نیز قابل حل است:
```
cargo rustc -- -C link-args="-e __start -static -nostartfiles"
```
اکنون برنامه ما باید با موفقیت بر روی macOS ساخته شود.
#### متحد کردن دستورات Build
در حال حاضر بسته به سیستم‌عامل میزبان، دستورات ساخت متفاوتی داریم که ایده آل نیست. برای جلوگیری از این، می‌توانیم فایلی با نام `cargo/config.toml.` ایجاد کنیم که حاوی آرگومان‌های خاص هر پلتفرم است:
```toml
# in .cargo/config.toml
[target.'cfg(target_os = "linux")']
rustflags = ["-C", "link-arg=-nostartfiles"]
[target.'cfg(target_os = "windows")']
rustflags = ["-C", "link-args=/ENTRY:_start /SUBSYSTEM:console"]
[target.'cfg(target_os = "macos")']
rustflags = ["-C", "link-args=-e __start -static -nostartfiles"]
```
کلید `rustflags` شامل آرگومان‌هایی است که بطور خودکار به هر فراخوانی `rustc` اضافه می‌شوند. برای کسب اطلاعات بیشتر در مورد فایل `cargo/config.toml.` به [اسناد رسمی](https://doc.rust-lang.org/cargo/reference/config.html) مراجعه کنید.
اکنون برنامه ما باید در هر سه سیستم‌عامل با یک `cargo build` ساده قابل بیلد باشد.
#### آیا شما باید این کار را انجام دهید؟
اگرچه ساخت یک اجرایی مستقل برای لینوکس، ویندوز و macOS امکان پذیر است، اما احتمالاً ایده خوبی نیست. چرا که اجرایی ما هنوز انتظار موارد مختلفی را دارد، به عنوان مثال با فراخوانی تابع `start_` یک پشته مقداردهی اولیه شده است. بدون رانتایم C، ممکن است برخی از این الزامات برآورده نشود، که ممکن است باعث شکست برنامه ما شود، به عنوان مثال از طریق `segmentation fault`.
اگر می خواهید یک باینری کوچک ایجاد کنید که بر روی سیستم‌عامل موجود اجرا شود، اضافه کردن `libc` و تنظیم ویژگی `[start]#` همان‌طور که [اینجا](https://doc.rust-lang.org/1.16.0/book/no-stdlib.html) شرح داده شده است، احتمالاً ایده بهتری است.
</details>
## خلاصه {#summary}
یک باینری مستقل مینیمال راست مانند این است:
`src/main.rs`:
```rust
#![no_std] // don't link the Rust standard library
#![no_main] // disable all Rust-level entry points
use core::panic::PanicInfo;
#[no_mangle] // don't mangle the name of this function
pub extern "C" fn _start() -> ! {
// this function is the entry point, since the linker looks for a function
// named `_start` by default
loop {}
}
/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
`Cargo.toml`:
```toml
[package]
name = "crate_name"
version = "0.1.0"
authors = ["Author Name <author@example.com>"]
# the profile used for `cargo build`
[profile.dev]
panic = "abort" # disable stack unwinding on panic
# the profile used for `cargo build --release`
[profile.release]
panic = "abort" # disable stack unwinding on panic
```
برای ساخت این باینری، ما باید برای یک هدف bare metal مانند `thumbv7em-none-eabihf` کامپایل کنیم:
```
cargo build --target thumbv7em-none-eabihf
```
یک راه دیگر این است که می‌توانیم آن را برای سیستم میزبان با استفاده از آرگومان‌های اضافی لینکر کامپایل کنیم:
```bash
# Linux
cargo rustc -- -C link-arg=-nostartfiles
# Windows
cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"
# macOS
cargo rustc -- -C link-args="-e __start -static -nostartfiles"
```
توجه داشته باشید که این فقط یک نمونه حداقلی از باینری مستقل راست است. این باینری انتظار چیزهای مختلفی را دارد، به عنوان مثال با فراخوانی تابع `start_` یک پشته مقداردهی اولیه می‌شود. **بنابراین برای هر گونه استفاده واقعی از چنین باینری، مراحل بیشتری لازم است**.
## بعدی چیست؟
[پست بعدی] مراحل مورد نیاز برای تبدیل باینری مستقل به حداقل هسته سیستم‌عامل را توضیح می‌دهد. که شامل ایجاد یک هدف سفارشی، ترکیب اجرایی ما با بوت‌لودر و یادگیری نحوه چاپ چیزی در صفحه است.
[پست بعدی]: @/edition-2/posts/02-minimal-rust-kernel/index.fa.md

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