Beispiel #1
0
void start_kernel(struct params_t *params, int choice)
{
	/* we use var[] instead of *var because sizeof(var) using */
#ifdef USE_HOST_DEBUG
	const char kexec_path[] = "/bin/echo";
#else
	const char kexec_path[] = KEXEC_PATH;
#endif
	const char mount_point[] = MOUNTPOINT;

	const char str_cmdline_start[] = "--command-line=root=";
	const char str_rootfstype[] = " rootfstype=";
	const char str_rootwait[] = " rootwait";
	const char str_ubirootdev[] = "ubi0";
	const char str_ubimtd[] = " ubi.mtd="; /* max ' ubi.mtd=15' len 11 +1 = 12 */

#ifdef UBI_VID_HDR_OFFSET
	const char str_ubimtd_off[] = UBI_VID_HDR_OFFSET;
#else
	const char str_ubimtd_off[] = "";
#endif

	char mount_dev[16];
	char mount_fstype[16];
	char str_mtd_id[3];

	/* Tags passed from host kernel cmdline to kexec'ed kernel */
	const char str_mtdparts[] = " mtdparts=";
	const char str_fbcon[] = " fbcon=";

	const char str_initrd_start[] = "--initrd=";

	/* empty environment */
	char *const envp[] = { NULL };

	const char *load_argv[] = { NULL, "-l", NULL, NULL, NULL, NULL };
	const char *exec_argv[] = { NULL, "-e", NULL, NULL};

	char *cmdline_arg = NULL, *initrd_arg = NULL;
	int n, idx, u;
	struct stat sinfo;
	struct boot_item_t *item;

	item = params->bootcfg->list[choice];

	exec_argv[0] = kexec_path;
	load_argv[0] = kexec_path;

	/* --command-line arg generation */
	idx = 2;	/* load_argv current option index */

	/* fill '--command-line' option */
	if (item->device) {
		/* default device to mount */
		strcpy(mount_dev, item->device);

		/* allocate space */
		n = sizeof(str_cmdline_start) + strlen(item->device) +
				sizeof(str_ubirootdev) + 2 +
				sizeof(str_ubimtd) + 2 + sizeof(str_ubimtd_off) + 1 +
				sizeof(str_rootwait) +
				sizeof(str_rootfstype) + strlen(item->fstype) + 2 +
				sizeof(str_mtdparts) + strlenn(params->cfg->mtdparts) +
				sizeof(str_fbcon) + strlenn(params->cfg->fbcon) +
				sizeof(char) + strlenn(item->cmdline);

		cmdline_arg = (char *)malloc(n);
		if (NULL == cmdline_arg) {
			perror("Can't allocate memory for cmdline_arg");
		} else {

			strcpy(cmdline_arg, str_cmdline_start);	/* --command-line=root= */

			if (item->fstype) {

				/* default fstype to mount */
				strcpy(mount_fstype, item->fstype);

				/* extra tags when we detect UBI */
				if (!strncmp(item->fstype,"ubi",3)) {

					/* mtd id [0-15] - one or two digits */
					if(isdigit(atoi(item->device+strlen(item->device)-2))) {
						strcpy(str_mtd_id, item->device+strlen(item->device)-2);
						strcat(str_mtd_id, item->device+strlen(item->device)-1);
					} else {
						strcpy(str_mtd_id, item->device+strlen(item->device)-1);
					}
					/* get corresponding ubi dev to mount */
					u = find_attached_ubi_device(str_mtd_id);

					sprintf(mount_dev, "/dev/ubi%d", u);
					 /* FIXME: first volume is hardcoded */
					strcat(mount_dev, "_0");

					/* HARDCODED: we assume it's ubifs */
					strcpy(mount_fstype,"ubifs");

					/* extra cmdline tags when we detect ubi */
					strcat(cmdline_arg, str_ubirootdev);
					 /* FIXME: first volume is hardcoded */
					strcat(cmdline_arg, "_0");

					strcat(cmdline_arg, str_ubimtd);
					strcat(cmdline_arg, str_mtd_id);
#ifdef UBI_VID_HDR_OFFSET
					strcat(cmdline_arg, ",");
					strcat(cmdline_arg, str_ubimtd_off);
#endif
				} else {
					strcat(cmdline_arg, item->device); /* root=item->device */
				}
				strcat(cmdline_arg, str_rootfstype);
				strcat(cmdline_arg, mount_fstype);
			}
			strcat(cmdline_arg, str_rootwait);

			if (params->cfg->mtdparts) {
				strcat(cmdline_arg, str_mtdparts);
				strcat(cmdline_arg, params->cfg->mtdparts);
			}

			if (params->cfg->fbcon) {
				strcat(cmdline_arg, str_fbcon);
				strcat(cmdline_arg, params->cfg->fbcon);
			}

			if (item->cmdline) {
				strcat(cmdline_arg, " ");
				strcat(cmdline_arg, item->cmdline);
			}
			load_argv[idx] = cmdline_arg;
			++idx;
		}
	}

	/* fill '--initrd' option */
	if (item->initrd) {
		/* allocate space */
		n = sizeof(str_initrd_start) + strlen(item->initrd);

		initrd_arg = (char *)malloc(n);
		if (NULL == initrd_arg) {
			perror("Can't allocate memory for initrd_arg");
		} else {
			strcpy(initrd_arg, str_initrd_start);	/* --initrd= */
			strcat(initrd_arg, item->initrd);
			load_argv[idx] = initrd_arg;
			++idx;
		}
	}

	/* Append kernelpath as last arg of kexec */
	load_argv[idx] = item->kernelpath;

	DPRINTF("load_argv: %s, %s, %s, %s, %s", load_argv[0],
			load_argv[1], load_argv[2],
			load_argv[3], load_argv[4]);

	/* Mount boot device */
	if ( -1 == mount(mount_dev, mount_point, mount_fstype,
			MS_RDONLY, NULL) ) {
		perror("Can't mount boot device");
		exit(-1);
	}

	/* Load kernel */
	n = fexecw(kexec_path, (char *const *)load_argv, envp);
	if (-1 == n) {
		perror("Kexec can't load kernel");
		exit(-1);
	}

	umount(mount_point);

	dispose(cmdline_arg);
	dispose(initrd_arg);

	/* Check /proc/sys/net presence */
	if ( -1 == stat("/proc/sys/net", &sinfo) ) {
		if (ENOENT == errno) {
			/* We have no network, don't issue ifdown() while kexec'ing */
			exec_argv[2] = "-x";
			DPRINTF("No network is detected, disabling ifdown()");
		} else {
			perror("Can't stat /proc/sys/net");
		}
	}

	DPRINTF("exec_argv: %s, %s, %s", exec_argv[0],
			exec_argv[1], exec_argv[2]);

	/* Boot new kernel */
	execve(kexec_path, (char *const *)exec_argv, envp);
}
Beispiel #2
0
void start_kernel(struct params_t *params, int choice)
{
	int n, idx, u;
	struct stat sinfo;
	struct boot_item_t *item;

	char mount_dev[16];
	char mount_fstype[16];
	char str_mtd_id[3];

	/* empty environment */
	char *const envp[] = { NULL };

	/* options set during configuration */
	const char mount_point[] = MOUNTPOINT;

	/* for --command-line */
	char *cmdline_arg = NULL;
	const char str_cmdline_start[] = "--command-line=";
#ifdef UBI_VID_HDR_OFFSET
	const char str_ubimtd_off[] = "," UBI_VID_HDR_OFFSET;
#else
	const char str_ubimtd_off[] = "";
#endif

	/* selected cmdline tags read from host kernel cmdline */
	const char str_mtdparts[] = " mtdparts=";
	const char str_fbcon[] = " fbcon=";

	/* initialize args */
	char **load_argv, **exec_argv;

	load_argv = calloc(MAX_LOAD_ARGV_NR, sizeof(*load_argv));
	if (!load_argv)
		return;

	exec_argv = calloc(MAX_EXEC_ARGV_NR, sizeof(*exec_argv));
	if (!exec_argv) {
		free(load_argv);
		return;
	}

	/*len of following strings is known at compile time */
	idx = 0;
#ifdef USE_HOST_DEBUG
	load_argv[idx] = strdup("/bin/echo");
	exec_argv[idx] = strdup(load_argv[idx]);
#else
	load_argv[idx] = strdup(KEXEC_PATH);
	exec_argv[idx] = strdup(load_argv[idx]);
#endif
	idx++;

	load_argv[idx] = strdup("-d");
	exec_argv[idx] = strdup("-e");
	idx++;

#ifdef MEM_MIN
	load_argv[idx] = asprintf("--mem-min=0x%08x", MEM_MIN);
	idx++;
#endif

#ifdef MEM_MAX
	load_argv[idx] = asprintf("--mem-max==0x%08x", MEM_MAX);
	idx++;
#endif

#ifdef USE_HARDBOOT
	load_argv[idx] = strdup("--load-hardboot");
#else
	load_argv[idx] = strdup("-l");
#endif
	idx++;

#ifdef USE_ATAGS
	load_argv[idx] = strdup("--atags");
	idx++;
#endif

#ifdef USE_NO_DTB
	load_argv[idx] = strdup("--no-dtb");
	idx++;
#endif

#ifdef USE_NO_CHECKS
	load_argv[idx] = strdup("-i");
	idx++;
#endif

#ifdef USE_KEXEC_FILE_SYSCALL
	load_argv[idx] = strdup("-s");
	idx++;
#elif defined(USE_KEXEC_SYSCALL)
	load_argv[idx] = strdup("-c");
	idx++;
#endif

	/* size is only known at runtime */
	item = params->bootcfg->list[choice];


	/* fll '--command-line' option */
	if (item->device) {
		/* default device to mount */
		strcpy(mount_dev, item->device);

		/* default fstype to mount */
		strcpy(mount_fstype, item->fstype);

		/* Overwrite if CMDLINE is configured, append if APPEND is configured */
		if (item->cmdline) {
			add_cmd_option(load_argv, str_cmdline_start, item->cmdline, &idx);
		} else {
			/* allocate space FIXME */
			cmdline_arg = malloc(MAX_ARG_LEN);
			if (NULL == cmdline_arg)
				perror("Can't allocate memory for cmdline_arg");

			strcpy(cmdline_arg, str_cmdline_start);	/* --command-line= */
			strcat(cmdline_arg, "root=");

			if (item->fstype) {

				/* inject extra tags for UBI */
				if (!check_for_ubi(item, cmdline_arg,
						   mount_dev, mount_fstype,
						   "ubi0", " ubi.mtd=",
						   str_mtd_id, str_ubimtd_off))
					strcat(cmdline_arg, item->device);

				strcat(cmdline_arg, " rootfstype=");
				strcat(cmdline_arg, mount_fstype);
			}

			strcat(cmdline_arg, " rootwait");

			if (params->cfg->mtdparts) {
				strcat(cmdline_arg, str_mtdparts);
				strcat(cmdline_arg, params->cfg->mtdparts);
			}

			if (params->cfg->fbcon) {
				strcat(cmdline_arg, str_fbcon);
				strcat(cmdline_arg, params->cfg->fbcon);
			}

			if (item->cmdline_append) {
				strcat(cmdline_arg, " ");
				strcat(cmdline_arg, item->cmdline_append);
			}
			load_argv[idx] = cmdline_arg;
			++idx;
		}
	}

	add_cmd_option(load_argv, "--dtb=", item->dtbpath, &idx);
	add_cmd_option(load_argv, "--initrd=", item->initrd, &idx);
	add_cmd_option(load_argv, NULL, item->kernelpath, &idx);

	for(u = 0; u < idx; u++) {
		DPRINTF("load_argv[%d]: %s", u, load_argv[u]);
	}

	/* Mount boot device */
	if ( -1 == mount(mount_dev, mount_point, mount_fstype,
			MS_RDONLY, NULL) ) {
		perror("Can't mount boot device");
		exit(-1);
	}

	/* Load kernel */
	n = fexecw(load_argv[0], (char *const *)load_argv, envp);
	if (-1 == n) {
		perror("Kexec can't load kernel");
		exit(-1);
	}

	umount(mount_point);

	dispose(cmdline_arg);

	/* Check /proc/sys/net presence */
	if ( -1 == stat("/proc/sys/net", &sinfo) ) {
		if (ENOENT == errno) {
			/* We have no network, don't issue ifdown() while kexec'ing */
			exec_argv[2] = "-x";
			DPRINTF("No network is detected, disabling ifdown()");
		} else {
			perror("Can't stat /proc/sys/net");
		}
	}

	DPRINTF("exec_argv: %s, %s, %s, %s", exec_argv[0],
			exec_argv[1], exec_argv[2], exec_argv[3]);

	/* Boot new kernel */
	execve(exec_argv[0], (char *const *)exec_argv, envp);

free:
	dispose(cmdline_arg);
	for (idx = 0; idx < MAX_LOAD_ARGV_NR; idx++)
		free(load_argv[idx]);
	dispose(load_argv);
	for (idx = 0; idx < MAX_EXEC_ARGV_NR; idx++)
		free(exec_argv[idx]);
	dispose(exec_argv);
}