diff --git a/blog/content/first-edition/extra/naked-exceptions/01-catching-exceptions/index.md b/blog/content/first-edition/extra/naked-exceptions/01-catching-exceptions/index.md index b45682b9..89b6995f 100644 --- a/blog/content/first-edition/extra/naked-exceptions/01-catching-exceptions/index.md +++ b/blog/content/first-edition/extra/naked-exceptions/01-catching-exceptions/index.md @@ -377,7 +377,7 @@ We can't know when the next IDT will be loaded. Maybe never. So in the worst cas This is exactly the definition of a [static lifetime]. So we can easily ensure that the IDT lives long enough by adding a `'static` requirement to the signature of the `load` function: -[static lifetime]: http://rustbyexample.com/scope/lifetime/static_lifetime.html +[static lifetime]: https://doc.rust-lang.org/rust-by-example/scope/lifetime/static_lifetime.html ```rust pub fn load(&'static self) {...} @@ -517,9 +517,9 @@ That's a not our exception handler. The reason is that Rust itself checks for a ### Inline Assembly In order to cause a divide-by-zero exception, we need to execute a [div] or [idiv] assembly instruction with operand 0. We could write a small assembly function and call it from our Rust code. An easier way is to use Rust's [inline assembly] macro. -[div]: http://x86.renejeschke.de/html/file_module_x86_id_72.html -[idiv]: http://x86.renejeschke.de/html/file_module_x86_id_137.html -[inline assembly]: https://doc.rust-lang.org/book/inline-assembly.html +[div]: https://www.felixcloutier.com/x86/div +[idiv]: https://www.felixcloutier.com/x86/idiv +[inline assembly]: https://doc.rust-lang.org/1.10.0/book/inline-assembly.html Inline assembly allows us to write raw x86 assembly within a Rust function. The feature is unstable, so we need to add `#![feature(asm)]` to our `src/lib.rs`. Then we're able to write a `divide_by_zero` function: diff --git a/blog/content/first-edition/extra/naked-exceptions/02-better-exception-messages/index.md b/blog/content/first-edition/extra/naked-exceptions/02-better-exception-messages/index.md index 08cb3d74..6c941a43 100644 --- a/blog/content/first-edition/extra/naked-exceptions/02-better-exception-messages/index.md +++ b/blog/content/first-edition/extra/naked-exceptions/02-better-exception-messages/index.md @@ -75,7 +75,7 @@ extern "C" fn divide_by_zero_handler() -> ! { ``` We're using [inline assembly] here to load the value from the `rsp` register into `stack_frame`. The syntax is a bit strange, so here's a quick explanation: -[inline assembly]: https://doc.rust-lang.org/nightly/book/inline-assembly.html +[inline assembly]: https://doc.rust-lang.org/1.10.0/book/inline-assembly.html - The `asm!` macro emits raw assembly instructions. This is the only way to read raw register values in Rust. - We insert a single assembly instruction: `mov $0, rsp`. It moves the value of `rsp` to some register (the `$0` is a placeholder for an arbitrary register, which gets filled by the compiler). @@ -339,7 +339,7 @@ objdump -d build/kernel-x86_64.bin | grep "10cf08:" ``` The [movaps] instruction is an [SSE] instruction that moves aligned 128bit values. It can fail for a number of reasons: -[movaps]: http://x86.renejeschke.de/html/file_module_x86_id_180.html +[movaps]: https://www.felixcloutier.com/x86/movaps [SSE]: https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions 1. For an illegal memory operand effective address in the CS, DS, ES, FS or GS segments. @@ -497,7 +497,7 @@ Invalid opcode faults have the vector number 6, so we set the 6th IDT entry. Thi We can test our new handler with the special [ud2] instruction, which generates a invalid opcode: -[ud2]: http://x86.renejeschke.de/html/file_module_x86_id_318.html +[ud2]: https://www.felixcloutier.com/x86/ud ```rust // in src/lib.rs diff --git a/blog/content/first-edition/extra/naked-exceptions/03-returning-from-exceptions/index.md b/blog/content/first-edition/extra/naked-exceptions/03-returning-from-exceptions/index.md index cddd5e41..8bdf8566 100644 --- a/blog/content/first-edition/extra/naked-exceptions/03-returning-from-exceptions/index.md +++ b/blog/content/first-edition/extra/naked-exceptions/03-returning-from-exceptions/index.md @@ -459,7 +459,7 @@ In order to fix this problem, we need to backup all caller-saved multimedia regi The Rust compiler (and LLVM) assume that the `x86_64-unknown-linux-gnu` target supports only MMX and SSE, so we don't need to save the `ymm0` through `ymm15`. But we need to save `xmm0` through `xmm15` and also `mm0` through `mm7`. There is a special instruction to do this: [fxsave]. This instruction saves the floating point and multimedia state to a given address. It needs _512 bytes_ to store that state. -[fxsave]: http://x86.renejeschke.de/html/file_module_x86_id_128.html +[fxsave]: https://www.felixcloutier.com/x86/fxsave In order to save/restore the multimedia registers, we _could_ add new macros: @@ -482,7 +482,7 @@ macro_rules! restore_multimedia_registers { ``` First, we reserve the 512 bytes on the stack and then we use `fxsave` to backup the multimedia registers. In order to restore them later, we use the [fxrstor] instruction. Note that `fxsave` and `fxrstor` require a 16 byte aligned memory address. -[fxrstor]: http://x86.renejeschke.de/html/file_module_x86_id_127.html +[fxrstor]: https://www.felixcloutier.com/x86/fxrstor However, _we won't do it that way_. The problem is the large amount of memory required. We will reuse the same code when we handle hardware interrupts in a future post. So for each mouse click, pressed key, or arrived network package we need to write 512 bytes to memory. This would be a huge performance problem. diff --git a/blog/content/first-edition/posts/01-multiboot-kernel/index.md b/blog/content/first-edition/posts/01-multiboot-kernel/index.md index 87c4af59..f12a8be6 100644 --- a/blog/content/first-edition/posts/01-multiboot-kernel/index.md +++ b/blog/content/first-edition/posts/01-multiboot-kernel/index.md @@ -247,9 +247,7 @@ You can test it on real hardware, too. Just burn the ISO to a disk or USB stick ## Build Automation -Right now we need to execute 4 commands in the right order every time we change a file. That's bad. So let's automate the build using a [Makefile][Makefile tutorial]. But first we should create some clean directory structure for our source files to separate the architecture specific files: - -[Makefile tutorial]: http://mrbook.org/blog/tutorials/make/ +Right now we need to execute 4 commands in the right order every time we change a file. That's bad. So let's automate the build using a `Makefile`. But first we should create some clean directory structure for our source files to separate the architecture specific files: ``` … diff --git a/blog/content/first-edition/posts/02-entering-longmode/index.md b/blog/content/first-edition/posts/02-entering-longmode/index.md index c5c22f6d..7824b33b 100644 --- a/blog/content/first-edition/posts/02-entering-longmode/index.md +++ b/blog/content/first-edition/posts/02-entering-longmode/index.md @@ -410,9 +410,7 @@ gdt64: dq 0 ; zero entry dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment ``` -We chose the `.rodata` section here because it's initialized read-only data. The `dq` command stands for `define quad` and outputs a 64-bit constant (similar to `dw` and `dd`). And the `(1<<43)` is a [bit shift] that sets bit 43. - -[bit shift]: http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/bitshift.html +We chose the `.rodata` section here because it's initialized read-only data. The `dq` command stands for `define quad` and outputs a 64-bit constant (similar to `dw` and `dd`). And the `(1<<43)` is a bit shift that sets bit 43. ### Loading the GDT To load our new 64-bit GDT, we have to tell the CPU its address and length. We do this by passing the memory location of a special pointer structure to the `lgdt` (load GDT) instruction. The pointer structure looks like this: diff --git a/blog/content/first-edition/posts/03-set-up-rust/index.md b/blog/content/first-edition/posts/03-set-up-rust/index.md index 01de1d01..53c4a7dd 100644 --- a/blog/content/first-edition/posts/03-set-up-rust/index.md +++ b/blog/content/first-edition/posts/03-set-up-rust/index.md @@ -78,7 +78,7 @@ Let's break it down: [attribute]: https://doc.rust-lang.org/book/attributes.html [name mangling]: https://en.wikipedia.org/wiki/Name_mangling [calling convention]: https://en.wikipedia.org/wiki/Calling_convention -[language item]: https://doc.rust-lang.org/book/lang-items.html +[language item]: https://doc.rust-lang.org/1.10.0/book/lang-items.html [unwinding]: https://doc.rust-lang.org/nomicon/unwinding.html ## Building Rust @@ -265,7 +265,7 @@ We add a new `kernel` target that just executes `xargo build` and modify the `$( But now `xargo build` is executed on every `make`, even if no source file was changed. And the ISO is recreated on every `make iso`/`make run`, too. We could try to avoid this by adding dependencies on all rust source and cargo configuration files to the `kernel` target, but the ISO creation takes only half a second on my machine and most of the time we will have changed a Rust file when we run `make`. So we keep it simple for now and let cargo do the bookkeeping of changed files (it does it anyway). -[github makefile]: https://github.com/phil-opp/blog_os/blob/post_3/Makefile +[github makefile]: https://github.com/phil-opp/blog_os/blob/first_edition_post_3/Makefile ### Calling Rust Now we can call the main method in `long_mode_start`: @@ -299,7 +299,7 @@ pub extern fn rust_main() { ``` When we test it using `make run`, it fails with `undefined reference to 'memcpy'`. The `memcpy` function is one of the basic functions of the C library (`libc`). Usually the `libc` crate is linked to every Rust program together with the standard library, but we opted out through `#![no_std]`. We could try to fix this by adding the [libc crate] as `extern crate`. But `libc` is just a wrapper for the system `libc`, for example `glibc` on Linux, so this won't work for us. Instead we need to recreate the basic `libc` functions such as `memcpy`, `memmove`, `memset`, and `memcmp` in Rust. -[libc crate]: https://doc.rust-lang.org/nightly/libc/index.html +[libc crate]: https://doc.rust-lang.org/1.10.0/libc/index.html #### rlibc Fortunately there already is a crate for that: [rlibc]. When we look at its [source code][rlibc source] we see that it contains no magic, just some [raw pointer] operations in a while loop. To add `rlibc` as a dependency we just need to add two lines to the `Cargo.toml`: @@ -343,7 +343,7 @@ target/x86_64-blog_os/debug/libblog_os.a(core-92335f822fa6c9a6.0.o): ``` [rlibc]: https://crates.io/crates/rlibc -[rlibc source]: https://github.com/rust-lang/rlibc/blob/master/src/lib.rs +[rlibc source]: https://github.com/alexcrichton/rlibc/blob/defb486e765846417a8e73329e8c5196f1dca49a/src/lib.rs [raw pointer]: https://doc.rust-lang.org/book/raw-pointers.html [crates.io]: https://crates.io diff --git a/blog/content/first-edition/posts/04-printing-to-screen/index.md b/blog/content/first-edition/posts/04-printing-to-screen/index.md index 09e78c04..94b83a2e 100644 --- a/blog/content/first-edition/posts/04-printing-to-screen/index.md +++ b/blog/content/first-edition/posts/04-printing-to-screen/index.md @@ -93,9 +93,7 @@ We use a [C-like enum] here to explicitly specify the number for each color. Bec Normally the compiler would issue a warning for each unused variant. By using the `#[allow(dead_code)]` attribute we disable these warnings for the `Color` enum. -To represent a full color code that specifies foreground and background color, we create a [newtype] on top of `u8`: - -[newtype]: https://aturon.github.io/features/types/newtype.html +To represent a full color code that specifies foreground and background color, we create a newtype on top of `u8`: ```rust struct ColorCode(u8); diff --git a/blog/content/first-edition/posts/06-page-tables/index.md b/blog/content/first-edition/posts/06-page-tables/index.md index 2757a4ac..e8e763ba 100644 --- a/blog/content/first-edition/posts/06-page-tables/index.md +++ b/blog/content/first-edition/posts/06-page-tables/index.md @@ -130,7 +130,7 @@ bitflags! { ``` To extract the flags from the entry we create an `Entry::flags` method that uses [from_bits_truncate]: -[from_bits_truncate]: https://doc.rust-lang.org/bitflags/bitflags/index.html#methods-1 +[from_bits_truncate]: https://docs.rs/bitflags/0.9.1/bitflags/example_generated/struct.Flags.html#method.from_bits_truncate ```rust pub fn flags(&self) -> EntryFlags { @@ -653,7 +653,7 @@ pub struct ActivePageTable { We can't store the `Table` directly because it needs to be at a special memory location (like the [VGA text buffer]). We could use a raw pointer or `&mut` instead of [Unique], but Unique indicates ownership better. [VGA text buffer]: ./first-edition/posts/04-printing-to-screen/index.md#the-text-buffer -[Unique]: https://doc.rust-lang.org/nightly/core/ptr/struct.Unique.html +[Unique]: https://doc.rust-lang.org/1.10.0/core/ptr/struct.Unique.html Because the `ActivePageTable` owns the unique recursive mapped P4 table, there must be only one `ActivePageTable` instance. Thus we make the constructor function unsafe: diff --git a/blog/content/first-edition/posts/07-remap-the-kernel/index.md b/blog/content/first-edition/posts/07-remap-the-kernel/index.md index 1968072c..b72c00a4 100644 --- a/blog/content/first-edition/posts/07-remap-the-kernel/index.md +++ b/blog/content/first-edition/posts/07-remap-the-kernel/index.md @@ -328,7 +328,7 @@ impl InactivePageTable { ``` We added two new arguments, `active_table` and `temporary_page`. We need an [inner scope] to ensure that the `table` variable is dropped before we try to unmap the temporary page again. This is required since the `table` variable exclusively borrows `temporary_page` as long as it's alive. -[inner scope]: http://rustbyexample.com/variable_bindings/scope.html +[inner scope]: https://doc.rust-lang.org/rust-by-example/variable_bindings/scope.html Now we are able to create valid inactive page tables, which are zeroed and recursively mapped. But we still can't modify them. To resolve this problem, we need to look at recursive mapping again. @@ -622,7 +622,7 @@ impl Iterator for FrameIter { Instead of creating a custom iterator, we could have used the [Range] struct of the standard library. But it requires that we implement the [One] and [Add] traits for `Frame`. Then every module could perform arithmetic operations on frames, for example `let frame3 = frame1 + frame2`. This would violate our safety invariants because `frame3` could be already in use. The `range_inclusive` function does not have these problems because it is only available inside the `memory` module. [Range]: https://doc.rust-lang.org/nightly/core/ops/struct.Range.html -[One]: https://doc.rust-lang.org/nightly/core/num/trait.One.html +[One]: https://doc.rust-lang.org/1.10.0/core/num/trait.One.html [Add]: https://doc.rust-lang.org/nightly/core/ops/trait.Add.html ### Page Align Sections @@ -784,7 +784,7 @@ pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable { ``` This function activates the given inactive table and returns the previous active table as a `InactivePageTable`. We don't need to flush the TLB here, as the CPU does it automatically when the P4 table is switched. In fact, the `tlb::flush_all` function, which we used above, does nothing more than [reloading the CR3 register]. -[reloading the CR3 register]: https://github.com/gz/rust-x86/blob/master/src/shared/tlb.rs#L19 +[reloading the CR3 register]: https://docs.rs/x86_64/0.1.2/src/x86_64/instructions/tlb.rs.html#11-14 Now we are finally able to switch to the new table. We do it by adding the following lines to our `remap_the_kernel` function: @@ -1093,8 +1093,8 @@ Now that we have a (mostly) safe kernel stack and a working page table module, w [next post]: ./first-edition/posts/08-kernel-heap/index.md [Box]: https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html -[Vec]: https://doc.rust-lang.org/nightly/collections/vec/struct.Vec.html -[BTreeMap]: https://doc.rust-lang.org/nightly/collections/btree_map/struct.BTreeMap.html +[Vec]: https://doc.rust-lang.org/1.10.0/collections/vec/struct.Vec.html +[BTreeMap]: https://doc.rust-lang.org/1.10.0/collections/btree_map/struct.BTreeMap.html ## Footnotes [^fn-debug-notes]: For this post the most useful GDB command is probably `p/x *((long int*)0xfffffffffffff000)@512`. It prints all entries of the recursively mapped P4 table by interpreting it as an array of 512 long ints (the `@512` is GDB's array syntax). Of course you can also print other tables by adjusting the address. diff --git a/blog/content/first-edition/posts/08-kernel-heap/index.md b/blog/content/first-edition/posts/08-kernel-heap/index.md index 62583415..a0b333ac 100644 --- a/blog/content/first-edition/posts/08-kernel-heap/index.md +++ b/blog/content/first-edition/posts/08-kernel-heap/index.md @@ -24,9 +24,9 @@ As always, you can find the complete source code on [GitHub]. Please file [issue ## Introduction The _heap_ is the memory area for long-lived allocations. The programmer can access it by using types like [Box][Box rustbyexample] or [Vec]. Behind the scenes, the compiler manages that memory by inserting calls to some memory allocator. By default, Rust links to the [jemalloc] allocator (for binaries) or the system allocator (for libraries). However, both rely on [system calls] such as [sbrk] and are thus unusable in our kernel. So we need to create and link our own allocator. -[Box rustbyexample]: http://rustbyexample.com/std/box.html +[Box rustbyexample]: https://doc.rust-lang.org/rust-by-example/std/box.html [Vec]: https://doc.rust-lang.org/book/vectors.html -[jemalloc]: http://www.canonware.com/jemalloc/ +[jemalloc]: http://jemalloc.net/ [system calls]: https://en.wikipedia.org/wiki/System_call [sbrk]: https://en.wikipedia.org/wiki/Sbrk @@ -42,7 +42,7 @@ These requirements make good allocators pretty complex. For example, [jemalloc] The allocator interface in Rust is defined through the [`Alloc` trait], which looks like this: -[`Alloc` trait]: https://doc.rust-lang.org/nightly/alloc/allocator/trait.Alloc.html +[`Alloc` trait]: https://doc.rust-lang.org/1.20.0/alloc/allocator/trait.Alloc.html ```rust pub unsafe trait Alloc { @@ -87,8 +87,8 @@ extern crate alloc; We don't need to add anything to our Cargo.toml, since the `alloc` crate is part of the standard library and shipped with the Rust compiler. The `alloc` crate provides the [format!] and [vec!] macros, so we use `#[macro_use]` to import them. -[format!]: //doc.rust-lang.org/nightly/collections/macro.format!.html -[vec!]: https://doc.rust-lang.org/nightly/collections/macro.vec!.html +[format!]: https://doc.rust-lang.org/1.10.0/collections/macro.format!.html +[vec!]: https://doc.rust-lang.org/1.10.0/collections/macro.vec!.html When we try to compile our crate now, the following error occurs: @@ -573,14 +573,14 @@ We can also use all other types of the `alloc` crate, including: - [BinaryHeap] - [BTreeMap] and [BTreeSet] -[Rc]: https://doc.rust-lang.org/nightly/alloc/rc/ -[Arc]: https://doc.rust-lang.org/nightly/alloc/arc/ -[String]: https://doc.rust-lang.org/nightly/collections/string/struct.String.html -[Linked List]: https://doc.rust-lang.org/nightly/collections/linked_list/struct.LinkedList.html -[VecDeque]: https://doc.rust-lang.org/nightly/collections/vec_deque/struct.VecDeque.html -[BinaryHeap]: https://doc.rust-lang.org/nightly/collections/binary_heap/struct.BinaryHeap.html -[BTreeMap]: https://doc.rust-lang.org/nightly/collections/btree_map/struct.BTreeMap.html -[BTreeSet]: https://doc.rust-lang.org/nightly/collections/btree_set/struct.BTreeSet.html +[Rc]: https://doc.rust-lang.org/1.10.0/alloc/rc/ +[Arc]: https://doc.rust-lang.org/1.10.0/alloc/arc/ +[String]: https://doc.rust-lang.org/1.10.0/collections/string/struct.String.html +[Linked List]: https://doc.rust-lang.org/1.10.0/collections/linked_list/struct.LinkedList.html +[VecDeque]: https://doc.rust-lang.org/1.10.0/collections/vec_deque/struct.VecDeque.html +[BinaryHeap]: https://doc.rust-lang.org/1.10.0/collections/binary_heap/struct.BinaryHeap.html +[BTreeMap]: https://doc.rust-lang.org/1.10.0/collections/btree_map/struct.BTreeMap.html +[BTreeSet]: https://doc.rust-lang.org/1.10.0/collections/btree_set/struct.BTreeSet.html ## A better Allocator Right now, we leak every freed memory block. Thus, we run out of memory quickly, for example, by creating a new `String` in each iteration of a loop: diff --git a/blog/content/first-edition/posts/09-handling-exceptions/index.md b/blog/content/first-edition/posts/09-handling-exceptions/index.md index 4cee4bf9..f22447ad 100644 --- a/blog/content/first-edition/posts/09-handling-exceptions/index.md +++ b/blog/content/first-edition/posts/09-handling-exceptions/index.md @@ -128,7 +128,7 @@ However, there is a major difference between exceptions and function calls: A fu [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]: https://en.wikipedia.org/wiki/Calling_convention -[System V ABI]: http://refspecs.linuxbase.org/elf/x86-64-abi-0.99.pdf +[System V ABI]: http://refspecs.linuxbase.org/elf/gabi41.pdf - the first six integer arguments are passed in registers `rdi`, `rsi`, `rdx`, `rcx`, `r8`, `r9` - additional arguments are passed on the stack @@ -449,7 +449,7 @@ The reason for the diffent instruction pointer values is that the stored value i In some cases, the distinction between faults and traps is vague. For example, the [debug exception] behaves like a fault in some cases, but like a trap in others. So to find out the meaning of the saved instruction pointer, it is a good idea to read the official documentation for the exception, which can be found in the [AMD64 manual] in Section 8.2. For example, for the breakpoint exception it says: [debug exception]: http://wiki.osdev.org/Exceptions#Debug -[AMD64 manual]: http://developer.amd.com/wordpress/media/2012/10/24593_APM_v21.pdf +[AMD64 manual]: https://www.amd.com/system/files/TechDocs/24593.pdf > `#BP` is a trap-type exception. The saved instruction pointer points to the byte after the `INT3` instruction. diff --git a/blog/content/first-edition/posts/10-double-faults/index.md b/blog/content/first-edition/posts/10-double-faults/index.md index 793ab8f8..946b9579 100644 --- a/blog/content/first-edition/posts/10-double-faults/index.md +++ b/blog/content/first-edition/posts/10-double-faults/index.md @@ -356,7 +356,7 @@ impl MemoryController { ``` The `MemoryController` struct holds the three types that are required for `alloc_stack` and provides a simpler interface (only one argument). The `alloc_stack` wrapper just takes the tree types as `&mut` through [destructuring] and forwards them to the `stack_allocator`. The [ref mut]-s are needed to take the inner fields by mutable reference. Note that we're re-exporting the `Stack` type since it is returned by `alloc_stack`. -[destructuring]: http://rust-lang.github.io/book/ch18-00-patterns.html#Destructuring +[destructuring]: https://doc.rust-lang.org/1.10.0/book/patterns.html#destructuring [ref mut]: http://rust-lang.github.io/book/ch18-00-patterns.html#ref-and-ref-mut The last step is to create a `StackAllocator` and return a `MemoryController` from `memory::init`: @@ -554,7 +554,7 @@ pub enum Descriptor { The flag bits are common between all descriptor types, so we create a general `DescriptorFlags` type (using the [bitflags] macro): -[bitflags]: https://doc.rust-lang.org/bitflags/bitflags/macro.bitflags.html +[bitflags]: https://docs.rs/bitflags/0.9.1/bitflags/macro.bitflags.html ```rust // in src/interrupts/gdt.rs @@ -882,8 +882,8 @@ pub fn init(memory_controller: &mut MemoryController) { We first set the descriptors to `empty` and then update them from inside the closure (which implicitly borrows them as `&mut`). Now we're able to reload the code segment register using [`set_cs`] and to load the TSS using [`load_tss`]. -[`set_cs`]: https://docs.rs/x86/0.8.0/x86/shared/segmentation/fn.set_cs.html -[`load_tss`]: https://docs.rs/x86/0.8.0/x86/shared/task/fn.load_tss.html +[`set_cs`]: https://docs.rs/x86_64/0.1.2/x86_64/instructions/segmentation/fn.set_cs.html +[`load_tss`]: https://docs.rs/x86_64/0.1.2/x86_64/instructions/tables/fn.load_tss.html 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: diff --git a/blog/content/second-edition/posts/03-vga-text-buffer/index.md b/blog/content/second-edition/posts/03-vga-text-buffer/index.md index 18625a21..0d894099 100644 --- a/blog/content/second-edition/posts/03-vga-text-buffer/index.md +++ b/blog/content/second-edition/posts/03-vga-text-buffer/index.md @@ -99,13 +99,13 @@ pub enum Color { ``` We use a [C-like enum] here to explicitly specify the number for each color. Because of the `repr(u8)` attribute each enum variant is stored as an `u8`. Actually 4 bits would be sufficient, but Rust doesn't have an `u4` type. -[C-like enum]: http://rustbyexample.com/custom_types/enum/c_like.html +[C-like enum]: https://doc.rust-lang.org/rust-by-example/custom_types/enum/c_like.html Normally the compiler would issue a warning for each unused variant. By using the `#[allow(dead_code)]` attribute we disable these warnings for the `Color` enum. By [deriving] the [`Copy`], [`Clone`], [`Debug`], [`PartialEq`], and [`Eq`] traits, we enable [copy semantics] for the type and make it printable and comparable. -[deriving]: http://rustbyexample.com/trait/derive.html +[deriving]: https://doc.rust-lang.org/rust-by-example/trait/derive.html [`Copy`]: https://doc.rust-lang.org/nightly/core/marker/trait.Copy.html [`Clone`]: https://doc.rust-lang.org/nightly/core/clone/trait.Clone.html [`Debug`]: https://doc.rust-lang.org/nightly/core/fmt/trait.Debug.html @@ -115,7 +115,7 @@ By [deriving] the [`Copy`], [`Clone`], [`Debug`], [`PartialEq`], and [`Eq`] trai To represent a full color code that specifies foreground and background color, we create a [newtype] on top of `u8`: -[newtype]: https://rustbyexample.com/generics/new_types.html +[newtype]: https://doc.rust-lang.org/rust-by-example/generics/new_types.html ```rust // in src/vga_buffer.rs diff --git a/blog/content/second-edition/posts/05-cpu-exceptions/index.md b/blog/content/second-edition/posts/05-cpu-exceptions/index.md index afaf522d..b4a5c124 100644 --- a/blog/content/second-edition/posts/05-cpu-exceptions/index.md +++ b/blog/content/second-edition/posts/05-cpu-exceptions/index.md @@ -278,7 +278,7 @@ This error occurs because the `x86-interrupt` calling convention is still unstab ### Loading the IDT 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: -[`lidt`]: http://x86.renejeschke.de/html/file_module_x86_id_156.html +[`lidt`]: https://www.felixcloutier.com/x86/lgdt:lidt [InterruptDescriptorTable::load]: https://docs.rs/x86_64/0.7.0/x86_64/structures/idt/struct.InterruptDescriptorTable.html#method.load ```rust diff --git a/blog/content/second-edition/posts/06-double-faults/index.md b/blog/content/second-edition/posts/06-double-faults/index.md index ce515a0f..41534e84 100644 --- a/blog/content/second-edition/posts/06-double-faults/index.md +++ b/blog/content/second-edition/posts/06-double-faults/index.md @@ -268,7 +268,7 @@ Note that this double fault stack has no guard page that protects against stack Now that we created a new TSS, we need a way to tell the CPU that it should use it. Unfortunately this is a bit cumbersome, since the TSS uses the segmentation system (for historical reasons). Instead of loading the table directly, we need to add a new segment descriptor to the [Global Descriptor Table] \(GDT). Then we can load our TSS invoking the [`ltr` instruction] with the respective GDT index. (This is the reason why we named our module `gdt`.) [Global Descriptor Table]: http://www.flingos.co.uk/docs/reference/Global-Descriptor-Table/ -[`ltr` instruction]: http://x86.renejeschke.de/html/file_module_x86_id_163.html +[`ltr` instruction]: https://www.felixcloutier.com/x86/ltr ### The Global Descriptor Table The Global Descriptor Table (GDT) is a relict that was used for [memory segmentation] before paging became the de facto standard. It is still needed in 64-bit mode for various things such as kernel/user mode configuration or TSS loading. diff --git a/blog/content/second-edition/posts/08-paging-introduction/index.md b/blog/content/second-edition/posts/08-paging-introduction/index.md index 4e2b93df..5ee100e1 100644 --- a/blog/content/second-edition/posts/08-paging-introduction/index.md +++ b/blog/content/second-edition/posts/08-paging-introduction/index.md @@ -229,7 +229,7 @@ Let's take a closer look at the available flags: The `x86_64` crate provides types for [page tables] and their [entries], so we don't need to create these structures ourselves. -[page tables]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/struct.PageTable.html +[page tables]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/page_table/struct.PageTable.html [entries]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/page_table/struct.PageTableEntry.html ### The Translation Lookaside Buffer diff --git a/blog/content/second-edition/posts/09-paging-implementation/index.md b/blog/content/second-edition/posts/09-paging-implementation/index.md index d5531c25..3e5c1965 100644 --- a/blog/content/second-edition/posts/09-paging-implementation/index.md +++ b/blog/content/second-edition/posts/09-paging-implementation/index.md @@ -247,7 +247,7 @@ The above code assumes that the last level 4 entry with index `0o777` (511) is r Alternatively to performing the bitwise operations by hand, you can use the [`RecursivePageTable`] type of the `x86_64` crate, which provides safe abstractions for various page table operations. For example, the code below shows how to translate a virtual address to its mapped physical address: -[`RecursivePageTable`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/struct.RecursivePageTable.html +[`RecursivePageTable`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/mapper/struct.RecursivePageTable.html ```rust // in src/memory.rs @@ -633,8 +633,8 @@ The base of the abstraction are two traits that define various page table mappin The traits only define the interface, they don't provide any implementation. The `x86_64` crate currently provides two types that implement the traits: [`MappedPageTable`] and [`RecursivePageTable`]. The former type requires that each page table frame is mapped somewhere (e.g. at an offset). The latter type can be used when the level 4 table is [mapped recursively](#recursive-page-tables). -[`MappedPageTable`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/struct.MappedPageTable.html -[`RecursivePageTable`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/struct.RecursivePageTable.html +[`MappedPageTable`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/mapper/struct.MappedPageTable.html +[`RecursivePageTable`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/mapper/struct.RecursivePageTable.html We have the complete physical memory mapped at `physical_memory_offset`, so we can use the `MappedPageTable` type. To initialize it, we create a new `init` function in our `memory` module: @@ -749,7 +749,7 @@ pub fn create_example_mapping( In addition to the `page` that should be mapped, the function expects a `mapper` instance and a `frame_allocator`. The `mapper` is a type that implements the `Mapper` trait, which provides the `map_to` method. The generic `Size4KiB` parameter is needed because the [`Mapper`] trait is [generic] over the [`PageSize`] trait to work with both standard 4KiB pages and huge 2MiB/1GiB pages. We only want to create 4KiB pages, so we can use `Mapper` instead of requiring `MapperAllSizes`. [generic]: https://doc.rust-lang.org/book/ch10-00-generics.html -[`PageSize`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/trait.PageSize.html +[`PageSize`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/page/trait.PageSize.html For the mapping, we set the `PRESENT` flag because it is required for all valid entries and the `WRITABLE` flag to make the mapped page writable. Calling `map_to` is unsafe because it's possible to break memory safety with invalid arguments, so we need to use an `unsafe` block. For a list of all possible flags, see the [_Page Table Format_] section of the previous post. @@ -759,7 +759,7 @@ The `map_to` function can fail, so it returns a [`Result`]. Since this is just s [`Result`]: https://doc.rust-lang.org/core/result/enum.Result.html [`expect`]: https://doc.rust-lang.org/core/result/enum.Result.html#method.expect -[`MapperFlush`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/struct.MapperFlush.html +[`MapperFlush`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/mapper/struct.MapperFlush.html [`flush`]: https://docs.rs/x86_64/0.7.0/x86_64/structures/paging/struct.MapperFlush.html#method.flush [must_use]: https://doc.rust-lang.org/std/result/#results-must-be-used diff --git a/blog/content/second-edition/posts/10-heap-allocation/index.md b/blog/content/second-edition/posts/10-heap-allocation/index.md index 5cb3fa1d..ee3db14e 100644 --- a/blog/content/second-edition/posts/10-heap-allocation/index.md +++ b/blog/content/second-edition/posts/10-heap-allocation/index.md @@ -625,14 +625,14 @@ Of course there are many more allocation and collection types in the `alloc` cra - the [`BinaryHeap`] priority queue - [`BTreeMap`] and [`BTreeSet`] -[`Arc`]: https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html -[`String`]: https://doc.rust-lang.org/collections/string/struct.String.html +[`Arc`]: https://doc.rust-lang.org/alloc/sync/struct.Arc.html +[`String`]: https://doc.rust-lang.org/alloc/collections/string/struct.String.html [`format!`]: https://doc.rust-lang.org/alloc/macro.format.html -[`LinkedList`]: https://doc.rust-lang.org/collections/linked_list/struct.LinkedList.html -[`VecDeque`]: https://doc.rust-lang.org/collections/vec_deque/struct.VecDeque.html -[`BinaryHeap`]: https://doc.rust-lang.org/collections/binary_heap/struct.BinaryHeap.html -[`BTreeMap`]: https://doc.rust-lang.org/collections/btree_map/struct.BTreeMap.html -[`BTreeSet`]: https://doc.rust-lang.org/collections/btree_set/struct.BTreeSet.html +[`LinkedList`]: https://doc.rust-lang.org/alloc/collections/linked_list/struct.LinkedList.html +[`VecDeque`]: https://doc.rust-lang.org/alloc/collections/vec_deque/struct.VecDeque.html +[`BinaryHeap`]: https://doc.rust-lang.org/alloc/collections/binary_heap/struct.BinaryHeap.html +[`BTreeMap`]: https://doc.rust-lang.org/alloc/collections/btree_map/struct.BTreeMap.html +[`BTreeSet`]: https://doc.rust-lang.org/alloc/collections/btree_set/struct.BTreeSet.html These types will become very useful when we want to implement thread lists, scheduling queues, or support for async/await. diff --git a/blog/content/status-update/2019-05-01.md b/blog/content/status-update/2019-05-01.md index 5d1c2bd1..97fcaf0b 100644 --- a/blog/content/status-update/2019-05-01.md +++ b/blog/content/status-update/2019-05-01.md @@ -19,7 +19,7 @@ This post is an experiment inspired by [_This Week in Rust_] and similar series. - The [_Rewrite bootimage for new bootloader build system_](https://github.com/rust-osdev/bootimage/pull/34) pull request completely revamped the implementation of the crate. This was released as version `0.7.0`. See the [changelog](https://github.com/rust-osdev/bootimage/blob/master/Changelog.md#070) for a list of changes. - The rewrite had the unintended side-effect that `bootimage run` no longer ignored executables named `test-*`, so that an additional `--bin` argument was required for specifying which executable to run. To avoid breaking users of `bootimage test`, we yanked version `0.7.0`. After [fixing the issue](https://github.com/rust-osdev/bootimage/commit/8746c15bf326cf8438a4e64ffdda332fbe59e30d), version `0.7.1` was released ([changelog](https://github.com/rust-osdev/bootimage/blob/master/Changelog.md#071)). -- The [_New features for `bootimage runner`_](https://github.com/rust-osdev/bootimage/pull/36) pull request added support for additional arguments and various functionality for supporting `cargo xtest`. The changes were released as version `0.7.2` ([changelog](https://github.com/rust-osdev/bootimage/blob/master/Charelog.md#072)). +- The [_New features for `bootimage runner`_](https://github.com/rust-osdev/bootimage/pull/36) pull request added support for additional arguments and various functionality for supporting `cargo xtest`. The changes were released as version `0.7.2` ([changelog](https://github.com/rust-osdev/bootimage/blob/master/Changelog.md#072)). - An argument parsing bug that broke the new `cargo bootimage` subcommand on Windows was [fixed](https://github.com/rust-osdev/bootimage/commit/101eb43de403fd9f3cb3f044e2c263356d2c179a). The fix was released as version `0.7.3`. ## Blog OS diff --git a/blog/templates/first-edition/comments/allocating-frames.html b/blog/templates/first-edition/comments/allocating-frames.html index 08e4204e..5604d773 100644 --- a/blog/templates/first-edition/comments/allocating-frames.html +++ b/blog/templates/first-edition/comments/allocating-frames.html @@ -1,250 +1,250 @@ {% raw %} -
Philipp Oppermann

There is some interesting discussion on reddit.

{% endraw %} diff --git a/blog/templates/first-edition/comments/better-exception-messages.html b/blog/templates/first-edition/comments/better-exception-messages.html index 9e17af5e..139c5e67 100644 --- a/blog/templates/first-edition/comments/better-exception-messages.html +++ b/blog/templates/first-edition/comments/better-exception-messages.html @@ -1,159 +1,159 @@ {% raw %} -
SmallEgg

Yay ! New post !

I'm so impatient to read the next one ^^
Thank you a lot for what you're doing :)

{% endraw %} diff --git a/blog/templates/first-edition/comments/catching-exceptions.html b/blog/templates/first-edition/comments/catching-exceptions.html index 07b84567..6ec13669 100644 --- a/blog/templates/first-edition/comments/catching-exceptions.html +++ b/blog/templates/first-edition/comments/catching-exceptions.html @@ -1,171 +1,171 @@ {% raw %} -
Michelle Ramur

Phil these tutorials are awesome, keep going!

{% endraw %} diff --git a/blog/templates/first-edition/comments/double-faults.html b/blog/templates/first-edition/comments/double-faults.html index caf4764c..e5c307e9 100644 --- a/blog/templates/first-edition/comments/double-faults.html +++ b/blog/templates/first-edition/comments/double-faults.html @@ -1,302 +1,301 @@ {% raw %} -
Blaž Šnuderl

Hey. This post seems to break returning from interruptions.

Eg. int!(3) produces a double fault while it returned correctly in the previous post

Aside from that, thanks for this series. It is superbly written with lots of useful info :)

