fixed a bug in the tty code that caused it to panic the system if you called read...
[newos.git] / kernel / elf.c
blob3940733879fbc4b8ddf847b9a7b1df679f166c74
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 <newos/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 <newos/elf32.h>
18 #include <string.h>
19 #include <stdio.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 %p:\n", image);
164 dprintf(" next %p\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%lx\n", i, image->regions[i].start);
169 dprintf(" regions[%d].size 0x%lx\n", i, image->regions[i].size);
170 dprintf(" regions[%d].delta %ld\n", i, image->regions[i].delta);
172 dprintf(" dynamic_ptr 0x%lx\n", image->dynamic_ptr);
173 dprintf(" needed %p\n", image->needed);
174 dprintf(" symhash %p\n", image->symhash);
175 dprintf(" syms %p\n", image->syms);
176 dprintf(" strtab %p\n", image->strtab);
177 dprintf(" rel %p\n", image->rel);
178 dprintf(" rel_len 0x%x\n", image->rel_len);
179 dprintf(" rela %p\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 %p, in image %p\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);
198 #if 0
199 #define PRINT(x) dprintf x
200 #else
201 #define PRINT(x)
202 #endif
205 /* Take an address to symbol. Taken from the OpenBeOS version of the newos kernel. */
206 int elf_reverse_lookup_symbol(addr address, addr *base_address, char *text, int len)
208 struct elf_image_info **ptr;
209 struct elf_image_info *image;
210 struct Elf32_Sym *sym;
211 struct elf_image_info *found_image;
212 struct Elf32_Sym *found_sym;
213 long found_delta;
214 int i,j,rv;
216 PRINT(("looking up %p\n",(void *)address));
218 mutex_lock(&image_lock);
220 found_sym = 0;
221 found_image = 0;
222 found_delta = 0x7fffffff;
223 for(ptr = &kernel_images; *ptr; ptr = &(*ptr)->next) {
224 image = *ptr;
226 PRINT((" image %p, base = %p, size = %p\n", image, (void *)image->regions[0].start, (void *)image->regions[0].size));
227 if ((address < image->regions[0].start) || (address >= (image->regions[0].start + image->regions[0].size)))
228 continue;
230 PRINT((" searching...\n"));
231 found_image = image;
232 for (i = 0; i < HASHTABSIZE(image); i++) {
233 for(j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) {
234 long d;
235 sym = &image->syms[j];
237 PRINT((" %p looking at %s, type = %d, bind = %d, addr = %p\n",sym,SYMNAME(image, sym),ELF32_ST_TYPE(sym->st_info),ELF32_ST_BIND(sym->st_info),(void *)sym->st_value));
238 PRINT((" symbol: %lx (%x + %lx)\n", sym->st_value + image->regions[0].delta, sym->st_value, image->regions[0].delta));
240 if (ELF32_ST_TYPE(sym->st_info) != STT_FUNC)
241 continue;
243 d = (long)address - (long)(sym->st_value + image->regions[0].delta);
244 if ((d >= 0) && (d < found_delta)) {
245 found_delta = d;
246 found_sym = sym;
250 break;
252 if (found_sym == 0) {
253 PRINT(("symbol not found!\n"));
254 strlcpy(text, "symbol not found", len);
255 rv = ERR_NOT_FOUND;
256 } else {
257 PRINT(("symbol at %p, in image %p\n", found_sym, found_image));
258 PRINT(("name index %d, '%s'\n", found_sym->st_name, SYMNAME(found_image, found_sym)));
259 PRINT(("addr = %#lx, offset = %#lx\n",(found_sym->st_value + found_image->regions[0].delta),found_delta));
260 // XXX should honor len here
261 // sprintf(text, "<%#lx:%s + %#lx> %s", (found_sym->st_value + found_image->regions[0].delta), SYMNAME(found_image, found_sym), found_delta, found_image->name);
262 strncpy(text, SYMNAME(found_image, found_sym), len);
263 text[len-1] = 0;
264 *base_address = found_sym->st_value + found_image->regions[0].delta;
265 rv = 0;
268 mutex_unlock(&image_lock);
269 return rv;
273 static struct Elf32_Sym *elf_find_symbol(struct elf_image_info *image, const char *name)
275 unsigned int hash;
276 unsigned int i;
278 if(!image->dynamic_ptr)
279 return NULL;
281 hash = elf_hash(name) % HASHTABSIZE(image);
282 for(i = HASHBUCKETS(image)[hash]; i != STN_UNDEF; i = HASHCHAINS(image)[i]) {
283 if(!strcmp(SYMNAME(image, &image->syms[i]), name)) {
284 return &image->syms[i];
288 return NULL;
291 addr elf_lookup_symbol(image_id id, const char *symbol)
293 struct elf_image_info *image;
294 struct Elf32_Sym *sym;
296 //dprintf( "elf_lookup_symbol: %s\n", symbol );
298 image = find_image(id);
299 if(!image)
300 return 0;
302 sym = elf_find_symbol(image, symbol);
303 if(!sym)
304 return 0;
306 if(sym->st_shndx == SHN_UNDEF) {
307 return 0;
310 /*dprintf( "found: %x (%x + %x)\n", sym->st_value + image->regions[0].delta,
311 sym->st_value, image->regions[0].delta );*/
312 return sym->st_value + image->regions[0].delta;
315 static int elf_parse_dynamic_section(struct elf_image_info *image)
317 struct Elf32_Dyn *d;
318 int i;
319 int needed_offset = -1;
321 // dprintf("top of elf_parse_dynamic_section\n");
323 image->symhash = 0;
324 image->syms = 0;
325 image->strtab = 0;
327 d = (struct Elf32_Dyn *)image->dynamic_ptr;
328 if(!d)
329 return ERR_GENERAL;
331 for(i=0; d[i].d_tag != DT_NULL; i++) {
332 switch(d[i].d_tag) {
333 case DT_NEEDED:
334 needed_offset = d[i].d_un.d_ptr + image->regions[0].delta;
335 break;
336 case DT_HASH:
337 image->symhash = (unsigned int *)(d[i].d_un.d_ptr + image->regions[0].delta);
338 break;
339 case DT_STRTAB:
340 image->strtab = (char *)(d[i].d_un.d_ptr + image->regions[0].delta);
341 break;
342 case DT_SYMTAB:
343 image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr + image->regions[0].delta);
344 break;
345 case DT_REL:
346 image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
347 break;
348 case DT_RELSZ:
349 image->rel_len = d[i].d_un.d_val;
350 break;
351 case DT_RELA:
352 image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr + image->regions[0].delta);
353 break;
354 case DT_RELASZ:
355 image->rela_len = d[i].d_un.d_val;
356 break;
357 // TK: procedure linkage table
358 case DT_JMPREL:
359 image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr + image->regions[0].delta);
360 break;
361 case DT_PLTRELSZ:
362 image->pltrel_len = d[i].d_un.d_val;
363 break;
364 default:
365 continue;
369 // lets make sure we found all the required sections
370 if(!image->symhash || !image->syms || !image->strtab)
371 return ERR_GENERAL;
373 // dprintf("needed_offset = %d\n", needed_offset);
375 if(needed_offset >= 0)
376 image->needed = STRING(image, needed_offset);
378 return NO_ERROR;
381 // this function first tries to see if the first image and it's already resolved symbol is okay, otherwise
382 // it tries to link against the shared_image
383 // XXX gross hack and needs to be done better
384 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)
386 struct Elf32_Sym *sym2;
387 char new_symname[512];
389 switch(sym->st_shndx) {
390 case SHN_UNDEF:
391 // patch the symbol name
392 strlcpy(new_symname, sym_prepend, sizeof(new_symname));
393 strlcat(new_symname, SYMNAME(image, sym), sizeof(new_symname));
395 // it's undefined, must be outside this image, try the other image
396 sym2 = elf_find_symbol(shared_image, new_symname);
397 if(!sym2) {
398 dprintf("elf_resolve_symbol: could not resolve symbol '%s'\n", new_symname);
399 return ERR_ELF_RESOLVING_SYMBOL;
402 // make sure they're the same type
403 if(ELF32_ST_TYPE(sym->st_info) != ELF32_ST_TYPE(sym2->st_info)) {
404 dprintf("elf_resolve_symbol: found symbol '%s' in shared image but wrong type\n", new_symname);
405 return ERR_ELF_RESOLVING_SYMBOL;
408 if(ELF32_ST_BIND(sym2->st_info) != STB_GLOBAL && ELF32_ST_BIND(sym2->st_info) != STB_WEAK) {
409 dprintf("elf_resolve_symbol: found symbol '%s' but not exported\n", new_symname);
410 return ERR_ELF_RESOLVING_SYMBOL;
413 *sym_addr = sym2->st_value + shared_image->regions[0].delta;
414 return NO_ERROR;
415 case SHN_ABS:
416 *sym_addr = sym->st_value;
417 return NO_ERROR;
418 case SHN_COMMON:
419 // XXX finish this
420 dprintf("elf_resolve_symbol: COMMON symbol, finish me!\n");
421 return ERR_NOT_IMPLEMENTED_YET;
422 default:
423 // standard symbol
424 *sym_addr = sym->st_value + image->regions[0].delta;
425 return NO_ERROR;
429 static int elf_relocate_rel(struct elf_image_info *image, const char *sym_prepend,
430 struct Elf32_Rel *rel, int rel_len )
432 int i;
433 struct Elf32_Sym *sym;
434 int vlErr;
435 addr S;
436 addr A;
437 addr P;
438 addr final_val;
440 S = A = P = 0;
442 for(i = 0; i * (int)sizeof(struct Elf32_Rel) < rel_len; i++) {
443 //dprintf("looking at rel type %d, offset 0x%x\n", ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset);
445 // calc S
446 switch(ELF32_R_TYPE(rel[i].r_info)) {
447 case R_386_32:
448 case R_386_PC32:
449 case R_386_GLOB_DAT:
450 case R_386_JMP_SLOT:
451 case R_386_GOTOFF:
452 sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
454 vlErr = elf_resolve_symbol(image, sym, kernel_image, sym_prepend,&S);
455 if(vlErr<0) return vlErr;
456 //dprintf("S 0x%x\n", S);
458 // calc A
459 switch(ELF32_R_TYPE(rel[i].r_info)) {
460 case R_386_32:
461 case R_386_PC32:
462 case R_386_GOT32:
463 case R_386_PLT32:
464 case R_386_RELATIVE:
465 case R_386_GOTOFF:
466 case R_386_GOTPC:
467 A = *(addr *)(image->regions[0].delta + rel[i].r_offset);
468 // dprintf("A 0x%x\n", A);
469 break;
471 // calc P
472 switch(ELF32_R_TYPE(rel[i].r_info)) {
473 case R_386_PC32:
474 case R_386_GOT32:
475 case R_386_PLT32:
476 case R_386_GOTPC:
477 P = image->regions[0].delta + rel[i].r_offset;
478 // dprintf("P 0x%x\n", P);
479 break;
482 switch(ELF32_R_TYPE(rel[i].r_info)) {
483 case R_386_NONE:
484 continue;
485 case R_386_32:
486 final_val = S + A;
487 break;
488 case R_386_PC32:
489 final_val = S + A - P;
490 break;
491 case R_386_RELATIVE:
492 // B + A;
493 final_val = image->regions[0].delta + A;
494 break;
495 case R_386_JMP_SLOT:
496 final_val = S;
497 dprintf( "final=%lx\n", final_val );
498 break;
499 default:
500 dprintf("unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
501 return ERR_NOT_ALLOWED;
503 *(addr *)(image->regions[0].delta + rel[i].r_offset) = final_val;
506 return NO_ERROR;
509 // XXX for now just link against the kernel
510 static int elf_relocate(struct elf_image_info *image, const char *sym_prepend)
512 int res = NO_ERROR;
513 int i;
514 // dprintf("top of elf_relocate\n");
516 // deal with the rels first
517 if( image->rel ) {
518 //dprintf( "total %i relocs\n", image->rel_len / (int)sizeof(struct Elf32_Rel) );
519 res = elf_relocate_rel( image, sym_prepend, image->rel, image->rel_len );
521 if( res )
522 return res;
525 if( image->pltrel ) {
526 //dprintf( "total %i plt-relocs\n", image->pltrel_len / (int)sizeof(struct Elf32_Rel) );
527 res = elf_relocate_rel( image, sym_prepend, image->pltrel, image->pltrel_len );
529 if( res )
530 return res;
533 if(image->rela) {
534 dprintf("RELA relocations not supported\n");
535 return ERR_NOT_ALLOWED;
536 for(i = 1; i * (int)sizeof(struct Elf32_Rela) < image->rela_len; i++) {
537 dprintf("rela: type %d\n", ELF32_R_TYPE(image->rela[i].r_info));
540 return res;
543 static int verify_eheader(struct Elf32_Ehdr *eheader)
545 if(memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0)
546 return ERR_INVALID_BINARY;
548 if(eheader->e_ident[4] != ELFCLASS32)
549 return ERR_INVALID_BINARY;
551 if(eheader->e_phoff == 0)
552 return ERR_INVALID_BINARY;
554 if(eheader->e_phentsize < sizeof(struct Elf32_Phdr))
555 return ERR_INVALID_BINARY;
557 return 0;
560 int elf_load_uspace(const char *path, struct proc *p, int flags, addr *entry)
562 struct Elf32_Ehdr eheader;
563 struct Elf32_Phdr *pheaders = NULL;
564 int fd;
565 int err;
566 int i;
567 ssize_t len;
569 dprintf("elf_load: entry path '%s', proc %p\n", path, p);
571 fd = sys_open(path, STREAM_TYPE_FILE, 0);
572 if(fd < 0)
573 return fd;
575 len = sys_read(fd, &eheader, 0, sizeof(eheader));
576 if(len < 0) {
577 err = len;
578 goto error;
580 if(len != sizeof(eheader)) {
581 // short read
582 err = ERR_INVALID_BINARY;
583 goto error;
585 err = verify_eheader(&eheader);
586 if(err < 0)
587 goto error;
589 pheaders = kmalloc(eheader.e_phnum * eheader.e_phentsize);
590 if(pheaders == NULL) {
591 dprintf("error allocating space for program headers\n");
592 err = ERR_NO_MEMORY;
593 goto error;
596 dprintf("reading in program headers at 0x%x, len 0x%x\n", eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize);
597 len = sys_read(fd, pheaders, eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize);
598 if(len < 0) {
599 err = len;
600 dprintf("error reading in program headers\n");
601 goto error;
603 if(len != eheader.e_phnum * eheader.e_phentsize) {
604 dprintf("short read while reading in program headers\n");
605 err = -1;
606 goto error;
609 for(i=0; i < eheader.e_phnum; i++) {
610 char region_name[64];
611 region_id id;
612 char *region_addr;
614 sprintf(region_name, "%s_seg%d", path, i);
616 region_addr = (char *)ROUNDOWN(pheaders[i].p_vaddr, PAGE_SIZE);
617 if(pheaders[i].p_flags & PF_W) {
619 * rw segment
621 unsigned start_clearing;
622 unsigned to_clear;
623 unsigned A= pheaders[i].p_vaddr+pheaders[i].p_memsz;
624 unsigned B= pheaders[i].p_vaddr+pheaders[i].p_filesz;
626 A= ROUNDOWN(A, PAGE_SIZE);
627 B= ROUNDOWN(B, PAGE_SIZE);
629 id= vm_map_file(
630 p->aspace_id,
631 region_name,
632 (void **)&region_addr,
633 REGION_ADDR_EXACT_ADDRESS,
634 ROUNDUP(pheaders[i].p_filesz+ (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE),
635 LOCK_RW,
636 REGION_PRIVATE_MAP,
637 path,
638 ROUNDOWN(pheaders[i].p_offset, PAGE_SIZE)
640 if(id < 0) {
641 dprintf("error allocating region!\n");
642 err = ERR_INVALID_BINARY;
643 goto error;
648 * clean garbage brought by mmap
650 start_clearing=
651 (unsigned)region_addr
652 + (pheaders[i].p_vaddr % PAGE_SIZE)
653 + pheaders[i].p_filesz;
654 to_clear=
655 ROUNDUP(pheaders[i].p_filesz+ (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE)
656 - (pheaders[i].p_vaddr % PAGE_SIZE)
657 - (pheaders[i].p_filesz);
658 memset((void*)start_clearing, 0, to_clear);
661 * check if we need extra storage for the bss
663 if(A != B) {
664 size_t bss_size;
666 bss_size=
667 ROUNDUP(pheaders[i].p_memsz+ (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE)
668 - ROUNDUP(pheaders[i].p_filesz+ (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE);
670 sprintf(region_name, "%s_bss%d", path, 'X');
672 region_addr+= ROUNDUP(pheaders[i].p_filesz+ (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE),
673 id= vm_create_anonymous_region(
674 p->aspace_id,
675 region_name,
676 (void **)&region_addr,
677 REGION_ADDR_EXACT_ADDRESS,
678 bss_size,
679 REGION_WIRING_LAZY,
680 LOCK_RW
682 if(id < 0) {
683 dprintf("error allocating region!\n");
684 err = ERR_INVALID_BINARY;
685 goto error;
688 } else {
690 * assume rx segment
692 id= vm_map_file(
693 p->aspace_id,
694 region_name,
695 (void **)&region_addr,
696 REGION_ADDR_EXACT_ADDRESS,
697 ROUNDUP(pheaders[i].p_memsz + (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE),
698 LOCK_RO,
699 REGION_PRIVATE_MAP,
700 path,
701 ROUNDOWN(pheaders[i].p_offset, PAGE_SIZE)
703 if(id < 0) {
704 dprintf("error mapping text!\n");
705 err = ERR_INVALID_BINARY;
706 goto error;
711 dprintf("elf_load: done!\n");
713 *entry = eheader.e_entry;
715 err = 0;
717 error:
718 if(pheaders)
719 kfree(pheaders);
720 sys_close(fd);
722 return err;
725 image_id elf_load_kspace(const char *path, const char *sym_prepend)
727 struct Elf32_Ehdr *eheader;
728 struct Elf32_Phdr *pheaders;
729 struct elf_image_info *image;
730 void *vnode = NULL;
731 int fd;
732 int err;
733 int i;
734 ssize_t len;
736 dprintf("elf_load_kspace: entry path '%s'\n", path);
738 fd = sys_open(path, STREAM_TYPE_FILE, 0);
739 if(fd < 0)
740 return fd;
742 err = vfs_get_vnode_from_fd(fd, true, &vnode);
743 if(err < 0)
744 goto error0;
746 // XXX awful hack to keep someone else from trying to load this image
747 // probably not a bad thing, shouldn't be too many races
748 mutex_lock(&image_load_lock);
750 // make sure it's not loaded already. Search by vnode
751 image = find_image_by_vnode(vnode);
752 if( image ) {
753 atomic_add( &image->ref_count, 1 );
754 //err = ERR_NOT_ALLOWED;
755 goto done;
758 eheader = (struct Elf32_Ehdr *)kmalloc( sizeof( *eheader ));
759 if( !eheader ) {
760 err = ERR_NO_MEMORY;
761 goto error;
764 len = sys_read(fd, eheader, 0, sizeof(*eheader));
765 if(len < 0) {
766 err = len;
767 goto error1;
769 if(len != sizeof(*eheader)) {
770 // short read
771 err = ERR_INVALID_BINARY;
772 goto error1;
774 err = verify_eheader(eheader);
775 if(err < 0)
776 goto error1;
778 image = create_image_struct();
779 if(!image) {
780 err = ERR_NO_MEMORY;
781 goto error1;
783 image->vnode = vnode;
784 image->eheader = eheader;
786 pheaders = kmalloc(eheader->e_phnum * eheader->e_phentsize);
787 if(pheaders == NULL) {
788 dprintf("error allocating space for program headers\n");
789 err = ERR_NO_MEMORY;
790 goto error2;
793 // dprintf("reading in program headers at 0x%x, len 0x%x\n", eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize);
794 len = sys_read(fd, pheaders, eheader->e_phoff, eheader->e_phnum * eheader->e_phentsize);
795 if(len < 0) {
796 err = len;
797 dprintf("error reading in program headers\n");
798 goto error3;
800 if(len != eheader->e_phnum * eheader->e_phentsize) {
801 dprintf("short read while reading in program headers\n");
802 err = -1;
803 goto error3;
806 for(i=0; i < eheader->e_phnum; i++) {
807 char region_name[64];
808 bool ro_segment_handled = false;
809 bool rw_segment_handled = false;
810 int image_region;
811 int lock;
813 // dprintf("looking at program header %d\n", i);
815 switch(pheaders[i].p_type) {
816 case PT_LOAD:
817 break;
818 case PT_DYNAMIC:
819 image->dynamic_ptr = pheaders[i].p_vaddr;
820 continue;
821 default:
822 dprintf("unhandled pheader type 0x%x\n", pheaders[i].p_type);
823 continue;
826 // we're here, so it must be a PT_LOAD segment
827 if((pheaders[i].p_flags & (PF_R | PF_W | PF_X)) == (PF_R | PF_W)) {
828 // this is the writable segment
829 if(rw_segment_handled) {
830 // we've already created this segment
831 continue;
833 rw_segment_handled = true;
834 image_region = 1;
835 lock = LOCK_RW|LOCK_KERNEL;
836 sprintf(region_name, "%s_rw", path);
837 } else if((pheaders[i].p_flags & (PF_R | PF_W | PF_X)) == (PF_R | PF_X)) {
838 // this is the non-writable segment
839 if(ro_segment_handled) {
840 // we've already created this segment
841 continue;
843 ro_segment_handled = true;
844 image_region = 0;
845 // lock = LOCK_RO|LOCK_KERNEL;
846 lock = LOCK_RW|LOCK_KERNEL;
847 sprintf(region_name, "%s_ro", path);
848 } else {
849 dprintf("weird program header flags 0x%x\n", pheaders[i].p_flags);
850 continue;
852 image->regions[image_region].size = ROUNDUP(pheaders[i].p_memsz + (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE);
853 image->regions[image_region].id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), region_name,
854 (void **)&image->regions[image_region].start, REGION_ADDR_ANY_ADDRESS,
855 image->regions[image_region].size, REGION_WIRING_WIRED, lock);
856 if(image->regions[image_region].id < 0) {
857 dprintf("error allocating region!\n");
858 err = ERR_INVALID_BINARY;
859 goto error3;
861 image->regions[image_region].delta = image->regions[image_region].start - ROUNDOWN(pheaders[i].p_vaddr, PAGE_SIZE);
863 // dprintf("elf_load_kspace: created a region at 0x%x\n", image->regions[image_region].start);
865 len = sys_read(fd, (void *)(image->regions[image_region].start + (pheaders[i].p_vaddr % PAGE_SIZE)),
866 pheaders[i].p_offset, pheaders[i].p_filesz);
867 if(len < 0) {
868 err = len;
869 dprintf("error reading in seg %d\n", i);
870 goto error4;
874 if(image->regions[1].start != 0) {
875 if(image->regions[0].delta != image->regions[1].delta) {
876 dprintf("could not load binary, fix the region problem!\n");
877 dump_image_info(image);
878 err = ERR_NO_MEMORY;
879 goto error4;
883 // modify the dynamic ptr by the delta of the regions
884 image->dynamic_ptr += image->regions[0].delta;
886 err = elf_parse_dynamic_section(image);
887 if(err < 0)
888 goto error4;
890 err = elf_relocate(image, sym_prepend);
891 if(err < 0)
892 goto error4;
894 err = 0;
896 kfree(pheaders);
897 sys_close(fd);
899 insert_image_in_list(image);
901 done:
902 mutex_unlock(&image_load_lock);
904 dprintf("elf_load_kspace: done!\n");
906 return image->id;
908 error4:
909 if(image->regions[1].id >= 0)
910 vm_delete_region(vm_get_kernel_aspace_id(), image->regions[1].id);
911 if(image->regions[0].id >= 0)
912 vm_delete_region(vm_get_kernel_aspace_id(), image->regions[0].id);
913 error3:
914 kfree(image);
915 error2:
916 kfree(pheaders);
917 error1:
918 kfree(eheader);
919 error:
920 mutex_unlock(&image_load_lock);
921 error0:
922 if(vnode)
923 vfs_put_vnode_ptr(vnode);
924 sys_close(fd);
926 return err;
929 static int elf_unload_image( struct elf_image_info *image );
931 static int elf_unlink_relocs( struct elf_image_info *image )
933 elf_linked_image *link, *next_link;
935 for( link = image->linked_images; link; link = next_link ) {
936 next_link = link->next;
937 elf_unload_image( link->image );
938 kfree( link );
941 return NO_ERROR;
944 static void elf_unload_image_final( struct elf_image_info *image )
946 int i;
948 for( i = 0; i < 2; ++i ) {
949 vm_delete_region( vm_get_kernel_aspace_id(), image->regions[i].id );
952 if( image->vnode )
953 vfs_put_vnode_ptr( image->vnode );
955 remove_image_from_list(image);
956 kfree( image->eheader );
957 kfree( image );
960 static int elf_unload_image( struct elf_image_info *image )
962 if( atomic_add( &image->ref_count, -1 ) > 0 )
963 return NO_ERROR;
965 elf_unlink_relocs( image );
966 elf_unload_image_final( image );
968 return NO_ERROR;
971 int elf_unload_kspace( const char *path )
973 int fd;
974 int err;
975 void *vnode;
976 struct elf_image_info *image;
978 fd = sys_open(path, STREAM_TYPE_FILE, 0);
979 if(fd < 0)
980 return fd;
982 err = vfs_get_vnode_from_fd(fd, true, &vnode);
983 if(err < 0)
984 goto error0;
986 mutex_lock(&image_load_lock);
988 image = find_image_by_vnode(vnode);
989 if( !image ) {
990 dprintf( "Tried to unload image that wasn't loaded (%s)\n", path );
991 err = ERR_NOT_FOUND;
992 goto error;
995 err = elf_unload_image( image );
997 error:
998 mutex_unlock(&image_load_lock);
999 error0:
1000 if(vnode)
1001 vfs_put_vnode_ptr(vnode);
1002 sys_close(fd);
1004 return err;
1007 int elf_init(kernel_args *ka)
1009 vm_region_info rinfo;
1010 int err;
1012 mutex_init(&image_lock, "kimages_lock");
1013 mutex_init(&image_load_lock, "kimages_load_lock");
1015 // build a image structure for the kernel, which has already been loaded
1016 kernel_image = create_image_struct();
1018 // text segment
1019 kernel_image->regions[0].id = vm_find_region_by_name(vm_get_kernel_aspace_id(), "kernel_ro");
1020 if(kernel_image->regions[0].id < 0)
1021 panic("elf_init: could not look up kernel text segment region\n");
1022 vm_get_region_info(kernel_image->regions[0].id, &rinfo);
1023 kernel_image->regions[0].start = rinfo.base;
1024 kernel_image->regions[0].size = rinfo.size;
1026 // data segment
1027 kernel_image->regions[1].id = vm_find_region_by_name(vm_get_kernel_aspace_id(), "kernel_rw");
1028 if(kernel_image->regions[1].id < 0)
1029 panic("elf_init: could not look up kernel data segment region\n");
1030 vm_get_region_info(kernel_image->regions[1].id, &rinfo);
1031 kernel_image->regions[1].start = rinfo.base;
1032 kernel_image->regions[1].size = rinfo.size;
1034 // we know where the dynamic section is
1035 kernel_image->dynamic_ptr = (addr)ka->kernel_dynamic_section_addr.start;
1037 // parse the dynamic section
1038 if(elf_parse_dynamic_section(kernel_image) < 0)
1039 dprintf("elf_init: WARNING elf_parse_dynamic_section couldn't find dynamic section.\n");
1041 // insert it first in the list of kernel images loaded
1042 kernel_images = NULL;
1043 insert_image_in_list(kernel_image);
1045 return 0;