[BOOT] Multiboot compliant kernel which runs 64 bit code

This commit is contained in:
Thomas Lovén 2016-07-24 00:45:20 +02:00
parent 1f8d5b3482
commit df86be2973
13 changed files with 433 additions and 4 deletions

View File

@ -1 +1,23 @@
file sysroot/boot/kernel
target remote localhost:1234
define q
monitor quit
end
define reg
monitor info registers
end
define mm
monitor info mem
end
define cpu
monitor info cpus
end
define reset
monitor system_reset
end

2
.gitignore vendored
View File

@ -3,3 +3,5 @@ sysroot/
*.iso
*.img
*.log
kernel/obj/
tags

View File

@ -4,12 +4,24 @@ ifeq ($(MITTOS64),)
$(error Build environment is not activated. Please source activate)
endif
.PHONY: all clean
.PHONY: all clean kernel
SHELL := bash
all:
CC=$(TARGET)-gcc
FLAGS_TO_PASS:= \
CC=$(CC)
all: kernel
# A trick to only build phony target if necessary
kernel:
ifeq ($(shell make -sqC kernel || echo 1), 1)
@(. util/helpers.sh; print_info "Building kernel")
$(MAKE) -C kernel install $(FLAGS_TO_PASS)
endif
clean:
@(. util/helpers.sh; print_info "Cleaning up")
$(MAKE) -C kernel clean
rm -f mittos64.iso
rm -f qemu-error.log

33
kernel/Link.ld Normal file
View File

@ -0,0 +1,33 @@
/* Guidance from http://wiki.osdev.org/Bare_Bones */
ENTRY(_start)
KERNEL_OFFSET = 0xFFFFFF8000000000;
KERNEL_START = 0x100000;
SECTIONS
{
. = KERNEL_START + KERNEL_OFFSET;
.text : AT(ADDR(.text) - KERNEL_OFFSET)
{
*(.multiboot) /* Multiboot header must be in first 4k of elf */
*(.text)
. = ALIGN(4096);
}
.rodata BLOCK(4K) :AT(ADDR(.rodata) - KERNEL_OFFSET)
{
*(.rodata*)
}
.data BLOCK(4K) :AT(ADDR(.data) - KERNEL_OFFSET)
{
*(.data)
}
.bss BLOCK(4K) :AT(ADDR(.bss) - KERNEL_OFFSET)
{
*(.COMMON)
*(.bss)
}
}

71
kernel/Makefile Normal file
View File

