summaryrefslogtreecommitdiff
path: root/src/kernel/elf.c
blob: 423d51a320b00d6a642b003c2836011ee6b268da (plain) (blame)
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <stdint.h>
#include "drive.h"
#include "elf.h"
#include "task.h"
#include "util.h"
#include "paging.h"
#include "pmap.h"

#define ELF_MAGIC 0x464c457f

enum {
  ELF_32 = 1,
  ELF_64 = 2
};

enum {
  LITTLE_ENDIAN = 1,
  BIG_ENDIAN    = 2
};

enum {
  //...
  ARCH_X86 = 0x03
  //...
};

struct elf_header {
  uint32_t magic;
  uint8_t word_size;
  uint8_t endianness;
  uint8_t elf_version;
  uint8_t target_os;//ignored
  uint8_t os_abi_version;//should be zero
  uint8_t reserved[7];
  uint16_t object_type;//TODO
  uint16_t architecture;//should be ARCH_X86
  uint32_t elf_version_2;
  uint32_t entry_vma;
  uint32_t phtable_fa;
  uint32_t shtable_fa;
  uint32_t flags;
  uint16_t eh_size;
  uint16_t phentry_size;
  uint16_t phtable_count;
  uint16_t shentry_size;
  uint16_t shtable_count;
  uint16_t sh_names_entry;
} __attribute__ ((packed));

enum {
  PT_UNUSED  = 0,
  PT_LOADME  = 1,
  PT_DYNLINK = 2,
  PT_INTERP  = 3,
  PT_COMMENT = 4,
  PT_SHARED  = 5,
  PT_PHTABLE = 6,
  PT_TL_TMPL = 7
};

enum {
  PH_WRITABLE = 0x02
};

struct ph_entry {
  uint32_t type;
  uint32_t fa;
  uint32_t vma;//must be page-aligned
  uint32_t pma;//ignored
  uint32_t fs;
  uint32_t vms;
  uint32_t flags;
  uint32_t align;
} __attribute__ ((packed));

bool try_elf_run(const struct drive *d, const char *path, const char *pass_old_vma) {
  file_id_t h = d->get_file(d, path);
  if (!h)
    return false;

  struct elf_header ehead;

  fmcpy(&ehead, d, h, 0, sizeof(struct elf_header));

  if ((ehead.magic != ELF_MAGIC) ||
      (ehead.word_size != ELF_32) ||
      (ehead.endianness != LITTLE_ENDIAN) ||
       ehead.os_abi_version) {
    d->free_file(d, h);
    return false;
  }

  uint32_t phtable_size = ehead.phentry_size * ehead.phtable_count;
  uint16_t phtable_pages = (phtable_size - 1) / 4096 + 1;

  void *phtable = allocate_kernel_pages(phtable_pages);
  fmcpy(phtable, d, h, ehead.phtable_fa, phtable_size);

  void *pd = new_task_pd();

  for (uint32_t phi = 0; phi < ehead.phtable_count; ++phi) {
    struct ph_entry *entry = phtable + phi * ehead.phentry_size;
    if (entry->type != PT_LOADME)
      continue;
    void *pma = pd_user_allocate(pd, entry->vma, (entry->vms - 1) / 4096 + 1, entry->flags & PH_WRITABLE);
    fmcpy(pma, d, h, entry->fa, entry->fs);
  }

  free_pages(phtable, phtable_pages);
  d->free_file(d, h);

  const char *pass = vma_to_pma(active_task->page_directory, pass_old_vma);

  uint32_t pass_l = 0;
  while (pass[pass_l++])
    ;

  void *pass_vma;
  void *pass_pma;
  user_allocate_anywhere_readonly_together(pd, ((pass_l - 1) >> 12) + 1, &pass_vma, &pass_pma);
  //TODO: handle error condition

  memcpy(pass_pma, pass, pass_l);

  struct task_state tstate;
  tstate.page_directory = pd;
  tstate.ret_addr = ehead.entry_vma;
  tstate.edx = (uint32_t)pass_vma;
  new_task(tstate);
  return true;
}