# load an embedded elf into a fresh address space and run it in ring 3 const PT_LOAD = 1 const PAGE_FLAGS = 6 # write | user const ARG_VADDR = 0x50000000 # where we map the argument string in the new space fn load_elf(base, arg) do if mem_read(base, 4) != 0x464c457f do puts("not an ELF\n") return :nil end const entry = mem_read(base + 24, 8) const phoff = mem_read(base + 32, 8) const phnum = mem_read(base + 56, 2) const phentsize = mem_read(base + 54, 2) const space = as_create() for i in 0..phnum do const phdr = base + phoff + i * phentsize if mem_read(phdr, 4) == PT_LOAD do const offset = mem_read(phdr + 8, 8) const vaddr = mem_read(phdr + 16, 8) const filesz = mem_read(phdr + 32, 8) const memsz = mem_read(phdr + 40, 8) let seg_off = 0 while seg_off < memsz do const frame = frame_alloc() mem_zero(frame, 4096) if seg_off < filesz do const left = filesz - seg_off mem_copy(frame, base + offset + seg_off, if left > 4096 4096 else left) end as_map(space, vaddr + seg_off, frame, PAGE_FLAGS) seg_off = seg_off + 4096 end end end const stack_top = 0x7fff0000 for p in 0..4 do as_map(space, stack_top - (p + 1) * 4096, frame_alloc(), PAGE_FLAGS) end let arg_ptr = 0 const arg_len = arg:len() if arg_len > 0 do const argframe = frame_alloc() mem_zero(argframe, 4096) for k in 0..arg_len do mem_write(argframe + k, arg[k]:ascii(), 1) end as_map(space, ARG_VADDR, argframe, PAGE_FLAGS) arg_ptr = ARG_VADDR end proc_run(space, entry, stack_top, arg_ptr, arg_len) end fn run_prog(name, arg) do let n = name if n:starts_with?("/bin/") n = n[5..] for i in 0..prog_count() do if prog_name(i) == n do load_elf(prog_phys(i), arg) return :true end end puts("no such program: #{name}\n") return :false end fn list_progs() do puts("programs:") for i in 0..prog_count() do puts(" #{prog_name(i)}") end puts("\n") end