patch-2.0.21-2.1.0 linux/arch/m68k/boot/amiga/bootstrap.c

Next file: linux/arch/m68k/boot/amiga/bootstrap.h
Previous file: linux/arch/m68k/boot/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/boot/amiga/bootstrap.c linux/arch/m68k/boot/amiga/bootstrap.c
@@ -1,18 +1,26 @@
 /*
-** bootstrap.c -- This program loads the Linux/68k kernel into an Amiga
-**                and and launches it.
+** linux/arch/m68k/boot/amiga/bootstrap.c -- This program loads the Linux/m68k
+**					     kernel into an Amiga and launches
+**					     it.
 **
 ** Copyright 1993,1994 by Hamish Macdonald, Greg Harp
 **
 ** Modified 11-May-94 by Geert Uytterhoeven
-**                      (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+**			(Geert.Uytterhoeven@cs.kuleuven.ac.be)
 **     - A3640 MapROM check
 ** Modified 31-May-94 by Geert Uytterhoeven
 **     - Memory thrash problem solved
 ** Modified 07-March-95 by Geert Uytterhoeven
 **     - Memory block sizes are rounded to a multiple of 256K instead of 1M
-**       This _requires_ >0.9pl5 to work!
-**       (unless all block sizes are multiples of 1M :-)
+**	 This _requires_ >0.9pl5 to work!
+**	 (unless all block sizes are multiples of 1M :-)
+** Modified 11-July-95 by Andreas Schwab
+**     - Support for ELF kernel (untested!)
+** Modified 10-Jan-96 by Geert Uytterhoeven
+**     - The real Linux/m68k boot code moved to linuxboot.[ch]
+** Modified 9-Sep-96 by Geert Uytterhoeven
+**     - Rewritten option parsing
+**     - New parameter passing to linuxboot() (linuxboot_args)
 **
 ** This file is subject to the terms and conditions of the GNU General Public
 ** License.  See the file COPYING in the main directory of this archive
@@ -23,760 +31,303 @@
 #include <stddef.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdarg.h>
 #include <string.h>
 #include <sys/file.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-/* Amiga bootstrap include file */
-#include "bootstrap.h"
-
-/* required Linux/68k include files */
+/* required Linux/m68k include files */
 #include <linux/a.out.h>