{% endraw %} diff --git a/blog/templates/first-edition/comments/entering-longmode.html b/blog/templates/first-edition/comments/entering-longmode.html index 14f7223d..6cb42f38 100644 --- a/blog/templates/first-edition/comments/entering-longmode.html +++ b/blog/templates/first-edition/comments/entering-longmode.html @@ -1,782 +1,782 @@ {% raw %} -
Daniel

Hi, thank you for the blog posts, finding them really accessible and interesting.

The test_long_mode function doesn't look quite right:


test_long_mode:
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
cpuid ; CPU identification.
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
jb .no_long_mode ; It is less, there is no long mode.
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
cpuid ; CPU identification.
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
jb .no_long_mode ; It is less, there is no long mode.
ret


^ should probaly be (according to your linked OSDEV page):


test_long_mode:
mov eax, 0x80000000 ; Set the A-register to 0x80000000.
cpuid ; CPU identification.
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001.
jb .no_long_mode ; It is less, there is no long mode.
mov eax, 0x80000001 ; Set the A-register to 0x80000001.
cpuid ; CPU identification.
test edx, 1 << 29 ; Test if the LM-bit, which is bit 29, is set in the D-register.
jz .no_long_mode ; They aren't, there is no long mode.
ret

{% endraw %} diff --git a/blog/templates/first-edition/comments/handling-exceptions.html b/blog/templates/first-edition/comments/handling-exceptions.html index 3dea9c33..f0c31baa 100644 --- a/blog/templates/first-edition/comments/handling-exceptions.html +++ b/blog/templates/first-edition/comments/handling-exceptions.html @@ -1,63 +1,63 @@ {% raw %} -
Rajivteja Nagipogu

