From 2c8cfb327ab8aff0deb44c826fe659bf0062fe59 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Sun, 7 Feb 2021 18:06:51 +0200 Subject: Rename kernel/ to src/ --- .gitignore | 2 +- kernel/boot.s | 93 -------------------------------------------- kernel/kernel.cc | 75 ----------------------------------- kernel/makefile | 2 - kernel/vga.cc | 61 ----------------------------- kernel/vga.h | 39 ------------------- makefile | 4 +- src/boot.s | 93 ++++++++++++++++++++++++++++++++++++++++++++ src/kernel.cc | 26 +++++++++++++ src/kernel/dump_multiboot.cc | 56 ++++++++++++++++++++++++++ src/makefile | 5 +++ src/vga.cc | 61 +++++++++++++++++++++++++++++ src/vga.h | 39 +++++++++++++++++++ 13 files changed, 283 insertions(+), 273 deletions(-) delete mode 100644 kernel/boot.s delete mode 100644 kernel/kernel.cc delete mode 100644 kernel/makefile delete mode 100644 kernel/vga.cc delete mode 100644 kernel/vga.h create mode 100644 src/boot.s create mode 100644 src/kernel.cc create mode 100644 src/kernel/dump_multiboot.cc create mode 100644 src/makefile create mode 100644 src/vga.cc create mode 100644 src/vga.h diff --git a/.gitignore b/.gitignore index ae3d99d..94e1555 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ glitch.elf glitch.iso -obj/ +build/ isodir/ diff --git a/kernel/boot.s b/kernel/boot.s deleted file mode 100644 index bb446d8..0000000 --- a/kernel/boot.s +++ /dev/null @@ -1,93 +0,0 @@ -/* - Declare a multiboot header that marks the program as a kernel. - https://www.gnu.org/software/grub/manual/multiboot2/html_node/index.html - - The Multiboot2 header must be contained completely within the first - 32kB of the OS image, and must be 64-bit (8 byte) aligned. -*/ -.set MULTIBOOT_HEADER_MAGIC, 0xe85250d6 # multiboot2 magic number -.set MULTIBOOT_ARCHITECTURE, 0 # protected mode i386 -.set MULTIBOOT_HEADER_TAG_END, 0 - -.section .multiboot -.align 8 -header_start: - .int MULTIBOOT_HEADER_MAGIC - .int MULTIBOOT_ARCHITECTURE - .int header_end - header_start - .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE + (header_end - header_start)) - - # TODO tags go here - - .short MULTIBOOT_HEADER_TAG_END - .short 0 - .int 8 -header_end: - -/* - 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. -*/ -.section .stack, "aw", @nobits -.align 16 -stack_bottom: - .skip 16 * 1024 -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. -*/ -.section .text -.global _start -.type _start, @function -_start: - mov $stack_top, %esp # point the stack pointer to the stack - - /* - 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. - */ - - pushl %ebx # push the pointer to the multiboot structure - pushl %eax # push the multiboot magic value - - /* - 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 pushed a multiple of 16 bytes to the - stack since (pushed 0 bytes so far), so the alignment has thus been - preserved and the call is well defined. - */ - 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 -hang: hlt - jmp hang - -/* -Set the size of the _start symbol to the current location '.' minus its start. -This is useful when debugging or when you implement call tracing. -*/ -.size _start, . - _start diff --git a/kernel/kernel.cc b/kernel/kernel.cc deleted file mode 100644 index 9ea5c95..0000000 --- a/kernel/kernel.cc +++ /dev/null @@ -1,75 +0,0 @@ -/* Check if the compiler thinks you are targeting the wrong operating system. */ -#if defined(__linux__) -#error "You are not using a cross-compiler" -#endif - -/* This tutorial will only work for the 32-bit ix86 targets. */ -#if !defined(__i386__) -#error "This tutorial needs to be compiled with a ix86-elf compiler" -#endif - -#include -#include -#include -#include "vga.h" - -extern "C" void kernel_main(uint32_t mb_magic, uint32_t mb_addr) { - VGA terminal; - Console::set(&terminal); - - printk("Hello, kernel World!\n"); - - printk("multiboot magic: ", uhex{mb_magic}, mb_magic == MULTIBOOT2_BOOTLOADER_MAGIC ? " valid" : " invalid", '\n'); - printk("multiboot addr: ", uhex{mb_addr}, !(mb_addr & 7) ? " is aligned" : " is not aligned", '\n'); - - struct multiboot_tag* tag; - const uint32_t size = *(unsigned*)mb_addr; - printk("Announced mbi size ", size, '\n'); - - for (tag = (struct multiboot_tag*)(mb_addr + 8); tag->type != MULTIBOOT_TAG_TYPE_END; - tag = (struct multiboot_tag*)((multiboot_uint8_t*)tag + ((tag->size + 7) & ~7))) { - switch (tag->type) { - case MULTIBOOT_TAG_TYPE_CMDLINE: { - auto* t = reinterpret_cast(tag); - printk("Command line = [", t->string, "]\n"); - } break; - - case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: { - auto* t = reinterpret_cast(tag); - printk("Boot loader name = [", t->string, "]\n"); - } break; - - case MULTIBOOT_TAG_TYPE_BOOTDEV: { - auto* t = reinterpret_cast(tag); - printk("Boot device ", uhex{t->biosdev}, " slice ", t->slice, " part ", t->part, '\n'); - } break; - - case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: { - auto* t = reinterpret_cast(tag); - printk("mem_lower = ", t->mem_lower, "KB\n", "mem_upper = ", t->mem_upper, "KB\n"); - } break; - - case MULTIBOOT_TAG_TYPE_MMAP: { - auto* t = reinterpret_cast(tag); - multiboot_memory_map_t* mmap; - - printk("memory map\n"); - for (mmap = t->entries; (multiboot_uint8_t*)mmap < (multiboot_uint8_t*)tag + tag->size; - mmap = (multiboot_memory_map_t*)((unsigned long)mmap + ((struct multiboot_tag_mmap*)tag)->entry_size)) { - printk(" base_addr = ", uhex{(unsigned)(mmap->addr >> 32)}, ' ', uhex{(unsigned)(mmap->addr & 0xffffffff)}); - printk(" length = ", (unsigned)(mmap->len >> 32), ' ', (unsigned)(mmap->len & 0xffffffff)); - printk(" type = ", (unsigned)mmap->type, '\n'); - } - } break; - - default: - printk("Tag ", tag->type, ", Size ", tag->size, '\n'); - break; - } // switch(tag->type) - } // for(each tag) - - tag = (struct multiboot_tag*)((multiboot_uint8_t*)tag + ((tag->size + 7) & ~7)); - printk("Total mbi size ", (unsigned)tag - mb_addr, '\n'); - - abort(); -} diff --git a/kernel/makefile b/kernel/makefile deleted file mode 100644 index 23e3683..0000000 --- a/kernel/makefile +++ /dev/null @@ -1,2 +0,0 @@ -AS_OBJ += kernel/boot.o -CXX_OBJ += kernel/kernel.o kernel/vga.o diff --git a/kernel/vga.cc b/kernel/vga.cc deleted file mode 100644 index 83d0060..0000000 --- a/kernel/vga.cc +++ /dev/null @@ -1,61 +0,0 @@ -#include "vga.h" -#include - -constexpr uint8_t vga_entry_color(VGA::vga_color fg, VGA::vga_color bg) { - return fg | bg << 4; -} - -constexpr uint16_t vga_entry(unsigned char uc, uint8_t color) { - return (uint16_t)uc | (uint16_t)color << 8; -} - -VGA::VGA(vga_color fg, vga_color bg, uint32_t address) { - color = vga_entry_color(fg, bg); - buffer = (uint16_t*)address; - - // clear buffer - for (size_t y = 0; y < max_rows; y++) { - for (size_t x = 0; x < max_columns; x++) { - const size_t index = y * max_columns + x; - buffer[index] = vga_entry(' ', color); - } - } -} - -void VGA::write(char c) { - switch (c) { - case '\n': - column = 0; - ++row; - break; - default: { - const size_t index = row * max_columns + column; - buffer[index] = vga_entry(c, (color == 0) ? this->color : color); - ++column; - } - } - - if (column == max_columns) { - column = 0; - ++row; - } - - if (row == max_rows) { - // scroll up - move rows 1~25 up by one - for (size_t y = 1; y < max_rows; y++) { - const auto prev_y = y - 1; - for (size_t x = 0; x < max_columns; ++x) { - const auto prev = prev_y * max_columns + x; - const auto idx = y * max_columns + x; - buffer[prev] = buffer[idx]; - } - } - --row; - } -} - -void VGA::write(ViewIterator& iter) { - while (iter) { - write(iter.next()); - } -} diff --git a/kernel/vga.h b/kernel/vga.h deleted file mode 100644 index 3052dbc..0000000 --- a/kernel/vga.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include - -class VGA : public Console { -public: - /* Hardware text mode color constants. */ - enum vga_color { - VGA_COLOR_BLACK = 0, - VGA_COLOR_BLUE = 1, - VGA_COLOR_GREEN = 2, - VGA_COLOR_CYAN = 3, - VGA_COLOR_RED = 4, - VGA_COLOR_MAGENTA = 5, - VGA_COLOR_BROWN = 6, - VGA_COLOR_LIGHT_GREY = 7, - VGA_COLOR_DARK_GREY = 8, - VGA_COLOR_LIGHT_BLUE = 9, - VGA_COLOR_LIGHT_GREEN = 10, - VGA_COLOR_LIGHT_CYAN = 11, - VGA_COLOR_LIGHT_RED = 12, - VGA_COLOR_LIGHT_MAGENTA = 13, - VGA_COLOR_LIGHT_BROWN = 14, - VGA_COLOR_WHITE = 15, - }; - - VGA(vga_color fg = VGA_COLOR_BLACK, vga_color bg = VGA_COLOR_LIGHT_GREY, uint32_t address = 0xB8000); - ~VGA() = default; - - void write(char c) override; - void write(ViewIterator& iter) override; - - void set_color(vga_color fg, vga_color bg) { color = (fg | bg << 4); } - -private: - const size_t max_columns = 80, max_rows = 25; - size_t column = 0, row = 0; - uint8_t color; - uint16_t* buffer; -}; diff --git a/makefile b/makefile index 6dd59d7..0235442 100644 --- a/makefile +++ b/makefile @@ -4,9 +4,9 @@ # != execute a shell script on the right-hand side and assign its result to the left-hand side include toolchain.makefile -OBJ_DIR := obj +OBJ_DIR := build -include kernel/makefile +include src/makefile include libk/makefile AS_OBJ := $(addprefix $(OBJ_DIR)/, $(AS_OBJ)) CXX_OBJ := $(addprefix $(OBJ_DIR)/, $(CXX_OBJ)) diff --git a/src/boot.s b/src/boot.s new file mode 100644 index 0000000..bb446d8 --- /dev/null +++ b/src/boot.s @@ -0,0 +1,93 @@ +/* + Declare a multiboot header that marks the program as a kernel. + https://www.gnu.org/software/grub/manual/multiboot2/html_node/index.html + + The Multiboot2 header must be contained completely within the first + 32kB of the OS image, and must be 64-bit (8 byte) aligned. +*/ +.set MULTIBOOT_HEADER_MAGIC, 0xe85250d6 # multiboot2 magic number +.set MULTIBOOT_ARCHITECTURE, 0 # protected mode i386 +.set MULTIBOOT_HEADER_TAG_END, 0 + +.section .multiboot +.align 8 +header_start: + .int MULTIBOOT_HEADER_MAGIC + .int MULTIBOOT_ARCHITECTURE + .int header_end - header_start + .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE + (header_end - header_start)) + + # TODO tags go here + + .short MULTIBOOT_HEADER_TAG_END + .short 0 + .int 8 +header_end: + +/* + 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. +*/ +.section .stack, "aw", @nobits +.align 16 +stack_bottom: + .skip 16 * 1024 +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. +*/ +.section .text +.global _start +.type _start, @function +_start: + mov $stack_top, %esp # point the stack pointer to the stack + + /* + 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. + */ + + pushl %ebx # push the pointer to the multiboot structure + pushl %eax # push the multiboot magic value + + /* + 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 pushed a multiple of 16 bytes to the + stack since (pushed 0 bytes so far), so the alignment has thus been + preserved and the call is well defined. + */ + 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 +hang: hlt + jmp hang + +/* +Set the size of the _start symbol to the current location '.' minus its start. +This is useful when debugging or when you implement call tracing. +*/ +.size _start, . - _start diff --git a/src/kernel.cc b/src/kernel.cc new file mode 100644 index 0000000..c083364 --- /dev/null +++ b/src/kernel.cc @@ -0,0 +1,26 @@ +/* Check if the compiler thinks you are targeting the wrong operating system. */ +#if defined(__linux__) +#error "You are not using a cross-compiler" +#endif + +/* This tutorial will only work for the 32-bit ix86 targets. */ +#if !defined(__i386__) +#error "This tutorial needs to be compiled with a ix86-elf compiler" +#endif + +#include +#include +#include "vga.h" + +extern "C" void dump_multiboot(uint32_t mb_magic, uint32_t mb_addr); + +extern "C" void kernel_main(uint32_t mb_magic, uint32_t mb_addr) { + VGA terminal; + Console::set(&terminal); + + printk("Hello, kernel World!\n"); + + dump_multiboot(mb_magic, mb_addr); + + abort(); +} diff --git a/src/kernel/dump_multiboot.cc b/src/kernel/dump_multiboot.cc new file mode 100644 index 0000000..60b4b91 --- /dev/null +++ b/src/kernel/dump_multiboot.cc @@ -0,0 +1,56 @@ +#include +#include + +extern "C" void dump_multiboot(uint32_t mb_magic, uint32_t mb_addr) { + printk("multiboot magic: ", uhex{mb_magic}, mb_magic == MULTIBOOT2_BOOTLOADER_MAGIC ? " valid" : " invalid", '\n'); + printk("multiboot addr: ", uhex{mb_addr}, !(mb_addr & 7) ? " is aligned" : " is not aligned", '\n'); + + struct multiboot_tag* tag; + const uint32_t size = *(unsigned*)mb_addr; + printk("Announced mbi size ", size, '\n'); + + for (tag = (struct multiboot_tag*)(mb_addr + 8); tag->type != MULTIBOOT_TAG_TYPE_END; + tag = (struct multiboot_tag*)((multiboot_uint8_t*)tag + ((tag->size + 7) & ~7))) { + switch (tag->type) { + case MULTIBOOT_TAG_TYPE_CMDLINE: { + auto* t = reinterpret_cast(tag); + printk("Command line = [", t->string, "]\n"); + } break; + + case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: { + auto* t = reinterpret_cast(tag); + printk("Boot loader name = [", t->string, "]\n"); + } break; + + case MULTIBOOT_TAG_TYPE_BOOTDEV: { + auto* t = reinterpret_cast(tag); + printk("Boot device ", uhex{t->biosdev}, " slice ", t->slice, " part ", t->part, '\n'); + } break; + + case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: { + auto* t = reinterpret_cast(tag); + printk("mem_lower = ", t->mem_lower, "KB\n", "mem_upper = ", t->mem_upper, "KB\n"); + } break; + + case MULTIBOOT_TAG_TYPE_MMAP: { + auto* t = reinterpret_cast(tag); + multiboot_memory_map_t* mmap; + + printk("memory map\n"); + for (mmap = t->entries; (multiboot_uint8_t*)mmap < (multiboot_uint8_t*)tag + tag->size; + mmap = (multiboot_memory_map_t*)((unsigned long)mmap + ((struct multiboot_tag_mmap*)tag)->entry_size)) { + printk(" base_addr = ", uhex{(unsigned)(mmap->addr >> 32)}, ' ', uhex{(unsigned)(mmap->addr & 0xffffffff)}); + printk(" length = ", (unsigned)(mmap->len >> 32), ' ', (unsigned)(mmap->len & 0xffffffff)); + printk(" type = ", (unsigned)mmap->type, '\n'); + } + } break; + + default: + printk("Tag ", tag->type, ", Size ", tag->size, '\n'); + break; + } // switch(tag->type) + } // for(each tag) + + tag = (struct multiboot_tag*)((multiboot_uint8_t*)tag + ((tag->size + 7) & ~7)); + printk("Total mbi size ", (unsigned)tag - mb_addr, '\n'); +} diff --git a/src/makefile b/src/makefile new file mode 100644 index 0000000..86c8877 --- /dev/null +++ b/src/makefile @@ -0,0 +1,5 @@ +AS_OBJ += src/boot.o + +CXX_OBJ += src/kernel.o \ + src/kernel/dump_multiboot.o \ + src/vga.o diff --git a/src/vga.cc b/src/vga.cc new file mode 100644 index 0000000..83d0060 --- /dev/null +++ b/src/vga.cc @@ -0,0 +1,61 @@ +#include "vga.h" +#include + +constexpr uint8_t vga_entry_color(VGA::vga_color fg, VGA::vga_color bg) { + return fg | bg << 4; +} + +constexpr uint16_t vga_entry(unsigned char uc, uint8_t color) { + return (uint16_t)uc | (uint16_t)color << 8; +} + +VGA::VGA(vga_color fg, vga_color bg, uint32_t address) { + color = vga_entry_color(fg, bg); + buffer = (uint16_t*)address; + + // clear buffer + for (size_t y = 0; y < max_rows; y++) { + for (size_t x = 0; x < max_columns; x++) { + const size_t index = y * max_columns + x; + buffer[index] = vga_entry(' ', color); + } + } +} + +void VGA::write(char c) { + switch (c) { + case '\n': + column = 0; + ++row; + break; + default: { + const size_t index = row * max_columns + column; + buffer[index] = vga_entry(c, (color == 0) ? this->color : color); + ++column; + } + } + + if (column == max_columns) { + column = 0; + ++row; + } + + if (row == max_rows) { + // scroll up - move rows 1~25 up by one + for (size_t y = 1; y < max_rows; y++) { + const auto prev_y = y - 1; + for (size_t x = 0; x < max_columns; ++x) { + const auto prev = prev_y * max_columns + x; + const auto idx = y * max_columns + x; + buffer[prev] = buffer[idx]; + } + } + --row; + } +} + +void VGA::write(ViewIterator& iter) { + while (iter) { + write(iter.next()); + } +} diff --git a/src/vga.h b/src/vga.h new file mode 100644 index 0000000..3052dbc --- /dev/null +++ b/src/vga.h @@ -0,0 +1,39 @@ +#pragma once +#include + +class VGA : public Console { +public: + /* Hardware text mode color constants. */ + enum vga_color { + VGA_COLOR_BLACK = 0, + VGA_COLOR_BLUE = 1, + VGA_COLOR_GREEN = 2, + VGA_COLOR_CYAN = 3, + VGA_COLOR_RED = 4, + VGA_COLOR_MAGENTA = 5, + VGA_COLOR_BROWN = 6, + VGA_COLOR_LIGHT_GREY = 7, + VGA_COLOR_DARK_GREY = 8, + VGA_COLOR_LIGHT_BLUE = 9, + VGA_COLOR_LIGHT_GREEN = 10, + VGA_COLOR_LIGHT_CYAN = 11, + VGA_COLOR_LIGHT_RED = 12, + VGA_COLOR_LIGHT_MAGENTA = 13, + VGA_COLOR_LIGHT_BROWN = 14, + VGA_COLOR_WHITE = 15, + }; + + VGA(vga_color fg = VGA_COLOR_BLACK, vga_color bg = VGA_COLOR_LIGHT_GREY, uint32_t address = 0xB8000); + ~VGA() = default; + + void write(char c) override; + void write(ViewIterator& iter) override; + + void set_color(vga_color fg, vga_color bg) { color = (fg | bg << 4); } + +private: + const size_t max_columns = 80, max_rows = 25; + size_t column = 0, row = 0; + uint8_t color; + uint16_t* buffer; +}; -- cgit v1.2.1