-#include <asm/bootinfo.h>
-
-/* temporary stack size */
-#define TEMP_STACKSIZE	256
-
-/* Exec Base */
-extern struct ExecBase *SysBase;
-
-extern char *optarg;
-
-struct exec kexec;
-char *memptr;
-u_long start_mem;
-u_long mem_size;
-u_long rd_size;
-
-struct ExpansionBase *ExpansionBase;
-struct GfxBase *GfxBase;
-
-struct bootinfo bi;
-u_long bi_size = sizeof bi;
-
-caddr_t CustomBase = (caddr_t)CUSTOM_PHYSADDR;
-
-void usage(void)
-{
-	fprintf (stderr, "Usage:\n"
-		 "\tbootstrap [-d] [-k kernel_executable] [-r ramdisk_file]"
-		 " [option...]\n");
-	exit (EXIT_FAILURE);
-}
-
-/*
- * This assembler code is copied to chip ram, and
- * then executed.
- * It copies the kernel (and ramdisk) to their
- * final resting place.
- */
-#ifndef __GNUC__
-#error GNU CC is required to compile the bootstrap program
-#endif
-asm("
-.text
-.globl _copyall, _copyallend
-_copyall:
-				| /* put variables in registers because they may */
-	lea	_kexec,a3	| /* be overwritten by kernel/ramdisk copy!! - G.U. */
-	movel	_memptr,a4
-	movel	_start_mem,a5
-	movel	_mem_size,d0
-	movel	_rd_size,d1
-	movel	_bi_size,d5
-	movel	a3@(4),d2	| kexec.a_text
-	movel	a3@(8),d3	| kexec.a_data
-	movel	a3@(12),d4	| kexec.a_bss
-
-				| /* copy kernel text and data */
-	movel	a4,a0		| src = (u_long *)memptr;
-	movel	a0,a2		| limit = (u_long *)(memptr + kexec.a_text + kexec.a_data);
-	addl	d2,a2
-	addl	d3,a2
-	movel	a5,a1		| dest = (u_long *)start_mem;
-1:	cmpl	a0,a2
-	beqs	2f		| while (src < limit)
-	moveb	a0@+,a1@+	|	*dest++ = *src++;
-	bras	1b
-2:
-
-				| /* clear kernel bss */
-	movel	a1,a0		| dest = (u_long *)(start_mem + kexec.a_text + kexec.a_data);
-	movel	a1,a2		| limit = dest + kexec.a_bss / sizeof(u_long);
-	addl	d4,a2
-1:	cmpl	a0,a2
-	beqs	2f		| while (dest < limit)
-	clrb	a0@+		|	*dest++ = 0;
-	bras	1b
-2:
-
-				| /* copy bootinfo to end of bss */
-	movel	a4,a1		| src = (u long *)memptr + kexec.a_text + kexec.a_data);
-	addl	d2,a1
-	addl	d3,a1		| dest = end of bss (already in a0)
-	movel   d5,d7		| count = sizeof bi
-	subql	#1,d7
-1:	moveb	a1@+,a0@+	| while (--count > -1)
-	dbra	d7,1b		|	*dest++ = *src++
-	
-
-				| /* copy the ramdisk to the top of memory (from back to front) */
-	movel	a5,a1		| dest = (u_long *)(start_mem + mem_size);
-	addl	d0,a1
-	movel	a4,a2		| limit = (u_long *)(memptr + kexec.a_text + kexec.a_data + sizeof bi);
-	addl	d2,a2
-	addl	d3,a2
-        addl    d5,a2
-	movel	a2,a0		| src = (u_long *)((u_long)limit + rd_size);
-	addl	d1,a0
-1:	cmpl	a0,a2
-	beqs	2f		| while (src > limit)
-	moveb	a0@-,a1@-	| 	*--dest = *--src;
-	bras	1b
-2:
-				| /* jump to start of kernel */
-	movel	a5,a0		| jump_to (START_MEM);
-	jsr	a0@
-_copyallend:
-");
-
-asm("
-.text
-.globl _maprommed
-_maprommed:
-	oriw	#0x0700,sr
-	moveml	#0x3f20,sp@-
-/* Save cache settings */
-	.long 	0x4e7a1002	/* movec cacr,d1 */
-/* Save MMU settings */
-	.long 	0x4e7a2003	/* movec tc,d2 */
-	.long 	0x4e7a3004	/* movec itt0,d3 */
-	.long 	0x4e7a4005	/* movec itt1,d4 */
-	.long 	0x4e7a5006	/* movec dtt0,d5 */
-	.long 	0x4e7a6007	/* movec dtt1,d6 */
-	moveq	#0,d0
-	movel	d0,a2
-/* Disable caches */
-	.long 	0x4e7b0002	/* movec d0,cacr */
-/* Disable MMU */
-	.long 	0x4e7b0003	/* movec d0,tc */
-	.long 	0x4e7b0004	/* movec d0,itt0 */
-	.long 	0x4e7b0005	/* movec d0,itt1 */
-	.long 	0x4e7b0006	/* movec d0,dtt0 */
-	.long 	0x4e7b0007	/* movec d0,dtt1 */
-	lea	0x07f80000,a0
-	lea	0x00f80000,a1
-	movel	a0@,d7
-	cmpl	a1@,d7
-	jnes	1f
-	movel	d7,d0
-	notl	d0
-	movel	d0,a0@
-	nop
-	cmpl	a1@,d0
-	jnes	1f
-/* MapROMmed A3640 present */
-	moveq	#-1,d0
-	movel	d0,a2
-1:	movel	d7,a0@
-/* Restore MMU settings */
-	.long 	0x4e7b2003	/* movec d2,tc */
-	.long 	0x4e7b3004	/* movec d3,itt0 */
-	.long 	0x4e7b4005	/* movec d4,itt1 */
-	.long 	0x4e7b5006	/* movec d5,dtt0 */
-	.long 	0x4e7b6007	/* movec d6,dtt1 */
-/* Restore cache settings */
-	.long 	0x4e7b1002	/* movec d1,cacr */
-	movel	a2,d0
-	moveml	sp@+,#0x04fc
-	rte
-");
-
-extern unsigned long maprommed();
+#include <linux/elf.h>
+#include <asm/setup.h>
+#include <asm/page.h>
 
+/* Amiga bootstrap include files */
+#include "linuxboot.h"
+#include "bootstrap.h"
 
-extern char copyall, copyallend;
-
-int main(int argc, char *argv[])
-{
-	int ch, debugflag = 0, kfd, rfd = -1, i;
-	long fast_total = 0;	     /* total Fast RAM in system */
-	struct MemHeader *mnp;
-	struct ConfigDev *cdp = NULL;
-	char *kernel_name = "vmlinux";
-	char *ramdisk_name = NULL;
-	char *memfile = NULL;
-	u_long memreq;
-	void (*startfunc)(void);
-	long startcodesize;
-	u_long *stack, text_offset;
-	unsigned char *rb3_reg = NULL, *piccolo_reg = NULL, *sd64_reg = NULL;
-
-	/* print the greet message */
-	puts("Linux/68k Amiga Bootstrap version 1.11");
-	puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n");
-
-	/* machine is Amiga */
-	bi.machtype = MACH_AMIGA;
-
-	/* check arguments */
-	while ((ch = getopt(argc, argv, "dk:r:m:")) != EOF)
-		switch (ch) {
-		    case 'd':
-			debugflag = 1;
-			break;
-		    case 'k':
-			kernel_name = optarg;
-			break;
-		    case 'r':
-			ramdisk_name = optarg;
-			break;
-		    case 'm':
-			memfile = optarg;
-			break;
-		    case '?':
-		    default:
-			usage();
-		}
-	argc -= optind;
-	argv += optind;
-
-	SysBase = *(struct ExecBase **)4;
-
-	/* Memory & AutoConfig based on 'unix_boot.c' by C= */
-
-	/* open Expansion Library */
-	ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library", 36);
-	if (!ExpansionBase) {
-		puts("Unable to open expansion.library V36 or greater!  Aborting...");
-		exit(EXIT_FAILURE);
-	}
-
-	/* find all of the autoconfig boards in the system */
-	cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1);
-	for (i=0; (i < NUM_AUTO) && cdp; i++) {
-		/* copy the contents of each structure into our boot info */
-		memcpy(&bi.bi_amiga.autocon[i], cdp, sizeof(struct ConfigDev));
 
-		/* count this device */
-		bi.bi_amiga.num_autocon++;
+/* Library Bases */
+extern const struct ExecBase *SysBase;
+const struct ExpansionBase *ExpansionBase;
+const struct GfxBase *GfxBase;
 
-		/* get next device */
-		cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1);
-	}
+static const char *memfile_name = NULL;
 
