summaryrefslogtreecommitdiff
path: root/lume-legacy/src/kernel/proc/exec.cc
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:31:46 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:31:46 +0800
commite90b72ec3082588b296956730bd2930cf8d5d671 (patch)
tree36ff6916af9b4176ea5a9662219d11e721f0b691 /lume-legacy/src/kernel/proc/exec.cc
parent1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (diff)
downloadlume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.gz
lume-e90b72ec3082588b296956730bd2930cf8d5d671.tar.xz
refactor: promote new architecture to repository root
Archive the deprecated implementation under lume-legacy, make the new kernel the default root-level build, and update repository entry points without changing kernel behavior.
Diffstat (limited to 'lume-legacy/src/kernel/proc/exec.cc')
-rw-r--r--lume-legacy/src/kernel/proc/exec.cc260
1 files changed, 260 insertions, 0 deletions
diff --git a/lume-legacy/src/kernel/proc/exec.cc b/lume-legacy/src/kernel/proc/exec.cc
new file mode 100644
index 0000000..8d8c467
--- /dev/null
+++ b/lume-legacy/src/kernel/proc/exec.cc
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Richard QIn
+ */
+#include "common/types.h"
+#include "kernel/riscv.h"
+#include "kernel/proc.h"
+#include "kernel/mm.h"
+#include "kernel/elf.h"
+#include "fs/fs.h"
+#include "lib/string.h"
+#include "drivers/uart.h"
+#include "kernel/trap.h"
+
+extern char trampoline[];
+
+// RAII: Page Table Resource Management
+class VmGuard
+{
+public:
+ uint64 *pagetable = nullptr;
+ uint64 sz = 0;
+
+ VmGuard() : pagetable(VM::uvmcreate()) {}
+
+ ~VmGuard()
+ {
+ if (pagetable)
+ {
+ VM::uvmfree(pagetable, sz);
+ }
+ }
+
+ // Copying is prohibited
+ VmGuard(const VmGuard &) = delete;
+ VmGuard &operator=(const VmGuard &) = delete;
+
+ // Submit resources: Ownership transfer, destructor no longer releases
+ uint64 *commit()
+ {
+ uint64 *pt = pagetable;
+ pagetable = nullptr;
+ return pt;
+ }
+};
+
+// RAII: Inode Lock Management
+class InodeGuard
+{
+public:
+ Inode *ip;
+ InodeGuard(Inode *i) : ip(i)
+ {
+ if (ip)
+ VFS::ilock(ip);
+ }
+ ~InodeGuard()
+ {
+ if (ip)
+ {
+ VFS::iunlockput(ip); // Automatically unlock and release references
+ }
+ }
+ // Copying is prohibited
+ InodeGuard(const InodeGuard &) = delete;
+ InodeGuard &operator=(const InodeGuard &) = delete;
+};
+
+// laod segment
+static int loadseg(uint64 *pagetable, uint64 va, Inode *ip, uint64 offset, uint64 sz)
+{
+ for (uint64 i = 0; i < sz; i += PGSIZE)
+ {
+ uint64 pa = VM::walkaddr(pagetable, va + i);
+ if (pa == 0)
+ {
+ Drivers::uart_puts("[Exec Debug] loadseg: walkaddr failed\n");
+ return -1;
+ }
+
+ uint64 n = PGSIZE - (va + i) % PGSIZE;
+ if (i + n > sz)
+ n = sz - i;
+
+ // Read physical address (isUser=0)
+ if (ip->read((char *)(pa + (va + i) % PGSIZE), offset + i, n, 0) != (int)n)
+ {
+ Drivers::uart_puts("[Exec Debug] loadseg: read failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+namespace Exec
+{
+ int exec(char *path, char **argv)
+ {
+ // 1. Get Inode
+ Inode *raw_ip = VFS::namei(path);
+ if (!raw_ip)
+ {
+ Drivers::uart_puts("[Exec Debug] namei failed for path: ");
+ Drivers::uart_puts(path);
+ Drivers::uart_puts("\n");
+ return -1;
+ }
+ InodeGuard iguard(raw_ip);
+
+ // Get ELF head
+ struct elfhdr elf;
+ if (raw_ip->read((char *)&elf, 0, sizeof(elf), 0) != sizeof(elf))
+ {
+ Drivers::uart_puts("[Exec Debug] read elf header failed\n");
+ return -1;
+ }
+ if (elf.magic != ELF_MAGIC)
+ {
+ Drivers::uart_puts("[Exec Debug] invalid elf magic\n");
+ return -1;
+ }
+
+ // Create new pagetable
+ VmGuard vm_guard;
+ if (!vm_guard.pagetable)
+ {
+ Drivers::uart_puts("[Exec Debug] uvmcreate failed\n");
+ return -1;
+ }
+
+ // Load Program Segment
+ struct proghdr ph;
+ for (int i = 0; i < elf.phnum; i++)
+ {
+ uint64 off = elf.phoff + i * sizeof(ph);
+ if (raw_ip->read((char *)&ph, off, sizeof(ph), 0) != sizeof(ph))
+ {
+ Drivers::uart_puts("[Exec Debug] read proghdr failed\n");
+ return -1;
+ }
+
+ if (ph.type != ELF_PROG_LOAD)
+ continue;
+ if (ph.memsz < ph.filesz)
+ return -1;
+ if (ph.vaddr + ph.memsz < ph.vaddr)
+ return -1;
+
+ uint64 sz1 = VM::uvmalloc(vm_guard.pagetable, vm_guard.sz, ph.vaddr + ph.memsz, PTE_W | PTE_X | PTE_R | PTE_U);
+ if (sz1 == 0)
+ {
+ Drivers::uart_puts("[Exec Debug] uvmalloc failed (segment)\n");
+ return -1;
+ }
+ vm_guard.sz = sz1;
+
+ if (loadseg(vm_guard.pagetable, ph.vaddr, raw_ip, ph.off, ph.filesz) < 0)
+ return -1;
+ }
+
+ // Prepare user stack
+ uint64 sz = PGROUNDUP(vm_guard.sz);
+
+ const int stack_data_pages = 16;
+ const int stack_total_pages = stack_data_pages + 1;
+
+ uint64 sz1 = VM::uvmalloc(vm_guard.pagetable, sz, sz + stack_total_pages * PGSIZE, PTE_W | PTE_R | PTE_U);
+ if (sz1 == 0)
+ {
+ Drivers::uart_puts("[Exec Debug] uvmalloc failed (stack)\n");
+ return -1;
+ }
+ vm_guard.sz = sz1;
+
+ VM::uvmunmap(vm_guard.pagetable, sz, 1, 0);
+
+ uint64 sp = sz1;
+ uint64 stackbase = sp - stack_data_pages * PGSIZE;
+ uint64 ustack[32];
+ uint64 argc = 0;
+
+ // Push parameter string
+ for (; argv[argc]; argc++)
+ {
+ if (argc >= 31)
+ return -1;
+ sp -= strlen(argv[argc]) + 1;
+ sp -= sp % 16;
+ if (sp < stackbase)
+ {
+ Drivers::uart_puts("[Exec Debug] stack overflow (args)\n");
+ return -1;
+ }
+
+ if (VM::copyout(vm_guard.pagetable, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
+ {
+ Drivers::uart_puts("[Exec Debug] copyout arg string failed\n");
+ return -1;
+ }
+ ustack[argc] = sp;
+ }
+ ustack[argc] = 0;
+
+ // Push into parameter array
+ sp -= (argc + 1) * sizeof(uint64);
+ sp -= sp % 16;
+ if (sp < stackbase)
+ {
+ Drivers::uart_puts("[Exec Debug] stack overflow (argv array)\n");
+ return -1;
+ }
+ if (VM::copyout(vm_guard.pagetable, sp, (char *)ustack, (argc + 1) * sizeof(uint64)) < 0)
+ {
+ Drivers::uart_puts("[Exec Debug] copyout argv array failed\n");
+ return -1;
+ }
+
+ // Commit Changes
+ struct Proc *p = myproc();
+ if (VM::mappages(vm_guard.pagetable, TRAPFRAME, PGSIZE, (uint64)p->tf, PTE_R | PTE_W) < 0)
+ {
+ Drivers::uart_puts("[Exec Debug] mappages TRAPFRAME failed\n");
+ return -1;
+ }
+
+ uint64 oldsz = p->sz;
+ uint64 *oldpagetable = p->pagetable;
+
+ p->tf->a0 = argc;
+ p->tf->a1 = sp;
+ p->tf->sp = sp;
+ p->tf->epc = elf.entry;
+
+ char *s = path, *last = path;
+ while (*s)
+ {
+ if (*s == '/')
+ last = s + 1;
+ s++;
+ }
+
+ size_t len = 0;
+ while (last[len] && len < sizeof(p->name) - 1)
+ {
+ p->name[len] = last[len];
+ len++;
+ }
+ p->name[len] = '\0';
+
+ // change pagetable
+ p->pagetable = vm_guard.commit();
+ p->sz = vm_guard.sz;
+
+ // release old pagetable
+ VM::uvmfree(oldpagetable, oldsz);
+ asm volatile("fence.i");
+
+ return 0; // iguard unlocks and releases IP upon destruction
+ }
+} \ No newline at end of file