/* * Load the new kernel */ static int my_load(const char *type, int fileind, int argc, char **argv, unsigned long kexec_flags) { char *kernel; char *kernel_buf; off_t kernel_size; int i = 0; int result; struct kexec_info info; int guess_only = 0; memset(&info, 0, sizeof(info)); info.segment = NULL; info.nr_segments = 0; info.entry = NULL; info.backup_start = 0; info.kexec_flags = kexec_flags; result = 0; if (argc - fileind <= 0) { fprintf(stderr, "No kernel specified\n"); usage(); return -1; } kernel = argv[fileind]; /* slurp in the input kernel */ kernel_buf = slurp_decompress_file(kernel, &kernel_size); #if 0 fprintf(stderr, "kernel: %p kernel_size: %lx\n", kernel_buf, kernel_size); #endif if (get_memory_ranges(&info.memory_range, &info.memory_ranges, info.kexec_flags) < 0) { fprintf(stderr, "Could not get memory layout\n"); return -1; } /* if a kernel type was specified, try to honor it */ if (type) { for (i = 0; i < file_types; i++) { if (strcmp(type, file_type[i].name) == 0) break; } if (i == file_types) { fprintf(stderr, "Unsupported kernel type %s\n", type); return -1; } else { /* make sure our file is really of that type */ if (file_type[i].probe(kernel_buf, kernel_size) < 0) guess_only = 1; } } if (!type || guess_only) { for (i = 0; i < file_types; i++) { if (file_type[i].probe(kernel_buf, kernel_size) >= 0) break; } if (i == file_types) { fprintf(stderr, "Cannot determine the file type " "of %s\n", kernel); return -1; } else { if (guess_only) { fprintf(stderr, "Wrong file type %s, " "file matches type %s\n", type, file_type[i].name); return -1; } } } if (file_type[i].load(argc, argv, kernel_buf, kernel_size, &info) < 0) { fprintf(stderr, "Cannot load %s\n", kernel); return -1; } /* If we are not in native mode setup an appropriate trampoline */ if (arch_compat_trampoline(&info) < 0) { return -1; } /* Verify all of the segments load to a valid location in memory */ for (i = 0; i < info.nr_segments; i++) { if (!valid_memory_segment(&info, info.segment +i)) { fprintf(stderr, "Invalid memory segment %p - %p\n", info.segment[i].mem, ((char *)info.segment[i].mem) + info.segment[i].memsz); return -1; } } /* Sort the segments and verify we don't have overlaps */ if (sort_segments(&info) < 0) { return -1; } /* if purgatory is loaded update it */ update_purgatory(&info); #if 0 fprintf(stderr, "kexec_load: entry = %p flags = %lx\n", info.entry, info.kexec_flags); print_segments(stderr, &info); #endif result = kexec_load( info.entry, info.nr_segments, info.segment, info.kexec_flags); if (result != 0) { /* The load failed, print some debugging information */ fprintf(stderr, "kexec_load failed: %s\n", strerror(errno)); fprintf(stderr, "entry = %p flags = %lx\n", info.entry, info.kexec_flags); print_segments(stderr, &info); } return result; }
static int atag_arm_load(struct kexec_info *info, unsigned long base, const char *command_line, off_t command_line_len, const char *initrd, off_t initrd_len) { struct tag *saved_tags = atag_read_tags(); char *buf, *cmdline_buf; off_t len, cmdline_len = 0; struct tag *params; uint32_t *initrd_start; int i; buf = xmalloc(getpagesize()); if (!buf) { fprintf(stderr, "Compiling ATAGs: out of memory\n"); return -1; } cmdline_buf = xmalloc(COMMAND_LINE_SIZE); if (!cmdline_buf) { fprintf(stderr, "Compiling Command line: out of memory\n"); return -1; } memset(buf, 0xff, getpagesize()); memset((void *)cmdline_buf, 0, COMMAND_LINE_SIZE); params = (struct tag *)buf; if (saved_tags) { // Copy tags saved_tags = (struct tag *) saved_tags; while(byte_size(saved_tags)) { switch (saved_tags->hdr.tag) { case ATAG_INITRD: case ATAG_INITRD2: case ATAG_NONE: // skip these tags break; case ATAG_CMDLINE: cmdline_len = strlen(saved_tags->u.cmdline.cmdline) + 1; if(cmdline_len > COMMAND_LINE_SIZE) die("Command line overflow\n"); strncpy(cmdline_buf, saved_tags->u.cmdline.cmdline, COMMAND_LINE_SIZE); cmdline_buf[COMMAND_LINE_SIZE - 1] = '\0'; break; default: // copy all other tags memcpy(params, saved_tags, byte_size(saved_tags)); params = tag_next(params); } saved_tags = tag_next(saved_tags); } } else { params->hdr.size = 2; params->hdr.tag = ATAG_CORE; params = tag_next(params); } if (initrd) { params->hdr.size = tag_size(tag_initrd); params->hdr.tag = ATAG_INITRD2; initrd_start = ¶ms->u.initrd.start; params->u.initrd.size = initrd_len; params = tag_next(params); } if (command_line) { command_line_len = command_line_len + cmdline_len -1; if(command_line_len > COMMAND_LINE_SIZE) die("Command line overflow\n"); strncat(cmdline_buf, command_line, COMMAND_LINE_SIZE - 1); params->hdr.size = (sizeof(struct tag_header) + command_line_len + 3) >> 2; params->hdr.tag = ATAG_CMDLINE; memcpy(params->u.cmdline.cmdline, cmdline_buf, command_line_len); params->u.cmdline.cmdline[command_line_len - 1] = '\0'; params = tag_next(params); } params->hdr.size = 0; params->hdr.tag = ATAG_NONE; len = ((char *)params - buf) + sizeof(struct tag_header); add_segment(info, buf, len, base, len); if (initrd) { struct memory_range *range; int ranges; get_memory_ranges(&range, &ranges, info->kexec_flags); for (i=0; range[i].start; i++) { printf("Memory Ranges: range[%d].start = 0x%x\n", i, range[i].start); } //*initrd_start = locate_hole(info, initrd_len, getpagesize(), range[0].start + 0x800000, ULONG_MAX, INT_MAX); /* Allocate memory from 0x400000 offset from start of capture kernel*/ if (range[ranges-1].start > 0) *initrd_start = range[ranges-1].start + 0x400000; printf("*initrd_start = %p\n", *initrd_start); if (*initrd_start == ULONG_MAX) return -1; add_segment(info, initrd, initrd_len, *initrd_start, initrd_len); } return 0; }
void setup_linux_system_parameters(struct x86_linux_param_header *real_mode) { /* Fill in information the BIOS would usually provide */ struct memory_range *range; int i, ranges; /* Default screen size */ real_mode->orig_x = 0; real_mode->orig_y = 0; real_mode->orig_video_page = 0; real_mode->orig_video_mode = 0; real_mode->orig_video_cols = 80; real_mode->orig_video_lines = 25; real_mode->orig_video_ega_bx = 0; real_mode->orig_video_isVGA = 1; real_mode->orig_video_points = 16; /* Fill in the memsize later */ real_mode->ext_mem_k = 0; real_mode->alt_mem_k = 0; real_mode->e820_map_nr = 0; /* Default APM info */ memset(&real_mode->apm_bios_info, 0, sizeof(real_mode->apm_bios_info)); /* Default drive info */ memset(&real_mode->drive_info, 0, sizeof(real_mode->drive_info)); /* Default sysdesc table */ real_mode->sys_desc_table.length = 0; /* default yes: this can be overridden on the command line */ real_mode->mount_root_rdonly = 0xFFFF; /* default /dev/hda * this can be overrident on the command line if necessary. */ real_mode->root_dev = (0x3 <<8)| 0; /* another safe default */ real_mode->aux_device_info = 0; /* Fill in the memory info */ if ((get_memory_ranges(&range, &ranges) < 0) || ranges == 0) { die("Cannot get memory information\n"); } if (ranges > E820MAX) { fprintf(stderr, "Too many memory ranges, truncating...\n"); ranges = E820MAX; } real_mode->e820_map_nr = ranges; for(i = 0; i < ranges; i++) { real_mode->e820_map[i].addr = range[i].start; real_mode->e820_map[i].size = range[i].end - range[i].start; switch (range[i].type) { case RANGE_RAM: real_mode->e820_map[i].type = E820_RAM; break; case RANGE_ACPI: real_mode->e820_map[i].type = E820_ACPI; break; case RANGE_ACPI_NVS: real_mode->e820_map[i].type = E820_NVS; break; default: case RANGE_RESERVED: real_mode->e820_map[i].type = E820_RESERVED; break; } if (range[i].type != RANGE_RAM) continue; if ((range[i].start <= 0x100000) && range[i].end > 0x100000) { unsigned long long mem_k = (range[i].end >> 10) - 0x100000; real_mode->ext_mem_k = mem_k; real_mode->alt_mem_k = mem_k; if (mem_k > 0xfc00) { real_mode->ext_mem_k = 0xfc00; /* 64M */ } if (mem_k > 0xffffffff) { real_mode->alt_mem_k = 0xffffffff; } } }
int multiboot_x86_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) /* Marshal up a multiboot-style kernel */ { struct multiboot_info *mbi; void *mbi_buf; struct mod_list *modp; unsigned long freespace; unsigned long long mem_lower = 0, mem_upper = 0; struct mem_ehdr ehdr; unsigned long mbi_base; struct entry32_regs regs; size_t mbi_bytes, mbi_offset; char *command_line = NULL; char *imagename, *cp, *append = NULL;; struct memory_range *range; int ranges; struct AddrRangeDesc *mmap; int command_line_len; int i; uint32_t u; int opt; int modules, mod_command_line_space; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, 0, OPT_CL }, { "append", 1, 0, OPT_CL }, { "reuse-cmdline", 0, 0, OPT_REUSE_CMDLINE }, { "module", 1, 0, OPT_MOD }, { 0, 0, 0, 0 }, }; static const char short_options[] = KEXEC_ARCH_OPT_STR ""; /* Probe for the MB header if it's not already found */ if (mbh == NULL && multiboot_x86_probe(buf, len) != 1) { fprintf(stderr, "Cannot find a loadable multiboot header.\n"); return -1; } /* Parse the command line */ command_line = ""; command_line_len = 0; modules = 0; mod_command_line_space = 0; while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch(opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) { break; } case '?': usage(); return -1; case OPT_CL: append = optarg; break; case OPT_REUSE_CMDLINE: command_line = get_command_line(); break; case OPT_MOD: modules++; mod_command_line_space += strlen(optarg) + 1; break; } } imagename = argv[optind]; command_line = concat_cmdline(command_line, append); command_line_len = strlen(command_line) + strlen(imagename) + 2; /* Load the ELF executable */ elf_exec_build_load(info, &ehdr, buf, len, 0); /* Load the setup code */ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0, ULONG_MAX, 1, 0); /* The first segment will contain the multiboot headers: * ============= * multiboot information (mbi) * ------------- * kernel command line * ------------- * bootloader name * ------------- * module information entries * ------------- * module command lines * ============== */ mbi_bytes = (sizeof(*mbi) + command_line_len + strlen (BOOTLOADER " " BOOTLOADER_VERSION) + 1 + 3) & ~3; mbi_buf = xmalloc(mbi_bytes); mbi = mbi_buf; memset(mbi, 0, sizeof(*mbi)); sprintf(((char *)mbi) + sizeof(*mbi), "%s %s", imagename, command_line); sprintf(((char *)mbi) + sizeof(*mbi) + command_line_len, "%s", BOOTLOADER " " BOOTLOADER_VERSION); mbi->flags = MB_INFO_CMDLINE | MB_INFO_BOOT_LOADER_NAME; /* We'll relocate these to absolute addresses later. For now, * all addresses within the first segment are relative to the * start of the MBI. */ mbi->cmdline = sizeof(*mbi); mbi->boot_loader_name = sizeof(*mbi) + command_line_len; /* Memory map */ if ((get_memory_ranges(&range, &ranges, info->kexec_flags) < 0) || ranges == 0) { fprintf(stderr, "Cannot get memory information\n"); return -1; } mmap = xmalloc(ranges * sizeof(*mmap)); for (i=0; i<ranges; i++) { unsigned long long length; length = range[i].end - range[i].start; /* Translate bzImage mmap to multiboot-speak */ mmap[i].size = sizeof(mmap[i]) - 4; mmap[i].base_addr_low = range[i].start & 0xffffffff; mmap[i].base_addr_high = range[i].start >> 32; mmap[i].length_low = length & 0xffffffff; mmap[i].length_high = length >> 32; if (range[i].type == RANGE_RAM) { mmap[i].Type = 1; /* RAM */ /* Is this the "low" memory? */ if ((range[i].start == 0) && (range[i].end > mem_lower)) mem_lower = range[i].end; /* Is this the "high" memory? */ if ((range[i].start <= 0x100000) && (range[i].end > mem_upper + 0x100000)) mem_upper = range[i].end - 0x100000; } else mmap[i].Type = 0xbad; /* Not RAM */ } if (mbh->flags & MULTIBOOT_MEMORY_INFO) { /* Provide a copy of the memory map to the kernel */ mbi->flags |= MB_INFO_MEMORY | MB_INFO_MEM_MAP; freespace = add_buffer(info, mmap, ranges * sizeof(*mmap), ranges * sizeof(*mmap), 4, 0, 0xFFFFFFFFUL, 1); mbi->mmap_addr = freespace; mbi->mmap_length = ranges * sizeof(*mmap); /* For kernels that care naught for fancy memory maps * and just want the size of low and high memory */ mbi->mem_lower = MIN(mem_lower>>10, 0xffffffff); mbi->mem_upper = MIN(mem_upper>>10, 0xffffffff); /* done */ }
static int atag_arm_load(struct kexec_info *info, unsigned long base, const char *command_line, off_t command_line_len, const char *initrd, off_t initrd_len) { struct tag *saved_tags = atag_read_tags(); char *buf; off_t len; struct tag *params; uint32_t *initrd_start; buf = xmalloc(getpagesize()); if (!buf) { fprintf(stderr, "Compiling ATAGs: out of memory\n"); return -1; } memset(buf, 0xff, getpagesize()); params = (struct tag *)buf; if (saved_tags) { // Copy tags saved_tags = (struct tag *) saved_tags; while(byte_size(saved_tags)) { switch (saved_tags->hdr.tag) { case ATAG_INITRD: case ATAG_INITRD2: case ATAG_CMDLINE: case ATAG_NONE: // skip these tags break; default: // copy all other tags memcpy(params, saved_tags, byte_size(saved_tags)); params = tag_next(params); } saved_tags = tag_next(saved_tags); } } else { params->hdr.size = 2; params->hdr.tag = ATAG_CORE; params = tag_next(params); } if (initrd) { params->hdr.size = tag_size(tag_initrd); params->hdr.tag = ATAG_INITRD2; initrd_start = ¶ms->u.initrd.start; params->u.initrd.size = initrd_len; params = tag_next(params); } if (command_line) { params->hdr.size = (sizeof(struct tag_header) + command_line_len + 3) >> 2; params->hdr.tag = ATAG_CMDLINE; memcpy(params->u.cmdline.cmdline, command_line, command_line_len); params->u.cmdline.cmdline[command_line_len - 1] = '\0'; params = tag_next(params); } params->hdr.size = 0; params->hdr.tag = ATAG_NONE; len = ((char *)params - buf) + sizeof(struct tag_header); add_segment(info, buf, len, base, len); if (initrd) { struct memory_range *range; int ranges; get_memory_ranges(&range, &ranges, info->kexec_flags); *initrd_start = locate_hole(info, initrd_len, getpagesize(), range[0].start + 0x800000, ULONG_MAX, INT_MAX); if (*initrd_start == ULONG_MAX) return -1; add_segment(info, initrd, initrd_len, *initrd_start, initrd_len); } return 0; }