Merge pull request #67 from phil-opp/grammar-set_up

Fix grammar: `set up` instead of `setup`
This commit is contained in:
Philipp Oppermann
2015-12-13 19:36:00 +01:00
4 changed files with 19 additions and 18 deletions

View File

@@ -4,7 +4,7 @@ title: 'Entering Long Mode'
redirect_from: "/2015/08/25/entering-longmode/"
updated: 2015-10-29 00:00:00 +0000
---
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 setup _Paging_ and switch to the 64-bit [long mode] first.
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.
I tried to explain everything in detail and to keep the code as simple as possible. If you have any questions, suggestions, or issues, please leave a comment or [create an issue] on Github. The source code is available in a [repository][source code], too.
@@ -130,7 +130,7 @@ test_long_mode:
jb .no_long_mode ; It is less, there is no long mode.
mov eax, 0x80000001 ; Set the A-register to 0x80000001.
cpuid ; CPU identification.
test edx, 1 << 29 ; Test if the LM-bit, which is bit 29, is set in the D-register.
test edx, 1 << 29 ; Test if the LM-bit is set in the D-register.
jz .no_long_mode ; They aren't, there is no long mode.
ret
.no_long_mode:
@@ -209,7 +209,7 @@ Bit(s) | Name | Meaning
52-62 | available | can be used freely by the OS
63 | no execute | forbid executing code on this page (the NXE bit in the EFER register must be set)
### Setup Identity Paging
### Set Up Identity Paging
When we switch to long mode, paging will be activated automatically. The CPU will then try to read the instruction at the following address, but this address is now a virtual address. So we need to do _identity mapping_, i.e. map a physical address to the same virtual address.
The `huge page` bit is now very useful to us. It creates a 2MiB (when used in P2) or even a 1GiB page (when used in P3). So we could map the first _gigabytes_ of the kernel with only one P4 and one P3 table by using 1GiB pages. Unfortunately 1GiB pages are relatively new feature, for example Intel introduced it 2010 in the [Westmere architecture]. Therefore we will use 2MiB pages instead to make our kernel compatible to older computers, too.
@@ -241,7 +241,7 @@ The `resb` command reserves the specified amount of bytes without initializing t
When GRUB creates the `.bss` section in memory, it will initialize it to `0`. So the `p4_table` is already valid (it contains 512 non-present entries) but not very useful. To be able to map 2MiB pages, we need to link P4's first entry to the `p3_table` and P3's first entry to the the `p2_table`:
```nasm
setup_page_tables:
set_up_page_tables:
; map first P4 entry to P3 table
mov eax, p3_table
or eax, 0b11 ; present + writable
@@ -260,7 +260,7 @@ We just set the present and writable bits (`0b11` is a binary number) in the ali
Now we need to map P2's first entry to a huge page starting at 0, P2's second entry to a huge page starting at 2MiB, P2's third entry to a huge page starting at 4MiB, and so on. It's time for our first (and only) assembly loop:
```nasm
setup_page_tables:
set_up_page_tables:
...
; map each P2 entry to a huge 2MiB page
mov ecx, 0 ; counter variable
@@ -333,7 +333,7 @@ start:
call test_cpuid
call test_long_mode
call setup_page_tables ; new
call set_up_page_tables ; new
call enable_paging ; new
; print `OK` to screen
@@ -344,7 +344,7 @@ start:
To test it we execute `make run`. If the green OK is still printed, we have successfully enabled paging!
## The Global Descriptor Table
After enabling Paging, the processor is in long mode. So we can use 64-bit instructions now, right? Wrong. The processor is still in some 32-bit compatibility submode. To actually execute 64-bit code, we need to setup a new Global Descriptor Table.
After enabling Paging, the processor is in long mode. So we can use 64-bit instructions now, right? Wrong. The processor is still in some 32-bit compatibility submode. To actually execute 64-bit code, we need to set up a new Global Descriptor Table.
The Global Descriptor Table (GDT) was used for _Segmentation_ in old operating systems. I won't explain Segmentation but the [Three Easy Pieces] OS book has good introduction ([PDF][Segmentation chapter]) again.
[Segmentation chapter]: http://pages.cs.wisc.edu/~remzi/OSTEP/vm-segmentation.pdf

View File

