patch-2.1.17 linux/arch/m68k/boot/amiga/linuxboot.c

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

diff -u --recursive --new-file v2.1.16/linux/arch/m68k/boot/amiga/linuxboot.c linux/arch/m68k/boot/amiga/linuxboot.c
@@ -28,6 +28,8 @@
 #endif /* __GNUC__ */
 
 
+#define BOOTINFO_COMPAT_1_0	/* bootinfo interface version 1.0 compatible */
+
 #include <stddef.h>
 #include <string.h>
 #include <errno.h>
@@ -36,8 +38,7 @@
 #include <linux/a.out.h>
 #include <linux/elf.h>
 #include <linux/linkage.h>
-#include <asm/setup.h>
-#include <asm/amigatypes.h>
+#include <asm/bootinfo.h>
 #include <asm/amigahw.h>
 #include <asm/page.h>
 
@@ -48,22 +49,37 @@
 #define custom ((*(volatile struct CUSTOM *)(CUSTOM_PHYSADDR)))
 
 /* temporary stack size */
-#define TEMP_STACKSIZE  (256)
+#define TEMP_STACKSIZE	(256)
+
+#define DEFAULT_BAUD	(9600)
 
 extern char copyall, copyallend;
 
 static struct exec kexec;
 static Elf32_Ehdr kexec_elf;
-static struct bootinfo bi;
-
 static const struct linuxboot_args *linuxboot_args;
 
+/* Bootinfo */
+static struct amiga_bootinfo bi;
+
+#ifdef BOOTINFO_COMPAT_1_0
+static struct compat_bootinfo compat_bootinfo;
+#endif /* BOOTINFO_COMPAT_1_0 */
+
+#define MAX_BI_SIZE	(4096)
+static u_long bi_size;
+static union {
+    struct bi_record record;
+    u_char fake[MAX_BI_SIZE];
+} bi_union;
+
 #define kernelname	linuxboot_args->kernelname
 #define ramdiskname	linuxboot_args->ramdiskname
 #define commandline	linuxboot_args->commandline
 #define debugflag	linuxboot_args->debugflag
 #define keep_video	linuxboot_args->keep_video
 #define reset_boards	linuxboot_args->reset_boards
+#define baud		linuxboot_args->baud
 
 #define Puts		linuxboot_args->puts
 #define GetChar		linuxboot_args->getchar
@@ -83,15 +99,22 @@
      */
 
 static u_long get_chipset(void);
-static u_long get_cpu(void);
+static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu);
 static u_long get_model(u_long chipset);
 static int probe_resident(const char *name);
 static int probe_resource(const char *name);
+static int create_bootinfo(void);
+#ifdef BOOTINFO_COMPAT_1_0
+static int create_compat_bootinfo(void);
+#endif /* BOOTINFO_COMPAT_1_0 */
+static int add_bi_record(u_short tag, u_short size, const void *data);
+static int add_bi_string(u_short tag, const u_char *s);
 static int check_bootinfo_version(const char *memptr);
 static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
 			 u_long start_mem, u_long mem_size, u_long rd_size,
 			 u_long kernel_size) __attribute__ ((noreturn));
 asmlinkage u_long maprommed(void);
+asmlinkage u_long check346(void);
 
 
     /*
@@ -126,7 +149,7 @@
 };
 #define NUM_BOARDRESET	sizeof(boardresetdb)/sizeof(*boardresetdb)
 
-static void (*boardresetfuncs[NUM_AUTO])(const struct ConfigDev *cd);
+static void (*boardresetfuncs[ZORRO_NUM_AUTO])(const struct ConfigDev *cd);
 
 
 const char *amiga_models[] = {
@@ -159,11 +182,13 @@
     u_long *stack = NULL;
     u_long fast_total, model_mask, startcodesize, start_mem, mem_size, rd_size;
     u_long kernel_size;
+    u_int realbaud;
     u_long memreq = 0, text_offset = 0;
     Elf32_Phdr *kernel_phdrs = NULL;
     void (*startfunc)(void);
     u_short manuf;
     u_char prod;
+    void *bi_ptr;
 
     linuxboot_args = args;
 
@@ -171,30 +196,31 @@
     Puts("\nLinux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n");
     Puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n\n");
 
+    memset(&bi, 0, sizeof(bi));
+
     /* machine is Amiga */
     bi.machtype = MACH_AMIGA;
 
     /* determine chipset */
