mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-17 23:07:50 +00:00
Update some broken anchor links (#1444)
This commit is contained in:
committed by
GitHub
parent
86c36479cf
commit
211f460251
@@ -251,7 +251,7 @@ pub fn print_something() {
|
||||
```
|
||||
Primero crea un nuevo Writer que apunta al buffer VGA en `0xb8000`. La sintaxis para esto podría parecer un poco extraña: Primero, convertimos el entero `0xb8000` como un [puntero sin procesar] mutable. Luego lo convertimos en una referencia mutable al desreferenciarlo (a través de `*`) y tomarlo prestado inmediatamente (a través de `&mut`). Esta conversión requiere un [bloque `unsafe`], ya que el compilador no puede garantizar que el puntero sin procesar sea válido.
|
||||
|
||||
[puntero sin procesar]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
||||
[puntero sin procesar]: https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
||||
[bloque `unsafe`]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
|
||||
|
||||
Luego escribe el byte `b'H'` en él. El prefijo `b` crea un [literal de byte], que representa un carácter ASCII. Al escribir las cadenas `"ello "` y `"Wörld!"`, probamos nuestro método `write_string` y el manejo de caracteres no imprimibles. Para ver la salida, necesitamos llamar a la función `print_something` desde nuestra función `_start`:
|
||||
|
||||
@@ -31,12 +31,12 @@ rtl = true
|
||||
## بافر متن VGA
|
||||
برای چاپ یک کاراکتر روی صفحه در حالت متن VGA ، باید آن را در بافر متن سخت افزار VGA بنویسید. بافر متن VGA یک آرایه دو بعدی است که به طور معمول 25 ردیف و 80 ستون دارد که مستقیماً به صفحه نمایش داده(رندر) می شود. هر خانه آرایه یک کاراکتر صفحه نمایش را از طریق قالب زیر توصیف می کند:
|
||||
|
||||
Bit(s) | Value
|
||||
------ | ----------------
|
||||
0-7 | ASCII code point
|
||||
8-11 | Foreground color
|
||||
12-14 | Background color
|
||||
15 | Blink
|
||||
| Bit(s) | Value |
|
||||
| ------ | ---------------- |
|
||||
| 0-7 | ASCII code point |
|
||||
| 8-11 | Foreground color |
|
||||
| 12-14 | Background color |
|
||||
| 15 | Blink |
|
||||
|
||||
اولین بایت کاراکتری در [کدگذاری ASCII] را نشان می دهد که باید چاپ شود. اگر بخواهیم دقیق باشیم ، دقیقاً ASCII نیست ، بلکه مجموعه ای از کاراکترها به نام [_کد صفحه 437_] با برخی کاراکتر های اضافی و تغییرات جزئی است. برای سادگی ، ما در این پست آنرا یک کاراکتر ASCII می نامیم.
|
||||
|
||||
@@ -45,16 +45,16 @@ Bit(s) | Value
|
||||
|
||||
بایت دوم نحوه نمایش کاراکتر را مشخص می کند. چهار بیت اول رنگ پیش زمینه را مشخص می کند ، سه بیت بعدی رنگ پس زمینه و بیت آخر اینکه کاراکتر باید چشمک بزند یا نه. رنگ های زیر موجود است:
|
||||
|
||||
Number | Color | Number + Bright Bit | Bright Color
|
||||
------ | ---------- | ------------------- | -------------
|
||||
0x0 | Black | 0x8 | Dark Gray
|
||||
0x1 | Blue | 0x9 | Light Blue
|
||||
0x2 | Green | 0xa | Light Green
|
||||
0x3 | Cyan | 0xb | Light Cyan
|
||||
0x4 | Red | 0xc | Light Red
|
||||
0x5 | Magenta | 0xd | Pink
|
||||
0x6 | Brown | 0xe | Yellow
|
||||
0x7 | Light Gray | 0xf | White
|
||||
| Number | Color | Number + Bright Bit | Bright Color |
|
||||
| ------ | ---------- | ------------------- | ------------ |
|
||||
| 0x0 | Black | 0x8 | Dark Gray |
|
||||
| 0x1 | Blue | 0x9 | Light Blue |
|
||||
| 0x2 | Green | 0xa | Light Green |
|
||||
| 0x3 | Cyan | 0xb | Light Cyan |
|
||||
| 0x4 | Red | 0xc | Light Red |
|
||||
| 0x5 | Magenta | 0xd | Pink |
|
||||
| 0x6 | Brown | 0xe | Yellow |
|
||||
| 0x7 | Light Gray | 0xf | White |
|
||||
|
||||
بیت 4، بیت روشنایی است ، که به عنوان مثال آبی به آبی روشن تبدیل میکند. برای رنگ پس زمینه ، این بیت به عنوان بیت چشمک مورد استفاده قرار می گیرد.
|
||||
|
||||
@@ -264,7 +264,7 @@ pub fn print_something() {
|
||||
```
|
||||
ابتدا یک Writer جدید ایجاد می کند که به بافر VGA در `0xb8000` اشاره دارد. سینتکس این ممکن است کمی عجیب به نظر برسد: اول ، ما عدد صحیح `0xb8000` را به عنوان [اشاره گر خام] قابل تغییر در نظر می گیریم. سپس با dereferencing کردن آن (از طریق "*") و بلافاصله ارجاع مجدد (از طریق `&mut`) آن را به یک مرجع قابل تغییر تبدیل می کنیم. این تبدیل به یک [بلوک `غیرایمن`] احتیاج دارد ، زیرا کامپایلر نمی تواند صحت اشارهگر خام را تضمین کند.
|
||||
|
||||
[اشاره گر خام]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
||||
[اشاره گر خام]: https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
||||
[بلوک `غیرایمن`]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
|
||||
|
||||
سپس بایت `b'H'` را روی آن می نویسد. پیشوند `b` یک [بایت لیترال] ایجاد می کند ، که بیانگر یک کاراکتر ASCII است. با نوشتن رشته های `"ello "` و `"Wörld!"` ، ما متد `write_string` و واکنش به کاراکترهای غیر قابل چاپ را آزمایش می کنیم. برای دیدن خروجی ، باید تابع `print_something` را از تابع `_start` فراخوانی کنیم:
|
||||
@@ -525,7 +525,7 @@ lazy_static! {
|
||||
|
||||
با این حال ، این `WRITER` بسیار بی فایده است زیرا غیر قابل تغییر است. این بدان معنی است که ما نمی توانیم چیزی در آن بنویسیم (از آنجا که همه متد های نوشتن `&mut self` را در ورودی میگیرند). یک راه حل ممکن استفاده از [استاتیک قابل تغییر] است. اما پس از آن هر خواندن و نوشتن آن ناامن (unsafe) است زیرا می تواند به راحتی باعث data race و سایر موارد بد باشد. استفاده از `static mut` بسیار نهی شده است ، حتی پیشنهادهایی برای [حذف آن][remove static mut] وجود داشت. اما گزینه های دیگر چیست؟ ما می توانیم سعی کنیم از یک استاتیک تغییرناپذیر با نوع سلول مانند [RefCell] یا حتی [UnsafeCell] استفاده کنیم که [تغییر پذیری داخلی] را فراهم می کند. اما این انواع [Sync] نیستند (با دلیل کافی) ، بنابراین نمی توانیم از آنها در استاتیک استفاده کنیم.
|
||||
|
||||
[استاتیک قابل تغییر]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable
|
||||
[استاتیک قابل تغییر]: https://doc.rust-lang.org/book/ch20-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
|
||||
[RefCell]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#keeping-track-of-borrows-at-runtime-with-refcellt
|
||||
[UnsafeCell]: https://doc.rust-lang.org/nightly/core/cell/struct.UnsafeCell.html
|
||||
@@ -584,7 +584,7 @@ pub extern "C" fn _start() -> ! {
|
||||
### یک ماکروی println
|
||||
اکنون که یک نویسنده گلوبال داریم ، می توانیم یک ماکرو `println` اضافه کنیم که می تواند از هر کجا در کد استفاده شود. [سینتکس ماکروی] راست کمی عجیب است ، بنابراین ما سعی نمی کنیم ماکرو را از ابتدا بنویسیم. در عوض به سورس [ماکروی `println!`] در کتابخانه استاندارد نگاه می کنیم:
|
||||
|
||||
[سینتکس ماکروی]: https://doc.rust-lang.org/nightly/book/ch19-06-macros.html#declarative-macros-with-macro_rules-for-general-metaprogramming
|
||||
[سینتکس ماکروی]: https://doc.rust-lang.org/nightly/book/ch20-05-macros.html#declarative-macros-for-general-metaprogramming
|
||||
[ماکروی `println!`]: https://doc.rust-lang.org/nightly/std/macro.println!.html
|
||||
|
||||
```rust
|
||||
|
||||
@@ -30,12 +30,12 @@ translators = ["swnakamura", "JohnTitor"]
|
||||
## VGAテキストバッファ
|
||||
VGAテキストモードにおいて、文字を画面に出力するには、VGAハードウェアのテキストバッファにそれを書き込まないといけません。VGAテキストバッファは、普通25行と80列からなる2次元配列で、画面に直接書き出されます。それぞれの配列の要素は画面上の一つの文字を以下の形式で表現しています:
|
||||
|
||||
ビット | 値
|
||||
------ | ----------------
|
||||
0-7 | ASCII コードポイント
|
||||
8-11 | フォアグラウンド(前景)色
|
||||
12-14 | バックグラウンド(背景)色
|
||||
15 | 点滅
|
||||
| ビット | 値 |
|
||||
| ------ | -------------------------- |
|
||||
| 0-7 | ASCII コードポイント |
|
||||
| 8-11 | フォアグラウンド(前景)色 |
|
||||
| 12-14 | バックグラウンド(背景)色 |
|
||||
| 15 | 点滅 |
|
||||
|
||||
最初の1バイトは、出力されるべき文字を[ASCIIエンコーディング][ASCII encoding]で表します。正確に言うと、完全にASCIIではなく、[コードページ437][_code page 437_]という、いくつか文字が追加され、軽微な修正のなされたものです。簡単のため、この記事ではASCII文字と呼ぶことにします。
|
||||
|
||||
@@ -44,16 +44,16 @@ VGAテキストモードにおいて、文字を画面に出力するには、VG
|
||||
|
||||
2つ目のバイトはその文字がどのように出力されるのかを定義します。最初の4ビットが前景色(訳注:文字自体の色)を、次の3ビットが背景色を、最後のビットがその文字が点滅するのかを決めます。以下の色を使うことができます:
|
||||
|
||||
数字 | 色 | 数字 + Bright Bit | <ruby>Bright<rp> (</rp><rt>明るい</rt><rp>) </rp></ruby> 色
|
||||
------ | ---------- | ------------------- | -------------
|
||||
0x0 | 黒 | 0x8 | 暗いグレー
|
||||
0x1 | 青 | 0x9 | 明るい青
|
||||
0x2 | 緑 | 0xa | 明るい緑
|
||||
0x3 | シアン | 0xb | 明るいシアン
|
||||
0x4 | 赤 | 0xc | 明るい赤
|
||||
0x5 | マゼンタ | 0xd | ピンク
|
||||
0x6 | 茶色 | 0xe | 黄色
|
||||
0x7 | 明るいグレー| 0xf | 白
|
||||
| 数字 | 色 | 数字 + Bright Bit | <ruby>Bright<rp> (</rp><rt>明るい</rt><rp>) </rp></ruby> 色 |
|
||||
| ---- | ------------ | ----------------- | ----------------------------------------------------------- |
|
||||
| 0x0 | 黒 | 0x8 | 暗いグレー |
|
||||
| 0x1 | 青 | 0x9 | 明るい青 |
|
||||
| 0x2 | 緑 | 0xa | 明るい緑 |
|
||||
| 0x3 | シアン | 0xb | 明るいシアン |
|
||||
| 0x4 | 赤 | 0xc | 明るい赤 |
|
||||
| 0x5 | マゼンタ | 0xd | ピンク |
|
||||
| 0x6 | 茶色 | 0xe | 黄色 |
|
||||
| 0x7 | 明るいグレー | 0xf | 白 |
|
||||
|
||||
4ビット目は **bright bit** で、これは(1になっているとき)たとえば青を明るい青に変えます。背景色については、このビットは点滅ビットとして再利用されています。
|
||||
|
||||
@@ -597,7 +597,7 @@ pub extern "C" fn _start() -> ! {
|
||||
### printlnマクロ
|
||||
大域的なwriterを手に入れたので、プログラムのどこでも使える`println`マクロを追加できます。Rustの[マクロの構文][macro syntax]はすこしややこしいので、一からマクロを書くことはしません。代わりに、標準ライブラリで[`println!`マクロ][`println!` macro]のソースを見てみます:
|
||||
|
||||
[macro syntax]: https://doc.rust-lang.org/nightly/book/ch19-06-macros.html#declarative-macros-with-macro_rules-for-general-metaprogramming
|
||||
[macro syntax]: https://doc.rust-lang.org/nightly/book/ch20-05-macros.html#declarative-macros-for-general-metaprogramming
|
||||
[`println!` macro]: https://doc.rust-lang.org/nightly/std/macro.println!.html
|
||||
|
||||
```rust
|
||||
|
||||
@@ -30,12 +30,12 @@ translators = ["JOE1994", "Quqqu"]
|
||||
## VGA 텍스트 버퍼
|
||||
VGA 텍스트 모드에서 화면에 문자를 출력하려면 VGA 하드웨어의 텍스트 버퍼에 해당 문자를 저장해야 합니다. VGA 텍스트 버퍼는 보통 25행 80열 크기의 2차원 배열이며, 해당 버퍼에 저장된 값들은 즉시 화면에 렌더링 됩니다. 배열의 각 원소는 화면에 출력될 문자를 아래의 형식으로 표현합니다:
|
||||
|
||||
비트 | 값
|
||||
------ | ----------------
|
||||
0-7 | ASCII 코드
|
||||
8-11 | 전경색
|
||||
12-14 | 배경색
|
||||
15 | 깜빡임 여부
|
||||
| 비트 | 값 |
|
||||
| ----- | ----------- |
|
||||
| 0-7 | ASCII 코드 |
|
||||
| 8-11 | 전경색 |
|
||||
| 12-14 | 배경색 |
|
||||
| 15 | 깜빡임 여부 |
|
||||
|
||||
첫 바이트는 [ASCII 인코딩][ASCII encoding]으로 출력될 문자를 나타냅니다. 엄밀히 따지자면 ASCII 인코딩이 아닌, 해당 인코딩에 문자들을 추가하고 살짝 변형한 [_code page 437_] 이라는 인코딩을 이용합니다. 설명을 간소화하기 위해 이하 본문에서는 그냥 ASCII 문자로 지칭하겠습니다.
|
||||
|
||||
@@ -44,16 +44,16 @@ VGA 텍스트 모드에서 화면에 문자를 출력하려면 VGA 하드웨어
|
||||
|
||||
두 번째 바이트는 표현하는 문자가 어떻게 표시될 것인지를 정의합니다. 두 번째 바이트의 첫 4비트는 전경색을 나타내고, 그 다음 3비트는 배경색을 나타내며, 마지막 비트는 해당 문자가 화면에서 깜빡이도록 할지 결정합니다. 아래의 색상들을 이용할 수 있습니다:
|
||||
|
||||
숫자 값 | 색상 | 색상 + 밝기 조정 비트 | 밝기 조정 후 최종 색상
|
||||
------ | ---------- | ------------------- | -------------
|
||||
0x0 | Black | 0x8 | Dark Gray
|
||||
0x1 | Blue | 0x9 | Light Blue
|
||||
0x2 | Green | 0xa | Light Green
|
||||
0x3 | Cyan | 0xb | Light Cyan
|
||||
0x4 | Red | 0xc | Light Red
|
||||
0x5 | Magenta | 0xd | Pink
|
||||
0x6 | Brown | 0xe | Yellow
|
||||
0x7 | Light Gray | 0xf | White
|
||||
| 숫자 값 | 색상 | 색상 + 밝기 조정 비트 | 밝기 조정 후 최종 색상 |
|
||||
| ------- | ---------- | --------------------- | ---------------------- |
|
||||
| 0x0 | Black | 0x8 | Dark Gray |
|
||||
| 0x1 | Blue | 0x9 | Light Blue |
|
||||
| 0x2 | Green | 0xa | Light Green |
|
||||
| 0x3 | Cyan | 0xb | Light Cyan |
|
||||
| 0x4 | Red | 0xc | Light Red |
|
||||
| 0x5 | Magenta | 0xd | Pink |
|
||||
| 0x6 | Brown | 0xe | Yellow |
|
||||
| 0x7 | Light Gray | 0xf | White |
|
||||
|
||||
두 번째 바이트의 네 번째 비트 (_밝기 조정 비트_)를 통해 파란색을 하늘색으로 조정하는 등 색의 밝기를 변경할 수 있습니다. 배경색을 지정하는 3비트 이후의 마지막 비트는 깜빡임 여부를 지정합니다.
|
||||
|
||||
@@ -263,7 +263,7 @@ pub fn print_something() {
|
||||
```
|
||||
우선 메모리 주소 `0xb8000`을 가리키는 새로운 Writer 인스턴스를 생성합니다. 이를 구현한 코드가 다소 난해하게 느껴질 수 있으니 단계별로 나누어 설명드리겠습니다: 먼저 정수 `0xb8000`을 읽기/쓰기 모두 가능한 (mutable) [포인터][raw pointer]로 타입 변환합니다. 그 후 `*` 연산자를 통해 이 포인터를 역참조 (dereference) 하고 `&mut`를 통해 즉시 borrow 함으로써 해당 주소에 저장된 값을 변경할 수 있는 레퍼런스 (mutable reference)를 만듭니다. 여기서 Rust 컴파일러는 포인터의 유효성 및 안전성을 보증할 수 없기에, [`unsafe` 블록][`unsafe` block]을 사용해야만 포인터를 레퍼런스로 변환할 수 있습니다.
|
||||
|
||||
[raw pointer]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
||||
[raw pointer]: https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
||||
[`unsafe` block]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
|
||||
|
||||
그 다음 Writer 인스턴스에 바이트 `b'H'`를 적습니다. 접두사 `b`는 ASCII 문자를 나타내는 [바이트 상수 (literal)][byte literal] 를 생성합니다. 문자열 `"ello "`와 `"Wörld!"`를 적음으로써 `write_string` 함수 및 출력 불가능한 문자에 대한 특수 처리가 잘 구현되었는지 테스트 해봅니다. 화면에 메시지가 출력되는지 확인하기 위해 `print_something` 함수를 `_start` 함수에서 호출합니다:
|
||||
@@ -524,7 +524,7 @@ lazy_static! {
|
||||
|
||||
현재 `WRITER`는 immutable (읽기 가능, 쓰기 불가능) 하여 실질적인 쓸모가 없습니다. 모든 쓰기 함수들은 첫 인자로 `&mut self`를 받기 때문에 `WRITER`로 어떤 쓰기 작업도 할 수가 없습니다. 이에 대한 해결책으로 [mutable static]은 어떨까요? 이 선택지를 고른다면 모든 읽기 및 쓰기 작업이 데이터 레이스 (data race) 및 기타 위험에 노출되기에 안전을 보장할 수 없게 됩니다. Rust에서 `static mut`는 웬만하면 사용하지 않도록 권장되며, 심지어 [Rust 언어에서 완전히 `static mut`를 제거하자는 제안][remove static mut]이 나오기도 했습니다. 이것 이외에도 대안이 있을까요? [내부 가변성 (interior mutability)][interior mutability]을 제공하는 [RefCell] 혹은 [UnsafeCell] 을 통해 immutable한 정적 변수를 만드는 것은 어떨까요? 이 타입들은 중요한 이유로 [Sync] 트레이트를 구현하지 않기에 정적 변수를 선언할 때에는 사용할 수 없습니다.
|
||||
|
||||
[mutable static]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable
|
||||
[mutable static]: https://doc.rust-lang.org/book/ch20-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
|
||||
[RefCell]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#keeping-track-of-borrows-at-runtime-with-refcellt
|
||||
[UnsafeCell]: https://doc.rust-lang.org/nightly/core/cell/struct.UnsafeCell.html
|
||||
@@ -583,7 +583,7 @@ pub extern "C" fn _start() -> ! {
|
||||
### println 매크로
|
||||
전역 변수 `Writer`도 갖추었으니 이제 프로젝트 내 어디서든 사용할 수 있는 `println` 매크로를 추가할 수 있습니다. Rust의 [매크로 문법][macro syntax]은 다소 난해하기에, 우리에게 필요한 매크로를 밑바닥부터 작성하지는 않을 것입니다. 그 대신 표준 라이브러리의 [`println!` 매크로][`println!` macro] 구현 코드를 참조할 것입니다:
|
||||
|
||||
[macro syntax]: https://doc.rust-lang.org/nightly/book/ch19-06-macros.html#declarative-macros-with-macro_rules-for-general-metaprogramming
|
||||
[macro syntax]: https://doc.rust-lang.org/nightly/book/ch20-05-macros.html#declarative-macros-for-general-metaprogramming
|
||||
[`println!` macro]: https://doc.rust-lang.org/nightly/std/macro.println!.html
|
||||
|
||||
```rust
|
||||
|
||||
@@ -27,12 +27,12 @@ This blog is openly developed on [GitHub]. If you have any problems or questions
|
||||
## The VGA Text Buffer
|
||||
To print a character to the screen in VGA text mode, one has to write it to the text buffer of the VGA hardware. The VGA text buffer is a two-dimensional array with typically 25 rows and 80 columns, which is directly rendered to the screen. Each array entry describes a single screen character through the following format:
|
||||
|
||||
Bit(s) | Value
|
||||
------ | ----------------
|
||||
0-7 | ASCII code point
|
||||
8-11 | Foreground color
|
||||
12-14 | Background color
|
||||
15 | Blink
|
||||
| Bit(s) | Value |
|
||||
| ------ | ---------------- |
|
||||
| 0-7 | ASCII code point |
|
||||
| 8-11 | Foreground color |
|
||||
| 12-14 | Background color |
|
||||
| 15 | Blink |
|
||||
|
||||
The first byte represents the character that should be printed in the [ASCII encoding]. To be more specific, it isn't exactly ASCII, but a character set named [_code page 437_] with some additional characters and slight modifications. For simplicity, we will proceed to call it an ASCII character in this post.
|
||||
|
||||
@@ -41,16 +41,16 @@ The first byte represents the character that should be printed in the [ASCII enc
|
||||
|
||||
The second byte defines how the character is displayed. The first four bits define the foreground color, the next three bits the background color, and the last bit whether the character should blink. The following colors are available:
|
||||
|
||||
Number | Color | Number + Bright Bit | Bright Color
|
||||
------ | ---------- | ------------------- | -------------
|
||||
0x0 | Black | 0x8 | Dark Gray
|
||||
0x1 | Blue | 0x9 | Light Blue
|
||||
0x2 | Green | 0xa | Light Green
|
||||
0x3 | Cyan | 0xb | Light Cyan
|
||||
0x4 | Red | 0xc | Light Red
|
||||
0x5 | Magenta | 0xd | Pink
|
||||
0x6 | Brown | 0xe | Yellow
|
||||
0x7 | Light Gray | 0xf | White
|
||||
| Number | Color | Number + Bright Bit | Bright Color |
|
||||
| ------ | ---------- | ------------------- | ------------ |
|
||||
| 0x0 | Black | 0x8 | Dark Gray |
|
||||
| 0x1 | Blue | 0x9 | Light Blue |
|
||||
| 0x2 | Green | 0xa | Light Green |
|
||||
| 0x3 | Cyan | 0xb | Light Cyan |
|
||||
| 0x4 | Red | 0xc | Light Red |
|
||||
| 0x5 | Magenta | 0xd | Pink |
|
||||
| 0x6 | Brown | 0xe | Yellow |
|
||||
| 0x7 | Light Gray | 0xf | White |
|
||||
|
||||
Bit 4 is the _bright bit_, which turns, for example, blue into light blue. For the background color, this bit is repurposed as the blink bit.
|
||||
|
||||
@@ -260,7 +260,7 @@ pub fn print_something() {
|
||||
```
|
||||
It first creates a new Writer that points to the VGA buffer at `0xb8000`. The syntax for this might seem a bit strange: First, we cast the integer `0xb8000` as a mutable [raw pointer]. Then we convert it to a mutable reference by dereferencing it (through `*`) and immediately borrowing it again (through `&mut`). This conversion requires an [`unsafe` block], since the compiler can't guarantee that the raw pointer is valid.
|
||||
|
||||
[raw pointer]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
||||
[raw pointer]: https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
||||
[`unsafe` block]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
|
||||
|
||||
Then it writes the byte `b'H'` to it. The `b` prefix creates a [byte literal], which represents an ASCII character. By writing the strings `"ello "` and `"Wörld!"`, we test our `write_string` method and the handling of unprintable characters. To see the output, we need to call the `print_something` function from our `_start` function:
|
||||
@@ -522,7 +522,7 @@ lazy_static! {
|
||||
|
||||
However, this `WRITER` is pretty useless since it is immutable. This means that we can't write anything to it (since all the write methods take `&mut self`). One possible solution would be to 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 were even proposals to [remove it][remove static mut]. But what are the alternatives? We could try to use an immutable static with a cell type like [RefCell] or even [UnsafeCell] that provides [interior mutability]. But these types aren't [Sync] \(with good reason), so we can't use them in statics.
|
||||
|
||||
[mutable static]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable
|
||||
[mutable static]: https://doc.rust-lang.org/book/ch20-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
|
||||
[RefCell]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#keeping-track-of-borrows-at-runtime-with-refcellt
|
||||
[UnsafeCell]: https://doc.rust-lang.org/nightly/core/cell/struct.UnsafeCell.html
|
||||
@@ -581,7 +581,7 @@ Note that we only have a single unsafe block in our code, which is needed to cre
|
||||
### A println Macro
|
||||
Now that we have a global writer, we can add a `println` macro that can be used from anywhere in the codebase. Rust's [macro syntax] is a bit strange, so we won't try to write a macro from scratch. Instead, we look at the source of the [`println!` macro] in the standard library:
|
||||
|
||||
[macro syntax]: https://doc.rust-lang.org/nightly/book/ch19-06-macros.html#declarative-macros-with-macro_rules-for-general-metaprogramming
|
||||
[macro syntax]: https://doc.rust-lang.org/nightly/book/ch20-05-macros.html#declarative-macros-for-general-metaprogramming
|
||||
[`println!` macro]: https://doc.rust-lang.org/nightly/std/macro.println!.html
|
||||
|
||||
```rust
|
||||
|
||||
@@ -31,12 +31,12 @@ Este blog é desenvolvido abertamente no [GitHub]. Se você tiver algum problema
|
||||
## O Buffer de Texto VGA
|
||||
Para imprimir um caractere na tela em modo de texto VGA, é preciso escrevê-lo no buffer de texto do hardware VGA. O buffer de texto VGA é um array bidimensional com tipicamente 25 linhas e 80 colunas, que é renderizado diretamente na tela. Cada entrada do array descreve um único caractere da tela através do seguinte formato:
|
||||
|
||||
Bit(s) | Valor
|
||||
------ | ----------------
|
||||
0-7 | Ponto de código ASCII
|
||||
8-11 | Cor do primeiro plano
|
||||
12-14 | Cor do fundo
|
||||
15 | Piscar
|
||||
| Bit(s) | Valor |
|
||||
| ------ | --------------------- |
|
||||
| 0-7 | Ponto de código ASCII |
|
||||
| 8-11 | Cor do primeiro plano |
|
||||
| 12-14 | Cor do fundo |
|
||||
| 15 | Piscar |
|
||||
|
||||
O primeiro byte representa o caractere que deve ser impresso na [codificação ASCII]. Para ser mais específico, não é exatamente ASCII, mas um conjunto de caracteres chamado [_página de código 437_] com alguns caracteres adicionais e pequenas modificações. Para simplificar, continuaremos chamando-o de caractere ASCII neste post.
|
||||
|
||||
@@ -45,16 +45,16 @@ O primeiro byte representa o caractere que deve ser impresso na [codificação A
|
||||
|
||||
O segundo byte define como o caractere é exibido. Os primeiros quatro bits definem a cor do primeiro plano, os próximos três bits a cor do fundo, e o último bit se o caractere deve piscar. As seguintes cores estão disponíveis:
|
||||
|
||||
Número | Cor | Número + Bit Brilhante | Cor Brilhante
|
||||
------ | ------------- | ---------------------- | --------------
|
||||
0x0 | Preto | 0x8 | Cinza Escuro
|
||||
0x1 | Azul | 0x9 | Azul Claro
|
||||
0x2 | Verde | 0xa | Verde Claro
|
||||
0x3 | Ciano | 0xb | Ciano Claro
|
||||
0x4 | Vermelho | 0xc | Vermelho Claro
|
||||
0x5 | Magenta | 0xd | Rosa
|
||||
0x6 | Marrom | 0xe | Amarelo
|
||||
0x7 | Cinza Claro | 0xf | Branco
|
||||
| Número | Cor | Número + Bit Brilhante | Cor Brilhante |
|
||||
| ------ | ----------- | ---------------------- | -------------- |
|
||||
| 0x0 | Preto | 0x8 | Cinza Escuro |
|
||||
| 0x1 | Azul | 0x9 | Azul Claro |
|
||||
| 0x2 | Verde | 0xa | Verde Claro |
|
||||
| 0x3 | Ciano | 0xb | Ciano Claro |
|
||||
| 0x4 | Vermelho | 0xc | Vermelho Claro |
|
||||
| 0x5 | Magenta | 0xd | Rosa |
|
||||
| 0x6 | Marrom | 0xe | Amarelo |
|
||||
| 0x7 | Cinza Claro | 0xf | Branco |
|
||||
|
||||
O bit 4 é o _bit brilhante_, que transforma, por exemplo, azul em azul claro. Para a cor de fundo, este bit é reaproveitado como o bit de piscar.
|
||||
|
||||
@@ -264,7 +264,7 @@ pub fn print_something() {
|
||||
```
|
||||
Primeiro ele cria um novo Writer que aponta para o buffer VGA em `0xb8000`. A sintaxe para isso pode parecer um pouco estranha: Primeiro, convertemos o inteiro `0xb8000` como um [ponteiro bruto] mutável. Então o convertemos em uma referência mutável ao desreferenciá-lo (através de `*`) e imediatamente emprestar novamente (através de `&mut`). Esta conversão requer um [bloco `unsafe`], pois o compilador não pode garantir que o ponteiro bruto é válido.
|
||||
|
||||
[ponteiro bruto]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
||||
[ponteiro bruto]: https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html#dereferencing-a-raw-pointer
|
||||
[bloco `unsafe`]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
|
||||
|
||||
Então ele escreve o byte `b'H'` nele. O prefixo `b` cria um [byte literal], que representa um caractere ASCII. Ao escrever as strings `"ello "` e `"Wörld!"`, testamos nosso método `write_string` e o tratamento de caracteres não imprimíveis. Para ver a saída, precisamos chamar a função `print_something` da nossa função `_start`:
|
||||
@@ -526,7 +526,7 @@ lazy_static! {
|
||||
|
||||
No entanto, este `WRITER` é praticamente inútil, pois é imutável. Isso significa que não podemos escrever nada nele (já que todos os métodos de escrita recebem `&mut self`). Uma solução possível seria usar um [static mutável]. Mas então cada leitura e escrita nele seria unsafe, pois poderia facilmente introduzir data races e outras coisas ruins. Usar `static mut` é altamente desencorajado. Até houve propostas para [removê-lo][remove static mut]. Mas quais são as alternativas? Poderíamos tentar usar um static imutável com um tipo de célula como [RefCell] ou até [UnsafeCell] que fornece [mutabilidade interior]. Mas esses tipos não são [Sync] \(com boa razão), então não podemos usá-los em statics.
|
||||
|
||||
[static mutável]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable
|
||||
[static mutável]: https://doc.rust-lang.org/book/ch20-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
|
||||
[RefCell]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#keeping-track-of-borrows-at-runtime-with-refcellt
|
||||
[UnsafeCell]: https://doc.rust-lang.org/nightly/core/cell/struct.UnsafeCell.html
|
||||
@@ -585,7 +585,7 @@ Note que temos apenas um bloco unsafe no nosso código, que é necessário para
|
||||
### Uma Macro println
|
||||
Agora que temos um writer global, podemos adicionar uma macro `println` que pode ser usada de qualquer lugar na base de código. A [sintaxe de macro] do Rust é um pouco estranha, então não tentaremos escrever uma macro do zero. Em vez disso, olhamos para o código-fonte da [macro `println!`] na biblioteca padrão:
|
||||
|
||||
[sintaxe de macro]: https://doc.rust-lang.org/nightly/book/ch19-06-macros.html#declarative-macros-with-macro_rules-for-general-metaprogramming
|
||||
[sintaxe de macro]: https://doc.rust-lang.org/nightly/book/ch20-05-macros.html#declarative-macros-with-macro_rules-for-general-metaprogramming
|
||||
[macro `println!`]: https://doc.rust-lang.org/nightly/std/macro.println!.html
|
||||
|
||||
```rust
|
||||
@@ -700,4 +700,4 @@ Neste post, aprendemos sobre a estrutura do buffer de texto VGA e como ele pode
|
||||
Graças ao cargo, também vimos como é fácil adicionar dependências em bibliotecas de terceiros. As duas dependências que adicionamos, `lazy_static` e `spin`, são muito úteis no desenvolvimento de SO e as usaremos em mais lugares em posts futuros.
|
||||
|
||||
## O que vem a seguir?
|
||||
O próximo post explica como configurar o framework de testes unitários embutido do Rust. Criaremos então alguns testes unitários básicos para o módulo de buffer VGA deste post.
|
||||
O próximo post explica como configurar o framework de testes unitários embutido do Rust. Criaremos então alguns testes unitários básicos para o módulo de buffer VGA deste post.
|
||||
|
||||
@@ -248,7 +248,7 @@ pub fn print_something() {
|
||||
}
|
||||
```
|
||||
|
||||
这个函数首先创建一个指向 `0xb8000` 地址VGA缓冲区的 `Writer`。实现这一点,我们需要编写的代码可能看起来有点奇怪:首先,我们把整数 `0xb8000` 强制转换为一个可变的**裸指针**([raw pointer](https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer));之后,通过运算符`*`,我们将这个裸指针解引用;最后,我们再通过 `&mut`,再次获得它的可变借用。这些转换需要 **`unsafe` 语句块**([unsafe block](https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html)),因为编译器并不能保证这个裸指针是有效的。
|
||||
这个函数首先创建一个指向 `0xb8000` 地址VGA缓冲区的 `Writer`。实现这一点,我们需要编写的代码可能看起来有点奇怪:首先,我们把整数 `0xb8000` 强制转换为一个可变的**裸指针**([raw pointer](https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html#dereferencing-a-raw-pointer));之后,通过运算符`*`,我们将这个裸指针解引用;最后,我们再通过 `&mut`,再次获得它的可变借用。这些转换需要 **`unsafe` 语句块**([unsafe block](https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html)),因为编译器并不能保证这个裸指针是有效的。
|
||||
|
||||
然后它将字节 `b'H'` 写入缓冲区内. 前缀 `b` 创建了一个字节常量([byte literal](https://doc.rust-lang.org/reference/tokens.html#byte-literals)),表示单个 ASCII 码字符;通过尝试写入 `"ello "` 和 `"Wörld!"`,我们可以测试 `write_string` 方法和其后对无法打印字符的处理逻辑。为了观察输出,我们需要在 `_start` 函数中调用 `print_something` 方法:
|
||||
|
||||
@@ -489,7 +489,7 @@ lazy_static! {
|
||||
}
|
||||
```
|
||||
|
||||
然而,这个 `WRITER` 可能没有什么用途,因为它目前还是**不可变变量**(immutable variable):这意味着我们无法向它写入数据,因为所有与写入数据相关的方法都需要实例的可变引用 `&mut self`。一种解决方案是使用**可变静态**([mutable static](https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable))的变量,但所有对它的读写操作都被规定为不安全的(unsafe)操作,因为这很容易导致数据竞争或发生其它不好的事情——使用 `static mut` 极其不被赞成,甚至有一些提案认为[应该将它删除](https://internals.rust-lang.org/t/pre-rfc-remove-static-mut/1437)。也有其它的替代方案,比如可以尝试使用比如 [RefCell](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#keeping-track-of-borrows-at-runtime-with-refcellt) 或甚至 [UnsafeCell](https://doc.rust-lang.org/nightly/core/cell/struct.UnsafeCell.html) 等类型提供的**内部可变性**([interior mutability](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html));但这些类型都被设计为非同步类型,即不满足 [Sync](https://doc.rust-lang.org/nightly/core/marker/trait.Sync.html) 约束,所以我们不能在静态变量中使用它们。
|
||||
然而,这个 `WRITER` 可能没有什么用途,因为它目前还是**不可变变量**(immutable variable):这意味着我们无法向它写入数据,因为所有与写入数据相关的方法都需要实例的可变引用 `&mut self`。一种解决方案是使用**可变静态**([mutable static](https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html#accessing-or-modifying-a-mutable-static-variable))的变量,但所有对它的读写操作都被规定为不安全的(unsafe)操作,因为这很容易导致数据竞争或发生其它不好的事情——使用 `static mut` 极其不被赞成,甚至有一些提案认为[应该将它删除](https://internals.rust-lang.org/t/pre-rfc-remove-static-mut/1437)。也有其它的替代方案,比如可以尝试使用比如 [RefCell](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#keeping-track-of-borrows-at-runtime-with-refcellt) 或甚至 [UnsafeCell](https://doc.rust-lang.org/nightly/core/cell/struct.UnsafeCell.html) 等类型提供的**内部可变性**([interior mutability](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html));但这些类型都被设计为非同步类型,即不满足 [Sync](https://doc.rust-lang.org/nightly/core/marker/trait.Sync.html) 约束,所以我们不能在静态变量中使用它们。
|
||||
|
||||
### spinlock
|
||||
|
||||
@@ -541,7 +541,7 @@ pub extern "C" fn _start() -> ! {
|
||||
|
||||
### `println!` 宏
|
||||
|
||||
现在我们有了一个全局的 `Writer` 实例,我们就可以基于它实现 `println!` 宏,这样它就能被任意地方的代码使用了。Rust 提供的[宏定义语法](https://doc.rust-lang.org/nightly/book/ch19-06-macros.html#declarative-macros-with-macro_rules-for-general-metaprogramming)需要时间理解,所以我们将不从零开始编写这个宏。我们先看看标准库中 [`println!` 宏的实现源码](https://doc.rust-lang.org/nightly/std/macro.println!.html):
|
||||
现在我们有了一个全局的 `Writer` 实例,我们就可以基于它实现 `println!` 宏,这样它就能被任意地方的代码使用了。Rust 提供的[宏定义语法](https://doc.rust-lang.org/nightly/book/ch20-05-macros.html#declarative-macros-for-general-metaprogramming)需要时间理解,所以我们将不从零开始编写这个宏。我们先看看标准库中 [`println!` 宏的实现源码](https://doc.rust-lang.org/nightly/std/macro.println!.html):
|
||||
|
||||
```rust
|
||||
#[macro_export]
|
||||
|
||||
Reference in New Issue
Block a user