refactor: use a more decent physical memory map
[lunaix-os.git] / lunaix-os / kernel / exe / elf32 / ldelf32.c
1 #include <lunaix/exebi/elf32.h>
2 #include <lunaix/load.h>
3 #include <lunaix/mm/mmap.h>
4 #include <lunaix/mm/page.h>
5 #include <lunaix/mm/valloc.h>
6 #include <lunaix/spike.h>
7
8 #include <sys/mm/mempart.h>
9
10 int
11 elf32_smap(struct load_context* ldctx,
12            const struct elf32* elf,
13            struct elf32_phdr* phdre,
14            uintptr_t base_va)
15 {
16     struct v_file* elfile = (struct v_file*)elf->elf_file;
17
18     assert(PG_ALIGNED(phdre->p_offset));
19
20     int proct = 0;
21     if ((phdre->p_flags & PF_R)) {
22         proct |= PROT_READ;
23     }
24     if ((phdre->p_flags & PF_W)) {
25         proct |= PROT_WRITE;
26     }
27     if ((phdre->p_flags & PF_X)) {
28         proct |= PROT_EXEC;
29     }
30
31     uintptr_t va = phdre->p_va + base_va;
32     struct exec_container* container = ldctx->container;
33     struct mmap_param param = { .vms_mnt = container->vms_mnt,
34                                 .pvms = &container->proc->mm,
35                                 .proct = proct,
36                                 .offset = PG_ALIGN(phdre->p_offset),
37                                 .mlen = ROUNDUP(phdre->p_memsz, PG_SIZE),
38                                 .flen = phdre->p_filesz,
39                                 .flags = MAP_FIXED | MAP_PRIVATE,
40                                 .type = REGION_TYPE_CODE };
41
42     struct mm_region* seg_reg;
43     int status = mem_map(NULL, &seg_reg, PG_ALIGN(va), elfile, &param);
44
45     if (!status) {
46         size_t next_addr = phdre->p_memsz + va;
47         ldctx->end = MAX(ldctx->end, ROUNDUP(next_addr, PG_SIZE));
48         ldctx->mem_sz += phdre->p_memsz;
49     } else {
50         // we probably fucked up our process
51         terminate_proc(-1);
52     }
53
54     return status;
55 }
56
57 int
58 load_executable(struct load_context* context, const struct v_file* exefile)
59 {
60     int errno = 0;
61
62     char* ldpath = NULL;
63     struct elf32 elf;
64     struct exec_container* container = context->container;
65
66     if ((errno = elf32_openat(&elf, exefile))) {
67         goto done;
68     }
69
70     if (!elf32_check_arch(&elf)) {
71         errno = EINVAL;
72         goto done;
73     }
74
75     if (!(elf32_check_exec(&elf, ET_EXEC) || elf32_check_exec(&elf, ET_DYN))) {
76         errno = ENOEXEC;
77         goto done;
78     }
79
80     ldpath = valloc(512);
81     errno = elf32_find_loader(&elf, ldpath, 512);
82     uintptr_t load_base = 0;
83
84     if (errno < 0) {
85         goto done;
86     }
87
88     if (errno != NO_LOADER) {
89         container->argv_pp[1] = ldpath;
90
91         // close old elf
92         if ((errno = elf32_close(&elf))) {
93             goto done;
94         }
95
96         // open the loader instead
97         if ((errno = elf32_open(&elf, ldpath))) {
98             goto done;
99         }
100
101         // Is this the valid loader?
102         if (!elf32_static_linked(&elf) || !elf32_check_exec(&elf, ET_DYN)) {
103             errno = ELIBBAD;
104             goto done_close_elf32;
105         }
106
107         load_base = USR_MMAP;
108     }
109
110     context->entry = elf.eheader.e_entry + load_base;
111
112     struct v_file* elfile = (struct v_file*)elf.elf_file;
113
114     for (size_t i = 0; i < elf.eheader.e_phnum && !errno; i++) {
115         struct elf32_phdr* phdr = &elf.pheaders[i];
116
117         if (phdr->p_type != PT_LOAD) {
118             continue;
119         }
120
121         if (phdr->p_align != PG_SIZE) {
122             // surprising alignment!
123             errno = ENOEXEC;
124             break;
125         }
126
127         errno = elf32_smap(context, &elf, phdr, load_base);
128     }
129
130 done_close_elf32:
131     elf32_close(&elf);
132
133 done:
134     vfree_safe(ldpath);
135     return errno;
136 }