1 |
/* ELF object format functions. |
/* ELF object format functions. |
2 |
Copyright 1999, 2000, 2001 Johan Rydberg, jrydberg@opencores.org. |
Copyright 1999, 2000, 2001, 2002 Johan Rydberg, jrydberg@opencores.org. |
3 |
|
|
4 |
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
5 |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
16 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
17 |
|
|
18 |
#include <rtmk/rtmk.h> |
#include <rtmk/rtmk.h> |
19 |
#include <rtmk/thread-status.h> |
#include <rtmk/thread-state.h> |
20 |
|
|
21 |
#include <errno.h> |
#include <errno.h> |
22 |
#include <stdlib.h> |
#include <stdlib.h> |
28 |
#include "objfmt.h" |
#include "objfmt.h" |
29 |
#include "objfmt-elf.h" |
#include "objfmt-elf.h" |
30 |
#include "io-uio.h" |
#include "io-uio.h" |
31 |
|
#include "pager.h" |
32 |
|
#include "nova-intern.h" |
33 |
|
|
34 |
|
#ifdef __i386__ |
35 |
|
# define THREAD_STATE_STRUCTURE thread_state_i386_cpu |
36 |
|
# define PC eip |
37 |
|
# define SP uesp |
38 |
|
#endif |
39 |
|
|
40 |
/* ??? */ |
/* ??? */ |
41 |
|
|
43 |
machine_init_thread (rtmk_port_t thread_name, vm_offset_t pc, |
machine_init_thread (rtmk_port_t thread_name, vm_offset_t pc, |
44 |
vm_offset_t sp) |
vm_offset_t sp) |
45 |
{ |
{ |
46 |
thread_state_i386_t ts; |
struct thread_state_i386_cpu ts; |
47 |
kern_return_t kr; |
kern_return_t kr; |
48 |
int count; |
int count; |
49 |
|
|
50 |
count = sizeof ts; |
count = sizeof ts; |
51 |
kr = thread_get_status (thread_name, THREAD_STATUS_FLAVOR_CPU_STATE, |
kr = thread_state_get (thread_name, THREAD_STATE_FLAVOR_I386_CPU, |
52 |
(thread_status_t *) &ts, &count); |
(char *) &ts, &count); |
53 |
if (kr) |
if (kr) |
54 |
return kr; |
return kr; |
55 |
|
|
57 |
ts.eip = (unsigned int) pc; |
ts.eip = (unsigned int) pc; |
58 |
|
|
59 |
count = sizeof ts; |
count = sizeof ts; |
60 |
kr = thread_set_status (thread_name, THREAD_STATUS_FLAVOR_CPU_STATE, |
kr = thread_state_set (thread_name, THREAD_STATE_FLAVOR_I386_CPU, |
61 |
(thread_status_t *) &ts, count); |
(char *) &ts, count); |
62 |
return kr; |
return kr; |
63 |
} |
} |
64 |
|
|
143 |
return 0; |
return 0; |
144 |
} |
} |
145 |
|
|
146 |
|
/* Load or allocate a section. */ |
147 |
|
static int |
148 |
|
load_section (void *section, rtmk_port_t filemap, |
149 |
|
rtmk_port_t task) |
150 |
|
{ |
151 |
|
Elf32_Phdr *ph = section; |
152 |
|
vm_address_t addr = 0; |
153 |
|
vm_offset_t filepos = 0; |
154 |
|
vm_size_t filesz = 0, memsz = 0; |
155 |
|
vm_prot_t vm_prot; |
156 |
|
int anywhere, err; |
157 |
|
|
158 |
|
vm_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXEC; |
159 |
|
|
160 |
|
addr = ph->p_vaddr & ~(ph->p_align - 1); |
161 |
|
memsz = ph->p_vaddr + ph->p_memsz - addr; |
162 |
|
filepos = ph->p_offset & ~(ph->p_align - 1); |
163 |
|
filesz = ph->p_offset + ph->p_filesz - filepos; |
164 |
|
|
165 |
|
if ((ph->p_flags & PF_R) == 0) |
166 |
|
vm_prot &= ~VM_PROT_READ; |
167 |
|
if ((ph->p_flags & PF_W) == 0) |
168 |
|
vm_prot &= ~VM_PROT_WRITE; |
169 |
|
if ((ph->p_flags & PF_X) == 0) |
170 |
|
vm_prot &= ~VM_PROT_EXEC; |
171 |
|
anywhere = 0; |
172 |
|
|
173 |
|
if (memsz == 0) |
174 |
|
/* This section is empty; ignore it. */ |
175 |
|
return 0; |
176 |
|
|
177 |
|
if (filesz != 0) |
178 |
|
{ |
179 |
|
vm_address_t mapstart = vm_round_page (addr); |
180 |
|
|
181 |
|
if (mapstart - addr < filesz) |
182 |
|
{ |
183 |
|
/* MAPSTART is the first page that starts inside the section. |
184 |
|
Map all the pages that start inside the section. */ |
185 |
|
|
186 |
|
/* Map the data into the task directly from the file. */ |
187 |
|
err = vm_map (task, &mapstart, filesz - (mapstart - addr), |
188 |
|
anywhere, filemap, filepos + (mapstart - addr), |
189 |
|
0, vm_prot, |
190 |
|
VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXEC, |
191 |
|
VM_INHERIT_COPY); |
192 |
|
if (err) |
193 |
|
return err; |
194 |
|
} |
195 |
|
|
196 |
|
if (mapstart > addr) |
197 |
|
{ |
198 |
|
assert (0); |
199 |
|
} |
200 |
|
} |
201 |
|
|
202 |
|
if (memsz != 0) |
203 |
|
{ |
204 |
|
/* SEC_ALLOC: Allocate zero-filled memory for the section. */ |
205 |
|
vm_address_t mapstart = vm_round_page (addr + filesz); |
206 |
|
|
207 |
|
if (mapstart - addr < memsz) |
208 |
|
{ |
209 |
|
/* MAPSTART is the first page that starts inside the section. |
210 |
|
Allocate all the pages that start inside the section. */ |
211 |
|
err = vm_map (task, &mapstart, memsz - (mapstart - addr), |
212 |
|
anywhere, RTMK_PORT_NULL, 0, 0, |
213 |
|
vm_prot, VM_PROT_ALL, VM_INHERIT_COPY); |
214 |
|
if (err) |
215 |
|
return err; |
216 |
|
} |
217 |
|
|
218 |
|
if (mapstart > addr) |
219 |
|
{ |
220 |
|
} |
221 |
|
} |
222 |
|
return 0; |
223 |
|
} |
224 |
|
|
225 |
|
|
226 |
static int |
static int |
227 |
elf_load (struct proc *p, struct vnode *vp, void *buf, |
elf_load (struct proc *p, struct vnode *vp, void *buf, |
228 |
int nargv, char **argv, int nenvp, char **envp) |
int nargv, char **argv, int nenvp, char **envp) |
229 |
{ |
{ |
230 |
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) buf; |
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) buf; |
231 |
Elf32_Phdr *phdr, *ph; |
Elf32_Phdr *phdr, *ph; |
232 |
|
vm_offset_t stack_top; |
233 |
|
struct pager *pager; |
234 |
size_t phsize; |
size_t phsize; |
235 |
int err, i; |
int err, i; |
|
vm_offset_t stack_top; |
|
236 |
|
|
237 |
struct io_iovec iovec; |
struct io_iovec iovec; |
238 |
struct io_uio uio; |
struct io_uio uio; |
247 |
phsize, &iovec, 1, p); |
phsize, &iovec, 1, p); |
248 |
err = VOP_READ (vp, &uio, 0); |
err = VOP_READ (vp, &uio, 0); |
249 |
if (err) |
if (err) |
250 |
return err; |
{ |
251 |
|
trace_printf ("no read"); |
252 |
|
return err; |
253 |
|
} |
254 |
|
|
255 |
/* Load program sections. */ |
/* Load program sections. */ |
|
|
|
256 |
for (i = 0; i < elf_hdr->e_phnum; i++) |
for (i = 0; i < elf_hdr->e_phnum; i++) |
257 |
{ |
{ |
258 |
ph = (Elf32_Phdr *) ((vm_offset_t) phdr + i * elf_hdr->e_phentsize); |
ph = (Elf32_Phdr *) ((vm_offset_t) phdr + i * elf_hdr->e_phentsize); |
259 |
if (ph->p_type == PT_LOAD) |
if (ph->p_type != PT_LOAD) |
260 |
{ |
continue; |
|
vm_prot_t protection = 0; |
|
|
vm_offset_t alloc_offset; |
|
|
vm_size_t vsize; |
|
|
|
|
|
if (ph->p_flags & PF_R) |
|
|
protection |= VM_PROT_READ; |
|
|
if (ph->p_flags & PF_W) |
|
|
protection |= VM_PROT_WRITE; |
|
|
if (ph->p_flags & PF_X) |
|
|
protection |= VM_PROT_EXEC; |
|
|
|
|
|
io_iov_init (&iovec, (void *) ph->p_vaddr, ph->p_filesz); |
|
|
io_uio_init (&uio, IO_UIO_WRITE, IO_UIO_USERSPACE, |
|
|
ph->p_offset, ph->p_filesz, &iovec, 1, p); |
|
261 |
|
|
262 |
vsize = vm_round_page (ph->p_memsz + (ph->p_vaddr & VM_PAGE_MASK)); |
pager = pager_create (vp, VM_PROT_ALL, 0); |
263 |
alloc_offset = vm_trunc_page (ph->p_vaddr); |
if (! pager) |
264 |
|
return ENOMEM; |
265 |
|
port_insert_right (task_self (), pager_get_right (pager), |
266 |
|
pager_get_right (pager), RTMK_MSG_TYPE_MAKE_SEND); |
267 |
|
|
268 |
err = vm_allocate (p->p_task, vsize, &alloc_offset, 0); |
load_section (ph, pager_get_right (pager), p->p_task); |
|
if (err) |
|
|
return err; |
|
|
|
|
|
err = VOP_READ (vp, &uio, 0); |
|
|
if (err) |
|
|
return err; |
|
|
} |
|
269 |
} |
} |
270 |
|
|
271 |
/* Allocate stack for the thread. */ |
/* Allocate stack for the thread. */ |
272 |
p->p_stksize = 16 * VM_PAGE_SIZE; |
p->p_stksize = 16 * VM_PAGE_SIZE; |
273 |
p->p_stkbase = (VM_USER_MAX_ADDRESS - VM_USER_MIN_ADDRESS) - p->p_stksize; |
p->p_stkbase = (VM_USER_MAX_ADDRESS - VM_USER_MIN_ADDRESS) - p->p_stksize; |
274 |
|
|
275 |
err = vm_allocate (p->p_task, p->p_stksize, &p->p_stkbase, 0); |
err = vm_allocate (p->p_task, &p->p_stkbase, p->p_stksize, 0); |
276 |
if (err) |
if (err) |
277 |
return err; |
return err; |
278 |
|
|