-	/* find out the memory in the system */
-	for (mnp = (struct MemHeader *)SysBase->MemList.l_head;
-	     (bi.num_memory < NUM_MEMINFO) && mnp->mh_Node.ln_Succ;
-	     mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ)
-	{
-		struct MemHeader mh;
-
-		/* copy the information */
-		mh = *mnp;
-
-		/* if we suspect that Kickstart is shadowed in an A3000,
-		   modify the entry to show 512K more at the top of RAM
-		   Check first for a MapROMmed A3640 board: overwriting the
-		   Kickstart image causes an infinite lock-up on reboot! */
-
-		if (mh.mh_Upper == (void *)0x07f80000)
-			if ((SysBase->AttnFlags & AFF_68040) && Supervisor(maprommed))
-				printf("A3640 MapROM detected.\n");
-			else {
-				mh.mh_Upper = (void *)0x08000000;
-				printf("A3000 shadowed Kickstart detected.\n");
-			}
-
-		/* if we suspect that Kickstart is zkicked,
-		   modify the entry to show 512K more at the bottom of RAM */
-		if (mh.mh_Lower == (void *)0x00280020) {
-		    mh.mh_Lower =  (void *)0x00200000;
-		    printf("ZKick detected.\n");
-		}
-
-		/*
-		 * If this machine has "LOCAL" memory between 0x07000000
-		 * and 0x080000000, then we'll call it an A3000.
-		 */
-		if (mh.mh_Lower >= (void *)0x07000000 &&
-		    mh.mh_Lower <  (void *)0x08000000 &&
-		    (mh.mh_Attributes & MEMF_LOCAL))
-			bi.bi_amiga.model = AMI_3000;
-
-		/* mask the memory limit values */
-		mh.mh_Upper = (void *)((u_long)mh.mh_Upper & 0xfffff000);
-		mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000);
-
-		/* if fast memory */
-		if (mh.mh_Attributes & MEMF_FAST) {
-			unsigned long size;
-
-			/* record the start */
-			bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower;
-
-			/* set the size value to the size of this block */
-			size = (u_long)mh.mh_Upper - (u_long)mh.mh_Lower;
-
-			/* mask off to a 256K increment */
-			size &= 0xfffc0000;
-
-			fast_total += size;
-
-			if (size > 0)
-				/* count this block */
-				bi.memory[bi.num_memory++].size  = size;
-
-		} else if (mh.mh_Attributes & MEMF_CHIP) {
-			/* if CHIP memory, record the size */
-			bi.bi_amiga.chip_size =
-				(u_long)mh.mh_Upper; /* - (u_long)mh.mh_Lower; */
-		}
-	}
+static int model = AMI_UNKNOWN;
 
-	CloseLibrary((struct Library *)ExpansionBase);
+static const char *ProgramName;
 
