Attention is currently required from: Felix Held, Fred Reitberger, Jason Glenesk, Matt DeVillier, Zheng Bao.
Hello Zheng Bao,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/84577?usp=email
to review the following change.
Change subject: soc/amd/cezanne: Heal the corruption in A/B recovery ......................................................................
soc/amd/cezanne: Heal the corruption in A/B recovery
Change-Id: I2cdab00a7122e4831fe5d91cf5d390ad11db0999 Signed-off-by: Zheng Bao fishbaozi@gmail.com --- M src/soc/amd/cezanne/Makefile.mk A src/soc/amd/cezanne/abrecovery.c M src/soc/amd/cezanne/include/soc/cpu.h 3 files changed, 191 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/77/84577/1
diff --git a/src/soc/amd/cezanne/Makefile.mk b/src/soc/amd/cezanne/Makefile.mk index 2747622..2445ed5 100644 --- a/src/soc/amd/cezanne/Makefile.mk +++ b/src/soc/amd/cezanne/Makefile.mk @@ -17,6 +17,7 @@ bootblock-y += espi_util.c
romstage-y += fsp_m_params.c +romstage-y += abrecovery.c
ramstage-y += acpi.c ramstage-y += chip.c @@ -231,6 +232,8 @@ --multilevel \ --output $@
+# --combo-config1 "src/soc/amd/cezanne/fw_rn.cfg" \ + $(PSP_BIOSBIN_FILE): $(PSP_ELF_FILE) $(AMDCOMPRESS) rm -f $@ @printf " AMDCOMPRS $(subst $(obj)/,,$(@))\n" diff --git a/src/soc/amd/cezanne/abrecovery.c b/src/soc/amd/cezanne/abrecovery.c new file mode 100644 index 0000000..868a4fc --- /dev/null +++ b/src/soc/amd/cezanne/abrecovery.c @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <gpio.h> +#include <soc/platform_descriptors.h> +#include <types.h> +#include <amdblocks/cpu.h> +#include <soc/cpu.h> +#include <soc/pci_devs.h> +#include <amdblocks/psp.h> +#include <amdblocks/smn.h> +#include <arch/io.h> +#include <spi_flash.h> +#include <amdblocks/reset.h> + +#define HAVE_ISH 0 +#define DATA_SIZE 0x400 +static uint8_t readbiosram(uint8_t idx) +{ + outb(idx, 0xcd4); + return inb(0xcd5); +} + +static uint32_t get_pspl1_offset(struct spi_flash *flash, uint32_t romsig_off) +{ + uint8_t data[DATA_SIZE]; + uint32_t psp; + + spi_flash_read(flash, romsig_off, DATA_SIZE, data); + psp = *(uint32_t *)(data + 0x14); + return psp; +} + +static void get_psp_entry(struct spi_flash *flash, uint32_t psp_dir, uint8_t entry_type, uint32_t *table_offset, uint32_t *table_size) +{ + uint8_t data[DATA_SIZE]; + uint32_t entry_off = 0, index, address_mode, entry_num; + + spi_flash_read(flash, psp_dir, DATA_SIZE, data); + entry_num = *(uint8_t *)(data + 0x08); + + for (index=0; index < entry_num; index++) { + entry_off = 0x10 + index * 0x10; + if (entry_type == data[entry_off]) + break; + } + address_mode = *(uint32_t *)(data + entry_off + 0xC) & 0xC0000000; + *table_offset = *(uint32_t *)(data + entry_off + 0x8); + if (address_mode == 0x80000000) + *table_offset += psp_dir; + + *table_size = *(uint32_t *)(data + entry_off + 0x4); +} + +#if HAVE_ISH +static uint32_t get_table_size(struct spi_flash *flash, uint32_t table) +{ + uint8_t data[DATA_SIZE]; + + spi_flash_read(flash, table, DATA_SIZE, data); + return (*(uint32_t *)(data+0xC) & 0x3ff) * 0x1000;/* Here 0x1000 is not sector_size. */ +} +#endif + +static void get_bios_entry(struct spi_flash *flash, uint32_t bios_dir, uint8_t entry_type, uint32_t *table_offset, uint32_t *table_size) +{ + uint8_t data[DATA_SIZE]; + uint32_t entry_off = 0, index, address_mode, entry_num; + + spi_flash_read(flash, bios_dir, DATA_SIZE, data); + entry_num = *(uint8_t *)(data + 0x08); + + for (index=0; index < entry_num; index++) { + entry_off = 0x10 + index * 0x18; + if (entry_type == data[entry_off]) + break; + } + address_mode = *(uint32_t *)(data + entry_off + 0xc) & 0xC0000000; + *table_offset = *(uint32_t *)(data + entry_off + 0x8); + if (address_mode == 0x80000000) + *table_offset += bios_dir; + + *table_size = *(uint32_t *)(data + entry_off + 0x4); +} + +#if HAVE_ISH +static uint32_t get_l2_from_ish(struct spi_flash *flash, uint32_t ish, uint32_t ish_size) +{ + uint8_t data[DATA_SIZE]; + uint32_t psp_l2; + spi_flash_read(flash, ish, DATA_SIZE, data); + psp_l2 = *(uint32_t *)(data + 0x10); + return psp_l2; +} +#endif + +void abrecovery(void) +{ + uint32_t reason, corrupt_entryid, corrupt_level; + struct spi_flash flash; + uint8_t data[0x1000]; + uint32_t index; + uint32_t psp_dir, pspl2a_dir, pspl2b_dir, pspl2a_size, pspl2b_size; + uint32_t biosl2a_dir, biosl2b_dir, biosl2a_size, biosl2b_size; + #if HAVE_ISH + uint32_t isha_dir, isha_size, ishb_dir, ishb_size; + #endif + uint32_t corrupt_ent_off, corrupt_ent_size, backup_ent_off, backup_ent_size; + uint32_t flash_sector_size; + + if (check_abrecovery()) { + printk(BIOS_DEBUG, "recovery\n"); + } else { + printk(BIOS_DEBUG, "no recovery\n"); + return; + } + reason = readbiosram(0x78); + corrupt_entryid = reason; + printk(BIOS_DEBUG, "recovery reason byte 1=%x\n", reason); + reason = readbiosram(0x79); + printk(BIOS_DEBUG, "recovery reason byte 2=%x\n", reason); + reason = readbiosram(0x7A); + corrupt_level = reason & 3; + printk(BIOS_DEBUG, "recovery reason byte 3=%x, corrupt_level=%x\n", reason, corrupt_level); + reason = readbiosram(0x7B); + printk(BIOS_DEBUG, "recovery reason byte 4=%x\n", reason); + spi_flash_probe(0, 0, &flash); + flash_sector_size = flash.sector_size; + psp_dir = get_pspl1_offset(&flash, CONFIG_AMD_FWM_POSITION); +#if !HAVE_ISH + /* NO ISH */ + get_psp_entry(&flash, psp_dir, 0x48, &pspl2a_dir, &pspl2a_size); + get_psp_entry(&flash, psp_dir, 0x4A, &pspl2b_dir, &pspl2b_size); + printk(BIOS_DEBUG, "pspl2a_dir=%x, pspl2a_size=%x\n", pspl2a_dir, pspl2a_size); + printk(BIOS_DEBUG, "pspl2b_dir=%x, pspl2b_size=%x\n", pspl2b_dir, pspl2b_size); +#else + get_psp_entry(&flash, psp_dir, 0x48, &isha_dir, &isha_size); + get_psp_entry(&flash, psp_dir, 0x4A, &ishb_dir, &ishb_size); + printk(BIOS_DEBUG, "isha_dir=%x, isha_size=%x\n", isha_dir, isha_size); + printk(BIOS_DEBUG, "ishb_dir=%x, ishb_size=%x\n", ishb_dir, ishb_size); + pspl2a_dir = get_l2_from_ish(&flash, isha_dir, isha_size); + pspl2b_dir = get_l2_from_ish(&flash, ishb_dir, ishb_size); + printk(BIOS_DEBUG, "pspl2a_dir=%x, pspl2a_size=%x\n", pspl2a_dir, pspl2a_size); + printk(BIOS_DEBUG, "pspl2b_dir=%x, pspl2b_size=%x\n", pspl2b_dir, pspl2b_size); + pspl2a_size = get_table_size(&flash, pspl2a_dir); + pspl2b_size = get_table_size(&flash, pspl2b_dir); + printk(BIOS_DEBUG, "pspl2a_size=%x, pspl2b_size=%x\n", pspl2a_size, pspl2b_size); +#endif + get_psp_entry(&flash, pspl2a_dir, 0x49, &biosl2a_dir, &biosl2a_size); + printk(BIOS_DEBUG, "biosl2a_offset=%x, biosl2b_size=%x\n", biosl2a_dir, biosl2a_size); + get_psp_entry(&flash, pspl2b_dir, 0x49, &biosl2b_dir, &biosl2b_size); + printk(BIOS_DEBUG, "biosl2a_offset=%x, biosl2b_size=%x\n", biosl2b_dir, biosl2b_size); + + if (corrupt_entryid == 0x48 && corrupt_level == 2) { + corrupt_ent_off = pspl2a_dir; + corrupt_ent_size = ALIGN_UP(pspl2a_size, flash_sector_size); + backup_ent_off = pspl2b_dir; + backup_ent_size = ALIGN_UP(pspl2b_size, flash_sector_size); + } else if (corrupt_entryid == 0x49 && corrupt_level == 2){ + corrupt_ent_off = biosl2a_dir; + corrupt_ent_size = ALIGN_UP(biosl2a_size, flash_sector_size); + backup_ent_off = biosl2b_dir; + backup_ent_size = ALIGN_UP(biosl2b_size, flash_sector_size); + } else if (corrupt_entryid >= 0x60 && corrupt_entryid <= 0x70 && corrupt_level == 2) { + get_bios_entry(&flash, biosl2b_dir, corrupt_entryid, &backup_ent_off, &backup_ent_size); + get_bios_entry(&flash, biosl2a_dir, corrupt_entryid, &corrupt_ent_off, &corrupt_ent_size); + } else if (corrupt_level == 2){ + get_psp_entry(&flash, pspl2b_dir, corrupt_entryid, &backup_ent_off, &backup_ent_size); + get_psp_entry(&flash, pspl2a_dir, corrupt_entryid, &corrupt_ent_off, &corrupt_ent_size); + } else { + printk(BIOS_DEBUG, "not covered\n"); + } + corrupt_ent_off &= ~(flash_sector_size - 1); /* align down */ + corrupt_ent_size = ALIGN_UP(corrupt_ent_size, flash_sector_size); + printk(BIOS_DEBUG, "2a.1:corrupt_ent_off=%x, corrupt_ent_size=%x\n", corrupt_ent_off, corrupt_ent_size); + spi_flash_erase(&flash, corrupt_ent_off, corrupt_ent_size); + backup_ent_off &= ~(flash_sector_size - 1); + backup_ent_size = ALIGN_UP(backup_ent_size, flash_sector_size); + printk(BIOS_DEBUG, "2b.1:back_ent_off=%x, back_ent_size=%x\n", backup_ent_off, backup_ent_size); + for (index=0; index<corrupt_ent_size; index += flash_sector_size) { + printk(BIOS_DEBUG, "index=%x\n", index); + spi_flash_read(&flash, backup_ent_off + index, flash_sector_size, data); + spi_flash_write(&flash, corrupt_ent_off + index, flash_sector_size, data); + } + do_cold_reset(); + for (;;); +} diff --git a/src/soc/amd/cezanne/include/soc/cpu.h b/src/soc/amd/cezanne/include/soc/cpu.h index 1506420..6d54c34 100644 --- a/src/soc/amd/cezanne/include/soc/cpu.h +++ b/src/soc/amd/cezanne/include/soc/cpu.h @@ -9,4 +9,6 @@ #define CEZANNE_VBIOS_VID_DID 0x10021638 #define BARCELO_VBIOS_VID_DID 0x100215e7
+void abrecovery(void); + #endif /* AMD_CEZANNE_CPU_H */