feat: handover + populate with dtb

This commit is contained in:
Jordan ⌨️ 2025-04-22 21:09:46 +02:00
parent 2f9560d866
commit 5d8ecae526
17 changed files with 486 additions and 51 deletions

View file

@ -11,3 +11,5 @@ Writer hal_writer(void);
void hal_brkpoint(void); void hal_brkpoint(void);
DTBNode* hal_dtb_root(void); DTBNode* hal_dtb_root(void);
size_t page_size(void);

View file

@ -1,17 +1,18 @@
#include <dtb> #include <dtb>
#include <hal>
#include <handover-dtb>
#include <heap/bump.h> #include <heap/bump.h>
#include <helpers/mem.h> #include <helpers/mem.h>
#include <logger> #include <logger>
#include <stddef.h> #include <pmm>
#include <string.h> #include <stdio.h>
#include "exception.h" #include "exception.h"
#include "mem.h"
extern char __bss[], __bss_end[]; extern char __bss[], __bss_end[];
extern void kmain(void); extern void kmain(void);
static uint8_t early_heap[kib$(20)]; static uint8_t early_heap[kib$(32)];
static DTBNode* dtb_root = NULL; static DTBNode* dtb_root = NULL;
void rv32_start(__attribute__((unused)) size_t hartid, uintptr_t dtb) { void rv32_start(__attribute__((unused)) size_t hartid, uintptr_t dtb) {
@ -20,7 +21,17 @@ void rv32_start(__attribute__((unused)) size_t hartid, uintptr_t dtb) {
BumpAllocator alloc = bump_allocator_create((void*)early_heap, sizeof(early_heap)); BumpAllocator alloc = bump_allocator_create((void*)early_heap, sizeof(early_heap));
dtb_root = dtb_init(dtb, &alloc.base); dtb_root = dtb_init(dtb, &alloc.base);
mem_init(); handover_init(dtb_root, &alloc.base);
handover_append(handover(), (HandoverRecord){
.tag = HANDOVER_LOADER,
.start = (uintptr_t)early_heap,
.size = sizeof(early_heap),
});
for (size_t i = 0; i < handover()->count; i++) {
debug$("%s (start: %x, len: %x)", handover_tag_name(handover()->records[i].tag), handover()->records[i].start, handover()->records[i].size);
}
kmain(); kmain();
} }

View file

@ -9,3 +9,7 @@ void hal_putc(int ch) {
void hal_brkpoint(void) { void hal_brkpoint(void) {
__asm__ volatile("ebreak"); __asm__ volatile("ebreak");
} }
size_t page_size(void) {
return 4096;
}

View file

@ -7,5 +7,5 @@
"sys": ["kernel"] "sys": ["kernel"]
}, },
"provides": ["hal-impl"], "provides": ["hal-impl"],
"requires": ["dtb"] "requires": ["dtb", "pmm", "handover-dtb"]
} }

View file

@ -1,42 +0,0 @@
#include <hal>
#include <helpers/mem.h>
#include <logger>
#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;
}
}

View file

@ -1,3 +0,0 @@
#pragma once
void mem_init(void);

View file

@ -3,3 +3,8 @@
#include <logger> #include <logger>
#define printf(...) _log(LOG_INFO, loc$(), __VA_ARGS__) #define printf(...) _log(LOG_INFO, loc$(), __VA_ARGS__)
#define fprintf(TYPE, ...) _log(TYPE, loc$(), __VA_ARGS__)
#define stdio LOG_INFO
#define stderr LOG_ERROR

View file

@ -0,0 +1,5 @@
{
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"type": "lib",
"id": "pmm"
}

14
src/kernel/pmm/mod.c Normal file
View file

@ -0,0 +1,14 @@
#include "mod.h"
#include <hal>
#include <logger>
Pmm* pmm = NULL;
void pmm_init(size_t start, size_t len) {
(void)start;
(void)len;
if (pmm != NULL) {
error$("PMM already initialized");
hal_brkpoint();
}
}

17
src/kernel/pmm/mod.h Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
typedef struct _Page {
struct _Page* next;
uintptr_t addr;
} Page;
typedef struct {
size_t total_pages;
size_t free_pages;
Page* freelist;
} Pmm;
void pmm_init(size_t start, size_t len);

View file

@ -0,0 +1,5 @@
{
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"type": "lib",
"id": "handover"
}

View file

