diff options
| author | Nathan Lee <me@nwlee.tech> | 2026-08-12 17:44:17 -0500 |
|---|---|---|
| committer | Nathan Lee <me@nwlee.tech> | 2026-08-12 17:44:17 -0500 |
| commit | 2c0efd93530c472e96ff3529aee983b53f3b78d9 (patch) | |
| tree | cc36e7334e162ba67df79333e267ac93b4d984b9 /kernel/common | |
| parent | 640a81b3ee366c651286efd1b80b37992cd53282 (diff) | |
rework project structure
Diffstat (limited to 'kernel/common')
| -rw-r--r-- | kernel/common/bump.c | 54 | ||||
| -rw-r--r-- | kernel/common/cpio.c | 71 | ||||
| -rw-r--r-- | kernel/common/dtb.c | 84 | ||||
| -rw-r--r-- | kernel/common/elf.c | 40 | ||||
| -rw-r--r-- | kernel/common/log.c | 109 | ||||
| -rw-r--r-- | kernel/common/mem.c | 116 |
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; +} + + |
