Skip to content

Commit 732014c

Browse files
authored
Merge pull request #990 from phil-opp/blog-nightly-fixes
Update posts to fix build on latest nightly
2 parents b070fa8 + 7992ce6 commit 732014c

File tree

9 files changed

+92
-92
lines changed

9 files changed

+92
-92
lines changed

blog/content/edition-2/posts/04-testing/index.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -174,18 +174,18 @@ The functionality of the `isa-debug-exit` device is very simple. When a `value`
174174

175175
Instead of manually invoking the `in` and `out` assembly instructions, we use the abstractions provided by the [`x86_64`] crate. To add a dependency on that crate, we add it to the `dependencies` section in our `Cargo.toml`:
176176

177-
[`x86_64`]: https://docs.rs/x86_64/0.13.2/x86_64/
177+
[`x86_64`]: https://docs.rs/x86_64/0.14.2/x86_64/
178178

179179
```toml
180180
# in Cargo.toml
181181

182182
[dependencies]
183-
x86_64 = "0.13.2"
183+
x86_64 = "0.14.2"
184184
```
185185

186186
Now we can use the [`Port`] type provided by the crate to create an `exit_qemu` function:
187187

188-
[`Port`]: https://docs.rs/x86_64/0.13.2/x86_64/instructions/port/struct.Port.html
188+
[`Port`]: https://docs.rs/x86_64/0.14.2/x86_64/instructions/port/struct.Port.html
189189

