| 161 | } |
| 162 | |
| 163 | static struct mh_cache *get_mh_cache(void) |
| 164 | { |
| 165 | static struct mh_cache mhc; |
| 166 | |
| 167 | /* |
| 168 | * A single invocation of cbfstool can process regions that use different CBFS metadata. |
| 169 | * Right now, the only such case is when Top Swap redundancy is in use. Check for Top |
| 170 | * Swap region to decide if the cache can be reused. |
| 171 | * |
| 172 | * This implicitly checks whether the cache is initialized. |
| 173 | */ |
| 174 | const enum mhc_kind kind = derive_mhc_kind(param.region_name); |
| 175 | if (mhc.kind == kind) |
| 176 | return &mhc; |
| 177 | |
| 178 | mhc.kind = kind; |
| 179 | |
| 180 | const struct fmap *fmap = partitioned_file_get_fmap(param.image_file); |
| 181 | if (!fmap) |
| 182 | goto no_metadata_hash; |
| 183 | |
| 184 | const char *bootblock_region = SECTION_NAME_BOOTBLOCK; |
| 185 | if (kind == MHC_SECONDARY) |
| 186 | bootblock_region = SECTION_NAME_BOOTBLOCK_B; |
| 187 | |
| 188 | /* Find the metadata_hash container. If there is a "BOOTBLOCK" FMAP section, it's |
| 189 | there. If not, it's a normal file in the primary CBFS section. */ |
| 190 | size_t offset, size; |
| 191 | struct buffer buffer; |
| 192 | if (fmap_find_area(fmap, bootblock_region)) { |
| 193 | if (!partitioned_file_read_region(&buffer, param.image_file, bootblock_region)) |
| 194 | goto no_metadata_hash; |
| 195 | mhc.region = bootblock_region; |
| 196 | offset = 0; |
| 197 | size = buffer.size; |
| 198 | } else { |
| 199 | if (kind != MHC_PRIMARY) { |
| 200 | /* Top Swap requires BOOTBLOCK_B region. */ |
| 201 | ERROR("Malformed image: '%s' region is missing\n", bootblock_region); |
| 202 | goto no_metadata_hash; |
| 203 | } |
| 204 | |
| 205 | struct cbfs_image cbfs; |
| 206 | struct cbfs_file *mh_container; |
| 207 | if (!partitioned_file_read_region(&buffer, param.image_file, SECTION_NAME_PRIMARY_CBFS)) |
| 208 | goto no_metadata_hash; |
| 209 | mhc.region = SECTION_NAME_PRIMARY_CBFS; |
| 210 | if (cbfs_image_from_buffer(&cbfs, &buffer, param.headeroffset)) |
| 211 | goto no_metadata_hash; |
| 212 | mh_container = cbfs_get_entry(&cbfs, "bootblock"); |
| 213 | if (!mh_container || be32toh(mh_container->type) != CBFS_TYPE_BOOTBLOCK) { |
| 214 | /* Check for apu/amdfw file */ |
| 215 | mh_container = cbfs_get_entry(&cbfs, "apu/amdfw"); |
| 216 | if (!mh_container || be32toh(mh_container->type) != CBFS_TYPE_AMDFW) |
| 217 | goto no_metadata_hash; |
| 218 | } |
| 219 | |
| 220 | offset = (void *)mh_container + be32toh(mh_container->offset) - |
no test coverage detected