-    bi.bi_amiga.chipset = get_chipset();
+    bi.chipset = get_chipset();
 
-    /* determine CPU type */
-    bi.cputype = get_cpu();
+    /* determine CPU, FPU and MMU type */
+    get_processor(&bi.cputype, &bi.fputype, &bi.mmutype);
 
     /* determine Amiga model */
-    bi.bi_amiga.model = get_model(bi.bi_amiga.chipset);
-    model_mask = (bi.bi_amiga.model != AMI_UNKNOWN) ? 1<<bi.bi_amiga.model : 0;
+    bi.model = get_model(bi.chipset);
+    model_mask = (bi.model != AMI_UNKNOWN) ? 1<<bi.model : 0;
 
     /* Memory & AutoConfig based on 'unix_boot.c' by C= */
 
     /* find all of the autoconfig boards in the system */
-    bi.bi_amiga.num_autocon = 0;
+    bi.num_autocon = 0;
     for (i = 0; (cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1)); i++) {
-	if (bi.bi_amiga.num_autocon < NUM_AUTO) {
+	if (bi.num_autocon < ZORRO_NUM_AUTO) {
 	    /* copy the contents of each structure into our boot info */
-	    memcpy(&bi.bi_amiga.autocon[bi.bi_amiga.num_autocon], cdp,
-		   sizeof(struct ConfigDev));
+	    memcpy(&bi.autocon[bi.num_autocon], cdp, sizeof(struct ConfigDev));
 	    /* count this device */
-	    bi.bi_amiga.num_autocon++;
+	    bi.num_autocon++;
 	} else
 	    Printf("Warning: too many AutoConfig devices. Ignoring device at "
 		   "0x%08lx\n", cdp->cd_BoardAddr);
@@ -257,13 +283,17 @@
 			   (u_long)mh.mh_Lower);
 	} else if (mh.mh_Attributes & MEMF_CHIP)
 	    /* if CHIP memory, record the size */
-	    bi.bi_amiga.chip_size = (u_long)mh.mh_Upper;
+	    bi.chip_size = (u_long)mh.mh_Upper;
     }
 
     /* get info from ExecBase */
-    bi.bi_amiga.vblank = SysBase->VBlankFrequency;
-    bi.bi_amiga.psfreq = SysBase->PowerSupplyFrequency;
-    bi.bi_amiga.eclock = SysBase->ex_EClockFrequency;
+    bi.vblank = SysBase->VBlankFrequency;
+    bi.psfreq = SysBase->PowerSupplyFrequency;
+    bi.eclock = SysBase->ex_EClockFrequency;
+
+    /* serial port */
+    realbaud = baud ? baud : DEFAULT_BAUD;
+    bi.serper = (5*bi.eclock+realbaud/2)/realbaud-1;
 
     /* copy command line options into the kernel command line */
     strncpy(bi.command_line, commandline, CL_SIZE);
@@ -274,17 +304,15 @@
     if (ModifyBootinfo && !ModifyBootinfo(&bi))
 	goto Fail;
 
-
     /* display Amiga model */
-    if (bi.bi_amiga.model >= first_amiga_model &&
-	bi.bi_amiga.model <= last_amiga_model)
-	Printf("%s ", amiga_models[bi.bi_amiga.model-first_amiga_model]);
+    if (bi.model >= first_amiga_model && bi.model <= last_amiga_model)
+	Printf("%s ", amiga_models[bi.model-first_amiga_model]);
     else
 	Puts("Amiga ");
 
     /* display the CPU type */
     Puts("CPU: ");
