arm64: add support for appended dtb (Squashed)

This commit is contained in:
oshmoun
2016-09-30 21:22:57 +09:00
committed by jollaman999
parent 12c48969ba
commit bb982d67c1
8 changed files with 277 additions and 19 deletions

View File

@@ -328,14 +328,190 @@ static int read_sys_dtb(struct dtb *dtb)
return 0;
}
#define DTB_PAD_SIZE 1024
#define INVALID_SOC_REV_ID 0xFFFFFFFF
struct msm_id
{
uint32_t platform_id;
uint32_t hardware_id;
uint32_t soc_rev;
};
static uint32_t dtb_compatible(void *dtb, struct msm_id *devid)
{
int root_offset;
const void *prop;
struct msm_id msm_id;
int len;
root_offset = fdt_path_offset(dtb, "/");
if (root_offset < 0)
return 0;
prop = fdt_getprop(dtb, root_offset, "qcom,msm-id", &len);
if (!prop || len <= 0) {
printf("DTB: qcom,msm-id entry not found\n");
return 0;
} else if (len < (int)sizeof(struct msm_id)) {
printf("DTB: qcom,msm-id entry size mismatch (%d != %d)\n",
len, sizeof(struct msm_id));
return 0;
}
msm_id.platform_id = fdt32_to_cpu(((const struct msm_id *)prop)->platform_id);
msm_id.hardware_id = fdt32_to_cpu(((const struct msm_id *)prop)->hardware_id);
msm_id.soc_rev = fdt32_to_cpu(((const struct msm_id *)prop)->soc_rev);
if (msm_id.platform_id != devid->platform_id ||
msm_id.hardware_id != devid->hardware_id) {
return INVALID_SOC_REV_ID;
}
return msm_id.soc_rev;
}
static int get_appended_dtb(const char *kernel, off_t kernel_len, struct dtb *dtb_struct)
{
char *kernel_end = (char*)kernel + kernel_len;
char *dtb;
FILE *f;
struct msm_id devid;
char *bestmatch_tag = NULL;
uint32_t bestmatch_tag_size;
uint32_t bestmatch_soc_rev_id = INVALID_SOC_REV_ID;
f = fopen("/proc/device-tree/qcom,msm-id", "r");
if(!f)
{
fprintf(stderr, "DTB: Couldn't open /proc/device-tree/qcom,msm-id!\n");
return 0;
}
fread(&devid, sizeof(struct msm_id), 1, f);
fclose(f);
devid.platform_id = fdt32_to_cpu(devid.platform_id);
devid.hardware_id = fdt32_to_cpu(devid.hardware_id);
devid.soc_rev = fdt32_to_cpu(devid.soc_rev);
printf("DTB: platform %u hw %u soc 0x%x\n", devid.platform_id, devid.hardware_id, devid.soc_rev);
// scan the compressed kernel buf for dtb
dtb = kernel;
while(dtb + sizeof(struct fdt_header) < kernel_end)
{
int ret = fdt_check_header(dtb);
if (ret != 0) {
dtb++;
continue;
} else {
printf("DTB: found dtb header at %zu\n", dtb);
}
uint32_t dtb_soc_rev_id;
uint32_t dtb_size;
// stop if we go over kernel_end
if (dtb + fdt_totalsize(dtb) > kernel_end) {
printf("DTB: went over kernel_end, BREAK!\n");
break;
}
dtb_size = fdt_totalsize(dtb);
dtb_soc_rev_id = dtb_compatible(dtb, &devid);
if (dtb_soc_rev_id == devid.soc_rev) {
dtb_struct->buf = xmalloc(dtb_size);
memcpy(dtb_struct->buf, dtb, dtb_size);
dtb_struct->size = dtb_size;
printf("DTB: match 0x%x, my id 0x%x, len %u\n", dtb_soc_rev_id, devid.soc_rev, dtb_size);
return 1;
} else if ((dtb_soc_rev_id != INVALID_SOC_REV_ID) &&
(dtb_soc_rev_id < devid.soc_rev)) {
/* if current bestmatch is less than new dtb_soc_rev_id then update
bestmatch_tag */
if((bestmatch_soc_rev_id == INVALID_SOC_REV_ID) ||
(bestmatch_soc_rev_id < dtb_soc_rev_id)) {
bestmatch_tag = dtb;
bestmatch_tag_size = dtb_size;
bestmatch_soc_rev_id = dtb_soc_rev_id;
}
}
/* goto the next device tree if any */
dtb += dtb_size;
}
if(bestmatch_tag) {
printf("DTB: bestmatch 0x%x, my id 0x%x\n", bestmatch_soc_rev_id, devid.soc_rev);
dtb_struct->buf = xmalloc(bestmatch_tag_size);
memcpy(dtb_struct->buf, bestmatch_tag, bestmatch_tag_size);
dtb_struct->size = bestmatch_tag_size;
return 1;
}
return 0;
}
int dtb_add_memory_reg(void *dtb_buf, int off)
{
FILE *f;
uint32_t reg;
int res;
f = fopen("/proc/device-tree/memory/reg", "r");
if(!f)
{
fprintf(stderr, "DTB: Failed to open /proc/device-tree/memory/reg!\n");
return 0;
}
fdt_delprop(dtb_buf, off, "reg");
while(fread(&reg, sizeof(reg), 1, f) == 1)
fdt_appendprop(dtb_buf, off, "reg", &reg, sizeof(reg));
fclose(f);
return 1;
}
int read_appended_dtb(const char *kernel_buf, off_t kernel_size, struct dtb *dtb) {
if(get_appended_dtb(kernel_buf, kernel_size, dtb))
{
int ret, off;
printf("DTB: Using DTB appended to zImage\n");
dtb->size = fdt_totalsize(dtb->buf) + DTB_PAD_SIZE;
dtb->buf = xrealloc(dtb->buf, dtb->size);
ret = fdt_open_into(dtb->buf, dtb->buf, dtb->size);
if(ret)
die("DTB: fdt_open_into failed");
ret = fdt_path_offset(dtb->buf, "/memory");
if (ret >= 0)
dtb_add_memory_reg(dtb->buf, ret);
else
fprintf(stderr, "DTB: Could not find memory node.\n");
// this shouldn't be used, but we set it for completeness
dtb->path = "appended";
return ret;
} else {
printf("DTB: appended DTB not detected\n");
}
return 1;
}
/**
* read_1st_dtb - Read the 1st stage kernel's dtb.
*/
static int read_1st_dtb(struct dtb *dtb)
static int read_1st_dtb(struct dtb *dtb, const char *kernel_buf, off_t kernel_size)
{
int result;
result = read_appended_dtb(kernel_buf, kernel_size, dtb);
if (!result)
goto on_success;
result = read_sys_dtb(dtb);
if (!result)
@@ -381,7 +557,8 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line)
*/
int arm64_load_other_segments(struct kexec_info *info,
uint64_t kernel_entry)
uint64_t kernel_entry, const char *kernel_buf,
off_t kernel_size)
{
int result;
uint64_t dtb_base;
@@ -407,9 +584,11 @@ int arm64_load_other_segments(struct kexec_info *info,
if (arm64_opts.dtb) {
dtb.name = "dtb_2";
dtb.buf = slurp_file(arm64_opts.dtb, &dtb.size);
// skip header if loading dtb.img
dtb.buf += 2048;
} else {
dtb.name = "dtb_1";
result = read_1st_dtb(&dtb);
result = read_1st_dtb(&dtb, kernel_buf, kernel_size);
if (result) {
fprintf(stderr,
@@ -595,7 +774,8 @@ static int get_memory_ranges_iomem(struct memory_range *array,
* get_memory_ranges_dt - Try to get the memory ranges from the 1st stage dtb.
*/
static int get_memory_ranges_dt(struct memory_range *array, unsigned int *count)
static int get_memory_ranges_dt(struct memory_range *array, unsigned int *count,
char *kernel_buf, off_t kernel_size)
{
struct region {uint64_t base; uint64_t size;};
struct dtb dtb = {.name = "range_dtb"};
@@ -604,7 +784,7 @@ static int get_memory_ranges_dt(struct memory_range *array, unsigned int *count)
*count = 0;
result = read_1st_dtb(&dtb);
result = read_1st_dtb(&dtb, kernel_buf, kernel_size);
if (result) {
goto on_error;
@@ -696,7 +876,7 @@ on_exit:
*/
int get_memory_ranges(struct memory_range **range, int *ranges,
unsigned long kexec_flags)
unsigned long kexec_flags, char *kernel_buf, off_t kernel_size)
{
static struct memory_range array[KEXEC_SEGMENT_MAX];
unsigned int count;
@@ -705,7 +885,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
result = get_memory_ranges_iomem(array, &count);
if (result)
result = get_memory_ranges_dt(array, &count);
result = get_memory_ranges_dt(array, &count, kernel_buf, kernel_size);
*range = result ? NULL : array;
*ranges = result ? 0 : count;

View File

@@ -23,12 +23,14 @@
int elf_arm64_probe(const char *kernel_buf, off_t kernel_size);
int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
off_t kernel_size, struct kexec_info *info);
off_t kernel_size, const char *kernel_compressed_buf,
off_t kernel_compressed_size, struct kexec_info *info);
void elf_arm64_usage(void);
int image_arm64_probe(const char *kernel_buf, off_t kernel_size);
int image_arm64_load(int argc, char **argv, const char *kernel_buf,
off_t kernel_size, struct kexec_info *info);
off_t kernel_size, const char *kernel_compressed_buf,
off_t kernel_compressed_size, struct kexec_info *info);
void image_arm64_usage(void);
off_t initrd_base;
@@ -65,6 +67,7 @@ static inline void set_phys_offset(uint64_t v)
int arm64_process_image_header(const struct arm64_image_header *h);
int arm64_load_other_segments(struct kexec_info *info,
uint64_t kernel_entry);
uint64_t kernel_entry, const char *kernel_buf,
off_t kernel_size);
#endif

View File

@@ -37,7 +37,8 @@ on_exit:
}
int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
off_t kernel_size, struct kexec_info *info)
off_t kernel_size, const char *kernel_compressed_buf,
off_t kernel_compressed_size, struct kexec_info *info)
{
struct mem_ehdr ehdr;
int result;
@@ -108,7 +109,7 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
}
result = arm64_load_other_segments(info,
virt_to_phys(ehdr.e_entry));
virt_to_phys(ehdr.e_entry), kernel_buf, kernel_size);
goto exit;
}

