1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
# 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 program_header_offset = mem_read(base + 32, 8)
const program_header_count = mem_read(base + 56, 2)
const program_header_size = mem_read(base + 54, 2)
const space = as_create()
for index in 0..program_header_count do
const header = base + program_header_offset + index * program_header_size
if mem_read(header, 4) == PT_LOAD do
const file_offset = mem_read(header + 8, 8)
const virtual_address = mem_read(header + 16, 8)
const file_size = mem_read(header + 32, 8)
const memory_size = mem_read(header + 40, 8)
let segment_offset = 0
while segment_offset < memory_size do
const frame = frame_alloc()
mem_zero(frame, 4096)
if segment_offset < file_size do
const remaining = file_size - segment_offset
mem_copy(frame, base + file_offset + segment_offset, if remaining > 4096 4096 else remaining)
end
as_map(space, virtual_address + segment_offset, frame, PAGE_FLAGS)
segment_offset = segment_offset + 4096
end
end
end
const stack_top = 0x7fff0000
for page in 0..4 do as_map(space, stack_top - (page + 1) * 4096, frame_alloc(), PAGE_FLAGS) end
let arg_ptr = 0
const arg_len = arg:len()
if arg_len > 0 do
const arg_frame = frame_alloc()
mem_zero(arg_frame, 4096)
for index in 0..arg_len do mem_write(arg_frame + index, arg[index]:ascii(), 1) end
as_map(space, ARG_VADDR, arg_frame, PAGE_FLAGS)
arg_ptr = ARG_VADDR
end
proc_run(space, entry, stack_top, arg_ptr, arg_len)
end
# one reused contiguous buffer to stage an elf image read off the disk, since
# load_elf wants a flat base to mem_read from and a file lands in scattered frames
# its a weird arch but wtv
global loader = { scratch = 0 }
const SCRATCH_PAGES = 64
fn load_file_elf(path, arg) do
const size = fs:size(path)
if size < 0 do puts("#{path}: not found\n") return :false end
if size > SCRATCH_PAGES * 4096 do puts("#{path}: too big to load\n") return :false end
if loader.scratch == 0 do loader.scratch = alloc_contig(SCRATCH_PAGES) end
if loader.scratch == 0 do puts("no memory for elf load\n") return :false end
blit_str(loader.scratch, fs:read_bytes(path, 0, size))
load_elf(loader.scratch, arg)
return :true
end
fn run_prog(name, arg) do
let bare_name = name
if bare_name:starts_with?("/usr/bin/") bare_name = bare_name[9..]
const path = "/usr/bin/#{bare_name}"
if fs:size(path) < 0 return :false
return load_file_elf(path, arg)
end
fn list_progs() do
puts("programs:")
for index in 0..prog_count() do puts(" #{prog_name(index)}") end
puts("\n")
end
|