mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Compare commits
19 Commits
first_edit
...
first_edit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bef5f13560 | ||
|
|
a1743eb3dd | ||
|
|
13cffc3319 | ||
|
|
ff623a90e3 | ||
|
|
5d8758df59 | ||
|
|
ca2ccc31aa | ||
|
|
8dd179a6f4 | ||
|
|
9f578640d8 | ||
|
|
8e5a85ece4 | ||
|
|
1c88c7f945 | ||
|
|
9136a7b66f | ||
|
|
415d27814f | ||
|
|
e684bfd262 | ||
|
|
936e2073a9 | ||
|
|
b199b02578 | ||
|
|
90e716827a | ||
|
|
9819e17a28 | ||
|
|
5ebdd89ffb | ||
|
|
78e86c2312 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
build
|
||||
target
|
||||
|
||||
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "blog_os"
|
||||
version = "0.1.0"
|
||||
authors = ["Philipp Oppermann <dev@phil-opp.com>"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
rlibc = "1.0"
|
||||
12
Makefile
12
Makefile
@@ -1,6 +1,8 @@
|
||||
arch ?= x86_64
|
||||
kernel := build/kernel-$(arch).bin
|
||||
iso := build/os-$(arch).iso
|
||||
target ?= $(arch)-blog_os
|
||||
rust_os := target/$(target)/debug/libblog_os.a
|
||||
|
||||
linker_script := src/arch/$(arch)/linker.ld
|
||||
grub_cfg := src/arch/$(arch)/grub.cfg
|
||||
@@ -8,7 +10,7 @@ assembly_source_files := $(wildcard src/arch/$(arch)/*.asm)
|
||||
assembly_object_files := $(patsubst src/arch/$(arch)/%.asm, \
|
||||
build/arch/$(arch)/%.o, $(assembly_source_files))
|
||||
|
||||
.PHONY: all clean run iso
|
||||
.PHONY: all clean run iso kernel
|
||||
|
||||
all: $(kernel)
|
||||
|
||||
@@ -27,8 +29,12 @@ $(iso): $(kernel) $(grub_cfg)
|
||||
@grub-mkrescue -o $(iso) build/isofiles 2> /dev/null
|
||||
@rm -r build/isofiles
|
||||
|
||||
$(kernel): $(assembly_object_files) $(linker_script)
|
||||
@ld -n -T $(linker_script) -o $(kernel) $(assembly_object_files)
|
||||
$(kernel): kernel $(rust_os) $(assembly_object_files) $(linker_script)
|
||||
@ld -n --gc-sections -T $(linker_script) -o $(kernel) \
|
||||
$(assembly_object_files) $(rust_os)
|
||||
|
||||
kernel:
|
||||
@xargo build --target $(target)
|
||||
|
||||
# compile assembly files
|
||||
build/arch/$(arch)/%.o: src/arch/$(arch)/%.asm
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Blog OS (A Minimal x86 Kernel)
|
||||
[](https://travis-ci.org/phil-opp/blog_os/branches)
|
||||
# Blog OS (Set Up Rust)
|
||||
[](https://travis-ci.org/phil-opp/blog_os/branches)
|
||||
|
||||
This repository contains the source code for the [A Minimal x86 Kernel](http://os.phil-opp.com/multiboot-kernel.html) post of the [Writing an OS in Rust](http://os.phil-opp.com) series.
|
||||
This repository contains the source code for the [Set Up Rust](http://os.phil-opp.com/set-up-rust.html) post of the [Writing an OS in Rust](http://os.phil-opp.com) series.
|
||||
|
||||
**Check out the [master branch](https://github.com/phil-opp/blog_os) for more information.**
|
||||
|
||||
## Building
|
||||
You need to have `nasm`, `grub-mkrescue`, `xorriso`, and `qemu` installed. Then you can run it using `make run`.
|
||||
You need to have `nasm`, `grub-mkrescue`, `xorriso`, `qemu`, and a nigthly Rust compiler installed. Then you can run it using `make run`.
|
||||
|
||||
Please file an issue if you have any problems.
|
||||
|
||||
|
||||
@@ -1,8 +1,164 @@
|
||||
global start
|
||||
extern long_mode_start
|
||||
|
||||
section .text
|
||||
bits 32
|
||||
start:
|
||||
mov esp, stack_top
|
||||
|
||||
call check_multiboot
|
||||
call check_cpuid
|
||||
call check_long_mode
|
||||
|
||||
call set_up_page_tables
|
||||
call enable_paging
|
||||
|
||||
; load the 64-bit GDT
|
||||
lgdt [gdt64.pointer]
|
||||
|
||||
jmp gdt64.code:long_mode_start
|
||||
|
||||
; print `OK` to screen
|
||||
mov dword [0xb8000], 0x2f4b2f4f
|
||||
hlt
|
||||
|
||||
check_multiboot:
|
||||
cmp eax, 0x36d76289
|
||||
jne .no_multiboot
|
||||
ret
|
||||
.no_multiboot:
|
||||
mov al, "0"
|
||||
jmp error
|
||||
|
||||
check_cpuid:
|
||||
; Check if CPUID is supported by attempting to flip the ID bit (bit 21)
|
||||
; in the FLAGS register. If we can flip it, CPUID is available.
|
||||
|
||||
; Copy FLAGS in to EAX via stack
|
||||
pushfd
|
||||
pop eax
|
||||
|
||||
; Copy to ECX as well for comparing later on
|
||||
mov ecx, eax
|
||||
|
||||
; Flip the ID bit
|
||||
xor eax, 1 << 21
|
||||
|
||||
; Copy EAX to FLAGS via the stack
|
||||
push eax
|
||||
popfd
|
||||
|
||||
; Copy FLAGS back to EAX (with the flipped bit if CPUID is supported)
|
||||
pushfd
|
||||
pop eax
|
||||
|
||||
; Restore FLAGS from the old version stored in ECX (i.e. flipping the
|
||||
; ID bit back if it was ever flipped).
|
||||
push ecx
|
||||
popfd
|
||||
|
||||
; Compare EAX and ECX. If they are equal then that means the bit
|
||||
; wasn't flipped, and CPUID isn't supported.
|
||||
cmp eax, ecx
|
||||
je .no_cpuid
|
||||
ret
|
||||
.no_cpuid:
|
||||
mov al, "1"
|
||||
jmp error
|
||||
|
||||
check_long_mode:
|
||||
; test if extended processor info in available
|
||||
mov eax, 0x80000000 ; implicit argument for cpuid
|
||||
cpuid ; get highest supported argument
|
||||
cmp eax, 0x80000001 ; it needs to be at least 0x80000001
|
||||
jb .no_long_mode ; if it's less, the CPU is too old for long mode
|
||||
|
||||
; use extended info to test if long mode is available
|
||||
mov eax, 0x80000001 ; argument for extended processor info
|
||||
cpuid ; returns various feature bits in ecx and edx
|
||||
test edx, 1 << 29 ; test if the LM-bit is set in the D-register
|
||||
jz .no_long_mode ; If it's not set, there is no long mode
|
||||
ret
|
||||
.no_long_mode:
|
||||
mov al, "2"
|
||||
jmp error
|
||||
|
||||
set_up_page_tables:
|
||||
; map first P4 entry to P3 table
|
||||
mov eax, p3_table
|
||||
or eax, 0b11 ; present + writable
|
||||
mov [p4_table], eax
|
||||
|
||||
; map first P3 entry to P2 table
|
||||
mov eax, p2_table
|
||||
or eax, 0b11 ; present + writable
|
||||
mov [p3_table], eax
|
||||
|
||||
; map each P2 entry to a huge 2MiB page
|
||||
mov ecx, 0 ; counter variable
|
||||
|
||||
.map_p2_table:
|
||||
; map ecx-th P2 entry to a huge page that starts at address 2MiB*ecx
|
||||
mov eax, 0x200000 ; 2MiB
|
||||
mul ecx ; start address of ecx-th page
|
||||
or eax, 0b10000011 ; present + writable + huge
|
||||
mov [p2_table + ecx * 8], eax ; map ecx-th entry
|
||||
|
||||
inc ecx ; increase counter
|
||||
cmp ecx, 512 ; if counter == 512, the whole P2 table is mapped
|
||||
jne .map_p2_table ; else map the next entry
|
||||
|
||||
ret
|
||||
|
||||
enable_paging:
|
||||
; load P4 to cr3 register (cpu uses this to access the P4 table)
|
||||
mov eax, p4_table
|
||||
mov cr3, eax
|
||||
|
||||
; enable PAE-flag in cr4 (Physical Address Extension)
|
||||
mov eax, cr4
|
||||
or eax, 1 << 5
|
||||
mov cr4, eax
|
||||
|
||||
; set the long mode bit in the EFER MSR (model specific register)
|
||||
mov ecx, 0xC0000080
|
||||
rdmsr
|
||||
or eax, 1 << 8
|
||||
wrmsr
|
||||
|
||||
; enable paging in the cr0 register
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31
|
||||
mov cr0, eax
|
||||
|
||||
ret
|
||||
|
||||
; Prints `ERR: ` and the given error code to screen and hangs.
|
||||
; parameter: error code (in ascii) in al
|
||||
error:
|
||||
mov dword [0xb8000], 0x4f524f45
|
||||
mov dword [0xb8004], 0x4f3a4f52
|
||||
mov dword [0xb8008], 0x4f204f20
|
||||
mov byte [0xb800a], al
|
||||
hlt
|
||||
|
||||
section .bss
|
||||
align 4096
|
||||
p4_table:
|
||||
resb 4096
|
||||
p3_table:
|
||||
resb 4096
|
||||
p2_table:
|
||||
resb 4096
|
||||
stack_bottom:
|
||||
resb 64
|
||||
stack_top:
|
||||
|
||||
section .rodata
|
||||
gdt64:
|
||||
dq 0 ; zero entry
|
||||
.code: equ $ - gdt64 ; new
|
||||
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment
|
||||
.pointer:
|
||||
dw $ - gdt64 - 1
|
||||
dq gdt64
|
||||
|
||||
@@ -6,7 +6,7 @@ SECTIONS {
|
||||
.boot :
|
||||
{
|
||||
/* ensure that the multiboot header is at the beginning */
|
||||
*(.multiboot_header)
|
||||
KEEP(*(.multiboot_header))
|
||||
}
|
||||
|
||||
.text :
|
||||
|
||||
22
src/arch/x86_64/long_mode_init.asm
Normal file
22
src/arch/x86_64/long_mode_init.asm
Normal file
@@ -0,0 +1,22 @@
|
||||
global long_mode_start
|
||||
extern rust_main
|
||||
|
||||
section .text
|
||||
bits 64
|
||||
long_mode_start:
|
||||
; load 0 into all data segment registers
|
||||
mov ax, 0
|
||||
mov ss, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; call the rust main
|
||||
extern rust_main
|
||||
call rust_main
|
||||
|
||||
; print `OKAY` to screen
|
||||
mov rax, 0x2f592f412f4b2f4f
|
||||
mov qword [0xb8000], rax
|
||||
hlt
|
||||
26
src/lib.rs
Normal file
26
src/lib.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
#![feature(lang_items)]
|
||||
#![no_std]
|
||||
|
||||
extern crate rlibc;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn rust_main() {
|
||||
// ATTENTION: we have a very small stack and no guard page
|
||||
|
||||
let hello = b"Hello World!";
|
||||
let color_byte = 0x1f; // white foreground, blue background
|
||||
|
||||
let mut hello_colored = [color_byte; 24];
|
||||
for (i, char_byte) in hello.into_iter().enumerate() {
|
||||
hello_colored[i*2] = *char_byte;
|
||||
}
|
||||
|
||||
// write `Hello World!` to the center of the VGA text buffer
|
||||
let buffer_ptr = (0xb8000 + 1988) as *mut _;
|
||||
unsafe { *buffer_ptr = hello_colored };
|
||||
|
||||
loop{}
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
#[lang = "panic_fmt"] #[no_mangle] pub extern fn panic_fmt() -> ! {loop{}}
|
||||
13
x86_64-blog_os.json
Normal file
13
x86_64-blog_os.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
|
||||
"linker-flavor": "gcc",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"arch": "x86_64",
|
||||
"os": "none",
|
||||
"disable-redzone": true,
|
||||
"features": "-mmx,-sse,+soft-float",
|
||||
"panic-strategy": "abort"
|
||||
}
|
||||
Reference in New Issue
Block a user