Compare commits

...

850 Commits

Author SHA1 Message Date
Philipp Oppermann
8fac34760c Merge pull request #1437 from phil-opp/nightly-fix
Update blog for `target-pointer-width` change
2025-09-03 18:04:23 +02:00
Philipp Oppermann
95d4fbd54c Update blog for target-pointer-width change 2025-09-03 18:02:19 +02:00
Philipp Oppermann
b3e0b5e139 Merge pull request #1435 from phil-opp/blog-test-true
Update testing post to set `test = true` in Cargo.toml
2025-08-26 16:41:16 +02:00
Philipp Oppermann
33b7979468 Update testing post to set test = true in Cargo.toml 2025-08-26 16:33:56 +02:00
Philipp Oppermann
a539c3b814 Merge pull request #1429 from ic3-w1ne/post12zhCN
Add post-12 simplified Chinese translation
2025-08-18 10:43:41 +02:00
ic3w1ne
1338660a81 Optimize translation with review. 2025-08-14 21:10:16 +08:00
ic3w1ne
21b2c1e198 Optimize translation. 2025-08-12 19:11:01 +08:00
Philipp Oppermann
f2966a5348 Merge pull request #1430 from L3Sota/patch-1
fix(post-01): typo
2025-08-12 10:04:49 +02:00
L3Sota
687226e9c1 fix(post-01): typo 2025-08-12 16:54:21 +09:00
Philipp Oppermann
7b54d2cde1 Merge pull request #1428 from ttttyy/main
fix  edition2@post-11 Chinese translation error
2025-08-11 17:41:46 +02:00
ic3w1ne
b45bd8fada Optimize translation. 2025-08-11 22:24:44 +08:00
ic3w1ne
de8054095c Optimize translation. 2025-08-11 18:00:22 +08:00
ic3w1ne
7c795ebdd1 fix typo 2025-08-09 22:00:27 +08:00
ic3w1ne
4e4c30deaa Update anchor 2025-08-09 21:17:50 +08:00
ic3w1ne
fcd3eca133 Update index.zh-CN.md 2025-08-09 21:11:21 +08:00
ic3w1ne
a03eaffe98 add post-12 simplified Chinese translation 2025-08-09 20:59:52 +08:00
glitter
ccfa6f500d fix Chinese translation error 2025-08-09 20:47:54 +08:00
Philipp Oppermann
67b3ac65dc Merge pull request #1420 from ttttyy/main
translate edition2@post-11 to Chinese
2025-08-08 15:59:25 +02:00
Philipp Oppermann
7262bf0f90 Merge pull request #1427 from phil-opp/blog-test-false
Update first post to set `test=false` for binary
2025-08-07 18:41:29 +02:00
Philipp Oppermann
9894147b30 Update first post to set test=false for binary
As implemented in #1412
2025-08-07 14:04:24 +02:00
Philipp Oppermann
5b4cb532e8 Merge pull request #1426 from phil-opp/blog-fix-target-c-int-width
Update blog for `target-c-int-width` change
2025-08-07 13:13:23 +02:00
Philipp Oppermann
9e325de9c7 Update blog for target-c-int-width change
See #1425
2025-08-07 13:12:58 +02:00
Philipp Oppermann
ad888bcb9b Merge pull request #1422 from imaspacecat/patch-1
Fix broken link in 04-testing
2025-08-01 14:30:26 +02:00
spacecat
7b9891b2b5 Fix broken link in 04-testing
the wikipedia link in "lots of UART models" wasn't working anymore, so I changed it to the newer link
2025-07-31 22:49:30 +00:00
gitter
359f457e53 change links 2025-06-25 23:47:56 +08:00
gitter
336391b9c9 change some translation 2025-06-25 23:31:56 +08:00
gitter
2de7654f05 finish translation of post-11 2025-06-25 23:20:42 +08:00
gitter
1b0c9752e6 translate 2025-06-24 21:04:56 +08:00
gitter
30bbcb94cf translate 2025-06-23 21:49:09 +08:00
gitter
187839ab53 translate post-11 2025-06-22 19:39:18 +08:00
Philipp Oppermann
4e51284661 Merge pull request #1414 from Liuliuliu7/heap-allocation-chinese-translation
Heap allocation chinese translation
2025-06-10 13:42:36 +02:00
Philipp Oppermann
3c8d567c1e Fix broken links 2025-06-10 13:41:41 +02:00
Wen Huan
8b702b732e Fix some broken links 2025-06-05 22:41:57 +08:00
Wen Huan
02adcf94ee Apply suggestions from code review
Refine  wording for better clarity

