2 ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
5 #include <kernel/kernel.h>
6 #include <sys/errors.h>
7 #include <kernel/elf.h>
8 #include <kernel/vfs.h>
10 #include <kernel/thread.h>
11 #include <kernel/debug.h>
12 #include <kernel/heap.h>
13 #include <kernel/arch/cpu.h>
15 #include <sys/elf32.h>
17 #include <libc/string.h>
18 #include <libc/printf.h>
26 struct elf_image_info
{
27 struct elf_image_info
*next
;
28 struct elf_region regions
[2]; // describes the text and data regions
29 addr dynamic_ptr
; // pointer to the dynamic section
31 // pointer to symbol participation data structures
32 unsigned int *symhash
;
33 struct Elf32_Sym
*syms
;
37 static struct elf_image_info
*kernel_images
= NULL
;
38 static struct elf_image_info
*kernel_image
= NULL
;
40 #define SYMNAME(image, sym) ((char *)(&(image)->strtab[(sym)->st_name]))
41 #define HASHTABSIZE(image) ((image)->symhash[0])
42 #define HASHBUCKETS(image) ((unsigned int *)&(image)->symhash[2])
43 #define HASHCHAINS(image) ((unsigned int *)&(image)->symhash[2+HASHTABSIZE(image)])
45 static unsigned long elf_hash(const unsigned char *name
)
47 unsigned long hash
= 0;
51 hash
= (hash
<< 4) + *name
++;
52 if((temp
= hash
& 0xf0000000))
59 static int verify_eheader(struct Elf32_Ehdr
*eheader
)
61 if(memcmp(eheader
->e_ident
, ELF_MAGIC
, 4) != 0)
62 return ERR_INVALID_BINARY
;
64 if(eheader
->e_ident
[4] != ELFCLASS32
)
65 return ERR_INVALID_BINARY
;
67 if(eheader
->e_phoff
== 0)
68 return ERR_INVALID_BINARY
;
70 if(eheader
->e_phentsize
< sizeof(struct Elf32_Phdr
))
71 return ERR_INVALID_BINARY
;
76 int elf_load_uspace(const char *path
, struct proc
*p
, int flags
, addr
*entry
)
78 struct Elf32_Ehdr eheader
;
79 struct Elf32_Phdr
*pheaders
;
85 dprintf("elf_load: entry path '%s', proc 0x%x\n", path
, p
);
87 fd
= sys_open(path
, STREAM_TYPE_FILE
, 0);
91 len
= sys_read(fd
, &eheader
, 0, sizeof(eheader
));
96 if(len
!= sizeof(eheader
)) {
98 err
= ERR_INVALID_BINARY
;
101 err
= verify_eheader(&eheader
);
105 pheaders
= kmalloc(eheader
.e_phnum
* eheader
.e_phentsize
);
106 if(pheaders
== NULL
) {
107 dprintf("error allocating space for program headers\n");
112 dprintf("reading in program headers at 0x%x, len 0x%x\n", eheader
.e_phoff
, eheader
.e_phnum
* eheader
.e_phentsize
);
113 len
= sys_read(fd
, pheaders
, eheader
.e_phoff
, eheader
.e_phnum
* eheader
.e_phentsize
);
116 dprintf("error reading in program headers\n");
119 if(len
!= eheader
.e_phnum
* eheader
.e_phentsize
) {
120 dprintf("short read while reading in program headers\n");
125 for(i
=0; i
< eheader
.e_phnum
; i
++) {
126 char region_name
[64];
130 sprintf(region_name
, "%s_seg%d", path
, i
);
132 region_addr
= (char *)ROUNDOWN(pheaders
[i
].p_vaddr
, PAGE_SIZE
);
133 id
= vm_create_anonymous_region(p
->aspace_id
, region_name
, (void **)®ion_addr
, REGION_ADDR_EXACT_ADDRESS
,
134 ROUNDUP(pheaders
[i
].p_memsz
+ (pheaders
[i
].p_vaddr
% PAGE_SIZE
), PAGE_SIZE
), REGION_WIRING_LAZY
, LOCK_RW
);
136 dprintf("error allocating region!\n");
137 err
= ERR_INVALID_BINARY
;
141 len
= sys_read(fd
, region_addr
+ (pheaders
[i
].p_vaddr
% PAGE_SIZE
), pheaders
[i
].p_offset
, pheaders
[i
].p_filesz
);
144 dprintf("error reading in seg %d\n", i
);
149 *entry
= pheaders
[i
].p_vaddr
;
152 dprintf("elf_load: done!\n");
162 static int elf_parse_dynamic_section(struct elf_image_info
*image
)
171 d
= (struct Elf32_Dyn
*)image
->dynamic_ptr
;
175 for(i
=0; d
[i
].d_tag
!= DT_NULL
; i
++) {
178 image
->symhash
= (unsigned int *)d
[i
].d_un
.d_ptr
;
181 image
->strtab
= (char *)d
[i
].d_un
.d_ptr
;
184 image
->syms
= (struct Elf32_Sym
*)d
[i
].d_un
.d_ptr
;
191 // lets make sure we found all the required sections
192 if(!image
->symhash
|| !image
->syms
|| !image
->strtab
)
198 static struct Elf32_Sym
*elf_find_symbol(struct elf_image_info
*image
, const char *name
)
203 hash
= elf_hash(name
) % HASHTABSIZE(image
);
204 for(i
= HASHBUCKETS(image
)[hash
]; i
!= STN_UNDEF
; i
= HASHCHAINS(image
)[i
]) {
205 if(!strcmp(SYMNAME(image
, &image
->syms
[i
]), name
)) {
206 return &image
->syms
[i
];
213 int elf_init(kernel_args
*ka
)
215 vm_region_info rinfo
;
218 // build a image structure for the kernel, which has already been loaded
219 kernel_image
= kmalloc(sizeof(struct elf_image_info
));
220 memset(kernel_image
, 0, sizeof(struct elf_image_info
));
223 kernel_image
->regions
[0].id
= vm_find_region_by_name(vm_get_kernel_aspace_id(), "kernel_ro");
224 if(kernel_image
->regions
[0].id
< 0)
225 panic("elf_init: could not look up kernel text segment region\n");
226 vm_get_region_info(kernel_image
->regions
[0].id
, &rinfo
);
227 kernel_image
->regions
[0].start
= rinfo
.base
;
228 kernel_image
->regions
[0].size
= rinfo
.size
;
231 kernel_image
->regions
[1].id
= vm_find_region_by_name(vm_get_kernel_aspace_id(), "kernel_rw");
232 if(kernel_image
->regions
[1].id
< 0)
233 panic("elf_init: could not look up kernel data segment region\n");
234 vm_get_region_info(kernel_image
->regions
[1].id
, &rinfo
);
235 kernel_image
->regions
[1].start
= rinfo
.base
;
236 kernel_image
->regions
[1].size
= rinfo
.size
;
238 // we know where the dynamic section is
239 kernel_image
->dynamic_ptr
= (addr
)ka
->kernel_dynamic_section_addr
.start
;
241 // parse the dynamic section
242 if(elf_parse_dynamic_section(kernel_image
) < 0)
243 panic("elf_init: elf_parse_dynamic_section doesn't like the kernel image\n");
245 // insert it first in the list of kernel images loaded
246 kernel_image
->next
= NULL
;
247 kernel_images
= kernel_image
;