-	/*
-	 * if we have a memory file, read the memory information from it
-	 */
-	if (memfile) {
-	    FILE *fp;
-	    int i;
-
-	    if ((fp = fopen (memfile, "r")) == NULL) {
-		perror ("open memory file");
-		fprintf (stderr, "Cannot open memory file %s\n", memfile);
-		exit (EXIT_FAILURE);
-	    }
+struct linuxboot_args args;
 
-	    if (fscanf (fp, "%lu", &bi.bi_amiga.chip_size) != 1) {
-		fprintf (stderr, "memory file does not contain chip memory size\n");
-		fclose (fp);
-		exit (EXIT_FAILURE);
-	    }
-		
-	    for (i = 0; i < NUM_MEMINFO; i++) {
-		if (fscanf (fp, "%lx %lu", &bi.memory[i].addr,
-			    &bi.memory[i].size) != 2)
-		    break;
-	    }
 
-	    fclose (fp);
+    /*
+     *  Function Prototypes
+     */
 
-	    if (i != bi.num_memory && i > 0)
-		bi.num_memory = i;
-	}
+static void Usage(void) __attribute__ ((noreturn));
+int main(int argc, char *argv[]);
+static void Puts(const char *str);
+static long GetChar(void);
+static void PutChar(char c);
+static void Printf(const char *fmt, ...);
+static int Open(const char *path);
+static int Seek(int fd, int offset);
+static int Read(int fd, char *buf, int count);
+static void Close(int fd);
+static int FileSize(const char *path);
+static void Sleep(u_long micros);
+static int ModifyBootinfo(struct bootinfo *bi);
 
-	/* get info from ExecBase */
-	bi.bi_amiga.vblank = SysBase->VBlankFrequency;
-	bi.bi_amiga.psfreq = SysBase->PowerSupplyFrequency;
-	bi.bi_amiga.eclock = SysBase->EClockFrequency;
-
-	/* open graphics library */
-	GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0);
-
-	/* determine chipset */
-	bi.bi_amiga.chipset = CS_STONEAGE;
-	if(GfxBase)
-	{
-	    if(GfxBase->ChipRevBits0 & GFXG_AGA)
-	    {
-		bi.bi_amiga.chipset = CS_AGA;
-		/*
-		 *  we considered this machine to be an A3000 because of its
-		 *  local memory just beneath $8000000; now if it has AGA, it
-		 *  must be an A4000
-		 *  except the case no RAM is installed on the motherboard but
-		 *  on an additional card like FastLane Z3 or on the processor
-		 *  board itself. Gotta check this out.
-		 */
-		bi.bi_amiga.model =
-		    (bi.bi_amiga.model == AMI_3000) ? AMI_4000 : AMI_1200;
-	    }
-	    else if(GfxBase->ChipRevBits0 & GFXG_ECS)
-		bi.bi_amiga.chipset = CS_ECS;
-	    else if(GfxBase->ChipRevBits0 & GFXG_OCS)
-		bi.bi_amiga.chipset = CS_OCS;
-	}
 
