mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
docs: remove &mut
Replace `&mut InterruptStackFrame` to `InterruptStackFrame` due to the version updating. Closes #1030
This commit is contained in:
@@ -129,7 +129,7 @@ pub struct InterruptDescriptorTable {
|
||||
بیایید ابتدا به نوع `HandlerFunc` نگاه کنیم:
|
||||
|
||||
```rust
|
||||
type HandlerFunc = extern "x86-interrupt" fn(_: &mut InterruptStackFrame);
|
||||
type HandlerFunc = extern "x86-interrupt" fn(_: InterruptStackFrame);
|
||||
```
|
||||
|
||||
این یک [نوع مستعار(type alias)] برای نوع "`extern "x86-interrupt" fn` است. کلمه کلیدی `extern` تابعی را با یک [قرارداد فراخوانی خارجی] تعریف می کند و اغلب برای برقراری ارتباط با کد C استفاده می شود(`extern "C" fn`) . اما قرارداد فراخوانی `x86-interrupt` چیست؟
|
||||
@@ -255,7 +255,7 @@ pub fn init_idt() {
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn breakpoint_handler(
|
||||
stack_frame: &mut InterruptStackFrame)
|
||||
stack_frame: InterruptStackFrame)
|
||||
{
|
||||
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
||||
}
|
||||
@@ -269,7 +269,7 @@ extern "x86-interrupt" fn breakpoint_handler(
|
||||
error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180)
|
||||
--> src/main.rs:53:1
|
||||
|
|
||||
53 | / extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) {
|
||||
53 | / extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
||||
54 | | println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
||||
55 | | }
|
||||
| |_^
|
||||
|
||||
@@ -127,7 +127,7 @@ pub struct InterruptDescriptorTable {
|
||||
まず`HandlerFunc`型を見てみましょう:
|
||||
|
||||
```rust
|
||||
type HandlerFunc = extern "x86-interrupt" fn(_: &mut InterruptStackFrame);
|
||||
type HandlerFunc = extern "x86-interrupt" fn(_: InterruptStackFrame);
|
||||
```
|
||||
|
||||
これは、`extern "x86-interrupt" fn`型への[型エイリアス][type alias]です。`extern`は[外部呼び出し規約][foreign calling convention]に従う関数を定義するのに使われ、おもにC言語のコードと連携したいときに使われます (`extern "C" fn`) 。しかし、`x86-interrupt`呼び出し規約とは何なのでしょう?
|
||||
@@ -253,7 +253,7 @@ pub fn init_idt() {
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn breakpoint_handler(
|
||||
stack_frame: &mut InterruptStackFrame)
|
||||
stack_frame: InterruptStackFrame)
|
||||
{
|
||||
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
||||
}
|
||||
@@ -267,7 +267,7 @@ extern "x86-interrupt" fn breakpoint_handler(
|
||||
error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180)
|
||||
--> src/main.rs:53:1
|
||||
|
|
||||
53 | / extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) {
|
||||
53 | / extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
||||
54 | | println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
||||
55 | | }
|
||||
| |_^
|
||||
|
||||
@@ -89,7 +89,7 @@ lazy_static! {
|
||||
|
||||
// new
|
||||
extern "x86-interrupt" fn double_fault_handler(
|
||||
stack_frame: &mut InterruptStackFrame, _error_code: u64) -> !
|
||||
stack_frame: InterruptStackFrame, _error_code: u64) -> !
|
||||
{
|
||||
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||
}
|
||||
@@ -543,7 +543,7 @@ use blog_os::{exit_qemu, QemuExitCode, serial_println};
|
||||
use x86_64::structures::idt::InterruptStackFrame;
|
||||
|
||||
extern "x86-interrupt" fn test_double_fault_handler(
|
||||
_stack_frame: &mut InterruptStackFrame,
|
||||
_stack_frame: InterruptStackFrame,
|
||||
_error_code: u64,
|
||||
) -> ! {
|
||||
serial_println!("[ok]");
|
||||
|
||||
@@ -84,7 +84,7 @@ lazy_static! {
|
||||
|
||||
// new
|
||||
extern "x86-interrupt" fn double_fault_handler(
|
||||
stack_frame: &mut InterruptStackFrame, _error_code: u64) -> !
|
||||
stack_frame: InterruptStackFrame, _error_code: u64) -> !
|
||||
{
|
||||
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||
}
|
||||
@@ -488,7 +488,7 @@ fn stack_overflow() {
|
||||
|
||||
しかし、ここではスタックオーバーフローを起こしたいので、コンパイラに削除されない、ダミーのvolatile読み込み文を関数の末尾に追加します。その結果、関数は**末尾再帰**ではなくなり、ループへの変換は防がれます。更に関数が無限に再帰することに対するコンパイラの警告をなくすために`allow(unconditional_recursion)`属性を追加します。
|
||||
|
||||
### IDTのテスト
|
||||
### IDTのテスト
|
||||
|
||||
上で述べたように、テストはカスタムしたダブルフォルトハンドラを含む専用のIDTが必要です。実装はこのようになります:
|
||||
|
||||
@@ -529,7 +529,7 @@ use blog_os::{exit_qemu, QemuExitCode, serial_println};
|
||||
use x86_64::structures::idt::InterruptStackFrame;
|
||||
|
||||
extern "x86-interrupt" fn test_double_fault_handler(
|
||||
_stack_frame: &mut InterruptStackFrame,
|
||||
_stack_frame: InterruptStackFrame,
|
||||
_error_code: u64,
|
||||
) -> ! {
|
||||
serial_println!("[ok]");
|
||||
|
||||
@@ -205,7 +205,7 @@ lazy_static! {
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn timer_interrupt_handler(
|
||||
_stack_frame: &mut InterruptStackFrame)
|
||||
_stack_frame: InterruptStackFrame)
|
||||
{
|
||||
print!(".");
|
||||
}
|
||||
@@ -230,7 +230,7 @@ extern "x86-interrupt" fn timer_interrupt_handler(
|
||||
// in src/interrupts.rs
|
||||
|
||||
extern "x86-interrupt" fn timer_interrupt_handler(
|
||||
_stack_frame: &mut InterruptStackFrame)
|
||||
_stack_frame: InterruptStackFrame)
|
||||
{
|
||||
print!(".");
|
||||
|
||||
@@ -543,7 +543,7 @@ lazy_static! {
|
||||
}
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(
|
||||
_stack_frame: &mut InterruptStackFrame)
|
||||
_stack_frame: InterruptStackFrame)
|
||||
{
|
||||
print!("k");
|
||||
|
||||
@@ -568,7 +568,7 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(
|
||||
// in src/interrupts.rs
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(
|
||||
_stack_frame: &mut InterruptStackFrame)
|
||||
_stack_frame: InterruptStackFrame)
|
||||
{
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
@@ -609,7 +609,7 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(
|
||||
// in src/interrupts.rs
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(
|
||||
_stack_frame: &mut InterruptStackFrame)
|
||||
_stack_frame: InterruptStackFrame)
|
||||
{
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
@@ -668,7 +668,7 @@ pc-keyboard = "0.5.0"
|
||||
// in/src/interrupts.rs
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(
|
||||
_stack_frame: &mut InterruptStackFrame)
|
||||
_stack_frame: InterruptStackFrame)
|
||||
{
|
||||
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
||||
use spin::Mutex;
|
||||
|
||||
@@ -166,7 +166,7 @@ rtl = true
|
||||

|
||||
|
||||
آدرس فیزیکی جدول صفحه سطح 4 که در حال حاضر فعال میباشد، و ریشه جدول صفحه سطح 4 است، در ثبات `CR3` ذخیره میشود. سپس هر ورودی جدول صفحه به قاب فیزیکی جدول سطح بعدی اشاره میکند. سپس ورودی جدول سطح 1 به قاب نگاشت شده اشاره میکند. توجه داشته باشید که تمام آدرسهای موجود در جدولهای صفحه فیزیکی هستند، به جای اینکه مجازی باشند، زیرا در غیر اینصورت CPU نیاز به ترجمه آن آدرسها نیز دارد (که این امر میتواند باعث بازگشت بیپایان شود).
|
||||
|
||||
|
||||
سلسله مراتب جدول صفحه بالا، دو صفحه را نگاشت میکند (به رنگ آبی). از اندیسهای جدول صفحه میتوان نتیجه گرفت که آدرسهای مجازی این دو صفحه `0x803FE7F000` و `0x803FE00000` است. بیایید ببینیم چه اتفاقی میافتد وقتی برنامه سعی میکند از آدرس `0x803FE7F5CE` بخواند. ابتدا آدرس را به باینری تبدیل میکنیم و اندیسهای جدول صفحه و آفست صفحه را برای آدرس تعیین میکنیم:
|
||||
|
||||

|
||||
@@ -244,7 +244,7 @@ Bit(s) | Name | Meaning
|
||||
|
||||
### بافر ترجمه Lookaside
|
||||
|
||||
یک جدول صفحه 4 سطحی، ترجمه آدرسهای مجازی را پُر هزینه میکند، زیرا هر ترجمه به 4 دسترسی حافظه نیاز دارد. برای بهبود عملکرد، معماری x86_64 آخرین ترجمهها را در _translation lookaside buffer_ یا به اختصار TLB ذخیره میکند. و این به ما اجازه میدهد تا از ترجمه کردن مجدد ترجمههایی که در حافظه پنهان قرار دارند خودداری کنیم.
|
||||
یک جدول صفحه 4 سطحی، ترجمه آدرسهای مجازی را پُر هزینه میکند، زیرا هر ترجمه به 4 دسترسی حافظه نیاز دارد. برای بهبود عملکرد، معماری x86_64 آخرین ترجمهها را در _translation lookaside buffer_ یا به اختصار TLB ذخیره میکند. و این به ما اجازه میدهد تا از ترجمه کردن مجدد ترجمههایی که در حافظه پنهان قرار دارند خودداری کنیم.
|
||||
|
||||
برخلاف سایر حافظههای پنهان پردازنده، TLB کاملاً شفاف نبوده و با تغییر محتوای جدولهای صفحه، ترجمهها را بهروز و حذف نمیکند. این بدان معنی است که هسته هر زمان که جدول صفحه را تغییر میدهد باید TLB را به صورت دستی بهروز کند. برای انجام این کار، یک دستورالعمل ویژه پردازنده وجود دارد به نام [`invlpg`] ("صفحه نامعتبر") که ترجمه برای صفحه مشخص شده را از TLB حذف میکند، بنابراین دوباره از جدول صفحه در دسترسی بعدی بارگیری میشود. TLB همچنین میتواند با بارگیری مجدد رجیستر `CR3`، که یک تعویض فضای آدرس را شبیهسازی میکند، کاملاً فلاش (کلمه: flush) شود. کریت `x86_64` توابع راست را برای هر دو نوع در [ماژول `tlb`] فراهم میکند.
|
||||
|
||||
@@ -288,7 +288,7 @@ use x86_64::structures::idt::PageFaultErrorCode;
|
||||
use crate::hlt_loop;
|
||||
|
||||
extern "x86-interrupt" fn page_fault_handler(
|
||||
stack_frame: &mut InterruptStackFrame,
|
||||
stack_frame: InterruptStackFrame,
|
||||
error_code: PageFaultErrorCode,
|
||||
) {
|
||||
use x86_64::registers::control::Cr2;
|
||||
|
||||
@@ -295,7 +295,7 @@ use x86_64::structures::idt::PageFaultErrorCode;
|
||||
use crate::hlt_loop;
|
||||
|
||||
extern "x86-interrupt" fn page_fault_handler(
|
||||
stack_frame: &mut InterruptStackFrame,
|
||||
stack_frame: InterruptStackFrame,
|
||||
error_code: PageFaultErrorCode,
|
||||
) {
|
||||
use x86_64::registers::control::Cr2;
|
||||
|
||||
@@ -1144,7 +1144,7 @@ pub(crate) fn add_scancode(scancode: u8) {
|
||||
// in src/interrupts.rs
|
||||
|
||||
extern "x86-interrupt" fn keyboard_interrupt_handler(
|
||||
_stack_frame: &mut InterruptStackFrame
|
||||
_stack_frame: InterruptStackFrame
|
||||
) {
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user