Skip to content
Snippets Groups Projects
Commit 1740fc30 authored by Overpeek's avatar Overpeek
Browse files

Attempt 1

parent 2fd118d0
Branches
No related tags found
No related merge requests found
[target.x86_64-unknown-none]
runner = "echo"
......@@ -6,4 +6,7 @@ build = "build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
#[lib]
#crate-type = ["staticlib"]
[dependencies]
......@@ -6,43 +6,73 @@ EXTRA_RUSTFLAGS =
KERNEL = kernel
KERNEL_ELF = target/$(TARGET)/release/$(KERNEL)
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LD_SCRIPT_PATH)/$(LD_SCRIPT) Cargo.toml
DEBUG_KERNEL_ELF = target/$(TARGET)/debug/$(KERNEL)
KERNEL_LIB = target/$(TARGET)/release/lib$(KERNEL).a
DEBUG_KERNEL_LIB = target/$(TARGET)/debug/lib$(KERNEL).a
OS_ISO = target/$(TARGET)/release/$(KERNEL).iso
DEBUG_OS_ISO = target/$(TARGET)/debug/$(KERNEL).iso
LD_SCRIPT_PATH = $(shell pwd)/src/arch/x86_64
LD_SCRIPT = kernel.ld
KERNEL_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d))
DEBUG_KERNEL_DEPS= $(filter-out %: ,$(file < $(DEBUG_KERNEL_ELF).d))
BOOT_SRC = $(shell find $(LD_SCRIPT_PATH)/boot -name *.asm)
BOOT_OBJ = $(patsubst $(LD_SCRIPT_PATH)/boot/%.asm, $(LD_SCRIPT_PATH)/boot/%.o, $(BOOT_SRC))
CARGO_DEPS = $(LD_SCRIPT_PATH)/$(LD_SCRIPT) Cargo.toml
RUSTFLAGS = $(EXTRA_RUSTFLAGS) \
-C link-arg=--library-path=$(LD_SCRIPT_PATH) \
-C link-arg=--script=$(LD_SCRIPT)
# -C relocation-model=static
CARGO_RUSTC = cargo rustc --release --target=$(TARGET)
CARGO_BUILD_DEBUG= cargo rustc --target=$(TARGET)
CARGO_BUILD = $(CARGO_BUILD_DEBUG) --release --verbose
.PHONY: run
#DEBUGGER = lldb $(DEBUG_KERNEL_ELF) -o "gdb-remote localhost:1234"
DEBUGGER = gdb $(DEBUG_KERNEL_ELF) --eval-command "target remote localhost:1234"
.PHONY: build run debug
# compile asm
$(BOOT_OBJ): $(BOOT_SRC) Makefile
@echo "Compiling boot assembly"
@for asm in ${BOOT_SRC}; do nasm -f elf64 $$asm; done
# compile kernel
$(KERNEL_ELF): $(KERNEL_ELF_DEPS) Makefile
@echo "Compiling kernel ELF"
@RUSTFLAGS="$(RUSTFLAGS)" cargo rustc --target=$(TARGET)
cp target/$(TARGET)/debug/$(KERNEL) target/$(TARGET)/release/$(KERNEL)
$(KERNEL_ELF): $(KERNEL_DEPS) $(CARGO_DEPS) Makefile
@echo "Compiling kernel lib"
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO_BUILD)
# compile debug kernel
$(DEBUG_KERNEL_ELF): $(DEBUG_KERNEL_DEPS) $(CARGO_DEPS) Makefile
@echo "Compiling debug kernel ELF"
@RUSTFLAGS="$(RUSTFLAGS)" $(CARGO_BUILD_DEBUG)
# generate grub iso
$(OS_ISO): $(KERNEL_ELF) Makefile
@echo "Generate os iso"
@cp $(KERNEL_ELF) iso/boot/kernel
@grub-mkrescue /usr/lib/grub/i386-pc -o $@ iso &> /dev/null
@cp $< iso/boot/kernel
@grub-mkrescue /usr/lib/grub/i386-pc -o $@ iso > /dev/null 2>&1
# generate debug grub iso
$(DEBUG_OS_ISO): $(DEBUG_KERNEL_ELF) Makefile
@echo "Generate debug os iso"
@cp $< iso/boot/kernel
@grub-mkrescue /usr/lib/grub/i386-pc -o $@ iso > /dev/null 2>&1
# just compile the kernel
build: $(KERNEL_ELF) Makefile
@echo "$(KERNEL_ELF)"
@echo "$<"
# compile and run silently
run: $(OS_ISO) Makefile
@echo "Running kernel in QEMU"
@$(QEMU) $(OS_ISO) &> /dev/null
@$(QEMU) $< &> /dev/null
# compile, run and start gdb
debug: $(KERNEL_ELF) $(OS_ISO) Makefile
debug: $(DEBUG_KERNEL_ELF) $(DEBUG_OS_ISO) Makefile
@echo "Debugging kernel in QEMU"
@$(QEMU) $(OS_ISO) -s &> /dev/null
@$(QEMU) $(DEBUG_OS_ISO) -s -no-reboot &> /dev/null
# wait for qemu to be ready
@sleep 1
@gdb $(KERNEL_ELF) --eval-command "target remote :1234"
@$(DEBUGGER)
// x86_64 multiboot2 kernel start
KERNEL_BASE = 0xFFFFFFFF80000000;
;
/*
Multiboot header
*/
......@@ -26,187 +28,55 @@ header_end:
/*
protected mode start
*/
.section .inittext
.section .inittext, "ax"
.global start
.code32
start:
// setup stack
mov esp, stack_top
// checks
call check_multiboot
call check_cpuid
call check_long_mode
// setups
call setup_page_tables
call enable_paging
// TODO: GDT before long mode
// lgdt [gdt64.pointer]
// jmp gdt64.code: start64
jmp start64
jmp halt
error:
// print 'ERR: <err>'
mov dword ptr [0xb8000], 0x4f524f45
mov dword ptr [0xb8004], 0x4f3a4f52
mov dword ptr [0xb8008], 0x4f204f20
mov byte ptr [0xb800a], al
jmp halt
halt:
cli
// print 'ZZZ' as halting
mov word ptr [0xb8f00], 0x0f5a
mov word ptr [0xb8f02], 0x0f5a
mov word ptr [0xb8f04], 0x0f5a
halt_repeat:
hlt
jmp halt_repeat
/*
checks
*/
// check if booted from a multiboot
// compliant bootloader
check_multiboot:
cmp eax, 0x36d76289
jne .no_multiboot
ret
.no_multiboot:
mov al, 'M'
jmp error
// check for cpuid instruction availability
// requirement for checking long mode support
check_cpuid:
pushfd
pop eax
mov ecx, eax
xor eax, 1 << 21
push eax
popfd
pushfd
pop eax
push ecx
popfd
cmp eax, ecx
je .no_cpuid
ret
.no_cpuid:
mov al, 'C'
jmp error
// check for long mode availability
// requires cpuid instruction availability
check_long_mode:
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .no_long_mode
mov eax, 0x80000001
cpuid
test edx, 1 << 29
jz .no_long_mode
ret
.no_long_mode:
mov al, 'L'
jmp error
/*
setups - page tables, paging, long mode
*/
setup_page_tables:
mov eax, p3_table
or eax, 0b11 // present, writeable
mov [p4_table], eax
mov eax, p2_table
or eax, 0b11 // present, writeable
mov [p3_table], eax
mov ecx, 0 // counter
.loop:
mov eax, 0x200000 // 2MiB
mul ecx
or eax, 0b10000011 // present, writeable, huge page
mov [p2_table + ecx * 8], eax
inc ecx // inc counter
cmp ecx, 512 // check if the whole table is mapped
jne .loop // if not: continue
ret
enable_paging:
// pass page table location to the cpu
mov eax, p4_table
mov cr3, eax
// enable PAE
mov multiboot_sig - KERNEL_BASE, eax
mov multiboot_ptr - KERNEL_BASE, ebx
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
// enable long mode
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
or eax, 0x80|0x20|0x10
mov cr3, eax
halt:
hlt
jmp halt
// enable paging
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
ret
.section .text
.code64
.globl start64
start64:
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
// print 'OK'
mov dword ptr [0xb8000], 0x2f4b2f4f
call kernel_main
jmp halt
/*
memory
*/
mov esp, stack_top
.section .bss
.align 4096
.code64
// page tables
p4_table:
p4_table: // PML4
// .quad p3_table + 3
// .rept 512 - 3
// .quad
// .endr
// .quad 0
// .quad p2_table + 3
.skip 4096
p3_table:
p3_table: // PDP
// .quad
.skip 4096
p2_table:
p2_table: // PD
.skip 4096
p1_table: // PT
// 16 KiB stack
stack_bottom:
.skip 4096 * 4
stack_top:
.section .data
multiboot_sig:
.long 0
multiboot_ptr:
.long 0
// TODO: global descriptor table
/*.section .rodata
gdt64:
......
// x86_64 multiboot2 kernel start
/*
Multiboot header
*/
.section .multiboot_header, "a"
.align 4
.global header_start
header_start:
// magic number (multiboot2)
.int 0xE85250D6
// arch (protected mode i386)
.int 0
// header length
.int header_end - header_start
// checksum
.int 0x100000000 - (0xe85250d6 + 0 + header_end - header_start)
// end tag
.word 0
.word 0
.int 8
header_end:
/*
protected mode start
*/
.section .inittext, "ax"
.global start
.code32
start:
// setup stack
mov esp, stack_top
// checks
call check_multiboot
call check_cpuid
call check_long_mode
// setups
call setup_page_tables
call enable_paging
// TODO: GDT before long mode
// lgdt [gdt64.pointer]
// jmp gdt64.code: start64
jmp start64
jmp halt
error:
// print 'ERR: <err>'
mov dword ptr [0xb8000], 0x4f524f45
mov dword ptr [0xb8004], 0x4f3a4f52
mov dword ptr [0xb8008], 0x4f204f20
mov byte ptr [0xb800a], al
jmp halt
halt:
cli
// print 'ZZZ' as halting
mov word ptr [0xb8f00], 0x0f5a
mov word ptr [0xb8f02], 0x0f5a
mov word ptr [0xb8f04], 0x0f5a
halt_repeat:
hlt
jmp halt_repeat
/*
checks
*/
// check if booted from a multiboot
// compliant bootloader
check_multiboot:
cmp eax, 0x36d76289
jne .no_multiboot
ret
.no_multiboot:
mov al, 'M'
jmp error
// check for cpuid instruction availability
// requirement for checking long mode support
check_cpuid:
pushfd
pop eax
mov ecx, eax
xor eax, 1 << 21
push eax
popfd
pushfd
pop eax
push ecx
popfd
cmp eax, ecx
je .no_cpuid
ret
.no_cpuid:
mov al, 'C'
jmp error
// check for long mode availability
// requires cpuid instruction availability
check_long_mode:
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .no_long_mode
mov eax, 0x80000001
cpuid
test edx, 1 << 29
jz .no_long_mode
ret
.no_long_mode:
mov al, 'L'
jmp error
/*
setups - page tables, paging, long mode
*/
// btw without these two next lines,
// the setup_page_tables and .no_long_mode
// gets corrupted for what ever reason
//
// even tho the section is the same already
// and the bits mode is already 32
setup_page_tables:
mov eax, p3_table
or eax, 0b11 // present, writeable
mov [p4_table], eax
mov eax, p2_table
or eax, 0b11 // present, writeable
mov [p3_table], eax
mov ecx, 0 // counter
.loop:
mov eax, 0x200000 // 2MiB
mul ecx
or eax, 0b10000011 // present, writeable, huge page
mov [p2_table + ecx * 8], eax
inc ecx // inc counter
cmp ecx, 512 // check if the whole table is mapped
jne .loop // if not: continue
hlt
ret
enable_paging:
// pass page table location to the cpu
mov eax, p4_table
mov cr3, eax
// enable PAE
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
// enable long mode
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
// enable paging
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
ret
nop
/*
Start in long mode and jump to the
kernel_main in main.rs
*/
.section .text
.code64
start64:
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
// print 'OK'
mov dword ptr [0xb8000], 0x2f4b2f4f
call kernel_main
jmp halt
/*
memory
*/
.section .bss
.align 4096
.code64
// page tables
p4_table: // PML4
// .quad p3_table + 3
// .rept 512 - 3
// .quad
// .endr
// .quad 0
// .quad p2_table + 3
.skip 4096
p3_table: // PDP
// .quad
.skip 4096
p2_table: // PD
.skip 4096
p1_table: // PT
// 16 KiB stack
stack_bottom:
.skip 4096 * 4
stack_top:
// TODO: global descriptor table
/*.section .rodata
gdt64:
.long 0 ; zero entry
.code_segment: equ $ - gdt64
.long (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53)
.pointer:
.word $ - gdt64 - 1
.long gdt64*/
/*.o
global check_multiboot, check_cpuid, check_long_mode
extern error
section .text
bits 32
; multiboot check
check_multiboot:
cmp eax, 0x36d76289
jne .no_multiboot
ret
.no_multiboot:
mov al, "M"
jmp error
; cpuid check
check_cpuid:
pushfd
pop eax
mov ecx, eax
xor eax, 1 << 21
push eax
popfd
pushfd
pop eax
push ecx
popfd
cmp eax, ecx
je .no_cpuid
ret
.no_cpuid:
mov al, "C"
jmp error
; long mode check
check_long_mode:
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .no_long_mode
mov eax, 0x80000001
cpuid
test edx, 1 << 29
jz .no_long_mode
ret
.no_long_mode:
mov al, "L"
jmp error
\ No newline at end of file
section .multiboot_header
header_start:
; magic number (multiboot2)
dd 0xe85250d6
; arch (protected mode i386)
dd 0
; header length
dd header_end - header_start
; checksum
dd 0x100000000 - (0xe85250d6 + 0 + header_end - header_start)
; end tag
dw 0
dw 0
dd 8
header_end:
\ No newline at end of file
global long_mode_start
extern kernel_main
section .text
bits 64
long_mode_start:
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; print 'OK'
mov dword [0xb8000], 0x2f4b2f4f
call kernel_main
hlt
\ No newline at end of file
global start, error
extern check_multiboot, check_cpuid, check_long_mode
extern setup_page_tables, enable_paging
extern stack_top, gdt64.pointer, gdt64.code_segment
extern long_mode_start
section .text
bits 32
start:
mov esp, stack_top
; checks
call check_multiboot
call check_cpuid
call check_long_mode
; setups
call setup_page_tables
call enable_paging
lgdt [gdt64.pointer]
jmp gdt64.code_segment: long_mode_start
jmp halt
error:
; print 'ERR: <err>'
mov dword [0xb8000], 0x4f524f45
mov dword [0xb8004], 0x4f3a4f52
mov dword [0xb8008], 0x4f204f20
mov byte [0xb800a], al
jmp halt
halt:
; halt the CPU
mov word [0xb8f00], 0x0f5a
mov word [0xb8f02], 0x0f5a
mov word [0xb8f04], 0x0f5a
hlt
\ No newline at end of file
global page_table_l4, page_table_l3, page_table_l2
global stack_top
global gdt64.pointer, gdt64.code_segment
section .bss
align 4096
; page tables
page_table_l4:
resb 4096
page_table_l3:
resb 4096
page_table_l2:
resb 4096
; stack
stack_bottom:
resb 4096 * 4
stack_top:
; global descriptor table
section .rodata
gdt64:
dq 0 ; zero entry
.code_segment: equ $ - gdt64
dq (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53)
.pointer:
dw $ - gdt64 - 1
dq gdt64
\ No newline at end of file
global setup_page_tables, enable_paging
extern page_table_l4, page_table_l3, page_table_l2
section .text
bits 32
; page tables
setup_page_tables:
mov eax, page_table_l3
or eax, 0b11 ; present, writeable
mov [page_table_l4], eax
mov eax, page_table_l2
or eax, 0b11 ; present, writeable
mov [page_table_l3], eax
mov ecx, 0 ; counter
.loop:
mov eax, 0x200000 ; 2MiB
mul ecx,
or eax, 0b10000011 ; present, writeable, huge page
mov [page_table_l2 + ecx * 8], eax
inc ecx ; inc counter
cmp ecx, 512 ; check if the whole table is mapped
jne .loop ; if not: continue
ret
; paging
enable_paging:
; pass page table location to the cpu
mov eax, page_table_l4
mov cr3, eax
; enable PAE
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
; enable long mode
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
; enable paging
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
ret
\ No newline at end of file
ENTRY(start)
OUTPUT_FORMAT(elf64-x86-64)
KERNEL_BASE = 0xFFFFFFFF80000000;
SECTIONS {
/* 2 << 20 */
. = 0x100000;
.boot : {
. += SIZEOF_HEADERS;
.init : AT(ADDR(.init)) {
KEEP( *(.multiboot_header) )
*(.inittext)
}
.text : {
*(.text)
. += KERNEL_BASE;
.text ALIGN(0x1000) : AT(ADDR(.text) - KERNEL_BASE) {
*(.text .text.*)
}
/* read-only data, page aligned to allow use of the no-execute feature */
.rodata ALIGN(0x1000) : AT(ADDR(.rodata) - KERNEL_BASE) {
*(.rodata .rodata.*)
}
.rodata : {
*(.rodata)
/* Read-write data, page aligned for the .padata section */
.data ALIGN(0x1000) : AT(ADDR(.data) - KERNEL_BASE) {
*(.padata)
*(.data .data.*)
}
.data : {
*(.data)
/* Zero-initialised data */
.bss : AT(ADDR(.bss) - KERNEL_BASE) {
*(.bss .bss.*)
}
.bss : {
*(.bss)
kernel_end = .;
/DISCARD/ : {
*(.note .note.*)
}
}
#![no_std]
#![no_main]
#![feature(custom_test_frameworks)]
#![test_runner(crate::test_runner)]
#![reexport_test_harness_main = "test_main"]
#[cfg(target_arch = "x86_64")]
#[path = "arch/x86_64/boot.rs"]
......@@ -13,4 +16,17 @@ fn panic_handler(_: &PanicInfo) -> ! {
}
#[no_mangle]
fn kernel_main() {}
pub extern "C" fn kernel_main() {
let mut vmem = unsafe { &mut *(0xb8000 as *mut [u8; 4]) };
vmem[0] = b'C';
#[cfg(test)]
test_main();
}
fn test_runner(tests: &[&dyn Fn()]) {}
#[test_case]
fn test() {
assert_eq!(1, 0)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment