Enscript Output

extractedLnx/linux/arch/m68k/boot/amiga/linuxboot.c_linuxboot.c

u_long linuxboot(const struct linuxboot_args *args)
{
    int kfd = -1, rfd = -1, elf_kernel = 0, do_fast, do_chip;
    int i, j;
    const struct MemHeader *mnp;
    struct ConfigDev *cdp = NULL;
    char *memptr = NULL;
    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;

    /* print the greet message */
    Puts("\nLinux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n");
    Puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n\n");

    /* Note: Initial values in bi override detected values */
    bi = args->bi;

    /* machine is Amiga */
    bi.machtype = MACH_AMIGA;

    /* determine chipset */
    if (!bi.chipset)
	bi.chipset = get_chipset();

    /* determine CPU, FPU and MMU type */
    if (!bi.cputype)
	get_processor(&bi.cputype, &bi.fputype, &bi.mmutype);

    /* determine Amiga model */
    if (!bi.model)
	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 */
    if (!bi.num_autocon)
	for (i = 0; (cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1)); i++)
	    if (bi.num_autocon < ZORRO_NUM_AUTO)
		/* copy the contents of each structure into our boot info and
		   count this device */
		memcpy(&bi.autocon[bi.num_autocon++], cdp,
		       sizeof(struct ConfigDev));
	    else
		Printf("Warning: too many AutoConfig devices. Ignoring device at "
		       "0x%08lx\n", cdp->cd_BoardAddr);

    do_fast = bi.num_memory ? 0 : 1;
    do_chip = bi.chip_size ? 0 : 1;
    /* find out the memory in the system */
    for (mnp = (struct MemHeader *)SysBase->MemList.lh_Head;
	 mnp->mh_Node.ln_Succ;
	 mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ) {
	struct MemHeader mh;

	/* copy the information */
	mh = *mnp;

	/* skip virtual memory */
	if (!(mh.mh_Attributes & MEMF_PUBLIC))
	    continue;

	/* 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) &&
	    (model_mask & (CLASS_A3000 | CLASS_A4000)))
	    if ((bi.cputype & CPU_68040) && Supervisor(maprommed))
		Puts("A3640 MapROM detected.\n");
	    else if (model_mask & CLASS_A3000) {
		mh.mh_Upper = (void *)0x08000000;
		Puts("A3000 shadowed Kickstart detected.\n");
	    }

	/* if we suspect that Kickstart is zkicked,
	   modify the entry to show 512K more at the botton of RAM */
	if ((mh.mh_Lower == (void *)0x00280020) &&
	    (model_mask & CLASS_ZKICK)) {
	    mh.mh_Lower = (void *)0x00200000;
	    Puts("ZKick detected.\n");
	}

	/* 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 (do_fast && mh.mh_Attributes & MEMF_FAST) {
	    /* set the size value to the size of this block and mask off to a
	       256K increment */
	    u_long size = ((u_long)mh.mh_Upper-(u_long)mh.mh_Lower)&0xfffc0000;
	    if (size > 0)
		if (bi.num_memory < NUM_MEMINFO) {
		    /* record the start and size */
		    bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower;
		    bi.memory[bi.num_memory].size = size;
		    /* count this block */
		    bi.num_memory++;
		} else
		    Printf("Warning: too many memory blocks. Ignoring block "
		    	   "of %ldK at 0x%08x\n", size>>10,
			   (u_long)mh.mh_Lower);
	} else if (do_chip && mh.mh_Attributes & MEMF_CHIP)
	    /* if CHIP memory, record the size */
	    bi.chip_size = (u_long)mh.mh_Upper;
    }

    /* get info from ExecBase */
    if (!bi.vblank)
	bi.vblank = SysBase->VBlankFrequency;
    if (!bi.psfreq)
	bi.psfreq = SysBase->PowerSupplyFrequency;
    if (!bi.eclock)
	bi.eclock = SysBase->ex_EClockFrequency;

    /* serial port */
    if (!bi.serper) {
	realbaud = baud ? baud : DEFAULT_BAUD;
	bi.serper = (5*bi.eclock+realbaud/2)/realbaud-1;
    }

    /* display 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) {
	case CPU_68020:
	    Puts("68020 (Do you have an MMU?)");
	    break;
	case CPU_68030:
	    Puts("68030");
	    break;
	case CPU_68040:
	    Puts("68040");
	    break;
	case CPU_68060:
	    Puts("68060");
	    break;
	default:
	    Puts("Insufficient for Linux.  Aborting...\n");
	    Printf("SysBase->AttnFlags = 0x%08lx\n", SysBase->AttnFlags);
	    goto Fail;
    }
    switch (bi.fputype) {
	case FPU_68881:
	    Puts(" with 68881 FPU");
	    break;
	case FPU_68882:
	    Puts(" with 68882 FPU");
	    break;
	case FPU_68040:
	case FPU_68060:
	    Puts(" with internal FPU");
	    break;
	default:
	    Puts(" without FPU");
	    break;
    }

    /* display the chipset */
    switch (bi.chipset) {
	case CS_STONEAGE:
	    Puts(", old or unknown chipset");
	    break;
	case CS_OCS:
	    Puts(", OCS");
	    break;
	case CS_ECS:
	    Puts(", ECS");
	    break;
	case CS_AGA:
	    Puts(", AGA chipset");
	    break;
    }

    Puts("\n\n");

    /* display the command line */
    Printf("Command line is '%s'\n", bi.command_line);

    /* display the clock statistics */
    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.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.autocon[i].cd_BoardAddr);
	    boardresetfuncs[i] = NULL;
	    if (reset_boards) {
		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)) {
			Printf(" [%s - will be reset at kernel boot time]",
			       boardresetdb[j].name);
			boardresetfuncs[i] = boardresetdb[j].reset;
			break;
		    }
	    }
	    PutChar('\n');
	}
    } else
	Puts("No AutoConfig Devices Found\n");

    /* display memory */
    if (bi.num_memory) {
	Printf("\nFound %ld Block%sof Memory\n", bi.num_memory,
	       bi.num_memory > 1 ? "s " : " ");
	for (i = 0; i < bi.num_memory; i++)
	    Printf("Block %ld: 0x%08lx to 0x%08lx (%ldK)\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...\n");
	goto Fail;
    }

    /* display chip memory size */
    Printf("%ldK of CHIP memory\n", bi.chip_size>>10);

    start_mem = bi.memory[0].addr;
    mem_size = bi.memory[0].size;

    /* tell us where the kernel will go */
    Printf("\nThe kernel will be located at 0x%08lx\n", start_mem);

    /* verify that there is enough Chip RAM */
    if (bi.chip_size < 512*1024) {
	Puts("Not enough Chip RAM in this system.  Aborting...\n");
	goto Fail;
    }

    /* verify that there is enough Fast RAM */
    for (fast_total = 0, i = 0; i < bi.num_memory; i++)
	fast_total += bi.memory[i].size;
    if (fast_total < 2*1024*1024) {
	Puts("Not enough Fast RAM in this system.  Aborting...\n");
	goto Fail;
    }

    /* support for ramdisk */
    if (ramdiskname) {
	int size;

	if ((size = FileSize(ramdiskname)) == -1) {
	    Printf("Unable to find size of ramdisk file `%s'\n", ramdiskname);
	    goto Fail;
	}
	/* record ramdisk size */
	bi.ramdisk.size = size;
    } else
	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) {
	Printf("Unable to open kernel file `%s'\n", kernelname);
	goto Fail;
    }
    if (KRead(kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
	Puts("Unable to read exec header from kernel file\n");
	goto Fail;
    }

#ifdef ZKERNEL
    if (((unsigned char *)&kexec)[0] == 037 &&
	(((unsigned char *)&kexec)[1] == 0213 ||
	 ((unsigned char *)&kexec)[1] == 0236)) {
	/* That's a compressed kernel */
	Puts("Kernel is compressed\n");
	if (load_zkernel(kfd)) {
	    Puts("Decompression error -- aborting\n");
	    goto Fail;
	}
    }
#endif

    switch (N_MAGIC(kexec)) {
	case ZMAGIC:
	    if (debugflag)
		Puts("\nLoading a.out (ZMAGIC) Linux/m68k kernel...\n");
	    text_offset = N_TXTOFF(kexec);
	    break;

	case QMAGIC:
	    if (debugflag)
		Puts("\nLoading a.out (QMAGIC) Linux/m68k kernel...\n");
	    text_offset = sizeof(kexec);
	    /* the text size includes the exec header; remove this */
	    kexec.a_text -= sizeof(kexec);
	    break;

	default:
	    /* Try to parse it as an ELF header */
	    KSeek(kfd, 0);
	    if ((KRead(kfd, (void *)&kexec_elf, sizeof(kexec_elf)) ==
		 sizeof(kexec_elf)) &&
		 (memcmp(&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)) {
		elf_kernel = 1;
		if (debugflag)
		    Puts("\nLoading ELF Linux/m68k kernel...\n");
		/* A few plausibility checks */
		if ((kexec_elf.e_type != ET_EXEC) ||
		    (kexec_elf.e_machine != EM_68K) ||
		    (kexec_elf.e_version != EV_CURRENT)) {
		    Puts("Invalid ELF header contents in kernel\n");
		    goto Fail;
		}
		/* Load the program headers */
		if (!(kernel_phdrs =
		      (Elf32_Phdr *)AllocMem(kexec_elf.e_phnum*sizeof(Elf32_Phdr),
					     MEMF_FAST | MEMF_PUBLIC |
					     MEMF_CLEAR))) {
		    Puts("Unable to allocate memory for program headers\n");
		    goto Fail;
		}
		KSeek(kfd, kexec_elf.e_phoff);
		if (KRead(kfd, (void *)kernel_phdrs,
			 kexec_elf.e_phnum*sizeof(*kernel_phdrs)) !=
		    kexec_elf.e_phnum*sizeof(*kernel_phdrs)) {
		    Puts("Unable to read program headers from kernel file\n");
		    goto Fail;
		}
		break;
	    }
	    Printf("Wrong magic number 0x%08lx in kernel header\n",
		   N_MAGIC(kexec));
	    goto Fail;
    }

    /* 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 */
    if (!elf_kernel)
	kexec.a_bss = (kexec.a_bss+3) & ~3;

    /* calculate the total required amount of memory */
    if (elf_kernel) {
	u_long min_addr = 0xffffffff, max_addr = 0;
	for (i = 0; i < kexec_elf.e_phnum; i++) {
	    if (min_addr > kernel_phdrs[i].p_vaddr)
		min_addr = kernel_phdrs[i].p_vaddr;
	    if (max_addr < kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz)
		max_addr = kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz;
	}
	/* This is needed for newer linkers that include the header in
	   the first segment.  */
	if (min_addr == 0) {
	    min_addr = PAGE_SIZE;
	    kernel_phdrs[0].p_vaddr += PAGE_SIZE;
	    kernel_phdrs[0].p_offset += PAGE_SIZE;
	    kernel_phdrs[0].p_filesz -= PAGE_SIZE;
	    kernel_phdrs[0].p_memsz -= PAGE_SIZE;
	}
	kernel_size = max_addr-min_addr;
    } else
	kernel_size = kexec.a_text+kexec.a_data+kexec.a_bss;
    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");
	goto Fail;
    }

    /* read the text and data segments from the kernel image */
    if (elf_kernel)
	for (i = 0; i < kexec_elf.e_phnum; i++) {
	    if (KSeek(kfd, kernel_phdrs[i].p_offset) == -1) {
		Printf("Failed to seek to segment %ld\n", i);
		goto Fail;
	    }
	    if (KRead(kfd, memptr+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
		      kernel_phdrs[i].p_filesz) != kernel_phdrs[i].p_filesz) {
		Printf("Failed to read segment %ld\n", i);
		goto Fail;
	    }
	}
    else {
	if (KSeek(kfd, text_offset) == -1) {
	    Puts("Failed to seek to text\n");
	    goto Fail;
	}
	if (KRead(kfd, memptr, kexec.a_text) != kexec.a_text) {
	    Puts("Failed to read text\n");
	    goto Fail;
	}
	/* data follows immediately after text */
	if (KRead(kfd, memptr+kexec.a_text, kexec.a_data) != kexec.a_data) {
	    Puts("Failed to read data\n");
	    goto Fail;
	}
    }
    KClose(kfd);
    kfd = -1;

    /* Check kernel's bootinfo version */
    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_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+bi_size, rd_size) != rd_size) {
	    Puts("Failed to read ramdisk file\n");
	    goto Fail;
	}
	Close(rfd);
	rfd = -1;
    }

    /* allocate temporary chip ram stack */
    if (!(stack = (u_long *)AllocMem(TEMP_STACKSIZE, MEMF_CHIP | MEMF_CLEAR))) {
	Puts("Unable to allocate memory for stack\n");
	goto Fail;
    }

    /* allocate chip ram for copy of startup code */
    startcodesize = &copyallend-&copyall;
    if (!(startfunc = (void (*)(void))AllocMem(startcodesize,
					       MEMF_CHIP | MEMF_CLEAR))) {
	Puts("Unable to allocate memory for startcode\n");
	goto Fail;
    }

    /* copy startup code to CHIP RAM */
    memcpy(startfunc, &copyall, startcodesize);

    if (debugflag) {
	if (bi.ramdisk.size)
	    Printf("RAM disk at 0x%08lx, size is %ldK\n",
		   (u_long)memptr+kernel_size+bi_size, bi.ramdisk.size>>10);

	if (elf_kernel) {
	    PutChar('\n');
	    for (i = 0; i < kexec_elf.e_phnum; i++)
		Printf("Kernel segment %ld at 0x%08lx, size %ld\n", i,
		       start_mem+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
		       kernel_phdrs[i].p_memsz);
	    Printf("Boot info        at 0x%08lx\n", start_mem+kernel_size);
	} else {
	    Printf("\nKernel text at 0x%08lx, code size 0x%08lx\n", start_mem,
		   kexec.a_text);
	    Printf("Kernel data at 0x%08lx, data size 0x%08lx\n",
		   start_mem+kexec.a_text, kexec.a_data);
	    Printf("Kernel bss  at 0x%08lx, bss  size 0x%08lx\n",
		   start_mem+kexec.a_text+kexec.a_data, kexec.a_bss);
	    Printf("Boot info   at 0x%08lx\n", start_mem+kernel_size);
	}
	Printf("\nKernel entry is 0x%08lx\n", elf_kernel ? kexec_elf.e_entry :
							   kexec.a_entry);

	Printf("ramdisk dest is 0x%08lx\n", bi.ramdisk.addr);
	Printf("ramdisk lower limit is 0x%08lx\n",
	       (u_long)memptr+kernel_size+bi_size);
	Printf("ramdisk src top is 0x%08lx\n",
	       (u_long)memptr+kernel_size+bi_size+rd_size);

	Puts("\nType a key to continue the Linux/m68k boot...");
	GetChar();
	PutChar('\n');
    }

    /* wait for things to settle down */
    Sleep(1000000);

    if (!keep_video)
	/* set graphics mode to a nice normal one */
	LoadView(NULL);

    Disable();

    /* reset nasty Zorro boards */
    if (reset_boards)
	for (i = 0; i < bi.num_autocon; i++)
	    if (boardresetfuncs[i])
		boardresetfuncs[i](&bi.autocon[i]);

    /* Turn off all DMA */
    custom.dmacon = DMAF_ALL | DMAF_MASTER;

    /* turn off caches */
    CacheControl(0, ~0);

    /* Go into supervisor state */
    SuperState();

    /* turn off any mmu translation */
    disable_mmu();

    /* execute the copy-and-go code (from CHIP RAM) */
    start_kernel(startfunc, (char *)stack+TEMP_STACKSIZE, memptr, start_mem,
		 kernel_size, bi.ramdisk.addr, rd_size);

    /* Clean up and exit in case of a failure */
Fail:
    if (kfd != -1)
	KClose(kfd);
    if (rfd != -1)
	Close(rfd);
    if (memptr)
	FreeMem((void *)memptr, memreq);
    if (stack)
	FreeMem((void *)stack, TEMP_STACKSIZE);
    if (kernel_phdrs)
	FreeMem((void *)kernel_phdrs, kexec_elf.e_phnum*sizeof(Elf32_Phdr));
    return(FALSE);
}

Generated by GNU enscript 1.6.4.