]> git.dujemihanovic.xyz Git - nameless-os.git/commitdiff
Merge branch 'ps2-driver' into mm origin/mm
authorDuje Mihanović <duje.mihanovic@skole.hr>
Mon, 22 Aug 2022 20:11:21 +0000 (22:11 +0200)
committerDuje Mihanović <duje.mihanovic@skole.hr>
Mon, 22 Aug 2022 20:11:21 +0000 (22:11 +0200)
46 files changed:
.gitignore
Makefile
boot/x86/Makefile
boot/x86/stage3/Makefile [new file with mode: 0644]
boot/x86/stage3/a20.s
boot/x86/stage3/e820.s [new file with mode: 0644]
boot/x86/stage3/elf.c [new file with mode: 0644]
boot/x86/stage3/elf.h [new file with mode: 0644]
boot/x86/stage3/gdt.s
boot/x86/stage3/loader.s
boot/x86/stage3/paging.c [new file with mode: 0644]
boot/x86/stage3/paging.h [new file with mode: 0644]
boot/x86/stage3/prekernel.c [new file with mode: 0644]
boot/x86/stage3/print.s
boot/x86/stage3/stage3.ld [new file with mode: 0644]
boot/x86/stage3/unreal.s
boot/x86/vbr-fat32.s
include/arch/x86/tty.h [deleted file]
kernel/Makefile [new file with mode: 0644]
kernel/arch/x86/Makefile [new file with mode: 0644]
kernel/arch/x86/entry.s [new file with mode: 0644]
kernel/arch/x86/halt.s [new file with mode: 0644]
kernel/arch/x86/irq/Makefile [new file with mode: 0644]
kernel/arch/x86/irq/interrupt.c
kernel/arch/x86/linker.ld [moved from kernel/linker.ld with 68% similarity]
kernel/arch/x86/tty.c [new file with mode: 0644]
kernel/arch/x86/tty/tty.c [deleted file]
kernel/drivers/Makefile [new file with mode: 0644]
kernel/drivers/input/Makefile [new file with mode: 0644]
kernel/drivers/irq/Makefile [new file with mode: 0644]
kernel/entry.s [deleted file]
kernel/include/arch/x86/bitflags.h [moved from include/arch/x86/bitflags.h with 100% similarity]
kernel/include/arch/x86/input/ps2.h [moved from include/arch/x86/input/ps2.h with 100% similarity]
kernel/include/arch/x86/io.h [moved from include/arch/x86/io.h with 100% similarity]
kernel/include/arch/x86/irq/i8259a.h [moved from include/arch/x86/irq/i8259a.h with 100% similarity]
kernel/include/arch/x86/irq/idt.h [moved from include/arch/x86/irq/idt.h with 100% similarity]
kernel/include/arch/x86/irq/interrupt.h [moved from include/arch/x86/irq/interrupt.h with 100% similarity]
kernel/include/arch/x86/mm/paging.h [new file with mode: 0644]
kernel/include/arch/x86/tty.h [new file with mode: 0644]
kernel/include/kprint.h [new file with mode: 0644]
kernel/include/panic.h [new file with mode: 0644]
kernel/kernel.c [deleted file]
kernel/kernel/Makefile [new file with mode: 0644]
kernel/kernel/kernel.c [new file with mode: 0644]
kernel/kernel/kprint.c [new file with mode: 0644]
nameless2disk

