Home | History | Annotate | Line # | Download | only in loadbsd
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