diff --git a/Makefile b/Makefile index c1eaed3a..2d0962bd 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ default: thor.flp kernel/debug/kernel.bin: force_look cd kernel; $(MAKE) +init/debug/init.bin: force_look + cd init; $(MAKE) + tlib/libtlib.a: force_look cd tlib; $(MAKE) @@ -17,13 +20,13 @@ bootloader/stage2.bin: force_look programs: force_look tlib/libtlib.a cd programs/; ${MAKE} dist -compile: bootloader/stage1.bin bootloader/stage2.bin kernel/debug/kernel.bin programs +compile: bootloader/stage1.bin bootloader/stage2.bin init/debug/init.bin kernel/debug/kernel.bin programs hdd.img: dd if=/dev/zero of=hdd.img bs=516096c count=1000 (echo n; echo p; echo 1; echo ""; echo ""; echo t; echo c; echo a; echo 1; echo w;) | sudo fdisk -u -C1000 -S63 -H16 hdd.img -thor.flp: hdd.img bootloader/stage1.bin bootloader/stage2.bin kernel/debug/kernel.bin programs +thor.flp: hdd.img bootloader/stage1.bin bootloader/stage2.bin init/debug/init.bin kernel/debug/kernel.bin programs mkdir -p mnt/fake/ dd if=bootloader/stage1.bin of=hdd.img conv=notrunc dd if=bootloader/stage2.bin of=hdd.img seek=1 conv=notrunc @@ -33,6 +36,7 @@ thor.flp: hdd.img bootloader/stage1.bin bootloader/stage2.bin kernel/debug/kerne sudo mkdir mnt/fake/bin/ sudo mkdir mnt/fake/sys/ sudo mkdir mnt/fake/dev/ + sudo /bin/cp init/debug/init.bin mnt/fake/ sudo /bin/cp kernel/debug/kernel.bin mnt/fake/ sudo /bin/cp programs/dist/* mnt/fake/bin/ sleep 0.1 @@ -67,6 +71,7 @@ force_look: clean: cd bootloader; $(MAKE) clean + cd init; $(MAKE) clean cd kernel; $(MAKE) clean cd programs/; $(MAKE) clean cd tlib/; $(MAKE) clean diff --git a/bootloader/stage2.asm b/bootloader/stage2.asm index f0927f4f..74fcf995 100644 --- a/bootloader/stage2.asm +++ b/bootloader/stage2.asm @@ -142,15 +142,15 @@ second_step: je .end_of_directory mov ax, [gs:si] - cmp ax, 0x454B ; EK + cmp ax, 0x4E49 ; NI jne .continue mov ax, [gs:(si+2)] - cmp ax, 0x4E52 ; NR + cmp ax, 0x5449 ; TI jne .continue mov ax, [gs:(si+4)] - cmp ax, 0x4C45 ; LE + cmp ax, 0x2020 ; space space jne .continue mov ax, [gs:(si+6)] @@ -383,4 +383,4 @@ error_end: ; Make it sector-aligned - times 1536-($-$$) db 0 \ No newline at end of file + times 1536-($-$$) db 0 diff --git a/init/.gitignore b/init/.gitignore new file mode 100644 index 00000000..d287cd3e --- /dev/null +++ b/init/.gitignore @@ -0,0 +1 @@ +debug diff --git a/init/Makefile b/init/Makefile new file mode 100644 index 00000000..5abe78b7 --- /dev/null +++ b/init/Makefile @@ -0,0 +1,32 @@ +default: debug/init.bin + +include ../cpp.mk + +# Compile the 16-bit and 32-bit parts of the executable + +INIT_FLAGS=-I../kernel/include + +debug/boot_16.o: src/boot_16.cpp + @ mkdir -p debug/ + $(CXX) $(COMMON_CPP_FLAGS) $(FLAGS_16) $(INIT_FLAGS) $(WARNING_FLAGS) -c src/boot_16.cpp -o debug/boot_16.o + +debug/boot_32.o: src/boot_32.cpp + @ mkdir -p debug/ + $(CXX) $(COMMON_CPP_FLAGS) $(FLAGS_32) $(INIT_FLAGS) $(WARNING_FLAGS) -c src/boot_32.cpp -o debug/boot_32.o + +debug/boot_16_64.o: debug/boot_16.o + $(OC) -I elf32-i386 -O elf64-x86-64 debug/boot_16.o debug/boot_16_64.o + +debug/boot_32_64.o: debug/boot_32.o + $(OC) -I elf32-i386 -O elf64-x86-64 debug/boot_32.o debug/boot_32_64.o + +LINK_O_FILES=debug/boot_16_64.o debug/boot_32_64.o + +debug/init.bin: $(LINK_O_FILES) + @ echo -e "$(MODE_COLOR)[debug]$(NO_COLOR) Link $(FILE_COLOR)$@$(NO_COLOR)" + $(CXX) $(KERNEL_LINK_FLAGS) $(KERNEL_CPP_FLAGS_64) -o $@.o $(LINK_O_FILES) + $(OC) -R .note -R .comment -O binary --set-section-flags .bss=alloc,load,contents $@.o $@ + +clean: + @ echo -e "Remove compiled files (deps/objects)" + @ rm -rf debug diff --git a/init/include/boot_32.hpp b/init/include/boot_32.hpp new file mode 100644 index 00000000..64ad7e77 --- /dev/null +++ b/init/include/boot_32.hpp @@ -0,0 +1,17 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +#ifndef BOOT_32_HPP +#define BOOT_32_HPP + +extern "C" { + +void __attribute((noreturn)) pm_main(); + +} //end of exern "C" + +#endif diff --git a/init/include/code16gcc.h b/init/include/code16gcc.h new file mode 100644 index 00000000..39aaab6b --- /dev/null +++ b/init/include/code16gcc.h @@ -0,0 +1,12 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +/* + * Hack to make GCC output 16-bit code. + */ + +asm(".code16gcc"); diff --git a/init/linker.ld b/init/linker.ld new file mode 100644 index 00000000..6f0924ff --- /dev/null +++ b/init/linker.ld @@ -0,0 +1,50 @@ +ENTRY(rm_main) + +SECTIONS +{ + /* This is where the bootloader will load the code */ + . = 0x6000; + + .text_16 BLOCK(512) : ALIGN(512) + { + debug/boot_16_64.o(.text) + } + + .rodata_16 BLOCK(512) : ALIGN(512) + { + debug/boot_16_64.o(.rodata) + } + + .bss_16 BLOCK(512) : ALIGN(512) + { + debug/boot_16_64.o(.bss) + } + + .data_16 BLOCK(512) : ALIGN(512) + { + debug/boot_16_64.o(.data) + } + + .text_32 BLOCK(512) : ALIGN(512) + { + debug/boot_32_64.o(.text) + } + + /* 4K of Read-only data */ + .rodata BLOCK(1K) : ALIGN(1K) + { + *(.rodata) + } + + /* 4K of Read-write initialized data. */ + .data BLOCK(1K) : ALIGN(1K) + { + *(.data) + } + + /* 4K of Read-write uninitialized data. */ + .bss BLOCK(1K) : ALIGN(1K) + { + *(.bss) + } +} diff --git a/init/src/boot_16.cpp b/init/src/boot_16.cpp new file mode 100644 index 00000000..2c665a03 --- /dev/null +++ b/init/src/boot_16.cpp @@ -0,0 +1,444 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +#define CODE_16 +#define THOR_INIT + +#include "code16gcc.h" +#include "boot_32.hpp" + +#include "gdt.hpp" +#include "e820.hpp" //Just for the address of the e820 map +#include "vesa.hpp" +#include "early_logging.hpp" + +// For debugging purposes +#include "virtual_debug.hpp" +#include "serial.hpp" + +//The Task State Segment +gdt::task_state_segment_t gdt::tss; + +uint32_t early::early_logs_count = 0; +uint32_t early::early_logs[early::MAX_EARLY_LOGGING]; + +e820::bios_e820_entry e820::bios_e820_entries[e820::MAX_E820_ENTRIES]; +int16_t e820::bios_e820_entry_count = 0; + +vesa::vbe_info_block_t vesa::vbe_info_block; +vesa::mode_info_block_t vesa::mode_info_block; +bool vesa::vesa_enabled = false; + +namespace { + +/* Early Logging */ + +//TODO Check out why only very few early log are possible and it seems only +//at some position... +void early_log(const char* s){ + early::early_logs[early::early_logs_count++] = reinterpret_cast(s); +} + +/* VESA */ + +constexpr const uint16_t DEFAULT_WIDTH = 1280; +constexpr const uint16_t DEFAULT_HEIGHT = 1024; +constexpr const uint16_t DEFAULT_BPP = 32; + +void set_ds(uint16_t seg){ + asm volatile("mov ds, %0" : : "rm" (seg)); +} + +void set_es(uint16_t seg){ + asm volatile("mov es, %0" : : "rm" (seg)); +} + +void set_gs(uint16_t seg){ + asm volatile("mov gs, %0" : : "rm" (seg)); +} + +void reset_segments(){ + set_ds(0); + set_es(0); +} + +int detect_memory_e820(){ + auto smap = &e820::bios_e820_entries[0]; + + uint16_t entries = 0; + + uint32_t contID = 0; + int signature; + int bytes; + + static e820::bios_e820_entry buf; + + do { + asm volatile ("int 0x15" + : "=a"(signature), "=c"(bytes), "=b"(contID) + : "a"(0xE820), "b"(contID), "c"(24), "d"(0x534D4150), "D"(&buf)); + + if (signature != 0x534D4150){ + early_log("e820 failed"); + return -1; + } + + if (bytes > 20 && (smap->acpi & 0x0001) == 0){ + // ignore this entry + } else { + *smap++ = buf; + entries++; + } + } while (contID != 0 && entries < e820::MAX_E820_ENTRIES); + + return entries; +} + +void detect_memory(){ + //TODO If e820 fails, try other solutions to get memory map + + e820::bios_e820_entry_count = detect_memory_e820(); +} + +uint16_t read_mode(uint16_t i){ + uint16_t mode; + asm volatile("mov gs, %2; mov si, %1; add si, %3; mov %0, gs:[si]" + : "=a" (mode) + : "rm" (vesa::vbe_info_block.video_modes_ptr[0]), + "rm" (vesa::vbe_info_block.video_modes_ptr[1]), + "rm" (i)); + return mode; +} + +uint16_t abs_diff(uint16_t a, uint16_t b){ + if(a > b){ + return a - b; + } else { + return b - a; + } +} + +template +constexpr bool bit_set(const T& value, uint8_t bit){ + return value & (1 << bit); +} + +void setup_vesa(){ + vesa::vbe_info_block.signature[0] = 'V'; + vesa::vbe_info_block.signature[1] = 'B'; + vesa::vbe_info_block.signature[2] = 'E'; + vesa::vbe_info_block.signature[3] = '2'; + + uint16_t return_code; + asm volatile ("int 0x10" + : "=a"(return_code) + : "a"(0x4F00), "D"(&vesa::vbe_info_block) + : "memory"); + + if(return_code == 0x4F){ + uint16_t best_mode = 0; + uint16_t best_size_diff = 65535; + + bool one = false; + + for(uint16_t i = 0, mode = read_mode(i); mode != 0xFFFF; mode = read_mode(2 * ++i)){ + asm volatile ("int 0x10" + : "=a"(return_code) + : "a"(0x4F01), "c"(mode), "D"(&vesa::mode_info_block) + : "memory"); + + //Make sure the mode is supported by get mode info function + if(return_code != 0x4F){ + continue; + } + + //Check that the mode support Linear Frame Buffer + if(!bit_set(vesa::mode_info_block.mode_attributes, 7)){ + continue; + } + + //Make sure it is a packed pixel or direct color model + if(vesa::mode_info_block.memory_model != 4 && vesa::mode_info_block.memory_model != 6){ + continue; + } + + if(vesa::mode_info_block.bpp != DEFAULT_BPP){ + continue; + } + + one = true; + + auto x_res = vesa::mode_info_block.width; + auto y_res = vesa::mode_info_block.height; + + auto size_diff = abs_diff(x_res, DEFAULT_WIDTH) + abs_diff(y_res, DEFAULT_HEIGHT); + + if(size_diff < best_size_diff){ + best_mode = mode; + best_size_diff = size_diff; + } + } + + if(!one || best_mode == 0xFFFF){ + vesa::vesa_enabled = false; + } else { + best_mode = best_mode | 0x4000; + + asm volatile ("int 0x10" + : "=a"(return_code) + : "a"(0x4F01), "c"(best_mode), "D"(&vesa::mode_info_block) + : "memory"); + + if(return_code == 0x4F){ + asm volatile ("int 0x10" + : "=a"(return_code) + : "a"(0x4F02), "b"(best_mode)); +vesa::vesa_enabled = return_code == 0x4F; + } else { + vesa::vesa_enabled = false; + } + } + } + + set_gs(0); +} + +void disable_interrupts(){ + asm volatile ("cli"); + + early_log("Interrupts disabled"); +} + +void enable_a20_gate(){ + early_log("A20 gate enabled"); + + //TODO This should really be improved: + // 1. Test if a20 already enabled + // 2- Use several methods of enabling if necessary until one succeeds + + //Enable A20 gate using fast method + auto port_a = in_byte(0x92); + port_a |= 0x02; + port_a &= ~0x01; + out_byte(port_a, 0x92); + +} + +void setup_idt(){ + static const gdt::gdt_ptr null_idt = {0, 0}; + asm volatile("lidt %0" : : "m" (null_idt)); +} + +gdt::gdt_descriptor_t null_descriptor(){ + gdt::gdt_descriptor_t descriptor; + + //zero-out the descriptor; + *(reinterpret_cast(&descriptor)) = 0; + + return descriptor; +} + +gdt::gdt_descriptor_t code_32_descriptor(){ + gdt::gdt_descriptor_t descriptor; + + descriptor.type = gdt::SEG_CODE_EXRD; + + descriptor.base_low = 0; + descriptor.base_high = 0; + descriptor.limit_low = 0xFFFF; + descriptor.limit_high = 0xF; + descriptor.always_1 = 1; + descriptor.dpl = 0; + descriptor.present = 1; + descriptor.avl = 0; + descriptor.big = 1; + descriptor.long_mode = 0; + descriptor.granularity = 1; + + return descriptor; +} + +gdt::gdt_descriptor_t code_64_descriptor(){ + gdt::gdt_descriptor_t descriptor; + + descriptor.type = gdt::SEG_CODE_EXRD; + + descriptor.base_low = 0; + descriptor.base_high = 0; + descriptor.limit_low = 0xFFFF; + descriptor.limit_high = 0xF; + descriptor.always_1 = 1; + descriptor.dpl = 0; + descriptor.present = 1; + descriptor.avl = 0; + descriptor.big = 0; + descriptor.long_mode = 1; + descriptor.granularity = 1; + + return descriptor; +} + +gdt::gdt_descriptor_t user_code_64_descriptor(){ + gdt::gdt_descriptor_t descriptor; + + descriptor.type = gdt::SEG_CODE_EXRD; + + descriptor.base_low = 0; + descriptor.base_high = 0; + descriptor.limit_low = 0xFFFF; + descriptor.limit_high = 0xF; + descriptor.always_1 = 1; + descriptor.dpl = 3; + descriptor.present = 1; + descriptor.avl = 0; + descriptor.big = 0; + descriptor.long_mode = 1; + descriptor.granularity = 1; + + return descriptor; +} + +gdt::gdt_descriptor_t data_descriptor(){ + gdt::gdt_descriptor_t descriptor; + + descriptor.type = gdt::SEG_DATA_RDWR; + + descriptor.base_low = 0; + descriptor.base_high = 0; + descriptor.limit_low = 0xFFFF; + descriptor.limit_high = 0xF; + descriptor.always_1 = 1; + descriptor.dpl = 0; + descriptor.present = 1; + descriptor.avl = 0; + descriptor.big = 1; + descriptor.long_mode = 0; + descriptor.granularity = 1; + + return descriptor; +} + +gdt::gdt_descriptor_t user_data_descriptor(){ + gdt::gdt_descriptor_t descriptor; + + descriptor.type = gdt::SEG_DATA_RDWR; + + descriptor.base_low = 0; + descriptor.base_high = 0; + descriptor.limit_low = 0xFFFF; + descriptor.limit_high = 0xF; + descriptor.always_1 = 1; + descriptor.dpl = 3; + descriptor.present = 1; + descriptor.avl = 0; + descriptor.big = 0; + descriptor.long_mode = 1; + descriptor.granularity = 1; + + return descriptor; +} + +//TODO On some machines, this should be aligned to 16 bits +static gdt::gdt_descriptor_t gdt[8]; + +static gdt::gdt_ptr gdtr; + +void setup_gdt(){ + //1. Init GDT descriptor + gdt[0] = null_descriptor(); + gdt[1] = code_32_descriptor(); + gdt[2] = data_descriptor(); + gdt[3] = code_64_descriptor(); + gdt[4] = user_code_64_descriptor(); + gdt[5] = user_data_descriptor(); + + //2. Init TSS Descriptor + + uint32_t base = reinterpret_cast(&gdt::tss); + uint32_t limit = base + sizeof(gdt::task_state_segment_t); + + auto tss_selector = reinterpret_cast(&gdt[6]); + tss_selector->type = gdt::SEG_TSS_AVAILABLE; + tss_selector->always_0_1 = 0; + tss_selector->always_0_2 = 0; + tss_selector->always_0_3 = 0; + tss_selector->dpl = 3; + tss_selector->present = 1; + tss_selector->avl = 0; + tss_selector->granularity = 0; + + tss_selector->base_low = base & 0xFFFFFF; //Bottom 24 bits + tss_selector->base_middle = (base & 0xFF000000) >> 24; //Top 8 bits + tss_selector->base_high = 0; //Top 32 bits are clear + + tss_selector->limit_low = limit & 0xFFFF; //Low 16 bits + tss_selector->limit_high = (limit & 0xF0000) >> 16; //Top 4 bits + + //3. Init the GDT Pointer + + gdtr.length = sizeof(gdt) - 1; + gdtr.pointer = reinterpret_cast(&gdt); + + //4. Load the GDT + + asm volatile("lgdt [%0]" : : "m" (gdtr)); + + //5. Zero-out the TSS + auto tss_ptr = reinterpret_cast(&gdt::tss); + for(unsigned int i = 0; i < sizeof(gdt::task_state_segment_t); ++i){ + *tss_ptr++ = 0; + } +} + +void protected_mode_enable(){ + asm volatile("mov eax, cr0; or al, 1; mov cr0, eax;"); +} + +void disable_paging(){ + asm volatile("mov eax, cr0; and eax, 0b01111111111111111111111111111111; mov cr0, eax;"); +} + +void __attribute__((noreturn)) pm_jump(){ + asm volatile(".byte 0x66, 0xea; .long pm_main; .word 0x8;"); + + __builtin_unreachable(); +} + +} //end of anonymous namespace + +void __attribute__ ((noreturn)) rm_main(){ + //Make sure segments are clean + reset_segments(); + + //Enable VESA + setup_vesa(); + + //Analyze memory + detect_memory(); + + //Make sure a20 gate is enabled + enable_a20_gate(); + + //Disable interrupts + disable_interrupts(); + + //Setup an IDT with null limits to prevents interrupts from being used in + //protected mode + setup_idt(); + + //Setup the GDT + setup_gdt(); + + //Switch to protected mode by activate PE bit of CR0 + protected_mode_enable(); + + //Disable paging + disable_paging(); + + //Protected mode jump + pm_jump(); +} diff --git a/init/src/boot_32.cpp b/init/src/boot_32.cpp new file mode 100644 index 00000000..ea26f522 --- /dev/null +++ b/init/src/boot_32.cpp @@ -0,0 +1,185 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +#define CODE_32 +#define THOR_INIT + +#include "boot/boot_32.hpp" +#include "kernel.hpp" +#include "paging.hpp" +#include "early_logging.hpp" + +#include "virtual_debug.hpp" + +namespace { + +constexpr const uint16_t COM1_PORT = 0x3f8; + +void early_log(const char* s){ + virtual_debug(s); + virtual_debug("\n"); + early::early_logs[early::early_logs_count++] = reinterpret_cast(s); +} + +typedef unsigned int uint8_t __attribute__((__mode__(__QI__))); +typedef unsigned int uint16_t __attribute__ ((__mode__ (__HI__))); +typedef unsigned int uint32_t __attribute__ ((__mode__ (__SI__))); +typedef unsigned int uint64_t __attribute__ ((__mode__ (__DI__))); + +static_assert(sizeof(uint8_t) == 1, "uint8_t must be 1 byte long"); +static_assert(sizeof(uint16_t) == 2, "uint16_t must be 2 bytes long"); +static_assert(sizeof(uint32_t) == 4, "uint32_t must be 4 bytes long"); +static_assert(sizeof(uint64_t) == 8, "uint64_t must be 8 bytes long"); + +const uint32_t PML4T = 0x70000; + +void set_segments(){ + asm volatile( + "mov ax, 0x10; \t\n" + "mov ds, ax \t\n" + "mov es, ax \t\n" + "mov fs, ax \t\n" + "mov gs, ax \t\n" + "mov ss, ax"); +} + +void activate_pae(){ + asm volatile("mov eax, cr4; or eax, 1 << 5; mov cr4, eax"); + + early_log("PAE Activated"); +} + +inline void clear_tables(uint32_t page){ + auto page_ptr = reinterpret_cast(page); + + for(uint32_t i = 0; i < (4 * 4096) / sizeof(uint32_t); ++i){ + *page_ptr++ = 0; + } +} + +void setup_paging(){ + //Clear all tables + clear_tables(PML4T); + + //Link tables (0x3 means Writeable and Supervisor) + + //PML4T[0] -> PDPT + *reinterpret_cast(PML4T) = PML4T + paging::PAGE_SIZE + 0x7; + + //PDPT[0] -> PDT + *reinterpret_cast(PML4T + 1 * paging::PAGE_SIZE) = PML4T + 2 * paging::PAGE_SIZE + 0x7; + + //PD[0] -> PT + *reinterpret_cast(PML4T + 2 * paging::PAGE_SIZE) = PML4T + 3 * paging::PAGE_SIZE + 0x7; + + //Map the first MiB + + auto page_table_ptr = reinterpret_cast(PML4T + 3 * paging::PAGE_SIZE); + auto phys = 0x3; + for(uint32_t i = 0; i < 256; ++i){ + *page_table_ptr = phys; + + phys += paging::PAGE_SIZE; + + //A page entry is 64 bit in size + page_table_ptr += 2; + } + + early_log("Paging configured"); +} + +void enable_long_mode(){ + asm volatile( + "mov ecx, 0xC0000080 \t\n" + "rdmsr \t\n" + "or eax, 0b100000000 \t\n" + "wrmsr \t\n"); + + early_log("Long mode enabled"); +} + +void set_pml4t(){ + asm volatile( + "mov eax, 0x70000 \t\n" // Bass address of PML4 + "mov cr3, eax \t\n"); // load page-map level-4 base + + early_log("PML4T set"); +} + +void enable_paging(){ + asm volatile( + "mov eax, cr0 \t\n" + "or eax, 0b10000000000000000000000000000000 \t\n" + "mov cr0, eax \t\n"); + + early_log("Paging enabled"); +} + +void __attribute__((noreturn)) lm_jump(){ + //The trick done in boot_16 does not work, so just jump at the same + //place and then call the function + asm volatile("jmp 0x18:fake_label; fake_label:"); + + //TODO kernel_main(); + + __builtin_unreachable(); +} + +void serial_init() { + out_byte(COM1_PORT + 1, 0x00); // Disable all interrupts + out_byte(COM1_PORT + 3, 0x80); // Enable DLAB + out_byte(COM1_PORT + 0, 0x03); // 38400 baud + out_byte(COM1_PORT + 1, 0x00); + out_byte(COM1_PORT + 3, 0x03); // 8 bits, no parity, one stop bit + out_byte(COM1_PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + out_byte(COM1_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set +} + +} //end of anonymous namespace + +bool serial_is_transmit_buffer_empty() { + return in_byte(COM1_PORT + 5) & 0x20; +} + +void serial_transmit(char a) { + while (serial_is_transmit_buffer_empty() == 0){} + + out_byte(COM1_PORT, a); +} + +extern "C" { + +void pm_main(){ + //Update segments + set_segments(); + + //Activate PAE + activate_pae(); + + //Setup paging + setup_paging(); + + // Initialize serial transmission (for debugging in Qemu) + serial_init(); + + //Enable long mode by setting the EFER.LME flag + enable_long_mode(); + + //Set the address of the PML4T + set_pml4t(); + + //Enable paging + enable_paging(); + + asm volatile("cli; hlt"); + __builtin_unreachable(); + + //long mode jump + lm_jump(); +} + +} //end of exern "C" diff --git a/kernel/include/kernel_utils.hpp b/kernel/include/kernel_utils.hpp index 59857a90..443d549b 100644 --- a/kernel/include/kernel_utils.hpp +++ b/kernel/include/kernel_utils.hpp @@ -8,7 +8,9 @@ #ifndef KERNEL_UTILS_H #define KERNEL_UTILS_H +#ifndef THOR_INIT #include +#endif inline uint8_t in_byte(uint16_t _port){ uint8_t rv; @@ -20,6 +22,14 @@ inline uint8_t in_byte(uint16_t _port){ return rv; } +inline void out_byte (uint16_t _port, uint8_t _data){ + asm volatile ("out %[port], %[data]" + : /* No outputs */ + : [port] "dN" (_port), [data] "a" (_data)); +} + +#ifndef THOR_INIT + inline uint16_t in_word(uint16_t _port){ uint16_t rv; @@ -50,12 +60,6 @@ inline uint64_t in_qword(uint16_t _port){ return rv; } -inline void out_byte (uint16_t _port, uint8_t _data){ - asm volatile ("out %[port], %[data]" - : /* No outputs */ - : [port] "dN" (_port), [data] "a" (_data)); -} - inline void out_word(uint16_t _port, uint16_t _data){ asm volatile ("out %[port], %[data]" : /* No outputs */ @@ -88,4 +92,6 @@ inline uint32_t switch_endian_32(uint32_t nb) { void print_stack(const char* msg, size_t check); #define SHOW_STACK(M) { size_t check = 0; asm volatile("mov %0, rsp;" : "=r" (check)); print_stack(((M)), check); } +#endif //THOR_INIT + #endif diff --git a/kernel/include/virtual_debug.hpp b/kernel/include/virtual_debug.hpp index 5521b4a3..c82033b2 100644 --- a/kernel/include/virtual_debug.hpp +++ b/kernel/include/virtual_debug.hpp @@ -11,7 +11,12 @@ //TODO Integrate Bochs Parallel debugging #include "kernel_utils.hpp" + +#ifdef THOR_INIT +void serial_transmit(char a); +#else #include "serial.hpp" +#endif #define BOCHS_E9 0xE9 @@ -32,7 +37,11 @@ inline void bochs_print(const char* s){ inline void serial_print(const char* s){ for(uint64_t i = 0; s[i] != '\0'; ++i){ +#ifdef THOR_INIT + serial_transmit(s[i]); +#else serial::transmit(s[i]); +#endif } }