Fix unpacking vendor boot images

This commit is contained in:
topjohnwu 2021-11-20 22:44:38 -08:00
parent 68ac409bfd
commit aebf2672cd
2 changed files with 84 additions and 78 deletions

View File

@ -235,31 +235,29 @@ static format_t check_fmt_lg(uint8_t *buf, unsigned sz) {
return fmt;
}
#define get_block(name) {\
name = addr + off; \
off += hdr->name##_size(); \
off = do_align(off, hdr->page_size()); \
}
#define CMD_MATCH(s) BUFFER_MATCH(h->cmdline, s)
void boot_img::parse_image(uint8_t *addr, format_t type) {
auto h = reinterpret_cast<boot_img_hdr_v0*>(addr);
dyn_img_hdr *boot_img::create_hdr(uint8_t *addr, format_t type) {
if (type == AOSP_VENDOR) {
fprintf(stderr, "VENDOR_BOOT_HDR\n");
auto h = reinterpret_cast<boot_img_hdr_vnd_v3*>(addr);
hdr_addr = addr;
switch (h->header_version) {
case 4:
hdr = new dyn_img_vnd_v4(addr);
break;
case 3:
return new dyn_img_vnd_v4(addr);
default:
hdr = new dyn_img_vnd_v3(addr);
break;
return new dyn_img_vnd_v3(addr);
}
} else if (h->page_size >= 0x02000000) {
}
auto h = reinterpret_cast<boot_img_hdr_v0*>(addr);
if (h->page_size >= 0x02000000) {
fprintf(stderr, "PXA_BOOT_HDR\n");
hdr = new dyn_img_pxa(addr);
} else {
hdr_addr = addr;
return new dyn_img_pxa(addr);
}
if (CMD_MATCH(NOOKHD_RL_MAGIC) ||
CMD_MATCH(NOOKHD_GL_MAGIC) ||
CMD_MATCH(NOOKHD_GR_MAGIC) ||
@ -274,25 +272,32 @@ void boot_img::parse_image(uint8_t *addr, format_t type) {
addr += ACCLAIM_PRE_HEADER_SZ;
}
// addr could be adjusted
h = reinterpret_cast<boot_img_hdr_v0*>(addr);
hdr_addr = addr;
switch (h->header_version) {
case 1:
hdr = new dyn_img_v1(addr);
break;
return new dyn_img_v1(addr);
case 2:
hdr = new dyn_img_v2(addr);
break;
return new dyn_img_v2(addr);
case 3:
hdr = new dyn_img_v3(addr);
break;
return new dyn_img_v3(addr);
case 4:
hdr = new dyn_img_v4(addr);
break;
return new dyn_img_v4(addr);
default:
hdr = new dyn_img_v0(addr);
break;
return new dyn_img_v0(addr);
}
}
#define get_block(name) \
name = hdr_addr + off; \
off += hdr->name##_size(); \
off = do_align(off, hdr->page_size());
void boot_img::parse_image(uint8_t *addr, format_t type) {
hdr = create_hdr(addr, type);
if (char *id = hdr->id()) {
for (int i = SHA_DIGEST_SIZE + 4; i < SHA256_DIGEST_SIZE; ++i) {
if (id[i]) {
@ -305,7 +310,6 @@ void boot_img::parse_image(uint8_t *addr, format_t type) {
hdr->print();
size_t off = hdr->hdr_space();
hdr_addr = addr;
get_block(kernel);
get_block(ramdisk);
get_block(second);

View File

@ -151,7 +151,15 @@ struct boot_img_hdr_v0_common {
struct boot_img_hdr_v0 : public boot_img_hdr_v0_common {
uint32_t tags_addr; /* physical addr for kernel tags */
// In AOSP headers, this field is used for page size.
// For Samsung PXA headers, the use of this field is unknown;
// however, its value is something unrealistic to be treated as page size.
// We use this fact to determine whether this is an AOSP or PXA header.
union {
uint32_t unknown;
uint32_t page_size; /* flash page size we assume */
};
// In header v1, this field is used for header version
// However, on some devices like Samsung, this field is used to store DTB
@ -374,13 +382,10 @@ struct dyn_img_hdr {
protected:
union {
// Main header could be either AOSP or PXA
boot_img_hdr_v2 *v2_hdr; /* AOSP v2 header */
boot_img_hdr_v3 *v3_hdr; /* AOSP v3 header */
boot_img_hdr_v4 *v4_hdr; /* AOSP v4 header */
boot_img_hdr_pxa *hdr_pxa; /* Samsung PXA header */
boot_img_hdr_vnd_v3 *v3_vnd; /* AOSP vendor v3 header */
boot_img_hdr_vnd_v4 *v4_vnd; /* AOSP vendor v4 header */
boot_img_hdr_pxa *hdr_pxa; /* Samsung PXA header */
void *raw; /* Raw pointer */
};
dyn_img_hdr(bool b) : is_vendor(b) {}
@ -401,9 +406,11 @@ name(void *ptr) { \
raw = xmalloc(sizeof(hdr)); \
memcpy(raw, ptr, sizeof(hdr)); \
} \
size_t hdr_size() override { return sizeof(hdr); } \
size_t hdr_size() override { \
return sizeof(hdr); \
} \
dyn_img_hdr *clone() override { \
auto p = new name(this->raw); \
auto p = new name(raw); \
p->kernel_dt_size = kernel_dt_size; \
return p; \
};
@ -411,14 +418,14 @@ dyn_img_hdr *clone() override { \
#define __impl_val(name, hdr_name) \
decltype(std::declval<dyn_img_hdr>().name()) name() override { return hdr_name->name; }
#define impl_cls(ver) __impl_cls(dyn_img_##ver, boot_img_hdr_##ver)
#define impl_val(name) __impl_val(name, v2_hdr)
struct dyn_img_hdr_boot : public dyn_img_hdr {
protected:
dyn_img_hdr_boot() : dyn_img_hdr(false) {}
};
#define impl_cls(ver) __impl_cls(dyn_img_##ver, boot_img_hdr_##ver)
#define impl_val(name) __impl_val(name, v2_hdr)
struct dyn_img_common : public dyn_img_hdr_boot {
impl_val(kernel_size)
impl_val(ramdisk_size)
@ -469,7 +476,7 @@ struct dyn_img_pxa : public dyn_img_common {
};
#undef impl_val
#define impl_val(name) __impl_val(name, v3_hdr)
#define impl_val(name) __impl_val(name, v4_hdr)
struct dyn_img_v3 : public dyn_img_hdr_boot {
impl_cls(v3)
@ -483,15 +490,12 @@ struct dyn_img_v3 : public dyn_img_hdr_boot {
// Make API compatible
uint32_t &page_size() override { page_sz = 4096; return page_sz; }
char *extra_cmdline() override { return &v3_hdr->cmdline[BOOT_ARGS_SIZE]; }
char *extra_cmdline() override { return &v4_hdr->cmdline[BOOT_ARGS_SIZE]; }
private:
uint32_t page_sz = 4096;
};
#undef impl_val
#define impl_val(name) __impl_val(name, v4_hdr)
struct dyn_img_v4 : public dyn_img_v3 {
impl_cls(v4)
};
@ -502,7 +506,7 @@ protected:
};
#undef impl_val
#define impl_val(name) __impl_val(name, v3_vnd)
#define impl_val(name) __impl_val(name, v4_vnd)
struct dyn_img_vnd_v3 : public dyn_img_hdr_vendor {
impl_cls(vnd_v3)
@ -518,12 +522,9 @@ struct dyn_img_vnd_v3 : public dyn_img_hdr_vendor {
size_t hdr_space() override { auto sz = page_size(); return do_align(hdr_size(), sz); }
// Make API compatible
char *extra_cmdline() override { return &v3_vnd->cmdline[BOOT_ARGS_SIZE]; }
char *extra_cmdline() override { return &v4_vnd->cmdline[BOOT_ARGS_SIZE]; }
};
#undef impl_val
#define impl_val(name) __impl_val(name, v4_vnd)
struct dyn_img_vnd_v4 : public dyn_img_vnd_v3 {
impl_cls(vnd_v4)
};
@ -616,4 +617,5 @@ struct boot_img {
~boot_img();
void parse_image(uint8_t *addr, format_t type);
dyn_img_hdr *create_hdr(uint8_t *addr, format_t type);
};