static int flash_nvram_start_read(void *dst, uint32_t src, uint32_t len) { int rc; if (!try_lock(&flash_lock)) return OPAL_BUSY; if (!nvram_flash) { rc = OPAL_HARDWARE; goto out; } if (nvram_flash->busy) { rc = OPAL_BUSY; goto out; } if ((src + len) > nvram_size) { prerror("FLASH_NVRAM: read out of bound (0x%x,0x%x)\n", src, len); rc = OPAL_PARAMETER; goto out; } nvram_flash->busy = true; unlock(&flash_lock); rc = blocklevel_read(nvram_flash->bl, nvram_offset + src, dst, len); lock(&flash_lock); nvram_flash->busy = false; out: unlock(&flash_lock); if (!rc) nvram_read_complete(true); return rc; }
static int do_iterate(struct gard_ctx *ctx, int (*func)(struct gard_ctx *ctx, int pos, struct gard_record *gard, void *priv), void *priv) { int rc = 0; unsigned int i; struct gard_record gard, null_gard; memset(&null_gard, UINT_MAX, sizeof(gard)); for (i = 0; i * sizeof_gard(ctx) < ctx->gard_data_len && rc == 0; i++) { memset(&gard, 0, sizeof(gard)); rc = blocklevel_read(ctx->bl, ctx->gard_data_pos + (i * sizeof_gard(ctx)), &gard, sizeof(gard)); /* It isn't super clear what constitutes the end, this should do */ if (rc || memcmp(&gard, &null_gard, sizeof(gard)) == 0) break; rc = func(ctx, i, &gard, priv); } return rc; }
static void do_read_file(const char *file, uint32_t start, uint32_t size) { int fd, rc; ssize_t len; uint32_t done = 0; fd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 00666); if (fd == -1) { perror("Failed to open file"); exit(1); } printf("Reading to \"%s\" from 0x%08x..0x%08x !\n", file, start, start + size); progress_init(size >> 8); while(size) { len = size > FILE_BUF_SIZE ? FILE_BUF_SIZE : size; rc = blocklevel_read(bl, start, file_buf, len); if (rc) { fprintf(stderr, "Flash read error %d for" " chunk at 0x%08x\n", rc, start); exit(1); } rc = write(fd, file_buf, len); if (rc < 0) { perror("Error writing file"); exit(1); } start += len; size -= len; done += len; progress_tick(done >> 8); } progress_end(); close(fd); }
/* * load a resource from FLASH * buf and len shouldn't account for ECC even if partition is ECCed. * * The API here is a bit strange. * If resource has a STB container, buf will contain it * If loading subpartition with STB container, buff will *NOT* contain it * For trusted boot, the whole partition containing the subpart is measured. * * Additionally, the logic to work out how much to read from flash is insane. */ static int flash_load_resource(enum resource_id id, uint32_t subid, void *buf, size_t *len) { int i; int rc = OPAL_RESOURCE; struct ffs_handle *ffs; struct flash *flash; const char *name; bool status = false; bool ecc; bool part_signed = false; void *bufp = buf; size_t bufsz = *len; int ffs_part_num, ffs_part_start, ffs_part_size; int content_size = 0; int offset = 0; lock(&flash_lock); if (!system_flash) { /** * @fwts-label SystemFlashNotFound * @fwts-advice No system flash was found. Check for missing * calls flash_register(...). */ prlog(PR_WARNING, "FLASH: Can't load resource id:%i. " "No system flash found\n", id); goto out_unlock; } flash = system_flash; if (flash->busy) goto out_unlock; for (i = 0, name = NULL; i < ARRAY_SIZE(part_name_map); i++) { if (part_name_map[i].id == id) { name = part_name_map[i].name; break; } } if (!name) { prerror("FLASH: Couldn't find partition for id %d\n", id); goto out_unlock; } /* * If partition doesn't have a subindex but the caller specifies one, * we fail. eg. kernel partition doesn't have a subindex */ if ((part_name_map[i].subid == RESOURCE_SUBID_NONE) && (subid != RESOURCE_SUBID_NONE)) { prerror("PLAT: Partition %s doesn't have subindex\n", name); goto out_unlock; } rc = ffs_init(0, flash->size, flash->bl, &ffs, 1); if (rc) { prerror("FLASH: Can't open ffs handle: %d\n", rc); goto out_unlock; } rc = ffs_lookup_part(ffs, name, &ffs_part_num); if (rc) { /* This is not an error per-se, some partitions * are purposefully absent, don't spam the logs */ prlog(PR_DEBUG, "FLASH: No %s partition\n", name); goto out_free_ffs; } rc = ffs_part_info(ffs, ffs_part_num, NULL, &ffs_part_start, NULL, &ffs_part_size, &ecc); if (rc) { prerror("FLASH: Failed to get %s partition info\n", name); goto out_free_ffs; } prlog(PR_DEBUG,"FLASH: %s partition %s ECC\n", name, ecc ? "has" : "doesn't have"); if (ffs_part_size < SECURE_BOOT_HEADERS_SIZE) { prerror("FLASH: secboot headers bigger than " "partition size 0x%x\n", ffs_part_size); goto out_free_ffs; } rc = blocklevel_read(flash->bl, ffs_part_start, bufp, SECURE_BOOT_HEADERS_SIZE); if (rc) { prerror("FLASH: failed to read the first 0x%x from " "%s partition, rc %d\n", SECURE_BOOT_HEADERS_SIZE, name, rc); goto out_free_ffs; } part_signed = stb_is_container(bufp, SECURE_BOOT_HEADERS_SIZE); prlog(PR_DEBUG, "FLASH: %s partition %s signed\n", name, part_signed ? "is" : "isn't"); /* * part_start/size are raw pointers into the partition. * ie. they will account for ECC if included. */ if (part_signed) { bufp += SECURE_BOOT_HEADERS_SIZE; bufsz -= SECURE_BOOT_HEADERS_SIZE; content_size = stb_sw_payload_size(buf, SECURE_BOOT_HEADERS_SIZE); *len = content_size + SECURE_BOOT_HEADERS_SIZE; if (content_size > bufsz) { prerror("FLASH: content size > buffer size\n"); rc = OPAL_PARAMETER; goto out_free_ffs; } ffs_part_start += SECURE_BOOT_HEADERS_SIZE; rc = blocklevel_read(flash->bl, ffs_part_start, bufp, content_size); if (rc) { prerror("FLASH: failed to read content size %d" " %s partition, rc %d\n", content_size, name, rc); goto out_free_ffs; } if (subid == RESOURCE_SUBID_NONE) goto done_reading; rc = flash_subpart_info(bufp, content_size, ffs_part_size, NULL, subid, &offset, &content_size); if (rc) { prerror("FLASH: Failed to parse subpart info for %s\n", name); goto out_free_ffs; } bufp += offset; goto done_reading; } else /* stb_signed */ { /* * Back to the old way of doing things, no STB header. */ if (subid == RESOURCE_SUBID_NONE) { if (id == RESOURCE_ID_KERNEL || id == RESOURCE_ID_INITRAMFS) { /* * Because actualSize is a lie, we compute the * size of the BOOTKERNEL based on what the ELF * headers say. Otherwise we end up reading more * than we should */ content_size = sizeof_elf_from_hdr(buf); if (!content_size) { prerror("FLASH: Invalid ELF header part" " %s\n", name); rc = OPAL_RESOURCE; goto out_free_ffs; } } else { content_size = ffs_part_size; } if (content_size > bufsz) { prerror("FLASH: %s content size %d > " " buffer size %lu\n", name, content_size, bufsz); rc = OPAL_PARAMETER; goto out_free_ffs; } prlog(PR_DEBUG, "FLASH: computed %s size %u\n", name, content_size); rc = blocklevel_read(flash->bl, ffs_part_start, buf, content_size); if (rc) { prerror("FLASH: failed to read content size %d" " %s partition, rc %d\n", content_size, name, rc); goto out_free_ffs; } *len = content_size; goto done_reading; } BUILD_ASSERT(FLASH_SUBPART_HEADER_SIZE <= SECURE_BOOT_HEADERS_SIZE); rc = flash_subpart_info(bufp, SECURE_BOOT_HEADERS_SIZE, ffs_part_size, &ffs_part_size, subid, &offset, &content_size); if (rc) { prerror("FLASH: FAILED reading subpart info. rc=%d\n", rc); goto out_free_ffs; } *len = ffs_part_size; prlog(PR_DEBUG, "FLASH: Computed %s partition size: %u " "(subpart %u size %u offset %u)\n", name, ffs_part_size, subid, content_size, offset); /* * For a sub partition, we read the whole (computed) * partition, and then measure that. * Afterwards, we memmove() things back into place for * the caller. */ rc = blocklevel_read(flash->bl, ffs_part_start, buf, ffs_part_size); bufp += offset; } done_reading: /* * Verify and measure the retrieved PNOR partition as part of the * secure boot and trusted boot requirements */ secureboot_verify(id, buf, *len); trustedboot_measure(id, buf, *len); /* Find subpartition */ if (subid != RESOURCE_SUBID_NONE) { memmove(buf, bufp, content_size); *len = content_size; } status = true; out_free_ffs: ffs_close(ffs); out_unlock: unlock(&flash_lock); return status ? OPAL_SUCCESS : rc; }
int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl, struct ffs_handle **ffs, bool mark_ecc) { struct ffs_hdr hdr; struct ffs_hdr blank_hdr; struct ffs_handle *f; uint64_t total_size; int rc, i; if (!ffs || !bl) return FLASH_ERR_PARM_ERROR; *ffs = NULL; rc = blocklevel_get_info(bl, NULL, &total_size, NULL); if (rc) { FL_ERR("FFS: Error %d retrieving flash info\n", rc); return rc; } if (total_size > UINT_MAX) return FLASH_ERR_VERIFY_FAILURE; if ((offset + max_size) < offset) return FLASH_ERR_PARM_ERROR; if ((max_size > total_size)) return FLASH_ERR_PARM_ERROR; /* Read flash header */ rc = blocklevel_read(bl, offset, &hdr, sizeof(hdr)); if (rc) { FL_ERR("FFS: Error %d reading flash header\n", rc); return rc; } /* * Flash controllers can get deconfigured or otherwise upset, when this * happens they return all 0xFF bytes. * An ffs_hdr consisting of all 0xFF cannot be valid and it would be * nice to drop a hint to the user to help with debugging. This will * help quickly differentiate between flash corruption and standard * type 'reading from the wrong place' errors vs controller errors or * reading erased data. */ memset(&blank_hdr, UINT_MAX, sizeof(struct ffs_hdr)); if (memcmp(&blank_hdr, &hdr, sizeof(struct ffs_hdr)) == 0) { FL_ERR("FFS: Reading the flash has returned all 0xFF.\n"); FL_ERR("Are you reading erased flash?\n"); FL_ERR("Is something else using the flash controller?\n"); return FLASH_ERR_BAD_READ; } /* Allocate ffs_handle structure and start populating */ f = malloc(sizeof(*f)); if (!f) return FLASH_ERR_MALLOC_FAILED; memset(f, 0, sizeof(*f)); f->toc_offset = offset; f->max_size = max_size; f->bl = bl; /* Convert and check flash header */ rc = ffs_check_convert_header(&f->hdr, &hdr); if (rc) { FL_INF("FFS: Flash header not found. Code: %d\n", rc); goto out; } /* Check header is sane */ if ((f->hdr.block_size * f->hdr.size) > max_size) { rc = FLASH_ERR_PARM_ERROR; FL_ERR("FFS: Flash header exceeds max flash size\n"); goto out; } if ((f->hdr.entry_size * f->hdr.entry_count) > (f->hdr.block_size * f->hdr.size)) { rc = FLASH_ERR_PARM_ERROR; FL_ERR("FFS: Flash header entries exceeds available blocks\n"); goto out; } /* * Decide how much of the image to grab to get the whole * partition map. */ f->cached_size = f->hdr.block_size * f->hdr.size; /* Check for overflow or a silly size */ if (!f->hdr.size || f->cached_size / f->hdr.size != f->hdr.block_size) { rc= FLASH_ERR_MALLOC_FAILED; FL_ERR("FFS: Cache size overflow (0x%x * 0x%x)\n", f->hdr.block_size, f->hdr.size); goto out; } FL_DBG("FFS: Partition map size: 0x%x\n", f->cached_size); /* Allocate cache */ f->cache = malloc(f->cached_size); if (!f->cache) { rc = FLASH_ERR_MALLOC_FAILED; goto out; } /* Read the cached map */ rc = blocklevel_read(bl, offset, f->cache, f->cached_size); if (rc) { FL_ERR("FFS: Error %d reading flash partition map\n", rc); goto out; } if (mark_ecc) { uint32_t start, total_size; bool ecc; for (i = 0; i < f->hdr.entry_count; i++) { rc = ffs_part_info(f, i, NULL, &start, &total_size, NULL, &ecc); if (rc) { FL_ERR("FFS: Failed to read ffs partition %d\n", i); goto out; } if (ecc) { rc = blocklevel_ecc_protect(bl, start, total_size); if (rc) { FL_ERR("FFS: Failed to blocklevel_ecc_protect(0x%08x, 0x%08x)\n", start, total_size); goto out; } } /* ecc */ } /* for */ } out: if (rc == 0) *ffs = f; else free(f); return rc; }