From f6f67fad12c291810a564579d8bc5374eaa1bc0b Mon Sep 17 00:00:00 2001 From: Utkarsh Maheshwari Date: Thu, 30 May 2019 15:01:54 +0530 Subject: [PATCH 1/2] boot: Setup a basic loader which will load kernel --- boot/.gitignore | 1 + boot/boot.asm | 26 ++++++++ boot/boot.c | 14 ++++ boot/include/multiboot.h | 139 +++++++++++++++++++++++++++++++++++++++ boot/linker.ld | 21 ++++++ boot/makefile | 87 ++++++++++++++++++++++++ bootloader/makefile | 2 +- makefile | 11 +++- 8 files changed, 298 insertions(+), 3 deletions(-) create mode 100644 boot/.gitignore create mode 100644 boot/boot.asm create mode 100644 boot/boot.c create mode 100644 boot/include/multiboot.h create mode 100644 boot/linker.ld create mode 100644 boot/makefile diff --git a/boot/.gitignore b/boot/.gitignore new file mode 100644 index 0000000..0a43424 --- /dev/null +++ b/boot/.gitignore @@ -0,0 +1 @@ +.COMPILER_INFO diff --git a/boot/boot.asm b/boot/boot.asm new file mode 100644 index 0000000..c9970db --- /dev/null +++ b/boot/boot.asm @@ -0,0 +1,26 @@ +; vi:filetype=nasm + +section .text ; start code section +align 4 + +section .multiboot + dd 0x1BADB002 ; magic number + dd 0x00 ; flags + dd - (0x1BADB002 + 0x00) ; checksum => + ; magic + flags + checksum = zero + +extern lmain + +global start +start: + cli ; prevent interrupts from waking halted CPU + mov esp, _stack ; initialize stack + push eax ; multiboot magic number + push ebx ; multiboot info + call lmain ; call the lmain function in boot.c + hlt ; halt CPU + +section .bss + + resb 8192 ; reserve space for stack (8kb) + _stack: diff --git a/boot/boot.c b/boot/boot.c new file mode 100644 index 0000000..7241a0a --- /dev/null +++ b/boot/boot.c @@ -0,0 +1,14 @@ +#include + +void lmain(multiboot_info_t *multiboot_info, uint32_t multiboot_magic) +{ + if (multiboot_magic != MULTIBOOT_EAX_MAGIC) { + return; + } + + (void)(multiboot_info); + + while (1) { + ; /* nop */ + } +} diff --git a/boot/include/multiboot.h b/boot/include/multiboot.h new file mode 100644 index 0000000..753c3c9 --- /dev/null +++ b/boot/include/multiboot.h @@ -0,0 +1,139 @@ +#ifndef MULTIBOOT_H_RKNBOMGQ +#define MULTIBOOT_H_RKNBOMGQ + +typedef unsigned long uint32_t; +typedef unsigned int uint16_t; +typedef unsigned long long uint64_t; +typedef unsigned char uint8_t; + + +/* magic numbers for multiboot. these help us verify that multiboot structure is + * indeed valid. */ +#define MULTIBOOT_MAGIC 0x1BADB002 +#define MULTIBOOT_EAX_MAGIC 0x2BADB002 + +#define MULTIBOOT_MOD_ALIGN 0x00001000 +#define MULTIBOOT_INFO_ALIGN 0x00000004 + +/* flags for multiboot_info */ +#define MULTIBOOT_FLAG_MEMORY 0x00000001 +#define MULTIBOOT_FLAG_BOOTDEV 0x00000002 +#define MULTIBOOT_FLAG_CMDLINE 0x00000004 +#define MULTIBOOT_FLAG_MODS 0x00000008 +#define MULTIBOOT_FLAG_AOUT_SYMS 0x00000010 +#define MULTIBOOT_FLAG_ELF_SHDR 0X00000020 +#define MULTIBOOT_FLAG_MEM_MAP 0x00000040 +#define MULTIBOOT_FLAG_DRIVE_INFO 0x00000080 +#define MULTIBOOT_FLAG_CONFIG_TABLE 0x00000100 +#define MULTIBOOT_FLAG_BOOT_LOADER_NAME 0x00000200 +#define MULTIBOOT_FLAG_APM_TABLE 0x00000400 +#define MULTIBOOT_FLAG_VBE_INFO 0x00000800 +#define MULTIBOOT_FLAG_FRAMEBUFFER_INFO 0x00001000 + +/* flags for multiboot framebuffer type */ +#define MULTIBOOT_FB_TYPE_INDEXED 0x00000000 +#define MULTIBOOT_FB_TYPE_RGB 0x00000001 +#define MULTIBOOT_FB_TYPE_EGA_TEXT 0x00000002 + + +typedef struct _multiboot_info_t { + uint32_t flags; + + uint32_t mem_lower; + uint32_t mem_upper; + + uint32_t boot_device; + + uint32_t cmdline; + + uint32_t mods_count; + uint32_t mods_addr; + + union { + struct { + uint32_t num; + uint32_t size; + uint32_t addr; + uint32_t shndx; + } __attribute__((packed)) efl_sec; + + struct { + uint32_t tabsize; + uint32_t strsize; + uint32_t addr; + uint32_t reserved; + } __attribute__((packed)) aout_sym; + }; + + uint32_t mmap_len; + uint32_t mmap_addr; + + uint32_t drives_len; + uint32_t driver_addr; + + uint32_t config_table; + + uint32_t bootloader_name; + + uint32_t apm_table; + + struct { + uint32_t control_info; + uint32_t mode_info; + uint16_t mode; + uint16_t interface_seg; + uint16_t interface_off; + uint16_t interface_len; + } __attribute__((packed)) vbe; + + struct { + uint64_t addr; + uint32_t pitch; + uint32_t width; + uint32_t height; + uint8_t bpp; + uint8_t type; + + union { + struct { + uint32_t addr; + uint16_t num_colors; + } __attribute__((packed)) palette; + + struct { + uint8_t red_field_position; + uint8_t red_mask_size; + uint8_t green_field_position; + uint8_t green_mask_size; + uint8_t blue_field_position; + uint8_t blue_mask_size; + } __attribute__((packed)); + }; + } __attribute__((packed)) framebuffer; +} __attribute__((packed)) multiboot_info_t; + + +typedef struct _multiboot_memory_map_t { + uint32_t size; + uint32_t base_addr_low; + uint32_t base_addr_high; + uint32_t len_low; + uint32_t len_high; +#define MULTIBOOT_MEM_TYPE_FREE 0x1 /* free memory */ +#define MULTIBOOT_MEM_TYPE_RSVD 0x2 /* reserved by system */ +#define MULTIBOOT_MEM_TYPE_ACPI 0x3 /* reclaimable ACPI memory */ +#define MULTIBOOT_MEM_TYPE_NVS 0x4 /* non-volatile storage */ +#define MULTIBOOT_MEM_TYPE_BADR 0x5 /* memory used by bad RAM modules */ + uint32_t type; +} __attribute__((packed)) multiboot_memory_map_t; + + +#define FOREACH_MEMORY_MAP(MMAP, INFO) \ + for(multiboot_memory_map_t *(MMAP) = \ + (multiboot_memory_map_t *)(uintptr_t)((INFO)->mmap_addr); \ + (uintptr_t)(MMAP) < (INFO)->mmap_addr + (INFO)->mmap_len; \ + (MMAP) = (multiboot_memory_map_t *) \ + ((uintptr_t)(MMAP) + (MMAP)->size + sizeof((MMAP)->size)) \ + ) + +#endif /* end of include guard: MULTIBOOT_H_RKNBOMGQ */ diff --git a/boot/linker.ld b/boot/linker.ld new file mode 100644 index 0000000..97cff12 --- /dev/null +++ b/boot/linker.ld @@ -0,0 +1,21 @@ +ENTRY(start) +SECTIONS +{ + . = 0x00000000; + + .multiboot : { + *(.multiboot) + } + + .text : { + *(.text) + } + + .data ALIGN(0x1000) : { + *(.data) + } + + .bss : { + *(.bss) + } +} diff --git a/boot/makefile b/boot/makefile new file mode 100644 index 0000000..1d86ecc --- /dev/null +++ b/boot/makefile @@ -0,0 +1,87 @@ +TARGET = i686-elf + +# Set debug mode +ifndef RELEASE + RELEASE = false +endif + +# Set architecture type +ifndef ARCH + ARCH = ARCH_X86 +endif + +CC = ../.deps/cross/bin/$(TARGET)-gcc +LD = ../.deps/cross/bin/$(TARGET)-ld +CC_ASM = nasm +CC_FLAGS = $(CFLAGS) -fno-builtin -std=gnu99 -Wall -Wextra -Werror + +ifeq ($(RELEASE), false) +CD_FLAGS = -g +endif + +LINT = clang-tidy +LINT_FLAGS = -fix-errors + +BUILD_DIR = ../build/boot +BIN = $(BUILD_DIR)/boot.bin + +ASM_SRC = $(shell find . -name "*.asm") +ASM_OBJ = $(patsubst %.asm,%_asm.o,$(ASM_SRC)) + +SRC = $(shell find . -name "*.c") +OBJ = $(patsubst %.c,%.o,$(SRC)) + +INCLUDE = $(shell find . -name "*.h") + +INCLUDE_DIR = include +phony = + +phony += all +all: $(BIN) + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +$(BIN): .COMPILER_INFO $(BUILD_DIR) $(ASM_OBJ) $(OBJ) linker.ld + @$(LD) -T linker.ld $(OBJ) $(ASM_OBJ) -o $@ + @echo building $@ + +$(ASM_OBJ):%_asm.o: %.asm makefile + @$(CC_ASM) -f elf32 $< -o $@ + @echo building $@ + +$(OBJ):%.o: %.c $(INCLUDE) makefile + @echo building $@ + @$(CC) $(CC_FLAGS) $(CD_FLAGS) -I. -I${INCLUDE_DIR} -c $< -o $@ + +.COMPILER_INFO: + @touch .COMPILER_INFO + @echo -- using `$(CC_ASM) -v` + @echo -- using $(CC) `$(CC) -dumpversion` `$(CC) -dumpmachine` + @echo -- using $(LD) `$(LD) -v` + +phony += qemu +qemu: all + qemu-system-x86_64 -kernel $(BIN) \ + -serial file:///tmp/jazz_serial1.log + +gdb: all + gdb $(BIN) \ + -ex "set architecture i386:x86-64" \ + -ex "target remote | qemu-system-x86_64 -kernel $(BIN) \ + -serial file:///tmp/jazz_serial1.log -gdb stdio -S" + +phony += lint +lint: + $(LINT) `find . -name "*.c" -or -name "*.h"` $(LINT_FLAGS)\ + -- -I. -Iinclude/ + +phony += clean +clean: + rm -rf $(BIN) $(OBJ) $(ASM_OBJ) .COMPILER_INFO + +phony += tags +tags: + ctags -R . + +.PHONY: $(phony) diff --git a/bootloader/makefile b/bootloader/makefile index ae26e1f..4ac8779 100644 --- a/bootloader/makefile +++ b/bootloader/makefile @@ -1,7 +1,7 @@ CC = nasm BUILD_DIR = ../build/bootloader -BIN = $(BUILD_DIR)/boot.bin +BIN = $(BUILD_DIR)/bootloader.bin all: $(BIN) diff --git a/makefile b/makefile index 6eaf323..70de141 100644 --- a/makefile +++ b/makefile @@ -14,7 +14,8 @@ DEPS_PREFIX = $(shell pwd)/.deps/cross BUILD_DIR = build DISK_IMG = $(BUILD_DIR)/disk.img -BOOTLOADER = $(BUILD_DIR)/bootloader/boot.bin +BOOTLOADER = $(BUILD_DIR)/bootloader/bootloader.bin +BOOT = $(BUILD_DIR)/boot/boot.bin KERNEL = $(BUILD_DIR)/kernel/kernel.bin MAKE_CMD = $(MAKE) \ @@ -26,7 +27,7 @@ MAKE_CMD = $(MAKE) \ phony = all all: $(DISK_IMG) -$(DISK_IMG): $(BUILD_DIR) $(BOOTLOADER) $(KERNEL) +$(DISK_IMG): $(BUILD_DIR) $(BOOTLOADER) $(BOOT) $(KERNEL) dd if=/dev/zero of=$(DISK_IMG) bs=512 count=2880 dd if=$(BOOTLOADER) of=$(DISK_IMG) bs=512 count=1 seek=0 dd if=$(KERNEL) of=$(DISK_IMG) bs=512 seek=1 @@ -39,6 +40,10 @@ phony += $(BOOTLOADER) $(BOOTLOADER): bootloader/boot.asm $(MAKE_CMD) --directory bootloader +phony += $(BOOT) +$(BOOT): deps + $(MAKE_CMD) --directory boot + phony += $(KERNEL) $(KERNEL): deps $(MAKE_CMD) --directory kernel @@ -57,11 +62,13 @@ qemu_kernel: $(KERNEL) phony += lint lint: + $(MAKE_CMD) --directory boot lint $(MAKE_CMD) --directory kernel lint phony += clean clean: $(MAKE_CMD) --directory bootloader clean + $(MAKE_CMD) --directory boot clean $(MAKE_CMD) --directory kernel clean rm -f $(DISK_IMG) From 1bc87f8f034f187f3ce63d1c4100062b4de03588 Mon Sep 17 00:00:00 2001 From: Utkarsh Maheshwari Date: Thu, 30 May 2019 17:09:34 +0530 Subject: [PATCH 2/2] boot: Implement module parsing and finding kernel --- boot/boot.c | 38 ++++++++++++++++++++++++++++++++- boot/elf.c | 10 +++++++++ boot/gdt.asm | 28 +++++++++++++++++++++++++ boot/gdt.c | 45 ++++++++++++++++++++++++++++++++++++++++ boot/include/elf.h | 6 ++++++ boot/include/gdt.h | 34 ++++++++++++++++++++++++++++++ boot/include/multiboot.h | 14 ++++++++----- boot/include/string.h | 6 ++++++ boot/include/types.h | 11 ++++++++++ boot/string.c | 24 +++++++++++++++++++++ 10 files changed, 210 insertions(+), 6 deletions(-) create mode 100644 boot/elf.c create mode 100644 boot/gdt.asm create mode 100644 boot/gdt.c create mode 100644 boot/include/elf.h create mode 100644 boot/include/gdt.h create mode 100644 boot/include/string.h create mode 100644 boot/include/types.h create mode 100644 boot/string.c diff --git a/boot/boot.c b/boot/boot.c index 7241a0a..2d5b816 100644 --- a/boot/boot.c +++ b/boot/boot.c @@ -1,4 +1,19 @@ +#include #include +#include +#include + +void setup_longmode() +{ + // TODO(coditva): +} + +void jump_to_kernel(void *kernel_entry, multiboot_info_t *multiboot_info) +{ + // TODO(coditva): + (void)(kernel_entry); + (void)(multiboot_info); +} void lmain(multiboot_info_t *multiboot_info, uint32_t multiboot_magic) { @@ -6,7 +21,28 @@ void lmain(multiboot_info_t *multiboot_info, uint32_t multiboot_magic) return; } - (void)(multiboot_info); + gdt_init(); + + void *kernel_entry = 0x0; + char *kernel_mod_name = "kernel"; + + if (multiboot_info->flags & MULTIBOOT_FLAG_MODS) { + for (uint32_t i = 0; i < multiboot_info->mods_count; i++) { + + multiboot_mod_t *module = (multiboot_mod_t *) + (multiboot_info->mods_addr + (i * sizeof(multiboot_mod_t))); + + if (strcmp((char *)&module->string, kernel_mod_name) == 0) { + kernel_entry = elf_load((void *)(uintptr_t)module->mod_start, + (void *)(uintptr_t)module->mod_end); + (void)(kernel_entry); + + } + } + } + + setup_longmode(); + jump_to_kernel(kernel_entry, multiboot_info); while (1) { ; /* nop */ diff --git a/boot/elf.c b/boot/elf.c new file mode 100644 index 0000000..157bf2f --- /dev/null +++ b/boot/elf.c @@ -0,0 +1,10 @@ +#include + +void * elf_load(void *start_address, void *end_address) +{ + // TODO(coditva): + (void)(start_address); + (void)(end_address); + return 0x0; +} + diff --git a/boot/gdt.asm b/boot/gdt.asm new file mode 100644 index 0000000..12c9404 --- /dev/null +++ b/boot/gdt.asm @@ -0,0 +1,28 @@ +; vi:filetype=nasm + +gdtr dw 0 + dd 0 + +; TODO: Think about moving to "higher half kernel" + +global gdt_load +gdt_load: + mov eax, [esp + 4] ; load gdt address + mov [gdtr + 2], eax + mov ax, [esp + 8] ; load gdt size + mov [gdtr], ax + lgdt [gdtr] ; load idt + ret + +global reload_segments +reload_segments: + jmp 0x08:complete_reload_segments ; load 0x08 into code selector (CS) + +complete_reload_segments: + mov ax, 0x10 ; load 0x10 into data selector + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + ret diff --git a/boot/gdt.c b/boot/gdt.c new file mode 100644 index 0000000..1e02551 --- /dev/null +++ b/boot/gdt.c @@ -0,0 +1,45 @@ +#include + +gdt_entry_t gdt[GDT_SIZE]; +extern void gdt_load(gdt_entry_t *, uint16_t size); + +void gdt_set_entry(uint32_t offset, uint32_t base, uint32_t limit, + uint8_t access_byte) +{ + if (limit > 65536) { /* adjust granularity */ + limit = limit >> 12; + gdt[offset].flags_limit_1 = 0xc0; + } else { + gdt[offset].flags_limit_1 = 0x40; + } + + gdt[offset].base_0 = (uint16_t)base & 0xff; + gdt[offset].base_1 = (uint8_t)(base >> 16) & 0xff; + gdt[offset].base_2 = (uint8_t)(base >> 24) & 0xff; + + gdt[offset].limit_0 = (uint16_t)limit & 0xff; + gdt[offset].flags_limit_1 |= (uint16_t)(limit >> 16) & 0xf; + + gdt[offset].access_byte = access_byte; +} + +void gdt_init(void) +{ + /* first entry is NULL entry */ + gdt_set_entry(0, 0, 0, 0); + + /* TODO: Remove sepecial numbers from these statements */ + /* kernel code and data segments */ + gdt_set_entry(1, CODE_SEGMENT_OFFSET, CODE_SEGMENT_SIZE, 0x9a); + gdt_set_entry(2, DATA_SEGMENT_OFFSET, DATA_SEGMENT_SIZE, 0x92); + + /* user code and data segments */ + gdt_set_entry(3, CODE_SEGMENT_OFFSET, CODE_SEGMENT_SIZE, 0xfa); + gdt_set_entry(4, DATA_SEGMENT_OFFSET, DATA_SEGMENT_SIZE, 0xf2); + + /* TODO: Setup tss (what?) */ + /* TODO: Setup ldt? */ + + gdt_load(gdt, GDT_SIZE * sizeof(gdt_entry_t) - 1); + reload_segments(); +} diff --git a/boot/include/elf.h b/boot/include/elf.h new file mode 100644 index 0000000..f73e8ac --- /dev/null +++ b/boot/include/elf.h @@ -0,0 +1,6 @@ +#ifndef LOAD_ELF_H_O54VNAX7 +#define LOAD_ELF_H_O54VNAX7 + +void * elf_load(void *, void *); + +#endif /* end of include guard: LOAD_ELF_H_O54VNAX7 */ diff --git a/boot/include/gdt.h b/boot/include/gdt.h new file mode 100644 index 0000000..bfecf47 --- /dev/null +++ b/boot/include/gdt.h @@ -0,0 +1,34 @@ +#ifndef GDT_H_9RIWT3SN +#define GDT_H_9RIWT3SN + +#include + +/** + * The structure of the entries in the GDT. + */ +typedef struct _gdt_entry_t { + uint16_t limit_0; + uint16_t base_0; + uint8_t base_1; + uint8_t access_byte; + uint8_t flags_limit_1; + uint8_t base_2; +} __attribute__((packed)) gdt_entry_t; + +#define GDT_SIZE 3 + +typedef struct _gdt_ptr_t { + uint16_t limit; + uint32_t base; +} __attribute__((packed)) gdt_ptr_t; + +void gdt_init(void); +void reload_segments(void); + +/* Using flat setup. TODO: Separate code and data segments(?) */ +#define CODE_SEGMENT_OFFSET 0x0 +#define CODE_SEGMENT_SIZE 0xffffffff +#define DATA_SEGMENT_OFFSET 0x0 +#define DATA_SEGMENT_SIZE 0xffffffff + +#endif /* end of include guard: GDT_H_9RIWT3SN */ diff --git a/boot/include/multiboot.h b/boot/include/multiboot.h index 753c3c9..e5f5b40 100644 --- a/boot/include/multiboot.h +++ b/boot/include/multiboot.h @@ -1,11 +1,7 @@ #ifndef MULTIBOOT_H_RKNBOMGQ #define MULTIBOOT_H_RKNBOMGQ -typedef unsigned long uint32_t; -typedef unsigned int uint16_t; -typedef unsigned long long uint64_t; -typedef unsigned char uint8_t; - +#include /* magic numbers for multiboot. these help us verify that multiboot structure is * indeed valid. */ @@ -128,6 +124,14 @@ typedef struct _multiboot_memory_map_t { } __attribute__((packed)) multiboot_memory_map_t; +typedef struct _multiboot_mod_t { + uint16_t mod_start; + uint16_t mod_end; + uint16_t string; + uint16_t reserved; +} __attribute__((packed)) multiboot_mod_t; + + #define FOREACH_MEMORY_MAP(MMAP, INFO) \ for(multiboot_memory_map_t *(MMAP) = \ (multiboot_memory_map_t *)(uintptr_t)((INFO)->mmap_addr); \ diff --git a/boot/include/string.h b/boot/include/string.h new file mode 100644 index 0000000..bcdba87 --- /dev/null +++ b/boot/include/string.h @@ -0,0 +1,6 @@ +#ifndef STRING_H_UQGSNPBM +#define STRING_H_UQGSNPBM + +int strcmp(const char*, const char*); + +#endif /* end of include guard: STRING_H_UQGSNPBM */ diff --git a/boot/include/types.h b/boot/include/types.h new file mode 100644 index 0000000..49cccdd --- /dev/null +++ b/boot/include/types.h @@ -0,0 +1,11 @@ +#ifndef TYPES_H_AO8U0VTC +#define TYPES_H_AO8U0VTC + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef unsigned long long uint64_t; + +typedef uint32_t uintptr_t; + +#endif /* end of include guard: TYPES_H_AO8U0VTC */ diff --git a/boot/string.c b/boot/string.c new file mode 100644 index 0000000..4fad906 --- /dev/null +++ b/boot/string.c @@ -0,0 +1,24 @@ +#include + +int strcmp(const char* str1, const char* str2) +{ + int index = 0; + while (str1[index] != '\0' && str2[index] != '\0') { + if (str1[index] < str2[index]) { + return -1; + } + if (str1[index] > str2[index]) { + return 1; + } + index += 1; + } + + if (str1[index] != '\0') { + return -1; + } + if (str2[index] != '\0') { + return 1; + } + + return 0; +}