error[E0425]: cannot find function `int3` in module `x86_64::instructions::interrupts`
--> src/lib.rs:55:39
|
55 | x86_64::instructions::interrupts::int3();
| ^^^^ not found in `x86_64::instructions::interrupts`

I am using x86_64 v0.1.0. I looked in both x86_64 and x86 crates.io documentation. There is no such function as int3() in them. May be they stopped support in the newer versions?

{% endraw %} diff --git a/blog/templates/first-edition/comments/kernel-heap.html b/blog/templates/first-edition/comments/kernel-heap.html index 491f5e4b..1ff28bd2 100644 --- a/blog/templates/first-edition/comments/kernel-heap.html +++ b/blog/templates/first-edition/comments/kernel-heap.html @@ -1,163 +1,163 @@ {% raw %} -
Maksadbek

Nice article, thanks

{% endraw %} diff --git a/blog/templates/first-edition/comments/multiboot-kernel.html b/blog/templates/first-edition/comments/multiboot-kernel.html index 9c59afa0..3d6142ee 100644 --- a/blog/templates/first-edition/comments/multiboot-kernel.html +++ b/blog/templates/first-edition/comments/multiboot-kernel.html @@ -1,1047 +1,1047 @@ {% raw %} -
Ali Shapal

great work in explaining how all the different pieces of hardware/software come together

