From 4ed250c18436a5f26fe31918356ab8424fb89d17 Mon Sep 17 00:00:00 2001 From: Igor Opaniuk Date: Sat, 24 May 2025 11:42:00 +0200 Subject: [PATCH] qdl: add support for vip table of digests generation Add support for Digests Table generation for Validated Image Programming (VIP), which is activated when Secure Boot is enabled on the target. VIP controls which packets are allowed to be issued to the target. Controlling the packets that can be sent to the target is done through hashing. The target applies a hashing function to all received data, comparing the resulting hash digest against an existing digest table in memory. If the calculated hash digest matches the next entry in the table, the packet (data or command) is accepted; otherwise, the packet is rejected, and the target halts. This change introduces logic for VIP table generation. In the current VIP design the first signed hash table can be a maximum of 8 KB. Considering that it must be in MBN format, and in addition to the raw hash table, it also includes an MBN header, a signature, and certificates, the number of hash digests it can contain is limited to 54 hashes (a 40-byte MBN header + a 1696-byte hash table + a 256-byte signature + 6144 bytes of certificates). All hashes left are stored in the additional ChainedTableOfDigests.bin files. To generate table of digests run QDL with --create-digests param, providing a path to store VIP tables. As a result 3 types of files are generated: - DIGEST_TABLE.bin - contains the SHA256 table of digests for all firehose packets to be sent to the target. It is an intermediary table and is used only for the subsequent generation of "DigestsToSign.bin" and "ChainedTableOfDigests.bin" files. It is not used by QDL for VIP programming. - DigestsToSign.bin - first 53 digests + digest of ChainedTableOfDigests.bin. This file has to be converted to MBN format and then signed with sectools: $ sectools mbn-tool generate --data DigestsToSign.bin --mbn-version 6 --outfile DigestsToSign.bin.mbn $ sectools secure-image --sign DigestsToSign.bin.mbn --image-id=VIP Please check the security profile for your SoC to determine which version of the MBN format should be used. - ChainedTableOfDigests.bin - contains left digests, split on multiple files with 255 digests + appended hash of next table. For example, for 400 packets supposed to be sent to the target, these files will be generated (all digests are 32 bytes in size): DIGEST_TABLE.bin _____________ | Digest 0 | | Digest 1 | | etc. | | | | Digest 399 | |_____________| DigestsTableToSign.bin ChainedTableOfDigests0.bin ChainedTableOfDigests1.bin ___________________ ___________________ ____________ | Digest 0 | | Digest 53 | | Digest 308 | | Digest 1 | | Digest 54 | | Digest 309 | | etc. | | etc. | | etc. | | Digest 52 | | Digest 307 | | Digest 399 | | Next table digest | | Next table digest | |____________| |___________________| |___________________| When QDL is executed with --debug parameter, it will also report Firehose packet SHA-256 hashes, for example: FIREHOSE WRITE: FIREHOSE PACKET SHA256: a27b1459042ea36f654c5eed795730bf73ce37ce5e92e204fe06833e5e5e1749 Signed-off-by: Igor Opaniuk --- Makefile | 2 +- firehose.c | 13 +- qdl.c | 19 ++- qdl.h | 4 + sim.c | 35 ++++- sim.h | 40 ++++++ usb.c | 4 - vip.c | 368 +++++++++++++++++++++++++++++++++++++++++++++++++++++ vip.h | 43 +++++++ 9 files changed, 520 insertions(+), 8 deletions(-) create mode 100644 sim.h create mode 100644 vip.c create mode 100644 vip.h diff --git a/Makefile b/Makefile index 203cb04..8b3b4ef 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CFLAGS += -O2 -Wall -g `pkg-config --cflags libxml-2.0 libusb-1.0` LDFLAGS += `pkg-config --libs libxml-2.0 libusb-1.0` prefix := /usr/local -QDL_SRCS := firehose.c io.c qdl.c sahara.c util.c patch.c program.c read.c sim.c ufs.c usb.c ux.c oscompat.c +QDL_SRCS := firehose.c io.c qdl.c sahara.c util.c patch.c program.c read.c sha2.c sim.c ufs.c usb.c ux.c oscompat.c vip.c QDL_OBJS := $(QDL_SRCS:.c=.o) RAMDUMP_SRCS := ramdump.c sahara.c io.c sim.c usb.c util.c ux.c oscompat.c diff --git a/firehose.c b/firehose.c index 65ece95..3f22623 100644 --- a/firehose.c +++ b/firehose.c @@ -50,6 +50,7 @@ #include "qdl.h" #include "ufs.h" #include "oscompat.h" +#include "vip.h" enum { FIREHOSE_ACK = 0, @@ -183,9 +184,11 @@ static int firehose_write(struct qdl_device *qdl, xmlDoc *doc) xmlDocDumpMemory(doc, &s, &len); + vip_gen_chunk_init(qdl); + for (;;) { ux_debug("FIREHOSE WRITE: %s\n", s); - + vip_gen_chunk_update(qdl, s, len); ret = qdl_write(qdl, s, len); saved_errno = errno; @@ -202,6 +205,7 @@ static int firehose_write(struct qdl_device *qdl, xmlDoc *doc) } } xmlFree(s); + vip_gen_chunk_store(qdl); return ret < 0 ? -saved_errno : 0; } @@ -428,6 +432,11 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int program->filename, program->sector_size * num_sectors); while (left > 0) { + /* + * We should calculate hash for every raw packet sent, + * not for the whole binary. + */ + vip_gen_chunk_init(qdl); chunk_size = MIN(max_payload_size / program->sector_size, left); n = read(fd, buf, chunk_size * program->sector_size); @@ -439,6 +448,7 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int if (n < max_payload_size) memset(buf + n, 0, max_payload_size - n); + vip_gen_chunk_update(qdl, buf, chunk_size * program->sector_size); n = qdl_write(qdl, buf, chunk_size * program->sector_size); if (n < 0) { ux_err("USB write failed for data chunk\n"); @@ -452,6 +462,7 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int } left -= chunk_size; + vip_gen_chunk_store(qdl); ux_progress("%s", num_sectors - left, num_sectors, program->label); } diff --git a/qdl.c b/qdl.c index 06145f0..56525b0 100644 --- a/qdl.c +++ b/qdl.c @@ -43,6 +43,7 @@ #include "program.h" #include "ufs.h" #include "oscompat.h" +#include "vip.h" #ifdef _WIN32 const char *__progname = "qdl"; @@ -107,7 +108,7 @@ static void print_usage(void) { extern const char *__progname; fprintf(stderr, - "%s [--debug] [--dry-run] [--version] [--allow-missing] [--storage ] [--finalize-provisioning] [--include ] [--serial ] [--out-chunk-size ] [ ...]\n", + "%s [--debug] [--dry-run] [--version] [--allow-missing] [--storage ] [--finalize-provisioning] [--include ] [--serial ] [--out-chunk-size ] [--create-digests ] [ ...]\n", __progname); } @@ -120,6 +121,7 @@ int main(int argc, char **argv) char *prog_mbn, *storage="ufs"; char *incdir = NULL; char *serial = NULL; + const char *vip_generate_dir= NULL; int type; int ret; int opt; @@ -141,6 +143,7 @@ int main(int argc, char **argv) {"allow-missing", no_argument, 0, 'f'}, {"allow-fusing", no_argument, 0, 'c'}, {"dry-run", no_argument, 0, 'n'}, + {"create-digests", required_argument, 0, 't'}, {0, 0, 0, 0} }; @@ -152,6 +155,11 @@ int main(int argc, char **argv) case 'n': qdl_dev_type = QDL_DEVICE_SIM; break; + case 't': + vip_generate_dir = optarg; + /* we also enforce dry-run mode */ + qdl_dev_type = QDL_DEVICE_SIM; + break; case 'v': print_version(); return 0; @@ -197,6 +205,12 @@ int main(int argc, char **argv) if (out_chunk_size) qdl_set_out_chunk_size(qdl, out_chunk_size); + if (vip_generate_dir) { + ret = vip_gen_init(qdl, vip_generate_dir); + if (ret) + goto out_cleanup; + } + ux_init(); if (qdl_debug) @@ -254,6 +268,9 @@ int main(int argc, char **argv) goto out_cleanup; out_cleanup: + if (vip_generate_dir) + vip_gen_finalize(qdl); + qdl_close(qdl); free_programs(); free_patches(); diff --git a/qdl.h b/qdl.h index d7d6880..15ec6e5 100644 --- a/qdl.h +++ b/qdl.h @@ -8,6 +8,10 @@ #include "read.h" #include +#define container_of(ptr, typecast, member) ({ \ + void *_ptr = (void *)(ptr); \ + ((typecast *)(_ptr - offsetof(typecast, member))); }) + #define MAPPING_SZ 64 enum QDL_DEVICE_TYPE diff --git a/sim.c b/sim.c index 350779a..e935797 100644 --- a/sim.c +++ b/sim.c @@ -30,11 +30,13 @@ #include #include -#include "qdl.h" +#include "sim.h" struct qdl_device_sim { struct qdl_device base; + struct vip_table_generator *vip_gen; + bool create_digests; }; static int sim_open(struct qdl_device *qdl, const char *serial) @@ -80,4 +82,35 @@ struct qdl_device *sim_init(void) qdl->set_out_chunk_size = sim_set_out_chunk_size; return qdl; +} + +struct vip_table_generator *sim_get_vip_generator(struct qdl_device *qdl) +{ + struct qdl_device_sim *qdl_sim; + + if (qdl->dev_type != QDL_DEVICE_SIM) + return NULL; + + qdl_sim = container_of(qdl, struct qdl_device_sim, base); + + if (!qdl_sim->create_digests) + return NULL; + + return qdl_sim->vip_gen; +} + +bool sim_set_digest_generation(bool create_digests, struct qdl_device *qdl, + struct vip_table_generator *vip_gen) +{ + struct qdl_device_sim *qdl_sim; + + if (qdl->dev_type != QDL_DEVICE_SIM) + return false; + + qdl_sim = container_of(qdl, struct qdl_device_sim, base); + + qdl_sim->create_digests = create_digests; + qdl_sim->vip_gen = vip_gen; + + return true; } \ No newline at end of file diff --git a/sim.h b/sim.h new file mode 100644 index 0000000..f758bc4 --- /dev/null +++ b/sim.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __SIM_H__ +#define __SIM_H__ + +#include "qdl.h" +#include "vip.h" + +struct vip_table_generator *sim_get_vip_generator(struct qdl_device *qdl); +bool sim_set_digest_generation(bool create_digests, struct qdl_device *qdl, + struct vip_table_generator *vip_gen); + +#endif /* __SIM_H__ */ \ No newline at end of file diff --git a/usb.c b/usb.c index 1db1227..83a4637 100644 --- a/usb.c +++ b/usb.c @@ -9,10 +9,6 @@ #include "qdl.h" -#define container_of(ptr, typecast, member) ({ \ - void *_ptr = (void *)(ptr); \ - ((typecast *)(_ptr - offsetof(typecast, member))); }) - #define DEFAULT_OUT_CHUNK_SIZE (1024 * 1024) struct qdl_device_usb diff --git a/vip.c b/vip.c new file mode 100644 index 0000000..27b547e --- /dev/null +++ b/vip.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#include "sim.h" + +#define DIGEST_FULL_TABLE_FILE "DIGEST_TABLE.bin" +#define CHAINED_TABLE_FILE_PREF "ChainedTableOfDigests" +#define CHAINED_TABLE_FILE_MAX_NAME 64 +#define DIGEST_TABLE_TO_SIGN_FILE "DigestsToSign.bin" +#define MAX_DIGESTS_PER_SIGNED_FILE 54 +#define MAX_DIGESTS_PER_SIGNED_TABLE (MAX_DIGESTS_PER_SIGNED_FILE - 1) +#define MAX_DIGESTS_PER_CHAINED_FILE 256 +#define MAX_DIGESTS_PER_CHAINED_TABLE (MAX_DIGESTS_PER_CHAINED_FILE - 1) +#define MAX_DIGESTS_PER_BUF 16 + +struct vip_table_generator +{ + unsigned char hash[SHA256_DIGEST_LENGTH]; + + SHA2_CTX ctx; + + FILE *digest_table_fd; + size_t digest_num_written; + + const char *path; +}; + +static void print_digest(unsigned char *buf) +{ + char hex_str[SHA256_DIGEST_STRING_LENGTH]; + + for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) + sprintf(hex_str + i * 2, "%02x", buf[i]); + + hex_str[SHA256_DIGEST_STRING_LENGTH - 1] = '\0'; + + ux_debug("FIREHOSE PACKET SHA256: %s\n", hex_str); +} + +int vip_gen_init(struct qdl_device *qdl, const char *path) +{ + struct vip_table_generator *vip_gen; + struct stat st; + char filepath[PATH_MAX]; + + if (qdl->dev_type != QDL_DEVICE_SIM) { + ux_err("Should be executed in simulation dry-run mode\n"); + return -1; + } + + if (stat(path, &st) || !S_ISDIR(st.st_mode)) { + ux_err("Directory '%s' to store VIP tables doesn't exist\n", path); + } + + vip_gen = malloc(sizeof(struct vip_table_generator)); + if (!vip_gen) { + ux_err("Can't allocate memory for vip_table_generator\n"); + return -1; + } + if (!sim_set_digest_generation(true, qdl, vip_gen)) { + ux_err("Can't enable digest table generation\n"); + goto out_cleanup; + } + vip_gen->digest_num_written = 0; + vip_gen->path = path; + + snprintf(filepath, sizeof(filepath), "%s/%s", path, DIGEST_FULL_TABLE_FILE); + + vip_gen->digest_table_fd = fopen(filepath, "wb"); + if (!vip_gen->digest_table_fd) { + ux_err("Can't create %s file\n", filepath); + goto out_cleanup; + } + + return 0; +out_cleanup: + free(vip_gen); + sim_set_digest_generation(false, qdl, NULL); + + return -1; +} + +void vip_gen_chunk_init(struct qdl_device *qdl) +{ + struct vip_table_generator *vip_gen; + + vip_gen = sim_get_vip_generator(qdl); + if (!vip_gen) + return; + + SHA256Init(&vip_gen->ctx); +} + +void vip_gen_chunk_update(struct qdl_device *qdl, const void *buf, size_t len) +{ + struct vip_table_generator *vip_gen; + + vip_gen = sim_get_vip_generator(qdl); + if (!vip_gen) + return; + + SHA256Update(&vip_gen->ctx, (uint8_t *)buf, len); +} + +void vip_gen_chunk_store(struct qdl_device *qdl) +{ + struct vip_table_generator *vip_gen; + + vip_gen = sim_get_vip_generator(qdl); + if (!vip_gen) + return; + + SHA256Final(vip_gen->hash, &vip_gen->ctx); + + print_digest(vip_gen->hash); + + if (fwrite(vip_gen->hash, SHA256_DIGEST_LENGTH, 1, vip_gen->digest_table_fd) != 1) { + ux_err("Failed to write digest to the " DIGEST_FULL_TABLE_FILE); + goto out_cleanup; + } + + vip_gen->digest_num_written++; + + return; + +out_cleanup: + fclose(vip_gen->digest_table_fd); +} + +static int write_output_file(const char *filename, bool append, const void *data, size_t len) +{ + FILE *fp; + char *mode = "wb"; + + if (append) + mode = "ab"; + + fp = fopen(filename, mode); + if (!fp) { + ux_err("Failed to open file for appending\n"); + return -1; + } + + if (fwrite(data, 1, len, fp) != len) { + ux_err("Failed to append to file\n"); + fclose(fp); + return -1; + } + + fclose(fp); + + return 0; +} + +static int calculate_hash_of_file(const char *filename, unsigned char *hash) +{ + unsigned char buf[1024]; + SHA2_CTX ctx; + + FILE *fp = fopen(filename, "rb"); + if (!fp) { + ux_err("Failed to open file for hashing\n"); + return -1; + } + + SHA256Init(&ctx); + + size_t bytes; + while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0) { + SHA256Update(&ctx, (uint8_t *)buf, bytes); + } + + fclose(fp); + + SHA256Final(hash, &ctx); + + return 0; +} + +static int write_digests_to_table(char *src_table, char *dest_table, size_t start_digest, size_t count) +{ + const size_t elem_size = SHA256_DIGEST_LENGTH; + unsigned char buf[MAX_DIGESTS_PER_BUF * SHA256_DIGEST_LENGTH]; + size_t written = 0; + int ret; + + int fd = open(src_table, O_RDONLY); + if (fd < 0) { + ux_err("Failed to open %s for reading\n", src_table); + return -1; + } + + /* Seek to offset of start_digest */ + size_t offset = elem_size * start_digest; + if (lseek(fd, offset, SEEK_SET) != offset) { + ux_err("Failed to seek in %s\n", src_table); + goto out_cleanup; + } + + while (written < (count * elem_size)) { + size_t to_read = count * elem_size - written; + if (to_read > sizeof(buf)) + to_read = sizeof(buf); + + size_t bytes = read(fd, buf, to_read); + if (bytes < 0 || (size_t) bytes != to_read) { + ux_err("Failed to read from %s\n", src_table); + goto out_cleanup; + } + + ret = write_output_file(dest_table, (written != 0), buf, bytes); + if (ret < 0) { + ux_err("Can't write digests to %s\n", dest_table); + goto out_cleanup; + } + + written += to_read; + } + close(fd); + + return 0; +out_cleanup: + close(fd); + + return -1; +} + +static int create_chained_tables(struct vip_table_generator *vip_gen) +{ + size_t chained_num = 0; + size_t tosign_count = 0; + size_t total_digests = vip_gen->digest_num_written; + char src_table[PATH_MAX]; + char dest_table[PATH_MAX]; + unsigned char hash[SHA256_DIGEST_LENGTH]; + int ret; + + snprintf(src_table, sizeof(src_table), "%s/%s", vip_gen->path, DIGEST_FULL_TABLE_FILE); + + /* Step 1: Write digest table to DigestsToSign.bin */ + snprintf(dest_table, sizeof(dest_table), "%s/%s", + vip_gen->path, DIGEST_TABLE_TO_SIGN_FILE); + tosign_count = total_digests < MAX_DIGESTS_PER_SIGNED_TABLE ? total_digests : + MAX_DIGESTS_PER_SIGNED_TABLE; + + ret = write_digests_to_table(src_table, dest_table, 0, tosign_count); + if (ret) { + ux_err("Writing digests to %s failed\n", dest_table); + return ret; + } + + /* Step 2: Write remaining digests to ChainedTableOfDigests.bin */ + if (total_digests > MAX_DIGESTS_PER_SIGNED_TABLE) { + size_t remaining_digests = total_digests - MAX_DIGESTS_PER_SIGNED_TABLE; + + while (remaining_digests > 0) { + size_t table_digests = remaining_digests > MAX_DIGESTS_PER_CHAINED_TABLE ? + MAX_DIGESTS_PER_CHAINED_TABLE : remaining_digests; + + snprintf(dest_table, sizeof(dest_table), + "%s/%s%zu.bin", vip_gen->path, + CHAINED_TABLE_FILE_PREF, chained_num); + + ret = write_digests_to_table(src_table, dest_table, + total_digests - remaining_digests, + table_digests); + if (ret) { + ux_err("Writing digests to %s failed\n", dest_table); + return ret; + } + + remaining_digests -= table_digests; + if (!remaining_digests) { + /* Add zero (the packet can't be multiple of 512 bytes) */ + ret = write_output_file(dest_table, true, "\0", 1); + if (ret < 0) { + ux_err("Can't write 0 to %s\n", dest_table); + return ret; + } + } + chained_num++; + } + } + + /* Step 3: Recursively hash and append backwards */ + for (ssize_t i = chained_num - 1; i >= 0; --i) { + snprintf(src_table, sizeof(src_table), + "%s/%s%zd.bin", vip_gen->path, + CHAINED_TABLE_FILE_PREF, i); + ret = calculate_hash_of_file(src_table, hash); + if (ret < 0) { + ux_err("Failed to hash %s\n", src_table); + return ret; + } + + if (i == 0) { + snprintf(dest_table, sizeof(dest_table), "%s/%s", + vip_gen->path, DIGEST_TABLE_TO_SIGN_FILE); + ret = write_output_file(dest_table, true, hash, SHA256_DIGEST_LENGTH); + if (ret < 0) { + ux_err("Failed to append hash to %s\n", dest_table); + return ret; + } + } else { + snprintf(dest_table, sizeof(dest_table), + "%s/%s%zd.bin", vip_gen->path, + CHAINED_TABLE_FILE_PREF, (i - 1)); + ret = write_output_file(dest_table, true, hash, SHA256_DIGEST_LENGTH); + if (ret < 0) { + ux_err("Failed to append hash to %s\n", dest_table); + return ret; + } + } + } + + return 0; +} + +void vip_gen_finalize(struct qdl_device *qdl) +{ + struct vip_table_generator *vip_gen; + + vip_gen = sim_get_vip_generator(qdl); + if (!vip_gen) + return; + + fclose(vip_gen->digest_table_fd); + + ux_debug("VIP TABLE DIGESTS: %lu\n", vip_gen->digest_num_written); + + if (create_chained_tables(vip_gen) < 0) + ux_err("Error occured when creating table of digests\n"); + + free(vip_gen); + sim_set_digest_generation(false, qdl, NULL); +} \ No newline at end of file diff --git a/vip.h b/vip.h new file mode 100644 index 0000000..5031be1 --- /dev/null +++ b/vip.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __VIP_H__ +#define __VIP_H__ + +#include "sha2.h" + +struct vip_table_generator; + +int vip_gen_init(struct qdl_device *qdl, const char *path); +void vip_gen_chunk_init(struct qdl_device *qdl); +void vip_gen_chunk_update(struct qdl_device *qdl, const void *buf, size_t len); +void vip_gen_chunk_store(struct qdl_device *qdl); +void vip_gen_finalize(struct qdl_device *qdl); + +#endif /* __VIP_H__ */ \ No newline at end of file