Convert all external links to https (if supported)

This commit is contained in:
Philipp Oppermann
2020-02-21 11:53:34 +01:00
parent 361108b88e
commit 0619f3a9e7
33 changed files with 120 additions and 120 deletions

View File

@@ -1,6 +1,6 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -192,7 +192,7 @@
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -110,8 +110,8 @@ The current version of the blog is already the second edition. The first edition
This project, with exception of the `blog/content` folder, is licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
https://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
at your option.

View File

@@ -4,13 +4,13 @@ This folder contains the content for the _"Writing an OS in Rust"_ blog.
## License
This folder is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License, available in [LICENSE-CC-BY-NC](LICENSE-CC-BY-NC) or under <http://creativecommons.org/licenses/by-nc/4.0/>.
This folder is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License, available in [LICENSE-CC-BY-NC](LICENSE-CC-BY-NC) or under <https://creativecommons.org/licenses/by-nc/4.0/>.
All _code examples_ between markdown code blocks denoted by three backticks (<code>\`\`\`</code>) are additionally licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or http://opensource.org/licenses/MIT)
https://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or https://opensource.org/licenses/MIT)
at your option.

View File

@@ -35,7 +35,7 @@ We've already seen several types of exceptions in our kernel:
For the full list of exceptions check out the [OSDev wiki][exceptions].
[exceptions]: http://wiki.osdev.org/Exceptions
[exceptions]: https://wiki.osdev.org/Exceptions
### The Interrupt Descriptor Table
In order to catch and handle exceptions, we have to set up a so-called _Interrupt Descriptor Table_ (IDT). In this table we can specify a handler function for each CPU exception. The hardware uses this table directly, so we need to follow a predefined format. Each entry must have the following 16-byte structure:
@@ -311,8 +311,8 @@ u64 | Offset | Virtual start address of the table.
This structure is already contained [in the x86_64 crate], so we don't need to create it ourselves. The same is true for the [lidt function]. So we just need to put the pieces together to create a `load` method:
[in the x86_64 crate]: http://docs.rs/x86_64/0.1.0/x86_64/instructions/tables/struct.DescriptorTablePointer.html
[lidt function]: http://docs.rs/x86_64/0.1.0/x86_64/instructions/tables/fn.lidt.html
[in the x86_64 crate]: https://docs.rs/x86_64/0.1.0/x86_64/instructions/tables/struct.DescriptorTablePointer.html
[lidt function]: https://docs.rs/x86_64/0.1.0/x86_64/instructions/tables/fn.lidt.html
```rust
impl Idt {
@@ -422,7 +422,7 @@ extern "C" fn divide_by_zero_handler() -> ! {
```
We register a single handler function for a [divide by zero error] \(index 0). Like the name says, this exception occurs when dividing a number by 0. Thus we have an easy way to test our new exception handler.
[divide by zero error]: http://wiki.osdev.org/Exceptions#Divide-by-zero_Error
[divide by zero error]: https://wiki.osdev.org/Exceptions#Divide-by-zero_Error
However, it doesn't work this way:

View File

@@ -394,7 +394,7 @@ The base pointer is initialized directly from the stack pointer (`rsp`) after pu
The reason is that our exception handler is defined as `extern "C" function`, which specifies that it's using the C [calling convention]. On x86_64 Linux, the C calling convention is specified by the System V AMD64 ABI ([PDF][system v abi]). Section 3.2.2 defines the following:
[calling convention]: https://en.wikipedia.org/wiki/X86_calling_conventions
[system v abi]: http://web.archive.org/web/20160801075139/http://www.x86-64.org/documentation/abi.pdf
[system v abi]: https://web.archive.org/web/20160801075139/https://www.x86-64.org/documentation/abi.pdf
> The end of the input argument area shall be aligned on a 16 byte boundary. In other words, the value (%rsp + 8) is always a multiple of 16 when control is transferred to the function entry point.

View File

@@ -38,7 +38,7 @@ The breakpoint exception is the perfect exception to test our upcoming return-fr
The breakpoint exception is commonly used in debuggers: When the user sets a breakpoint, the debugger overwrites the corresponding instruction with the `int3` instruction so that the CPU throws the breakpoint exception when it reaches that line. When the user wants to continue the program, the debugger replaces the `int3` instruction with the original instruction again and continues the program. For more details, see the [How debuggers work] series.
[How debuggers work]: http://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints
[How debuggers work]: https://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints
For our use case, we don't need to overwrite any instructions (it wouldn't even be possible since we [set the page table flags] to read-only). Instead, we just want to print a message when the breakpoint instruction is executed and then continue the program.
@@ -250,7 +250,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/gabi41.pdf
[System V ABI]: https://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
@@ -518,7 +518,7 @@ The `llvm-target` field specifies the target triple that is passed to LLVM. We w
The other fields are used for conditional compilation. This allows crate authors to use `cfg` variables to write special code for depending on the OS or the architecture. There isn't any up-to-date documentation about these fields but the [corresponding source code][target specification] is quite readable.
[data layout]: http://llvm.org/docs/LangRef.html#data-layout
[data layout]: https://llvm.org/docs/LangRef.html#data-layout
[target specification]: https://github.com/rust-lang/rust/blob/c772948b687488a087356cb91432425662e034b9/src/librustc_back/target/mod.rs#L194-L214
#### Disabling MMX and SSE
@@ -695,7 +695,7 @@ So now our return-from-exception logic works without problems in _most_ cases. H
## The Red Zone
The [red zone] is an optimization of the [System V ABI] that allows functions to temporary use the 128 bytes below its stack frame without adjusting the stack pointer:
[red zone]: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone
[red zone]: https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone
![stack frame with red zone](red-zone.svg)
@@ -709,7 +709,7 @@ However, this optimization leads to huge problems with exceptions. Let's assume
The CPU and the exception handler overwrite the data in red zone. But this data is still needed by the interrupted function. So the function won't work correctly anymore when we return from the exception handler. It might fail or cause another exception, but it could also lead to strange bugs that [take weeks to debug].
[take weeks to debug]: http://forum.osdev.org/viewtopic.php?t=21720
[take weeks to debug]: https://forum.osdev.org/viewtopic.php?t=21720
### Adjusting our Exception Handler?
The problem is that the [System V ABI] demands that the red zone _“shall not be modified by signal or interrupt handlers.”_ Our current exception handlers do not respect this. We could try to fix it by subtracting 128 from the stack pointer before pushing anything:

View File

@@ -32,7 +32,7 @@ Remote 'g' packet reply is too long: [a very long number]
```
This issue is known [since 2012][gdb issue patch] but it is still not fixed. Maybe we find the reason in the [issue thread][gdb issue thread]:
[gdb issue patch]: https://web.archive.org/web/20190114181420/http://www.cygwin.com/ml/gdb-patches/2012-03/msg00116.html
[gdb issue patch]: https://web.archive.org/web/20190114181420/https://www.cygwin.com/ml/gdb-patches/2012-03/msg00116.html
[gdb issue thread]: https://sourceware.org/bugzilla/show_bug.cgi?id=13984#c11
> from my (limited) experience, unless you ping the gdb-patches list weekly, this patch is more likely to remain forgotten :-)
@@ -73,5 +73,5 @@ After connecting to QEMU, you can use various gdb commands to control execution
Of course there are many more commands. Feel free to send a PR if you think this list is missing something important. For a more complete GDB overview, check out [Beej's Quick Guide][bggdb] or the [website for Harvard's CS161 course][CS161].
[bggdb]: http://beej.us/guide/bggdb/
[CS161]: http://www.eecs.harvard.edu/~cs161/resources/gdb.html
[bggdb]: https://beej.us/guide/bggdb/
[CS161]: https://www.eecs.harvard.edu/~cs161/resources/gdb.html

View File

@@ -9,7 +9,7 @@ template = "first-edition/page.html"
This post explains how to create a minimal x86 operating system kernel using the Multiboot standard. In fact, it will just boot and print `OK` to the screen. In subsequent blog posts we will extend it using the [Rust] programming language.
[Rust]: http://www.rust-lang.org/
[Rust]: https://www.rust-lang.org/
<!-- more -->
@@ -28,19 +28,19 @@ When you turn on a computer, it loads the [BIOS] from some special flash memory.
[BIOS]: https://en.wikipedia.org/wiki/BIOS
[protected mode]: https://en.wikipedia.org/wiki/Protected_mode
[real mode]: http://wiki.osdev.org/Real_Mode
[real mode]: https://wiki.osdev.org/Real_Mode
We won't write a bootloader because that would be a complex project on its own (if you really want to do it, check out [_Rolling Your Own Bootloader_]). Instead we will use one of the [many well-tested bootloaders][bootloader comparison] out there to boot our kernel from a CD-ROM. But which one?
[_Rolling Your Own Bootloader_]: http://wiki.osdev.org/Rolling_Your_Own_Bootloader
[_Rolling Your Own Bootloader_]: https://wiki.osdev.org/Rolling_Your_Own_Bootloader
[bootloader comparison]: https://en.wikipedia.org/wiki/Comparison_of_boot_loaders
## Multiboot
Fortunately there is a bootloader standard: the [Multiboot Specification][multiboot]. Our kernel just needs to indicate that it supports Multiboot and every Multiboot-compliant bootloader can boot it. We will use the Multiboot 2 specification ([PDF][Multiboot 2]) together with the well-known [GRUB 2] bootloader.
[multiboot]: https://en.wikipedia.org/wiki/Multiboot_Specification
[multiboot 2]: http://nongnu.askapache.com/grub/phcoder/multiboot.pdf
[grub 2]: http://wiki.osdev.org/GRUB_2
[multiboot 2]: https://nongnu.askapache.com/grub/phcoder/multiboot.pdf
[grub 2]: https://wiki.osdev.org/GRUB_2
To indicate our Multiboot 2 support to the bootloader, our kernel must start with a _Multiboot Header_, which has the following format:
@@ -130,7 +130,7 @@ Through assembling, viewing and disassembling we can see the CPU [Opcodes] in ac
To boot our executable later through GRUB, it should be an [ELF] executable. So we want `nasm` to create ELF [object files] instead of plain binaries. To do that, we simply pass the `f elf64` argument to it.
[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
[object files]: http://wiki.osdev.org/Object_Files
[object files]: https://wiki.osdev.org/Object_Files
To create the ELF _executable_, we need to [link] the object files together. We use a custom [linker script] named `linker.ld`:

View File

@@ -12,7 +12,7 @@ updated = "2015-10-29"
In the [previous post] we created a minimal multiboot kernel. It just prints `OK` and hangs. The goal is to extend it and call 64-bit [Rust] code. But the CPU is currently in [protected mode] and allows only 32-bit instructions and up to 4GiB memory. So we need to set up _Paging_ and switch to the 64-bit [long mode] first.
[previous post]: @/first-edition/posts/01-multiboot-kernel/index.md
[Rust]: http://www.rust-lang.org/
[Rust]: https://www.rust-lang.org/
[protected mode]: https://en.wikipedia.org/wiki/Protected_mode
[long mode]: https://en.wikipedia.org/wiki/Long_mode
@@ -47,7 +47,7 @@ A screen character consists of a 8 bit color code and a 8 bit [ASCII] character.
Now we can add some check _functions_. A function is just a normal label with an `ret` (return) instruction at the end. The `call` instruction can be used to call it. Unlike the `jmp` instruction that just jumps to a memory address, the `call` instruction will push a return address to the stack (and the `ret` will jump to this address). But we don't have a stack yet. The [stack pointer] in the esp register could point to some important data or even invalid memory. So we need to update it and point it to some valid stack memory.
[stack pointer]: http://stackoverflow.com/a/1464052/866447
[stack pointer]: https://stackoverflow.com/a/1464052/866447
### Creating a Stack
To create stack memory we reserve some bytes at the end of our `boot.asm`:
@@ -96,14 +96,14 @@ We use the `cmp` instruction to compare the value in `eax` to the magic value. I
In `no_multiboot`, we use the `jmp` (“jump”) instruction to jump to our error function. We could just as well use the `call` instruction, which additionally pushes the return address. But the return address is not needed because `error` never returns. To pass `0` as error code to the `error` function, we move it into `al` before the jump (`error` will read it from there).
[Multiboot specification]: http://nongnu.askapache.com/grub/phcoder/multiboot.pdf
[Multiboot specification]: https://nongnu.askapache.com/grub/phcoder/multiboot.pdf
[FLAGS register]: https://en.wikipedia.org/wiki/FLAGS_register
### CPUID check
[CPUID] is a CPU instruction that can be used to get various information about the CPU. But not every processor supports it. CPUID detection is quite laborious, so we just copy a detection function from the [OSDev wiki][CPUID detection]:
[CPUID]: http://wiki.osdev.org/CPUID
[CPUID detection]: http://wiki.osdev.org/Setting_Up_Long_Mode#Detection_of_CPUID
[CPUID]: https://wiki.osdev.org/CPUID
[CPUID detection]: https://wiki.osdev.org/Setting_Up_Long_Mode#Detection_of_CPUID
```nasm
check_cpuid:
@@ -151,7 +151,7 @@ Don't worry, you don't need to understand the details.
### Long Mode check
Now we can use CPUID to detect whether long mode can be used. I use code from [OSDev][long mode detection] again:
[long mode detection]: http://wiki.osdev.org/Setting_Up_Long_Mode#x86_or_x86-64
[long mode detection]: https://wiki.osdev.org/Setting_Up_Long_Mode#x86_or_x86-64
```nasm
check_long_mode:
@@ -400,7 +400,7 @@ Bit(s) | Name | Meaning
54 | 32-bit | must be 0 for 64-bit segments
55-63 | ignored | ignored in 64-bit mode
[ring level]: http://wiki.osdev.org/Security#Rings
[ring level]: https://wiki.osdev.org/Security#Rings
We need one code segment, a data segment is not necessary in 64-bit mode. Code segments have the following bits set: _descriptor type_, _present_, _executable_ and the _64-bit_ flag. Translated to assembly the long mode GDT looks like this:
@@ -451,7 +451,7 @@ gdt64:
```
We can't just use a normal label here, since we need the table _offset_. We calculate this offset using the current address `$` and set the label to this value using [equ]. Now we can use `gdt64.code` instead of 8 and this label will still work if we modify the GDT.
[equ]: http://www.nasm.us/doc/nasmdoc3.html#section-3.2.4
[equ]: https://www.nasm.us/doc/nasmdoc3.html#section-3.2.4
In order to finally enter the true 64-bit mode, we need to load `cs` with `gdt64.code`. But we can't do it through `mov`. The only way to reload the code selector is a _far jump_ or a _far return_. These instructions work like a normal jump/return but change the code selector. We use a far jump to a long mode label:

View File

@@ -36,7 +36,7 @@ The code from this post (and all following) is [automatically tested](https://tr
## Creating a Cargo project
[Cargo] is Rust's excellent package manager. Normally you would call `cargo new` when you want to create a new project folder. We can't use it because our folder already exists, so we need to do it manually. Fortunately we only need to add a cargo configuration file named `Cargo.toml`:
[Cargo]: http://doc.crates.io/guide.html
[Cargo]: https://doc.crates.io/guide.html
```toml
[package]
@@ -114,7 +114,7 @@ Rust allows us to define [custom targets] through a JSON configuration file. A m
The `llvm-target` field specifies the target triple that is passed to LLVM. [Target triples] are a naming convention that define the CPU architecture (e.g., `x86_64` or `arm`), the vendor (e.g., `apple` or `unknown`), the operating system (e.g., `windows` or `linux`), and the [ABI] \(e.g., `gnu` or `msvc`). For example, the target triple for 64-bit Linux is `x86_64-unknown-linux-gnu` and for 32-bit Windows the target triple is `i686-pc-windows-msvc`.
[Target triples]: http://llvm.org/docs/LangRef.html#target-triple
[Target triples]: https://llvm.org/docs/LangRef.html#target-triple
[ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
The `data-layout` field is also passed to LLVM and specifies how data should be laid out in memory. It consists of various specifications separated by a `-` character. For example, the `e` means little endian and `S128` specifies that the stack should be 128 bits (= 16 byte) aligned. The format is described in detail in the [LLVM documentation][data layout] but there shouldn't be a reason to change this string.
@@ -126,7 +126,7 @@ The `linker-flavor` field was recently introduced in [#40018] with the intention
The other fields are used for conditional compilation. This allows crate authors to use `cfg` variables to write special code for depending on the OS or the architecture. There isn't any up-to-date documentation about these fields but the [corresponding source code][target specification] is quite readable.
[data layout]: http://llvm.org/docs/LangRef.html#data-layout
[data layout]: https://llvm.org/docs/LangRef.html#data-layout
[target specification]: https://github.com/rust-lang/rust/blob/c772948b687488a087356cb91432425662e034b9/src/librustc_back/target/mod.rs#L194-L214
### A Kernel Target Specification
@@ -152,8 +152,8 @@ As `llvm-target` we use `x86_64-unknown-none`, which defines the `x86_64` archit
#### The Red Zone
The [red zone] is an optimization of the [System V ABI] that allows functions to temporary use the 128 bytes below its stack frame without adjusting the stack pointer:
[red zone]: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone
[System V ABI]: http://wiki.osdev.org/System_V_ABI
[red zone]: https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone
[System V ABI]: https://wiki.osdev.org/System_V_ABI
![stack frame with red zone](red-zone.svg)
@@ -167,7 +167,7 @@ However, this optimization leads to huge problems with exceptions or hardware in
The CPU and the exception handler overwrite the data in red zone. But this data is still needed by the interrupted function. So the function won't work correctly anymore when we return from the exception handler. This might lead to strange bugs that [take weeks to debug].
[take weeks to debug]: http://forum.osdev.org/viewtopic.php?t=21720
[take weeks to debug]: https://forum.osdev.org/viewtopic.php?t=21720
To avoid such bugs when we implement exception handling in the future, we disable the red zone right from the beginning. This is achieved by adding the `"disable-redzone": true` line to our target configuration file.

View File

@@ -205,7 +205,7 @@ error[E0507]: cannot move out of borrowed content
The reason it that Rust _moves_ values by default instead of copying them like other languages. And we cannot move `color_code` out of `self` because we only borrowed `self`. For more information check out the [ownership section] in the Rust book.
[ownership section]: https://doc.rust-lang.org/book/ownership.html
[by reference]: http://rust-lang.github.io/book/ch04-02-references-and-borrowing.html
[by reference]: https://rust-lang.github.io/book/ch04-02-references-and-borrowing.html
To fix it, we can implement the [Copy] trait for the `ColorCode` type. The easiest way to do this is to use the built-in [derive macro]:
@@ -287,8 +287,8 @@ volatile = "0.1.0"
The `0.1.0` is the [semantic] version number. For more information, see the [Specifying Dependencies] guide of the cargo documentation.
[semantic]: http://semver.org/
[Specifying Dependencies]: http://doc.crates.io/specifying-dependencies.html
[semantic]: https://semver.org/
[Specifying Dependencies]: https://doc.crates.io/specifying-dependencies.html
Now we've declared that our project depends on the `volatile` crate and are able to import it in `src/lib.rs`:
@@ -354,7 +354,7 @@ You can try it yourself in the `print_something` function.
When you print strings with some special characters like `ä` or `λ`, you'll notice that they cause weird symbols on screen. That's because they are represented by multiple bytes in [UTF-8]. By converting them to bytes, we of course get strange results. But since the VGA buffer doesn't support UTF-8, it's not possible to display these characters anyway.
[core tracking issue]: https://github.com/rust-lang/rust/issues/27701
[UTF-8]: http://www.fileformat.info/info/unicode/utf8.htm
[UTF-8]: https://www.fileformat.info/info/unicode/utf8.htm
### Support Formatting Macros
It would be nice to support Rust's formatting macros, too. That way, we can easily print different types like integers or floats. To support them, we need to implement the [core::fmt::Write] trait. The only required method of this trait is `write_str` that looks quite similar to our `write_str` method. To implement the trait, we just need to move it into an `impl fmt::Write for Writer` block and add a return type:
@@ -657,7 +657,7 @@ _Note_: You need to [cross compile binutils] to build it (or you create some sym
- [Redox]: Probably the most complete Rust OS today. It has an active community and over 1000 Github stars. File systems, network, an audio player, a picture viewer, and much more. Just take a look at the [screenshots][redox screenshots].
[Rust Bare-Bones Kernel]: https://github.com/thepowersgang/rust-barebones-kernel
[higher half]: http://wiki.osdev.org/Higher_Half_Kernel
[higher half]: https://wiki.osdev.org/Higher_Half_Kernel
[cross compile binutils]: @/first-edition/extra/cross-compile-binutils.md
[RustOS]: https://github.com/RustOS-Fork-Holding-Ground/RustOS
["Tifflin" Experimental Kernel]:https://github.com/thepowersgang/rust_os

View File

@@ -71,7 +71,7 @@ Now we can use it to print available memory areas.
### Available Memory
The boot information structure consists of various _tags_. See section 3.4 of the Multiboot specification ([PDF][multiboot specification]) for a complete list. The _memory map_ tag contains a list of all available RAM areas. Special areas such as the VGA text buffer at `0xb8000` are not available. Note that some of the available memory is already used by our kernel and by the multiboot information structure itself.
[multiboot specification]: http://nongnu.askapache.com/grub/phcoder/multiboot.pdf
[multiboot specification]: https://nongnu.askapache.com/grub/phcoder/multiboot.pdf
To print all available memory areas, we can use the `multiboot2` crate in our `rust_main` as follows:
@@ -100,7 +100,7 @@ So we have one area from `0x0` to `0x9fc00`, which is a bit below the 1MiB mark.
If you give QEMU more than 4GiB of memory by passing `-m 5G`, you get another unusable area below the 4GiB mark. This memory is normally mapped to some hardware devices. See the [OSDev Wiki][Memory_map] for more information.
[Memory_map]: http://wiki.osdev.org/Memory_Map_(x86)
[Memory_map]: https://wiki.osdev.org/Memory_Map_(x86)
### Handling Panics
We used `expect` in the code above, which will panic if there is no memory map tag. But our current panic handler just loops without printing any error message. Of course we could replace `expect` by a `match`, but we should fix the panic handler nonetheless:
@@ -217,7 +217,7 @@ We could create some kind of linked list from the free frames. For example, each
Another approach is to create some kind of data structure such as a [bitmap or a stack] to manage free frames. We could place it in the already identity mapped area right behind the kernel or multiboot structure. That way we would not need to (temporary) map each free frame. But it has the same problem of the slow initial creating/filling. In fact, we will use this approach in a future post to manage frames that are freed again. But for the initial management of free frames, we use a different method.
[bitmap or a stack]: http://wiki.osdev.org/Page_Frame_Allocation#Physical_Memory_Allocators
[bitmap or a stack]: https://wiki.osdev.org/Page_Frame_Allocation#Physical_Memory_Allocators
In the following, we will use Multiboot's memory map directly. The idea is to maintain a simple counter that starts at frame 0 and is increased constantly. If the current frame is available (part of an available area in the memory map) and not used by the kernel or the multiboot structure (we know their start and end addresses), we know that it's free and return it. Else, we increase the counter to the next possibly free frame. That way, we don't need to create a data structure when booting and the physical frames can remain unmapped. The only problem is that we cannot reasonably free frames again, but we will solve that problem in a future post (by adding an intermediate frame stack that saves freed frames).
@@ -421,7 +421,7 @@ for i in 0.. {
```
You can try different amounts of memory by passing e.g. `-m 500M` to QEMU. To compare these numbers, [WolframAlpha] can be very helpful.
[WolframAlpha]: http://www.wolframalpha.com/input/?i=%2832605+*+4096%29+bytes+in+MiB
[WolframAlpha]: https://www.wolframalpha.com/input/?i=%2832605+*+4096%29+bytes+in+MiB
## Conclusion

View File

@@ -368,7 +368,7 @@ pub fn with<F>(&mut self,
```
It overwrites the 511th P4 entry and points it to the inactive table frame. Then it flushes the [translation lookaside buffer (TLB)][TLB], which still contains some old translations. We need to flush all pages that are part of the recursive mapping, so the easiest way is to flush the TLB completely.
[TLB]: http://wiki.osdev.org/TLB
[TLB]: https://wiki.osdev.org/TLB
Now that the recursive mapping points to the given inactive table, we execute the closure in the new context. The closure can call all active table methods such as `translate` or `map_to`. It could even call `with` again and chain another inactive table! Wait… that would not work:
@@ -466,7 +466,7 @@ let backup = Frame::containing_address(
```
Why is it unsafe? Because reading the CR3 register leads to a CPU exception if the processor is not running in kernel mode ([Ring 0]). But this code will always run in kernel mode, so the `unsafe` block is completely safe here.
[Ring 0]: http://wiki.osdev.org/Security#Low-level_Protection_Mechanisms
[Ring 0]: https://wiki.osdev.org/Security#Low-level_Protection_Mechanisms
Now that we have a backup of the original P4 frame, we need a way to restore it after the closure has run. So we need to somehow modify the 511th entry of the original P4 frame, which is still the active table in the CPU. But we can't access it because the recursive mapping now points to the inactive table:
@@ -826,9 +826,9 @@ These lines are the important ones. We can read many useful information from the
- `CR2=00000000000b8f00`: Finally the most useful register. It tells us which virtual address caused the page fault. In our case it's `0xb8f00`, which is part of the [VGA text buffer].
[osdev exception overview]: http://wiki.osdev.org/Exceptions
[page fault]: http://wiki.osdev.org/Exceptions#Page_Fault
[page fault error code]: http://wiki.osdev.org/Exceptions#Error_code
[osdev exception overview]: https://wiki.osdev.org/Exceptions
[page fault]: https://wiki.osdev.org/Exceptions#Page_Fault
[page fault error code]: https://wiki.osdev.org/Exceptions#Error_code
[GDT segment]: @/first-edition/posts/02-entering-longmode/index.md#loading-the-gdt
[VGA text buffer]: @/first-edition/posts/04-printing-to-screen/index.md#the-vga-text-buffer

View File

@@ -34,7 +34,7 @@ A good allocator is fast and reliable. It also effectively utilizes the availabl
[cache locality]: http://docs.cray.com/books/S-2315-50/html-S-2315-50/qmeblljm.html
[fragmentation]: https://en.wikipedia.org/wiki/Fragmentation_(computing)
[false sharing]: http://mechanical-sympathy.blogspot.de/2011/07/false-sharing.html
[false sharing]: https://mechanical-sympathy.blogspot.de/2011/07/false-sharing.html
These requirements make good allocators pretty complex. For example, [jemalloc] has over 30.000 lines of code. This complexity is out of scope for our kernel, so we will create a much simpler allocator. Nevertheless, it should suffice for the foreseeable future, since we'll allocate only when it's absolutely necessary.
@@ -344,7 +344,7 @@ check_exception old: 0xffffffff new 0xe
```
Aha! It's a [page fault] \(`v=0e`) and was caused by the code at `0x102860`. The code tried to write (`e=0002`) to address `0x40000000`. This address is `0o_000_001_000_000_0000` in octal, which is the `HEAP_START` address defined above. Of course it page-faults: We have forgotten to map the heap memory to some physical memory.
[page fault]: http://wiki.osdev.org/Exceptions#Page_Fault
[page fault]: https://wiki.osdev.org/Exceptions#Page_Fault
### Some Refactoring
In order to map the heap cleanly, we do a bit of refactoring first. We move all memory initialization from our `rust_main` to a new `memory::init` function. Now our `rust_main` looks like this:

View File

@@ -9,7 +9,7 @@ template = "first-edition/page.html"
In this post, we start exploring CPU exceptions. Exceptions occur in various erroneous situations, for example when accessing an invalid memory address or when dividing by zero. To catch them, we have to set up an _interrupt descriptor table_ that provides handler functions. At the end of this post, our kernel will be able to catch [breakpoint exceptions] and to resume normal execution afterwards.
[breakpoint exceptions]: http://wiki.osdev.org/Exceptions#Breakpoint
[breakpoint exceptions]: https://wiki.osdev.org/Exceptions#Breakpoint
<!-- more -->
@@ -30,7 +30,7 @@ We've already seen several types of exceptions in our kernel:
For the full list of exceptions check out the [OSDev wiki][exceptions].
[exceptions]: http://wiki.osdev.org/Exceptions
[exceptions]: https://wiki.osdev.org/Exceptions
### The Interrupt Descriptor Table
In order to catch and handle exceptions, we have to set up a so-called _Interrupt Descriptor Table_ (IDT). In this table we can specify a handler function for each CPU exception. The hardware uses this table directly, so we need to follow a predefined format. Each entry must have the following 16-byte structure:
@@ -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/gabi41.pdf
[System V ABI]: https://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
@@ -221,11 +221,11 @@ pub fn init() {
Now we can add handler functions. We start by adding a handler for the [breakpoint exception]. The breakpoint exception is the perfect exception to test exception handling. Its only purpose is to temporary pause a program when the breakpoint instruction `int3` is executed.
[breakpoint exception]: http://wiki.osdev.org/Exceptions#Breakpoint
[breakpoint exception]: https://wiki.osdev.org/Exceptions#Breakpoint
The breakpoint exception is commonly used in debuggers: When the user sets a breakpoint, the debugger overwrites the corresponding instruction with the `int3` instruction so that the CPU throws the breakpoint exception when it reaches that line. When the user wants to continue the program, the debugger replaces the `int3` instruction with the original instruction again and continues the program. For more details, see the ["_How debuggers work_"] series.
["_How debuggers work_"]: http://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints
["_How debuggers work_"]: https://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints
For our use case, we don't need to overwrite any instructions (it wouldn't even be possible since we [set the page table flags] to read-only). Instead, we just want to print a message when the breakpoint instruction is executed and then continue the program.
@@ -439,16 +439,16 @@ The answer is that the stored instruction pointer only points to the causing ins
- **Aborts** are fatal exceptions that can't be recovered. Examples are [machine check exception] or the [double fault].
- **Traps** are only reported to the kernel, but don't hinder the continuation of the program. Examples are the breakpoint exception and the [overflow exception].
[page fault]: http://wiki.osdev.org/Exceptions#Page_Fault
[machine check exception]: http://wiki.osdev.org/Exceptions#Machine_Check
[double fault]: http://wiki.osdev.org/Exceptions#Double_Fault
[overflow exception]: http://wiki.osdev.org/Exceptions#Overflow
[page fault]: https://wiki.osdev.org/Exceptions#Page_Fault
[machine check exception]: https://wiki.osdev.org/Exceptions#Machine_Check
[double fault]: https://wiki.osdev.org/Exceptions#Double_Fault
[overflow exception]: https://wiki.osdev.org/Exceptions#Overflow
The reason for the diffent instruction pointer values is that the stored value is also the return address. So for faults, the instruction that caused the exception is restarted and might cause the same exception again if it's not resolved. This would not make much sense for traps, since invoking the breakpoint exception again would just cause another breakpoint exception[^fn-breakpoint-restart-use-cases]. Thus the instruction pointer points to the _next_ instruction for these exceptions.
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
[debug exception]: https://wiki.osdev.org/Exceptions#Debug
[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.
@@ -456,7 +456,7 @@ In some cases, the distinction between faults and traps is vague. For example, t
The documentation of the [`Idt`] struct and the [OSDev Wiki][osdev wiki exceptions] also contain this information.
[`Idt`]: https://docs.rs/x86_64/0.1.1/x86_64/structures/idt/struct.Idt.html
[osdev wiki exceptions]: http://wiki.osdev.org/Exceptions
[osdev wiki exceptions]: https://wiki.osdev.org/Exceptions
## Too much Magic?
The `x86-interrupt` calling convention and the [`Idt`] 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.
@@ -466,8 +466,8 @@ The `x86-interrupt` calling convention and the [`Idt`] type made the exception h
## What's next?
We've successfully caught our first exception and returned from it! The next step is to add handlers for other common exceptions such as page faults. We also need to make sure that we never cause a [triple fault], since it causes a complete system reset. The next post explains how we can avoid this by correctly catching [double faults].
[triple fault]: http://wiki.osdev.org/Triple_Fault
[double faults]: http://wiki.osdev.org/Double_Fault#Double_Fault
[triple fault]: https://wiki.osdev.org/Triple_Fault
[double faults]: https://wiki.osdev.org/Double_Fault#Double_Fault
## Footnotes
[^fn-breakpoint-restart-use-cases]: There are valid use cases for restarting an instruction that caused a breakpoint. The most common use case is a debugger: When setting a breakpoint on some code line, the debugger overwrites the corresponding instruction with an `int3` instruction, so that the CPU traps when that line is executed. When the user continues execution, the debugger swaps in the original instruction and continues the program from the replaced instruction.

View File

@@ -128,12 +128,12 @@ First Exception | Second Exception
[Divide-by-zero],<br>[Invalid TSS],<br>[Segment Not Present],<br>[Stack-Segment Fault],<br>[General Protection Fault] | [Invalid TSS],<br>[Segment Not Present],<br>[Stack-Segment Fault],<br>[General Protection Fault]
[Page Fault] | [Page Fault],<br>[Invalid TSS],<br>[Segment Not Present],<br>[Stack-Segment Fault],<br>[General Protection Fault]
[Divide-by-zero]: http://wiki.osdev.org/Exceptions#Divide-by-zero_Error
[Invalid TSS]: http://wiki.osdev.org/Exceptions#Invalid_TSS
[Segment Not Present]: http://wiki.osdev.org/Exceptions#Segment_Not_Present
[Stack-Segment Fault]: http://wiki.osdev.org/Exceptions#Stack-Segment_Fault
[General Protection Fault]: http://wiki.osdev.org/Exceptions#General_Protection_Fault
[Page Fault]: http://wiki.osdev.org/Exceptions#Page_Fault
[Divide-by-zero]: https://wiki.osdev.org/Exceptions#Divide-by-zero_Error
[Invalid TSS]: https://wiki.osdev.org/Exceptions#Invalid_TSS
[Segment Not Present]: https://wiki.osdev.org/Exceptions#Segment_Not_Present
[Stack-Segment Fault]: https://wiki.osdev.org/Exceptions#Stack-Segment_Fault
[General Protection Fault]: https://wiki.osdev.org/Exceptions#General_Protection_Fault
[Page Fault]: https://wiki.osdev.org/Exceptions#Page_Fault
[AMD64 manual]: https://www.amd.com/system/files/TechDocs/24593.pdf
@@ -438,7 +438,7 @@ We allocate a 4096 bytes stack (one page) for our double fault handler. Now we j
The Interrupt Stack Table (IST) is part of an old legacy structure called _[Task State Segment]_ \(TSS). The TSS used to hold various information (e.g. processor register state) about a task in 32-bit mode and was for example used for [hardware context switching]. However, hardware context switching is no longer supported in 64-bit mode and the format of the TSS changed completely.
[Task State Segment]: https://en.wikipedia.org/wiki/Task_state_segment
[hardware context switching]: http://wiki.osdev.org/Context_Switching#Hardware_Context_Switching
[hardware context switching]: https://wiki.osdev.org/Context_Switching#Hardware_Context_Switching
On x86_64, the TSS no longer holds any task specific information at all. Instead, it holds two stack tables (the IST is one of them). The only common field between the 32-bit and 64-bit TSS is the pointer to the [I/O port permissions bitmap].
@@ -608,7 +608,7 @@ Bit(s) | Name | Meaning
64-95 | **base 32-63** | the last four bytes of the base address
96-127 | ignored/must be zero | bits 104-108 must be zero, the rest is ignored
[ring level]: http://wiki.osdev.org/Security#Rings
[ring level]: https://wiki.osdev.org/Security#Rings
We only need the bold fields for our TSS descriptor. For example, we don't need the `limit 16-19` field since a TSS has a fixed size that is smaller than `2^16`.

View File

@@ -24,7 +24,7 @@ The [first edition] required several C-tools for building:
[`grub-mkrescue`]: https://www.gnu.org/software/grub/manual/grub/html_node/Invoking-grub_002dmkrescue.html
[`xorriso`]: https://www.gnu.org/software/xorriso/
[entering long mode]: @/first-edition/posts/02-entering-longmode/index.md
[`nasm`]: http://www.nasm.us/xdoc/2.13.03/html/nasmdoc1.html
[`nasm`]: https://www.nasm.us/xdoc/2.13.03/html/nasmdoc1.html
[`ld`]: https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html
[linker script]: http://www.scoberlin.de/content/media/http/informatik/gcc_docs/ld_3.html
[`make`]: https://www.gnu.org/software/make/

View File

@@ -67,7 +67,7 @@ blog_os
The `Cargo.toml` contains the crate configuration, for example the crate name, the author, the [semantic version] number, and dependencies. The `src/main.rs` file contains the root module of our crate and our `main` function. You can compile your crate through `cargo build` and then run the compiled `blog_os` binary in the `target/debug` subfolder.
[semantic version]: http://semver.org/
[semantic version]: https://semver.org/
### The `no_std` Attribute
@@ -152,8 +152,8 @@ While providing custom implementations of language items is possible, it should
The [`eh_personality` language item] marks a function that is used for implementing [stack unwinding]. By default, Rust uses unwinding to run the destructors of all live stack variables in case of a [panic]. This ensures that all used memory is freed and allows the parent thread to catch the panic and continue execution. Unwinding, however, is a complicated process and requires some OS specific libraries (e.g. [libunwind] on Linux or [structured exception handling] on Windows), so we don't want to use it for our operating system.
[`eh_personality` language item]: https://github.com/rust-lang/rust/blob/edb368491551a77d77a48446d4ee88b35490c565/src/libpanic_unwind/gcc.rs#L11-L45
[stack unwinding]: http://www.bogotobogo.com/cplusplus/stackunwinding.php
[libunwind]: http://www.nongnu.org/libunwind/
[stack unwinding]: https://www.bogotobogo.com/cplusplus/stackunwinding.php
[libunwind]: https://www.nongnu.org/libunwind/
[structured exception handling]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680657(v=vs.85).aspx
### Disabling Unwinding

View File

@@ -56,7 +56,7 @@ blog_os
└── main.rs
```
在这里,`Cargo.toml` 文件包含了包的**配置**configuration比如包的名称、作者、[semver版本](http://semver.org/) 和项目依赖项;`src/main.rs` 文件包含包的**根模块**root module和 main 函数。我们可以使用 `cargo build` 来编译这个包,然后在 `target/debug` 文件夹内找到编译好的 `blog_os` 二进制文件。
在这里,`Cargo.toml` 文件包含了包的**配置**configuration比如包的名称、作者、[semver版本](https://semver.org/) 和项目依赖项;`src/main.rs` 文件包含包的**根模块**root module和 main 函数。我们可以使用 `cargo build` 来编译这个包,然后在 `target/debug` 文件夹内找到编译好的 `blog_os` 二进制文件。
### no_std 属性
@@ -128,7 +128,7 @@ fn panic(_info: &PanicInfo) -> ! {
我们可以自己实现语言项,但这是下下策:目前来看,语言项是高度不稳定的语言细节实现,它们不会经过编译期类型检查(所以编译器甚至不确保它们的参数类型是否正确)。幸运的是,我们有更稳定的方式,来修复上面的语言项错误。
`eh_personality` 语言项标记的函数,将被用于实现**栈展开**[stack unwinding](http://www.bogotobogo.com/cplusplus/stackunwinding.php))。在使用标准库的情况下,当 panic 发生时Rust 将使用栈展开,来运行在栈上所有活跃的变量的**析构函数**destructor——这确保了所有使用的内存都被释放允许调用程序的**父进程**parent thread捕获 panic处理并继续运行。但是栈展开是一个复杂的过程如 Linux 的 [libunwind](http://www.nongnu.org/libunwind/) 或 Windows 的**结构化异常处理**[structured exception handling, SEH](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680657(v=vs.85).aspx)),通常需要依赖于操作系统的库;所以我们不在自己编写的操作系统中使用它。
`eh_personality` 语言项标记的函数,将被用于实现**栈展开**[stack unwinding](https://www.bogotobogo.com/cplusplus/stackunwinding.php))。在使用标准库的情况下,当 panic 发生时Rust 将使用栈展开,来运行在栈上所有活跃的变量的**析构函数**destructor——这确保了所有使用的内存都被释放允许调用程序的**父进程**parent thread捕获 panic处理并继续运行。但是栈展开是一个复杂的过程如 Linux 的 [libunwind](https://www.nongnu.org/libunwind/) 或 Windows 的**结构化异常处理**[structured exception handling, SEH](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680657(v=vs.85).aspx)),通常需要依赖于操作系统的库;所以我们不在自己编写的操作系统中使用它。
### 禁用栈展开

View File

@@ -152,8 +152,8 @@ Language item 是一些編譯器需求的特殊函式或類型。舉例來說,
`eh_personality` language item 標記的函式將被用於實作[堆疊回溯][stack unwinding]。在預設情況下當 panic 發生時Rust 會使用堆疊回溯來執行所有存在堆疊上變數的解構子destructor。這確保所有使用的記憶體都被釋放並讓 parent thread 獲取 panic 資訊並繼續運行。但是堆疊回溯是一個複雜的過程,通常會需要一些 OS 的函式庫如 Linux 的 [libunwind] 或 Windows 的 [structured exception handling]。所以我們並不希望在我們的作業系統中使用它。
[stack unwinding]: http://www.bogotobogo.com/cplusplus/stackunwinding.php
[libunwind]: http://www.nongnu.org/libunwind/
[stack unwinding]: https://www.bogotobogo.com/cplusplus/stackunwinding.php
[libunwind]: https://www.nongnu.org/libunwind/
[structured exception handling]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680657(v=vs.85).aspx
### 停用回溯

View File

@@ -7,8 +7,8 @@ template = "second-edition/extra.html"
The [red zone] is an optimization of the [System V ABI] that allows functions to temporarily use the 128 bytes below its stack frame without adjusting the stack pointer:
[red zone]: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone
[System V ABI]: http://wiki.osdev.org/System_V_ABI
[red zone]: https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone
[System V ABI]: https://wiki.osdev.org/System_V_ABI
<!-- more -->
@@ -24,6 +24,6 @@ However, this optimization leads to huge problems with exceptions or hardware in
The CPU and the exception handler overwrite the data in red zone. But this data is still needed by the interrupted function. So the function won't work correctly anymore when we return from the exception handler. This might lead to strange bugs that [take weeks to debug].
[take weeks to debug]: http://forum.osdev.org/viewtopic.php?t=21720
[take weeks to debug]: https://forum.osdev.org/viewtopic.php?t=21720
To avoid such bugs when we implement exception handling in the future, we disable the red zone right from the beginning. This is achieved by adding the `"disable-redzone": true` line to our target configuration file.

View File

@@ -163,7 +163,7 @@ Instead of using the platform's default linker (which might not support Linux ta
This setting specifies that the target doesn't support [stack unwinding] on panic, so instead the program should abort directly. This has the same effect as the `panic = "abort"` option in our Cargo.toml, so we can remove it from there. (Note that in contrast to the Cargo.toml option, this target option also applies when we recompile the `core` library later in this post. So be sure to add this option, even if you prefer to keep the Cargo.toml option.)
[stack unwinding]: http://www.bogotobogo.com/cplusplus/stackunwinding.php
[stack unwinding]: https://www.bogotobogo.com/cplusplus/stackunwinding.php
```json
"disable-redzone": true,

View File

@@ -128,7 +128,7 @@ Nightly 版本的编译器允许我们在源码的开头插入**特性标签**
"panic-strategy": "abort",
```
这个配置项的意思是,我们的编译目标不支持 panic 时的**栈展开**[stack unwinding](http://www.bogotobogo.com/cplusplus/stackunwinding.php)),所以我们选择直接**在 panic 时中止**abort on panic。这和在 `Cargo.toml` 文件中添加 `panic = "abort"` 选项的作用是相同的,所以我们可以不在这里的配置清单中填写这一项。
这个配置项的意思是,我们的编译目标不支持 panic 时的**栈展开**[stack unwinding](https://www.bogotobogo.com/cplusplus/stackunwinding.php)),所以我们选择直接**在 panic 时中止**abort on panic。这和在 `Cargo.toml` 文件中添加 `panic = "abort"` 选项的作用是相同的,所以我们可以不在这里的配置清单中填写这一项。
```json
"disable-redzone": true,

View File

@@ -237,7 +237,7 @@ impl Writer {
The VGA text buffer only supports ASCII and the additional bytes of [code page 437]. Rust strings are [UTF-8] by default, so they might contain bytes that are not supported by the VGA text buffer. We use a match to differentiate printable ASCII bytes (a newline or anything in between a space character and a `~` character) and unprintable bytes. For unprintable bytes, we print a `■` character, which has the hex code `0xfe` on the VGA hardware.
[code page 437]: https://en.wikipedia.org/wiki/Code_page_437
[UTF-8]: http://www.fileformat.info/info/unicode/utf8.htm
[UTF-8]: https://www.fileformat.info/info/unicode/utf8.htm
#### Try it out!
To write some characters to the screen, you can create a temporary function:
@@ -307,8 +307,8 @@ volatile = "0.2.6"
The `0.2.6` is the [semantic] version number. For more information, see the [Specifying Dependencies] guide of the cargo documentation.
[semantic]: http://semver.org/
[Specifying Dependencies]: http://doc.crates.io/specifying-dependencies.html
[semantic]: https://semver.org/
[Specifying Dependencies]: https://doc.crates.io/specifying-dependencies.html
Let's use it to make writes to the VGA buffer volatile. We update our `Buffer` type as follows:

View File

@@ -222,7 +222,7 @@ impl Writer {
}
```
VGA 字符缓冲区只支持 ASCII 码字节和**代码页 437**[Code page 437](https://en.wikipedia.org/wiki/Code_page_437)定义的字节。Rust 语言的字符串默认编码为 [UTF-8](http://www.fileformat.info/info/unicode/utf8.htm),也因此可能包含一些 VGA 字符缓冲区不支持的字节:我们使用 `match` 语句,来区别可打印的 ASCII 码或换行字节,和其它不可打印的字节。对每个不可打印的字节,我们打印一个 `■` 符号;这个符号在 VGA 硬件中被编码为十六进制的 `0xfe`
VGA 字符缓冲区只支持 ASCII 码字节和**代码页 437**[Code page 437](https://en.wikipedia.org/wiki/Code_page_437)定义的字节。Rust 语言的字符串默认编码为 [UTF-8](https://www.fileformat.info/info/unicode/utf8.htm),也因此可能包含一些 VGA 字符缓冲区不支持的字节:我们使用 `match` 语句,来区别可打印的 ASCII 码或换行字节,和其它不可打印的字节。对每个不可打印的字节,我们打印一个 `■` 符号;这个符号在 VGA 硬件中被编码为十六进制的 `0xfe`
我们可以亲自试一试已经编写的代码。为了这样做,我们可以临时编写一个函数:
@@ -259,7 +259,7 @@ pub extern "C" fn _start() -> ! {
![QEMU output with a yellow Hello W■■rld! in the lower left corner](https://os.phil-opp.com/vga-text-mode/vga-hello.png)
需要注意的是,`ö` 字符被打印为两个 `■` 字符。这是因为在 [UTF-8](http://www.fileformat.info/info/unicode/utf8.htm) 编码下,字符 `ö` 是由两个字节表述的——而这两个字节并不处在可打印的 ASCII 码字节范围之内。事实上,这是 UTF-8 编码的基本特点之一:**如果一个字符占用多个字节,那么每个组成它的独立字节都不是有效的 ASCII 码字节**the individual bytes of multi-byte values are never valid ASCII
需要注意的是,`ö` 字符被打印为两个 `■` 字符。这是因为在 [UTF-8](https://www.fileformat.info/info/unicode/utf8.htm) 编码下,字符 `ö` 是由两个字节表述的——而这两个字节并不处在可打印的 ASCII 码字节范围之内。事实上,这是 UTF-8 编码的基本特点之一:**如果一个字符占用多个字节,那么每个组成它的独立字节都不是有效的 ASCII 码字节**the individual bytes of multi-byte values are never valid ASCII
### 易失操作
@@ -278,7 +278,7 @@ pub extern "C" fn _start() -> ! {
volatile = "0.2.3"
```
`0.2.3` 表示一个**语义版本号**[semantic version number](http://semver.org/)),在 cargo 文档的[《指定依赖项》章节](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html)可以找到与它相关的使用指南。
`0.2.3` 表示一个**语义版本号**[semantic version number](https://semver.org/)),在 cargo 文档的[《指定依赖项》章节](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html)可以找到与它相关的使用指南。
现在,我们使用它来完成 VGA 缓冲区的 volatile 写入操作。我们将 `Buffer` 类型的定义修改为下列代码:

View File

@@ -10,7 +10,7 @@ chapter = "Interrupts"
CPU exceptions occur in various erroneous situations, for example when accessing an invalid memory address or when dividing by zero. To react to them we have to set up an _interrupt descriptor table_ that provides handler functions. At the end of this post, our kernel will be able to catch [breakpoint exceptions] and to resume normal execution afterwards.
[breakpoint exceptions]: http://wiki.osdev.org/Exceptions#Breakpoint
[breakpoint exceptions]: https://wiki.osdev.org/Exceptions#Breakpoint
<!-- more -->
@@ -37,7 +37,7 @@ On x86 there are about 20 different CPU exception types. The most important are:
For the full list of exceptions check out the [OSDev wiki][exceptions].
[exceptions]: http://wiki.osdev.org/Exceptions
[exceptions]: https://wiki.osdev.org/Exceptions
### The Interrupt Descriptor Table
In order to catch and handle exceptions, we have to set up a so-called _Interrupt Descriptor Table_ (IDT). In this table we can specify a handler function for each CPU exception. The hardware uses this table directly, so we need to follow a predefined format. Each entry must have the following 16-byte structure:
@@ -139,7 +139,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]: https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf
- the first six integer arguments are passed in registers `rdi`, `rsi`, `rdx`, `rcx`, `r8`, `r9`
- additional arguments are passed on the stack
@@ -229,11 +229,11 @@ pub fn init_idt() {
Now we can add handler functions. We start by adding a handler for the [breakpoint exception]. The breakpoint exception is the perfect exception to test exception handling. Its only purpose is to temporarily pause a program when the breakpoint instruction `int3` is executed.
[breakpoint exception]: http://wiki.osdev.org/Exceptions#Breakpoint
[breakpoint exception]: https://wiki.osdev.org/Exceptions#Breakpoint
The breakpoint exception is commonly used in debuggers: When the user sets a breakpoint, the debugger overwrites the corresponding instruction with the `int3` instruction so that the CPU throws the breakpoint exception when it reaches that line. When the user wants to continue the program, the debugger replaces the `int3` instruction with the original instruction again and continues the program. For more details, see the ["_How debuggers work_"] series.
["_How debuggers work_"]: http://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints
["_How debuggers work_"]: https://eli.thegreenplace.net/2011/01/27/how-debuggers-work-part-2-breakpoints
For our use case, we don't need to overwrite any instructions. Instead, we just want to print a message when the breakpoint instruction is executed and then continue the program. So let's create a simple `breakpoint_handler` function and add it to our IDT:
@@ -466,5 +466,5 @@ The `x86-interrupt` calling convention and the [`InterruptDescriptorTable`] type
## What's next?
We've successfully caught our first exception and returned from it! The next step is to ensure that we catch all exceptions, because an uncaught exception causes a fatal [triple fault], which leads to a system reset. The next post explains how we can avoid this by correctly catching [double faults].
[triple fault]: http://wiki.osdev.org/Triple_Fault
[double faults]: http://wiki.osdev.org/Double_Fault#Double_Fault
[triple fault]: https://wiki.osdev.org/Triple_Fault
[double faults]: https://wiki.osdev.org/Double_Fault#Double_Fault

View File

@@ -128,12 +128,12 @@ First Exception | Second Exception
[Divide-by-zero],<br>[Invalid TSS],<br>[Segment Not Present],<br>[Stack-Segment Fault],<br>[General Protection Fault] | [Invalid TSS],<br>[Segment Not Present],<br>[Stack-Segment Fault],<br>[General Protection Fault]
[Page Fault] | [Page Fault],<br>[Invalid TSS],<br>[Segment Not Present],<br>[Stack-Segment Fault],<br>[General Protection Fault]
[Divide-by-zero]: http://wiki.osdev.org/Exceptions#Divide-by-zero_Error
[Invalid TSS]: http://wiki.osdev.org/Exceptions#Invalid_TSS
[Segment Not Present]: http://wiki.osdev.org/Exceptions#Segment_Not_Present
[Stack-Segment Fault]: http://wiki.osdev.org/Exceptions#Stack-Segment_Fault
[General Protection Fault]: http://wiki.osdev.org/Exceptions#General_Protection_Fault
[Page Fault]: http://wiki.osdev.org/Exceptions#Page_Fault
[Divide-by-zero]: https://wiki.osdev.org/Exceptions#Divide-by-zero_Error
[Invalid TSS]: https://wiki.osdev.org/Exceptions#Invalid_TSS
[Segment Not Present]: https://wiki.osdev.org/Exceptions#Segment_Not_Present
[Stack-Segment Fault]: https://wiki.osdev.org/Exceptions#Stack-Segment_Fault
[General Protection Fault]: https://wiki.osdev.org/Exceptions#General_Protection_Fault
[Page Fault]: https://wiki.osdev.org/Exceptions#Page_Fault
[AMD64 manual]: https://www.amd.com/system/files/TechDocs/24593.pdf
@@ -206,7 +206,7 @@ For each exception handler, we can choose a stack from the IST through the `stac
The Interrupt Stack Table (IST) is part of an old legacy structure called _[Task State Segment]_ \(TSS). The TSS used to hold various information (e.g. processor register state) about a task in 32-bit mode and was for example used for [hardware context switching]. However, hardware context switching is no longer supported in 64-bit mode and the format of the TSS changed completely.
[Task State Segment]: https://en.wikipedia.org/wiki/Task_state_segment
[hardware context switching]: http://wiki.osdev.org/Context_Switching#Hardware_Context_Switching
[hardware context switching]: https://wiki.osdev.org/Context_Switching#Hardware_Context_Switching
On x86_64, the TSS no longer holds any task specific information at all. Instead, it holds two stack tables (the IST is one of them). The only common field between the 32-bit and 64-bit TSS is the pointer to the [I/O port permissions bitmap].

View File

@@ -38,7 +38,7 @@ Apart from correctness, there are many secondary design goals. For example, the
[cache locality]: http://docs.cray.com/books/S-2315-50/html-S-2315-50/qmeblljm.html
[_fragmentation_]: https://en.wikipedia.org/wiki/Fragmentation_(computing)
[false sharing]: http://mechanical-sympathy.blogspot.de/2011/07/false-sharing.html
[false sharing]: https://mechanical-sympathy.blogspot.de/2011/07/false-sharing.html
These requirements can make good allocators very complex. For example, [jemalloc] has over 30.000 lines of code. This complexity is often undesired in kernel code where a single bug can lead to severe security vulnerabilities. Fortunately, the allocation patterns of kernel code are often much simpler compared to userspace code, so that relatively simple allocator designs often suffice.

View File

@@ -10,7 +10,7 @@ This post gives an overview of the recent updates to the _Writing an OS in Rust_
- [Use cast crate instead of usize_conversions crate](https://github.com/rust-osdev/x86_64/pull/70) (released as version 0.5.5).
- [Make FrameAllocator an unsafe trait](https://github.com/rust-osdev/x86_64/pull/71) (released as version 0.6.0).
- [Change Port::read and PortReadOnly::read to take &mut self](https://github.com/rust-osdev/x86_64/pull/76) (released as version 0.7.0).
- [@npmccallum](https://github.com/npmccallum) started working on [moving the type declarations to a separate crate](https://github.com/rust-osdev/x86_64/issues/72) to make them usable for more projects. We created the experimental [x86_64_types](http://github.com/rust-osdev/x86_64_types/) crate for this.
- [@npmccallum](https://github.com/npmccallum) started working on [moving the type declarations to a separate crate](https://github.com/rust-osdev/x86_64/issues/72) to make them usable for more projects. We created the experimental [x86_64_types](https://github.com/rust-osdev/x86_64_types/) crate for this.
## Cargo-Xbuild

View File

@@ -95,7 +95,7 @@
</path>
</g>
</svg>
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"></div></div></div><div id="isso-198" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="666df3217240"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="12" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Philipp Oppermann</span><span class="spacer"></span><a rel="nofollow" href="#isso-198" class="permalink"><time title="Sun May 29 2016 12:59:05 GMT+0200 (Central European Summer Time)" datetime="2016-04-00T10:59:05Z">vor 3 Jahren</time></a><span class="note"></span></div><div class="text"><p>I'm a computer science student and I've taken some great OS courses. It's also a hobby of mine and I've experimented with a lot with toy x86 kernels and Rust. Most of the x86 information is from the <a rel="nofollow" href="http://wiki.osdev.org/Main_Page">OSDev wiki</a> and the <a rel="nofollow" href="http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html">Intel</a>/<a rel="nofollow" href="https://developer.amd.com/resources/developer-guides-manuals/">AMD</a> manuals.</p><p>I also have a great research assistant job since November, where I try to bring Rust to an ARM Cortex-M7 board.</p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"></div></div></div><div id="isso-198" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="666df3217240"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="12" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Philipp Oppermann</span><span class="spacer"></span><a rel="nofollow" href="#isso-198" class="permalink"><time title="Sun May 29 2016 12:59:05 GMT+0200 (Central European Summer Time)" datetime="2016-04-00T10:59:05Z">vor 3 Jahren</time></a><span class="note"></span></div><div class="text"><p>I'm a computer science student and I've taken some great OS courses. It's also a hobby of mine and I've experimented with a lot with toy x86 kernels and Rust. Most of the x86 information is from the <a rel="nofollow" href="https://wiki.osdev.org/Main_Page">OSDev wiki</a> and the <a rel="nofollow" href="http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html">Intel</a>/<a rel="nofollow" href="https://developer.amd.com/resources/developer-guides-manuals/">AMD</a> manuals.</p><p>I also have a great research assistant job since November, where I try to bring Rust to an ARM Cortex-M7 board.</p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
<g>
<path d="M 24.773,18.299c-0.651-0.669-7.512-7.203-7.512-7.203C 16.912,10.739, 16.456,10.56, 16,10.56c-0.458,0-0.914,0.179-1.261,0.536 c0,0-6.861,6.534-7.514,7.203c-0.651,0.669-0.696,1.872,0,2.586c 0.698,0.712, 1.669,0.77, 2.522,0L 16,14.89l 6.251,5.995 c 0.854,0.77, 1.827,0.712, 2.522,0C 25.47,20.17, 25.427,18.966, 24.773,18.299z">
</path>

View File

@@ -83,7 +83,7 @@
</path>
</g>
</svg>
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"></div></div></div><div id="isso-234" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="666df3217240"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="12" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Philipp Oppermann</span><span class="spacer"></span><a rel="nofollow" href="#isso-234" class="permalink"><time title="Thu Oct 29 2015 20:32:02 GMT+0100 (Central European Standard Time)" datetime="2015-09-04T19:32:02Z">vor 4 Jahren</time></a><span class="note"></span></div><div class="text"><p></p><blockquote>Are there any OS development books that you recommend for ideas on further enhancing this basic system?</blockquote><p></p><p>Well, there is the <a rel="nofollow" href="http://pages.cs.wisc.edu/~remzi/OSTEP/">Three Easy Pieces</a> book I linked in the post, which gives a theoretical overview over different OS concepts. Then there's <a rel="nofollow" href="http://littleosbook.github.io">the little book about OS development</a>, which is more practical and contains C example code. Of course there are <a rel="nofollow" href="http://wiki.osdev.org/Books#Operating_Systems">many paid books</a>, too.</p><p>Besides books, the <a rel="nofollow" href="http://wiki.osdev.org/Main_Page">OSDev Wiki</a> is also a good resource for many topics. Looking at the source of e.g. <a rel="nofollow" href="https://github.com/redox-os/redox">Redox</a> can be helpful, too.</p><p>For exotical ideas, I really like the concept of <a rel="nofollow" href="https://en.wikipedia.org/wiki/Phantom_OS">Phantom OS</a> and Rust's memory safety might allow something similar… We'll see ;)</p><p></p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"></div></div></div><div id="isso-234" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="666df3217240"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="12" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Philipp Oppermann</span><span class="spacer"></span><a rel="nofollow" href="#isso-234" class="permalink"><time title="Thu Oct 29 2015 20:32:02 GMT+0100 (Central European Standard Time)" datetime="2015-09-04T19:32:02Z">vor 4 Jahren</time></a><span class="note"></span></div><div class="text"><p></p><blockquote>Are there any OS development books that you recommend for ideas on further enhancing this basic system?</blockquote><p></p><p>Well, there is the <a rel="nofollow" href="http://pages.cs.wisc.edu/~remzi/OSTEP/">Three Easy Pieces</a> book I linked in the post, which gives a theoretical overview over different OS concepts. Then there's <a rel="nofollow" href="http://littleosbook.github.io">the little book about OS development</a>, which is more practical and contains C example code. Of course there are <a rel="nofollow" href="https://wiki.osdev.org/Books#Operating_Systems">many paid books</a>, too.</p><p>Besides books, the <a rel="nofollow" href="https://wiki.osdev.org/Main_Page">OSDev Wiki</a> is also a good resource for many topics. Looking at the source of e.g. <a rel="nofollow" href="https://github.com/redox-os/redox">Redox</a> can be helpful, too.</p><p>For exotical ideas, I really like the concept of <a rel="nofollow" href="https://en.wikipedia.org/wiki/Phantom_OS">Phantom OS</a> and Rust's memory safety might allow something similar… We'll see ;)</p><p></p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
<g>
<path d="M 24.773,18.299c-0.651-0.669-7.512-7.203-7.512-7.203C 16.912,10.739, 16.456,10.56, 16,10.56c-0.458,0-0.914,0.179-1.261,0.536 c0,0-6.861,6.534-7.514,7.203c-0.651,0.669-0.696,1.872,0,2.586c 0.698,0.712, 1.669,0.77, 2.522,0L 16,14.89l 6.251,5.995 c 0.854,0.77, 1.827,0.712, 2.522,0C 25.47,20.17, 25.427,18.966, 24.773,18.299z">
</path>
@@ -359,7 +359,7 @@
</path>
</g>
</svg>
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"></div></div></div><div id="isso-253" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="666df3217240"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="12" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Philipp Oppermann</span><span class="spacer"></span><a rel="nofollow" href="#isso-253" class="permalink"><time title="Wed Mar 02 2016 16:30:12 GMT+0100 (Central European Standard Time)" datetime="2016-02-03T15:30:12Z">vor 3 Jahren</time></a><span class="note"></span></div><div class="text"><p>Thanks for the overview and the simplified example! I haven't had the time to look at it in detail, but the problem in your simplified example could be the <a rel="nofollow" href="http://wiki.osdev.org/Programmable_Interval_Timer">Programmable Interval timer</a>. From the “Outputs” section:</p><p></p><blockquote>The output from PIT channel 0 is connected to the PIC chip, so that it generates an "IRQ 0". Typically during boot the BIOS sets channel 0 with a count of 65535 or 0 (which translates to 65536), which gives an output frequency of 18.2065 Hz (or an IRQ every 54.9254 ms).</blockquote><p></p><p>So it seems like the BIOS turns it on by default so that it causes an interrupts every ~55ms. This causes a double fault, since there is no interrupt handler for IRQ 0.</p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"></div></div></div><div id="isso-253" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="666df3217240"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="12" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Philipp Oppermann</span><span class="spacer"></span><a rel="nofollow" href="#isso-253" class="permalink"><time title="Wed Mar 02 2016 16:30:12 GMT+0100 (Central European Standard Time)" datetime="2016-02-03T15:30:12Z">vor 3 Jahren</time></a><span class="note"></span></div><div class="text"><p>Thanks for the overview and the simplified example! I haven't had the time to look at it in detail, but the problem in your simplified example could be the <a rel="nofollow" href="https://wiki.osdev.org/Programmable_Interval_Timer">Programmable Interval timer</a>. From the “Outputs” section:</p><p></p><blockquote>The output from PIT channel 0 is connected to the PIC chip, so that it generates an "IRQ 0". Typically during boot the BIOS sets channel 0 with a count of 65535 or 0 (which translates to 65536), which gives an output frequency of 18.2065 Hz (or an IRQ every 54.9254 ms).</blockquote><p></p><p>So it seems like the BIOS turns it on by default so that it causes an interrupts every ~55ms. This causes a double fault, since there is no interrupt handler for IRQ 0.</p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
<g>
<path d="M 24.773,18.299c-0.651-0.669-7.512-7.203-7.512-7.203C 16.912,10.739, 16.456,10.56, 16,10.56c-0.458,0-0.914,0.179-1.261,0.536 c0,0-6.861,6.534-7.514,7.203c-0.651,0.669-0.696,1.872,0,2.586c 0.698,0.712, 1.669,0.77, 2.522,0L 16,14.89l 6.251,5.995 c 0.854,0.77, 1.827,0.712, 2.522,0C 25.47,20.17, 25.427,18.966, 24.773,18.299z">
</path>
@@ -383,7 +383,7 @@
</path>
</g>
</svg>
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"></div></div></div><div id="isso-255" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="3773460ec1e4"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="4" width="8" height="8" style="fill: #be5168"></rect><rect x="36" y="4" width="8" height="8" style="fill: #be5168"></rect><rect x="4" y="20" width="8" height="8" style="fill: #be5168"></rect><rect x="36" y="20" width="8" height="8" style="fill: #be5168"></rect><rect x="4" y="28" width="8" height="8" style="fill: #be5168"></rect><rect x="36" y="28" width="8" height="8" style="fill: #be5168"></rect><rect x="12" y="36" width="8" height="8" style="fill: #be5168"></rect><rect x="28" y="36" width="8" height="8" style="fill: #be5168"></rect><rect x="20" y="4" width="8" height="8" style="fill: #be5168"></rect><rect x="20" y="12" width="8" height="8" style="fill: #be5168"></rect><rect x="20" y="20" width="8" height="8" style="fill: #be5168"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Wink Saville</span><span class="spacer"></span><a rel="nofollow" href="#isso-255" class="permalink"><time title="Fri Mar 04 2016 01:53:38 GMT+0100 (Central European Standard Time)" datetime="2016-02-05T00:53:38Z">vor 3 Jahren</time></a><span class="note"></span></div><div class="text"><p>Here is a solution. There doesn't seem to be a way to disable the PIT, but you can disable all IRQ's from the PIC, adding the following code to my test_enable_interrupts branch allows the code to work even with the enabling interrupts:</p><p>```<br> ; Disable PIC interrupts so we don't get interrupts if the PIC<br> ; was being used by grub or BIOS. See Disabling section of<br> ; <a rel="nofollow" href="http://wiki.osdev.org/PIC">http://wiki.osdev.org/PIC</a>. If the application wants to use devices<br>; connected to the PIC, such at the PIT, it will probably want<br> ; to remap the PIC interrupts to be above 0 .. 31 which are<br> ; used or reserved by Intel. See the Initialisation section of<br> ; the same page for the PIC_remap subroutine.</p><p> mov al,0xff<br> out 0xa1, al<br> out 0x21, al<br>```</p><p>Thanks again for your help.</p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"></div></div></div><div id="isso-255" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="3773460ec1e4"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="4" width="8" height="8" style="fill: #be5168"></rect><rect x="36" y="4" width="8" height="8" style="fill: #be5168"></rect><rect x="4" y="20" width="8" height="8" style="fill: #be5168"></rect><rect x="36" y="20" width="8" height="8" style="fill: #be5168"></rect><rect x="4" y="28" width="8" height="8" style="fill: #be5168"></rect><rect x="36" y="28" width="8" height="8" style="fill: #be5168"></rect><rect x="12" y="36" width="8" height="8" style="fill: #be5168"></rect><rect x="28" y="36" width="8" height="8" style="fill: #be5168"></rect><rect x="20" y="4" width="8" height="8" style="fill: #be5168"></rect><rect x="20" y="12" width="8" height="8" style="fill: #be5168"></rect><rect x="20" y="20" width="8" height="8" style="fill: #be5168"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Wink Saville</span><span class="spacer"></span><a rel="nofollow" href="#isso-255" class="permalink"><time title="Fri Mar 04 2016 01:53:38 GMT+0100 (Central European Standard Time)" datetime="2016-02-05T00:53:38Z">vor 3 Jahren</time></a><span class="note"></span></div><div class="text"><p>Here is a solution. There doesn't seem to be a way to disable the PIT, but you can disable all IRQ's from the PIC, adding the following code to my test_enable_interrupts branch allows the code to work even with the enabling interrupts:</p><p>```<br> ; Disable PIC interrupts so we don't get interrupts if the PIC<br> ; was being used by grub or BIOS. See Disabling section of<br> ; <a rel="nofollow" href="https://wiki.osdev.org/PIC">https://wiki.osdev.org/PIC</a>. If the application wants to use devices<br>; connected to the PIC, such at the PIT, it will probably want<br> ; to remap the PIC interrupts to be above 0 .. 31 which are<br> ; used or reserved by Intel. See the Initialisation section of<br> ; the same page for the PIC_remap subroutine.</p><p> mov al,0xff<br> out 0xa1, al<br> out 0x21, al<br>```</p><p>Thanks again for your help.</p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
<g>
<path d="M 24.773,18.299c-0.651-0.669-7.512-7.203-7.512-7.203C 16.912,10.739, 16.456,10.56, 16,10.56c-0.458,0-0.914,0.179-1.261,0.536 c0,0-6.861,6.534-7.514,7.203c-0.651,0.669-0.696,1.872,0,2.586c 0.698,0.712, 1.669,0.77, 2.522,0L 16,14.89l 6.251,5.995 c 0.854,0.77, 1.827,0.712, 2.522,0C 25.47,20.17, 25.427,18.966, 24.773,18.299z">
</path>

View File

@@ -215,7 +215,7 @@
</path>
</g>
</svg>
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"></div></div></div><div id="isso-135" class="isso-comment"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="4ac55151f530"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="20" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="20" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="20" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="20" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="20" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="28" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Arnaud Bailly</span><span class="spacer"></span><a rel="nofollow" href="#isso-135" class="permalink"><time title="Thu Nov 12 2015 10:04:06 GMT+0100 (Central European Standard Time)" datetime="2015-10-04T09:04:06Z">vor 4 Jahren</time></a><span class="note"></span></div><div class="text"><p>This is definitely fun! I tried to do this from my Mac OS X (Yosemite) and could not properly boot my fresh ISO disk. Compilation works fine, I have installed a cross-compiler for x86_64-elf architecture, compiled grub following instructions here <a rel="nofollow" href="http://wiki.osdev.org/GRUB_2#Installing_GRUB2_on_Mac_OS_X">http://wiki.osdev.org/GRUB_...</a>... I generate a correct ISO file (checked it by mounting using Disk Utility) but it does not boot and I cannot see the GRUB message.</p><p>Not sure how to troubleshoot this issue.... I suspect this might be a problem with incorrect format in grub as the last stage of compilation shows this message:</p><p> ../grub/configure --build=x86_64-elf --target=x86_64-elf --disable-werror TARGET_CC=x86_64-elf-gcc TARGET_OBJCOPY=x86_64-elf-objcopy TARGET_STRIP=x86_64-elf-strip TARGET_NM=x86_64-elf-nm TARGET_RANLIB=x86_64-elf-ranlib LD_FLAGS=/usr/local/opt/flex/ CPP_FLAGS=/usr/local/opt/flex/include/</p><p>[..]</p><p>config.status: linking ../grub/include/grub/i386 to include/grub/cpu<br>config.status: linking ../grub/include/grub/i386/pc to include/grub/machine<br>config.status: executing depfiles commands<br>config.status: executing po-directories commands<br>config.status: creating po/POTFILES<br>config.status: creating po/Makefile<br>*******************************************************<br>GRUB2 will be compiled with following components:<br>Platform: i386-pc<br>With devmapper support: No (need libdevmapper header)<br>With memory debugging: No<br>With disk cache statistics: No<br>With boot time statistics: No<br>efiemu runtime: Yes<br>grub-mkfont: Yes<br>grub-mount: No (need FUSE headers)<br>starfield theme: No (No DejaVu found)<br>With libzfs support: No (need zfs library)<br>Build-time grub-mkfont: No (no fonts)<br>Without unifont (no build-time grub-mkfont)<br>With liblzma from -llzma (support for XZ-compressed mips images)<br>*******************************************************</p><p>I don't know what the i386-pc refer too, but if this is the target platform then it's probably incorrect. Note that I tried to boot using qemu-system-i386 but to no avail.</p><p>Regards,</p></div><div class="isso-comment-footer"><span class="votes">-1</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"></div></div></div><div id="isso-135" class="isso-comment"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="4ac55151f530"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="20" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="20" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="20" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="20" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="20" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="28" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Arnaud Bailly</span><span class="spacer"></span><a rel="nofollow" href="#isso-135" class="permalink"><time title="Thu Nov 12 2015 10:04:06 GMT+0100 (Central European Standard Time)" datetime="2015-10-04T09:04:06Z">vor 4 Jahren</time></a><span class="note"></span></div><div class="text"><p>This is definitely fun! I tried to do this from my Mac OS X (Yosemite) and could not properly boot my fresh ISO disk. Compilation works fine, I have installed a cross-compiler for x86_64-elf architecture, compiled grub following instructions here <a rel="nofollow" href="https://wiki.osdev.org/GRUB_2#Installing_GRUB2_on_Mac_OS_X">https://wiki.osdev.org/GRUB_...</a>... I generate a correct ISO file (checked it by mounting using Disk Utility) but it does not boot and I cannot see the GRUB message.</p><p>Not sure how to troubleshoot this issue.... I suspect this might be a problem with incorrect format in grub as the last stage of compilation shows this message:</p><p> ../grub/configure --build=x86_64-elf --target=x86_64-elf --disable-werror TARGET_CC=x86_64-elf-gcc TARGET_OBJCOPY=x86_64-elf-objcopy TARGET_STRIP=x86_64-elf-strip TARGET_NM=x86_64-elf-nm TARGET_RANLIB=x86_64-elf-ranlib LD_FLAGS=/usr/local/opt/flex/ CPP_FLAGS=/usr/local/opt/flex/include/</p><p>[..]</p><p>config.status: linking ../grub/include/grub/i386 to include/grub/cpu<br>config.status: linking ../grub/include/grub/i386/pc to include/grub/machine<br>config.status: executing depfiles commands<br>config.status: executing po-directories commands<br>config.status: creating po/POTFILES<br>config.status: creating po/Makefile<br>*******************************************************<br>GRUB2 will be compiled with following components:<br>Platform: i386-pc<br>With devmapper support: No (need libdevmapper header)<br>With memory debugging: No<br>With disk cache statistics: No<br>With boot time statistics: No<br>efiemu runtime: Yes<br>grub-mkfont: Yes<br>grub-mount: No (need FUSE headers)<br>starfield theme: No (No DejaVu found)<br>With libzfs support: No (need zfs library)<br>Build-time grub-mkfont: No (no fonts)<br>Without unifont (no build-time grub-mkfont)<br>With liblzma from -llzma (support for XZ-compressed mips images)<br>*******************************************************</p><p>I don't know what the i386-pc refer too, but if this is the target platform then it's probably incorrect. Note that I tried to boot using qemu-system-i386 but to no avail.</p><p>Regards,</p></div><div class="isso-comment-footer"><span class="votes">-1</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
<g>
<path d="M 24.773,18.299c-0.651-0.669-7.512-7.203-7.512-7.203C 16.912,10.739, 16.456,10.56, 16,10.56c-0.458,0-0.914,0.179-1.261,0.536 c0,0-6.861,6.534-7.514,7.203c-0.651,0.669-0.696,1.872,0,2.586c 0.698,0.712, 1.669,0.77, 2.522,0L 16,14.89l 6.251,5.995 c 0.854,0.77, 1.827,0.712, 2.522,0C 25.47,20.17, 25.427,18.966, 24.773,18.299z">
</path>
@@ -287,7 +287,7 @@
</path>
</g>
</svg>
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"><div id="isso-140" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="666df3217240"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="12" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Philipp Oppermann</span><span class="spacer"></span><a rel="nofollow" href="#isso-140" class="permalink"><time title="Wed Nov 18 2015 22:46:08 GMT+0100 (Central European Standard Time)" datetime="2015-10-03T21:46:08Z">vor 4 Jahren</time></a><span class="note"></span></div><div class="text"><p>Yes, that exactly what happens. The CPU simply tries to read the next instruction, even if it doesn't exist, until it causes some <a rel="nofollow" href="http://wiki.osdev.org/Exceptions">exception</a>. QEMU can print these exceptions, the "Setup Rust" post explains <a rel="nofollow" href="http://os.phil-opp.com/setup-rust.html#debugging">how</a>. I just tried it and it hits an Invalid Opcode exception at some point because some memory is no valid instruction.</p><p>Bonus: You can use GDB to disassemble the “code” behind the start label. You need to start `qemu-system-x86_64 -hda build/os-x86_64.iso -s -S` in one console and `gdb build/kernel-x86_64.bin` in another. Then you need the following gdb commands:</p><p>- `set architecture i386` because we are still in 32-bit mode<br>- `target remote :1234` to connect to QEMU<br>(- `disas /r start,+250` to disassemble the 250 bytes after the `start` label. Everything will be 0 as GRUB did not load our kernel yet)<br>- `break start` to set a breakpoint at `start`<br>- `continue` to continue execution until start is reached. Now the kernel is loaded and we can use<br>- `disas /r start,+250` to disassemble the 250 bytes after the `start` label</p><p>Then you can look at the faulting address you got from the QEMU debugging to see your invalid instruction. For me it seems to be an `add (%eax),%al` with the Opcode `02 00`.</p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"><div id="isso-140" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="666df3217240"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="12" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Philipp Oppermann</span><span class="spacer"></span><a rel="nofollow" href="#isso-140" class="permalink"><time title="Wed Nov 18 2015 22:46:08 GMT+0100 (Central European Standard Time)" datetime="2015-10-03T21:46:08Z">vor 4 Jahren</time></a><span class="note"></span></div><div class="text"><p>Yes, that exactly what happens. The CPU simply tries to read the next instruction, even if it doesn't exist, until it causes some <a rel="nofollow" href="https://wiki.osdev.org/Exceptions">exception</a>. QEMU can print these exceptions, the "Setup Rust" post explains <a rel="nofollow" href="http://os.phil-opp.com/setup-rust.html#debugging">how</a>. I just tried it and it hits an Invalid Opcode exception at some point because some memory is no valid instruction.</p><p>Bonus: You can use GDB to disassemble the “code” behind the start label. You need to start `qemu-system-x86_64 -hda build/os-x86_64.iso -s -S` in one console and `gdb build/kernel-x86_64.bin` in another. Then you need the following gdb commands:</p><p>- `set architecture i386` because we are still in 32-bit mode<br>- `target remote :1234` to connect to QEMU<br>(- `disas /r start,+250` to disassemble the 250 bytes after the `start` label. Everything will be 0 as GRUB did not load our kernel yet)<br>- `break start` to set a breakpoint at `start`<br>- `continue` to continue execution until start is reached. Now the kernel is loaded and we can use<br>- `disas /r start,+250` to disassemble the 250 bytes after the `start` label</p><p>Then you can look at the faulting address you got from the QEMU debugging to see your invalid instruction. For me it seems to be an `add (%eax),%al` with the Opcode `02 00`.</p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
<g>
<path d="M 24.773,18.299c-0.651-0.669-7.512-7.203-7.512-7.203C 16.912,10.739, 16.456,10.56, 16,10.56c-0.458,0-0.914,0.179-1.261,0.536 c0,0-6.861,6.534-7.514,7.203c-0.651,0.669-0.696,1.872,0,2.586c 0.698,0.712, 1.669,0.77, 2.522,0L 16,14.89l 6.251,5.995 c 0.854,0.77, 1.827,0.712, 2.522,0C 25.47,20.17, 25.427,18.966, 24.773,18.299z">
</path>
@@ -743,7 +743,7 @@
</path>
</g>
</svg>
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"><div id="isso-298" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="5db23f819f9f"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #447c69"></rect><rect x="36" y="12" width="8" height="8" style="fill: #447c69"></rect><rect x="4" y="20" width="8" height="8" style="fill: #447c69"></rect><rect x="36" y="20" width="8" height="8" style="fill: #447c69"></rect><rect x="12" y="4" width="8" height="8" style="fill: #447c69"></rect><rect x="28" y="4" width="8" height="8" style="fill: #447c69"></rect><rect x="12" y="12" width="8" height="8" style="fill: #447c69"></rect><rect x="28" y="12" width="8" height="8" style="fill: #447c69"></rect><rect x="12" y="20" width="8" height="8" style="fill: #447c69"></rect><rect x="28" y="20" width="8" height="8" style="fill: #447c69"></rect><rect x="12" y="28" width="8" height="8" style="fill: #447c69"></rect><rect x="28" y="28" width="8" height="8" style="fill: #447c69"></rect><rect x="12" y="36" width="8" height="8" style="fill: #447c69"></rect><rect x="28" y="36" width="8" height="8" style="fill: #447c69"></rect><rect x="20" y="4" width="8" height="8" style="fill: #447c69"></rect><rect x="20" y="28" width="8" height="8" style="fill: #447c69"></rect><rect x="20" y="36" width="8" height="8" style="fill: #447c69"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header">Philipp Oppermann<span class="spacer"></span><a rel="nofollow" href="#isso-298" class="permalink"><time title="Mon Jun 19 2017 13:39:01 GMT+0200 (Central European Summer Time)" datetime="2017-05-01T11:39:01Z">letztes Jahr</time></a><span class="note"></span></div><div class="text"><p>See <a rel="nofollow" href="http://wiki.osdev.org/Shutdown">http://wiki.osdev.org/Shutdown</a></p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"><div id="isso-298" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="5db23f819f9f"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #447c69"></rect><rect x="36" y="12" width="8" height="8" style="fill: #447c69"></rect><rect x="4" y="20" width="8" height="8" style="fill: #447c69"></rect><rect x="36" y="20" width="8" height="8" style="fill: #447c69"></rect><rect x="12" y="4" width="8" height="8" style="fill: #447c69"></rect><rect x="28" y="4" width="8" height="8" style="fill: #447c69"></rect><rect x="12" y="12" width="8" height="8" style="fill: #447c69"></rect><rect x="28" y="12" width="8" height="8" style="fill: #447c69"></rect><rect x="12" y="20" width="8" height="8" style="fill: #447c69"></rect><rect x="28" y="20" width="8" height="8" style="fill: #447c69"></rect><rect x="12" y="28" width="8" height="8" style="fill: #447c69"></rect><rect x="28" y="28" width="8" height="8" style="fill: #447c69"></rect><rect x="12" y="36" width="8" height="8" style="fill: #447c69"></rect><rect x="28" y="36" width="8" height="8" style="fill: #447c69"></rect><rect x="20" y="4" width="8" height="8" style="fill: #447c69"></rect><rect x="20" y="28" width="8" height="8" style="fill: #447c69"></rect><rect x="20" y="36" width="8" height="8" style="fill: #447c69"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header">Philipp Oppermann<span class="spacer"></span><a rel="nofollow" href="#isso-298" class="permalink"><time title="Mon Jun 19 2017 13:39:01 GMT+0200 (Central European Summer Time)" datetime="2017-05-01T11:39:01Z">letztes Jahr</time></a><span class="note"></span></div><div class="text"><p>See <a rel="nofollow" href="https://wiki.osdev.org/Shutdown">https://wiki.osdev.org/Shutdown</a></p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
<g>
<path d="M 24.773,18.299c-0.651-0.669-7.512-7.203-7.512-7.203C 16.912,10.739, 16.456,10.56, 16,10.56c-0.458,0-0.914,0.179-1.261,0.536 c0,0-6.861,6.534-7.514,7.203c-0.651,0.669-0.696,1.872,0,2.586c 0.698,0.712, 1.669,0.77, 2.522,0L 16,14.89l 6.251,5.995 c 0.854,0.77, 1.827,0.712, 2.522,0C 25.47,20.17, 25.427,18.966, 24.773,18.299z">
</path>

View File

@@ -300,7 +300,7 @@ May be you used cross compiled 'ld' ?</p></div><div class="isso-comment-footer">
</path>
</g>
</svg>
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"><div id="isso-106" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="666df3217240"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="12" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Philipp Oppermann</span><span class="spacer"></span><a rel="nofollow" href="#isso-106" class="permalink"><time title="Thu Jul 14 2016 10:04:05 GMT+0200 (Central European Summer Time)" datetime="2016-06-04T08:04:05Z">vor 3 Jahren</time></a><span class="note"></span></div><div class="text"><p>Good catch! However, SSE2 should always be available if the long mode is available. Citing the <a rel="nofollow" href="http://wiki.osdev.org/SSE">OSDev wiki</a>:</p><p></p><blockquote>When the X86-64 architecture was introduced, AMD demanded a minimum level of SSE support to simplify OS code. Any system capable of long mode should support at least SSE and SSE2</blockquote><p></p><p>So SSE and SSE2 should always be available in our case (if the wiki is correct). So we could even remove the SSE check. However, I think it's better to leave it in, because we enable SSE before switching to long mode.</p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
</a><a rel="nofollow" href="#" class="reply">Antworten</a></div><div class="isso-follow-up"><div id="isso-106" class="isso-comment isso-no-votes"><div class="avatar"><svg version="1.1" viewBox="0 0 48 48" preserveAspectRatio="xMinYMin meet" shape-rendering="crispEdges" data-hash="666df3217240"><rect x="0" y="0" width="56" height="56" style="fill: #f0f0f0"></rect><rect x="4" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="12" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="4" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="36" y="36" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="4" width="8" height="8" style="fill: #9abf88"></rect><rect x="12" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="28" y="28" width="8" height="8" style="fill: #9abf88"></rect><rect x="20" y="12" width="8" height="8" style="fill: #9abf88"></rect></svg></div><div class="text-wrapper"><div role="meta" class="isso-comment-header"><span class="author">Philipp Oppermann</span><span class="spacer"></span><a rel="nofollow" href="#isso-106" class="permalink"><time title="Thu Jul 14 2016 10:04:05 GMT+0200 (Central European Summer Time)" datetime="2016-06-04T08:04:05Z">vor 3 Jahren</time></a><span class="note"></span></div><div class="text"><p>Good catch! However, SSE2 should always be available if the long mode is available. Citing the <a rel="nofollow" href="https://wiki.osdev.org/SSE">OSDev wiki</a>:</p><p></p><blockquote>When the X86-64 architecture was introduced, AMD demanded a minimum level of SSE support to simplify OS code. Any system capable of long mode should support at least SSE and SSE2</blockquote><p></p><p>So SSE and SSE2 should always be available in our case (if the wiki is correct). So we could even remove the SSE check. However, I think it's better to leave it in, because we enable SSE before switching to long mode.</p></div><div class="isso-comment-footer"><span class="votes">0</span><a rel="nofollow" href="#" class="upvote"><!-- Generator: IcoMoon.io --><svg width="16" height="16" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="gray">
<g>
<path d="M 24.773,18.299c-0.651-0.669-7.512-7.203-7.512-7.203C 16.912,10.739, 16.456,10.56, 16,10.56c-0.458,0-0.914,0.179-1.261,0.536 c0,0-6.861,6.534-7.514,7.203c-0.651,0.669-0.696,1.872,0,2.586c 0.698,0.712, 1.669,0.77, 2.522,0L 16,14.89l 6.251,5.995 c 0.854,0.77, 1.827,0.712, 2.522,0C 25.47,20.17, 25.427,18.966, 24.773,18.299z">
</path>