Пример #1
0
/*
 *	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;
}
Пример #2
0
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 = &params->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;
}
Пример #3
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;
			}
		}
	}
Пример #4
0
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 = &params->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;
}