summaryrefslogtreecommitdiff
path: root/kernel/common
diff options
context:
space:
mode:
authorNathan Lee <me@nwlee.tech>2026-08-12 17:44:17 -0500
committerNathan Lee <me@nwlee.tech>2026-08-12 17:44:17 -0500
commit2c0efd93530c472e96ff3529aee983b53f3b78d9 (patch)
treecc36e7334e162ba67df79333e267ac93b4d984b9 /kernel/common
parent640a81b3ee366c651286efd1b80b37992cd53282 (diff)
rework project structure
Diffstat (limited to 'kernel/common')
-rw-r--r--kernel/common/bump.c54
-rw-r--r--kernel/common/cpio.c71
-rw-r--r--kernel/common/dtb.c84
-rw-r--r--kernel/common/elf.c40
-rw-r--r--kernel/common/log.c109
-rw-r--r--kernel/common/mem.c116
6 files changed, 474 insertions, 0 deletions
diff --git a/kernel/common/bump.c b/kernel/common/bump.c
new file mode 100644
index 0000000..1e07837
--- /dev/null
+++ b/kernel/common/bump.c
@@ -0,0 +1,54 @@
+#include <early/bump.h>
+#include <sys/log.h>
+#include <sys/mem.h>
+
+static char eheap[EHEAP_SIZE] = {0};
+static size_t eheap_off = 0;
+
+struct mem_info *km_find_memory(struct dt_node *head) {
+ struct dt_node *child = head->children;
+ while (child) {
+ struct mem_info *location = km_find_memory(child);
+ if (location) {
+ return location;
+ } else {
+ child = child->next;
+ }
+ }
+
+ if (strlen(head->name) != 0) {
+ struct dt_prop *prop_head = head->props;
+ while (prop_head) {
+ if (strcmp(prop_head->name, "device_type") == 0
+ && strcmp(prop_head->value, "memory") == 0) {
+ size_t len = 0;
+ uint32_t *reg = (uint32_t *)dt_get_prop(head, "reg", &len);
+ if (reg && len >= 8) {
+ uint32_t base = btohi(reg[0]);
+ uint32_t size = btohi(reg[1]);
+ struct mem_info *ret = kemalloc(sizeof(struct mem_info));
+ ret->start = (void*)base;
+ ret->size = (size_t)size;
+
+ return ret;
+ }
+ }
+ prop_head = prop_head->next;
+ }
+ }
+ return NULL;
+}
+
+
+void* kemalloc(size_t size) {
+ size = (size + 7) & ~7;
+
+ if (eheap_off + size > EHEAP_SIZE) {
+ return NULL;
+ }
+
+ void *ptr = &eheap[eheap_off];
+ eheap_off += size;
+ return ptr;
+}
+
diff --git a/kernel/common/cpio.c b/kernel/common/cpio.c
new file mode 100644
index 0000000..c8f7850
--- /dev/null
+++ b/kernel/common/cpio.c
@@ -0,0 +1,71 @@
+#include <sys/cpio.h>
+#include <sys/log.h>
+
+static uint32_t parse_hex(const char *p)
+{
+ uint32_t value = 0;
+
+ for (int i = 0; i < 8; i++) {
+ char c = p[i];
+ value <<= 4;
+
+ if (c >= '0' && c <= '9')
+ value |= c - '0';
+ else if (c >= 'A' && c <= 'F')
+ value |= c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ value |= c - 'a' + 10;
+ }
+ return value;
+}
+
+static size_t align4(size_t x)
+{
+ return (x + 3) & ~3;
+}
+
+void *cpio_get_file(void *archive, size_t size, const char *filename) {
+ const uint8_t *p = (uint8_t *)archive;
+ const uint8_t *end = archive + size;
+
+ while (p + CPIO_HEADER_LEN <= end) {
+ const struct cpio_newc_hdr *hdr =
+ (const struct cpio_newc_hdr *)p;
+
+ if (memcmp(hdr->magic, "070701", 6) &&
+ memcmp(hdr->magic, "070702", 6)) {
+ printk("Error parsing cpio: bad magic number!\n");
+ return NULL;
+ }
+
+ uint32_t namesize = parse_hex(hdr->namesize);
+ uint32_t filesize = parse_hex(hdr->filesize);
+
+ p += CPIO_HEADER_LEN;
+
+ if (p + namesize > end) {
+ printk("Error parsing cpio: truncated filename\n");
+ return NULL;
+ }
+
+ const char *name = (const char *)p;
+
+ if (strcmp(name, "TRAILER!!!") == 0)
+ return 0;
+
+ p += align4(namesize);
+
+ if (p + filesize > end) {
+ printk("Error parsing cpio: truncated file\n");
+ return NULL;
+ }
+
+ if (strcmp(name, filename) == 0) {
+ return (void*)p;
+ }
+
+ p += align4(filesize);
+ }
+ return NULL;
+}
+
diff --git a/kernel/common/dtb.c b/kernel/common/dtb.c
new file mode 100644
index 0000000..b345db0
--- /dev/null
+++ b/kernel/common/dtb.c
@@ -0,0 +1,84 @@
+#include <early/dtb.h>
+#include <early/bump.h>
+
+struct dt_node *dt_parse(void *fdt) {
+ struct fdt_header *hdr = fdt;
+
+ if (hdr->magic != FDT_MAGIC) {
+ return NULL;
+ }
+
+ uint32_t *p = (uint32_t *)(fdt + btohi(hdr->off_dt_struct));
+ char *strings = fdt + btohi(hdr->off_dt_strings);
+
+ struct dt_node *root = NULL;
+ struct dt_node *stack[DTB_MAX_NODES];
+ int sp = 0;
+
+ while (1) {
+ uint32_t token = btohi(*p++);
+ switch (token) {
+ case FDT_BEGIN_NODE: {
+ char *name = (char *)p;
+ p += (strlen(name) + 3) / 4;
+
+ struct dt_node *node = dt_node_alloc(name);
+ if (sp == 0) {
+ root = node;
+ } else {
+ node->next = stack[sp-1]->children;
+ stack[sp-1]->children = node;
+ }
+ stack[sp++] = node;
+ break;
+ }
+ case FDT_PROP: {
+ uint32_t len = btohi(*p++);
+ uint32_t nameoff = btohi(*p++);
+ void *value = p;
+ p += (len + 3) / 4;
+
+ struct dt_prop *prop = dt_prop_alloc(strings + nameoff, value, len);
+ prop->next = stack[sp-1]->props;
+ stack[sp-1]->props = prop;
+ break;
+ }
+ case FDT_END_NODE:
+ sp--;
+ break;
+ case FDT_END:
+ return root;
+ }
+ }
+}
+
+void *dt_get_prop(struct dt_node *node, char *name, size_t *len) {
+ for (struct dt_prop *p = node->props; p; p = p->next) {
+ if (strcmp(p->name, name) == 0) {
+ if (len) *len = p->len;
+ return p->value;
+ }
+ }
+ return NULL;
+}
+
+struct dt_node *dt_node_alloc(char *name) {
+ struct dt_node *node = kemalloc(sizeof(struct dt_node));
+ node->name = name;
+ node->props = NULL;
+ node->children = NULL;
+ node->next = NULL;
+ return node;
+}
+
+struct dt_prop *dt_prop_alloc(char *name, void *value, size_t len) {
+ struct dt_prop *prop = kemalloc(sizeof(struct dt_prop));
+ prop->name = name;
+ prop->value = value;
+ prop->len = len;
+ prop->next = NULL;
+
+ return prop;
+}
+
+
diff --git a/kernel/common/elf.c b/kernel/common/elf.c
new file mode 100644
index 0000000..871eee7
--- /dev/null
+++ b/kernel/common/elf.c
@@ -0,0 +1,40 @@
+#include <sys/elf.h>
+
+int elf_chk_header(struct elf_header *header) {
+ uint32_t magic_chk;
+ memcpy(&magic_chk, header->e_ident, sizeof(uint32_t));
+ if (magic_chk != ltohi(ELF_MAGIC_LE)) {
+ return -1;
+ }
+
+ if (header->e_ident[EI_CLASS] != ELFHOSTCLASS) {
+ return -1;
+ }
+
+ if (header->e_ident[EI_DATA] != ELFHOSTDATA) {
+ return -1;
+ }
+
+ if (header->e_ident[EI_VERSION] != EV_CURRENT) {
+ return -1;
+ }
+
+ return 0;
+}
+
+struct elf_section_header *elf_get_section(struct elf_header *hdr, void *data, uint32_t index) {
+ uint8_t *base = (uint8_t *)data;
+
+ if (index >= hdr->e_shnum) {
+ return 0;
+ }
+
+ return (struct elf_section_header *)(base
+ + hdr->e_shoff
+ + index * hdr->e_shentsize);
+}
+
+char *elf_get_section_name(struct elf_header *hdr, struct elf_section_header *section, void *data) {
+ struct elf_section_header *shstrtab = elf_get_section(hdr, data, hdr->e_shstrndx);
+ return (char *)((uintptr_t)section->sh_name + (uintptr_t)shstrtab->sh_offset + (uintptr_t)data);
+}
diff --git a/kernel/common/log.c b/kernel/common/log.c
new file mode 100644
index 0000000..88136f2
--- /dev/null
+++ b/kernel/common/log.c
@@ -0,0 +1,109 @@
+#include <sys/log.h>
+
+__attribute__((section(".ringbuf"), aligned(64)))
+volatile char log_ring[RINGBUF_SIZE];
+static int pos = 0;
+
+void stub(char c) {
+ (void)c;
+ return;
+}
+
+console_callback_t callback = stub;
+
+void put_char(char c) {
+ log_ring[pos++] = c;
+ if (pos >= RINGBUF_SIZE)
+ pos = 0;
+
+ callback(c);
+}
+
+void put_string(const char *s) {
+ while (*s)
+ put_char(*s++);
+}
+
+void put_uint(unsigned int value, unsigned int radix) {
+ char tmp[16];
+ const char digits[] = "0123456789abcdef";
+ int i = 0;
+
+ if (value == 0) {
+ put_char('0');
+ return;
+ }
+
+ while (value) {
+ tmp[i++] = digits[value % radix];
+ value /= radix;
+ }
+
+ while (i--)
+ put_char(tmp[i]);
+}
+
+void put_int(int value) {
+ if (value < 0) {
+ put_char('-');
+ put_uint((unsigned int)(-value), 10);
+ } else {
+ put_uint((unsigned int)value, 10);
+ }
+}
+
+void vprintk(const char *fmt, __builtin_va_list args) {
+ while (*fmt) {
+ if (*fmt != '%') {
+ put_char(*fmt++);
+ continue;
+ }
+
+ fmt++;
+
+ switch (*fmt) {
+ case '%':
+ put_char('%');
+ break;
+
+ case 'c':
+ put_char((char)__builtin_va_arg(args, int));
+ break;
+
+ case 's':
+ put_string(__builtin_va_arg(args, const char *));
+ break;
+
+ case 'd':
+ case 'i':
+ put_int(__builtin_va_arg(args, int));
+ break;
+
+ case 'u':
+ put_uint(__builtin_va_arg(args, unsigned int), 10);
+ break;
+
+ case 'x':
+ put_uint(__builtin_va_arg(args, unsigned int), 16);
+ break;
+
+ default:
+ put_char('%');
+ put_char(*fmt);
+ break;
+ }
+
+ fmt++;
+ }
+}
+
+void printk(const char *fmt, ...) {
+ __builtin_va_list args;
+ __builtin_va_start(args, fmt);
+ vprintk(fmt, args);
+ __builtin_va_end(args);
+}
+
+void register_console_callback(console_callback_t cb) {
+ callback = cb;
+}
diff --git a/kernel/common/mem.c b/kernel/common/mem.c
new file mode 100644
index 0000000..fee0761
--- /dev/null
+++ b/kernel/common/mem.c
@@ -0,0 +1,116 @@
+#include <sys/mem.h>
+#include <early/dtb.h>
+
+static struct page *free_list;
+
+static void merge_freelist() {
+ struct page *list = free_list;
+
+ while (list && list->next) {
+ if ((void*)list + list->size == list->next) {
+ list->size += list->next->size;
+ list->next = list->next->next;
+ continue;
+ }
+ list = list->next;
+ }
+}
+
+void* kmalloc(size_t size) {
+ struct page *page = free_list;
+ struct page *last = NULL;
+
+ size_t combined_size = size + sizeof(struct page);
+
+ while (page && page->size < combined_size) {
+ last = page;
+ page = page->next;
+ }
+
+ if (page == NULL)
+ return NULL;
+
+
+ if (page->size - combined_size < sizeof(struct page)) {
+ // Return the entire page
+ if (last)
+ last->next = page->next;
+ else
+ free_list = page->next;
+
+ } else {
+ // break page and create a new one
+ struct page *broken = (void *)page + combined_size;
+ broken->size = page->size - combined_size;
+ broken->next = page->next;
+ broken->status = MEMPAGE_FREE;
+
+ page->size = combined_size;
+ page->next = broken;
+
+ if (last)
+ last->next = broken;
+ else
+ free_list = broken;
+ }
+
+ page->status = MEMPAGE_USED;
+
+ return (void *)page + sizeof(struct page);
+}
+
+void* kzalloc(size_t size) {
+ char *ptr = kmalloc(size);
+
+ if (!ptr)
+ return NULL;
+
+ for (size_t i = 0; i < size; i++) {
+ *(ptr + i) = 0;
+ }
+
+ return ptr;
+}
+
+void kfree(void *ptr) {
+ if (!ptr)
+ return;
+
+ struct page *page_info = (struct page *)(ptr - sizeof(struct page));
+ struct page *iter = free_list;
+
+ page_info->status = MEMPAGE_FREE;
+
+ if (!iter) {
+ free_list = page_info;
+ page_info->next = NULL;
+ goto merge;
+ }
+ if (page_info < free_list) {
+ page_info->next = iter;
+ free_list = page_info;
+ goto merge;
+ }
+
+ while (iter->next && iter->next < page_info) {
+ iter = iter->next;
+ }
+
+ page_info->next = iter->next;
+ iter->next = page_info;
+
+ merge:
+ merge_freelist();
+}
+
+
+void km_init(struct mem_info *info) {
+ struct page *base = (struct page *)info->start;
+ base->next = NULL;
+ base->size = info->size - sizeof(struct page);
+ base->status = MEMPAGE_FREE;
+
+ free_list = base;
+}
+
+