feat: handover + populate with dtb
This commit is contained in:
parent
2f9560d866
commit
5d8ecae526
17 changed files with 486 additions and 51 deletions
|
@ -11,3 +11,5 @@ Writer hal_writer(void);
|
|||
void hal_brkpoint(void);
|
||||
|
||||
DTBNode* hal_dtb_root(void);
|
||||
|
||||
size_t page_size(void);
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
#include <dtb>
|
||||
#include <hal>
|
||||
#include <handover-dtb>
|
||||
#include <heap/bump.h>
|
||||
#include <helpers/mem.h>
|
||||
#include <logger>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <pmm>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "exception.h"
|
||||
#include "mem.h"
|
||||
|
||||
extern char __bss[], __bss_end[];
|
||||
extern void kmain(void);
|
||||
|
||||
static uint8_t early_heap[kib$(20)];
|
||||
static uint8_t early_heap[kib$(32)];
|
||||
static DTBNode* dtb_root = NULL;
|
||||
|
||||
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));
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,3 +9,7 @@ void hal_putc(int ch) {
|
|||
void hal_brkpoint(void) {
|
||||
__asm__ volatile("ebreak");
|
||||
}
|
||||
|
||||
size_t page_size(void) {
|
||||
return 4096;
|
||||
}
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
"sys": ["kernel"]
|
||||
},
|
||||
"provides": ["hal-impl"],
|
||||
"requires": ["dtb"]
|
||||
"requires": ["dtb", "pmm", "handover-dtb"]
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
void mem_init(void);
|
|
@ -3,3 +3,8 @@
|
|||
#include <logger>
|
||||
|
||||
#define printf(...) _log(LOG_INFO, loc$(), __VA_ARGS__)
|
||||
|
||||
#define fprintf(TYPE, ...) _log(TYPE, loc$(), __VA_ARGS__)
|
||||
|
||||
#define stdio LOG_INFO
|
||||
#define stderr LOG_ERROR
|
||||
|
|
5
src/kernel/pmm/manifest.json
Normal file
5
src/kernel/pmm/manifest.json
Normal 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
14
src/kernel/pmm/mod.c
Normal 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
17
src/kernel/pmm/mod.h
Normal 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);
|
5
src/libs/handover/base/manifest.json
Normal file
5
src/libs/handover/base/manifest.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
|
||||
"type": "lib",
|
||||
"id": "handover"
|
||||
}
|
158
src/libs/handover/base/mod.c
Normal file
158
src/libs/handover/base/mod.c
Normal 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;
|
||||
}
|
159
src/libs/handover/base/mod.h
Normal file
159
src/libs/handover/base/mod.h
Normal 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
|
9
src/libs/handover/dtb/manifest.json
Normal file
9
src/libs/handover/dtb/manifest.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
|
||||
"type": "lib",
|
||||
"id": "handover-dtb",
|
||||
"requires": [
|
||||
"dtb",
|
||||
"handover"
|
||||
]
|
||||
}
|
78
src/libs/handover/dtb/mod.c
Normal file
78
src/libs/handover/dtb/mod.c
Normal 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;
|
||||
}
|
9
src/libs/handover/dtb/mod.h
Normal file
9
src/libs/handover/dtb/mod.h
Normal 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
4
src/libs/helpers/misc.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
#define GENERATE_ENUM(ENUM) ENUM,
|
||||
#define GENERATE_STRING(STRING) #STRING,
|
Loading…
Add table
Reference in a new issue