diff options
20 files changed, 853 insertions, 0 deletions
diff --git a/Documentation/mainboard/emulation/qemu-sbsa.md b/Documentation/mainboard/emulation/qemu-sbsa.md new file mode 100644 index 0000000000..abbd1895a5 --- /dev/null +++ b/Documentation/mainboard/emulation/qemu-sbsa.md @@ -0,0 +1,42 @@ +# QEMU SBSA emulator +This page describes how to build and run ```coreboot``` for QEMU's sbsa-ref machine. +The qemu-sbsa ```coreboot``` image acts as BL-3.3 for Arm Trusted Firmware (```TF-A```) and +mainly takes care of setting up SMBIOS and ACPI tables, hence, in order to boot, +you also need to supply a ```TF-A``` image. + +## Building TF-A + +You can build ```TF-A``` from source by fetching +``` +https://github.com/ARM-software/arm-trusted-firmware +``` +and building the qemu-sbsa platform +``` +PLAT=qemu_sbsa +``` +Upon entry, ```coreboot``` expects a FDT pointer in x0, so make sure to compile ```TF-A``` with +``` +ARM_LINUX_KERNEL_AS_BL33=1 +``` +This will force ```TF-A``` to pass a pointer to the FDT in x0. + +## Building coreboot + +Simply select the qemu-sbsa board and, optionally, configure a payload. We recommend +the ```leanefi``` payload. ```leanefi``` will setup a minimal set of UEFI services, just enough +to boot into a linux kernel. + +## Running coreboot in QEMU + +Once you have obtained ```TF-A``` and ```coreboot``` images, launch qemu via + +```bash +qemu-system-aarch64 -nographic -m 1024 -M sbsa-ref -pflash <path/to/TFA.fd> \ + -pflash <path/to/coreboot.rom> +``` + +## LBBR bootflow + +arm and 9elements worked together in order to create a LBBR compliant bootflow +consisting of ```TF-A```, ```coreboot```, ```leanefi``` and ```LinuxBoot```. A proof of concept +can be found here https://gitlab.arm.com/systemready/firmware-build/linuxboot/lbbr-coreboot-poc diff --git a/Documentation/mainboard/index.md b/Documentation/mainboard/index.md index 5a80d46c14..e54b01fa38 100644 --- a/Documentation/mainboard/index.md +++ b/Documentation/mainboard/index.md @@ -90,6 +90,7 @@ The boards in this section are not real mainboards, but emulators. Spike RISC-V emulator <emulation/spike-riscv.md> QEMU RISC-V emulator <emulation/qemu-riscv.md> QEMU AArch64 emulator <emulation/qemu-aarch64.md> +QEMU SBSA emulator <emulation/qemu-sbsa.md> QEMU x86 Q35 <emulation/qemu-q35.md> QEMU x86 PC <emulation/qemu-i440fx.md> QEMU POWER9 <emulation/qemu-power9.md> diff --git a/src/mainboard/emulation/Kconfig b/src/mainboard/emulation/Kconfig index 5f596b87c0..1c2ab86aaf 100644 --- a/src/mainboard/emulation/Kconfig +++ b/src/mainboard/emulation/Kconfig @@ -3,6 +3,7 @@ # ugly to put it in here, but unavoidable config SEPARATE_ROMSTAGE default n if BOARD_EMULATION_QEMU_RISCV + default n if BOARD_EMULATION_QEMU_SBSA if VENDOR_EMULATION diff --git a/src/mainboard/emulation/qemu-sbsa/Kconfig b/src/mainboard/emulation/qemu-sbsa/Kconfig new file mode 100644 index 0000000000..a28ae62290 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/Kconfig @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if BOARD_EMULATION_QEMU_SBSA + +config BOARD_SPECIFIC_OPTIONS + def_bool y + select ARCH_BOOTBLOCK_ARMV8_64 + select ARCH_VERSTAGE_ARMV8_64 + select ARCH_ROMSTAGE_ARMV8_64 + select ARCH_RAMSTAGE_ARMV8_64 + select ARM64_USE_ARCH_TIMER + select BOARD_ROMSIZE_KB_32768 + select BOOTBLOCK_CUSTOM + select BOOT_DEVICE_NOT_SPI_FLASH + select DRIVERS_UART_PL011 + select FLATTENED_DEVICE_TREE + select HAVE_LINEAR_FRAMEBUFFER + select MAINBOARD_FORCE_NATIVE_VGA_INIT + select MAINBOARD_HAS_NATIVE_VGA_INIT + select MISSING_BOARD_RESET + select PCI + select HAVE_ACPI_TABLES + select ACPI_GTDT + select ACPI_COMMON_MADT_GICC_V3 + select GENERATE_SMBIOS_TABLES + +config ARM64_CURRENT_EL + default 2 + +config ECAM_MMCONF_BASE_ADDRESS + default 0xf0000000 + +config ECAM_MMCONF_BUS_NUMBER + default 256 + +config FMDFILE + default "src/mainboard/emulation/qemu-sbsa/flash.fmd" + +config MAINBOARD_DIR + default "emulation/qemu-sbsa" + +config MAINBOARD_PART_NUMBER + default "QEMU sbsa" + +config MAX_CPUS + default 128 + +config MAINBOARD_VENDOR + default "QEMU" + +config DRAM_SIZE_MB + int + default 8388608 # The maximum dram size is 8192GiB. + +endif # BOARD_EMULATION_QEMU_SBSA diff --git a/src/mainboard/emulation/qemu-sbsa/Kconfig.name b/src/mainboard/emulation/qemu-sbsa/Kconfig.name new file mode 100644 index 0000000000..6fefa0c0a1 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/Kconfig.name @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config BOARD_EMULATION_QEMU_SBSA + bool "QEMU sbsa" diff --git a/src/mainboard/emulation/qemu-sbsa/Makefile.mk b/src/mainboard/emulation/qemu-sbsa/Makefile.mk new file mode 100644 index 0000000000..e3855bae03 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/Makefile.mk @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +bootblock-y += bootblock.c + +romstage-y += cbmem.c + +bootblock-y += media.c +romstage-y += media.c +ramstage-y += media.c + +bootblock-y += mmio.c +romstage-y += mmio.c +ramstage-y += mmio.c + +ramstage-y += acpi.c + +bootblock-y += bootblock_custom.S + +CPPFLAGS_common += -mcmodel=large -I$(src)/mainboard/$(MAINBOARDDIR)/include + +build_complete:: + @printf "Truncating coreboot.rom to 256M\n" + truncate -s 256M $(obj)/coreboot.rom diff --git a/src/mainboard/emulation/qemu-sbsa/acpi.c b/src/mainboard/emulation/qemu-sbsa/acpi.c new file mode 100644 index 0000000000..1dae24277f --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/acpi.c @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi.h> +#include <mainboard/addressmap.h> + + +void acpi_fill_fadt(acpi_fadt_t *fadt) +{ + fadt->ARM_boot_arch |= ACPI_FADT_ARM_PSCI_COMPLIANT; +} + +unsigned long acpi_fill_madt(unsigned long current) +{ + return current; +} + +uintptr_t platform_get_gicd_base(void) +{ + return SBSA_GIC_DIST; +} + +uintptr_t platform_get_gicr_base(void) +{ + return SBSA_GIC_REDIST; +} + +#define SEC_EL1_TIMER_GISV 0x1d +#define NONSEC_EL1_TIMER_GSIV 0x1e +#define VIRTUAL_TIMER_GSIV 0x1b +#define NONSEC_EL2_TIMER_GSIV 0x1a + +#define SBSA_TIMER_FLAGS (ACPI_GTDT_INTERRUPT_POLARITY | ACPI_GTDT_ALWAYS_ON) + +void acpi_soc_fill_gtdt(acpi_gtdt_t *gtdt) +{ + /* This value is optional if the system implements EL3 (Security + Extensions). If not provided, this field must be 0xFFFFFFFFFFFFFFFF. */ + gtdt->counter_block_address = UINT64_MAX; + gtdt->secure_el1_interrupt = SEC_EL1_TIMER_GISV; + gtdt->secure_el1_flags = SBSA_TIMER_FLAGS; + gtdt->non_secure_el1_interrupt = NONSEC_EL1_TIMER_GSIV; + gtdt->non_secure_el1_flags = SBSA_TIMER_FLAGS; + gtdt->virtual_timer_interrupt = VIRTUAL_TIMER_GSIV; + gtdt->virtual_timer_flags = SBSA_TIMER_FLAGS; + gtdt->non_secure_el2_interrupt = NONSEC_EL2_TIMER_GSIV; + gtdt->non_secure_el2_flags = SBSA_TIMER_FLAGS; + /* This value is optional if the system implements EL3 + (Security Extensions). If not provided, this field must be + 0xFFFFFFFFFFFFFFF. */ + gtdt->counter_read_block_address = UINT64_MAX; +} + +#define WD_TIMER_GSIV 0x30 + +unsigned long acpi_soc_gtdt_add_timers(uint32_t *count, unsigned long current) +{ + (*count)++; + return acpi_gtdt_add_watchdog(current, SBSA_GWDT_REFRESH, SBSA_GWDT_CONTROL, + WD_TIMER_GSIV, 0); +} diff --git a/src/mainboard/emulation/qemu-sbsa/board_info.txt b/src/mainboard/emulation/qemu-sbsa/board_info.txt new file mode 100644 index 0000000000..16a92be4b3 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/board_info.txt @@ -0,0 +1,3 @@ +Board name: QEMU sbsa +Category: emulation +Board URL: https://wiki.qemu.org/Main_Page diff --git a/src/mainboard/emulation/qemu-sbsa/bootblock.c b/src/mainboard/emulation/qemu-sbsa/bootblock.c new file mode 100644 index 0000000000..b38df6ec71 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/bootblock.c @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/mmu.h> +#include <bootblock_common.h> +#include <symbols.h> + +void bootblock_mainboard_init(void) +{ + mmu_init(); + + /* Everything below DRAM is device memory */ + mmu_config_range((void *)0, (uintptr_t)_dram, MA_DEV | MA_RW); + /* Set a dummy value for DRAM. ramstage should update the mapping. */ + mmu_config_range(_dram, ((size_t) CONFIG_DRAM_SIZE_MB) * MiB, MA_MEM | MA_RW); + + mmu_config_range(_ttb, REGION_SIZE(ttb), MA_MEM | MA_S | MA_RW); + mmu_config_range(_bootblock, REGION_SIZE(bootblock), MA_MEM | MA_S | MA_RW); + mmu_config_range(_ramstage, REGION_SIZE(ramstage), MA_MEM | MA_S | MA_RW); + mmu_config_range((void *)CONFIG_ECAM_MMCONF_BASE_ADDRESS, CONFIG_ECAM_MMCONF_LENGTH, + MA_DEV | MA_RW); + mmu_enable(); +} diff --git a/src/mainboard/emulation/qemu-sbsa/bootblock_custom.S b/src/mainboard/emulation/qemu-sbsa/bootblock_custom.S new file mode 100644 index 0000000000..c05afed5ff --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/bootblock_custom.S @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Early initialization code for sbsa-ref machine + */ + +#include <arch/asm.h> + +ENTRY(_start) + + /* TF-A arg which contains a pointer to fdt */ + ldr x1, =_fdt_pointer + str x0, [x1] + + /* Setup CPU. */ + /* bl arm64_init_cpu */ + + /* ==== stack init from arm64_init_cpu ==== */ + + msr SPSel, #0 /* use SP_EL0 */ + + ldr x2, =0xdeadbeefdeadbeef + ldr x0, =_stack + ldr x1, =_estack +1: + stp x2, x2, [x0], #16 + cmp x0, x1 + bne 1b + + sub sp, x0, #16 + + /* ==== END ==== */ + + /* Get code positions. */ + ldr x1, =_flash + ldr x0, =_bootblock + + /* Calculate bootblock size. */ + ldr x2, =_ebootblock + sub x2, x2, x0 + + /* Call memcpy in arch/arm64/memcpy.S */ + bl memcpy + dmb sy + + /* Calculate relocation offset between bootblock in flash and in DRAM. */ + ldr x0, =_flash + ldr x1, =_bootblock + sub x1, x1, x0 + + /* Jump to main() in DRAM. */ + adr x0, main + add x0, x0, x1 + blr x0 +ENDPROC(_start) diff --git a/src/mainboard/emulation/qemu-sbsa/cbmem.c b/src/mainboard/emulation/qemu-sbsa/cbmem.c new file mode 100644 index 0000000000..ebc8a78da3 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/cbmem.c @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <cbmem.h> +#include <symbols.h> +#include <device_tree.h> +#include <console/console.h> + +DECLARE_REGION(fdt_pointer) +uintptr_t cbmem_top_chipset(void) +{ + const uint64_t top = fdt_get_memory_top((void *) *((uintptr_t *)_fdt_pointer)); + + if (top == 0) { + /* corrupted FDT? */ + die("Could not find top of memory in FDT!"); + } + + printk(BIOS_DEBUG, "%s: 0x%llx\n", __func__, top); + return (uintptr_t)top; +} diff --git a/src/mainboard/emulation/qemu-sbsa/chip.h b/src/mainboard/emulation/qemu-sbsa/chip.h new file mode 100644 index 0000000000..98c6c71076 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/chip.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef MAINBOARD_EMULATION_QEMU_SBSA_CHIP_H +#define MAINBOARD_EMULATION_QEMU_SBSA_CHIP_H + +#include <types.h> + +struct mainboard_emulation_qemu_sbsa_config { + uint32_t vgic_maintenance_interrupt; + uint32_t performance_interrupt_gsiv; +}; + +#endif diff --git a/src/mainboard/emulation/qemu-sbsa/devicetree.cb b/src/mainboard/emulation/qemu-sbsa/devicetree.cb new file mode 100644 index 0000000000..2e2cf3d01e --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/devicetree.cb @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +chip mainboard/emulation/qemu-sbsa + register "vgic_maintenance_interrupt" = "0x19" + register "performance_interrupt_gsiv" = "0x17" + + device cpu_cluster 0 on ops qemu_aarch64_cpu_ops end + + device domain 0 on ops qemu_aarch64_pci_domain_ops + device pci 00.0 on end + end +end diff --git a/src/mainboard/emulation/qemu-sbsa/dsdt.asl b/src/mainboard/emulation/qemu-sbsa/dsdt.asl new file mode 100644 index 0000000000..8280cb7431 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/dsdt.asl @@ -0,0 +1,271 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#define LINK_DEVICE(Uid, LinkName, Irq) \ + Device (LinkName) { \ + Name (_HID, EISAID("PNP0C0F")) \ + Name (_UID, Uid) \ + Name (_CRS, ResourceTemplate() { \ + Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { Irq } \ + }) \ + } + +#define USB_PORT(PortName, Adr) \ + Device (PortName) { \ + Name (_ADR, Adr) \ + Name (_UPC, Package() { \ + 0xFF, \ + 0x00, \ + 0x00000000, \ + 0x00000000 \ + }) \ + Name (_PLD, Package() { \ + Buffer(0x10) { \ + 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x31, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \ + } \ + }) \ + } + +#define PRT_ENTRY(Address, Pin, Link) \ + Package (4) { \ + Address, Pin, Link, Zero \ + } + +#define PRT_ENTRY_GROUP(Address, Link0, Link1, Link2, Link3) \ + PRT_ENTRY (Address, 0, Link0), \ + PRT_ENTRY (Address, 1, Link1), \ + PRT_ENTRY (Address, 2, Link2), \ + PRT_ENTRY (Address, 3, Link3) + +#include <acpi/acpi.h> +#include <mainboard/addressmap.h> + +DefinitionBlock( + "dsdt.aml", + "DSDT", + ACPI_DSDT_REV_2, + OEM_ID, + ACPI_TABLE_CREATOR, + 0x20230621 +) +{ + #include <acpi/dsdt_top.asl> + + Scope (_SB) { + // UART PL011 + Device (COM0) { + Name (_HID, "ARMH0011") + Name (_UID, Zero) + Name (_CRS, ResourceTemplate () { + Memory32Fixed (ReadWrite, SBSA_UART_BASE, 0x00001000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 33 } + }) + } + + // AHCI Host Controller + Device (AHC0) { + Name (_HID, "LNRO001E") + Name (_CLS, Package (3) { + 0x01, + 0x06, + 0x01, + }) + Name (_CCA, 1) + Name (_CRS, ResourceTemplate() { + Memory32Fixed (ReadWrite, SBSA_AHCI_BASE, 0x00010000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 42 } + }) + } + + // USB EHCI Host Controller + Device (USB0) { + Name (_HID, "LNRO0D20") + Name (_CID, "PNP0D20") + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, SBSA_EHCI_BASE, 0x00010000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 43 } + }) + Return (RBUF) + } + + // Root Hub + Device (RHUB) { + Name (_ADR, 0x00000000) // Address of Root Hub should be 0 as per ACPI 5.0 spec + + // Ports connected to Root Hub + Device (HUB1) { + Name (_ADR, 0x00000001) + Name (_UPC, Package() { + 0x00, // Port is NOT connectable + 0xFF, // Don't care + 0x00000000, // Reserved 0 must be zero + 0x00000000 // Reserved 1 must be zero + }) + USB_PORT (PRT1, 0x00000001) // USB0_RHUB_HUB1_PRT1 + USB_PORT (PRT2, 0x00000002) // USB0_RHUB_HUB1_PRT2 + USB_PORT (PRT3, 0x00000003) // USB0_RHUB_HUB1_PRT3 + USB_PORT (PRT4, 0x00000004) // USB0_RHUB_HUB1_PRT4 + } // USB0_RHUB_HUB1 + } // USB0_RHUB + } // USB0 + + Device (PCI0) + { + Name (_HID, EISAID ("PNP0A08")) // PCI Express Root Bridge + Name (_CID, EISAID ("PNP0A03")) // Compatible PCI Root Bridge + Name (_SEG, Zero) // PCI Segment Group number + Name (_BBN, Zero) // PCI Base Bus Number + Name (_UID, "PCI0") + Name (_CCA, One) // Initially mark the PCI coherent (for JunoR1) + + Method (_CBA, 0, NotSerialized) { + return (SBSA_PCIE_ECAM_BASE) + } + + LINK_DEVICE (0, GSI0, 0x23) + LINK_DEVICE (1, GSI1, 0x24) + LINK_DEVICE (2, GSI2, 0x25) + LINK_DEVICE (3, GSI3, 0x26) + + Name (_PRT, Package () { + + // _PRT: PCI Routing Table + PRT_ENTRY_GROUP (0x0000FFFF, GSI0, GSI1, GSI2, GSI3), + PRT_ENTRY_GROUP (0x0001FFFF, GSI1, GSI2, GSI3, GSI0), + PRT_ENTRY_GROUP (0x0002FFFF, GSI2, GSI3, GSI0, GSI1), + PRT_ENTRY_GROUP (0x0003FFFF, GSI3, GSI0, GSI1, GSI2), + PRT_ENTRY_GROUP (0x0004FFFF, GSI0, GSI1, GSI2, GSI3), + PRT_ENTRY_GROUP (0x0005FFFF, GSI1, GSI2, GSI3, GSI0), + PRT_ENTRY_GROUP (0x0006FFFF, GSI2, GSI3, GSI0, GSI1), + PRT_ENTRY_GROUP (0x0007FFFF, GSI3, GSI0, GSI1, GSI2), + PRT_ENTRY_GROUP (0x0008FFFF, GSI0, GSI1, GSI2, GSI3), + PRT_ENTRY_GROUP (0x0009FFFF, GSI1, GSI2, GSI3, GSI0), + PRT_ENTRY_GROUP (0x000AFFFF, GSI2, GSI3, GSI0, GSI1), + PRT_ENTRY_GROUP (0x000BFFFF, GSI3, GSI0, GSI1, GSI2), + PRT_ENTRY_GROUP (0x000CFFFF, GSI0, GSI1, GSI2, GSI3), + PRT_ENTRY_GROUP (0x000DFFFF, GSI1, GSI2, GSI3, GSI0), + PRT_ENTRY_GROUP (0x000EFFFF, GSI2, GSI3, GSI0, GSI1), + PRT_ENTRY_GROUP (0x000FFFFF, GSI3, GSI0, GSI1, GSI2), + PRT_ENTRY_GROUP (0x0010FFFF, GSI0, GSI1, GSI2, GSI3), + PRT_ENTRY_GROUP (0x0011FFFF, GSI1, GSI2, GSI3, GSI0), + PRT_ENTRY_GROUP (0x0012FFFF, GSI2, GSI3, GSI0, GSI1), + PRT_ENTRY_GROUP (0x0013FFFF, GSI3, GSI0, GSI1, GSI2), + PRT_ENTRY_GROUP (0x0014FFFF, GSI0, GSI1, GSI2, GSI3), + PRT_ENTRY_GROUP (0x0015FFFF, GSI1, GSI2, GSI3, GSI0), + PRT_ENTRY_GROUP (0x0016FFFF, GSI2, GSI3, GSI0, GSI1), + PRT_ENTRY_GROUP (0x0017FFFF, GSI3, GSI0, GSI1, GSI2), + PRT_ENTRY_GROUP (0x0018FFFF, GSI0, GSI1, GSI2, GSI3), + PRT_ENTRY_GROUP (0x0019FFFF, GSI1, GSI2, GSI3, GSI0), + PRT_ENTRY_GROUP (0x001AFFFF, GSI2, GSI3, GSI0, GSI1), + PRT_ENTRY_GROUP (0x001BFFFF, GSI3, GSI0, GSI1, GSI2), + PRT_ENTRY_GROUP (0x001CFFFF, GSI0, GSI1, GSI2, GSI3), + PRT_ENTRY_GROUP (0x001DFFFF, GSI1, GSI2, GSI3, GSI0), + PRT_ENTRY_GROUP (0x001EFFFF, GSI2, GSI3, GSI0, GSI1), + PRT_ENTRY_GROUP (0x001FFFFF, GSI3, GSI0, GSI1, GSI2), + }) + + // Root complex resources + Method (_CRS, 0, Serialized) { + Name (RBUF, ResourceTemplate () { + WordBusNumber ( // Bus numbers assigned to this root + ResourceProducer, + MinFixed, MaxFixed, PosDecode, + 0, // AddressGranularity + 0, // AddressMinimum - Minimum Bus Number + 255, // AddressMaximum - Maximum Bus Number + 0, // AddressTranslation - Set to 0 + 256 // RangeLength - Number of Busses + ) + + DWordMemory ( // 32-bit BAR Windows + ResourceProducer, PosDecode, + MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, // Granularity + SBSA_PCIE_MMIO_BASE, // Min Base Address + SBSA_PCIE_MMIO_LIMIT, // Max Base Address + 0, // Translate + SBSA_PCIE_MMIO_SIZE // Length + ) + + QWordMemory ( // 64-bit BAR Windows + ResourceProducer, PosDecode, + MinFixed, MaxFixed, + Cacheable, ReadWrite, + 0x00000000, // Granularity + SBSA_PCIE_MMIO_HIGH_BASE, // Min Base Address + SBSA_PCIE_MMIO_HIGH_LIMIT, // Max Base Address + 0, // Translate + SBSA_PCIE_MMIO_HIGH_SIZE // Length + ) + + DWordIo ( // IO window + ResourceProducer, + MinFixed, + MaxFixed, + PosDecode, + EntireRange, + 0x00000000, // Granularity + 0, // Min Base Address + 0xffff, // Max Base Address + SBSA_PCIE_PIO_BASE, // Translate + 0x10000, // Length + ,,,TypeTranslation + ) + }) // Name(RBUF) + + Return (RBUF) + } // Method(_CRS) + + // OS Control Handoff + Name (SUPP, Zero) // PCI _OSC Support Field value + Name (CTRL, Zero) // PCI _OSC Control Field value + + /* + * See [1] 6.2.10, [2] 4.5 + */ + Method (_OSC,4) { + // Check for proper UUID + If (Arg0 == ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766")) { + // Create DWord-adressable fields from the Capabilities Buffer + CreateDWordField (Arg3,0,CDW1) + CreateDWordField (Arg3,4,CDW2) + CreateDWordField (Arg3,8,CDW3) + + // Save Capabilities DWord2 & 3 + SUPP = CDW2 + CTRL = CDW3 + + // Only allow native hot plug control if OS supports: + // * ASPM + // * Clock PM + // * MSI/MSI-X + If ((SUPP & 0x16) != 0x16) { + CTRL &= 0x1E // Mask bit 0 (and undefined bits) + } + + // Always allow native PME, AER (no dependencies) + + // Never allow SHPC (no SHPC controller in this system) + CTRL &= 0x1D + + If (Arg1 != One) { // Unknown revision + CDW1 |= 0x08 + } + + If (CDW3 != CTRL) { // Capabilities bits were masked + CDW1 |= 0x10 + } + + // Update DWORD3 in the buffer + CDW3 = CTRL + Return (Arg3) + } Else { + CDW1 |= 4 // Unrecognized UUID + Return (Arg3) + } + } // End _OSC + } + } // Scope (_SB) +} diff --git a/src/mainboard/emulation/qemu-sbsa/flash.fmd b/src/mainboard/emulation/qemu-sbsa/flash.fmd new file mode 100644 index 0000000000..fcc6e19a99 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/flash.fmd @@ -0,0 +1,23 @@ +# +# custom fmap which takes the additional TF-A region into account +# +# +-------------+ <-- 0x0 +# | TF-A | +# +-------------+ <-- BIOS_BASE +# | bootblock | +# +-------------+ <-- BIOS_BASE + 128K +# | FMAP | +# +-------------+ <-- BIOS_BASE + 128K + FMAP_SIZE +# | CBFS | +# +-------------+ <-- ROM_SIZE +# + +FLASH@0x10000000 CONFIG_ROM_SIZE { + + BIOS { + + BOOTBLOCK 128K + FMAP 0x200 + COREBOOT(CBFS) + } +} diff --git a/src/mainboard/emulation/qemu-sbsa/include/mainboard/addressmap.h b/src/mainboard/emulation/qemu-sbsa/include/mainboard/addressmap.h new file mode 100644 index 0000000000..84c2d05bca --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/include/mainboard/addressmap.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Base addresses for QEMU sbsa-ref machine + * [hw/arm/sbsa-ref.c, c6f3cbca32bde9ee94d9949aa63e8a7ef2d7bc5b] + */ + +#define SBSA_FLASH_BASE 0x00000000 +#define SBSA_FLASH_SIZE 0x20000000 +#define SBSA_GIC_DIST 0x40060000 +#define SBSA_GIC_REDIST 0x40080000 +#define SBSA_GWDT_REFRESH 0x50010000 +#define SBSA_GWDT_CONTROL 0x50011000 +#define SBSA_UART_BASE 0x60000000 +#define SBSA_RTC_BASE 0x60010000 +#define SBSA_GPIO_BASE 0x60020000 +#define SBSA_SECURE_UART_BASE 0x60030000 +#define SBSA_SMMU_BASE 0x60050000 +#define SBSA_AHCI_BASE 0x60100000 +#define SBSA_EHCI_BASE 0x60110000 +#define SBSA_SECMEM_BASE 0x20000000 +#define SBSA_SECMEM_SIZE 0x20000000 +#define SBSA_PCIE_MMIO_BASE 0x80000000 +#define SBSA_PCIE_MMIO_LIMIT 0xefffffff +#define SBSA_PCIE_MMIO_SIZE 0x70000000 +#define SBSA_PCIE_PIO_BASE 0x7fff0000 +#define SBSA_PCIE_ECAM_BASE 0xf0000000 +#define SBSA_PCIE_ECAM_LIMIT 0xffffffff +#define SBSA_PCIE_ECAM_SIZE 0x10000000 +#define SBSA_PCIE_MMIO_HIGH_BASE 0x100000000 +#define SBSA_PCIE_MMIO_HIGH_LIMIT 0xffffffffff +#define SBSA_PCIE_MMIO_HIGH_SIZE 0xff00000000 diff --git a/src/mainboard/emulation/qemu-sbsa/mainboard.c b/src/mainboard/emulation/qemu-sbsa/mainboard.c new file mode 100644 index 0000000000..112e1183e4 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/mainboard.c @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "chip.h" +#include <acpi/acpigen.h> +#include <arch/mmu.h> +#include <bootmem.h> +#include <cbfs.h> +#include <device/device.h> +#include <device_tree.h> +#include <bootmem.h> +#include <arch/mmu.h> +#include <mainboard/addressmap.h> +#include <stdint.h> +#include <symbols.h> + +static size_t ram_size(void) +{ + return (size_t)cbmem_top() - (uintptr_t)_dram; +} + +static void mainboard_init(void *chip_info) +{ + mmu_config_range(_dram, ram_size(), MA_MEM | MA_RW); +} + +void smbios_cpu_get_core_counts(u16 *core_count, u16 *thread_count) +{ + *core_count = 0; + struct device *dev = NULL; + while ((dev = dev_find_path(dev, DEVICE_PATH_GICC_V3))) + *core_count += 1; + + *thread_count = 1; +} + +static void qemu_aarch64_init(struct device *dev) +{ + struct memory_info *mem_info; + + mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info)); + if (mem_info == NULL) + return; + + memset(mem_info, 0, sizeof(*mem_info)); + + mem_info->ecc_type = MEMORY_ARRAY_ECC_UNKNOWN; + mem_info->max_capacity_mib = 0x800000; // Fixed at 8 TiB for qemu-sbsa + mem_info->number_of_devices = mem_info->dimm_cnt = 1; + + mem_info->dimm[0].dimm_size = ram_size() / MiB; + mem_info->dimm[0].ddr_type = MEMORY_TYPE_DRAM; + mem_info->dimm[0].ddr_frequency = 0; + mem_info->dimm[0].channel_num = mem_info->dimm[0].dimm_num = 0; + mem_info->dimm[0].bank_locator = 0; + + mem_info->dimm[0].bus_width = 0x03; // 64-bit, no parity + mem_info->dimm[0].vdd_voltage = 0; + mem_info->dimm[0].max_speed_mts = mem_info->dimm[0].configured_speed_mts = 0; +} + +static unsigned long mb_write_acpi_tables(const struct device *dev, unsigned long current, + acpi_rsdp_t *rsdp) +{ + printk(BIOS_DEBUG, "ACPI: * DBG2\n"); + return acpi_pl011_write_dbg2_uart(rsdp, current, SBSA_UART_BASE, "\\_SB.COM0"); +} + + +static void mainboard_enable(struct device *dev) +{ + dev->ops->init = qemu_aarch64_init; + dev->ops->write_acpi_tables = mb_write_acpi_tables; +} + + +struct chip_operations mainboard_ops = { + .enable_dev = mainboard_enable, + .init = mainboard_init, +}; + +struct chip_operations mainboard_emulation_qemu_sbsa_ops = { }; + +static void qemu_aarch64_domain_read_resources(struct device *dev) +{ + struct resource *res; + int index = 0; + + /* Initialize the system-wide I/O space constraints. */ + res = new_resource(dev, index++); + res->limit = 0xffffUL; + res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED; + + /* Initialize the system-wide memory resources constraints. */ + res = new_resource(dev, index++); + res->base = SBSA_PCIE_MMIO_BASE; + res->limit = SBSA_PCIE_MMIO_LIMIT; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED; + + res = new_resource(dev, index++); + res->base = SBSA_PCIE_MMIO_HIGH_BASE; + res->limit = SBSA_PCIE_MMIO_HIGH_LIMIT; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED; + + mmio_range(dev, index++, SBSA_PCIE_ECAM_BASE, SBSA_PCIE_ECAM_SIZE); + + ram_range(dev, index++, (uintptr_t)_dram, ram_size()); + + mmio_range(dev, index++, SBSA_FLASH_BASE, SBSA_FLASH_SIZE); + reserved_ram_range(dev, index++, SBSA_SECMEM_BASE, SBSA_SECMEM_SIZE); +} + +struct device_operations qemu_aarch64_pci_domain_ops = { + .read_resources = qemu_aarch64_domain_read_resources, + .set_resources = pci_domain_set_resources, + .scan_bus = pci_host_bridge_scan_bus, +}; + +static void qemu_sbsa_fill_cpu_ssdt(const struct device *dev) +{ + acpigen_write_processor_device(dev->path.gicc_v3.mpidr); + acpigen_write_processor_device_end(); +} + +struct device_operations qemu_sbsa_cpu_ops = { + .acpi_fill_ssdt = qemu_sbsa_fill_cpu_ssdt, +}; + +DECLARE_REGION(fdt_pointer) +static void qemu_aarch64_scan_bus(struct device *dev) +{ + struct bus *bus = alloc_bus(dev); + uintptr_t fdt_blob = *(uintptr_t *)_fdt_pointer; + struct device_tree *tree; + struct device_tree_node *node; + char path[14]; + u16 fdt_cpu_count = 0; + struct mainboard_emulation_qemu_sbsa_config *config = dev->chip_info; + + tree = fdt_unflatten((void *)fdt_blob); + if (tree == NULL) + return; + + snprintf(path, sizeof(path), "/cpus/cpu@%d", fdt_cpu_count); + while ((node = dt_find_node_by_path(tree, path, NULL, NULL, 0)) != NULL) { + struct device_tree_property *prop; + int64_t mpidr = -1; + list_for_each(prop, node->properties, list_node) { + if (!strcmp("reg", prop->prop.name)) { + mpidr = be64toh(*(uint64_t *)prop->prop.data); + break; + } + } + if (mpidr >= 0) { + struct device_path devpath = { .type = DEVICE_PATH_GICC_V3, + .gicc_v3 = { .mpidr = mpidr, + .vgic_mi = config->vgic_maintenance_interrupt, + .pi_gsiv = config->performance_interrupt_gsiv, }, + + }; + struct device *cpu = alloc_dev(bus, &devpath); + assert(cpu); + cpu->ops = &qemu_sbsa_cpu_ops; + } + snprintf(path, sizeof(path), "/cpus/cpu@%d", ++fdt_cpu_count); + } +} + +struct device_operations qemu_aarch64_cpu_ops = { + .scan_bus = qemu_aarch64_scan_bus, +}; diff --git a/src/mainboard/emulation/qemu-sbsa/media.c b/src/mainboard/emulation/qemu-sbsa/media.c new file mode 100644 index 0000000000..00ed54c4a3 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/media.c @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <boot_device.h> + +/* Maps directly to NOR flash up to ROM size. */ +static const struct mem_region_device boot_dev = + MEM_REGION_DEV_RO_INIT((void *)0x10000000, CONFIG_ROM_SIZE); + +const struct region_device *boot_device_ro(void) +{ + return &boot_dev.rdev; +} diff --git a/src/mainboard/emulation/qemu-sbsa/memlayout.ld b/src/mainboard/emulation/qemu-sbsa/memlayout.ld new file mode 100644 index 0000000000..d178521b6e --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/memlayout.ld @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <memlayout.h> +#include <arch/header.ld> + +/* + * Memory map for QEMU sbsa-ref machine since + * [hw/arm/sbsa-ref.c, c6f3cbca32bde9ee94d9949aa63e8a7ef2d7bc5b] + */ +SECTIONS +{ + REGION(flash, 0x10000000, CONFIG_ROM_SIZE, 8) + + DRAM_START(0x10000000000) + BOOTBLOCK(0x10020010000, 64K) + STACK(0x10020020000, 54K) + CBFS_MCACHE(0x1002002D800, 8K) + FMAP_CACHE(0x1002002F800, 2K) + TIMESTAMP(0x10020030000, 1K) + TTB(0x10020070000, 128K) + RAMSTAGE(0x100200b0000, 16M) + REGION(fdt_pointer, 0x100210b0000, ARCH_POINTER_ALIGN_SIZE, ARCH_POINTER_ALIGN_SIZE) + + POSTRAM_CBFS_CACHE(0x10021200000, 1M) +} diff --git a/src/mainboard/emulation/qemu-sbsa/mmio.c b/src/mainboard/emulation/qemu-sbsa/mmio.c new file mode 100644 index 0000000000..6b50856b94 --- /dev/null +++ b/src/mainboard/emulation/qemu-sbsa/mmio.c @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <console/uart.h> +#include <mainboard/addressmap.h> + +uintptr_t uart_platform_base(unsigned int idx) +{ + return SBSA_UART_BASE; +} |