Merge branch 'main' into edition-3

This commit is contained in:
Philipp Oppermann
2023-07-08 13:21:06 +02:00
18 changed files with 55 additions and 63 deletions

View File

@@ -51,6 +51,9 @@ translation_contributors = "With contributions from"
word_separator = "and" word_separator = "and"
# Chinese (simplified) # 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] [languages.zh-CN.translations]
lang_name = "Chinese (simplified)" lang_name = "Chinese (simplified)"
toc = "目录" toc = "目录"
@@ -66,6 +69,9 @@ translation_contributors = "With contributions from"
word_separator = "和" word_separator = "和"
# Chinese (traditional) # 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] [languages.zh-TW.translations]
lang_name = "Chinese (traditional)" lang_name = "Chinese (traditional)"
toc = "目錄" toc = "目錄"
@@ -81,6 +87,9 @@ translation_contributors = "With contributions from"
word_separator = "和" word_separator = "和"
# Japanese # 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] [languages.ja.translations]
lang_name = "Japanese" lang_name = "Japanese"
toc = "目次" toc = "目次"
@@ -96,6 +105,9 @@ translation_contributors = "With contributions from"
word_separator = "及び" word_separator = "及び"
# Persian # 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] [languages.fa.translations]
lang_name = "Persian" lang_name = "Persian"
toc = "فهرست مطالب" toc = "فهرست مطالب"
@@ -111,6 +123,9 @@ translation_contributors = "With contributions from"
word_separator = "و" word_separator = "و"
# Russian # 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] [languages.ru.translations]
lang_name = "Russian" lang_name = "Russian"
toc = "Содержание" toc = "Содержание"
@@ -126,6 +141,9 @@ translation_contributors = "With contributions from"
word_separator = "и" word_separator = "и"
# French # 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] [languages.fr.translations]
lang_name = "French" lang_name = "French"
toc = "Table des matières" toc = "Table des matières"
@@ -141,6 +159,9 @@ translation_contributors = "With contributions from"
word_separator = "et" word_separator = "et"
# Korean # 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] [languages.ko.translations]
lang_name = "Korean" lang_name = "Korean"
toc = "목차" toc = "목차"

View File

@@ -1,5 +1,5 @@
+++ +++
title = "Un binaire Rust autonome" title = "Un binaire Rust autoporté"
weight = 1 weight = 1
path = "fr/freestanding-rust-binary" path = "fr/freestanding-rust-binary"
date = 2018-02-10 date = 2018-02-10
@@ -29,7 +29,7 @@ Ce blog est développé sur [GitHub]. Si vous avez un problème ou une question,
## Introduction ## 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. 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]. 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/ [option]: https://doc.rust-lang.org/core/option/
[result]:https://doc.rust-lang.org/core/result/ [result]:https://doc.rust-lang.org/core/result/
@@ -47,18 +47,18 @@ Cet article décrit les étapes nécessaires pour créer un exécutable Rust aut
## Désactiver la Bibliothèque Standard ## Désactiver la Bibliothèque Standard
Par défaut, tous les crates Rust relient la [bibliothèque standard], qui dépend du système d'exploitation pour les fonctionnalités telles que les fils d'exécution, les fichiers ou le réseau. Elle dépend aussi de la bibliothèque standard de C `libc`, qui intéragit de près avec les services de 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`]. 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/ [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 [attribut `no std`]: https://doc.rust-lang.org/1.30.0/book/first-edition/using-rust-without-the-standard-library.html
Nous commencons par créer un nouveau projet d'application cargo. La manière la plus simple de faire est avec la ligne de commande : 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 cargo new blog_os --bin --edition 2018
``` ```
J'ai nommé le projet `blog_os`, mais vous pouvez bien-sûr 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 : 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 [édition 2018]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/index.html
@@ -75,7 +75,7 @@ Le fichier `Cargo.toml` contient la configuration de la crate, par exemple le no
### L'Attribut `no_std` ### L'Attribut `no_std`
Pour l'instant, notre crate relie la bilbiothèque standard implicitement. Désactivons cela en ajoutant 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 ```rust
// main.rs // main.rs

View File