{% endraw %} diff --git a/blog/templates/first-edition/comments/page-tables.html b/blog/templates/first-edition/comments/page-tables.html index 75964b48..6293b6a2 100644 --- a/blog/templates/first-edition/comments/page-tables.html +++ b/blog/templates/first-edition/comments/page-tables.html @@ -1,544 +1,544 @@ {% raw %} -
Philipp Oppermann

There is some interesting discussion on /r/programming and /r/rust.

{% endraw %} diff --git a/blog/templates/first-edition/comments/printing-to-screen.html b/blog/templates/first-edition/comments/printing-to-screen.html index 89376cbf..44316f07 100644 --- a/blog/templates/first-edition/comments/printing-to-screen.html +++ b/blog/templates/first-edition/comments/printing-to-screen.html @@ -1,529 +1,529 @@ {% raw %} -
Retep998

Please add #[repr(C)] to some of your structs, in particular the ones that depend on having a specific layout.

{% endraw %} diff --git a/blog/templates/first-edition/comments/remap-the-kernel.html b/blog/templates/first-edition/comments/remap-the-kernel.html index 8fad28c9..f0bd28f4 100644 --- a/blog/templates/first-edition/comments/remap-the-kernel.html +++ b/blog/templates/first-edition/comments/remap-the-kernel.html @@ -1,155 +1,155 @@ {% raw %} -
Philipp Oppermann

