-toolchain/
-boot.img
-boot/x86/boot
**/*.o
**/*.bin
**/*.elf
export AS = yasm
+ASFLAGS = -g dwarf2 -f elf
export CC = i686-elf-gcc
QEMU = qemu-system-i386 -monitor stdio
export GIT_REV = $(shell git describe --long HEAD)
-CFLAGS = -g -fgnu89-inline -Iinclude/arch/x86 -ffreestanding -DGIT_COMMIT=\"$(GIT_REV)\"
+CFLAGS = -g -fgnu89-inline -Ikernel/include -Ikernel/include/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/sample_handler.o kernel/kernel.o
+KERNEL_OBJ = kernel/entry.o kernel/arch/x86/halt.o kernel/arch/x86/tty/tty.o kernel/drivers/irq/i8259a.o kernel/arch/x86/irq/idt.o kernel/arch/x86/irq/sample_handler.o kernel/kernel.o
-BOOTLOADER_OBJ = boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN
+BOOTLOADER_OBJ = boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN boot/x86/stage3/loader.elf
default: kernel/kernel.elf bootloader
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
+boot/x86/stage3/LOADER.BIN: boot/x86/stage3/*.s boot/x86/stage3/*.c boot/x86/fat32/*.s boot/x86/stage3/stage3.ld
+boot/x86/stage3/loader.elf: boot/x86/stage3/*.s boot/x86/stage3/*.c boot/x86/fat32/*.s boot/x86/stage3/stage3.ld
$(BOOTLOADER_OBJ):
$(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: boot/x86/mbr boot/x86/vbr-fat32 boot/x86/stage3/LOADER.BIN 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/entry.o: kernel/entry.s
- $(AS) -f elf $< -o $@
+ mcopy -i boot/x86/disk.img@@1M kernel/kernel.elf ::./KERNEL.ELF
kernel/arch/x86/irq/sample_handler.o: kernel/arch/x86/irq/sample_handler.c
$(CC) $(CFLAGS) -mgeneral-regs-only -c $< -o $@
-kernel/kernel.elf: kernel/kernel.bin
- $(CC) -ffreestanding -nostdlib -o $@ -T kernel/linker.ld ${KERNEL_OBJ} -Wl,--oformat=elf32-i386
+kernel/kernel.elf: $(KERNEL_OBJ)
+ $(CC) -ffreestanding -nostdlib -o $@ -T kernel/linker.ld ${KERNEL_OBJ} -lgcc
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
clean:
- -rm kernel/kernel.{bin,dbg,elf} ${KERNEL_OBJ}
+ -rm kernel/kernel.{dbg,elf} ${KERNEL_OBJ}
cd boot/x86 && $(MAKE) clean
-.PHONY: default all clean run bootloader
+.PHONY: default all clean run debug bootloader
-default: mbr vbr-fat32 stage3/LOADER.BIN
+default: mbr vbr-fat32 stage3/LOADER.BIN stage3/loader.elf
+
+CFLAGS=-g -ffreestanding -Istage3
+LD=i686-elf-gcc
+LDFLAGS=-T stage3/stage3.ld -ffreestanding -nostdlib -g
+
+STAGE3_OBJ=stage3/loader.o stage3/paging.o stage3/elf.o stage3/prekernel.o
mbr: mbr.s
$(AS) $(ASFLAGS) -w-zeroing -o $@ $<
vbr-fat32: vbr-fat32.s fat32/*.s
$(AS) $(ASFLAGS) -o $@ $<
-stage3/LOADER.BIN: stage3/loader.s stage3/*.s
- $(AS) $(ASFLAGS) -DGIT_REVISION=\"$(GIT_REV)\" -o $@ $<
+stage3/loader.elf: $(STAGE3_OBJ)
+ $(CC) $(LDFLAGS) -o $@ $^ -lgcc -Wl,--oformat=elf32-i386
+
+stage3/LOADER.BIN: $(STAGE3_OBJ)
+ $(CC) $(LDFLAGS) -o $@ $^ -lgcc
+
+stage3/loader.o: stage3/loader.s stage3/*.s
+ $(AS) $(ASFLAGS) -f elf -g dwarf2 -DGIT_REVISION=\"$(GIT_REV)\" -o $@ $<
clean:
- -rm mbr vbr-fat32 stage3/LOADER.BIN disk.img
+ -rm mbr vbr-fat32 stage3/LOADER.BIN stage3/loader.elf $(STAGE3_OBJ) disk.img
.PHONY : default clean
+bits 16
+section .text
+
%macro in_wait 0
push ax
%%loop:
; Code for getting the BIOS E820 memory map
bits 16
+section .text
; Return: ECX - number of entries, DI - pointer to map
get_e820_map:
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
--- /dev/null
+/* 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);
+}
--- /dev/null
+#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
; Initial GDT for kernel, which wants a flat code and data descriptor
+
+section .rodata
+
gdt:
dw .end-.start-1
dd .start
bits 16
cpu 686
-org 0x1800
+extern run_kernel
+
+section .text
%include "../fat32/fat32-structs.s"
%macro print 1
pop si
%endmacro
+extern __STACK_BOTTOM__
+
+global _start
_start:
+ mov sp, __STACK_BOTTOM__
mov [BOOT_DRIVE], dl
call enable_unreal
print begin
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
print kernel_loaded
call get_e820_map
+ mov ebx, ecx
+ mov eax, 24
+ mul ecx
+ add eax, 20
+ sub sp, ax
cli
lgdt [gdt]
pop esi
ret
-
%include "unreal.s"
%include "a20.s"
%include "../fat32/fat32.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 fs, ax
mov gs, ax
- call load_paging_structs
- call enable_paging
+ push dword [KERNEL_SIZE]
+ push 0x100000
+ push ebx
+ push edi
+ call run_kernel
+
+section .bss
+KERNEL_SIZE: resd 1
- jmp 0x8:0xc0000000
- nop
+section .rodata
-kernel_name: db "KERNEL BIN"
+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
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
--- /dev/null
+/* 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;
+}
--- /dev/null
+#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
--- /dev/null
+#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();
+ }
+}
; Routines for printing
+bits 16
+section .text
+
print_str:
push ax
push bx
--- /dev/null
+ENTRY(_start)
+OUTPUT_FORMAT(binary)
+
+SECTIONS {
+ . = 0x1800;
+ .text : {
+ stage3/loader.o(.text)
+ *(.text)
+ }
+ .rodata : { *(.rodata) }
+ .data : { *(.data) }
+ .bss : {
+ *(.bss)
+ . += 1K;
+ PROVIDE(__STACK_BOTTOM__ = .);
+ }
+}
; Routine for enabling unreal mode, which allows using 32-bit offsets in real mode
+bits 16
+section .text
+
enable_unreal:
cli
push eax
sti
ret
+section .rodata
+
; GDT with 1 flat data segment descriptor
gdt_info:
dw gdt_end-gdt_start-1
--- /dev/null
+; x86-specific routine for halting
+
+bits 32
+global halt
+
+halt:
+ cli
+ hlt
+ jmp $-1
#include <io.h>
#include <stdint.h>
#include <mm/paging.h>
+#include <panic.h>
typedef uint32_t uword_t;
int address;
struct pf_errcode errcode = frame->error_code;
asm ("mov %%cr2, %0": "=a" (address));
- kprint("A page fault occurred!\n", VGA_COLOR_DARK_RED);
+ kprint("A page fault occurred!\n", VGA_COLOR_BRIGHT_RED);
kprint("Faulting address: ", 0);
kprintd(address);
kprint("\n", 0);
if (errcode.id) {
kprint("Fault occurred while fetching instruction\n", 0);
}
- asm("cli");
-halt:
- asm("hlt");
- goto halt;
+ PANIC("page fault");
}
__attribute__((interrupt))
void double_fault(struct abort_frame *frame)
{
- *(volatile uint32_t *) (0xb8000) = 0xcf28cf3a;
-halt:
- asm volatile ("cli; hlt");
- goto halt;
+ PANIC("double fault");
}
temp = qword & 0xF;
kprintc(hex_chars[temp], VGA_COLOR_LIGHT_GRAY);
}
+
+int kprintdec(uint32_t num, uint8_t color)
+{
+ 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--) {
+ 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, color);
+ return digits;
+}
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
- push ecx
- push edi
+ ; 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
--- /dev/null
+#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
--- /dev/null
+#ifndef PANIC_H
+#define PANIC_H
+
+extern void halt();
+
+#define PANIC(msg) \
+ kprint("PANIC (", VGA_COLOR_BRIGHT_RED);\
+ kprint(msg, VGA_COLOR_BRIGHT_RED);\
+ kprint(") in ", VGA_COLOR_BRIGHT_RED);\
+ kprint(__FILE__, VGA_COLOR_BRIGHT_RED);\
+ kprintc(':', VGA_COLOR_BRIGHT_RED);\
+ kprintdec(__LINE__, VGA_COLOR_BRIGHT_RED);\
+ kprintc(':', VGA_COLOR_BRIGHT_RED);\
+ kprint(__func__, VGA_COLOR_BRIGHT_RED);\
+ kprint("()", VGA_COLOR_BRIGHT_RED);\
+ halt();
+
+#endif
-#ifndef X86_TTY_H
-#define X86_TTY_H
+#ifndef TTY_H
+#define TTY_H
#include <stdint.h>
extern void kprintw(const uint16_t word);
extern void kprintd(const uint32_t dword);
extern void kprintq(const uint64_t qword);
+extern int kprintdec(uint32_t num, uint8_t color);
#endif
ENTRY(_start)
-OUTPUT_FORMAT(binary)
SECTIONS
{
#!/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_binaries() {
for i in "${BINARIES[@]}"; do
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