@@ -383,7 +383,7 @@ error: linking with `cc` failed: exit code: 1
cargo rustc -- -C link-args="-e __start" cargo rustc -- -C link-args="-e __start"
``` ```
`-e` 表示口點的函式名稱,然後由於 macOS 上所有的函式都會加上前綴 `_`,我們需要設置入口點為 `__start` 而不是 `_start` `-e` 表示口點的函式名稱,然後由於 macOS 上所有的函式都會加上前綴 `_`,我們需要設置入口點為 `__start` 而不是 `_start`
接下來會出現另一個連結器錯誤: 接下來會出現另一個連結器錯誤:

View File

@@ -323,7 +323,7 @@ build-std-features = ["compiler-builtins-mem"]
در پشت صحنه، این پرچم [ویژگی `mem`] از کریت `compiler_builtins` را فعال می‌کند. اثرش این است که صفت `[no_mangle]#` بر روی [پیاده‌سازی `memcpy` و بقیه موارد] از کریت اعمال می‌شود، که آن‌ها در دسترس لینکر قرار می‌دهد. شایان ذکر است که این توابع در حال حاضر [بهینه نشده‌اند]، بنابراین ممکن است عملکرد آ‌ن‌ها در بهترین حالت نباشد، اما حداقل صحیح هستند. برای `x86_64` ، یک pull request باز برای [بهینه سازی این توابع با استفاده از دستورالعمل‌های خاص اسمبلی][memcpy rep movsb] وجود دارد. در پشت صحنه، این پرچم [ویژگی `mem`] از کریت `compiler_builtins` را فعال می‌کند. اثرش این است که صفت `[no_mangle]#` بر روی [پیاده‌سازی `memcpy` و بقیه موارد] از کریت اعمال می‌شود، که آن‌ها در دسترس لینکر قرار می‌دهد. شایان ذکر است که این توابع در حال حاضر [بهینه نشده‌اند]، بنابراین ممکن است عملکرد آ‌ن‌ها در بهترین حالت نباشد، اما حداقل صحیح هستند. برای `x86_64` ، یک pull request باز برای [بهینه سازی این توابع با استفاده از دستورالعمل‌های خاص اسمبلی][memcpy rep movsb] وجود دارد.
[ویژگی `mem`]: https://github.com/rust-lang/compiler-builtins/blob/eff506cd49b637f1ab5931625a33cef7e91fbbf6/Cargo.toml#L51-L52 [ویژگی `mem`]: https://github.com/rust-lang/compiler-builtins/blob/eff506cd49b637f1ab5931625a33cef7e91fbbf6/Cargo.toml#L51-L52
[پیاده‌سازی `memcpy` و بقیه موارد]: (https://github.com/rust-lang/compiler-builtins/blob/eff506cd49b637f1ab5931625a33cef7e91fbbf6/src/mem.rs#L12-L69) [پیاده‌سازی `memcpy` و بقیه موارد]: https://github.com/rust-lang/compiler-builtins/blob/eff506cd49b637f1ab5931625a33cef7e91fbbf6/src/mem.rs#L12-L69
[بهینه نشده‌اند]: https://github.com/rust-lang/compiler-builtins/issues/339 [بهینه نشده‌اند]: https://github.com/rust-lang/compiler-builtins/issues/339
[memcpy rep movsb]: https://github.com/rust-lang/compiler-builtins/pull/365 [memcpy rep movsb]: https://github.com/rust-lang/compiler-builtins/pull/365

View File

@@ -317,7 +317,7 @@ build-std-features = ["compiler-builtins-mem"]
このとき、裏で`compiler_builtins`クレートの[`mem`機能][`mem` feature]が有効化されています。これにより、このクレートの[`memcpy`などの実装][`memcpy` etc. implementations]に`#[no_mangle]`アトリビュートが適用され、リンカがこれらを利用できるようになっています。 このとき、裏で`compiler_builtins`クレートの[`mem`機能][`mem` feature]が有効化されています。これにより、このクレートの[`memcpy`などの実装][`memcpy` etc. implementations]に`#[no_mangle]`アトリビュートが適用され、リンカがこれらを利用できるようになっています。
[`mem` feature]: https://github.com/rust-lang/compiler-builtins/blob/eff506cd49b637f1ab5931625a33cef7e91fbbf6/Cargo.toml#L51-L52 [`mem` feature]: https://github.com/rust-lang/compiler-builtins/blob/eff506cd49b637f1ab5931625a33cef7e91fbbf6/Cargo.toml#L51-L52
[`memcpy` etc. implementations]: (https://github.com/rust-lang/compiler-builtins/blob/eff506cd49b637f1ab5931625a33cef7e91fbbf6/src/mem.rs#L12-L69) [`memcpy` etc. implementations]: https://github.com/rust-lang/compiler-builtins/blob/eff506cd49b637f1ab5931625a33cef7e91fbbf6/src/mem.rs#L12-L69
この変更をもって、私達のカーネルはコンパイラに必要とされているすべての関数の有効な実装を手に入れたので、コードがもっと複雑になっても変わらずコンパイルできるでしょう。 この変更をもって、私達のカーネルはコンパイラに必要とされているすべての関数の有効な実装を手に入れたので、コードがもっと複雑になっても変わらずコンパイルできるでしょう。

View File

@@ -99,7 +99,7 @@ UEFI 표준으로 동작하는 최신 기기들도 가상 BIOS를 지원하기
지난 포스트에서 우리는 `cargo`를 통해 freestanding 실행파일을 만들었었는데, 호스트 시스템의 운영체제에 따라 프로그램 실행 시작 지점의 이름 및 컴파일 인자들을 다르게 설정해야 했습니다. 이것은 `cargo`가 기본적으로 _호스트 시스템_ (여러 분이 실행 중인 컴퓨터 시스템) 을 목표로 빌드하기 때문이었습니다. 우리의 커널은 다른 운영체제 (예를 들어 Windows) 위에서 실행될 것이 아니기에, 호스트 시스템에 설정 값을 맞추는 대신에 우리가 명확히 정의한 _목표 시스템 (target system)_ 을 목표로 컴파일할 것입니다. 지난 포스트에서 우리는 `cargo`를 통해 freestanding 실행파일을 만들었었는데, 호스트 시스템의 운영체제에 따라 프로그램 실행 시작 지점의 이름 및 컴파일 인자들을 다르게 설정해야 했습니다. 이것은 `cargo`가 기본적으로 _호스트 시스템_ (여러 분이 실행 중인 컴퓨터 시스템) 을 목표로 빌드하기 때문이었습니다. 우리의 커널은 다른 운영체제 (예를 들어 Windows) 위에서 실행될 것이 아니기에, 호스트 시스템에 설정 값을 맞추는 대신에 우리가 명확히 정의한 _목표 시스템 (target system)_ 을 목표로 컴파일할 것입니다.
### Rust Nightly 설치하기 {#installing-rust-nightly} ### Rust Nightly 설치하기 {#installing-rust-nightly}
Rust는 _stable_, _beta_ 그리고 _nightly_ 이렇게 세 가지의 채널을 통해 배포됩니다. Rust Book에 [세 채널들 간의 차이에 대해 잘 정리한 챕터]((https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#choo-choo-release-channels-and-riding-the-trains))가 있습니다. 운영체제를 빌드하기 위해서는 _nightly_ 채널에서만 제공하는 실험적인 기능들을 이용해야 하기에 _nightly_ 버전의 Rust를 설치하셔야 합니다. Rust는 _stable_, _beta_ 그리고 _nightly_ 이렇게 세 가지의 채널을 통해 배포됩니다. Rust Book에 [세 채널들 간의 차이에 대해 잘 정리한 챕터](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#choo-choo-release-channels-and-riding-the-trains)가 있습니다. 운영체제를 빌드하기 위해서는 _nightly_ 채널에서만 제공하는 실험적인 기능들을 이용해야 하기에 _nightly_ 버전의 Rust를 설치하셔야 합니다.
여러 버전의 Rust 언어 설치 파일들을 관리할 때 [rustup]을 사용하는 것을 강력 추천합니다. rustup을 통해 nightly, beta 그리고 stable 컴파일러들을 모두 설치하고 업데이트할 수 있습니다. `rustup override set nightly` 명령어를 통해 현재 디렉토리에서 항상 nightly 버전의 Rust를 사용하도록 설정할 수 있습니다. 여러 버전의 Rust 언어 설치 파일들을 관리할 때 [rustup]을 사용하는 것을 강력 추천합니다. rustup을 통해 nightly, beta 그리고 stable 컴파일러들을 모두 설치하고 업데이트할 수 있습니다. `rustup override set nightly` 명령어를 통해 현재 디렉토리에서 항상 nightly 버전의 Rust를 사용하도록 설정할 수 있습니다.
`rust-toolchain`이라는 파일을 프로젝트 루트 디렉토리에 만들고 이 파일에 `nightly`라는 텍스트를 적어 놓아도 같은 효과를 볼 수 있습니다. `rustc --version` 명령어를 통해 현재 nightly 버전이 설치되어 있는지 확인할 수 있습니다 (출력되는 버전 넘버가 `-nightly`라는 텍스트로 끝나야 합니다). `rust-toolchain`이라는 파일을 프로젝트 루트 디렉토리에 만들고 이 파일에 `nightly`라는 텍스트를 적어 놓아도 같은 효과를 볼 수 있습니다. `rustc --version` 명령어를 통해 현재 nightly 버전이 설치되어 있는지 확인할 수 있습니다 (출력되는 버전 넘버가 `-nightly`라는 텍스트로 끝나야 합니다).

View File

@@ -49,7 +49,7 @@ pub extern "C" fn _start() -> ! {
// trigger a page fault // trigger a page fault
unsafe { unsafe {
*(0xdeadbeef as *mut u64) = 42; *(0xdeadbeef as *mut u8) = 42;
}; };
// as before // as before

View File

@@ -45,7 +45,7 @@ pub extern "C" fn _start() -> ! {
// ページフォルトを起こす // ページフォルトを起こす
unsafe { unsafe {
*(0xdeadbeef as *mut u64) = 42; *(0xdeadbeef as *mut u8) = 42;
}; };
// 前回同様 // 前回同様

View File

@@ -48,7 +48,7 @@ pub extern "C" fn _start() -> ! {
// 페이지 폴트 일으키기 // 페이지 폴트 일으키기
unsafe { unsafe {
*(0xdeadbeef as *mut u64) = 42; *(0xdeadbeef as *mut u8) = 42;
}; };
// 이전과 동일 // 이전과 동일

View File

@@ -42,7 +42,7 @@ pub extern "C" fn _start() -> ! {
// trigger a page fault // trigger a page fault
unsafe { unsafe {
*(0xdeadbeef as *mut u64) = 42; *(0xdeadbeef as *mut u8) = 42;
}; };
// as before // as before
@@ -374,9 +374,9 @@ pub fn init() {
} }
``` ```
We reload the code segment register using [`set_cs`] and load the TSS using [`load_tss`]. The functions are marked as `unsafe`, so we need an `unsafe` block to invoke them. The reason is that it might be possible to break memory safety by loading invalid selectors. We reload the code segment register using [`CS::set_reg`] and load the TSS using [`load_tss`]. The functions are marked as `unsafe`, so we need an `unsafe` block to invoke them. The reason is that it might be possible to break memory safety by loading invalid selectors.
[`set_cs`]: https://docs.rs/x86_64/0.14.2/x86_64/instructions/segmentation/fn.set_cs.html [`CS::set_reg`]: https://docs.rs/x86_64/0.14.5/x86_64/instructions/segmentation/struct.CS.html#method.set_reg
[`load_tss`]: https://docs.rs/x86_64/0.14.2/x86_64/instructions/tables/fn.load_tss.html [`load_tss`]: https://docs.rs/x86_64/0.14.2/x86_64/instructions/tables/fn.load_tss.html
Now that we have loaded a valid TSS and interrupt stack table, we can set the stack index for our double fault handler in the IDT: Now that we have loaded a valid TSS and interrupt stack table, we can set the stack index for our double fault handler in the IDT:

View File

@@ -47,7 +47,7 @@ pub extern "C" fn _start() -> ! {
// trigger a page fault // trigger a page fault
unsafe { unsafe {
*(0xdeadbeef as *mut u64) = 42; *(0xdeadbeef as *mut u8) = 42;
}; };
// as before // as before

View File

@@ -322,7 +322,7 @@ pub extern "C" fn _start() -> ! {
blog_os::init(); blog_os::init();
// new // new
let ptr = 0xdeadbeaf as *mut u32; let ptr = 0xdeadbeaf as *mut u8;
unsafe { *ptr = 42; } unsafe { *ptr = 42; }
// as before // as before
@@ -347,7 +347,7 @@ pub extern "C" fn _start() -> ! {
```rust ```rust
// Note: The actual address might be different for you. Use the address that // Note: The actual address might be different for you. Use the address that
// your page fault handler reports. // your page fault handler reports.
let ptr = 0x2031b2 as *mut u32; let ptr = 0x2031b2 as *mut u8;
// read from a code page // read from a code page
unsafe { let x = *ptr; } unsafe { let x = *ptr; }

View File

@@ -329,7 +329,7 @@ pub extern "C" fn _start() -> ! {
blog_os::init(); blog_os::init();
// ここを追加 // ここを追加
let ptr = 0xdeadbeaf as *mut u32; let ptr = 0xdeadbeaf as *mut u8;
unsafe { *ptr = 42; } unsafe { *ptr = 42; }
// ここはこれまでと同じ // ここはこれまでと同じ
@@ -354,7 +354,7 @@ pub extern "C" fn _start() -> ! {
```rust ```rust
// 注意:実際のアドレスは個々人で違うかもしれません。 // 注意:実際のアドレスは個々人で違うかもしれません。
// あなたのページフォルトハンドラが報告した値を使ってください。 // あなたのページフォルトハンドラが報告した値を使ってください。
let ptr = 0x2031b2 as *mut u32; let ptr = 0x2031b2 as *mut u8;
// コードページから読み込む // コードページから読み込む
unsafe { let x = *ptr; } unsafe { let x = *ptr; }

View File

@@ -316,7 +316,7 @@ pub extern "C" fn _start() -> ! {
blog_os::init(); blog_os::init();
// new // new
let ptr = 0xdeadbeaf as *mut u32; let ptr = 0xdeadbeaf as *mut u8;
unsafe { *ptr = 42; } unsafe { *ptr = 42; }
// as before // as before
@@ -341,7 +341,7 @@ We see that the current instruction pointer is `0x2031b2`, so we know that this
```rust ```rust
// Note: The actual address might be different for you. Use the address that // Note: The actual address might be different for you. Use the address that
// your page fault handler reports. // your page fault handler reports.
let ptr = 0x2031b2 as *mut u32; let ptr = 0x2031b2 as *mut u8;
// read from a code page // read from a code page
unsafe { let x = *ptr; } unsafe { let x = *ptr; }

View File

@@ -325,7 +325,7 @@ pub extern "C" fn _start() -> ! {
blog_os::init(); blog_os::init();
// new // new
let ptr = 0xdeadbeaf as *mut u32; let ptr = 0xdeadbeaf as *mut u8;
unsafe { *ptr = 42; } unsafe { *ptr = 42; }
// as before // as before
@@ -350,7 +350,7 @@ pub extern "C" fn _start() -> ! {
```rust ```rust
// Note: The actual address might be different for you. Use the address that // Note: The actual address might be different for you. Use the address that
// your page fault handler reports. // your page fault handler reports.
let ptr = 0x2031b2 as *mut u32; let ptr = 0x2031b2 as *mut u8;
// read from a code page // read from a code page
unsafe { let x = *ptr; } unsafe { let x = *ptr; }

View File

@@ -214,7 +214,7 @@ Since we are compiling for a custom target, we can't use the precompiled version
[unstable] [unstable]
build-std = ["core", "compiler_builtins", "alloc"] build-std = ["core", "compiler_builtins", "alloc"]
```` ```
Now the compiler will recompile and include the `alloc` crate in our kernel. Now the compiler will recompile and include the `alloc` crate in our kernel.
@@ -223,18 +223,12 @@ The reason that the `alloc` crate is disabled by default in `#[no_std]` crates i
``` ```
error: no global memory allocator found but one is required; link to std or add error: no global memory allocator found but one is required; link to std or add
#[global_allocator] to a static item that implements the GlobalAlloc trait. #[global_allocator] to a static item that implements the GlobalAlloc trait.
error: `#[alloc_error_handler]` function required, but not found
``` ```
The first error occurs because the `alloc` crate requires a heap allocator, which is an object that provides the `allocate` and `deallocate` functions. In Rust, heap allocators are described by the [`GlobalAlloc`] trait, which is mentioned in the error message. To set the heap allocator for the crate, the `#[global_allocator]` attribute must be applied to a `static` variable that implements the `GlobalAlloc` trait. The error occurs because the `alloc` crate requires a heap allocator, which is an object that provides the `allocate` and `deallocate` functions. In Rust, heap allocators are described by the [`GlobalAlloc`] trait, which is mentioned in the error message. To set the heap allocator for the crate, the `#[global_allocator]` attribute must be applied to a `static` variable that implements the `GlobalAlloc` trait.
The second error occurs because calls to `allocate` can fail, most commonly when there is no more memory available. Our program must be able to react to this case, which is what the `#[alloc_error_handler]` function is for.
[`GlobalAlloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html [`GlobalAlloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html
We will describe these traits and attributes in detail in the following sections.
### The `GlobalAlloc` Trait ### The `GlobalAlloc` Trait
The [`GlobalAlloc`] trait defines the functions that a heap allocator must provide. The trait is special because it is almost never used directly by the programmer. Instead, the compiler will automatically insert the appropriate calls to the trait methods when using the allocation and collection types of `alloc`. The [`GlobalAlloc`] trait defines the functions that a heap allocator must provide. The trait is special because it is almost never used directly by the programmer. Instead, the compiler will automatically insert the appropriate calls to the trait methods when using the allocation and collection types of `alloc`.
@@ -329,32 +323,7 @@ static ALLOCATOR: Dummy = Dummy;
Since the `Dummy` allocator is a [zero-sized type], we don't need to specify any fields in the initialization expression. Since the `Dummy` allocator is a [zero-sized type], we don't need to specify any fields in the initialization expression.
When we now try to compile it, the first error should be gone. Let's fix the remaining second error: With this static, the compilation errors should be fixed. Now we can use the allocation and collection types of `alloc`. For example, we can use a [`Box`] to allocate a value on the heap:
```
error: `#[alloc_error_handler]` function required, but not found
```
### The `#[alloc_error_handler]` Attribute
As we learned when discussing the `GlobalAlloc` trait, the `alloc` function can signal an allocation error by returning a null pointer. The question is: how should the Rust runtime react to such an allocation failure? This is where the `#[alloc_error_handler]` attribute comes in. It specifies a function that is called when an allocation error occurs, similar to how our panic handler is called when a panic occurs.
Let's add such a function to fix the compilation error:
```rust
// in src/lib.rs
#![feature(alloc_error_handler)] // at the top of the file
#[alloc_error_handler]
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
panic!("allocation error: {:?}", layout)
}
```
The `alloc_error_handler` function is still unstable, so we need a feature gate to enable it. The function receives a single argument: the `Layout` instance that was passed to `alloc` when the allocation failure occurred. There's nothing we can do to resolve the failure, so we just panic with a message that contains the `Layout` instance.
With this function, the compilation errors should be fixed. Now we can use the allocation and collection types of `alloc`. For example, we can use a [`Box`] to allocate a value on the heap:
[`Box`]: https://doc.rust-lang.org/alloc/boxed/struct.Box.html [`Box`]: https://doc.rust-lang.org/alloc/boxed/struct.Box.html
@@ -380,11 +349,11 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
Note that we need to specify the `extern crate alloc` statement in our `main.rs` too. This is required because the `lib.rs` and `main.rs` parts are treated as separate crates. However, we don't need to create another `#[global_allocator]` static because the global allocator applies to all crates in the project. In fact, specifying an additional allocator in another crate would be an error. Note that we need to specify the `extern crate alloc` statement in our `main.rs` too. This is required because the `lib.rs` and `main.rs` parts are treated as separate crates. However, we don't need to create another `#[global_allocator]` static because the global allocator applies to all crates in the project. In fact, specifying an additional allocator in another crate would be an error.
When we run the above code, we see that our `alloc_error_handler` function is called: When we run the above code, we see that a panic occurs:
![QEMU printing "panicked at `allocation error: Layout { size_: 4, align_: 4 }, src/lib.rs:89:5"](qemu-dummy-output.png) ![QEMU printing "panicked at `allocation error: Layout { size_: 4, align_: 4 }, src/lib.rs:89:5"](qemu-dummy-output.png)
The error handler is called because the `Box::new` function implicitly calls the `alloc` function of the global allocator. Our dummy allocator always returns a null pointer, so every allocation fails. To fix this, we need to create an allocator that actually returns usable memory. The panic occurs because the `Box::new` function implicitly calls the `alloc` function of the global allocator. Our dummy allocator always returns a null pointer, so every allocation fails. To fix this, we need to create an allocator that actually returns usable memory.
## Creating a Kernel Heap ## Creating a Kernel Heap

View File

@@ -58,7 +58,7 @@ translation_contributors = ["asami-kawasaki", "Foo-x"]
[コールスタック]: https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%BC%E3%83%AB%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF [コールスタック]: https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%BC%E3%83%AB%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF
[コンテキスト・スイッチ (context switch)]: https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%B9%E3%82%A4%E3%83%83%E3%83%81 [コンテキスト・スイッチ (context switch)]: https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%B9%E3%82%A4%E3%83%83%E3%83%81
コールスタックは非常に大きくなる可能性があるため、OSは通常、各タスクのスイッチでコールスタックの内容をバックアップする代わりに、各タスクに個別のコールスタックを設定します。このような独立したスタックを持つタスクは、[_thread of execution_](略して**スレッド**)と呼ばれます。タスクごとに独立したスタックを使用することで、コンテキスト・スイッチの際に保存する必要があるのはレジスタの内容だけになります(プログラム・カウンタとスタック・ポインタを含む)。この方法を取ることで、コンテキスト・スイッチの性能上のオーバーヘッドが最小限になります。これは、コンテキスト・スイッチが1秒間に100回も行われることがあるため、非常に重要なことです。 コールスタックは非常に大きくなる可能性があるため、OSは通常、各タスクのスイッチでコールスタックの内容をバックアップする代わりに、各タスクに個別のコールスタックを設定します。このような独立したスタックを持つタスクは、[略して**スレッド**][_thread of execution_]と呼ばれます。タスクごとに独立したスタックを使用することで、コンテキスト・スイッチの際に保存する必要があるのはレジスタの内容だけになります(プログラム・カウンタとスタック・ポインタを含む)。この方法を取ることで、コンテキスト・スイッチの性能上のオーバーヘッドが最小限になります。これは、コンテキスト・スイッチが1秒間に100回も行われることがあるため、非常に重要なことです。
[_thread of execution_]: https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89_(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF) [_thread of execution_]: https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89_(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF)

View File

@@ -10,9 +10,11 @@
{% macro giscus(search_term, lang) %} {% macro giscus(search_term, lang) %}
{% if lang != "en" %} {% if lang != "en" %}
{% set category = "Post Comments (translated)" %} {% set category = "Post Comments (translated)" %}
{% set category_id = "DIC_kwDOAlvePc4CPg4c" %}
{% set category_path = "post-comments-translated" %} {% set category_path = "post-comments-translated" %}
{% else %} {% else %}
{% set category = "Post Comments" %} {% set category = "Post Comments" %}
{% set category_id = "MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMzMDE4OTg1" %}
{% set category_path = "post-comments" %} {% set category_path = "post-comments" %}
{% endif %} {% endif %}
@@ -33,7 +35,7 @@
data-repo="phil-opp/blog_os" data-repo="phil-opp/blog_os"
data-repo-id="MDEwOlJlcG9zaXRvcnkzOTU3NTEwMQ==" data-repo-id="MDEwOlJlcG9zaXRvcnkzOTU3NTEwMQ=="
data-category="{{ category }}" data-category="{{ category }}"
data-category-id="MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMzMDE4OTg1" data-category-id="{{ category_id }}"
{% if search_term is number %} {% if search_term is number %}
data-mapping="number" data-mapping="number"
{% else %} {% else %}