There is some discussion on hacker news, /r/rust, and /r/programming.

{% endraw %} diff --git a/blog/templates/first-edition/comments/returning-from-exceptions.html b/blog/templates/first-edition/comments/returning-from-exceptions.html index 3900fa9c..fcc7422e 100644 --- a/blog/templates/first-edition/comments/returning-from-exceptions.html +++ b/blog/templates/first-edition/comments/returning-from-exceptions.html @@ -1,111 +1,111 @@ {% raw %} -
Philipp Oppermann

There are also great comments on hackernews and /r/rust!

{% endraw %} diff --git a/blog/templates/first-edition/comments/set-up-rust.html b/blog/templates/first-edition/comments/set-up-rust.html index 6cf3edd9..6bd57bcf 100644 --- a/blog/templates/first-edition/comments/set-up-rust.html +++ b/blog/templates/first-edition/comments/set-up-rust.html @@ -1,393 +1,393 @@ {% raw %} -
emk1024

If you decide to add interrupt support to your OS (for keyboard input, for example), you may not want Rust to be generating SSE code. If you use SEE code in the kernel, then you need to save SSE registers in interrupts, and saving SSE registers is slow and takes a lot of RAM. As far as I can tell, a lot of kernels simply avoid floating point to help keep interrupts and system calls efficient.

Also, as you noted in your bug on GitHub, you'll also want to set no-redzone to prevent memory corruption during interrupts.

Since we need to set a bunch of compiler flags for all generated code, including libcore, the right answer may be to replace the target x86_64-unknown-linux-gnu with a custom target that uses the right options by default. There's a discussion here and an example target file in the zinc OS.

{% endraw %}