more network stack work, everything works up to udp, need to start creating a sockets...
[newos.git] / kernel / elf.c
blobbe05d84687b6e3196fd40f3b25fe091b12fc799f
1 /*
2 ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
4 */
6 #include <kernel/kernel.h>
7 #include <sys/errors.h>
8 #include <kernel/elf.h>
9 #include <kernel/vfs.h>
10 #include <kernel/vm.h>
11 #include <kernel/thread.h>
12 #include <kernel/debug.h>
13 #include <kernel/heap.h>
14 #include <kernel/arch/cpu.h>
16 #include <sys/elf32.h>
18 #include <libc/string.h>
19 #include <libc/printf.h>
21 struct elf_region {
22 region_id id;
23 addr start;
24 addr size;
25 long delta;
28 struct elf_image_info {
29 struct elf_image_info *next;
30 image_id id;
31 int ref_count;
32 void *vnode;
33 struct elf_region regions[2]; // describes the text and data regions
34 addr dynamic_ptr; // pointer to the dynamic section
35 struct elf_linked_image *linked_images;
37 struct Elf32_Ehdr *eheader;
39 // pointer to symbol participation data structures
40 char *needed;
41 unsigned int *symhash;
42 struct Elf32_Sym *syms;
43 char *strtab;
44 struct Elf32_Rel *rel;
45 int rel_len;
46 struct Elf32_Rela *rela;
47 int rela_len;
48 struct Elf32_Rel *pltrel;
49 int pltrel_len;
52 // XXX TK this shall contain a list of linked images
53 // (don't know enough about ELF how to get this list)
54 typedef struct elf_linked_image {
55 struct elf_linked_image *next;
56 struct elf_image_info *image;
57 } elf_linked_image;
59 static struct elf_image_info *kernel_images = NULL;
60 static struct elf_image_info *kernel_image = NULL;
61 static mutex image_lock;
62 static mutex image_load_lock;
63 static image_id next_image_id = 0;
65 #define STRING(image, offset) ((char *)(&(image)->strtab[(offset)]))
66 #define SYMNAME(image, sym) STRING(image, (sym)->st_name)
67 #define SYMBOL(image, num) ((struct Elf32_Sym *)&(image)->syms[num])
68 #define HASHTABSIZE(image) ((image)->symhash[0])
69 #define HASHBUCKETS(image) ((unsigned int *)&(image)->symhash[2])
70 #define HASHCHAINS(image) ((unsigned int *)&(image)->symhash[2+HASHTABSIZE(image)])
72 static void insert_image_in_list(struct elf_image_info *image)
74 mutex_lock(&image_lock);
76 image->next = kernel_images;
77 kernel_images = image;
79 mutex_unlock(&image_lock);
82 static void remove_image_from_list(struct elf_image_info *image)
84 struct elf_image_info **ptr;
86 mutex_lock(&image_lock);
88 for(ptr = &kernel_images; *ptr; ptr = &(*ptr)->next) {
89 if(*ptr == image) {
90 *ptr = image->next;
91 image->next = 0;
92 break;
96 mutex_unlock(&image_lock);
99 static struct elf_image_info *find_image(image_id id)
101 struct elf_image_info *image;
103 mutex_lock(&image_lock);
105 for(image = kernel_images; image; image = image->next) {
106 if(image->id == id)
107 break;
109 mutex_unlock(&image_lock);
111 return image;
114 static struct elf_image_info *find_image_by_vnode(void *vnode)
116 struct elf_image_info *image;
118 mutex_lock(&image_lock);
120 for(image = kernel_images; image; image = image->next) {
121 if(image->vnode == vnode)
122 break;
124 mutex_unlock(&image_lock);
126 return image;
129 static struct elf_image_info *create_image_struct()
131 struct elf_image_info *image;
133 image = kmalloc(sizeof(struct elf_image_info));
134 if(!image)
135 return NULL;
136 memset(image, 0, sizeof(struct elf_image_info));
137 image->regions[0].id = -1;
138 image->regions[1].id = -1;
139 image->id = atomic_add(&next_image_id, 1);
140 image->ref_count = 1;
141 image->linked_images = NULL;
142 return image;
145 static unsigned long elf_hash(const unsigned char *name)
147 unsigned long hash = 0;
148 unsigned long temp;
150 while(*name) {
151 hash = (hash << 4) + *name++;
152 if((temp = hash & 0xf0000000))
153 hash ^= temp >> 24;
154 hash &= ~temp;
156 return hash;
159 static void dump_image_info(struct elf_image_info *image)
161 int i;
163 dprintf("elf_image_info at 0x%x:\n", image);
164 dprintf(" next 0x%x\n", image->next);
165 dprintf(" id 0x%x\n", image->id);
166 for(i=0; i<2; i++) {
167 dprintf(" regions[%d].id 0x%x\n", i, image->regions[i].id);
168 dprintf(" regions[%d].start 0x%x\n", i, image->regions[i].start);
169 dprintf(" regions[%d].size 0x%x\n", i, image->regions[i].size);
170 dprintf(" regions[%d].delta %d\n", i, image->regions[i].delta);
172 dprintf(" dynamic_ptr 0x%x\n", image->dynamic_ptr);
173 dprintf(" needed 0x%x\n", image->needed);
174 dprintf(" symhash 0x%x\n", image->symhash);
175 dprintf(" syms 0x%x\n", image->syms);
176 dprintf(" strtab 0x%x\n", image->strtab);
177 dprintf(" rel 0x%x\n", image->rel);
178 dprintf(" rel_len 0x%x\n", image->rel_len);
179 dprintf(" rela 0x%x\n", image->rela);
180 dprintf(" rela_len 0x%x\n", image->rela_len);
183 static void dump_symbol(struct elf_image_info *image, struct Elf32_Sym *sym)
186 dprintf("symbol at 0x%x, in image 0x%x\n", sym, image);
188 dprintf(" name index %d, '%s'\n", sym->st_name, SYMNAME(image, sym));
189 dprintf(" st_value 0x%x\n", sym->st_value);
190 dprintf(" st_size %d\n", sym->st_size);
191 dprintf(" st_info 0x%x\n", sym->st_info);
192 dprintf(" st_other 0x%x\n", sym->st_other);
193 dprintf(" st_shndx %d\n", sym->st_shndx);
196 static struct Elf32_Sym *elf_find_symbol(struct elf_image_info *image, const char *name)
198 unsigned int hash;
199 unsigned int i;
201 if(!image->dynamic_ptr)
202 return NULL;
204 hash = elf_hash(name) % HASHTABSIZE(image);
205 for(i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) {
206 if(!strcmp(SYMNAME(image, &image->syms[i]), name)) {
207 return &image->syms[i];
211 return NULL;
214 addr elf_lookup_symbol(image_id id, const char *symbol)
216 struct elf_image_info *image;
217 struct Elf32_Sym *sym;
219 //dprintf( "elf_lookup_symbol: %s\n", symbol );
221 image = find_image(id);
222 if(!image)
223 return 0;
225 sym = elf_find_symbol(image, symbol);
226 if(!sym)
227 return 0;
229 if(sym->st_shndx == SHN_UNDEF) {
230 return 0;
233 /*dprintf( "found: %x (%x + %x)\n", sym->st_value + image->regions[0].delta,
234 sym->st_value, image->regions[0].delta );*/
235 return sym->st_value + image->regions[0].delta;
238 static int elf_parse_dynamic_section(struct elf_image_info *image)
240 struct Elf32_Dyn *d;
241 int i;
242 int needed_offset = -1;
244 // dprintf("top of elf_parse_dynamic_section\n");
246 image->symhash = 0;
247 image->syms = 0;
248 image->strtab = 0;
250 d = (struct Elf32_Dyn *)image->dynamic_ptr;
251 if(!d)
252 return ERR_GENERAL;
254 for(i=0; d[i].d_tag != DT_NULL; i++) {
255 switch(d[i].d_tag) {
256 case DT_NEEDED:
257 needed_offset = d[i].d_un.d_ptr + image->regions[0].delta;
258 break;
259 case DT_HASH:
260 image->symhash = (unsigned int *)(d[i].d_un.d_ptr + image->regions[0].delta);
261 break;
262 case DT_STRTAB:
263 image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
264 break;
265 case DT_SYMTAB:
266 image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
267 break;
268 case DT_REL:
269 image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
270 break;
271 case DT_RELSZ:
272 image->rel_len = d[i].d_un.d_val;
273 break;
274 case DT_RELA:
275 image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
276 break;
277 case DT_RELASZ:
278 image->rela_len = d[i].d_un.d_val;
279 break;
280 // TK: procedure linkage table
281 case DT_JMPREL:
282 image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
283 break;
284 case DT_PLTRELSZ:
285 image->pltrel_len = d[i].d_un.d_val;
286 break;
287 default:
288 continue;
292 // lets make sure we found all the required sections
293 if(!image->symhash || !image->syms || !image->strtab)
294 return ERR_GENERAL;
296 // dprintf("needed_offset = %d\n", needed_offset);
298 if(needed_offset >= 0)
299 image->needed = STRING(image, needed_offset);
301 return NO_ERROR;
304 // this function first tries to see if the first image and it's already resolved symbol is okay, otherwise
305 // it tries to link against the shared_image
306 // XXX gross hack and needs to be done better
307 static int elf_resolve_symbol(struct elf_image_info *image, struct Elf32_Sym *sym, struct elf_image_info *shared_image, const char *sym_prepend,addr *sym_addr)
309 struct Elf32_Sym *sym2;
310 char new_symname[512];
312 switch(sym->st_shndx) {
313 case SHN_UNDEF:
314 // patch the symbol name
315 strcpy(new_symname, sym_prepend);
316 strcat(new_symname, SYMNAME(image, sym));
318 // it's undefined, must be outside this image, try the other image
319 sym2 = elf_find_symbol(shared_image, new_symname);
320 if(!sym2) {
321 dprintf("elf_resolve_symbol: could not resolve symbol '%s'\n", new_symname);
322 return ERR_ELF_RESOLVING_SYMBOL;
325 // make sure they're the same type
326 if(ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) {
327 dprintf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", new_symname);
328 return ERR_ELF_RESOLVING_SYMBOL;
331 if(ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL && ELF32_ST_BIND(sym2->st_info) != STB_WEAK) {
332 dprintf("elf_resolve_symbol: found symbol '%s' but not exported\n", new_symname);
333 return ERR_ELF_RESOLVING_SYMBOL;
336 *sym_addr = sym2->st_value + shared_image->regions[0].delta;
337 return NO_ERROR;
338 case SHN_ABS:
339 *sym_addr = sym->st_value;
340 return NO_ERROR;
341 case SHN_COMMON:
342 // XXX finish this
343 dprintf("elf_resolve_symbol: COMMON symbol, finish me!\n");
344 return ERR_NOT_IMPLEMENTED_YET;
345 default:
346 // standard symbol
347 *sym_addr = sym->st_value + image->regions[0].delta;
348 return NO_ERROR;
352 static int elf_relocate_rel(struct elf_image_info *image, const char *sym_prepend,
353 struct Elf32_Rel *rel, int rel_len )
355 int i;
356 struct Elf32_Sym *sym;
357 int vlErr;
358 addr S;
359 addr A;
360 addr P;
361 addr final_val;
363 S = A = P = 0;
365 for(i = 0; i * (int)sizeof(struct Elf32_Rel) < rel_len; i++) {
366 //dprintf("looking at rel type %d, offset 0x%x\n", ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset);
368 // calc S
369 switch(ELF32_R_TYPE(rel[i].r_info)) {
370 case R_386_32:
371 case R_386_PC32:
372 case R_386_GLOB_DAT:
373 case R_386_JMP_SLOT:
374 case R_386_GOTOFF:
375 sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
377 vlErr = elf_resolve_symbol(image, sym, kernel_image, sym_prepend,&S);
378 if(vlErr<0) return vlErr;
379 //dprintf("S 0x%x\n", S);
381 // calc A
382 switch(ELF32_R_TYPE(rel[i].r_info)) {
383 case R_386_32:
384 case R_386_PC32:
385 case R_386_GOT32:
386 case R_386_PLT32:
387 case R_386_RELATIVE:
388 case R_386_GOTOFF:
389 case R_386_GOTPC:
390 A = *(addr *)(image->regions[0].delta + rel[i].r_offset);
391 // dprintf("A 0x%x\n", A);
392 break;
394 // calc P
395 switch(ELF32_R_TYPE(rel[i].r_info)) {
396 case R_386_PC32:
397 case R_386_GOT32:
398 case R_386_PLT32:
399 case R_386_GOTPC:
400 P = image->regions[0].delta + rel[i].r_offset;
401 // dprintf("P 0x%x\n", P);
402 break;
405 switch(ELF32_R_TYPE(rel[i].r_info)) {
406 case R_386_NONE:
407 continue;
408 case R_386_32:
409 final_val = S + A;
410 break;
411 case R_386_PC32:
412 final_val = S + A - P;
413 break;
414 case R_386_RELATIVE:
415 // B + A;
416 final_val = image->regions[0].delta + A;
417 break;
418 case R_386_JMP_SLOT:
419 final_val = S;
420 dprintf( "final=%x\n", final_val );
421 break;
422 default:
423 dprintf("unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
424 return ERR_NOT_ALLOWED;
426 *(addr *)(image->regions[0].delta + rel[i].r_offset) = final_val;
429 return NO_ERROR;
432 // XXX for now just link against the kernel
433 static int elf_relocate(struct elf_image_info *image, const char *sym_prepend)
435 int res = NO_ERROR;
436 int i;
437 // dprintf("top of elf_relocate\n");
439 // deal with the rels first
440 if( image->rel ) {
441 //dprintf( "total %i relocs\n", image->rel_len / (int)sizeof(struct Elf32_Rel) );
442 res = elf_relocate_rel( image, sym_prepend, image->rel, image->rel_len );
444 if( res )
445 return res;
448 if( image->pltrel ) {
449 //dprintf( "total %i plt-relocs\n", image->pltrel_len / (int)sizeof(struct Elf32_Rel) );
450 res = elf_relocate_rel( image, sym_prepend, image->pltrel, image->pltrel_len );
452 if( res )
453 return res;
456 if(image->rela) {
457 dprintf("RELA relocations not supported\n");
458 return ERR_NOT_ALLOWED;
459 for(i = 1; i * (int)sizeof(struct Elf32_Rela) < image->rela_len; i++) {
460 dprintf("rela: type %d\n", ELF32_R_TYPE(image->rela[i].r_info));
463 return res;
466 static int verify_eheader(struct Elf32_Ehdr *eheader)
468 if(memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
469 return ERR_INVALID_BINARY;
471 if(eheader->e_ident[4] != ELFCLASS32)
472 return ERR_INVALID_BINARY;
474 if(eheader->e_phoff == 0)
475 return ERR_INVALID_BINARY;
477 if(eheader->e_phentsize < sizeof(struct Elf32_Phdr))
478 return ERR_INVALID_BINARY;
480 return 0;
483 int elf_load_uspace(const char *path, struct proc *p, int flags, addr *entry)
485 struct Elf32_Ehdr eheader;
486 struct Elf32_Phdr *pheaders = NULL;
487 int fd;
488 int err;
489 int i;
490 ssize_t len;
492 dprintf("elf_load: entry path '%s', proc 0x%x\n", path, p);
494 fd = sys_open(path, STREAM_TYPE_FILE, 0);
495 if(fd < 0)
496 return fd;
498 len = sys_read(fd, &eheader, 0, sizeof(eheader));
499 if(len < 0) {
500 err = len;
501 goto error;
503 if(len != sizeof(eheader)) {
504 // short read
505 err = ERR_INVALID_BINARY;
506 goto error;
508 err = verify_eheader(&eheader);
509 if(err < 0)
510 goto error;
512 pheaders = kmalloc(eheader.e_phnum * eheader.e_phentsize);
513 if(pheaders == NULL) {
514 dprintf("error allocating space for program headers\n");
515 err = ERR_NO_MEMORY;
516 goto error;
519 dprintf("reading in program headers at 0x%x, len 0x%x\n", eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize);
520 len = sys_read(fd, pheaders, eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize);
521 if(len < 0) {
522 err = len;
523 dprintf("error reading in program headers\n");
524 goto error;
526 if(len != eheader.e_phnum * eheader.e_phentsize) {
527 dprintf("short read while reading in program headers\n");
528 err = -1;
529 goto error;
532 for(i=0; i < eheader.e_phnum; i++) {
533 char region_name[64];
534 region_id id;
535 char *region_addr;
537 sprintf(region_name, "%s_seg%d", path, i);
539 region_addr = (char *)ROUNDOWN(pheaders[i].p_vaddr, PAGE_SIZE);
540 id = vm_create_anonymous_region(p->aspace_id, region_name, (void **)&region_addr, REGION_ADDR_EXACT_ADDRESS,
541 ROUNDUP(pheaders[i].p_memsz + (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE), REGION_WIRING_LAZY, LOCK_RW);
542 if(id < 0) {
543 dprintf("error allocating region!\n");
544 err = ERR_INVALID_BINARY;
545 goto error;
548 len = sys_read(fd, region_addr + (pheaders[i].p_vaddr % PAGE_SIZE), pheaders[i].p_offset, pheaders[i].p_filesz);
549 if(len < 0) {
550 err = len;
551 dprintf("error reading in seg %d\n", i);
552 goto error;
556 dprintf("elf_load: done!\n");
558 *entry = eheader.e_entry;
560 err = 0;
562 error:
563 if(pheaders)
564 kfree(pheaders);
565 sys_close(fd);
567 return err;
570 image_id elf_load_kspace(const char *path, const char *sym_prepend)
572 struct Elf32_Ehdr *eheader;
573 struct Elf32_Phdr *pheaders;
574 struct elf_image_info *image;
575 void *vnode = NULL;
576 int fd;
577 int err;
578 int i;
579 ssize_t len;
581 dprintf("elf_load_kspace: entry path '%s'\n", path);
583 fd = sys_open(path, STREAM_TYPE_FILE, 0);
584 if(fd < 0)
585 return fd;
587 err = vfs_get_vnode_from_fd(fd, true, &vnode);
588 if(err < 0)
589 goto error0;
591 // XXX awful hack to keep someone else from trying to load this image
592 // probably not a bad thing, shouldn't be too many races
593 mutex_lock(&image_load_lock);
595 // make sure it's not loaded already. Search by vnode
596 image = find_image_by_vnode(vnode);
597 if( image ) {
598 atomic_add( &image->ref_count, 1 );
599 //err = ERR_NOT_ALLOWED;
600 goto done;
603 eheader = (struct Elf32_Ehdr *)kmalloc( sizeof( *eheader ));
604 if( !eheader ) {
605 err = ERR_NO_MEMORY;
606 goto error;
609 len = sys_read(fd, eheader, 0, sizeof(*eheader));
610 if(len < 0) {
611 err = len;
612 goto error1;
614 if(len != sizeof(*eheader)) {
615 // short read
616 err = ERR_INVALID_BINARY;
617 goto error1;
619 err = verify_eheader(eheader);
620 if(err < 0)
621 goto error1;
623 image = create_image_struct();
624 if(!image) {
625 err = ERR_NO_MEMORY;
626 goto error1;
628 image->vnode = vnode;
629 image->eheader = eheader;
631 pheaders = kmalloc(eheader->e_phnum * eheader->e_phentsize);
632 if(pheaders == NULL) {
633 dprintf("error allocating space for program headers\n");
634 err = ERR_NO_MEMORY;
635 goto error2;
638 // dprintf("reading in program headers at 0x%x, len 0x%x\n", eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize);
639 len = sys_read(fd, pheaders, eheader->e_phoff, eheader->e_phnum * eheader->e_phentsize);
640 if(len < 0) {
641 err = len;
642 dprintf("error reading in program headers\n");
643 goto error3;
645 if(len != eheader->e_phnum * eheader->e_phentsize) {
646 dprintf("short read while reading in program headers\n");
647 err = -1;
648 goto error3;
651 for(i=0; i < eheader->e_phnum; i++) {
652 char region_name[64];
653 bool ro_segment_handled = false;
654 bool rw_segment_handled = false;
655 int image_region;
656 int lock;
658 // dprintf("looking at program header %d\n", i);
660 switch(pheaders[i].p_type) {
661 case PT_LOAD:
662 break;
663 case PT_DYNAMIC:
664 image->dynamic_ptr = pheaders[i].p_vaddr;
665 continue;
666 default:
667 dprintf("unhandled pheader type 0x%x\n", pheaders[i].p_type);
668 continue;
671 // we're here, so it must be a PT_LOAD segment
672 if((pheaders[i].p_flags & (PF_R | PF_W | PF_X)) == (PF_R | PF_W)) {
673 // this is the writable segment
674 if(rw_segment_handled) {
675 // we've already created this segment
676 continue;
678 rw_segment_handled = true;
679 image_region = 1;
680 lock = LOCK_RW|LOCK_KERNEL;
681 sprintf(region_name, "%s_rw", path);
682 } else if((pheaders[i].p_flags & (PF_R | PF_W | PF_X)) == (PF_R | PF_X)) {
683 // this is the non-writable segment
684 if(ro_segment_handled) {
685 // we've already created this segment
686 continue;
688 ro_segment_handled = true;
689 image_region = 0;
690 // lock = LOCK_RO|LOCK_KERNEL;
691 lock = LOCK_RW|LOCK_KERNEL;
692 sprintf(region_name, "%s_ro", path);
693 } else {
694 dprintf("weird program header flags 0x%x\n", pheaders[i].p_flags);
695 continue;
697 image->regions[image_region].size = ROUNDUP(pheaders[i].p_memsz + (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE);
698 image->regions[image_region].id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), region_name,
699 (void **)&image->regions[image_region].start, REGION_ADDR_ANY_ADDRESS,
700 image->regions[image_region].size, REGION_WIRING_WIRED, lock);
701 if(image->regions[image_region].id < 0) {
702 dprintf("error allocating region!\n");
703 err = ERR_INVALID_BINARY;
704 goto error3;
706 image->regions[image_region].delta = image->regions[image_region].start - ROUNDOWN(pheaders[i].p_vaddr, PAGE_SIZE);
708 // dprintf("elf_load_kspace: created a region at 0x%x\n", image->regions[image_region].start);
710 len = sys_read(fd, (void *)(image->regions[image_region].start + (pheaders[i].p_vaddr % PAGE_SIZE)),
711 pheaders[i].p_offset, pheaders[i].p_filesz);
712 if(len < 0) {
713 err = len;
714 dprintf("error reading in seg %d\n", i);
715 goto error4;
719 if(image->regions[1].start != 0) {
720 if(image->regions[0].delta != image->regions[1].delta) {
721 dprintf("could not load binary, fix the region problem!\n");
722 dump_image_info(image);
723 err = ERR_NO_MEMORY;
724 goto error4;
728 // modify the dynamic ptr by the delta of the regions
729 image->dynamic_ptr += image->regions[0].delta;
731 err = elf_parse_dynamic_section(image);
732 if(err < 0)
733 goto error4;
735 err = elf_relocate(image, sym_prepend);
736 if(err < 0)
737 goto error4;
739 err = 0;
741 kfree(pheaders);
742 sys_close(fd);
744 insert_image_in_list(image);
746 done:
747 mutex_unlock(&image_load_lock);
749 dprintf("elf_load_kspace: done!\n");
751 return image->id;
753 error4:
754 if(image->regions[1].id >= 0)
755 vm_delete_region(vm_get_kernel_aspace_id(), image->regions[1].id);
756 if(image->regions[0].id >= 0)
757 vm_delete_region(vm_get_kernel_aspace_id(), image->regions[0].id);
758 error3:
759 kfree(image);
760 error2:
761 kfree(pheaders);
762 error1:
763 kfree(eheader);
764 error:
765 mutex_unlock(&image_load_lock);
766 error0:
767 if(vnode)
768 vfs_put_vnode_ptr(vnode);
769 sys_close(fd);
771 return err;
774 static int elf_unload_image( struct elf_image_info *image );
776 static int elf_unlink_relocs( struct elf_image_info *image )
778 elf_linked_image *link, *next_link;
780 for( link = image->linked_images; link; link = next_link ) {
781 next_link = link->next;
782 elf_unload_image( link->image );
783 kfree( link );
786 return NO_ERROR;
789 static void elf_unload_image_final( struct elf_image_info *image )
791 int i;
793 for( i = 0; i < 2; ++i ) {
794 vm_delete_region( vm_get_kernel_aspace_id(), image->regions[i].id );
797 if( image->vnode )
798 vfs_put_vnode_ptr( image->vnode );
800 remove_image_from_list(image);
801 kfree( image->eheader );
802 kfree( image );
805 static int elf_unload_image( struct elf_image_info *image )
807 if( atomic_add( &image->ref_count, -1 ) > 0 )
808 return NO_ERROR;
810 elf_unlink_relocs( image );
811 elf_unload_image_final( image );
813 return NO_ERROR;
816 int elf_unload_kspace( const char *path )
818 int fd;
819 int err;
820 void *vnode;
821 struct elf_image_info *image;
823 fd = sys_open(path, STREAM_TYPE_FILE, 0);
824 if(fd < 0)
825 return fd;
827 err = vfs_get_vnode_from_fd(fd, true, &vnode);
828 if(err < 0)
829 goto error0;
831 mutex_lock(&image_load_lock);
833 image = find_image_by_vnode(vnode);
834 if( !image ) {
835 dprintf( "Tried to unload image that wasn't loaded (%s)\n", path );
836 err = ERR_NOT_FOUND;
837 goto error;
840 err = elf_unload_image( image );
842 error:
843 mutex_unlock(&image_load_lock);
844 error0:
845 if(vnode)
846 vfs_put_vnode_ptr(vnode);
847 sys_close(fd);
849 return err;
852 int elf_init(kernel_args *ka)
854 vm_region_info rinfo;
855 int err;
857 // build a image structure for the kernel, which has already been loaded
858 kernel_image = create_image_struct();
860 // text segment
861 kernel_image->regions[0].id = vm_find_region_by_name(vm_get_kernel_aspace_id(), "kernel_ro");
862 if(kernel_image->regions[0].id < 0)
863 panic("elf_init: could not look up kernel text segment region\n");
864 vm_get_region_info(kernel_image->regions[0].id, &rinfo);
865 kernel_image->regions[0].start = rinfo.base;
866 kernel_image->regions[0].size = rinfo.size;
868 // data segment
869 kernel_image->regions[1].id = vm_find_region_by_name(vm_get_kernel_aspace_id(), "kernel_rw");
870 if(kernel_image->regions[1].id < 0)
871 panic("elf_init: could not look up kernel data segment region\n");
872 vm_get_region_info(kernel_image->regions[1].id, &rinfo);
873 kernel_image->regions[1].start = rinfo.base;
874 kernel_image->regions[1].size = rinfo.size;
876 // we know where the dynamic section is
877 kernel_image->dynamic_ptr = (addr)ka->kernel_dynamic_section_addr.start;
879 // parse the dynamic section
880 if(elf_parse_dynamic_section(kernel_image) < 0)
881 dprintf("elf_init: WARNING elf_parse_dynamic_section couldn't find dynamic section.\n");
883 // insert it first in the list of kernel images loaded
884 kernel_images = NULL;
885 insert_image_in_list(kernel_image);
887 mutex_init(&image_lock, "kimages_lock");
888 mutex_init(&image_load_lock, "kimages_load_lock");
890 return 0;