@ -0,0 +1,158 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mod.h"
char const* handover_tag_name(HandoverTag tag) {
switch (tag) {
#define TAG(NAME, VALUE) \
case HANDOVER_##NAME: \
return #NAME;
HANDOVER_TAGS(TAG)
#undef TAG
}
return "UNKNOWN";
}
bool handover_mergeable(uint32_t tag) {
switch (tag) {
case HANDOVER_FREE:
case HANDOVER_LOADER:
case HANDOVER_KERNEL:
case HANDOVER_RESERVED:
return true;
default:
return false;
}
}
bool handover_overlap(HandoverRecord lhs, HandoverRecord rhs) {
return lhs.start < rhs.start + rhs.size && rhs.start < lhs.start + lhs.size;
}
bool handover_just_before(HandoverRecord lhs, HandoverRecord rhs) {
return lhs.start + lhs.size == rhs.start;
}
bool handover_just_after(HandoverRecord lhs, HandoverRecord rhs) {
return lhs.start == rhs.start + rhs.size;
}
HandoverRecord handover_half_under(HandoverRecord self, HandoverRecord other) {
if (handover_overlap(self, other) &&
self.start < other.start) {
return (HandoverRecord){
.tag = self.tag,
.flags = 0,
.start = self.start,
.size = other.start - self.start,
};
}
return (HandoverRecord){0};
}
HandoverRecord handover_half_over(HandoverRecord self, HandoverRecord other) {
if (handover_overlap(self, other) &&
self.start + self.size > other.start + other.size) {
return (HandoverRecord){
.tag = self.tag,
.flags = 0,
.start = other.start + other.size,
.size = self.start + self.size - other.start - other.size,
};
}
return (HandoverRecord){0};
}
void handover_insert(HandoverPayload* payload, size_t index, HandoverRecord record) {
for (size_t i = payload->count; i > index; i--) {
payload->records[i] = payload->records[i - 1];
}
payload->records[index] = record;
payload->count++;
}
void handover_remove(HandoverPayload* payload, size_t index) {
for (size_t i = index; i < payload->count - 1; i++) {
payload->records[i] = payload->records[i + 1];
}
payload->count--;
}
void handover_append(HandoverPayload* payload, HandoverRecord record) {
if (record.size == 0) {
return;
}
for (size_t i = 0; i < payload->count; i++) {
HandoverRecord other = payload->records[i];
if (record.tag == other.tag && handover_just_after(record, other) && handover_mergeable(record.tag)) {
handover_remove(payload, i);
other.size += record.size;
handover_append(payload, other);
return;
}
if (record.tag == other.tag && handover_just_before(record, other) && handover_mergeable(record.tag)) {
handover_remove(payload, i);
other.start -= record.size;
other.size += record.size;
handover_append(payload, other);
return;
}
if (handover_overlap(record, other)) {
if ((handover_mergeable(record.tag) && !handover_mergeable(other.tag)) || other.tag == HANDOVER_FREE) {
handover_remove(payload, i);
HandoverRecord lower = handover_half_under(other, record);
HandoverRecord upper = handover_half_over(other, record);
handover_append(payload, record);
handover_append(payload, lower);
handover_append(payload, upper);
return;
} else if (!handover_mergeable(record.tag) && handover_mergeable(other.tag)) {
handover_remove(payload, i);
HandoverRecord lower = handover_half_under(record, other);
HandoverRecord upper = handover_half_over(record, other);
handover_append(payload, other);
handover_append(payload, lower);
handover_append(payload, upper);
return;
} else {
fprintf(stderr, "handover: record %s (start: %x, len: %x) collides with %s (start: %x, len: %x)\n", handover_tag_name(record.tag), record.start, record.size, handover_tag_name(other.tag), other.start, other.size);
abort();
}
}
if (record.start < other.start) {
handover_insert(payload, i, record);
return;
}
}
payload->records[payload->count++] = record;
}
char const* handover_str(HandoverPayload const* payload, uint32_t offset) {
return (char const*)payload + offset;
}
size_t handover_add_string(HandoverPayload* handover, char const* str) {
size_t len = strlen(str) + 1;
size_t offset = handover->size - len;
memset((void*)((uintptr_t)handover + offset), 0, len);
memcpy((void*)((uintptr_t)handover + offset), str, len);
handover->size -= len;
return offset;
}

View file

