diff options
| -rw-r--r-- | .gitignore | 4 | ||||
| m--------- | limine | 0 | ||||
| -rw-r--r-- | limine.conf | 6 | ||||
| -rw-r--r-- | linker.ld | 68 | ||||
| -rw-r--r-- | makefile | 85 | ||||
| -rw-r--r-- | source/LimineRequests.c | 45 | ||||
| -rw-r--r-- | source/LimineRequests.h | 15 | ||||
| -rw-r--r-- | source/main.c | 51 | ||||
| -rw-r--r-- | source/memory.c | 48 | ||||
| -rw-r--r-- | source/memory.h | 12 |
10 files changed, 334 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..05df4a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +bin +image.iso +iso_root +objects diff --git a/limine b/limine new file mode 160000 +Subproject 7d2bf778c27067ba421e95154208c8b0f3bbf10 diff --git a/limine.conf b/limine.conf new file mode 100644 index 0000000..816d479 --- /dev/null +++ b/limine.conf @@ -0,0 +1,6 @@ +timeout: 5 + +/kernel.bin + protocol: limine + path: boot():/boot/kernel.bin + diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..3b35556 --- /dev/null +++ b/linker.ld @@ -0,0 +1,68 @@ +/* Tell the linker that we want an x86_64 ELF64 output file */ +OUTPUT_FORMAT(elf64-x86-64) + +/* We want the symbol kmain to be our entry point */ +ENTRY(KernelMain) + +/* Define the program headers we want so the bootloader gives us the right */ +/* MMU permissions; this also allows us to exert more control over the linking */ +/* process. */ +PHDRS +{ + limine_requests PT_LOAD; + text PT_LOAD; + rodata PT_LOAD; + data PT_LOAD; +} + +SECTIONS +{ + /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ + /* and because that is what the Limine spec mandates. */ + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ + /* that is the beginning of the region. */ + . = 0xffffffff80000000; + + /* Define a section to contain the Limine requests and assign it to its own PHDR */ + .limine_requests : { + KEEP(*(.limine_requests_start)) + KEEP(*(.limine_requests)) + KEEP(*(.limine_requests_end)) + } :limine_requests + + /* Move to the next memory page for .text */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .text : { + *(.text .text.*) + } :text + + /* Move to the next memory page for .rodata */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .rodata : { + *(.rodata .rodata.*) + } :rodata + + /* Move to the next memory page for .data */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .data : { + *(.data .data.*) + } :data + + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ + /* unnecessary zeros will be written to the binary. */ + /* If you need, for example, .init_array and .fini_array, those should be placed */ + /* above this. */ + .bss : { + *(.bss .bss.*) + *(COMMON) + } :data + + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ + /DISCARD/ : { + *(.eh_frame*) + *(.note .note.*) + } +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..fef52a2 --- /dev/null +++ b/makefile @@ -0,0 +1,85 @@ +BIN_DIR = bin +BIN = $(BIN_DIR)/kernel.bin +ISO = image.iso +ISO_ROOT = iso_root +SRC_DIR = source +SOURCES = $(SRC_DIR)/main.c \ + $(SRC_DIR)/LimineRequests.c \ + $(SRC_DIR)/memory.c +CFILES = $(filter %.c,$(SOURCES)) +ASFILES = $(filter %.S,$(SOURCES)) +NASMFILES = $(filter %.asm,$(SOURCES)) +OBJ_DIR = objects +OBJECTS = $(addprefix $(OBJ_DIR)/,$(notdir $(CFILES:.c=.c.o)) \ + $(notdir $(ASFILES:.S=.S.o)) \ + $(notdir $(NASMFILES:.asm=.asm.o))) +CC = gcc +CFLAGS = -Wall \ + -Wextra \ + -Werror \ + -Wpedantic \ + -std=gnu23 \ + -ffreestanding \ + -fno-stack-protector \ + -fno-stack-check \ + -fno-PIC \ + -m64 \ + -march=x86-64 \ + -mno-80387 \ + -mno-mmx \ + -mno-sse \ + -mno-sse2 \ + -mno-red-zone \ + -I src \ + -DLIMINE_API_REVISION=3 \ + -MMD \ + -MP \ + -mcmodel=kernel +LDFLAGS = -Wl,-m,elf_x86_64 \ + -Wl,--build-id=none \ + -nostdlib \ + -static \ + -z max-page-size=0x1000 \ + -T linker.ld +NASMFLAGS = -Wall -f elf64 + +.PHONY: all clean run +all: $(ISO) + + +$(BIN_DIR) $(OBJ_DIR) $(ISO_ROOT): + mkdir $@ + +$(BIN): linker.ld $(OBJECTS) | $(BIN_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJECTS) -o $@ + +$(OBJ_DIR)/%.c.o: $(SRC_DIR)/%.c | $(OBJ_DIR) + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +$(OBJ_DIR)/%.S.o: $(SRC_DIR)/%.S | $(OBJ_DIR) + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +$(OBJ_DIR)/%.asm.o: $(SRC_DIR)/%.asm | $(OBJ_DIR) + nasm $(NASMFLAGS) $< -o $@ + +$(ISO): $(BIN) | $(ISO_ROOT) + mkdir -p $(ISO_ROOT)/boot/limine + cp -v $(BIN) $(ISO_ROOT)/boot/ + cp -v limine.conf limine/limine-bios.sys limine/limine-bios-cd.bin \ + limine/limine-uefi-cd.bin $(ISO_ROOT)/boot/limine/ + mkdir -p iso_root/EFI/BOOT + cp -v limine/BOOTX64.EFI iso_root/EFI/BOOT/ + cp -v limine/BOOTIA32.EFI iso_root/EFI/BOOT/ + xorriso -as mkisofs -R -r -J -b boot/limine/limine-bios-cd.bin \ + -no-emul-boot -boot-load-size 4 -boot-info-table -hfsplus \ + -apm-block-size 2048 --efi-boot boot/limine/limine-uefi-cd.bin \ + -efi-boot-part --efi-boot-image --protective-msdos-label \ + iso_root -o $@ + ./limine/limine bios-install $@ + +run: $(ISO) + qemu-system-x86_64 -hda $(ISO) + +clean: + rm -rf $(BIN_DIR) $(OBJ_DIR) $(ISO) $(ISO_ROOT) + diff --git a/source/LimineRequests.c b/source/LimineRequests.c new file mode 100644 index 0000000..a3b9bd5 --- /dev/null +++ b/source/LimineRequests.c @@ -0,0 +1,45 @@ +#include <stdint.h> +#include <limine.h> +#include "LimineRequests.h" + +__attribute__((used, section(".limine_requests_start"))) +LIMINE_REQUESTS_START_MARKER + +__attribute__((used, section(".limine_requests"))) +static volatile LIMINE_BASE_REVISION(3) + +bool VerifyBaseRevision(void) { + return (limine_base_revision[2] == 0); +} + +__attribute__((used, section(".limine_requests"))) +struct limine_stack_size_request stackSizeRequest = { + LIMINE_STACK_SIZE_REQUEST, + 0, + nullptr, + //0xFFFF + 0x100000 +}; + +bool VerifyStackSizeRequest(void) { + return ((stackSizeRequest.response != nullptr) && + (stackSizeRequest.response->revision >= stackSizeRequest.revision)); +} + +__attribute__((used, section(".limine_requests"))) +struct limine_framebuffer_request framebufferRequest = { + LIMINE_FRAMEBUFFER_REQUEST, + 0, + nullptr +}; + +bool VerifyFramebufferRequest(void) { + return ((framebufferRequest.response != nullptr) && + (framebufferRequest.response->framebuffer_count > 0) && + (framebufferRequest.response->revision >= + framebufferRequest.revision)); +} + +__attribute__((used, section(".limine_requests_end"))) +LIMINE_REQUESTS_END_MARKER + diff --git a/source/LimineRequests.h b/source/LimineRequests.h new file mode 100644 index 0000000..45da613 --- /dev/null +++ b/source/LimineRequests.h @@ -0,0 +1,15 @@ +#ifndef LIMINEREQUESTS_H_ +#define LIMINEREQUESTS_H_ + +#include <stdint.h> +#include <limine.h> + +extern struct limine_stack_size_request stackSizeRequest; +extern struct limine_framebuffer_request framebufferRequest; + +bool VerifyBaseRevision(void); +bool VerifyStackSizeRequest(void); +bool VerifyFramebufferRequest(void); + +#endif // LIMINEREQUESTS_H_ + diff --git a/source/main.c b/source/main.c new file mode 100644 index 0000000..316274f --- /dev/null +++ b/source/main.c @@ -0,0 +1,51 @@ +#include <stddef.h> +#include <limine.h> +#include "LimineRequests.h" +#include "memory.h" + +static void HaltForever(void) { + while (true) { + asm("hlt"); + } +} + +void KernelMain(void) { + if (!VerifyBaseRevision()) { + HaltForever(); + } + + if (!VerifyStackSizeRequest()) { + HaltForever(); + } + + if (!VerifyFramebufferRequest()) { + HaltForever(); + } + + const uint64_t framebufferCount = + framebufferRequest.response->framebuffer_count; + + struct limine_framebuffer **framebuffers = + framebufferRequest.response->framebuffers; + + struct limine_framebuffer *framebuffer = nullptr; + + const uint32_t colors[] = {0xFF0000, 0x00FF00, 0x0000FF}; + uint8_t count = 0; + uint8_t color = 0; + + for (uint64_t i = 0; i < framebufferCount; i++) { + framebuffer = framebuffers[i]; + volatile uint32_t *fb_ptr = (volatile uint32_t *)framebuffer->address; + for (uint64_t j = 0; j < framebuffer->height && j < framebuffer->width; + j++) { + fb_ptr[j * (framebuffer->pitch / 4) + j] = colors[color]; + if ((count = (count + 1) % 16) == 0) { + color = (color + 1) % 3; + } + } + } + + HaltForever(); +} + diff --git a/source/memory.c b/source/memory.c new file mode 100644 index 0000000..b9d0405 --- /dev/null +++ b/source/memory.c @@ -0,0 +1,48 @@ +#include <stdint.h> +#include "memory.h" + +void *memcpy(void *dest, const void *src, const size_t n) { + uint8_t *destB = (void *)dest; + const uint8_t *srcB = (void *)src; + + for (size_t i = 0; i < n; i++) { + destB[i] = srcB[i]; + } + + return dest; +} + +void *memset(void *s, int c, size_t n) { + uint8_t *sB = (uint8_t *)s; + + for (size_t i = 0; i < n; i++) { + sB[i] = (uint8_t)c; + } + + return s; +} + +void *memmove(void *dest, const void *src, const size_t n) { + uint8_t *db = (uint8_t *)dest; + const uint8_t *sb = (const uint8_t *)src; + + for (size_t i = n; i > 0; i--) { + db[i - 1] = sb[i - 1]; + } + + return dest; +} + +int memcmp(const void *s1, const void *s2, const size_t n) { + const uint8_t *s1b = (const uint8_t *)s1; + const uint8_t *s2b = (const uint8_t *)s2; + + for (size_t i = 0; i < n; i++) { + if (s1b[i] != s2b[i]) { + return ((s1b[i] > s2b[i]) ? 1 : -1); + } + } + + return 0; +} + diff --git a/source/memory.h b/source/memory.h new file mode 100644 index 0000000..0404144 --- /dev/null +++ b/source/memory.h @@ -0,0 +1,12 @@ +#ifndef MEMORY_H_ +#define MEMORY_H_ + +#include <stddef.h> + +void *memcpy(void *dest, const void *src, const size_t n); +void *memset(void *s, int c, size_t n); +void *memmove(void *dest, const void *src, const size_t n); +int memcmp(const void *s1, const void *s2, const size_t n); + +#endif // MEMORY_H_ + |