@@ -1,17 +1,18 @@
---
layout: post
title: 'Setup Rust'
title: 'Set Up Rust'
redirect_from: "/2015/09/02/setup-rust/"
redirect_from: "/setup-rust.html"
---
In the previous posts we created a [minimal Multiboot kernel][multiboot post] and [switched to Long Mode][long mode post]. Now we can finally switch to [Rust] code. Rust is a high-level language without runtime. It allows us to not link the standard library and write bare metal code. Unfortunately the setup is not quite hassle-free yet.
This blog post tries to setup Rust step-by-step and point out the different problems. If you have any questions, problems, or suggestions please [file an issue] or create a comment at the bottom. The code from this post is in a [Github repository], too.
This blog post tries to set up Rust step-by-step and point out the different problems. If you have any questions, problems, or suggestions please [file an issue] or create a comment at the bottom. The code from this post is in a [Github repository], too.
[multiboot post]: {{ page.previous.previous.url }}
[long mode post]: {{ page.previous.url }}
[Rust]: https://www.rust-lang.org/
[file an issue]: https://github.com/phil-opp/blog_os/issues
[Github repository]: https://github.com/phil-opp/blog_os/tree/setup_rust
[Github repository]: https://github.com/phil-opp/blog_os/tree/set_up_rust
## Installing Rust
We need a nightly compiler, as we will use many unstable features. To manage Rust installations I highly recommend brson's [multirust]. It allows you to install nightly, beta, and stable compilers side-by-side and makes it easy to update them. To use a nightly compiler for the current directory, you can run `multirust override nightly`.
@@ -92,7 +93,7 @@ We added a new `cargo` target that just executes `cargo build` and modified the
But now `cargo build` is executed on every `make`, even if no source file was changed. And the ISO is recreated on every `make iso`/`make run`, too. We could try to avoid this by adding dependencies on all rust source and cargo configuration files to the `cargo` target, but the ISO creation takes only half a second on my machine and most of the time we will have changed a Rust file when we run `make`. So we keep it simple for now and let cargo do the bookkeeping of changed files (it does it anyway).
[github makefile]: https://github.com/phil-opp/blog_os/blob/setup_rust/Makefile
[github makefile]: https://github.com/phil-opp/blog_os/blob/set_up_rust/Makefile
## Calling Rust
Now we can call the main method in `long_mode_start`:
@@ -279,7 +280,7 @@ We add it to the `boot.asm` file:
```nasm
; Check for SSE and enable it. If it's not supported throw error "a".
setup_SSE:
set_up_SSE:
; check for SSE
mov eax, 0x1
cpuid
@@ -302,7 +303,7 @@ setup_SSE:
```
The code is from the great [OSDev Wiki][osdev sse] again. Notice that it sets/unsets exactly the bits that can cause the `Invalid Opcode` exception.
When we insert a `call setup_SSE` somewhere in the `start` function (for example after `call enable_paging`), our Rust code will finally work.
When we insert a `call set_up_SSE` somewhere in the `start` function (for example after `call enable_paging`), our Rust code will finally work.
[32-bit error function]: {{ page.previous.url }}#some-tests
[osdev sse]: http://wiki.osdev.org/SSE#Checking_for_SSE

View File

@@ -249,7 +249,7 @@ mov eax, p4_table
or eax, 0b11 ; present + writable
mov [p4_table + 511 * 8], eax
```
I put it right after the `setup_page_tables` label, but you can add it wherever you like.
I put it right after the `set_up_page_tables` label, but you can add it wherever you like.
Now we can use special virtual addresses to access the page tables. The P4 table is available at `0xfffffffffffff000`. Let's add a P4 constant to the `table` submodule:

View File

@@ -27,9 +27,9 @@ start:
call test_cpuid
call test_long_mode
call setup_page_tables
call set_up_page_tables
call enable_paging
call setup_SSE
call set_up_SSE
; load the 64-bit GDT
lgdt [gdt64.pointer]
@@ -42,7 +42,7 @@ start:
jmp gdt64.code:long_mode_start
setup_page_tables:
set_up_page_tables:
; recursive map P4
mov eax, p4_table
or eax, 0b11 ; present + writable
@@ -149,7 +149,7 @@ test_long_mode:
jmp error
; Check for SSE and enable it. If it's not supported throw error "a".
setup_SSE:
set_up_SSE:
; check for SSE
mov eax, 0x1
cpuid