View File

@@ -25,7 +25,8 @@ int image_arm64_probe(const char *kernel_buf, off_t kernel_size)
}
int image_arm64_load(int argc, char **argv, const char *kernel_buf,
off_t kernel_size, struct kexec_info *info)
off_t kernel_size, const char *kernel_compressed_buf,
off_t kernel_compressed_size, struct kexec_info *info)
{
const struct arm64_image_header *h;
unsigned long image_base;
@@ -49,7 +50,8 @@ int image_arm64_load(int argc, char **argv, const char *kernel_buf,
add_segment_phys_virt(info, kernel_buf, kernel_size, image_base,
arm64_mem.image_size, 0);
return arm64_load_other_segments(info, image_base);
return arm64_load_other_segments(info, image_base,
kernel_compressed_buf, kernel_compressed_size);
}
void image_arm64_usage(void)

View File

@@ -693,6 +693,8 @@ static int my_load(const char *type, int fileind, int argc, char **argv,
char *kernel;
char *kernel_buf;
off_t kernel_size;
char *kernel_compressed_buf;
off_t kernel_compressed_size;
int i = 0;
int result;
struct kexec_info info;
@@ -711,12 +713,16 @@ static int my_load(const char *type, int fileind, int argc, char **argv,
kernel = argv[fileind];
/* slurp in the input kernel */
kernel_buf = slurp_decompress_file(kernel, &kernel_size);
// make sure to always slurp in the compressed input kernel
// this is used to check for appended dtb
kernel_compressed_buf = slurp_file(kernel, &kernel_compressed_size);
dbgprintf("kernel: %p kernel_size: %#llx\n",
kernel_buf, (unsigned long long)kernel_size);
if (get_memory_ranges(&info.memory_range, &info.memory_ranges,
info.kexec_flags) < 0 || info.memory_ranges == 0) {
info.kexec_flags, kernel_compressed_buf, kernel_compressed_size) < 0 ||
info.memory_ranges == 0) {
fprintf(stderr, "Could not get memory layout\n");
return -1;
}
@@ -760,7 +766,8 @@ static int my_load(const char *type, int fileind, int argc, char **argv,
}
info.kexec_flags |= native_arch;
result = file_type[i].load(argc, argv, kernel_buf, kernel_size, &info);
result = file_type[i].load(argc, argv, kernel_buf, kernel_size,
kernel_compressed_buf, kernel_compressed_size, &info);
if (result < 0) {
switch (result) {
case ENOCRASHKERNEL:
@@ -1131,7 +1138,9 @@ static int do_kexec_file_load(int fileind, int argc, char **argv,
struct kexec_info info;
int ret = 0;
char *kernel_buf;
char *kernel_compressed_buf;
off_t kernel_size;
off_t kernel_compressed_size;
memset(&info, 0, sizeof(info));
info.segment = NULL;
@@ -1165,6 +1174,9 @@ static int do_kexec_file_load(int fileind, int argc, char **argv,
/* slurp in the input kernel */
kernel_buf = slurp_decompress_file(kernel, &kernel_size);
// make sure to always slurp in the compressed input kernel
// this is used to check for appended dtb
kernel_compressed_buf = slurp_decompress_file(kernel, &kernel_compressed_size);
for (i = 0; i < file_types; i++) {
if (file_type[i].probe(kernel_buf, kernel_size) >= 0)
@@ -1177,7 +1189,8 @@ static int do_kexec_file_load(int fileind, int argc, char **argv,
return -1;
}
ret = file_type[i].load(argc, argv, kernel_buf, kernel_size, &info);
ret = file_type[i].load(argc, argv, kernel_buf, kernel_size,
kernel_compressed_buf, kernel_compressed_size, &info);
if (ret < 0) {
fprintf(stderr, "Cannot load %s\n", kernel);
return ret;

View File

@@ -182,7 +182,8 @@ long kernel_version(void);
void usage(void);
int get_memory_ranges(struct memory_range **range, int *ranges,
unsigned long kexec_flags);
unsigned long kexec_flags, char *kernel_buf,
off_t kernel_size);
int valid_memory_range(struct kexec_info *info,
unsigned long sstart, unsigned long send);
void print_segments(FILE *file, struct kexec_info *info);
@@ -194,7 +195,8 @@ unsigned long locate_hole(struct kexec_info *info,
typedef int (probe_t)(const char *kernel_buf, off_t kernel_size);
typedef int (load_t )(int argc, char **argv,
const char *kernel_buf, off_t kernel_size,
const char *kernel_buf, off_t kernel_size,
const char *kernel_compressed_buf, off_t kernel_compressed_size,
struct kexec_info *info);
typedef void (usage_t)(void);
struct file_type {

View File

@@ -289,6 +289,33 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
return 0;
}
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
struct fdt_property *prop;
int err, oldlen, newlen;
FDT_RW_CHECK_HEADER(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (prop) {
newlen = len + oldlen;
err = _fdt_splice_struct(fdt, prop->data,
FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(newlen));
if (err)
return err;
prop->len = cpu_to_fdt32(newlen);
memcpy(prop->data + oldlen, val, len);
} else {
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
memcpy(prop->data, val, len);
}
return 0;
}
int fdt_delprop(void *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;

View File

@@ -974,6 +974,36 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
#define fdt_setprop_string(fdt, nodeoffset, name, str) \
fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
/**
* fdt_appendprop - append to or create a property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to append to
* @val: pointer to data to append to the property value
* @len: length of the data to append to the property value
*
* fdt_appendprop() appends the value to the named property in the
* given node, creating the property if it does not already exist.
*
* This function may insert data into the blob, and will therefore
* change the offsets of some existing nodes.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
* contain the new property value
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len);
/**
* fdt_delprop - delete a property
* @fdt: pointer to the device tree blob