[BOOT] Multiboot compliant kernel which runs 64 bit code
This commit is contained in:
parent
1f8d5b3482
commit
df86be2973
22
.gdbinit
22
.gdbinit
@ -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
2
.gitignore
vendored
@ -3,3 +3,5 @@ sysroot/
|
||||
*.iso
|
||||
*.img
|
||||
*.log
|
||||
kernel/obj/
|
||||
tags
|
||||
|
16
Makefile
16
Makefile
@ -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
33
kernel/Link.ld
Normal 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
71
kernel/Makefile
Normal 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
122
kernel/boot/boot.S
Normal 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 .
|
54
kernel/boot/boot_structures.S
Normal file
54
kernel/boot/boot_structures.S
Normal 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
34
kernel/boot/kmain.c
Normal 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");
|
||||
}
|
23
kernel/boot/multiboot_header.S
Normal file
23
kernel/boot/multiboot_header.S
Normal 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
12
kernel/include/gdt.h
Normal 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
27
kernel/include/mem.h
Normal 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
|
14
kernel/include/multiboot.h
Normal file
14
kernel/include/multiboot.h
Normal 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)
|
||||
|
@ -1,6 +1,9 @@
|
||||
set timeout=0
|
||||
set timeout=1
|
||||
set default=0
|
||||
|
||||
menuentry "mittos64" {
|
||||
|
||||
multiboot2 /boot/kernel
|
||||
}
|
||||
menuentry "mittos64 MultiBoot1" {
|
||||
multiboot /boot/kernel
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user