diff --git a/blog/content/second-edition/extra/_index.md b/blog/content/second-edition/extra/_index.md new file mode 100644 index 00000000..72c0bc40 --- /dev/null +++ b/blog/content/second-edition/extra/_index.md @@ -0,0 +1,6 @@ ++++ +title = "Extra Content" +insert_anchor_links = "left" +render = false +sort_by = "order" ++++ diff --git a/blog/content/second-edition/extra/disable-red-zone/index.md b/blog/content/second-edition/extra/disable-red-zone/index.md new file mode 100644 index 00000000..b677b625 --- /dev/null +++ b/blog/content/second-edition/extra/disable-red-zone/index.md @@ -0,0 +1,27 @@ ++++ +title = "Disable the Red Zone" +order = 1 +path = "red-zone" +template = "second-edition/extra.html" ++++ + +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 + +![stack frame with red zone](red-zone.svg) + +The image shows the stack frame of a function with `n` local variables. On function entry, the stack pointer is adjusted to make room on the stack for the return address and the local variables. + +The red zone is defined as the 128 bytes below the adjusted stack pointer. The function can use this area for temporary data that's not needed across function calls. Thus, the two instructions for adjusting the stack pointer can be avoided in some cases (e.g. in small leaf functions). + +However, this optimization leads to huge problems with exceptions or hardware interrupts. Let's assume that an exception occurs while a function uses the red zone: + +![red zone overwritten by exception handler](red-zone-overwrite.svg) + +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 + +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. diff --git a/blog/content/second-edition/extra/disable-red-zone/red-zone-overwrite.svg b/blog/content/second-edition/extra/disable-red-zone/red-zone-overwrite.svg new file mode 100644 index 00000000..d3be0805 --- /dev/null +++ b/blog/content/second-edition/extra/disable-red-zone/red-zone-overwrite.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + Old Stack Pointer + + + + + + + + + + + + + + + + + + + Return Address + + + + + + + + + + Local Variable 1 + + + + + + + Local Variables 2..n + + + + + + + + + Red Zone + + + 128 bytes + + + + + + + Exception Stack Frame + + + + + + + Register Backup + + + + + + + Handler Function Stack Frame + + + + + + + + + New Stack Pointer + + diff --git a/blog/content/second-edition/extra/disable-red-zone/red-zone.svg b/blog/content/second-edition/extra/disable-red-zone/red-zone.svg new file mode 100644 index 00000000..c5194ca8 --- /dev/null +++ b/blog/content/second-edition/extra/disable-red-zone/red-zone.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + Stack Pointer + + + + + + + + + + + + + + + + + + + Return Address + + + + + + + + + + Local Variable 1 + + + + + + + Local Variables 2..n + + + + + + + + + Red Zone + + + 128 bytes + + diff --git a/blog/content/second-edition/extra/disable-simd/index.md b/blog/content/second-edition/extra/disable-simd/index.md new file mode 100644 index 00000000..785c8b2e --- /dev/null +++ b/blog/content/second-edition/extra/disable-simd/index.md @@ -0,0 +1,42 @@ ++++ +title = "Disable SIMD" +order = 2 +path = "disable-simd" +template = "second-edition/extra.html" ++++ + +[Single Instruction Multiple Data (SIMD)] instructions are able to perform an operation (e.g. addition) simultaneously on multiple data words, which can speed up programs significantly. The `x86_64` architecture supports various SIMD standards: + +[Single Instruction Multiple Data (SIMD)]: https://en.wikipedia.org/wiki/SIMD + +- [MMX]: The _Multi Media Extension_ instruction set was introduced in 1997 and defines eight 64 bit registers called `mm0` through `mm7`. These registers are just aliases for the registers of the [x87 floating point unit]. +- [SSE]: The _Streaming SIMD Extensions_ instruction set was introduced in 1999. Instead of re-using the floating point registers, it adds a completely new register set. The sixteen new registers are called `xmm0` through `xmm15` and are 128 bits each. +- [AVX]: The _Advanced Vector Extensions_ are extensions that further increase the size of the multimedia registers. The new registers are called `ymm0` through `ymm15` and are 256 bits each. They extend the `xmm` registers, so e.g. `xmm0` is the lower half of `ymm0`. + +[MMX]: https://en.wikipedia.org/wiki/MMX_(instruction_set) +[x87 floating point unit]: https://en.wikipedia.org/wiki/X87 +[SSE]: https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions +[AVX]: https://en.wikipedia.org/wiki/Advanced_Vector_Extensions + +By using such SIMD standards, programs can often speed up significantly. Good compilers are able to transform normal loops into such SIMD code automatically through a process called [auto-vectorization]. + +[auto-vectorization]: https://en.wikipedia.org/wiki/Automatic_vectorization + +However, the large SIMD registers lead to problems in OS kernels. The reason is that the kernel has to backup all registers that it uses in hardware interrupt, because they need to have their original values when the interrupted program continues. So if the kernel uses SIMD registers, it has to backup a lot more data, which noticably decreases performance. To avoid this performance loss, we want to disable the `sse` and `mmx` features (the `avx` feature is disabled by default). + +We can do that through the the `features` field in our target specification. To disable the `mmx` and `sse` features we add them prefixed with a minus: + +```json +"features": "-mmx,-sse" +``` + +## Floating Point +Unfortunately for us, the `x86_64` architecture uses SSE registers for floating point operations. Thus, every use of floating point with disabled SSE causes an error in LLVM. The problem is that Rust's core library already uses floats (e.g., it implements traits for `f32` and `f64`), so avoiding floats in our kernel does not suffice. + +Fortunately, LLVM has support for a `soft-float` feature, emulates all floating point operations through software functions based on normal integers. This makes it possible to use floats in our kernel without SSE, it will just be a bit slower. + +To turn on the `soft-float` feature for our kernel, we add it to the `features` line in our target specification, prefixed with a plus: + +```json +"features": "-mmx,-sse,+soft-float" +``` diff --git a/blog/content/second-edition/extra/installing-lld/index.md b/blog/content/second-edition/extra/installing-lld/index.md new file mode 100644 index 00000000..94237b41 --- /dev/null +++ b/blog/content/second-edition/extra/installing-lld/index.md @@ -0,0 +1,18 @@ ++++ +title = "Installing LLD" +order = 3 +path = "installing-lld" +template = "second-edition/extra.html" ++++ + +[LLD] is the linker by the LLVM project. It has the big advantage that it is a cross-linker by default. This means that you can link libraries and executables for all kinds of platforms with the same LLD installation. + +[LLD]: https://lld.llvm.org/ + +There are plans to distribute LLD together with the Rust compiler, but is not quite there yet. So you have to install it manually. On this page, we try to describe the installation procedure for as many platforms as possible, so if you have additional information for any listed or unlisted platform, please send a pull request on the [Github repo](https://github.com/phil-opp/blog_os)! + +## Linux +On most Linux distributions LLD can be installed through the package manager. For example, for Debian and Ubuntu there is are official apt sources at . + +## Other Platforms +For Windows and Mac you can download a pre-built LLVM release from , which contains LLD. If there are no pre-compiled versions for your platform (e.g. some other Linux distribution), you can download the source code and [build it yourself](https://lld.llvm.org/#build). diff --git a/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md b/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md index 78203d07..b5f89ef7 100644 --- a/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md +++ b/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md @@ -243,7 +243,9 @@ Let's try it: Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs ``` -TODO linker error LLD +(If you're getting a linking error because LLD could not be found, see our “[Installing LLD]” guide.) + +[Installing LLD]: ./second-edition/extra/installing-lld/index.md It worked! We see that `xargo` cross-compiled the `core` library for our new custom target and then continued to compile our `blog_os` crate. diff --git a/blog/templates/second-edition/extra.html b/blog/templates/second-edition/extra.html new file mode 100644 index 00000000..bc66e273 --- /dev/null +++ b/blog/templates/second-edition/extra.html @@ -0,0 +1,24 @@ +{% extends "second-edition/base.html" %} + +{% block title %}{{ page.title }} | {{ config.title }}{% endblock title %} + +{% block main %} +

{{ page.title }}

+
+ Note: This post is part of the upcoming second edition of “Writing an OS in Rust”, which is still under construction. To read the first edition, go here. +
+ {{ page.content | safe }} +{% endblock main %} + +{% block after_main %} +
+
+

Comments

+ +
+{% endblock after_main %}