Skip to content

Commit cefe916

Browse files
Merge pull request #29 from Frost-Wing/codex/fix-elf-execution-error-in-fsh-4mkmu5
Add userland exec path: ELF VFS loader, stack/auxv/TLS setup, and related filesystem/paging fixes
2 parents 09bb429 + 3cc33db commit cefe916

5 files changed

Lines changed: 230 additions & 4 deletions

File tree

source/includes/userland.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#define USER_HEAP_VADDR 0x0000400010000000ULL // user heap right above code region
2323
#define USER_MMAP_VADDR (USER_HEAP_VADDR + USER_HEAP_SIZE)
2424
#define USER_TLS_VADDR (USER_MMAP_VADDR + USER_MMAP_SIZE)
25+
#define USER_PHDR_VADDR (USER_TLS_VADDR + 0x1000ULL)
2526
#define USER_STACK_TOP 0x00007FFFFFFFF000ULL // near top of canonical lower half
2627

2728
void enter_userland_at(uint64_t entry_point);

source/kernel/C/executables/elf.c

Lines changed: 122 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,121 @@
1515
#include <heap.h>
1616
#include <filesystems/vfs.h>
1717
#include <paging.h>
18+
#include <userland.h>
19+
20+
static uint32_t* elf_vfs_pos_ptr(vfs_file_t* file)
21+
{
22+
if (!file || !file->mnt)
23+
return NULL;
24+
25+
switch (file->mnt->type) {
26+
case FS_FAT16:
27+
return &file->f.fat16.pos;
28+
case FS_FAT32:
29+
return &file->f.fat32.pos;
30+
case FS_ISO9660:
31+
return &file->f.iso9660.pos;
32+
default:
33+
return NULL;
34+
}
35+
}
36+
37+
static int elf_vfs_seek(vfs_file_t* file, uint32_t offset)
38+
{
39+
uint32_t* pos = elf_vfs_pos_ptr(file);
40+
if (!pos)
41+
return -1;
42+
43+
if (file->mnt->type == FS_FAT32) {
44+
fat32_file_t* fat32 = &file->f.fat32;
45+
uint32_t cluster_size = fat32->fs->sectors_per_cluster * FAT32_SECTOR_SIZE;
46+
uint32_t cluster = fat32->start_cluster;
47+
uint32_t steps = cluster_size ? (offset / cluster_size) : 0;
48+
49+
while (steps > 0 && cluster < FAT32_CLUSTER_EOC) {
50+
cluster = fat32_read_fat(fat32->fs, cluster);
51+
steps--;
52+
}
53+
54+
fat32->current_cluster = cluster;
55+
}
56+
57+
*pos = offset;
58+
return 0;
59+
}
60+
61+
static int elf_vfs_read_exact(vfs_file_t* file, uint32_t offset, void* buf, uint32_t size)
62+
{
63+
if (elf_vfs_seek(file, offset) != 0)
64+
return -1;
65+
66+
int rd = vfs_read(file, (uint8_t*)buf, size);
67+
return (rd >= 0 && (uint32_t)rd == size) ? 0 : -1;
68+
}
69+
70+
static int elf_vfs_read_exact_path(const char* path, uint32_t offset, void* buf, uint32_t size)
71+
{
72+
vfs_file_t file;
73+
if (vfs_open(path, VFS_RDONLY, &file) != 0)
74+
return -1;
75+
76+
int rc = elf_vfs_read_exact(&file, offset, buf, size);
77+
vfs_close(&file);
78+
return rc;
79+
}
80+
81+
static uint64_t elf_runtime_addr_for_offset(Elf64_Phdr* headers, uint16_t phnum, uint64_t file_offset)
82+
{
83+
for (uint16_t i = 0; i < phnum; ++i) {
84+
Elf64_Phdr* ph = &headers[i];
85+
if (ph->p_type != PT_LOAD || ph->p_filesz == 0)
86+
continue;
87+
88+
uint64_t seg_start = ph->p_offset;
89+
uint64_t seg_end = ph->p_offset + ph->p_filesz;
90+
if (file_offset >= seg_start && file_offset < seg_end)
91+
return ph->p_vaddr + (file_offset - ph->p_offset);
92+
}
93+
94+
return 0;
95+
}
96+
97+
static uint64_t elf_stage_phdrs_for_user(Elf64_Phdr* headers, uint64_t phdr_bytes)
98+
{
99+
if (!headers || phdr_bytes == 0)
100+
return 0;
101+
102+
uint64_t base = USER_PHDR_VADDR;
103+
uint64_t aligned = (phdr_bytes + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
104+
105+
for (uint64_t off = 0; off < aligned; off += PAGE_SIZE) {
106+
uint64_t phys = allocate_page();
107+
map_user_page(base + off, phys, USER_DATA_FLAGS);
108+
}
109+
110+
memset((void*)base, 0, aligned);
111+
memcpy((void*)base, headers, phdr_bytes);
112+
return base;
113+
}
114+
115+
static int elf_validate_header(const Elf64_Ehdr* header, uint64_t file_size)
116+
{
117+
if (memcmp(&header->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0 || header->e_ident[EI_CLASS] != ELFCLASS64 ||
118+
header->e_ident[EI_DATA] != ELFDATA2LSB || header->e_type != ET_EXEC ||
119+
header->e_machine != EM_X86_64 || header->e_version != EV_CURRENT)
120+
{
121+
error("Not a valid ELF file to load!", __FILE__);
122+
return -1;
123+
}
124+
125+
if (header->e_phoff + ((uint64_t)header->e_phnum * header->e_phentsize) > file_size ||
126+
header->e_phentsize != sizeof(Elf64_Phdr)) {
127+
eprintf("elf: invalid program header table");
128+
return -1;
129+
}
130+
131+
return 0;
132+
}
18133

19134
static uint32_t* elf_vfs_pos_ptr(vfs_file_t* file)
20135
{
@@ -255,7 +370,10 @@ void* elf_load_from_memory_ex(void* file_base_address, uint64_t file_size, elf_i
255370

256371
if (info) {
257372
info->entry = header.e_entry;
258-
info->phdr_addr = elf_runtime_addr_for_offset(program_headers_start, header.e_phnum, header.e_phoff);
373+
info->phdr_addr = elf_stage_phdrs_for_user(program_headers_start,
374+
(uint64_t)header.e_phnum * header.e_phentsize);
375+
if (info->phdr_addr == 0)
376+
info->phdr_addr = elf_runtime_addr_for_offset(program_headers_start, header.e_phnum, header.e_phoff);
259377
info->phentsize = header.e_phentsize;
260378
info->phnum = header.e_phnum;
261379
}
@@ -338,7 +456,9 @@ void* elf_load_from_vfs_ex(const char* path, elf_image_info_t* info)
338456

339457
if (info) {
340458
info->entry = header.e_entry;
341-
info->phdr_addr = elf_runtime_addr_for_offset(program_headers, header.e_phnum, header.e_phoff);
459+
info->phdr_addr = elf_stage_phdrs_for_user(program_headers, phdr_bytes);
460+
if (info->phdr_addr == 0)
461+
info->phdr_addr = elf_runtime_addr_for_offset(program_headers, header.e_phnum, header.e_phoff);
342462
info->phentsize = header.e_phentsize;
343463
info->phnum = header.e_phnum;
344464
}

source/kernel/C/interrupts/isr.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,25 @@
1616

1717
irq_handler interrupt_handlers[256];
1818

19+
static void log_page_fault_details(InterruptFrame* frame) {
20+
if (!frame || frame->int_no != 14)
21+
return;
22+
23+
uint64_t err = frame->err_code;
24+
eprintf("pagefault: rip=0x%X addr=0x%X err=0x%X present=%d write=%d user=%d reserved=%d fetch=%d",
25+
frame->rip,
26+
getCR2(),
27+
err,
28+
(int)(err & 0x1),
29+
(int)((err >> 1) & 0x1),
30+
(int)((err >> 2) & 0x1),
31+
(int)((err >> 3) & 0x1),
32+
(int)((err >> 4) & 0x1));
33+
}
34+
1935
void exceptionHandler(InterruptFrame* frame) {
2036
enable_logging = false; // disables logger as fast as it can to get the last instance of panic.
37+
log_page_fault_details(frame);
2138

2239
switch (frame->int_no) {
2340
case 0:

source/kernel/C/meltdown.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,30 @@ void meltdown_screen(cstring message, cstring file, int line, int64 error_code,
5858
frost_compilation_information();
5959
#endif
6060
#ifdef clean_mode
61-
eprintf("[MELTDOWN] %s (%s:%d) (cr2:0x%X)", message, file, line, cr2);
61+
eprintf("[MELTDOWN] %s (%s:%d) (int=%d err=0x%X cr2=0x%X rip=0x%X cs=0x%X rsp=0x%X rflags=0x%X)",
62+
message,
63+
file,
64+
line,
65+
int_no,
66+
error_code,
67+
cr2,
68+
frame ? frame->rip : 0,
69+
frame ? frame->cs : 0,
70+
frame ? frame->rsp : 0,
71+
frame ? frame->rflags : 0);
72+
73+
if (frame) {
74+
eprintf("[MELTDOWN] regs rax=0x%X rcx=0x%X rdx=0x%X rsi=0x%X rdi=0x%X r8=0x%X r9=0x%X r10=0x%X r11=0x%X",
75+
frame->rax,
76+
frame->rcx,
77+
frame->rdx,
78+
frame->rsi,
79+
frame->rdi,
80+
frame->r8,
81+
frame->r9,
82+
frame->r10,
83+
frame->r11);
84+
}
6285
#endif
6386
}
6487

@@ -77,4 +100,4 @@ void interrupt_frame_dump(InterruptFrame* frame) {
77100
printf("\tRSP = 0x%X", frame->rsp);
78101

79102
printf("===============================");
80-
}
103+
}

source/kernel/C/userland.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ static uint64_t user_heap_mapped_end = USER_HEAP_VADDR;
7878
static uint64_t user_mmap_cursor = USER_MMAP_VADDR;
7979
static uint64_t user_mmap_end = USER_MMAP_VADDR;
8080

81+
static void debug_dump_initial_stack(uint64_t stack_top) {
82+
uint64_t* words = (uint64_t*)stack_top;
83+
debug_printf("userland: initial rsp=%x argc=%u argv0=%x argv1=%x env0=%x aux0=%x aux1=%x\n",
84+
stack_top,
85+
(uint32_t)words[0],
86+
words[1],
87+
words[2],
88+
words[(uint32_t)words[0] + 2],
89+
words[(uint32_t)words[0] + 4],
90+
words[(uint32_t)words[0] + 5]);
91+
}
92+
8193
static uint64_t rdtsc64_local(void) {
8294
uint32_t lo = 0;
8395
uint32_t hi = 0;
@@ -232,6 +244,12 @@ static void init_user_tls(void) {
232244
tcb->feature_1 = 0;
233245
tcb->ssp_base = 0;
234246

247+
debug_printf("userland: tls base=%x dtv=%x stack_guard=%x pointer_guard=%x\n",
248+
USER_TLS_VADDR,
249+
tcb->dtv,
250+
tcb->stack_guard,
251+
tcb->pointer_guard);
252+
235253
wrmsr64_local(IA32_FS_BASE_MSR, USER_TLS_VADDR);
236254
}
237255

@@ -375,3 +393,50 @@ int userland_exec(const char* path, int argc, const char* const* argv, const cha
375393

376394
return 0;
377395
}
396+
397+
int userland_exec(const char* path, int argc, const char* const* argv, const char* const* envp) {
398+
elf_image_info_t image_info = {0};
399+
void* entry = elf_load_from_vfs_ex(path, &image_info);
400+
if (!entry)
401+
return -1;
402+
403+
map_user_stack();
404+
userland_heap_init();
405+
init_user_tls();
406+
407+
uint64_t stack_top = build_initial_user_stack(path, argc, argv, envp, &image_info);
408+
409+
debug_printf("userland: exec path=%s entry=%x phdr=%x phentsz=%u phnum=%u stack=%x\n",
410+
path,
411+
entry,
412+
image_info.phdr_addr,
413+
image_info.phentsize,
414+
image_info.phnum,
415+
stack_top);
416+
debug_dump_initial_stack(stack_top);
417+
418+
asm volatile (
419+
"cli\n"
420+
"mov %0, %%r11\n"
421+
"mov %1, %%r10\n"
422+
"xor %%rax, %%rax\n"
423+
"xor %%rbx, %%rbx\n"
424+
"xor %%rcx, %%rcx\n"
425+
"xor %%rdx, %%rdx\n"
426+
"xor %%rsi, %%rsi\n"
427+
"xor %%rdi, %%rdi\n"
428+
"xor %%r8, %%r8\n"
429+
"xor %%r9, %%r9\n"
430+
"pushq $0x23\n"
431+
"pushq %%r11\n"
432+
"pushq $0x202\n"
433+
"pushq $0x1B\n"
434+
"pushq %%r10\n"
435+
"iretq\n"
436+
:
437+
: "r"(stack_top), "r"((uint64_t)entry)
438+
: "memory", "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11"
439+
);
440+
441+
return 0;
442+
}

0 commit comments

Comments
 (0)