Refactor kexec loading, add support for standalone dtb.img
This commit is contained in:
@@ -23,7 +23,8 @@ LOCAL_SRC_FILES:= \
|
|||||||
fstab.c \
|
fstab.c \
|
||||||
workers.c \
|
workers.c \
|
||||||
containers.c \
|
containers.c \
|
||||||
rom_quirks.c
|
rom_quirks.c \
|
||||||
|
kexec.c
|
||||||
|
|
||||||
ifeq ($(ARCH_ARM_HAVE_NEON),true)
|
ifeq ($(ARCH_ARM_HAVE_NEON),true)
|
||||||
LOCAL_SRC_FILES += col32cb16blend_neon.S
|
LOCAL_SRC_FILES += col32cb16blend_neon.S
|
||||||
|
|||||||
114
kexec.c
Normal file
114
kexec.c
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of MultiROM.
|
||||||
|
*
|
||||||
|
* MultiROM 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 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* MultiROM 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 MultiROM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "kexec.h"
|
||||||
|
#include "containers.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
// kexec --load-hardboot ./zImage --command-line="$(cat /proc/cmdline)" --mem-min=0xA0000000 --initrd=./rd.img
|
||||||
|
// --mem-min should be somewhere in System RAM (see /proc/iomem). Location just above kernel seems to work fine.
|
||||||
|
// It must not conflict with vmalloc ram. Vmalloc area seems to be allocated from top of System RAM.
|
||||||
|
|
||||||
|
void kexec_init(struct kexec *k, const char *path)
|
||||||
|
{
|
||||||
|
k->args = NULL;
|
||||||
|
kexec_add_arg(k, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kexec_destroy(struct kexec *k)
|
||||||
|
{
|
||||||
|
list_clear(&k->args, &free);
|
||||||
|
}
|
||||||
|
|
||||||
|
int kexec_load_exec(struct kexec *k)
|
||||||
|
{
|
||||||
|
int i, len;
|
||||||
|
|
||||||
|
INFO("Loading kexec:\n");
|
||||||
|
for(i = 0; k->args && k->args[i]; ++i)
|
||||||
|
{
|
||||||
|
len = strlen(k->args[i]);
|
||||||
|
|
||||||
|
if(len < 480)
|
||||||
|
INFO(" %s\n", k->args[i]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char buff[481];
|
||||||
|
char *itr;
|
||||||
|
const char *end = k->args[i]+len;
|
||||||
|
int chunk = 0;
|
||||||
|
|
||||||
|
for(itr = k->args[i]; itr < end; itr += chunk)
|
||||||
|
{
|
||||||
|
chunk = imin(480, end - itr);
|
||||||
|
|
||||||
|
memcpy(buff, itr, chunk);
|
||||||
|
buff[chunk] = 0;
|
||||||
|
|
||||||
|
INFO(" %s\n", buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(run_cmd(k->args) == 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("kexec call failed, re-running it to get info:\n");
|
||||||
|
char *r = run_get_stdout(k->args);
|
||||||
|
if(!r)
|
||||||
|
ERROR("run_get_stdout returned NULL!\n");
|
||||||
|
|
||||||
|
char *p = strtok(r, "\n\r");
|
||||||
|
while(p)
|
||||||
|
{
|
||||||
|
ERROR(" %s\n", p);
|
||||||
|
p = strtok(NULL, "\n\r");
|
||||||
|
}
|
||||||
|
free(r);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kexec_add_arg(struct kexec *k, const char *arg)
|
||||||
|
{
|
||||||
|
list_add(strdup(arg), &k->args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kexec_add_arg_prefix(struct kexec *k, const char *prefix, const char *value)
|
||||||
|
{
|
||||||
|
int len = strlen(prefix) + strlen(value) + 1;
|
||||||
|
char *arg = malloc(len);
|
||||||
|
snprintf(arg, len, "%s%s", prefix, value);
|
||||||
|
|
||||||
|
list_add(arg, &k->args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kexec_add_kernel(struct kexec *k, const char *path, int hardboot)
|
||||||
|
{
|
||||||
|
if(hardboot)
|
||||||
|
kexec_add_arg(k, "--load-hardboot");
|
||||||
|
else
|
||||||
|
kexec_add_arg(k, "-l");
|
||||||
|
kexec_add_arg(k, path);
|
||||||
|
}
|
||||||
33
kexec.h
Normal file
33
kexec.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of MultiROM.
|
||||||
|
*
|
||||||
|
* MultiROM 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 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* MultiROM 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 MultiROM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEXEC_H
|
||||||
|
#define KEXEC_H
|
||||||
|
|
||||||
|
struct kexec
|
||||||
|
{
|
||||||
|
char **args;
|
||||||
|
};
|
||||||
|
|
||||||
|
void kexec_init(struct kexec *k, const char *path);
|
||||||
|
void kexec_destroy(struct kexec *k);
|
||||||
|
int kexec_load_exec(struct kexec *k);
|
||||||
|
void kexec_add_arg(struct kexec *k, const char *arg);
|
||||||
|
void kexec_add_arg_prefix(struct kexec *k, const char *prefix, const char *value);
|
||||||
|
void kexec_add_kernel(struct kexec *k, const char *path, int hardboot);
|
||||||
|
|
||||||
|
#endif
|
||||||
152
multirom.c
152
multirom.c
@@ -47,6 +47,7 @@
|
|||||||
#include "hooks.h"
|
#include "hooks.h"
|
||||||
#include "containers.h"
|
#include "containers.h"
|
||||||
#include "rom_quirks.h"
|
#include "rom_quirks.h"
|
||||||
|
#include "kexec.h"
|
||||||
|
|
||||||
#define REALDATA "/realdata"
|
#define REALDATA "/realdata"
|
||||||
#define BUSYBOX_BIN "busybox"
|
#define BUSYBOX_BIN "busybox"
|
||||||
@@ -1485,6 +1486,10 @@ int multirom_find_file(char *res, const char *name_part, const char *path)
|
|||||||
|
|
||||||
int multirom_load_kexec(struct multirom_status *s, struct multirom_rom *rom)
|
int multirom_load_kexec(struct multirom_status *s, struct multirom_rom *rom)
|
||||||
{
|
{
|
||||||
|
int res = -1;
|
||||||
|
struct kexec kexec;
|
||||||
|
int loop_mounted = 0;
|
||||||
|
|
||||||
// to find /data partition
|
// to find /data partition
|
||||||
if(!rom->partition && multirom_update_partitions(s) < 0)
|
if(!rom->partition && multirom_update_partitions(s) < 0)
|
||||||
{
|
{
|
||||||
@@ -1492,35 +1497,20 @@ int multirom_load_kexec(struct multirom_status *s, struct multirom_rom *rom)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = -1;
|
kexec_init(&kexec, kexec_path);
|
||||||
// kexec --load-hardboot ./zImage --command-line="$(cat /proc/cmdline)" --mem-min=0xA0000000 --initrd=./rd.img
|
kexec_add_arg(&kexec, "--mem-min="MR_KEXEC_MEM_MIN);
|
||||||
// --mem-min should be somewhere in System RAM (see /proc/iomem). Location just above kernel seems to work fine.
|
|
||||||
// It must not conflict with vmalloc ram. Vmalloc area seems to be allocated from top of System RAM.
|
|
||||||
char *cmd[] = {
|
|
||||||
kexec_path, // 0
|
|
||||||
"--load-hardboot", // 1
|
|
||||||
malloc(1024), // 2 - path to zImage
|
|
||||||
"--mem-min="MR_KEXEC_MEM_MIN, // 3
|
|
||||||
malloc(1024), // 4 - --initrd=<path to initrd>
|
|
||||||
malloc(2048), // 5 - --command-line=<cmdline>
|
|
||||||
#ifdef MR_KEXEC_DTB
|
|
||||||
"--dtb", // 6
|
|
||||||
#endif
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
int loop_mounted = 0;
|
|
||||||
switch(rom->type)
|
switch(rom->type)
|
||||||
{
|
{
|
||||||
case ROM_ANDROID_INTERNAL:
|
case ROM_ANDROID_INTERNAL:
|
||||||
case ROM_ANDROID_USB_DIR:
|
case ROM_ANDROID_USB_DIR:
|
||||||
case ROM_ANDROID_USB_IMG:
|
case ROM_ANDROID_USB_IMG:
|
||||||
if(multirom_fill_kexec_android(s, rom, cmd) != 0)
|
if(multirom_fill_kexec_android(s, rom, &kexec) != 0)
|
||||||
goto exit;
|
goto exit;
|
||||||
break;
|
break;
|
||||||
case ROM_LINUX_INTERNAL:
|
case ROM_LINUX_INTERNAL:
|
||||||
case ROM_LINUX_USB:
|
case ROM_LINUX_USB:
|
||||||
loop_mounted = multirom_fill_kexec_linux(s, rom, cmd);
|
loop_mounted = multirom_fill_kexec_linux(s, rom, &kexec);
|
||||||
if(loop_mounted < 0)
|
if(loop_mounted < 0)
|
||||||
goto exit;
|
goto exit;
|
||||||
break;
|
break;
|
||||||
@@ -1529,36 +1519,7 @@ int multirom_load_kexec(struct multirom_status *s, struct multirom_rom *rom)
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ERROR("Loading kexec: %s %s %s %s %s\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]);
|
res = kexec_load_exec(&kexec);
|
||||||
ERROR("With cmdline: ");
|
|
||||||
char *itr = cmd[5];
|
|
||||||
int len;
|
|
||||||
for(len = strlen(itr); len > 0; len = strlen(itr))
|
|
||||||
{
|
|
||||||
if(len > 450)
|
|
||||||
len = 450;
|
|
||||||
char *b = strndup(itr, len);
|
|
||||||
ERROR(" %s\n", b);
|
|
||||||
free(b);
|
|
||||||
itr += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(run_cmd(cmd) == 0)
|
|
||||||
res = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERROR("kexec call failed, re-running it to get info:\n");
|
|
||||||
char *r = run_get_stdout(cmd);
|
|
||||||
if(!r)
|
|
||||||
ERROR("run_get_stdout returned NULL!\n");
|
|
||||||
char *p = strtok(r, "\n\r");
|
|
||||||
while(p)
|
|
||||||
{
|
|
||||||
ERROR(" %s\n", p);
|
|
||||||
p = strtok(NULL, "\n\r");
|
|
||||||
}
|
|
||||||
free(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *cmd_cp[] = { busybox_path, "cp", kexec_path, "/kexec", NULL };
|
char *cmd_cp[] = { busybox_path, "cp", kexec_path, "/kexec", NULL };
|
||||||
run_cmd(cmd_cp);
|
run_cmd(cmd_cp);
|
||||||
@@ -1570,13 +1531,11 @@ int multirom_load_kexec(struct multirom_status *s, struct multirom_rom *rom)
|
|||||||
multirom_copy_log(NULL);
|
multirom_copy_log(NULL);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
free(cmd[2]);
|
kexec_destroy(&kexec);
|
||||||
free(cmd[4]);
|
|
||||||
free(cmd[5]);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int multirom_fill_kexec_android(struct multirom_status *s, struct multirom_rom *rom, char **cmd)
|
int multirom_fill_kexec_android(struct multirom_status *s, struct multirom_rom *rom, struct kexec *kexec)
|
||||||
{
|
{
|
||||||
int res = -1;
|
int res = -1;
|
||||||
char img_path[256];
|
char img_path[256];
|
||||||
@@ -1591,9 +1550,20 @@ int multirom_fill_kexec_android(struct multirom_status *s, struct multirom_rom *
|
|||||||
|
|
||||||
if(libbootimg_dump_kernel(&img, "/zImage") < 0)
|
if(libbootimg_dump_kernel(&img, "/zImage") < 0)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
if(libbootimg_dump_ramdisk(&img, "/initrd.img") < 0)
|
if(libbootimg_dump_ramdisk(&img, "/initrd.img") < 0)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
kexec_add_kernel(kexec, "/zImage", 1);
|
||||||
|
kexec_add_arg(kexec, "--initrd=/initrd.img");
|
||||||
|
|
||||||
|
#ifdef MR_KEXEC_DTB
|
||||||
|
if(libbootimg_dump_dtb(&img, "/dtb.img") >= 0)
|
||||||
|
kexec_add_arg(kexec, "--dtb=/dtb.img");
|
||||||
|
else
|
||||||
|
kexec_add_arg(kexec, "--dtb");
|
||||||
|
#endif
|
||||||
|
|
||||||
// Trampolines in ROM boot images may get out of sync, so we need to check it and
|
// Trampolines in ROM boot images may get out of sync, so we need to check it and
|
||||||
// update if needed. I can't do that during ZIP installation because of USB drives.
|
// update if needed. I can't do that during ZIP installation because of USB drives.
|
||||||
// That header.name is added by recovery.
|
// That header.name is added by recovery.
|
||||||
@@ -1624,35 +1594,32 @@ int multirom_fill_kexec_android(struct multirom_status *s, struct multirom_rom *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char cmdline[1024];
|
char cmdline[1536];
|
||||||
if(multirom_get_bootloader_cmdline(s, cmdline, sizeof(cmdline)) == -1)
|
strcpy(cmdline, "--command-line=");
|
||||||
{
|
|
||||||
ERROR("Failed to get cmdline\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(cmd[2], "/zImage");
|
|
||||||
strcpy(cmd[4], "--initrd=/initrd.img");
|
|
||||||
|
|
||||||
strcpy(cmd[5], "--command-line=");
|
|
||||||
if(img.hdr.cmdline[0] != 0)
|
if(img.hdr.cmdline[0] != 0)
|
||||||
{
|
{
|
||||||
img.hdr.cmdline[BOOT_ARGS_SIZE-1] = 0;
|
img.hdr.cmdline[BOOT_ARGS_SIZE-1] = 0;
|
||||||
|
|
||||||
// see multirom_get_bootloader_cmdline
|
// see multirom_get_bootloader_cmdline
|
||||||
#ifdef FLO_CMDLINE_HACK
|
#ifdef FLO_CMDLINE_HACK
|
||||||
strcat(cmd[5], (char*)img.hdr.cmdline+26);
|
strcat(cmdline, (char*)img.hdr.cmdline+26);
|
||||||
#else
|
#else
|
||||||
strcat(cmd[5], (char*)img.hdr.cmdline);
|
strcat(cmdline, (char*)img.hdr.cmdline);
|
||||||
#endif
|
#endif
|
||||||
strcat(cmd[5], " ");
|
strcat(cmdline, " ");
|
||||||
}
|
}
|
||||||
if(cmdline[0] != 0)
|
|
||||||
|
if(multirom_get_bootloader_cmdline(s, cmdline+strlen(cmdline), sizeof(cmdline)-strlen(cmdline)-1) == -1)
|
||||||
{
|
{
|
||||||
strcat(cmd[5], cmdline);
|
ERROR("Failed to get cmdline\n");
|
||||||
strcat(cmd[5], " ");
|
goto exit;
|
||||||
}
|
}
|
||||||
strcat(cmd[5], "mrom_kexecd=1");
|
|
||||||
|
if(sizeof(cmdline)-strlen(cmdline)-1 >= sizeof("mrom_kexecd=1"))
|
||||||
|
strcat(cmdline, "mrom_kexecd=1");
|
||||||
|
|
||||||
|
kexec_add_arg(kexec, cmdline);
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
exit:
|
exit:
|
||||||
@@ -1693,7 +1660,7 @@ static char *find_boot_file(char *path, char *root_path, char *base_path)
|
|||||||
return strdup(res);
|
return strdup(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
int multirom_fill_kexec_linux(struct multirom_status *s, struct multirom_rom *rom, char **cmd)
|
int multirom_fill_kexec_linux(struct multirom_status *s, struct multirom_rom *rom, struct kexec *kexec)
|
||||||
{
|
{
|
||||||
struct rom_info *info = multirom_parse_rom_info(s, rom);
|
struct rom_info *info = multirom_parse_rom_info(s, rom);
|
||||||
if(!info)
|
if(!info)
|
||||||
@@ -1754,24 +1721,49 @@ int multirom_fill_kexec_linux(struct multirom_status *s, struct multirom_rom *ro
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *str = find_boot_file(map_get_val(info->str_vals, "kernel_path"), root_path, rom->base_path);
|
char *str = find_boot_file(map_get_val(info->str_vals, "kernel_path"), root_path, rom->base_path);
|
||||||
if(!str)
|
if(str)
|
||||||
|
{
|
||||||
|
kexec_add_kernel(kexec, str, 1);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// kernel is required
|
||||||
goto exit;
|
goto exit;
|
||||||
|
}
|
||||||
cmd[2] = str;
|
|
||||||
|
|
||||||
str = find_boot_file(map_get_val(info->str_vals, "initrd_path"), root_path, rom->base_path);
|
str = find_boot_file(map_get_val(info->str_vals, "initrd_path"), root_path, rom->base_path);
|
||||||
if(str)
|
if(str)
|
||||||
{
|
{
|
||||||
sprintf(cmd[4], "--initrd=%s", str);
|
kexec_add_arg_prefix(kexec, "--initrd=", str);
|
||||||
free(str);
|
free(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(cmd[5], "--command-line=%s ", (char*)map_get_val(info->str_vals, "base_cmdline"));
|
char cmdline[1536];
|
||||||
|
snprintf(cmdline, sizeof(cmdline), "--command-line=%s ", (char*)map_get_val(info->str_vals, "base_cmdline"));
|
||||||
|
|
||||||
if(root_type == 0 && (str = map_get_val(info->str_vals, "dir_cmdline")))
|
str = NULL;
|
||||||
strcat(cmd[5], str);
|
if(root_type == 0)
|
||||||
else if(root_type == 1 && (str = map_get_val(info->str_vals, "img_cmdline")))
|
str = map_get_val(info->str_vals, "dir_cmdline");
|
||||||
strcat(cmd[5], str);
|
else if(root_type == 1)
|
||||||
|
str = map_get_val(info->str_vals, "img_cmdline");
|
||||||
|
|
||||||
|
if(str)
|
||||||
|
{
|
||||||
|
if(strlen(str)+strlen(cmdline)+1 <= sizeof(cmdline))
|
||||||
|
strcat(cmdline, str);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR("failed to fill kexec info, cmdline is too long!\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kexec_add_arg(kexec, cmdline);
|
||||||
|
|
||||||
|
#ifdef MR_KEXEC_DTB
|
||||||
|
kexec_add_arg(kexec, "--dtb");
|
||||||
|
#endif
|
||||||
|
|
||||||
res = loop_mounted;
|
res = loop_mounted;
|
||||||
exit:
|
exit:
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "fstab.h"
|
#include "fstab.h"
|
||||||
#include "containers.h"
|
#include "containers.h"
|
||||||
|
#include "kexec.h"
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -139,8 +140,8 @@ int multirom_has_kexec(void);
|
|||||||
int multirom_load_kexec(struct multirom_status *s, struct multirom_rom *rom);
|
int multirom_load_kexec(struct multirom_status *s, struct multirom_rom *rom);
|
||||||
int multirom_get_bootloader_cmdline(struct multirom_status *s, char *str, size_t size);
|
int multirom_get_bootloader_cmdline(struct multirom_status *s, char *str, size_t size);
|
||||||
int multirom_find_file(char *res, const char *name_part, const char *path);
|
int multirom_find_file(char *res, const char *name_part, const char *path);
|
||||||
int multirom_fill_kexec_linux(struct multirom_status *s, struct multirom_rom *rom, char **cmd);
|
int multirom_fill_kexec_linux(struct multirom_status *s, struct multirom_rom *rom, struct kexec *kexec);
|
||||||
int multirom_fill_kexec_android(struct multirom_status *s, struct multirom_rom *rom, char **cmd);
|
int multirom_fill_kexec_android(struct multirom_status *s, struct multirom_rom *rom, struct kexec *kexec);
|
||||||
int multirom_extract_bytes(const char *dst, FILE *src, size_t size);
|
int multirom_extract_bytes(const char *dst, FILE *src, size_t size);
|
||||||
int multirom_update_partitions(struct multirom_status *s);
|
int multirom_update_partitions(struct multirom_status *s);
|
||||||
void multirom_destroy_partition(void *part);
|
void multirom_destroy_partition(void *part);
|
||||||
|
|||||||
Reference in New Issue
Block a user