loadbsd.c revision 1.10 1 /*
2 * $Id: loadbsd.c,v 1.10 1994/05/12 05:57:33 chopps Exp $
3 */
4
5 #include <sys/types.h>
6 #include <a.out.h>
7 #include <stdio.h>
8 #include <unistd.h>
9
10 #include <exec/types.h>
11 #include <exec/execbase.h>
12 #include <exec/memory.h>
13 #include <exec/resident.h>
14 #include <libraries/configregs.h>
15 #include <libraries/expansionbase.h>
16 #include <graphics/gfxbase.h>
17
18 #include <inline/exec.h>
19 #include <inline/expansion.h>
20 #include <inline/graphics.h>
21
22 /* Get definitions for boothowto */
23 #include "reboot.h"
24
25 static char usage[] =
26 "
27 NAME
28 \t%s - loads NetBSD from amiga dos.
29 SYNOPSIS
30 \t%s some-vmunix [-a] [-b] [-k] [-m memory] [-p] [-t] [-V]
31 OPTIONS
32 \t-a Boot up to multiuser mode.
33 \t-b Ask for which root device.
34 \t Its possible to have multiple roots and choose between them.
35 \t-k Reserve the first 4M of fast mem [Some one else
36 \t is going to have to answer what that it is used for].
37 \t-m Tweak amount of available memory, for finding minimum amount
38 \t of memory required to run. Sets fastmem size to specified
39 \t size in Kbytes.
40 \t-p Use highest priority fastmem segement instead of the largest
41 \t segment. The higher priority segment is usually faster
42 \t (i.e. 32 bit memory), but some people have smaller amounts
43 \t of 32 bit memory.
44 \t-t This is a *test* option. It prints out the memory
45 \t list information being passed to the kernel and also
46 \t exits without actually starting NetBSD.
47 \t-S Include kernel symbol table.
48 \t-D Enter debugger
49 \t-V Version of loadbsd program.
50 HISTORY
51 This version supports Kernel version 720 +
52 ";
53
54 struct ExpansionBase *ExpansionBase;
55 struct GfxBase *GfxBase;
56
57 #undef __LDPGSZ
58 #define __LDPGSZ 8192
59
60 #define MAX_MEM_SEG 16
61
62 /*
63 * Kernel parameter passing version
64 * 1: first version of loadbsd
65 * 2: needs esym location passed in a4
66 */
67 #define KERNEL_PARAMETER_VERSION 2
68
69 /*
70 * Version history:
71 * 1.x Kernel parameter passing version check.
72 * 2.0 Added symbol table end address and symbol table support.
73 * 2.1 03/23/94 - Round up end of fastram segment.
74 * Check fastram segment size for minimum of 2M.
75 * Use largest segment of highest priority if -p option.
76 * Print out fastram size in KB if not a multiple of MB.
77 * 2.2 03/24/94 - Zero out all unused registers.
78 * Started version history comment.
79 * 2.3 04/26/94 - Added -D option to enter debugger on boot.
80 * 2.4 04/30/94 - Cpuid includes base machine type.
81 * Also check if CPU is capable of running NetBSD.
82 */
83
84 struct MEM_LIST {
85 u_long num_mem;
86 struct MEM_SEG {
87 u_long mem_start;
88 u_long mem_size;
89 u_short mem_attrib;
90 short mem_prio;
91 } mem_seg[MAX_MEM_SEG];
92 } mem_list, *kmem_list;
93
94 int k_opt;
95 int a_opt;
96 int b_opt;
97 int p_opt;
98 int t_opt;
99 int m_opt;
100 int S_opt;
101 int D_opt;
102
103 u_long cpuid;
104
105 extern char *optarg;
106 extern int optind;
107
108 void get_mem_config (void **fastmem_start, u_long *fastmem_size, u_long *chipmem_size);
109 void get_cpuid (void);
110 void Usage (char *program_name);
111 void Version (void);
112
113 static const char _version[] = "$VER: LoadBSD 2.4 (30.4.94)";
114
115 int
116 main (int argc, char *argv[])
117 {
118 struct exec e;
119 int fd;
120 int boothowto = RB_SINGLE;
121
122 if (argc >= 2)
123 {
124 if ((fd = open (argv[1], 0)) >= 0)
125 {
126 if (read (fd, &e, sizeof (e)) == sizeof (e))
127 {
128 if (e.a_magic == NMAGIC)
129 {
130 u_char *kernel;
131 int kernel_size;
132 int text_size;
133 struct ConfigDev *cd;
134 int num_cd;
135 void *fastmem_start;
136 u_long fastmem_size, chipmem_size;
137 int i;
138 u_short *kern_vers;
139 char *esym;
140 int string_size;
141
142 GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library", 0);
143 if (! GfxBase) /* not supposed to fail... */
144 abort();
145 ExpansionBase= (struct ExpansionBase *) OpenLibrary ("expansion.library", 0);
146 if (! ExpansionBase) /* not supposed to fail... */
147 abort();
148 optind = 2;
149 while ((i = getopt (argc, argv, "kabptVm:SD")) != EOF)
150 switch (i) {
151 case 'k':
152 k_opt = 1;
153 break;
154 case 'a':
155 a_opt = 1;
156 break;
157 case 'b':
158 b_opt = 1;
159 break;
160 case 'p':
161 p_opt = 1;
162 break;
163 case 't':
164 t_opt = 1;
165 break;
166 case 'm':
167 m_opt = atoi (optarg) * 1024;
168 break;
169 case 'V':
170 Version();
171 break;
172 case 'S':
173 S_opt = 1;
174 break;
175 case 'D':
176 D_opt = 1;
177 break;
178 default:
179 Usage(argv[0]);
180 fprintf(stderr,"Unrecognized option \n");
181 exit(-1);
182 }
183
184 for (cd = 0, num_cd = 0; cd = FindConfigDev (cd, -1, -1); num_cd++) ;
185 get_mem_config (&fastmem_start, &fastmem_size, &chipmem_size);
186 get_cpuid ();
187
188 text_size = (e.a_text + __LDPGSZ - 1) & (-__LDPGSZ);
189 esym = NULL;
190 kernel_size = text_size + e.a_data + e.a_bss
191 + num_cd*sizeof(*cd) + 4
192 + mem_list.num_mem*sizeof(struct MEM_SEG) + 4;
193 /*
194 * get symbol table size & string size
195 * (should check kernel version to see if it will handle it)
196 */
197 if (S_opt && e.a_syms) {
198 S_opt = 0; /* prepare for failure */
199 if (lseek(fd, e.a_text + e.a_data + e.a_syms, SEEK_CUR) > 0) {
200 if (read (fd, &string_size, 4) == 4) {
201 if (lseek(fd, sizeof(e), SEEK_SET) < 0) {
202 printf ("Error repositioning to text\n");
203 exit(0); /* Give up! */
204 }
205 kernel_size += e.a_syms + 4 + string_size;
206 S_opt = 1; /* sucess! Keep -S option */
207 }
208 }
209 }
210
211 kernel = (u_char *) malloc (kernel_size);
212
213 if (t_opt)
214 for (i = 0; i < mem_list.num_mem; ++i) {
215 printf ("mem segment %d: start=%08lx size=%08lx attribute=%04lx pri=%d\n",
216 i + 1, mem_list.mem_seg[i].mem_start,
217 mem_list.mem_seg[i].mem_size,
218 mem_list.mem_seg[i].mem_attrib,
219 mem_list.mem_seg[i].mem_prio);
220 }
221
222 if (kernel)
223 {
224 if (read (fd, kernel, e.a_text) == e.a_text
225 && read (fd, kernel + text_size, e.a_data) == e.a_data)
226 {
227 int *knum_cd;
228 struct ConfigDev *kcd;
229 int mem_ix;
230
231 if (k_opt)
232 {
233 fastmem_start += 4*1024*1024;
234 fastmem_size -= 4*1024*1024;
235 }
236
237 if (m_opt && m_opt <= fastmem_size)
238 {
239 fastmem_size = m_opt;
240 }
241
242 if (a_opt)
243 {
244 printf("Autobooting...");
245 boothowto = RB_AUTOBOOT;
246 }
247
248 if (b_opt)
249 {
250 printf("Askboot...");
251 boothowto |= RB_ASKNAME;
252 }
253
254 if (D_opt)
255 {
256 boothowto |= RB_KDB;
257 }
258
259 printf ("Using %d%c FASTMEM at 0x%x, %dM CHIPMEM\n",
260 (fastmem_size & 0xfffff) ? fastmem_size>>10 :
261 fastmem_size>>20,
262 (fastmem_size & 0xfffff) ? 'K' : 'M',
263 fastmem_start, chipmem_size>>20);
264 kern_vers = (u_short *) (kernel + e.a_entry - 2);
265 if (*kern_vers > KERNEL_PARAMETER_VERSION &&
266 *kern_vers != 0x4e73)
267 {
268 printf ("This kernel requires a newer version of loadbsd: %d\n", *kern_vers);
269 exit (0);
270 }
271 if ((cpuid & AFB_68020) == 0)
272 {
273 printf ("Hmmm... You don't seem to have a CPU capable\n");
274 printf (" of running NetBSD. You need a 68020\n");
275 printf (" or better\n");
276 exit (0);
277 }
278 /* give them a chance to read the information... */
279 sleep(2);
280
281 bzero (kernel + text_size + e.a_data, e.a_bss);
282 /*
283 * If symbols wanted (and kernel can handle them),
284 * load symbol table & strings and set esym to end.
285 */
286 knum_cd = (int *) (kernel + text_size + e.a_data + e.a_bss);
287 if (*kern_vers != 0x4e73 && *kern_vers > 1 && S_opt && e.a_syms) {
288 *knum_cd++ = e.a_syms;
289 read(fd, (char *)knum_cd, e.a_syms);
290 knum_cd = (int *)((char *)knum_cd + e.a_syms);
291 read(fd, (char *)knum_cd, string_size);
292 knum_cd = (int*)((char *)knum_cd + string_size);
293 esym = (char *) (text_size + e.a_data + e.a_bss
294 + e.a_syms + 4 + string_size);
295 }
296 *knum_cd = num_cd;
297 for (kcd = (struct ConfigDev *) (knum_cd+1);
298 cd = FindConfigDev (cd, -1, -1);
299 *kcd++ = *cd)
300 ;
301 kmem_list = (struct MEM_LIST *)kcd;
302 kmem_list->num_mem = mem_list.num_mem;
303 for (mem_ix = 0; mem_ix < mem_list.num_mem; mem_ix++)
304 kmem_list->mem_seg[mem_ix] = mem_list.mem_seg[mem_ix];
305 if (t_opt) /* if test option */
306 exit (0); /* don't start kernel */
307 /* AGA startup - may need more */
308 LoadView (NULL);
309 startit (kernel, kernel_size,
310 e.a_entry, fastmem_start,
311 fastmem_size, chipmem_size,
312 boothowto, esym, cpuid );
313 }
314 else
315 fprintf (stderr, "Executable corrupt!\n");
316 }
317 else
318 fprintf (stderr, "Out of memory! (%d)\n", text_size + e.a_data + e.a_bss
319 + num_cd*sizeof(*cd) + 4
320 + mem_list.num_mem*sizeof(struct MEM_SEG) + 4);
321 }
322 else
323 fprintf (stderr, "Unsupported executable: %o\n", e.a_magic);
324 }
325 else
326 fprintf (stderr, "Can't read header of %s\n", argv[1]);
327
328 close (fd);
329 }
330 else
331 perror ("open");
332 }
333 else
334 Usage(argv[0]);
335 Version();
336 }/* main() */
337
338 void
339 get_mem_config (void **fastmem_start, u_long *fastmem_size, u_long *chipmem_size)
340 {
341 extern struct ExecBase *SysBase;
342 struct MemHeader *mh, *nmh;
343 int num_mem = 0;
344 u_int seg_size;
345 u_int seg_start;
346 u_int seg_end;
347 char mem_pri = -128;
348
349 *fastmem_size = 0;
350 *chipmem_size = 0;
351
352 /* walk thru the exec memory list */
353 Forbid ();
354 for (mh = (struct MemHeader *) SysBase->MemList.lh_Head;
355 nmh = (struct MemHeader *) mh->mh_Node.ln_Succ;
356 mh = nmh, num_mem++)
357 {
358 mem_list.mem_seg[num_mem].mem_attrib = mh->mh_Attributes;
359 mem_list.mem_seg[num_mem].mem_prio = mh->mh_Node.ln_Pri;
360 seg_start = (u_int)mh->mh_Lower;
361 seg_end = (u_int)mh->mh_Upper;
362 seg_size = seg_end - seg_start;
363 mem_list.mem_seg[num_mem].mem_size = seg_size;
364 mem_list.mem_seg[num_mem].mem_start = seg_start;
365
366 if (mh->mh_Attributes & MEMF_CHIP)
367 {
368 /* there should hardly be more than one entry for chip mem, but
369 handle it the same nevertheless */
370 /* chipmem always starts at 0, so include vector area */
371 mem_list.mem_seg[num_mem].mem_start = seg_start = 0;
372 /* round to multiple of 512K */
373 seg_size = (seg_size + 512*1024 - 1) & -(512*1024);
374 mem_list.mem_seg[num_mem].mem_size = seg_size;
375 if (seg_size > *chipmem_size)
376 {
377 *chipmem_size = seg_size;
378 }
379 }
380 else
381 {
382 /* some heuristics.. */
383 seg_start &= -__LDPGSZ;
384 seg_end = (seg_end + __LDPGSZ - 1) & -__LDPGSZ;
385 /* get the mem back stolen by incore kickstart on A3000 with
386 V36 bootrom. */
387 if (seg_end == 0x07f80000)
388 seg_end = 0x08000000;
389
390 /* or by zkick on a A2000. */
391 if (seg_start == 0x280000
392 && strcmp (mh->mh_Node.ln_Name, "zkick memory") == 0)
393 seg_start = 0x200000;
394
395 seg_size = seg_end - seg_start;
396 mem_list.mem_seg[num_mem].mem_start = seg_start;
397 mem_list.mem_seg[num_mem].mem_size = seg_size;
398 /*
399 * If this segment is smaller than 2M,
400 * don't use it to load the kernel
401 */
402 if (seg_size < 2 * 1024 * 1024)
403 continue;
404 /* if p_opt is set, select memory by priority instead of size */
405 if ((!p_opt && seg_size > *fastmem_size) ||
406 (p_opt && mem_pri <= mh->mh_Node.ln_Pri && seg_size > *fastmem_size))
407 {
408 *fastmem_size = seg_size;
409 *fastmem_start = (void *)seg_start;
410 mem_pri = mh->mh_Node.ln_Pri;
411 }
412 }
413 }
414 mem_list.num_mem = num_mem;
415 Permit();
416 }
417
418 /*
419 * Try to determine the machine ID by searching the resident module list
420 * for modules only present on specific machines. (Thanks, Bill!)
421 */
422
423 void
424 get_cpuid ()
425 {
426 extern struct ExecBase *SysBase;
427 u_long *rl;
428 struct Resident *rm;
429
430 cpuid = SysBase->AttnFlags; /* get FPU and CPU flags */
431 rl = (u_long *) SysBase->ResModules;
432 if (rl == NULL)
433 return;
434
435 while (*rl) {
436 rm = (struct Resident *) *rl;
437 if (strcmp (rm->rt_Name, "A4000 Bonus") == 0 ||
438 strcmp (rm->rt_Name, "A1000 Bonus") == 0) {
439 cpuid |= 4000 << 16;
440 break;
441 }
442 if (strcmp (rm->rt_Name, "A3000 Bonus") == 0) {
443 cpuid |= 3000 << 16;
444 break;
445 }
446 if (strcmp (rm->rt_Name, "card.resource") == 0) {
447 cpuid |= 1200 << 16; /* or A600 :-) */
448 break;
449 }
450 ++rl;
451 }
452 if (*rl == 0) /* Nothing found, it's probably an A2000 or A500 */
453 cpuid |= 2000 << 16;
454 }
455
456
457 asm ("
458 .set ABSEXECBASE,4
459
460 .text
461 .globl _startit
462
463 _startit:
464 movel sp,a3
465 movel 4:w,a6
466 lea pc@(start_super-.+2),a5
467 jmp a6@(-0x1e) | supervisor-call
468
469 start_super:
470 movew #0x2700,sr
471
472 | the BSD kernel wants values into the following registers:
473 | a0: fastmem-start
474 | d0: fastmem-size
475 | d1: chipmem-size
476 | d5: AttnFlags (cpuid)
477 | d7: boothowto
478 | a4: esym location
479 | All other registers zeroed for possible future requirements.
480
481 movel a3@(4),a1 | loaded kernel
482 movel a3@(8),d2 | length of loaded kernel
483 movel a3@(12),sp@- | entry point [save on stack for rts]
484 movel a3@(16),a0 | fastmem-start
485 movel a3@(20),d0 | fastmem-size
486 movel a3@(24),d1 | chipmem-size
487 movel a3@(28),d7 | boothowto
488 movel a3@(32),a4 | esym
489 movel a3@(36),d5 | cpuid
490 subl a5,a5 | target, load to 0
491
492 btst #3,(ABSEXECBASE)@(0x129) | AFB_68040,SysBase->AttnFlags
493 beq not040
494
495 | Turn off 68040 MMU
496
497 .word 0x4e7b,0xd003 | movec a5,tc
498 .word 0x4e7b,0xd806 | movec a5,urp
499 .word 0x4e7b,0xd807 | movec a5,srp
500 .word 0x4e7b,0xd004 | movec a5,itt0
501 .word 0x4e7b,0xd005 | movec a5,itt1
502 .word 0x4e7b,0xd006 | movec a5,dtt0
503 .word 0x4e7b,0xd007 | movec a5,dtt1
504 bra nott
505
506 not040:
507 lea pc@(zero-.+2),a3
508 pmove a3@,tc | Turn off MMU
509 lea pc@(nullrp-.+2),a3
510 pmove a3@,crp | Turn off MMU some more
511 pmove a3@,srp | Really, really, turn off MMU
512
513 | Turn off 68030 TT registers
514
515 btst #2,(ABSEXECBASE)@(0x129) | AFB_68030,SysBase->AttnFlags
516 beq nott | Skip TT registers if not 68030
517 lea pc@(zero-.+2),a3
518 .word 0xf013,0x0800 | pmove a3@,tt0 (gas only knows about 68851 ops..)
519 .word 0xf013,0x0c00 | pmove a3@,tt1 (gas only knows about 68851 ops..)
520
521 nott:
522
523 movew #(1<<9),0xdff096 | disable DMA
524
525 L0:
526 moveb a1@+,a5@+
527 subl #1,d2
528 bcc L0
529
530
531 moveq #0,d2 | zero out unused registers
532 moveq #0,d3 | (might make future compatibility
533 moveq #0,d4 | a little easier, since all registers
534 moveq #0,d6 | would have known contents)
535 movel d6,a1
536 movel d6,a2
537 movel d6,a3
538 movel d6,a5
539 movel d6,a6
540 rts | return to kernel entry point
541
542
543 | A do-nothing MMU root pointer (includes the following long as well)
544
545 nullrp: .long 0x7fff0001
546 zero: .long 0
547
548
549 ");
550
551 void Usage(char *program_name)
552 {
553 fprintf(stderr,usage,program_name,program_name);
554 }
555
556 void Version()
557 {
558 fprintf(stderr,"%s\n",_version + 6);
559 }
560