Revert "util/cbfstool: Port elogtool to libflashrom"
[coreboot.git] / util / cbfstool / platform_fixups.c
blobea2d3161a2a94b638c85524ab491fc2d193e0b1a
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include "cbfs.h"
4 #include "cbfs_sections.h"
5 #include "elfparsing.h"
7 /*
8 * NOTE: This currently only implements support for MBN version 6 (as used by sc7180). Support
9 * for other MBN versions could probably be added but may require more parsing to tell them
10 * apart, and minor modifications (e.g. different hash algorithm). Add later as needed.
12 static void *qualcomm_find_hash(struct buffer *in, size_t bb_offset, struct vb2_hash *real_hash)
14 struct buffer elf;
15 buffer_clone(&elf, in);
17 /* When buffer_size(&elf) becomes this small, we know we've searched through 32KiB (or
18 the whole bootblock) without finding anything, so we know we can stop looking. */
19 size_t search_end_size = MIN(0, buffer_size(in) - 32 * KiB);
21 /* To identify a Qualcomm image, first we find the GPT header... */
22 while (buffer_size(&elf) > search_end_size &&
23 !buffer_check_magic(&elf, "EFI PART", 8))
24 buffer_seek(&elf, 512);
26 /* ...then shortly afterwards there's an ELF header... */
27 while (buffer_size(&elf) > search_end_size &&
28 !buffer_check_magic(&elf, ELFMAG, 4))
29 buffer_seek(&elf, 512);
31 if (buffer_size(&elf) <= search_end_size)
32 return NULL; /* Doesn't seem to be a Qualcomm image. */
34 struct parsed_elf pelf;
35 if (parse_elf(&elf, &pelf, ELF_PARSE_PHDR))
36 return NULL; /* Not an ELF -- guess not a Qualcomm MBN after all? */
38 /* Qualcomm stores an array of SHA-384 hashes in a special ELF segment. One special one
39 to start with, and then one for each segment in order. */
40 void *bb_hash = NULL;
41 void *hashtable = NULL;
42 int i;
43 int bb_segment = -1;
44 for (i = 0; i < pelf.ehdr.e_phnum; i++) {
45 Elf64_Phdr *ph = &pelf.phdr[i];
46 if ((ph->p_flags & PF_QC_SG_MASK) == PF_QC_SG_HASH) {
47 if ((int)ph->p_filesz !=
48 (pelf.ehdr.e_phnum + 1) * VB2_SHA384_DIGEST_SIZE) {
49 ERROR("fixups: Qualcomm hash segment has wrong size!\n");
50 goto destroy_elf;
51 } /* Found the table with the hashes -- store its address. */
52 hashtable = buffer_get(&elf) + ph->p_offset;
53 } else if (bb_segment < 0 && ph->p_offset + ph->p_filesz < buffer_size(&elf) &&
54 buffer_offset(&elf) + ph->p_offset <= bb_offset &&
55 buffer_offset(&elf) + ph->p_offset + ph->p_filesz > bb_offset) {
56 bb_segment = i; /* Found the bootblock segment -- store its index. */
59 if (!hashtable) /* ELF but no special QC hash segment -- guess not QC after all? */
60 goto destroy_elf;
61 if (bb_segment < 0) { /* Can assume it's QC if we found the special segment. */
62 ERROR("fixups: Cannot find bootblock code in Qualcomm MBN!\n");
63 goto destroy_elf;
66 /* Pass out the actual hash of the current bootblock segment in |real_hash|. */
67 if (vb2_hash_calculate(buffer_get(&elf) + pelf.phdr[bb_segment].p_offset,
68 pelf.phdr[bb_segment].p_filesz, VB2_HASH_SHA384, real_hash)) {
69 ERROR("fixups: vboot digest error\n");
70 goto destroy_elf;
71 } /* Return pointer to where the bootblock hash needs to go in Qualcomm's table. */
72 bb_hash = hashtable + (bb_segment + 1) * VB2_SHA384_DIGEST_SIZE;
74 destroy_elf:
75 parsed_elf_destroy(&pelf);
76 return bb_hash;
79 static bool qualcomm_probe(struct buffer *buffer, size_t offset)
81 struct vb2_hash real_hash;
82 void *table_hash = qualcomm_find_hash(buffer, offset, &real_hash);
83 if (!table_hash)
84 return false;
86 if (memcmp(real_hash.raw, table_hash, VB2_SHA384_DIGEST_SIZE)) {
87 ERROR("fixups: Identified Qualcomm MBN, but existing hash doesn't match!\n");
88 return false;
91 return true;
94 static int qualcomm_fixup(struct buffer *buffer, size_t offset)
96 struct vb2_hash real_hash;
97 void *table_hash = qualcomm_find_hash(buffer, offset, &real_hash);
98 if (!table_hash) {
99 ERROR("fixups: Cannot find Qualcomm MBN headers anymore!\n");
100 return -1;
103 memcpy(table_hash, real_hash.raw, VB2_SHA384_DIGEST_SIZE);
104 INFO("fixups: Updated Qualcomm MBN header bootblock hash.\n");
105 return 0;
108 platform_fixup_func platform_fixups_probe(struct buffer *buffer, size_t offset,
109 const char *region_name)
111 if (!strcmp(region_name, SECTION_NAME_BOOTBLOCK)) {
112 if (qualcomm_probe(buffer, offset))
113 return qualcomm_fixup;
114 } else if (!strcmp(region_name, SECTION_NAME_PRIMARY_CBFS)) {
115 /* TODO: add fixups for primary CBFS bootblock platforms, if needed */
116 } else {
117 ERROR("%s called for unexpected FMAP region %s!\n", __func__, region_name);
120 return NULL;