summaryrefslogtreecommitdiffstats
path: root/lib/fsl-qe-firmware.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fsl-qe-firmware.c')
-rw-r--r--lib/fsl-qe-firmware.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/lib/fsl-qe-firmware.c b/lib/fsl-qe-firmware.c
new file mode 100644
index 0000000000..960703f561
--- /dev/null
+++ b/lib/fsl-qe-firmware.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <crc.h>
+#include <soc/fsl/qe.h>
+
+/*
+ * qe_validate_firmware - Validate a QE firmware
+ *
+ * This function checks a QE firmware for validity. It checks the crc
+ * and consistency of various fields. Returns 0 for success or a negative
+ * error code otherwise.
+ */
+int qe_validate_firmware(const struct qe_firmware *firmware, int size)
+{
+ u32 crc;
+ size_t calc_size;
+ int i;
+ const struct qe_header *hdr = &firmware->header;
+
+ if (size < sizeof(*firmware)) {
+ pr_err("firmware is too small\n");
+ return -EINVAL;
+ }
+
+ if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
+ (hdr->magic[2] != 'F')) {
+ pr_err("Data at %p is not a QE firmware\n", firmware);
+ return -EPERM;
+ }
+
+ if (size != be32_to_cpu(hdr->length)) {
+ pr_err("Firmware size doesn't match size in header\n");
+ return -EINVAL;
+ }
+
+ if (hdr->version != 1) {
+ pr_err("Unsupported firmware version %u\n", hdr->version);
+ return -EPERM;
+ }
+
+ calc_size = sizeof(*firmware) +
+ (firmware->count - 1) * sizeof(struct qe_microcode);
+
+ if (size < calc_size)
+ return -EINVAL;
+
+ for (i = 0; i < firmware->count; i++)
+ calc_size += sizeof(u32) *
+ be32_to_cpu(firmware->microcode[i].count);
+
+ if (size != calc_size + sizeof(u32)) {
+ pr_err("Invalid length in firmware header\n");
+ return -EPERM;
+ }
+
+ crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
+ if (crc != (crc32_no_comp(0, (const void *)firmware, calc_size))) {
+ pr_err("Firmware CRC is invalid\n");
+ return -EIO;
+ }
+
+ return 0;
+}