-    switch (bi.cputype & CPU_MASK) {
+    switch (bi.cputype) {
 	case CPU_68020:
 	    Puts("68020 (Do you have an MMU?)");
 	    break;
@@ -302,7 +330,7 @@
 	    Printf("SysBase->AttnFlags = 0x%08lx\n", SysBase->AttnFlags);
 	    goto Fail;
     }
-    switch (bi.cputype & ~CPU_MASK) {
+    switch (bi.fputype) {
 	case FPU_68881:
 	    Puts(" with 68881 FPU");
 	    break;
@@ -319,7 +347,7 @@
     }
 
     /* display the chipset */
-    switch(bi.bi_amiga.chipset) {
+    switch(bi.chipset) {
 	case CS_STONEAGE:
 	    Puts(", old or unknown chipset");
 	    break;
@@ -340,21 +368,21 @@
     Printf("Command line is '%s'\n", bi.command_line);
 
     /* display the clock statistics */
-    Printf("Vertical Blank Frequency: %ldHz\n", bi.bi_amiga.vblank);
-    Printf("Power Supply Frequency: %ldHz\n", bi.bi_amiga.psfreq);
-    Printf("EClock Frequency: %ldHz\n\n", bi.bi_amiga.eclock);
+    Printf("Vertical Blank Frequency: %ldHz\n", bi.vblank);
+    Printf("Power Supply Frequency: %ldHz\n", bi.psfreq);
+    Printf("EClock Frequency: %ldHz\n\n", bi.eclock);
 
     /* display autoconfig devices */
-    if (bi.bi_amiga.num_autocon) {
-	Printf("Found %ld AutoConfig Device%s\n", bi.bi_amiga.num_autocon,
-	       bi.bi_amiga.num_autocon > 1 ? "s" : "");
-	for (i = 0; i < bi.bi_amiga.num_autocon; i++) {
+    if (bi.num_autocon) {
+	Printf("Found %ld AutoConfig Device%s\n", bi.num_autocon,
+	       bi.num_autocon > 1 ? "s" : "");
+	for (i = 0; i < bi.num_autocon; i++) {
 	    Printf("Device %ld: addr = 0x%08lx", i,
-		   (u_long)bi.bi_amiga.autocon[i].cd_BoardAddr);
+		   (u_long)bi.autocon[i].cd_BoardAddr);
 	    boardresetfuncs[i] = NULL;
 	    if (reset_boards) {
-		manuf = bi.bi_amiga.autocon[i].cd_Rom.er_Manufacturer;
-		prod = bi.bi_amiga.autocon[i].cd_Rom.er_Product;
+		manuf = bi.autocon[i].cd_Rom.er_Manufacturer;
+		prod = bi.autocon[i].cd_Rom.er_Product;
 		for (j = 0; j < NUM_BOARDRESET; j++)
 		    if ((manuf == boardresetdb[j].manuf) &&
 			(prod == boardresetdb[j].prod)) {
@@ -383,7 +411,7 @@
     }
 
     /* display chip memory size */
-    Printf("%ldK of CHIP memory\n", bi.bi_amiga.chip_size>>10);
+    Printf("%ldK of CHIP memory\n", bi.chip_size>>10);
 
     start_mem = bi.memory[0].addr;
     mem_size = bi.memory[0].size;
@@ -392,7 +420,7 @@
     Printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
 
     /* verify that there is enough Chip RAM */
-    if (bi.bi_amiga.chip_size < 512*1024) {
+    if (bi.chip_size < 512*1024) {
 	Puts("Not enough Chip RAM in this system.  Aborting...\n");
 	goto Fail;
     }
@@ -414,11 +442,15 @@
 	    goto Fail;
 	}
 	/* record ramdisk size */
-	bi.ramdisk_size = (size+1023)>>10;
+	bi.ramdisk.size = size;
     } else
-	bi.ramdisk_size = 0;
-    rd_size = bi.ramdisk_size<<10;
-    bi.ramdisk_addr = start_mem+mem_size-rd_size;
+	bi.ramdisk.size = 0;
+    rd_size = bi.ramdisk.size;
+    bi.ramdisk.addr = (u_long)start_mem+mem_size-rd_size;
+
+    /* create the bootinfo structure */
+    if (!create_bootinfo())
+	goto Fail;
 
     /* open kernel executable and read exec header */
     if ((kfd = Open(kernelname)) == -1) {
@@ -511,7 +543,11 @@
 	kernel_size = max_addr-min_addr;
     } else
 	kernel_size = kexec.a_text+kexec.a_data+kexec.a_bss;
-    memreq = kernel_size+sizeof(struct bootinfo)+rd_size;
+    memreq = kernel_size+bi_size+rd_size;
+#ifdef BOOTINFO_COMPAT_1_0
+    if (sizeof(compat_bootinfo) > bi_size)
+	memreq = kernel_size+sizeof(compat_bootinfo)+rd_size;
+#endif /* BOOTINFO_COMPAT_1_0 */
     if (!(memptr = (char *)AllocMem(memreq, MEMF_FAST | MEMF_PUBLIC |
 					    MEMF_CLEAR))) {
 	Puts("Unable to allocate memory\n");
@@ -533,16 +569,16 @@
 	}
     else {
 	if (Seek(kfd, text_offset) == -1) {
-	    Printf("Failed to seek to text\n");
+	    Puts("Failed to seek to text\n");
 	    goto Fail;
 	}
 	if (Read(kfd, memptr, kexec.a_text) != kexec.a_text) {
-	    Printf("Failed to read text\n");
+	    Puts("Failed to read text\n");
 	    goto Fail;
 	}
 	/* data follows immediately after text */
 	if (Read(kfd, memptr+kexec.a_text, kexec.a_data) != kexec.a_data) {
-	    Printf("Failed to read data\n");
+	    Puts("Failed to read data\n");
 	    goto Fail;
 	}
     }
@@ -550,19 +586,34 @@
     kfd = -1;
 
     /* Check kernel's bootinfo version */
-    if (!check_bootinfo_version(memptr))
-	goto Fail;
+    switch (check_bootinfo_version(memptr)) {
+	case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION):
+	    bi_ptr = &bi_union.record;
+	    break;
+
+#ifdef BOOTINFO_COMPAT_1_0
+	case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION):
+	    if (!create_compat_bootinfo())
+		goto Fail;
+	    bi_ptr = &compat_bootinfo;
+	    bi_size = sizeof(compat_bootinfo);
+	    break;
+#endif /* BOOTINFO_COMPAT_1_0 */
+
+	default:
+	    goto Fail;
+    }
 
     /* copy the bootinfo to the end of the kernel image */
-    memcpy((void *)(memptr+kernel_size), &bi, sizeof(struct bootinfo));
+    memcpy((void *)(memptr+kernel_size), bi_ptr, bi_size);
 
     if (ramdiskname) {
 	if ((rfd = Open(ramdiskname)) == -1) {
 	    Printf("Unable to open ramdisk file `%s'\n", ramdiskname);
 	    goto Fail;
 	}
-	if (Read(rfd, memptr+kernel_size+sizeof(bi), rd_size) != rd_size) {
-	    Printf("Failed to read ramdisk file\n");
+	if (Read(rfd, memptr+kernel_size+bi_size, rd_size) != rd_size) {
+	    Puts("Failed to read ramdisk file\n");
 	    goto Fail;
 	}
 	Close(rfd);
@@ -587,9 +638,9 @@
     memcpy(startfunc, &copyall, startcodesize);
 
     if (debugflag) {
-	if (bi.ramdisk_size)
+	if (bi.ramdisk.size)
 	    Printf("RAM disk at 0x%08lx, size is %ldK\n",
-		   (u_long)memptr+kernel_size, bi.ramdisk_size);
+		   (u_long)memptr+kernel_size, bi.ramdisk.size>>10);
 
 	if (elf_kernel) {
 	    PutChar('\n');
@@ -611,9 +662,10 @@
 							   kexec.a_entry);
 
 	Printf("ramdisk dest top is 0x%08lx\n", start_mem+mem_size);
-	Printf("ramdisk lower limit is 0x%08lx\n", (u_long)memptr+kernel_size);
+	Printf("ramdisk lower limit is 0x%08lx\n",
+	       (u_long)(memptr+kernel_size));
 	Printf("ramdisk src top is 0x%08lx\n",
-	       (u_long)memptr+kernel_size+rd_size);
+	       (u_long)(memptr+kernel_size)+rd_size);
 
 	Puts("\nType a key to continue the Linux/m68k boot...");
 	GetChar();
@@ -631,9 +683,9 @@
 
     /* reset nasty Zorro boards */
     if (reset_boards)
-	for (i = 0; i < bi.bi_amiga.num_autocon; i++)
+	for (i = 0; i < bi.num_autocon; i++)
 	    if (boardresetfuncs[i])
-		boardresetfuncs[i](&bi.bi_amiga.autocon[i]);
+		boardresetfuncs[i](&bi.autocon[i]);
 
     /* Turn off all DMA */
     custom.dmacon = DMAF_ALL | DMAF_MASTER;
@@ -696,32 +748,49 @@
      *	Determine the CPU Type
      */
 
-static u_long get_cpu(void)
-{
-    u_long cpu = 0;
+/* Dectection of 68030 and up is unreliable, so we check ourself */
+/* Keep consistent with asm/setup.h! */
+/* 24.11.1996 Joerg Dorchain */
+asm( ".text\n"
+ALIGN_STR "\n"
+SYMBOL_NAME_STR(check346) ":
+	orw	#0x700,%sr	| disable ints
+	movec	%vbr,%a0	| get vbr
+	movel	%a0@(11*4),%a1	| save old trap vector (Line F)
+	movel	#L1,%a0@(11*4)	| set L1 as new vector
+	movel	%sp,%d1		| save stack pointer
+	moveq	#2,%d0		| value with exception (030)
+	.long	0xf6208000	| move16 %a0@+,%a0@+, the 030 test instruction
+	nop			| clear instruction pipeline
+	movel	%d1,%sp		| restore stack pointer
+	movec	%vbr,%a0	| get vbr again
+	moveq	#4,%d0		| value with exception (040)
+	.word	0xf5c8		| plpar %a0@, the 040 test instruction
+	nop			| clear instruction pipeline
+	moveq	#8,%d0		| value if we come here
+L1:	movel	%d1,%sp		| restore stack pointer
+	movel	%a1,%a0@(11*4)	| restore vector
+	rte"
+);
 
-    if (SysBase->AttnFlags & AFF_68060) {
-	cpu = CPU_68060;
-	if (SysBase->AttnFlags & AFF_FPU40)
-	    cpu |= FPU_68060;
-    } else if (SysBase->AttnFlags & AFF_68040) {
-	cpu = CPU_68040;
+static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu)
+{
+    if (SysBase->AttnFlags & (AFF_68030|AFF_68040|AFF_68060))
+        *cpu = Supervisor(check346);
+    else if (SysBase->AttnFlags & AFF_68020)
+        *cpu = CPU_68020;
+    if (*cpu == CPU_68040 || *cpu == CPU_68060) {
 	if (SysBase->AttnFlags & AFF_FPU40)
-	    cpu |= FPU_68040;
+	    *fpu = *cpu;
     } else {
-	if (SysBase->AttnFlags & AFF_68030)
-	    cpu = CPU_68030;
-	else if (SysBase->AttnFlags & AFF_68020)
-	    cpu = CPU_68020;
 	if (SysBase->AttnFlags & AFF_68882)
-	    cpu |= FPU_68882;
+	    *fpu = FPU_68882;
 	else if (SysBase->AttnFlags & AFF_68881)
-	    cpu |= FPU_68881;
+	    *cpu = FPU_68881;
     }
-    return(cpu);
+    *mmu = *cpu;
 }
 
-
     /*
      *	Determine the Amiga Model
      */
@@ -810,7 +879,7 @@
 	if (res)
 	    Printf("0x%08lx\n", res);
 	else
-	    Printf("not present\n");
+	    Puts("not present\n");
     return(res ? TRUE : FALSE);
 }
 
@@ -830,12 +899,179 @@
 	if (res)
 	    Printf("0x%08lx\n", res);
 	else
-	    Printf("not present\n");
+	    Puts("not present\n");
     return(res ? TRUE : FALSE);
 }
 
 
     /*
+     *  Create the Bootinfo structure
+     */
+
+static int create_bootinfo(void)
+{
+    int i;
+    struct bi_record *record;
+
+    /* Initialization */
+    bi_size = 0;
+
+    /* Generic tags */
+    if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype))
+	return(0);
+    if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype))
+	return(0);
+    if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype))
+	return(0);
+    if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype))
+	return(0);
+    for (i = 0; i < bi.num_memory; i++)
+	if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i]))
+	    return(0);
+    if (bi.ramdisk.size)
+	if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk))
+	    return(0);
+    if (!add_bi_string(BI_COMMAND_LINE, bi.command_line))
+	return(0);
+
+    /* Amiga tags */
+    if (!add_bi_record(BI_AMIGA_MODEL, sizeof(bi.model), &bi.model))
+	return(0);
+    for (i = 0; i < bi.num_autocon; i++)
+	if (!add_bi_record(BI_AMIGA_AUTOCON, sizeof(bi.autocon[i]),
+			    &bi.autocon[i]))
+	    return(0);
+    if (!add_bi_record(BI_AMIGA_CHIP_SIZE, sizeof(bi.chip_size), &bi.chip_size))
+	return(0);
+    if (!add_bi_record(BI_AMIGA_VBLANK, sizeof(bi.vblank), &bi.vblank))
+	return(0);
+    if (!add_bi_record(BI_AMIGA_PSFREQ, sizeof(bi.psfreq), &bi.psfreq))
+	return(0);
+    if (!add_bi_record(BI_AMIGA_ECLOCK, sizeof(bi.eclock), &bi.eclock))
+	return(0);
+    if (!add_bi_record(BI_AMIGA_CHIPSET, sizeof(bi.chipset), &bi.chipset))
+	return(0);
+    if (!add_bi_record(BI_AMIGA_SERPER, sizeof(bi.serper), &bi.serper))
+	return(0);
+
+    /* Trailer */
+    record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
+    record->tag = BI_LAST;
+    bi_size += sizeof(bi_union.record.tag);
+
+    return(1);
+}
+
+
+    /*
+     *  Add a Record to the Bootinfo Structure
+     */
+
+static int add_bi_record(u_short tag, u_short size, const void *data)
+{
+    struct bi_record *record;
+    u_int size2;
+
+    size2 = (sizeof(struct bi_record)+size+3)&-4;
+    if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) {
+	Puts("Can't add bootinfo record. Ask a wizard to enlarge me.\n");
+	return(0);
+    }
+    record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
+    record->tag = tag;
+    record->size = size2;
+    memcpy(record->data, data, size);
+    bi_size += size2;
+    return(1);
+}
+
+
+    /*
+     *  Add a String Record to the Bootinfo Structure
+     */
+
+static int add_bi_string(u_short tag, const u_char *s)
+{
+    return(add_bi_record(tag, strlen(s)+1, (void *)s));
+}
+
+
+#ifdef BOOTINFO_COMPAT_1_0
+
+    /*
+     *  Create the Bootinfo structure for backwards compatibility mode
+     */
+
+static int create_compat_bootinfo(void)
+{
+    u_int i;
+
+    compat_bootinfo.machtype = bi.machtype;
+    if (bi.cputype & CPU_68020)
+	compat_bootinfo.cputype = COMPAT_CPU_68020;
+    else if (bi.cputype & CPU_68030)
+	compat_bootinfo.cputype = COMPAT_CPU_68030;
+    else if (bi.cputype & CPU_68040)
+	compat_bootinfo.cputype = COMPAT_CPU_68040;
+    else if (bi.cputype & CPU_68060)
+	compat_bootinfo.cputype = COMPAT_CPU_68060;
+    else {
+	Printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
+	return(0);
+    }
+    if (bi.fputype & FPU_68881)
+	compat_bootinfo.cputype |= COMPAT_FPU_68881;
+    else if (bi.fputype & FPU_68882)
+	compat_bootinfo.cputype |= COMPAT_FPU_68882;
+    else if (bi.fputype & FPU_68040)
+	compat_bootinfo.cputype |= COMPAT_FPU_68040;
+    else if (bi.fputype & FPU_68060)
+	compat_bootinfo.cputype |= COMPAT_FPU_68060;
+    else {
+	Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
+	return(0);
+    }
+    compat_bootinfo.num_memory = bi.num_memory;
+    if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) {
+	Printf("Warning: using only %ld blocks of memory\n",
+	       COMPAT_NUM_MEMINFO);
+	compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO;
+    }
+    for (i = 0; i < compat_bootinfo.num_memory; i++) {
+	compat_bootinfo.memory[i].addr = bi.memory[i].addr;
+	compat_bootinfo.memory[i].size = bi.memory[i].size;
+    }
+    if (bi.ramdisk.size) {
+	compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024;
+	compat_bootinfo.ramdisk_addr = bi.ramdisk.addr;
+    } else {
+	compat_bootinfo.ramdisk_size = 0;
+	compat_bootinfo.ramdisk_addr = 0;
+    }
+    strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE);
+    compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0';
+
+    compat_bootinfo.bi_amiga.model = bi.model;
+    compat_bootinfo.bi_amiga.num_autocon = bi.num_autocon;
+    if (compat_bootinfo.bi_amiga.num_autocon > COMPAT_NUM_AUTO) {
+	Printf("Warning: using only %ld AutoConfig devices\n",
+	       COMPAT_NUM_AUTO);
+	compat_bootinfo.bi_amiga.num_autocon = COMPAT_NUM_AUTO;
+    }
+    for (i = 0; i < compat_bootinfo.bi_amiga.num_autocon; i++)
+	compat_bootinfo.bi_amiga.autocon[i] = bi.autocon[i];
+    compat_bootinfo.bi_amiga.chip_size = bi.chip_size;
+    compat_bootinfo.bi_amiga.vblank = bi.vblank;
+    compat_bootinfo.bi_amiga.psfreq = bi.psfreq;
+    compat_bootinfo.bi_amiga.eclock = bi.eclock;
+    compat_bootinfo.bi_amiga.chipset = bi.chipset;
+    compat_bootinfo.bi_amiga.hw_present = 0;
+    return(1);
+}
+#endif /* BOOTINFO_COMPAT_1_0 */
+
+
+    /*
      *  Compare the Bootstrap and Kernel Versions
      */
 
