/* * (C) Copyright 2000-2006 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * 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 */ /* * Boot support */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Continue booting an OS image; caller already has: * - copied image header to global variable `header' * - checked header magic number, checksums (both header & image), * - verified image architecture (PPC) and type (KERNEL or MULTI), * - loaded (first part of) image to header load address, * - disabled interrupts. */ typedef void boot_os_Fcn(struct command *cmdtp, int flag, int argc, char *argv[], ulong addr, /* of image to boot */ ulong *len_ptr, /* multi-file image length table */ int verify); /* getenv("verify")[0] != 'n' */ #ifndef CFG_BOOTM_LEN #define CFG_BOOTM_LEN 0x800000 /* use 8MByte as default max gunzip size */ #endif #ifdef CONFIG_SILENT_CONSOLE static void fixup_silent_linux () { char buf[256], *start, *end; char *cmdline = getenv ("bootargs"); /* Only fix cmdline when requested */ if (!(gd->flags & GD_FLG_SILENT)) return; debug ("before silent fix-up: %s\n", cmdline); if (cmdline) { if ((start = strstr (cmdline, "console=")) != NULL) { end = strchr (start, ' '); strncpy (buf, cmdline, (start - cmdline + 8)); if (end) strcpy (buf + (start - cmdline + 8), end); else buf[start - cmdline + 8] = '\0'; } else { strcpy (buf, cmdline); strcat (buf, " console="); } } else { strcpy (buf, "console="); } setenv ("bootargs", buf); debug ("after silent fix-up: %s\n", buf); } #endif /* CONFIG_SILENT_CONSOLE */ struct image_handle_data* image_handle_data_get_by_num(struct image_handle* handle, int num) { if (!handle || num < 0 || num >= handle->nb_data_entries) return NULL; return &handle->data_entries[num]; } int relocate_image(struct image_handle *handle, void *load_address) { image_header_t *hdr = &handle->header; unsigned long len = image_get_size(hdr); struct image_handle_data *iha; unsigned long data; #if defined CONFIG_CMD_BOOTM_ZLIB || defined CONFIG_CMD_BOOTM_BZLIB uint unc_len = CFG_BOOTM_LEN; #endif iha = image_handle_data_get_by_num(handle, 0); data = (unsigned long)(iha->data); switch (image_get_comp(hdr)) { case IH_COMP_NONE: if(image_get_load(hdr) == data) { printf (" XIP ... "); } else { memmove ((void *) image_get_load(hdr), (uchar *)data, len); } break; #ifdef CONFIG_CMD_BOOTM_ZLIB case IH_COMP_GZIP: printf (" Uncompressing ... "); if (gunzip (load_address, unc_len, (uchar *)data, &len) != 0) return -1; break; #endif #ifdef CONFIG_CMD_BOOTM_BZLIB case IH_COMP_BZIP2: printf (" Uncompressing ... "); /* * If we've got less than 4 MB of malloc() space, * use slower decompression algorithm which requires * at most 2300 KB of memory. */ if (BZ2_bzBuffToBuffDecompress (load_address, &unc_len, (char *)data, len, MALLOC_SIZE < (4096 * 1024), 0) != BZ_OK) return -1; break; #endif default: printf("Unimplemented compression type %d\n", image_get_comp(hdr)); return -1; } return 0; } EXPORT_SYMBOL(relocate_image); static LIST_HEAD(handler_list); int register_image_handler(struct image_handler *handler) { list_add_tail(&handler->list, &handler_list); return 0; } /* * generate a image_handle from a multi_image * this image_handle can be free by unmap_image */ static struct image_handle *get_fake_image_handle(struct image_data *data, int num) { struct image_handle *handle; struct image_handle_data* iha; image_header_t *header; iha = image_handle_data_get_by_num(data->os, num); handle = xzalloc(sizeof(struct image_handle)); header = &handle->header; handle->data_entries = gen_image_handle_data(iha->data, iha->len); handle->nb_data_entries = 1; header->ih_size = cpu_to_uimage(iha->len); handle->data = handle->data_entries[0].data; return handle; } static int initrd_handler_parse_options(struct image_data *data, int opt, char *optarg) { uint32_t initrd_start; switch(opt) { case 'L': if (!data->initrd) { eprintf("Warning -L ingnored. Specify the initrd first\n"); break; } initrd_start = simple_strtoul(optarg, NULL, 0); printf("initrd_start=0x%x\n", initrd_start); data->initrd->header.ih_load = cpu_to_uimage(initrd_start); break; case 'r': printf("use initrd %s\n", optarg); /* check for multi image @ */ if (optarg[0] == '@') { int num = simple_strtol(optarg + 1, NULL, 0); data->initrd = get_fake_image_handle(data, num); } else { data->initrd = map_image(optarg, data->verify); } if (!data->initrd) return -1; break; default: return 1; } return 0; } static struct image_handler initrd_handler = { .cmdline_options = "r:L:", .cmdline_parse = initrd_handler_parse_options, .help_string = " -r specify an initrd image\n" " -L specify initrd load address", }; static int initrd_register_image_handler(void) { return register_image_handler(&initrd_handler); } late_initcall(initrd_register_image_handler); static int handler_parse_options(struct image_data *data, int opt, char *optarg) { struct image_handler *handler; int ret; list_for_each_entry(handler, &handler_list, list) { if (!handler->cmdline_parse) continue; ret = handler->cmdline_parse(data, opt, optarg); if (ret > 0) continue; return ret; } return -1; } static int do_bootm(struct command *cmdtp, int argc, char *argv[]) { int opt; image_header_t *os_header; struct image_handle *os_handle, *initrd_handle = NULL; struct image_handler *handler; struct image_data data; char options[53]; /* worst case: whole alphabet with colons */ memset(&data, 0, sizeof(struct image_data)); data.verify = 1; /* Collect options from registered handlers */ strcpy(options, "nh"); list_for_each_entry(handler, &handler_list, list) { if (handler->cmdline_options) strcat(options, handler->cmdline_options); } while((opt = getopt(argc, argv, options)) > 0) { switch(opt) { case 'n': data.verify = 0; break; case 'h': printf("bootm advanced options:\n"); list_for_each_entry(handler, &handler_list, list) { if (handler->help_string) printf("%s\n", handler->help_string); } return 0; default: break; } } if (optind == argc) return COMMAND_ERROR_USAGE; os_handle = map_image(argv[optind], data.verify); if (!os_handle) return 1; data.os = os_handle; os_header = &os_handle->header; if (image_get_arch(os_header) != IH_ARCH) { printf("Unsupported Architecture 0x%x\n", image_get_arch(os_header)); goto err_out; } optind = 0; while((opt = getopt(argc, argv, options)) > 0) { switch(opt) { case 'h': case 'n': break; default: if (!handler_parse_options(&data, opt, optarg)) continue; return 1; } } /* * We have reached the point of no return: we are going to * overwrite all exception vector code, so we cannot easily * recover from any failures any more... */ disable_interrupts(); puts ("OK\n"); /* loop through the registered handlers */ list_for_each_entry(handler, &handler_list, list) { if (image_get_os(os_header) == handler->image_type) { handler->bootm(&data); printf("handler returned!\n"); goto err_out; } } printf("no image handler found for image type %d\n", image_get_os(os_header)); err_out: if (os_handle) unmap_image(os_handle); if (initrd_handle) unmap_image(initrd_handle); return 1; } BAREBOX_CMD_HELP_START(bootm) BAREBOX_CMD_HELP_USAGE("bootm [-n] image\n") BAREBOX_CMD_HELP_SHORT("Boot an application image.\n") BAREBOX_CMD_HELP_OPT ("-n", "Do not verify the image (speeds up boot process)\n") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(bootm) .cmd = do_bootm, .usage = "boot an application image", BAREBOX_CMD_HELP(cmd_bootm_help) BAREBOX_CMD_END /** * @page bootm_command \todo What does bootm do, what kind of image does it boot? */ #ifdef CONFIG_CMD_IMI static int do_iminfo(struct command *cmdtp, int argc, char *argv[]) { int arg; ulong addr; int rcode=0; if (argc < 2) { return image_info (load_addr); } for (arg=1; arg ih_hcrc = 0; if (crc32 (0, (uchar *)data, len) != checksum) { puts (" Bad Header Checksum\n"); return 1; } /* for multi-file images we need the data part, too */ print_image_hdr ((image_header_t *)addr); data = addr + image_get_header_size(); len = image_get_size(hdr); puts (" Verifying Checksum ... "); if (crc32 (0, (uchar *)data, len) != image_get_dcrc(hdr)) { puts (" Bad Data CRC\n"); return 1; } puts ("OK\n"); return 0; } BAREBOX_CMD_HELP_START(iminfo) BAREBOX_CMD_HELP_USAGE("iminfo\n") BAREBOX_CMD_HELP_SHORT("Print header information for an application image.\n") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(iminfo) .cmd = do_iminfo, .usage = "print header information for an application image", BAREBOX_CMD_HELP(cmd_iminfo_help) BAREBOX_CMD_END #endif /* CONFIG_CMD_IMI */ #ifdef CONFIG_BZLIB void bz_internal_error(int errcode) { printf ("BZIP2 internal error %d\n", errcode); } #endif /* CONFIG_BZLIB */ /** * @file * @brief Boot support for Linux */ /** * @page boot_preparation Preparing for Boot * * This chapter describes what's to be done to forward the control from * barebox to Linux. This part describes the generic part, below you can find * the architecture specific part. * * - @subpage arm_boot_preparation * - @subpage ppc_boot_preparation * - @subpage x86_boot_preparation */