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