Co-authored-by: xtex <xtex@envs.net>
2025-06-05 22:27:07 +08:00
Liuliuliu7
d5e981bca9 docs: Translate "Heap Allocation"(post 10) article to Chinese 2025-05-20 18:39:41 +08:00
Philipp Oppermann
2edf0221a3 Merge pull request #1409 from fduxiao/main
Fix the missing '&' in post 09
2025-04-21 11:12:07 +02:00
fduxiao
32f629fb2d Fix the missing '&' in post 09 2025-04-18 00:04:39 -04:00
Philipp Oppermann
98f616964d Merge pull request #1407 from JINHUILYU/main
Update index.zh-CN.md
2025-04-02 15:22:39 +02:00
Via Lyu
557da037c7 Update index.zh-CN.md
Fix translation inconsistency: Update incorrect term "组建" to the correct term "组件" at line 645.
2025-04-02 20:30:42 +08:00
Philipp Oppermann
5a849b05d6 Merge pull request #1368 from dobleuber/add-spanish-translation
Latam Spanish translation
2025-03-27 17:54:54 +01:00
Philipp Oppermann
9da248032f Fix config file exclude (typo check) 2025-03-27 17:54:02 +01:00
Philipp Oppermann
52b31ded4d Format markdown 2025-03-27 17:52:48 +01:00
Philipp Oppermann
88fd5aabdd List dobleuber as translator 2025-03-27 17:52:28 +01:00
Philipp Oppermann
411d42ac8d Don't check for typos in config file 2025-03-27 17:47:09 +01:00
Philipp Oppermann
ae810ce83d Fix: Bring back translations for ar 2025-03-27 17:41:27 +01:00
Philipp Oppermann
d4daf93050 Merge pull request #1405 from phil-opp/rust-2024
Update blog to Rust 2024 edition
2025-03-27 15:42:20 +01:00
Philipp Oppermann
c0fc0bed9e Unsafe operations in unsafe fn require an unsafe block since Rust 2024 2025-03-27 15:39:55 +01:00
Philipp Oppermann
9753695744 The no_mangle attribute is unsafe since Rust 2024 2025-03-27 15:39:15 +01:00
dobleuber
725085abea Fix Wikipedia links to point to English versions instead of Spanish ones 2025-03-03 21:24:46 -05:00
dobleuber
98cf0d4850 Exclude Spanish files from typos check 2025-03-03 21:19:04 -05:00
dobleuber
b9b1ae8c08 Fix broken internal links in Spanish translations 2025-03-03 21:08:36 -05:00
dobleuber
cf91244de6 Add es/ prefix to Spanish file paths to avoid route collisions 2025-03-03 20:59:55 -05:00
dobleuber
ffd0555a5a Add Spanish language configuration to config.toml 2025-03-03 20:53:22 -05:00
dobleuber
0e9f50d773 Translate code comments to Spanish in all units 2025-03-03 20:46:39 -05:00
Philipp Oppermann
9345886d44 Merge pull request #1399 from felixpackard/post-02-fix-typo
Fix typo when referencing the `rustc-abi` field.
2025-02-20 17:15:00 +01:00
Felix Packard
b1bf2e51d6 Fix typo when referencing the rustc-abi field. 2025-02-20 15:46:05 +00:00
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
dobleuber
c9307a422f All blogs translate, but not reviewed yet 2025-01-13 22:08:29 -05:00
dobleuber
d9de86f6df Minimal rust kernel 2024-12-21 14:26:47 -05:00
dobleuber
8971334f57 Fix typos and rename files 2024-12-21 12:50:05 -05:00
dobleuber
ab232d3051 A Freestanding Rust Binary 2024-12-20 20:13:39 -05: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
9c6cdff785 A CPU with 5-level paging is available now 2020-01-31 11:10:09 +01:00
Rustin
6d4f1d6c43 post-3 translation refactor (#725) 2020-01-30 10:37:40 +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
Rustin
55f19fdcdc post-2 translation refactor (#708) 2020-01-05 19:30:44 +01: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
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
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
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
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
341 changed files with 48303 additions and 1675 deletions

View File

@@ -1,4 +1,4 @@
name: Build Site
name: Blog
on:
push:
@@ -20,9 +20,7 @@ jobs:
- uses: actions/checkout@v1
- name: 'Download Zola'
run: curl -sL https://github.com/getzola/zola/releases/download/v0.9.0/zola-v0.9.0-x86_64-unknown-linux-gnu.tar.gz | tar zxv
- name: "Install Python Tools"
run: python -m pip install --upgrade pip setuptools wheel
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"
@@ -35,26 +33,11 @@ jobs:
working-directory: "blog"
- name: Upload Generated Site
uses: actions/upload-artifact@v1.0.0
uses: actions/upload-artifact@v4
with:
name: generated_site
path: blog/public
zola_check:
name: "Zola Check"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: 'Download Zola'
run: curl -sL https://github.com/getzola/zola/releases/download/v0.9.0/zola-v0.9.0-x86_64-unknown-linux-gnu.tar.gz | tar zxv
- name: "Run zola check"
run: ../zola check
working-directory: "blog"
continue-on-error: true
check_spelling:
name: "Check Spelling"
runs-on: ubuntu-latest
@@ -62,22 +45,23 @@ jobs:
steps:
- uses: actions/checkout@v1
- run: curl -L https://git.io/misspell | bash
name: "Install misspell"
- run: bin/misspell -error blog/content
name: "Check for common typos"
- 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/master' && (github.event_name == 'push' || github.event_name == 'schedule')
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')
steps:
- name: "Download Generated Site"
uses: actions/download-artifact@v1
uses: actions/download-artifact@v4
with:
name: generated_site
path: generated_site
- name: Setup SSH Keys and known_hosts
run: |
@@ -85,7 +69,7 @@ jobs:
ssh-keyscan github.com >> ~/.ssh/known_hosts
ssh-agent -a $SSH_AUTH_SOCK > /dev/null
ssh-add - <<< "$deploy_key"
echo ::set-env name=SSH_AUTH_SOCK::$SSH_AUTH_SOCK
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK" >> $GITHUB_ENV
env:
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
deploy_key: ${{ secrets.DEPLOY_SSH_KEY }}

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

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

@@ -10,7 +10,7 @@ The code for each post lives in a separate git branch. This makes it possible to
**The code for the latest post is available [here][latest-post].**
[latest-post]: https://github.com/phil-opp/blog_os/tree/post-11
[latest-post]: https://github.com/phil-opp/blog_os/tree/post-12
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.
@@ -59,10 +59,17 @@ The goal of this project is to provide step-by-step tutorials in individual blog
- [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)
@@ -105,13 +112,15 @@ The current version of the blog is already the second edition. The first edition
- [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
This project, with exception of the `blog/content` folder, is licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
https://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
at your option.

1
blog/.gitignore vendored
View File

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

View File

@@ -2,12 +2,13 @@
# -*- coding: utf-8 -*-
import io
import urllib
import datetime
from github import Github
from datetime import datetime, timedelta
g = Github()
one_month_ago = datetime.now() - timedelta(days=32)
one_month_ago = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=32)
def filter_date(issue):
return issue.closed_at > one_month_ago
@@ -21,20 +22,20 @@ def format_number(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")[:10]
recent_relnotes_issues = filter(filter_date, relnotes_issues)
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 recent_relnotes_issues:
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 = '<time datetime="' + iso_date + '">' + readable_date + '</time>'
recent_updates.write(u" <li>" + link + datetime + "</li>\n")
datetime_str = '<time datetime="' + iso_date + '">' + readable_date + '</time>'
recent_updates.write(u" <li>" + link + datetime_str + "</li>\n")
recent_updates.write(u"</ul>")
@@ -47,3 +48,42 @@ with io.open("templates/auto/stars.html", 'w', encoding='utf8') as stars:
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)

View File

@@ -1,13 +1,281 @@
title = "Writing an OS in Rust"
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"
generate_rss = true
smart_punctuation = true
ignored_content = ["*/README.md"]
[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", "es"]
[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.
"""
# Spanish
[languages.es]
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.es.translations]
lang_name = "Spanish"
toc = "Tabla de Contenidos"
all_posts = "« Todos los Posts"
comments = "Comentarios"
comments_notice = "Por favor deja tus comentarios en inglés si es posible."
readmore = "leer&nbsp;más&nbsp;»"
not_translated = "(Este post aún no está traducido.)"
translated_content = "Contenido Traducido:"
translated_content_notice = "Esta es una traducción comunitaria del post <strong><a href=\"_original.permalink_\">_original.title_</a></strong>. Puede estar incompleta, desactualizada o contener errores. ¡Por favor reporta cualquier problema!"
translated_by = "Traducción por"
translation_contributors = "Con contribuciones de"
word_separator = "y"
support_me = """
<h2>Apóyame</h2>
<p>Crear y mantener este blog y las bibliotecas asociadas es mucho trabajo, pero realmente disfruto haciéndolo. Al apoyarme, me permites invertir más tiempo en nuevo contenido, nuevas características y mantenimiento continuo. La mejor manera de apoyarme es <a href=\"https://github.com/sponsors/phil-opp\"><em>patrocinarme en GitHub</em></a>. ¡Gracias!</p>
"""
comment_note = """
¿Tienes algún problema, quieres compartir comentarios o discutir más ideas? ¡No dudes en dejar un comentario aquí! Por favor, utiliza inglés y sigue el <a href=\"https://www.rust-lang.org/policies/code-of-conduct\">código de conducta</a> de Rust. Este hilo de comentarios se vincula directamente con una <a href=\"_discussion_url_\"><em>discusión en GitHub</em></a>, así que también puedes comentar allí si lo prefieres.
"""

View File

@@ -4,13 +4,13 @@ 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 <http://creativecommons.org/licenses/by-nc/4.0/>.
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
http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or http://opensource.org/licenses/MIT)
https://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or https://opensource.org/licenses/MIT)
at your option.

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.es.md Normal file
View File

@@ -0,0 +1,13 @@
+++
template = "edition-2/index.html"
+++
<h1 style="visibility: hidden; height: 0px; margin: 0px; padding: 0px;">Escribiendo un sistema operativo en Rust</h1>
<div class="front-page-introduction">
Esta serie de blogs crea un pequeño sistema operativo en el [lenguaje de programación Rust](https://www.rust-lang.org/). Cada publicación es un pequeño tutorial e incluye todo el código necesario, para que puedas seguir los pasos si lo deseas. El código fuente también está disponible en el [repositorio correspondiente de Github](https://github.com/phil-opp/blog_os).
Última publicación: <!-- 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

@@ -4,7 +4,7 @@ weight = 1
path = "catching-exceptions"
aliases = ["catching-exceptions.html"]
date = 2016-05-28
template = "first-edition/page.html"
template = "edition-1/page.html"
[extra]
updated = "2016-06-25"
+++
@@ -20,8 +20,8 @@ As always, the complete source code is on [GitHub]. Please file [issues] for any
> **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”]: @/first-edition/extra/naked-exceptions/_index.md
[“Handling Exceptions”]: @/first-edition/posts/09-handling-exceptions/index.md
[“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.
@@ -35,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:
@@ -245,7 +245,7 @@ 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](normal-vs-interrupt-function-return.svg)
@@ -311,8 +311,8 @@ u64 | Offset | Virtual start address of the table.
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_64 crate]: http://docs.rs/x86_64/0.1.0/x86_64/instructions/tables/struct.DescriptorTablePointer.html
[lidt function]: http://docs.rs/x86_64/0.1.0/x86_64/instructions/tables/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 {
@@ -422,7 +422,7 @@ extern "C" fn divide_by_zero_handler() -> ! {
```
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]: http://wiki.osdev.org/Exceptions#Divide-by-zero_Error
[divide by zero error]: https://wiki.osdev.org/Exceptions#Division_Error
However, it doesn't work this way:

View File

@@ -4,7 +4,7 @@ weight = 2
path = "better-exception-messages"
aliases = ["better-exception-messages.html"]
date = 2016-08-03
template = "first-edition/page.html"
template = "edition-1/page.html"
[extra]
updated = "2016-11-01"
+++
@@ -21,8 +21,8 @@ As always, the complete source code is on [GitHub]. Please file [issues] for any
> **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”]: @/first-edition/extra/naked-exceptions/_index.md
[“Handling Exceptions”]: @/first-edition/posts/09-handling-exceptions/index.md
[“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.
@@ -394,7 +394,7 @@ The base pointer is initialized directly from the stack pointer (`rsp`) after pu
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]: http://web.archive.org/web/20160801075139/http://www.x86-64.org/documentation/abi.pdf
[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.
@@ -628,7 +628,7 @@ bitflags! {
- 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-priviledged mode.
- 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.

View File

@@ -4,7 +4,7 @@ weight = 3
path = "returning-from-exceptions"
aliases = ["returning-from-exceptions.html"]
date = 2016-09-21
template = "first-edition/page.html"
template = "edition-1/page.html"
[extra]
updated = "2016-11-01"
+++
@@ -21,8 +21,8 @@ As always, the complete source code is on [GitHub]. Please file [issues] for any
> **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”]: @/first-edition/extra/naked-exceptions/_index.md
[“Handling Exceptions”]: @/first-edition/posts/09-handling-exceptions/index.md
[“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:
@@ -38,11 +38,11 @@ The breakpoint exception is the perfect exception to test our upcoming return-fr
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]: http://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints
[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]: @/first-edition/posts/07-remap-the-kernel/index.md#using-the-correct-flags
[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:
@@ -126,9 +126,9 @@ Instead of pushing a return address, the CPU pushes the stack and instruction po
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 manual ([PDF][amd-manual]) even demands that `iretq` “_must_ be used to terminate the exception or interrupt handler associated with the exception”.
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://support.amd.com/TechDocs/24594.pdf
[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.
@@ -144,7 +144,7 @@ EXCEPTION: BREAKPOINT at 0x110970
So let's disassemble the instruction at `0x110970` and its predecessor:
```shell
```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)
@@ -216,7 +216,7 @@ Instead of the expected _“It did not crash”_ message after the breakpoint ex
### 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]: @/first-edition/extra/set-up-gdb/index.md
[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:
@@ -250,7 +250,7 @@ However, there is a major difference between exceptions and function calls: A fu
[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]: http://refspecs.linuxbase.org/elf/gabi41.pdf
[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
@@ -304,7 +304,7 @@ Unfortunately, Rust does not support such a calling convention. It was [proposed
[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]: @/first-edition/extra/naked-exceptions/02-better-exception-messages/index.md#naked-functions
[naked fn post]: @/edition-1/extra/naked-exceptions/02-better-exception-messages/index.md#naked-functions
### A naked wrapper function
@@ -426,7 +426,7 @@ 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 assummed 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.
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_:
@@ -505,7 +505,7 @@ A minimal target specification that describes the `x86_64-unknown-linux-gnu` tar
```json
{
"llvm-target": "x86_64-unknown-linux-gnu",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"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",
@@ -518,7 +518,7 @@ The `llvm-target` field specifies the target triple that is passed to LLVM. We w
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]: http://llvm.org/docs/LangRef.html#data-layout
[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
@@ -527,7 +527,7 @@ In order to disable the multimedia extensions, we create a new target named `x86
```json
{
"llvm-target": "x86_64-unknown-linux-gnu",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"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",
@@ -574,7 +574,7 @@ It doesn't compile anymore. The error tells us that the Rust compiler no longer
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]: @/first-edition/posts/03-set-up-rust/index.md
[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.
@@ -695,7 +695,7 @@ So now our return-from-exception logic works without problems in _most_ cases. H
## 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]: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone
[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)
@@ -709,7 +709,7 @@ However, this optimization leads to huge problems with exceptions. Let's assume
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]: http://forum.osdev.org/viewtopic.php?t=21720
[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:

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"]
+++

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -2,6 +2,7 @@
title = "Set Up GDB"
template = "plain.html"
path = "set-up-gdb"
aliases = ["set-up-gdb.html"]
weight = 4
+++
@@ -32,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 :-)
@@ -73,5 +74,5 @@ After connecting to QEMU, you can use various gdb commands to control execution
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

@@ -4,12 +4,12 @@ weight = 1
path = "multiboot-kernel"
aliases = ["multiboot-kernel.html", "/2015/08/18/multiboot-kernel/", "/rust-os/multiboot-kernel.html"]
date = 2015-08-18
template = "first-edition/page.html"
template = "edition-1/page.html"
+++
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 -->
@@ -28,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 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:
@@ -130,7 +130,7 @@ 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`:
@@ -187,7 +187,7 @@ Idx Name Size VMA LMA File off Algn
```
_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]: @/first-edition/extra/cross-compile-binutils.md
[cross compile binutils]: @/edition-1/extra/cross-compile-binutils.md
## Creating the ISO
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:
@@ -315,7 +315,7 @@ 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]: @/first-edition/posts/02-entering-longmode/index.md
[next post]: @/edition-1/posts/02-entering-longmode/index.md
[long mode]: https://en.wikipedia.org/wiki/Long_mode
## Footnotes

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -4,15 +4,15 @@ weight = 2
path = "entering-longmode"
aliases = ["entering-longmode.html", "/2015/08/25/entering-longmode/", "/rust-os/entering-longmode.html"]
date = 2015-08-25
template = "first-edition/page.html"
template = "edition-1/page.html"
[extra]
updated = "2015-10-29"
+++
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]: @/first-edition/posts/01-multiboot-kernel/index.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
@@ -39,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]: @/first-edition/posts/04-printing-to-screen/index.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.
@@ -47,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`:
@@ -96,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:
@@ -151,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:
@@ -400,7 +400,7 @@ Bit(s) | Name | Meaning
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 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:
@@ -451,7 +451,7 @@ gdt64:
```
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
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:
@@ -492,8 +492,8 @@ _Congratulations_! You have successfully wrestled through this CPU configuration
#### 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.
[iretq]: @/first-edition/extra/naked-exceptions/03-returning-from-exceptions/index.md#the-iretq-instruction
[_Returning from Exceptions_]: @/first-edition/extra/naked-exceptions/03-returning-from-exceptions/index.md
[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:
@@ -515,7 +515,7 @@ long_mode_start:
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]: @/first-edition/posts/03-set-up-rust/index.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.

View File

@@ -4,15 +4,15 @@ 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 = "first-edition/page.html"
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]: @/first-edition/posts/01-multiboot-kernel/index.md
[long mode post]: @/first-edition/posts/02-entering-longmode/index.md
[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 -->
@@ -31,12 +31,10 @@ nightly
[rustup]: https://www.rustup.rs/
The code from this post (and all following) is [automatically tested](https://travis-ci.org/phil-opp/blog_os) every day and should always work for the newest nightly. If it doesn't, please [file an issue](https://github.com/phil-opp/blog_os/issues).
## 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]: http://doc.crates.io/guide.html
[Cargo]: https://doc.crates.io/guide.html
```toml
[package]
@@ -49,7 +47,7 @@ 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]: http://doc.crates.io/manifest.html#the-package-section
[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`:
@@ -92,7 +90,7 @@ Let's define some properties of our target system:
- **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”]: @/first-edition/posts/09-handling-exceptions/index.md
[“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:
@@ -100,7 +98,7 @@ Rust allows us to define [custom targets] through a JSON configuration file. A m
```json
{
"llvm-target": "x86_64-unknown-linux-gnu",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"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",
@@ -114,7 +112,7 @@ Rust allows us to define [custom targets] through a JSON configuration file. A m
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]: http://llvm.org/docs/LangRef.html#target-triple
[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.
@@ -126,7 +124,7 @@ The `linker-flavor` field was recently introduced in [#40018] with the intention
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]: http://llvm.org/docs/LangRef.html#data-layout
[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
@@ -135,7 +133,7 @@ For our target system, we define the following JSON configuration in a file name
```json
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"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",
@@ -152,8 +150,8 @@ As `llvm-target` we use `x86_64-unknown-none`, which defines the `x86_64` archit
#### 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]: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone
[System V ABI]: http://wiki.osdev.org/System_V_ABI
[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)
@@ -167,7 +165,7 @@ However, this optimization leads to huge problems with exceptions or hardware in
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]: http://forum.osdev.org/viewtopic.php?t=21720
[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.
@@ -406,9 +404,7 @@ So the linker can't find a function named `_Unwind_Resume` that is referenced e.
[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.
[recover from panics]: https://doc.rust-lang.org/book/concurrency.html#panics
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:
@@ -479,17 +475,17 @@ Some notes:
- `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.html#characters-and-strings
[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]: @/first-edition/posts/02-entering-longmode/index.md#creating-a-stack
[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]: @/first-edition/posts/04-printing-to-screen/index.md
[next post]: @/edition-1/posts/04-printing-to-screen/index.md

View File

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -4,14 +4,14 @@ 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 = "first-edition/page.html"
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]: @/first-edition/posts/03-set-up-rust/index.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
@@ -190,7 +190,7 @@ When printing a byte, the writer checks if the current line is full. In that cas
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.10.0/core/ptr/struct.Unique.html#method.as_mut
[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:
@@ -205,7 +205,7 @@ error[E0507]: 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.
[ownership section]: https://doc.rust-lang.org/book/ownership.html
[by reference]: http://rust-lang.github.io/book/ch04-02-references-and-borrowing.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]:
@@ -257,7 +257,7 @@ It just creates a new Writer that points to the VGA buffer at `0xb8000`. To use
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:
[byte character]: https://doc.rust-lang.org/reference.html#characters-and-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)
@@ -287,8 +287,8 @@ 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]: http://semver.org/
[Specifying Dependencies]: http://doc.crates.io/specifying-dependencies.html
[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`:
@@ -354,7 +354,7 @@ 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 fmt::Write for Writer` block and add a return type:
@@ -441,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/second-edition/ch19-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable
[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.
@@ -529,7 +529,7 @@ The macro expands to a call of the [`_print` function] in the `io` module. The [
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/book/macros.html#the-variable-crate
[`$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
@@ -642,7 +642,7 @@ In the next posts we will map the kernel pages correctly so that accessing `0x0`
The [next post] describes the Multiboot information structure and creates a frame allocator using the information about memory areas.
[next post]: @/first-edition/posts/05-allocating-frames/index.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:
@@ -657,8 +657,8 @@ _Note_: You need to [cross compile binutils] to build it (or you create some sym
- [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]: http://wiki.osdev.org/Higher_Half_Kernel
[cross compile binutils]: @/first-edition/extra/cross-compile-binutils.md
[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

View File

@@ -4,7 +4,7 @@ weight = 5
path = "allocating-frames"
aliases = ["allocating-frames.html"]
date = 2015-11-15
template = "first-edition/page.html"
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.
@@ -71,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:
@@ -100,7 +100,7 @@ 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:
@@ -217,7 +217,7 @@ We could create some kind of linked list from the free frames. For example, each
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).
@@ -394,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(
@@ -421,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
@@ -430,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]: @/first-edition/posts/06-page-tables/index.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]: @/first-edition/posts/04-printing-to-screen/index.md
[Printing to Screen]: @/edition-1/posts/04-printing-to-screen/index.md

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -4,7 +4,7 @@ weight = 6
path = "page-tables"
aliases = ["page-tables.html", "modifying-page-tables.html"]
date = 2015-12-09
template = "first-edition/page.html"
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.
@@ -52,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]: @/first-edition/posts/05-allocating-frames/index.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:
@@ -323,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> {...}
@@ -652,7 +652,7 @@ 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]: @/first-edition/posts/04-printing-to-screen/index.md#the-text-buffer
[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:
@@ -881,7 +881,7 @@ 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]: @/first-edition/posts/07-remap-the-kernel/index.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`.

View File

@@ -4,7 +4,7 @@ weight = 7
path = "remap-the-kernel"
aliases = ["remap-the-kernel.html"]
date = 2016-01-01
template = "first-edition/page.html"
template = "edition-1/page.html"
[extra]
updated = "2016-03-06"
+++
@@ -21,18 +21,18 @@ As always, you can find the source code on [GitHub]. Don't hesitate to file issu
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]: @/first-edition/posts/06-page-tables/index.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]: @/first-edition/posts/05-allocating-frames/index.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]: @/first-edition/extra/set-up-gdb/index.md
[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:
@@ -281,7 +281,7 @@ 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]: @/first-edition/posts/06-page-tables/index.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.
@@ -368,7 +368,7 @@ 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:
@@ -466,7 +466,7 @@ let backup = Frame::containing_address(
```
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:
@@ -554,7 +554,7 @@ First, we create a temporary page at page number `0xcafebabe`. We could use `0xd
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]: @/first-edition/posts/05-allocating-frames/index.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:
@@ -641,7 +641,7 @@ 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:
@@ -826,11 +826,11 @@ These lines are the important ones. We can read many useful information from the
- `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].
[osdev exception overview]: http://wiki.osdev.org/Exceptions
[page fault]: http://wiki.osdev.org/Exceptions#Page_Fault
[page fault error code]: http://wiki.osdev.org/Exceptions#Error_code
[GDT segment]: @/first-edition/posts/02-entering-longmode/index.md#loading-the-gdt
[VGA text buffer]: @/first-edition/posts/04-printing-to-screen/index.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:
@@ -882,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
@@ -1028,7 +1028,7 @@ 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]: @/first-edition/posts/06-page-tables/index.md
[silent stack overflow]: @/edition-1/posts/06-page-tables/index.md
```nasm
; in src/arch/x86_64/boot.asm
@@ -1089,7 +1089,7 @@ 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]: @/first-edition/posts/08-kernel-heap/index.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/1.10.0/collections/vec/struct.Vec.html
[BTreeMap]: https://doc.rust-lang.org/1.10.0/collections/btree_map/struct.BTreeMap.html

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -4,14 +4,15 @@ weight = 8
path = "kernel-heap"
aliases = ["kernel-heap.html"]
date = 2016-04-11
template = "edition-1/page.html"
[extra]
updated = "2017-11-19"
template = "first-edition/page.html"
+++
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]: @/first-edition/posts/05-allocating-frames/index.md
[page table module]: @/first-edition/posts/06-page-tables/index.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
<!-- more -->
@@ -32,9 +33,9 @@ The _heap_ is the memory area for long-lived allocations. The programmer can acc
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. Nevertheless, it should suffice for the foreseeable future, since we'll allocate only when it's absolutely necessary.
@@ -332,7 +333,7 @@ let heap_test = Box::new(42);
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]:
[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
@@ -344,7 +345,7 @@ check_exception old: 0xffffffff new 0xe
```
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:
@@ -414,7 +415,7 @@ 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 artificially increased by such sections.
- We use the `start_address()` and `end_address()` methods of `boot_info` instead of calculating the adresses manually.
- 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
@@ -460,8 +461,8 @@ That's it. Now our `memory::init` function can only be called once. The macro wo
### 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 [page table] and [kernel remapping] posts). For that we return it from the `paging::remap_the_kernel` function:
[page table]: @/first-edition/posts/06-page-tables/index.md
[kernel remapping]: @/first-edition/posts/07-remap-the-kernel/index.md
[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
@@ -674,7 +675,7 @@ I created the [linked_list_allocator] crate to handle all of these cases. It con
We need to add the extern crate to our `Cargo.toml` and our `lib.rs`:
``` shell
``` bash
> cargo add linked_list_allocator
```
@@ -736,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]: @/first-edition/posts/09-handling-exceptions/index.md
[next post]: @/edition-1/posts/09-handling-exceptions/index.md

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -4,12 +4,12 @@ weight = 9
path = "handling-exceptions"
aliases = ["handling-exceptions.html"]
date = 2017-03-26
template = "first-edition/page.html"
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]: http://wiki.osdev.org/Exceptions#Breakpoint
[breakpoint exceptions]: https://wiki.osdev.org/Exceptions#Breakpoint
<!-- more -->
@@ -30,7 +30,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:
@@ -118,7 +118,7 @@ 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/book/ffi.html#foreign-calling-conventions
[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.
@@ -128,7 +128,7 @@ However, there is a major difference between exceptions and function calls: A fu
[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]: http://refspecs.linuxbase.org/elf/gabi41.pdf
[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
@@ -221,15 +221,15 @@ pub fn init() {
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]: http://wiki.osdev.org/Exceptions#Breakpoint
[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_"]: http://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints
["_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]: @/first-edition/posts/07-remap-the-kernel/index.md#using-the-correct-flags
[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:
@@ -317,7 +317,7 @@ pub fn init() {
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/book/second-edition/ch19-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable
[`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;
@@ -334,7 +334,7 @@ pub fn init() {
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/book/second-edition/ch19-01-unsafe-rust.html#unsafe-superpowers
[`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.
@@ -379,7 +379,7 @@ 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 unitialized) value. So this solution also uses `unsafe` behind the scenes, but it is abstracted away in a safe interface.
> 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
@@ -439,16 +439,16 @@ The answer is that the stored instruction pointer only points to the causing ins
- **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]: http://wiki.osdev.org/Exceptions#Page_Fault
[machine check exception]: http://wiki.osdev.org/Exceptions#Machine_Check
[double fault]: http://wiki.osdev.org/Exceptions#Double_Fault
[overflow exception]: http://wiki.osdev.org/Exceptions#Overflow
[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]: http://wiki.osdev.org/Exceptions#Debug
[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.
@@ -456,18 +456,18 @@ In some cases, the distinction between faults and traps is vague. For example, t
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]: http://wiki.osdev.org/Exceptions
[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”]: @/first-edition/extra/naked-exceptions/_index.md
[“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]: http://wiki.osdev.org/Triple_Fault
[double faults]: http://wiki.osdev.org/Double_Fault#Double_Fault
[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.

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -4,7 +4,7 @@ weight = 10
path = "double-faults"
aliases = ["double-faults.html"]
date = 2017-01-02
template = "first-edition/page.html"
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.
@@ -20,7 +20,7 @@ As always, the complete source code is available on [GitHub]. Please file [issue
## 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]: @/first-edition/posts/09-handling-exceptions/index.md#the-interrupt-descriptor-table
[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.
@@ -119,7 +119,7 @@ For example, what happens if… :
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]: @/first-edition/posts/07-remap-the-kernel/index.md#creating-a-guard-page
[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:
@@ -128,12 +128,12 @@ 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]: http://wiki.osdev.org/Exceptions#Divide-by-zero_Error
[Invalid TSS]: http://wiki.osdev.org/Exceptions#Invalid_TSS
[Segment Not Present]: http://wiki.osdev.org/Exceptions#Segment_Not_Present
[Stack-Segment Fault]: http://wiki.osdev.org/Exceptions#Stack-Segment_Fault
[General Protection Fault]: http://wiki.osdev.org/Exceptions#General_Protection_Fault
[Page Fault]: http://wiki.osdev.org/Exceptions#Page_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
@@ -155,7 +155,7 @@ Let's look at the fourth question:
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]: http://os.phil-opp.com/better-exception-messages.html#exceptions-in-detail
[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.
@@ -199,7 +199,7 @@ struct InterruptStackTable {
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]: @/first-edition/posts/09-handling-exceptions/index.md#the-interrupt-descriptor-table
[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:
@@ -230,7 +230,7 @@ impl StackAllocator {
```
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]: @/first-edition/posts/08-kernel-heap/index.md#mapping-the-heap
[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:
@@ -285,8 +285,8 @@ impl StackAllocator {
```
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]: @/first-edition/posts/06-page-tables/index.md#page-table-ownership
[FrameAllocator]: @/first-edition/posts/05-allocating-frames/index.md#a-frame-allocator
[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`).
@@ -297,7 +297,7 @@ In order to be able to clone `PageIter`, we add a `#[derive(Clone)]` to its defi
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]: @/first-edition/posts/06-page-tables/index.md#more-mapping-functions
[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:
@@ -438,7 +438,7 @@ We allocate a 4096 bytes stack (one page) for our double fault handler. Now we j
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]: http://wiki.osdev.org/Context_Switching#Hardware_Context_Switching
[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].
@@ -495,7 +495,7 @@ We define that the 0th IST entry is the double fault stack (any other IST index
#### 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]: http://www.flingos.co.uk/docs/reference/Global-Descriptor-Table/
[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)
@@ -505,7 +505,7 @@ The Global Descriptor Table (GDT) is a relict that was used for [memory segmenta
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]: @/first-edition/posts/02-entering-longmode/index.md#the-global-descriptor-table
[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:
@@ -608,7 +608,7 @@ Bit(s) | Name | Meaning
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]: http://wiki.osdev.org/Security#Rings
[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`.

View File

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

View File

@@ -3,5 +3,5 @@ title = "Extra Content"
insert_anchor_links = "left"
render = false
sort_by = "weight"
page_template = "second-edition/extra.html"
page_template = "edition-2/extra.html"
+++

View File

@@ -1,19 +1,25 @@
+++
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](https://f-droid.org/packages/com.termux/). After installing, open it and perform the following steps:
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:
```
@@ -29,7 +35,7 @@ First, install [termux](https://termux.com/) from the [Google Play Store](https:
pkg install wget tar
```
- Add the [community repository by its-pointless](https://wiki.termux.com/wiki/Package_Management#By_its-pointless_.28live_the_dream.29:):
- 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

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,522 @@
+++
title = "Un Binario Rust Autónomo"
weight = 1
path = "es/freestanding-rust-binary"
date = 2018-02-10
[extra]
chapter = "Bare Bones"
# GitHub usernames of the people that translated this post
translators = ["dobleuber"]
+++
El primer paso para crear nuestro propio kernel de sistema operativo es crear un ejecutable en Rust que no enlace con la biblioteca estándar. Esto hace posible ejecutar código Rust directamente en el [bare metal] sin un sistema operativo subyacente.
[bare metal]: https://en.wikipedia.org/wiki/Bare_machine
<!-- more -->
Este blog se desarrolla abiertamente en [GitHub]. Si tienes algún problema o pregunta, por favor abre un issue allí. También puedes dejar comentarios [al final]. El código fuente completo para esta publicación se encuentra en la rama [`post-01`][post branch].
[GitHub]: https://github.com/phil-opp/blog_os
[al final]: #comments
<!-- solución para el verificador de anclajes de zola (el objetivo está en la plantilla): <a id="comments"> -->
[post branch]: https://github.com/phil-opp/blog_os/tree/post-01
<!-- toc -->
## Introducción
Para escribir un kernel de sistema operativo, necesitamos código que no dependa de características del sistema operativo. Esto significa que no podemos usar hilos, archivos, memoria dinámica, redes, números aleatorios, salida estándar ni ninguna otra característica que requiera abstracciones de sistema operativo o hardware específico. Esto tiene sentido, ya que estamos intentando escribir nuestro propio sistema operativo y nuestros propios controladores.
Esto implica que no podemos usar la mayor parte de la [biblioteca estándar de Rust], pero hay muchas características de Rust que sí _podemos_ usar. Por ejemplo, podemos utilizar [iteradores], [closures], [pattern matching], [option] y [result], [formateo de cadenas] y, por supuesto, el [sistema de ownership]. Estas características hacen posible escribir un kernel de una manera muy expresiva y de alto nivel, sin preocuparnos por el [comportamiento indefinido] o la [seguridad de la memoria].
[option]: https://doc.rust-lang.org/core/option/
[result]: https://doc.rust-lang.org/core/result/
[biblioteca estándar de Rust]: https://doc.rust-lang.org/std/
[iteradores]: 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
[formateo de cadenas]: https://doc.rust-lang.org/core/macro.write.html
[sistema de ownership]: https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html
[comportamiento indefinido]: https://www.nayuki.io/page/undefined-behavior-in-c-and-cplusplus-programs
[seguridad de la memoria]: https://tonyarcieri.com/it-s-time-for-a-memory-safety-intervention
Para crear un kernel de sistema operativo en Rust, necesitamos crear un ejecutable que pueda ejecutarse sin un sistema operativo subyacente. Dicho ejecutable se llama frecuentemente un ejecutable “autónomo” o de “bare metal”.
Esta publicación describe los pasos necesarios para crear un binario autónomo en Rust y explica por qué son necesarios. Si solo te interesa un ejemplo mínimo, puedes **[saltar al resumen](#resumen)**.
## Deshabilitando la Biblioteca Estándar
Por defecto, todos los crates de Rust enlazan con la [biblioteca estándar], que depende del sistema operativo para características como hilos, archivos o redes. También depende de la biblioteca estándar de C, `libc`, que interactúa estrechamente con los servicios del sistema operativo. Como nuestro plan es escribir un sistema operativo, no podemos usar ninguna biblioteca que dependa del sistema operativo. Por lo tanto, tenemos que deshabilitar la inclusión automática de la biblioteca estándar mediante el atributo [`no_std`].
[biblioteca estándar]: 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
Comenzamos creando un nuevo proyecto de aplicación en Cargo. La forma más fácil de hacerlo es a través de la línea de comandos:
```
cargo new blog_os --bin --edition 2018
```
Nombré el proyecto `blog_os`, pero, por supuesto, puedes elegir tu propio nombre. La bandera `--bin` especifica que queremos crear un binario ejecutable (en contraste con una biblioteca), y la bandera `--edition 2018` indica que queremos usar la [edición 2018] de Rust para nuestro crate. Al ejecutar el comando, Cargo crea la siguiente estructura de directorios para nosotros:
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
```
blog_os
├── Cargo.toml
└── src
└── main.rs
```
El archivo `Cargo.toml` contiene la configuración del crate, como el nombre del crate, el autor, el número de [versión semántica] y las dependencias. El archivo `src/main.rs` contiene el módulo raíz de nuestro crate y nuestra función `main`. Puedes compilar tu crate utilizando `cargo build` y luego ejecutar el binario compilado `blog_os` ubicado en la subcarpeta `target/debug`.
[semantic version]: https://semver.org/
### El Atributo `no_std`
Actualmente, nuestro crate enlaza implícitamente con la biblioteca estándar. Intentemos deshabilitar esto añadiendo el [`atributo no_std`]:
```rust
// main.rs
#![no_std]
fn main() {
println!("Hello, world!");
}
```
Cuando intentamos compilarlo ahora (ejecutando `cargo build`), ocurre el siguiente error:
```
error: cannot find macro `println!` in this scope
--> src/main.rs:4:5
|
4 | println!("Hello, world!");
| ^^^^^^^
```
La razón de este error es que la [macro `println`] forma parte de la biblioteca estándar, la cual ya no estamos incluyendo. Por lo tanto, ya no podemos imprimir cosas. Esto tiene sentido, ya que `println` escribe en la [salida estándar], que es un descriptor de archivo especial proporcionado por el sistema operativo.
[macro `println`]: https://doc.rust-lang.org/std/macro.println.html
[salida estándar]: https://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29
Así que eliminemos la impresión e intentemos de nuevo con una función `main` vacía:
```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`
```
Ahora el compilador indica que falta una función `#[panic_handler]` y un _elemento de lenguaje_ (_language item_).
## Implementación de Panic
El atributo `panic_handler` define la función que el compilador invoca cuando ocurre un [panic]. La biblioteca estándar proporciona su propia función de panico, pero en un entorno `no_std` debemos definirla nosotros mismos:
[panic]: https://doc.rust-lang.org/stable/book/ch09-01-unrecoverable-errors-with-panic.html
```rust
// en main.rs
use core::panic::PanicInfo;
/// Esta función se llama cuando ocurre un pánico.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
El [parámetro `PanicInfo`][PanicInfo] contiene el archivo y la línea donde ocurrió el panic, así como el mensaje opcional del panic. La función no debería retornar nunca, por lo que se marca como una [función divergente][diverging function] devolviendo el [tipo “never”][“never” type] `!`. Por ahora, no hay mucho que podamos hacer en esta función, así que simplemente entramos en un bucle infinito.
[PanicInfo]: https://doc.rust-lang.org/nightly/core/panic/struct.PanicInfo.html
[diverging function]: https://doc.rust-lang.org/1.30.0/book/first-edition/functions.html#diverging-functions
[“never” type]: https://doc.rust-lang.org/nightly/std/primitive.never.html
## El Elemento de Lenguaje `eh_personality`
Los elementos de lenguaje son funciones y tipos especiales que el compilador requiere internamente. Por ejemplo, el trait [`Copy`] es un elemento de lenguaje que indica al compilador qué tipos tienen [_semántica de copia_][`Copy`]. Si observamos su [implementación][copy code], veremos que tiene el atributo especial `#[lang = "copy"]`, que lo define como un elemento de lenguaje.
[`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
Aunque es posible proporcionar implementaciones personalizadas de elementos de lenguaje, esto debería hacerse solo como último recurso. La razón es que los elementos de lenguaje son detalles de implementación altamente inestables y ni siquiera están verificados por tipos (el compilador no comprueba si una función tiene los tipos de argumento correctos). Afortunadamente, hay una forma más estable de solucionar el error relacionado con el elemento de lenguaje mencionado.
El [elemento de lenguaje `eh_personality`][`eh_personality` language item] marca una función utilizada para implementar el [desenrollado de pila][stack unwinding]. Por defecto, Rust utiliza unwinding para ejecutar los destructores de todas las variables de pila activas en caso de un [pánico][panic]. Esto asegura que toda la memoria utilizada sea liberada y permite que el hilo principal capture el pánico y continúe ejecutándose. Sin embargo, el unwinding es un proceso complicado y requiere algunas bibliotecas específicas del sistema operativo (por ejemplo, [libunwind] en Linux o [manejadores estructurados de excepciones][structured exception handling] en Windows), por lo que no queremos usarlo en nuestro sistema operativo.
[`eh_personality` language item]: 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/
[structured exception handling]: https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling
[panic]: https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html
### Deshabilitando el Unwinding
Existen otros casos de uso en los que el no es deseable, por lo que Rust proporciona una opción para [abortar en caso de pánico][abort on panic]. Esto desactiva la generación de información de símbolos de unwinding y, por lo tanto, reduce considerablemente el tamaño del binario. Hay múltiples lugares donde podemos deshabilitar el unwinding. La forma más sencilla es agregar las siguientes líneas a nuestro archivo `Cargo.toml`:
```toml
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
```
Esto establece la estrategia de pánico en `abort` tanto para el perfil `dev` (utilizado en `cargo build`) como para el perfil `release` (utilizado en `cargo build --release`). Ahora, el elemento de lenguaje `eh_personality` ya no debería ser necesario.
[abort on panic]: https://github.com/rust-lang/rust/pull/32900
Ahora hemos solucionado ambos errores anteriores. Sin embargo, si intentamos compilarlo ahora, ocurre otro error:
```
> cargo build
error: requires `start` lang_item
```
Nuestro programa carece del elemento de lenguaje `start`, que define el punto de entrada.
## El Atributo `start`
Podría pensarse que la función `main` es la primera que se ejecuta al correr un programa. Sin embargo, la mayoría de los lenguajes tienen un [sistema de tiempo de ejecución][runtime system], encargado de tareas como la recolección de basura (por ejemplo, en Java) o los hilos de software (por ejemplo, goroutines en Go). Este sistema de tiempo de ejecución necesita ejecutarse antes de `main`, ya que debe inicializarse.
[runtime system]: https://en.wikipedia.org/wiki/Runtime_system
En un binario típico de Rust que enlaza con la biblioteca estándar, la ejecución comienza en una biblioteca de tiempo de ejecución de C llamada `crt0` ("C runtime zero"), que configura el entorno para una aplicación en C. Esto incluye la creación de una pila y la colocación de los argumentos en los registros adecuados. Luego, el tiempo de ejecución de C invoca el [punto de entrada del tiempo de ejecución de Rust][rt::lang_start], que está marcado por el elemento de lenguaje `start`. Rust tiene un tiempo de ejecución muy minimalista, que se encarga de tareas menores como configurar los guardias de desbordamiento de pila o imprimir un backtrace en caso de pánico. Finalmente, el tiempo de ejecución llama a la función `main`.
[rt::lang_start]: https://github.com/rust-lang/rust/blob/bb4d1491466d8239a7a5fd68bd605e3276e97afb/src/libstd/rt.rs#L32-L73
Nuestro ejecutable autónomo no tiene acceso al tiempo de ejecución de Rust ni a `crt0`, por lo que necesitamos definir nuestro propio punto de entrada. Implementar el elemento de lenguaje `start` no ayudaría, ya que aún requeriría `crt0`. En su lugar, debemos sobrescribir directamente el punto de entrada de `crt0`.
### Sobrescribiendo el Punto de Entrada
Para indicar al compilador de Rust que no queremos usar la cadena normal de puntos de entrada, agregamos el atributo `#![no_main]`:
```rust
#![no_std]
#![no_main]
use core::panic::PanicInfo;
/// Esta función se llama cuando ocurre un pánico.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
Podrás notar que eliminamos la función `main`. La razón es que una función `main` no tiene sentido sin un sistema de tiempo de ejecución subyacente que la invoque. En su lugar, estamos sobrescribiendo el punto de entrada del sistema operativo con nuestra propia función `_start`:
```rust
#[no_mangle]
pub extern "C" fn _start() -> ! {
loop {}
}
```
Al usar el atributo `#[no_mangle]`, deshabilitamos el [name mangling] para asegurarnos de que el compilador de Rust realmente genere una función con el nombre `_start`. Sin este atributo, el compilador generaría un símbolo críptico como `_ZN3blog_os4_start7hb173fedf945531caE` para dar un nombre único a cada función. Este atributo es necesario porque necesitamos informar al enlazador el nombre de la función de punto de entrada en el siguiente paso.
También debemos marcar la función como `extern "C"` para indicar al compilador que debe usar la [convención de llamadas en C][C calling convention] para esta función (en lugar de la convención de llamadas de Rust, que no está especificada). El motivo para nombrar la función `_start` es que este es el nombre predeterminado del punto de entrada en la mayoría de los sistemas.
[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
[C calling convention]: https://en.wikipedia.org/wiki/Calling_convention
El tipo de retorno `!` significa que la función es divergente, es decir, no está permitido que retorne nunca. Esto es necesario porque el punto de entrada no es llamado por ninguna función, sino que es invocado directamente por el sistema operativo o el bootloader. En lugar de retornar, el punto de entrada debería, por ejemplo, invocar la [llamada al sistema `exit`][`exit` system call] del sistema operativo. En nuestro caso, apagar la máquina podría ser una acción razonable, ya que no queda nada por hacer si un binario autónomo regresa. Por ahora, cumplimos con este requisito entrando en un bucle infinito.
[`exit` system call]: https://en.wikipedia.org/wiki/Exit_(system_call)
Cuando ejecutamos `cargo build` ahora, obtenemos un feo error del _linker_ (enlazador).
## Errores del Enlazador
El enlazador es un programa que combina el código generado en un ejecutable. Dado que el formato del ejecutable varía entre Linux, Windows y macOS, cada sistema tiene su propio enlazador que lanza errores diferentes. Sin embargo, la causa fundamental de los errores es la misma: la configuración predeterminada del enlazador asume que nuestro programa depende del tiempo de ejecución de C, lo cual no es cierto.
Para solucionar los errores, necesitamos informar al enlazador que no debe incluir el tiempo de ejecución de C. Esto puede hacerse pasando un conjunto específico de argumentos al enlazador o construyendo para un destino de bare metal.
### Construyendo para un Destino de Bare Metal
Por defecto, Rust intenta construir un ejecutable que pueda ejecutarse en el entorno actual de tu sistema. Por ejemplo, si estás usando Windows en `x86_64`, Rust intenta construir un ejecutable `.exe` para Windows que utilice instrucciones `x86_64`. Este entorno se llama tu sistema "host".
Para describir diferentes entornos, Rust utiliza una cadena llamada [_target triple_]. Puedes ver el _target triple_ de tu sistema host ejecutando:
```
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
```
El resultado anterior es de un sistema Linux `x86_64`. Vemos que la tripleta del `host` es `x86_64-unknown-linux-gnu`, lo que incluye la arquitectura de la CPU (`x86_64`), el proveedor (`unknown`), el sistema operativo (`linux`) y el [ABI] (`gnu`).
[ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
Al compilar para la tripleta del host, el compilador de Rust y el enlazador asumen que hay un sistema operativo subyacente como Linux o Windows que utiliza el tiempo de ejecución de C de forma predeterminada, lo que provoca los errores del enlazador. Para evitar estos errores, podemos compilar para un entorno diferente que no tenga un sistema operativo subyacente.
Un ejemplo de este tipo de entorno bare metal es la tripleta de destino `thumbv7em-none-eabihf`, que describe un sistema [embebido][embedded] basado en [ARM]. Los detalles no son importantes, lo que importa es que la tripleta de destino no tiene un sistema operativo subyacente, lo cual se indica por el `none` en la tripleta de destino. Para poder compilar para este destino, necesitamos agregarlo usando `rustup`:
```
rustup target add thumbv7em-none-eabihf
```
Esto descarga una copia de las bibliotecas estándar (y core) para el sistema. Ahora podemos compilar nuestro ejecutable autónomo para este destino:
```
cargo build --target thumbv7em-none-eabihf
```
Al pasar un argumento `--target`, realizamos un [compilado cruzado][cross compile] de nuestro ejecutable para un sistema bare metal. Dado que el sistema de destino no tiene un sistema operativo, el enlazador no intenta enlazar con el tiempo de ejecución de C, y nuestra compilación se completa sin errores del enlazador.
[cross compile]: https://en.wikipedia.org/wiki/Cross_compiler
Este es el enfoque que utilizaremos para construir nuestro kernel de sistema operativo. En lugar de `thumbv7em-none-eabihf`, utilizaremos un [destino personalizado][custom target] que describa un entorno bare metal `x86_64`. Los detalles se explicarán en la siguiente publicación.
[custom target]: https://doc.rust-lang.org/rustc/targets/custom.html
### Argumentos del Enlazador
En lugar de compilar para un sistema bare metal, también es posible resolver los errores del enlazador pasando un conjunto específico de argumentos al enlazador. Este no es el enfoque que usaremos para nuestro kernel, por lo tanto, esta sección es opcional y se proporciona solo para completar. Haz clic en _"Argumentos del Enlazador"_ a continuación para mostrar el contenido opcional.
<details>
<summary>Argumentos del Enlazador</summary>
En esta sección discutimos los errores del enlazador que ocurren en Linux, Windows y macOS, y explicamos cómo resolverlos pasando argumentos adicionales al enlazador. Ten en cuenta que el formato del ejecutable y el enlazador varían entre sistemas operativos, por lo que se requiere un conjunto diferente de argumentos para cada sistema.
#### Linux
En Linux ocurre el siguiente error del enlazador (resumido):
```
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
```
El problema es que el enlazador incluye por defecto la rutina de inicio del tiempo de ejecución de C, que también se llama `_start`. Esta rutina requiere algunos símbolos de la biblioteca estándar de C `libc` que no incluimos debido al atributo `no_std`, por lo que el enlazador no puede resolver estas referencias. Para solucionar esto, podemos indicar al enlazador que no enlace la rutina de inicio de C pasando la bandera `-nostartfiles`.
Una forma de pasar atributos al enlazador a través de Cargo es usar el comando `cargo rustc`. Este comando se comporta exactamente como `cargo build`, pero permite pasar opciones a `rustc`, el compilador subyacente de Rust. `rustc` tiene la bandera `-C link-arg`, que pasa un argumento al enlazador. Combinados, nuestro nuevo comando de compilación se ve así:
```
cargo rustc -- -C link-arg=-nostartfiles
```
¡Ahora nuestro crate se compila como un ejecutable autónomo en Linux!
No fue necesario especificar explícitamente el nombre de nuestra función de punto de entrada, ya que el enlazador busca una función con el nombre `_start` por defecto.
#### Windows
En Windows, ocurre un error del enlazador diferente (resumido):
```
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
```
El error "entry point must be defined" significa que el enlazador no puede encontrar el punto de entrada. En Windows, el nombre predeterminado del punto de entrada [depende del subsistema utilizado][windows-subsystems]. Para el subsistema `CONSOLE`, el enlazador busca una función llamada `mainCRTStartup`, y para el subsistema `WINDOWS`, busca una función llamada `WinMainCRTStartup`. Para anular este comportamiento predeterminado y decirle al enlazador que busque nuestra función `_start`, podemos pasar un argumento `/ENTRY` al enlazador:
[windows-subsystems]: https://docs.microsoft.com/en-us/cpp/build/reference/entry-entry-point-symbol
```
cargo rustc -- -C link-arg=/ENTRY:_start
```
Por el formato diferente del argumento, podemos ver claramente que el enlazador de Windows es un programa completamente distinto al enlazador de Linux.
Ahora ocurre un error diferente del enlazador:
```
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
```
Este error ocurre porque los ejecutables de Windows pueden usar diferentes [subsistemas][windows-subsystems]. En programas normales, se infieren dependiendo del nombre del punto de entrada: si el punto de entrada se llama `main`, se usa el subsistema `CONSOLE`, y si el punto de entrada se llama `WinMain`, se usa el subsistema `WINDOWS`. Dado que nuestra función `_start` tiene un nombre diferente, necesitamos especificar el subsistema explícitamente:
```
cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"
```
Aquí usamos el subsistema `CONSOLE`, pero el subsistema `WINDOWS` también funcionaría. En lugar de pasar `-C link-arg` varias veces, podemos usar `-C link-args`, que acepta una lista de argumentos separados por espacios.
Con este comando, nuestro ejecutable debería compilarse exitosamente en Windows.
#### macOS
En macOS, ocurre el siguiente error del enlazador (resumido):
```
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 […]
```
Este mensaje de error nos indica que el enlazador no puede encontrar una función de punto de entrada con el nombre predeterminado `main` (por alguna razón, en macOS todas las funciones tienen un prefijo `_`). Para establecer el punto de entrada en nuestra función `_start`, pasamos el argumento del enlazador `-e`:
```
cargo rustc -- -C link-args="-e __start"
```
La bandera `-e` especifica el nombre de la función de punto de entrada. Dado que en macOS todas las funciones tienen un prefijo adicional `_`, necesitamos establecer el punto de entrada en `__start` en lugar de `_start`.
Ahora ocurre el siguiente error del enlazador:
```
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 […]
```
macOS [no admite oficialmente binarios enlazados estáticamente] y requiere que los programas enlacen la biblioteca `libSystem` por defecto. Para anular esto y enlazar un binario estático, se pasa la bandera `-static` al enlazador:
[no admite oficialmente binarios enlazados estáticamente]: https://developer.apple.com/library/archive/qa/qa1118/_index.html
```
cargo rustc -- -C link-args="-e __start -static"
```
Esto aún no es suficiente, ya que ocurre un tercer error del enlazador:
```
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 […]
```
Este error ocurre porque los programas en macOS enlazan con `crt0` (“C runtime zero”) por defecto. Esto es similar al error que tuvimos en Linux y también se puede resolver añadiendo el argumento del enlazador `-nostartfiles`:
```
cargo rustc -- -C link-args="-e __start -static -nostartfiles"
```
Ahora nuestro programa debería compilarse exitosamente en macOS.
#### Unificando los Comandos de Construcción
Actualmente, tenemos diferentes comandos de construcción dependiendo de la plataforma host, lo cual no es ideal. Para evitar esto, podemos crear un archivo llamado `.cargo/config.toml` que contenga los argumentos específicos de cada plataforma:
```toml
# en .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"]
```
La clave `rustflags` contiene argumentos que se añaden automáticamente a cada invocación de `rustc`. Para más información sobre el archivo `.cargo/config.toml`, consulta la [documentación oficial](https://doc.rust-lang.org/cargo/reference/config.html).
Ahora nuestro programa debería poder construirse en las tres plataformas con un simple `cargo build`.
#### ¿Deberías Hacer Esto?
Aunque es posible construir un ejecutable autónomo para Linux, Windows y macOS, probablemente no sea una buena idea. La razón es que nuestro ejecutable aún espera varias cosas, por ejemplo, que una pila esté inicializada cuando se llama a la función `_start`. Sin el tiempo de ejecución de C, algunos de estos requisitos podrían no cumplirse, lo que podría hacer que nuestro programa falle, por ejemplo, con un error de segmentación.
Si deseas crear un binario mínimo que se ejecute sobre un sistema operativo existente, incluir `libc` y configurar el atributo `#[start]` como se describe [aquí](https://doc.rust-lang.org/1.16.0/book/no-stdlib.html) probablemente sea una mejor idea.
</details>
## Resumen {#resumen}
Un binario mínimo autónomo en Rust se ve así:
`src/main.rs`:
```rust
#![no_std] // no enlazar con la biblioteca estándar de Rust
#![no_main] // deshabilitar todos los puntos de entrada a nivel de Rust
use core::panic::PanicInfo;
#[no_mangle] // no modificar el nombre de esta función
pub extern "C" fn _start() -> ! {
// esta función es el punto de entrada, ya que el enlazador busca una función
// llamada `_start` por defecto
loop {}
}
/// Esta función se llama cuando ocurre un pánico.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
`Cargo.toml`:
```toml
[package]
name = "crate_name"
version = "0.1.0"
authors = ["Author Name <author@example.com>"]
# el perfil usado para `cargo build`
[profile.dev]
panic = "abort" # deshabilitar el desenrollado de la pila en caso de pánico
# el perfil usado para `cargo build --release`
[profile.release]
panic = "abort" # deshabilitar el desenrollado de la pila en caso de pánico
```
Para construir este binario, necesitamos compilar para un destino bare metal, como `thumbv7em-none-eabihf`:
```
cargo build --target thumbv7em-none-eabihf
```
Alternativamente, podemos compilarlo para el sistema host pasando argumentos adicionales al enlazador:
```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"
```
Ten en cuenta que este es solo un ejemplo mínimo de un binario autónomo en Rust. Este binario espera varias cosas, por ejemplo, que una pila esté inicializada cuando se llama a la función `_start`. **Por lo tanto, para cualquier uso real de un binario como este, se requieren más pasos**.
## ¿Qué sigue?
La [próxima publicación][next post] explica los pasos necesarios para convertir nuestro binario autónomo en un kernel de sistema operativo mínimo. Esto incluye crear un destino personalizado, combinar nuestro ejecutable con un bootloader y aprender cómo imprimir algo en la pantalla.
[next post]: @/edition-2/posts/02-minimal-rust-kernel/index.md

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
#[unsafe(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;
#[unsafe(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

View File

@@ -0,0 +1,523 @@
+++
title = "Un binaire Rust autoporté"
weight = 1
path = "fr/freestanding-rust-binary"
date = 2018-02-10
[extra]
# Please update this when updating the translation
translation_based_on_commit = "3e87916b6c2ed792d1bdb8c0947906aef9013ac1"
# GitHub usernames of the people that translated this post
translators = ["AlexandreMarcq", "alaincao"]
+++
La première étape pour créer notre propre noyau de système d'exploitation est de créer un exécutable Rust qui ne relie pas la bibliothèque standard. Cela rend possible l'exécution du code Rust sur la ["bare machine"][machine nue] sans système d'exploitation sous-jacent.
[machine nue]: https://en.wikipedia.org/wiki/Bare_machine
<!-- more -->
Ce blog est développé sur [GitHub]. Si vous avez un problème ou une question, veuillez ouvrir une issue. Vous pouvez aussi laisser un commentaire [en bas de page]. Le code source complet de cet article est disponible sur la branche [`post-01`][post branch].
[GitHub]: https://github.com/phil-opp/blog_os
[en bas de page]: #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 -->
## Introduction
Pour écrire un noyau de système d'exploitation, nous avons besoin d'un code qui ne dépend pas de fonctionnalités de système d'exploitation. Cela signifie que nous ne pouvons pas utiliser les fils d'exécution, les fichiers, la mémoire sur le tas, le réseau, les nombres aléatoires, la sortie standard ou tout autre fonctionnalité nécessitant une abstraction du système d'exploitation ou un matériel spécifique. Cela a du sens, étant donné que nous essayons d'écrire notre propre OS et nos propres pilotes.
Cela signifie que nous ne pouvons pas utiliser la majeure partie de la [bibliothèque standard de Rust]. Il y a néanmoins beaucoup de fonctionnalités de Rust que nous _pouvons_ utiliser. Par exemple, nous pouvons utiliser les [iterators], les [closures], le [pattern matching], l'[option] et le [result], le [string formatting], et bien sûr l'[ownership system]. Ces fonctionnalités permettent l'écriture d'un noyau d'une façon expressive et haut-niveau sans se soucier des [comportements indéfinis] ou de la [sécurité de la mémoire].
[option]: https://doc.rust-lang.org/core/option/
[result]:https://doc.rust-lang.org/core/result/
[bibliothèque standard de Rust]: 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
[comportement non-défini]: https://www.nayuki.io/page/undefined-behavior-in-c-and-cplusplus-programs
[sécurité de la mémoire]: https://tonyarcieri.com/it-s-time-for-a-memory-safety-intervention
Pour créer un noyau d'OS en Rust, nous devons créer un exécutable qui peut tourner sans système d'exploitation sous-jacent. Un tel exécutable est appelé “freestanding” (autoporté) ou “bare-metal”.
Cet article décrit les étapes nécessaires pour créer un exécutable Rust autoporté et explique pourquoi ces étapes sont importantes. Si vous n'êtes intéressé que par un exemple minimal, vous pouvez **[aller au résumé](#resume)**.
## Désactiver la Bibliothèque Standard
Par défaut, toutes les crates Rust sont liées à la bibliothèque standard, qui repose sur les fonctionnalités du système dexploitation telles que les fils d'exécution, les fichiers et la connectivité réseau. Elle est également liée à la bibliothèque standard C `libc`, qui interagit étroitement avec les services fournis par l'OS. Comme notre plan est d'écrire un système d'exploitation, nous ne pouvons pas utiliser des bibliothèques dépendant de l'OS. Nous devons donc désactiver l'inclusion automatique de la bibliothèque standard en utilisant l'[attribut `no std`].
[bibliothèque standard]: https://doc.rust-lang.org/std/
[attribut `no std`]: https://doc.rust-lang.org/1.30.0/book/first-edition/using-rust-without-the-standard-library.html
Nous commençons par créer un nouveau projet d'application cargo. La manière la plus simple de faire est avec la ligne de commande :
```
cargo new blog_os --bin --edition 2018
```
J'ai nommé le projet `blog_os`, mais vous pouvez évidemment choisir le nom qu'il vous convient. Le flag `--bin` indique que nous voulons créer un exécutable (contrairement à une bibliothèque) et le flag `--edition 2018` indique que nous voulons utiliser l'[édition 2018] de Rust pour notre crate. Quand nous lançons la commande, cargo crée la structure de répertoire suivante pour nous :
[édition 2018]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
```
blog_os
├── Cargo.toml
└── src
└── main.rs
```
Le fichier `Cargo.toml` contient la configuration de la crate, par exemple le nom de la crate, l'auteur, le numéro de [versionnage sémantique] et les dépendances. Le fichier `src/main.rs` contient le module racine de notre crate et notre fonction `main`. Vous pouvez compiler votre crate avec `cargo build` et ensuite exécuter l'exécutable compilé `blog_os` dans le sous-dossier `target/debug`.
[versionnage sémantique]: https://semver.org/
### L'Attribut `no_std`
Pour l'instant, notre crate relie la bibliothèque standard implicitement. Désactivons cela en ajoutant l'[attribut `no std`] :
```rust
// main.rs
#![no_std]
fn main() {
println!("Hello, world!");
}
```
Quand nous essayons maintenant de compiler (avec `cargo build)`, l'erreur suivante se produit :
```
error: cannot find macro `println!` in this scope
--> src/main.rs:4:5
|
4 | println!("Hello, world!");
| ^^^^^^^
```
La raison est que la [macro `println`] fait partie de la bibliothèque standard, que nous ne pouvons plus utiliser. Nous ne pouvons donc plus afficher de texte avec. Cela est logique, car `println` écrit dans la [sortie standard], qui est un descripteur de fichier spécial fourni par le système d'eploitation.
[macro `println`]: https://doc.rust-lang.org/std/macro.println.html
[sortie standard]: https://fr.wikipedia.org/wiki/Flux_standard#Sortie_standard
Supprimons l'affichage et essayons à nouveau avec une fonction main vide :
```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`
```
Maintenant le compilateur a besoin d'une fonction `#[panic_handler]` et d'un _objet de langage_.
## Implémentation de Panic
L'attribut `panic_handler` définit la fonction que le compilateur doit appeler lorsqu'un [panic] arrive. La bibliothèque standard fournit sa propre fonction de gestion de panic mais dans un environnement `no_std`, nous avons besoin de le définir nous-mêmes :
[panic]: https://doc.rust-lang.org/stable/book/ch09-01-unrecoverable-errors-with-panic.html
```rust
// dans main.rs
use core::panic::PanicInfo;
/// Cette fonction est appelée à chaque panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
Le [paramètre `PanicInfo`][PanicInfo] contient le fichier et la ligne où le panic a eu lieu et le message optionnel de panic. La fonction ne devrait jamais retourner quoi que ce soit, elle est donc marquée comme [fonction divergente] en retournant le [type “never”] `!`. Nous ne pouvons pas faire grand chose dans cette fonction pour le moment, nous bouclons donc indéfiniment.
[PanicInfo]: https://doc.rust-lang.org/nightly/core/panic/struct.PanicInfo.html
[fonction divergente]: https://doc.rust-lang.org/1.30.0/book/first-edition/functions.html#diverging-functions
[type “never”]: https://doc.rust-lang.org/nightly/std/primitive.never.html
## L'Objet de Langage `eh_personality`
Les objets de langage sont des fonctions et des types spéciaux qui sont requis par le compilateur de manière interne. Par exemple, le trait [`Copy`] est un objet de langage qui indique au compilateur quels types possèdent la [sémantique copy][`Copy`]. Quand nous regardons l'[implémentation][copy code] du code, nous pouvons voir qu'il possède l'attribut spécial `#[lang = copy]` qui le définit comme étant un objet de langage.
[`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
Bien qu'il soit possible de fournir des implémentations personnalisées des objets de langage, cela ne devrait être fait qu'en dernier recours. La raison est que les objets de langages sont des détails d'implémentation très instables et qui ne sont même pas vérifiés au niveau de leur type (donc le compilateur ne vérifie même pas qu'une fonction possède les bons types d'arguments). Heureusement, il y a une manière plus robuste de corriger l'erreur d'objet de langage ci-dessus.
L'[objet de langage `eh_personality`] marque une fonction qui est utilisée pour l'implémentation du [déroulement de pile]. Par défaut, Rust utilise le déroulement de pile pour exécuter les destructeurs de chaque variable vivante sur la pile en cas de [panic]. Cela assure que toute la mémoire utilisée est libérée et permet au fil d'exécution parent d'attraper la panic et de continuer l'exécution. Le déroulement toutefois est un processus compliqué et nécessite des bibliothèques spécifiques à l'OS ([libunwind] pour Linux ou [gestion structurée des erreurs] pour Windows), nous ne voulons donc pas l'utiliser pour notre système d'exploitation.
[objet de langage `eh_personality`]: https://github.com/rust-lang/rust/blob/edb368491551a77d77a48446d4ee88b35490c565/src/libpanic_unwind/gcc.rs#L11-L45
[déroulement de pile]: https://docs.microsoft.com/fr-fr/cpp/cpp/exceptions-and-stack-unwinding-in-cpp?view=msvc-160
[libunwind]: https://www.nongnu.org/libunwind/
[gestion structurée des erreurs]: https://docs.microsoft.com/fr-fr/windows/win32/debug/structured-exception-handling
### Désactiver le Déroulement
Il y a d'autres cas d'utilisation pour lesquels le déroulement n'est pas souhaité. Rust offre donc une option pour [interrompre après un panic]. Cela désactive la génération de symboles de déroulement et ainsi réduit considérablement la taille de l'exécutable. Il y a de multiples endroit où nous pouvons désactiver le déroulement. Le plus simple est d'ajouter les lignes suivantes dans notre `Cargo.toml` :
```toml
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
```
Cela configure la stratégie de panic à `abort` pour le profil `dev` (utilisé pour `cargo build`) et le profil `release` (utilisé pour `cargo build --release`). Maintenant l'objet de langage `eh_personality` ne devrait plus être requis.
[interrompre après un panic]: https://github.com/rust-lang/rust/pull/32900
Nous avons dorénavant corrigé les deux erreurs ci-dessus. Toutefois, si nous essayons de compiler, une autre erreur apparaît :
```
> cargo build
error: requires `start` lang_item
```
L'objet de langage `start` manque à notre programme. Il définit le point d'entrée.
## L'attribut `start`
On pourrait penser que la fonction `main` est la première fonction appelée lorsqu'un programme est exécuté. Toutefois, la plupart des langages ont un [environnement d'exécution] qui est responsable des tâches telles que le ramassage des miettes (ex: dans Java) ou les fils d'exécution logiciel (ex: les goroutines dans Go). Cet environnement doit être appelé avant `main` puisqu'il a besoin de s'initialiser.
[environnement d'exécution]: https://fr.wikipedia.org/wiki/Environnement_d%27ex%C3%A9cution
Dans un exécutable Rust classique qui relie la bibliothèque standard, l'exécution commence dans une bibliothèque d'environnement d'exécution C appelé `crt0` (“C runtime zero”). Elle configure l'environnement pour une application C. Cela comprend la création d'une pile et le placement des arguments dans les bons registres. L'environnement d'exécution C appelle ensuite [le point d'entrée de l'environnement d'exécution de Rust][rt::lang_start], qui est marqué par l'objet de langage `start`. Rust possède un environnement d'exécution très minime, qui se charge de petites tâches telles que la configuration des guardes de dépassement de pile ou l'affichage de la trace d'appels lors d'un panic. L'environnement d'exécution finit par appeler la fonction `main`.
[rt::lang_start]: https://github.com/rust-lang/rust/blob/bb4d1491466d8239a7a5fd68bd605e3276e97afb/src/libstd/rt.rs#L32-L73
Notre exécutable autoporté n'a pas accès à l'environnement d'exécution de Rust ni à `crt0`. Nous avons donc besoin de définir notre propre point d'entrée. Implémenter l'objet de langage `start` n'aiderait pas car nous aurions toujours besoin de `crt0`. Nous avons plutôt besoin de réécrire le point d'entrée de `crt0` directement.
### Réécrire le Point d'Entrée
Pour indiquer au compilateur que nous ne voulons pas utiliser la chaîne de point d'entrée normale, nous ajoutons l'attribut `#![no_main]`.
```rust
#![no_std]
#![no_main]
use core::panic::PanicInfo;
/// Cette fonction est appelée à chaque panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
Vous remarquerez peut-être que nous avons retiré la fonction `main`. La raison est que la présence de cette fonction n'a pas de sens sans un environnement d'exécution sous-jacent qui l'appelle. À la place, nous réécrivons le point d'entrée du système d'exploitation avec notre propre fonction `_start` :
```rust
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! {
loop {}
}
```
En utilisant l'attribut `#[unsafe(no_mangle)]`, nous désactivons la [décoration de nom] pour assurer que le compilateur Rust crée une fonction avec le nom `_start`. Sans cet attribut, le compilateur génèrerait un symbol obscure `_ZN3blog_os4_start7hb173fedf945531caE` pour donner un nom unique à chaque fonction. L'attribut est nécessaire car nous avons besoin d'indiquer le nom de la fonction de point d'entrée à l'éditeur de lien (*linker*) dans l'étape suivante.
Nous devons aussi marquer la fonction avec `extern C` pour indiquer au compilateur qu'il devrait utiliser la [convention de nommage] de C pour cette fonction (au lieu de la convention de nommage de Rust non-spécifiée). Cette fonction se nomme `_start` car c'est le nom par défaut des points d'entrée pour la plupart des systèmes.
[décoration de nom]: https://fr.wikipedia.org/wiki/D%C3%A9coration_de_nom
[convention de nommage]: https://fr.wikipedia.org/wiki/Convention_de_nommage
Le type de retour `!` signifie que la fonction est divergente, c-à-d qu'elle n'a pas le droit de retourner quoi que ce soit. Cela est nécessaire car le point d'entrée n'est pas appelé par une fonction, mais invoqué directement par le système d'exploitation ou par le chargeur d'amorçage. Donc au lieu de retourner une valeur, le point d'entrée doit invoquer l'[appel système `exit`] du système d'exploitation. Dans notre cas, arrêter la machine pourrait être une action convenable, puisqu'il ne reste rien d'autre à faire si un exécutable autoporté s'arrête. Pour l'instant, nous remplissons la condition en bouclant indéfiniement.
[appel système `exit`]: https://fr.wikipedia.org/wiki/Appel_syst%C3%A8me
Quand nous lançons `cargo build`, nous obtenons une erreur de _linker_.
## Erreurs de Linker
Le linker est un programme qui va transformer le code généré en exécutable. Comme le format de l'exécutable differt entre Linux, Windows et macOS, chaque système possède son propre linker qui lève une erreur différente. La cause fondamentale de cette erreur est la même : la configuration par défaut du linker part du principe que notre programme dépend de l'environnement d'exécution de C, ce qui n'est pas le cas.
Pour résoudre les erreurs, nous devons indiquer au linker qu'il ne doit pas inclure l'environnement d'exécution de C. Nous pouvons faire cela soit en passant un ensemble précis d'arguments, soit en compilant pour une cible bare metal.
### Compiler pour une Cible Bare Metal
Par défaut Rust essaie de compiler un exécutable qui est compatible avec l'environnment du système actuel. Par exemple, si vous utilisez Windows avec `x86_64`, Rust essaie de compiler un exécutable Windows `.exe` qui utilises des instructions `x86_64`. Cet environnement est appelé système "hôte".
Pour décrire plusieurs environnements, Rust utilise une chaîne de caractères appelée [_triplé cible_]. Vous pouvez voir le triplé cible de votre système hôte en lançant la commande `rustc --version --verbose` :
[_triplé cible_]: 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
```
La sortie ci-dessus provient d'un système Linux `x86_64`. Nous pouvons voir que le triplé `host` est `x86_64-unknown-linux-gnu`, qui inclut l'architecture du CPU (`x86_64`), le vendeur (`unknown`), le système d'exploitation (`linux`) et l'[ABI] (`gnu`).
[ABI]: https://fr.wikipedia.org/wiki/Application_binary_interface
En compilant pour notre triplé hôte, le compilateur Rust ainsi que le linker supposent qu'il y a un système d'exploitation sous-jacent comme Linux ou Windows qui utilise l'environnement d'exécution C par défaut, ce qui cause les erreurs de linker. Donc pour éviter ces erreurs, nous pouvons compiler pour un environnement différent sans système d'exploitation sous-jacent.
Un exemple d'un tel envrironnement est le triplé cible `thumbv7em-none-eabihf`, qui décrit un système [ARM] [embarqué]. Les détails ne sont pas importants, tout ce qui compte est que le triplé cible n'a pas de système d'exploitation sous-jacent, ce qui est indiqué par le `none` dans le triplé cible. Pour pouvoir compiler pour cette cible, nous avons besoin de l'ajouter dans rustup :
[embarqué]: https://fr.wikipedia.org/wiki/Syst%C3%A8me_embarqu%C3%A9
[ARM]: https://fr.wikipedia.org/wiki/Architecture_ARM
```
rustup target add thumbv7em-none-eabihf
```
Cela télécharge une copie de la bibliothèque standard (et core) pour le système. Maintenant nous pouvons compiler notre exécutable autoporté pour cette cible :
```
cargo build --target thumbv7em-none-eabihf
```
En donnant un argument `--target`, nous effectuons une [compilation croisée][cross_compile] de notre exécutable pour un système bare metal. Comme le système cible n'a pas de système d'exploitation, le linker n'essaie pas de lier l'environnement d'exécution C et notre compilation réussit sans erreur de linker.
[cross compile]: https://en.wikipedia.org/wiki/Cross_compiler
C'est l'approche que nous allons utiliser pour construire notre noyau d'OS. Plutôt que `thumbv7em-none-eabihf`, nous allons utiliser une [cible personnalisée][custom target] qui décrit un environnement bare metal `x86_64`. Les détails seront expliqués dans le prochain article.
[custom target]: https://doc.rust-lang.org/rustc/targets/custom.html
### Arguments du Linker
Au lieu de compiler pour un système bare metal, il est aussi possible de résoudre les erreurs de linker en passant un ensemble précis d'arguments au linker. Ce n'est pas l'approche que nous allons utiliser pour notre noyau. Cette section est donc optionnelle et fournis uniquement à titre de complétude. Cliquez sur _"Arguments du Linker"_ ci-dessous pour montrer le contenu optionel.
<details>
<summary>Arguments du Linker</summary>
Dans cette section nous allons parler des erreurs de linker qui se produisent sur Linux, Windows et macOS. Nous allons aussi apprendre à résoudre ces erreurs en passant des arguments complémentaires au linker. À noter que le format de l'exécutable et le linker diffèrent entre les systèmes d'exploitation. Il faut donc un ensemble d'arguments différent pour chaque système.
#### Linux
Sur Linux, voici l'erreur de linker qui se produit (raccourcie) :
```
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
```
Le problème est que le linker inclut par défaut la routine de démarrage de l'environnement d'exécution de C, qui est aussi appelée `_start`. Elle requiert des symboles de la bibliothèque standard de C `libc` que nous n'incluons pas à cause de l'attribut `no_std`. Le linker ne peut donc pas résoudre ces références. Pour résoudre cela, nous pouvons indiquer au linker qu'il ne devrait pas lier la routine de démarrage de C en passant l'argument `-nostartfiles`.
Une façon de passer des attributs au linker via cargo est la commande `cargo rustc`. Cette commande se comporte exactement comme `cargo build`, mais permet aussi de donner des options à `rustc`, le compilateur Rust sous-jacent. `rustc` possède le flag `-C link-arg`, qui donne un argument au linker. Combinés, notre nouvelle commande ressemble à ceci :
```
cargo rustc -- -C link-arg=-nostartfiles
```
Dorénavant notre crate compile en tant qu'exécutable Linux autoporté !
Nous n'avions pas besoin de spécifier le nom de notre point d'entrée de façon explicite car le linker cherche par défaut une fonction nommée `_start`.
#### Windows
Sur Windows, une erreur de linker différente se produit (raccourcie) :
```
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
```
Cette erreur signifie que le linker ne peut pas trouver le point d'entrée. Sur Windows, le nom par défaut du point d'entrée [dépend du sous-système utilisé][windows-subsystems]. Pour le sous-système `CONSOLE`, le linker cherche une fonction nommée `mainCRTStartup` et pour le sous-système `WINDOWS`, il cherche une fonction nomée `WinMainCRTStartup`. Pour réécrire la valeur par défaut et indiquer au linker de chercher notre fonction `_start` à la place, nous pouvons donner l'argument `/ENTRY` au linker :
[windows-subsystems]: https://docs.microsoft.com/fr-fr/cpp/build/reference/entry-entry-point-symbol?view=msvc-160
```
cargo rustc -- -C link-arg=/ENTRY:_start
```
Vu le format d'argument différent nous pouvons clairement voir que le linker Windows est un programme totalement différent du linker Linux.
Maintenant une erreur de linker différente se produit :
```
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
```
Cette erreur se produit car les exécutables Windows peuvent utiliser différents [sous-systèmes][windows-subsystems]. Pour les programmes normaux, ils sont inférés en fonction du nom du point d'entrée : s'il est nommé `main`, le sous-système `CONSOLE` est utilisé. Si le point d'entrée est nommé `WinMain`, alors le sous-sytème `WINDOWS` est utilisé. Comme notre fonction `_start` possède un nom différent, nous devons préciser le sous-système explicitement :
```
cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"
```
Ici nous utilisons le sous-système `CONSOLE`, mais le sous-système `WINDOWS` pourrait fonctionner aussi. Au lieu de donner `-C link-arg` plusieurs fois, nous utilisons `-C link-args` qui utilise des arguments séparés par des espaces.
Avec cette commande, notre exécutable devrait compiler avec succès sous Windows.
#### macOS
Sur macOS, voici l'erreur de linker qui se produit (raccourcie) :
```
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 […]
```
Cette erreur nous indique que le linker ne peut pas trouver une fonction de point d'entrée avec le nom par défaut `main` (pour une quelconque raison, toutes les fonctions sur macOS sont précédées de `_`). Pour configurer le point d'entrée sur notre fonction `_start`, nous donnons l'argument `-e` au linker :
```
cargo rustc -- -C link-args="-e __start"
```
L'argument `-e` spécifie le nom de la fonction de point d'entrée. Comme toutes les fonctions ont un préfixe supplémentaire `_` sur macOS, nous devons configurer le point d'entrée comme étant `__start` au lieu de `_start`.
Maintenant l'erreur de linker suivante se produit :
```
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 […]
```
macOS [ne supporte pas officiellement les bibliothèques liées de façon statique] et necéessite que les programmes lient la bibliothèque `libSystem` par défaut. Pour réécrire ceci et lier une bibliothèque statique, nous donnons l'argument `-static` au linker :
[ne supporte pas officiellement les bibliothèques liées de façon statique]: https://developer.apple.com/library/archive/qa/qa1118/_index.html
```
cargo rustc -- -C link-args="-e __start -static"
```
Cela ne suffit toujours pas, une troisième erreur de linker se produit :
```
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 […]
```
Cette erreur se produit car les programmes sous macOS lient `crt0` (“C runtime zero”) par défaut. Ceci est similaire à l'erreur que nous avions eu sous Linux et peut aussi être résolue en ajoutant l'argument `-nostartfiles` au linker :
```
cargo rustc -- -C link-args="-e __start -static -nostartfiles"
```
Maintenant notre programme compile avec succès sous macOS.
#### Unifier les Commandes de Compilation
À cet instant nous avons différentes commandes de compilation en fonction de la plateforme hôte, ce qui n'est pas idéal. Pour éviter cela, nous pouvons créer un ficher nommé `.cargo/config.toml` qui contient les arguments spécifiques aux plateformes :
```toml
# dans .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"]
```
La clé `rustflags` contient des arguments qui sont automatiquement ajoutés à chaque appel de `rustc`. Pour plus d'informations sur le fichier `.cargo/config.toml`, allez voir la [documentation officielle](https://doc.rust-lang.org/cargo/reference/config.html)
Maintenant notre programme devrait être compilable sur les trois plateformes avec un simple `cargo build`.
#### Devriez-vous Faire Ça ?
Bien qu'il soit possible de compiler un exécutable autoporté pour Linux, Windows et macOS, ce n'est probablement pas une bonne idée. La raison est que notre exécutable s'attend toujours à trouver certaines choses, par exemple une pile initialisée lorsque la fonction `_start` est appelée. Sans l'environnement d'exécution C, certaines de ces conditions peuvent ne pas être remplies, ce qui pourrait faire planter notre programme, avec par exemple une erreur de segmentation.
Si vous voulez créer un exécutable minimal qui tourne sur un système d'exploitation existant, include `libc` et mettre l'attribut `#[start]` come décrit [ici](https://doc.rust-lang.org/1.16.0/book/no-stdlib.html) semble être une meilleure idée.
</details>
## Résumé
Un exécutable Rust autoporté minimal ressemble à ceci :
`src/main.rs`:
```rust
#![no_std] // ne pas lier la bibliothèque standard Rust
#![no_main] // désactiver tous les points d'entrée au niveau de Rust
use core::panic::PanicInfo;
#[unsafe(no_mangle)] // ne pas décorer le nom de cette fonction
pub extern "C" fn _start() -> ! {
// cette fonction est le point d'entrée, comme le linker cherche une fonction
// nomée `_start` par défaut
loop {}
}
/// Cette fonction est appelée à chaque 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>"]
# le profile utilisé pour `cargo build`
[profile.dev]
panic = "abort" # désactive le déroulement de la pile lors d'un panic
# le profile utilisé pour `cargo build --release`
[profile.release]
panic = "abort" # désactive le déroulement de la pile lors d'un panic
```
Pour compiler cet exécutable, nous devons compiler pour une cible bare metal telle que `thumbv7em-none-eabihf` :
```
cargo build --target thumbv7em-none-eabihf
```
Sinon, nous pouvons aussi compiler pour le système hôte en donnant des arguments supplémentaires pour le linker :
```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"
```
À noter que ceci est juste un exemple minimal d'un exécutable Rust autoporté. Cet exécutable s'attend à de nombreuses choses, comme par exemple le fait qu'une pile soit initialisée lorsque la fonction `_start` est appelée. **Donc pour une réelle utilisation d'un tel exécutable, davantages d'étapes sont requises.**
## Et ensuite ?
Le [poste suivant][next post] explique les étapes nécessaires pour transformer notre exécutable autoporté minimal en noyau de système d'opération. Cela comprend la création d'une cible personnalisée, l'intégration de notre exécutable avec un chargeur d'amorçage et l'apprentissage de comment imprimer quelque chose sur l'écran.
[next post]: @/edition-2/posts/02-minimal-rust-kernel/index.md

View File

@@ -0,0 +1,530 @@
+++
title = "フリースタンディングな Rust バイナリ"
weight = 1
path = "ja/freestanding-rust-binary"
date = 2018-02-10
[extra]
# Please update this when updating the translation
translation_based_on_commit = "6f1f87215892c2be12c6973a6f753c9a25c34b7e"
# GitHub usernames of the people that translated this post
translators = ["JohnTitor"]
+++
私達自身のオペレーティングシステム(以下、OS)カーネルを作っていく最初のステップは標準ライブラリとリンクしない Rust の実行可能ファイルをつくることです。これにより、基盤となる OS がない[ベアメタル][bare metal]上で Rust のコードを実行することができるようになります。
[bare metal]: https://en.wikipedia.org/wiki/Bare_machine
<!-- more -->
このブログの内容は [GitHub] 上で公開・開発されています。何か問題や質問などがあれば issue をたててください (訳注: リンクは原文(英語)のものになります)。また[こちら][comments]にコメントを残すこともできます。この記事の完全なソースコードは[`post-01` ブランチ][post branch]にあります。
[GitHub]: https://github.com/phil-opp/blog_os
[comments]: #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 -->
## 導入
OS カーネルを書くためには、いかなる OS の機能にも依存しないコードが必要となります。つまり、スレッドやヒープメモリ、ネットワーク、乱数、標準出力、その他 OS による抽象化や特定のハードウェアを必要とする機能は使えません。私達は自分自身で OS とそのドライバを書こうとしているので、これは理にかなっています。
これは [Rust の標準ライブラリ][Rust standard library]をほとんど使えないということを意味しますが、それでも私達が使うことのできる Rust の機能はたくさんあります。例えば、[イテレータ][iterators]や[クロージャ][closures]、[パターンマッチング][pattern matching]、 [`Option`][option] や [`Result`][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 で OS カーネルを書くには、基盤となる OS なしで動く実行環境をつくる必要があります。そのような実行環境はフリースタンディング環境やベアメタルのように呼ばれます。
この記事では、フリースタンディングな Rust のバイナリをつくるために必要なステップを紹介し、なぜそれが必要なのかを説明します。もし最小限の説明だけを読みたいのであれば **[概要](#summary)** まで飛ばしてください。
## 標準ライブラリの無効化
デフォルトでは、全ての Rust クレートは[標準ライブラリ][standard library]にリンクされています。標準ライブラリはスレッドやファイル、ネットワークのような OS の機能に依存しています。また OS と密接な関係にある C の標準ライブラリ(`libc`)にも依存しています。私達の目的は OS を書くことなので、 OS 依存のライブラリを使うことはできません。そのため、 [`no_std` attribute] を使って標準ライブラリが自動的にリンクされるのを無効にします。
[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 プロジェクトをつくるところから始めましょう。もっとも簡単なやり方はコマンドラインで以下を実行することです。
```bash
cargo new blog_os --bin --edition 2018
```
プロジェクト名を `blog_os` としましたが、もちろんお好きな名前をつけていただいても大丈夫です。`--bin`フラグは実行可能バイナリを作成することを、 `--edition 2018` は[2018エディション][2018 edition]を使用することを明示的に指定します。コマンドを実行すると、 Cargoは以下のようなディレクトリ構造を作成します:
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
```bash
blog_os
├── Cargo.toml
└── src
└── main.rs
```
`Cargo.toml` にはクレートの名前や作者名、[セマンティックバージョニング][semantic version]に基づくバージョンナンバーや依存関係などが書かれています。`src/main.rs` には私達のクレートのルートモジュールと `main` 関数が含まれています。`cargo build` コマンドでこのクレートをコンパイルして、 `target/debug` ディレクトリの中にあるコンパイルされた `blog_os` バイナリを実行することができます。
[semantic version]: https://semver.org/
### `no_std` Attribute
今のところ私達のクレートは暗黙のうちに標準ライブラリをリンクしています。[`no_std` attribute]を追加してこれを無効にしてみましょう:
```rust
// main.rs
#![no_std]
fn main() {
println!("Hello, world!");
}
```
(`cargo build` を実行して)ビルドしようとすると、次のようなエラーが発生します:
```bash
error: cannot find macro `println!` in this scope
--> src/main.rs:4:5
|
4 | println!("Hello, world!");
| ^^^^^^^
```
これは [`println` マクロ][`println` macro]が標準ライブラリに含まれているためです。`no_std` で標準ライブラリを無効にしたので、何かをプリントすることはできなくなりました。`println` は標準出力に書き込むのでこれは理にかなっています。[標準出力][standard output]は OS によって提供される特別なファイル記述子であるためです。
[`println` macro]: https://doc.rust-lang.org/std/macro.println.html
[standard output]: https://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29
では、 `println` を削除し `main` 関数を空にしてもう一度ビルドしてみましょう:
```rust
// main.rs
#![no_std]
fn main() {}
```
```bash
> 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` attribute は[パニック]が発生したときにコンパイラが呼び出す関数を定義します。標準ライブラリには独自のパニックハンドラー関数がありますが、 `no_std` 環境では私達の手でそれを実装する必要があります:
[パニック]: https://doc.rust-lang.org/stable/book/ch09-01-unrecoverable-errors-with-panic.html
```rust
// in main.rs
use core::panic::PanicInfo;
/// この関数はパニック時に呼ばれる
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
[`PanicInfo` パラメータ]には、パニックが発生したファイルと行、およびオプションでパニックメッセージが含まれます。この関数は戻り値を取るべきではないので、["never" 型(`!`)][“never” type]を返すことで[発散する関数][diverging function]となります。今のところこの関数でできることは多くないので、無限にループするだけです。
[`PanicInfo` パラメータ]: https://doc.rust-lang.org/nightly/core/panic/struct.PanicInfo.html
[diverging function]: https://doc.rust-lang.org/1.30.0/book/first-edition/functions.html#diverging-functions
[“never” type]: https://doc.rust-lang.org/nightly/std/primitive.never.html
## `eh_personality` Language Item
language item はコンパイラによって内部的に必要とされる特別な関数や型です。例えば、[`Copy`] トレイトはどの型が[コピーセマンティクス][`Copy`]を持っているかをコンパイラに伝える language item です。[実装][copy code]を見てみると、 language item として定義されている特別な `#[lang = "copy"]` attribute を持っていることが分かります。
[`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
独自に language item を実装することもできますが、これは最終手段として行われるべきでしょう。というのも、language item は非常に不安定な実装であり型検査も行われないからです(なので、コンパイラは関数が正しい引数の型を取っているかさえ検査しません)。幸い、上記の language item のエラーを修正するためのより安定した方法があります。
[`eh_personality` language item] は[スタックアンワインド][stack unwinding] を実装するための関数を定義します。デフォルトでは、パニックが起きた場合には Rust はアンワインドを使用してすべてのスタックにある変数のデストラクタを実行します。これにより、使用されている全てのメモリが確実に解放され、親スレッドはパニックを検知して実行を継続できます。しかしアンワインドは複雑であり、いくつかの OS 特有のライブラリ(例えば、Linux では [libunwind] 、Windows では[構造化例外][structured exception handling])を必要とするので、私達の OS には使いたくありません。
[`eh_personality` language item]: 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/
[structured exception handling]: https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling
### アンワインドの無効化
他にもアンワインドが望ましくないユースケースがあります。そのため、Rust には代わりに[パニックで中止する][abort on panic]オプションがあります。これにより、アンワインドのシンボル情報の生成が無効になり、バイナリサイズが大幅に削減されます。アンワインドを無効にする方法は複数あります。もっとも簡単な方法は、`Cargo.toml` に次の行を追加することです:
```toml
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
```
これは dev プロファイル(`cargo build` に使用される)と release プロファイル(`cargo build --release` に使用される)の両方でパニックで中止するようにするための設定です。これで `eh_personality` language item が不要になりました。
[abort on panic]: https://github.com/rust-lang/rust/pull/32900
これで上の2つのエラーを修正しました。しかし、コンパイルしようとすると別のエラーが発生します:
```bash
> cargo build
error: requires `start` lang_item
```
私達のプログラムにはエントリポイントを定義する `start` language item がありません。
## `start` attribute
`main` 関数はプログラムを実行したときに最初に呼び出される関数であると思うかもしれません。しかし、ほとんどの言語には[ランタイムシステム][runtime system]があり、これはガベージコレクション(Java など)やソフトウェアスレッド(Go のゴルーチン)などを処理します。ランタイムは自身を初期化する必要があるため、`main` 関数の前に呼び出す必要があります。これにはスタック領域の作成と正しいレジスタへの引数の配置が含まれます。
[runtime system]: https://en.wikipedia.org/wiki/Runtime_system
標準ライブラリをリンクする一般的な Rust バイナリでは、`crt0` ("C runtime zero")と呼ばれる C のランタイムライブラリで実行が開始され、C アプリケーションの環境が設定されます。その後 C ランタイムは、`start` language item で定義されている [Rust ランタイムのエントリポイント][rt::lang_start]を呼び出します。Rust にはごくわずかなランタイムしかありません。これは、スタックオーバーフローを防ぐ設定やパニック時のバックトレースの表示など、いくつかの小さな処理を行います。最後に、ランタイムは `main` 関数を呼び出します。
[rt::lang_start]: https://github.com/rust-lang/rust/blob/bb4d1491466d8239a7a5fd68bd605e3276e97afb/src/libstd/rt.rs#L32-L73
私達のフリースタンディングな実行可能ファイルは今のところ Rust ランタイムと `crt0` へアクセスできません。なので、私達は自身でエントリポイントを定義する必要があります。`start` language item を実装することは `crt0` を必要とするのでここではできません。代わりに `crt0` エントリポイントを直接上書きしなければなりません。
### エントリポイントの上書き
Rust コンパイラに通常のエントリポイントを使いたくないことを伝えるために、`#![no_main]` attribute を追加します。
```rust
#![no_std]
#![no_main]
use core::panic::PanicInfo;
/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
`main` 関数を削除したことに気付いたかもしれません。`main` 関数を呼び出す基盤となるランタイムなしには置いていても意味がないからです。代わりに、OS のエントリポイントを独自の `_start` 関数で上書きしていきます:
```rust
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! {
loop {}
}
```
Rust コンパイラが `_start` という名前の関数を実際に出力するように、`#[unsafe(no_mangle)]` attributeを用いて[名前修飾][name mangling]を無効にします。この attribute がないと、コンパイラはすべての関数にユニークな名前をつけるために、 `_ZN3blog_os4_start7hb173fedf945531caE` のようなシンボルを生成します。次のステップでエントリポイントとなる関数の名前をリンカに伝えるため、この属性が必要となります。
また、(指定されていない Rust の呼び出し規約の代わりに)この関数に [C の呼び出し規約][C calling convention]を使用するようコンパイラに伝えるために、関数を `extern "C"` として定義する必要があります。`_start`という名前をつける理由は、これがほとんどのシステムのデフォルトのエントリポイント名だからです。
[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
[C calling convention]: https://en.wikipedia.org/wiki/Calling_convention
戻り値の型である `!` は関数が発散している、つまり値を返すことができないことを意味しています。エントリポイントはどの関数からも呼び出されず、OS またはブートローダから直接呼び出されるので、これは必須です。なので、値を返す代わりに、エントリポイントは例えば OS の [`exit` システムコール][`exit` system call]を呼び出します。今回はフリースタンディングなバイナリが返されたときマシンをシャットダウンするようにすると良いでしょう。今のところ、私達は無限ループを起こすことで要件を満たします。
[`exit` system call]: https://en.wikipedia.org/wiki/Exit_(system_call)
`cargo build` を実行すると、見づらいリンカエラーが発生します。
## リンカエラー
リンカは、生成されたコードを実行可能ファイルに紐付けるプログラムです。実行可能ファイルの形式は Linux や Windows、macOS でそれぞれ異なるため、各システムにはそれぞれ異なるエラーを発生させる独自のリンカがあります。エラーの根本的な原因は同じです。リンカのデフォルト設定では、プログラムが C ランタイムに依存していると仮定していますが、実際にはしていません。
エラーを回避するためにはリンカに C ランタイムに依存しないことを伝える必要があります。これはリンカに一連の引数を渡すか、ベアメタルターゲット用にビルドすることで可能となります。
### ベアメタルターゲット用にビルドする
デフォルトでは、Rust は現在のシステム環境に合った実行可能ファイルをビルドしようとします。例えば、`x86_64` で Windows を使用している場合、Rust は `x86_64` 用の `.exe` Windows 実行可能ファイルをビルドしようとします。このような環境は「ホスト」システムと呼ばれます。
様々な環境を表現するために、Rust は [_target triple_] という文字列を使います。`rustc --version --verbose` を実行すると、ホストシステムの target triple を確認できます:
[_target triple_]: https://clang.llvm.org/docs/CrossCompilation.html#target-triple
```bash
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` の Linux によるものです。`host``x86_64-unknown-linux-gnu` です。これには CPU アーキテクチャ(`x86_64`)、ベンダー(`unknown`)、OS(`Linux`)、そして [ABI] (`gnu`)が含まれています。
[ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
ホストの triple 用にコンパイルすることで、Rust コンパイラとリンカは、デフォルトで C ランタイムを使用する Linux や Windows のような基盤となる OS があると想定し、それによってリンカエラーが発生します。なのでリンカエラーを回避するために、基盤となる OS を使用せずに異なる環境用にコンパイルします。
このようなベアメタル環境の例としては、`thumbv7em-none-eabihf` target triple があります。これは、[組込みシステム][embedded]を表しています。詳細は省きますが、重要なのは `none` という文字列からわかるように、 この target triple に基盤となる OS がないことです。このターゲット用にコンパイルできるようにするには、 rustup にこれを追加する必要があります:
[embedded]: https://en.wikipedia.org/wiki/Embedded_system
```bash
rustup target add thumbv7em-none-eabihf
```
これにより、この target triple 用の標準(およびコア)ライブラリのコピーがダウンロードされます。これで、このターゲット用にフリースタンディングな実行可能ファイルをビルドできます:
```bash
cargo build --target thumbv7em-none-eabihf
```
`--target` 引数を渡すことで、ベアメタルターゲット用に実行可能ファイルを[クロスコンパイル][cross compile]します。このターゲットシステムには OS がないため、リンカは C ランタイムをリンクしようとせず、ビルドはリンカエラーなしで成功します。
[cross compile]: https://en.wikipedia.org/wiki/Cross_compiler
これが私達の OS カーネルを書くために使うアプローチです。`thumbv7em-none-eabihf` の代わりに、`x86_64` のベアメタル環境を表す[カスタムターゲット][custom target]を使用することもできます。詳細は次のセクションで説明します。
[custom target]: https://doc.rust-lang.org/rustc/targets/custom.html
### リンカへの引数
ベアメタルターゲット用にコンパイルする代わりに、特定の引数のセットをリンカにわたすことでリンカエラーを回避することもできます。これは私達がカーネルに使用するアプローチではありません。したがって、このセクションはオプションであり、選択肢を増やすために書かれています。表示するには以下の「リンカへの引数」をクリックしてください。
<details>
<summary>リンカへの引数</summary>
このセクションでは、Linux、Windows、および macOS で発生するリンカエラーについてと、リンカに追加の引数を渡すことによってそれらを解決する方法を説明します。実行可能ファイルの形式とリンカは OS によって異なるため、システムごとに異なる引数のセットが必要です。
#### Linux
Linux では以下のようなエラーが発生します(抜粋):
```
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` とも呼ばれます。`no_std` attribute により、C 標準ライブラリ `libc` のいくつかのシンボルが必要となります。なので、リンカはこれらの参照を解決できません。これを解決するために、リンカに `-nostartfiles` フラグを渡して、C の起動ルーチンをリンクしないようにします。
Cargo を通してリンカの attribute を渡す方法の一つに、`cargo rustc` コマンドがあります。このコマンドは `cargo build` と全く同じように動作しますが、基本となる Rust コンパイラである `rustc` にオプションを渡すことができます。`rustc` にはリンカに引数を渡す `-C link-arg` フラグがあります。新しいビルドコマンドは次のようになります:
```bash
cargo rustc -- -C link-arg=-nostartfiles
```
これで crate を Linux 上で独立した実行ファイルとしてビルドできます!
リンカはデフォルトで `_start` という名前の関数を探すので、エントリポイントとなる関数の名前を明示的に指定する必要はありません。
#### Windows
Windows では別のリンカエラーが発生します(抜粋):
```
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 では、デフォルトのエントリポイント名は[使用するサブシステム][windows-subsystems]によって異なります。`CONSOLE` サブシステムの場合、リンカは `mainCRTStartup` という名前の関数を探し、`WINDOWS` サブシステムの場合は、`WinMainCRTStartup` という名前の関数を探します。デフォルトの動作を無効にし、代わりに `_start` 関数を探すようにリンカに指示するには、`/ENTRY` 引数をリンカに渡します:
[windows-subsystems]: https://docs.microsoft.com/en-us/cpp/build/reference/entry-entry-point-symbol
```bash
cargo rustc -- -C link-arg=/ENTRY:_start
```
引数の形式が異なることから、Windows のリンカは 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][windows-subsystems] を使用することができるために発生します。通常のプログラムでは、エントリポイント名に基づいて推定されます。エントリポイントが `main` という名前の場合は `CONSOLE` サブシステムが使用され、エントリポイント名が `WinMain` である場合には `WINDOWS` サブシステムが使用されます。`_start` 関数は別の名前を持っているので、サブシステムを明示的に指定する必要があります:
This error occurs because Windows executables can use different [subsystems][windows-subsystems]. For normal programs they are inferred depending on the entry point name: If the entry point is named `main`, the `CONSOLE` subsystem is used, and if the entry point is named `WinMain`, the `WINDOWS` subsystem is used. Since our `_start` function has a different name, we need to specify the subsystem explicitly:
```bash
cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"
```
ここでは `CONSOLE` サブシステムを使用しますが、`WINDOWS` サブシステムを使うこともできます。`-C link-arg` を複数渡す代わりに、スペースで区切られたリストを引数として取る `-C link-args` を渡します。
このコマンドで、実行可能ファイルが Windows 上で正しくビルドされます。
#### 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` というリンカ引数を渡します:
```bash
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 […]
```
macOS は[正式には静的にリンクされたバイナリをサポートしておらず][does not officially support statically linked binaries]、プログラムはデフォルトで `libSystem` ライブラリにリンクされる必要があります。これを無効にして静的バイナリをリンクするには、`-static` フラグをリンカに渡します:
[does not officially support statically linked binaries]: https://developer.apple.com/library/archive/qa/qa1118/_index.html
```bash
cargo rustc -- -C link-args="-e __start -static"
```
これでもまだ十分ではありません、3つ目のリンカエラーが発生します:
```
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 runtime zero") にリンクされるために発生します。これは Linux 上で起きたエラーと似ており、`-nostartfiles` というリンカ引数を追加することで解決できます:
```bash
cargo rustc -- -C link-args="-e __start -static -nostartfiles"
```
これで 私達のプログラムを macOS 上で正しくビルドできます。
#### ビルドコマンドの統一
現時点では、ホストプラットフォームによって異なるビルドコマンドを使っていますが、これは理想的ではありません。これを回避するために、プラットフォーム固有の引数を含む `.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` についての詳細は[公式のドキュメント][official documentation]を確認してください。
[official documentation]: https://doc.rust-lang.org/cargo/reference/config.html
これで私達のプログラムは3つすべてのプラットフォーム上で、シンプルに `cargo build` のみでビルドすることができるようになります。
#### 私達はこれをすべきですか?
これらの手順で Linux、Windows および macOS 用の独立した実行可能ファイルをビルドすることはできますが、おそらく良い方法ではありません。その理由は、例えば `_start` 関数が呼ばれたときにスタックが初期化されるなど、まだ色々なことを前提としているからです。C ランタイムがなければ、これらの要件のうちいくつかが満たされない可能性があり、セグメンテーション違反(segfault)などによってプログラムが失敗する可能性があります。
もし既存の OS 上で動作する最小限のバイナリを作成したいなら、`libc` を使って `#[start]` attribute を[ここ][no-stdlib]で説明するとおりに設定するのが良いでしょう。
[no-stdlib]: https://doc.rust-lang.org/1.16.0/book/no-stdlib.html
</details>
## 概要 {#summary}
最小限の独立した Rust バイナリは次のようになります:
`src/main.rs`:
```rust
#![no_std] // Rust の標準ライブラリにリンクしない
#![no_main] // 全ての Rust レベルのエントリポイントを無効にする
use core::panic::PanicInfo;
#[unsafe(no_mangle)] // この関数の名前修飾をしない
pub extern "C" fn _start() -> ! {
// リンカはデフォルトで `_start` という名前の関数を探すので、
// この関数がエントリポイントとなる
loop {}
}
/// この関数はパニック時に呼ばれる
#[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
```
このバイナリをビルドするために、`thumbv7em-none-eabihf` のようなベアメタルターゲット用にコンパイルする必要があります:
```bash
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"
```
これは独立した Rust バイナリの最小の例にすぎないことに注意してください。このバイナリは `_start` 関数が呼び出されたときにスタックが初期化されるなど、さまざまなことを前提としています。**そのため、このようなバイナリを実際に使用するには、より多くの手順が必要となります**。
## 次は?
[次の記事][next post]では、この独立したバイナリを最小限の OS カーネルにするために必要なステップを説明しています。カスタムターゲットの作成、実行可能ファイルとブートローダの組み合わせ、画面に何か文字を表示する方法について説明しています。
[next post]: @/edition-2/posts/02-minimal-rust-kernel/index.ja.md

View File

@@ -0,0 +1,545 @@
+++
title = "Rust로 'Freestanding 실행파일' 만들기"
weight = 1
path = "ko/freestanding-rust-binary"
date = 2018-02-10
[extra]
# Please update this when updating the translation
translation_based_on_commit = "c1af4e31b14e562826029999b9ab1dce86396b93"
# GitHub usernames of the people that translated this post
translators = ["JOE1994", "Quqqu"]
+++
운영체제 커널을 만드는 첫 단계는 표준 라이브러리(standard library)를 링크하지 않는 Rust 실행파일을 만드는 것입니다. 이 실행파일은 운영체제가 없는 [bare metal] 시스템에서 동작할 수 있습니다.
[bare metal]: https://en.wikipedia.org/wiki/Bare_machine
<!-- more -->
이 블로그는 [GitHub 저장소][GitHub]에서 오픈 소스로 개발되고 있으니, 문제나 문의사항이 있다면 저장소의 'Issue' 기능을 이용해 제보해주세요. [페이지 맨 아래][at the bottom]에 댓글을 남기실 수도 있습니다. 이 포스트와 관련된 모든 소스 코드는 저장소의 [`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 -->
## 소개
운영체제 커널을 만드려면 운영체제에 의존하지 않는 코드가 필요합니다. 자세히 설명하자면, 스레드, 파일, 동적 메모리, 네트워크, 난수 생성기, 표준 출력 및 기타 운영체제의 추상화 또는 특정 하드웨어의 기능을 필요로 하는 것들은 전부 사용할 수 없다는 뜻입니다. 우리는 스스로 운영체제 및 드라이버를 직접 구현하려는 상황이니 어찌 보면 당연한 조건입니다.
운영체제에 의존하지 않으려면 [Rust 표준 라이브러리][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로 운영체제 커널을 작성하려면, 운영체제 없이도 실행가능한 실행파일이 필요합니다. 이러한 실행파일은
보통 "freestanding 실행파일" 혹은 "bare-metal 실행파일" 이라고 불립니다.
이 포스트에서는 "freestanding 실행 파일" 을 만드는 데 필요한 것들을 여러 단계로 나누고, 각 단계가 왜 필요한지에 대해 설명해드립니다. 중간 과정은 생략하고 그저 최소한의 예제 코드만 확인하고 싶으시면 **[요약 섹션으로 넘어가시면 됩니다](#summary)**.
## Rust 표준 라이브러리 링크 해제하기
모든 Rust 프로그램들은 Rust 표준 라이브러리를 링크하는데, 이 라이브러리는 스레드, 파일, 네트워킹 등의 기능을 제공하기 위해 운영체제에 의존합니다. Rust 표준 라이브러리는 또한 C 표준 라이브러리인 `libc`에도 의존합니다 (`libc`는 운영체제의 여러 기능들을 이용합니다).
우리가 운영체제를 직접 구현하기 위해서는 운영체제를 이용하는 라이브러리들은 사용할 수 없습니다. 그렇기에 우선 [`no_std` 속성][`no_std` attribute]을 이용해 자동으로 Rust 표준 라이브러리가 링크되는 것을 막아야 합니다.
[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 애플리케이션 크레이트를 만듭니다.
```
cargo new blog_os --bin --edition 2018
```
프로젝트 이름은 `blog_os` 또는 원하시는 이름으로 정해주세요. `--bin` 인자는 우리가 cargo에게 실행 파일 (라이브러리와 대조됨)을 만들겠다고 알려주고, `--edition 2018` 인자는 cargo에게 우리가 [Rust 2018 에디션][2018 edition]을 사용할 것이라고 알려줍니다.
위 명령어를 실행하고 나면, cargo가 아래와 같은 크레이트 디렉토리를 만들어줍니다.
[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` 파일에 크레이트 실행 시 맨 처음 호출되는 `main` 함수를 포함한 중추 모듈이 있습니다.
`cargo build` 명령어를 통해 크레이트를 빌드하면 `target/debug` 디렉토리에 `blog_os` 실행파일이 생성됩니다.
[semantic version]: https://semver.org/
### `no_std` 속성
현재 우리가 만든 크레이트는 암시적으로 Rust 표준 라이브러리를 링크합니다. 아래와 같이 [`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` 매크로][`println` macro]를 제공하는 Rust 표준 라이브러리를 우리의 크레이트에 링크하지 않게 되었기 때문입니다.
`println`은 [표준 입출력][standard output] (운영체제가 제공하는 특별한 파일 서술자)으로 데이터를 쓰기 때문에, 우리는 이제 `println`을 이용해 메세지를 출력할 수 없습니다.
[`println` macro]: https://doc.rust-lang.org/std/macro.println.html
[standard output]: https://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29
`println` 매크로 호출 코드를 지운 후 크레이트를 다시 빌드해봅시다.
```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]이 일어날 경우 `panic_handler` 속성이 적용된 함수가 호출되도록 합니다. 표준 라이브러리는 패닉 시 호출되는 함수가 제공되지만, `no_std` 환경에서는 우리가 패닉 시 호출될 함수를 직접 설정해야 합니다.
[panic]: https://doc.rust-lang.org/stable/book/ch09-01-unrecoverable-errors-with-panic.html
```rust
// in main.rs
use core::panic::PanicInfo;
/// 패닉이 일어날 경우, 이 함수가 호출됩니다.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
[`PanicInfo` 인자][PanicInfo]는 패닉이 일어난 파일명, 패닉이 파일 내 몇 번째 줄에서 일어났는지, 그리고 패닉시 전달된 메세지에 대한 정보를 가진 구조체입니다.
`panic` 함수는 절대로 반환하지 않기에 ["never" 타입][“never” type] `!`을 반환하도록 적어 컴파일러에게 이 함수가 [반환 함수][diverging function]임을 알립니다.
당장 이 함수에서 우리가 하고자 하는 일은 없기에 그저 함수가 반환하지 않도록 무한루프를 넣어줍니다.
[PanicInfo]: https://doc.rust-lang.org/nightly/core/panic/struct.PanicInfo.html
[diverging function]: https://doc.rust-lang.org/1.30.0/book/first-edition/functions.html#diverging-functions
[“never” type]: https://doc.rust-lang.org/nightly/std/primitive.never.html
## `eh_personality` Language Item
Language item은 컴파일러가 내부적으로 요구하는 특별한 함수 및 타입들을 가리킵니다. 예를 들어 [`Copy`] 트레잇은 어떤 타입들이 [_copy semantics_][`Copy`] 를 가지는지 컴파일러에게 알려주는 language item 입니다.
[`Copy` 트레잇이 구현된 코드][copy code]에 있는 `#[lang = "copy"]` 속성을 통해 이 트레잇이 language item으로 선언되어 있음을 확인할 수 있습니다.
[`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
임의로 구현한 language item을 사용할 수는 있지만, 위험할 수도 있기에 주의해야 합니다.
그 이유는 language item의 구현 코드는 매우 자주 변경되어 불안정하며, language item에 대해서 컴파일러가 타입 체크 조차 하지 않습니다 (예시: language item 함수의 인자 타입이 정확한지 조차 체크하지 않습니다).
임의로 구현한 language item을 이용하는 것보다 더 안정적으로 위의 language item 오류를 고칠 방법이 있습니다.
[`eh_personality` language item]은 [스택 되감기 (stack unwinding)][stack unwinding]을 구현하는 함수를 가리킵니다. 기본적으로 Rust는 [패닉][panic]이 일어났을 때 스택 되감기를 통해 스택에 살아있는 각 변수의 소멸자를 호출합니다. 이를 통해 자식 스레드에서 사용 중이던 모든 메모리 리소스가 반환되고, 부모 스레드가 패닉에 대처한 후 계속 실행될 수 있게 합니다. 스택 되감기는 복잡한 과정으로 이루어지며 운영체제마다 특정한 라이브러리를 필요로 하기에 (예: Linux는 [libunwind], Windows는 [structured exception handling]), 우리가 구현할 운영체제에서는 이 기능을 사용하지 않을 것입니다.
[`eh_personality` language item]: 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/
[structured exception handling]: https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling
### 스택 되감기를 해제하는 방법
스택 되감기가 불필요한 상황들이 여럿 있기에, Rust 언어는 [패닉 시 실행 종료][abort on panic] 할 수 있는 선택지를 제공합니다. 이는 스택 되감기에 필요한 심볼 정보 생성을 막아주어 실행 파일의 크기 자체도 많이 줄어들게 됩니다. 스택 되감기를 해제하는 방법은 여러가지 있지만, 가장 쉬운 방법은 `Cargo.toml` 파일에 아래의 코드를 추가하는 것입니다.
```toml
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
```
위의 코드를 통해 `dev` 빌드 (`cargo build` 실행)와 `release` 빌드 (`cargo build --release` 실행) 에서 모두 패닉 시 실행이 종료되도록 설정되었습니다.
이제 더 이상 컴파일러가 `eh_personality` language item을 필요로 하지 않습니다.
[abort on panic]: https://github.com/rust-lang/rust/pull/32900
위에서 본 오류들을 고쳤지만, 크레이트를 빌드하려고 하면 새로운 오류가 뜰 것입니다:
```
> cargo build
error: requires `start` lang_item
```
우리의 프로그램에는 프로그램 실행 시 최초 실행 시작 지점을 지정해주는 `start` language item이 필요합니다.
## `start` 속성
혹자는 프로그램 실행 시 언제나 `main` 함수가 가장 먼저 호출된다고 생각할지도 모릅니다. 대부분의 프로그래밍 언어들은 [런타임 시스템][runtime system]을 가지고 있는데, 이는 가비지 컬렉션 (예시: Java) 혹은 소프트웨어 스레드 (예시: GoLang의 goroutine) 등의 기능을 담당합니다.
이러한 런타임 시스템은 프로그램 실행 이전에 초기화 되어야 하기에 `main` 함수 호출 이전에 먼저 호출됩니다.
[runtime system]: https://en.wikipedia.org/wiki/Runtime_system
러스트 표준 라이브러리를 링크하는 전형적인 러스트 실행 파일의 경우, 프로그램 실행 시 C 런타임 라이브러리인 `crt0` (“C runtime zero”) 에서 실행이 시작됩니다. `crt0`는 C 프로그램의 환경을 설정하고 초기화하는 런타임 시스템으로, 스택을 만들고 프로그램에 주어진 인자들을 적절한 레지스터에 배치합니다. `crt0`가 작업을 마친 후 `start` language item으로 지정된 [Rust 런타임의 실행 시작 함수][rt::lang_start]를 호출합니다.
Rust는 최소한의 런타임 시스템을 가지며, 주요 기능은 스택 오버플로우 가드를 초기화하고 패닉 시 역추적 (backtrace) 정보를 출력하는 것입니다. Rust 런타임의 초기화 작업이 끝난 후에야 `main` 함수가 호출됩니다.
[rt::lang_start]: https://github.com/rust-lang/rust/blob/bb4d1491466d8239a7a5fd68bd605e3276e97afb/src/libstd/rt.rs#L32-L73
우리의 "freestanding 실행 파일" 은 Rust 런타임이나 `crt0`에 접근할 수 없기에, 우리가 직접 프로그램 실행 시작 지점을 지정해야 합니다.
`crt0``start` language item을 호출해주는 방식으로 동작하기에, `start` language item을 구현하고 지정하는 것만으로는 문제를 해결할 수 없습니다.
대신 우리가 직접 `crt0`의 시작 지점을 대체할 새로운 실행 시작 지점을 제공해야 합니다.
### 실행 시작 지점 덮어쓰기
`#![no_main]` 속성을 이용해 Rust 컴파일러에게 우리가 일반적인 실행 시작 호출 단계를 이용하지 않겠다고 선언합니다.
```rust
#![no_std]
#![no_main]
use core::panic::PanicInfo;
/// 패닉이 일어날 경우, 이 함수가 호출됩니다.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
`main` 함수가 사라진 것을 눈치채셨나요? `main` 함수를 호출해주는 런타임 시스템이 없는 이상 `main` 함수의 존재도 더 이상 의미가 없습니다.
우리는 운영체제가 호출하는 프로그램 실행 시작 지점 대신 우리의 새로운 `_start` 함수를 실행 시작 지점으로 대체할 것입니다.
```rust
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! {
loop {}
}
```
`#[unsafe(no_mangle)]` 속성을 통해 [name mangling]을 해제하여 Rust 컴파일러가 `_start` 라는 이름 그대로 함수를 만들도록 합니다. 이 속성이 없다면, 컴파일러가 각 함수의 이름을 고유하게 만드는 과정에서 이 함수의 실제 이름을 `_ZN3blog_os4_start7hb173fedf945531caE` 라는 이상한 이름으로 바꿔 생성합니다. 우리가 원하는 실제 시작 지점 함수의 이름을 정확히 알고 있어야 링커 (linker)에도 그 이름을 정확히 전달할 수 있기에 (후속 단계에서 진행) `#[unsafe(no_mangle)]` 속성이 필요합니다.
또한 우리는 이 함수에 `extern "C"`라는 표시를 추가하여 이 함수가 Rust 함수 호출 규약 대신에 [C 함수 호출 규약][C calling convention]을 사용하도록 합니다. 함수의 이름을 `_start`로 지정한 이유는 그저 런타임 시스템들의 실행 시작 함수 이름이 대부분 `_start`이기 때문입니다.
[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
[C calling convention]: https://en.wikipedia.org/wiki/Calling_convention
`!` 반환 타입은 이 함수가 발산 함수라는 것을 의미합니다. 시작 지점 함수는 오직 운영체제나 부트로더에 의해서만 직접 호출됩니다. 따라서 시작 지점 함수는 반환하는 대신 운영체제의 [`exit` 시스템콜][`exit` system call]을 이용해 종료됩니다. 우리의 "freestanding 실행 파일" 은 실행 종료 후 더 이상 실행할 작업이 없기에, 시작 지점 함수가 작업을 마친 후 기기를 종료하는 것이 합리적입니다. 여기서는 일단 `!` 타입의 조건을 만족시키기 위해 무한루프를 넣어 줍니다.
[`exit` system call]: https://en.wikipedia.org/wiki/Exit_(system_call)
다시 `cargo build`를 실행하면, 끔찍한 _링커_ 오류를 마주하게 됩니다.
## 링커 오류
링커는 컴파일러가 생성한 코드들을 묶어 실행파일로 만드는 프로그램입니다. 실행 파일 형식은 Linux, Windows, macOS 마다 전부 다르기에 각 운영체제는 자신만의 링커가 있고 링커마다 다른 오류 메세지를 출력할 것입니다.
오류가 나는 근본적인 원인은 모두 동일한데, 링커는 주어진 프로그램이 C 런타임 시스템을 이용할 것이라고 가정하는 반면 우리의 크레이트는 그렇지 않기 때문입니다.
이 링커 오류를 해결하려면 링커에게 C 런타임을 링크하지 말라고 알려줘야 합니다. 두 가지 방법이 있는데, 하나는 링커에 특정 인자들을 주는 것이고, 또다른 하나는 크레이트 컴파일 대상 기기를 bare metal 기기로 설정하는 것입니다.
### Bare Metal 시스템을 목표로 빌드하기
기본적으로 Rust는 당신의 현재 시스템 환경에서 실행할 수 있는 실행파일을 생성하고자 합니다. 예를 들어 Windows `x86_64` 사용자의 경우, Rust는 `x86_64` 명령어 셋을 사용하는 `.exe` 확장자 실행파일을 생성합니다. 사용자의 기본 시스템 환경을 "호스트" 시스템이라고 부릅니다.
여러 다른 시스템 환경들을 표현하기 위해 Rust는 [_target triple_]이라는 문자열을 이용합니다. 현재 호스트 시스템의 target triple이 궁금하시다면 `rustc --version --verbose` 명령어를 실행하여 확인 가능합니다.
[_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` Linux 시스템에서 얻은 것입니다. 호스트 target triple이 `x86_64-unknown-linux-gnu`으로 나오는데, 이는 CPU 아키텍쳐 정보 (`x86_64`)와 하드웨어 판매자 (`unknown`), 운영체제 (`linux`) 그리고 [응용 프로그램 이진 인터페이스 (ABI)][ABI] (`gnu`) 정보를 모두 담고 있습니다.
[ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
우리의 호스트 시스템 triple을 위해 컴파일하는 경우, Rust 컴파일러와 링커는 Linux나 Windows와 같은 운영체제가 있다고 가정하고 또한 운영체제가 C 런타임 시스템을 사용할 것이라고 가정하기 때문에 링커 오류 메세지가 출력된 것입니다. 이런 링커 오류를 피하려면 운영체제가 없는 시스템 환경에서 코드가 구동하는 것을 목표로 컴파일해야 합니다.
운영체제가 없는 bare metal 시스템 환경의 한 예시로 `thumbv7em-none-eabihf` target triple이 있습니다 (이는 [임베디드][embedded] [ARM] 시스템을 가리킵니다). Target triple의 `none`은 시스템에 운영체제가 동작하지 않음을 의미하며, 이 target triple의 나머지 부분의 의미는 아직 모르셔도 괜찮습니다. 이 시스템 환경에서 구동 가능하도록 컴파일하려면 rustup에서 해당 시스템 환경을 추가해야 합니다.
[embedded]: https://en.wikipedia.org/wiki/Embedded_system
[ARM]: https://en.wikipedia.org/wiki/ARM_architecture
```
rustup target add thumbv7em-none-eabihf
```
위 명령어를 실행하면 해당 시스템을 위한 Rust 표준 라이브러리 및 코어 라이브러리를 설치합니다. 이제 해당 target triple을 목표로 하는 freestanding 실행파일을 만들 수 있습니다.
```
cargo build --target thumbv7em-none-eabihf
```
`--target` 인자를 통해 우리가 해당 bare metal 시스템을 목표로 [크로스 컴파일][cross compile]할 것이라는 것을 cargo에게 알려줍니다. 목표 시스템 환경에 운영체제가 없는 것을 링커도 알기 때문에 C 런타임을 링크하려고 시도하지 않으며 이제는 링커 에러 없이 빌드가 성공할 것입니다.
[cross compile]: https://en.wikipedia.org/wiki/Cross_compiler
우리는 이 방법을 이용하여 우리의 운영체제 커널을 빌드해나갈 것입니다. 위에서 보인 `thumbv7em-none-eabihf` 시스템 환경 대신 bare metal `x86_64` 시스템 환경을 묘사하는 [커스텀 시스템 환경][custom target]을 설정하여 빌드할 것입니다. 더 자세한 내용은 다음 포스트에서 더 설명하겠습니다.
[custom target]: https://doc.rust-lang.org/rustc/targets/custom.html
### 링커 인자
Bare metal 시스템을 목표로 컴파일하는 대신, 링커에게 특정 인자들을 추가로 주어 링커 오류를 해결하는 방법도 있습니다.
이 방법은 앞으로 우리가 작성해나갈 커널 코드를 빌드할 때는 사용하지 않을 것이지만, 더 알고싶어 하실 분들을 위해서 이 섹션을 준비했습니다.
아래의 _"링커 인자"_ 텍스트를 눌러 이 섹션의 내용을 확인하세요.
<details>
<summary>링커 인자</summary>
이 섹션에서는 Linux, Windows 그리고 macOS 각각의 운영체제에서 나타나는 링커 오류에 대해 다루고 각 운영체제마다 링커에 어떤 추가 인자들을 주어 링커 오류를 해결할 수 있는지 설명할 것입니다.
#### Linux
Linux 에서는 아래와 같은 링커 오류 메세지가 출력됩니다 (일부 생략됨):
```
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`라는 이름을 가집니다. 이 `_start` 루틴은 C 표준 라이브러리 (`libc`)가 포함하는 여러 symbol들을 필요로 하지만, 우리는 `no_std` 속성을 이용해 크레이트에서 `libc`를 링크하지 않기 때문에 링커가 몇몇 symbol들의 출처를 찾지 못하여 위와 같은 링커 오류 메세지가 출력되는 것입니다. 이 문제를 해결하려면, 링커에게 `--nostartfiles` 인자를 전달하여 더 이상 링커가 C 런타임의 실행 시작 루틴을 링크하지 않도록 해야 합니다.
링커에 인자를 전달하는 한 방법은 `cargo rustc` 명령어를 이용하는 것입니다. 이 명령어는 `cargo build`와 유사하게 동작하나, `rustc`(Rust 컴파일러)에 직접 인자를 전달할 수 있게 해줍니다. `rustc``-C link-arg` 인자를 통해 링커에게 인자를 전달할 수 있게 해줍니다. 우리가 이용할 새로운 빌드 명령어는 아래와 같습니다:
```
cargo rustc -- -C link-arg=-nostartfiles
```
이제 우리의 크레이트가 성공적으로 빌드되고 Linux에서 동작하는 freestanding 실행파일이 생성됩니다!
우리는 위의 빌드 명령어에서 실행 시작 함수의 이름을 명시적으로 전달하지 않았는데, 그 이유는 링커가 기본적으로 `_start` 라는 이름의 함수를 찾아 그 함수를 실행 시작 함수로 이용하기 때문입니다.
#### Windows
Windows에서는 다른 링커 오류를 마주하게 됩니다 (일부 생략):
```
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)에 따라 다릅니다][windows-subsystems]. `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에서와는 다른 인자 형식을 통해 Windows의 링커는 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 실행파일들은 여러 가지 [서브시스템][windows-subsystems]을 사용할 수 있기 때문입니다. 일반적인 프로그램들의 경우, 실행 시작 지점 함수의 이름에 따라 어떤 서브시스템을 사용하는지 추론합니다: 실행 시작 지점의 이름이 `main`인 경우 `CONSOLE` 서브시스템이 사용 중이라는 것을 알 수 있으며, 실행 시작 지점의 이름이 `WinMain`인 경우 `WINDOWS` 서브시스템이 사용 중이라는 것을 알 수 있습니다. 우리는 `_start`라는 새로운 이름의 실행 시작 지점을 이용할 것이기에, 우리가 어떤 서브시스템을 사용할 것인지 인자를 통해 명시적으로 링커에게 알려줘야 합니다:
```
cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"
```
위 명령어에서는 `CONSOLE` 서브시스템을 서용했지만, `WINDOWS` 서브시스템을 적용해도 괜찮습니다. `-C link-arg` 인자를 반복해서 쓰는 대신, `-C link-args`인자를 이용해 여러 인자들을 빈칸으로 구분하여 전달할 수 있습니다.
이 명령어를 통해 우리의 실행 파일을 Windows에서도 성공적으로 빌드할 수 있을 것입니다.
#### 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 […]
```
macOS는 [공식적으로는 정적으로 링크된 실행파일을 지원하지 않으며][does not officially support statically linked binaries], 기본적으로 모든 프로그램이 `libSystem` 라이브러리를 링크하도록 요구합니다. 이러한 기본 요구사항을 무시하고 정적으로 링크된 실행 파일을 만드려면 링커에게 `-static` 인자를 주어야 합니다:
[does not officially support statically linked binaries]: 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 runtime zero”)를 링크하기 때문입니다. 이 오류는 우리가 Linux에서 봤던 오류와 유사한 것으로, 똑같이 링커에 `-nostartfiles` 인자를 주어 해결할 수 있습니다:
```
cargo rustc -- -C link-args="-e __start -static -nostartfiles"
```
이제는 우리의 프로그램을 macOS에서 성공적으로 빌드할 수 있을 것입니다.
#### 플랫폼 별 빌드 명령어들을 하나로 통합하기
위에서 살펴본 대로 호스트 플랫폼 별로 상이한 빌드 명령어가 필요한데, `.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`가 실행될 때마다 자동적으로 `rustc`에 인자로 전달됩니다. `.cargo/config.toml`에 대한 더 자세한 정보는 [공식 안내 문서](https://doc.rust-lang.org/cargo/reference/config.html)를 통해 확인해주세요.
이제 `cargo build` 명령어 만으로 세 가지 플랫폼 어디에서도 우리의 프로그램을 성공적으로 빌드할 수 있습니다.
#### 이렇게 하는 것이 괜찮나요?
Linux, Windows 또는 macOS 위에서 동작하는 freestanding 실행파일을 빌드하는 것이 가능하긴 해도 좋은 방법은 아닙니다. 운영체제가 갖춰진 환경을 목표로 빌드를 한다면, 실행 파일 동작 시 다른 많은 조건들이 런타임에 의해 제공될 것이라는 가정 하에 빌드가 이뤄지기 때문입니다 (예: 실행 파일이 `_start` 함수가 호출되는 시점에 이미 스택이 초기화되어있을 것이라고 간주하고 작동합니다). C 런타임 없이는 실행 파일이 필요로 하는 조건들이 갖춰지지 않아 결국 세그멘테이션 오류가 나는 등 프로그램이 제대로 실행되지 못할 수 있습니다.
이미 존재하는 운영체제 위에서 동작하는 최소한의 실행 파일을 만들고 싶다면, `libc`를 링크하고 [이 곳의 설명](https://doc.rust-lang.org/1.16.0/book/no-stdlib.html)에 따라 `#[start]` 속성을 설정하는 것이 더 좋은 방법일 것입니다.
</details>
## 요약 {#summary}
아래와 같은 최소한의 코드로 "freestanding" Rust 실행파일을 만들 수 있습니다:
`src/main.rs`:
```rust
#![no_std] // Rust 표준 라이브러리를 링크하지 않도록 합니다
#![no_main] // Rust 언어에서 사용하는 실행 시작 지점 (main 함수)을 사용하지 않습니다
use core::panic::PanicInfo;
#[unsafe(no_mangle)] // 이 함수의 이름을 mangle하지 않습니다
pub extern "C" fn _start() -> ! {
// 링커는 기본적으로 '_start' 라는 이름을 가진 함수를 실행 시작 지점으로 삼기에,
// 이 함수는 실행 시작 지점이 됩니다
loop {}
}
/// 패닉이 일어날 경우, 이 함수가 호출됩니다.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```
`Cargo.toml`:
```toml
[package]
name = "crate_name"
version = "0.1.0"
authors = ["Author Name <author@example.com>"]
# `cargo build` 실행 시 이용되는 빌드 설정
[profile.dev]
panic = "abort" # 패닉 시 스택 되감기를 하지 않고 바로 프로그램 종료
# `cargo build --release` 실행 시 이용되는 빌드 설정
[profile.release]
panic = "abort" # 패닉 시 스택 되감기를 하지 않고 바로 프로그램 종료
```
이 실행 파일을 빌드하려면, `thumbv7em-none-eabihf`와 같은 bare metal 시스템 환경을 목표로 컴파일해야 합니다:
```
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"
```
주의할 것은 이것이 정말 최소한의 freestanding Rust 실행 파일이라는 것입니다. 실행 파일은 여러 가지 조건들을 가정하는데, 그 예로 실행파일 동작 시 `_start` 함수가 호출될 때 스택이 초기화되어 있을 것을 가정합니다. **이 freestanding 실행 파일을 이용해 실제로 유용한 작업을 처리하려면 아직 더 많은 코드 구현이 필요합니다**.
## 다음 단계는 무엇일까요?
[다음 포스트][next post]에서는 우리의 freestanding 실행 파일을 최소한의 기능을 갖춘 운영체제 커널로 만드는 과정을 단게별로 설명할 것입니다.
예시로 커스텀 시스템 환경을 설정하는 방법, 우리의 실행 파일을 부트로더와 합치는 방법, 그리고 화면에 메세지를 출력하는 방법 등에 대해 다루겠습니다.
[next post]: @/edition-2/posts/02-minimal-rust-kernel/index.md

View File

@@ -6,6 +6,9 @@ date = 2018-02-10
[extra]
chapter = "Bare Bones"
# GitHub usernames of the people that translated this post
translators = ["dobleuber"]
+++
The first step in creating our own operating system kernel is to create a Rust executable that does not link the standard library. This makes it possible to run Rust code on the [bare metal] without an underlying operating system.
@@ -18,6 +21,7 @@ This blog is openly developed on [GitHub]. If you have any problems or questions
[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 -->
@@ -43,7 +47,7 @@ In order to create an OS kernel in Rust, we need to create an executable that ca
This post describes the necessary steps to create a freestanding Rust binary and explains why the steps are needed. If you're just interested in a minimal example, you can **[jump to the summary](#summary)**.
## Disabling the Standard Library
By default, all Rust crates link the [standard library], which depends on the operating system for features such as threads, files, or networking. It also depends on the C standard library `libc`, which closely interacts with OS services. Since our plan is to write an operating system, we can not use any OS-dependent libraries. So we have to disable the automatic inclusion of the standard library through the [`no_std` attribute].
By default, all Rust crates link the [standard library], which depends on the operating system for features such as threads, files, or networking. It also depends on the C standard library `libc`, which closely interacts with OS services. Since our plan is to write an operating system, we can't use any OS-dependent libraries. So we have to disable the automatic inclusion of the standard library through the [`no_std` attribute].
[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
@@ -56,7 +60,7 @@ cargo new blog_os --bin --edition 2018
I named the project `blog_os`, but of course you can choose your own name. The `--bin` flag specifies that we want to create an executable binary (in contrast to a library) and the `--edition 2018` flag specifies that we want to use the [2018 edition] of Rust for our crate. When we run the command, cargo creates the following directory structure for us:
[2018 edition]: https://rust-lang-nursery.github.io/edition-guide/rust-2018/index.html
[2018 edition]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
```
blog_os
@@ -67,7 +71,7 @@ blog_os
The `Cargo.toml` contains the crate configuration, for example the crate name, the author, the [semantic version] number, and dependencies. The `src/main.rs` file contains the root module of our crate and our `main` function. You can compile your crate through `cargo build` and then run the compiled `blog_os` binary in the `target/debug` subfolder.
[semantic version]: http://semver.org/
[semantic version]: https://semver.org/
### The `no_std` Attribute
@@ -149,12 +153,12 @@ Language items are special functions and types that are required internally by t
While providing custom implementations of language items is possible, it should only be done as a last resort. The reason is that language items are highly unstable implementation details and not even type checked (so the compiler doesn't even check if a function has the right argument types). Fortunately, there is a more stable way to fix the above language item error.
The [`eh_personality` language item] marks a function that is used for implementing [stack unwinding]. By default, Rust uses unwinding to run the destructors of all live stack variables in case of a [panic]. This ensures that all used memory is freed and allows the parent thread to catch the panic and continue execution. Unwinding, however, is a complicated process and requires some OS specific libraries (e.g. [libunwind] on Linux or [structured exception handling] on Windows), so we don't want to use it for our operating system.
The [`eh_personality` language item] marks a function that is used for implementing [stack unwinding]. By default, Rust uses unwinding to run the destructors of all live stack variables in case of a [panic]. This ensures that all used memory is freed and allows the parent thread to catch the panic and continue execution. Unwinding, however, is a complicated process and requires some OS-specific libraries (e.g. [libunwind] on Linux or [structured exception handling] on Windows), so we don't want to use it for our operating system.
[`eh_personality` language item]: https://github.com/rust-lang/rust/blob/edb368491551a77d77a48446d4ee88b35490c565/src/libpanic_unwind/gcc.rs#L11-L45
[stack unwinding]: http://www.bogotobogo.com/cplusplus/stackunwinding.php
[libunwind]: http://www.nongnu.org/libunwind/
[structured exception handling]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680657(v=vs.85).aspx
[stack unwinding]: https://www.bogotobogo.com/cplusplus/stackunwinding.php
[libunwind]: https://www.nongnu.org/libunwind/
[structured exception handling]: https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling
### Disabling Unwinding
@@ -212,13 +216,13 @@ fn panic(_info: &PanicInfo) -> ! {
You might notice that we removed the `main` function. The reason is that a `main` doesn't make sense without an underlying runtime that calls it. Instead, we are now overwriting the operating system entry point with our own `_start` function:
```rust
#[no_mangle]
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! {
loop {}
}
```
By using the `#[no_mangle]` attribute we disable the [name mangling] to ensure that the Rust compiler really outputs a function with the name `_start`. Without the attribute, the compiler would generate some cryptic `_ZN3blog_os4_start7hb173fedf945531caE` symbol to give every function an unique name. The attribute is required because we need to tell the name of the entry point function to the linker in the next step.
By using the `#[unsafe(no_mangle)]` attribute, we disable [name mangling] to ensure that the Rust compiler really outputs a function with the name `_start`. Without the attribute, the compiler would generate some cryptic `_ZN3blog_os4_start7hb173fedf945531caE` symbol to give every function a unique name. The attribute is required because we need to tell the name of the entry point function to the linker in the next step.
We also have to mark the function as `extern "C"` to tell the compiler that it should use the [C calling convention] for this function (instead of the unspecified Rust calling convention). The reason for naming the function `_start` is that this is the default entry point name for most systems.
@@ -239,7 +243,7 @@ To solve the errors, we need to tell the linker that it should not include the C
### Building for a Bare Metal Target
By default Rust tries to build an executable that is able to run in your current system environment. For example, if you're using Windows on `x86_64`, Rust tries to build a `.exe` Windows executable that uses `x86_64` instructions. This environment is called your "host" system.
By default Rust tries to build an executable that is able to run in your current system environment. For example, if you're using Windows on `x86_64`, Rust tries to build an `.exe` Windows executable that uses `x86_64` instructions. This environment is called your "host" system.
To describe different environments, Rust uses a string called [_target triple_]. You can see the target triple for your host system by running `rustc --version --verbose`:
@@ -259,9 +263,9 @@ The above output is from a `x86_64` Linux system. We see that the `host` triple
[ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
By compiling for our host triple, the Rust compiler and the linker assume that there is an underlying operating system such as Linux or Windows that use the C runtime by default, which causes the linker errors. So to avoid the linker errors, we can compile for a different environment with no underlying operating system.
By compiling for our host triple, the Rust compiler and the linker assume that there is an underlying operating system such as Linux or Windows that uses the C runtime by default, which causes the linker errors. So, to avoid the linker errors, we can compile for a different environment with no underlying operating system.
An example for such a bare metal environment is the `thumbv7em-none-eabihf` target triple, which describes an [embedded] [ARM] system. The details are not important, all that matters is that the target triple has no underlying operating system, which is indicated by the `none` in the target triple. To be able to compile for this target, we need to add it in rustup:
An example of such a bare metal environment is the `thumbv7em-none-eabihf` target triple, which describes an [embedded] [ARM] system. The details are not important, all that matters is that the target triple has no underlying operating system, which is indicated by the `none` in the target triple. To be able to compile for this target, we need to add it in rustup:
[embedded]: https://en.wikipedia.org/wiki/Embedded_system
[ARM]: https://en.wikipedia.org/wiki/ARM_architecture
@@ -334,7 +338,7 @@ error: linking with `link.exe` failed: exit code: 1561
= note: LINK : fatal error LNK1561: entry point must be defined
```
The "entry point must be defined" error means that the linker can't find the entry point. On Windows, the default entry point name [depends on the used subsystem][windows-subsystems]. For the `CONSOLE` subsystem the linker looks for a function named `mainCRTStartup` and for the `WINDOWS` subsystem it looks for a function named `WinMainCRTStartup`. To override the default and tell the linker to look for our `_start` function instead, we can pass an `/ENTRY` argument to the linker:
The "entry point must be defined" error means that the linker can't find the entry point. On Windows, the default entry point name [depends on the used subsystem][windows-subsystems]. For the `CONSOLE` subsystem, the linker looks for a function named `mainCRTStartup` and for the `WINDOWS` subsystem, it looks for a function named `WinMainCRTStartup`. To override the default and tell the linker to look for our `_start` function instead, we can pass an `/ENTRY` argument to the linker:
[windows-subsystems]: https://docs.microsoft.com/en-us/cpp/build/reference/entry-entry-point-symbol
@@ -354,7 +358,7 @@ error: linking with `link.exe` failed: exit code: 1221
defined
```
This error occurs because Windows executables can use different [subsystems][windows-subsystems]. For normal programs they are inferred depending on the entry point name: If the entry point is named `main`, the `CONSOLE` subsystem is used, and if the entry point is named `WinMain`, the `WINDOWS` subsystem is used. Since our `_start` function has a different name, we need to specify the subsystem explicitly:
This error occurs because Windows executables can use different [subsystems][windows-subsystems]. For normal programs, they are inferred depending on the entry point name: If the entry point is named `main`, the `CONSOLE` subsystem is used, and if the entry point is named `WinMain`, the `WINDOWS` subsystem is used. Since our `_start` function has a different name, we need to specify the subsystem explicitly:
```
cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"
@@ -376,7 +380,7 @@ error: linking with `cc` failed: exit code: 1
clang: error: linker command failed with exit code 1 […]
```
This error message tells us that the linker can't find an entry point function with the default name `main` (for some reason all functions are prefixed with a `_` on macOS). To set the entry point to our `_start` function, we pass the `-e` linker argument:
This error message tells us that the linker can't find an entry point function with the default name `main` (for some reason, all functions are prefixed with a `_` on macOS). To set the entry point to our `_start` function, we pass the `-e` linker argument:
```
cargo rustc -- -C link-args="-e __start"
@@ -397,13 +401,13 @@ error: linking with `cc` failed: exit code: 1
macOS [does not officially support statically linked binaries] and requires programs to link the `libSystem` library by default. To override this and link a static binary, we pass the `-static` flag to the linker:
[does not officially support statically linked binaries]: https://developer.apple.com/library/content/qa/qa1118/_index.html
[does not officially support statically linked binaries]: https://developer.apple.com/library/archive/qa/qa1118/_index.html
```
cargo rustc -- -C link-args="-e __start -static"
```
This still not suffices, as a third linker error occurs:
This still does not suffice, as a third linker error occurs:
```
error: linking with `cc` failed: exit code: 1
@@ -413,7 +417,7 @@ error: linking with `cc` failed: exit code: 1
clang: error: linker command failed with exit code 1 […]
```
This error occurs because programs on macOS link to `crt0` (“C runtime zero”) by default. This is similar to the error we had on Linux and can be also solved by adding the `-nostartfiles` linker argument:
This error occurs because programs on macOS link to `crt0` (“C runtime zero”) by default. This is similar to the error we had on Linux and can also be solved by adding the `-nostartfiles` linker argument:
```
cargo rustc -- -C link-args="-e __start -static -nostartfiles"
@@ -423,10 +427,10 @@ Now our program should build successfully on macOS.
#### Unifying the Build Commands
Right now we have different build commands depending on the host platform, which is not ideal. To avoid this, we can create a file named `.cargo/config` that contains the platform specific arguments:
Right now we have different build commands depending on the host platform, which is not ideal. To avoid this, we can create a file named `.cargo/config.toml` that contains the platform-specific arguments:
```toml
# in .cargo/config
# in .cargo/config.toml
[target.'cfg(target_os = "linux")']
rustflags = ["-C", "link-arg=-nostartfiles"]
@@ -438,7 +442,7 @@ rustflags = ["-C", "link-args=/ENTRY:_start /SUBSYSTEM:console"]
rustflags = ["-C", "link-args=-e __start -static -nostartfiles"]
```
The `rustflags` key contains arguments that are automatically added to every invocation of `rustc`. For more information on the `.cargo/config` file check out the [official documentation](https://doc.rust-lang.org/cargo/reference/config.html).
The `rustflags` key contains arguments that are automatically added to every invocation of `rustc`. For more information on the `.cargo/config.toml` file, check out the [official documentation](https://doc.rust-lang.org/cargo/reference/config.html).
Now our program should be buildable on all three platforms with a simple `cargo build`.
@@ -462,7 +466,7 @@ A minimal freestanding Rust binary looks like this:
use core::panic::PanicInfo;
#[no_mangle] // don't mangle the name of this function
#[unsafe(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
@@ -510,10 +514,82 @@ cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"
cargo rustc -- -C link-args="-e __start -static -nostartfiles"
```
Note that this is just a minimal example of a freestanding Rust binary. This binary expects various things, for example that a stack is initialized when the `_start` function is called. **So for any real use of such a binary, more steps are required**.
Note that this is just a minimal example of a freestanding Rust binary. This binary expects various things, for example, that a stack is initialized when the `_start` function is called. **So for any real use of such a binary, more steps are required**.
## Making `rust-analyzer` happy
The [`rust-analyzer`](https://rust-analyzer.github.io/) project is a great way to get code completion and "go to definition" support (and many other features) for Rust code in your editor.
It works really well for `#![no_std]` projects too, so I recommend using it for kernel development!
If you're using the [`checkOnSave`](https://rust-analyzer.github.io/book/configuration.html#checkOnSave) feature of `rust-analyzer` (enabled by default), it might report an error for the panic function of our kernel:
```
found duplicate lang item `panic_impl`
```
The reason for this error is that `rust-analyzer` invokes `cargo check --all-targets` by default, which also tries to build the binary in [test](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) and [benchmark](https://doc.rust-lang.org/rustc/tests/index.html#benchmarks) mode.
<div class="note">
### The two meanings of "target"
The `--all-targets` flag is completely unrelated to the `--target` argument.
There are two different meanings of the term "target" in `cargo`:
- The `--target` flag specifies the **[_compilation target_]** that should be passed to the `rustc` compiler. This should be set to the [target triple] of the machine that should run our code.
- The `--all-targets` flag references the **[_package target_]** of Cargo. Cargo packages can be a library and binary at the same time, so you can specify in which way you like to build your crate. In addition, Cargo also has package targets for [examples](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#examples), [tests](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#tests), and [benchmarks](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#benchmarks). These package targets can co-exist, so you can build/check the same crate in e.g. library or test mode.
[_compilation target_]: https://doc.rust-lang.org/rustc/targets/index.html
[target triple]: https://clang.llvm.org/docs/CrossCompilation.html#target-triple
[_package target_]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html
</div>
By default, `cargo check` only builds the _library_ and _binary_ package targets.
However, `rust-analyzer` chooses to check all package targets by default when [`checkOnSave`](https://rust-analyzer.github.io/book/configuration.html#checkOnSave) is enabled.
This is the reason that `rust-analyzer` reports the above `lang item` error that we don't see in `cargo check`.
If we run `cargo check --all-targets`, we see the error too:
```
error[E0152]: found duplicate lang item `panic_impl`
--> src/main.rs:13:1
|
13 | / fn panic(_info: &PanicInfo) -> ! {
14 | | loop {}
15 | | }
| |_^
|
= note: the lang item is first defined in crate `std` (which `test` depends on)
= note: first definition in `std` loaded from /home/[...]/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-8df6be531efb3fd0.rlib
= note: second definition in the local crate (`blog_os`)
```
The first `note` tells us that the panic language item is already defined in the `std` crate, which is a dependency of the `test` crate.
The `test` crate is automatically included when building a crate in [test mode](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#tests).
This does not make sense for our `#![no_std]` kernel as there is no way to support the standard library on bare metal.
So this error is not relevant to our project and we can safely ignore it.
The proper way to avoid this error is to specify in our `Cargo.toml` that our binary does not support building in `test` and `bench` modes.
We can do that by adding a `[[bin]]` section to our `Cargo.toml` to [configure the build](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target) of our binary:
```toml
# in Cargo.toml
[[bin]]
name = "blog_os"
test = false
bench = false
```
The double-brackets around `bin` are not a mistake, this is how the TOML format defines keys that can appear multiple times.
Since a crate can have multiple binaries, the `[[bin]]` section can appear multiple times in the `Cargo.toml` as well.
This is also the reason for the mandatory `name` field, which needs to match the name of the binary (so that `cargo` knows which settings should be applied to which binary).
By setting the [`test`](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-test-field) and [`bench` ](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-bench-field) fields to `false`, we instruct `cargo` to not build our binary in test or benchmark mode.
Now `cargo check --all-targets` should not throw any errors anymore, and the `checkOnSave` implementation of `rust-analyzer` should be happy too.
## What's next?
The [next post] explains the steps needed for turning our freestanding binary into a minimal operating system kernel. This includes creating a custom target, combining our executable with a bootloader, and learning how to print something to the screen.
[next post]: @/second-edition/posts/02-minimal-rust-kernel/index.md
[next post]: @/edition-2/posts/02-minimal-rust-kernel/index.md

View File

@@ -0,0 +1,522 @@
+++
title = "Независимый бинарный файл на Rust"
weight = 1
path = "ru/freestanding-rust-binary"
date = 2018-02-10
[extra]
translators = ["MrZloHex"]
+++
Первый шаг в создании собственного ядра операционной системы &mdash; это создание исполняемого файла на Rust, который не будет подключать стандартную библиотеку. Именно это дает возможность запускать Rust код на [голом железе][bare metal] без слоя операционной системы.
[bare metal]: https://en.wikipedia.org/wiki/Bare_machine
<!-- more -->
Этот блог открыто разрабатывается на [GitHub]. Если у вас возникли какие-либо проблемы или вопросы, пожалуйста, создайте _issue_. Также вы можете оставлять комментарии [в конце страницы][at the bottom]. Полный исходный код для этого поста вы можете найти в репозитории в ветке [`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 -->
## Введение
Для того, чтобы написать ядро операционной системы, нужен код, который не зависит от операционной системы и ее возможностей. Это означает, что нельзя использовать потоки, файлы, [кучу][heap], сети, случайные числа, стандартный вывод или другие возможности, которые зависят от ОС или определённого железа.
[heap]: https://en.wikipedia.org/wiki/Heap_(data_structure)
Это значит, что нельзя использовать большую часть [стандартной библиотеки Rust][Rust Standard library], но остается множество других возможностей Rust, которые _можно использовать_. Например, [итераторы][iterators], [замыкания][closures], [сопоставление с образцом][pattern matching], [`Option`][option] и [`Result`][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 и объясняет, почему эти шаги нужны. Если вам интересен только минимальный пример, можете сразу перейти к __[итогам](#summary)__.
## Отключение стандартной библиотеки
По умолчанию, все Rust-крейты подключают [стандартную библиотеку][standard library], которая зависит от возможностей операционной системы, таких как потоки, файлы, сети. Она также зависит от стандартной библиотки C `libc`, которая очень тесно взаимодействует с возможностями ОС. Так как мы хотим написать операционную систему, мы не можем использовать библиотеки, которые зависят от операционной системы. Поэтому необходимо отключить автоматические подключение стандартной библиотеки через [атрибут `no_std`][attribute].
[standard library]: https://doc.rust-lang.org/std/
[attribute]: https://doc.rust-lang.org/1.30.0/book/first-edition/using-rust-without-the-standard-library.html
Мы начнем с создания нового проекта cargo. Самый простой способ сделать это &mdash; через командную строку:
```
cargo new blog_os --bin -- edition 2018
```
Я назвал этот проект `blog_os`, но вы можете назвать как вам угодно. Флаг `--bin` указывает на то, что мы хотим создать исполняемый файл (а не библиотеку), а флаг `--edition 2018` указывает, что мы хотим использовать [редакцию Rust 2018][edition] для нашего крейта. После выполнения команды cargo создаст каталог со следующей структурой:
[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` содержит корневой модуль нашего крейта и функцию `main`. Можно скомпилировать крейт с помощью `cargo build` и запустить скомпилированную программу `blog_os` в поддиректории `target/debug`.
[semantic version]: https://semver.org/
### Атрибут `no_std`
В данный момент наш крейт неявно подключает стандартную библиотеку. Это можно исправить путем добавления [атрибута `no_std`][attribute]:
```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] &mdash; часть стандартной библиотеки, которая была отключена. Поэтому у нас больше нет возможность выводить что-либо на экран. Это логично, так как `println` печатает через [стандартный вывод][standard output], который, в свою очередь, является специальным файловым дескриптором, предоставляемым операционной системой.
[macro]: https://doc.rust-lang.org/std/macro.println.html
[standard output]: https://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29
Давайте уберем макрос `println` и попробуем скомпилировать еще раз:
```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]` и «элемент языка».
## Реализация _паники_
Атрибут `pаnic_handler` определяет функцию, которая должна вызываться, когда происходит [паника (panic)][panic]. Стандартная библиотека предоставляет собственную функцию обработчика паники, но после отключения стандартной библиотеки мы должны написать собственный обработчик:
[panic]: 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 functions] и она возращает [пустой тип]["never" type] `!`. Пока что мы ничего не можем сделать в этой функции, поэтому мы просто войдем в бесконечный цикл.
[PanicInfo]: https://doc.rust-lang.org/nightly/core/panic/struct.PanicInfo.html
[diverging functions]: https://doc.rust-lang.org/1.30.0/book/first-edition/functions.html#diverging-functions
["never" type]: https://doc.rust-lang.org/nightly/std/primitive.never.html
## Элемент языка `eh_personality`
Элементы языка &mdash; это специальные функции и типы, которые необходимы компилятору. Например, трейт [`Copy`] указывает компилятору, у каких типов есть [_семантика копирования_][`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`][language item] указывает на функцию, которая используется для реализации [раскрутки стека][stack unwinding]. По умолчанию, Rust использует раскрутку для запуска деструктуров для всех _живых_ переменных на стеке в случае [паники][panic]. Это гарантирует, что вся использованная память будет освобождена, и позволяет родительскому потоку перехватить панику и продолжить выполнение. Раскрутка &mdash; очень сложный процесс и требует некоторых специльных библиотек ОС (например, [libunwind] для Linux или [structured exception handling] для Windows), так что мы не должны использовать её для нашей операционной системы.
[language item]: 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/
[structured exception handling]: https://docs.microsoft.com/ru-ru/windows/win32/debug/structured-exception-handling
### Отключение раскрутки
Существуют и другие случаи использования, для которых раскрутка нежелательна, поэтому Rust предоставляет опцию [прерывания выполнения при панике][abort on panic]. Это отключает генерацию информации о символах раскрутки и, таким образом, значительно уменьшает размер бинарного файла. Есть несколько мест, где мы можем отключить раскрутку. Самый простой способ &mdash; добавить следующие строки в наш `Cargo.toml`:
```toml
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
```
Это устанавливает стратегию паники на `abort` (прерывание) как для профиля `dev` (используемого для `cargo build`), так и для профиля `release` (используемого для `cargo build --release`). Теперь элемент языка `eh_personality` больше не должен требоваться.
[abort on panic]: https://github.com/rust-lang/rust/pull/32900
Теперь мы исправили обе вышеуказанные ошибки. Однако, если мы сейчас попытаемся скомпилировать программу, возникнет другая ошибка:
```
> cargo build
error: requires `start` lang_item
```
В нашей программе отсутствует элемент языка `start`, который определяет начальную точку входа программы.
## Аттрибут `start`
Можно подумать, что функция `main` &mdash; это первая функция, вызываемая при запуске программы. Однако в большинстве языков есть [среда выполнения][runtime system], которая отвечает за такие вещи, как сборка мусора (например, в Java) или программные потоки (например, goroutines в Go). Эта система выполнения должна быть вызвана до `main`, поскольку ей необходимо инициализировать себя.
[runtime system]: https://en.wikipedia.org/wiki/Runtime_system
В типичном исполнимом файле Rust, который использует стандартную библиотеку, выполнение начинается в runtime-библиотеке C под названием `crt0` ("C runtime zero"), которая создает окружение для C-приложения. Это включает создание стека и размещение аргументов в нужных регистрах. Затем C runtime вызывает [точку входа для Rust-приложения][rt::lang_start], которая обозначается элементом языка `start`. Rust имеет очень маленький runtime, который заботится о некоторых мелочах, таких как установка защиты от переполнения стека или вывод сообщения при панике. Затем рантайм вызывает функцию `main`.
[rt::lang_start]: https://github.com/rust-lang/rust/blob/bb4d1491466d8239a7a5fd68bd605e3276e97afb/src/libstd/rt.rs#L32-L73
Наш независимый исполняемый файл не имеет доступа к runtime Rust и `crt0`, поэтому нам нужно определить собственную точку входа. Реализация языкового элемента `start` не поможет, поскольку он все равно потребует `crt0`. Вместо этого нам нужно напрямую переопределить точку входа `crt0`.
### Переопределение точки входа
Чтобы сообщить компилятору Rust, что мы не хотим использовать стандартную цепочку точек входа, мы добавляем атрибут `#![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` не имеет смысла без стандартного runtime, которая ее вызывает. Вместо этого мы переопределим точку входа операционной системы с помощью нашей собственной функции `_start`:
```rust
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! {
loop {}
}
```
Используя атрибут `#[unsafe(no_mangle)]`, мы отключаем [искажение имен][name mangling], чтобы гарантировать, что компилятор Rust сгенерирует функцию с именем `_start`. Без этого атрибута компилятор генерировал бы какой-нибудь загадочный символ `_ZN3blog_os4_start7hb173fedf945531caE`, чтобы дать каждой функции уникальное имя. Атрибут необходим, потому что на следующем этапе нам нужно сообщить имя функции точки входа компоновщику.
Мы также должны пометить функцию как `extern "C"`, чтобы указать компилятору, что он должен использовать [соглашение о вызове C][C calling convention] для этой функции (вместо неопределенного соглашения о вызове Rust). Причина именования функции `_start` в том, что это имя точки входа по умолчанию для большинства систем.
[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
[C calling convention]: https://en.wikipedia.org/wiki/Calling_convention
Возвращаемый `!` означает, что функция является расходящейся, т.е. не имеет права возвращаться. Это необходимо, поскольку точка входа не вызывается никакой функцией, а вызывается непосредственно операционной системой или загрузчиком. Поэтому вместо возврата точка входа должна, например, вызвать [системный вызов `exit`][`exit` system call] операционной системы. В нашем случае разумным действием может быть выключение машины, поскольку ничего не останется делать, если независимый исполнимый файл завершит исполнение. Пока что мы выполняем это требование путем бесконечного цикла.
[`exit` system call]: https://en.wikipedia.org/wiki/Exit_(system_call)
Если мы выполним `cargo build` сейчас, мы получим ошибку компоновщика (_linker_ error).
## Ошибки компоновщика
Компоновщик &mdash; это программа, которая объединяет сгенерированный код в исполняемый файл. Поскольку формат исполняемого файла отличается в Linux, Windows и macOS, в каждой системе есть свой компоновщик, и каждый покажет свою ошибку. Основная причина ошибок одна и та же: конфигурация компоновщика по умолчанию предполагает, что наша программа зависит от C runtime, а это не так.
Чтобы устранить ошибки, нам нужно сообщить компоновщику, что он не должен включать C runtime. Мы можем сделать это, передав компоновщику определенный набор аргументов или выполнив компиляцию для голого железа.
### Компиляция для голого железа
По умолчанию Rust пытается создать исполняемый файл, который может быть запущен в окружении вашей текущей системы. Например, если вы используете Windows на `x86_64`, Rust пытается создать исполняемый файл Windows `.exe`, который использует инструкции `x86_64`. Это окружение называется вашей "хост-системой".
Для описания различных окружений Rust использует строку [_target triple_]. Вы можете узнать тройку вашей хост-системы, выполнив команду `rustc --version --verbose`:
[_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` Linux. Мы видим, что тройка `host` &mdash; это `x86_64-unknown-linux-gnu`, которая включает архитектуру процессора (`x86_64`), производителя (`unknown`), операционную систему (`linux`) и [ABI] (`gnu`).
[ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
Компилируя для тройки нашего хоста, компилятор Rust и компоновщик предполагают наличие базовой операционной системы, такой как Linux или Windows, которая по умолчанию использует C runtime, что вызывает ошибки компоновщика. Поэтому, чтобы избежать ошибок компоновщика, мы можем настроить компиляцию для другого окружения без базовой операционной системы.
Примером такого "голого" окружения является тройка `thumbv7em-none-eabihf`, которая описывает [ARM] архитектуру. Детали не важны, важно лишь то, что тройка не имеет базовой операционной системы, на что указывает `none` в тройке. Чтобы иметь возможность компилировать для этой системы, нам нужно добавить ее в rustup:
[ARM]: https://en.wikipedia.org/wiki/ARM_architecture
```
rustup target add thumbv7em-none-eabihf
```
Это загружает копию стандартной библиотеки (и `core`) для системы. Теперь мы можем собрать наш независимый исполняемый файл для этой системы:
```
cargo build --target thumbv7em-none-eabihf
```
Передавая аргумент `--target`, мы [кросс-компилируем][cross compile] наш исполняемый файл для голого железа. Поскольку система, под которую мы компилируем, не имеет операционной системы, компоновщик не пытается компоновать C runtime, и наша компиляция проходит успешно без каких-либо ошибок компоновщика.
[cross compile]: https://en.wikipedia.org/wiki/Cross_compiler
Именно этот подход мы будем использовать для сборки ядра нашей ОС. Вместо `thumbv7em-none-eabihf` мы будем использовать [custom target], который описывает окружение для архитектуры `x86_64`. Подробности будут описаны в следующем посте.
[custom target]: https://doc.rust-lang.org/rustc/targets/custom.html
### Аргументы компоновщика
Вместо компиляции под голое железо, ошибки компоновщика можно исправить, передав ему определенный набор аргументов. Мы не будем использовать этот подход для нашего ядра, поэтому данный раздел является необязательным и приводится только для полноты картины. Щелкните на _"Аргументы компоновщика"_ ниже, чтобы показать необязательное содержание.
<details>
<summary>Аргументы компоновщика</summary>
В этом разделе мы рассмотрим ошибки компоновщика, возникающие в Linux, Windows и macOS, и объясним, как их решить, передав компоновщику дополнительные аргументы. Обратите внимание, что формат исполняемого файла и компоновщик отличаются в разных операционных системах, поэтому для каждой системы требуется свой набор аргументов.
#### Linux
На Linux возникает следующая ошибка компоновщика (сокращенно):
```
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 runtime, которая также называется `_start`. Она требует некоторых символов стандартной библиотеки C `libc`, которые мы не включаем из-за атрибута `no_std`, поэтому компоновщик не может подключить эти библиотеки, поэтому появляются ошибки. Чтобы решить эту проблему, мы можем сказать компоновщику, что он не должен компоновать процедуру запуска C, передав флаг `-nostartfiles`.
Одним из способов передачи атрибутов компоновщика через cargo является команда `cargo rustc`. Команда ведет себя точно так же, как `cargo build`, но позволяет передавать опции `rustc`, базовому компилятору Rust. У `rustc` есть флаг `-C link-arg`, который передает аргумент компоновщику. В совокупности наша новая команда сборки выглядит следующим образом:
```
cargo rustc -- -C link-arg=-nostartfiles
```
Теперь наш крейт собирается как независимый исполняемый файл в Linux!
Нам не нужно было явно указывать имя нашей функции точки входа, поскольку компоновщик по умолчанию ищет функцию с именем `_start`.
#### Windows
В Windows возникает другая ошибка компоновщика (сокращенно):
```
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 имя точки входа по умолчанию [зависит от используемой подсистемы][windows-subsystems]. Для подсистемы `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
```
Из разного формата аргументов мы ясно видим, что компоновщик Windows - это совершенно другая программа, чем компоновщик 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 могут использовать различные [подсистемы][windows-subsystems]. Для обычных программ они определяются в зависимости от имени точки входа: если точка входа называется `main`, то используется подсистема `CONSOLE`, а если точка входа называется `WinMain`, то используется подсистема `WINDOWS`. Поскольку наша функция `_start` имеет другое имя, нам нужно явно указать подсистему:
```
cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"
```
Здесь мы используем подсистему `CONSOLE`, но подойдет и подсистема `WINDOWS`. Вместо того, чтобы передавать `-C link-arg` несколько раз, мы используем `-C link-args`, который принимает список аргументов, разделенных пробелами.
С помощью этой команды наш исполняемый файл должен успешно скомпилироваться под Windows.
#### 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 […]
```
macOS [официально не поддерживает статически скомпонованные исполняемые файлы][static binary] и по умолчанию требует от программ компоновки библиотеки `libSystem`. Чтобы переопределить это поведение и скомпоновать статический исполняемый файл, передадим компоновщику флаг `-static`:
[static binary]: 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 runtime zero"). Она похожа на ошибку под Linux и тоже может быть решена добавлением аргумента компоновщика `-nostartfiles`:
```
cargo rustc -- -C link-args="-e __start -static -nostartfiles"
```
Теперь наша программа должна успешно скомпилироваться на macOS.
#### Объединение команд сборки
Сейчас у нас разные команды сборки в зависимости от платформы хоста, что не идеально. Чтобы избежать этого, мы можем создать файл с именем `.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`.
#### Должны ли вы это делать?
Хотя можно создать независимый исполняемый файл для Linux, Windows и macOS, это, вероятно, не очень хорошая идея. Причина в том, что наш исполняемый файл все еще ожидает различных вещей, например, инициализации стека при вызове функции `_start`. Без C runtime некоторые из этих требований могут быть не выполнены, что может привести к сбою нашей программы, например, из-за ошибки сегментации.
Если вы хотите создать минимальный исполняемый файл, запускаемый поверх существующей операционной системы, то включение `libc` и установка атрибута `#[start]`, как описано [здесь] (https://doc.rust-lang.org/1.16.0/book/no-stdlib.html), вероятно, будет идеей получше.
</details>
## Итоги {#summary}
Минимальный независимый исполняемый бинарный файл Rust выглядит примерно так:
`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;
#[unsafe(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
```
Чтобы собрать этот исполняемый файл, его надо скомпилировать для голого железа, например, `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"
```
Обратите внимание, что это лишь минимальный пример независимого бинарного файла Rust. Этот бинарник ожидает различных вещей, например, инициализацию стека при вызове функции `_start`. **Поэтому для любого реального использования такого бинарного файла потребуется совершить еще больше действий**.
## Что дальше?
В [следующем посте][next post] описаны шаги, необходимые для превращения нашего независимого бинарного файла в минимальное ядро операционной системы. Сюда входит создание custom target, объединение нашего исполняемого файла с загрузчиком и изучение, как вывести что-то на экран.
[next post]: @/edition-2/posts/02-minimal-rust-kernel/index.ru.md

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