summaryrefslogtreecommitdiff
path: root/lib_sparc/bootm.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib_sparc/bootm.c')
-rw-r--r--lib_sparc/bootm.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/lib_sparc/bootm.c b/lib_sparc/bootm.c
new file mode 100644
index 0000000..8900b2e
--- /dev/null
+++ b/lib_sparc/bootm.c
@@ -0,0 +1,226 @@
+/* SPARC code for booting linux 2.6
+ *
+ * (C) Copyright 2007
+ * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/byteorder.h>
+#include <asm/prom.h>
+#include <asm/cache.h>
+
+#define PRINT_KERNEL_HEADER
+
+extern image_header_t header;
+extern void srmmu_init_cpu(unsigned int entry);
+extern void prepare_bootargs(char *bootargs);
+extern int do_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]);
+
+#ifdef CONFIG_USB_UHCI
+extern int usb_lowlevel_stop(void);
+#endif
+
+/* sparc kernel argument (the ROM vector) */
+struct linux_romvec *kernel_arg_promvec;
+
+/* page szie is 4k */
+#define PAGE_SIZE 0x1000
+#define RAMDISK_IMAGE_START_MASK 0x07FF
+#define RAMDISK_PROMPT_FLAG 0x8000
+#define RAMDISK_LOAD_FLAG 0x4000
+struct __attribute__ ((packed)) {
+ char traptable[PAGE_SIZE];
+ char swapper_pg_dir[PAGE_SIZE];
+ char pg0[PAGE_SIZE];
+ char pg1[PAGE_SIZE];
+ char pg2[PAGE_SIZE];
+ char pg3[PAGE_SIZE];
+ char empty_bad_page[PAGE_SIZE];
+ char empty_bad_page_table[PAGE_SIZE];
+ char empty_zero_page[PAGE_SIZE];
+ unsigned char hdr[4]; /* ascii "HdrS" */
+ /* 00.02.06.0b is for Linux kernel 2.6.11 */
+ unsigned char linuxver_mega_major;
+ unsigned char linuxver_major;
+ unsigned char linuxver_minor;
+ unsigned char linuxver_revision;
+ /* header version 0x0203 */
+ unsigned short hdr_ver;
+ union __attribute__ ((packed)) {
+ struct __attribute__ ((packed)) {
+ unsigned short root_flags;
+ unsigned short root_dev;
+ unsigned short ram_flags;
+ unsigned int sparc_ramdisk_image;
+ unsigned int sparc_ramdisk_size;
+ unsigned int reboot_command;
+ unsigned int resv[3];
+ unsigned int end;
+ } ver_0203;
+ } hdr_input;
+} *linux_hdr;
+
+/* temporary initrd image holder */
+image_header_t ihdr;
+
+/* boot the linux kernel */
+void do_bootm_linux(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[],
+ bootm_headers_t * images)
+{
+ char *bootargs;
+ ulong ep, load;
+ ulong initrd_start, initrd_end;
+ ulong rd_data_start, rd_data_end, rd_len;
+ unsigned int data, len, checksum;
+ unsigned int initrd_addr, kernend;
+ void (*kernel) (struct linux_romvec *, void *);
+ struct lmb *lmb = images->lmb;
+ int ret;
+
+ if (images->legacy_hdr_valid) {
+ ep = image_get_ep(images->legacy_hdr_os);
+ load = image_get_load(images->legacy_hdr_os);
+#if defined(CONFIG_FIT)
+ } else if (images->fit_uname_os) {
+ int ret = fit_image_get_entry(images->fit_hdr_os,
+ images->fit_noffset_os, &ep);
+ if (ret) {
+ puts("Can't get entry point property!\n");
+ goto error;
+ }
+
+ ret = fit_image_get_load(images->fit_hdr_os,
+ images->fit_noffset_os, &load);
+ if (ret) {
+ puts("Can't get load address property!\n");
+ goto error;
+ }
+#endif
+ } else {
+ puts("Could not find kernel entry point!\n");
+ goto error;
+ }
+
+ /* Get virtual address of kernel start */
+ linux_hdr = (void *)load;
+
+ /* */
+ kernel = (void (*)(struct linux_romvec *, void *))ep;
+
+ /* check for a SPARC kernel */
+ if ((linux_hdr->hdr[0] != 'H') ||
+ (linux_hdr->hdr[1] != 'd') ||
+ (linux_hdr->hdr[2] != 'r') || (linux_hdr->hdr[3] != 'S')) {
+ puts("Error reading header of SPARC Linux kernel, aborting\n");
+ goto error;
+ }
+#ifdef PRINT_KERNEL_HEADER
+ printf("## Found SPARC Linux kernel %d.%d.%d ...\n",
+ linux_hdr->linuxver_major,
+ linux_hdr->linuxver_minor, linux_hdr->linuxver_revision);
+#endif
+
+#ifdef CONFIG_USB_UHCI
+ usb_lowlevel_stop();
+#endif
+
+ /* set basic boot params in kernel header now that it has been
+ * extracted and is writeable.
+ */
+
+ /*
+ * Are we going to use an initrd image?
+ */
+ ret = boot_get_ramdisk(argc, argv, images, IH_ARCH_SPARC,
+ &rd_data_start, &rd_data_end);
+ if (ret) {
+ /* RAM disk found but was corrupt */
+ puts("RAM Disk corrupt\n");
+ goto error;
+ }
+
+ /* Calc length of RAM disk, if zero no ramdisk available */
+ rd_len = rd_data_end - rd_data_start;
+
+ if (rd_len) {
+
+ /* Reserve the space used by PROM and stack. This is done
+ * to avoid that the RAM image is copied over stack or
+ * PROM.
+ */
+ lmb_reserve(lmb, CFG_RELOC_MONITOR_BASE, CFG_RAM_END);
+
+ ret = boot_ramdisk_high(lmb, rd_data_start, rd_len,
+ &initrd_start, &initrd_end);
+ if (ret) {
+ puts("### Failed to relocate RAM disk\n");
+ goto error;
+ }
+
+ /* Update SPARC kernel header so that Linux knows
+ * what is going on and where to find RAM disk.
+ *
+ * Set INITRD Image address relative to RAM Start
+ */
+ linux_hdr->hdr_input.ver_0203.sparc_ramdisk_image =
+ initrd_start - CFG_RAM_BASE;
+ linux_hdr->hdr_input.ver_0203.sparc_ramdisk_size = rd_len;
+ /* Clear READ ONLY flag if set to non-zero */
+ linux_hdr->hdr_input.ver_0203.root_flags = 1;
+ /* Set root device to: Root_RAM0 */
+ linux_hdr->hdr_input.ver_0203.root_dev = 0x100;
+ linux_hdr->hdr_input.ver_0203.ram_flags = 0;
+ } else {
+ /* NOT using RAMDISK image, overwriting kernel defaults */
+ linux_hdr->hdr_input.ver_0203.sparc_ramdisk_image = 0;
+ linux_hdr->hdr_input.ver_0203.sparc_ramdisk_size = 0;
+ /* Leave to kernel defaults
+ linux_hdr->hdr_input.ver_0203.root_flags = 1;
+ linux_hdr->hdr_input.ver_0203.root_dev = 0;
+ linux_hdr->hdr_input.ver_0203.ram_flags = 0;
+ */
+ }
+
+ /* Copy bootargs from bootargs variable to kernel readable area */
+ bootargs = getenv("bootargs");
+ prepare_bootargs(bootargs);
+
+ if (!images->autostart)
+ return;
+
+ /* turn on mmu & setup context table & page table for process 0 (kernel) */
+ srmmu_init_cpu((unsigned int)kernel);
+
+ /* Enter SPARC Linux kernel
+ * From now on the only code in u-boot that will be
+ * executed is the PROM code.
+ */
+ kernel(kernel_arg_promvec, (void *)ep);
+
+ /* It will never come to this... */
+ while (1) ;
+
+ error:
+ if (images->autostart)
+ do_reset(cmdtp, flag, argc, argv);
+ return;
+}