index 9fc5bb791de04c0037818d3ffd4aa4f55db8b732..505290e343ff63ed7a90f33cc3aed7a0d612bd91 100644 (file)
@@ -1,6 +1,3 @@
-toolchain/
-boot.img
-boot/x86/boot
 **/*.o
 **/*.bin
 **/*.elf
index ae1a7160e9e89533eb315f05771600de91f65ab3..cc923070db4ab2271cf64205407ea297284157b1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,54 +1,40 @@
+export CROSS_COMPILE = i686-elf-
 export AS = yasm
-ASFLAGS = -f elf -g dwarf2
-export CC = i686-elf-gcc
-QEMU = qemu-system-i386 -monitor stdio
-
+export CC = gcc
+export QEMU = qemu-system-i386 -monitor stdio
 export GIT_REV = $(shell git describe --long HEAD)
-
-CFLAGS = -std=gnu11 -g -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\"
-
-KERNEL_OBJ = kernel/entry.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/interrupt.o kernel/arch/x86/irq/stub.o kernel/drivers/input/ps2.o kernel/kernel.o
-BOOTLOADER_OBJ = boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN
+export REAL_CC = $(CROSS_COMPILE)$(CC)
+export CFLAGS
+export LDFLAGS
+export ASFLAGS
+MAKEFLAGS += -rR
 
 default: kernel/kernel.elf bootloader
-
 all: default boot/x86/disk.img
-
-bootloader: $(BOOTLOADER_OBJ)
-
 run: all
        $(QEMU) boot/x86/disk.img
+debug: all
+       $(QEMU) -s -S boot/x86/disk.img
 
-boot/x86/mbr: boot/x86/mbr.s
-boot/x86/vbr-fat32: boot/x86/vbr-fat32.s boot/x86/fat32/*.s 
-boot/x86/stage3/LOADER.BIN: boot/x86/stage3/*.s boot/x86/fat32/*.s
-$(BOOTLOADER_OBJ):
+kernel/kernel.elf:
+       $(MAKE) -C kernel
+bootloader:
        $(MAKE) -C boot/x86
 
-boot/x86/disk.img: boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN boot/x86/disk.dump kernel/kernel.bin
+boot/x86/disk.img: bootloader boot/x86/disk.dump kernel/kernel.elf
        truncate -s1G boot/x86/disk.img
        sfdisk boot/x86/disk.img < boot/x86/disk.dump
        mkfs.fat -F 32 --offset 2048 boot/x86/disk.img
        dd if=boot/x86/mbr of=boot/x86/disk.img bs=440 count=1 conv=notrunc
        dd if=boot/x86/vbr-fat32 of=boot/x86/disk.img bs=1 skip=90 seek=1048666 conv=notrunc
        mcopy -i boot/x86/disk.img@@1M boot/x86/stage3/LOADER.BIN ::.
-       mcopy -i boot/x86/disk.img@@1M kernel/kernel.bin ::./KERNEL.BIN
-
-kernel/kernel.bin: ${KERNEL_OBJ} kernel/linker.ld
-       $(CC) -ffreestanding -nostdlib -o $@ -T kernel/linker.ld ${KERNEL_OBJ}
-
-kernel/drivers/input/ps2.o: kernel/drivers/input/ps2.c
-
-kernel/kernel.o: kernel/kernel.c
-
-kernel/kernel.elf: kernel/kernel.bin
-       $(CC) -ffreestanding -nostdlib -o $@ -T kernel/linker.ld ${KERNEL_OBJ} -Wl,--oformat=elf32-i386
-       i686-elf-objcopy --only-keep-debug kernel/kernel.elf kernel/kernel.dbg
-       i686-elf-objcopy --add-gnu-debuglink=kernel/kernel.dbg kernel/kernel.elf
-       i686-elf-strip --strip-unneeded kernel/kernel.elf
+       mcopy -i boot/x86/disk.img@@1M kernel/kernel.elf ::./KERNEL.ELF
 
 clean:
-       -rm kernel/kernel.{bin,dbg,elf} ${KERNEL_OBJ}
-       cd boot/x86 && $(MAKE) clean
+       $(MAKE) -C boot/x86 clean
+       $(MAKE) -C kernel clean
 
-.PHONY: default all clean run bootloader
+# Even though kernel.elf is a real target, it's considered phony so that the
+# kernel Makefile is always run. We don't check is the kernel binary up-to-date
+# here because we want to be more recursive.
+.PHONY: default all clean run debug bootloader kernel/kernel.elf
index 877930a2dba1bebbef0df31bfe0e7557711dfb39..89891a8a8f4b2ef4e55c750a68111cd66a8c73af 100644 (file)
@@ -1,17 +1,19 @@
-AS = yasm
-ASFLAGS = -f bin
-default: mbr vbr-fat32 stage3/LOADER.BIN
+BOOTLOADER_OBJ = mbr vbr-fat32
+ASFLAGS_BASE = -w-zeroing
 
-mbr: mbr.s
-       $(AS) $(ASFLAGS) -w-zeroing -o $@ $<
+default: $(BOOTLOADER_OBJ) stage3
 
-vbr-fat32: vbr-fat32.s fat32/*.s
-       $(AS) $(ASFLAGS) -o $@ $<
+stage3:
+       $(MAKE) -C stage3
 
-stage3/LOADER.BIN: stage3/loader.s stage3/*.s
-       $(AS) $(ASFLAGS) -DGIT_REVISION=\"$(GIT_REV)\" -o $@ $<
+vbr-fat32: vbr-fat32.s fat32/*.s
 
 clean:
-       -rm mbr vbr-fat32 stage3/LOADER.BIN disk.img
+       -rm mbr vbr-fat32 disk.img
+       $(MAKE) -C stage3 clean
+
+# Implicit rules
+%: %.s
+       $(AS) $(ASFLAGS_BASE) $(ASFLAGS) -f bin $< -o $@
 
-.PHONY : default clean
+.PHONY : default clean stage3
diff --git a/boot/x86/stage3/Makefile b/boot/x86/stage3/Makefile
new file mode 100644 (file)
index 0000000..25b0265
--- /dev/null
@@ -0,0 +1,26 @@
+STAGE3_OBJ = loader.o elf.o paging.o prekernel.o
+
+ASFLAGS_BASE = -f elf -g dwarf2 -DGIT_REVISION=\"$(GIT_REV)\"
+CFLAGS_BASE = -ffreestanding -nostdlib -DGIT_REVISION=\"$(GIT_REV)\" -g \
+             -Og
+LDFLAGS_BASE = -ffreestanding -nostdlib -g -lgcc -T stage3.ld
+
+default: LOADER.BIN loader.elf
+
+loader.elf: $(STAGE3_OBJ)
+       $(REAL_CC) $(LDFLAGS_BASE) $(LDFLAGS) -Wl,--oformat=elf32-i386 $^ -o $@
+
+LOADER.BIN: $(STAGE3_OBJ)
+       $(REAL_CC) $(LDFLAGS_BASE) $(LDFLAGS) $^ -o $@
+
+# Implicit rules
+%.o: %.c
+       $(REAL_CC) $(CFLAGS_BASE) $(CFLAGS) -c $< -o $@
+
+%.o: %.s
+       $(AS) $(ASFLAGS_BASE) $(ASFLAGS) $< -o $@
+
+clean:
+       -rm -f $(STAGE3_OBJ) LOADER.BIN loader.elf
+
+.PHONY: default clean
index 8748dde580673653b15db546ade7739a1db13ac3..392e83de920c1fac19e06c301979ceb618348824 100644 (file)
@@ -1,3 +1,6 @@
+bits 16
+section .text
+
 %macro in_wait 0
        push ax
 %%loop:
diff --git a/boot/x86/stage3/e820.s b/boot/x86/stage3/e820.s
new file mode 100644 (file)
index 0000000..2d1780b
--- /dev/null
@@ -0,0 +1,67 @@
+; Code for getting the BIOS E820 memory map
+
+bits 16
+section .text
+
+; Return: ECX - number of entries, DI - pointer to map
+get_e820_map:
+       push eax
+       push ebx
+       push edx
+       push esi
+       push es
+
+       xor ax, ax
+       mov es, ax
+       push dword 1
+       sub sp, 20
+       xor si, si
+       xor ebx, ebx
+       mov edx, 0x534d4150
+       mov eax, 0xe820
+       mov ecx, 24
+       mov di, sp
+       int 0x15
+       jc .no_e820
+       cmp eax, 0x534d4150
+       jne .unexpected
+       inc si
+       .loop:
+               push dword 1
+               sub sp, 20
+               mov di, sp
+               mov eax, 0xe820
+               mov ecx, 24
+               int 0x15
+               jc .carry_done
+               inc si
+               cmp ebx, 0
+               je .done
+               jmp .loop
+       .carry_done:
+               add sp, 24
+       .done:
+               movzx ecx, si
+               movzx edi, sp
+               mov ax, 24
+               mul si
+               add sp, ax
+               pop es
+               pop esi
+               pop edx
+               pop ebx
+               pop eax
+               ret
+       .no_e820:
+               print no_e820
+               hlt
+               jmp $-1
+       .unexpected
+               print e820_unexpected
+               call print_dword
+               hlt
+               jmp $-1
+
+section .rodata
+no_e820: db "BIOS does not support E820, cannot proceed!", 0xd, 0xa, 0
+e820_unexpected: db "Unexpected value in EAX after getting map entry: expected SMAP, got ", 0
diff --git a/boot/x86/stage3/elf.c b/boot/x86/stage3/elf.c
new file mode 100644 (file)
index 0000000..8621c39
--- /dev/null
@@ -0,0 +1,78 @@
+/* Code for parsing ELF binaries (the kernel) */
+
+#include "elf.h"
+#include "paging.h"
+#include <stdint.h>
+
+int check_elf_header(struct elf_header *header)
+{
+       if (header->magic != ELF_MAGIC)
+               return ELF_HEADER_INVALID;
+       if (header->bits != ELF_32BIT)
+               return MISMATCHED_SYSTEM;
+       if (header->endianness != ELF_LITTLE_ENDIAN)
+               return MISMATCHED_SYSTEM;
+       if (header->header_ver != 1)
+               return ELF_HEADER_INVALID;
+       if (header->os_abi != ELF_SYSV_ABI)
+               return MISMATCHED_SYSTEM;
+       if (header->type != ELF_TYPE_EXECUTABLE)
+               return NOT_EXECUTABLE;
+       if (header->machine != ELF_X86_ISA)
+               return MISMATCHED_SYSTEM;
+       if (header->elf_ver != 1)
+               return ELF_HEADER_INVALID;
+
+       return 0;
+}
+
+int setup_elf_executable(struct elf_header *header)
+{
+       /* Check the header. */
+       int header_valid = check_elf_header(header);
+       if (header_valid)
+               return header_valid;
+
+       /* Get the program header. The casting is necessary because without it
+        * the code will add some multiple of the program header offset rather
+        * than the actual offset. */
+       struct program_header *prog_hdr = (struct program_header *) ((uint32_t) header+header->program_hdr);
+       for (int i=0; i<header->ph_entry_count; i++) {
+               /* We're only interested in loadable segments. */
+               if (prog_hdr[i].seg_type != ELF_PT_LOAD)
+                       continue;
+
+               /* Calculate the memory range. */
+               void *phys_start, *phys_end, *virt_end;
+               int flags;
+               phys_start = (void *) header + prog_hdr[i].file_offset;
+               if (prog_hdr[i].memsz & 0xfff) { /* Align if needed. */
+                       phys_end = phys_start+((prog_hdr[i].memsz+0x1000) & ~0xfff);
+                       virt_end = prog_hdr[i].vaddr+((prog_hdr[i].memsz+0x1000) & ~0xfff);
+               }
+               else {
+                       phys_end = phys_start+prog_hdr[i].memsz;
+                       virt_end = prog_hdr[i].vaddr+prog_hdr[i].memsz;
+               }
+
+               flags = prog_hdr[i].flags & ELF_FLAG_WRITABLE;
+
+               /* Map the range. */
+               int ret = map_range(phys_start, phys_end, prog_hdr[i].vaddr, virt_end, flags);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int execute_elf(struct elf_header *header, void *arg1, int arg2)
+{
+       /* Check the header and map all needed memory ranges. */
+       int ret = setup_elf_executable(header);
+       if (ret)
+               return ret;
+
+       /* Execute the kernel. */
+       header->entry(arg1, arg2);
+}
diff --git a/boot/x86/stage3/elf.h b/boot/x86/stage3/elf.h
new file mode 100644 (file)
index 0000000..9692633
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef BOOT_X86_ELF_H
+#define BOOT_X86_ELF_H
+
+#include <stdint.h>
+
+/* Some constants we will test against. */
+#define ELF_MAGIC 0x464c457f
+#define ELF_32BIT 0x1
+#define ELF_LITTLE_ENDIAN 0x1
+#define ELF_SYSV_ABI 0x0
+#define ELF_TYPE_EXECUTABLE 0x2
+#define ELF_X86_ISA 0x3
+
+#define ELF_PT_LOAD 0x1
+
+#define ELF_FLAG_EXECUTABLE 0x1
+#define ELF_FLAG_WRITABLE 0x2
+#define ELF_FLAG_READABLE 0x4
+
+/* Return error codes for the functions. */
+#define ELF_HEADER_INVALID 5
+#define MISMATCHED_SYSTEM 6
+#define NOT_EXECUTABLE 7
+
+struct elf_header {
+       uint32_t magic;
+       uint8_t bits;
+       uint8_t endianness;
+       uint8_t header_ver; /* always 1 */
+       uint8_t os_abi;
+       uint8_t padding[8];
+       uint16_t type;
+       uint16_t machine;
+       uint32_t elf_ver; /* always 1 */
+       void (*entry)(void *, int);
+       uint32_t program_hdr; /* offset into file */
+       uint32_t section_hdr;
+       uint32_t flags;
+       uint16_t hdr_size;
+       uint16_t ph_entry_size;
+       uint16_t ph_entry_count;
+       uint16_t sh_entry_size;
+       uint16_t sh_entry_count;
+       uint16_t sh_name_index;
+};
+
+struct program_header {
+       uint32_t seg_type;
+       uint32_t file_offset;
+       void *vaddr;
+       uint32_t undefined;
+       uint32_t filesz;
+       uint32_t memsz;
+       uint32_t flags;
+       uint32_t align;
+};
+
+extern int execute_elf(struct elf_header *header, void *arg1, int arg2);
+
+#endif
index d81bb64ecd34e90a144bab77c73f8afa7dba3f84..843df7bbdd259d040d8e8b442433b77e9090f758 100644 (file)
@@ -1,4 +1,7 @@
 ; Initial GDT for kernel, which wants a flat code and data descriptor
+
+section .rodata
+
 gdt:
        dw .end-.start-1
        dd .start
index ec08c61bd0f5d00644cf471ebe26274f93153c9e..87598f4b0c93a6d95cbb1aa21dcf6a87723ff1da 100644 (file)
@@ -1,7 +1,9 @@
 bits 16
 cpu 686
-org 0x1800
 
+extern run_kernel
+
+section .text
 %include "../fat32/fat32-structs.s"
 
 %macro print 1
@@ -11,7 +13,11 @@ org 0x1800
        pop si
 %endmacro
 
+extern __STACK_BOTTOM__
+
+global _start
 _start:
+       mov sp, __STACK_BOTTOM__
        mov [BOOT_DRIVE], dl
        call enable_unreal
        print begin
@@ -55,15 +61,24 @@ _start:
        pop si
        pop cx
        print kernel_found
+       mov eax, [es:di+dir_entry.filesize]
+       mov [KERNEL_SIZE], eax
        mov ax, [es:di+dir_entry.firstclushi]
        shl eax, 16
-       mov ax, [es:di+(dir_entry.firstcluslo)]
+       mov ax, [es:di+dir_entry.firstcluslo]
        call print_dword
        mov edi, 0x100000
        print kernel_loading
        call read_clus_chain_unreal ; load kernel
        print kernel_loaded
        
+       call get_e820_map
+       mov ebx, ecx
+       mov eax, 24
+       mul ecx
+       add eax, 20
+       sub sp, ax
+
        cli
        lgdt [gdt]
        mov eax, cr0
@@ -145,26 +160,35 @@ memcpy:
        pop esi
        ret
 
-
 %include "unreal.s"
 %include "a20.s"
 %include "../fat32/fat32.s"
 %include "gdt.s"
 %include "print.s"
+%include "e820.s"
 
-in_protected:
 bits 32
+section .text
+in_protected:
        mov ax, 0x10
        mov ds, ax
        mov es, ax
        mov ss, ax
        mov fs, ax
        mov gs, ax
-       call 0x100000
-       hlt
-       jmp $-1
 
-kernel_name: db "KERNEL  BIN"
+       push dword [KERNEL_SIZE]
+       push 0x100000
+       push ebx
+       push edi
+       call run_kernel
+
+section .bss
+KERNEL_SIZE: resd 1
+
+section .rodata
+
+kernel_name: db "KERNEL  ELF"
 begin: db "Nameless Bootloader revision ", GIT_REVISION, 0xd, 0xa, 0
 a20_enabled: db "A20 has been enabled", 0xd, 0xa, "Searching for kernel...", 0xd, 0xa, 0
 a20_fail: db "Failed to enable A20, giving up!", 0xd, 0xa, 0
@@ -172,7 +196,7 @@ crit_err: db "A critical error occurred, dumping registers now: ", 0xd, 0xa, 0
 kernel_found: db "Found kernel at cluster ", 0
 kernel_loading: db 0xd, 0xa, "Loading kernel...", 0xd, 0xa, 0
 kernel_loaded: db "Kernel successfully loaded.", 0xd, 0xa, "Setting up kernel environment and running kernel...", 0xd, 0xa, 0
-missing_kernel: db "Could not find KERNEL.BIN", 0xd, 0xa, 0
+missing_kernel: db "Could not find KERNEL.ELF", 0xd, 0xa, 0
 eax_s: db "EAX: ", 0
 ebx_s: db "EBX: ", 0
 ecx_s: db "ECX: ", 0
diff --git a/boot/x86/stage3/paging.c b/boot/x86/stage3/paging.c
new file mode 100644 (file)
index 0000000..14afe85
--- /dev/null
@@ -0,0 +1,67 @@
+/* Code for enabling paging */
+
+#include <stdint.h>
+#include "paging.h"
+
+/* Preallocated page tables. */
+static uint32_t page_directory[1024] __attribute__((aligned(4096))) __attribute__((section(".data")));
+static uint32_t page_table_firstmb[1024] __attribute__((aligned(4096))) __attribute__((section(".data")));
+static uint32_t page_table_kernel[1024] __attribute__((aligned(4096))) __attribute__((section(".data")));
+
+void enable_paging()
+{
+       int cr3;
+       asm ("mov %0, %%cr3": : "a" (page_directory));
+       asm ("mov %%cr0, %0": "=a" (cr3));
+       cr3 |= 0x80000000;
+       asm ("mov %0, %%cr0": : "a" (cr3));
+}
+
+int map_address(void *physical, void *virtual, int flags)
+{
+       if ((uint32_t) physical & 0xfff || (uint32_t) virtual & 0xfff)
+               return ADDRESS_NOT_ALIGNED;
+
+       uint32_t pdir_index = (uint32_t) virtual >> 22;
+       if (pdir_index != 0 && pdir_index != 0x300)
+               return INVL_ADDRESS;
+
+       uint32_t ptbl_index = ((uint32_t) virtual >> 12) & 0x3ff;
+       switch (pdir_index) {
+       case 0:
+               if (page_table_firstmb[ptbl_index] & 1 == 1)
+                       return ADDRESS_ALREADY_MAPPED;
+               page_table_firstmb[ptbl_index] = ((uint32_t) physical & ~0xfff) | (flags & 0xfff) | 1;
+               break;
+       case 0x300:
+               if (page_table_kernel[ptbl_index] & 1 == 1)
+                       return ADDRESS_ALREADY_MAPPED;
+               page_table_kernel[ptbl_index] = ((uint32_t) physical & ~0xfff) | (flags & 0xfff) | 1;
+       }
+
+       return 0;
+}
+
+int map_range(void *phys_start, void *phys_end, void *virt_start, void *virt_end, int flags)
+{
+       if ((uint32_t) phys_start & 0xfff || (uint32_t) phys_end & 0xfff ||
+                       (uint32_t) virt_start & 0xfff || (uint32_t) virt_end & 0xfff)
+               return ADDRESS_NOT_ALIGNED;
+
+       if ((uint32_t) phys_end - (uint32_t) phys_start != (uint32_t) virt_end - (uint32_t) virt_start)
+               return ADDRESS_RANGE_MISMATCHED;
+
+       int loops = ((uint32_t) phys_end - (uint32_t) phys_start) / 4096;
+       for (int i=0; i<loops; i++) {
+               int ret = map_address(phys_start + i*4096, virt_start + i*4096, flags);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+void set_up_page_directory()
+{
+       page_directory[0] = (uint32_t) page_table_firstmb | 3;
+       page_directory[0x300] = (uint32_t) page_table_kernel | 3;
+}
diff --git a/boot/x86/stage3/paging.h b/boot/x86/stage3/paging.h
new file mode 100644 (file)
index 0000000..487943e
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef BOOT_X86_PAGING_H
+#define BOOT_X86_PAGING_H
+
+#define ADDRESS_NOT_ALIGNED 1
+#define INVL_ADDRESS 2
+#define ADDRESS_ALREADY_MAPPED 3
+#define ADDRESS_RANGE_MISMATCHED 4
+
+extern int map_range(void *phys_start, void *phys_end, void *virt_start, void *virt_end, int flags);
+extern void set_up_page_directory();
+extern void enable_paging();
+
+#endif
diff --git a/boot/x86/stage3/prekernel.c b/boot/x86/stage3/prekernel.c
new file mode 100644 (file)
index 0000000..07bd721
--- /dev/null
@@ -0,0 +1,62 @@
+#include "elf.h"
+#include "paging.h"
+
+/* This bit of code will be run right after the segment registers have been set
+ * up for protected mode. */
+
+const char *error_messages[] = {
+       "Tried to page an invalid address, the bootloader is buggy!",
+       "Tried to page an invalid address, the bootloader is buggy!",
+       "Tried to page an invalid address, the bootloader is buggy!",
+       "Tried to page an invalid address, the bootloader is buggy!",
+       "KERNEL.ELF is not a valid ELF file!",
+       "KERNEL.ELF is a non-x86 or userspace executable!",
+       "KERNEL.ELF is not an executable ELF file!"
+};
+
+void printerr(const char *error)
+{
+       char *message = (char *) error;
+       for (int i=0;;i++) {
+               char temp = *message;
+               if (!temp) return;
+               *(char *) (0xb8000+i*2) = temp;
+               *(char *) (0xb8000+1+i*2) = 0xcf;
+               message++;
+       }
+}
+
+void halt()
+{
+loop:
+       asm("hlt":);
+       goto loop;
+}
+
+void run_kernel(void *e820_map, unsigned int e820_map_size, struct elf_header *kernel, unsigned int kernel_size)
+{
+       /* Before trying to parse our kernel ELF, let's set up paging. */
+       unsigned int bootloader_mem_size = 0x100000 + kernel_size;
+
+       /* Align the size to a 4K boundary. */
+       if (bootloader_mem_size & 0xfff) {
+               bootloader_mem_size += 0x1000;
+               bootloader_mem_size &= ~0xfff;
+       }
+
+       /* Map the bootloader memory. */
+       int ret = map_range(0, (void *) bootloader_mem_size, 0, (void *) bootloader_mem_size, 2);
+       if (ret) {
+               printerr(error_messages[ret-1]);
+               halt();
+       }
+       set_up_page_directory();
+       enable_paging();
+
+       /* Parse and run the kernel ELF. */
+       ret = execute_elf(kernel, e820_map, e820_map_size);
+       if (ret) {
+               printerr(error_messages[ret-1]);
+               halt();
+       }
+}
index 73b34d5adb8f5cf4fb5215e051202a40278b296d..edc71077c3a2312ab1b7284cb3e4353349e36f31 100644 (file)
@@ -1,5 +1,8 @@
 ; Routines for printing
 
+bits 16
+section .text
+
 print_str:
        push ax
        push bx
diff --git a/boot/x86/stage3/stage3.ld b/boot/x86/stage3/stage3.ld
new file mode 100644 (file)
index 0000000..e8bb5e7
--- /dev/null
@@ -0,0 +1,17 @@
+ENTRY(_start)
+OUTPUT_FORMAT(binary)
+
+SECTIONS {
+       . = 0x1800;
+       .text : {
+               loader.o(.text)
+               *(.text)
+       }
+       .rodata : { *(.rodata) }
+       .data : { *(.data) }
+       .bss : {
+               *(.bss)
+               . += 1K;
+               PROVIDE(__STACK_BOTTOM__ = .);
+       }
+}
index cdd361bbdd85ccf6ca83f2039d52494fc9362cda..1fbe1f909cf0953f26037dcb57df79362d7ad31a 100644 (file)
@@ -1,5 +1,8 @@
 ; Routine for enabling unreal mode, which allows using 32-bit offsets in real mode
 
+bits 16
+section .text
+
 enable_unreal:
        cli
        push eax
@@ -25,6 +28,8 @@ enable_unreal:
        sti
        ret
 
+section .rodata
+
 ; GDT with 1 flat data segment descriptor
 gdt_info:
        dw gdt_end-gdt_start-1
index 439157f3c4299b6f7bf116f3f519fcbb0d860deb..7af11562331bec8bd2727fd14418addd251f8da2 100644 (file)
@@ -72,8 +72,8 @@ real_start:
        mov di, STAGE3_OFFSET
        call read_cluster_chain ; read stage 3
        mov dl, [BOOT_DRIVE]
-       call STAGE3_ADDRESS ; call stage 3
-       jmp .halt ; halt in case we return, which should never happen
+       jmp 0:STAGE3_ADDRESS ; call stage 3
+       nop
 
 .stage3_missing:
        print stage3_missing
diff --git a/include/arch/x86/tty.h b/include/arch/x86/tty.h
deleted file mode 100644 (file)
index 2224737..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef X86_TTY_H
-#define X86_TTY_H
-
-#include <stdint.h>
-
-#define VGA_COLOR_BLACK 0x0
-#define VGA_COLOR_BLUE 0x1
-#define VGA_COLOR_GREEN 0x2
-#define VGA_COLOR_TEAL 0x3
-#define VGA_COLOR_DARK_RED 0x4
-#define VGA_COLOR_MAGENTA 0x5
-#define VGA_COLOR_BROWN 0x6
-#define VGA_COLOR_LIGHT_GRAY 0x7
-#define VGA_COLOR_DARK_GRAY 0x8
-#define VGA_COLOR_PURPLE 0x9
-#define VGA_COLOR_LIME 0xA
-#define VGA_COLOR_CYAN 0xB
-#define VGA_COLOR_BRIGHT_RED 0xC
-#define VGA_COLOR_PINK 0xD
-#define VGA_COLOR_YELLOW 0xE
-#define VGA_COLOR_WHITE 0xF
-
-extern void screen_clear(void);
-extern void kprint(const char *string, uint8_t color);
-extern void kprintb(const uint8_t byte);
-extern void kprintw(const uint16_t word);
-extern void kprintd(const uint32_t dword);
-#endif
diff --git a/kernel/Makefile b/kernel/Makefile
new file mode 100644 (file)
index 0000000..8bb12d8
--- /dev/null
@@ -0,0 +1,27 @@
+include arch/x86/Makefile
+include drivers/Makefile
+include kernel/Makefile
+
+ASFLAGS_BASE = -f elf -g dwarf2
+CFLAGS_BASE = -fgnu89-inline -ffreestanding -nostdlib -Iinclude \
+             -Iinclude/arch/x86 -g -DGIT_COMMIT=\"$(GIT_REV)\" \
+             -Og
+LDFLAGS_BASE = -ffreestanding -nostdlib -lgcc -g -T arch/x86/linker.ld
+
+kernel.elf kernel.dbg: $(KERNEL_OBJ)
+       $(REAL_CC) $(LDFLAGS_BASE) $(LDFLAGS) $^ -o $@
+       $(CROSS_COMPILE)objcopy --only-keep-debug kernel.elf kernel.dbg
+       $(CROSS_COMPILE)objcopy --add-gnu-debuglink=kernel.dbg kernel.elf
+       $(CROSS_COMPILE)strip --strip-unneeded kernel.elf
+
+clean:
+       -rm $(KERNEL_OBJ) kernel.elf kernel.dbg
+
+# Implicit rules
+%.o: %.c
+       $(REAL_CC) $(CFLAGS_BASE) $(CFLAGS) -c $< -o $@
+
+%.o: %.s
+       $(AS) $(ASFLAGS_BASE) $(ASFLAGS) $< -o $@
+
+.PHONY: clean
diff --git a/kernel/arch/x86/Makefile b/kernel/arch/x86/Makefile
new file mode 100644 (file)
index 0000000..c15bef9
--- /dev/null
@@ -0,0 +1,3 @@
+include arch/x86/irq/Makefile
+
+KERNEL_OBJ += $(addprefix arch/x86/, entry.o halt.o tty.o)
diff --git a/kernel/arch/x86/entry.s b/kernel/arch/x86/entry.s
new file mode 100644 (file)
index 0000000..d6490a1
--- /dev/null
@@ -0,0 +1,32 @@
+bits 32
+extern kmain
+extern __STACK_BOTTOM__
+
+section .text
+global _start
+_start:
+       ; Here, the stack will look like:
+       ; return address, map pointer, map size.
+
+       ; Skip the return address.
+       add esp, 4
+       ; Save the kernel arguments.
+       ; Can this be done without the global variables?
+       pop dword [e820_map]
+       pop dword [e820_map_size]
+       sub esp, 12
+       ; Do the stack switch.
+       mov ebp, __STACK_BOTTOM__
+       mov esp, ebp
+       ; Restore the kernel arguments.
+       push dword [e820_map_size]
+       push dword [e820_map]
+       ; Call the actual kernel.
+       call kmain
+       hlt
+       jmp $-1
+
+; Temporarily save arguments here to survive the upcoming stack switch.
+section .bss
+e820_map: resd 1
+e820_map_size: resd 1
diff --git a/kernel/arch/x86/halt.s b/kernel/arch/x86/halt.s
new file mode 100644 (file)
index 0000000..aded520
--- /dev/null
@@ -0,0 +1,9 @@
+; x86-specific routine for halting
+
+bits 32
+global halt
+
+halt:
+       cli
+       hlt
+       jmp $-1
diff --git a/kernel/arch/x86/irq/Makefile b/kernel/arch/x86/irq/Makefile
new file mode 100644 (file)
index 0000000..3dc6f82
--- /dev/null
@@ -0,0 +1 @@
+KERNEL_OBJ += $(addprefix arch/x86/irq/, idt.o interrupt.o stub.o)
index f7cbcdcce60622ddf2ac2b85283b59a6bdc84e7d..b3c31735af156cba8e01422cb03969f933bea41e 100644 (file)
@@ -1,6 +1,6 @@
 #include <irq/idt.h>
 #include <irq/interrupt.h>
-#include <tty.h>
+#include <kprint.h>
 #include <stddef.h>
 #include <irq/i8259a.h>
 
@@ -11,15 +11,15 @@ void int_handler(struct interrupt_frame *frame)
 {
        int interrupt = frame->interrupt;
        if (int_handler_table[interrupt] == NULL) {
-               kprint("WARNING: Unhandled interrupt ", 0);
-               kprintb(interrupt);
-               kprint(" occurred!\n", 0);
+               kprint("WARNING: Unhandled interrupt ", VGA_YELLOW, VGA_BLACK);
+               kprintb(interrupt, 1);
+               kprint(" occurred!\n", VGA_YELLOW, VGA_BLACK);
        } else {
                int ret = (*int_handler_table[interrupt])(frame);
                if (ret) {
-                       kprint("WARNING: Error while handling interrupt ", 0);
-                       kprintb(interrupt);
-                       kprint("!\n", 0);
+                       kprint("WARNING: Error while handling interrupt ", VGA_YELLOW, VGA_BLACK);
+                       kprintb(interrupt, 1);
+                       kprint("!\n", VGA_YELLOW, VGA_BLACK);
                }
        }
        if (interrupt >= 0x20) {
similarity index 68%
rename from kernel/linker.ld
rename to kernel/arch/x86/linker.ld
index 645a82421029a638d8ea58a86e8282852af09936..98ee468fac7eb46536fb0fe07e18480995a8c435 100644 (file)
@@ -1,16 +1,20 @@
 ENTRY(_start)
-OUTPUT_FORMAT(binary)
 
 SECTIONS
 {
-       . = 0x100000;
+       . = 0xc0000000;
        __KERNEL_BASE__ = .;
 
-       .text : ALIGN(4K) { 
-               kernel/entry.o (.text)
-               *(.text) 
+       .text : ALIGN(4K) {
+               __TEXT_BASE__ = .;
+               *(.text)
+               __TEXT_END__ = .;
+       }
+       .rodata : ALIGN(4K) {
+               __RODATA_BASE__ = .;
+               *(.rodata)
+               __RODATA_END__ = .;
        }
-       .rodata : ALIGN(4K) { *(.rodata) }
 
        /* .rodata is put after .text so that the read-only entry in the program
         * header covers .rodata as well. When .rodata is after .data, that entry
@@ -21,12 +25,18 @@ SECTIONS
         * matter yet because we (currently) assume that the NX bit is not
         * supported anyway. */
 
-       .data : ALIGN(4K) { *(.data) }
-       .bss : ALIGN(4K) { 
+       .data : ALIGN(4K) {
+               __DATA_BASE__ = .;
+               *(.data)
+               __DATA_END__ = .;
+       }
+       .bss : ALIGN(4K) {
+               __BSS_BASE__ = .;
                *(.bss)
                /* Reserving 16KiB for the stack. A __STACK_TOP__ is not really
                 * needed (yet). */
-               . += 16K; 
+               . += 16K;
                __STACK_BOTTOM__ = .;
+               __BSS_END__ = .;
        }
 }
diff --git a/kernel/arch/x86/tty.c b/kernel/arch/x86/tty.c
new file mode 100644 (file)
index 0000000..6796594
--- /dev/null
@@ -0,0 +1,94 @@
+#include <io.h>
+#include <tty.h>
+#include <stdint.h>
+
+#define VGA_WIDTH 80
+#define VGA_HEIGHT 25
+
+static int cursor_x = 0; /* keep track of where cursor is */
+static int cursor_y = 0;
+static uint16_t crtc_port;
+
+static inline uint8_t vga_get_color(const enum vga_color fg, const enum vga_color bg)
+{
+       return fg&0xf | bg<<4;
+}
+
+static inline uint16_t vga_get_char(const enum vga_color fg, const enum vga_color bg, char character)
+{
+       return character | vga_get_color(fg, bg)<<8;
+}
+
+static inline char *vga_get_memory_address(int x, int y)
+{
+       return (char *) 0xb8000 + (y*VGA_WIDTH + x)*2;
+}
+
+static void vga_scroll_up(void)
+{
+       for (int y=1; y<VGA_HEIGHT; y++) {
+               for (int x = 0; x<VGA_WIDTH; x++) {
+                       *vga_get_memory_address(x, y-1) = *vga_get_memory_address(x, y);
+               }
+       }
+
+       for (int x = 0; x<VGA_WIDTH; x++) {
+               *vga_get_memory_address(x, VGA_HEIGHT-1) = vga_get_char(VGA_LIGHT_GRAY, VGA_BLACK, ' ');
+       }
+       cursor_y = VGA_HEIGHT - 1;
+}
+
+static void vga_set_cursor(int x, int y)
+{
+       uint16_t cursor_address = y*VGA_WIDTH + x;
+
+       outb(crtc_port, 0xe);
+       outb(crtc_port+1, cursor_address>>8);
+       outb(crtc_port, 0xf);
+       outb(crtc_port+1, cursor_address);
+}
+
+static void vga_screen_clear(void)
+{
+       for (int y=0; y<VGA_HEIGHT; y++) {
+               for (int x=0; x<VGA_WIDTH; x++) {
+                       *vga_get_memory_address(x, y) = vga_get_char(VGA_LIGHT_GRAY, VGA_BLACK, ' ');
+               }
+       }
+
+       cursor_x = 0;
+       cursor_y = 0;
+       vga_set_cursor(0, 0);
+}
+
+void vga_print_char(const char character, const enum vga_color fg, const enum vga_color bg)
+{
+       if (character == '\n') {
+               cursor_x = 0;
+               cursor_y++;
+       } else {
+               *vga_get_memory_address(cursor_x, cursor_y) = vga_get_char(fg, bg, character);
+               cursor_x++;
+       }
+
+       if (cursor_x >= VGA_WIDTH) {
+               cursor_x = 0;
+               cursor_y++;
+       }
+
+       if (cursor_y >= VGA_HEIGHT)
+               vga_scroll_up();
+
+       vga_set_cursor(cursor_x, cursor_y);
+}
+
+void vga_initialize()
+{
+       uint8_t vga_misc = inb(0x3cc);
+       if (vga_misc&1)
+               crtc_port = 0x3d4;
+       else
+               crtc_port = 0x3b4;
+
+       vga_screen_clear();
+}
diff --git a/kernel/arch/x86/tty/tty.c b/kernel/arch/x86/tty/tty.c
deleted file mode 100644 (file)
index 07d734e..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-#include <io.h>
-#include <tty.h>
-#include <stdint.h>
-
-#define VGA_WIDTH 80
-#define VGA_HEIGHT 25
-
-volatile char *video_memory = (char *) 0xB8000; /* VGA VRAM starts at 0xB8000 */
-
-static int cursor_x = 0; /* keep track of where cursor is */
-static int cursor_y = 0;
-
-char *hex_chars = "0123456789ABCDEF";
-
-void screen_clear(void)
-{
-       int x, y;
-       for ( y = 0; y < VGA_HEIGHT; y++ ) {
-               for ( x = 0; x < VGA_WIDTH; x++ ) {
-                       video_memory[(y * VGA_WIDTH + x) * 2 + 1] = VGA_COLOR_LIGHT_GRAY;
-                       video_memory[(y * VGA_WIDTH + x) * 2] = ' ';
-               }
-       }
-
-       cursor_x = 0;
-       cursor_y = 0;
-}
-
-void scroll_up(void)
-{
-       int x, y;
-       for ( y = 1; y < VGA_HEIGHT; y++ ) {
-               for ( x = 0; x < VGA_WIDTH; x++ ) {
-                       video_memory[((y - 1) * VGA_WIDTH + x) * 2] = video_memory[(y * VGA_WIDTH + x) * 2];
-               }
-       }
-       for ( x = 0; x < VGA_WIDTH; x++ ) {
-               video_memory[((VGA_HEIGHT - 1) * VGA_WIDTH + x) * 2] = ' ';
-       }
-       cursor_y = VGA_HEIGHT - 1;
-}
-
-void kprint(const char *string, uint8_t color)
-{
-       char next_char;
-       uint8_t vga_misc_output;
-       uint16_t crtc_port;
-       next_char = *string;
-
-       while ( next_char != 0 ) {
-               if ( next_char == '\n') { cursor_x = 0; cursor_y++; }
-               else { video_memory[(cursor_y * VGA_WIDTH + cursor_x) * 2] = next_char; video_memory[((cursor_y * VGA_WIDTH + cursor_x++) * 2)+ 1] = color != 0 ? color : VGA_COLOR_LIGHT_GRAY; }
-               if ( cursor_x >= VGA_WIDTH ) { cursor_x = 0; cursor_y++; }
-               if ( cursor_y >= VGA_HEIGHT ) { scroll_up(); }
-               next_char = *++string;
-       }
-
-       vga_misc_output = inb(0x3CC);
-       if (vga_misc_output & 0x1 == 0) {
-               crtc_port = 0x3B4;
-       } else {
-               crtc_port = 0x3D4;
-       }
-
-       outb(crtc_port, 0xE);
-       outb(crtc_port + 1, (cursor_y * VGA_WIDTH + cursor_x) >> 8);
-       outb(crtc_port, 0xF);
-       outb(crtc_port + 1, (cursor_y * VGA_WIDTH + cursor_x) & 0xFF);
-}
-
-void kprintc(const char character, uint8_t color)
-{
-       uint8_t vga_misc_output;
-       uint16_t crtc_port;
-
-       if ( character == '\n') { cursor_x = 0; cursor_y++; }
-       else { video_memory[(cursor_y * VGA_WIDTH + cursor_x) * 2] = character; video_memory[((cursor_y * VGA_WIDTH + cursor_x++) * 2)+ 1] = color != 0 ? color : VGA_COLOR_LIGHT_GRAY; }
-       if ( cursor_x >= VGA_WIDTH ) { cursor_x = 0; cursor_y++; }
-       if ( cursor_y >= VGA_HEIGHT ) { scroll_up(); }
-
-       vga_misc_output = inb(0x3CC);
-       if (vga_misc_output & 0x1 == 0) {
-               crtc_port = 0x3B4;
-       } else {
-               crtc_port = 0x3D4;
-       }
-
-       outb(crtc_port, 0xE);
-       outb(crtc_port + 1, (cursor_y * VGA_WIDTH + cursor_x) >> 8);
-       outb(crtc_port, 0xF);
-       outb(crtc_port + 1, (cursor_y * VGA_WIDTH + cursor_x) & 0xFF);
-
-}
-
-void kprintb(uint8_t byte)
-{
-       uint8_t temp;
-       temp = byte >> 4;
-       kprint("0x", VGA_COLOR_LIGHT_GRAY);
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = byte & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-}
-
-void kprintw(uint16_t word)
-{
-       uint8_t temp;
-       temp = word >> 12;
-       kprint("0x", VGA_COLOR_LIGHT_GRAY);
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = (word >> 8) & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = (word >> 4) & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = word & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-}
-
-void kprintd(uint32_t dword)
-{
-       uint8_t temp;
-       temp = dword >> 28;
-       kprint("0x", VGA_COLOR_LIGHT_GRAY);
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = (dword >> 24) & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = (dword >> 20) & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = (dword >> 16) & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = (dword >> 12) & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = (dword >> 8) & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = (dword >> 4) & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-       temp = dword & 0xF;
-       kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
-}
diff --git a/kernel/drivers/Makefile b/kernel/drivers/Makefile
new file mode 100644 (file)
index 0000000..c7a3619
--- /dev/null
@@ -0,0 +1,2 @@
+include drivers/input/Makefile
+include drivers/irq/Makefile
diff --git a/kernel/drivers/input/Makefile b/kernel/drivers/input/Makefile
new file mode 100644 (file)
index 0000000..7577b52
--- /dev/null
@@ -0,0 +1 @@
+KERNEL_OBJ += drivers/input/ps2.o
diff --git a/kernel/drivers/irq/Makefile b/kernel/drivers/irq/Makefile
new file mode 100644 (file)
index 0000000..cd5b834
--- /dev/null
@@ -0,0 +1 @@
+KERNEL_OBJ += drivers/irq/i8259a.o
diff --git a/kernel/entry.s b/kernel/entry.s
deleted file mode 100644 (file)
index 10c95e8..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-bits 32
-extern kmain
-extern __STACK_BOTTOM__
-
-global _start
-_start:
-       mov ebp, __STACK_BOTTOM__
-       mov esp, ebp
-       call kmain
-       hlt
-       jmp $-1
diff --git a/kernel/include/arch/x86/mm/paging.h b/kernel/include/arch/x86/mm/paging.h
new file mode 100644 (file)
index 0000000..a4bdf22
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef X86_PAGING_H
+#define X86_PAGING_H
+
+struct page_directory_entry {
+       unsigned p: 1,
+                rw: 1,
+                us: 1,
+                pwt: 1,
+                pcd: 1,
+                a: 1,
+                ignored: 1,
+                ps: 1,
+                ignored2: 4,
+                page_table_addr: 20;
+} __attribute__((packed));
+
+struct page_table_entry {
+       unsigned p: 1,
+                rw: 1,
+                us: 1,
+                pwt: 1,
+                pcd: 1,
+                a: 1,
+                d: 1,
+                pat: 1,
+                g: 1,
+                ignored: 3,
+                page_frame_addr: 20;
+} __attribute__((packed));
+
+struct pf_errcode {
+       unsigned p: 1, wr: 1, us: 1, rsvd: 1, id: 1, pk: 1, ss: 1, hlat: 1, reserved: 7, sgx: 1, reserved2: 15;
+} __attribute__((packed));
+
+#endif
diff --git a/kernel/include/arch/x86/tty.h b/kernel/include/arch/x86/tty.h
new file mode 100644 (file)
index 0000000..a7cb8cf
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef X86_TTY_H
+#define X86_TTY_H
+
+enum vga_color {
+       VGA_BLACK,
+       VGA_BLUE,
+       VGA_GREEN,
+       VGA_TEAL,
+       VGA_DARK_RED,
+       VGA_MAGENTA,
+       VGA_BROWN,
+       VGA_LIGHT_GRAY,
+       VGA_DARK_GRAY,
+       VGA_PURPLE,
+       VGA_LIME,
+       VGA_CYAN,
+       VGA_BRIGHT_RED,
+       VGA_PINK,
+       VGA_YELLOW,
+       VGA_WHITE
+};
+
+extern void vga_initialize(void);
+extern void vga_print_char(const char character, enum vga_color fg, enum vga_color bg);
+#endif
diff --git a/kernel/include/kprint.h b/kernel/include/kprint.h
new file mode 100644 (file)
index 0000000..b883c14
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef KPRINT_H
+#define KPRINT_H
+
+#include <stdint.h>
+#include <tty.h>
+
+extern void tty_initialize();
+extern void kprint(const char *string, const enum vga_color fg, const enum vga_color bg);
+extern void kprintc(const char character, const enum vga_color fg, const enum vga_color bg);
+extern void kprintnibble(uint8_t nibble);
+extern void kprintb(const uint8_t byte, const int print_delm);
+extern void kprintw(const uint16_t word, const int print_delm);
+extern void kprintd(const uint32_t dword, const int print_delm);
+extern void kprintq(const uint64_t qword, const int print_delm);
+extern int kprintdec(uint32_t num, const enum vga_color fg, const enum vga_color bg);
+
+#endif
diff --git a/kernel/include/panic.h b/kernel/include/panic.h
new file mode 100644 (file)
index 0000000..5c4d662
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef PANIC_H
+#define PANIC_H
+
+extern void halt();
+
+#define PANIC(msg) \
+       kprint("PANIC (", VGA_BRIGHT_RED, VGA_BLACK);\
+       kprint(msg, VGA_BRIGHT_RED, VGA_BLACK);\
+       kprint(") in ", VGA_BRIGHT_RED, VGA_BLACK);\
+       kprint(__FILE__, VGA_BRIGHT_RED, VGA_BLACK);\
+       kprintc(':', VGA_BRIGHT_RED, VGA_BLACK);\
+       kprintdec(__LINE__, VGA_BRIGHT_RED, VGA_BLACK);\
+       kprintc(':', VGA_BRIGHT_RED, VGA_BLACK);\
+       kprint(__func__, VGA_BRIGHT_RED, VGA_BLACK);\
+       kprint("()", VGA_BRIGHT_RED, VGA_BLACK);\
+       halt();
+
+#endif
diff --git a/kernel/kernel.c b/kernel/kernel.c
deleted file mode 100644 (file)
index c82bd4d..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-#include <stdint.h>
-#include <tty.h>
-#include <io.h>
-#include <irq/idt.h>
-#include <irq/interrupt.h>
-#include <irq/i8259a.h>
-#include <input/ps2.h>
-
-struct idt_descriptor idt[256] __attribute__((aligned(0x10)));
-struct idtr idtr __attribute__((aligned(0x10)));
-extern void (*_int_handler_table[48])(void);
-
-/* Small handler for double faults. Will be put elsewhere eventually. */
-int double_fault_handler(struct interrupt_frame *frame)
-{
-       kprint("PANIC: Double fault occurred!\n", VGA_COLOR_BRIGHT_RED);
-       kprint("EAX: ", VGA_COLOR_BRIGHT_RED);
-       kprintd(frame->eax);
-       kprint("\n", VGA_COLOR_BRIGHT_RED);
-       kprint("EBX: ", VGA_COLOR_BRIGHT_RED);
-       kprintd(frame->ebx);
-       kprint("\n", VGA_COLOR_BRIGHT_RED);
-       kprint("ECX: ", VGA_COLOR_BRIGHT_RED);
-       kprintd(frame->ecx);
-       kprint("\n", VGA_COLOR_BRIGHT_RED);
-       kprint("EDX: ", VGA_COLOR_BRIGHT_RED);
-       kprintd(frame->edx);
-       kprint("\n", VGA_COLOR_BRIGHT_RED);
-       kprint("EBP: ", VGA_COLOR_BRIGHT_RED);
-       kprintd(frame->ebp);
-       kprint("\n", VGA_COLOR_BRIGHT_RED);
-       kprint("ESP: ", VGA_COLOR_BRIGHT_RED);
-       kprintd(frame->esp);
-       kprint("\n", VGA_COLOR_BRIGHT_RED);
-       kprint("ESI: ", VGA_COLOR_BRIGHT_RED);
-       kprintd(frame->esi);
-       kprint("\n", VGA_COLOR_BRIGHT_RED);
-       kprint("EDI: ", VGA_COLOR_BRIGHT_RED);
-       kprintd(frame->edi);
-       kprint("\n", VGA_COLOR_BRIGHT_RED);
-       kprint("EIP: ", VGA_COLOR_BRIGHT_RED);
-       kprintd(frame->eip);
-       kprint("\n", VGA_COLOR_BRIGHT_RED);
-       kprint("EFLAGS: ", VGA_COLOR_BRIGHT_RED);
-       kprintd(frame->eflags);
-       kprint("\n", VGA_COLOR_BRIGHT_RED);
-
-       /* IF has already been cleared for us */
-halt:
-       asm("hlt");
-       goto halt;
-}
-
-void kmain(void)
-{
-       int ps2_success;
-       screen_clear();
-       kprint("Welcome to Nameless OS!\nRunning revision: ", 0);
-       kprint(GIT_COMMIT, 0);
-       kprint("\n", 0);
-       kprint("Preparing IDT...\n", 0);
-       for (int i=0; i<48; i++) {
-               idt_set_descriptor(idt, i, 0x8, _int_handler_table[i], IDT_INTERRUPT_GATE, 0);
-       }
-       kprint("IDT prepared, loading...\n", 0);
-       populate_idtr(&idtr, idt);
-       load_idt(idtr);
-       kprint("Setting up interrupts...\n", 0);
-       register_interrupt(8, &double_fault_handler);
-       pic_init(0x20, 0x28);
-       pic_mask_all();
-       ps2_success = ps2_initialize();
-       switch (ps2_success) {
-               case -1:
-                       kprint("No PS/2 devices found or working, we will have no input\n", 0);
-                       break;
-               case 0:
-                       kprint("Found one working PS/2 device\n", 0);
-                       break;
-               case 1:
-                       kprint("Found two working PS/2 devices\n", 0);
-       }
-       asm volatile ("sti");
-       kprint("All done\n", 0);
-       while(1);
-}
diff --git a/kernel/kernel/Makefile b/kernel/kernel/Makefile
new file mode 100644 (file)
index 0000000..1827b72
--- /dev/null
@@ -0,0 +1 @@
+KERNEL_OBJ += $(addprefix kernel/, kernel.o kprint.o)
diff --git a/kernel/kernel/kernel.c b/kernel/kernel/kernel.c
new file mode 100644 (file)
index 0000000..b198fcf
--- /dev/null
@@ -0,0 +1,110 @@
+#include <kprint.h>
+#include <io.h>
+#include <irq/idt.h>
+#include <irq/interrupt.h>
+#include <irq/i8259a.h>
+#include <input/ps2.h>
+#include <stdint.h>
+#include <mm/paging.h>
+#include <panic.h>
+
+struct idt_descriptor idt[256] __attribute__((aligned(0x10)));
+struct idtr idtr __attribute__((aligned(0x10)));
+extern void (*_int_handler_table[48])(void);
+
+struct e820_map {
+       uint64_t base;
+       uint64_t length;
+       uint32_t type;
+       uint32_t attrib;
+};
+
+void print_e820(struct e820_map *mmap, int mmap_size)
+{
+       kprint("       Base       |      Length      |   Type   |  Attrib  |\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("------------------------------------------------------------\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       for (int i=0; i<mmap_size; i++) {
+               kprintq(mmap[i].base, 1);
+               kprintc('|', VGA_LIGHT_GRAY, VGA_BLACK);
+               kprintq(mmap[i].length, 1);
+               kprintc('|', VGA_LIGHT_GRAY, VGA_BLACK);
+               kprintd(mmap[i].type, 1);
+               kprintc('|', VGA_LIGHT_GRAY, VGA_BLACK);
+               kprintd(mmap[i].attrib, 1);
+               kprintc('|', VGA_LIGHT_GRAY, VGA_BLACK);
+               kprintc('\n', VGA_LIGHT_GRAY, VGA_BLACK);
+       }
+}
+
+/* Small handler for double faults. Will be put elsewhere eventually. */
+int double_fault_handler(struct interrupt_frame *frame)
+{
+       kprint("Double fault occurred!\n", VGA_BRIGHT_RED, VGA_BLACK);
+       kprint("EAX: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprintd(frame->eax, 1);
+       kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("EBX: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprintd(frame->ebx, 1);
+       kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("ECX: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprintd(frame->ecx, 1);
+       kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("EDX: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprintd(frame->edx, 1);
+       kprintc('\n', VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("EBP: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprintd(frame->ebp, 1);
+       kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("ESP: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprintd(frame->esp, 1);
+       kprintc('\n', VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("ESI: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprintd(frame->esi, 1);
+       kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("EDI: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprintd(frame->edi, 1);
+       kprintc('\n', VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("EIP: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprintd(frame->eip, 1);
+       kprintc(' ', VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("EFLAGS: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprintd(frame->eflags, 1);
+       kprintc('\n', VGA_LIGHT_GRAY, VGA_BLACK);
+       PANIC("double fault");
+}
+
+void kmain(struct e820_map *mmap, int mmap_size)
+{
+       vga_initialize();
+       kprint("Welcome to Nameless OS!\nRunning revision: ", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint(GIT_COMMIT, VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       kprint("BIOS memory map:\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       print_e820(mmap, mmap_size);
+       kprint("Preparing IDT...\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       for (int i=0; i<48; i++) {
+               idt_set_descriptor(idt, i, 0x8, _int_handler_table[i], IDT_INTERRUPT_GATE, 0);
+       }
+       kprint("IDT prepared, loading...\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       populate_idtr(&idtr, idt);
+       load_idt(idtr);
+       kprint("Setting up interrupts...\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       register_interrupt(8, &double_fault_handler);
+       pic_init(0x20, 0x28);
+       pic_mask_all();
+       asm volatile ("sti");
+       kprint("Initializing PS/2...\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       int ret = ps2_initialize();
+       switch (ret) {
+       case -1:
+               kprint("No PS/2 devices found or something is faulty\n", VGA_LIGHT_GRAY, VGA_BLACK);
+               break;
+       case 0:
+               kprint("One PS/2 device found\n", VGA_LIGHT_GRAY, VGA_BLACK);
+               break;
+       case 1:
+               kprint("Two PS/2 devices found\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       }
+       kprint("All done\n", VGA_LIGHT_GRAY, VGA_BLACK);
+       while(1);
+}
diff --git a/kernel/kernel/kprint.c b/kernel/kernel/kprint.c
new file mode 100644 (file)
index 0000000..654a0a0
--- /dev/null
@@ -0,0 +1,100 @@
+#include <stdint.h>
+#include <kprint.h>
+
+void tty_initialize()
+{
+       vga_initialize();
+}
+
+void kprint(const char *string, const enum vga_color fg, const enum vga_color bg)
+{
+       char character = *string;
+       for (int i=1; character; i++) {
+               vga_print_char(character, fg, bg);
+               character = string[i];
+       }
+}
+
+void kprintc(const char character, const enum vga_color fg, const enum vga_color bg)
+{
+       vga_print_char(character, fg, bg);
+}
+
+void kprintnibble(uint8_t nibble)
+{
+       nibble &= 0xf;
+       if (nibble < 0xa)
+               kprintc('0' + nibble, VGA_LIGHT_GRAY, VGA_BLACK);
+       else kprintc('a' - 0xa + nibble, VGA_LIGHT_GRAY, VGA_BLACK);
+}
+
+void kprintb(const uint8_t byte, const int print_delm)
+{
+       if (print_delm)
+               kprint("0x", VGA_LIGHT_GRAY, VGA_BLACK);
+
+       kprintnibble(byte >> 4);
+       kprintnibble(byte);
+}
+
+void kprintw(const uint16_t word, const int print_delm)
+{
+       if (print_delm)
+               kprint("0x", VGA_LIGHT_GRAY, VGA_BLACK);
+
+       kprintb(word >> 8, 0);
+       kprintb(word, 0);
+}
+
+void kprintd(const uint32_t dword, const int print_delm)
+{
+       if (print_delm)
+               kprint("0x", VGA_LIGHT_GRAY, VGA_BLACK);
+
+       kprintw(dword >> 16, 0);
+       kprintw(dword, 0);
+}
+
+void kprintq(const uint64_t qword, const int print_delm)
+{
+       if (print_delm)
+               kprint("0x", VGA_LIGHT_GRAY, VGA_BLACK);
+
+       kprintd(qword >> 32, 0);
+       kprintd(qword, 0);
+}
+
+int kprintdec(uint32_t num, const enum vga_color fg, const enum vga_color bg)
+{
+       char buffer[11];
+       int digits = 10;
+       /* TODO: make an actual memset function to use instead of this */
+       for (int i=0; i<11; i++) {
+               buffer[i] = 0;
+       }
+
+       /* put the numbers in the buffer */
+       for (int i=9; i>0 && num>0; i--) {
+               const uint8_t currdigit = num%10;
+               buffer[i] = currdigit+'0';
+               num /= 10;
+       }
+
+       /* shift the array as much as needed */
+       while (*buffer == '\0') {
+               digits--;
+               for (int i=0; i<9; i++) {
+                       buffer[i] = buffer[i+1];
+               }
+       }
+
+       /* zero out any leftovers */
+       if (digits < 10) {
+               for (int i=digits; i<10; i++) {
+                       buffer[i] = '\0';
+               }
+       }
+
+       kprint(buffer, fg, bg);
+       return digits;
+}
index 28b3427ca0063b2dd83fb2402fba23d28111264c..116c41f09e90fd289635b6c88b04a2e89af8132d 100755 (executable)
@@ -1,7 +1,15 @@
 #!/bin/sh
 # Shell script to install Nameless to a disk.
 
-BINARIES=( boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN kernel/kernel.bin )
+BINARIES=( boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN kernel/kernel.elf )
+
+check_root() {
+       local user=$(whoami)
+       if [ $user != "root" ]; then
+               echo nameless2disk needs to be run as root!
+               exit 1
+       fi
+}
 
 check_binaries() {
        for i in "${BINARIES[@]}"; do
@@ -72,7 +80,7 @@ install_blkdev() {
                exit 1
        fi
        cp boot/x86/stage3/LOADER.BIN $mountpoint/LOADER.BIN
-       cp kernel/kernel.bin $mountpoint/KERNEL.BIN
+       cp kernel/kernel.elf $mountpoint/KERNEL.ELF
        if ! [ $? -eq 0 ]; then
                echo An error occurred!
                exit 1
@@ -92,6 +100,9 @@ install_blkdev() {
 [ -z $(command -v fdisk) ] && echo fdisk not found, is util-linux installed? && exit 127
 [ -z $(command -v mkfs.fat) ] && echo mkfs.fat not found, is dosfstools installed? && exit 127
 
+# Check for root privileges.
+check_root
+
 # Make sure that Nameless has been compiled.
 check_binaries