-	/* Display amiga model */
-	switch (bi.bi_amiga.model) {
-	    case AMI_UNKNOWN:
-		break;
-	    case AMI_500:
-		printf ("Amiga 500 ");
-		break;
-	    case AMI_2000:
-		printf ("Amiga 2000 ");
-		break;
-	    case AMI_3000:
-		printf ("Amiga 3000 ");
-		break;
-	    case AMI_4000:
-		printf ("Amiga 4000 ");
-		break;
-	    case AMI_1200:		/* this implies an upgraded model   */
-		printf ("Amiga 1200 "); /* equipped with at least 68030 !!! */
-		break;
-	}
-
-	/* display and set the CPU <type */
-	printf("CPU: ");
-	if (SysBase->AttnFlags & AFF_68040) {
-		printf("68040");
-		bi.cputype = CPU_68040;
-		if (SysBase->AttnFlags & AFF_FPU40) {
-			printf(" with internal FPU");
-			bi.cputype |= FPU_68040;
-		} else
-			printf(" without FPU");
-	} else {
-		if (SysBase->AttnFlags & AFF_68030) {
-			printf("68030");
-			bi.cputype = CPU_68030;
-		} else if (SysBase->AttnFlags & AFF_68020) {
-			printf("68020 (Do you have an MMU?)");
-			bi.cputype = CPU_68020;
-		} else {
-			puts("Insufficient for Linux.  Aborting...");
-			printf("SysBase->AttnFlags = %#x\n", SysBase->AttnFlags);
-			exit (EXIT_FAILURE);
-		}
-		if (SysBase->AttnFlags & AFF_68882) {
-			printf(" with 68882 FPU");
-			bi.cputype |= FPU_68882;
-		} else if (SysBase->AttnFlags & AFF_68881) {
-			printf(" with 68881 FPU");
-			bi.cputype |= FPU_68881;
-		} else
-			printf(" without FPU");
-	}
-
-	switch(bi.bi_amiga.chipset)
-	{
-	    case CS_STONEAGE:
-		printf(", old or unknown chipset");
-		break;
-	    case CS_OCS:
-		printf(", OCS");
-		break;
-	    case CS_ECS:
-		printf(", ECS");
-		break;
-	    case CS_AGA:
-		printf(", AGA chipset");
-		break;
-	}
-
-	putchar ('\n');
-	putchar ('\n');
-
-	/*
-	 * Copy command line options into the kernel command line.
-	 */
-	i = 0;
-	while (argc--) {
-		if ((i+strlen(*argv)+1) < CL_SIZE) {
-			i += strlen(*argv) + 1;
-			if (bi.command_line[0])
-				strcat (bi.command_line, " ");
-			strcat (bi.command_line, *argv++);
-		}
-	}
-	printf ("Command line is '%s'\n", bi.command_line);
-
-	/* display the clock statistics */
-	printf("Vertical Blank Frequency: %dHz\nPower Supply Frequency: %dHz\n",
-	       bi.bi_amiga.vblank, bi.bi_amiga.psfreq);
-	printf("EClock Frequency: %7.5fKHz\n\n",
-	       (float)bi.bi_amiga.eclock / 1000);
-
-	/* display autoconfig devices */
-	if (bi.bi_amiga.num_autocon) {
-		printf("Found %d AutoConfig Device%s", bi.bi_amiga.num_autocon,
-		       (bi.bi_amiga.num_autocon > 1)?"s\n":"\n");
-		for (i=0; i<bi.bi_amiga.num_autocon; i++)
-		{
-			printf("Device %d: addr = %08lx\n", i,
-			       (u_long)bi.bi_amiga.autocon[i].cd_BoardAddr);
-			/* check for a Rainbow 3 and prepare to reset it if there is one */
-			if ( (bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer == MANUF_HELFRICH1) &&
-				 (bi.bi_amiga.autocon[i].cd_Rom.er_Product == PROD_RAINBOW3) )
-			{
-				printf("(Found a Rainbow 3 board - will reset it at kernel boot time)\n");
-				rb3_reg = (unsigned char *)(bi.bi_amiga.autocon[i].cd_BoardAddr + 0x01002000);
-			}
-
-			/* check for a Piccolo and prepare to reset it if there is one */
-			if ( (bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer == MANUF_HELFRICH2) &&
-				 (bi.bi_amiga.autocon[i].cd_Rom.er_Product == PROD_PICCOLO_REG) )
-			{
-				printf("(Found a Piccolo board - will reset it at kernel boot time)\n");
-				piccolo_reg = (unsigned char *)(bi.bi_amiga.autocon[i].cd_BoardAddr + 0x8000);
-			}
-
-			/* check for a SD64 and prepare to reset it if there is one */
-			if ( (bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer == MANUF_HELFRICH2) &&
-				 (bi.bi_amiga.autocon[i].cd_Rom.er_Product == PROD_SD64_REG) )
-			{
-				printf("(Found a SD64 board - will reset it at kernel boot time)\n");
-				sd64_reg = (unsigned char *)(bi.bi_amiga.autocon[i].cd_BoardAddr + 0x8000);
-			}
-
-			/* what this code lacks - what if there are several boards of  */
-			/* the same brand ? In that case I should reset them one after */
-			/* the other, which is currently not done - a rare case...FN   */
-			/* ok, MY amiga currently hosts all three of the above boards ;-) */
-		}
-	} else
-		puts("No AutoConfig Devices Found");
-
-	/* display memory */
-	if (bi.num_memory) {
-		printf("\n%d Block%sof Memory Found\n", bi.num_memory,
-		       (bi.num_memory > 1)?"s ":" ");
-		for (i=0; i<bi.num_memory; i++) {
-			printf("Block %d: %08lx to %08lx (%ldKB)\n",
-			       i, bi.memory[i].addr,
-			       bi.memory[i].addr + bi.memory[i].size,
-			       bi.memory[i].size >> 10);
-		}
-	} else {
-		puts("No memory found?!  Aborting...");
-		exit(10);
-	}
+static void Usage(void)
+{
+    fprintf(stderr,
+	    "Linux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n\n"
+	    "Usage: %s [options] [kernel command line]\n\n"
+	    "Valid options are:\n"
+	    "    -h, --help           Display this usage information\n"
+	    "    -k, --kernel file    Use kernel image `file' (default is `vmlinux')\n"
+	    "    -r, --ramdisk file   Use ramdisk image `file'\n"
+	    "    -d, --debug          Enable debug mode\n"
+	    "    -m, --memfile file   Use memory file `file'\n"
+	    "    -v, --keep-video     Don't reset the video mode\n"
+	    "    -t, --model id       Set the Amiga model to `id'\n\n",
+	    ProgramName);
+    exit(EXIT_FAILURE);
+}
 
-	/* display chip memory size */
-	printf ("%ldK of CHIP memory\n", bi.bi_amiga.chip_size >> 10);
 
