This commit is contained in:
2026-04-12 19:31:01 +08:00
parent 138c685de1
commit aa8c0bd8d1
13 changed files with 2188 additions and 29 deletions

View File

@@ -345,6 +345,7 @@ set(USER_APP_NAMES)
set(RAMDISK_SHELL_APPS)
set(RAMDISK_DRIVER_APPS)
set(RAMDISK_SYSTEM_APPS)
set(RAMDISK_ROOT_APPS)
foreach(SRC IN LISTS USER_APP_MAIN_SOURCES)
get_filename_component(_stem "${SRC}" NAME_WE)
@@ -375,6 +376,8 @@ foreach(SRC IN LISTS USER_APP_MAIN_SOURCES)
list(APPEND USER_APP_OUTPUTS "${_app_out}")
if(_app_name MATCHES ".*drv$")
list(APPEND RAMDISK_DRIVER_APPS "${_app_out}")
elseif(_app_name STREQUAL "hello")
list(APPEND RAMDISK_ROOT_APPS "${_app_out}")
else()
list(APPEND RAMDISK_SHELL_APPS "${_app_out}")
endif()
@@ -427,6 +430,10 @@ foreach(_app IN LISTS RAMDISK_SHELL_APPS)
get_filename_component(_app_file "${_app}" NAME)
list(APPEND RAMDISK_COPY_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy "${_app}" "${RAMDISK_ROOT}/shell/${_app_file}")
endforeach()
foreach(_app IN LISTS RAMDISK_ROOT_APPS)
get_filename_component(_app_file "${_app}" NAME)
list(APPEND RAMDISK_COPY_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy "${_app}" "${RAMDISK_ROOT}/${_app_file}")
endforeach()
foreach(_app IN LISTS RAMDISK_DRIVER_APPS)
get_filename_component(_app_file "${_app}" NAME)
list(APPEND RAMDISK_COPY_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy "${_app}" "${RAMDISK_ROOT}/driver/${_app_file}")
@@ -616,3 +623,4 @@ add_custom_target(cleonos-help
COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target run"
COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target debug"
)

View File

@@ -0,0 +1,7 @@
#include <cleonos_syscall.h>
int cleonos_app_main(void) {
static const char msg[] = "[USER][HELLO] Hello world from /hello.elf\n";
(void)cleonos_sys_tty_write(msg, (u64)(sizeof(msg) - 1U));
return 0;
}

View File

@@ -4,13 +4,9 @@ typedef int (*cleonos_entry_fn)(void);
extern int cleonos_app_main(void);
void _start(void) {
volatile int code;
u64 _start(void) {
int code;
code = ((cleonos_entry_fn)cleonos_app_main)();
(void)code;
for (;;) {
__asm__ volatile("pause");
}
return (u64)code;
}

View File

@@ -4,7 +4,7 @@ ENTRY(_start)
PHDRS {
text PT_LOAD FLAGS(5);
rodata PT_LOAD FLAGS(4);
data PT_LOAD FLAGS(6);
data PT_LOAD FLAGS(7);
}
SECTIONS {
@@ -35,4 +35,4 @@ SECTIONS {
*(.eh_frame)
*(.note .note.*)
}
}
}

View File

@@ -4,7 +4,7 @@ ENTRY(_start)
PHDRS {
text PT_LOAD FLAGS(5);
rodata PT_LOAD FLAGS(4);
data PT_LOAD FLAGS(6);
data PT_LOAD FLAGS(7);
}
SECTIONS {
@@ -39,4 +39,4 @@ SECTIONS {
*(.eh_frame)
*(.note .note.*)
}
}
}

View File

@@ -24,6 +24,9 @@ struct clks_elf64_loaded_segment {
struct clks_elf64_loaded_image {
u64 entry;
void *image_base;
u64 image_size;
u64 image_vaddr_base;
u16 segment_count;
struct clks_elf64_loaded_segment segments[CLKS_ELF64_MAX_SEGMENTS];
};
@@ -31,5 +34,7 @@ struct clks_elf64_loaded_image {
clks_bool clks_elf64_validate(const void *image, u64 size);
clks_bool clks_elf64_inspect(const void *image, u64 size, struct clks_elf64_info *out_info);
clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_image *out_loaded);
void clks_elf64_unload(struct clks_elf64_loaded_image *loaded);
void *clks_elf64_entry_pointer(const struct clks_elf64_loaded_image *loaded, u64 entry);
#endif
#endif

View File

@@ -174,6 +174,11 @@ clks_bool clks_elf64_inspect(const void *image, u64 size, struct clks_elf64_info
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;
@@ -186,31 +191,83 @@ clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_
}
eh = (const struct clks_elf64_ehdr *)image;
out_loaded->entry = eh->e_entry;
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));
void *dst;
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;
}
dst = clks_kmalloc((usize)ph->p_memsz);
if (dst == CLKS_NULL) {
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;
}
clks_memset(dst, 0, (usize)ph->p_memsz);
clks_memcpy(dst, (const void *)((const u8 *)image + ph->p_offset), (usize)ph->p_filesz);
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 = dst;
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;
@@ -219,4 +276,36 @@ clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_
}
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);
}

