diff --git a/src/kernel/hal/mod.h b/src/kernel/hal/mod.h index fd5b7c0..4930024 100644 --- a/src/kernel/hal/mod.h +++ b/src/kernel/hal/mod.h @@ -1,5 +1,6 @@ #pragma once +#include #include void hal_setup(void); @@ -8,3 +9,5 @@ void hal_putc(int ch); Writer hal_writer(void); void hal_brkpoint(void); + +DTBNode* hal_dtb_root(void); diff --git a/src/kernel/hal/rv32/boot.c b/src/kernel/hal/rv32/boot.c index e85c61a..46f1573 100644 --- a/src/kernel/hal/rv32/boot.c +++ b/src/kernel/hal/rv32/boot.c @@ -6,29 +6,24 @@ #include #include "exception.h" +#include "mem.h" extern char __bss[], __bss_end[]; extern void kmain(void); static uint8_t early_heap[kib$(20)]; +static DTBNode* dtb_root = NULL; void rv32_start(__attribute__((unused)) size_t hartid, uintptr_t dtb) { write_csr$(stvec, (uint32_t)interrupt_kernel); BumpAllocator alloc = bump_allocator_create((void*)early_heap, sizeof(early_heap)); - DTBNode* root = dtb_init(dtb, &alloc.base); - DTBNode* mem = dtb_lookup(root, "reserved-memory"); - - if (mem == NULL) { - error$("Failed to find reserved-memory node in device tree"); - __asm__ volatile("ebreak"); - } - - DTBProp* prop = mem->props; - while (prop != NULL) { - debug$("prop: %s", prop->name); - prop = prop->next; - } + dtb_root = dtb_init(dtb, &alloc.base); + mem_init(); kmain(); } + +DTBNode* hal_dtb_root(void) { + return dtb_root; +} diff --git a/src/kernel/hal/rv32/mem.c b/src/kernel/hal/rv32/mem.c new file mode 100644 index 0000000..fed1c7a --- /dev/null +++ b/src/kernel/hal/rv32/mem.c @@ -0,0 +1,42 @@ +#include +#include +#include + +#include "mem.h" + +void mem_init(void) { + DTBNode* root = hal_dtb_root(); + if (root == NULL) { + error$("No DTB found"); + hal_brkpoint(); + } + + DTBNode* mem = dtb_lookup(root, "memory"); + if (mem == NULL) { + error$("No memory node found in DTB"); + hal_brkpoint(); + } + + RegValue reg_val = dtb_lookup_reg(mem); + if (reg_val.len == 0) { + warn$("Memory node size is larger than 4GB. Defaulting to 4GB"); + reg_val.len = align_down$(gib$(4) - 1, 4096); + } + + debug$("Memory node found at %x with size %x", reg_val.addr, reg_val.len); + + DTBNode* reserved = dtb_lookup(root, "reserved-memory"); + if (reserved == NULL) { + error$("No reserved memory node found in DTB"); + hal_brkpoint(); + } + + DTBNode* child = reserved->children; + + while (child != NULL) { + RegValue reg = dtb_lookup_reg(child); + debug$("Reserved memory node with name %s found at %x with size %x", child->name, reg.addr, reg.len); + + child = child->next; + } +} diff --git a/src/kernel/hal/rv32/mem.h b/src/kernel/hal/rv32/mem.h new file mode 100644 index 0000000..c73eda1 --- /dev/null +++ b/src/kernel/hal/rv32/mem.h @@ -0,0 +1,3 @@ +#pragma once + +void mem_init(void); diff --git a/src/libs/dtb/mod.c b/src/libs/dtb/mod.c index aaf074d..b6ff6b1 100644 --- a/src/libs/dtb/mod.c +++ b/src/libs/dtb/mod.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include "mod.h" @@ -15,7 +14,7 @@ static uint32_t read_offset(uint8_t** offset) { static DTBNode* dtb_parse(FDTHeader* dtb_header, Allocator* alloc) { if (dtb_header == NULL) { error$("Device tree blob not initialized"); - abort(); + return NULL; } DTBNode* current_node = NULL; @@ -36,13 +35,13 @@ static DTBNode* dtb_parse(FDTHeader* dtb_header, Allocator* alloc) { if (!root) { if (*node_name) { error$("Invalid device tree blob. Expected root node to be empty"); - abort(); + return NULL; } root = alloc->alloc(alloc, sizeof(DTBNode)); if (root == NULL) { error$("Failed to allocate memory for device tree node"); - abort(); + return NULL; } memset(current_node, 0, sizeof(DTBNode)); @@ -55,7 +54,7 @@ static DTBNode* dtb_parse(FDTHeader* dtb_header, Allocator* alloc) { DTBNode* new_node = alloc->alloc(alloc, sizeof(DTBNode)); if (new_node == NULL) { error$("Failed to allocate memory for device tree node"); - abort(); + return NULL; } memset(new_node, 0, sizeof(DTBNode)); @@ -94,7 +93,7 @@ static DTBNode* dtb_parse(FDTHeader* dtb_header, Allocator* alloc) { DTBProp* prop = alloc->alloc(alloc, sizeof(DTBProp)); if (prop == NULL) { error$("Failed to allocate memory for device tree property"); - abort(); + return NULL; } char const* prop_name = strtab + nameoff; @@ -128,7 +127,7 @@ static DTBNode* dtb_parse(FDTHeader* dtb_header, Allocator* alloc) { default: { error$("Unknown token %x", token); - abort(); + return NULL; } } } @@ -141,7 +140,7 @@ DTBNode* dtb_init(uintptr_t dtb, Allocator* alloc) { if (from_be32(dtb_header->magic) != DTB_MAGIC) { error$("Invalid device tree blob magic number. Excecting %x, got %x", DTB_MAGIC, from_be32(dtb_header->magic)); - abort(); + return NULL; } return dtb_parse(dtb_header, alloc); @@ -174,3 +173,46 @@ DTBProp* dtb_lookup_prop(DTBNode* node, char const* name) { return NULL; } + +RegValue dtb_lookup_reg(DTBNode* node) { + RegValue reg = {0}; + + DTBProp* prop = dtb_lookup_prop(node, "reg"); + if (prop == NULL) { + error$("Failed to find reg property in device tree node %s", node->name); + return reg; + } + + uint8_t* offset = (uint8_t*)prop->value; + + DTBProp* address_cells_prop = dtb_lookup_prop(node->parent, "#address-cells"); + if (address_cells_prop == NULL) { + error$("Failed to find #address-cells property in device tree node %s", node->parent->name); + return reg; + } + + DTBProp* size_cells_prop = dtb_lookup_prop(node->parent, "#size-cells"); + if (size_cells_prop == NULL) { + error$("Failed to find #size-cells property in device tree node %s", node->parent->name); + return reg; + } + + size_t address_cells = from_be32(*(uint32_t*)address_cells_prop->value); + size_t size_cells = from_be32(*(uint32_t*)size_cells_prop->value); + + uint64_t tmp_addr = 0; + uint64_t tmp_len = 0; + + for (size_t i = 0; i < address_cells; i++) { + tmp_addr = (tmp_addr << 32) | read_offset(&offset); + } + + for (size_t i = 0; i < size_cells; i++) { + tmp_len = (tmp_len << 32) | read_offset(&offset); + } + + reg.addr = tmp_addr; + reg.len = tmp_len; + + return reg; +} diff --git a/src/libs/dtb/mod.h b/src/libs/dtb/mod.h index 5ef0189..0d57d47 100644 --- a/src/libs/dtb/mod.h +++ b/src/libs/dtb/mod.h @@ -40,8 +40,15 @@ typedef struct _DTBNode { struct _DTBNode* parent; } DTBNode; +typedef struct { + uintptr_t addr; + size_t len; +} RegValue; + DTBNode* dtb_init(uintptr_t dtb, Allocator* alloc); DTBNode* dtb_lookup(DTBNode* root, char const* name); DTBProp* dtb_lookup_prop(DTBNode* node, char const* name); + +RegValue dtb_lookup_reg(DTBNode* node);