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