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