From b91de2f3746c427a7f18bc50de07e6568bbe722b Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 2 Mar 2024 16:30:50 +1300 Subject: [PATCH] update --- .gitmodules | 3 + GNUmakefile => Makefile | 4 +- kernel/{GNUmakefile => Makefile} | 16 +++- kernel/src/ctype.c | 5 + kernel/src/ctype.h | 6 ++ kernel/src/framebuffer.c | 18 ++++ kernel/src/framebuffer.h | 9 ++ kernel/src/hcf.asm | 7 ++ kernel/src/hcf.h | 6 ++ kernel/src/main.c | 156 +++++++++++++++---------------- kernel/src/memory.c | 35 +++++++ kernel/src/memory.h | 18 ++++ kernel/src/stdio.c | 73 +++++++++++++++ kernel/src/stdio.h | 8 ++ kernel/src/stdlib.c | 77 +++++++++++++++ kernel/src/stdlib.h | 9 ++ kernel/src/string.c | 8 ++ kernel/src/string.h | 8 ++ kernel/src/terminal.c | 11 +++ kernel/src/terminal.h | 7 ++ kernel/vendor/flanterm | 1 + limine.cfg | 10 +- 22 files changed, 403 insertions(+), 92 deletions(-) create mode 100644 .gitmodules rename GNUmakefile => Makefile (96%) rename kernel/{GNUmakefile => Makefile} (90%) create mode 100644 kernel/src/ctype.c create mode 100644 kernel/src/ctype.h create mode 100644 kernel/src/framebuffer.c create mode 100644 kernel/src/framebuffer.h create mode 100644 kernel/src/hcf.asm create mode 100644 kernel/src/hcf.h create mode 100644 kernel/src/memory.c create mode 100644 kernel/src/memory.h create mode 100644 kernel/src/stdio.c create mode 100644 kernel/src/stdio.h create mode 100644 kernel/src/stdlib.c create mode 100644 kernel/src/stdlib.h create mode 100644 kernel/src/string.c create mode 100644 kernel/src/string.h create mode 100644 kernel/src/terminal.c create mode 100644 kernel/src/terminal.h create mode 160000 kernel/vendor/flanterm diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9b0e69e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "kernel/vendor/flanterm"] + path = kernel/vendor/flanterm + url = https://github.com/mintsuki/flanterm diff --git a/GNUmakefile b/Makefile similarity index 96% rename from GNUmakefile rename to Makefile index 97807ab..3d316fd 100644 --- a/GNUmakefile +++ b/Makefile @@ -1,7 +1,7 @@ # Nuke built-in rules and variables. override MAKEFLAGS += -rR -override IMAGE_NAME := template +override IMAGE_NAME := radix # Convenience macro to reliably declare user overridable variables. define DEFAULT_VAR = @@ -33,7 +33,7 @@ all-hdd: $(IMAGE_NAME).hdd .PHONY: run run: $(IMAGE_NAME).iso - qemu-system-x86_64 -M q35 -m 2G -cdrom $(IMAGE_NAME).iso -boot d + qemu-system-x86_64 -m 1G -cdrom $(IMAGE_NAME).iso -enable-kvm -cpu host -boot d .PHONY: run-uefi run-uefi: ovmf $(IMAGE_NAME).iso diff --git a/kernel/GNUmakefile b/kernel/Makefile similarity index 90% rename from kernel/GNUmakefile rename to kernel/Makefile index 0d6004a..f08e9d7 100644 --- a/kernel/GNUmakefile +++ b/kernel/Makefile @@ -44,6 +44,7 @@ $(eval $(call DEFAULT_VAR,LDFLAGS,$(DEFAULT_LDFLAGS))) # Internal C flags that should not be changed by the user. override CFLAGS += \ -Wall \ + -Werror \ -Wextra \ -std=gnu11 \ -ffreestanding \ @@ -62,6 +63,7 @@ override CFLAGS += \ # Internal C preprocessor flags that should not be changed by the user. override CPPFLAGS := \ -I src \ + -I vendor \ $(CPPFLAGS) \ -MMD \ -MP @@ -84,7 +86,7 @@ override NASMFLAGS += \ # Use "find" to glob all *.c, *.S, and *.asm files in the tree and obtain the # object and header dependency file names. -override CFILES := $(shell cd src && find -L * -type f -name '*.c') +override CFILES := $(shell cd src && find -L * -type f -name '*.c') $(shell cd vendor && find -L * -type f -name '*.c') override ASFILES := $(shell cd src && find -L * -type f -name '*.S') override NASMFILES := $(shell cd src && find -L * -type f -name '*.asm') override OBJ := $(addprefix obj/,$(CFILES:.c=.c.o) $(ASFILES:.S=.S.o) $(NASMFILES:.asm=.asm.o)) @@ -98,7 +100,7 @@ src/limine.h: curl -Lo $@ https://github.com/limine-bootloader/limine/raw/trunk/limine.h # Link rules for the final kernel executable. -bin/$(KERNEL): GNUmakefile linker.ld $(OBJ) +bin/$(KERNEL): Makefile linker.ld $(OBJ) mkdir -p "$$(dirname $@)" $(LD) $(OBJ) $(LDFLAGS) -o $@ @@ -106,17 +108,21 @@ bin/$(KERNEL): GNUmakefile linker.ld $(OBJ) -include $(HEADER_DEPS) # Compilation rules for *.c files. -obj/%.c.o: src/%.c GNUmakefile src/limine.h +obj/%.c.o: src/%.c Makefile src/limine.h + mkdir -p "$$(dirname $@)" + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +obj/%.c.o: vendor/%.c Makefile src/limine.h mkdir -p "$$(dirname $@)" $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ # Compilation rules for *.S files. -obj/%.S.o: src/%.S GNUmakefile +obj/%.S.o: src/%.S Makefile mkdir -p "$$(dirname $@)" $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ # Compilation rules for *.asm (nasm) files. -obj/%.asm.o: src/%.asm GNUmakefile +obj/%.asm.o: src/%.asm Makefile mkdir -p "$$(dirname $@)" nasm $(NASMFLAGS) $< -o $@ diff --git a/kernel/src/ctype.c b/kernel/src/ctype.c new file mode 100644 index 0000000..6a3efa7 --- /dev/null +++ b/kernel/src/ctype.c @@ -0,0 +1,5 @@ +#include + +int isdigit(char c) { + return c >= '0' && c <= '9'; +} diff --git a/kernel/src/ctype.h b/kernel/src/ctype.h new file mode 100644 index 0000000..6003680 --- /dev/null +++ b/kernel/src/ctype.h @@ -0,0 +1,6 @@ +#ifndef __CTYPE_H__ +#define __CTYPE_H__ + +int isdigit(char c); + +#endif diff --git a/kernel/src/framebuffer.c b/kernel/src/framebuffer.c new file mode 100644 index 0000000..57a478a --- /dev/null +++ b/kernel/src/framebuffer.c @@ -0,0 +1,18 @@ +#include +#include +#include + +struct limine_framebuffer_request framebuffer_request = { + .id = LIMINE_FRAMEBUFFER_REQUEST, + .revision = 0 +}; + +struct limine_framebuffer* framebuffer = { 0 }; + +void fb_init() { + if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) { + hcf(); + } + + framebuffer = framebuffer_request.response->framebuffers[0]; +} diff --git a/kernel/src/framebuffer.h b/kernel/src/framebuffer.h new file mode 100644 index 0000000..3b974c3 --- /dev/null +++ b/kernel/src/framebuffer.h @@ -0,0 +1,9 @@ +#ifndef __FRAMEBUFFER_H__ +#define __FRAMEBUFFER_H__ + +#include + +extern struct limine_framebuffer* framebuffer; +void fb_init(); + +#endif diff --git a/kernel/src/hcf.asm b/kernel/src/hcf.asm new file mode 100644 index 0000000..0c09ada --- /dev/null +++ b/kernel/src/hcf.asm @@ -0,0 +1,7 @@ +global hcf + +hcf: + cli +loop: + hlt + jmp loop diff --git a/kernel/src/hcf.h b/kernel/src/hcf.h new file mode 100644 index 0000000..7eeab97 --- /dev/null +++ b/kernel/src/hcf.h @@ -0,0 +1,6 @@ +#ifndef __HCF_H__ +#define __HCF_H__ + +extern void hcf(); + +#endif diff --git a/kernel/src/main.c b/kernel/src/main.c index 5130e2b..2c6b325 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -1,112 +1,108 @@ #include #include #include +#include +#include +#include #include - -// Set the base revision to 1, this is recommended as this is the latest -// base revision described by the Limine boot protocol specification. -// See specification for further info. +#include +#include LIMINE_BASE_REVISION(1) -// The Limine requests can be placed anywhere, but it is important that -// the compiler does not optimise them away, so, in C, they should -// NOT be made "static". - -struct limine_framebuffer_request framebuffer_request = { - .id = LIMINE_FRAMEBUFFER_REQUEST, - .revision = 0 +struct limine_memmap_request memmap_request = { + .id = LIMINE_MEMMAP_REQUEST, + .revision = 0 }; -// GCC and Clang reserve the right to generate calls to the following -// 4 functions even if they are not directly called. -// Implement them as the C specification mandates. -// DO NOT remove or rename these functions, or stuff will eventually break! -// They CAN be moved to a different .c file. +void* memcpy(void* dest, const void* src, size_t n) { + uint8_t* pdest = (uint8_t*)dest; + const uint8_t* psrc = (const uint8_t*)src; -void *memcpy(void *dest, const void *src, size_t n) { - uint8_t *pdest = (uint8_t *)dest; - const uint8_t *psrc = (const uint8_t *)src; + for(size_t i = 0; i < n; i++) { + pdest[i] = psrc[i]; + } - for (size_t i = 0; i < n; i++) { - pdest[i] = psrc[i]; - } - - return dest; + return dest; } -void *memset(void *s, int c, size_t n) { - uint8_t *p = (uint8_t *)s; +void* memset(void* s, int c, size_t n) { + uint8_t* p = (uint8_t*)s; - for (size_t i = 0; i < n; i++) { - p[i] = (uint8_t)c; - } + for(size_t i = 0; i < n; i++) { + p[i] = (uint8_t)c; + } - return s; + return s; } -void *memmove(void *dest, const void *src, size_t n) { - uint8_t *pdest = (uint8_t *)dest; - const uint8_t *psrc = (const uint8_t *)src; +void* memmove(void* dest, const void* src, size_t n) { + uint8_t* pdest = (uint8_t*)dest; + const uint8_t* psrc = (const uint8_t*)src; - if (src > dest) { - for (size_t i = 0; i < n; i++) { - pdest[i] = psrc[i]; - } - } else if (src < dest) { - for (size_t i = n; i > 0; i--) { - pdest[i-1] = psrc[i-1]; - } - } + if(src > dest) { + for(size_t i = 0; i < n; i++) { + pdest[i] = psrc[i]; + } + } else if(src < dest) { + for(size_t i = n; i > 0; i--) { + pdest[i-1] = psrc[i-1]; + } + } - return dest; + return dest; } -int memcmp(const void *s1, const void *s2, size_t n) { - const uint8_t *p1 = (const uint8_t *)s1; - const uint8_t *p2 = (const uint8_t *)s2; +int memcmp(const void* s1, const void* s2, size_t n) { + const uint8_t* p1 = (const uint8_t*)s1; + const uint8_t* p2 = (const uint8_t*)s2; - for (size_t i = 0; i < n; i++) { - if (p1[i] != p2[i]) { - return p1[i] < p2[i] ? -1 : 1; - } - } + for(size_t i = 0; i < n; i++) { + if(p1[i] != p2[i]) { + return p1[i] < p2[i] ? -1 : 1; + } + } - return 0; + return 0; } -// Halt and catch fire function. -static void hcf(void) { - asm ("cli"); - for (;;) { - asm ("hlt"); - } -} +const char* types[] = { + "USABLE", + "RESERVED", + "ACPI_RECLAIMABLE", + "ACPI_NVS", + "BAD_MEMORY", + "BOOTLOADER_RECLAIMABLE", + "KERNEL_AND_MODULES", + "FRAMEBUFFER" +}; -// The following will be our kernel's entry point. -// If renaming _start() to something else, make sure to change the -// linker script accordingly. void _start(void) { - // Ensure the bootloader actually understands our base revision (see spec). - if (LIMINE_BASE_REVISION_SUPPORTED == false) { - hcf(); - } + if(LIMINE_BASE_REVISION_SUPPORTED == false) { + hcf(); + } + + fb_init(); + term_init(); + mem_init(); - // Ensure we got a framebuffer. - if (framebuffer_request.response == NULL - || framebuffer_request.response->framebuffer_count < 1) { - hcf(); - } + printf("running at %dx%d\n", framebuffer->width, framebuffer->height); - // Fetch the first framebuffer. - struct limine_framebuffer *framebuffer = framebuffer_request.response->framebuffers[0]; + struct limine_memmap_response* memmap = memmap_request.response; - // Note: we assume the framebuffer model is RGB with 32-bit pixels. - for (size_t i = 0; i < 100; i++) { - volatile uint32_t *fb_ptr = framebuffer->address; - fb_ptr[i * (framebuffer->pitch / 4) + i] = 0xffffff; - } + printf("%d memmap entries present.\n", memmap->entry_count); - // We're done, just hang... - hcf(); + for(uint64_t i = 0; i < memmap->entry_count; i++) { + struct limine_memmap_entry* entry = memmap->entries[i]; + if(entry->type == LIMINE_MEMMAP_USABLE) + mem_add(entry->base, entry->length); + + printf("0x%010x - 0x%010x (type: % 22s, size: % 10u)\n", + entry->base, entry->base + entry->length, types[entry->type], entry->length); + } + + void* a = mem_alloc(10); + printf("memory allocated at %x", a); + + hcf(); } diff --git a/kernel/src/memory.c b/kernel/src/memory.c new file mode 100644 index 0000000..765587d --- /dev/null +++ b/kernel/src/memory.c @@ -0,0 +1,35 @@ +#include + +void* mem_start; +void* mem_ptr; +int blocks = 0; + +struct limine_kernel_address_request kernel_address_request = { + .id = LIMINE_KERNEL_ADDRESS_REQUEST, + .revision = 0 +}; + +struct limine_kernel_address_response* kernel_address = { 0 }; + +void mem_init() { + kernel_address = kernel_address_request.response; +} + +void mem_add(uint64_t base, uint64_t len) { + if(!mem_start) { + mem_start = mem_ptr = (void*)kernel_address->virtual_base + base; + *((struct mem_desc*)mem_start) = (struct mem_desc) { + .base = base, + .len = len + }; + mem_ptr += sizeof(struct mem_desc); + blocks++; + } +} + +void* mem_alloc(size_t sz) { + void* start = mem_ptr; + *((size_t*)start) = sz; + mem_ptr += sz + sizeof(size_t); + return start + sizeof(size_t); +} diff --git a/kernel/src/memory.h b/kernel/src/memory.h new file mode 100644 index 0000000..8ac6450 --- /dev/null +++ b/kernel/src/memory.h @@ -0,0 +1,18 @@ +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +#include +#include + +void mem_init(); +void mem_add(uint64_t base, uint64_t len); +void* mem_alloc(size_t sz); + +struct mem_desc { + uint64_t base; + uint64_t len; +}; + +extern struct limine_kernel_address_response* kernel_address; + +#endif diff --git a/kernel/src/stdio.c b/kernel/src/stdio.c new file mode 100644 index 0000000..6a44ddc --- /dev/null +++ b/kernel/src/stdio.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include + +void putc(char ch) { + flanterm_write(ft_ctx, &ch, 1); +} + +void puts(const char* str) { + flanterm_write(ft_ctx, str, strlen(str)); +} + +void printf(const char *str, ...) { + va_list list; + va_start(list, str); + + char buf[128]; + + for(int i = 0; str[i] != '\0'; i++) + { + switch(str[i]) + { + case '%': + i++; + + size_t width = 0; + char padding_char = str[i]; + if(isdigit(str[i]) || str[i] == ' ') { + i++; + int pos = 0; + while(isdigit(str[i])) { + buf[pos++] = str[i++]; + } + buf[pos] = '\0'; + width = atoi(buf); + } + + const char* out = 0; + + if(str[i] == 's') + out = va_arg(list, const char*); + if(str[i] == 'd') + out = itoa(va_arg(list, int), buf, 10); + if(str[i] == 'u') + out = ultoa(va_arg(list, uint64_t), buf, 10); + if(str[i] == 'x') + out = ultoa(va_arg(list, uint64_t), buf, 16); + if(str[i] == 'c') + putc(va_arg(list, int)); + + size_t len = strlen(out); + if(width > len) { + char padding[256]; + size_t j = 0; + for(; j < width - len; j++) + padding[j] = padding_char; + padding[j] = '\0'; + puts(padding); + } + + puts(out); + break; + default: + putc(str[i]); + break; + } + } + + va_end(list); +} diff --git a/kernel/src/stdio.h b/kernel/src/stdio.h new file mode 100644 index 0000000..20a2271 --- /dev/null +++ b/kernel/src/stdio.h @@ -0,0 +1,8 @@ +#ifndef __STDIO_H__ +#define __STDIO_H__ + +void putc(char ch); +void puts(const char* str); +void printf(const char *str, ...); + +#endif diff --git a/kernel/src/stdlib.c b/kernel/src/stdlib.c new file mode 100644 index 0000000..1da8ad2 --- /dev/null +++ b/kernel/src/stdlib.c @@ -0,0 +1,77 @@ +#include +#include + +const char* itoa(int value, char* str, int base) +{ + char* rc; + char* ptr; + char* low; + + if (base < 2 || base > 36) + { + *str = '\0'; + return str; + } + rc = ptr = str; + if (value < 0 && base == 10) + { + *ptr++ = '-'; + } + + low = ptr; + do + { + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + value % base]; + value /= base; + } while (value); + + *ptr-- = '\0'; + while (low < ptr) + { + char tmp = *low; + *low++ = *ptr; + *ptr-- = tmp; + } + return rc; +} + +const char* ultoa(uint64_t value, char* str, int base) +{ + char* rc; + char* ptr; + char* low; + + if (base < 2 || base > 36) + { + *str = '\0'; + return str; + } + rc = ptr = str; + + low = ptr; + do + { + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + value % base]; + value /= base; + } while (value); + + *ptr-- = '\0'; + while (low < ptr) + { + char tmp = *low; + *low++ = *ptr; + *ptr-- = tmp; + } + return rc; +} + +int atoi(const char* str) { + int value = 0; + while(isdigit(*str)) { + value *= 10; + value += (*str)-'0'; + str++; + } + + return value; +} diff --git a/kernel/src/stdlib.h b/kernel/src/stdlib.h new file mode 100644 index 0000000..fb566ab --- /dev/null +++ b/kernel/src/stdlib.h @@ -0,0 +1,9 @@ +#ifndef __STDLIB_H__ +#define __STDLIB_H__ +#include + +const char* itoa(int value, char* str, int base); +const char* ultoa(uint64_t value, char* str, int base); +int atoi(const char* str); + +#endif diff --git a/kernel/src/string.c b/kernel/src/string.c new file mode 100644 index 0000000..8ac0dbe --- /dev/null +++ b/kernel/src/string.c @@ -0,0 +1,8 @@ +#include + +size_t strlen(const char* str) { + size_t len = 0; + while (str[len]) + len++; + return len; +} diff --git a/kernel/src/string.h b/kernel/src/string.h new file mode 100644 index 0000000..052baf2 --- /dev/null +++ b/kernel/src/string.h @@ -0,0 +1,8 @@ +#ifndef __STRING_H__ +#define __STRING_H__ + +#include + +size_t strlen(const char* str); + +#endif diff --git a/kernel/src/terminal.c b/kernel/src/terminal.c new file mode 100644 index 0000000..9b49fc8 --- /dev/null +++ b/kernel/src/terminal.c @@ -0,0 +1,11 @@ +#include +#include +#include + +struct flanterm_context* ft_ctx = { 0 }; + +void term_init() { + ft_ctx = flanterm_fb_simple_init( + framebuffer->address, framebuffer->width, framebuffer->height, framebuffer->pitch + ); +} diff --git a/kernel/src/terminal.h b/kernel/src/terminal.h new file mode 100644 index 0000000..de3f3e3 --- /dev/null +++ b/kernel/src/terminal.h @@ -0,0 +1,7 @@ +#ifndef __TERMINAL_H__ +#define __TERMINAL_H__ + +void term_init(); +extern struct flanterm_context* ft_ctx; + +#endif diff --git a/kernel/vendor/flanterm b/kernel/vendor/flanterm new file mode 160000 index 0000000..545ab1f --- /dev/null +++ b/kernel/vendor/flanterm @@ -0,0 +1 @@ +Subproject commit 545ab1faa8ba7493ae7a43064d520e402ad308b5 diff --git a/limine.cfg b/limine.cfg index 8557be3..10d0624 100644 --- a/limine.cfg +++ b/limine.cfg @@ -1,16 +1,16 @@ # Timeout in seconds that Limine will use before automatically booting. -TIMEOUT=3 +TIMEOUT=0 # The entry name that will be displayed in the boot menu. -:Limine Template (KASLR on) +#:Limine Template (KASLR on) # We use the Limine boot protocol. - PROTOCOL=limine +# PROTOCOL=limine # Path to the kernel to boot. boot:/// represents the partition on which limine.cfg is located. - KERNEL_PATH=boot:///kernel +# KERNEL_PATH=boot:///kernel # Same thing, but without KASLR. -:Limine Template (KASLR off) +:radix PROTOCOL=limine # Disable KASLR (it is enabled by default for relocatable kernels)