diff --git a/src/arch/ppc64/Makefile.mk b/src/arch/ppc64/Makefile.mk index 4299e7409c..4a118b638a 100644 --- a/src/arch/ppc64/Makefile.mk +++ b/src/arch/ppc64/Makefile.mk @@ -1,6 +1,15 @@ ## SPDX-License-Identifier: GPL-2.0-only ppc64_flags = -I$(src)/arch/ppc64/ -mbig-endian -mcpu=power8 -mtune=power8 +ifeq ($(CONFIG_COMPILER_GCC),y) +# disable use of %r11 for static chains on invoking nested functions through +# pointers +ppc64_flags += -mno-pointers-to-nested-functions +else ifeq ($(CONFIG_COMPILER_LLVM_CLANG),y) +# use GNU assember at least until LLVM's integrated PPC64 assember will be able +# to handle "slbia" instruction with an argument +ppc64_flags += -fno-integrated-as +endif ppc64_asm_flags = diff --git a/src/arch/ppc64/bootblock_crt0.S b/src/arch/ppc64/bootblock_crt0.S index 5a9496024e..f5e269fbea 100644 --- a/src/arch/ppc64/bootblock_crt0.S +++ b/src/arch/ppc64/bootblock_crt0.S @@ -27,15 +27,67 @@ oris r,r, (e)@h; \ ori r,r, (e)@l; +/* Load an immediate 32-bit value into a register */ +#define LOAD_IMM32(r, e) \ + li r, 0; \ + oris r,r, (e)@h; \ + ori r,r, (e)@l; + +/* + * On POWER, 0 is wherever HRMOR points to rather than physical DRAM start. + * HRMOR is ORed with address, not added to it, meaning that memory space + * overlaps after 2^(least significant set bit of HRMOR). This becomes + * chaotic when nonconsecutive bits are set... + * + * Two and a half possible cases: + * 0. bootblock started with QEMU in hb-mode + * - NIA = 0x10 (bug?) + * - HRMOR = 0x08000000 (128M) + * - no physical memory to enable/train, everything accessible from start + * 1. bootblock loaded by HBBL + * - NIA = 0 + * - HRMOR = 0xF8000000 (4G - 128M) + * - initialized L3 = 0x400000 (4M) + * - top address before RAM = 0xF8400000 + * 2. bootblock in SEEPROM, loaded by SBE + * - NIA = 0x3000 (placeholder for int. vectors) + * - HRMOR = 0xF8200000 (4G - 128 M + 2 M) + * - initialized L3 = 0x8000 (bootblock/HBBL size = 32K) + * - no way 32K will be enough, must initialize more L3 in bootblock + * - HRMOR still applies, so memory overlaps every 2M + * + * Common subset (assuming 2. initializes as much memory as possible) is + * 0xF8200000-0xF8400000. 2M should be more than enough for pre-RAM code, + * but it isn't enough to load ramstage. We could implement postcar stage, + * but KISS: initialize L3 from _ebootblock to 0xF8980000: up to 9.5M into + * cache, leaving bottom 2M (0xF8000000-0xF8200000) either uninitialized + * (when started from SEEPROM) or just unused for anything but bootblock + * (loaded by HBBL). Last 0.5M of L3 cache is left for interrupt vectors + * normally located at address 0. + * + * Set HRMOR to 0 before jumping to C code in bootblock and forget it even + * exists. + * + * For QEMU s/0xF8/0x08/ in above description but code remains the same. + * L3 initialization is unnecessary in this case but won't break anything. + * + * TODO: there is a structure with SBE->HBBL data at 0 in 2nd option. It + * holds some useful data like XSCOM BAR and LPC BAR. If, for any reason, + * these addresses are different than default, they should be used instead + * of predefined values. + */ + .section ".text._start", "ax", %progbits .globl _start _start: /* QEMU with hb-mode=on starts at address 0x10, while hardware at 0x0 */ +#if !CONFIG(BOOTBLOCK_IN_SEEPROM) nop nop nop nop FIXUP_ENDIAN +#endif /* Store FDT address provided by QEMU in %r3 to pass it later to * payload */ @@ -44,32 +96,54 @@ _start: /* Set program priority to medium */ or %r2, %r2, %r2 - /* Stack */ - lis %r1, _estack@ha - addi %r1, %r1, _estack@l + li %r10, 1 + rotldi %r10, %r10, 63 /* MSB is "ignore HRMOR" */ - /* Clear .bss section */ - /* Currently not needed, .bss is zeroed in the file. If it were to be - * used, make sure that .bss is 128B aligned (size of cache line), - * otherwise dcbz will clear (part of) .opd section! */ -/* - lis %r5, _bss@ha - addi %r5, %r5, _bss@l - lis %r6, _ebss@ha - addi %r6, %r6, _ebss@l + /* Assumption: we are linked at address that isn't changed by HRMOR */ + LOAD_IMM32(%r7, ignoreHRMOR) + or %r9, %r7, %r10 + + mtlr %r9 + blr + +ignoreHRMOR: + /* Now we are at 0x8000000000000000 | linked address */ + li %r0, 0 + mtspr SPR_HRMOR, %r0 /* Clear HRMOR */ + isync + + /* We can't just "b stopIgnoringHRMOR", it would use relative offset */ + addi %r9, %r7, stopIgnoringHRMOR - ignoreHRMOR + mtlr %r9 + blr + +stopIgnoringHRMOR: + /* Now we are at linked address */ + slbia 7 + sync + isync + + /* + * When coming from SBE, L3 cache is invalid except for [2M, end of HBBL] + * range. Make the rest of it valid, or embrace the checkstops. + */ + + /* Validate and initialize to zeroes [end of HBBL, 9.5M] range */ + LOAD_IMM32(%r5, _ebootblock) /* Assume it is at least 128B aligned */ + LOAD_IMM32(%r6, _epreram_cbfs_cache) /* Same */ addi %r6, %r6, -1 1: dcbz 0, %r5 addi %r5, %r5, 128 cmpld cr7, %r5, %r6 blt cr7, 1b -*/ + + /* Stack */ + LOAD_IMM32(%r1, _estack) /* This is tested by checkstack() just before jumping to payload */ LOAD_IMM64(%r3, 0xDEADBEEFDEADBEEF) - lis %r5, _stack@ha - addi %r5, %r5, _stack@l - subi %r5, %r5, 8 + LOAD_IMM32(%r5, _stack - 8) sub %r4, %r1, %r5 sradi %r4, %r4, 3 /* Divide by 8 */ mtctr %r4 @@ -87,11 +161,10 @@ _start: mfmsr %r3 ori %r3, %r3, 0x2000 /* FP = 1 */ oris %r3, %r3, 0x0280 /* VEC = 1, VSX = 1 */ - mtmsr %r3 + mtmsrd %r3 /* Load official procedure descriptor address for main() */ - lis %r12, main@ha - addi %r12, %r12, main@l + LOAD_IMM32(%r12, main) /* Load TOC pointer and jump to main() */ ld %r2, 8(%r12) diff --git a/src/mainboard/emulation/qemu-power8/memlayout.ld b/src/mainboard/emulation/qemu-power8/memlayout.ld index 66f2c7577b..5aca5408b1 100644 --- a/src/mainboard/emulation/qemu-power8/memlayout.ld +++ b/src/mainboard/emulation/qemu-power8/memlayout.ld @@ -4,15 +4,74 @@ #include -// TODO: fill in these blanks for Power8. SECTIONS { DRAM_START(0x0) - BOOTBLOCK(0x100, 64K) - ROMSTAGE(0x20000, 128K) - STACK(0x40000, 0x3ff00) - PRERAM_CBMEM_CONSOLE(0x80000, 8K) - FMAP_CACHE(0x82000, 2K) - CBFS_MCACHE(0x82800, 8K) - RAMSTAGE(0x100000, 16M) + + /* + * On POWER, 0 is wherever HRMOR points to rather than physical DRAM start. + * HRMOR is ORed with address, not added to it, meaning that memory space + * overlaps after 2^(least significant set bit of HRMOR). This becomes + * chaotic when nonconsecutive bits are set... + * + * Two and a half possible cases: + * 0. bootblock started with QEMU in hb-mode + * - NIA = 0x10 (bug?) + * - HRMOR = 0x08000000 (128M) + * - no physical memory to enable/train, everything accessible from start + * 1. bootblock loaded by HBBL + * - NIA = 0 + * - HRMOR = 0xF8000000 (4G - 128M) + * - initialized L3 = 0x400000 (4M) + * - top address before RAM = 0xF8400000 + * 2. bootblock in SEEPROM, loaded by SBE + * - NIA = 0x3000 (placeholder for int. vectors) + * - HRMOR = 0xF8200000 (4G - 128 M + 2 M) + * - initialized L3 = 0x8000 (bootblock/HBBL size = 32K) + * - no way 32K will be enough, must initialize more L3 in bootblock + * - HRMOR still applies, so memory overlaps every 2M + * + * Common subset (assuming 2. initializes as much memory as possible) is + * 0xF8200000-0xF8400000. 2M should be more than enough for pre-RAM code, + * but it isn't enough to load ramstage. We could implement postcar stage, + * but KISS: initialize L3 from _ebootblock to 0xF8980000: up to 9.5M into + * cache, leaving bottom 2M (0xF8000000-0xF8200000) either uninitialized + * (when started from SEEPROM) or just unused for anything but bootblock + * (loaded by HBBL). Last 0.5M of L3 cache is left for interrupt vectors + * normally located at address 0. + * + * Set HRMOR to 0 before jumping to C code in bootblock and forget it even + * exists. + * + * For QEMU s/0xF8/0x08/ in above description but code remains the same. + * L3 initialization is unnecessary in this case but won't break anything. + * + * TODO: there is a structure with SBE->HBBL data at 0 in 2nd option. It + * holds some useful data like XSCOM BAR and LPC BAR. If, for any reason, + * these addresses are different than default, they should be used instead + * of predefined values. + */ + +#if !CONFIG(BOOTBLOCK_IN_SEEPROM) + BOOTBLOCK( 0x08000000, 32K) +#else + BOOTBLOCK( 0x08203000, 20K) +#endif + + STACK( 0x08208000, 32K) + PRERAM_CBMEM_CONSOLE(0x08210000, 128K) + FMAP_CACHE( 0x08230000, 4K) + CBFS_MCACHE( 0x08231000, 8K) + TIMESTAMP( 0x08233000, 4K) + + ROMSTAGE( 0x08240000, 256K) + + /* + * bootblock_crt0.S assumes this is the last part of L3, leaving for + * interrupt vectors at least 0.5M because of cache associativity. If + * more CBFS_CACHE is needed, split this into pre-/postram caches. + */ + CBFS_CACHE( 0x08280000, 7M) + + RAMSTAGE( 0x09000000, 2M) } diff --git a/src/mainboard/emulation/qemu-power9/memlayout.ld b/src/mainboard/emulation/qemu-power9/memlayout.ld index d9c2a7167a..5aca5408b1 100644 --- a/src/mainboard/emulation/qemu-power9/memlayout.ld +++ b/src/mainboard/emulation/qemu-power9/memlayout.ld @@ -8,27 +8,70 @@ SECTIONS { DRAM_START(0x0) - BOOTBLOCK(0, 32K) + /* + * On POWER, 0 is wherever HRMOR points to rather than physical DRAM start. + * HRMOR is ORed with address, not added to it, meaning that memory space + * overlaps after 2^(least significant set bit of HRMOR). This becomes + * chaotic when nonconsecutive bits are set... + * + * Two and a half possible cases: + * 0. bootblock started with QEMU in hb-mode + * - NIA = 0x10 (bug?) + * - HRMOR = 0x08000000 (128M) + * - no physical memory to enable/train, everything accessible from start + * 1. bootblock loaded by HBBL + * - NIA = 0 + * - HRMOR = 0xF8000000 (4G - 128M) + * - initialized L3 = 0x400000 (4M) + * - top address before RAM = 0xF8400000 + * 2. bootblock in SEEPROM, loaded by SBE + * - NIA = 0x3000 (placeholder for int. vectors) + * - HRMOR = 0xF8200000 (4G - 128 M + 2 M) + * - initialized L3 = 0x8000 (bootblock/HBBL size = 32K) + * - no way 32K will be enough, must initialize more L3 in bootblock + * - HRMOR still applies, so memory overlaps every 2M + * + * Common subset (assuming 2. initializes as much memory as possible) is + * 0xF8200000-0xF8400000. 2M should be more than enough for pre-RAM code, + * but it isn't enough to load ramstage. We could implement postcar stage, + * but KISS: initialize L3 from _ebootblock to 0xF8980000: up to 9.5M into + * cache, leaving bottom 2M (0xF8000000-0xF8200000) either uninitialized + * (when started from SEEPROM) or just unused for anything but bootblock + * (loaded by HBBL). Last 0.5M of L3 cache is left for interrupt vectors + * normally located at address 0. + * + * Set HRMOR to 0 before jumping to C code in bootblock and forget it even + * exists. + * + * For QEMU s/0xF8/0x08/ in above description but code remains the same. + * L3 initialization is unnecessary in this case but won't break anything. + * + * TODO: there is a structure with SBE->HBBL data at 0 in 2nd option. It + * holds some useful data like XSCOM BAR and LPC BAR. If, for any reason, + * these addresses are different than default, they should be used instead + * of predefined values. + */ - ROMSTAGE(0x1f00000, 1M) - -#if !ENV_RAMSTAGE - STACK(0x2000000, 32K) +#if !CONFIG(BOOTBLOCK_IN_SEEPROM) + BOOTBLOCK( 0x08000000, 32K) +#else + BOOTBLOCK( 0x08203000, 20K) #endif - FMAP_CACHE(0x2108000, 4K) - CBFS_MCACHE(0x2109000, 8K) - TIMESTAMP(0x210b000, 4K) - CBFS_CACHE(0x210c000, 512K) - PRERAM_CBMEM_CONSOLE(0x218c000, 128K) + STACK( 0x08208000, 32K) + PRERAM_CBMEM_CONSOLE(0x08210000, 128K) + FMAP_CACHE( 0x08230000, 4K) + CBFS_MCACHE( 0x08231000, 8K) + TIMESTAMP( 0x08233000, 4K) - /* By default all memory addresses are affected by the value of HRMOR - * (Hypervisor Real Mode Offset Register) which is ORed to them. HRMOR - * has initial value of 0x8000000 in QEMU and is changed to 0 in - * ramstage. This means that before ramstage 0 actually points to - * 0x8000000. */ -#if ENV_RAMSTAGE - STACK(0xa000000, 32K) -#endif - RAMSTAGE(0xa008000, 2M) + ROMSTAGE( 0x08240000, 256K) + + /* + * bootblock_crt0.S assumes this is the last part of L3, leaving for + * interrupt vectors at least 0.5M because of cache associativity. If + * more CBFS_CACHE is needed, split this into pre-/postram caches. + */ + CBFS_CACHE( 0x08280000, 7M) + + RAMSTAGE( 0x09000000, 2M) } diff --git a/src/mainboard/raptor-cs/talos-2/Kconfig b/src/mainboard/raptor-cs/talos-2/Kconfig index 46513945e0..b0fd7d3e22 100644 --- a/src/mainboard/raptor-cs/talos-2/Kconfig +++ b/src/mainboard/raptor-cs/talos-2/Kconfig @@ -2,6 +2,14 @@ if BOARD_RAPTOR_CS_TALOS_2 +config BOOTBLOCK_IN_SEEPROM + bool "Bootblock in SEEPROM" + default n + help + Enable this option if coreboot shall build image with separate + bootblock (i.e. not in coreboot.rom) to be put into SEEPROM + directly. + config BOARD_SPECIFIC_OPTIONS def_bool y select CPU_POWER9 @@ -15,6 +23,11 @@ config BOARD_SPECIFIC_OPTIONS config MEMLAYOUT_LD_FILE default "src/mainboard/\$(CONFIG_MAINBOARD_DIR)/memlayout.ld" +config FMDFILE + string + default "src/mainboard/\$(CONFIG_MAINBOARD_DIR)/board-bootblock-in-seeprom.fmd" if BOOTBLOCK_IN_SEEPROM + default "src/mainboard/\$(CONFIG_MAINBOARD_DIR)/board.fmd" if !BOOTBLOCK_IN_SEEPROM + config MAINBOARD_DIR default "raptor-cs/talos-2" diff --git a/src/mainboard/raptor-cs/talos-2/board-bootblock-in-seeprom.fmd b/src/mainboard/raptor-cs/talos-2/board-bootblock-in-seeprom.fmd new file mode 100644 index 0000000000..8884751120 --- /dev/null +++ b/src/mainboard/raptor-cs/talos-2/board-bootblock-in-seeprom.fmd @@ -0,0 +1,15 @@ +# layout for firmware when flash address space matches used address layout +# +-------------+ <-- 0 +# | unspecified | +# +-------------+ <-- BIOS_BASE +# | FMAP | +# +-------------+ <-- BIOS_BASE + 128K + FMAP_SIZE +# | CBFS | +# +-------------+ <-- ROM_SIZE + +FLASH@0 CONFIG_ROM_SIZE { + BIOS@0 CONFIG_ROM_SIZE { + FMAP 0x200 + COREBOOT(CBFS) + } +} diff --git a/src/mainboard/raptor-cs/talos-2/board.fmd b/src/mainboard/raptor-cs/talos-2/board.fmd new file mode 100644 index 0000000000..462cdea751 --- /dev/null +++ b/src/mainboard/raptor-cs/talos-2/board.fmd @@ -0,0 +1,18 @@ +# layout for firmware when flash address space matches used address layout +# +-------------+ <-- 0 +# | unspecified | +# +-------------+ <-- BIOS_BASE +# | bootblock | +# +-------------+ <-- BIOS_BASE + 128K +# | FMAP | +# +-------------+ <-- BIOS_BASE + 128K + FMAP_SIZE +# | CBFS | +# +-------------+ <-- ROM_SIZE + +FLASH@0 CONFIG_ROM_SIZE { + BIOS@0 CONFIG_ROM_SIZE { + BOOTBLOCK 128K + FMAP 0x200 + COREBOOT(CBFS) + } +} diff --git a/src/mainboard/raptor-cs/talos-2/memlayout.ld b/src/mainboard/raptor-cs/talos-2/memlayout.ld index c5136b9d14..c9e7c9502e 100644 --- a/src/mainboard/raptor-cs/talos-2/memlayout.ld +++ b/src/mainboard/raptor-cs/talos-2/memlayout.ld @@ -4,15 +4,74 @@ #include -// TODO: fill in these blanks for Power9. SECTIONS { DRAM_START(0x0) - BOOTBLOCK(0, 64K) - ROMSTAGE(0x120000, 128K) - STACK(0x140000, 0x3ff00) - PRERAM_CBMEM_CONSOLE(0x180000, 8K) - FMAP_CACHE(0x182000, 2K) - CBFS_MCACHE(0x182800, 8K) - RAMSTAGE(0x200000, 16M) + + /* + * On POWER, 0 is wherever HRMOR points to rather than physical DRAM start. + * HRMOR is ORed with address, not added to it, meaning that memory space + * overlaps after 2^(least significant set bit of HRMOR). This becomes + * chaotic when nonconsecutive bits are set... + * + * Two and a half possible cases: + * 0. bootblock started with QEMU in hb-mode + * - NIA = 0x10 (bug?) + * - HRMOR = 0x08000000 (128M) + * - no physical memory to enable/train, everything accessible from start + * 1. bootblock loaded by HBBL + * - NIA = 0 + * - HRMOR = 0xF8000000 (4G - 128M) + * - initialized L3 = 0x400000 (4M) + * - top address before RAM = 0xF8400000 + * 2. bootblock in SEEPROM, loaded by SBE + * - NIA = 0x3000 (placeholder for int. vectors) + * - HRMOR = 0xF8200000 (4G - 128 M + 2 M) + * - initialized L3 = 0x8000 (bootblock/HBBL size = 32K) + * - no way 32K will be enough, must initialize more L3 in bootblock + * - HRMOR still applies, so memory overlaps every 2M + * + * Common subset (assuming 2. initializes as much memory as possible) is + * 0xF8200000-0xF8400000. 2M should be more than enough for pre-RAM code, + * but it isn't enough to load ramstage. We could implement postcar stage, + * but KISS: initialize L3 from _ebootblock to 0xF8980000: up to 9.5M into + * cache, leaving bottom 2M (0xF8000000-0xF8200000) either uninitialized + * (when started from SEEPROM) or just unused for anything but bootblock + * (loaded by HBBL). Last 0.5M of L3 cache is left for interrupt vectors + * normally located at address 0. + * + * Set HRMOR to 0 before jumping to C code in bootblock and forget it even + * exists. + * + * For QEMU s/0xF8/0x08/ in above description but code remains the same. + * L3 initialization is unnecessary in this case but won't break anything. + * + * TODO: there is a structure with SBE->HBBL data at 0 in 2nd option. It + * holds some useful data like XSCOM BAR and LPC BAR. If, for any reason, + * these addresses are different than default, they should be used instead + * of predefined values. + */ + +#if !CONFIG(BOOTBLOCK_IN_SEEPROM) + BOOTBLOCK( 0xF8000000, 32K) +#else + BOOTBLOCK( 0xF8203000, 20K) +#endif + + STACK( 0xF8208000, 32K) + PRERAM_CBMEM_CONSOLE(0xF8210000, 128K) + FMAP_CACHE( 0xF8230000, 4K) + CBFS_MCACHE( 0xF8231000, 8K) + TIMESTAMP( 0xF8233000, 4K) + + ROMSTAGE( 0xF8240000, 256K) + + /* + * bootblock_crt0.S assumes this is the last part of L3, leaving for + * interrupt vectors at least 0.5M because of cache associativity. If + * more CBFS_CACHE is needed, split this into pre-/postram caches. + */ + CBFS_CACHE( 0xF8280000, 7M) + + RAMSTAGE( 0xF9000000, 2M) } diff --git a/src/soc/ibm/power9/Makefile.mk b/src/soc/ibm/power9/Makefile.mk index b2aa581afa..9a3961d87d 100644 --- a/src/soc/ibm/power9/Makefile.mk +++ b/src/soc/ibm/power9/Makefile.mk @@ -30,18 +30,24 @@ endif [ -e "$(KEYDIR)/hw_key_b.key" ] || ( echo "error: $(KEYDIR)/hw_key_b.key" is missing; exit 1 ) [ -e "$(KEYDIR)/hw_key_c.key" ] || ( echo "error: $(KEYDIR)/hw_key_c.key" is missing; exit 1 ) [ -e "$(KEYDIR)/sw_key_p.key" ] || ( echo "error: $(KEYDIR)/sw_key_p.key" is missing; exit 1 ) - $(CREATE_CONTAINER) -a $(KEYDIR)/hw_key_a.key -b $(KEYDIR)/hw_key_b.key -c $(KEYDIR)/hw_key_c.key \ - -p $(KEYDIR)/sw_key_p.key --payload $(objcbfs)/bootblock.bin \ - --imagefile $(obj)/bootblock.signed $(CREATE_CONTAINER) -a $(KEYDIR)/hw_key_a.key -b $(KEYDIR)/hw_key_b.key -c $(KEYDIR)/hw_key_c.key \ -p $(KEYDIR)/sw_key_p.key --payload $< --imagefile $<.signed @printf " ECC $(subst $(obj)/,,$<)\n" $(ECCTOOL) --inject $<.signed --output $<.signed.ecc --p8 +ifeq ($(CONFIG_BOOTBLOCK_IN_SEEPROM),y) + @printf " ECC bootblock\n" + $(ECCTOOL) --inject $(objcbfs)/bootblock.bin --output $(obj)/bootblock.ecc --p8 +else + @printf " SBSIGN bootblock\n" + $(CREATE_CONTAINER) -a $(KEYDIR)/hw_key_a.key -b $(KEYDIR)/hw_key_b.key -c $(KEYDIR)/hw_key_c.key \ + -p $(KEYDIR)/sw_key_p.key --payload $(objcbfs)/bootblock.bin \ + --imagefile $(obj)/bootblock.signed $(ECCTOOL) --inject $< --output $<.ecc --p8 @printf " ECC bootblock\n" dd if=$(obj)/bootblock.signed of=$(obj)/bootblock.signed.pad ibs=25486 conv=sync 2> /dev/null $(ECCTOOL) --inject $(obj)/bootblock.signed.pad --output $(obj)/bootblock.signed.ecc --p8 rm $(obj)/bootblock.signed $(obj)/bootblock.signed.pad +endif # CONFIG_BOOTBLOCK_IN_SEEPROM files_added:: sign_and_add_ecc