hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/kernel/proc.rv
blob: 8d7827a148449fb77e2e6a54a0ebc8be78ff160b (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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# 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) -> bool 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) -> bool 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