View File

@@ -2,11 +2,28 @@
#include <clks/exec.h>
#include <clks/fs.h>
#include <clks/log.h>
#include <clks/string.h>
#include <clks/types.h>
typedef u64 (*clks_exec_entry_fn)(void);
#define CLKS_EXEC_STATUS_UNSUPPORTED 0xFFFFFFFFFFFFFFFEULL
static u64 clks_exec_requests = 0ULL;
static u64 clks_exec_success = 0ULL;
static clks_bool clks_exec_is_sync_unsupported(const char *path) {
if (path == CLKS_NULL) {
return CLKS_FALSE;
}
if (clks_strcmp(path, "/shell/shell.elf") == 0) {
return CLKS_TRUE;
}
return CLKS_FALSE;
}
void clks_exec_init(void) {
clks_exec_requests = 0ULL;
clks_exec_success = 0ULL;
@@ -17,6 +34,9 @@ clks_bool clks_exec_run_path(const char *path, u64 *out_status) {
const void *image;
u64 image_size = 0ULL;
struct clks_elf64_info info;
struct clks_elf64_loaded_image loaded;
void *entry_ptr;
u64 run_ret;
clks_exec_requests++;
@@ -29,6 +49,17 @@ clks_bool clks_exec_run_path(const char *path, u64 *out_status) {
return CLKS_FALSE;
}
if (clks_exec_is_sync_unsupported(path) == CLKS_TRUE) {
clks_log(CLKS_LOG_WARN, "EXEC", "SYNC EXEC UNSUPPORTED FOR INTERACTIVE ELF");
clks_log(CLKS_LOG_WARN, "EXEC", path);
if (out_status != CLKS_NULL) {
*out_status = CLKS_EXEC_STATUS_UNSUPPORTED;
}
return CLKS_FALSE;
}
image = clks_fs_read_all(path, &image_size);
if (image == CLKS_NULL || image_size == 0ULL) {
@@ -43,17 +74,38 @@ clks_bool clks_exec_run_path(const char *path, u64 *out_status) {
return CLKS_FALSE;
}
clks_exec_success++;
if (out_status != CLKS_NULL) {
*out_status = 0ULL;
if (clks_elf64_load(image, image_size, &loaded) == CLKS_FALSE) {
clks_log(CLKS_LOG_WARN, "EXEC", "EXEC ELF LOAD FAILED");
clks_log(CLKS_LOG_WARN, "EXEC", path);
return CLKS_FALSE;
}
clks_log(CLKS_LOG_INFO, "EXEC", "EXEC REQUEST ACCEPTED");
entry_ptr = clks_elf64_entry_pointer(&loaded, info.entry);
if (entry_ptr == CLKS_NULL) {
clks_log(CLKS_LOG_WARN, "EXEC", "ENTRY POINTER RESOLVE FAILED");
clks_log(CLKS_LOG_WARN, "EXEC", path);
clks_elf64_unload(&loaded);
return CLKS_FALSE;
}
clks_log(CLKS_LOG_INFO, "EXEC", "EXEC RUN START");
clks_log(CLKS_LOG_INFO, "EXEC", path);
clks_log_hex(CLKS_LOG_INFO, "EXEC", "ENTRY", info.entry);
clks_log_hex(CLKS_LOG_INFO, "EXEC", "PHNUM", (u64)info.phnum);
run_ret = ((clks_exec_entry_fn)entry_ptr)();
clks_log(CLKS_LOG_INFO, "EXEC", "RUN RETURNED");
clks_log(CLKS_LOG_INFO, "EXEC", path);
clks_log_hex(CLKS_LOG_INFO, "EXEC", "RET", run_ret);
clks_exec_success++;
if (out_status != CLKS_NULL) {
*out_status = run_ret;
}
clks_elf64_unload(&loaded);
return CLKS_TRUE;
}
@@ -63,4 +115,4 @@ u64 clks_exec_request_count(void) {
u64 clks_exec_success_count(void) {
return clks_exec_success;
}
}

View File

@@ -1,5 +1,6 @@
#include <clks/exec.h>
#include <clks/fs.h>
#include <clks/elf64.h>
#include <clks/heap.h>
#include <clks/keyboard.h>
#include <clks/log.h>
@@ -699,6 +700,7 @@ static clks_bool clks_shell_cmd_help(void) {
clks_shell_writeln(" rusttest");
clks_shell_writeln(" panic");
clks_shell_writeln(" exec <path|name>");
clks_shell_writeln(" elfloader [path] (kernel builtin, default /hello.elf)");
clks_shell_writeln(" clear");
clks_shell_writeln(" kbdstat");
clks_shell_writeln("edit keys: Left/Right, Home/End, Up/Down history");
@@ -1057,6 +1059,55 @@ static clks_bool clks_shell_cmd_rm(const char *arg) {
return CLKS_TRUE;
}
static clks_bool clks_shell_cmd_elfloader(const char *arg) {
const char *target = arg;
char path[CLKS_SHELL_PATH_MAX];
const void *image;
u64 size = 0ULL;
struct clks_elf64_info info;
u64 status = (u64)-1;
if (target == CLKS_NULL || target[0] == '\0') {
target = "/hello.elf";
}
if (target[0] == '/') {
clks_shell_copy_line(path, sizeof(path), target);
} else if (clks_shell_resolve_path(target, path, sizeof(path)) == CLKS_FALSE) {
clks_shell_writeln("elfloader: invalid path");
return CLKS_FALSE;
}
image = clks_fs_read_all(path, &size);
if (image == CLKS_NULL || size == 0ULL) {
clks_shell_writeln("elfloader: file missing");
return CLKS_FALSE;
}
if (clks_elf64_inspect(image, size, &info) == CLKS_FALSE) {
clks_shell_writeln("elfloader: invalid elf64");
return CLKS_FALSE;
}
clks_shell_writeln("elfloader: kernel builtin");
clks_shell_write(" PATH: ");
clks_shell_writeln(path);
clks_shell_print_kv_hex(" ELF_SIZE", size);
clks_shell_print_kv_hex(" ENTRY", info.entry);
clks_shell_print_kv_hex(" PHNUM", (u64)info.phnum);
clks_shell_print_kv_hex(" LOAD_SEGMENTS", (u64)info.loadable_segments);
clks_shell_print_kv_hex(" TOTAL_MEMSZ", info.total_load_memsz);
if (clks_exec_run_path(path, &status) == CLKS_TRUE && status == 0ULL) {
clks_shell_writeln("elfloader: exec accepted");
return CLKS_TRUE;
}
clks_shell_writeln("elfloader: exec failed");
return CLKS_FALSE;
}
static clks_bool clks_shell_cmd_exec(const char *arg) {
char path[CLKS_SHELL_PATH_MAX];
u64 status = (u64)-1;
@@ -1280,6 +1331,8 @@ static void clks_shell_execute_line(const char *line) {
success = clks_shell_cmd_rusttest();
} else if (clks_shell_streq(cmd, "panic") == CLKS_TRUE) {
success = clks_shell_cmd_panic();
} else if (clks_shell_streq(cmd, "elfloader") == CLKS_TRUE) {
success = clks_shell_cmd_elfloader(arg);
} else if (clks_shell_streq(cmd, "exec") == CLKS_TRUE || clks_shell_streq(cmd, "run") == CLKS_TRUE) {
success = clks_shell_cmd_exec(arg);
} else if (clks_shell_streq(cmd, "clear") == CLKS_TRUE) {
@@ -1486,4 +1539,5 @@ void clks_shell_pump_input(u32 max_chars) {
void clks_shell_tick(u64 tick) {
(void)tick;
clks_shell_drain_input(CLKS_SHELL_INPUT_BUDGET);
}
}

View File

@@ -22,6 +22,7 @@
- `stage23.md`
- `stage24.md`
- `stage25.md`
- `stage26.md`
## Notes
- Stage docs use a fixed template: goal, implementation, acceptance criteria, build targets, QEMU command, and debugging notes.

37
docs/stage26.md Normal file
View File

@@ -0,0 +1,37 @@
# Stage 26 - Kernel Builtin ELF Loader + Root Hello ELF
## Goal
- Move `elfloader` from standalone user ELF into a kernel builtin command.
- Keep `hello.elf` as root-level user ELF test payload.
## Implementation
- Removed standalone user app `elfloader_main.c`.
- Added kernel shell builtin command: `elfloader [path]`.
- Default target path: `/hello.elf`.
- Builtin flow: `fs_read -> elf64 inspect -> exec load -> entry call -> return status`.
- Updated CMake ramdisk placement rules:
- `hello.elf` -> `/hello.elf`
- Simplified user Rust library back to shared helper export (`cleonos_rust_guarded_len`).
## Acceptance Criteria
- No `elfloader.elf` is generated or packed.
- Ramdisk root contains `/hello.elf`.
- In kernel shell:
- `elfloader` loads and executes `/hello.elf`, then returns status.
- `elfloader /path/to/app.elf` works for other absolute/relative paths.
## Build Targets
- `make userapps`
- `make ramdisk`
- `make iso`
- `make run`
## QEMU Command
- `make run`
## Debug Notes
- If `elfloader` reports `file missing`, check ramdisk root packaging for `/hello.elf`.
- If it reports `invalid elf64`, verify user app link script and ELF output format.
- If it reports `exec failed`, inspect `EXEC` channel logs for load/entry/return status.
- `hello.elf` is supported in current synchronous exec mode.
- `/shell/shell.elf` is intentionally blocked in synchronous mode (interactive loop requires process/task context switching stage).

1907
gdb.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,4 +3,7 @@ CLeonOS ramdisk root layout
/system : kernel-mode ELF apps and core system components
/shell : user shell and command ELF apps
/temp : runtime temp/cache files
/driver : hardware and peripheral drivers
/driver : hardware and peripheral drivers
Root ELF demos:
/hello.elf : Hello world user ELF