Implement serial logging. Finish modularizing power management.
[monolithium.git] / kernel / src / exec / aout.c
1 /*
2  * aout.c
3  *
4  * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as
8  * published by the Free Software Foundation, either version 3 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <exec/aout.h>
21 #include <memory.h>
22 #include <heap.h>
23 #include <syscalls.h>
24
25 dword_t load_aout(handle_t file, thread_state_t *initial_state)
26 {
27     aout_header_t header;
28     size_t bytes_read;
29     char filename[MAX_PATH];
30     qword_t filesize;
31     uintptr_t i;
32
33     dword_t ret = syscall(SYSCALL_QUERY_FILE, file, FILE_INFO_NAME, filename, sizeof(filename));
34     if (ret != ERR_SUCCESS) return ret;
35
36     ret = syscall(SYSCALL_QUERY_FILE, file, FILE_INFO_SIZE, &filesize, sizeof(filesize));
37     if (ret != ERR_SUCCESS) return ret;
38
39     ret = syscall(SYSCALL_READ_FILE, file, &header, 0ULL, sizeof(aout_header_t), &bytes_read);
40     if (ret != ERR_SUCCESS) return ret;
41
42     void *address = (void*)0x7FE00000;
43     void *data_address;
44     void *bss_address;
45
46     ret = syscall(SYSCALL_ALLOC_MEMORY,
47                   INVALID_HANDLE,
48                   &address,
49                   0x200000,
50                   MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_WRITABLE | MEMORY_BLOCK_USERMODE | MEMORY_BLOCK_EVICTABLE);
51     if (ret != ERR_SUCCESS) return ret;
52
53     initial_state->regs.esp = (uintptr_t)address + 0x200000;
54
55     address = (void*)0x1000;
56
57     switch (header.midmag & 0xFFFF)
58     {
59     case OMAGIC:
60     {
61         data_address = (void*)((uintptr_t)address + header.text_size + sizeof(aout_header_t));
62         bss_address = (void*)((uintptr_t)address + header.text_size + header.data_size + sizeof(aout_header_t));
63
64         ret = syscall(SYSCALL_ALLOC_MEMORY,
65                       INVALID_HANDLE,
66                       &address,
67                       sizeof(aout_header_t) + header.text_size + header.data_size + header.bss_size,
68                       MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_WRITABLE | MEMORY_BLOCK_EXECUTABLE | MEMORY_BLOCK_USERMODE | MEMORY_BLOCK_EVICTABLE);
69         if (ret != ERR_SUCCESS) return ret;
70
71         ret = syscall(SYSCALL_READ_FILE,
72                       file,
73                       address,
74                       0ULL,
75                       sizeof(aout_header_t) + header.text_size + header.data_size,
76                       &bytes_read);
77         if (ret != ERR_SUCCESS) syscall(SYSCALL_FREE_MEMORY, INVALID_HANDLE, address);
78
79         initial_state->regs.eip = (uintptr_t)address + header.entry_point + sizeof(aout_header_t);
80         break;
81     }
82
83     case NMAGIC:
84         return ERR_NOSYSCALL; // TODO
85
86     case ZMAGIC:
87     {
88         handle_t section;
89         data_address = (void*)((uintptr_t)address + PAGE_ALIGN_UP(header.text_size));
90         bss_address = (void*)((uintptr_t)address + PAGE_ALIGN_UP(header.text_size) + PAGE_ALIGN_UP(header.data_size));
91
92         ret = syscall(SYSCALL_CREATE_MEMORY_SECTION, filename, file, (size_t)filesize, MEMORY_SECTION_WRITABLE, &section);
93         if (ret != ERR_SUCCESS) return ret;
94
95         ret = syscall(SYSCALL_MAP_MEMORY_SECTION,
96                       INVALID_HANDLE,
97                       section,
98                       &address,
99                       (qword_t)sizeof(aout_header_t),
100                       PAGE_ALIGN_UP(header.text_size),
101                       MEMORY_BLOCK_ACCESSIBLE
102                       | MEMORY_BLOCK_WRITABLE
103                       | MEMORY_BLOCK_USERMODE
104                       | MEMORY_BLOCK_EXECUTABLE
105                       | MEMORY_BLOCK_EVICTABLE);
106         if (ret != ERR_SUCCESS)
107         {
108             syscall(SYSCALL_CLOSE_OBJECT, section);
109             return ret;
110         }
111
112         if (header.data_size > 0)
113         {
114             ret = syscall(SYSCALL_MAP_MEMORY_SECTION,
115                           INVALID_HANDLE,
116                           section,
117                           &data_address,
118                           (qword_t)(sizeof(aout_header_t) + header.text_size),
119                           PAGE_ALIGN_UP(header.data_size),
120                           MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_WRITABLE | MEMORY_BLOCK_USERMODE | MEMORY_BLOCK_EVICTABLE);
121             if (ret != ERR_SUCCESS)
122             {
123                 syscall(SYSCALL_FREE_MEMORY, address);
124                 syscall(SYSCALL_CLOSE_OBJECT, section);
125                 return ret;
126             }
127         }
128
129         if (header.bss_size > 0)
130         {
131             ret = syscall(SYSCALL_ALLOC_MEMORY,
132                           INVALID_HANDLE,
133                           &bss_address,
134                           header.bss_size,
135                           MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_WRITABLE | MEMORY_BLOCK_USERMODE | MEMORY_BLOCK_EVICTABLE);
136             if (ret != ERR_SUCCESS)
137             {
138                 syscall(SYSCALL_FREE_MEMORY, address);
139                 if (header.data_size > 0) syscall(SYSCALL_FREE_MEMORY, data_address);
140                 syscall(SYSCALL_CLOSE_OBJECT, section);
141                 return ret;
142             }
143         }
144
145         syscall(SYSCALL_CLOSE_OBJECT, section);
146         initial_state->regs.eip = (uintptr_t)address + header.entry_point;
147         break;
148     }
149
150     default:
151         return ERR_INVALID;
152     }
153
154     uintptr_t num_text_relocs = header.text_reloc_size / sizeof(aout_reloc_t);
155     uintptr_t num_data_relocs = header.data_reloc_size / sizeof(aout_reloc_t);
156     uintptr_t num_symbols = header.sym_size / sizeof(aout_symbol_t);
157     aout_reloc_t *text_relocs = NULL;
158     aout_reloc_t *data_relocs = NULL;
159     aout_symbol_t *symbols = NULL;
160     uintptr_t string_table_size = 0;
161     char *string_table = NULL;
162
163     if (header.text_reloc_size)
164     {
165         text_relocs = (aout_reloc_t*)malloc(header.text_reloc_size);
166         if (text_relocs == NULL) return ERR_NOMEMORY;
167
168         ret = syscall(SYSCALL_READ_FILE,
169                       file,
170                       text_relocs,
171                       (qword_t)(sizeof(aout_header_t) + header.text_size + header.data_size),
172                       header.text_reloc_size,
173                       &bytes_read);
174         if (ret != ERR_SUCCESS) goto cleanup;
175     }
176
177     if (header.data_reloc_size)
178     {
179         data_relocs = (aout_reloc_t*)malloc(header.data_reloc_size);
180         if (data_relocs == NULL) return ERR_NOMEMORY;
181
182         ret = syscall(SYSCALL_READ_FILE,
183                       file,
184                       data_relocs,
185                       (qword_t)(sizeof(aout_header_t)
186                                 + header.text_size
187                                 + header.data_size
188                                 + header.text_reloc_size),
189                       header.data_reloc_size,
190                       &bytes_read);
191         if (ret != ERR_SUCCESS) goto cleanup;
192     }
193
194     if (header.sym_size)
195     {
196         symbols = (aout_symbol_t*)malloc(header.sym_size);
197         if (symbols == NULL) return ERR_NOMEMORY;
198
199         ret = syscall(SYSCALL_READ_FILE,
200                       file,
201                       symbols,
202                       (qword_t)(sizeof(aout_header_t)
203                                 + header.text_size
204                                 + header.data_size
205                                 + header.text_reloc_size
206                                 + header.data_reloc_size),
207                       header.sym_size,
208                       &bytes_read);
209         if (ret != ERR_SUCCESS) goto cleanup;
210     }
211
212     ret = syscall(SYSCALL_READ_FILE,
213                   file,
214                   &string_table_size,
215                   (qword_t)(sizeof(aout_header_t)
216                             + header.text_size
217                             + header.data_size
218                             + header.sym_size
219                             + header.text_reloc_size
220                             + header.data_reloc_size),
221                   sizeof(string_table_size),
222                   &bytes_read);
223     if (ret != ERR_SUCCESS) goto cleanup;
224
225     string_table = malloc(string_table_size);
226     if (string_table == NULL)
227     {
228         ret = ERR_NOMEMORY;
229         goto cleanup;
230     }
231
232     ret = syscall(SYSCALL_READ_FILE,
233                   file,
234                   string_table,
235                   (qword_t)(sizeof(aout_header_t)
236                             + header.text_size
237                             + header.data_size
238                             + header.sym_size
239                             + header.text_reloc_size
240                             + header.data_reloc_size),
241                   string_table_size,
242                   &bytes_read);
243     if (ret != ERR_SUCCESS) goto cleanup;
244
245     for (i = 0; i < num_symbols; i++)
246     {
247         symbols[i].name = (char*)((uintptr_t)string_table + symbols[i].name_offset);
248
249         switch (AOUT_TYPE_FIELD(symbols[i].type))
250         {
251         case AOUT_SYM_UNDEFINED:
252             // TODO: Resolve symbol
253             break;
254
255         case AOUT_SYM_TEXT:
256             symbols[i].value += (uintptr_t)address + sizeof(aout_header_t);
257             break;
258
259         case AOUT_SYM_DATA:
260             symbols[i].value += (uintptr_t)data_address;
261             break;
262
263         case AOUT_SYM_BSS:
264             symbols[i].value += (uintptr_t)bss_address;
265             break;
266         }
267     }
268
269     for (i = 0; i < num_text_relocs + num_data_relocs; i++)
270     {
271         aout_reloc_t *reloc = (i < num_text_relocs) ? &text_relocs[i] : &data_relocs[i];
272         uintptr_t base_address = (i < num_text_relocs) ? ((uintptr_t)address + sizeof(aout_header_t)) : (uintptr_t)data_address;
273         dword_t offset;
274
275         if (!reloc->external)
276         {
277             offset = (uintptr_t)address + sizeof(aout_header_t);
278         }
279         else
280         {
281             if (reloc->symbol_num >= num_symbols)
282             {
283                 ret = ERR_INVALID;
284                 goto cleanup;
285             }
286
287             offset = symbols[reloc->symbol_num].value;
288         }
289
290         switch (reloc->length)
291         {
292         case 0:
293             *(byte_t*)(base_address + reloc->address) += offset;
294             break;
295         case 1:
296             *(word_t*)(base_address + reloc->address) += offset;
297             break;
298         case 2:
299             *(dword_t*)(base_address + reloc->address) += offset;
300             break;
301         }
302     }
303
304     if ((header.midmag & 0xFFFF) == ZMAGIC)
305     {
306         syscall(SYSCALL_SET_MEMORY_FLAGS,
307                 INVALID_HANDLE,
308                 address,
309                 MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_USERMODE | MEMORY_BLOCK_EXECUTABLE | MEMORY_BLOCK_EVICTABLE);
310     }
311
312 cleanup:
313     if (symbols) free(symbols);
314     if (string_table) free(string_table);
315     return ret;
316 }