/* * Will relocate the DTB to the tags addr if the device tree is found and return * its address * * Arguments: kernel - Start address of the kernel loaded in RAM * tags - Start address of the tags loaded in RAM * kernel_size - Size of the kernel in bytes * * Return Value: DTB address : If appended device tree is found * 'NULL' : Otherwise */ void *dev_tree_appended(void *kernel, void *tags, uint32_t kernel_size) { uint32_t app_dtb_offset = 0; uint32_t size; memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t)); /* * Check if we have valid offset for the DTB, if not return error. * If the kernel image does not have appeneded device tree, DTB offset * might contain some random address which is not accessible & cause * data abort. If kernel start + dtb offset address exceed the total * size of the kernel, then we dont have an appeneded DTB. */ if (app_dtb_offset < kernel_size) { if (!fdt_check_header((void*) (kernel + app_dtb_offset))) { void *dtb; int rc; debugf( "Found Appeneded Flattened Device tree\n"); dtb = kernel + app_dtb_offset; size = fdt_totalsize(dtb); if (check_aboot_addr_range_overlap(tags, size)) { debugf("Appended dtb aboot overlap check failed.\n"); return NULL; } rc = fdt_open_into(dtb, tags, size); if (rc == 0) { /* clear out the old DTB magic so kernel doesn't find it */ *((uint32_t *)dtb) = 0; return tags; } } } else debugf( "DTB offset is incorrect, kernel image does not have appended DTB\n"); return NULL; }
/* * Will relocate the DTB to the tags addr if the device tree is found and return * its address * * Arguments: kernel - Start address of the kernel loaded in RAM * tags - Start address of the tags loaded in RAM * kernel_size - Size of the kernel in bytes * * Return Value: DTB address : If appended device tree is found * 'NULL' : Otherwise */ void *dev_tree_appended(void *kernel, uint32_t kernel_size, void *tags) { void *kernel_end = kernel + kernel_size; uint32_t app_dtb_offset = 0; void *dtb; void *bestmatch_tag = NULL; uint32_t bestmatch_tag_size; uint32_t bestmatch_soc_rev_id = INVALID_SOC_REV_ID; memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t)); dtb = kernel + app_dtb_offset; while (dtb + sizeof(struct fdt_header) < kernel_end) { uint32_t dtb_soc_rev_id; struct fdt_header dtb_hdr; uint32_t dtb_size; /* the DTB could be unaligned, so extract the header, * and operate on it separately */ memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header)); if (fdt_check_header((const void *)&dtb_hdr) != 0 || (dtb + fdt_totalsize((const void *)&dtb_hdr) > kernel_end)) break; dtb_size = fdt_totalsize(&dtb_hdr); if (check_aboot_addr_range_overlap(tags, dtb_size)) { dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n"); return NULL; } /* now that we know we have a valid DTB, we need to copy * it somewhere aligned, like tags */ memcpy(tags, dtb, dtb_size); dtb_soc_rev_id = dev_tree_compatible(tags); if (dtb_soc_rev_id == board_soc_version()) { /* clear out the old DTB magic so kernel doesn't find it */ *((uint32_t *)(kernel + app_dtb_offset)) = 0; return tags; } else if ((dtb_soc_rev_id != INVALID_SOC_REV_ID) && (dtb_soc_rev_id < board_soc_version())) { /* 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) { dprintf(INFO,"DTB found with bestmatch soc rev id 0x%x.Board soc rev id 0x%x\n", bestmatch_soc_rev_id, board_soc_version()); memcpy(tags, bestmatch_tag, bestmatch_tag_size); /* clear out the old DTB magic so kernel doesn't find it */ *((uint32_t *)(kernel + app_dtb_offset)) = 0; return tags; } dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n"); return NULL; }