commit 17364e2e24d6ac0c9b12517ee0cf2433d9c187bf Author: Maciej Krzyżanowski Date: Fri Oct 13 09:30:58 2023 +0200 And so it begins diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..caa78bf --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +boot.o +kernel.o +isodir/ +mkos.bin +mkos.iso diff --git a/boot.s b/boot.s new file mode 100644 index 0000000..a475f37 --- /dev/null +++ b/boot.s @@ -0,0 +1,65 @@ +/* + Nagłówek Multiboot +*/ + +/* Moduły bootujące jak i sam kernel zostanie załaodwany z wyrównaniem do 4 KB + * stron */ +.set ALIGN, 1<<0 +/* Kernelowi zostaną udostępnione informacje o pamięci, które zdobył + * bootloader. Opcjonalnie nawet mapa pamięci */ +.set MEMINFO, 1<<1 +/* Połączenie flag */ +.set FLAGS, ALIGN | MEMINFO +/* Wartość magicznego numerka dla Multiboot 1 */ +.set MAGIC, 0x1BADB002 +/* Suma kontrola, która w sumie z flagami i numerkiem ma dać 0, czyli należy + * podać ich odwrotność. */ +.set CHECKSUM, -(MAGIC + FLAGS) + +// TODO: Dopisać czas do dziennika + +/* Faktyczny nagłówek multiboot z wykorzystaniem powyższych wartości */ +.section .multiboot +.align 4 +.long MAGIC +.long FLAGS +.long CHECKSUM + +/* + Alokacja stosu +*/ + +.section .bss +.align 16 +stack_bottom: +/* Stos o wielkości 16 KB */ +.skip 16834 +stack_top: + +/* + Oznaczenie startu, tu zaczyna się kod kernela! +*/ +.section .text +.global _start +.type _start, @function +_start: +/* Tutaj podobno jest tryb chroniony już, jednak zastanawia czy faktycznie +bootloader ustawia za nas segmentacje pamięci? */ + +/* Ustawienie ESP na wierzchołek stosu */ +mov $stack_top, %esp + +/* Tutaj jakieś ustawienia inicjalizacyjne trzeba zrobić normalnie */ + +/* Wywołanie kernela */ +call kernel_main + +/* Wieczne oczekiwanie po zakończeniu kodu kernela */ + cli +1: hlt + /* Skacze do (lokalnej) labelki o nazwie 1, wstecz */ + jmp 1b + +/* Ustawienie wielkości funkcji start, co pozwala uniknąć błędów z + * debuggowaniem */ +.size _start, . - _start diff --git a/grub.cfg b/grub.cfg new file mode 100644 index 0000000..4fe5dcb --- /dev/null +++ b/grub.cfg @@ -0,0 +1,3 @@ +menuentry "mkos" { + multiboot /boot/mkos.bin +} diff --git a/kernel.c b/kernel.c new file mode 100644 index 0000000..344732a --- /dev/null +++ b/kernel.c @@ -0,0 +1,200 @@ +#include +#include +#include + +/* Check if the compiler thinks you are targeting the wrong operating system. */ +#if defined(__linux__) +#error "You are not using a cross-compiler, you will most certainly run into trouble" +#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 + +/* 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, +}; + +static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) +{ + return fg | bg << 4; +} + +static inline uint16_t vga_entry(unsigned char uc, uint8_t color) +{ + return (uint16_t) uc | (uint16_t) color << 8; +} + +size_t strlen(const char* str) +{ + size_t len = 0; + while (str[len]) + len++; + return len; +} + +static const size_t VGA_WIDTH = 80; +static const size_t VGA_HEIGHT = 25; + +size_t terminal_row; +size_t terminal_column; +uint8_t terminal_color; +uint16_t* terminal_buffer; + +void terminal_initialize(void) +{ + terminal_row = 0; + terminal_column = 0; + terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + terminal_buffer = (uint16_t*) 0xB8000; + for (size_t y = 0; y < VGA_HEIGHT; y++) { + for (size_t x = 0; x < VGA_WIDTH; x++) { + const size_t index = y * VGA_WIDTH + x; + terminal_buffer[index] = vga_entry(' ', terminal_color); + } + } +} + +void terminal_setcolor(uint8_t color) +{ + terminal_color = color; +} + +void terminal_putentryat(char c, uint8_t color, size_t x, size_t y) +{ + const size_t index = y * VGA_WIDTH + x; + terminal_buffer[index] = vga_entry(c, color); +} + +void terminal_putchar(char c) +{ + terminal_putentryat(c, terminal_color, terminal_column, terminal_row); + if (++terminal_column == VGA_WIDTH) { + terminal_column = 0; + if (++terminal_row == VGA_HEIGHT) { + terminal_row--; + // Fixed at last row now + // Now we need to move from second line to end to the start + for (size_t y = 1; y < VGA_HEIGHT; y++) { + for (size_t x = 0; x < VGA_WIDTH; x++) { + const size_t src_index = y * VGA_WIDTH + x; + char toCopy = terminal_buffer[src_index]; + terminal_putentryat(toCopy, terminal_color, x, y-1); + } + } + + for (size_t x = 0; x < VGA_WIDTH; x++) { + terminal_putentryat(' ', terminal_color, x, VGA_HEIGHT - 1); + } + } + } + + // Write branding + uint8_t prevColor = terminal_color; + + terminal_color = vga_entry_color(VGA_COLOR_BLACK, + VGA_COLOR_LIGHT_MAGENTA); + terminal_putentryat('M', terminal_color, VGA_WIDTH - 4, 0); + terminal_color = vga_entry_color(VGA_COLOR_BLACK, + VGA_COLOR_LIGHT_CYAN); + terminal_putentryat('K', terminal_color, VGA_WIDTH - 3, 0); + terminal_color = vga_entry_color(VGA_COLOR_BLACK, + VGA_COLOR_LIGHT_BLUE); + terminal_putentryat('O', terminal_color, VGA_WIDTH - 2, 0); + terminal_color = vga_entry_color(VGA_COLOR_BLACK, + VGA_COLOR_LIGHT_GREEN); + terminal_putentryat('S', terminal_color, VGA_WIDTH - 1, 0); + + terminal_color = prevColor; +} + +void terminal_newline() { + for(size_t x = terminal_column; x < VGA_WIDTH; x++) { + terminal_putchar(' '); + } +} + +void terminal_write(const char* data, size_t size) +{ + for (size_t i = 0; i < size; i++) { + if (data[i] == '\n') { + terminal_newline(); + } else { + terminal_putchar(data[i]); + } + } +} + +void terminal_writenum(int number) { + size_t size = 0; + char numChars[15]; + + while (number != 0) { + int rest = number / 10; + int digit = number % 10; + + numChars[14 - size++] = 48 + digit; + number = rest; + } + + terminal_write(numChars + (15 - size), size); +} + +void terminal_writestring(const char* data) +{ + terminal_write(data, strlen(data)); +} + +void terminal_writegreeting() { + terminal_writestring(" .-'''-. \n"); + terminal_writestring(" ' _ \\ \n"); + terminal_writestring(" __ __ ___ . / /` '. \\ \n"); + terminal_writestring("| |/ `.' `. .'| . | \\ ' \n"); + terminal_writestring("| .-. .-. ' .' | | ' | ' \n"); + terminal_writestring("| | | | | |< | \\ \\ / / \n"); + terminal_writestring("| | | | | | | | ____`. ` ..' / _ \n"); + terminal_writestring("| | | | | | | | \\ .' '-...-'`.' | \n"); + terminal_writestring("| | | | | | | |/ . . | / \n"); + terminal_writestring("|__| |__| |__| | /\\ \\ .'.'| |// \n"); + terminal_writestring(" | | \\ \\ .'.'.-' / \n"); + terminal_writestring(" ' \\ \\ \\ .' \\_.' \n"); + terminal_writestring(" '------' '---' \n"); +} + +void kernel_main(void) +{ + /* Initialize terminal interface */ + terminal_initialize(); + + /* Newline support is left as an exercise. */ + terminal_writestring("TEGO NIE POWINNO BYC WIDAC\n"); + terminal_writestring("Witam i pozdrawiam, MK\nTest wielolinijkowosci\n"); + for (size_t i = 0; i < VGA_HEIGHT - 3; i++) { + for (size_t j = 0; j < i; j++) { + terminal_writestring("*"); + } + if (i != VGA_HEIGHT - 3) + terminal_writestring("\n"); + } + terminal_newline(); + terminal_writenum(123456789); + terminal_newline(); + terminal_writegreeting(); +} diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..38ddd94 --- /dev/null +++ b/linker.ld @@ -0,0 +1,43 @@ +/* The bootloader will look at this image and start execution at the symbol + designated as the entry point. */ +ENTRY(_start) + +/* 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; + + /* 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) + { + *(.multiboot) + *(.text) + } + + /* Read-only data. */ + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + /* Read-write data (initialized) */ + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + /* Read-write data (uninitialized) and stack */ + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } + + /* 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. */ +} diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..e74fbac --- /dev/null +++ b/start.sh @@ -0,0 +1,4 @@ +#!/bin/bash +../Kompilator/cross/bin/i686-elf-gcc -c kernel.c -o kernel.o -std=gnu99 -ffreestanding -O2 -Wall -Wextra +../Kompilator/cross/bin/i686-elf-gcc -T linker.ld -o mkos.bin -ffreestanding -O2 -nostdlib boot.o kernel.o -lgcc +qemu-system-i386 -kernel mkos.bin