-	start_mem = bi.memory[0].addr;
-	mem_size = bi.memory[0].size;
+int main(int argc, char *argv[])
+{
+    int i;
+    int debugflag = 0, keep_video = 0;
+    const char *kernel_name = NULL;
+    const char *ramdisk_name = NULL;
+    char commandline[CL_SIZE] = "";
+
+    ProgramName = argv[0];
+    while (--argc) {
+	argv++;
+	if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help"))
+	    Usage();
+	else if (!strcmp(argv[0], "-k") || !strcmp(argv[0], "--kernel"))
+            if (--argc && !kernel_name) {
+                kernel_name = argv[1];
+                argv++;
+            } else
+                Usage();
+	else if (!strcmp(argv[0], "-r") || !strcmp(argv[0], "--ramdisk"))
+            if (--argc && !ramdisk_name) {
+                ramdisk_name = argv[1];
+                argv++;
+            } else
+                Usage();
+	else if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "--debug"))
+	    debugflag = 1;
+	else if (!strcmp(argv[0], "-m") || !strcmp(argv[0], "--memfile"))
+            if (--argc && !memfile_name) {
+                memfile_name = argv[1];
+                argv++;
+            } else
+                Usage();
+	else if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--keep-video"))
+	    keep_video = 1;
+	else if (!strcmp(argv[0], "-t") || !strcmp(argv[0], "--model"))
+            if (--argc && !model) {
+                model = atoi(argv[1]);
+                argv++;
+            } else
+                Usage();
+	else
+	    break;
+    }
+    if (!kernel_name)
+	kernel_name = "vmlinux";
+
+    SysBase = *(struct ExecBase **)4;
+
+    /* open Expansion Library */
+    ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",
+							36);
+    if (!ExpansionBase) {
+	fputs("Unable to open expansion.library V36 or greater!  Aborting...\n",
+	      stderr);
+	exit(EXIT_FAILURE);
+   }
+
+    /* open Graphics Library */
+    GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0);
+    if (!GfxBase) {
+	fputs("Unable to open graphics.library!  Aborting...\n", stderr);
+	exit(EXIT_FAILURE);
+    }
+
+    /*
+     *	Join command line options
+     */
+    i = 0;
+    while (argc--) {
+	if ((i+strlen(*argv)+1) < CL_SIZE) {
+	    i += strlen(*argv) + 1;
+	    if (commandline[0])
+		strcat(commandline, " ");
+	    strcat(commandline, *argv++);
+	}
+    }
+
+    args.kernelname = kernel_name;
+    args.ramdiskname = ramdisk_name;
+    args.commandline = commandline;
+    args.debugflag = debugflag;
+    args.keep_video = keep_video;
+    args.reset_boards = 1;
+    args.puts = Puts;
+    args.getchar = GetChar;
+    args.putchar = PutChar;
+    args.printf = Printf;
+    args.open = Open;
+    args.seek = Seek;
+    args.read = Read;
+    args.close = Close;
+    args.filesize = FileSize;
+    args.sleep = Sleep;
+    args.modify_bootinfo = ModifyBootinfo;
 
-	/* tell us where the kernel will go */
-	printf("\nThe kernel will be located at %08lx\n", start_mem);
+    /* Do The Right Stuff */
+    linuxboot(&args);
 
-	/* verify that there is enough Chip RAM */
-	if (bi.bi_amiga.chip_size < 512*1024) {
-		puts("\nNot enough Chip RAM in this system.  Aborting...");
-		exit(10);
-	}
+    CloseLibrary((struct Library *)GfxBase);
+    CloseLibrary((struct Library *)ExpansionBase);
 
-	/* verify that there is enough Fast RAM */
-	if (fast_total < 2*1024*1024) {
-		puts("\nNot enough Fast RAM in this system.  Aborting...");
-		exit(10);
-	}
+    /* if we ever get here, something went wrong */
+    exit(EXIT_FAILURE);
+}
 
-	/* open kernel executable and read exec header */
-	if ((kfd = open (kernel_name, O_RDONLY)) == -1) {
-		fprintf (stderr, "Unable to open kernel file %s\n", kernel_name);
-		exit (EXIT_FAILURE);
-	}
 
