From d6b58d5c76a383f6a9f106b7af3b479d7a786ca3 Mon Sep 17 00:00:00 2001 From: Rob Barnes Date: Wed, 14 Jun 2023 11:19:53 -0600 Subject: [PATCH] util/apcb: Add apcb edit tool for phoenix Add a new apcb edit tool, apcb_v3a_edit.py, that injects SPDs into an APCB for phoenix platform. The tool makes several assumptions: * Each SPD only uses blocks 0, 1, 3 and 5. All other blocks are zero. * Each block is 64 bytes. * Dimm and socket are always 0 * Unused SPD entries are zero'd BUG=b:281983434 BRANCH=None TEST=build, flash, boot myst Change-Id: Ifb50287de77138170714a702ab87d56427aacfef Signed-off-by: Rob Barnes Reviewed-on: https://review.coreboot.org/c/coreboot/+/76188 Reviewed-by: Karthik Ramasubramanian Tested-by: build bot (Jenkins) --- Makefile.inc | 2 + src/mainboard/google/myst/Makefile.inc | 33 +++---- util/apcb/apcb_v3a_edit.py | 130 +++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 17 deletions(-) create mode 100755 util/apcb/apcb_v3a_edit.py diff --git a/Makefile.inc b/Makefile.inc index 9a34c61f6c..0d38ea37d6 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -615,6 +615,8 @@ APCB_EDIT_TOOL:=$(top)/util/apcb/apcb_edit.py APCB_V3_EDIT_TOOL:=$(top)/util/apcb/apcb_v3_edit.py +APCB_V3A_EDIT_TOOL:=$(top)/util/apcb/apcb_v3a_edit.py + CBOOTIMAGE:=$(objutil)/cbootimage/cbootimage FUTILITY?=$(objutil)/futility/futility diff --git a/src/mainboard/google/myst/Makefile.inc b/src/mainboard/google/myst/Makefile.inc index 9a8f8d8918..59c11f46f1 100644 --- a/src/mainboard/google/myst/Makefile.inc +++ b/src/mainboard/google/myst/Makefile.inc @@ -28,23 +28,22 @@ APCB_SOURCES = $(MAINBOARD_BLOBS_DIR)/$(APCB_NAME).bin # Add the below section back in after the apcbtool is updated to handle the # Phoenix APCB SPD configuration. -#ifneq ($(wildcard $(src)/mainboard/$(MAINBOARDDIR)/variants/$(VARIANT_DIR)/memory/Makefile.inc),) -# -#LIB_SPD_DEPS = $(SPD_SOURCES) -# -#APCB_SOURCES = $(obj)/$(APCB_NAME).gen -# -#$(obj)/$(APCB_NAME).gen: $(SPD_SOURCES) \ -# $(APCB_V3_EDIT_TOOL) \ -# $(MAINBOARD_BLOBS_DIR)/$(APCB_NAME).bin -# $(APCB_V3_EDIT_TOOL) $(MAINBOARD_BLOBS_DIR)/$(APCB_NAME).bin \ -# $(obj)/$(APCB_NAME).gen \ -# --spd_sources $(SPD_SOURCES) \ -# --mem_type 'lp5' -#else -#$(info SPD sources not found. Skipping APCB.) -#files_added:: die_no_apcb -#endif +ifneq ($(wildcard $(src)/mainboard/$(MAINBOARDDIR)/variants/$(VARIANT_DIR)/memory/Makefile.inc),) + +LIB_SPD_DEPS = $(SPD_SOURCES) + +APCB_SOURCES = $(obj)/$(APCB_NAME).gen + +$(obj)/$(APCB_NAME).gen: $(SPD_SOURCES) \ + $(APCB_V3A_EDIT_TOOL) \ + $(MAINBOARD_BLOBS_DIR)/$(APCB_NAME).bin + $(APCB_V3A_EDIT_TOOL) $(MAINBOARD_BLOBS_DIR)/$(APCB_NAME).bin \ + $(obj)/$(APCB_NAME).gen \ + --spd_sources $(SPD_SOURCES) +else +$(info SPD sources not found. Skipping APCB.) +files_added:: die_no_apcb +endif else $(info APCB sources not found. Skipping APCB.) diff --git a/util/apcb/apcb_v3a_edit.py b/util/apcb/apcb_v3a_edit.py new file mode 100755 index 0000000000..ba106602fa --- /dev/null +++ b/util/apcb/apcb_v3a_edit.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +# Script for injecting SPDs into APCB_v3a binaries. + +import re +import argparse +from collections import namedtuple +from struct import * + +APCB_CHECKSUM_OFFSET = 16 +SPD_ENTRY_MAGIC = bytes.fromhex('0200480000000000') +SPD_SIZE = 512 +EMPTY_SPD = b'\x00' * SPD_SIZE +ZERO_BLOCKS = (2, 4, 6, 7) +SPD_BLOCK_SIZE = 64 +SPD_BLOCK_HEADER_FMT = ' 0, "No SPDs provided" + + # Inject SPDs into APCB + apcb_offset = 0 + spd_idx = 0 + while True: + apcb_offset = apcb.find(SPD_ENTRY_MAGIC, apcb_offset) + if apcb_offset < 0: + print(f'No more SPD entries found') + assert spd_idx >= len(spds), f'Not enough SPD entries in APCB. Need {len(spds)}, found {spd_idx}' + break + + if spd_idx < len(spds): + print(f'Injecting SPD instance {spd_idx}') + spd = spds[spd_idx] + else: + print(f'Injecting empty SPD for instance {spd_idx}') + spd = EMPTY_SPD + + # Inject SPD blocks + for b in range(int(SPD_SIZE/SPD_BLOCK_SIZE)): + if b in ZERO_BLOCKS: continue + header_data = apcb[apcb_offset:apcb_offset + SPD_BLOCK_HEADER_SIZE] + header = spd_block_header._make(unpack(SPD_BLOCK_HEADER_FMT, header_data)) + socket = (header.Key >> 12) & 0xF + channel = (header.Key >> 8) & 0xF + dimm = (header.Key >> 4) & 0xF + block_id = (header.Key >> 0) & 0xF + + assert header.Type == 2 + assert header.Length == SPD_BLOCK_HEADER_SIZE + SPD_BLOCK_SIZE + assert socket == 0 + assert channel == 0 + assert block_id == b + assert dimm == 0 + assert header.Reserved == 0 + + spd_block = spd[b*SPD_BLOCK_SIZE:(b+1)*SPD_BLOCK_SIZE] + apcb_offset += SPD_BLOCK_HEADER_SIZE + apcb = inject(apcb, spd_block, apcb_offset) + apcb_offset += SPD_BLOCK_SIZE + + spd_idx += 1 + + # Fix APCB checksum + print(f'Fixing APCB checksum') + apcb = inject(apcb, bytes([chksum(apcb)]), APCB_CHECKSUM_OFFSET) + assert chksum(apcb) == apcb[APCB_CHECKSUM_OFFSET], 'Final checksum is invalid' + assert orig_apcb_len == len(apcb), 'The size of the APCB changed.' + + # Write APCB to file + print(f'Writing {len(apcb)} byte APCB to {args.apcb_out}') + with open(args.apcb_out, 'wb') as f: + f.write(apcb) + + +if __name__ == "__main__": + main()