@ -0,0 +1,159 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#ifdef __ck_bits_64__
# define KERNEL_BASE 0xffffffff80000000;
# define UPPER_HALF 0xffff800000000000;
#else
# define KERNEL_BASE 0xc0000000;
# define UPPER_HALF 0xc0000000;
#endif //!__ck_bits_64__
#define HANDOVER_COOLBOOT 0xc001b001
#define HANDOVER_SECTION ".handover"
#define HANDOVER_TAGS(TAG) \
TAG(FREE, 0x00000000) \
TAG(MAGIC, HANDOVER_COOLBOOT) \
TAG(SELF, 0xa24f988d) \
TAG(STACK, 0xf65b391b) \
TAG(KERNEL, 0xbfc71b20) \
TAG(LOADER, 0xf1f80c26) \
TAG(FILE, 0xcbc36d3b) \
TAG(RSDP, 0x8ef29c18) \
TAG(FDT, 0xb628bbc1) \
TAG(FB, 0xe2d55685) \
TAG(CMDLINE, 0x435140c4) \
TAG(RESERVED, 0xb8841d2d) \
TAG(END, 0xffffffff)
typedef enum {
#define TAG(NAME, VALUE) HANDOVER_##NAME = VALUE,
HANDOVER_TAGS(TAG)
#undef TAG
} HandoverTag;
typedef struct
{
uint32_t tag;
uint32_t flags;
uintptr_t start;
size_t size;
union {
struct
{
uint16_t width;
uint16_t height;
uint16_t pitch;
#define HANDOVER_RGBX8888 0x7451
#define HANDOVER_BGRX8888 0xd040
uint16_t format;
} fb;
struct
{
uint32_t name;
uint32_t meta;
} file;
uint64_t more;
};
} HandoverRecord;
typedef struct
{
uint32_t magic, agent, size, count;
HandoverRecord records[];
} HandoverPayload;
typedef struct
{
uint32_t tag;
uint32_t flags;
uint64_t more;
} HandoverRequest;
typedef void HandoverEntry(
uint64_t magic,
HandoverPayload const* payload
);
/* --- Header Utilities ----------------------------------------------------- */
#define HANDOVER_REQ_START \
{ \
.tag = HANDOVER_MAGIC \
}
#define HANDOVER_REQ_END \
{ \
.tag = HANDOVER_END \
}
#define WITH_FB \
{ \
.tag = HANDOVER_FB \
}
#define WITH_ACPI \
{ \
.tag = HANDOVER_RSDP \
}
#define WITH_FDT \
{ \
.tag = HANDOVER_FDT \
}
#define WITH_FILES \
{ \
.tag = HANDOVER_FILE \
}
#define WITH_CMDLINE \
{ \
.tag = HANDOVER_CMDLINE \
}
#define HANDOVER(...) \
__attribute__((section(HANDOVER_SECTION), used)) static HandoverRequest handover_header[] = { \
{.tag = HANDOVER_MAGIC}, \
__VA_ARGS__ __VA_OPT__(, ){.tag = HANDOVER_END}, \
};
/* --- Utilities ------------------------------------------------------------ */
char const* handover_tag_name(HandoverTag tag);
bool handover_mergeable(uint32_t tag);
bool handover_overlap(HandoverRecord lhs, HandoverRecord rhs);
bool handover_just_before(HandoverRecord lhs, HandoverRecord rhs);
bool handover_just_after(HandoverRecord lhs, HandoverRecord rhs);
HandoverRecord handover_half_under(HandoverRecord self, HandoverRecord other);
HandoverRecord handover_half_over(HandoverRecord self, HandoverRecord other);
void handover_insert(HandoverPayload* payload, size_t index, HandoverRecord record);
void handover_remove(HandoverPayload* payload, size_t index);
void handover_append(HandoverPayload* payload, HandoverRecord record);
char const* handover_str(HandoverPayload const* payload, uint32_t offset);
size_t handover_add_string(HandoverPayload* handover, char const* str);
#pragma GCC diagnostic pop

View file

@ -0,0 +1,9 @@
{
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
"type": "lib",
"id": "handover-dtb",
"requires": [
"dtb",
"handover"
]
}

View file

@ -0,0 +1,78 @@
#include <helpers/mem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "handover/base/mod.h"
#include "logger/mod.h"
#include "mod.h"
static DTBNode* dtb_root = NULL;
static HandoverPayload* payload = NULL;
static void handover_mmap(void) {
if (dtb_root == NULL) {
fprintf(stderr, "No DTB found");
abort();
}
DTBNode* mem = dtb_lookup(dtb_root, "memory");
if (mem == NULL) {
fprintf(stderr, "No memory node found in DTB");
abort();
}
RegValue reg_val = dtb_lookup_reg(mem);
if (reg_val.len == 0) {
printf("WARNING: Memory node size is larger than 4GB. Defaulting to 4GB");
reg_val.len = align_down$(gib$(4) - 1, 4096);
}
handover_append(payload, (HandoverRecord){
.tag = HANDOVER_FREE,
.start = reg_val.addr,
.size = reg_val.len,
});
DTBNode* reserved = dtb_lookup(dtb_root, "reserved-memory");
if (reserved == NULL) {
fprintf(stderr, "No reserved memory node found in DTB");
abort();
}
DTBNode* child = reserved->children;
while (child != NULL) {
RegValue reg = dtb_lookup_reg(child);
handover_append(payload, (HandoverRecord){
.tag = HANDOVER_RESERVED,
.start = reg.addr,
.size = reg.len,
});
child = child->next;
}
}
void handover_init(DTBNode* dtb, Allocator* alloc) {
if (dtb_root != NULL) {
fprintf(stderr, "Handover is already initialized");
abort();
}
dtb_root = dtb;
payload = alloc->alloc(alloc, kib$(16));
if (payload == NULL) {
fprintf(stderr, "Failed to allocate memory for handover payload");
abort();
}
payload->count = 0;
payload->magic = HANDOVER_MAGIC;
handover_mmap();
}
HandoverPayload* handover(void) {
return payload;
}

View file

@ -0,0 +1,9 @@
#pragma once
#include <dtb>
#include <handover>
#include <traits/allocator.h>
void handover_init(DTBNode* dtb, Allocator* alloc);
HandoverPayload* handover(void);

4
src/libs/helpers/misc.h Normal file
View file

@ -0,0 +1,4 @@
#pragma once
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,