mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 18:44:01 +00:00
代码分类
This commit is contained in:
214
clks/kernel/runtime/driver.c
Normal file
214
clks/kernel/runtime/driver.c
Normal file
@@ -0,0 +1,214 @@
|
||||
#include <clks/driver.h>
|
||||
#include <clks/audio.h>
|
||||
#include <clks/elf64.h>
|
||||
#include <clks/framebuffer.h>
|
||||
#include <clks/fs.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_DRIVER_MAX 32U
|
||||
#define CLKS_DRIVER_CHILD_NAME_MAX 96U
|
||||
#define CLKS_DRIVER_PATH_MAX 224U
|
||||
|
||||
static struct clks_driver_info clks_driver_table[CLKS_DRIVER_MAX];
|
||||
static u64 clks_driver_table_count = 0ULL;
|
||||
static u64 clks_driver_table_elf_count = 0ULL;
|
||||
|
||||
static void clks_driver_copy_name(char *dst, usize dst_size, const char *src) {
|
||||
usize i = 0U;
|
||||
|
||||
if (dst == CLKS_NULL || dst_size == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (src == CLKS_NULL) {
|
||||
dst[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
while (i + 1U < dst_size && src[i] != '\0') {
|
||||
dst[i] = src[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
static clks_bool clks_driver_has_elf_suffix(const char *name) {
|
||||
usize len;
|
||||
|
||||
if (name == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
len = clks_strlen(name);
|
||||
|
||||
if (len < 4U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return (name[len - 4U] == '.' && name[len - 3U] == 'e' && name[len - 2U] == 'l' && name[len - 1U] == 'f')
|
||||
? CLKS_TRUE
|
||||
: CLKS_FALSE;
|
||||
}
|
||||
|
||||
static clks_bool clks_driver_build_path(const char *child_name, char *out_path, usize out_size) {
|
||||
static const char prefix[] = "/driver/";
|
||||
usize prefix_len = sizeof(prefix) - 1U;
|
||||
usize child_len;
|
||||
|
||||
if (child_name == CLKS_NULL || out_path == CLKS_NULL || out_size == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
child_len = clks_strlen(child_name);
|
||||
|
||||
if (prefix_len + child_len + 1U > out_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memcpy(out_path, prefix, prefix_len);
|
||||
clks_memcpy(out_path + prefix_len, child_name, child_len);
|
||||
out_path[prefix_len + child_len] = '\0';
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_driver_push(const char *name, enum clks_driver_kind kind, enum clks_driver_state state,
|
||||
clks_bool from_elf, u64 image_size, u64 elf_entry) {
|
||||
struct clks_driver_info *slot;
|
||||
|
||||
if (clks_driver_table_count >= CLKS_DRIVER_MAX) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
slot = &clks_driver_table[clks_driver_table_count];
|
||||
clks_memset(slot, 0, sizeof(*slot));
|
||||
|
||||
clks_driver_copy_name(slot->name, sizeof(slot->name), name);
|
||||
slot->kind = kind;
|
||||
slot->state = state;
|
||||
slot->from_elf = from_elf;
|
||||
slot->image_size = image_size;
|
||||
slot->elf_entry = elf_entry;
|
||||
|
||||
clks_driver_table_count++;
|
||||
|
||||
if (from_elf == CLKS_TRUE) {
|
||||
clks_driver_table_elf_count++;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_driver_register_builtins(void) {
|
||||
clks_driver_push("serial", CLKS_DRIVER_KIND_BUILTIN_CHAR, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL, 0ULL);
|
||||
|
||||
if (clks_fb_ready() == CLKS_TRUE) {
|
||||
clks_driver_push("framebuffer", CLKS_DRIVER_KIND_BUILTIN_VIDEO, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL,
|
||||
0ULL);
|
||||
clks_driver_push("tty", CLKS_DRIVER_KIND_BUILTIN_TTY, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL, 0ULL);
|
||||
} else {
|
||||
clks_driver_push("framebuffer", CLKS_DRIVER_KIND_BUILTIN_VIDEO, CLKS_DRIVER_STATE_FAILED, CLKS_FALSE, 0ULL,
|
||||
0ULL);
|
||||
clks_driver_push("tty", CLKS_DRIVER_KIND_BUILTIN_TTY, CLKS_DRIVER_STATE_FAILED, CLKS_FALSE, 0ULL, 0ULL);
|
||||
}
|
||||
|
||||
if (clks_audio_available() == CLKS_TRUE) {
|
||||
clks_driver_push("pcspeaker", CLKS_DRIVER_KIND_BUILTIN_AUDIO, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL, 0ULL);
|
||||
} else {
|
||||
clks_driver_push("pcspeaker", CLKS_DRIVER_KIND_BUILTIN_AUDIO, CLKS_DRIVER_STATE_FAILED, CLKS_FALSE, 0ULL, 0ULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_driver_probe_driver_dir(void) {
|
||||
u64 child_count;
|
||||
u64 i;
|
||||
|
||||
if (clks_fs_is_ready() == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "DRV", "FS NOT READY FOR DRIVER PROBE");
|
||||
return;
|
||||
}
|
||||
|
||||
child_count = clks_fs_count_children("/driver");
|
||||
|
||||
for (i = 0ULL; i < child_count; i++) {
|
||||
char child_name[CLKS_DRIVER_CHILD_NAME_MAX];
|
||||
char full_path[CLKS_DRIVER_PATH_MAX];
|
||||
const void *image;
|
||||
u64 image_size = 0ULL;
|
||||
struct clks_elf64_info info;
|
||||
|
||||
clks_memset(child_name, 0, sizeof(child_name));
|
||||
clks_memset(full_path, 0, sizeof(full_path));
|
||||
|
||||
if (clks_fs_get_child_name("/driver", i, child_name, sizeof(child_name)) == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_driver_has_elf_suffix(child_name) == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_driver_build_path(child_name, full_path, sizeof(full_path)) == CLKS_FALSE) {
|
||||
clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_FAILED, CLKS_TRUE, 0ULL, 0ULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
image = clks_fs_read_all(full_path, &image_size);
|
||||
|
||||
if (image == CLKS_NULL) {
|
||||
clks_log(CLKS_LOG_ERROR, "DRV", "DRIVER ELF MISSING");
|
||||
clks_log(CLKS_LOG_ERROR, "DRV", full_path);
|
||||
clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_FAILED, CLKS_TRUE, 0ULL, 0ULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_elf64_inspect(image, image_size, &info) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "DRV", "DRIVER ELF INVALID");
|
||||
clks_log(CLKS_LOG_ERROR, "DRV", full_path);
|
||||
clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_FAILED, CLKS_TRUE, image_size, 0ULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "DRV", "DRIVER ELF READY");
|
||||
clks_log(CLKS_LOG_INFO, "DRV", full_path);
|
||||
clks_log_hex(CLKS_LOG_INFO, "DRV", "ENTRY", info.entry);
|
||||
|
||||
clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_READY, CLKS_TRUE, image_size, info.entry);
|
||||
}
|
||||
}
|
||||
|
||||
void clks_driver_init(void) {
|
||||
clks_memset(clks_driver_table, 0, sizeof(clks_driver_table));
|
||||
clks_driver_table_count = 0ULL;
|
||||
clks_driver_table_elf_count = 0ULL;
|
||||
|
||||
clks_driver_register_builtins();
|
||||
clks_driver_probe_driver_dir();
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "DRV", "DRIVER MANAGER ONLINE");
|
||||
clks_log_hex(CLKS_LOG_INFO, "DRV", "REGISTERED", clks_driver_table_count);
|
||||
clks_log_hex(CLKS_LOG_INFO, "DRV", "ELF_DRIVERS", clks_driver_table_elf_count);
|
||||
}
|
||||
|
||||
u64 clks_driver_count(void) {
|
||||
return clks_driver_table_count;
|
||||
}
|
||||
|
||||
u64 clks_driver_elf_count(void) {
|
||||
return clks_driver_table_elf_count;
|
||||
}
|
||||
|
||||
clks_bool clks_driver_get(u64 index, struct clks_driver_info *out_info) {
|
||||
if (out_info == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (index >= clks_driver_table_count) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_info = clks_driver_table[index];
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
309
clks/kernel/runtime/elf64.c
Normal file
309
clks/kernel/runtime/elf64.c
Normal file
@@ -0,0 +1,309 @@
|
||||
#include <clks/elf64.h>
|
||||
#include <clks/heap.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_ELF64_MAGIC_0 0x7FU
|
||||
#define CLKS_ELF64_MAGIC_1 'E'
|
||||
#define CLKS_ELF64_MAGIC_2 'L'
|
||||
#define CLKS_ELF64_MAGIC_3 'F'
|
||||
|
||||
#define CLKS_ELF64_CLASS_64 2U
|
||||
#define CLKS_ELF64_DATA_LSB 1U
|
||||
#define CLKS_ELF64_VERSION 1U
|
||||
|
||||
#define CLKS_ELF64_ET_EXEC 2U
|
||||
#define CLKS_ELF64_ET_DYN 3U
|
||||
|
||||
#define CLKS_ELF64_EM_X86_64 62U
|
||||
|
||||
struct clks_elf64_ehdr {
|
||||
u8 e_ident[16];
|
||||
u16 e_type;
|
||||
u16 e_machine;
|
||||
u32 e_version;
|
||||
u64 e_entry;
|
||||
u64 e_phoff;
|
||||
u64 e_shoff;
|
||||
u32 e_flags;
|
||||
u16 e_ehsize;
|
||||
u16 e_phentsize;
|
||||
u16 e_phnum;
|
||||
u16 e_shentsize;
|
||||
u16 e_shnum;
|
||||
u16 e_shstrndx;
|
||||
};
|
||||
|
||||
struct clks_elf64_phdr {
|
||||
u32 p_type;
|
||||
u32 p_flags;
|
||||
u64 p_offset;
|
||||
u64 p_vaddr;
|
||||
u64 p_paddr;
|
||||
u64 p_filesz;
|
||||
u64 p_memsz;
|
||||
u64 p_align;
|
||||
};
|
||||
|
||||
static clks_bool clks_elf64_header_ok(const struct clks_elf64_ehdr *eh) {
|
||||
if (eh->e_ident[0] != CLKS_ELF64_MAGIC_0 || eh->e_ident[1] != CLKS_ELF64_MAGIC_1 ||
|
||||
eh->e_ident[2] != CLKS_ELF64_MAGIC_2 || eh->e_ident[3] != CLKS_ELF64_MAGIC_3) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_ident[4] != CLKS_ELF64_CLASS_64 || eh->e_ident[5] != CLKS_ELF64_DATA_LSB) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_ident[6] != CLKS_ELF64_VERSION || eh->e_version != CLKS_ELF64_VERSION) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_type != CLKS_ELF64_ET_EXEC && eh->e_type != CLKS_ELF64_ET_DYN) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_machine != CLKS_ELF64_EM_X86_64) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_ehsize != sizeof(struct clks_elf64_ehdr)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_phentsize != sizeof(struct clks_elf64_phdr)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_elf64_range_ok(u64 off, u64 len, u64 total) {
|
||||
if (off > total) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (len > (total - off)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_elf64_validate(const void *image, u64 size) {
|
||||
const struct clks_elf64_ehdr *eh;
|
||||
u64 ph_table_size;
|
||||
u16 i;
|
||||
|
||||
if (image == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (size < sizeof(struct clks_elf64_ehdr)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
eh = (const struct clks_elf64_ehdr *)image;
|
||||
|
||||
if (clks_elf64_header_ok(eh) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
ph_table_size = (u64)eh->e_phnum * (u64)eh->e_phentsize;
|
||||
|
||||
if (clks_elf64_range_ok(eh->e_phoff, ph_table_size, size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ph->p_filesz > ph->p_memsz) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_elf64_range_ok(ph->p_offset, ph->p_filesz, size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_elf64_inspect(const void *image, u64 size, struct clks_elf64_info *out_info) {
|
||||
const struct clks_elf64_ehdr *eh;
|
||||
u16 i;
|
||||
|
||||
if (out_info == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memset(out_info, 0, sizeof(*out_info));
|
||||
|
||||
if (clks_elf64_validate(image, size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
eh = (const struct clks_elf64_ehdr *)image;
|
||||
|
||||
out_info->entry = eh->e_entry;
|
||||
out_info->phnum = eh->e_phnum;
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
out_info->loadable_segments++;
|
||||
out_info->total_load_memsz += ph->p_memsz;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_image *out_loaded) {
|
||||
const struct clks_elf64_ehdr *eh;
|
||||
u16 i;
|
||||
u16 load_count = 0U;
|
||||
u64 min_vaddr = 0ULL;
|
||||
u64 max_vaddr_end = 0ULL;
|
||||
u64 span;
|
||||
void *image_base;
|
||||
|
||||
if (out_loaded == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memset(out_loaded, 0, sizeof(*out_loaded));
|
||||
|
||||
if (clks_elf64_validate(image, size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
eh = (const struct clks_elf64_ehdr *)image;
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
u64 seg_end;
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (load_count == 0U || ph->p_vaddr < min_vaddr) {
|
||||
min_vaddr = ph->p_vaddr;
|
||||
}
|
||||
|
||||
seg_end = ph->p_vaddr + ph->p_memsz;
|
||||
if (seg_end < ph->p_vaddr) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (load_count == 0U || seg_end > max_vaddr_end) {
|
||||
max_vaddr_end = seg_end;
|
||||
}
|
||||
|
||||
load_count++;
|
||||
}
|
||||
|
||||
if (load_count == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (load_count > CLKS_ELF64_MAX_SEGMENTS) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
span = max_vaddr_end - min_vaddr;
|
||||
if (span == 0ULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
image_base = clks_kmalloc((usize)span);
|
||||
if (image_base == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memset(image_base, 0, (usize)span);
|
||||
|
||||
out_loaded->entry = eh->e_entry;
|
||||
out_loaded->image_base = image_base;
|
||||
out_loaded->image_size = span;
|
||||
out_loaded->image_vaddr_base = min_vaddr;
|
||||
out_loaded->segment_count = 0U;
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
u64 seg_off;
|
||||
u8 *seg_dst;
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (out_loaded->segment_count >= CLKS_ELF64_MAX_SEGMENTS) {
|
||||
clks_elf64_unload(out_loaded);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
seg_off = ph->p_vaddr - min_vaddr;
|
||||
if (seg_off > span || ph->p_memsz > (span - seg_off)) {
|
||||
clks_elf64_unload(out_loaded);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
seg_dst = (u8 *)image_base + (usize)seg_off;
|
||||
clks_memcpy(seg_dst, (const void *)((const u8 *)image + ph->p_offset), (usize)ph->p_filesz);
|
||||
|
||||
out_loaded->segments[out_loaded->segment_count].base = seg_dst;
|
||||
out_loaded->segments[out_loaded->segment_count].vaddr = ph->p_vaddr;
|
||||
out_loaded->segments[out_loaded->segment_count].memsz = ph->p_memsz;
|
||||
out_loaded->segments[out_loaded->segment_count].filesz = ph->p_filesz;
|
||||
out_loaded->segments[out_loaded->segment_count].flags = ph->p_flags;
|
||||
out_loaded->segment_count++;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
void clks_elf64_unload(struct clks_elf64_loaded_image *loaded) {
|
||||
if (loaded == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (loaded->image_base != CLKS_NULL) {
|
||||
clks_kfree(loaded->image_base);
|
||||
}
|
||||
|
||||
clks_memset(loaded, 0, sizeof(*loaded));
|
||||
}
|
||||
|
||||
void *clks_elf64_entry_pointer(const struct clks_elf64_loaded_image *loaded, u64 entry) {
|
||||
u64 off;
|
||||
|
||||
if (loaded == CLKS_NULL || loaded->image_base == CLKS_NULL) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (entry < loaded->image_vaddr_base) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
off = entry - loaded->image_vaddr_base;
|
||||
|
||||
if (off >= loaded->image_size) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
return (void *)((u8 *)loaded->image_base + (usize)off);
|
||||
}
|
||||
38
clks/kernel/runtime/elfrunner.c
Normal file
38
clks/kernel/runtime/elfrunner.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <clks/boot.h>
|
||||
#include <clks/elf64.h>
|
||||
#include <clks/elfrunner.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
static clks_bool clks_elfrunner_ready = CLKS_FALSE;
|
||||
|
||||
void clks_elfrunner_init(void) {
|
||||
clks_elfrunner_ready = CLKS_TRUE;
|
||||
clks_log(CLKS_LOG_INFO, "ELF", "ELFRUNNER FRAMEWORK ONLINE");
|
||||
}
|
||||
|
||||
clks_bool clks_elfrunner_probe_kernel_executable(void) {
|
||||
const struct limine_file *exe = clks_boot_get_executable_file();
|
||||
struct clks_elf64_info info;
|
||||
|
||||
if (clks_elfrunner_ready == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (exe == CLKS_NULL || exe->address == CLKS_NULL || exe->size == 0ULL) {
|
||||
clks_log(CLKS_LOG_ERROR, "ELF", "NO EXECUTABLE FILE FROM LIMINE");
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_elf64_inspect(exe->address, exe->size, &info) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "ELF", "KERNEL ELF INSPECT FAILED");
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_log_hex(CLKS_LOG_INFO, "ELF", "ENTRY", info.entry);
|
||||
clks_log_hex(CLKS_LOG_INFO, "ELF", "PHNUM", info.phnum);
|
||||
clks_log_hex(CLKS_LOG_INFO, "ELF", "LOAD_SEGMENTS", info.loadable_segments);
|
||||
clks_log_hex(CLKS_LOG_INFO, "ELF", "TOTAL_MEMSZ", info.total_load_memsz);
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
2528
clks/kernel/runtime/exec.c
Normal file
2528
clks/kernel/runtime/exec.c
Normal file
File diff suppressed because it is too large
Load Diff
250
clks/kernel/runtime/kelf.c
Normal file
250
clks/kernel/runtime/kelf.c
Normal file
@@ -0,0 +1,250 @@
|
||||
#include <clks/elf64.h>
|
||||
#include <clks/fs.h>
|
||||
#include <clks/heap.h>
|
||||
#include <clks/kelf.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_KELF_MAX_APPS 8U
|
||||
#define CLKS_ELF64_PT_LOAD 1U
|
||||
|
||||
struct clks_elf64_ehdr {
|
||||
u8 e_ident[16];
|
||||
u16 e_type;
|
||||
u16 e_machine;
|
||||
u32 e_version;
|
||||
u64 e_entry;
|
||||
u64 e_phoff;
|
||||
u64 e_shoff;
|
||||
u32 e_flags;
|
||||
u16 e_ehsize;
|
||||
u16 e_phentsize;
|
||||
u16 e_phnum;
|
||||
u16 e_shentsize;
|
||||
u16 e_shnum;
|
||||
u16 e_shstrndx;
|
||||
};
|
||||
|
||||
struct clks_elf64_phdr {
|
||||
u32 p_type;
|
||||
u32 p_flags;
|
||||
u64 p_offset;
|
||||
u64 p_vaddr;
|
||||
u64 p_paddr;
|
||||
u64 p_filesz;
|
||||
u64 p_memsz;
|
||||
u64 p_align;
|
||||
};
|
||||
|
||||
struct clks_kelf_app {
|
||||
clks_bool loaded;
|
||||
char path[64];
|
||||
void *runtime_image;
|
||||
u64 runtime_size;
|
||||
clks_kelf_entry_fn entry;
|
||||
u64 run_count;
|
||||
u64 last_run_tick;
|
||||
u64 last_ret;
|
||||
};
|
||||
|
||||
static struct clks_kelf_app clks_kelf_apps[CLKS_KELF_MAX_APPS];
|
||||
static u64 clks_kelf_app_count = 0ULL;
|
||||
static u64 clks_kelf_total_runs_count = 0ULL;
|
||||
static u64 clks_kelf_rr_index = 0ULL;
|
||||
static u64 clks_kelf_last_dispatch_tick = 0ULL;
|
||||
|
||||
static void clks_kelf_copy_name(char *dst, usize dst_size, const char *src) {
|
||||
usize i = 0U;
|
||||
|
||||
if (dst == CLKS_NULL || dst_size == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (i + 1U < dst_size && src[i] != '\0') {
|
||||
dst[i] = src[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
static clks_bool clks_kelf_load_runtime_image(const void *image, u64 size, void **out_runtime, u64 *out_runtime_size,
|
||||
clks_kelf_entry_fn *out_entry) {
|
||||
const struct clks_elf64_ehdr *eh;
|
||||
u64 min_vaddr = 0xffffffffffffffffULL;
|
||||
u64 max_vaddr = 0ULL;
|
||||
u16 i;
|
||||
u8 *runtime;
|
||||
|
||||
if (out_runtime == CLKS_NULL || out_runtime_size == CLKS_NULL || out_entry == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_elf64_validate(image, size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
eh = (const struct clks_elf64_ehdr *)image;
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
u64 seg_end;
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ph->p_filesz > ph->p_memsz) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (ph->p_offset > size || ph->p_filesz > (size - ph->p_offset)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
seg_end = ph->p_vaddr + ph->p_memsz;
|
||||
|
||||
if (seg_end < ph->p_vaddr) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (ph->p_vaddr < min_vaddr) {
|
||||
min_vaddr = ph->p_vaddr;
|
||||
}
|
||||
|
||||
if (seg_end > max_vaddr) {
|
||||
max_vaddr = seg_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_vaddr <= min_vaddr) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_runtime_size = max_vaddr - min_vaddr;
|
||||
runtime = (u8 *)clks_kmalloc((usize)(*out_runtime_size));
|
||||
|
||||
if (runtime == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memset(runtime, 0, (usize)(*out_runtime_size));
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
clks_memcpy(runtime + (usize)(ph->p_vaddr - min_vaddr), (const u8 *)image + ph->p_offset, (usize)ph->p_filesz);
|
||||
}
|
||||
|
||||
if (eh->e_entry < min_vaddr || eh->e_entry >= max_vaddr) {
|
||||
clks_kfree(runtime);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_entry = (clks_kelf_entry_fn)(void *)(runtime + (usize)(eh->e_entry - min_vaddr));
|
||||
*out_runtime = runtime;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_kelf_probe_path(const char *path) {
|
||||
const void *image;
|
||||
u64 size = 0ULL;
|
||||
void *runtime = CLKS_NULL;
|
||||
u64 runtime_size = 0ULL;
|
||||
clks_kelf_entry_fn entry = CLKS_NULL;
|
||||
struct clks_kelf_app *slot;
|
||||
|
||||
if (clks_kelf_app_count >= CLKS_KELF_MAX_APPS) {
|
||||
return;
|
||||
}
|
||||
|
||||
image = clks_fs_read_all(path, &size);
|
||||
|
||||
if (image == CLKS_NULL || size == 0ULL) {
|
||||
clks_log(CLKS_LOG_WARN, "KELF", "APP FILE NOT FOUND");
|
||||
clks_log(CLKS_LOG_WARN, "KELF", path);
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_kelf_load_runtime_image(image, size, &runtime, &runtime_size, &entry) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "KELF", "APP LOAD FAILED");
|
||||
clks_log(CLKS_LOG_ERROR, "KELF", path);
|
||||
return;
|
||||
}
|
||||
|
||||
slot = &clks_kelf_apps[clks_kelf_app_count];
|
||||
clks_memset(slot, 0, sizeof(*slot));
|
||||
|
||||
slot->loaded = CLKS_TRUE;
|
||||
clks_kelf_copy_name(slot->path, sizeof(slot->path), path);
|
||||
slot->runtime_image = runtime;
|
||||
slot->runtime_size = runtime_size;
|
||||
slot->entry = entry;
|
||||
|
||||
clks_kelf_app_count++;
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "KELF", "APP READY");
|
||||
clks_log(CLKS_LOG_INFO, "KELF", path);
|
||||
clks_log_hex(CLKS_LOG_INFO, "KELF", "RUNTIME_SIZE", runtime_size);
|
||||
}
|
||||
|
||||
void clks_kelf_init(void) {
|
||||
clks_memset(clks_kelf_apps, 0, sizeof(clks_kelf_apps));
|
||||
clks_kelf_app_count = 0ULL;
|
||||
clks_kelf_total_runs_count = 0ULL;
|
||||
clks_kelf_rr_index = 0ULL;
|
||||
clks_kelf_last_dispatch_tick = 0ULL;
|
||||
|
||||
clks_kelf_probe_path("/system/elfrunner.elf");
|
||||
clks_kelf_probe_path("/system/memc.elf");
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "KELF", "EXECUTOR ONLINE");
|
||||
clks_log_hex(CLKS_LOG_INFO, "KELF", "APP_COUNT", clks_kelf_app_count);
|
||||
}
|
||||
|
||||
void clks_kelf_tick(u64 tick) {
|
||||
struct clks_kelf_app *app;
|
||||
|
||||
if (clks_kelf_app_count == 0ULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tick - clks_kelf_last_dispatch_tick < 200ULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
clks_kelf_last_dispatch_tick = tick;
|
||||
app = &clks_kelf_apps[clks_kelf_rr_index % clks_kelf_app_count];
|
||||
clks_kelf_rr_index++;
|
||||
|
||||
if (app->loaded == CLKS_FALSE || app->entry == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
app->run_count++;
|
||||
app->last_run_tick = tick;
|
||||
/* NX-safe stage mode: keep dispatch accounting without jumping into runtime image. */
|
||||
app->last_ret = (tick ^ (app->run_count << 8)) + clks_kelf_rr_index;
|
||||
clks_kelf_total_runs_count++;
|
||||
|
||||
if ((app->run_count & 0x7ULL) == 1ULL) {
|
||||
clks_log(CLKS_LOG_DEBUG, "KELF", "APP DISPATCHED");
|
||||
clks_log(CLKS_LOG_DEBUG, "KELF", app->path);
|
||||
clks_log_hex(CLKS_LOG_DEBUG, "KELF", "RET", app->last_ret);
|
||||
}
|
||||
}
|
||||
|
||||
u64 clks_kelf_count(void) {
|
||||
return clks_kelf_app_count;
|
||||
}
|
||||
|
||||
u64 clks_kelf_total_runs(void) {
|
||||
return clks_kelf_total_runs_count;
|
||||
}
|
||||
1957
clks/kernel/runtime/syscall.c
Normal file
1957
clks/kernel/runtime/syscall.c
Normal file
File diff suppressed because it is too large
Load Diff
183
clks/kernel/runtime/userland.c
Normal file
183
clks/kernel/runtime/userland.c
Normal file
@@ -0,0 +1,183 @@
|
||||
#include <clks/elf64.h>
|
||||
#include <clks/exec.h>
|
||||
#include <clks/fs.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/types.h>
|
||||
#include <clks/userland.h>
|
||||
|
||||
#define CLKS_USERLAND_RETRY_INTERVAL 500ULL
|
||||
|
||||
#ifndef CLKS_CFG_USERLAND_AUTO_EXEC
|
||||
#define CLKS_CFG_USERLAND_AUTO_EXEC 1
|
||||
#endif
|
||||
|
||||
#ifndef CLKS_CFG_USER_INIT_SCRIPT_PROBE
|
||||
#define CLKS_CFG_USER_INIT_SCRIPT_PROBE 1
|
||||
#endif
|
||||
|
||||
#ifndef CLKS_CFG_USER_SYSTEM_APP_PROBE
|
||||
#define CLKS_CFG_USER_SYSTEM_APP_PROBE 1
|
||||
#endif
|
||||
|
||||
static clks_bool clks_user_shell_ready = CLKS_FALSE;
|
||||
static clks_bool clks_user_shell_exec_requested_flag = CLKS_FALSE;
|
||||
static clks_bool clks_user_shell_exec_enabled = CLKS_FALSE;
|
||||
static u64 clks_user_launch_attempt_count = 0ULL;
|
||||
static u64 clks_user_launch_success_count = 0ULL;
|
||||
static u64 clks_user_launch_fail_count = 0ULL;
|
||||
static u64 clks_user_last_try_tick = 0ULL;
|
||||
static clks_bool clks_user_first_try_pending = CLKS_FALSE;
|
||||
|
||||
static clks_bool clks_userland_probe_elf(const char *path, const char *tag) {
|
||||
const void *image;
|
||||
u64 size = 0ULL;
|
||||
struct clks_elf64_info info;
|
||||
|
||||
image = clks_fs_read_all(path, &size);
|
||||
|
||||
if (image == CLKS_NULL) {
|
||||
clks_log(CLKS_LOG_ERROR, "USER", "ELF FILE MISSING");
|
||||
clks_log(CLKS_LOG_ERROR, "USER", path);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_elf64_inspect(image, size, &info) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "USER", "ELF INSPECT FAILED");
|
||||
clks_log(CLKS_LOG_ERROR, "USER", path);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "USER", tag);
|
||||
clks_log_hex(CLKS_LOG_INFO, "USER", "ELF_SIZE", size);
|
||||
clks_log_hex(CLKS_LOG_INFO, "USER", "ENTRY", info.entry);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
#if CLKS_CFG_USER_INIT_SCRIPT_PROBE
|
||||
static void clks_userland_probe_init_script(void) {
|
||||
const void *data;
|
||||
u64 size = 0ULL;
|
||||
|
||||
data = clks_fs_read_all("/shell/init.cmd", &size);
|
||||
|
||||
if (data == CLKS_NULL || size == 0ULL) {
|
||||
clks_log(CLKS_LOG_WARN, "USER", "INIT SCRIPT NOT FOUND /SHELL/INIT.CMD");
|
||||
return;
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "USER", "INIT SCRIPT READY /SHELL/INIT.CMD");
|
||||
clks_log_hex(CLKS_LOG_INFO, "USER", "INIT_SCRIPT_SIZE", size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static clks_bool clks_userland_request_shell_exec(void) {
|
||||
u64 status = (u64)-1;
|
||||
|
||||
if (clks_user_shell_ready == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_user_launch_attempt_count++;
|
||||
|
||||
if (clks_exec_run_path("/shell/shell.elf", &status) == CLKS_TRUE && status == 0ULL) {
|
||||
clks_user_shell_exec_requested_flag = CLKS_TRUE;
|
||||
clks_user_launch_success_count++;
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "USER", "SHELL EXEC REQUESTED");
|
||||
clks_log_hex(CLKS_LOG_INFO, "USER", "SHELL_STATUS", status);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_user_launch_fail_count++;
|
||||
clks_log(CLKS_LOG_WARN, "USER", "SHELL EXEC REQUEST FAILED");
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_bool clks_userland_init(void) {
|
||||
clks_log(CLKS_LOG_INFO, "USER", "USERLAND FRAMEWORK ONLINE");
|
||||
|
||||
clks_user_shell_ready = CLKS_FALSE;
|
||||
clks_user_shell_exec_requested_flag = CLKS_FALSE;
|
||||
clks_user_shell_exec_enabled = (CLKS_CFG_USERLAND_AUTO_EXEC != 0) ? CLKS_TRUE : CLKS_FALSE;
|
||||
clks_user_launch_attempt_count = 0ULL;
|
||||
clks_user_launch_success_count = 0ULL;
|
||||
clks_user_launch_fail_count = 0ULL;
|
||||
clks_user_last_try_tick = 0ULL;
|
||||
clks_user_first_try_pending = CLKS_TRUE;
|
||||
|
||||
if (clks_userland_probe_elf("/shell/shell.elf", "SHELL ELF READY") == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_user_shell_ready = CLKS_TRUE;
|
||||
clks_log(CLKS_LOG_INFO, "USER", "SHELL COMMAND ABI READY");
|
||||
#if CLKS_CFG_USER_INIT_SCRIPT_PROBE
|
||||
clks_userland_probe_init_script();
|
||||
#else
|
||||
clks_log(CLKS_LOG_WARN, "USER", "INIT SCRIPT PROBE DISABLED BY MENUCONFIG");
|
||||
#endif
|
||||
|
||||
#if CLKS_CFG_USER_SYSTEM_APP_PROBE
|
||||
if (clks_userland_probe_elf("/system/elfrunner.elf", "ELFRUNNER ELF READY") == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_userland_probe_elf("/system/memc.elf", "MEMC ELF READY") == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
#else
|
||||
clks_log(CLKS_LOG_WARN, "USER", "SYSTEM APP PROBE DISABLED BY MENUCONFIG");
|
||||
#endif
|
||||
|
||||
if (clks_user_shell_exec_enabled == CLKS_TRUE) {
|
||||
clks_log(CLKS_LOG_INFO, "USER", "USER SHELL AUTO EXEC ENABLED");
|
||||
} else {
|
||||
clks_log(CLKS_LOG_WARN, "USER", "USER SHELL AUTO EXEC DISABLED BY MENUCONFIG");
|
||||
}
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
void clks_userland_tick(u64 tick) {
|
||||
if (clks_user_shell_exec_enabled == CLKS_FALSE || clks_user_shell_ready == CLKS_FALSE ||
|
||||
clks_user_shell_exec_requested_flag == CLKS_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_user_first_try_pending == CLKS_TRUE) {
|
||||
clks_user_first_try_pending = CLKS_FALSE;
|
||||
clks_user_last_try_tick = tick;
|
||||
(void)clks_userland_request_shell_exec();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tick - clks_user_last_try_tick < CLKS_USERLAND_RETRY_INTERVAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
clks_user_last_try_tick = tick;
|
||||
(void)clks_userland_request_shell_exec();
|
||||
}
|
||||
|
||||
clks_bool clks_userland_shell_ready(void) {
|
||||
return clks_user_shell_ready;
|
||||
}
|
||||
|
||||
clks_bool clks_userland_shell_exec_requested(void) {
|
||||
return clks_user_shell_exec_requested_flag;
|
||||
}
|
||||
|
||||
clks_bool clks_userland_shell_auto_exec_enabled(void) {
|
||||
return clks_user_shell_exec_enabled;
|
||||
}
|
||||
|
||||
u64 clks_userland_launch_attempts(void) {
|
||||
return clks_user_launch_attempt_count;
|
||||
}
|
||||
|
||||
u64 clks_userland_launch_success(void) {
|
||||
return clks_user_launch_success_count;
|
||||
}
|
||||
|
||||
u64 clks_userland_launch_failures(void) {
|
||||
return clks_user_launch_fail_count;
|
||||
}
|
||||
Reference in New Issue
Block a user