@@ -852,7 +1088,7 @@
 		break;
 	    }
     if (!version)
-	Printf("Kernel has no bootinfo version info, assuming 0.0\n");
+	Puts("Kernel has no bootinfo version info, assuming 0.0\n");
 
     kernel_major = BI_VERSION_MAJOR(version);
     kernel_minor = BI_VERSION_MINOR(version);
@@ -863,16 +1099,27 @@
     Printf("Kernel's bootinfo version   : %ld.%ld\n", kernel_major,
 	   kernel_minor);
 
-    if (kernel_major != boots_major) {
-	Printf("\nThis bootstrap is too %s for this kernel!\n",
-	       boots_major < kernel_major ? "old" : "new");
-	return(0);
-    }
-    if (kernel_minor > boots_minor) {
-	Printf("Warning: Bootinfo version of bootstrap and kernel differ!\n" );
-	Printf("         Certain features may not work.\n");
+    switch (kernel_major) {
+	case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION):
+	    if (kernel_minor > boots_minor) {
+		Puts("Warning: Bootinfo version of bootstrap and kernel "
+		       "differ!\n");
+		Puts("         Certain features may not work.\n");
+	    }
+	    break;
+
+#ifdef BOOTINFO_COMPAT_1_0
+	case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION):
+	    Puts("(using backwards compatibility mode)\n");
+	    break;
+#endif /* BOOTINFO_COMPAT_1_0 */
+
+	default:
+	    Printf("\nThis bootstrap is too %s for this kernel!\n",
+		   boots_major < kernel_major ? "old" : "new");
+	    return(0);
     }
