Index: stand/fdt/fdt_loader_cmd.c =================================================================== --- stand/fdt/fdt_loader_cmd.c +++ stand/fdt/fdt_loader_cmd.c @@ -340,60 +340,76 @@ fdt_apply_overlays() { struct preloaded_file *fp; - size_t overlays_size, max_overlay_size, new_fdtp_size; - void *new_fdtp; + size_t max_overlay_size, next_fdtp_size; + size_t current_fdtp_size; + void *current_fdtp; + void *next_fdtp; void *overlay; int rv; if ((fdtp == NULL) || (fdtp_size == 0)) return; - overlays_size = 0; max_overlay_size = 0; for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) { if (max_overlay_size < fp->f_size) max_overlay_size = fp->f_size; - overlays_size += fp->f_size; } /* Nothing to apply */ - if (overlays_size == 0) + if (max_overlay_size == 0) return; - /* It's actually more than enough */ - new_fdtp_size = fdtp_size + overlays_size; - new_fdtp = malloc(new_fdtp_size); - if (new_fdtp == NULL) { - printf("failed to allocate memory for DTB blob with overlays\n"); - return; - } - overlay = malloc(max_overlay_size); if (overlay == NULL) { printf("failed to allocate memory for DTB blob with overlays\n"); - free(new_fdtp); - return; - } - - rv = fdt_open_into(fdtp, new_fdtp, new_fdtp_size); - if (rv != 0) { - printf("failed to open DTB blob for applying overlays\n"); - free(new_fdtp); - free(overlay); return; } - + current_fdtp = fdtp; + current_fdtp_size = fdtp_size; for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) { printf("applying DTB overlay '%s'\n", fp->f_name); + next_fdtp_size = current_fdtp_size + fp->f_size; + next_fdtp = malloc(next_fdtp_size); + if (next_fdtp == NULL) { + /* + * Output warning, then move on to applying other + * overlays in case this one is simply too large. + */ + printf("failed to allocate memory for overlay base\n"); + continue; + } + rv = fdt_open_into(current_fdtp, next_fdtp, next_fdtp_size); + if (rv == 0) { + printf("failed to open base dtb into overlay base\n"); + continue; + } COPYOUT(fp->f_addr, overlay, fp->f_size); - /* Both overlay and new_fdtp may be modified in place */ - fdt_overlay_apply(new_fdtp, overlay); + /* Both overlay and next_fdtp may be modified in place */ + rv = fdt_overlay_apply(next_fdtp, overlay); + if (rv == 0) { + /* Rotate next -> current */ + if (current_fdtp != fdtp) + free(current_fdtp); + current_fdtp = next_fdtp; + current_fdtp_size = next_fdtp_size; + } else { + /* + * Assume here that the base we tried to apply on is + * either trashed or in an inconsistent state. Trying to + * load it might work, but it's better to discard it and + * play it safe. */ + free(next_fdtp); + printf("failed to apply overlay: %s\n", + fdt_strerror(rv)); + } + } + /* We could have failed to apply all overlays; then we do nothing */ + if (current_fdtp != fdtp) { + free(fdtp); + fdtp = current_fdtp; + fdtp_size = current_fdtp_size; } - - free(fdtp); - fdtp = new_fdtp; - fdtp_size = new_fdtp_size; - free(overlay); }