Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | /* * BK Id: SCCS/s.main.c 1.9 06/15/01 13:16:10 paulus */ /* * Copyright (c) 1997 Paul Mackerras <paulus@cs.anu.edu.au> * Initial Power Macintosh COFF version. * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> * Modifications for an ELF-based IBM evaluation board version. * Copyright 2000-2001 MontaVista Software Inc. * PPC405GP modifications * Author: MontaVista Software, Inc. * frank_rowand@mvista.com or source@mvista.com * debbie_chu@mvista.com * * Module name: main.c * * Description: * This module does most of the real work for the boot loader. It * checks the variables holding the absolute start address and size * of the Linux kernel "image" and initial RAM disk "initrd" sections * and if they are present, moves them to their "proper" locations. * * For the Linux kernel, "proper" is physical address 0x00000000. * For the RAM disk, "proper" is the image's size below the top * of physical memory. The Linux kernel may be in either raw * binary form or compressed with GNU zip (aka gzip). * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ #include <linux/config.h> #include <asm/ppc4xx.h> #include "nonstdio.h" #include "irSect.h" #if defined(CONFIG_SERIAL_CONSOLE) #include "ns16550.h" #endif /* CONFIG_SERIAL_CONSOLE */ /* Preprocessor Defines */ /* * Location of the IBM boot ROM function pointer address for retrieving * the board information structure. */ #define BOARD_INFO_VECTOR 0xFFFE0B50 /* * Warning: the board_info doesn't contain valid data until get_board_info() * gets called in start(). */ #define RAM_SIZE board_info.bi_memsize #define RAM_PBASE 0x00000000 #define RAM_PEND (RAM_PBASE + RAM_SIZE) #define RAM_VBASE 0xC0000000 #define RAM_VEND (RAM_VBASE + RAM_SIZE) #define RAM_START RAM_PBASE #define RAM_END RAM_PEND #define RAM_FREE (imageSect_start + imageSect_size + initrdSect_size) #define PROG_START RAM_START /* Function Macros */ #define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) /* Global Variables */ /* Needed by zalloc and zfree for allocating memory */ char *avail_ram; /* Indicates start of RAM available for heap */ char *end_avail; /* Indicates end of RAM available for heap */ /* Needed for serial I/O. */ extern unsigned long *com_port; bd_t board_info; /* ** The bootrom may change bootrom_cmdline to point to a buffer in the ** bootrom. */ char *bootrom_cmdline = ""; char treeboot_bootrom_cmdline[512]; #ifdef CONFIG_CMDLINE char *cmdline = CONFIG_CMDLINE; #else char *cmdline = ""; #endif /* Function Prototypes */ extern void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp); void kick_watchdog(void) { #ifdef CONFIG_405GP mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS)); #endif } void start(void) { void *options; int ns, oh, i; unsigned long sa, len; void *dst; unsigned char *im; unsigned long initrd_start, initrd_size; bd_t *(*get_board_info)(void) = (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); bd_t *bip = NULL; com_port = (struct NS16550 *)serial_init(0); #ifdef CONFIG_405GP /* turn off on-chip ethernet */ /* This is to fix a problem with early walnut bootrom. */ { /* Physical mapping of ethernet register space. */ static struct ppc405_enet_regs *ppc405_enet_regp = (struct ppc405_enet_regs *)PPC405_EM0_REG_ADDR; mtdcr(DCRN_MALCR, MALCR_MMSR); /* 1st reset MAL */ while (mfdcr(DCRN_MALCR) & MALCR_MMSR) {}; /* wait for the reset */ ppc405_enet_regp->em0mr0 = 0x20000000; /* then reset EMAC */ } #endif if ((bip = get_board_info()) != NULL) memcpy(&board_info, bip, sizeof(bd_t)); /* Init RAM disk (initrd) section */ kick_watchdog(); if (initrdSect_start != 0 && (initrd_size = initrdSect_size) != 0) { initrd_start = (RAM_END - initrd_size) & ~0xFFF; _printk("Initial RAM disk at 0x%08x (%u bytes)\n", initrd_start, initrd_size); memcpy((char *)initrd_start, (char *)(initrdSect_start), initrdSect_size); end_avail = (char *)initrd_start; } else { initrd_start = initrd_size = 0; end_avail = (char *)RAM_END; } /* Linux kernel image section */ kick_watchdog(); im = (unsigned char *)(imageSect_start); len = imageSect_size; dst = (void *)PROG_START; /* Check for the gzip archive magic numbers */ if (im[0] == 0x1f && im[1] == 0x8b) { /* The gunzip routine needs everything nice and aligned */ void *cp = (void *)ALIGN_UP(RAM_FREE, 8); avail_ram = (void *)(cp + ALIGN_UP(len, 8)); /* used by zalloc() */ memcpy(cp, im, len); /* I'm not sure what the 0x200000 parameter is for, but it works. */ /* It tells gzip the end of the area you wish to reserve, and it * can use data past that point....unfortunately, this value * isn't big enough (luck ran out). -- Dan */ gunzip(dst, 0x400000, cp, (int *)&len); } else { memmove(dst, im, len); } kick_watchdog(); flush_cache(dst, len); sa = (unsigned long)dst; (*(void (*)())sa)(&board_info, initrd_start, initrd_start + initrd_size, cmdline, cmdline + strlen(cmdline)); pause(); } |