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); }
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); }