loadbsd.c revision 1.6
1#include <sys/types.h>
2#include <a.out.h>
3#include <stdio.h>
4
5#include <exec/types.h>
6#include <exec/execbase.h>
7#include <exec/memory.h>
8#include <libraries/configregs.h>
9#include <libraries/expansionbase.h>
10#include <graphics/gfxbase.h>
11
12#include <inline/exec.h>
13#include <inline/expansion.h>
14#include <inline/graphics.h>
15
16/* Get definitions for boothowto */
17#include "reboot.h"
18
19static char usage[] =
20"
21NAME
22\t%s - loads NetBSD from amiga dos.
23SYNOPSIS
24\t%s some-vmunix [-a] [-b] [-k] [-m memory] [-p] [-t] [-V]
25OPTIONS
26\t-a  Boot up to multiuser mode.
27\t-b  Ask for which root device.
28\t    Its possible to have multiple roots and choose between them.
29\t-k  Reserve the first 4M of fast mem [Some one else
30\t    is going to have to answer what that it is used for].
31\t-m  Tweak amount of available memory, for finding minimum amount
32\t    of memory required to run. Sets fastmem size to specified
33\t    size in Kbytes.
34\t-p  Use highest priority fastmem segement instead of the largest
35\t    segment. The higher priority segment is usually faster
36\t    (i.e. 32 bit memory), but some people have smaller amounts
37\t    of 32 bit memory.
38\t-t  This is a *test* option.  It prints out the memory
39\t    list information being passed to the kernel and also
40\t    exits without actually starting NetBSD.
41\t-V  Version of loadbsd program.
42HISTORY
43      This version supports Kernel version 720 +
44";
45
46struct ExpansionBase *ExpansionBase;
47struct GfxBase *GfxBase;
48
49#undef __LDPGSZ
50#define __LDPGSZ 8192
51
52#define MAX_MEM_SEG	16
53
54/*
55 * Kernel parameter passing version
56 */
57#define KERNEL_PARAMETER_VERSION	1
58
59struct MEM_LIST {
60	u_long	num_mem;
61	struct MEM_SEG {
62		u_long	mem_start;
63		u_long	mem_size;
64		u_short	mem_attrib;
65		short	mem_prio;
66	} mem_seg[MAX_MEM_SEG];
67} mem_list, *kmem_list;
68
69int k_opt;
70int a_opt;
71int b_opt;
72int p_opt;
73int t_opt;
74int m_opt;
75
76extern char *optarg;
77extern int optind;
78
79void get_mem_config (void **fastmem_start, u_long *fastmem_size, u_long *chipmem_size);
80void Usage (char *program_name);
81void Version (void);
82
83static const char _version[] = "$VER: LoadBSD 1.744 (28.1.94)";
84
85int
86main (int argc, char *argv[])
87{
88  struct exec e;
89  int fd;
90  int boothowto = RB_SINGLE;
91
92  if (argc >= 2)
93    {
94      if ((fd = open (argv[1], 0)) >= 0)
95        {
96          if (read (fd, &e, sizeof (e)) == sizeof (e))
97            {
98              if (e.a_magic == NMAGIC)
99                {
100                  u_char *kernel;
101		  int text_size;
102		  struct ConfigDev *cd;
103		  int num_cd;
104		  void *fastmem_start;
105		  u_long fastmem_size, chipmem_size;
106		  int i;
107		  u_short *kern_vers;
108
109		  GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library", 0);
110		  if (! GfxBase)	/* not supposed to fail... */
111		    abort();
112		  ExpansionBase= (struct ExpansionBase *) OpenLibrary ("expansion.library", 0);
113		  if (! ExpansionBase)	/* not supposed to fail... */
114		    abort();
115		  optind = 2;
116		  while ((i = getopt (argc, argv, "kabptVm:")) != EOF)
117		    switch (i) {
118		    case 'k':
119		      k_opt = 1;
120		      break;
121		    case 'a':
122		      a_opt = 1;
123		      break;
124		    case 'b':
125		      b_opt = 1;
126		      break;
127		    case 'p':
128		      p_opt = 1;
129		      break;
130		    case 't':
131		      t_opt = 1;
132		      break;
133		    case 'm':
134		      m_opt = atoi (optarg) * 1024;
135		      break;
136                    case 'V':
137                      Version();
138                      break;
139                    default:
140                      Usage(argv[0]);
141                      fprintf(stderr,"Unrecognized option \n");
142                      exit(-1);
143		    }
144
145		  for (cd = 0, num_cd = 0; cd = FindConfigDev (cd, -1, -1); num_cd++) ;
146		  get_mem_config (&fastmem_start, &fastmem_size, &chipmem_size);
147
148		  text_size = (e.a_text + __LDPGSZ - 1) & (-__LDPGSZ);
149		  kernel = (u_char *) malloc (text_size + e.a_data + e.a_bss
150				              + num_cd*sizeof(*cd) + 4
151					      + mem_list.num_mem*sizeof(struct MEM_SEG) + 4);
152
153		  if (t_opt)
154		    for (i = 0; i < mem_list.num_mem; ++i) {
155		      printf ("mem segment %d: start=%08lx size=%08lx attribute=%04lx pri=%d\n",
156			i + 1, mem_list.mem_seg[i].mem_start,
157			mem_list.mem_seg[i].mem_size,
158			mem_list.mem_seg[i].mem_attrib,
159			mem_list.mem_seg[i].mem_prio);
160		    }
161
162                  if (kernel)
163                    {
164		      if (read (fd, kernel, e.a_text) == e.a_text
165			  && read (fd, kernel + text_size, e.a_data) == e.a_data)
166			{
167			  int *knum_cd;
168			  struct ConfigDev *kcd;
169			  int mem_ix;
170
171			  if (k_opt)
172			    {
173			      fastmem_start += 4*1024*1024;
174			      fastmem_size  -= 4*1024*1024;
175			    }
176
177			  if (m_opt && m_opt <= fastmem_size)
178			    {
179			      fastmem_size = m_opt;
180			    }
181
182			  if (a_opt)
183			    {
184			      printf("Autobooting...");
185			      boothowto = RB_AUTOBOOT;
186			    }
187
188			  if (b_opt)
189			    {
190			      printf("Askboot...");
191			      boothowto |= RB_ASKNAME;
192			    }
193
194			  printf ("Using %dM FASTMEM at 0x%x, %dM CHIPMEM\n",
195				  fastmem_size>>20, fastmem_start, chipmem_size>>20);
196			  kern_vers = (u_short *) (kernel + e.a_entry - 2);
197			  if (*kern_vers > KERNEL_PARAMETER_VERSION &&
198			      *kern_vers != 0x4e73)
199			    {
200			      printf ("This kernel requires a newer version of loadbsd: %d\n", *kern_vers);
201			      exit (0);
202			    }
203			  if (t_opt)		/* if test option */
204			    exit (0);		/*   don't start kernel */
205			  /* give them a chance to read the information... */
206			  sleep(2);
207
208			  bzero (kernel + text_size + e.a_data, e.a_bss);
209			  knum_cd = (int *) (kernel + text_size + e.a_data + e.a_bss);
210			  *knum_cd = num_cd;
211			  for (kcd = (struct ConfigDev *) (knum_cd+1);
212			       cd = FindConfigDev (cd, -1, -1);
213			       *kcd++ = *cd)
214				;
215			  kmem_list = (struct MEM_LIST *)kcd;
216			  kmem_list->num_mem = mem_list.num_mem;
217			  for (mem_ix = 0; mem_ix < mem_list.num_mem; mem_ix++)
218			  	kmem_list->mem_seg[mem_ix] = mem_list.mem_seg[mem_ix];
219			  /* AGA startup - probably needs more */
220			  LoadView (NULL);
221			  startit (kernel,
222				   text_size + e.a_data + e.a_bss + num_cd*sizeof(*cd) + 4
223				     + mem_list.num_mem*sizeof(struct MEM_SEG) + 4,
224				   e.a_entry, fastmem_start,
225				   fastmem_size, chipmem_size,
226				   boothowto );
227			}
228		      else
229			fprintf (stderr, "Executable corrupt!\n");
230                    }
231                  else
232		    fprintf (stderr, "Out of memory! (%d)\n", text_size + e.a_data + e.a_bss
233				   + num_cd*sizeof(*cd) + 4
234				   + mem_list.num_mem*sizeof(struct MEM_SEG) + 4);
235                }
236	      else
237	        fprintf (stderr, "Unsupported executable: %o\n", e.a_magic);
238            }
239          else
240	    fprintf (stderr, "Can't read header of %s\n", argv[1]);
241
242	  close (fd);
243        }
244      else
245	perror ("open");
246    }
247  else
248    Usage(argv[0]);
249  Version();
250}/* main() */
251
252void
253get_mem_config (void **fastmem_start, u_long *fastmem_size, u_long *chipmem_size)
254{
255  extern struct ExecBase *SysBase;
256  struct MemHeader *mh, *nmh;
257  int num_mem = 0;
258  u_int seg_size;
259  u_int seg_start;
260  u_int seg_end;
261
262  *fastmem_size = 0;
263  *chipmem_size = 0;
264
265  /* walk thru the exec memory list */
266  Forbid ();
267  for (mh  = (struct MemHeader *) SysBase->MemList.lh_Head;
268       nmh = (struct MemHeader *) mh->mh_Node.ln_Succ;
269       mh  = nmh, num_mem++)
270    {
271      mem_list.mem_seg[num_mem].mem_attrib = mh->mh_Attributes;
272      mem_list.mem_seg[num_mem].mem_prio = mh->mh_Node.ln_Pri;
273      seg_start = (u_int)mh->mh_Lower;
274      seg_end = (u_int)mh->mh_Upper;
275      seg_size = seg_end - seg_start;
276      mem_list.mem_seg[num_mem].mem_size = seg_size;
277      mem_list.mem_seg[num_mem].mem_start = seg_start;
278
279      if (mh->mh_Attributes & MEMF_CHIP)
280        {
281	  /* there should hardly be more than one entry for chip mem, but
282	     handle it the same nevertheless */
283	  /* chipmem always starts at 0, so include vector area */
284	  mem_list.mem_seg[num_mem].mem_start = seg_start = 0;
285	  /* round to multiple of 512K */
286	  seg_size = (seg_size + 512*1024 - 1) & -(512*1024);
287	  mem_list.mem_seg[num_mem].mem_size = seg_size;
288	  if (seg_size > *chipmem_size)
289	    {
290	      *chipmem_size = seg_size;
291	    }
292        }
293      else
294	{
295	  /* some heuristics.. */
296	  seg_start &= -__LDPGSZ;
297	  /* get the mem back stolen by incore kickstart on A3000 with
298	     V36 bootrom. */
299	  if (seg_end == 0x07f80000)
300	    seg_end = 0x08000000;
301
302	  /* or by zkick on a A2000.  */
303	  if (seg_start == 0x280000
304	    && strcmp (mh->mh_Node.ln_Name, "zkick memory") == 0)
305	      seg_start = 0x200000;
306
307	  seg_size = seg_end - seg_start;
308	  mem_list.mem_seg[num_mem].mem_start = seg_start;
309	  mem_list.mem_seg[num_mem].mem_size = seg_size;
310/* if p_opt is set, select memory by priority instead of size */
311	  if ((!p_opt && seg_size > *fastmem_size) ||
312            (p_opt && *fastmem_size == 0))
313	    {
314	      *fastmem_size = seg_size;
315	      *fastmem_start = (void *)seg_start;
316	    }
317	}
318    }
319  mem_list.num_mem = num_mem;
320  Permit();
321}
322
323
324
325
326asm ("
327	.set	ABSEXECBASE,4
328
329	.text
330	.globl	_startit
331
332_startit:
333	movel	sp,a3
334	movel	4:w,a6
335	lea	pc@(start_super-.+2),a5
336	jmp	a6@(-0x1e)		| supervisor-call
337
338start_super:
339	movew	#0x2700,sr
340
341	| the BSD kernel wants values into the following registers:
342	| a0:  fastmem-start
343	| d0:  fastmem-size
344	| d1:  chipmem-size
345	| d5:  AttnFlags (cpuid)
346	| d7:  boothowto
347
348	movel	a3@(4),a1		| loaded kernel
349	movel	a3@(8),d2		| length of loaded kernel
350	movel	a3@(12),a2		| entry point
351	movel	a3@(16),a0		| fastmem-start
352	movel	a3@(20),d0		| fastmem-size
353	movel	a3@(24),d1		| chipmem-size
354	movel	#0,d5
355	movew	(ABSEXECBASE)@(0x128),d5 | SysBase->AttnFlags
356	movel	a3@(28),d7		| boothowto
357	subl	a4,a4			| target, load to 0
358
359	btst	#3,(ABSEXECBASE)@(0x129) | AFB_68040,SysBase->AttnFlags
360	beq	not040
361
362| Turn off 68040 MMU
363
364	.word 0x4e7b,0xc003		| movec a4,tc
365	.word 0x4e7b,0xc806		| movec a4,urp
366	.word 0x4e7b,0xc807		| movec a4,srp
367	.word 0x4e7b,0xc004		| movec a4,itt0
368	.word 0x4e7b,0xc005		| movec a4,itt1
369	.word 0x4e7b,0xc006		| movec a4,dtt0
370	.word 0x4e7b,0xc007		| movec a4,dtt1
371	bra	nott
372
373not040:
374	lea	pc@(zero-.+2),a3
375	pmove	a3@,tc			| Turn off MMU
376	lea	pc@(nullrp-.+2),a3
377	pmove	a3@,crp			| Turn off MMU some more
378	pmove	a3@,srp			| Really, really, turn off MMU
379
380| Turn off 68030 TT registers
381
382	btst	#2,(ABSEXECBASE)@(0x129) | AFB_68030,SysBase->AttnFlags
383	beq	nott			| Skip TT registers if not 68030
384	lea	pc@(zero-.+2),a3
385	.word 0xf013,0x0800		| pmove a3@,tt0 (gas only knows about 68851 ops..)
386	.word 0xf013,0x0c00		| pmove a3@,tt1 (gas only knows about 68851 ops..)
387
388nott:
389
390	movew	#(1<<9),0xdff096	| disable DMA
391
392L0:
393	moveb	a1@+,a4@+
394	subl	#1,d2
395	bcc	L0
396
397
398	jmp	a2@
399
400
401| A do-nothing MMU root pointer (includes the following long as well)
402
403nullrp:	.long	0x7fff0001
404zero:	.long	0
405
406
407");
408
409void Usage(char *program_name)
410{
411   fprintf(stderr,usage,program_name,program_name);
412}
413
414void Version()
415{
416  fprintf(stderr,"%s\n",_version + 6);
417}
418