Boot framework rework (#45)
[lunaix-os.git] / lunaix-os / kernel / exe / elf-generic / elfbfmt.c
1 #include <lunaix/exebi/elf.h>
2 #include <lunaix/fs.h>
3 #include <lunaix/mm/valloc.h>
4 #include <lunaix/spike.h>
5
6 #include <klibc/string.h>
7
8 static inline int
9 elf_read(struct v_file* elf, void* data, size_t off, size_t len)
10 {
11     // it is wise to do cached read
12     return pcache_read(elf->inode, data, len, off);
13 }
14
15 static int
16 elf_do_open(struct elf* elf, struct v_file* elf_file)
17 {
18     int status = 0;
19     elf->pheaders = NULL;
20     elf->elf_file = elf_file;
21
22     if ((status = elf_read_ehdr(elf)) < 0) {
23         elf_close(elf);
24         return status;
25     }
26
27     if ((status = elf_read_phdr(elf)) < 0) {
28         elf_close(elf);
29         return status;
30     }
31
32     return 0;
33 }
34
35 defualt int
36 elf_open(struct elf* elf, const char* path)
37 {
38     struct v_dnode* elfdn;
39     struct v_file* elffile;
40     int error = 0;
41
42     if ((error = vfs_walk_proc(path, &elfdn, NULL, 0))) {
43         return error;
44     }
45
46     if ((error = vfs_open(elfdn, &elffile))) {
47         return error;
48     }
49
50     return elf_do_open(elf, elffile);
51 }
52
53 defualt int
54 elf_openat(struct elf* elf, void* elf_vfile)
55 {
56     // so the ref count kept in sync
57     vfs_ref_file(elf_vfile);
58     return elf_do_open(elf, elf_vfile);
59 }
60
61 defualt int
62 elf_close(struct elf* elf)
63 {
64     if (elf->pheaders) {
65         vfree(elf->pheaders);
66     }
67
68     if (elf->elf_file) {
69         vfs_close((struct v_file*)elf->elf_file);
70     }
71
72     memset(elf, 0, sizeof(*elf));
73
74     return 0;
75 }
76
77 defualt int
78 elf_static_linked(const struct elf* elf)
79 {
80     for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
81         struct elf_phdr* phdre = &elf->pheaders[i];
82         if (phdre->p_type == PT_INTERP) {
83             return 0;
84         }
85     }
86     return 1;
87 }
88
89 defualt size_t
90 elf_loadable_memsz(const struct elf* elf)
91 {
92     // XXX: Hmmmm, I am not sure if we need this. This is designed to be handy
93     // if we decided to map the heap region before transfer to loader. As
94     // currently, we push *everything* to user-space loader, thus we modify the
95     // brk syscall to do the initial heap mapping.
96
97     size_t sz = 0;
98     for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
99         struct elf_phdr* phdre = &elf->pheaders[i];
100         if (phdre->p_type == PT_LOAD) {
101             sz += phdre->p_memsz;
102         }
103     }
104
105     return sz;
106 }
107
108 defualt int
109 elf_find_loader(const struct elf* elf, char* path_out, size_t len)
110 {
111     int retval = NO_LOADER;
112
113     assert_msg(len >= sizeof(DEFAULT_LOADER), "path_out: too small");
114
115     struct v_file* elfile = (struct v_file*)elf->elf_file;
116
117     for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
118         struct elf_phdr* phdre = &elf->pheaders[i];
119         if (phdre->p_type == PT_INTERP) {
120             if (len >= phdre->p_filesz) {
121                 return EINVAL;
122             }
123
124             retval =
125               elf_read(elfile, path_out, phdre->p_offset, phdre->p_filesz);
126
127             if (retval < 0) {
128                 return retval;
129             }
130
131             break;
132         }
133     }
134
135     return retval;
136 }
137
138 defualt int
139 elf_read_ehdr(struct elf* elf)
140 {
141     struct v_file* elfile = (struct v_file*)elf->elf_file;
142
143     return elf_read(elfile, (void*)&elf->eheader, 0, SIZE_EHDR);
144 }
145
146 defualt int
147 elf_read_phdr(struct elf* elf)
148 {
149     int status = 0;
150
151     struct v_file* elfile = (struct v_file*)elf->elf_file;
152
153     size_t entries = elf->eheader.e_phnum;
154     size_t tbl_sz = entries * SIZE_PHDR;
155
156     struct elf_phdr* phdrs = valloc(tbl_sz);
157
158     if (!phdrs) {
159         return ENOMEM;
160     }
161
162     status = elf_read(elfile, phdrs, elf->eheader.e_phoff, tbl_sz);
163
164     if (status < 0) {
165         vfree(phdrs);
166         return status;
167     }
168
169     elf->pheaders = phdrs;
170     return entries;
171 }
172
173 defualt int
174 elf_check_exec(const struct elf* elf, int type)
175 {
176     const struct elf_ehdr* ehdr = &elf->eheader;
177
178     return (ehdr->e_entry) && ehdr->e_type == type;
179 }
180
181 defualt int
182 elf_check_arch(const struct elf* elf)
183 {
184     const struct elf_ehdr* ehdr = &elf->eheader;
185
186     return *(u32_t*)(ehdr->e_ident) == ELFMAGIC_LE;
187 }