master
Сергей Маринкевич 4 years ago
parent 934c47ee55
commit 8342172d62

181
main.c

@ -12,6 +12,8 @@
#define debug(...) #define debug(...)
#endif #endif
static int reads_counter = 0;
static int firmware_fdt_read_blob(const char *filename, char **buffp, int *len) static int firmware_fdt_read_blob(const char *filename, char **buffp, int *len)
{ {
int fd = 0; /* assume stdin */ int fd = 0; /* assume stdin */
@ -60,7 +62,7 @@ static int firmware_fdt_read_blob(const char *filename, char **buffp, int *len)
return ret; return ret;
} }
static int firmware_fdt_read_chunk(const char *filename, char *buf, int len, int offset) static int firmware_fdt_read_chunk(const char *filename, char *buf, int offset, int len)
{ {
int fd = 0; /* assume stdin */ int fd = 0; /* assume stdin */
int ret = 0; int ret = 0;
@ -99,6 +101,7 @@ static int firmware_fdt_read_chunk(const char *filename, char *buf, int len, int
close(fd); close(fd);
memset(buf + readed, 0, len - readed); memset(buf + readed, 0, len - readed);
reads_counter++;
return readed; return readed;
} }
@ -106,7 +109,7 @@ int a()
{ {
int len = 0; int len = 0;
char *buf = NULL; char *buf = NULL;
const char *filename = "/tmp/esr1x.firmware"; const char *filename = "/tmp/firmware";
firmware_fdt_read_blob(filename, &buf, &len); firmware_fdt_read_blob(filename, &buf, &len);
@ -116,36 +119,32 @@ int a()
node = fdt_path_offset(buf, "/images/sbi@1"); node = fdt_path_offset(buf, "/images/sbi@1");
printf("fdt_path_offset of sbi@1: %x\n", node); printf("fdt_path_offset of sbi@1: %x\n", node);
int d = 0; int d = 0;
#if 0
node = fdt_next_node(buf, 0, &d);
node = fdt_next_node(buf, node, &d);
node = fdt_next_node(buf, node, &d);
node = fdt_next_node(buf, node, &d);
node = fdt_next_node(buf, node, &d);
node = fdt_next_node(buf, node, &d);
node = fdt_next_node(buf, node, &d);
node = fdt_next_node(buf, node, &d);
printf("node: %x\n", node);
#endif
return 0; return 0;
} }
static inline const void *fdt_offset_ptr_(const void *fdt, const void *buf, int buf_offset) static inline const void *fdt_offset_ptr_(const void *fdt, const void *buf, int buf_offset)
{ {
debug("fdt_offset_ptr_: %p + %d + %x\n", buf, fdt_off_dt_struct(fdt), buf_offset); debug("fdt_offset_ptr_: %p + %x\n", buf, buf_offset);
return (const char *)buf + fdt_off_dt_struct(fdt) + buf_offset; return (const char *)buf + buf_offset;
}
static inline const int fdt_offset_to_file_offset(const void *fdt, int buf_offset)
{
debug("fdt_offset_ptr_: %x\n", buf_offset);
return buf_offset + fdt_off_dt_struct(fdt);
} }
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
/* Do not touch any forward data, caller will validate it later */ /* Do not touch any forward data, caller will validate it later */
int guess_next_tag(char * fdt, int offset, char * buf) int guess_next_tag(char * fdt, int offset, char * buf, int buf_offset)
{ {
const unsigned * val = fdt_offset_ptr_(fdt, buf, 0); const unsigned * val = fdt_offset_ptr_(fdt, buf, buf_offset);
unsigned tag = fdt32_to_cpu(*val); unsigned tag = fdt32_to_cpu(*val);
char * ptr = NULL; char * ptr = NULL;
int offset_adjust = 0;
switch (tag) { switch (tag) {
case FDT_BEGIN_NODE: case FDT_BEGIN_NODE:
@ -154,29 +153,31 @@ int guess_next_tag(char * fdt, int offset, char * buf)
debug("Starts: '%s'\n", ptr); debug("Starts: '%s'\n", ptr);
while (*ptr != '\0') while (*ptr != '\0')
ptr++; ptr++;
offset += ptr - (char *)val + 1; offset_adjust += ptr - (char *)val + 1;
debug("skipped %d chars\n", ptr - (char *)val + 1); debug("skipped %d chars\n", offset_adjust - FDT_TAGSIZE);
break; break;
case FDT_PROP: case FDT_PROP:
ptr = (char *)val; ptr = (char *)val;
ptr += FDT_TAGSIZE; ptr += FDT_TAGSIZE;
int len = fdt32_to_cpu(*((int *)ptr)); int len = fdt32_to_cpu(*((int *)ptr));
debug("It's prop: len %d\n", len); debug("It's prop: len %d\n", len);
offset += sizeof(struct fdt_property) + len; offset_adjust += sizeof(struct fdt_property) + len;
break; break;
case FDT_END: case FDT_END:
case FDT_END_NODE: case FDT_END_NODE:
case FDT_NOP: case FDT_NOP:
offset += FDT_TAGSIZE; offset_adjust += FDT_TAGSIZE;
break; break;
default: default:
printf("Unknown label: %x\n", tag); printf("Unknown label: %x\n", tag);
return -1; return -1;
} }
offset = FDT_TAGALIGN(offset);
offset += offset_adjust;
offset_adjust += FDT_TAGALIGN(offset) - offset;
debug("Next tag offset: %x\n", offset); debug("Next tag offset: %x\n", offset);
return offset; return offset_adjust;
} }
int is_offset_valid(char * fdt, int offset, int len) int is_offset_valid(char * fdt, int offset, int len)
@ -200,45 +201,67 @@ int is_offset_valid(char * fdt, int offset, int len)
return 1; return 1;
} }
#define WINDOW_SIZE 512 #define WINDOW_SIZE (1024 * 100)
int buf_offset_left_after_tag(int offset)
{
#define GUESS_NODE_NAME_LEN 64
/* In edge case we have:
* |----|----------------|
* |tag |node name 0|
* ^-- last readed byte
*/
return WINDOW_SIZE - offset - FDT_TAGSIZE - GUESS_NODE_NAME_LEN;
}
static int fdt_node_get_prop(char * filename, char * fdt, char * strings, int offset, const char * prop_name, int * data_offset, int * data_len) static int fdt_node_get_prop(char * filename, char * fdt, char * strings, int offset, const char * prop_name, int * data_offset, int * data_len)
{ {
char * buf = malloc(WINDOW_SIZE); char * buf = malloc(WINDOW_SIZE);
int readed = firmware_fdt_read_chunk(filename, buf, WINDOW_SIZE, offset); int readed = firmware_fdt_read_chunk(filename, buf, fdt_offset_to_file_offset(fdt, offset),
WINDOW_SIZE);
if (readed <= 0) if (readed <= 0)
return -1; return -1;
*data_offset = 0; *data_offset = 0;
*data_len = 0; *data_len = 0;
int buf_offset = 0;
do { do {
int nextoffset = guess_next_tag(fdt, offset, buf); int offset_adjust = guess_next_tag(fdt, offset, buf, buf_offset);
readed = firmware_fdt_read_chunk(filename, buf, WINDOW_SIZE, nextoffset); int valid = is_offset_valid(fdt, offset, offset_adjust);
debug("DUMP: Read additional %d bytes from offset %x\n", readed, nextoffset);
int valid = is_offset_valid(fdt, offset, nextoffset - offset);
if (!valid) if (!valid)
{ {
printf("DUMP: next tag is not valid! (%d %d)\n", offset, nextoffset); printf("DUMP: next tag is not valid! (%d + %d)\n", offset, offset_adjust);
break; break;
} }
debug("DUMP: Offset %x is valid\n", nextoffset); offset += offset_adjust;
offset = nextoffset; buf_offset += offset_adjust;
debug("DUMP: Offset %x(%x) is valid\n", offset, buf_offset);
if (FDT_PROP == fdt32_to_cpu(*(int *)(fdt_offset_ptr_(fdt, buf, 0)))) /* Check if we exceed the window */
if (buf_offset_left_after_tag(buf_offset) < 0)
{ {
const struct fdt_property *prop = fdt_offset_ptr_(fdt, buf, 0); readed = firmware_fdt_read_chunk(filename, buf,
fdt_offset_to_file_offset(fdt, offset),
WINDOW_SIZE);
debug("DUMP: Read additional %d bytes from offset %x\n", readed, offset);
buf_offset = 0;
}
if (FDT_PROP == fdt32_to_cpu(*(int *)(fdt_offset_ptr_(fdt, buf, buf_offset))))
{
const struct fdt_property *prop = fdt_offset_ptr_(fdt, buf, buf_offset);
debug("prop->nameoff: %x (%x)\n", fdt32_to_cpu(prop->nameoff), fdt_off_dt_strings(fdt)); debug("prop->nameoff: %x (%x)\n", fdt32_to_cpu(prop->nameoff), fdt_off_dt_strings(fdt));
char * name = strings + fdt32_to_cpu(prop->nameoff); char * name = strings + fdt32_to_cpu(prop->nameoff);
debug("Property name: '%s'\n", name); debug("Property name: '%s'\n", name);
if (strcmp(name, "data")) if (strcmp(name, prop_name))
continue; continue;
*data_offset = prop->data - (char *)prop + offset; *data_offset = prop->data - (char *)prop + offset;
*data_len = fdt32_to_cpu(prop->len); *data_len = fdt32_to_cpu(prop->len);
debug("Property \"data\" at offset %x len %d\n", data_offset, data_len); debug("Property \"%s\" at offset %x len %d\n", prop_name, data_offset, data_len);
return 0; return 0;
} }
} while (FDT_END != fdt32_to_cpu(*(int *)(fdt_offset_ptr_(fdt, buf, 0)))); } while (FDT_END != fdt32_to_cpu(*(int *)(fdt_offset_ptr_(fdt, buf, buf_offset))));
return -1; return -1;
} }
@ -251,11 +274,22 @@ static int fdt_dump_node_data(char * fdt, char * strings, const char *outname, c
return -1; return -1;
char * data = malloc(data_len); char * data = malloc(data_len);
int readed = firmware_fdt_read_chunk(filename, data, data_len, int readed = firmware_fdt_read_chunk(filename, data,
fdt_off_dt_struct(fdt) + data_offset); fdt_off_dt_struct(fdt) + data_offset, data_len);
if (readed <= 0) if (readed <= 0)
return -1; return -1;
#if 1
if (fdt_node_get_prop(filename, fdt, strings, offset, "commit", &data_offset, &data_len))
return -1;
char * buf = malloc(WINDOW_SIZE);
readed = firmware_fdt_read_chunk(filename, buf,
fdt_off_dt_struct(fdt) + data_offset, data_len);
char commit[42] = {0};
strncpy(commit, buf, sizeof(commit));
printf("Commit(len: %d): '%s'\n", data_len, commit);
#if 0
int fd = 0; /* assume stdin */ int fd = 0; /* assume stdin */
int ret = 0; int ret = 0;
@ -296,32 +330,57 @@ static int fdt_dump_node_data(char * fdt, char * strings, const char *outname, c
int b() int b()
{ {
int len = 0; int len = 0;
const char *filename = "/tmp/esr1x.firmware"; const char *filename = "/tmp/firmware";
char *fdt = malloc(WINDOW_SIZE);
int readed = firmware_fdt_read_chunk(filename, fdt, 0, WINDOW_SIZE);
if (readed <= 0)
return -1;
char *buf = malloc(WINDOW_SIZE); char *buf = malloc(WINDOW_SIZE);
int file_offset = 0; readed = firmware_fdt_read_chunk(filename, buf, fdt_offset_to_file_offset(fdt, 0),
int readed = firmware_fdt_read_chunk(filename, buf, WINDOW_SIZE, file_offset); WINDOW_SIZE);
if (readed <= 0) if (readed <= 0)
return -1; return -1;
char *fdt = buf;
buf = malloc(WINDOW_SIZE);
memcpy(buf, fdt, WINDOW_SIZE);
printf("B:\n"); printf("B:\n");
int offset = 0; int offset = 0;
struct { const char * name; int offset; } node_offsets[] = { struct { const char * name; int offset; } node_offsets[] = {
{ "sbi@1", 0 }, { "bdk@1", 0 },
{ "uboot-spi@1", 0 }, { "bl1@1", 0 },
{ "uboot-nand@1", 0 } { "uboot@1", 0 }
}; };
int buf_offset = 0;
do { do {
if (FDT_BEGIN_NODE == fdt32_to_cpu(*(int *)(fdt_offset_ptr_(fdt, buf, 0)))) int offset_adjust = guess_next_tag(fdt, offset, buf, buf_offset);
int valid = is_offset_valid(fdt, offset, offset_adjust);
if (!valid)
{
printf("READ: next tag is not valid! (%d + %d)\n", offset, offset_adjust);
break;
}
offset += offset_adjust;
buf_offset += offset_adjust;
debug("READ: Offset %x(%x) is valid\n", offset, buf_offset);
/* Check if we exceed the window */
if (buf_offset_left_after_tag(buf_offset) < 0)
{
readed = firmware_fdt_read_chunk(filename, buf,
fdt_offset_to_file_offset(fdt, offset),
WINDOW_SIZE);
debug("READ: Read additional %d bytes from offset %x\n", readed, offset);
buf_offset = 0;
}
if (FDT_BEGIN_NODE == fdt32_to_cpu(*(int *)(fdt_offset_ptr_(fdt, buf, buf_offset))))
{ {
debug("Search starts\n"); debug("Search starts\n");
for (int i = 0; i < sizeof(node_offsets) / sizeof(*node_offsets); i++) for (int i = 0; i < sizeof(node_offsets) / sizeof(*node_offsets); i++)
{ {
if (!strcmp(node_offsets[i].name, if (!strcmp(node_offsets[i].name,
(char *)(fdt_offset_ptr_(fdt, buf, FDT_TAGSIZE)))) (char *)(fdt_offset_ptr_(fdt, buf,
buf_offset + FDT_TAGSIZE))))
{ {
node_offsets[i].offset = offset; node_offsets[i].offset = offset;
} }
@ -329,32 +388,18 @@ int b()
} }
debug("Search ends\n"); debug("Search ends\n");
} }
} while (FDT_END != fdt32_to_cpu(*(int *)(fdt_offset_ptr_(fdt, buf, buf_offset))));
int nextoffset = guess_next_tag(fdt, offset, buf);
readed = firmware_fdt_read_chunk(filename, buf, WINDOW_SIZE, nextoffset);
debug("Read additional %d bytes from offset %x\n", readed, nextoffset);
int valid = is_offset_valid(fdt, offset, nextoffset - offset);
if (!valid)
{
printf("next tag is not valid! (%d %d)\n", offset, nextoffset);
break;
}
debug("Offset %x is valid\n", nextoffset);
offset = nextoffset;
} while (FDT_END != fdt32_to_cpu(*(int *)(fdt_offset_ptr_(fdt, buf, 0))));
debug("Yay\n"); debug("Yay\n");
char * strings = malloc(WINDOW_SIZE); char * strings = malloc(WINDOW_SIZE);
readed = firmware_fdt_read_chunk(filename, strings, WINDOW_SIZE, fdt_off_dt_strings(fdt)); readed = firmware_fdt_read_chunk(filename, strings, fdt_off_dt_strings(fdt), WINDOW_SIZE);
if (readed <= 0) if (readed <= 0)
return -1; return -1;
for (int i = 0; i < sizeof(node_offsets) / sizeof(*node_offsets); i++) for (int i = 0; i < sizeof(node_offsets) / sizeof(*node_offsets); i++)
{ {
printf("%s offset: %x\n", node_offsets[i].name, node_offsets[i].offset); printf("%s offset: %x\n", node_offsets[i].name, node_offsets[i].offset);
readed = firmware_fdt_read_chunk(filename, buf, WINDOW_SIZE,
node_offsets[i].offset);
int writed = fdt_dump_node_data(fdt, strings, node_offsets[i].name, filename, node_offsets[i].offset); int writed = fdt_dump_node_data(fdt, strings, node_offsets[i].name, filename, node_offsets[i].offset);
printf("Written %d bytes\n", writed); printf("Written %d bytes\n", writed);
} }
@ -365,7 +410,7 @@ int b()
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
a();
b(); b();
printf("Counter: %d\n", reads_counter);
return 0; return 0;
} }

Loading…
Cancel
Save