From 122552970866f6bb84d1603d2a1ea84c16b00a61 Mon Sep 17 00:00:00 2001 From: Xnoe Date: Mon, 11 Oct 2021 20:47:04 +0100 Subject: [PATCH] Fixed paging fully now. Kernel is loaded with virtual memory enabled. Just need to write an allocator and make kernel use virtual memory addresses for its stuff. Restructured codebase to be less messy. Updated Makefile to put binary files under build/ rather than in root directory --- Makefile | 52 ++++++----- boot_stage2.ld | 15 --- kernel.ld | 15 --- boot.asm => src/boot/boot.asm | 0 src/boot_stage2/atapio.c | 122 +++++++++++++++++++++++++ src/boot_stage2/atapio.h | 16 ++++ src/boot_stage2/boot_stage2.ld | 14 +++ src/boot_stage2/io.c | 19 ++++ src/boot_stage2/io.h | 12 +++ src/boot_stage2/main.c | 9 +- src/boot_stage2/paging.c | 46 ++++++++++ src/boot_stage2/paging.h | 37 ++++++++ src/boot_stage2/screenstuff.c | 161 +++++++++++++++++++++++++++++++++ src/boot_stage2/screenstuff.h | 19 ++++ src/boot_stage2/strings.c | 69 ++++++++++++++ src/boot_stage2/strings.h | 11 +++ src/boot_stage2/types.h | 11 +++ src/kernel/kernel.ld | 15 +++ 18 files changed, 585 insertions(+), 58 deletions(-) delete mode 100644 boot_stage2.ld delete mode 100644 kernel.ld rename boot.asm => src/boot/boot.asm (100%) create mode 100644 src/boot_stage2/atapio.c create mode 100644 src/boot_stage2/atapio.h create mode 100644 src/boot_stage2/boot_stage2.ld create mode 100644 src/boot_stage2/io.c create mode 100644 src/boot_stage2/io.h create mode 100644 src/boot_stage2/paging.c create mode 100644 src/boot_stage2/paging.h create mode 100644 src/boot_stage2/screenstuff.c create mode 100644 src/boot_stage2/screenstuff.h create mode 100644 src/boot_stage2/strings.c create mode 100644 src/boot_stage2/strings.h create mode 100644 src/boot_stage2/types.h create mode 100644 src/kernel/kernel.ld diff --git a/Makefile b/Makefile index 1a5ea81..a30d12e 100644 --- a/Makefile +++ b/Makefile @@ -1,45 +1,49 @@ CFLAGS = -m32 -mgeneral-regs-only -nostdlib -fno-builtin -fno-exceptions -fno-leading-underscore -fno-pie -fno-stack-protector -Wno-pointer-to-int-cast LDFLAGS = -DISK_IMG_FILES = kernel.bin -KERNEL32_OBJS = screenstuff.o io.o idt.o keyboard.o strings.o atapio.o c_code_entry.o kernel.o paging.o +DISK_IMG_FILES = build/kernel/kernel.bin +KERNEL_OBJS = build/c_code_entry.o build/kernel/screenstuff.o build/kernel/io.o build/kernel/idt.o build/kernel/keyboard.o build/kernel/strings.o build/kernel/atapio.o build/kernel/kernel.o build/kernel/paging.o +STAGE2_OBS = build/c_code_entry.o build/boot_stage2/io.o build/boot_stage2/atapio.o build/boot_stage2/strings.o build/boot_stage2/screenstuff.o build/boot_stage2/stage2.o build/boot_stage2/paging.o run: disk.img qemu-system-x86_64 disk.img -disk.img: clean boot.sector boot.stage2 $(DISK_IMG_FILES) +disk.img: clean prepare build/boot/boot.bin build/boot_stage2/boot.bin $(DISK_IMG_FILES) dd if=/dev/zero of=disk.img count=43 bs=100k - dd if=boot.sector of=disk.img conv=notrunc - dd obs=512 seek=1 if=boot.stage2 of=disk.img conv=notrunc + dd if=build/boot/boot.bin of=disk.img conv=notrunc + dd obs=512 seek=1 if=build/boot_stage2/boot.bin of=disk.img conv=notrunc mount disk.img img.d - cp *.bin img.d/ + cp $(DISK_IMG_FILES) img.d/ cp hello.txt img.d/ umount img.d chmod 777 disk.img -clean: - rm $(DISK_IMG_FILES) $(KERNEL32_OBJS) boot.sector disk.img || true +prepare: + mkdir -p img.d + mkdir -p build/boot + mkdir -p build/boot_stage2 + mkdir -p build/kernel -boot.sector: boot.asm +clean: + rm -rf build + +build/boot/boot.bin: src/boot/boot.asm nasm $< -o $@ -boot.stage2: boot_stage2.ld boot.stage2.o - ld $(LDFLAGS) -T $< boot.stage2.o +build/boot_stage2/boot.bin: src/boot_stage2/boot_stage2.ld $(STAGE2_OBS) + ld $(LDFLAGS) -T $< $(STAGE2_OBS) -boot.stage2.o: src/boot_stage2/main.c io.o atapio.o strings.o c_code_entry.o screenstuff.o paging.o +build/kernel/kernel.bin: src/kernel/kernel.ld $(KERNEL_OBJS) + ld $(LDFLAGS) -T $< $(KERNEL_OBJS) + +build/boot_stage2/stage2.o: src/boot_stage2/main.c gcc $(CFLAGS) -o $@ -c $< -%.bin: %.asm - nasm $< -o $@ +build/kernel/%.o: src/kernel/%.c + gcc $(CFLAGS) -o $@ -c $< -kernel.bin: kernel.ld $(KERNEL32_OBJS) - ld $(LDFLAGS) -T $< $(KERNEL32_OBJS) +build/boot_stage2/%.o: src/boot_stage2/%.c + gcc $(CFLAGS) -o $@ -c $< -%.o: src/kernel/%.asm - nasm -felf32 $< -o $@ - -%.o: src/%.asm - nasm -felf32 $< -o $@ - -%.o: src/kernel/%.c - gcc $(CFLAGS) -o $@ -c $< \ No newline at end of file +build/%.o: src/%.asm + nasm -felf32 $< -o $@ \ No newline at end of file diff --git a/boot_stage2.ld b/boot_stage2.ld deleted file mode 100644 index b98d550..0000000 --- a/boot_stage2.ld +++ /dev/null @@ -1,15 +0,0 @@ -OUTPUT_FORMAT(binary) -OUTPUT_ARCH(i386:i386) - -INPUT(io.o atapio.o strings.o c_code_entry.o screenstuff.o paging.o) -OUTPUT(boot.stage2) - -SECTIONS { - . = 0x7E00; - - .text : { - c_code_entry.o(.text) - boot.stage2.o(.text) - *(.text) - } -} \ No newline at end of file diff --git a/kernel.ld b/kernel.ld deleted file mode 100644 index ca526ef..0000000 --- a/kernel.ld +++ /dev/null @@ -1,15 +0,0 @@ -OUTPUT_FORMAT(binary) -OUTPUT_ARCH(i386:i386) - -OUTPUT(kernel.bin) - -SECTIONS { - . = 0xc0000000; - - .text : { - c_code_entry.o(.text) - kernel.o(.text) - *(.text) - heap_section = .; - } -} \ No newline at end of file diff --git a/boot.asm b/src/boot/boot.asm similarity index 100% rename from boot.asm rename to src/boot/boot.asm diff --git a/src/boot_stage2/atapio.c b/src/boot_stage2/atapio.c new file mode 100644 index 0000000..c6e7745 --- /dev/null +++ b/src/boot_stage2/atapio.c @@ -0,0 +1,122 @@ +#include "atapio.h" + +// Disk code + +// Primary ATA Bus: 0x1f0 to 0x1f7 +// Device Control Register: 0x3f6 +// Secondary ATA Bus: 0x170 to 0x177 +// Device Control Register: 0x376 + + +uint16_t identify_result[256]; +uint32_t total_28_lbas = 0; + +uint8_t* rootDirEntries = 0x1000000; +uint16_t* FAT1 = 0x1002000; + +uint16_t countReserved; +uint8_t countFATs; +uint16_t countRDEs; +uint16_t sectorsPerFAT; + + +void init_atapio() { + countReserved = *(uint16_t*)0x7c0e; + countFATs = *(uint8_t*)0x7c10; + countRDEs = *(uint16_t*)0x7c11; + sectorsPerFAT = *(uint16_t*)0x7c16; + + // Select Drive 0 on the Primary Bus + outb(0x1f6, 0xa0); + + // Set sector count to 0 for IDENTIFY + outb(0x1f2, 0); + // Set LBAlo to 0 + outb(0x1f3, 0); + // Set LBAmid to 0 + outb(0x1f4, 0); + // Set LBAhi to 0 + outb(0x1f5, 0); + + // Send IDENTIFY command + outb(0x1f7, 0xec); + + uint8_t status = inb(0x1f7); + if (status) { + while ((status = inb(0x1f7)) & 0x80); + + if ( !(inb(0x1f4) || inb(0x1f5)) ) { + while ( !(status & 8 || status & 1) ) + status = inb(0x1f7); + + if (!(status & 1)) { + for (int index=0; index<256; index++) + identify_result[index] = inw(0x1f0); + } + } + } + + total_28_lbas = *(uint32_t*)(identify_result+60); + + // We've initialised now, let's load the FAT and RootDirEntries. + read_sectors(sectorsPerFAT * countFATs + countReserved, countRDEs / 16, rootDirEntries); + read_sectors(countReserved, sectorsPerFAT, FAT1); +} + +void read_sector(uint32_t address, uint8_t* buffer) { + outb(0x1f6, 0xe0 | ((address>>24)&0x0f)); + // Read a single sector + outb(0x1f2, 1); + // Set LBAlo, LBAmid and LBAhi + outb(0x1f3, address); + outb(0x1f4, address>>8); + outb(0x1f5, address>>16); + + // Send read command + outb(0x1f7, 0x20); + // Poll + uint8_t status = inb(0x1f7); + while ( (status & 0x80) && !(status & 8) ) + status = inb(0x1f7); + + for (int index=0; index<256; index++) + ((uint16_t*)buffer)[index] = inw(0x1f0); +} + +void read_sectors(uint32_t address, int count, uint8_t* buffer) { + for (int i=0; i + +#include "io.h" +#include "types.h" +#include "strings.h" + +void init_atapio(); +void read_sector(uint32_t address, uint8_t* buffer); +void read_sectors(uint32_t address, int count, uint8_t* buffer); +uint16_t file_exists(char* filename); +void load_file(char* filename, uint8_t* location); + +#endif \ No newline at end of file diff --git a/src/boot_stage2/boot_stage2.ld b/src/boot_stage2/boot_stage2.ld new file mode 100644 index 0000000..682c583 --- /dev/null +++ b/src/boot_stage2/boot_stage2.ld @@ -0,0 +1,14 @@ +OUTPUT_FORMAT(binary) +OUTPUT_ARCH(i386:i386) + +OUTPUT(build/boot_stage2/boot.bin) + +SECTIONS { + . = 0x7E00; + + .text : { + build/c_code_entry.o(.text) + build/boot_stage2/stage2.o(.text) + build/boot_stage2/*(.text) + } +} \ No newline at end of file diff --git a/src/boot_stage2/io.c b/src/boot_stage2/io.c new file mode 100644 index 0000000..ae78e65 --- /dev/null +++ b/src/boot_stage2/io.c @@ -0,0 +1,19 @@ +#include "io.h" + +void outb(uint16_t portnumber, uint8_t data) { + asm volatile("outb %0, %1" : : "a" (data), "Nd" (portnumber)); +} +uint8_t inb(uint16_t portnumber) { + uint8_t result; + asm volatile("inb %1, %0" : "=a" (result) : "Nd" (portnumber)); + return result; +} + +void outw(uint16_t portnumber, uint16_t data) { + asm volatile("outw %0, %1" : : "a" (data), "Nd" (portnumber)); +} +uint16_t inw(uint16_t portnumber) { + uint16_t result; + asm volatile("inw %1, %0" : "=a" (result) : "Nd" (portnumber)); + return result; +} \ No newline at end of file diff --git a/src/boot_stage2/io.h b/src/boot_stage2/io.h new file mode 100644 index 0000000..8df8ec6 --- /dev/null +++ b/src/boot_stage2/io.h @@ -0,0 +1,12 @@ +#ifndef IO_H +#define IO_H + +#include "types.h" + +void outb(uint16_t portnumber, uint8_t data); +uint8_t inb(uint16_t portnumber); + +void outw(uint16_t portnumber, uint16_t data); +uint16_t inw(uint16_t portnumber); + +#endif \ No newline at end of file diff --git a/src/boot_stage2/main.c b/src/boot_stage2/main.c index 2dbc016..7011b08 100644 --- a/src/boot_stage2/main.c +++ b/src/boot_stage2/main.c @@ -1,6 +1,6 @@ -#include "../kernel/atapio.h" -#include "../kernel/screenstuff.h" -#include "../kernel/paging.h" +#include "atapio.h" +#include "screenstuff.h" +#include "paging.h" typedef struct { uint32_t base_low; @@ -120,7 +120,8 @@ void main() { map_many_4k_phys_to_virt(0x121000, 0xc0101000, kernel_page_directory, kernel_page_tables, 1024); // Map 1024 pages from 0x121000 to 0xc0101000 map_4k_phys_to_virt(0xb8000, 0xc0501000, kernel_page_directory, kernel_page_tables); // Map 0xb8000 (video) to 0xc0501000 - map_4k_phys_to_virt(0x8000, 0x8000, kernel_page_directory, kernel_page_tables); + map_many_4k_phys_to_virt(0x7000, 0x7000, kernel_page_directory, kernel_page_tables, 2); + map_4k_phys_to_virt(0x8f000, 0x8f000, kernel_page_directory, kernel_page_tables); load_file("KERNEL BIN", kernel_location); diff --git a/src/boot_stage2/paging.c b/src/boot_stage2/paging.c new file mode 100644 index 0000000..63978d3 --- /dev/null +++ b/src/boot_stage2/paging.c @@ -0,0 +1,46 @@ +#include "paging.h" + +typedef struct { + uint32_t page_offset : 12; + uint32_t pt_index : 10; + uint32_t pd_index : 10; +}__attribute__((packed)) split_addr; + +void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables) { + split_addr* split = (split_addr*)&virtual; + + page_directory[split->pd_index] = (PDE){ + .address = (uint32_t)(page_tables[split->pd_index]) >> 12, + .available = 0, + .page_4mb = 0, + .accessed = 0, + .disable_cache = 0, + .write_through_cache = 0, + .privilege = 0, + .present = 1, + .read_write = 1, + + .ignored = 0, + .ignored2 = 0 + }; + + page_tables[split->pd_index][split->pt_index] = (PTE){ + .address = physical >> 12, + .available = 0, + .global = 0, + .accessed = 0, + .disable_cache = 0, + .dirty = 0, + .write_through_cache = 0, + .privilege = 0, + .present = 1, + .read_write = 1, + + .ignored = 0 + }; +} + +void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count) { + for (int i=0; i +#include "types.h" + +typedef struct { + uint32_t present : 1; + uint32_t read_write : 1; + uint32_t privilege : 1; + uint32_t write_through_cache : 1; + uint32_t disable_cache : 1; + uint32_t accessed : 1; + uint32_t ignored2 : 1; + uint32_t page_4mb : 1; + uint32_t ignored : 1; + uint32_t available : 3; + uint32_t address : 20; +}__attribute__((packed)) PDE; + +typedef struct { + uint32_t present : 1; + uint32_t read_write : 1; + uint32_t privilege : 1; + uint32_t write_through_cache : 1; + uint32_t disable_cache : 1; + uint32_t accessed : 1; + uint32_t dirty : 1; + uint32_t ignored : 1; + uint32_t global : 1; + uint32_t available : 3; + uint32_t address : 20; +}__attribute__((packed)) PTE; + +void map_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables); +void map_many_4k_phys_to_virt(uint32_t physical, uint32_t virtual, PDE* page_directory, PTE** page_tables, uint32_t count); +#endif \ No newline at end of file diff --git a/src/boot_stage2/screenstuff.c b/src/boot_stage2/screenstuff.c new file mode 100644 index 0000000..7700d2a --- /dev/null +++ b/src/boot_stage2/screenstuff.c @@ -0,0 +1,161 @@ +#include "screenstuff.h" + +uint16_t* VMEM_ADDR = (uint16_t*)0xb8000; +const int TERM_WIDTH = 80; +const int TERM_HEIGHT = 25; + +int cursor_x = 0; +int cursor_y = 0; + +uint16_t get_curpos() { + uint16_t cursor_position = 0; + uint8_t* cursor_position_split = (uint8_t*)&cursor_position; + outb(0x3D4, 0x0F); + cursor_position_split[0] = inb(0x3D5); + outb(0x3D4, 0x0E); + cursor_position_split[1] = inb(0x3D5); + return cursor_position; +} + +void init_term() { + uint16_t cursor_position = get_curpos(); + + cursor_y = cursor_position / TERM_WIDTH; + cursor_x = cursor_position % TERM_WIDTH; +} + +void clear_screen() { + for (int i=0; i +#include "types.h" +#include "io.h" + +uint16_t get_curpos(); +void init_term(); +void clear_screen(); +void clear_line(int line); +void set_curpos_raw(int curpos); +void set_curpos(int x, int y); +int int_to_decimal(unsigned int number, char* string_buffer); +int int_to_hex(unsigned int number, char* string_buffer); +void printf(const char* string, ...); +void non_moving_put(char chr); + +#endif \ No newline at end of file diff --git a/src/boot_stage2/strings.c b/src/boot_stage2/strings.c new file mode 100644 index 0000000..cc48b9f --- /dev/null +++ b/src/boot_stage2/strings.c @@ -0,0 +1,69 @@ +#include "strings.h" + +bool strcmp(char* a, char* b, int max) { + int index = 0; + while (index < max) { + if (a[index] != b[index]) + return false; + index++; + } + return true; +} + +char* split_on_first(char delimeter, char* string) { + int index = 0; + char current; + + while (current = string[index++]) { + if (current == delimeter) { + string[index-1] = 0; + return string+index; + } + } + + return 0; +} + +int string_split(char delimeter, char* string, char** pointer_array) { + int index = 0; + int last_split_index = 0; + int split_count = 0; + + char current; + + while (current = string[index]) { + if (current == delimeter) { + string[index] = 0; + pointer_array[split_count++] = (string+last_split_index); + last_split_index = (index+1); + } + index++; + } + + // Add remaining part of the string to the pointer_array + pointer_array[split_count] = (string+last_split_index); + + return split_count; +} + +void decode_filename(char* nice_name, char* filenamebuffer) { + // Clear filenamebuffer + for (int i=0; i<11; i++) + filenamebuffer[i] = ' '; + filenamebuffer[11] = 0; + + int fbIndex = 0; + for (int i=0; i<12; i++) { + if (nice_name[i] == 0) + return; + if (nice_name[i] == '.') { + fbIndex = 8; + continue; + } + + if (nice_name[i] >= 0x61 && nice_name[i] <= 0x7f) + filenamebuffer[fbIndex++] = nice_name[i] - 32; + else + filenamebuffer[fbIndex++] = nice_name[i]; + } +} \ No newline at end of file diff --git a/src/boot_stage2/strings.h b/src/boot_stage2/strings.h new file mode 100644 index 0000000..baf7c5c --- /dev/null +++ b/src/boot_stage2/strings.h @@ -0,0 +1,11 @@ +#ifndef STRINGS_H +#define STRINGS_H + +#include + +bool strcmp(char* a, char* b, int max); +char* split_on_first(char delimeter, char* string); +int string_split(char delimeter, char* string, char** pointer_array); +void decode_filename(char* nice_name, char* filenamebuffer); + +#endif \ No newline at end of file diff --git a/src/boot_stage2/types.h b/src/boot_stage2/types.h new file mode 100644 index 0000000..1bae039 --- /dev/null +++ b/src/boot_stage2/types.h @@ -0,0 +1,11 @@ +#ifndef TYPES_H +#define TYPES_H + +typedef char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef long int int32_t; +typedef unsigned long int uint32_t; + +#endif \ No newline at end of file diff --git a/src/kernel/kernel.ld b/src/kernel/kernel.ld new file mode 100644 index 0000000..e1ee885 --- /dev/null +++ b/src/kernel/kernel.ld @@ -0,0 +1,15 @@ +OUTPUT_FORMAT(binary) +OUTPUT_ARCH(i386:i386) + +OUTPUT(build/kernel/kernel.bin) + +SECTIONS { + . = 0xc0000000; + + .text : { + build/c_code_entry.o(.text) + build/kernel/kernel.o(.text) + build/kernel/*(.text) + heap_section = .; + } +} \ No newline at end of file