hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/kernel/proc.rv
blob: 5019fa851c3a6d74f345ddeeae48b81b018355b1 (plain)
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?("/bin/") bare_name = bare_name[5..]
  const path = "/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