-	if (read (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
-		fprintf (stderr, "Unable to read exec header from %s\n",
-			 kernel_name);
-		exit (EXIT_FAILURE);
-	}
+    /*
+     *  Routines needed by linuxboot
+     */
 
-	switch (N_MAGIC(kexec)) {
-	  case ZMAGIC:
-	    text_offset = N_TXTOFF(kexec);
-	    break;
-	  case QMAGIC:
-	    text_offset = sizeof(kexec);
-	    /* the text size includes the exec header; remove this */
-	    kexec.a_text -= sizeof(kexec);
-	    break;
-	  default:
-	    fprintf (stderr, "Wrong magic number %lo in kernel header\n",
-		     N_MAGIC(kexec));
-	    exit (EXIT_FAILURE);
-	}
+static void Puts(const char *str)
+{
+    fputs(str, stderr);
+}
 
-	/* Load the kernel at one page after start of mem */
-	start_mem += PAGE_SIZE;
-	mem_size -= PAGE_SIZE;
-	/* Align bss size to multiple of four */
-	kexec.a_bss = (kexec.a_bss + 3) & ~3;
-
-	if (ramdisk_name) {
-		if ((rfd = open (ramdisk_name, O_RDONLY)) == -1) {
-			fprintf (stderr, "Unable to open ramdisk file %s\n",
-				 ramdisk_name);
-			exit (EXIT_FAILURE);
-		}
-		/* record ramdisk size */
-		bi.ramdisk_size = (lseek (rfd, 0, L_XTND) + 1023) >> 10;
-	} else
-		bi.ramdisk_size = 0;
-
-	rd_size = bi.ramdisk_size << 10;
-	bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size;
-
-	memreq = kexec.a_text + kexec.a_data + sizeof(bi) + rd_size;
-	if (!(memptr = (char *)AllocMem (memreq, MEMF_FAST | MEMF_CLEAR))) {
-		fprintf (stderr, "Unable to allocate memory\n");
-		exit (EXIT_FAILURE);
-	}
+static long GetChar(void)
+{
+    return(getchar());
+}
 
-	if (lseek (kfd, text_offset, L_SET) == -1) {
-		fprintf (stderr, "Failed to seek to text\n");
-		FreeMem ((void *)memptr, memreq);
-		exit (EXIT_FAILURE);
-	}
-	if (read (kfd, memptr, kexec.a_text) != kexec.a_text) {
-		fprintf (stderr, "Failed to read text\n");
-		FreeMem ((void *)memptr, memreq);
-		exit (EXIT_FAILURE);
-	}
+static void PutChar(char c)
+{
+    fputc(c, stderr);
+}
 
-	/* data follows immediately after text */
-	if (read (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data) {
-		fprintf (stderr, "Failed to read data\n");
-		FreeMem ((void *)memptr, memreq);
-		exit (EXIT_FAILURE);
-	}
-	close (kfd);
+static void Printf(const char *fmt, ...)
+{
+    va_list args;
 
-	/* copy the boot_info struct to the end of the kernel image */
-	memcpy ((void *)(memptr + kexec.a_text + kexec.a_data), &bi,
-		sizeof(bi));
-
-	if (rfd != -1) {
-		if (lseek (rfd, 0, L_SET) == -1) {
-			fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
-			FreeMem ((void *)memptr, memreq);
-			exit (EXIT_FAILURE);
-		}
-		if (read (rfd, memptr + kexec.a_text + kexec.a_data 
-			  + sizeof(bi), rd_size) != rd_size) {
-			fprintf (stderr, "Failed to read ramdisk file\n");
-			FreeMem ((void *)memptr, memreq);
-			exit (EXIT_FAILURE);
-		}
-		close (rfd);
-	}
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+}
 
-	/* allocate temporary chip ram stack */
-	stack = (u_long *)AllocMem( TEMP_STACKSIZE, MEMF_CHIP|MEMF_CLEAR);
-	if (!stack) {
-		fprintf (stderr, "Unable to allocate memory for stack\n");
-		FreeMem ((void *)memptr, memreq);
-		exit (EXIT_FAILURE);
-	}
+static int Open(const char *path)
+{
+    return(open(path, O_RDONLY));
+}
 
-	/* allocate chip ram for copy of startup code */
-	startcodesize = &copyallend - &copyall;
-	startfunc = (void (*)(void))AllocMem( startcodesize, MEMF_CHIP);
-	if (!startfunc) {
-		fprintf (stderr, "Unable to allocate memory for code\n");
-		FreeMem ((void *)memptr, memreq);
-		FreeMem ((void *)stack, TEMP_STACKSIZE);
-		exit (EXIT_FAILURE);
-	}
+static int Seek(int fd, int offset)
+{
+    return(lseek(fd, offset, SEEK_SET));
+}
 
-	/* copy startup code to CHIP RAM */
-	memcpy (startfunc, &copyall, startcodesize);
 
-	if (debugflag) {
-		if (bi.ramdisk_size)
-			printf ("RAM disk at %#lx, size is %ldK\n",
-				(u_long)memptr + kexec.a_text + kexec.a_data,
-				bi.ramdisk_size);
-
-		printf ("\nKernel text at %#lx, code size %x\n",
-			start_mem, kexec.a_text);
-		printf ("Kernel data at %#lx, data size %x\n",
-			start_mem + kexec.a_text, kexec.a_data );
-		printf ("Kernel bss  at %#lx, bss  size %x\n",
-			start_mem + kexec.a_text + kexec.a_data,
-			kexec.a_bss );
-		printf ("boot info at %#lx\n", start_mem + kexec.a_text
-			+ kexec.a_data + kexec.a_bss);
-
-		printf ("\nKernel entry is %#x\n", kexec.a_entry );
-
-		printf ("ramdisk dest top is %#lx\n", start_mem + mem_size);
-		printf ("ramdisk lower limit is %#lx\n",
-			(u_long)(memptr + kexec.a_text + kexec.a_data));
-		printf ("ramdisk src top is %#lx\n",
-			(u_long)(memptr + kexec.a_text + kexec.a_data)
-			+ rd_size);
-
-		printf ("Type a key to continue the Linux boot...");
-		fflush (stdout);
-		getchar();
-	}
+static int Read(int fd, char *buf, int count)
+{
+    return(read(fd, buf, count));
+}
 
-	/* wait for things to settle down */
-	sleep(2);
+static void Close(int fd)
+{
+    close(fd);
+}
 
-	/* FN: If a Rainbow III board is present, reset it to disable */
-	/* its (possibly activated) vertical blank interrupts as the */
-	/* kernel is not yet prepared to handle them (level 6). */
-	if (rb3_reg != NULL)
-	{
-		/* set RESET bit in special function register */
-		*rb3_reg = 0x01;
-		/* actually, only a few cycles delay are required... */
-		sleep(1);
-		/* clear reset bit */
-		*rb3_reg = 0x00;
-	}
+static int FileSize(const char *path)
+{
+    int fd, size = -1;
 
-	/* the same stuff as above, for the Piccolo board. */
-	/* this also has the side effect of resetting the board's */
-	/* output selection logic to use the Amiga's display in single */
-	/* monitor systems - which is currently what we want. */
-	if (piccolo_reg != NULL)
-	{
-		/* set RESET bit in special function register */
-		*piccolo_reg = 0x01;
-		/* actually, only a few cycles delay are required... */
-		sleep(1);
-		/* clear reset bit */
-		*piccolo_reg = 0x51;
-	}
+    if ((fd = open(path, O_RDONLY)) != -1) {
+        size = lseek(fd, 0, SEEK_END);
+        close(fd);
+    }
+    return(size);
+}
 
-	/* the same stuff as above, for the SD64 board. */
-	/* just as on the Piccolo, this also resets the monitor switch */
-	if (sd64_reg != NULL)
-	{
-		/* set RESET bit in special function register */
-		*sd64_reg = 0x1f;
-		/* actually, only a few cycles delay are required... */
-		sleep(1);
-	/* clear reset bit AND switch monitor bit (0x20) */
-	*sd64_reg = 0x4f;
-	}
+static void Sleep(u_long micros)
+{
+    struct MsgPort *TimerPort;
+    struct timerequest *TimerRequest;
 
-	if (GfxBase) {
-		/* set graphics mode to a nice normal one */
-		LoadView (NULL);
-		CloseLibrary ((struct Library *)GfxBase);
+    if ((TimerPort = CreateMsgPort())) {
+	if ((TimerRequest = CreateIORequest(TimerPort,
+					    sizeof(struct timerequest)))) {
+	    if (!OpenDevice("timer.device", UNIT_VBLANK,
+			    (struct IORequest *)TimerRequest, 0)) {
+		TimerRequest->io_Command = TR_ADDREQUEST;
+		TimerRequest->io_Flags = IOF_QUICK;
+		TimerRequest->tv_secs = micros/1000000;
+		TimerRequest->tv_micro = micros%1000000;
+		DoIO((struct IORequest *)TimerRequest);
+		CloseDevice((struct IORequest *)TimerRequest);
+	    }
+	    DeleteIORequest(TimerRequest);
 	}
+	DeleteMsgPort(TimerPort);
+    }
+}
 
-	Disable();
-
-	/* Turn off all DMA */
-	custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
-	/* turn off caches */
-	CacheControl (0L, ~0L);
-
-	/* Go into supervisor state */
-	SuperState ();
-
-	/* setup stack */
-	change_stack ((char *) stack + TEMP_STACKSIZE);
-
-	/* turn off any mmu translation */
-	disable_mmu ();
 
-	/* execute the copy-and-go code (from CHIP RAM) */
-	startfunc();
+static int ModifyBootinfo(struct bootinfo *bi)
+{
+   /*
+    * if we have a memory file, read the memory information from it
+    */
+   if (memfile_name) {
+      FILE *fp;
+      int i;
+
+      if ((fp = fopen(memfile_name, "r")) == NULL) {
+         perror("open memory file");
+         fprintf(stderr, "Cannot open memory file %s\n", memfile_name);
+         return(FALSE);
+      }
+
+      if (fscanf(fp, "%lu", &bi->bi_amiga.chip_size) != 1) {
+         fprintf(stderr, "memory file does not contain chip memory size\n");
+         fclose(fp);
+         return(FALSE);
+      }
+                
+      for (i = 0; i < NUM_MEMINFO; i++) {
+         if (fscanf(fp, "%lx %lu", &bi->memory[i].addr, &bi->memory[i].size)
+	     != 2)
+            break;
+      }
+
+      fclose(fp);
+
+      if (i != bi->num_memory && i > 0)
+         bi->num_memory = i;
+   }
+
+   /*
+    * change the Amiga model, if necessary
+    */
+   if (model != AMI_UNKNOWN)
+      bi->bi_amiga.model = model;
 
-	/* NOTREACHED */
+   return(TRUE);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov