osloader.c revision 1.1 1 /*********************************************************************
2 * NetBSD(SH3) boot loader
3 *
4 * 1998.11.10
5 * By T.Horiuchi (Brains, Corp.)
6 *********************************************************************/
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/param.h>
11 #include <sys/gmon.h>
12 #include <sys/stat.h>
13 #include <sys/sysctl.h>
14 #include <sys/socket.h>
15 #include <sys/file.h>
16 #include <vm/vm_param.h>
17 #include <machine/cpu.h>
18 #include "osloader.h"
19
20 #define vm_page_size (1<<12)
21
22 char *netbsd = "/netbsd";
23 struct coff_filehdr FileHdr;
24 struct coff_aouthdr AoutHdr;
25
26 static int coff_find_section __P((FILE *, struct coff_filehdr *,
27 struct coff_scnhdr *, int));
28
29 void LoadAndReset __P((char *));
30
31 /*
32 * coff_find_section - load specified section header
33 *
34 * TODO - optimize by reading all section headers in at once
35 */
36
37 static int
38 coff_find_section( fd, fp, sh, s_type)
39 FILE *fd;
40 struct coff_filehdr *fp;
41 struct coff_scnhdr *sh;
42 int s_type;
43 {
44 int i, pos, siz;
45
46 pos = COFF_HDR_SIZE;
47 for (i = 0; i < fp->f_nscns; i++, pos += sizeof(struct coff_scnhdr)) {
48 siz = sizeof(struct coff_scnhdr);
49 if( fread(sh, 1, siz, fd ) != siz ){
50 perror("osloader");
51 exit( 1 );
52 }
53
54 if (sh->s_flags == s_type)
55 return 0;
56 }
57 return -1;
58 }
59
60 void
61 LoadAndReset( char *osimage )
62 {
63 int mib[2];
64 u_long val;
65 int len;
66
67 mib[0] = CTL_MACHDEP;
68 mib[1] = CPU_LOADANDRESET;
69 val = (u_long)osimage;
70 len = sizeof( val );
71
72 sysctl(mib, 2, NULL, NULL, &val, len);
73 }
74
75 int
76 main(int argc, char *argv[] )
77 {
78 FILE *fp;
79 int error;
80 long dsize;
81 struct coff_scnhdr sh;
82 u_long ep_taddr;
83 u_long ep_tsize;
84 u_long toffset;
85 u_long ep_daddr;
86 u_long ep_dsize;
87 u_long doffset;
88 char *osimage;
89 char *p;
90 int i;
91 u_long cksum;
92 u_long size;
93
94 #if 0
95 printf("osloader: start\n");
96 #endif
97
98 fp = fopen( netbsd, "r" );
99 if( fp == NULL ){
100 perror("osloader");
101 exit( 1 );
102 }
103
104 if( fread( &FileHdr, 1, sizeof( FileHdr ), fp ) != sizeof(FileHdr)){
105 perror("osloader");
106 exit( 1 );
107 }
108
109 if(fread( &AoutHdr, 1, sizeof( AoutHdr ), fp ) != sizeof(AoutHdr)){
110 perror("osloader");
111 exit( 1 );
112 }
113
114 /* set up command for text segment */
115 error = coff_find_section(fp, &FileHdr, &sh, COFF_STYP_TEXT);
116 if (error) {
117 printf("can't find text section: %d\n", error);
118 exit( 1 );
119 }
120
121 ep_taddr = COFF_ALIGN(sh.s_vaddr);
122 toffset = sh.s_scnptr - (sh.s_vaddr - ep_taddr);
123 ep_tsize = sh.s_size + (sh.s_vaddr - ep_taddr);
124
125 printf("VMCMD: addr %lx size 0x%lx offset 0x%lx\n", ep_taddr,
126 ep_tsize, toffset);
127
128 /* set up command for data segment */
129 error = coff_find_section(fp, &FileHdr, &sh, COFF_STYP_DATA);
130 if (error) {
131 printf("can't find data section: %d\n", error);
132 exit( 1 );
133 }
134
135 ep_daddr = COFF_ALIGN(sh.s_vaddr);
136 doffset = sh.s_scnptr - (sh.s_vaddr - ep_daddr);
137 dsize = sh.s_size + (sh.s_vaddr - ep_daddr);
138 ep_dsize = round_page(dsize) + AoutHdr.a_bsize;
139
140 printf("VMCMD: addr 0x%lx size 0x%lx offset 0x%lx\n", ep_daddr,
141 dsize, doffset);
142
143 osimage = malloc( ep_tsize+dsize+sizeof(u_long)*2 );
144 if( osimage == NULL){
145 printf("osloader:no memory\n");
146 exit( 1 );
147 }
148
149 *(u_long *)osimage = ep_tsize+dsize;
150 p = osimage + 2*sizeof( u_long );
151
152 /* load text area */
153 fseek( fp, toffset, SEEK_SET );
154 if( fread(p, 1, ep_tsize, fp) != ep_tsize ){
155 perror("osloader:");
156 exit( 1 );
157 }
158
159 /* load data area */
160 fseek( fp, doffset, SEEK_SET );
161 if( fread(p+ep_daddr-ep_taddr, 1, dsize, fp) != dsize ){
162 perror("osloader:");
163 exit( 1 );
164 }
165
166 fclose( fp );
167
168 cksum = 0;
169 size = (ep_tsize + dsize) >> 2;
170
171 for( i = 0; i < size; i++){
172 cksum += *(u_long *)p;
173 p += sizeof(u_long );
174 }
175
176 *(u_long *)(osimage+sizeof(u_long)) = cksum ;
177
178 #if 0
179 printf("osimage = %p\n", osimage );
180 #endif
181
182 LoadAndReset( osimage );
183
184 return (0); /* NOT REACHED */
185 }
186
187
188 #ifdef NOTDEF
189
190 /*
191 * exec_coff_makecmds(): Check if it's an coff-format executable.
192 *
193 * Given a proc pointer and an exec package pointer, see if the referent
194 * of the epp is in coff format. Check 'standard' magic numbers for
195 * this architecture. If that fails, return failure.
196 *
197 * This function is responsible for creating a set of vmcmds which can be
198 * used to build the process's vm space and inserting them into the exec
199 * package.
200 */
201
202 int
203 exec_coff_makecmds(p, epp)
204 struct proc *p;
205 struct exec_package *epp;
206 {
207 int error;
208 struct coff_filehdr *fp = epp->ep_hdr;
209 struct coff_aouthdr *ap;
210
211 if (epp->ep_hdrvalid < COFF_HDR_SIZE)
212 return ENOEXEC;
213
214 if (COFF_BADMAG(fp))
215 return ENOEXEC;
216
217 ap = epp->ep_hdr + sizeof(struct coff_filehdr);
218 switch (ap->a_magic) {
219 case COFF_OMAGIC:
220 error = exec_coff_prep_omagic(p, epp, fp, ap);
221 break;
222 case COFF_NMAGIC:
223 error = exec_coff_prep_nmagic(p, epp, fp, ap);
224 break;
225 case COFF_ZMAGIC:
226 error = exec_coff_prep_zmagic(p, epp, fp, ap);
227 break;
228 default:
229 return ENOEXEC;
230 }
231
232 #ifdef TODO
233 if (error == 0)
234 error = cpu_exec_coff_hook(p, epp );
235 #endif
236
237 if (error)
238 kill_vmcmds(&epp->ep_vmcmds);
239
240 return error;
241 }
242
243 /*
244 * exec_coff_setup_stack(): Set up the stack segment for a coff
245 * executable.
246 *
247 * Note that the ep_ssize parameter must be set to be the current stack
248 * limit; this is adjusted in the body of execve() to yield the
249 * appropriate stack segment usage once the argument length is
250 * calculated.
251 *
252 * This function returns an int for uniformity with other (future) formats'
253 * stack setup functions. They might have errors to return.
254 */
255
256 int
257 exec_coff_setup_stack(p, epp)
258 struct proc *p;
259 struct exec_package *epp;
260 {
261 /* DPRINTF(("enter exec_coff_setup_stack\n")); */
262
263 epp->ep_maxsaddr = USRSTACK - MAXSSIZ;
264 epp->ep_minsaddr = USRSTACK;
265 epp->ep_ssize = p->p_rlimit[RLIMIT_STACK].rlim_cur;
266
267 /*
268 * set up commands for stack. note that this takes *two*, one to
269 * map the part of the stack which we can access, and one to map
270 * the part which we can't.
271 *
272 * arguably, it could be made into one, but that would require the
273 * addition of another mapping proc, which is unnecessary
274 *
275 * note that in memory, things assumed to be: 0 ....... ep_maxsaddr
276 * <stack> ep_minsaddr
277 */
278 /* DPRINTF(("VMCMD: addr %x size %d\n", epp->ep_maxsaddr,
279 (epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr)); */
280 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero,
281 ((epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr),
282 epp->ep_maxsaddr, NULLVP, 0, VM_PROT_NONE);
283 /* DPRINTF(("VMCMD: addr %x size %d\n",
284 epp->ep_minsaddr - epp->ep_ssize,
285 epp->ep_ssize)); */
286 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize,
287 (epp->ep_minsaddr - epp->ep_ssize), NULLVP, 0,
288 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
289
290 return 0;
291 }
292
293
294 /*
295 * exec_coff_prep_omagic(): Prepare a COFF OMAGIC binary's exec package
296 */
297
298 int
299 exec_coff_prep_omagic(p, epp, fp, ap)
300 struct proc *p;
301 struct exec_package *epp;
302 struct coff_filehdr *fp;
303 struct coff_aouthdr *ap;
304 {
305 epp->ep_taddr = COFF_SEGMENT_ALIGN(ap, ap->a_tstart);
306 epp->ep_tsize = ap->a_tsize;
307 epp->ep_daddr = COFF_SEGMENT_ALIGN(ap, ap->a_dstart);
308 epp->ep_dsize = ap->a_dsize;
309 epp->ep_entry = ap->a_entry;
310
311 /* set up command for text and data segments */
312 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
313 ap->a_tsize + ap->a_dsize, epp->ep_taddr, epp->ep_vp,
314 COFF_TXTOFF(fp, ap),
315 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
316
317 /* set up command for bss segment */
318 #ifdef sh3
319 if (ap->a_bsize > 0)
320 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ap->a_bsize,
321 COFF_ROUND(ap->a_dstart + ap->a_dsize, COFF_LDPGSZ),
322 NULLVP, 0,
323 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
324 #else
325 if (ap->a_bsize > 0)
326 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ap->a_bsize,
327 COFF_SEGMENT_ALIGN(ap, ap->a_dstart + ap->a_dsize),
328 NULLVP, 0,
329 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
330 #endif
331
332 return exec_coff_setup_stack(p, epp);
333 }
334
335 /*
336 * exec_coff_prep_nmagic(): Prepare a 'native' NMAGIC COFF binary's exec
337 * package.
338 */
339
340 int
341 exec_coff_prep_nmagic(p, epp, fp, ap)
342 struct proc *p;
343 struct exec_package *epp;
344 struct coff_filehdr *fp;
345 struct coff_aouthdr *ap;
346 {
347 epp->ep_taddr = COFF_SEGMENT_ALIGN(ap, ap->a_tstart);
348 epp->ep_tsize = ap->a_tsize;
349 epp->ep_daddr = COFF_ROUND(ap->a_dstart, COFF_LDPGSZ);
350 epp->ep_dsize = ap->a_dsize;
351 epp->ep_entry = ap->a_entry;
352
353 /* set up command for text segment */
354 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, epp->ep_tsize,
355 epp->ep_taddr, epp->ep_vp, COFF_TXTOFF(fp, ap),
356 VM_PROT_READ|VM_PROT_EXECUTE);
357
358 /* set up command for data segment */
359 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, epp->ep_dsize,
360 epp->ep_daddr, epp->ep_vp, COFF_DATOFF(fp, ap),
361 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
362
363 /* set up command for bss segment */
364 if (ap->a_bsize > 0)
365 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ap->a_bsize,
366 COFF_SEGMENT_ALIGN(ap, ap->a_dstart + ap->a_dsize),
367 NULLVP, 0,
368 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
369
370 return exec_coff_setup_stack(p, epp);
371 }
372
373 /*
374 * coff_find_section - load specified section header
375 *
376 * TODO - optimize by reading all section headers in at once
377 */
378
379 static int
380 coff_find_section(p, vp, fp, sh, s_type)
381 struct proc *p;
382 struct vnode *vp;
383 struct coff_filehdr *fp;
384 struct coff_scnhdr *sh;
385 int s_type;
386 {
387 int i, pos, resid, siz, error;
388
389 pos = COFF_HDR_SIZE;
390 for (i = 0; i < fp->f_nscns; i++, pos += sizeof(struct coff_scnhdr)) {
391 siz = sizeof(struct coff_scnhdr);
392 error = vn_rdwr(UIO_READ, vp, (caddr_t) sh,
393 siz, pos, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred,
394 &resid, p);
395 if (error) {
396 DPRINTF(("section hdr %d read error %d\n", i, error));
397 return error;
398 }
399 siz -= resid;
400 if (siz != sizeof(struct coff_scnhdr)) {
401 DPRINTF(("incomplete read: hdr %d ask=%d, rem=%d got %d\n",
402 s_type, sizeof(struct coff_scnhdr),
403 resid, siz));
404 return ENOEXEC;
405 }
406 /* DPRINTF(("found section: %x\n", sh->s_flags)); */
407 if (sh->s_flags == s_type)
408 return 0;
409 }
410 return ENOEXEC;
411 }
412
413 /*
414 * exec_coff_prep_zmagic(): Prepare a COFF ZMAGIC binary's exec package
415 *
416 * First, set the various offsets/lengths in the exec package.
417 *
418 * Then, mark the text image busy (so it can be demand paged) or error
419 * out if this is not possible. Finally, set up vmcmds for the
420 * text, data, bss, and stack segments.
421 */
422
423 int
424 exec_coff_prep_zmagic(p, epp, fp, ap)
425 struct proc *p;
426 struct exec_package *epp;
427 struct coff_filehdr *fp;
428 struct coff_aouthdr *ap;
429 {
430 int error;
431 u_long offset;
432 long dsize;
433 #ifndef sh3
434 long baddr, bsize;
435 #endif
436 struct coff_scnhdr sh;
437
438 /* DPRINTF(("enter exec_coff_prep_zmagic\n")); */
439
440 /* set up command for text segment */
441 error = coff_find_section(p, epp->ep_vp, fp, &sh, COFF_STYP_TEXT);
442 if (error) {
443 DPRINTF(("can't find text section: %d\n", error));
444 return error;
445 }
446 /* DPRINTF(("COFF text addr %x size %d offset %d\n", sh.s_vaddr,
447 sh.s_size, sh.s_scnptr)); */
448 epp->ep_taddr = COFF_ALIGN(sh.s_vaddr);
449 offset = sh.s_scnptr - (sh.s_vaddr - epp->ep_taddr);
450 epp->ep_tsize = sh.s_size + (sh.s_vaddr - epp->ep_taddr);
451
452 #ifdef notyet
453 /*
454 * check if vnode is in open for writing, because we want to
455 * demand-page out of it. if it is, don't do it, for various
456 * reasons
457 */
458 if ((ap->a_tsize != 0 || ap->a_dsize != 0) &&
459 epp->ep_vp->v_writecount != 0) {
460 #ifdef DIAGNOSTIC
461 if (epp->ep_vp->v_flag & VTEXT)
462 panic("exec: a VTEXT vnode has writecount != 0\n");
463 #endif
464 return ETXTBSY;
465 }
466 epp->ep_vp->v_flag |= VTEXT;
467 #endif
468
469 /* DPRINTF(("VMCMD: addr %x size %d offset %d\n", epp->ep_taddr,
470 epp->ep_tsize, offset)); */
471 #ifdef notyet
472 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, epp->ep_tsize,
473 epp->ep_taddr, epp->ep_vp, offset,
474 VM_PROT_READ|VM_PROT_EXECUTE);
475 #else
476 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, epp->ep_tsize,
477 epp->ep_taddr, epp->ep_vp, offset,
478 VM_PROT_READ|VM_PROT_EXECUTE);
479 #endif
480
481 /* set up command for data segment */
482 error = coff_find_section(p, epp->ep_vp, fp, &sh, COFF_STYP_DATA);
483 if (error) {
484 DPRINTF(("can't find data section: %d\n", error));
485 return error;
486 }
487 /* DPRINTF(("COFF data addr %x size %d offset %d\n", sh.s_vaddr,
488 sh.s_size, sh.s_scnptr)); */
489 epp->ep_daddr = COFF_ALIGN(sh.s_vaddr);
490 offset = sh.s_scnptr - (sh.s_vaddr - epp->ep_daddr);
491 dsize = sh.s_size + (sh.s_vaddr - epp->ep_daddr);
492 #ifdef sh3
493 epp->ep_dsize = round_page(dsize) + ap->a_bsize;
494 #else
495 epp->ep_dsize = dsize + ap->a_bsize;
496 #endif
497
498 /* DPRINTF(("VMCMD: addr %x size %d offset %d\n", epp->ep_daddr,
499 dsize, offset)); */
500 #ifdef notyet
501 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, dsize,
502 epp->ep_daddr, epp->ep_vp, offset,
503 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
504 #else
505 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
506 dsize, epp->ep_daddr, epp->ep_vp, offset,
507 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
508 #endif
509
510 #ifdef sh3
511 if (ap->a_bsize > 0){
512 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ap->a_bsize,
513 COFF_ROUND(ap->a_dstart + ap->a_dsize, COFF_LDPGSZ),
514 NULLVP, 0,
515 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
516
517 }
518 #else
519 /* set up command for bss segment */
520 baddr = round_page(epp->ep_daddr + dsize);
521 bsize = epp->ep_daddr + epp->ep_dsize - baddr;
522 if (bsize > 0) {
523 /* DPRINTF(("VMCMD: addr %x size %d offset %d\n",
524 baddr, bsize, 0)); */
525 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero,
526 bsize, baddr, NULLVP, 0,
527 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
528 }
529 #endif
530
531 #ifdef TODO
532 /* load any shared libraries */
533 error = coff_find_section(p, epp->ep_vp, fp, &sh, COFF_STYP_SHLIB);
534 if (!error) {
535 int resid;
536 struct coff_slhdr *slhdr;
537 char buf[128], *bufp; /* FIXME */
538 int len = sh.s_size, path_index, entry_len;
539
540 /* DPRINTF(("COFF shlib size %d offset %d\n",
541 sh.s_size, sh.s_scnptr)); */
542
543 error = vn_rdwr(UIO_READ, epp->ep_vp, (caddr_t) buf,
544 len, sh.s_scnptr,
545 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred,
546 &resid, p);
547 if (error) {
548 DPRINTF(("shlib section read error %d\n", error));
549 return ENOEXEC;
550 }
551 bufp = buf;
552 while (len) {
553 slhdr = (struct coff_slhdr *)bufp;
554 path_index = slhdr->path_index * sizeof(long);
555 entry_len = slhdr->entry_len * sizeof(long);
556
557 /* DPRINTF(("path_index: %d entry_len: %d name: %s\n",
558 path_index, entry_len, slhdr->sl_name)); */
559
560 error = coff_load_shlib(p, slhdr->sl_name, epp);
561 if (error)
562 return ENOEXEC;
563 bufp += entry_len;
564 len -= entry_len;
565 }
566 }
567 #endif
568
569 /* set up entry point */
570 epp->ep_entry = ap->a_entry;
571
572 #if 0
573 DPRINTF(("text addr: %x size: %d data addr: %x size: %d entry: %x\n",
574 epp->ep_taddr, epp->ep_tsize,
575 epp->ep_daddr, epp->ep_dsize,
576 epp->ep_entry));
577 #endif
578
579 return exec_coff_setup_stack(p, epp);
580 }
581
582
583 #endif /* NOTDEF */
584