190190
```rust
191191
// in src/main.rs

blog/content/edition-2/posts/05-cpu-exceptions/index.md

+11-11
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Don't worry about steps 4 and 5 for now, we will learn about the global descript
8484
## An IDT Type
8585
Instead of creating our own IDT type, we will use the [`InterruptDescriptorTable` struct] of the `x86_64` crate, which looks like this:
8686

87-
[`InterruptDescriptorTable` struct]: https://docs.rs/x86_64/0.13.2/x86_64/structures/idt/struct.InterruptDescriptorTable.html
87+
[`InterruptDescriptorTable` struct]: https://docs.rs/x86_64/0.14.2/x86_64/structures/idt/struct.InterruptDescriptorTable.html
8888

8989
``` rust
9090
#[repr(C)]
@@ -115,15 +115,15 @@ pub struct InterruptDescriptorTable {
115115

116116
The fields have the type [`idt::Entry<F>`], which is a struct that represents the fields of an IDT entry (see the table above). The type parameter `F` defines the expected handler function type. We see that some entries require a [`HandlerFunc`] and some entries require a [`HandlerFuncWithErrCode`]. The page fault even has its own special type: [`PageFaultHandlerFunc`].
117117

118-
[`idt::Entry<F>`]: https://docs.rs/x86_64/0.13.2/x86_64/structures/idt/struct.Entry.html
119-
[`HandlerFunc`]: https://docs.rs/x86_64/0.13.2/x86_64/structures/idt/type.HandlerFunc.html
120-
[`HandlerFuncWithErrCode`]: https://docs.rs/x86_64/0.13.2/x86_64/structures/idt/type.HandlerFuncWithErrCode.html
121-
[`PageFaultHandlerFunc`]: https://docs.rs/x86_64/0.13.2/x86_64/structures/idt/type.PageFaultHandlerFunc.html
118+
[`idt::Entry<F>`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/idt/struct.Entry.html
119+
[`HandlerFunc`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/idt/type.HandlerFunc.html
120+
[`HandlerFuncWithErrCode`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/idt/type.HandlerFuncWithErrCode.html
121+
[`PageFaultHandlerFunc`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/idt/type.PageFaultHandlerFunc.html
122122

123123
Let's look at the `HandlerFunc` type first:
124124

125125
```rust
126-
type HandlerFunc = extern "x86-interrupt" fn(_: &mut InterruptStackFrame);
126+
type HandlerFunc = extern "x86-interrupt" fn(_: InterruptStackFrame);
127127
```
128128

129129
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?
@@ -195,7 +195,7 @@ So the _interrupt stack frame_ looks like this:
195195

196196
In the `x86_64` crate, the interrupt stack frame is represented by the [`InterruptStackFrame`] struct. It is passed to interrupt handlers as `&mut` and can be used to retrieve additional information about the exception's cause. The struct contains no error code field, since only some few exceptions push an error code. These exceptions use the separate [`HandlerFuncWithErrCode`] function type, which has an additional `error_code` argument.
197197

198-
[`InterruptStackFrame`]: https://docs.rs/x86_64/0.13.2/x86_64/structures/idt/struct.InterruptStackFrame.html
198+
[`InterruptStackFrame`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/idt/struct.InterruptStackFrame.html
199199

200200
### Behind the Scenes
201201
The `x86-interrupt` calling convention is a powerful abstraction that hides almost all of the messy details of the exception handling process. However, sometimes it's useful to know what's happening behind the curtain. Here is a short overview of the things that the `x86-interrupt` calling convention takes care of:
@@ -249,7 +249,7 @@ pub fn init_idt() {
249249
}
250250

251251
extern "x86-interrupt" fn breakpoint_handler(
252-
stack_frame: &mut InterruptStackFrame)
252+
stack_frame: InterruptStackFrame)
253253
{
254254
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
255255
}
@@ -263,7 +263,7 @@ When we try to compile it, the following error occurs:
263263
error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180)
264264
--> src/main.rs:53:1
265265
|
266-
53 | / extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) {
266+
53 | / extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
267267
54 | | println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
268268
55 | | }
269269
| |_^
@@ -277,7 +277,7 @@ This error occurs because the `x86-interrupt` calling convention is still unstab
277277
In order that the CPU uses our new interrupt descriptor table, we need to load it using the [`lidt`] instruction. The `InterruptDescriptorTable` struct of the `x86_64` provides a [`load`][InterruptDescriptorTable::load] method function for that. Let's try to use it:
278278

279279
[`lidt`]: https://www.felixcloutier.com/x86/lgdt:lidt
280-
[InterruptDescriptorTable::load]: https://docs.rs/x86_64/0.13.2/x86_64/structures/idt/struct.InterruptDescriptorTable.html#method.load
280+
[InterruptDescriptorTable::load]: https://docs.rs/x86_64/0.14.2/x86_64/structures/idt/struct.InterruptDescriptorTable.html#method.load
281281

282282
```rust
283283
// in src/interrupts.rs
@@ -457,7 +457,7 @@ blog_os::interrupts::test_breakpoint_exception... [ok]
457457
The `x86-interrupt` calling convention and the [`InterruptDescriptorTable`] 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. Note that these posts are based on the [first edition] of this blog and might be out of date.
458458

459459
[“Handling Exceptions with Naked Functions”]: @/edition-1/extra/naked-exceptions/_index.md
460-
[`InterruptDescriptorTable`]: https://docs.rs/x86_64/0.13.2/x86_64/structures/idt/struct.InterruptDescriptorTable.html
460+
[`InterruptDescriptorTable`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/idt/struct.InterruptDescriptorTable.html
461461
[first edition]: @/edition-1/_index.md
462462

463463
## What's next?

blog/content/edition-2/posts/06-double-faults/index.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ lazy_static! {
8181

8282
// new
8383
extern "x86-interrupt" fn double_fault_handler(
84-
stack_frame: &mut InterruptStackFrame, _error_code: u64) -> !
84+
stack_frame: InterruptStackFrame, _error_code: u64) -> !
8585
{
8686
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
8787
}
@@ -229,7 +229,7 @@ The _Privilege Stack Table_ is used by the CPU when the privilege level changes.
229229
### Creating a TSS
230230
Let's create a new TSS that contains a separate double fault stack in its interrupt stack table. For that we need a TSS struct. Fortunately, the `x86_64` crate already contains a [`TaskStateSegment` struct] that we can use.
231231

232-
[`TaskStateSegment` struct]: https://docs.rs/x86_64/0.13.2/x86_64/structures/tss/struct.TaskStateSegment.html
232+
[`TaskStateSegment` struct]: https://docs.rs/x86_64/0.14.2/x86_64/structures/tss/struct.TaskStateSegment.html
233233

234234
We create the TSS in a new `gdt` module (the name will make sense later):
235235

@@ -375,8 +375,8 @@ pub fn init() {
375375

376376
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.
377377

378-
[`set_cs`]: https://docs.rs/x86_64/0.13.2/x86_64/instructions/segmentation/fn.set_cs.html
379-
[`load_tss`]: https://docs.rs/x86_64/0.13.2/x86_64/instructions/tables/fn.load_tss.html
378+
[`set_cs`]: https://docs.rs/x86_64/0.14.2/x86_64/instructions/segmentation/fn.set_cs.html
379+
[`load_tss`]: https://docs.rs/x86_64/0.14.2/x86_64/instructions/tables/fn.load_tss.html
380380

381381
Now that we loaded a valid TSS and interrupt stack table, we can set the stack index for our double fault handler in the IDT:
382382

@@ -526,7 +526,7 @@ use blog_os::{exit_qemu, QemuExitCode, serial_println};
526526
use x86_64::structures::idt::InterruptStackFrame;
527527

528528
extern "x86-interrupt" fn test_double_fault_handler(
529-
_stack_frame: &mut InterruptStackFrame,
529+
_stack_frame: InterruptStackFrame,
530530
_error_code: u64,
531531
) -> ! {
532532
serial_println!("[ok]");

blog/content/edition-2/posts/07-hardware-interrupts/index.md

+16-16
Original file line numberDiff line numberDiff line change
@@ -75,29 +75,29 @@ Each controller can be configured through two [I/O ports], one “command” por
7575

7676
The default configuration of the PICs is not usable, because it sends interrupt vector numbers in the range 0–15 to the CPU. These numbers are already occupied by CPU exceptions, for example number 8 corresponds to a double fault. To fix this overlapping issue, we need to remap the PIC interrupts to different numbers. The actual range doesn't matter as long as it does not overlap with the exceptions, but typically the range 32–47 is chosen, because these are the first free numbers after the 32 exception slots.
7777

78-
The configuration happens by writing special values to the command and data ports of the PICs. Fortunately there is already a crate called [`pic8259_simple`], so we don't need to write the initialization sequence ourselves. In case you are interested how it works, check out [its source code][pic crate source], it's fairly small and well documented.
78+
The configuration happens by writing special values to the command and data ports of the PICs. Fortunately there is already a crate called [`pic8259`], so we don't need to write the initialization sequence ourselves. In case you are interested how it works, check out [its source code][pic crate source], it's fairly small and well documented.
7979

80-
[pic crate source]: https://docs.rs/crate/pic8259_simple/0.2.0/source/src/lib.rs
80+
[pic crate source]: https://docs.rs/crate/pic8259/0.10.0/source/src/lib.rs
8181

8282
To add the crate as dependency, we add the following to our project:
8383

84-
[`pic8259_simple`]: https://docs.rs/pic8259_simple/0.2.0/pic8259_simple/
84+
[`pic8259`]: https://docs.rs/pic8259/0.10.0/pic8259/
8585

8686
```toml
8787
# in Cargo.toml
8888

8989
[dependencies]
90-
pic8259_simple = "0.2.0"
90+
pic8259 = "0.10.1"
9191
```
9292

9393
The main abstraction provided by the crate is the [`ChainedPics`] struct that represents the primary/secondary PIC layout we saw above. It is designed to be used in the following way:
9494

95-
[`ChainedPics`]: https://docs.rs/pic8259_simple/0.2.0/pic8259_simple/struct.ChainedPics.html
95+
[`ChainedPics`]: https://docs.rs/pic8259/0.10.1/pic8259/struct.ChainedPics.html
9696

9797
```rust
9898
// in src/interrupts.rs
9999

100-
use pic8259_simple::ChainedPics;
100+
use pic8259::ChainedPics;
101101
use spin;
102102

103103
pub const PIC_1_OFFSET: u8 = 32;
@@ -125,7 +125,7 @@ pub fn init() {
125125

126126
We use the [`initialize`] function to perform the PIC initialization. Like the `ChainedPics::new` function, this function is also unsafe because it can cause undefined behavior if the PIC is misconfigured.
127127

128-
[`initialize`]: https://docs.rs/pic8259_simple/0.2.0/pic8259_simple/struct.ChainedPics.html#method.initialize
128+
[`initialize`]: https://docs.rs/pic8259/0.10.1/pic8259/struct.ChainedPics.html#method.initialize
129129

130130
If all goes well we should continue to see the "It did not crash" message when executing `cargo run`.
131131

@@ -200,15 +200,15 @@ lazy_static! {
200200
}
201201

202202
extern "x86-interrupt" fn timer_interrupt_handler(
203-
_stack_frame: &mut InterruptStackFrame)
203+
_stack_frame: InterruptStackFrame)
204204
{
205205
print!(".");
206206
}
207207
```
208208

209209
Our `timer_interrupt_handler` has the same signature as our exception handlers, because the CPU reacts identically to exceptions and external interrupts (the only difference is that some exceptions push an error code). The [`InterruptDescriptorTable`] struct implements the [`IndexMut`] trait, so we can access individual entries through array indexing syntax.
210210

211-
[`InterruptDescriptorTable`]: https://docs.rs/x86_64/0.13.2/x86_64/structures/idt/struct.InterruptDescriptorTable.html
211+
[`InterruptDescriptorTable`]: https://docs.rs/x86_64/0.14.2/x86_64/structures/idt/struct.InterruptDescriptorTable.html
212212
[`IndexMut`]: https://doc.rust-lang.org/core/ops/trait.IndexMut.html
213213

214214
In our timer interrupt handler, we print a dot to the screen. As the timer interrupt happens periodically, we would expect to see a dot appearing on each timer tick. However, when we run it we see that only a single dot is printed:
@@ -225,7 +225,7 @@ To send the EOI, we use our static `PICS` struct again:
225225
// in src/interrupts.rs
226226

227227
extern "x86-interrupt" fn timer_interrupt_handler(
228-
_stack_frame: &mut InterruptStackFrame)
228+
_stack_frame: InterruptStackFrame)
229229
{
230230
print!(".");
231231

@@ -333,7 +333,7 @@ pub fn _print(args: fmt::Arguments) {
333333

334334
The [`without_interrupts`] function takes a [closure] and executes it in an interrupt-free environment. We use it to ensure that no interrupt can occur as long as the `Mutex` is locked. When we run our kernel now we see that it keeps running without hanging. (We still don't notice any dots, but this is because they're scrolling by too fast. Try to slow down the printing, e.g. by putting a `for _ in 0..10000 {}` inside the loop.)
335335

336-
[`without_interrupts`]: https://docs.rs/x86_64/0.13.2/x86_64/instructions/interrupts/fn.without_interrupts.html
336+
[`without_interrupts`]: https://docs.rs/x86_64/0.14.2/x86_64/instructions/interrupts/fn.without_interrupts.html
337337
[closure]: https://doc.rust-lang.org/book/ch13-01-closures.html
338338

339339
We can apply the same change to our serial printing function to ensure that no deadlocks occur with it either:
@@ -538,7 +538,7 @@ lazy_static! {
538538
}
539539

540540
extern "x86-interrupt" fn keyboard_interrupt_handler(
541-
_stack_frame: &mut InterruptStackFrame)
541+
_stack_frame: InterruptStackFrame)
542542
{
543543
print!("k");
544544

@@ -563,7 +563,7 @@ To find out _which_ key was pressed, we need to query the keyboard controller. W
563563
// in src/interrupts.rs
564564

565565
extern "x86-interrupt" fn keyboard_interrupt_handler(
566-
_stack_frame: &mut InterruptStackFrame)
566+
_stack_frame: InterruptStackFrame)
567567
{
568568
use x86_64::instructions::port::Port;
569569

@@ -580,7 +580,7 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(
580580

581581
We use the [`Port`] type of the `x86_64` crate to read a byte from the keyboard's data port. This byte is called the [_scancode_] and is a number that represents the key press/release. We don't do anything with the scancode yet, we just print it to the screen:
582582

583-
[`Port`]: https://docs.rs/x86_64/0.13.2/x86_64/instructions/port/struct.Port.html
583+
[`Port`]: https://docs.rs/x86_64/0.14.2/x86_64/instructions/port/struct.Port.html
584584
[_scancode_]: https://en.wikipedia.org/wiki/Scancode
585585

586586
![QEMU printing scancodes to the screen when keys are pressed](qemu-printing-scancodes.gif)
@@ -604,7 +604,7 @@ To translate the scancodes to keys, we can use a match statement:
604604
// in src/interrupts.rs
605605

606606
extern "x86-interrupt" fn keyboard_interrupt_handler(
607-
_stack_frame: &mut InterruptStackFrame)
607+
_stack_frame: InterruptStackFrame)
608608
{
609609
use x86_64::instructions::port::Port;
610610

@@ -663,7 +663,7 @@ Now we can use this crate to rewrite our `keyboard_interrupt_handler`:
663663
// in/src/interrupts.rs
664664

665665
extern "x86-interrupt" fn keyboard_interrupt_handler(
666-
_stack_frame: &mut InterruptStackFrame)
666+
_stack_frame: InterruptStackFrame)
667667
{
668668
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
669669
use spin::Mutex;

0 commit comments

Comments
 (0)