update readme for more up-to-date information
[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 int
9 elf32_smap(struct load_context* ldctx,
10            const struct elf32* elf,
11            struct elf32_phdr* phdre)
12 {
13     struct v_file* elfile = (struct v_file*)elf->elf_file;
14
15     assert(PG_ALIGNED(phdre->p_offset));
16
17     int proct = 0;
18     if ((phdre->p_flags & PF_R)) {
19         proct |= PROT_READ;
20     }
21     if ((phdre->p_flags & PF_W)) {
22         proct |= PROT_WRITE;
23     }
24     if ((phdre->p_flags & PF_X)) {
25         proct |= PROT_EXEC;
26     }
27
28     struct exec_container* container = ldctx->container;
29     struct mmap_param param = { .vms_mnt = container->vms_mnt,
30                                 .pvms = &container->proc->mm,
31                                 .proct = proct,
32                                 .offset = PG_ALIGN(phdre->p_offset),
33                                 .mlen = ROUNDUP(phdre->p_memsz, PG_SIZE),
34                                 .flen = phdre->p_filesz + PG_MOD(phdre->p_va),
35                                 .flags = MAP_FIXED | MAP_PRIVATE,
36                                 .type = REGION_TYPE_CODE };
37
38     struct mm_region* seg_reg;
39     int status = mem_map(NULL, &seg_reg, PG_ALIGN(phdre->p_va), elfile, &param);
40
41     if (!status) {
42         size_t next_addr = phdre->p_memsz + phdre->p_va;
43         ldctx->end = MAX(ldctx->end, ROUNDUP(next_addr, PG_SIZE));
44         ldctx->mem_sz += phdre->p_memsz;
45     } else {
46         // we probably fucked up our process
47         terminate_proc(-1);
48     }
49
50     return status;
51 }
52
53 int
54 load_executable(struct load_context* context, const struct v_file* exefile)
55 {
56     int errno = 0;
57
58     char* ldpath = NULL;
59     struct elf32 elf;
60     struct exec_container* container = context->container;
61
62     if ((errno = elf32_openat(&elf, exefile))) {
63         goto done;
64     }
65
66     if (!elf32_check_exec(&elf)) {
67         errno = ENOEXEC;
68         goto done;
69     }
70
71     ldpath = valloc(512);
72     errno = elf32_find_loader(&elf, ldpath, 512);
73
74     if (errno < 0) {
75         goto done;
76     }
77
78     if (errno != NO_LOADER) {
79         container->argv_pp[1] = ldpath;
80
81         // close old elf
82         if ((errno = elf32_close(&elf))) {
83             goto done;
84         }
85
86         // open the loader instead
87         if ((errno = elf32_open(&elf, ldpath))) {
88             goto done;
89         }
90
91         // Is this the valid loader?
92         if (!elf32_static_linked(&elf) || !elf32_check_exec(&elf)) {
93             errno = ELIBBAD;
94             goto done_close_elf32;
95         }
96
97         // TODO: relocate loader
98     } else {
99         context->entry = elf.eheader.e_entry;
100     }
101
102     struct v_file* elfile = (struct v_file*)elf.elf_file;
103
104     for (size_t i = 0; i < elf.eheader.e_phnum && !errno; i++) {
105         struct elf32_phdr* phdr = &elf.pheaders[i];
106
107         if (phdr->p_type == PT_LOAD) {
108             if (phdr->p_align != PG_SIZE) {
109                 // surprising alignment!
110                 errno = ENOEXEC;
111                 continue;
112             }
113
114             errno = elf32_smap(context, &elf, phdr);
115         }
116         // TODO Handle relocation
117     }
118
119 done_close_elf32:
120     elf32_close(&elf);
121 done:
122     vfree_safe(ldpath);
123     return errno;
124 }