-    return(1);
+    return(kernel_major);
 }
 
 
@@ -891,7 +1138,7 @@
     register u_long d0 __asm("d0") = mem_size;
     register u_long d1 __asm("d1") = rd_size;
     register u_long d2 __asm("d2") = kernel_size;
-    register u_long d3 __asm("d3") = sizeof(struct bootinfo);
+    register u_long d3 __asm("d3") = bi_size;
 
     __asm __volatile ("movel a2,sp;"
 		      "jmp a0@"
@@ -915,7 +1162,7 @@
      *	    d0 = mem_size
      *	    d1 = rd_size
      *	    d2 = kernel_size
-     *	    d3 = sizeof(struct bootinfo)
+     *	    d3 = bi_size
      */
 
 asm(".text\n"
@@ -931,10 +1178,10 @@
 	moveb	a0@+,a1@+	|  *dest++ = *src++;
 	jra	1b
 2:
-				| /* copy early bootinfo to end of bss */
+				| /* copy bootinfo to end of bss */
 	movel	a3,a0		| src = (u_long *)(memptr+kernel_size);
 	addl	d2,a0		| dest = end of bss (already in a1)
-	movel	d3,d7		| count = sizeof(struct bootinfo)
+	movel	d3,d7		| count = bi_size
 	subql	#1,d7
 1:	moveb	a0@+,a1@+	| while (--count > -1)
 	dbra	d7,1b		|     *dest++ = *src++
@@ -944,7 +1191,7 @@
 	movel	a4,a1		| dest = (u_long *)(start_mem+mem_size);
 	addl	d0,a1
 	movel	a3,a2		| limit = (u_long *)(memptr+kernel_size +
-	addl	d2,a2		|		     sizeof(struct bootinfo));
+	addl	d2,a2		|		     bi_size);
 	addl	d3,a2
 	movel	a2,a0		| src = (u_long *)((u_long)limit+rd_size);
 	addl	d1,a0

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