CeDOS - Commit 894c8470

Added paging implementation This doesn't execute, it produces a triple fault when far jumping to kernel code. Not sure why
Celina Sophie Kalus
Sat, 23 Dec 2017 23:43:01 +0100
15 files changed, 226 insertions(+), 47 deletions(-)
M boot/boot.sboot/boot.s

@@ -73,6 +73,7 @@ mov %eax, %ds

mov %eax, %es mov %eax, %fs mov %eax, %gs + mov %eax, %ss # jump to second stage code ljmp $0x08, $_ss_start

@@ -112,8 +113,3 @@

IDT_DESCRIPTOR: .word 0 .int 0 - -end: - .=510 - .byte 0x55 - .byte 0xAA
A kernel/entry.s

@@ -0,0 +1,20 @@

+.global _kernel_start +_kernel_start: + # this code prints out all ascii characters in reverse order in + # rainbow colors just to test if this point of the code was reached + # (you might call it overkill, i call it fabulous) + mov $255, %ecx + mov $0xB8000, %esi + +test: + movb %cl, (%esi) + inc %esi + movb %cl, (%esi) + inc %esi + loop test + + # loop until the heat death of the universe +loop: + jmp loop + + .ascii "hey now youre an allstar get your game on"
A kernel/link.txt

@@ -0,0 +1,17 @@

+INPUT(build/entry.o) +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) +ENTRY(_kernel_start) + +SECTIONS +{ + .text : + { + *.*(.text) + } + + .data : + { + *.*(.data) + } +}
A kernel/makefile

@@ -0,0 +1,17 @@

+.RECIPEPREFIX = > + +.PHONY: build +build: build/entry.o +> $(GCC_PREFIX)ld -r -T link.txt -o $(BUILD_DIR)/kernel.o --oformat elf32-i386 + +.PHONY: clear +clear: +> @rm build/*.* 2> /dev/null; true + +.PHONY: rebuild +rebuild: +> $(MAKE) clear +> $(MAKE) build + +build/entry.o: entry.s +> $(GCC_PREFIX)as -o $@ $<
M link.txtlink.txt

@@ -9,6 +9,7 @@ {

BOOT : ORIGIN = 0x00007C00, LENGTH = 0x00000200 SECOND_STAGE : ORIGIN = 0x00010000, LENGTH = 0x00090000 KERNEL : ORIGIN = 0xC0000000, LENGTH = 0x30000000 + APPLICATION : ORIGIN = 0x10000000, LENGTH = 0xB0000000 } SECTIONS

@@ -16,6 +17,9 @@ {

BOOT : AT(0x0000) { build/boot.o(.*) + . = 510; + BYTE(0x55) + BYTE(0xAA) } >BOOT SECOND_STAGE : AT(LOADADDR(BOOT) + SIZEOF(BOOT))

@@ -24,9 +28,14 @@ build/second_stage.o(.*)

} >SECOND_STAGE KERNEL : AT(LOADADDR(SECOND_STAGE) + SIZEOF(SECOND_STAGE)) + { + build/kernel.o(.*) + } >KERNEL + + APPLICATION : AT(LOADADDR(KERNEL) + SIZEOF(KERNEL)) { - } >KERNEL + } >APPLICATION } __SS_LMA = LOADADDR(SECOND_STAGE);

@@ -36,3 +45,9 @@

__KERNEL_LMA = LOADADDR(KERNEL); __KERNEL_VMA = ADDR(KERNEL); __KERNEL_SIZE = SIZEOF(KERNEL); + +__APP_LMA = LOADADDR(APPLICATION); +__APP_VMA = ADDR(APPLICATION); +__APP_SIZE = SIZEOF(APPLICATION); + +ASSERT(__SS_SIZE + __KERNEL_SIZE + __APP_SIZE <= 0x48 * 0x200, "bootloader payload too big!");
M makefilemakefile

@@ -14,6 +14,7 @@ .PHONY: build

build: > $(MAKE) -C boot build > $(MAKE) -C second_stage build +> $(MAKE) -C kernel build > $(GCC_PREFIX)ld -T link.txt -Map=$(DEBUG_DIR)/mapfile.txt -o $(BUILD_DIR)/base.img --oformat binary .PHONY: clear

@@ -21,6 +22,7 @@ clear:

> @rm $(BUILD_DIR)/*.* 2> /dev/null; true > @$(MAKE) -C boot clear 2> /dev/null; true > @$(MAKE) -C second_stage clear 2> /dev/null; true +> @$(MAKE) -C kernel clear 2> /dev/null; true .PHONY: run run:

@@ -30,3 +32,7 @@ .PHONY: rebuild

rebuild: > $(MAKE) clear > $(MAKE) build + +.PHONY: objdump +objdump: +> $(GCC_PREFIX)objdump -D $(FILE) > debug/objdump.txt
M run.shrun.sh

@@ -1,1 +1,1 @@

-qemu -L .\ -fda build/base.img -m 64 -monitor stdio -no-reboot -d int,cpu_reset+qemu -L .\ -fda build/base.img -m 64 -monitor stdio -no-reboot -d int,cpu_reset 2> debug/err.log
M second_stage/entry.ssecond_stage/entry.s

@@ -1,34 +1,29 @@

.section .text .global _ss_start _ss_start: + # copy the kernel code to 0x00100000 + call copy_kernel - # this code prints out all ascii characters in reverse order in - # rainbow colors just to test if this point of the code was reached - # (you might call it overkill, i call it fabulous) - mov $255, %ecx - mov $0xB8000, %esi + # create a page directory for the kernel that maps it to 0xC0000000 + # and identity maps the first 1M of memory + call create_kernel_environment + + # load kernel page directory + movl %eax, %cr3 -test: - movb %cl, (%esi) - inc %esi - movb %cl, (%esi) - inc %esi - loop test - + # set paging enable and protection bit + movl %cr0, %eax + or $0x80000010, %eax + movl %eax, %cr0 # TODO: - # - copy the kernel code to 0x00100000 - call copy_kernel - - # - create a page directory for the kernel that maps it to 0xC0000000 - # and identity maps the first 1M of memory - # - enable paging - # - jump to kernel code - + # jump to kernel code + ljmp $8, $__KERNEL_VMA # loop until the heat death of the universe loop: jmp loop + .section .data low_kernel_welcome:
M second_stage/gdt.csecond_stage/gdt.c

@@ -8,16 +8,22 @@ (uint8_t)(base >> 8), \

(uint8_t)(base >> 16), \ (uint8_t)(access), \ (uint8_t)(((limit >> 16) & 0x0F) | ((flags << 4) & 0xF0)), \ - (uint8_t)(base >> 24), \ + (uint8_t)(base >> 24) \ } -GDT_ENTRY GDT[3] = { +GDT_ENTRY GDT[5] = { // null descriptor GDT_MAKE_ENTRY(0x00000000, 0x00000000, 0x00, 0x0), - // identity mapping (code) + // identity mapping (code, ring 0) GDT_MAKE_ENTRY(0x00000000, 0x000FFFFF, 0x9A, 0xC), - // identity mapping (data) - GDT_MAKE_ENTRY(0x00000000, 0x000FFFFF, 0x92, 0xC) + // identity mapping (data, ring 0) + GDT_MAKE_ENTRY(0x00000000, 0x000FFFFF, 0x92, 0xC), + + // identity mapping (code, ring 3) + GDT_MAKE_ENTRY(0x00000000, 0x000FFFFF, 0xFA, 0xC), + + // identity mapping (data, ring 3) + GDT_MAKE_ENTRY(0x00000000, 0x000FFFFF, 0xF2, 0xC) };
M second_stage/gdt.hsecond_stage/gdt.h

@@ -14,7 +14,7 @@ uint8_t limit_and_flags;

uint8_t base_24; } __attribute__((packed)) GDT_ENTRY; -GDT_ENTRY GDT[3]; +GDT_ENTRY GDT[5]; /*struct { uint32_t gdt_offset;
M second_stage/link.txtsecond_stage/link.txt

@@ -1,4 +1,4 @@

-INPUT(build/entry.o build/gdt.o build/main.o) +INPUT(build/entry.o build/gdt.o build/main.o build/paging.o) OUTPUT_FORMAT(elf32-i386) OUTPUT_ARCH(i386) ENTRY(_ss_start)

@@ -7,15 +7,11 @@ SECTIONS

{ .text : { - build/entry.o(.text) - build/gdt.o(.text) - build/main.o(.text) + *.*(.text) } .data : { - build/entry.o(.data) - build/gdt.o(.data) - build/main.o(.data) + *.*(.data) } }
M second_stage/main.csecond_stage/main.c

@@ -1,20 +1,37 @@

#include "linker.h" +#include "paging.h" + +#define VGA_TEXTMODE_COLUMNS 80 +#define VGA_TEXTMODE_LINES 25 +#define VGA_TEXTMODE_CELLS (VGA_TEXTMODE_COLUMNS * VGA_TEXTMODE_LINES) + +#define VGA_TEXT_COLOR 0x02 +const uint8_t const *display_start = (uint8_t*)0xB8000; uint8_t *display = (uint8_t*)0xB8000; void simple_clear(void) { - display = (uint8_t*)0xB8000; + display = (uint8_t*)display_start; - for (int i = 0; i < 80 * 25; i++) { + for (int i = 0; i < VGA_TEXTMODE_CELLS; i++) { display[2 * i] = 0x00; display[2 * i + 1] = 0x00; } } -void simple_print(const char* src) { +void simple_print(const char *src) { while (*src) { *display++ = *src++; - *display++ = 0x02; + *display++ = VGA_TEXT_COLOR; + } +} + +void simple_println(const char *src) { + simple_print(src); + + while ((display - display_start) % (2 * VGA_TEXTMODE_COLUMNS)) { + display++; + display++; } }

@@ -29,5 +46,5 @@ for (uint32_t i = 0; i < KERNEL_SIZE; i++) {

kernel_dest[i] = kernel_src[i]; } - simple_print("DONE."); + simple_println("DONE."); }
M second_stage/makefilesecond_stage/makefile

@@ -1,7 +1,7 @@

.RECIPEPREFIX = > .PHONY: build -build: build/entry.o build/gdt.o build/main.o +build: build/entry.o build/gdt.o build/main.o build/paging.o > $(GCC_PREFIX)ld -r -T link.txt -o $(BUILD_DIR)/second_stage.o --oformat elf32-i386 .PHONY: clear

@@ -20,4 +20,7 @@ build/gdt.o: gdt.c gdt.h

> $(GCC_PREFIX)gcc -c -I$(INCLUDE_DIR) --prefix=$(GCC_PREFIX) $(GCC_OPTIONS) -o $@ $< build/main.o: main.c -> $(GCC_PREFIX)gcc -c -I$(INCLUDE_DIR) --prefix=$(GCC_PREFIX) $(GCC_OPTIONS) -o $@ $<+> $(GCC_PREFIX)gcc -c -I$(INCLUDE_DIR) --prefix=$(GCC_PREFIX) $(GCC_OPTIONS) -o $@ $< + +build/paging.o: paging.c paging.h +> $(GCC_PREFIX)gcc -c -I$(INCLUDE_DIR) --prefix=$(GCC_PREFIX) $(GCC_OPTIONS) -o $@ $<
A second_stage/paging.c

@@ -0,0 +1,38 @@

+#include "paging.h" +#include "linker.h" + +void *ss_memset(void *ptr, uint8_t value, uint32_t num) { + for (uint32_t i = 0; i < num; i++) { + ((uint8_t*)ptr)[i] = value; + } + return ptr; +} + +void *create_kernel_environment() { + PAGE_DIR_ENTRY (*pdir)[PAGE_ENTRY_COUNT] = (void*)(0 * PAGE_SIZE); + PAGE_TABLE_ENTRY (*kernel)[PAGE_ENTRY_COUNT] = (void*)(1 * PAGE_SIZE); + PAGE_TABLE_ENTRY (*lowmem)[PAGE_ENTRY_COUNT] = (void*)(2 * PAGE_SIZE); + + // set everything to zero + ss_memset(pdir, 0, 3 * PAGE_SIZE); + + // map page directory to itself + //(*pdir)[PAGE_DIR_INDEX(0)].entry = MAKE_PAGE_ENTRY(pdir, 0b000000000011); + + // map kernel to 0xC0000000 + (*pdir)[PAGE_DIR_INDEX(KERNEL_VMA)].entry = MAKE_PAGE_ENTRY(kernel, 0b000000000011); + + + for (uint32_t i = 0; i < 1 << 8; i++) { + (*kernel)[i].entry = MAKE_PAGE_ENTRY(KERNEL_LMA + PAGE_SIZE * i, 0b000000000011); + } + + // identity map first 4M of memory + (*pdir)[PAGE_DIR_INDEX(0)].entry = MAKE_PAGE_ENTRY(lowmem, 0b000000000011); + + for (uint32_t i = 0; i < 1 << 10; i++) { + (*lowmem)[i].entry = MAKE_PAGE_ENTRY(PAGE_SIZE * i, 0b000000000011); + } + + return pdir; +}
A second_stage/paging.h

@@ -0,0 +1,53 @@

+#ifndef PAGING_H +#define PAGING_H + +#include <stdint.h> + +#define PAGE_ENTRY_COUNT (1 << 10) +#define PAGE_SIZE (1 << 12) + +typedef union { + uint32_t entry; + struct + { + uint32_t present : 1; + uint32_t read_write : 1; + uint32_t user_supervisor : 1; + uint32_t write_through : 1; + uint32_t cache_disabled : 1; + uint32_t accessed : 1; + uint32_t __zero : 1; + uint32_t page_size : 1; + uint32_t __ignored : 1; + uint32_t available : 3; + uint32_t page_table_addr : 20; + } __attribute((packed)) fields; +} PAGE_DIR_ENTRY; + +typedef union { + uint32_t entry; + uint8_t bytes[4]; + struct { + uint32_t present : 1; + uint32_t read_write : 1; + uint32_t user_supervisor : 1; + uint32_t write_through : 1; + uint32_t cache_disabled : 1; + uint32_t accessed : 1; + uint32_t dirty : 1; + uint32_t __zero : 1; + uint32_t global : 1; + uint32_t available : 3; + uint32_t page_addr : 20; + } __attribute((packed)) fields; +} PAGE_TABLE_ENTRY; + +#define MAKE_PAGE_ENTRY(addr, flags) (uint32_t)(((uint32_t)(addr) & 0xFFFFF000) | (flags)) + +#define PAGE_DIRECTORY (PAGE_DIR_ENTRY[PAGE_ENTRY_COUNT]) +#define PAGE_TABLE (PAGE_TABLE_ENTRY[PAGE_ENTRY_COUNT]) + +#define PAGE_DIR_INDEX(addr) ((uint32_t)(addr) >> 22) +#define PAGE_TABLE_INDEX(addr) ((uint32_t)(addr) >> 12) + +#endif