From 4baf81d91c92e30f10fc6200dc778cfebe5677ba Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 28 Sep 2018 16:10:20 -0400 Subject: [PATCH] Initial work on paging & higher-half kernel --- boot/CMakeLists.txt | 8 --- boot/disk.asm | 42 ----------- boot/gdt.asm | 35 --------- boot/main.asm | 98 ------------------------- boot/pm.asm | 22 ------ boot/print.asm | 23 ------ kernel/drivers/ata.c | 8 --- kernel/drivers/pci.c | 36 +++++----- kernel/drivers/vga.c | 2 + kernel/drivers/vga.h | 1 - kernel/isr.c | 5 +- kernel/main.c | 3 + kernel/multiboot.c | 93 +++++------------------- kernel/shell.c | 4 +- kernel/tests/vector.c | 10 ++- linker.ld | 41 ++++------- multiboot.asm | 162 +++++++++++++++++++++--------------------- 17 files changed, 147 insertions(+), 446 deletions(-) delete mode 100644 boot/CMakeLists.txt delete mode 100644 boot/disk.asm delete mode 100644 boot/gdt.asm delete mode 100644 boot/main.asm delete mode 100644 boot/pm.asm delete mode 100644 boot/print.asm diff --git a/boot/CMakeLists.txt b/boot/CMakeLists.txt deleted file mode 100644 index 72be1ff..0000000 --- a/boot/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -cmake_minimum_required(VERSION 3.2) -project(boot NONE) - -set(CMAKE_ASM_NASM_OBJECT_FORMAT bin) -set(CMAKE_ASM_NASM_LINK_EXECUTABLE "cp ") # hacky hack -enable_language(ASM_NASM) - -add_executable(boot.bin main.asm) \ No newline at end of file diff --git a/boot/disk.asm b/boot/disk.asm deleted file mode 100644 index 5c22dae..0000000 --- a/boot/disk.asm +++ /dev/null @@ -1,42 +0,0 @@ -; load 'dh' sectors from drive 'dl' into ES:BX -disk_load: - pusha - ; reading from disk requires setting specific values in all registers - ; so we will overwrite our input parameters from 'dx'. Let's save it - ; to the stack for later use. - push dx - - mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read' - mov al, dh ; al <- number of sectors to read (0x01 .. 0x80) - mov cl, 0x02 ; cl <- sector (0x01 .. 0x11) - ; 0x01 is our boot sector, 0x02 is the first 'available' sector - mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl') - ; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS - ; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2) - mov dh, 0x00 ; dh <- head number (0x0 .. 0xF) - - ; [es:bx] <- pointer to buffer where the data will be stored - ; caller sets it up for us, and it is actually the standard location for int 13h - int 0x13 ; BIOS interrupt - jc disk_error ; if error (stored in the carry bit) - - pop dx - cmp al, dh ; BIOS also sets 'al' to the # of sectors read. Compare it. - jne sectors_error - popa - ret - -disk_error: - mov bx, DISK_ERROR - call print_str - mov dh, ah ; ah = error code, dl = disk drive that dropped the error - mov bx, dx - call print_hex - jmp $ - -sectors_error: - mov dx, SECTORS_ERROR - call print_str - -DISK_ERROR: db "Disk read error", 0Dh, 0Ah, 0 -SECTORS_ERROR: db "Incorrect number of sectors read", 0Dh, 0Ah, 0 \ No newline at end of file diff --git a/boot/gdt.asm b/boot/gdt.asm deleted file mode 100644 index 3a0ecb0..0000000 --- a/boot/gdt.asm +++ /dev/null @@ -1,35 +0,0 @@ -gdt_start: ; don't remove the labels, they're needed to compute sizes and jumps - ; the GDT starts with a null 8-byte - dd 0x0 ; 4 byte - dd 0x0 ; 4 byte - -; GDT for code segment. base = 0x00000000, length = 0xfffff -; for flags, refer to os-dev.pdf document, page 36 -gdt_code: - dw 0xffff ; segment length, bits 0-15 - dw 0x0 ; segment base, bits 0-15 - db 0x0 ; segment base, bits 16-23 - db 10011010b ; flags (8 bits) - db 11001111b ; flags (4 bits) + segment length, bits 16-19 - db 0x0 ; segment base, bits 24-31 - -; GDT for data segment. base and length identical to code segment -; some flags changed, again, refer to os-dev.pdf -gdt_data: - dw 0xffff - dw 0x0 - db 0x0 - db 10010010b - db 11001111b - db 0x0 - -gdt_end: - -; GDT descriptor -gdt_descriptor: - dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size - dd gdt_start ; address (32 bit) - -; define some constants for later use -CODE_SEG equ gdt_code - gdt_start -DATA_SEG equ gdt_data - gdt_start \ No newline at end of file diff --git a/boot/main.asm b/boot/main.asm deleted file mode 100644 index fc1d73a..0000000 --- a/boot/main.asm +++ /dev/null @@ -1,98 +0,0 @@ -[bits 16] -[org 0x7C00] -STACK_BASE equ 0x9000 -KERNEL_OFFSET equ 0x1000 - -start: - mov bp, STACK_BASE ; position our stack pointer - mov sp, bp - - mov ax, 0x0003 ; "Set Video Mode" (mode 03h) - int 10h - - mov bx, STARTING_UP - call print_str - - mov bx, KERNEL_OFFSET - mov dh, 33 - ; mov dl, [BOOT_DRIVE] - call disk_load - - mov ax, 0x0003 ; "Set Video Mode" (mode 03h) - int 10h - - call switch_to_pm - jmp $ ; never called - -; Prints null-terminated string referenced by `bx` -print_str: - mov ah, 0Eh ; "Write Character in TTY Mode" -.inner: - mov al, [bx] - test al, al - je .end - int 10h - add bx, 1 - jmp .inner -.end: - ret - -; Prints hex string of 16-bit value stored in `bx` -print_hex: - mov ah, 0Eh ; "Write Character in TTY Mode" - mov al, '0' - int 10h - mov al, 'x' - int 10h - - mov al, bh - shr al, 4 - call print_hex_char - - mov al, bh - and al, 0Fh - call print_hex_char - - mov al, bl - shr al, 4 - call print_hex_char - - mov al, bl - and al, 0Fh - call print_hex_char - ret - -; Prints hex representation of the value stored in `al` -print_hex_char: - mov ah, 0Eh ; "Write Character in TTY Mode" - cmp al, 9 - jle .inner - add al, 7 -.inner: - add al, 30h - int 10h - ret - -%include "disk.asm" -%include "pm.asm" ; start of 32-bit PM code -%include "gdt.asm" -%include "print.asm" - -begin_pm: - call KERNEL_OFFSET - jmp $ ; spin forever - -; datas -ENDL: db 0Dh, 0Ah, 0 -STARTING_UP: db 'Reading boot sector...', 0Dh, 0Ah, 0 -PROT_MODE db "Loaded 32-bit protected mode", 0 - -; Fill rest of the bin with nops -times 510-($-$$) nop - -; Bootloader magic! -dw 0xAA55 - -; my awesome kernel -; incbin "kernel/main.bin" -; incbin "boot/zero.bin" ; some padding diff --git a/boot/pm.asm b/boot/pm.asm deleted file mode 100644 index 60962cc..0000000 --- a/boot/pm.asm +++ /dev/null @@ -1,22 +0,0 @@ -[bits 16] -switch_to_pm: - cli ; 1. disable interrupts - lgdt [gdt_descriptor] ; 2. load the GDT descriptor - mov eax, cr0 - or eax, 0x1 ; 3. set 32-bit mode bit in cr0 - mov cr0, eax - jmp CODE_SEG:init_pm ; 4. far jump by using a different segment - -[bits 32] -init_pm: ; we are now using 32-bit instructions - mov ax, DATA_SEG ; 5. update the segment registers - mov ds, ax - mov ss, ax - mov es, ax - mov fs, ax - mov gs, ax - - mov ebp, 0x90000 ; 6. update the stack right at the top of the free space - mov esp, ebp - - call begin_pm ; 7. Call a well-known label with useful code \ No newline at end of file diff --git a/boot/print.asm b/boot/print.asm deleted file mode 100644 index 94f7e92..0000000 --- a/boot/print.asm +++ /dev/null @@ -1,23 +0,0 @@ -VIDEO_MEMORY equ 0xb8000 -WHITE_ON_BLACK equ 0x0f ; the color byte for each character - -print_string_pm: - pusha - mov edx, VIDEO_MEMORY - -print_string_pm_loop: - mov al, [ebx] ; [ebx] is the address of our character - mov ah, WHITE_ON_BLACK - - test al, al ; check if end of string - je print_string_pm_done - - mov [edx], ax ; store character + attribute in video memory - add ebx, 1 ; next char - add edx, 2 ; next video memory position - - jmp print_string_pm_loop - -print_string_pm_done: - popa - ret \ No newline at end of file diff --git a/kernel/drivers/ata.c b/kernel/drivers/ata.c index 9085f8f..ac0ff4c 100644 --- a/kernel/drivers/ata.c +++ b/kernel/drivers/ata.c @@ -92,7 +92,6 @@ void ide_read_buffer(uint8_t channel, uint8_t reg, uint32_t *buffer, uint32_t qu */ if (reg > 0x07 && reg < 0x0C) ide_write(channel, ATA_REG_CONTROL, (uint8_t) (0x80 | channels[channel].nIEN)); - __asm__("pushw %es; movw %ds, %ax; movw %ax, %es"); if (reg < 0x08) insl((uint16_t) (channels[channel].base + reg - 0x00), buffer, quads); else if (reg < 0x0C) @@ -101,7 +100,6 @@ void ide_read_buffer(uint8_t channel, uint8_t reg, uint32_t *buffer, uint32_t qu insl((uint16_t) (channels[channel].ctrl + reg - 0x0A), buffer, quads); else if (reg < 0x16) insl((uint16_t) (channels[channel].bm_ide + reg - 0x0E), buffer, quads); - __asm__("popw %es;"); if (reg > 0x07 && reg < 0x0C) ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN); } @@ -401,20 +399,14 @@ uint8_t ide_ata_access(uint8_t direction, uint8_t drive, uint32_t lba, for (i = 0; i < numsects; i++) { if ((err = ide_polling(channel, 1))) return err; // Polling, set error and exit if there is. - __asm__("pushw %es"); - __asm__("mov %%ax, %%es" : : "a"(selector)); __asm__("rep insw" : : "c"(words), "d"(bus), "D"(edi)); // Receive Data. - __asm__("popw %es"); edi += (words * 2); } else { // PIO Write. for (i = 0; i < numsects; i++) { ide_polling(channel, 0); // Polling. - __asm__("pushw %ds"); - __asm__("mov %%ax, %%ds"::"a"(selector)); __asm__("rep outsw"::"c"(words), "d"(bus), "S"(edi)); // Send Data - __asm__("popw %ds"); edi += (words * 2); } ide_write(channel, ATA_REG_COMMAND, diff --git a/kernel/drivers/pci.c b/kernel/drivers/pci.c index 9fcc703..17ac62a 100644 --- a/kernel/drivers/pci.c +++ b/kernel/drivers/pci.c @@ -59,24 +59,24 @@ bool pci_check_function(uint32_t id) { uint16_t class = pci_read_class(id); uint16_t revision = pci_read_revision(id); uint8_t header_type = pci_read_header_type(id); - vc_vector_push_back(pci_devices, &(pci_device_t) { - .loc = { - .bus = PCI_ID_BUS(id), - .device = PCI_ID_DEV(id), - .function = PCI_ID_FUNC(id) - }, - .class = class, - .vendor_id = vendor_id, - .device_id = device_id, - .revision_id = (uint8_t) (revision & 0xFF), - .prog_if = (uint8_t) (revision >> 8 & 0xFF), - .bar0 = pci_config_read_long(id, PCI_HEADER_BAR0_ADDR), - .bar1 = pci_config_read_long(id, PCI_HEADER_BAR1_ADDR), - .bar2 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR2_ADDR) : 0, - .bar3 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR3_ADDR) : 0, - .bar4 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR4_ADDR) : 0, - .bar5 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR5_ADDR) : 0, - }); + // vc_vector_push_back(pci_devices, &(pci_device_t) { + // .loc = { + // .bus = PCI_ID_BUS(id), + // .device = PCI_ID_DEV(id), + // .function = PCI_ID_FUNC(id) + // }, + // .class = class, + // .vendor_id = vendor_id, + // .device_id = device_id, + // .revision_id = (uint8_t) (revision & 0xFF), + // .prog_if = (uint8_t) (revision >> 8 & 0xFF), + // .bar0 = pci_config_read_long(id, PCI_HEADER_BAR0_ADDR), + // .bar1 = pci_config_read_long(id, PCI_HEADER_BAR1_ADDR), + // .bar2 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR2_ADDR) : 0, + // .bar3 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR3_ADDR) : 0, + // .bar4 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR4_ADDR) : 0, + // .bar5 = header_type == 0x00 ? pci_config_read_long(id, PCI_HEADER_BAR5_ADDR) : 0, + // }); // PCI-to-PCI bridge if (class == 0x0604) { diff --git a/kernel/drivers/vga.c b/kernel/drivers/vga.c index aff6342..308b3c0 100644 --- a/kernel/drivers/vga.c +++ b/kernel/drivers/vga.c @@ -3,6 +3,8 @@ #include +#define VIDEO_ADDRESS ((uint16_t *) 0xC00B8000) + /********************************************************** * Private kernel functions * **********************************************************/ diff --git a/kernel/drivers/vga.h b/kernel/drivers/vga.h index 87ae740..ec7d18d 100644 --- a/kernel/drivers/vga.h +++ b/kernel/drivers/vga.h @@ -2,7 +2,6 @@ #include "../../libc/common.h" -#define VIDEO_ADDRESS ((volatile uint16_t *) 0xb8000) #define MAX_ROWS 25 #define MAX_COLS 80 diff --git a/kernel/isr.c b/kernel/isr.c index 2be84c5..590c47b 100644 --- a/kernel/isr.c +++ b/kernel/isr.c @@ -12,9 +12,12 @@ _unused void isr_handler(registers_t regs) { kprint("Received interrupt: "); kprint_uint32(regs.int_no); - kprint(" @ "); + kprint(" (err: "); + kprint_uint32(regs.err_code); + kprint(") @ "); kprint_uint32(regs.eip); kprint_char('\n'); + panic(NULL); } _unused diff --git a/kernel/main.c b/kernel/main.c index ea41931..a6a7b5f 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -12,6 +12,8 @@ // #define KDEBUG +extern bool vc_vector_run_tests(); + _noreturn _unused void kernel_main(uint32_t multiboot_magic, void *multiboot_info) { serial_init(); @@ -22,6 +24,7 @@ void kernel_main(uint32_t multiboot_magic, void *multiboot_info) { ata_init(); clear_screen(); + vc_vector_run_tests(); #ifdef KDEBUG kprint("Initializing timer...\n"); diff --git a/kernel/multiboot.c b/kernel/multiboot.c index 343aac7..f1d3c81 100644 --- a/kernel/multiboot.c +++ b/kernel/multiboot.c @@ -1,6 +1,9 @@ #include "multiboot.h" #include "console.h" +#define PAGE_OFFSET 0xC0000000 +#define KERNEL_OFFSET 0x100000 // FIXME + extern void *malloc_memory_start; extern void *malloc_memory_end; @@ -16,13 +19,14 @@ void multiboot_init(uint32_t magic, void *info_ptr) { panic("multiboot_magic: Invalid magic.\n"); } - struct multiboot_info *info = (struct multiboot_info *) info_ptr; - kprint("flags = "); kprint_uint32(info->flags); kprint_char('\n'); + struct multiboot_info *info = (struct multiboot_info *) (info_ptr + PAGE_OFFSET); + kprint("multiboot_info = "); kprint_uint32((uintptr_t) info); + kprint("\nflags = "); kprint_uint32(info->flags); kprint_char('\n'); if (CHECK_FLAG(info->flags, MULTIBOOT_INFO_MEMORY)) { - malloc_memory_start = (void *) 0x100000; + malloc_memory_start = (void *) 0x100000 + PAGE_OFFSET + KERNEL_OFFSET; // 1 MiB + (info->mem_upper * 1 KiB) - malloc_memory_end = malloc_memory_start + (info->mem_upper * 0x400); + malloc_memory_end = malloc_memory_start + (info->mem_upper * 0x400) - KERNEL_OFFSET; kprint("upper_memory_end = "); kprint_uint32((uintptr_t) malloc_memory_end); kprint_char('\n'); } else { @@ -35,7 +39,7 @@ void multiboot_init(uint32_t magic, void *info_ptr) { } if (CHECK_FLAG(info->flags, MULTIBOOT_INFO_CMDLINE)) { - kprint("cmdline = "); kprint((char *) info->cmdline); + kprint("cmdline = "); kprint((char *) (info->cmdline + PAGE_OFFSET)); kprint_char('\n'); } @@ -46,12 +50,12 @@ void multiboot_init(uint32_t magic, void *info_ptr) { kprint("mods_count = "); kprint_uint32(info->mods_count); kprint(", mods_addr = "); kprint_uint32(info->mods_addr); kprint_char('\n'); - for (i = 0, mod = (struct multiboot_mod_list *) info->mods_addr; + for (i = 0, mod = (struct multiboot_mod_list *) (info->mods_addr + PAGE_OFFSET); i < info->mods_count; i++, mod++) { kprint(" mod_start = "); kprint_uint32(mod->mod_start); kprint(", mod_end = "); kprint_uint32(mod->mod_end); - kprint(", cmdline = "); kprint((char *) mod->cmdline); + kprint(", cmdline = "); kprint((char *) (mod->cmdline + PAGE_OFFSET)); kprint_char('\n'); } } @@ -92,8 +96,8 @@ void multiboot_init(uint32_t magic, void *info_ptr) { kprint_char('\n'); struct multiboot_mmap_entry *largest_available_entry = NULL; - for (mmap = (struct multiboot_mmap_entry *) info->mmap_addr; - (unsigned long) mmap < info->mmap_addr + info->mmap_length; + for (mmap = (struct multiboot_mmap_entry *) (info->mmap_addr + PAGE_OFFSET); + (unsigned long) mmap < info->mmap_addr + PAGE_OFFSET + info->mmap_length; mmap = (struct multiboot_mmap_entry *) ((unsigned long) mmap + mmap->size + sizeof(mmap->size))) { if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE && @@ -109,93 +113,32 @@ void multiboot_init(uint32_t magic, void *info_ptr) { } if (largest_available_entry != NULL) { - malloc_memory_start = (void *) (uint32_t) largest_available_entry->addr; - malloc_memory_end = malloc_memory_start + largest_available_entry->len; + // malloc_memory_start = (void *) (uint32_t) largest_available_entry->addr + PAGE_OFFSET + KERNEL_OFFSET; + // malloc_memory_end = malloc_memory_start + largest_available_entry->len - KERNEL_OFFSET; kprint("malloc_memory_start = "); kprint_uint32((uintptr_t) malloc_memory_start); kprint(", end = "); kprint_uint32((uintptr_t) malloc_memory_end); kprint_char('\n'); } } - /* Draw diagonal blue line. */ + /* Check VGA framebuffer. */ if (CHECK_FLAG (info->flags, MULTIBOOT_INFO_FRAMEBUFFER_INFO)) { - uint32_t color; - unsigned i; - void *fb = (void *) (unsigned long) info->framebuffer_addr; - kprint("framebuffer addr = "); kprint_uint64(info->framebuffer_addr); kprint(", type = "); kprint_uint8(info->framebuffer_type); kprint(", bpp = "); kprint_uint8(info->framebuffer_bpp); kprint_char('\n'); switch (info->framebuffer_type) { - case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED: { - unsigned best_distance, distance; - struct multiboot_color *palette; - - palette = (struct multiboot_color *) info->framebuffer_palette_addr; - - color = 0; - best_distance = 4 * 256 * 256; - - for (i = 0; i < info->framebuffer_palette_num_colors; i++) { - distance = (0xff - palette[i].blue) * (0xff - palette[i].blue) - + palette[i].red * palette[i].red - + palette[i].green * palette[i].green; - if (distance < best_distance) { - color = i; - best_distance = distance; - } - } - } - break; - - case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: - color = ((1 << info->framebuffer_blue_mask_size) - 1) - << info->framebuffer_blue_field_position; - break; - case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT: console_set_vga_enabled(true); - color = '\\' | 0x0100; break; default: - color = 0xffffffff; - break; - } - - for (i = 0; i < info->framebuffer_width - && i < info->framebuffer_height; i++) { - switch (info->framebuffer_bpp) { - case 8: { - uint8_t *pixel = fb + info->framebuffer_pitch * i + i; - *pixel = (uint8_t) color; - } - break; - case 15: - case 16: { - uint16_t *pixel - = fb + info->framebuffer_pitch * i + 2 * i; - *pixel = (uint16_t) color; - } - break; - case 24: { - uint32_t *pixel - = fb + info->framebuffer_pitch * i + 3 * i; - *pixel = (color & 0xffffff) | (*pixel & 0xff000000); - } - break; - - case 32: { - uint32_t *pixel - = fb + info->framebuffer_pitch * i + 4 * i; - *pixel = color; - } break; } - } } else { console_set_vga_enabled(true); // FIXME } + + kprint("Multiboot info loaded.\n"); } \ No newline at end of file diff --git a/kernel/shell.c b/kernel/shell.c index 2d16a61..764323d 100644 --- a/kernel/shell.c +++ b/kernel/shell.c @@ -23,7 +23,7 @@ static size_t key_buffer_printed; static vc_vector *shell_history; static size_t shell_history_offset = 0; -static void command_lspci() { +void command_lspci() { vc_vector *pci_devices = pci_get_devices(); for (pci_device_t *device = vc_vector_begin(pci_devices); device != vc_vector_end(pci_devices); @@ -84,7 +84,7 @@ static void command_lspci() { kprint_char('\n'); } -static void command_lsata() { +void command_lsata() { for (uint8_t i = 0; i < 4; i++) { if (ide_devices[i].reserved == 1) { kprint_uint8(i); diff --git a/kernel/tests/vector.c b/kernel/tests/vector.c index dac1380..86458a5 100644 --- a/kernel/tests/vector.c +++ b/kernel/tests/vector.c @@ -23,11 +23,15 @@ // ---------------------------------------------------------------------------- bool test_vc_vector_create() { + kprint("starting vector create\n"); const size_t size_of_type = sizeof(int); + kprint("fetching default\n"); const size_t default_count_of_elements = vc_vector_get_default_count_of_elements(); // Creating vector with default count of elements + kprint("creating vector w/ "); kprint_uint32(size_of_type); kprint_char('\n'); vc_vector *vector = vc_vector_create(0, size_of_type, NULL); + kprint("vector ptr = "); kprint_uint32((uintptr_t) vector); kprint_char('\n'); ASSERT_NE(NULL, vector); ASSERT_EQ(0, vc_vector_count(vector)); ASSERT_EQ(0, vc_vector_size(vector)); @@ -319,10 +323,12 @@ bool test_vc_vector_with_strfreefunc() { } bool vc_vector_run_tests() { - return test_vc_vector_create() && + kprint("from "); kprint_uint32(*(uint32_t *) 0x8000000); kprint_char('\n'); + kprint("starting vector tests "); kprint_uint32((uintptr_t) test_vc_vector_create); kprint_char('\n'); + return test_vc_vector_create() /*&& test_vc_vector_element_access() && test_vc_vector_iterators() && test_vc_vector_capacity() && test_vc_vector_modifiers() && - test_vc_vector_with_strfreefunc(); + test_vc_vector_with_strfreefunc()*/; } \ No newline at end of file diff --git a/linker.ld b/linker.ld index 1f39ed4..48df831 100644 --- a/linker.ld +++ b/linker.ld @@ -1,56 +1,39 @@ -/* The bootloader will look at this image and start execution at the symbol - designated as the entry point. */ ENTRY(_start) +OUTPUT_FORMAT(elf32-i386) -/* Tell where the various sections of the object files will be put in the final - kernel image. */ -SECTIONS -{ - /* Begin putting sections at 1 MiB, a conventional place for kernels to be - loaded at by the bootloader. */ - . = 1M; +SECTIONS { + /* The kernel will live at 3GB + 1MB in the virtual + address space, which will be mapped to 1MB in the + physical address space. */ + . = 0xC0100000; /* First put the multiboot header, as it is required to be put very early early in the image or the bootloader won't recognize the file format. Next we'll put the .text section. */ - .text BLOCK(4K) : ALIGN(4K) + .text : AT(ADDR(.text) - 0xC0000000) { *(.multiboot) *(.text) } - /* Make sure the GNU notes information is placed after .text. Failure to - to do so may push the GRUB multiboot information beyond the first 8k - and GRUB will not identify this kernel as multiboot capable. - Alternative to this is to compile the final binary with this linker - option to exclude this unqiue header: - -Wl,--build-id=none */ - - .note.gnu.build-id BLOCK(4K) : ALIGN(4K) - { - *(.note.gnu.build-id) - } - /* Read-only data. */ - .rodata BLOCK(4K) : ALIGN(4K) + .rodata ALIGN(4K) : AT(ADDR(.rodata) - 0xC0000000) { *(.rodata) } /* Read-write data (initialized) */ - .data BLOCK(4K) : ALIGN(4K) + .data ALIGN(4K) : AT(ADDR(.data) - 0xC0000000) { *(.data) } /* Read-write data (uninitialized) and stack */ - .bss BLOCK(4K) : ALIGN(4K) + .bss ALIGN(4K) : AT(ADDR(.bss) - 0xC0000000) { + _sbss = .; *(COMMON) *(.bss) - *(.bootstrap_stack) + _ebss = .; } - - /* The compiler may produce other sections, by default it will put them in - a segment with the same name. Simply add stuff here as needed. */ } \ No newline at end of file diff --git a/multiboot.asm b/multiboot.asm index 1f6b534..c125efa 100644 --- a/multiboot.asm +++ b/multiboot.asm @@ -6,6 +6,30 @@ FLAGS equ FMBALIGN | FMEMINFO | FVIDMODE MAGIC equ 0x1BADB002 CHECKSUM equ -(MAGIC + FLAGS) +; This is the virtual base address of kernel space. It must be used to convert virtual +; addresses into physical addresses until paging is enabled. +KERNEL_VIRTUAL_BASE equ 0xC0000000 ; 3GB +KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; 768 -- Page directory index of kernel's 4MB PTE. + +section .data +align 0x1000 +boot_page_directory: + ; This page directory entry identity-maps the first 4MB of the 32-bit physical address space. + ; All bits are clear except the following: + ; bit 7: PS The kernel page is 4MB. + ; bit 1: RW The kernel page is read/write. + ; bit 0: P The kernel page is present. + + ; This entry must be here -- otherwise the kernel will crash immediately after paging is + ; enabled because it can't fetch the next instruction! It's ok to unmap this page later. + dd 0x00000083 + times (KERNEL_PAGE_NUMBER - 1) dd 0 ; Pages before kernel space. + + ; This page directory entry defines a 4MB page containing the kernel. + dd 0x00000083 + dd 0x00000083 + times (1024 - KERNEL_PAGE_NUMBER - 2) dd 0 ; Pages after the kernel image. + ; Declare a multiboot header that marks the program as a kernel. These are magic ; values that are documented in the multiboot standard. The bootloader will ; search for this signature in the first 8 KiB of the kernel file, aligned at a @@ -14,39 +38,30 @@ CHECKSUM equ -(MAGIC + FLAGS) section .multiboot align 4 ; header - dd MAGIC - dd FLAGS - dd CHECKSUM + dd MAGIC + dd FLAGS + dd CHECKSUM - ; address tag - dd 0 ; header_addr - dd 0 ; load_addr - dd 0 ; load_end_addr - dd 0 ; bss_end_addr - dd 0 ; entry_addr + ; address tag + dd 0 ; header_addr + dd 0 ; load_addr + dd 0 ; load_end_addr + dd 0 ; bss_end_addr + dd 0 ; entry_addr - ; graphics tag - dd 0 ; mode_type - dd 800 ; width - dd 600 ; height - dd 32 ; depth + ; graphics tag + dd 1 ; mode_type + dd 800 ; width + dd 600 ; height + dd 32 ; depth -; The multiboot standard does not define the value of the stack pointer register -; (esp) and it is up to the kernel to provide a stack. This allocates room for a -; small stack by creating a symbol at the bottom of it, then allocating 16384 -; bytes for it, and finally creating a symbol at the top. The stack grows -; downwards on x86. The stack is in its own section so it can be marked nobits, -; which means the kernel file is smaller because it does not contain an -; uninitialized stack. The stack on x86 must be 16-byte aligned according to the -; System V ABI standard and de-facto extensions. The compiler will assume the -; stack is properly aligned and failure to align the stack will result in -; undefined behavior. +; Create bootstrap stack section .bss align 16 stack_bottom: -resb 16384 ; 16 KiB +resb 0x4000 ; 16 KiB stack_top: - + ; The linker script specifies _start as the entry point to the kernel and the ; bootloader will jump to this position once the kernel has been loaded. It ; doesn't make sense to return from this function as the bootloader is gone. @@ -54,74 +69,57 @@ stack_top: section .text global _start:function (_start.end - _start) _start: - ; The bootloader has loaded us into 32-bit protected mode on a x86 - ; machine. Interrupts are disabled. Paging is disabled. The processor - ; state is as defined in the multiboot standard. The kernel has full - ; control of the CPU. The kernel can only make use of hardware features - ; and any code it provides as part of itself. There's no printf - ; function, unless the kernel provides its own header and a - ; printf implementation. There are no security restrictions, no - ; safeguards, no debugging mechanisms, only what the kernel provides - ; itself. It has absolute and complete power over the - ; machine. + mov ecx, (boot_page_directory - KERNEL_VIRTUAL_BASE) + mov cr3, ecx ; Load Page Directory Base Register. - ; To set up a stack, we set the esp register to point to the top of our - ; stack (as it grows downwards on x86 systems). This is necessarily done - ; in assembly as languages such as C cannot function without a stack. - mov esp, stack_top + mov ecx, cr4 + or ecx, (1 << 4) ; Set PSE bit in CR4 to enable 4MB pages. + mov cr4, ecx + + mov ecx, cr0 + or ecx, (1 << 31) ; Set PG bit in CR0 to enable paging. + mov cr0, ecx + + lea ecx, [.start_higher_half] ; far jump + jmp ecx + +.start_higher_half: + ; Unmap the identity-mapped first 4MB of physical address space. + ; It should not be needed anymore. + mov dword [boot_page_directory], 0 + invlpg [0] + + ; Set up stack + mov esp, stack_top ; Save multiboot information - push ebx ; multiboot_info - push eax ; multiboot_magic - - ; This is a good place to initialize crucial processor state before the - ; high-level kernel is entered. It's best to minimize the early - ; environment where crucial features are offline. Note that the - ; processor is not fully initialized yet: Features such as floating - ; point instructions and instruction set extensions are not initialized - ; yet. The GDT should be loaded here. Paging should be enabled here. - ; C++ features such as global constructors and exceptions will require - ; runtime support to work as well. + push ebx ; multiboot_info + push eax ; multiboot_magic - ; -- START SSE - mov eax, cr0 - and ax, 0xFFFB ;clear coprocessor emulation CR0.EM - or ax, 0x2 ;set coprocessor monitoring CR0.MP + ; Enable SSE + mov eax, cr0 + and ax, 0xFFFB ; clear coprocessor emulation CR0.EM + or ax, (1 << 2) ; set coprocessor monitoring CR0.MP mov cr0, eax mov eax, cr4 - or ax, 3 << 9 ;set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time + or ax, (3 << 9) ; set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time mov cr4, eax - ; -- END SSE - ; -- START GDT/IDT + ; Initialize GDT & IDT extern init_descriptor_tables call init_descriptor_tables - ; -- END GDT/IDT - ; Enter the high-level kernel. The ABI requires the stack is 16-byte - ; aligned at the time of the call instruction (which afterwards pushes - ; the return pointer of size 4 bytes). The stack was originally 16-byte - ; aligned above and we've since pushed a multiple of 16 bytes to the - ; stack since (pushed 0 bytes so far) and the alignment is thus - ; preserved and the call is well defined. - ; note, that if you are building on Windows, C functions may have "_" prefix in assembly: _kernel_main - extern kernel_main - call kernel_main + ; Enter the high-level kernel. The ABI requires the stack is 16-byte + ; aligned at the time of the call instruction (which afterwards pushes + ; the return pointer of size 4 bytes). The stack was originally 16-byte + ; aligned above and we've since pushed a multiple of 16 bytes to the + ; stack since (pushed 0 bytes so far) and the alignment is thus + ; preserved and the call is well defined. + extern kernel_main + call kernel_main - ; If the system has nothing more to do, put the computer into an - ; infinite loop. To do that: - ; 1) Disable interrupts with cli (clear interrupt enable in eflags). - ; They are already disabled by the bootloader, so this is not needed. - ; Mind that you might later enable interrupts and return from - ; kernel_main (which is sort of nonsensical to do). - ; 2) Wait for the next interrupt to arrive with hlt (halt instruction). - ; Since they are disabled, this will lock up the computer. - ; 3) Jump to the hlt instruction if it ever wakes up due to a - ; non-maskable interrupt occurring or due to system management mode. - cli - + cli .hang: hlt - jmp .hang - + jmp .hang .end: