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<n>.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<n>.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: <?xml version="1.0"?>
<data><patch SECTOR_SIZE_IN_BYTES="4096" byte_offset="72" filename="DISK"
physical_partition_number="5" size_in_bytes="8"
start_sector="NUM_DISK_SECTORS-1" value="NUM_DISK_SECTORS-5."/></data>

FIREHOSE PACKET SHA256: a27b1459042ea36f654c5eed795730bf73ce37ce5e92e204fe06833e5e5e1749

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
This commit is contained in:
Igor Opaniuk
2025-05-24 11:42:00 +02:00
parent 824d4c067e
commit 4ed250c184
9 changed files with 520 additions and 8 deletions

View File

@@ -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

View File

@@ -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);
}

19
qdl.c
View File

@@ -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 <emmc|nand|ufs>] [--finalize-provisioning] [--include <PATH>] [--serial <NUM>] [--out-chunk-size <SIZE>] <prog.mbn> [<program> <patch> ...]\n",
"%s [--debug] [--dry-run] [--version] [--allow-missing] [--storage <emmc|nand|ufs>] [--finalize-provisioning] [--include <PATH>] [--serial <NUM>] [--out-chunk-size <SIZE>] [--create-digests <PATH>] <prog.mbn> [<program> <patch> ...]\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();

4
qdl.h
View File

@@ -8,6 +8,10 @@
#include "read.h"
#include <libxml/tree.h>
#define container_of(ptr, typecast, member) ({ \
void *_ptr = (void *)(ptr); \
((typecast *)(_ptr - offsetof(typecast, member))); })
#define MAPPING_SZ 64
enum QDL_DEVICE_TYPE

35
sim.c
View File

@@ -30,11 +30,13 @@
#include <stdlib.h>
#include <string.h>
#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;
}

40
sim.h Normal file
View File

@@ -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__ */

4
usb.c
View File

@@ -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

368
vip.c Normal file
View File

@@ -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 <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#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<n>.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);
}

43
vip.h Normal file
View File

@@ -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__ */