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_SHELL_APPS)
set(RAMDISK_DRIVER_APPS) set(RAMDISK_DRIVER_APPS)
set(RAMDISK_SYSTEM_APPS) set(RAMDISK_SYSTEM_APPS)
set(RAMDISK_ROOT_APPS)
foreach(SRC IN LISTS USER_APP_MAIN_SOURCES) foreach(SRC IN LISTS USER_APP_MAIN_SOURCES)
get_filename_component(_stem "${SRC}" NAME_WE) 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}") list(APPEND USER_APP_OUTPUTS "${_app_out}")
if(_app_name MATCHES ".*drv$") if(_app_name MATCHES ".*drv$")
list(APPEND RAMDISK_DRIVER_APPS "${_app_out}") list(APPEND RAMDISK_DRIVER_APPS "${_app_out}")
elseif(_app_name STREQUAL "hello")
list(APPEND RAMDISK_ROOT_APPS "${_app_out}")
else() else()
list(APPEND RAMDISK_SHELL_APPS "${_app_out}") list(APPEND RAMDISK_SHELL_APPS "${_app_out}")
endif() endif()
@@ -427,6 +430,10 @@ foreach(_app IN LISTS RAMDISK_SHELL_APPS)
get_filename_component(_app_file "${_app}" NAME) get_filename_component(_app_file "${_app}" NAME)
list(APPEND RAMDISK_COPY_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy "${_app}" "${RAMDISK_ROOT}/shell/${_app_file}") list(APPEND RAMDISK_COPY_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy "${_app}" "${RAMDISK_ROOT}/shell/${_app_file}")
endforeach() 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) foreach(_app IN LISTS RAMDISK_DRIVER_APPS)
get_filename_component(_app_file "${_app}" NAME) get_filename_component(_app_file "${_app}" NAME)
list(APPEND RAMDISK_COPY_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy "${_app}" "${RAMDISK_ROOT}/driver/${_app_file}") 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 run"
COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target debug" 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); extern int cleonos_app_main(void);
void _start(void) { u64 _start(void) {
volatile int code; int code;
code = ((cleonos_entry_fn)cleonos_app_main)(); code = ((cleonos_entry_fn)cleonos_app_main)();
(void)code; return (u64)code;
for (;;) {
__asm__ volatile("pause");
}
} }

View File

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

View File

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

View File

