diff options
Diffstat (limited to 'arch/arm/mach-rockchip/rk_atags.c')
-rw-r--r-- | arch/arm/mach-rockchip/rk_atags.c | 192 |
1 files changed, 139 insertions, 53 deletions
diff --git a/arch/arm/mach-rockchip/rk_atags.c b/arch/arm/mach-rockchip/rk_atags.c index cde2f23a3e..be5dfecad7 100644 --- a/arch/arm/mach-rockchip/rk_atags.c +++ b/arch/arm/mach-rockchip/rk_atags.c @@ -10,6 +10,7 @@ #include <debug_uart.h> #endif +#define HASH_LEN sizeof(u32) #define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) #define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2) #define for_each_tag(t, base) \ @@ -72,11 +73,36 @@ void *memcpy(void *dest, const void *src, size_t count) } #endif -static int inline bad_magic(u32 magic) +static u32 js_hash(void *buf, u32 len) { - return ((magic != ATAG_CORE) && - (magic != ATAG_NONE) && - (magic < ATAG_SERIAL || magic > ATAG_MAX)); + u32 i, hash = 0x47C6A7E6; + char *data = buf; + + if (!buf || !len) + return hash; + + for (i = 0; i < len; i++) + hash ^= ((hash << 5) + data[i] + (hash >> 2)); + + return hash; +} + +static int bad_magic(u32 magic) +{ + bool bad; + + bad = ((magic != ATAG_CORE) && + (magic != ATAG_NONE) && + (magic < ATAG_SERIAL || magic > ATAG_MAX)); + if (bad) { +#if !CONFIG_IS_ENABLED(TINY_FRAMEWORK) + printf("Magic(%x) is not support\n", magic); +#else + printascii("Magic is not support\n"); +#endif + } + + return bad; } static int inline atags_size_overflow(struct tag *t, u32 tag_size) @@ -84,6 +110,23 @@ static int inline atags_size_overflow(struct tag *t, u32 tag_size) return (unsigned long)t + (tag_size << 2) - ATAGS_PHYS_BASE > ATAGS_SIZE; } +static int atags_overflow(struct tag *t) +{ + bool overflow; + + overflow = atags_size_overflow(t, 0) || + atags_size_overflow(t, t->hdr.size); + if (overflow) { +#if !CONFIG_IS_ENABLED(TINY_FRAMEWORK) + printf("Tag is overflow\n"); +#else + printascii("Tag is overflow\n"); +#endif + } + + return overflow; +} + int atags_is_available(void) { struct tag *t = (struct tag *)ATAGS_PHYS_BASE; @@ -93,21 +136,14 @@ int atags_is_available(void) int atags_set_tag(u32 magic, void *tagdata) { - u32 length, size = 0; + u32 length, size = 0, hash; struct tag *t = (struct tag *)ATAGS_PHYS_BASE; if (!tagdata) return -ENODATA; - if (bad_magic(magic)) { -#if !CONFIG_IS_ENABLED(TINY_FRAMEWORK) - printf("%s: magic(%x) is not support\n", __func__, magic); -#else - printascii("magic is not support\n"); -#endif - + if (bad_magic(magic)) return -EINVAL; - } /* Not allowed to be set by user directly, so do nothing */ if ((magic == ATAG_CORE) || (magic == ATAG_NONE)) @@ -125,21 +161,15 @@ int atags_set_tag(u32 magic, void *tagdata) } else { /* Find the end, and use it as a new tag */ for_each_tag(t, (struct tag *)ATAGS_PHYS_BASE) { - /* - * We had better check magic to avoid traversing an - * unknown tag, in case of atags has been damaged by - * some unknown reason. - */ - if (bad_magic(t->hdr.magic)) { -#if !CONFIG_IS_ENABLED(TINY_FRAMEWORK) - printf("%s: find unknown magic(%x)\n", - __func__, t->hdr.magic); -#else - printascii("find unknown magic\n"); -#endif + if (atags_overflow(t)) + return -EINVAL; + if (bad_magic(t->hdr.magic)) return -EINVAL; - } + + /* This is an old tag, override it */ + if (t->hdr.magic == magic) + break; if (t->hdr.magic == ATAG_NONE) break; @@ -166,24 +196,27 @@ int atags_set_tag(u32 magic, void *tagdata) case ATAG_ATF_MEM: size = tag_size(tag_atf_mem); break; + case ATAG_PUB_KEY: + size = tag_size(tag_pub_key); + break; + case ATAG_SOC_INFO: + size = tag_size(tag_soc_info); + break; }; - if (atags_size_overflow(t, size)) { -#if !CONFIG_IS_ENABLED(TINY_FRAMEWORK) - printf("%s: failed! no memory to setup magic(%x), max_mem=0x%x\n", - __func__, magic, ATAGS_SIZE); -#else - printascii("no memory to setup magic\n"); -#endif + if (!size) + return -EINVAL; + if (atags_size_overflow(t, size)) return -ENOMEM; - } /* It's okay to setup a new tag */ t->hdr.magic = magic; t->hdr.size = size; - length = (t->hdr.size << 2) - sizeof(struct tag_header); + length = (t->hdr.size << 2) - sizeof(struct tag_header) - HASH_LEN; memcpy(&t->u, (char *)tagdata, length); + hash = js_hash(t, (size << 2) - HASH_LEN); + memcpy((char *)&t->u + length, &hash, HASH_LEN); /* Next tag */ t = tag_next(t); @@ -197,24 +230,38 @@ int atags_set_tag(u32 magic, void *tagdata) struct tag *atags_get_tag(u32 magic) { + u32 *hash, calc_hash, size; struct tag *t; if (!atags_is_available()) return NULL; for_each_tag(t, (struct tag *)ATAGS_PHYS_BASE) { - if (bad_magic(t->hdr.magic)) { -#if !CONFIG_IS_ENABLED(TINY_FRAMEWORK) - printf("%s: find unknown magic(%x)\n", - __func__, t->hdr.magic); -#else - printascii("find unknown magic\n"); -#endif + if (atags_overflow(t)) return NULL; - } - if (t->hdr.magic == magic) + if (bad_magic(t->hdr.magic)) + return NULL; + + if (t->hdr.magic != magic) + continue; + + size = t->hdr.size; + hash = (u32 *)((ulong)t + (size << 2) - HASH_LEN); + if (!*hash) { + debug("No hash, magic(%x)\n", magic); return t; + } else { + calc_hash = js_hash(t, (size << 2) - HASH_LEN); + if (calc_hash == *hash) { + debug("Hash okay, magic(%x)\n", magic); + return t; + } else { + debug("Hash bad, magic(%x), orgHash=%x, nowHash=%x\n", + magic, *hash, calc_hash); + return NULL; + } + } } return NULL; @@ -234,12 +281,15 @@ void atags_stat(void) u32 start = ATAGS_PHYS_BASE, end = ATAGS_PHYS_BASE + ATAGS_SIZE; struct tag *t; + if (!atags_is_available()) + return; + for_each_tag(t, (struct tag *)ATAGS_PHYS_BASE) { - if (bad_magic(t->hdr.magic)) { - printf("%s: find unknown magic(%x)\n", - __func__, t->hdr.magic); + if (atags_overflow(t)) + return; + + if (bad_magic(t->hdr.magic)) return; - } in_use += (t->hdr.size << 2); } @@ -273,6 +323,7 @@ void atags_print_tag(struct tag *t) printf(" id = 0x%x\n", t->u.serial.id); for (i = 0; i < ARRAY_SIZE(t->u.serial.reserved); i++) printf(" res[%d] = 0x%x\n", i, t->u.serial.reserved[i]); + printf(" hash = 0x%x\n", t->u.serial.hash); break; case ATAG_BOOTDEV: printf("[bootdev]:\n"); @@ -285,6 +336,7 @@ void atags_print_tag(struct tag *t) for (i = 0; i < ARRAY_SIZE(t->u.bootdev.reserved); i++) printf(" res[%d] = 0x%x\n", i, t->u.bootdev.reserved[i]); + printf(" hash = 0x%x\n", t->u.bootdev.hash); break; case ATAG_TOS_MEM: printf("[tos_mem]:\n"); @@ -303,6 +355,8 @@ void atags_print_tag(struct tag *t) printf(" flags = 0x%x\n", t->u.tos_mem.drm_mem.flags); for (i = 0; i < ARRAY_SIZE(t->u.tos_mem.reserved); i++) printf(" res[%d] = 0x%llx\n", i, t->u.tos_mem.reserved[i]); + printf(" res1 = 0x%x\n", t->u.tos_mem.reserved1); + printf(" hash = 0x%x\n", t->u.tos_mem.hash); break; case ATAG_DDR_MEM: printf("[ddr_mem]:\n"); @@ -314,6 +368,7 @@ void atags_print_tag(struct tag *t) printf(" bank[%d] = 0x%llx\n", i, t->u.ddr_mem.bank[i]); for (i = 0; i < ARRAY_SIZE(t->u.ddr_mem.reserved); i++) printf(" res[%d] = 0x%x\n", i, t->u.ddr_mem.reserved[i]); + printf(" hash = 0x%x\n", t->u.ddr_mem.hash); break; case ATAG_RAM_PARTITION: printf("[ram_partition]:\n"); @@ -324,11 +379,14 @@ void atags_print_tag(struct tag *t) printf(" res[%d] = 0x%x\n", i, t->u.ram_part.reserved[i]); printf(" Part: Name Start Addr Size\t\n"); - for (i = 0; i < t->u.ram_part.count; i++) + for (i = 0; i < ARRAY_SIZE(t->u.ram_part.part); i++) printf("%16s 0x%08llx 0x%08llx\n", t->u.ram_part.part[i].name, t->u.ram_part.part[i].start, t->u.ram_part.part[i].size); + for (i = 0; i < ARRAY_SIZE(t->u.ram_part.reserved1); i++) + printf(" res1[%d] = 0x%x\n", i, t->u.ram_part.reserved1[i]); + printf(" hash = 0x%x\n", t->u.ram_part.hash); break; case ATAG_ATF_MEM: printf("[atf_mem]:\n"); @@ -339,6 +397,25 @@ void atags_print_tag(struct tag *t) printf(" size = 0x%x\n", t->u.atf_mem.size); for (i = 0; i < ARRAY_SIZE(t->u.atf_mem.reserved); i++) printf(" res[%d] = 0x%x\n", i, t->u.atf_mem.reserved[i]); + printf(" hash = 0x%x\n", t->u.atf_mem.hash); + break; + case ATAG_PUB_KEY: + printf("[pub_key_mem]:\n"); + printf(" magic = 0x%x\n", t->hdr.magic); + printf(" size = 0x%x\n\n", t->hdr.size << 2); + printf(" version = 0x%x\n", t->u.pub_key.version); + printf(" hash = 0x%x\n", t->u.pub_key.hash); + break; + case ATAG_SOC_INFO: + printf("[soc_info]:\n"); + printf(" magic = 0x%x\n", t->hdr.magic); + printf(" size = 0x%x\n\n", t->hdr.size << 2); + printf(" version = 0x%x\n", t->u.soc.version); + printf(" name = 0x%x\n", t->u.soc.name); + printf(" flags = 0x%x\n", t->u.soc.flags); + for (i = 0; i < ARRAY_SIZE(t->u.soc.reserved); i++) + printf(" res[%d] = 0x%x\n", i, t->u.soc.reserved[i]); + printf(" hash = 0x%x\n", t->u.soc.hash); break; case ATAG_CORE: printf("[core]:\n"); @@ -359,12 +436,15 @@ void atags_print_all_tags(void) { struct tag *t; + if (!atags_is_available()) + return; + for_each_tag(t, (struct tag *)ATAGS_PHYS_BASE) { - if (bad_magic(t->hdr.magic)) { - printf("%s: find unknown magic(%x)\n", - __func__, t->hdr.magic); + if (atags_overflow(t)) + return; + + if (bad_magic(t->hdr.magic)) return; - } atags_print_tag(t); } @@ -378,6 +458,8 @@ void atags_test(void) struct tag_tos_mem t_tos_mem; struct tag_ram_partition t_ram_param; struct tag_atf_mem t_atf_mem; + struct tag_pub_key t_pub_key; + struct tag_soc_info t_soc; memset(&t_serial, 0x1, sizeof(t_serial)); memset(&t_bootdev, 0x2, sizeof(t_bootdev)); @@ -385,6 +467,8 @@ void atags_test(void) memset(&t_tos_mem, 0x4, sizeof(t_tos_mem)); memset(&t_ram_param, 0x0, sizeof(t_ram_param)); memset(&t_atf_mem, 0x5, sizeof(t_atf_mem)); + memset(&t_pub_key, 0x6, sizeof(t_pub_key)); + memset(&t_soc, 0x7, sizeof(t_soc)); memcpy(&t_tos_mem.tee_mem.name, "tee_mem", 8); memcpy(&t_tos_mem.drm_mem.name, "drm_mem", 8); @@ -415,6 +499,8 @@ void atags_test(void) atags_set_tag(ATAG_TOS_MEM, &t_tos_mem); atags_set_tag(ATAG_RAM_PARTITION, &t_ram_param); atags_set_tag(ATAG_ATF_MEM, &t_atf_mem); + atags_set_tag(ATAG_PUB_KEY, &t_pub_key); + atags_set_tag(ATAG_SOC_INFO, &t_soc); atags_print_all_tags(); atags_stat(); |