mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Fix Grammar
`set up` not `setup`
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user