@@ -24,6 +24,9 @@ struct clks_elf64_loaded_segment {
struct clks_elf64_loaded_image { struct clks_elf64_loaded_image {
u64 entry; u64 entry;
void *image_base;
u64 image_size;
u64 image_vaddr_base;
u16 segment_count; u16 segment_count;
struct clks_elf64_loaded_segment segments[CLKS_ELF64_MAX_SEGMENTS]; 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_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_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); 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) { clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_image *out_loaded) {
const struct clks_elf64_ehdr *eh; const struct clks_elf64_ehdr *eh;
u16 i; 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) { if (out_loaded == CLKS_NULL) {
return CLKS_FALSE; 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; eh = (const struct clks_elf64_ehdr *)image;
out_loaded->entry = eh->e_entry;
for (i = 0; i < eh->e_phnum; i++) { for (i = 0; i < eh->e_phnum; i++) {
const struct clks_elf64_phdr *ph = const struct clks_elf64_phdr *ph =
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize)); (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) { if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) {
continue; continue;
} }
if (out_loaded->segment_count >= CLKS_ELF64_MAX_SEGMENTS) { if (out_loaded->segment_count >= CLKS_ELF64_MAX_SEGMENTS) {
clks_elf64_unload(out_loaded);
return CLKS_FALSE; return CLKS_FALSE;
} }
dst = clks_kmalloc((usize)ph->p_memsz); seg_off = ph->p_vaddr - min_vaddr;
if (seg_off > span || ph->p_memsz > (span - seg_off)) {
if (dst == CLKS_NULL) { clks_elf64_unload(out_loaded);
return CLKS_FALSE; return CLKS_FALSE;
} }
clks_memset(dst, 0, (usize)ph->p_memsz); seg_dst = (u8 *)image_base + (usize)seg_off;
clks_memcpy(dst, (const void *)((const u8 *)image + ph->p_offset), (usize)ph->p_filesz); 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].vaddr = ph->p_vaddr;
out_loaded->segments[out_loaded->segment_count].memsz = ph->p_memsz; 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].filesz = ph->p_filesz;
@@ -220,3 +277,35 @@ clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_
return CLKS_TRUE; 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/exec.h>
#include <clks/fs.h> #include <clks/fs.h>
#include <clks/log.h> #include <clks/log.h>
#include <clks/string.h>
#include <clks/types.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_requests = 0ULL;
static u64 clks_exec_success = 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) { void clks_exec_init(void) {
clks_exec_requests = 0ULL; clks_exec_requests = 0ULL;
clks_exec_success = 0ULL; clks_exec_success = 0ULL;
@@ -17,6 +34,9 @@ clks_bool clks_exec_run_path(const char *path, u64 *out_status) {
const void *image; const void *image;
u64 image_size = 0ULL; u64 image_size = 0ULL;
struct clks_elf64_info info; struct clks_elf64_info info;
struct clks_elf64_loaded_image loaded;
void *entry_ptr;
u64 run_ret;
clks_exec_requests++; clks_exec_requests++;
@@ -29,6 +49,17 @@ clks_bool clks_exec_run_path(const char *path, u64 *out_status) {
return CLKS_FALSE; 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); image = clks_fs_read_all(path, &image_size);
if (image == CLKS_NULL || image_size == 0ULL) { 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; return CLKS_FALSE;
} }
clks_exec_success++; if (clks_elf64_load(image, image_size, &loaded) == CLKS_FALSE) {
clks_log(CLKS_LOG_WARN, "EXEC", "EXEC ELF LOAD FAILED");
if (out_status != CLKS_NULL) { clks_log(CLKS_LOG_WARN, "EXEC", path);
*out_status = 0ULL; 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(CLKS_LOG_INFO, "EXEC", path);
clks_log_hex(CLKS_LOG_INFO, "EXEC", "ENTRY", info.entry); clks_log_hex(CLKS_LOG_INFO, "EXEC", "ENTRY", info.entry);
clks_log_hex(CLKS_LOG_INFO, "EXEC", "PHNUM", (u64)info.phnum); 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; return CLKS_TRUE;
} }

View File

@@ -1,5 +1,6 @@
#include <clks/exec.h> #include <clks/exec.h>
#include <clks/fs.h> #include <clks/fs.h>
#include <clks/elf64.h>
#include <clks/heap.h> #include <clks/heap.h>
#include <clks/keyboard.h> #include <clks/keyboard.h>
#include <clks/log.h> #include <clks/log.h>
@@ -699,6 +700,7 @@ static clks_bool clks_shell_cmd_help(void) {
clks_shell_writeln(" rusttest"); clks_shell_writeln(" rusttest");
clks_shell_writeln(" panic"); clks_shell_writeln(" panic");
clks_shell_writeln(" exec <path|name>"); clks_shell_writeln(" exec <path|name>");
clks_shell_writeln(" elfloader [path] (kernel builtin, default /hello.elf)");
clks_shell_writeln(" clear"); clks_shell_writeln(" clear");
clks_shell_writeln(" kbdstat"); clks_shell_writeln(" kbdstat");
clks_shell_writeln("edit keys: Left/Right, Home/End, Up/Down history"); 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; 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) { static clks_bool clks_shell_cmd_exec(const char *arg) {
char path[CLKS_SHELL_PATH_MAX]; char path[CLKS_SHELL_PATH_MAX];
u64 status = (u64)-1; u64 status = (u64)-1;
@@ -1280,6 +1331,8 @@ static void clks_shell_execute_line(const char *line) {
success = clks_shell_cmd_rusttest(); success = clks_shell_cmd_rusttest();
} else if (clks_shell_streq(cmd, "panic") == CLKS_TRUE) { } else if (clks_shell_streq(cmd, "panic") == CLKS_TRUE) {
success = clks_shell_cmd_panic(); 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) { } else if (clks_shell_streq(cmd, "exec") == CLKS_TRUE || clks_shell_streq(cmd, "run") == CLKS_TRUE) {
success = clks_shell_cmd_exec(arg); success = clks_shell_cmd_exec(arg);
} else if (clks_shell_streq(cmd, "clear") == CLKS_TRUE) { } else if (clks_shell_streq(cmd, "clear") == CLKS_TRUE) {
@@ -1487,3 +1540,4 @@ void clks_shell_tick(u64 tick) {
(void)tick; (void)tick;
clks_shell_drain_input(CLKS_SHELL_INPUT_BUDGET); clks_shell_drain_input(CLKS_SHELL_INPUT_BUDGET);
} }

View File

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

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