Record networking and DMA development progress
Add the current OS source tree, build scripts, system image layout, and development notes covering DMA page allocation, e1000 bring-up, net API dispatch, and DHCP work in progress.
This commit is contained in:
@@ -0,0 +1,444 @@
|
||||
#include <utsm/dkm.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/arena.h>
|
||||
#include "../arch/x86_64/limine.h"
|
||||
|
||||
#define ELF_MAGIC0 0x7f
|
||||
#define ELF_MAGIC1 'E'
|
||||
#define ELF_MAGIC2 'L'
|
||||
#define ELF_MAGIC3 'F'
|
||||
#define ELFCLASS64 2
|
||||
#define ELFDATA2LSB 1
|
||||
#define ET_REL 1
|
||||
#define ET_DYN 3
|
||||
#define ET_EXEC 2
|
||||
#define EM_X86_64 62
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_NOBITS 8
|
||||
|
||||
#define SHF_ALLOC 0x2
|
||||
#define SHF_WRITE 0x1
|
||||
#define SHF_EXECINSTR 0x4
|
||||
|
||||
#define R_X86_64_64 1
|
||||
#define R_X86_64_32 10
|
||||
#define R_X86_64_32S 11
|
||||
#define R_X86_64_PC32 2
|
||||
|
||||
void *memset(void *dst, int value, usize len);
|
||||
void *memcpy(void *dst, const void *src, usize len);
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_module_request g_module_request = {
|
||||
.id = LIMINE_MODULE_REQUEST_ID,
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests_start")))
|
||||
static volatile u64 g_limine_requests_start[4] = { LIMINE_COMMON_MAGIC, 0xf6b8f4b39de7d1aeULL, 0xfab91a6940fcb9cfULL };
|
||||
|
||||
__attribute__((used, section(".limine_requests_end")))
|
||||
static volatile u64 g_limine_requests_end[2] = { 0, 0 };
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_rsdp_request g_rsdp_request = {
|
||||
.id = LIMINE_RSDP_REQUEST_ID,
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_framebuffer_request g_fb_request = {
|
||||
.id = LIMINE_FRAMEBUFFER_REQUEST_ID,
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_hhdm_request g_hhdm_request = {
|
||||
.id = { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852ULL, 0x63984e959a98244bULL },
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_kernel_address_request g_kernel_address_request = {
|
||||
.id = LIMINE_KERNEL_ADDRESS_REQUEST_ID,
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_memmap_request g_memmap_request = {
|
||||
.id = LIMINE_MEMMAP_REQUEST_ID,
|
||||
.revision = 0,
|
||||
.response = 0
|
||||
};
|
||||
|
||||
typedef struct elf64_ehdr {
|
||||
u8 ident[16];
|
||||
u16 type;
|
||||
u16 machine;
|
||||
u32 version;
|
||||
u64 entry;
|
||||
u64 phoff;
|
||||
u64 shoff;
|
||||
u32 flags;
|
||||
u16 ehsize;
|
||||
u16 phentsize;
|
||||
u16 phnum;
|
||||
u16 shentsize;
|
||||
u16 shnum;
|
||||
u16 shstrndx;
|
||||
} elf64_ehdr;
|
||||
|
||||
typedef struct elf64_shdr {
|
||||
u32 name;
|
||||
u32 type;
|
||||
u64 flags;
|
||||
u64 addr;
|
||||
u64 offset;
|
||||
u64 size;
|
||||
u32 link;
|
||||
u32 info;
|
||||
u64 addralign;
|
||||
u64 entsize;
|
||||
} elf64_shdr;
|
||||
|
||||
typedef struct elf64_sym {
|
||||
u32 name;
|
||||
u8 info;
|
||||
u8 other;
|
||||
u16 shndx;
|
||||
u64 value;
|
||||
u64 size;
|
||||
} elf64_sym;
|
||||
|
||||
typedef struct elf64_rela {
|
||||
u64 offset;
|
||||
u64 info;
|
||||
i64 addend;
|
||||
} elf64_rela;
|
||||
|
||||
static int streq(const char *a, const char *b) {
|
||||
usize i = 0;
|
||||
while (a[i] && b[i]) {
|
||||
if (a[i] != b[i]) {
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return a[i] == b[i];
|
||||
}
|
||||
|
||||
int dkm_check_elf64(const void *address, u64 size) {
|
||||
if (!address || size < sizeof(elf64_ehdr)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const elf64_ehdr *ehdr = (const elf64_ehdr *)address;
|
||||
if (ehdr->ident[0] != ELF_MAGIC0 || ehdr->ident[1] != ELF_MAGIC1 || ehdr->ident[2] != ELF_MAGIC2 || ehdr->ident[3] != ELF_MAGIC3) {
|
||||
return -2;
|
||||
}
|
||||
if (ehdr->ident[4] != ELFCLASS64 || ehdr->ident[5] != ELFDATA2LSB) {
|
||||
return -3;
|
||||
}
|
||||
if (ehdr->machine != EM_X86_64) {
|
||||
return -4;
|
||||
}
|
||||
if (ehdr->type != ET_REL && ehdr->type != ET_DYN && ehdr->type != ET_EXEC) {
|
||||
return -5;
|
||||
}
|
||||
if (ehdr->ehsize < sizeof(elf64_ehdr)) {
|
||||
return -6;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int range_ok(u64 offset, u64 length, u64 size) {
|
||||
if (offset > size) {
|
||||
return 0;
|
||||
}
|
||||
if (length > size - offset) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dkm_scan_symbols(const void *address, u64 size, struct dkm_symbol_scan *out) {
|
||||
const elf64_ehdr *ehdr = (const elf64_ehdr *)address;
|
||||
out->driver_desc = 0;
|
||||
out->driver_init = 0;
|
||||
out->driver_exit = 0;
|
||||
|
||||
if (ehdr->shoff == 0 || ehdr->shnum == 0 || ehdr->shentsize < sizeof(elf64_shdr)) {
|
||||
log_error("[DKM] ELF has no section table");
|
||||
return -1;
|
||||
}
|
||||
if (!range_ok(ehdr->shoff, (u64)ehdr->shnum * ehdr->shentsize, size)) {
|
||||
log_error("[DKM] ELF section table out of range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const elf64_shdr *sections = (const elf64_shdr *)((const u8 *)address + ehdr->shoff);
|
||||
const elf64_shdr *symtab = 0;
|
||||
const elf64_shdr *strtab = 0;
|
||||
|
||||
for (u16 i = 0; i < ehdr->shnum; i++) {
|
||||
const elf64_shdr *section = (const elf64_shdr *)((const u8 *)sections + (u64)i * ehdr->shentsize);
|
||||
if (section->type == SHT_SYMTAB) {
|
||||
symtab = section;
|
||||
if (section->link < ehdr->shnum) {
|
||||
strtab = (const elf64_shdr *)((const u8 *)sections + (u64)section->link * ehdr->shentsize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!symtab || !strtab || strtab->type != SHT_STRTAB) {
|
||||
log_error("[DKM] missing symtab/strtab");
|
||||
return -1;
|
||||
}
|
||||
if (symtab->entsize < sizeof(elf64_sym) || !range_ok(symtab->offset, symtab->size, size) || !range_ok(strtab->offset, strtab->size, size)) {
|
||||
log_error("[DKM] invalid symtab/strtab range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_info("[DKM] symtab found");
|
||||
log_hex64("[DKM] symbol count=", symtab->size / symtab->entsize);
|
||||
|
||||
for (u64 off = 0; off + sizeof(elf64_sym) <= symtab->size; off += symtab->entsize) {
|
||||
const elf64_sym *sym = (const elf64_sym *)((const u8 *)address + symtab->offset + off);
|
||||
if (sym->name >= strtab->size) {
|
||||
continue;
|
||||
}
|
||||
const char *name = (const char *)address + strtab->offset + sym->name;
|
||||
if (streq(name, "driver_desc")) {
|
||||
out->driver_desc = sym;
|
||||
log_info("[DKM] found driver_desc");
|
||||
log_hex64("[DKM] driver_desc section=", sym->shndx);
|
||||
log_hex64("[DKM] driver_desc value=", sym->value);
|
||||
} else if (streq(name, "driver_init")) {
|
||||
out->driver_init = sym;
|
||||
log_info("[DKM] found driver_init");
|
||||
log_hex64("[DKM] driver_init section=", sym->shndx);
|
||||
log_hex64("[DKM] driver_init value=", sym->value);
|
||||
} else if (streq(name, "driver_exit")) {
|
||||
out->driver_exit = sym;
|
||||
log_info("[DKM] found driver_exit");
|
||||
log_hex64("[DKM] driver_exit section=", sym->shndx);
|
||||
log_hex64("[DKM] driver_exit value=", sym->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (out->driver_desc && out->driver_init && out->driver_exit) {
|
||||
log_info("[DKM] required driver symbols ok");
|
||||
return 0;
|
||||
}
|
||||
log_error("[DKM] required driver symbols missing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dkm_load_elf_rel(const void *address, u64 size, const struct dkm_symbol_scan *symbols) {
|
||||
const elf64_ehdr *ehdr = (const elf64_ehdr *)address;
|
||||
const elf64_shdr *sections = (const elf64_shdr *)((const u8 *)address + ehdr->shoff);
|
||||
u64 image_offset[64];
|
||||
u64 total_size = 0;
|
||||
u64 max_align = 16;
|
||||
u16 alloc_count = 0;
|
||||
|
||||
for (u16 i = 1; i < ehdr->shnum && alloc_count < 64; i++) {
|
||||
const elf64_shdr *sh = (const elf64_shdr *)((const u8 *)sections + (u64)i * ehdr->shentsize);
|
||||
if (!(sh->flags & SHF_ALLOC)) {
|
||||
continue;
|
||||
}
|
||||
if (sh->addralign > max_align) {
|
||||
max_align = sh->addralign;
|
||||
}
|
||||
total_size = utsm_align_up_u64(total_size, sh->addralign);
|
||||
image_offset[i] = total_size;
|
||||
total_size += sh->size;
|
||||
alloc_count++;
|
||||
}
|
||||
|
||||
if (total_size == 0) {
|
||||
log_error("[DKM] no allocatable sections");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u8 *image = (u8 *)kmem_alloc_aligned(total_size, max_align);
|
||||
if (!image) {
|
||||
log_error("[DKM] failed to allocate module memory");
|
||||
return -1;
|
||||
}
|
||||
memset(image, 0, total_size);
|
||||
|
||||
for (u16 i = 1; i < ehdr->shnum; i++) {
|
||||
const elf64_shdr *sh = (const elf64_shdr *)((const u8 *)sections + (u64)i * ehdr->shentsize);
|
||||
if (!(sh->flags & SHF_ALLOC)) {
|
||||
continue;
|
||||
}
|
||||
if (sh->type == SHT_PROGBITS && sh->size > 0 && range_ok(sh->offset, sh->size, size)) {
|
||||
memcpy(image + image_offset[i], (const u8 *)address + sh->offset, sh->size);
|
||||
}
|
||||
}
|
||||
|
||||
for (u16 i = 1; i < ehdr->shnum; i++) {
|
||||
const elf64_shdr *sh = (const elf64_shdr *)((const u8 *)sections + (u64)i * ehdr->shentsize);
|
||||
if (sh->type != SHT_RELA) {
|
||||
continue;
|
||||
}
|
||||
if (sh->entsize < sizeof(elf64_rela) || !range_ok(sh->offset, sh->size, size)) {
|
||||
continue;
|
||||
}
|
||||
if (sh->info >= ehdr->shnum) {
|
||||
continue;
|
||||
}
|
||||
const elf64_shdr *target = (const elf64_shdr *)((const u8 *)sections + (u64)sh->info * ehdr->shentsize);
|
||||
if (!(target->flags & SHF_ALLOC)) {
|
||||
continue;
|
||||
}
|
||||
u8 *target_base = image + image_offset[sh->info];
|
||||
|
||||
const elf64_shdr *rela_symtab = 0;
|
||||
if (sh->link < ehdr->shnum) {
|
||||
rela_symtab = (const elf64_shdr *)((const u8 *)sections + (u64)sh->link * ehdr->shentsize);
|
||||
}
|
||||
const elf64_shdr *rela_strtab = 0;
|
||||
if (rela_symtab && rela_symtab->link < ehdr->shnum) {
|
||||
rela_strtab = (const elf64_shdr *)((const u8 *)sections + (u64)rela_symtab->link * ehdr->shentsize);
|
||||
}
|
||||
(void)rela_strtab;
|
||||
|
||||
for (u64 off = 0; off + sizeof(elf64_rela) <= sh->size; off += sh->entsize) {
|
||||
const elf64_rela *rela = (const elf64_rela *)((const u8 *)address + sh->offset + off);
|
||||
u32 sym_idx = (u32)(rela->info >> 32);
|
||||
u32 reloc_type = (u32)(rela->info & 0xffffffff);
|
||||
|
||||
u64 sym_value = 0;
|
||||
u16 sym_shndx = 0;
|
||||
if (rela_symtab && rela_strtab &&
|
||||
rela_symtab->entsize >= sizeof(elf64_sym) &&
|
||||
range_ok(rela_symtab->offset, rela_symtab->size, size)) {
|
||||
u64 sym_entry_off = (u64)sym_idx * rela_symtab->entsize;
|
||||
if (sym_entry_off + sizeof(elf64_sym) <= rela_symtab->size) {
|
||||
const elf64_sym *sym = (const elf64_sym *)((const u8 *)address + rela_symtab->offset + sym_entry_off);
|
||||
sym_value = sym->value;
|
||||
sym_shndx = sym->shndx;
|
||||
}
|
||||
}
|
||||
|
||||
u64 S = sym_value;
|
||||
if (sym_shndx > 0 && sym_shndx < 64) {
|
||||
S = (u64)image + image_offset[sym_shndx] + sym_value;
|
||||
}
|
||||
u64 P = (u64)image + image_offset[sh->info] + rela->offset;
|
||||
u64 A = rela->addend;
|
||||
|
||||
u64 patch = 0;
|
||||
if (reloc_type == R_X86_64_64) {
|
||||
patch = S + A;
|
||||
} else if (reloc_type == R_X86_64_32 || reloc_type == R_X86_64_32S) {
|
||||
patch = (u64)((i64)(i32)(S + A));
|
||||
} else if (reloc_type == R_X86_64_PC32) {
|
||||
patch = (u64)((i64)(i32)(S + A - P));
|
||||
} else {
|
||||
log_error("[DKM] unsupported relocation type");
|
||||
log_hex64("[DKM] reloc type=", (u64)reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rela->offset + 8 <= target->size) {
|
||||
if (reloc_type == R_X86_64_32 || reloc_type == R_X86_64_32S || reloc_type == R_X86_64_PC32) {
|
||||
*(u32 *)(target_base + rela->offset) = (u32)patch;
|
||||
} else {
|
||||
*(u64 *)(target_base + rela->offset) = patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const elf64_sym *desc_sym = (const elf64_sym *)symbols->driver_desc;
|
||||
const elf64_sym *init_sym = (const elf64_sym *)symbols->driver_init;
|
||||
const dkm_driver_desc *desc = (const dkm_driver_desc *)(image + image_offset[desc_sym->shndx] + desc_sym->value);
|
||||
if (desc->magic != DKM_DRIVER_MAGIC) {
|
||||
log_error("[DKM] external driver_desc magic mismatch");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_info("[DKM] external driver loaded");
|
||||
log_hex64("[DKM] desc ptr=", (u64)desc);
|
||||
log_hex64("[DKM] name ptr=", (u64)desc->name);
|
||||
log_info(desc->name);
|
||||
|
||||
dkm_driver_init_fn init = (dkm_driver_init_fn)(image + image_offset[init_sym->shndx] + init_sym->value);
|
||||
|
||||
dkm_driver_handle handle;
|
||||
handle.desc = desc;
|
||||
handle.state = DKM_STATE_INITING;
|
||||
handle.init_status = 0;
|
||||
handle.load_stage = desc->stage;
|
||||
handle.flags = desc->flags;
|
||||
|
||||
int result = init(dkm_get_kernel_api(), &handle);
|
||||
handle.init_status = result;
|
||||
if (result != 0) {
|
||||
handle.state = DKM_STATE_FAILED;
|
||||
log_error("[DKM] external driver init failed");
|
||||
return result;
|
||||
}
|
||||
handle.state = DKM_STATE_ACTIVE;
|
||||
log_info("[DKM] external driver active");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dkm_scan_boot_modules(void) {
|
||||
struct limine_module_response *response = g_module_request.response;
|
||||
if (!response) {
|
||||
log_warn("[DKM] no Limine module response");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("[DKM] boot modules scan begin");
|
||||
log_hex64("[DKM] boot module count=", response->module_count);
|
||||
|
||||
for (u64 i = 0; i < response->module_count; i++) {
|
||||
struct limine_file *file = response->modules[i];
|
||||
if (!file) {
|
||||
log_warn("[DKM] null module entry");
|
||||
continue;
|
||||
}
|
||||
|
||||
log_info("[DKM] module path");
|
||||
if (file->path) {
|
||||
log_info(file->path);
|
||||
}
|
||||
if (file->cmdline) {
|
||||
log_info(file->cmdline);
|
||||
}
|
||||
log_hex64("[DKM] module size=", file->size);
|
||||
|
||||
int status = dkm_check_elf64(file->address, file->size);
|
||||
if (status == 0) {
|
||||
log_info("[DKM] module ELF64 x86_64 ok");
|
||||
struct dkm_symbol_scan symbols;
|
||||
if (dkm_scan_symbols(file->address, file->size, &symbols) == 0) {
|
||||
log_info("[DKM] loading external ELF driver");
|
||||
int load_result = dkm_load_elf_rel(file->address, file->size, &symbols);
|
||||
if (load_result != 0) {
|
||||
log_error("[DKM] external driver load failed");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_error("[DKM] module ELF64 rejected");
|
||||
log_hex64("[DKM] elf status=", (u64)(i64)status);
|
||||
}
|
||||
}
|
||||
|
||||
log_info("[DKM] boot modules scan end");
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,47 @@
|
||||
#include <utsm/dkm.h>
|
||||
|
||||
static const char *const console_early_provides[] = {
|
||||
"console",
|
||||
"early-log"
|
||||
};
|
||||
|
||||
static const dkm_driver_desc console_early_desc = {
|
||||
.magic = DKM_DRIVER_MAGIC,
|
||||
.abi_version = DKM_ABI_VERSION,
|
||||
.desc_size = sizeof(dkm_driver_desc),
|
||||
.name = "console_early",
|
||||
.version = "0.1.0",
|
||||
.vendor = "Deshab",
|
||||
.driver_class = DKM_CLASS_CONSOLE,
|
||||
.stage = 0,
|
||||
.flags = DKM_F_REQUIRED | DKM_F_BOOT_MODULE | DKM_F_NO_UNLOAD | DKM_F_EARLY_LOG,
|
||||
.priority = 0,
|
||||
.depends = 0,
|
||||
.depends_count = 0,
|
||||
.provides = console_early_provides,
|
||||
.provides_count = 2,
|
||||
.min_kernel_abi = DKM_KERNEL_API_VERSION,
|
||||
.feature_bits = 0,
|
||||
.reserved0 = 0,
|
||||
.reserved1 = 0
|
||||
};
|
||||
|
||||
static int console_early_init(const dkm_kernel_api *api, dkm_driver_handle *handle) {
|
||||
(void)handle;
|
||||
if (!api || !api->log || !api->log->info) {
|
||||
return -1;
|
||||
}
|
||||
api->log->info("[DKM:console_early] serial console online");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int console_early_exit(dkm_driver_handle *handle) {
|
||||
(void)handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const dkm_builtin_driver dkm_builtin_console_early = {
|
||||
.desc = &console_early_desc,
|
||||
.init = console_early_init,
|
||||
.exit = console_early_exit
|
||||
};
|
||||
Binary file not shown.
@@ -0,0 +1,67 @@
|
||||
#include <utsm/dkm.h>
|
||||
#include <utsm/log.h>
|
||||
|
||||
static int dkm_validate_desc(const dkm_driver_desc *desc) {
|
||||
if (!desc) {
|
||||
return -1;
|
||||
}
|
||||
if (desc->magic != DKM_DRIVER_MAGIC) {
|
||||
return -2;
|
||||
}
|
||||
if (desc->abi_version != DKM_ABI_VERSION) {
|
||||
return -3;
|
||||
}
|
||||
if (desc->desc_size < sizeof(dkm_driver_desc)) {
|
||||
return -4;
|
||||
}
|
||||
if (!desc->name || !desc->version) {
|
||||
return -5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dkm_init(void) {
|
||||
log_info("[DKM] init begin");
|
||||
int status = dkm_load_builtin(&dkm_builtin_console_early);
|
||||
if (status == 0) {
|
||||
log_info("[DKM] init ok");
|
||||
} else {
|
||||
log_error("[DKM] init failed");
|
||||
}
|
||||
}
|
||||
|
||||
int dkm_load_builtin(const dkm_builtin_driver *driver) {
|
||||
if (!driver || !driver->desc || !driver->init) {
|
||||
log_error("[DKM] invalid builtin driver");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int status = dkm_validate_desc(driver->desc);
|
||||
if (status != 0) {
|
||||
log_error("[DKM] driver_desc rejected");
|
||||
return status;
|
||||
}
|
||||
|
||||
dkm_driver_handle handle;
|
||||
handle.desc = driver->desc;
|
||||
handle.state = DKM_STATE_ABI_CHECKED;
|
||||
handle.init_status = 0;
|
||||
handle.load_stage = driver->desc->stage;
|
||||
handle.flags = driver->desc->flags;
|
||||
|
||||
log_info("[DKM] builtin driver init begin");
|
||||
log_info(driver->desc->name);
|
||||
handle.state = DKM_STATE_INITING;
|
||||
status = driver->init(dkm_get_kernel_api(), &handle);
|
||||
handle.init_status = status;
|
||||
|
||||
if (status != 0) {
|
||||
handle.state = DKM_STATE_FAILED;
|
||||
log_error("[DKM] builtin driver init failed");
|
||||
return status;
|
||||
}
|
||||
|
||||
handle.state = DKM_STATE_ACTIVE;
|
||||
log_info("[DKM] builtin driver active");
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,90 @@
|
||||
#include <utsm/dkm.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/idt.h>
|
||||
#include <utsm/net.h>
|
||||
|
||||
static void dkm_api_info(const char *msg) {
|
||||
log_info(msg);
|
||||
}
|
||||
|
||||
static void dkm_api_warn(const char *msg) {
|
||||
log_warn(msg);
|
||||
}
|
||||
|
||||
static void dkm_api_error(const char *msg) {
|
||||
log_error(msg);
|
||||
}
|
||||
|
||||
static void dkm_api_panic(const char *msg) {
|
||||
log_error(msg);
|
||||
for (;;) {
|
||||
__asm__ volatile("cli; hlt");
|
||||
}
|
||||
}
|
||||
|
||||
static const dkm_log_api g_log_api = {
|
||||
.info = dkm_api_info,
|
||||
.warn = dkm_api_warn,
|
||||
.error = dkm_api_error,
|
||||
.panic = dkm_api_panic
|
||||
};
|
||||
|
||||
static dkm_kernel_api g_kernel_api = {
|
||||
.version = DKM_KERNEL_API_VERSION,
|
||||
.size = sizeof(dkm_kernel_api),
|
||||
.feature_bits = 0,
|
||||
.log = &g_log_api,
|
||||
.mem = 0,
|
||||
.utsm = 0,
|
||||
.irq = 0,
|
||||
.pci = 0,
|
||||
.dma = 0,
|
||||
.vfs = 0,
|
||||
.net = 0,
|
||||
.timer = 0,
|
||||
.drr = 0,
|
||||
.rsdp_address = 0,
|
||||
.fb_address = 0,
|
||||
.fb_width = 0,
|
||||
.fb_height = 0,
|
||||
.fb_pitch = 0,
|
||||
.fb_bpp = 0,
|
||||
.boot_modules_response = 0,
|
||||
.irq_register = 0,
|
||||
.hhdm_offset = 0,
|
||||
.block = 0
|
||||
};
|
||||
|
||||
const dkm_kernel_api *dkm_get_kernel_api(void) {
|
||||
return &g_kernel_api;
|
||||
}
|
||||
|
||||
#include "../arch/x86_64/limine.h"
|
||||
extern volatile struct limine_rsdp_request g_rsdp_request;
|
||||
extern volatile struct limine_framebuffer_request g_fb_request;
|
||||
extern volatile struct limine_module_request g_module_request;
|
||||
extern volatile struct limine_hhdm_request g_hhdm_request;
|
||||
|
||||
void dkm_fill_platform_info(void) {
|
||||
g_kernel_api.dma = dma_get_api();
|
||||
g_kernel_api.net = net_get_api();
|
||||
g_kernel_api.block = block_get_api();
|
||||
if (g_rsdp_request.response && g_rsdp_request.response->address) {
|
||||
g_kernel_api.rsdp_address = g_rsdp_request.response->address;
|
||||
}
|
||||
if (g_fb_request.response && g_fb_request.response->framebuffer_count > 0) {
|
||||
struct limine_framebuffer *fb = g_fb_request.response->framebuffers[0];
|
||||
g_kernel_api.fb_address = fb->address;
|
||||
g_kernel_api.fb_width = fb->width;
|
||||
g_kernel_api.fb_height = fb->height;
|
||||
g_kernel_api.fb_pitch = fb->pitch;
|
||||
g_kernel_api.fb_bpp = fb->bpp;
|
||||
}
|
||||
if (g_module_request.response) {
|
||||
g_kernel_api.boot_modules_response = g_module_request.response;
|
||||
}
|
||||
g_kernel_api.irq_register = (int (*)(u8,void*))((u64)irq_register);
|
||||
if (g_hhdm_request.response) {
|
||||
g_kernel_api.hhdm_offset = g_hhdm_request.response->offset;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,359 @@
|
||||
#include <utsm/dkm.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
#include "../arch/x86_64/limine.h"
|
||||
|
||||
#define DSM_MAX_DRIVERS_PER_STAGE 8
|
||||
#define DSM_MAX_STAGES 4
|
||||
#define DSM_MAX_DEPENDS 4
|
||||
#define DSM_MAX_PROVIDES 4
|
||||
|
||||
typedef struct dsm_driver_entry {
|
||||
char name[32];
|
||||
char path[64];
|
||||
u32 class_id;
|
||||
u32 required;
|
||||
char depends[DSM_MAX_DEPENDS][32];
|
||||
u32 depend_count;
|
||||
char provides[DSM_MAX_PROVIDES][32];
|
||||
u32 provide_count;
|
||||
struct limine_file *boot_module;
|
||||
int loaded;
|
||||
} dsm_driver_entry;
|
||||
|
||||
typedef struct dsm_stage_entry {
|
||||
u32 id;
|
||||
char name[16];
|
||||
u32 required;
|
||||
dsm_driver_entry drivers[DSM_MAX_DRIVERS_PER_STAGE];
|
||||
u32 driver_count;
|
||||
} dsm_stage_entry;
|
||||
|
||||
static dsm_stage_entry g_stages[DSM_MAX_STAGES];
|
||||
static u32 g_stage_count;
|
||||
|
||||
extern volatile struct limine_module_request g_module_request;
|
||||
|
||||
static int dsm_skip_ws(const char **p) {
|
||||
while (**p == ' ' || **p == '\t' || **p == '\n' || **p == '\r') { (*p)++; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsm_expect(const char **p, char c) {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == c) { (*p)++; return 0; }
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dsm_read_string(const char **p, char *out, u32 max_len) {
|
||||
dsm_skip_ws(p);
|
||||
if (**p != '"') return -1;
|
||||
(*p)++;
|
||||
u32 i = 0;
|
||||
while (**p && **p != '"' && i + 1 < max_len) {
|
||||
out[i++] = **p;
|
||||
(*p)++;
|
||||
}
|
||||
out[i] = 0;
|
||||
if (**p != '"') return -1;
|
||||
(*p)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsm_skip_value(const char **p) {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == '"') {
|
||||
char tmp[256];
|
||||
return dsm_read_string(p, tmp, sizeof(tmp));
|
||||
}
|
||||
if (**p == '{') {
|
||||
(*p)++;
|
||||
int depth = 1;
|
||||
while (depth > 0 && **p) {
|
||||
if (**p == '{') depth++;
|
||||
else if (**p == '}') depth--;
|
||||
else if (**p == '"') { (*p)++; while (**p && **p != '"') (*p)++; if (**p) (*p)++; continue; }
|
||||
if (depth > 0) (*p)++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (**p == '[') {
|
||||
(*p)++;
|
||||
int depth = 1;
|
||||
while (depth > 0 && **p) {
|
||||
if (**p == '[') depth++;
|
||||
else if (**p == ']') depth--;
|
||||
else if (**p == '"') { (*p)++; while (**p && **p != '"') (*p)++; if (**p) (*p)++; continue; }
|
||||
if (depth > 0) (*p)++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
while (**p && **p != ',' && **p != '}' && **p != ']') (*p)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct limine_file *dsm_find_boot_module(const char *path) {
|
||||
struct limine_module_response *rsp = g_module_request.response;
|
||||
if (!rsp) return 0;
|
||||
for (u64 i = 0; i < rsp->module_count; i++) {
|
||||
struct limine_file *f = rsp->modules[i];
|
||||
if (f && f->path) {
|
||||
const char *fp = f->path;
|
||||
while (*fp == '/') fp++;
|
||||
usize j = 0;
|
||||
usize k = 0;
|
||||
while (fp[j]) j++;
|
||||
while (path[k]) k++;
|
||||
if (j == k) {
|
||||
int match = 1;
|
||||
for (usize x = 0; x < j; x++) {
|
||||
if (fp[x] != path[x]) { match = 0; break; }
|
||||
}
|
||||
if (match) return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int streq_static(const char *a, const char *b) {
|
||||
usize i = 0;
|
||||
while (a[i] && b[i]) {
|
||||
if (a[i] != b[i]) return 0;
|
||||
i++;
|
||||
}
|
||||
return a[i] == b[i];
|
||||
}
|
||||
|
||||
static void dsm_parse_driver(const char **p, dsm_driver_entry *drv) {
|
||||
drv->depend_count = 0;
|
||||
drv->provide_count = 0;
|
||||
drv->required = 1;
|
||||
drv->boot_module = 0;
|
||||
drv->loaded = 0;
|
||||
drv->class_id = 0;
|
||||
|
||||
if (dsm_expect(p, '{') != 0) return;
|
||||
while (**p && **p != '}') {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == '}') break;
|
||||
char key[32];
|
||||
if (dsm_read_string(p, key, sizeof(key)) != 0) return;
|
||||
dsm_expect(p, ':');
|
||||
|
||||
if (streq_static(key, "name")) {
|
||||
dsm_read_string(p, drv->name, sizeof(drv->name));
|
||||
} else if (streq_static(key, "path")) {
|
||||
dsm_read_string(p, drv->path, sizeof(drv->path));
|
||||
} else if (streq_static(key, "class")) {
|
||||
char cls[32];
|
||||
dsm_read_string(p, cls, sizeof(cls));
|
||||
if (streq_static(cls, "platform")) drv->class_id = 1;
|
||||
else if (streq_static(cls, "bus")) drv->class_id = 2;
|
||||
else if (streq_static(cls, "interrupt")) drv->class_id = 3;
|
||||
else if (streq_static(cls, "timer")) drv->class_id = 4;
|
||||
else if (streq_static(cls, "console")) drv->class_id = 5;
|
||||
else if (streq_static(cls, "storage")) drv->class_id = 6;
|
||||
else if (streq_static(cls, "fs")) drv->class_id = 7;
|
||||
else if (streq_static(cls, "fs-core")) drv->class_id = 8;
|
||||
else if (streq_static(cls, "net")) drv->class_id = 9;
|
||||
else if (streq_static(cls, "input")) drv->class_id = 10;
|
||||
} else if (streq_static(key, "required")) {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == 't') { drv->required = 1; (*p) += 4; }
|
||||
else if (**p == 'f') { drv->required = 0; (*p) += 5; }
|
||||
} else if (streq_static(key, "depends")) {
|
||||
if (dsm_expect(p, '[') != 0) return;
|
||||
while (**p && **p != ']') {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ']') break;
|
||||
if (drv->depend_count < DSM_MAX_DEPENDS) {
|
||||
dsm_read_string(p, drv->depends[drv->depend_count], 32);
|
||||
drv->depend_count++;
|
||||
} else { dsm_skip_value(p); }
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ',') { (*p)++; continue; }
|
||||
if (**p == ']') break;
|
||||
}
|
||||
dsm_expect(p, ']');
|
||||
} else if (streq_static(key, "provides")) {
|
||||
if (dsm_expect(p, '[') != 0) return;
|
||||
while (**p && **p != ']') {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ']') break;
|
||||
if (drv->provide_count < DSM_MAX_PROVIDES) {
|
||||
dsm_read_string(p, drv->provides[drv->provide_count], 32);
|
||||
drv->provide_count++;
|
||||
} else { dsm_skip_value(p); }
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ',') { (*p)++; continue; }
|
||||
if (**p == ']') break;
|
||||
}
|
||||
dsm_expect(p, ']');
|
||||
} else {
|
||||
dsm_skip_value(p);
|
||||
}
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ',') (*p)++;
|
||||
}
|
||||
dsm_expect(p, '}');
|
||||
}
|
||||
|
||||
static void dsm_parse_stage(const char **p, dsm_stage_entry *stage) {
|
||||
stage->driver_count = 0;
|
||||
if (dsm_expect(p, '{') != 0) return;
|
||||
while (**p && **p != '}') {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == '}') break;
|
||||
char key[32];
|
||||
if (dsm_read_string(p, key, sizeof(key)) != 0) return;
|
||||
dsm_expect(p, ':');
|
||||
|
||||
if (streq_static(key, "id")) {
|
||||
dsm_skip_ws(p);
|
||||
u32 val = 0;
|
||||
while (**p >= '0' && **p <= '9') { val = val * 10 + (u32)(**p - '0'); (*p)++; }
|
||||
stage->id = val;
|
||||
} else if (streq_static(key, "name")) {
|
||||
dsm_read_string(p, stage->name, sizeof(stage->name));
|
||||
} else if (streq_static(key, "required")) {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == 't') { stage->required = 1; (*p) += 4; }
|
||||
else if (**p == 'f') { stage->required = 0; (*p) += 5; }
|
||||
} else if (streq_static(key, "drivers")) {
|
||||
if (dsm_expect(p, '[') != 0) return;
|
||||
while (**p && **p != ']') {
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ']') break;
|
||||
if (stage->driver_count < DSM_MAX_DRIVERS_PER_STAGE) {
|
||||
dsm_parse_driver(p, &stage->drivers[stage->driver_count]);
|
||||
stage->driver_count++;
|
||||
} else {
|
||||
dsm_skip_value(p);
|
||||
}
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ',') { (*p)++; continue; }
|
||||
if (**p == ']') break;
|
||||
}
|
||||
dsm_expect(p, ']');
|
||||
} else {
|
||||
dsm_skip_value(p);
|
||||
}
|
||||
dsm_skip_ws(p);
|
||||
if (**p == ',') (*p)++;
|
||||
}
|
||||
dsm_expect(p, '}');
|
||||
}
|
||||
|
||||
static int dsm_parse_manifest(const char *text, u64 size) {
|
||||
g_stage_count = 0;
|
||||
const char *p = text;
|
||||
const char *end = text + size;
|
||||
|
||||
while (p < end && *p) {
|
||||
dsm_skip_ws(&p);
|
||||
if (p >= end || !*p) break;
|
||||
if (*p == '{' || *p == '}') { p++; continue; }
|
||||
if (*p == ',' || *p == ':') { p++; continue; }
|
||||
if (*p == '[' || *p == ']') { p++; continue; }
|
||||
|
||||
char key[32];
|
||||
if (dsm_read_string(&p, key, sizeof(key)) != 0) break;
|
||||
dsm_expect(&p, ':');
|
||||
|
||||
if (streq_static(key, "stages")) {
|
||||
if (dsm_expect(&p, '[') != 0) return -1;
|
||||
while (p < end && *p) {
|
||||
dsm_skip_ws(&p);
|
||||
if (*p == ']') { p++; break; }
|
||||
if (g_stage_count < DSM_MAX_STAGES) {
|
||||
dsm_parse_stage(&p, &g_stages[g_stage_count]);
|
||||
g_stage_count++;
|
||||
}
|
||||
dsm_skip_ws(&p);
|
||||
if (*p == ',') p++;
|
||||
}
|
||||
} else {
|
||||
dsm_skip_value(&p);
|
||||
}
|
||||
dsm_skip_ws(&p);
|
||||
if (*p == ',' || *p == '}' || *p == ']') p++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dsm_load_by_manifest(void) {
|
||||
struct limine_module_response *rsp = g_module_request.response;
|
||||
if (!rsp) {
|
||||
log_warn("[DSM] no Limine module response");
|
||||
return;
|
||||
}
|
||||
|
||||
struct limine_file *manifest_file = 0;
|
||||
for (u64 i = 0; i < rsp->module_count; i++) {
|
||||
struct limine_file *f = rsp->modules[i];
|
||||
if (f && f->path && f->cmdline && streq_static(f->cmdline, "dkm:manifest")) {
|
||||
manifest_file = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!manifest_file) {
|
||||
log_warn("[DSM] manifest not found in boot modules");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("[DSM] parsing manifest");
|
||||
dsm_parse_manifest((const char *)manifest_file->address, manifest_file->size);
|
||||
log_info("[DSM] manifest parsed");
|
||||
log_hex64("[DSM] stages=", (u64)g_stage_count);
|
||||
|
||||
for (u32 si = 0; si < g_stage_count; si++) {
|
||||
dsm_stage_entry *stage = &g_stages[si];
|
||||
log_info("[DSM] stage begin");
|
||||
log_info(stage->name);
|
||||
log_hex64("[DSM] driver count=", stage->driver_count);
|
||||
|
||||
for (u32 di = 0; di < stage->driver_count; di++) {
|
||||
dsm_driver_entry *drv = &stage->drivers[di];
|
||||
|
||||
drv->boot_module = dsm_find_boot_module(drv->path);
|
||||
if (!drv->boot_module) {
|
||||
log_info("[DSM] module not found");
|
||||
log_info(drv->name);
|
||||
if (drv->required && stage->required) {
|
||||
log_error("[DSM] required module missing, abort stage");
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
struct limine_file *f = drv->boot_module;
|
||||
log_info("[DSM] loading driver");
|
||||
log_info(drv->name);
|
||||
|
||||
if (dkm_check_elf64(f->address, f->size) != 0) {
|
||||
log_error("[DSM] ELF check failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
struct dkm_symbol_scan symbols;
|
||||
if (dkm_scan_symbols(f->address, f->size, &symbols) != 0) {
|
||||
log_error("[DSM] symbol scan failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
int result = dkm_load_elf_rel(f->address, f->size, &symbols);
|
||||
if (result != 0) {
|
||||
log_error("[DSM] load failed");
|
||||
if (drv->required && stage->required) {
|
||||
log_error("[DSM] required driver failed, abort stage");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
drv->loaded = 1;
|
||||
}
|
||||
}
|
||||
log_info("[DSM] stage end");
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user