mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Compare commits
8 Commits
0873c3ae1d
...
5217bc27b7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5217bc27b7 | ||
|
|
f365ade976 | ||
|
|
f6777e621d | ||
|
|
ee893a7ba0 | ||
|
|
58eca98ae1 | ||
|
|
f56b4a0a32 | ||
|
|
c393e4442d | ||
|
|
7954a9f424 |
@@ -213,7 +213,7 @@ impl Writer {
|
|||||||
for byte in s.bytes() {
|
for byte in s.bytes() {
|
||||||
match byte {
|
match byte {
|
||||||
// 可以是能打印的 ASCII 码字节,也可以是换行符
|
// 可以是能打印的 ASCII 码字节,也可以是换行符
|
||||||
0x20...0x7e | b'\n' => self.write_byte(byte),
|
0x20..=0x7e | b'\n' => self.write_byte(byte),
|
||||||
// 不包含在上述范围之内的字节
|
// 不包含在上述范围之内的字节
|
||||||
_ => self.write_byte(0xfe),
|
_ => self.write_byte(0xfe),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1014,7 +1014,7 @@ Apart from creating `should_panic` tests, disabling the `harness` attribute can
|
|||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
Testing is a very useful technique to ensure that certain components have a desired behavior. Even if they cannot show the absence of bugs, they're still an useful tool for finding them and especially for avoiding regressions.
|
Testing is a very useful technique to ensure that certain components have a desired behavior. Even if they cannot show the absence of bugs, they're still a useful tool for finding them and especially for avoiding regressions.
|
||||||
|
|
||||||
This post explained how to set up a test framework for our Rust kernel. We used the custom test frameworks feature of Rust to implement support for a simple `#[test_case]` attribute in our bare-metal environment. By using the `isa-debug-exit` device of QEMU, our test runner can exit QEMU after running the tests and report the test status out. To print error messages to the console instead of the VGA buffer, we created a basic driver for the serial port.
|
This post explained how to set up a test framework for our Rust kernel. We used the custom test frameworks feature of Rust to implement support for a simple `#[test_case]` attribute in our bare-metal environment. By using the `isa-debug-exit` device of QEMU, our test runner can exit QEMU after running the tests and report the test status out. To print error messages to the console instead of the VGA buffer, we created a basic driver for the serial port.
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ It's a [type alias] for an `extern "x86-interrupt" fn` type. The `extern` keywor
|
|||||||
## The Interrupt Calling Convention
|
## 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 the CPU jumps to the return address and continues the execution of the parent function.
|
Exceptions are quite similar to function calls: The CPU jumps to the first instruction of the called function and executes it. Afterwards the CPU jumps to the return address and continues the execution of the parent function.
|
||||||
|
|
||||||
However, there is a major difference between exceptions and function calls: A function call is invoked voluntary by a compiler inserted `call` instruction, while an exception might occur at _any_ instruction. In order to understand the consequences of this difference, we need to examine function calls in more detail.
|
However, there is a major difference between exceptions and function calls: A function call is invoked voluntarily by a compiler inserted `call` instruction, while an exception might occur at _any_ instruction. In order to understand the consequences of this difference, we need to examine function calls in more detail.
|
||||||
|
|
||||||
[Calling conventions] specify the details of a function call. For example, they specify where function parameters are placed (e.g. in registers or on the stack) and how results are returned. On x86_64 Linux, the following rules apply for C functions (specified in the [System V ABI]):
|
[Calling conventions] 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]):
|
||||||
|
|
||||||
|
|||||||
@@ -363,12 +363,12 @@ Now we can use the selectors to reload the `cs` segment register and load our `T
|
|||||||
// in src/gdt.rs
|
// in src/gdt.rs
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
use x86_64::instructions::segmentation::set_cs;
|
|
||||||
use x86_64::instructions::tables::load_tss;
|
use x86_64::instructions::tables::load_tss;
|
||||||
|
use x86_64::instructions::segmentation::{CS, Segment};
|
||||||
|
|
||||||
GDT.0.load();
|
GDT.0.load();
|
||||||
unsafe {
|
unsafe {
|
||||||
set_cs(GDT.1.code_selector);
|
CS::set_reg(GDT.1.code_selector);
|
||||||
load_tss(GDT.1.tss_selector);
|
load_tss(GDT.1.tss_selector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -447,7 +447,7 @@ When we run it, we see the following output:
|
|||||||
|
|
||||||
We see that there are various non-empty entries, which all map to different level 3 tables. There are so many regions because kernel code, kernel stack, the physical memory mapping, and the boot information all use separate memory areas.
|
We see that there are various non-empty entries, which all map to different level 3 tables. There are so many regions because kernel code, kernel stack, the physical memory mapping, and the boot information all use separate memory areas.
|
||||||
|
|
||||||
To traverse the page tables further and take a look at a level 3 table, we can take the mapped frame of an entry convert it to a virtual address again:
|
To traverse the page tables further and take a look at a level 3 table, we can take the mapped frame of an entry and convert it to a virtual address again:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// in the `for` loop in src/main.rs
|
// in the `for` loop in src/main.rs
|
||||||
|
|||||||
Reference in New Issue
Block a user