diff --git a/init/src/boot_16.cpp b/init/src/boot_16.cpp index 2c665a03..5aab8d34 100644 --- a/init/src/boot_16.cpp +++ b/init/src/boot_16.cpp @@ -6,42 +6,60 @@ //======================================================================= #define CODE_16 -#define THOR_INIT -#include "code16gcc.h" -#include "boot_32.hpp" +#include "boot/code16gcc.h" +#include "boot/boot_32.hpp" -#include "gdt.hpp" -#include "e820.hpp" //Just for the address of the e820 map -#include "vesa.hpp" -#include "early_logging.hpp" +#include "gdt_types.hpp" +#include "e820_types.hpp" +#include "vesa_types.hpp" +#include "early_memory.hpp" -// For debugging purposes -#include "virtual_debug.hpp" -#include "serial.hpp" +e820::bios_e820_entry bios_e820_entries[e820::MAX_E820_ENTRIES]; -//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; +gdt::task_state_segment_t tss; // TODO Remove this (causes relocation errors for now) namespace { +vesa::vbe_info_block_t vbe_info_block; +vesa::mode_info_block_t mode_info_block; + +// Note: it seems to be impossible to pass parameters > 16 bit to +// functions, thus the macros. This should be fixable by +// reconfiguring better gcc for 16bit compilation which is highly +// inconvenient right now + +#define early_write_32(ADDRESS, VALUE) \ +{ \ + auto seg = early::early_base / 0x10; \ + auto offset = ADDRESS - early::early_base; \ + asm volatile("mov fs, %[seg]; mov eax, %[offset]; mov [fs:0x0 + eax], %[value]; xor eax, eax; mov fs, eax;" \ + : /* nothing */ \ + : [seg] "r" (seg), [offset] "r" (offset), [value] "r" (VALUE) \ + : "eax"); \ +} + +#define early_read_32(ADDRESS, VALUE) \ +{\ + uint32_t temp_value; \ + auto seg = early::early_base / 0x10; \ + auto offset = ADDRESS - early::early_base; \ + asm volatile("mov fs, %[seg]; mov eax, %[offset]; mov %[value], [fs:0x0 + eax]; xor eax, eax; mov fs, eax;" \ + : [value] "=r" (temp_value) \ + : [seg] "r" (seg), [offset] "r" (offset) \ + : "eax"); \ + VALUE = temp_value; \ +} + /* 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); -} +#define early_log(STRING) \ + { \ + uint32_t c; \ + early_read_32(early::early_logs_count_address, c); \ + early_write_32(early::early_logs_address + c * 4, STRING); \ + early_write_32(early::early_logs_count_address, c + 1); \ + } /* VESA */ @@ -49,6 +67,16 @@ constexpr const uint16_t DEFAULT_WIDTH = 1280; constexpr const uint16_t DEFAULT_HEIGHT = 1024; constexpr const uint16_t DEFAULT_BPP = 32; +void out_byte(uint8_t value, uint16_t port){ + asm volatile("out %1, %0" : : "a" (value), "dN" (port)); +} + +uint8_t in_byte(uint16_t port){ + uint8_t value; + asm volatile("in %0,%1" : "=a" (value) : "dN" (port)); + return value; +} + void set_ds(uint16_t seg){ asm volatile("mov ds, %0" : : "rm" (seg)); } @@ -66,10 +94,10 @@ void reset_segments(){ set_es(0); } -int detect_memory_e820(){ - auto smap = &e820::bios_e820_entries[0]; +uint32_t detect_memory_e820(){ + auto smap = &bios_e820_entries[0]; - uint16_t entries = 0; + uint32_t entries = 0; uint32_t contID = 0; int signature; @@ -99,17 +127,31 @@ int detect_memory_e820(){ } void detect_memory(){ - //TODO If e820 fails, try other solutions to get memory map + // Init it to 0 + early_write_32(early::e820_entry_count_address, 0); - e820::bios_e820_entry_count = detect_memory_e820(); + auto entry_count = detect_memory_e820(); + early_write_32(early::e820_entry_count_address, entry_count); + + auto smap = reinterpret_cast((&bios_e820_entries[0])); + + // Copy to early memory + for(uint16_t i = 0; i < entry_count; ++i){ + for(uint16_t j = 0; j < 5; ++j){ + early_write_32(early::e820_entry_address + (i * 5 + j) * 4, *smap); + ++smap; + } + } + + //TODO If e820 fails, try other solutions to get memory map } 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" (vbe_info_block.video_modes_ptr[0]), + "rm" (vbe_info_block.video_modes_ptr[1]), "rm" (i)); return mode; } @@ -128,15 +170,15 @@ constexpr bool bit_set(const T& value, uint8_t 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'; + vbe_info_block.signature[0] = 'V'; + vbe_info_block.signature[1] = 'B'; + vbe_info_block.signature[2] = 'E'; + vbe_info_block.signature[3] = '2'; uint16_t return_code; asm volatile ("int 0x10" : "=a"(return_code) - : "a"(0x4F00), "D"(&vesa::vbe_info_block) + : "a"(0x4F00), "D"(&vbe_info_block) : "memory"); if(return_code == 0x4F){ @@ -148,7 +190,7 @@ void setup_vesa(){ 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) + : "a"(0x4F01), "c"(mode), "D"(&mode_info_block) : "memory"); //Make sure the mode is supported by get mode info function @@ -157,23 +199,23 @@ void setup_vesa(){ } //Check that the mode support Linear Frame Buffer - if(!bit_set(vesa::mode_info_block.mode_attributes, 7)){ + if(!bit_set(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){ + if(mode_info_block.memory_model != 4 && mode_info_block.memory_model != 6){ continue; } - if(vesa::mode_info_block.bpp != DEFAULT_BPP){ + if(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 x_res = mode_info_block.width; + auto y_res = mode_info_block.height; auto size_diff = abs_diff(x_res, DEFAULT_WIDTH) + abs_diff(y_res, DEFAULT_HEIGHT); @@ -183,23 +225,33 @@ void setup_vesa(){ } } + early_write_32(early::vesa_enabled_address, 0); + if(!one || best_mode == 0xFFFF){ - vesa::vesa_enabled = false; + early_write_32(early::vesa_enabled_address, 0); } else { best_mode = best_mode | 0x4000; asm volatile ("int 0x10" : "=a"(return_code) - : "a"(0x4F01), "c"(best_mode), "D"(&vesa::mode_info_block) + : "a"(0x4F01), "c"(best_mode), "D"(&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; + + early_write_32(early::vesa_enabled_address, return_code == 0x4F ? 1 : 0); + + auto value = reinterpret_cast(&mode_info_block); + + // Copy to early memory + for(uint16_t i = 0; i < 256 / 4; ++i){ + early_write_32(early::vesa_mode_info_address + i * 4, *value++); + } } else { - vesa::vesa_enabled = false; + early_write_32(early::vesa_enabled_address, 0); } } } @@ -214,7 +266,6 @@ void disable_interrupts(){ } void enable_a20_gate(){ - early_log("A20 gate enabled"); //TODO This should really be improved: // 1. Test if a20 already enabled @@ -226,6 +277,7 @@ void enable_a20_gate(){ port_a &= ~0x01; out_byte(port_a, 0x92); + early_log("A20 gate enabled"); } void setup_idt(){ @@ -358,7 +410,7 @@ void setup_gdt(){ //2. Init TSS Descriptor - uint32_t base = reinterpret_cast(&gdt::tss); + uint32_t base = early::tss_address; uint32_t limit = base + sizeof(gdt::task_state_segment_t); auto tss_selector = reinterpret_cast(&gdt[6]); @@ -388,9 +440,8 @@ void setup_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; + for(uint16_t i = 0; i < 128; i += 4){ + early_write_32(early::tss_address + i * 4, 0); } } @@ -414,6 +465,9 @@ void __attribute__ ((noreturn)) rm_main(){ //Make sure segments are clean reset_segments(); + // Initialize the number of early logs + early_write_32(early::early_logs_count_address, 0); + //Enable VESA setup_vesa();