@ -0,0 +1,71 @@
#
# Makefile for mittos64 kernel
# (c) Thomas Lovén 2016-2017
# mittos64@thomasloven.com
#
ifeq ($(MITTOS64),)
$(error Build environment is not activated. Please source activate)
endif
# Find all source files and corresponding object files
KERNEL_SRC := $(wildcard **/*.[cS])
KERNEL_OBJS := $(addprefix obj/,$(patsubst %,%.o,$(basename $(KERNEL_SRC))))
# Kernel object file
KERNEL := obj/boot/kernel
# Default compilation flags
CFLAGS ?= -Wall -Wextra
CFLAGS += -ffreestanding -mcmodel=large
CPPFLAGS += -Iinclude
# Optimize only if not debugging
ifdef NDEBUG
CFLAGS += -O2
CPPFLAGS += -DNDEBUG
else
CFLAGS += -ggdb -O0
ASFLAGS += -ggdb
endif
KERNEL_DEP := $(KERNEL_OBJS:.o=.d)
DEPFLAGS = -MT $@ -MMD -MP -MF obj/$*.d
all: $(KERNEL)
# Make sure the object directories exist
OBJ_DIRS := $(sort $(dir $(KERNEL_OBJS)))
$(KERNEL_OBJS): | $(OBJ_DIRS)
$(OBJ_DIRS):
mkdir -p $@
# The kernel needs some special flags
$(KERNEL): LDFLAGS += -n -nostdlib -T Link.ld
$(KERNEL): LDLIBS := -lgcc
$(KERNEL): $(KERNEL_OBJS)
$(LINK.c) $^ -o $@
# Use the default make compilation rules
obj/%.o: %.c obj/%.d
$(COMPILE.c) $(DEPFLAGS) $< -o $@
obj/%.o: %.S obj/%.d
$(COMPILE.S) $(DEPFLAGS) $< -o $@
obj/%.d: ;
# For installing stuff
${SYSROOT}/%: obj/%
mkdir -p $(dir $@)
cp $< $@
install-kernel: ${SYSROOT}/boot/kernel
install: install-kernel
clean:
rm -rf obj/
-include $(KERNEL_DEP)
.PHONY: all clean install install-kernel

122
kernel/boot/boot.S Normal file
View File

@ -0,0 +1,122 @@
.intel_syntax noprefix
#include <mem.h>
// Some info from here: http://os.phil-opp.com/multiboot-kernel.html
.section .text
.global _start
.code32 // GRUB leaves us in 32 bit mode
_start:
cli
// Check if long mode is available
// Otherwise, there's no point in continuing
call check_longmode
// Enable long mode through process described in
// AMD64 manual vol. 2 ch. 14
// Enable Physical Address Extension
mov eax, cr4
or eax, 1<<5
mov cr4, eax
// Load page directory into cr3
mov eax, offset V2P(BootP4)
mov cr3, 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
// We are now in 32 bit long mode
// Go to 64 bit mode by loading a GDT
// and perforing a far jump
lgdt [V2P(BootGDTp)]
mov eax, 0x10
mov ss, eax
mov ds, eax
mov es, eax
.extern long_mode_start
jmp 0x8:V2P(long_mode_start)
.code64
long_mode_start:
// We are now in 64 bit long mode
// but we are still running code in the identity mapped low memory kernel mirror
// Next we jump to code in high memory (> 32 bits)
movabs rax, offset .upper_memory
jmp rax
.upper_memory:
// We are now in high memory
// Set up a stack and set up a fake return address to stop backtracing
movabs rsp, offset BootStack
push 0
mov rbp, rsp
// Remove identity mapping
mov rax, 0x0
mov [V2P(BootP4)], rax
// Call c kernel code
.extern kmain
call kmain
hlt
.code32
// Check if CPUID is available
// Method described in AMD64 manual vol. 3
check_cpuid:
pushfd
pushfd
xor dword ptr[esp], 0x00200000
popfd
pushfd
pop eax
xor eax, [esp]
popfd
and eax, 1<<21
jz error
ret
// Check if long mode is available using cpuid
// AMD manual vol. 3 Appendix E
check_longmode:
call check_cpuid
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb error
mov eax, 0x80000001
cpuid
test edx, 1<<29
jz error
ret
// Jump here if something went wrong
error:
// Print ERR! to screen
mov [0xb8000], dword ptr 0x4f524f45
mov [0xb8004], dword ptr 0x4f214f52
jmp .

View File

@ -0,0 +1,54 @@
.intel_syntax noprefix
#include <mem.h>
#include <gdt.h>
// Hardcode the initial page mapping
// Identity map the first GiB of memory
// Also map the same memory at KERNEL_OFFSET
.section .data
.align 0x1000
.global BootP4
BootP4:
.quad V2P(BootP3) + (PAGE_PRESENT | PAGE_WRITE)
.rept P4_OFFSET(KERNEL_OFFSET)-1
.quad 0x0
.endr
.quad V2P(BootP3) + (PAGE_PRESENT | PAGE_WRITE)
.rept 510 - P4_OFFSET(KERNEL_OFFSET) + 1
.quad 0x0
.endr
BootP3:
.quad V2P(BootP2) + (PAGE_PRESENT | PAGE_WRITE)
.rept 511
.quad 0x0
.endr
BootP2:
.set i, 0
.rept 512
.quad (i << 21) + (PAGE_PRESENT | PAGE_WRITE | PAGE_HUGE)
.set i, (i+1)
.endr
// Hardcode initial GDT segments
// Only kernel code (0x8) and data (0x10) for now
.section .rodata
.align 0x1000
.global BootGDT
.global BootGDTp
BootGDT:
.quad 0
.quad (GDT_PRESENT | GDT_CODEDATA | GDT_WRITE | GDT_EXECUTE | GDT_64BIT)
.quad (GDT_PRESENT | GDT_CODEDATA | GDT_WRITE)
BootGDTp: // We can't put the gdt pointer in the gdt, it's too big
.short 3*8-1
.quad V2P(BootGDT)
// Reserved space for the stack
.section .bss
.global BootStack
.align 0x1000
.skip 0x1000
BootStack:

34
kernel/boot/kmain.c Normal file
View File

@ -0,0 +1,34 @@
#include <mem.h>
#define VGA_MEMORY 0xb8000
#define VGA_ROWS 24
#define VGA_COLS 80
void clear_screen()
{
// Clear the video memory
unsigned char *m = (void *)P2V(VGA_MEMORY);
for(int i = 0; i < VGA_ROWS*VGA_COLS*2; i++)
{
*m++ = 0;
}
}
void prints(const char *s, unsigned int row, unsigned int col)
{
// Very simple pure ascii string printing
unsigned char *m = (void *)P2V(VGA_MEMORY);
m += 2*VGA_COLS*row+2*col;
while(*s)
{
*m++ = *s++;
*m++ = 0x7;
}
}
int kmain(void)
{
clear_screen();
prints("Hello, world!", 0, 0);
for(;;)asm("hlt");
}

View File

@ -0,0 +1,23 @@
.section .multiboot
#include <multiboot.h>
.align 0x1000
MultiBootHeader1:
.long MBOOT1_MAGIC
.long MBOOT1_HEADER_FLAGS
.long MBOOT1_HEADER_CHECKSUM
.align 0x1000
MultiBootHeader:
.long MBOOT2_MAGIC
.long MBOOT2_ARCH
.long MBOOT2_LENGTH
.long MBOOT2_CHECKSUM
// Multiboot tags
// End tag
.short 0
.short 0
.long 8
MultiBootHeaderEnd:

12
kernel/include/gdt.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#define GDT_WRITE (1<<41)
#define GDT_EXECUTE (1<<43)
#define GDT_CODEDATA (1<<44)
#define GDT_PRESENT (1<<47)
#define GDT_64BIT (1<<53)
#ifndef __ASSEMBLER__
#include <stdint.h>
extern uint64_t BootGDT;
#endif

27
kernel/include/mem.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#define KERNEL_OFFSET 0xFFFFFF8000000000
#ifdef __ASSEMBLER__
#define V2P(a) ((a) - KERNEL_OFFSET)
#define P2V(a) ((a) + KERNEL_OFFSET)
#define P1_OFFSET(p) (((p) >> 12) & 0x1FF)
#define P2_OFFSET(p) (((p) >> 21) & 0x1FF)
#define P3_OFFSET(p) (((p) >> 30) & 0x1FF)
#define P4_OFFSET(p) (((p) >> 39) & 0x1FF)
#else
#include <stdint.h>
#define V2P(a) ((uintptr_t)(a) - KERNEL_OFFSET)
#define P2V(a) ((void *)((uintptr_t)(a) + KERNEL_OFFSET))
#endif
// Paging
#define PAGE_PRESENT 0x001
#define PAGE_WRITE 0x002
#define PAGE_USER 0x004
#define PAGE_WRITETHROUGH 0x008
#define PAGE_NOCACHE 0x010
#define PAGE_ACCESSED 0x020
#define PAGE_DIRTY 0x040
#define PAGE_HUGE 0x080
#define PAGE_GLOBAL 0x100

View File

@ -0,0 +1,14 @@
#pragma once
#define MBOOT1_MAGIC 0x1BADB002
#define MBOOT1_MAGIC2 0x2BADB002
#define MBOOT1_FLAG_PAGE_ALIGN 0x01
#define MBOOT1_FLAG_MEM_INFO 0x02
#define MBOOT1_HEADER_FLAGS (MBOOT1_FLAG_PAGE_ALIGN | MBOOT1_FLAG_MEM_INFO)
#define MBOOT1_HEADER_CHECKSUM -(MBOOT1_HEADER_FLAGS + MBOOT1_MAGIC)
#define MBOOT2_MAGIC 0xE85250D6
#define MBOOT2_MAGIC2 0x36D76289
#define MBOOT2_ARCH 0
#define MBOOT2_LENGTH (MultiBootHeaderEnd - MultiBootHeader)
#define MBOOT2_CHECKSUM -(MBOOT2_MAGIC + MBOOT2_ARCH + MBOOT2_LENGTH)

View File

@ -1,6 +1,9 @@
set timeout=0
set timeout=1
set default=0
menuentry "mittos64" {
multiboot2 /boot/kernel
}
menuentry "mittos64 MultiBoot1" {
multiboot /boot/kernel
}