Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 3 | #include <assert.h> |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 4 | #include <fcntl.h> |
| 5 | #include <errno.h> |
| 6 | #include <limits.h> |
| 7 | #include <openssl/sha.h> |
| 8 | #include <stdio.h> |
| 9 | #include <sys/stat.h> |
| 10 | #include <unistd.h> |
| 11 | #include <string.h> |
| 12 | #include <stdlib.h> |
| 13 | |
| 14 | #include "amdfwtool.h" |
| 15 | |
| 16 | /* Defines related to hashing signed binaries */ |
| 17 | enum hash_header_ver { |
| 18 | HASH_HDR_V1 = 1, |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 19 | HASH_HDR_V2, |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 20 | }; |
| 21 | /* Signature ID enums are defined by PSP based on the algorithm used. */ |
| 22 | enum signature_id { |
| 23 | SIG_ID_RSA2048, |
| 24 | SIG_ID_RSA4096 = 2, |
| 25 | }; |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 26 | |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 27 | #define HASH_FILE_SUFFIX ".hash" |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 28 | struct psp_fw_hash_file_info { |
| 29 | int fd; |
| 30 | bool present; |
| 31 | struct psp_fw_hash_table hash_header; |
| 32 | }; |
| 33 | static struct psp_fw_hash_file_info hash_files[MAX_NUM_HASH_TABLES]; |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 34 | |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 35 | #define UUID_MAGIC "gpd.ta.appID" |
| 36 | |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 37 | static uint16_t get_psp_fw_type(enum platform soc_id, struct amd_fw_header *header) |
| 38 | { |
| 39 | switch (soc_id) { |
| 40 | case PLATFORM_MENDOCINO: |
| 41 | case PLATFORM_PHOENIX: |
| 42 | case PLATFORM_GLINDA: |
| 43 | /* Fallback to fw_type if fw_id is not populated, which serves the same |
| 44 | purpose on older SoCs. */ |
| 45 | return header->fw_id ? header->fw_id : header->fw_type; |
| 46 | default: |
| 47 | return header->fw_type; |
| 48 | } |
| 49 | } |
| 50 | |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 51 | static void get_psp_fw_uuid(void *buf, size_t buf_len, uint8_t *uuid) |
| 52 | { |
| 53 | void *ptr = memmem(buf, buf_len, UUID_MAGIC, strlen(UUID_MAGIC)); |
| 54 | |
| 55 | assert(ptr != NULL); |
| 56 | |
| 57 | memcpy(uuid, ptr + strlen(UUID_MAGIC), UUID_LEN_BYTES); |
| 58 | } |
| 59 | |
| 60 | static int add_single_sha(amd_fw_entry_hash *entry, void *buf, enum platform soc_id, |
| 61 | fwid_type_t fwid_type) |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 62 | { |
| 63 | uint8_t hash[SHA384_DIGEST_LENGTH]; |
| 64 | struct amd_fw_header *header = (struct amd_fw_header *)buf; |
| 65 | /* Include only signed part for hash calculation. */ |
| 66 | size_t len = header->fw_size_signed + sizeof(struct amd_fw_header); |
| 67 | uint8_t *body = (uint8_t *)buf; |
| 68 | |
| 69 | if (len > header->size_total) |
| 70 | return -1; |
| 71 | |
| 72 | if (header->sig_id == SIG_ID_RSA4096) { |
| 73 | SHA384(body, len, hash); |
| 74 | entry->sha_len = SHA384_DIGEST_LENGTH; |
| 75 | } else if (header->sig_id == SIG_ID_RSA2048) { |
| 76 | SHA256(body, len, hash); |
| 77 | entry->sha_len = SHA256_DIGEST_LENGTH; |
| 78 | } else { |
| 79 | fprintf(stderr, "%s: Unknown signature id: 0x%08x\n", |
| 80 | __func__, header->sig_id); |
| 81 | return -1; |
| 82 | } |
| 83 | |
| 84 | memcpy(entry->sha, hash, entry->sha_len); |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 85 | entry->fwid_type = fwid_type; |
| 86 | if (fwid_type == FWID_TYPE_UUID) |
| 87 | get_psp_fw_uuid(buf, header->size_total, entry->uuid); |
| 88 | else |
| 89 | entry->fw_id = get_psp_fw_type(soc_id, header); |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 90 | entry->subtype = header->fw_subtype; |
| 91 | |
| 92 | return 0; |
| 93 | } |
| 94 | |
| 95 | static int get_num_binaries(void *buf, size_t buf_size) |
| 96 | { |
| 97 | struct amd_fw_header *header = (struct amd_fw_header *)buf; |
| 98 | size_t total_len = 0; |
| 99 | int num_binaries = 0; |
| 100 | |
| 101 | while (total_len < buf_size) { |
| 102 | num_binaries++; |
| 103 | total_len += header->size_total; |
| 104 | header = (struct amd_fw_header *)(buf + total_len); |
| 105 | } |
| 106 | |
| 107 | if (total_len != buf_size) { |
| 108 | fprintf(stderr, "Malformed binary\n"); |
| 109 | return -1; |
| 110 | } |
| 111 | return num_binaries; |
| 112 | } |
| 113 | |
| 114 | static int add_sha(amd_fw_entry *entry, void *buf, size_t buf_size, enum platform soc_id) |
| 115 | { |
| 116 | struct amd_fw_header *header = (struct amd_fw_header *)buf; |
| 117 | /* Include only signed part for hash calculation. */ |
| 118 | size_t total_len = 0; |
| 119 | int num_binaries = get_num_binaries(buf, buf_size); |
| 120 | |
| 121 | if (num_binaries <= 0) |
| 122 | return num_binaries; |
| 123 | |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 124 | entry->hash_entries = calloc(num_binaries, sizeof(amd_fw_entry_hash)); |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 125 | if (!entry->hash_entries) { |
| 126 | fprintf(stderr, "Error allocating memory to add FW hash\n"); |
| 127 | return -1; |
| 128 | } |
| 129 | entry->num_hash_entries = num_binaries; |
| 130 | |
| 131 | /* Iterate through each binary */ |
| 132 | for (int i = 0; i < num_binaries; i++) { |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 133 | if (add_single_sha(&entry->hash_entries[i], buf + total_len, soc_id, |
| 134 | entry->fwid_type)) { |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 135 | free(entry->hash_entries); |
| 136 | return -1; |
| 137 | } |
| 138 | total_len += header->size_total; |
| 139 | header = (struct amd_fw_header *)(buf + total_len); |
| 140 | } |
| 141 | |
| 142 | return 0; |
| 143 | } |
| 144 | |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 145 | static void write_one_psp_firmware_hash_entry(int fd, amd_fw_entry_hash *entry, |
| 146 | uint8_t hash_tbl_id) |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 147 | { |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 148 | uint16_t subtype = entry->subtype; |
| 149 | |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 150 | if (hash_files[hash_tbl_id].hash_header.version == HASH_HDR_V2) { |
| 151 | write_or_fail(fd, entry->uuid, UUID_LEN_BYTES); |
| 152 | } else { |
| 153 | write_or_fail(fd, &entry->fw_id, sizeof(entry->fw_id)); |
| 154 | write_or_fail(fd, &subtype, sizeof(subtype)); |
| 155 | } |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 156 | write_or_fail(fd, entry->sha, entry->sha_len); |
| 157 | } |
| 158 | |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 159 | static void open_psp_fw_hash_files(const char *file_prefix) |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 160 | { |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 161 | size_t hash_file_strlen; |
| 162 | char *hash_file_name; |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 163 | |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 164 | /* Hash Table ID is part of the file name. For now only single digit ID is |
| 165 | supported and is sufficient. Hence assert MAX_NUM_HASH_TABLES < 10 before |
| 166 | constructing file name. Revisit later when > 10 hash tables are required. */ |
| 167 | assert(MAX_NUM_HASH_TABLES < 10); |
| 168 | /* file_prefix + ".[1-9]" + ".hash" + '\0' */ |
| 169 | hash_file_strlen = strlen(file_prefix) + 2 + strlen(HASH_FILE_SUFFIX) + 1; |
| 170 | hash_file_name = malloc(hash_file_strlen); |
| 171 | if (!hash_file_name) { |
| 172 | fprintf(stderr, "malloc(%lu) failed\n", hash_file_strlen); |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 173 | exit(-1); |
| 174 | } |
| 175 | |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 176 | for (unsigned int i = 0; i < MAX_NUM_HASH_TABLES; i++) { |
| 177 | /* Hash table IDs are expected to be contiguous and hence holes are not |
| 178 | expected. */ |
| 179 | if (!hash_files[i].present) |
| 180 | break; |
| 181 | |
| 182 | if (i) |
| 183 | snprintf(hash_file_name, hash_file_strlen, "%s.%d%s", |
| 184 | file_prefix, i, HASH_FILE_SUFFIX); |
| 185 | else |
| 186 | /* Default file name without number for backwards compatibility. */ |
| 187 | snprintf(hash_file_name, hash_file_strlen, "%s%s", |
| 188 | file_prefix, HASH_FILE_SUFFIX); |
| 189 | |
| 190 | hash_files[i].fd = open(hash_file_name, O_RDWR | O_CREAT | O_TRUNC, 0666); |
| 191 | if (hash_files[i].fd < 0) { |
| 192 | fprintf(stderr, "Error opening file: %s: %s\n", |
| 193 | hash_file_name, strerror(errno)); |
| 194 | free(hash_file_name); |
| 195 | exit(-1); |
| 196 | } |
| 197 | } |
| 198 | free(hash_file_name); |
| 199 | } |
| 200 | |
| 201 | static void close_psp_fw_hash_files(void) |
| 202 | { |
| 203 | for (unsigned int i = 0; i < MAX_NUM_HASH_TABLES; i++) { |
| 204 | if (!hash_files[i].present) |
| 205 | break; |
| 206 | |
| 207 | close(hash_files[i].fd); |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | static void write_psp_firmware_hash(amd_fw_entry *fw_table) |
| 212 | { |
| 213 | uint8_t hash_tbl_id; |
| 214 | |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 215 | for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 216 | hash_tbl_id = fw_table[i].hash_tbl_id; |
| 217 | assert(hash_files[hash_tbl_id].present); |
| 218 | |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 219 | for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) { |
| 220 | if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH) { |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 221 | hash_files[hash_tbl_id].hash_header.no_of_entries_256++; |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 222 | } else if (fw_table[i].hash_entries[j].sha_len == |
| 223 | SHA384_DIGEST_LENGTH) { |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 224 | hash_files[hash_tbl_id].hash_header.no_of_entries_384++; |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 225 | } else if (fw_table[i].hash_entries[j].sha_len) { |
| 226 | fprintf(stderr, "%s: Error invalid sha_len %d\n", |
| 227 | __func__, fw_table[i].hash_entries[j].sha_len); |
| 228 | exit(-1); |
| 229 | } |
| 230 | } |
| 231 | } |
| 232 | |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 233 | for (unsigned int i = 0; i < MAX_NUM_HASH_TABLES; i++) { |
| 234 | if (!hash_files[i].present) |
| 235 | continue; |
| 236 | write_or_fail(hash_files[i].fd, &hash_files[i].hash_header, |
| 237 | sizeof(hash_files[i].hash_header)); |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 238 | /* Add a reserved field as expected by version 2 header */ |
| 239 | if (hash_files[i].hash_header.version == HASH_HDR_V2) { |
| 240 | uint16_t reserved = 0; |
| 241 | |
| 242 | write_or_fail(hash_files[i].fd, &reserved, sizeof(reserved)); |
| 243 | } |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 244 | } |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 245 | |
| 246 | /* Add all the SHA256 hash entries first followed by SHA384 entries. PSP verstage |
| 247 | processes the table in that order. Mixing and matching SHA256 and SHA384 entries |
| 248 | will cause the hash verification failure at run-time. */ |
| 249 | for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 250 | hash_tbl_id = fw_table[i].hash_tbl_id; |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 251 | for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) { |
| 252 | if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH) |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 253 | write_one_psp_firmware_hash_entry(hash_files[hash_tbl_id].fd, |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 254 | &fw_table[i].hash_entries[j], hash_tbl_id); |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 255 | } |
| 256 | } |
| 257 | |
| 258 | for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 259 | hash_tbl_id = fw_table[i].hash_tbl_id; |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 260 | for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) { |
| 261 | if (fw_table[i].hash_entries[j].sha_len == SHA384_DIGEST_LENGTH) |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 262 | write_one_psp_firmware_hash_entry(hash_files[hash_tbl_id].fd, |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 263 | &fw_table[i].hash_entries[j], hash_tbl_id); |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 264 | } |
| 265 | } |
| 266 | |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 267 | for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { |
| 268 | if (!fw_table[i].num_hash_entries || !fw_table[i].hash_entries) |
| 269 | continue; |
| 270 | |
| 271 | free(fw_table[i].hash_entries); |
| 272 | fw_table[i].hash_entries = NULL; |
| 273 | fw_table[i].num_hash_entries = 0; |
| 274 | } |
| 275 | } |
| 276 | |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 277 | static void update_hash_files_config(amd_fw_entry *fw_table) |
| 278 | { |
| 279 | uint16_t version = fw_table->fwid_type == FWID_TYPE_UUID ? HASH_HDR_V2 : HASH_HDR_V1; |
| 280 | |
| 281 | hash_files[fw_table->hash_tbl_id].present = true; |
| 282 | if (version > hash_files[fw_table->hash_tbl_id].hash_header.version) |
| 283 | hash_files[fw_table->hash_tbl_id].hash_header.version = version; |
| 284 | } |
| 285 | |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 286 | /** |
| 287 | * process_signed_psp_firmwares() - Process the signed PSP binaries to keep them separate |
| 288 | * @signed_rom: Output file path grouping all the signed PSP binaries. |
| 289 | * @fw_table: Table of all the PSP firmware entries/binaries to be processed. |
| 290 | * @signed_start_addr: Offset of the FMAP section, within the flash device, to hold |
| 291 | * the signed PSP binaries. |
| 292 | * @soc_id: SoC ID of the PSP binaries. |
| 293 | */ |
| 294 | void process_signed_psp_firmwares(const char *signed_rom, |
| 295 | amd_fw_entry *fw_table, |
| 296 | uint64_t signed_start_addr, |
| 297 | enum platform soc_id) |
| 298 | { |
| 299 | unsigned int i; |
| 300 | int fd; |
| 301 | int signed_rom_fd; |
| 302 | ssize_t bytes, align_bytes; |
| 303 | uint8_t *buf; |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 304 | struct amd_fw_header header; |
| 305 | struct stat fd_stat; |
| 306 | /* Every blob in amdfw*.rom has to start at address aligned to 0x100. Prepare an |
| 307 | alignment data with 0xff to pad the blobs and meet the alignment requirement. */ |
| 308 | uint8_t align_data[BLOB_ALIGNMENT - 1]; |
| 309 | |
| 310 | memset(align_data, 0xff, sizeof(align_data)); |
| 311 | signed_rom_fd = open(signed_rom, O_RDWR | O_CREAT | O_TRUNC, |
| 312 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); |
| 313 | if (signed_rom_fd < 0) { |
| 314 | fprintf(stderr, "Error opening file: %s: %s\n", |
| 315 | signed_rom, strerror(errno)); |
| 316 | return; |
| 317 | } |
| 318 | |
| 319 | for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { |
| 320 | fw_table[i].num_hash_entries = 0; |
| 321 | fw_table[i].hash_entries = NULL; |
| 322 | |
| 323 | if (!(fw_table[i].filename) || fw_table[i].skip_hashing) |
| 324 | continue; |
| 325 | |
| 326 | memset(&header, 0, sizeof(header)); |
| 327 | |
| 328 | fd = open(fw_table[i].filename, O_RDONLY); |
| 329 | if (fd < 0) { |
| 330 | /* Keep the file along with set of unsigned PSP binaries & continue. */ |
| 331 | fprintf(stderr, "Error opening file: %s: %s\n", |
| 332 | fw_table[i].filename, strerror(errno)); |
| 333 | continue; |
| 334 | } |
| 335 | |
| 336 | if (fstat(fd, &fd_stat)) { |
| 337 | /* Keep the file along with set of unsigned PSP binaries & continue. */ |
| 338 | fprintf(stderr, "fstat error: %s\n", strerror(errno)); |
| 339 | close(fd); |
| 340 | continue; |
| 341 | } |
| 342 | |
| 343 | bytes = read_from_file_to_buf(fd, &header, sizeof(struct amd_fw_header)); |
| 344 | if (bytes != (ssize_t)sizeof(struct amd_fw_header)) { |
| 345 | /* Keep the file along with set of unsigned PSP binaries & continue. */ |
| 346 | fprintf(stderr, "%s: Error reading header from %s\n", |
| 347 | __func__, fw_table[i].filename); |
| 348 | close(fd); |
| 349 | continue; |
| 350 | } |
| 351 | |
| 352 | /* If firmware header looks like invalid, assume it's not signed */ |
| 353 | if (!header.fw_type && !header.fw_id) { |
| 354 | fprintf(stderr, "%s: Invalid FWID for %s\n", |
| 355 | __func__, fw_table[i].filename); |
| 356 | close(fd); |
| 357 | continue; |
| 358 | } |
| 359 | |
| 360 | |
| 361 | /* PSP binary is not signed and should not be part of signed PSP binaries |
| 362 | set. */ |
| 363 | if (header.sig_opt != 1) { |
| 364 | close(fd); |
| 365 | continue; |
| 366 | } |
| 367 | |
| 368 | buf = malloc(fd_stat.st_size); |
| 369 | if (!buf) { |
| 370 | /* Keep the file along with set of unsigned PSP binaries & continue. */ |
| 371 | fprintf(stderr, "%s: failed to allocate memory with size %lld\n", |
| 372 | __func__, (long long)fd_stat.st_size); |
| 373 | close(fd); |
| 374 | continue; |
| 375 | } |
| 376 | |
| 377 | lseek(fd, SEEK_SET, 0); |
| 378 | bytes = read_from_file_to_buf(fd, buf, fd_stat.st_size); |
| 379 | if (bytes != fd_stat.st_size) { |
| 380 | /* Keep the file along with set of unsigned PSP binaries & continue. */ |
| 381 | fprintf(stderr, "%s: failed to read %s\n", |
| 382 | __func__, fw_table[i].filename); |
| 383 | free(buf); |
| 384 | close(fd); |
| 385 | continue; |
| 386 | } |
| 387 | |
| 388 | bytes = write_from_buf_to_file(signed_rom_fd, buf, fd_stat.st_size); |
| 389 | if (bytes != fd_stat.st_size) { |
| 390 | /* Keep the file along with set of unsigned PSP binaries & continue. */ |
| 391 | fprintf(stderr, "%s: failed to write %s\n", |
| 392 | __func__, fw_table[i].filename); |
| 393 | free(buf); |
| 394 | close(fd); |
| 395 | continue; |
| 396 | } |
| 397 | |
| 398 | /* Write Blob alignment bytes */ |
| 399 | align_bytes = 0; |
| 400 | if (fd_stat.st_size & (BLOB_ALIGNMENT - 1)) { |
| 401 | align_bytes = BLOB_ALIGNMENT - |
| 402 | (fd_stat.st_size & (BLOB_ALIGNMENT - 1)); |
| 403 | bytes = write_from_buf_to_file(signed_rom_fd, align_data, align_bytes); |
| 404 | if (bytes != align_bytes) { |
| 405 | fprintf(stderr, "%s: failed to write alignment data for %s\n", |
| 406 | __func__, fw_table[i].filename); |
| 407 | lseek(signed_rom_fd, SEEK_CUR, -fd_stat.st_size); |
| 408 | free(buf); |
| 409 | close(fd); |
| 410 | continue; |
| 411 | } |
| 412 | } |
| 413 | |
| 414 | if (add_sha(&fw_table[i], buf, fd_stat.st_size, soc_id)) |
| 415 | exit(-1); |
| 416 | |
| 417 | /* File is successfully processed and is part of signed PSP binaries set. */ |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 418 | fw_table[i].addr_signed = signed_start_addr; |
| 419 | fw_table[i].file_size = (uint32_t)fd_stat.st_size; |
Karthikeyan Ramasubramanian | abaca2a | 2023-07-13 17:24:13 -0600 | [diff] [blame^] | 420 | update_hash_files_config(&fw_table[i]); |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 421 | |
| 422 | signed_start_addr += fd_stat.st_size + align_bytes; |
| 423 | |
| 424 | free(buf); |
| 425 | close(fd); |
| 426 | } |
| 427 | |
| 428 | close(signed_rom_fd); |
| 429 | |
Karthikeyan Ramasubramanian | d7a5d9e | 2023-05-03 13:34:41 -0600 | [diff] [blame] | 430 | open_psp_fw_hash_files(signed_rom); |
| 431 | write_psp_firmware_hash(fw_table); |
| 432 | close_psp_fw_hash_files(); |
Zheng Bao | f080cd5 | 2023-03-22 12:50:36 +0800 | [diff] [blame] | 433 | } |