[PATCH v8 25/37] board: emulation: Add QEMU sbsa support

Patrick Rudolph patrick.rudolph at 9elements.com
Tue Oct 15 11:26:23 CEST 2024


Hi Moritz,
On Tue, Oct 15, 2024 at 11:12 AM Moritz Fischer <moritzf at google.com> wrote:
>
> Hi Patrick,
>
> On Mon, Oct 14, 2024 at 6:17 AM Patrick Rudolph
> <patrick.rudolph at 9elements.com> wrote:
> >
> > Add support for Arm sbsa [1] v0.3+ that is supported by QEMU [2].
> >
> > Unlike other Arm based platforms the machine only provides a minimal
> > FDT that contains number of CPUs, ammount of memory and machine-version.
> > The boot firmware has to provide ACPI tables to the OS.
> > Due to this design a full DTB is added here as well that allows U-Boot's
> > driver to properly function. The DTB is appended at the end of the U-Boot
> > image and will be merged with the QEMU provided DTB.
> >
> > In addition provide documentation how to use, enable binman to fabricate both
> > ROMs that are required to boot and add ACPI tables to make it full compatible
> > to the EDK2 reference implementation.
> >
> > The board was tested using Fedora 40 Aarch64 Workstation. It's able
> > to boot from USB and AHCI or network.
> >
> > Tested and found working:
> > - serial
> > - PCI
> > - xHCI
> > - Bochs display
> > - AHCI
> > - network using e1000e
> > - CPU init
> > - Booting Fedora 40
> >
> > 1: Server Base System Architecture (SBSA)
> > 2: https://www.qemu.org/docs/master/system/arm/sbsa.html
> >
> > Signed-off-by: Patrick Rudolph <patrick.rudolph at 9elements.com>
> > Cc: Peter Robinson <pbrobinson at gmail.com>
> > Cc: Simon Glass <sjg at chromium.org>
> > Cc: Tom Rini <trini at konsulko.com>
> > ---
> > Changelog v3:
> > - Add GIC and GIC-ITS to devicetree
> > - Select GICv3 driver
> > - Drop acpi_fill_madt and use driver model instead
> > Changelog v4:
> > - Drop CPU platform code
> > - Enhance the DT to allow MADT generation from DT
> > Changelog v5:
> > - Add full DT and place it at the end of U-Boot
> > - Merge DT with QEMU's DT
> > - Drop DT generation code
> > - Fix flash region length
> > - Drop enable_caches()
> > - Support platforms that do not pass FDT in x0
> > Changelog v6:
> > - Update header order
> > - Drop pad-byte from DT
> > - select BINMAN_FDT
> > - select E1000_NO_NVM
> > - drop config.h include
> > - drop a few CFG_ defines that were used for SPL
> > Changelog v8:
> > - Use /bits/ 64 in DT
> > - Drop flash access helper functions
> > - Add cfi-flash to DT
> > - Mark secure-flash as no execute
> > - Only use defines in DT when it's also used in other files
> > ---
> >  arch/arm/Kconfig                            |   3 +-
> >  arch/arm/dts/qemu-sbsa.dts                  | 137 ++++++
> >  arch/arm/include/asm/arch-qemu-sbsa/boot0.h |  34 ++
> >  arch/arm/mach-qemu/Kconfig                  |  36 +-
> >  board/emulation/qemu-arm/MAINTAINERS        |   2 +
> >  board/emulation/qemu-sbsa/Kconfig           |  58 +++
> >  board/emulation/qemu-sbsa/Makefile          |   8 +
> >  board/emulation/qemu-sbsa/acpi.c            | 192 ++++++++
> >  board/emulation/qemu-sbsa/dsdt.asl          | 483 ++++++++++++++++++++
> >  board/emulation/qemu-sbsa/lowlevel_init.S   |  22 +
> >  board/emulation/qemu-sbsa/qemu-sbsa.c       | 273 +++++++++++
> >  board/emulation/qemu-sbsa/qemu-sbsa.env     |  14 +
> >  board/emulation/qemu-sbsa/qemu-sbsa.h       |  38 ++
> >  board/emulation/qemu-sbsa/smc.c             |  71 +++
> >  configs/qemu-arm-sbsa_defconfig             |  10 +
> >  doc/board/emulation/index.rst               |   1 +
> >  doc/board/emulation/qemu-sbsa.rst           |  98 ++++
> >  doc/develop/driver-model/virtio.rst         |   1 +
> >  include/configs/qemu-sbsa.h                 |  89 ++++
> >  19 files changed, 1563 insertions(+), 7 deletions(-)
> >  create mode 100644 arch/arm/dts/qemu-sbsa.dts
> >  create mode 100644 arch/arm/include/asm/arch-qemu-sbsa/boot0.h
> >  create mode 100644 board/emulation/qemu-sbsa/Kconfig
> >  create mode 100644 board/emulation/qemu-sbsa/Makefile
> >  create mode 100644 board/emulation/qemu-sbsa/acpi.c
> >  create mode 100644 board/emulation/qemu-sbsa/dsdt.asl
> >  create mode 100644 board/emulation/qemu-sbsa/lowlevel_init.S
> >  create mode 100644 board/emulation/qemu-sbsa/qemu-sbsa.c
> >  create mode 100644 board/emulation/qemu-sbsa/qemu-sbsa.env
> >  create mode 100644 board/emulation/qemu-sbsa/qemu-sbsa.h
> >  create mode 100644 board/emulation/qemu-sbsa/smc.c
> >  create mode 100644 configs/qemu-arm-sbsa_defconfig
> >  create mode 100644 doc/board/emulation/qemu-sbsa.rst
> >  create mode 100644 include/configs/qemu-sbsa.h
> >
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 263f85b0d0..0d0c731dd0 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -1054,7 +1054,7 @@ config ARCH_QEMU
> >         imply DM_RNG
> >         imply DM_RTC
> >         imply RTC_PL031
> > -       imply OF_HAS_PRIOR_STAGE
> > +       imply OF_HAS_PRIOR_STAGE if !TARGET_QEMU_ARM_SBSA
> >         imply VIDEO
> >         imply VIDEO_BOCHS
> >         imply SYS_WHITE_ON_BLACK
> > @@ -2381,6 +2381,7 @@ source "board/broadcom/bcmns3/Kconfig"
> >  source "board/cavium/thunderx/Kconfig"
> >  source "board/eets/pdu001/Kconfig"
> >  source "board/emulation/qemu-arm/Kconfig"
> > +source "board/emulation/qemu-sbsa/Kconfig"
> >  source "board/freescale/ls2080aqds/Kconfig"
> >  source "board/freescale/ls2080ardb/Kconfig"
> >  source "board/freescale/ls1088a/Kconfig"
> > diff --git a/arch/arm/dts/qemu-sbsa.dts b/arch/arm/dts/qemu-sbsa.dts
> > new file mode 100644
> > index 0000000000..d6f8a3ac58
> > --- /dev/null
> > +++ b/arch/arm/dts/qemu-sbsa.dts
> > @@ -0,0 +1,137 @@
> > +// SPDX-License-Identifier: GPL-2.0+ OR MIT
> > +/*
> > + * Devicetree with onboard devices for qemu_sbsa-ref for internal use only!
> > + * DO NOT PASS TO THE OS!
> > + *
> > + * As QEMU provides only a minimal devicetree this one is merged with
> > + * it and then fixed at runtime.
> > + *
> > + * Copyright 2024 9elements GmbH
> > + */
> > +#include "configs/qemu-sbsa.h"
> > +
> > +/dts-v1/;
> > +
> > +/ {
> > +       #address-cells = <2>;
> > +       #size-cells = <2>;
> > +       interrupt-parent = <&intc>;
> > +       compatible = "linux,sbsa-ref";
> > +
> > +       binman: binman {
> > +               multiple-images;
> > +       };
> > +
> > +       cpus {
> > +               /* Filled by fdtdec_board_setup() */
> > +       };
> > +
> > +       memory {
> > +               /* Filled by fdtdec_board_setup() */
> > +       };
> > +
> > +       soc {
> > +               compatible = "simple-bus";
> > +               #address-cells = <2>;
> > +               #size-cells = <2>;
> > +               ranges;
> > +
> > +               cfi_flash {
> > +                       compatible = "cfi-flash";
> > +                       reg = /bits/ 64 <SBSA_FLASH_BASE_ADDR
> > +                                        SBSA_FLASH_LENGTH>;
> > +                       status = "okay";
> > +               };
> > +
> > +               uart0 {
> > +                       compatible = "arm,pl011";
> > +                       status = "okay";
> > +                       reg = /bits/ 64 <SBSA_UART_BASE_ADDR
> > +                                        SBSA_UART_LENGTH>;
> > +               };
> > +
> > +               ahci {
> > +                       compatible = "generic-ahci";
> > +                       status = "okay";
> > +                       reg = /bits/ 64 <0x60100000 0x00010000>;
> > +               };
> > +
> > +               xhci {
> > +                       compatible = "generic-xhci";
> > +                       status = "okay";
> > +                       reg = /bits/ 64 <0x60110000 0x00010000>;
> > +               };
> > +
> > +               pci {
> > +                       #address-cells = <3>;
> > +                       #size-cells = <2>;
> > +                       compatible = "pci-host-ecam-generic";
> > +                       device_type = "pci";
> > +                       status = "okay";
> > +                       reg = /bits/ 64 <0xf0000000 0x10000000>;
> > +                       bus-range = <0 0xff>;
> > +                       ranges = /bits/ 32 <0x01000000>,
> > +                                /bits/ 64 <0
> > +                                           SBSA_PIO_BASE_ADDR
> > +                                           SBSA_PIO_LENGTH>,
> > +                                /bits/ 32 <0x02000000>,
> > +                                /bits/ 64 <SBSA_PCIE_MMIO_BASE_ADDR
> > +                                           SBSA_PCIE_MMIO_BASE_ADDR
> > +                                           SBSA_PCIE_MMIO_LENGTH>,
> > +                                /bits/ 32 <0x43000000>,
> > +                                /bits/ 64 <SBSA_PCIE_MMIO_HIGH_BASE_ADDR
> > +                                           SBSA_PCIE_MMIO_HIGH_BASE_ADDR
> > +                                           SBSA_PCIE_MMIO_HIGH_LENGTH>;
> > +               };
> > +       };
> > +
> > +       intc: interrupt-controller {
> > +               compatible = "arm,gic-v3";
> > +               #interrupt-cells = <1>;
> > +               status = "okay";
> > +               interrupt-controller;
> > +               interrupts = <25>;
> > +               reg = /bits/ 64 <SBSA_GIC_DIST_BASE_ADDR SBSA_GIC_DIST_LENGTH>,
> > +                     /bits/ 64 <SBSA_GIC_REDIST_BASE_ADDR SBSA_GIC_REDIST_LENGTH>,
> > +                     /bits/ 64 <0 0>,
> > +                     /bits/ 64 <SBSA_GIC_HBASE_ADDR SBSA_GIC_HBASE_LENGTH>,
> > +                     /bits/ 64 <SBSA_GIC_VBASE_ADDR SBSA_GIC_VBASE_LENGTH>;
> > +       };
> > +
> > +       its {
> > +               compatible = "arm,gic-v3-its";
> > +               status = "disabled";
> > +       };
>
> I think usually its nodes are subnodes of the intc / gic node. See
> examples here:
> https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic-v3.txt
>
Yes, but that doesn't work here.
The U-Boot ACPI generator currently does not iterate over child nodes
when the current node has a method to write ACPI tables.
Thus the two nodes on the same level, which allow to write ACPI tables
in both nodes.

> > +};
> > +
> > +&binman {
> > +       secure-world {
> > +               filename = "secure-world.rom";
> > +               size = <SBSA_SECURE_FLASH_LENGTH>;
> > +
> > +               bl1 {
> > +                       offset = <0x0>;
> > +                       description = "ARM Trusted Firmware BL1";
> > +                       filename = "bl1.bin";
> > +                       type = "blob-ext";
> > +               };
> > +
> > +               fip {
> > +                       offset = <0x12000>;
> > +                       description = "ARM Trusted Firmware FIP";
> > +                       filename = "fip.bin";
> > +                       type = "blob-ext";
> > +               };
> > +       };
> > +
> > +       unsecure-world {
> > +               filename = "unsecure-world.rom";
> > +               size = <SBSA_FLASH_LENGTH>;
> > +
> > +               u-boot {
> > +               };
> > +               u-boot-dtb {
> > +                       compress = "lz4";
> > +               };
> > +       };
> > +};
> > diff --git a/arch/arm/include/asm/arch-qemu-sbsa/boot0.h b/arch/arm/include/asm/arch-qemu-sbsa/boot0.h
> > new file mode 100644
> > index 0000000000..4a1a254b92
> > --- /dev/null
> > +++ b/arch/arm/include/asm/arch-qemu-sbsa/boot0.h
> > @@ -0,0 +1,34 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * sbsa-ref starts U-Boot in XIP memory. Need to relocate U-Boot
> > + * to DRAM which is already up. Instead of using SPL this simple loader
> > + * is being used.
> > + */
> > +relocate_check:
> > +       /* x0 contains the pointer to FDT provided by ATF */
> > +       adr     x1, _start              /* x1 <- Runtime value of _start */
> > +       ldr     x2, _TEXT_BASE          /* x2 <- Linked value of _start */
> > +       subs    x9, x1, x2              /* x9 <- Run-vs-link offset */
> > +       beq     reset
> > +
> > +       adrp    x1, __image_copy_start          /* x2 <- address bits [31:12] */
> > +       add     x1, x1, :lo12:__image_copy_start/* x2 <- address bits [11:00] */
> > +       adrp    x3, __image_copy_end            /* x3 <- address bits [31:12] */
> > +       add     x3, x3, :lo12:__image_copy_end  /* x3 <- address bits [11:00] */
> > +       add     x3, x3, #0x100000               /* 1 MiB for the DTB found at _end */
> > +
> > +copy_loop:
> > +       ldp     x10, x11, [x1], #16     /* copy from source address [x1] */
> > +       stp     x10, x11, [x2], #16     /* copy to   target address [x2] */
> > +       cmp     x1, x3                  /* until source end address [x3] */
> > +       b.lo    copy_loop
> > +
> > +       isb
> > +       ldr     x2, _TEXT_BASE          /* x2 <- Linked value of _start */
> > +       br      x2                      /* Jump to linked address */
> > +       /* Never reaches this point */
> > +1:
> > +       wfi
> > +       b 1b
> > +
> > +relocate_done:
> > \ No newline at end of file
> > diff --git a/arch/arm/mach-qemu/Kconfig b/arch/arm/mach-qemu/Kconfig
> > index 186c3582eb..9c06c6a3a5 100644
> > --- a/arch/arm/mach-qemu/Kconfig
> > +++ b/arch/arm/mach-qemu/Kconfig
> > @@ -3,12 +3,6 @@ if ARCH_QEMU
> >  config SYS_VENDOR
> >         default "emulation"
> >
> > -config SYS_BOARD
> > -       default "qemu-arm"
> > -
> > -config SYS_CONFIG_NAME
> > -       default "qemu-arm"
> > -
> >  choice
> >         prompt "QEMU ARM architecture"
> >         default TARGET_QEMU_ARM_64BIT
> > @@ -25,6 +19,36 @@ config TARGET_QEMU_ARM_64BIT
> >         select ARM64
> >         select BOARD_LATE_INIT
> >
> > +config TARGET_QEMU_ARM_SBSA
> > +       bool "SBSA Reference"
> > +       select ARM64
> > +       select BINMAN
> > +       select BOARD_LATE_INIT
> > +       select ENABLE_ARM_SOC_BOOT0_HOOK
> > +       select MISC_INIT_R
> >  endchoice
> >
> > +if TARGET_QEMU_ARM_32BIT || TARGET_QEMU_ARM_64BIT
> > +
> > +config SYS_BOARD
> > +       default "qemu-arm"
> > +
> > +config SYS_CONFIG_NAME
> > +       default "qemu-arm"
> > +
> > +endif
> > +
> > +if TARGET_QEMU_ARM_SBSA
> > +
> > +config SYS_BOARD
> > +       default "qemu-sbsa"
> > +
> > +config SYS_CONFIG_NAME
> > +       default "qemu-sbsa"
> > +
> > +config SYS_SOC
> > +       default "qemu-sbsa"
> > +
> > +endif
> > +
> >  endif
> > diff --git a/board/emulation/qemu-arm/MAINTAINERS b/board/emulation/qemu-arm/MAINTAINERS
> > index 5154262f29..7bc0ee698c 100644
> > --- a/board/emulation/qemu-arm/MAINTAINERS
> > +++ b/board/emulation/qemu-arm/MAINTAINERS
> > @@ -4,5 +4,7 @@ S:      Maintained
> >  F:     board/emulation/qemu-arm/
> >  F:     board/emulation/common/
> >  F:     include/configs/qemu-arm.h
> > +F:     include/configs/qemu-sbsa.h
> >  F:     configs/qemu_arm_defconfig
> >  F:     configs/qemu_arm64_defconfig
> > +F:     configs/qemu-arm-sbsa_defconfig
> > diff --git a/board/emulation/qemu-sbsa/Kconfig b/board/emulation/qemu-sbsa/Kconfig
> > new file mode 100644
> > index 0000000000..e8de29306c
> > --- /dev/null
> > +++ b/board/emulation/qemu-sbsa/Kconfig
> > @@ -0,0 +1,58 @@
> > +if TARGET_QEMU_ARM_SBSA
> > +
> > +config SYS_SOC
> > +       default "qemu-sbsa"
> > +
> > +config TEXT_BASE
> > +       default 0x10000100000
> > +
> > +config SYS_LOAD_ADDR
> > +       default 0x10000100000
> > +
> > +config PRE_CON_BUF_ADDR
> > +       default 0x100000FF000
> > +
> > +config DEFAULT_DEVICE_TREE
> > +       default "qemu-sbsa"
> > +
> > +config BOARD_SPECIFIC_OPTIONS # dummy
> > +       def_bool y
> > +       select AHCI
> > +       select ACPIGEN
> > +       select ACPI
> > +       select CPU
> > +       select CPU_ARMV8
> > +       select DM
> > +       select DM_USB
> > +       select DM_MTD
> > +       select GENERATE_ACPI_TABLE
> > +       select HAS_ROM
> > +       select MTD
> > +       select OF_LIBFDT_OVERLAY
> > +       select OF_SEPARATE
> > +       select PCI
> > +       select PCIE_ECAM_GENERIC
> > +       select USB
> > +       select GIC_V3
> > +       select GIC_V3_ITS
> > +       select SYS_FLASH_CFI_WIDTH_16BIT
> > +       imply AHCI_GENERIC
> > +       imply USB_XHCI_HCD
> > +       imply USB_XHCI_GENERIC
> > +       imply USB_STORAGE
> > +       imply E1000
> > +       imply E1000_NO_NVM
> > +       imply NET_RANDOM_ETHADDR
> > +       imply VIDEO_BOCHS
> > +       imply CFI_FLASH
> > +       imply SYS_MTDPARTS_RUNTIME
> > +       imply SET_DFU_ALT_INFO
> > +
> > +if DEBUG_UART
> > +
> > +config DEBUG_UART_BASE
> > +       default 0x60000000
> > +endif
> > +
> > +source "board/emulation/common/Kconfig"
> > +endif
> > diff --git a/board/emulation/qemu-sbsa/Makefile b/board/emulation/qemu-sbsa/Makefile
> > new file mode 100644
> > index 0000000000..bacae320e7
> > --- /dev/null
> > +++ b/board/emulation/qemu-sbsa/Makefile
> > @@ -0,0 +1,8 @@
> > +# SPDX-License-Identifier: GPL-2.0+
> > +
> > +obj-y  += qemu-sbsa.o
> > +obj-y  += lowlevel_init.o
> > +obj-y  += smc.o
> > +
> > +obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o
> > +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o
> > diff --git a/board/emulation/qemu-sbsa/acpi.c b/board/emulation/qemu-sbsa/acpi.c
> > new file mode 100644
> > index 0000000000..ba85e08fc7
> > --- /dev/null
> > +++ b/board/emulation/qemu-sbsa/acpi.c
> > @@ -0,0 +1,192 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (c) 2024 9elements GmbH
> > + */
> > +
> > +#include <cpu.h>
> > +#include <tables_csum.h>
> > +#include <string.h>
> > +#include <acpi/acpi_table.h>
> > +#include <asm/acpi_table.h>
> > +#include <asm/armv8/sec_firmware.h>
> > +#include <configs/qemu-sbsa.h>
> > +#include <dm/uclass.h>
> > +#include <dm/device.h>
> > +#include "qemu-sbsa.h"
> > +
> > +#define SBSAQEMU_MADT_GIC_VBASE          0x2c020000
> > +#define SBSAQEMU_MADT_GIC_HBASE          0x2c010000
> > +#define SBSAQEMU_MADT_GIC_PMU_IRQ        23
> > +
> > +#define SBSA_PLATFORM_WATCHDOG_COUNT    1
> > +#define SBSA_PLATFORM_TIMER_COUNT       (SBSA_PLATFORM_WATCHDOG_COUNT)
> > +
> > +#define L2_ATTRIBUTES (ACPI_PPTT_READ_ALLOC | ACPI_PPTT_WRITE_ALLOC | \
> > +                       (ACPI_PPTT_CACHE_TYPE_UNIFIED << \
> > +                        ACPI_PPTT_CACHE_TYPE_SHIFT))
> > +#define L2_SIZE 0x80000
> > +#define L2_SETS 0x400
> > +#define L2_WAYS 8
> > +
> > +#define L1D_ATTRIBUTES (ACPI_PPTT_READ_ALLOC | ACPI_PPTT_WRITE_ALLOC | \
> > +                       (ACPI_PPTT_CACHE_TYPE_DATA << \
> > +                        ACPI_PPTT_CACHE_TYPE_SHIFT))
> > +#define L1D_SIZE 0x8000
> > +#define L1D_SETS 0x100
> > +#define L1D_WAYS 2
> > +
> > +#define L1I_ATTRIBUTES (ACPI_PPTT_READ_ALLOC | \
> > +                       (ACPI_PPTT_CACHE_TYPE_INSTR << \
> > +                        ACPI_PPTT_CACHE_TYPE_SHIFT))
> > +#define L1I_SIZE 0x8000
> > +#define L1I_SETS 0x100
> > +#define L1I_WAYS 2
> > +
> > +int acpi_fill_iort(struct acpi_ctx *ctx)
> > +{
> > +       u32 its_offset, smmu_offset;
> > +       u64 gic_its_base = 0;
> > +
> > +       smc_get_gic_its_base(&gic_its_base);
> > +       if (gic_its_base == 0)
> > +               return 0;
> > +
> > +       u32 identifiers[] = { 0 };
> > +
> > +       its_offset = acpi_iort_add_its_group(ctx, ARRAY_SIZE(identifiers),
> > +                                            identifiers);
> > +
> > +       struct acpi_iort_id_mapping map_smmu[] = {{
> > +               0, 0xffff, 0, its_offset, 0
> > +       }};
> > +
> > +       smmu_offset = acpi_iort_add_smmu_v3(ctx,
> > +                                           SBSA_SMMU_BASE_ADDR, // Base address
> > +                                           ACPI_IORT_SMMU_V3_COHACC_OVERRIDE, // Flags
> > +                                           0,  // VATOS address
> > +                                           0,  // SMMUv3 Model
> > +                                           74, // Event
> > +                                           75, // Pri
> > +                                           77, // Gerror
> > +                                           76, // Sync
> > +                                           0,  // Proximity domain
> > +                                           1,  // DevIDMappingIndex
> > +                                           ARRAY_SIZE(map_smmu),
> > +                                           map_smmu);
> > +
> > +       struct acpi_iort_id_mapping map_rc[] = {{
> > +               0, 0xffff, 0, smmu_offset, 0
> > +       }};
> > +
> > +       acpi_iort_add_rc(ctx,
> > +                        BIT(0) | BIT(56),  // CacheCoherent + CPM
> > +                        0,  // AtsAttribute
> > +                        0,  // PciSegmentNumber
> > +                        64, // MemoryAddressSizeLimit
> > +                        ARRAY_SIZE(map_rc),
> > +                        map_rc);
> > +       return 0;
> > +}
> > +
> > +void acpi_fill_fadt(struct acpi_fadt *fadt)
> > +{
> > +       fadt->flags = ACPI_FADT_HW_REDUCED_ACPI | ACPI_FADT_LOW_PWR_IDLE_S0;
> > +       fadt->preferred_pm_profile = ACPI_PM_PERFORMANCE_SERVER;
> > +       fadt->arm_boot_arch = ACPI_ARM_PSCI_COMPLIANT;
> > +}
> > +
> > +int acpi_fill_mcfg(struct acpi_ctx *ctx)
> > +{
> > +       size_t size;
> > +
> > +       /* PCI Segment Group 0, Start Bus Number 0, End Bus Number is 255 */
> > +       size = acpi_create_mcfg_mmconfig((void *)ctx->current,
> > +                                        SBSA_PCIE_ECAM_BASE_ADDR, 0, 0, 255);
> > +       acpi_inc(ctx, size);
> > +
> > +       return 0;
> > +}
> > +
> > +static int sbsa_write_gtdt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
> > +{
> > +       struct acpi_table_header *header;
> > +       struct acpi_gtdt *gtdt;
> > +
> > +       gtdt = ctx->current;
> > +       header = &gtdt->header;
> > +
> > +       memset(gtdt, '\0', sizeof(struct acpi_gtdt));
> > +
> > +       acpi_fill_header(header, "GTDT");
> > +       header->length = sizeof(struct acpi_gtdt);
> > +       header->revision = acpi_get_table_revision(ACPITAB_GTDT);
> > +
> > +       gtdt->cnt_ctrl_base = 0xFFFFFFFFFFFFFFFF;
> > +       gtdt->sec_el1_gsiv = 29;
> > +       gtdt->sec_el1_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> > +       gtdt->el1_gsiv = 30;
> > +       gtdt->el1_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> > +       gtdt->virt_el1_gsiv = 27;
> > +       gtdt->virt_el1_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> > +       gtdt->el2_gsiv = 26;
> > +       gtdt->el2_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> > +       gtdt->cnt_read_base = 0xffffffffffffffff;
> > +
> > +       // FIXME: VirtualPL2Timer
> > +       header->checksum = table_compute_checksum(header, header->length);
> > +
> > +       acpi_add_table(ctx, gtdt);
> > +
> > +       acpi_inc(ctx, sizeof(struct acpi_gtdt));
> > +
> > +       return 0;
> > +};
> > +
> > +ACPI_WRITER(5gtdt, "GTDT", sbsa_write_gtdt, 0);
> > +
> > +static int acpi_write_pptt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
> > +{
> > +       struct acpi_table_header *header;
> > +       int cluster_offset, l2_offset;
> > +       u32 offsets[2];
> > +
> > +       header = ctx->current;
> > +       ctx->tab_start = ctx->current;
> > +
> > +       memset(header, '\0', sizeof(struct acpi_table_header));
> > +
> > +       acpi_fill_header(header, "PPTT");
> > +       header->revision = acpi_get_table_revision(ACPITAB_PPTT);
> > +       acpi_inc(ctx, sizeof(*header));
> > +
> > +       cluster_offset = acpi_pptt_add_proc(ctx, ACPI_PPTT_PHYSICAL_PACKAGE |
> > +                                           ACPI_PPTT_CHILDREN_IDENTICAL,
> > +                                           0, 0, 0, NULL);
> > +
> > +       l2_offset = acpi_pptt_add_cache(ctx, ACPI_PPTT_ALL_VALID, 0, L2_SIZE,
> > +                                       L2_SETS, L2_WAYS, L2_ATTRIBUTES, 64);
> > +
> > +       offsets[0] = acpi_pptt_add_cache(ctx, ACPI_PPTT_ALL_VALID, l2_offset,
> > +                                        L1D_SIZE, L1D_SETS, L1D_WAYS,
> > +                                        L1D_ATTRIBUTES, 64);
> > +
> > +       offsets[1] = acpi_pptt_add_cache(ctx, ACPI_PPTT_ALL_BUT_WRITE_POL,
> > +                                        l2_offset, L1I_SIZE, L1I_SETS,
> > +                                        L1I_WAYS, L1I_ATTRIBUTES, 64);
> > +
> > +       for (int i = 0; i < uclass_id_count(UCLASS_CPU); i++) {
> > +               acpi_pptt_add_proc(ctx, ACPI_PPTT_CHILDREN_IDENTICAL |
> > +                                  ACPI_PPTT_NODE_IS_LEAF | ACPI_PPTT_PROC_ID_VALID,
> > +                                  cluster_offset, i, 2, offsets);
> > +       }
> > +
> > +       header->length = ctx->current - ctx->tab_start;
> > +       header->checksum = table_compute_checksum(header, header->length);
> > +
> > +       acpi_inc(ctx, header->length);
> > +       acpi_add_table(ctx, header);
> > +
> > +       return 0;
> > +};
> > +
> > +ACPI_WRITER(5pptt, "PPTT", acpi_write_pptt, 0);
> > diff --git a/board/emulation/qemu-sbsa/dsdt.asl b/board/emulation/qemu-sbsa/dsdt.asl
> > new file mode 100644
> > index 0000000000..f12cca04e2
> > --- /dev/null
> > +++ b/board/emulation/qemu-sbsa/dsdt.asl
> > @@ -0,0 +1,483 @@
> > +/** @file
> > +*  Differentiated System Description Table Fields (DSDT).
> > +*
> > +*  Copyright (c) 2020, Linaro Ltd. All rights reserved.
> > +*
> > +*  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#include <configs/qemu-sbsa.h>
> > +
> > +#define LINK_DEVICE(Uid, LinkName, Irq)                                        \
> > +        Device (LinkName) {                                                    \
> > +            Name (_HID, EISAID("PNP0C0F"))                                     \
> > +            Name (_UID, Uid)                                                   \
> > +            Name (_PRS, ResourceTemplate() {                                   \
> > +                Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { Irq } \
> > +            })                                                                 \
> > +            Method (_STA) {                                                    \
> > +              Return (0xF)                                                     \
> > +            }                                                                  \
> > +            Method (_CRS, 0) { Return (_PRS) }                                 \
> > +            Method (_SRS, 1) { }                                               \
> > +            Method (_DIS) { }                                                  \
> > +        }
> > +
> > +#define PRT_ENTRY(Address, Pin, Link)                                          \
> > +        Package (4) {                                                          \
> > +            Address, Pin, Link, Zero                                           \
> > +          }
> > +
> > +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "U-Boot", "SBSAQEMU", 2) {
> > +  Scope (_SB) {
> > +    // UART PL011
> > +    Device (COM0) {
> > +      Name (_HID, "ARMH0011")
> > +      Name (_UID, Zero)
> > +      Name (_CRS, ResourceTemplate () {
> > +        Memory32Fixed (ReadWrite,
> > +                       SBSA_UART_BASE_ADDR,
> > +                       SBSA_UART_LENGTH)
> > +        Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 33 }
> > +      })
> > +      Method (_STA) {
> > +        Return (0xF)
> > +      }
> > +    }
> > +
> > +    // 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_ADDR,
> > +                       SBSA_AHCI_LENGTH)
> > +        Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 42 }
> > +      })
> > +      Method (_STA) {
> > +        Return (0xF)
> > +      }
> > +    }
> > +
> > +
> > +    // USB XHCI Host Controller
> > +    Device (USB0) {
> > +        Name (_HID, "PNP0D10")      // _HID: Hardware ID
> > +        Name (_UID, 0x00)            // _UID: Unique ID
> > +        Name (_CCA, 0x01)            // _CCA: Cache Coherency Attribute
> > +        Name (XHCI, 0xF)            // will be set using AcpiLib
> > +        Method (_STA) {
> > +          Return (XHCI)
> > +        }
> > +        Name (_CRS, ResourceTemplate() {
> > +            Memory32Fixed (ReadWrite,
> > +                           SBSA_XHCI_BASE_ADDR,
> > +                           SBSA_XHCI_LENGTH)
> > +            Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 43 }
> > +        })
> > +
> > +        // Root Hub
> > +        Device (RHUB) {
> > +            Name (_ADR, 0x00000000)  // Address of Root Hub should be 0 as per ACPI 5.0 spec
> > +            Method (_STA) {
> > +              Return (0xF)
> > +            }
> > +
> > +            // 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
> > +                })
> > +                Method (_STA) {
> > +                  Return (0xF)
> > +                }
> > +
> > +                Device (PRT1) {
> > +                    Name (_ADR, 0x00000001)
> > +                    Name (_UPC, Package() {
> > +                        0xFF,        // Port is connectable
> > +                        0x00,        // Port connector is A
> > +                        0x00000000,
> > +                        0x00000000
> > +                    })
> > +                    Name (_PLD, Package() {
> > +                        Buffer(0x10) {
> > +                            0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > +                            0x31, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> > +                        }
> > +                    })
> > +                    Method (_STA) {
> > +                      Return (0xF)
> > +                    }
> > +                } // USB0_RHUB_HUB1_PRT1
> > +                Device (PRT2) {
> > +                    Name (_ADR, 0x00000002)
> > +                    Name (_UPC, Package() {
> > +                        0xFF,        // Port is connectable
> > +                        0x00,        // Port connector is A
> > +                        0x00000000,
> > +                        0x00000000
> > +                    })
> > +                    Name (_PLD, Package() {
> > +                        Buffer(0x10) {
> > +                            0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > +                            0x31, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> > +                        }
> > +                    })
> > +                    Method (_STA) {
> > +                      Return (0xF)
> > +                    }
> > +                } // USB0_RHUB_HUB1_PRT2
> > +
> > +                Device (PRT3) {
> > +                    Name (_ADR, 0x00000003)
> > +                    Name (_UPC, Package() {
> > +                        0xFF,        // Port is connectable
> > +                        0x09,        // Type C connector - USB2 and SS with Switch
> > +                        0x00000000,
> > +                        0x00000000
> > +                    })
> > +                    Name (_PLD, Package() {
> > +                        Buffer (0x10) {
> > +                            0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > +                            0x31, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> > +                        }
> > +                    })
> > +                    Method (_STA) {
> > +                      Return (0xF)
> > +                    }
> > +                } // USB0_RHUB_HUB1_PRT3
> > +
> > +                Device (PRT4) {
> > +                    Name (_ADR, 0x00000004)
> > +                    Name (_UPC, Package() {
> > +                        0xFF,        // Port is connectable
> > +                        0x09,        // Type C connector - USB2 and SS with Switch
> > +                        0x00000000,
> > +                        0x00000000
> > +                    })
> > +                    Name (_PLD, Package() {
> > +                        Buffer (0x10){
> > +                            0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > +                            0x31, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> > +                        }
> > +                    })
> > +                    Method (_STA) {
> > +                      Return (0xF)
> > +                    }
> > +                } // 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 (_STA) {
> > +        Return (0xF)
> > +      }
> > +
> > +      Method (_CBA, 0, NotSerialized) {
> > +          return (SBSA_PCIE_ECAM_BASE_ADDR)
> > +      }
> > +
> > +      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(0x0000FFFF, 0, GSI0),
> > +        PRT_ENTRY(0x0000FFFF, 0, GSI1),
> > +        PRT_ENTRY(0x0000FFFF, 0, GSI2),
> > +        PRT_ENTRY(0x0000FFFF, 0, GSI3),
> > +
> > +        PRT_ENTRY(0x0001FFFF, 0, GSI1),
> > +        PRT_ENTRY(0x0001FFFF, 1, GSI2),
> > +        PRT_ENTRY(0x0001FFFF, 2, GSI3),
> > +        PRT_ENTRY(0x0001FFFF, 3, GSI0),
> > +
> > +        PRT_ENTRY(0x0002FFFF, 0, GSI2),
> > +        PRT_ENTRY(0x0002FFFF, 1, GSI3),
> > +        PRT_ENTRY(0x0002FFFF, 2, GSI0),
> > +        PRT_ENTRY(0x0002FFFF, 3, GSI1),
> > +
> > +        PRT_ENTRY(0x0003FFFF, 0, GSI3),
> > +        PRT_ENTRY(0x0003FFFF, 1, GSI0),
> > +        PRT_ENTRY(0x0003FFFF, 2, GSI1),
> > +        PRT_ENTRY(0x0003FFFF, 3, GSI2),
> > +
> > +        PRT_ENTRY(0x0004FFFF, 0, GSI0),
> > +        PRT_ENTRY(0x0004FFFF, 1, GSI1),
> > +        PRT_ENTRY(0x0004FFFF, 2, GSI2),
> > +        PRT_ENTRY(0x0004FFFF, 3, GSI3),
> > +
> > +        PRT_ENTRY(0x0005FFFF, 0, GSI1),
> > +        PRT_ENTRY(0x0005FFFF, 1, GSI2),
> > +        PRT_ENTRY(0x0005FFFF, 2, GSI3),
> > +        PRT_ENTRY(0x0005FFFF, 3, GSI0),
> > +
> > +        PRT_ENTRY(0x0006FFFF, 0, GSI2),
> > +        PRT_ENTRY(0x0006FFFF, 1, GSI3),
> > +        PRT_ENTRY(0x0006FFFF, 2, GSI0),
> > +        PRT_ENTRY(0x0006FFFF, 3, GSI1),
> > +
> > +        PRT_ENTRY(0x0007FFFF, 0, GSI3),
> > +        PRT_ENTRY(0x0007FFFF, 1, GSI0),
> > +        PRT_ENTRY(0x0007FFFF, 2, GSI1),
> > +        PRT_ENTRY(0x0007FFFF, 3, GSI2),
> > +
> > +        PRT_ENTRY(0x0008FFFF, 0, GSI0),
> > +        PRT_ENTRY(0x0008FFFF, 1, GSI1),
> > +        PRT_ENTRY(0x0008FFFF, 2, GSI2),
> > +        PRT_ENTRY(0x0008FFFF, 3, GSI3),
> > +
> > +        PRT_ENTRY(0x0009FFFF, 0, GSI1),
> > +        PRT_ENTRY(0x0009FFFF, 1, GSI2),
> > +        PRT_ENTRY(0x0009FFFF, 2, GSI3),
> > +        PRT_ENTRY(0x0009FFFF, 3, GSI0),
> > +
> > +        PRT_ENTRY(0x000AFFFF, 0, GSI2),
> > +        PRT_ENTRY(0x000AFFFF, 1, GSI3),
> > +        PRT_ENTRY(0x000AFFFF, 2, GSI0),
> > +        PRT_ENTRY(0x000AFFFF, 3, GSI1),
> > +
> > +        PRT_ENTRY(0x000BFFFF, 0, GSI3),
> > +        PRT_ENTRY(0x000BFFFF, 1, GSI0),
> > +        PRT_ENTRY(0x000BFFFF, 2, GSI1),
> > +        PRT_ENTRY(0x000BFFFF, 3, GSI2),
> > +
> > +        PRT_ENTRY(0x000CFFFF, 0, GSI0),
> > +        PRT_ENTRY(0x000CFFFF, 1, GSI1),
> > +        PRT_ENTRY(0x000CFFFF, 2, GSI2),
> > +        PRT_ENTRY(0x000CFFFF, 3, GSI3),
> > +
> > +        PRT_ENTRY(0x000DFFFF, 0, GSI1),
> > +        PRT_ENTRY(0x000DFFFF, 1, GSI2),
> > +        PRT_ENTRY(0x000DFFFF, 2, GSI3),
> > +        PRT_ENTRY(0x000DFFFF, 3, GSI0),
> > +
> > +        PRT_ENTRY(0x000EFFFF, 0, GSI2),
> > +        PRT_ENTRY(0x000EFFFF, 1, GSI3),
> > +        PRT_ENTRY(0x000EFFFF, 2, GSI0),
> > +        PRT_ENTRY(0x000EFFFF, 3, GSI1),
> > +
> > +        PRT_ENTRY(0x000FFFFF, 0, GSI3),
> > +        PRT_ENTRY(0x000FFFFF, 1, GSI0),
> > +        PRT_ENTRY(0x000FFFFF, 2, GSI1),
> > +        PRT_ENTRY(0x000FFFFF, 3, GSI2),
> > +
> > +        PRT_ENTRY(0x0010FFFF, 0, GSI0),
> > +        PRT_ENTRY(0x0010FFFF, 1, GSI1),
> > +        PRT_ENTRY(0x0010FFFF, 2, GSI2),
> > +        PRT_ENTRY(0x0010FFFF, 3, GSI3),
> > +
> > +        PRT_ENTRY(0x0011FFFF, 0, GSI1),
> > +        PRT_ENTRY(0x0011FFFF, 1, GSI2),
> > +        PRT_ENTRY(0x0011FFFF, 2, GSI3),
> > +        PRT_ENTRY(0x0011FFFF, 3, GSI0),
> > +
> > +        PRT_ENTRY(0x0012FFFF, 0, GSI2),
> > +        PRT_ENTRY(0x0012FFFF, 1, GSI3),
> > +        PRT_ENTRY(0x0012FFFF, 2, GSI0),
> > +        PRT_ENTRY(0x0012FFFF, 3, GSI1),
> > +
> > +        PRT_ENTRY(0x0013FFFF, 0, GSI3),
> > +        PRT_ENTRY(0x0013FFFF, 1, GSI0),
> > +        PRT_ENTRY(0x0013FFFF, 2, GSI1),
> > +        PRT_ENTRY(0x0013FFFF, 3, GSI2),
> > +
> > +        PRT_ENTRY(0x0014FFFF, 0, GSI0),
> > +        PRT_ENTRY(0x0014FFFF, 1, GSI1),
> > +        PRT_ENTRY(0x0014FFFF, 2, GSI2),
> > +        PRT_ENTRY(0x0014FFFF, 3, GSI3),
> > +
> > +        PRT_ENTRY(0x0015FFFF, 0, GSI1),
> > +        PRT_ENTRY(0x0015FFFF, 1, GSI2),
> > +        PRT_ENTRY(0x0015FFFF, 2, GSI3),
> > +        PRT_ENTRY(0x0015FFFF, 3, GSI0),
> > +
> > +        PRT_ENTRY(0x0016FFFF, 0, GSI2),
> > +        PRT_ENTRY(0x0016FFFF, 1, GSI3),
> > +        PRT_ENTRY(0x0016FFFF, 2, GSI0),
> > +        PRT_ENTRY(0x0016FFFF, 3, GSI1),
> > +
> > +        PRT_ENTRY(0x0017FFFF, 0, GSI3),
> > +        PRT_ENTRY(0x0017FFFF, 1, GSI0),
> > +        PRT_ENTRY(0x0017FFFF, 2, GSI1),
> > +        PRT_ENTRY(0x0017FFFF, 3, GSI2),
> > +
> > +        PRT_ENTRY(0x0018FFFF, 0, GSI0),
> > +        PRT_ENTRY(0x0018FFFF, 1, GSI1),
> > +        PRT_ENTRY(0x0018FFFF, 2, GSI2),
> > +        PRT_ENTRY(0x0018FFFF, 3, GSI3),
> > +
> > +        PRT_ENTRY(0x0019FFFF, 0, GSI1),
> > +        PRT_ENTRY(0x0019FFFF, 1, GSI2),
> > +        PRT_ENTRY(0x0019FFFF, 2, GSI3),
> > +        PRT_ENTRY(0x0019FFFF, 3, GSI0),
> > +
> > +        PRT_ENTRY(0x001AFFFF, 0, GSI2),
> > +        PRT_ENTRY(0x001AFFFF, 1, GSI3),
> > +        PRT_ENTRY(0x001AFFFF, 2, GSI0),
> > +        PRT_ENTRY(0x001AFFFF, 3, GSI1),
> > +
> > +        PRT_ENTRY(0x001BFFFF, 0, GSI3),
> > +        PRT_ENTRY(0x001BFFFF, 1, GSI0),
> > +        PRT_ENTRY(0x001BFFFF, 2, GSI1),
> > +        PRT_ENTRY(0x001BFFFF, 3, GSI2),
> > +
> > +        PRT_ENTRY(0x001CFFFF, 0, GSI0),
> > +        PRT_ENTRY(0x001CFFFF, 1, GSI1),
> > +        PRT_ENTRY(0x001CFFFF, 2, GSI2),
> > +        PRT_ENTRY(0x001CFFFF, 3, GSI3),
> > +
> > +        PRT_ENTRY(0x001DFFFF, 0, GSI1),
> > +        PRT_ENTRY(0x001DFFFF, 1, GSI2),
> > +        PRT_ENTRY(0x001DFFFF, 2, GSI3),
> > +        PRT_ENTRY(0x001DFFFF, 3, GSI0),
> > +
> > +        PRT_ENTRY(0x001EFFFF, 0, GSI2),
> > +        PRT_ENTRY(0x001EFFFF, 1, GSI3),
> > +        PRT_ENTRY(0x001EFFFF, 2, GSI0),
> > +        PRT_ENTRY(0x001EFFFF, 3, GSI1),
> > +
> > +        PRT_ENTRY(0x001FFFFF, 0, GSI3),
> > +        PRT_ENTRY(0x001FFFFF, 1, GSI0),
> > +        PRT_ENTRY(0x001FFFFF, 2, GSI1),
> > +        PRT_ENTRY(0x001FFFFF, 3, GSI2),
> > +      })
> > +
> > +      // Root complex resources
> > +      Name (_CRS, ResourceTemplate () {
> > +        WordBusNumber ( // Bus numbers assigned to this root
> > +        ResourceProducer,
> > +        MinFixed, MaxFixed, PosDecode,
> > +        0,   // AddressGranularity
> > +        0,   // AddressMinimum - Minimum Bus Number
> > +        0xff,// AddressMaximum - Maximum Bus Number
> > +        0,   // AddressTranslation - Set to 0
> > +        256  // RangeLength - Number of Busses
> > +        )
> > +
> > +        // IO to mmio window
> > +        QWordIO (
> > +          ResourceProducer, MinFixed,
> > +          MaxFixed, PosDecode,
> > +          EntireRange,
> > +          0x00000000,                              // Granularity
> > +          0x0000,                                  // Min Base Address
> > +          0xffff,                                  // Max Base Address
> > +          SBSA_PIO_BASE_ADDR,                      // Translate
> > +          SBSA_PIO_LENGTH                          // Length
> > +        )
> > +
> > +        DWordMemory ( // 32-bit BAR Windows
> > +          ResourceProducer, PosDecode,
> > +          MinFixed, MaxFixed,
> > +          Cacheable, ReadWrite,
> > +          0x00000000,                              // Granularity
> > +          SBSA_PCIE_MMIO_BASE_ADDR,                // Min Base Address
> > +          SBSA_PCIE_MMIO_END,                      // Max Base Address
> > +          0,                                       // Translate
> > +          SBSA_PCIE_MMIO_LENGTH                    // Length
> > +          )
> > +
> > +        QWordMemory ( // 64-bit BAR Windows
> > +          ResourceProducer, PosDecode,
> > +          MinFixed, MaxFixed,
> > +          Cacheable, ReadWrite,
> > +          0x00000000,                              // Granularity
> > +          SBSA_PCIE_MMIO_HIGH_BASE_ADDR,           // Min Base Address
> > +          SBSA_PCIE_MMIO_HIGH_END,                 // Max Base Address
> > +          0,                                       // Translate
> > +          SBSA_PCIE_MMIO_HIGH_LENGTH               // Length
> > +          )
> > +      }) // Name(_CRS)
> > +
> > +      Device (RES0)
> > +      {
> > +        Name (_HID, "PNP0C02" /* PNP Motherboard Resources */)  // _HID: Hardware ID
> > +        Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
> > +        {
> > +           QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
> > +           0x0000000000000000,                       // Granularity
> > +           SBSA_PCIE_ECAM_BASE_ADDR,                 // Range Minimum
> > +           SBSA_PCIE_ECAM_END,                       // Range Maximum
> > +           0x0000000000000000,                       // Translation Offset
> > +           SBSA_PCIE_ECAM_LENGTH,                    // Length
> > +           ,, , AddressRangeMemory, TypeStatic)
> > +        })
> > +        Method (_STA) {
> > +          Return (0xF)
> > +        }
> > +      }
> > +
> > +      // 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
> > +          Store (CDW2,SUPP)
> > +          Store (CDW3,CTRL)
> > +
> > +          // 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
> > +          Store (CTRL,CDW3)
> > +          Return (Arg3)
> > +        } Else {
> > +          CDW1 |= 4 // Unrecognized UUID
> > +          Return (Arg3)
> > +        }
> > +      } // End _OSC
> > +    }
> > +  } // Scope (_SB)
> > +}
> > diff --git a/board/emulation/qemu-sbsa/lowlevel_init.S b/board/emulation/qemu-sbsa/lowlevel_init.S
> > new file mode 100644
> > index 0000000000..c997721af9
> > --- /dev/null
> > +++ b/board/emulation/qemu-sbsa/lowlevel_init.S
> > @@ -0,0 +1,22 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * (C) Copyright 2016
> > + * Cédric Schieli <cschieli at gmail.com>
> > + */
> > +
> > +#include <config.h>
> > +
> > +/*
> > + * Routine: save_boot_params (called after reset from start.S)
> > + * Description: save ATAG/FDT address provided by the firmware at boot time
> > + */
> > +
> > +.global save_boot_params
> > +save_boot_params:
> > +       /* The firmware provided ATAG/FDT address can be found in r2/x0 */
> > +       adr     x8, fw_dtb_pointer
> > +       str     x0, [x8]
> > +
> > +
> > +       /* Returns */
> > +       b       save_boot_params_ret
> > diff --git a/board/emulation/qemu-sbsa/qemu-sbsa.c b/board/emulation/qemu-sbsa/qemu-sbsa.c
> > new file mode 100644
> > index 0000000000..3943c92432
> > --- /dev/null
> > +++ b/board/emulation/qemu-sbsa/qemu-sbsa.c
> > @@ -0,0 +1,273 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright (c) 2017 Tuomas Tynkkynen
> > + */
> > +
> > +#include <cpu_func.h>
> > +#include <dm.h>
> > +#include <env.h>
> > +#include <fdtdec.h>
> > +#include <fdt_support.h>
> > +#include <init.h>
> > +#include <log.h>
> > +#include <usb.h>
> > +#include <asm/armv8/mmu.h>
> > +
> > +#include "qemu-sbsa.h"
> > +
> > +/* Assigned in lowlevel_init.S
> > + * Push the variable into the .data section so that it
> > + * does not get cleared later.
> > + */
> > +unsigned long __section(".data") fw_dtb_pointer;
> > +
> > +static struct mm_region qemu_sbsa_mem_map[] = {
> > +       {
> > +               /* Secure flash */
> > +               .virt = SBSA_SECURE_FLASH_BASE_ADDR,
> > +               .phys = SBSA_SECURE_FLASH_BASE_ADDR,
> > +               .size = SBSA_SECURE_FLASH_LENGTH,
> > +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> > +                        PTE_BLOCK_INNER_SHARE |
> > +                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
> > +       }, {
> > +               /* Flash */
> > +               .virt = SBSA_FLASH_BASE_ADDR,
> > +               .phys = SBSA_FLASH_BASE_ADDR,
> > +               .size = SBSA_FLASH_LENGTH,
> > +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> > +                        PTE_BLOCK_INNER_SHARE
> > +       }, {
> > +               /* Lowmem peripherals */
> > +               .virt = SBSA_PERIPH_BASE_ADDR,
> > +               .phys = SBSA_PERIPH_BASE_ADDR,
> > +               .size = SBSA_PCIE_MMIO_BASE_ADDR - SBSA_PERIPH_BASE_ADDR,
> > +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> > +                        PTE_BLOCK_NON_SHARE |
> > +                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
> > +       }, {
> > +               /* 32-bit address PCIE MMIO space */
> > +               .virt = SBSA_PCIE_MMIO_BASE_ADDR,
> > +               .phys = SBSA_PCIE_MMIO_BASE_ADDR,
> > +               .size = SBSA_PCIE_MMIO_LENGTH,
> > +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> > +                        PTE_BLOCK_NON_SHARE |
> > +                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
> > +       }, {
> > +               /* PCI-E ECAM memory area */
> > +               .virt = SBSA_PCIE_ECAM_BASE_ADDR,
> > +               .phys = SBSA_PCIE_ECAM_BASE_ADDR,
> > +               .size = SBSA_PCIE_ECAM_LENGTH,
> > +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> > +                        PTE_BLOCK_NON_SHARE |
> > +                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
> > +       }, {
> > +               /* Highmem PCI-E MMIO memory area */
> > +               .virt = SBSA_PCIE_MMIO_HIGH_BASE_ADDR,
> > +               .phys = SBSA_PCIE_MMIO_HIGH_BASE_ADDR,
> > +               .size = SBSA_PCIE_MMIO_HIGH_LENGTH,
> > +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> > +                        PTE_BLOCK_NON_SHARE |
> > +                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
> > +       }, {
> > +               /* DRAM */
> > +               .virt = SBSA_MEM_BASE_ADDR,
> > +               .phys = SBSA_MEM_BASE_ADDR,
> > +               .size = 0x800000000000ULL,
> > +               .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
> > +                        PTE_BLOCK_INNER_SHARE
> > +       }, {
> > +               /* List terminator */
> > +               0,
> > +       }
> > +};
> > +
> > +struct mm_region *mem_map = qemu_sbsa_mem_map;
> > +
> > +int board_late_init(void)
> > +{
> > +       /* start usb so that usb keyboard can be used as input device */
> > +       if (CONFIG_IS_ENABLED(USB_KEYBOARD))
> > +               usb_init();
> > +
> > +       return 0;
> > +}
> > +
> > +int board_init(void)
> > +{
> > +       return 0;
> > +}
> > +
> > +/**
> > + * dtb_dt_qemu - Return the address of the QEMU provided FDT.
> > + *
> > + * @return: Pointer to FDT or NULL on failure
> > + */
> > +static void *dtb_dt_qemu(void)
> > +{
> > +       /* FDT might be at start of DRAM */
> > +       if (fdt_magic(SBSA_MEM_BASE_ADDR) == FDT_MAGIC)
> > +               return (void *)(u64)SBSA_MEM_BASE_ADDR;
> > +
> > +       /* When ARM_LINUX_KERNEL_AS_BL33 is enabled in ATF, it's passed in x0 */
> > +       if (fw_dtb_pointer >= SBSA_MEM_BASE_ADDR &&
> > +           fdt_magic(fw_dtb_pointer) == FDT_MAGIC) {
> > +               return (void *)fw_dtb_pointer;
> > +       }
> > +
> > +       return NULL;
> > +}
> > +
> > +/*
> > + * QEMU doesn't set compatible on cpus.
> > + * Add them to make sure the U-Boot driver properly bind.
> > + */
> > +static int fdtdec_fix_cpus(void *fdt_blob)
> > +{
> > +       int cpus_offset, off, ret;
> > +       u64 mpidr, i = 0;
> > +
> > +       cpus_offset = fdt_path_offset(fdt_blob, "/cpus");
> > +       if (cpus_offset < 0) {
> > +               puts("couldn't find /cpus node\n");
> > +               return cpus_offset;
> > +       }
> > +
> > +       fdt_for_each_subnode(off, fdt_blob, cpus_offset) {
> > +               if (strncmp(fdt_get_name(fdt_blob, off, NULL), "cpu@", 4))
> > +                       continue;
> > +
> > +               mpidr = 0;
> > +               ret = smc_get_mpidr(i, &mpidr);
> > +               if (ret) {
> > +                       log_warning("Failed to get MPIDR for processor %lld from SMC: %d\n",
> > +                                   i, ret);
> > +                       mpidr = i;
> > +               }
> > +
> > +               ret = fdt_setprop_string(fdt_blob, off, "compatible", "arm,armv8");
> > +               if (ret < 0)
> > +                       return ret;
> > +
> > +               ret = fdt_setprop_string(fdt_blob, off, "device_type", "cpu");
> > +               if (ret < 0)
> > +                       return ret;
> > +
> > +               ret = fdt_setprop_u64(fdt_blob, off, "reg", mpidr);
> > +               if (ret < 0)
> > +                       return ret;
> > +               i++;
> > +       }
> > +       return 0;
> > +}
> > +
> > +/*
> > + * Update the GIC node when necessary and add optional ITS when it has a
> > + * non zero base-address.
> > + */
> > +static int fdtdec_fix_gic(void *fdt)
> > +{
> > +       u64 gic_dist_base = SBSA_GIC_DIST_BASE_ADDR;
> > +       u64 gic_redist_base = SBSA_GIC_REDIST_BASE_ADDR;
> > +       u64 gic_its_base = 0;
> > +       int offs, ret;
> > +       u64 reg[10];
> > +
> > +       /* Invoke SMC to get real base-address */
> > +       smc_get_gic_dist_base(&gic_dist_base);
> > +       smc_get_gic_redist_base(&gic_redist_base);
> > +
> > +       if ((gic_dist_base != SBSA_GIC_DIST_BASE_ADDR) ||
> > +           (gic_redist_base != SBSA_GIC_REDIST_BASE_ADDR)) {
> > +               offs = fdt_path_offset(fdt, "/interrupt-controller");
> > +               if (offs < 0) {
> > +                       puts("couldn't find /interrupt-controller node\n");
> > +                       return offs;
> > +               }
> > +
> > +               reg[0] = cpu_to_fdt64(gic_dist_base);
> > +               reg[1] = cpu_to_fdt64((u64)SBSA_GIC_DIST_LENGTH);
> > +               reg[2] = cpu_to_fdt64(gic_redist_base);
> > +               reg[3] = cpu_to_fdt64((u64)SBSA_GIC_REDIST_LENGTH);
> > +               reg[4] = cpu_to_fdt64(0);
> > +               reg[5] = cpu_to_fdt64(0);
> > +               reg[6] = cpu_to_fdt64(SBSA_GIC_HBASE_ADDR);
> > +               reg[7] = cpu_to_fdt64((u64)SBSA_GIC_HBASE_LENGTH);
> > +               reg[8] = cpu_to_fdt64(SBSA_GIC_VBASE_ADDR);
> > +               reg[9] = cpu_to_fdt64((u64)SBSA_GIC_VBASE_LENGTH);
> > +
> > +               ret = fdt_setprop_inplace(fdt, offs, "reg", reg, sizeof(reg));
> > +       }
> > +
> > +       smc_get_gic_its_base(&gic_its_base);
> > +
> > +       if (gic_its_base != 0) {
> > +               offs = fdt_path_offset(fdt, "/its");
> > +               if (offs < 0)
> > +                       return offs;
> > +
> > +               ret = fdt_setprop_string(fdt, offs, "status", "okay");
> > +               if (ret < 0)
> > +                       return ret;
> > +
> > +               reg[0] = cpu_to_fdt64(gic_its_base);
> > +               reg[1] = 0;
> > +
> > +               ret = fdt_setprop(fdt, offs, "reg", reg, sizeof(u64) * 2);
> > +               if (ret < 0)
> > +                       return ret;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +int fdtdec_board_setup(const void *fdt_blob)
> > +{
> > +       void *qemu_fdt;
> > +       int ret;
> > +
> > +       /*
> > +        * Locate the QEMU provided DTB that contains the CPUs and amount of DRAM.
> > +        */
> > +       qemu_fdt = dtb_dt_qemu();
> > +       if (!qemu_fdt) {
> > +               log_err("QEMU FDT not found\n");
> > +               return -ENODEV;
> > +       }
> > +
> > +       ret = fdt_increase_size((void *)fdt_blob, 1024 + fdt_totalsize(qemu_fdt));
> > +       if (ret)
> > +               return -ENOMEM;
> > +
> > +       /*
> > +        * Merge the QEMU DTB as overlay into the U-Boot provided DTB.
> > +        */
> > +       ret = fdt_overlay_apply_node((void *)fdt_blob, 0, qemu_fdt, 0);
> > +       if (ret < 0)
> > +               log_err("Failed to apply overlay: %d\n", ret);
> > +
> > +       /* Fix QEMU nodes to make sure U-Boot drivers are properly working */
> > +       ret = fdtdec_fix_cpus((void *)fdt_blob);
> > +       if (ret < 0)
> > +               log_err("Failed to fix CPUs in FDT: %d\n", ret);
> > +
> > +       ret = fdtdec_fix_gic((void *)fdt_blob);
> > +       if (ret < 0)
> > +               log_err("Failed to fix INTC in FDT: %d\n", ret);
> > +
> > +       return 0;
> > +}
> > +
> > +int misc_init_r(void)
> > +{
> > +       return env_set_hex("fdt_addr", (uintptr_t)gd->fdt_blob);
> > +}
> > +
> > +void reset_cpu(void)
> > +{
> > +}
> > +
> > +int dram_init(void)
> > +{
> > +       return fdtdec_setup_mem_size_base();
> > +}
> > \ No newline at end of file
> > diff --git a/board/emulation/qemu-sbsa/qemu-sbsa.env b/board/emulation/qemu-sbsa/qemu-sbsa.env
> > new file mode 100644
> > index 0000000000..88fdb0ec1c
> > --- /dev/null
> > +++ b/board/emulation/qemu-sbsa/qemu-sbsa.env
> > @@ -0,0 +1,14 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +
> > +/* environment for qemu-arm and qemu-arm64 */
> > +
> > +stdin=serial,usbkbd
> > +stdout=serial,vidconsole
> > +stderr=serial,vidconsole
> > +fdt_high=0xffffffffffffffff
> > +initrd_high=0xffffffffffffffff
> > +scriptaddr=0x100000300000
> > +pxefile_addr_r=0x10000400000
> > +kernel_addr_r=0x10000200000
> > +ramdisk_addr_r=0x10001000000
> > +boot_targets=qfw usb scsi virtio nvme dhcp
> > diff --git a/board/emulation/qemu-sbsa/qemu-sbsa.h b/board/emulation/qemu-sbsa/qemu-sbsa.h
> > new file mode 100644
> > index 0000000000..391a70bdc4
> > --- /dev/null
> > +++ b/board/emulation/qemu-sbsa/qemu-sbsa.h
> > @@ -0,0 +1,38 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright (c) 2024 9elements GmbH
> > + */
> > +
> > +/**
> > + * smc_get_mpidr() - Call into SMC and get the MPIDR for given CPU
> > + *
> > + * @id:                CPU index
> > + * @mpidr:     Pointer where to place the MPIDR
> > + * @return 0 if OK, other -ve on error
> > + */
> > +int smc_get_mpidr(unsigned long id, u64 *mpidr);
> > +
> > +/**
> > + * smc_get_gic_dist_base() - Call into SMC and get GIC dist base address
> > + *
> > + * @mpidr:     Pointer where to place the base address
> > + * @return 0 if OK, other -ve on error
> > + */
> > +int smc_get_gic_dist_base(u64 *base);
> > +
> > +/**
> > + * smc_get_gic_redist_base() - Call into SMC and get the GIC redistributor
> > + *                             base address
> > + *
> > + * @mpidr:     Pointer where to place the base address
> > + * @return 0 if OK, other -ve on error
> > + */
> > +int smc_get_gic_redist_base(u64 *base);
> > +
> > +/**
> > + * smc_get_gic_its_base() - Call into SMC and get the ITS base address
> > + *
> > + * @mpidr:     Pointer where to place the base address
> > + * @return 0 if OK, other -ve on error
> > + */
> > +int smc_get_gic_its_base(u64 *base);
> > diff --git a/board/emulation/qemu-sbsa/smc.c b/board/emulation/qemu-sbsa/smc.c
> > new file mode 100644
> > index 0000000000..9a2d091bea
> > --- /dev/null
> > +++ b/board/emulation/qemu-sbsa/smc.c
> > @@ -0,0 +1,71 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (c) 2024 9elements GmbH
> > + */
> > +
> > +#include <cpu.h>
> > +#include <init.h>
> > +#include <log.h>
> > +#include <linux/arm-smccc.h>
> > +
> > +#define SMC_SIP_FUNCTION_ID(n)  (0xC2000000 | (n))
> > +
> > +#define SIP_SVC_VERSION        SMC_SIP_FUNCTION_ID(1)
> > +#define SIP_SVC_GET_GIC        SMC_SIP_FUNCTION_ID(100)
> > +#define SIP_SVC_GET_GIC_ITS    SMC_SIP_FUNCTION_ID(101)
> > +#define SIP_SVC_GET_CPU_COUNT  SMC_SIP_FUNCTION_ID(200)
> > +#define SIP_SVC_GET_CPU_NODE   SMC_SIP_FUNCTION_ID(201)
> > +#define SIP_SVC_GET_MEMORY_NODE_COUNT SMC_SIP_FUNCTION_ID(300)
> > +#define SIP_SVC_GET_MEMORY_NODE SMC_SIP_FUNCTION_ID(301)
> > +
> > +int smc_get_mpidr(unsigned long id, u64 *mpidr)
> > +{
> > +       struct arm_smccc_res res;
> > +
> > +       res.a0 = ~0;
> > +       arm_smccc_smc(SIP_SVC_GET_CPU_NODE, id, 0, 0, 0, 0, 0, 0, &res);
> > +
> > +       if (!res.a0)
> > +               *mpidr = res.a2;
> > +
> > +       return res.a0;
> > +}
> > +
> > +int smc_get_gic_dist_base(u64 *base)
> > +{
> > +       struct arm_smccc_res res;
> > +
> > +       res.a0 = ~0;
> > +       arm_smccc_smc(SIP_SVC_GET_GIC, 0, 0, 0, 0, 0, 0, 0, &res);
> > +
> > +       if (!res.a0)
> > +               *base = res.a1;
> > +
> > +       return res.a0;
> > +}
> > +
> > +int smc_get_gic_redist_base(u64 *base)
> > +{
> > +       struct arm_smccc_res res;
> > +
> > +       res.a0 = ~0;
> > +       arm_smccc_smc(SIP_SVC_GET_GIC, 0, 0, 0, 0, 0, 0, 0, &res);
> > +
> > +       if (!res.a0)
> > +               *base = res.a2;
> > +
> > +       return res.a0;
> > +}
> > +
> > +int smc_get_gic_its_base(u64 *base)
> > +{
> > +       struct arm_smccc_res res;
> > +
> > +       res.a0 = ~0;
> > +       arm_smccc_smc(SIP_SVC_GET_GIC_ITS, 0, 0, 0, 0, 0, 0, 0, &res);
> > +
> > +       if (!res.a0)
> > +               *base = res.a1;
> > +
> > +       return res.a0;
> > +}
> > diff --git a/configs/qemu-arm-sbsa_defconfig b/configs/qemu-arm-sbsa_defconfig
> > new file mode 100644
> > index 0000000000..a58c3dec4c
> > --- /dev/null
> > +++ b/configs/qemu-arm-sbsa_defconfig
> > @@ -0,0 +1,10 @@
> > +CONFIG_ARM=y
> > +CONFIG_ARCH_QEMU=y
> > +CONFIG_TARGET_QEMU_ARM_SBSA=y
> > +CONFIG_USE_BOOTCOMMAND=y
> > +CONFIG_BOOTCOMMAND="bootflow scan"
> > +CONFIG_EFI_PARTITION=y
> > +CONFIG_PARTITION_TYPE_GUID=y
> > +CONFIG_EFI_MEDIA=y
> > +CONFIG_FS_FAT=y
> > +CONFIG_EFI_VARIABLE_NO_STORE=y
> > diff --git a/doc/board/emulation/index.rst b/doc/board/emulation/index.rst
> > index 98a0b26ad2..0419d72415 100644
> > --- a/doc/board/emulation/index.rst
> > +++ b/doc/board/emulation/index.rst
> > @@ -13,5 +13,6 @@ Emulation
> >     qemu-mips
> >     qemu-ppce500
> >     qemu-riscv
> > +   qemu-sbsa
> >     qemu-x86
> >     qemu-xtensa
> > diff --git a/doc/board/emulation/qemu-sbsa.rst b/doc/board/emulation/qemu-sbsa.rst
> > new file mode 100644
> > index 0000000000..fe1dc3249e
> > --- /dev/null
> > +++ b/doc/board/emulation/qemu-sbsa.rst
> > @@ -0,0 +1,98 @@
> > +.. SPDX-License-Identifier: GPL-2.0+
> > +.. Copyright (C) 2024, Patrick Rudolph <patrick.rudolph at 9elements.com>
> > +
> > +QEMU ARM SBSA
> > +=============
> > +
> > +QEMU for ARM supports Arm Server Base System Architecture Reference board,
> > +short 'sbsa-ref' that utilizes ACPI over FDT. This document describes how to run
> > +U-Boot under it. Only AArch64 is supported.
> > +
> > +The 'sbsa' platform provides the following as the basic functionality:
> > +
> > +    - A freely configurable amount of CPU cores
> > +    - U-Boot loaded and executing in the emulated flash at address 0x10000000
> > +    - No device tree blob
> > +    - A freely configurable amount of RAM
> > +    - A PL011 serial port
> > +    - An ARMv8/ARMv8 architected timer
> > +    - PSCI for rebooting the system
> > +    - A generic ECAM-based PCI host controller
> > +
> > +Additionally, a number of optional peripherals can be added to the PCI bus.
> > +
> > +Compile ARM Trusted Firmware (ATF)
> > +----------------------------------
> > +
> > +Get and Build the ARM Trusted firmware
> > +--------------------------------------
> > +
> > +Note: srctree is U-Boot source directory
> > +Get ATF from: https://github.com/ARM-software/arm-trusted-firmware
> > +
> > +.. code-block:: bash
> > +
> > +  git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git tfa
> > +  cd tfa
> > +  make CROSS_COMPILE=aarch64-linux-gnu- all fip \
> > +    ARM_LINUX_KERNEL_AS_BL33=1 DEBUG=1 PLAT=qemu_sbsa
> > +
> > +Copy the resulting FIP and BL1 binary
> > +
> > +.. code-block:: bash
> > +
> > +  cp build/qemu_sbsa/debug/fip.bin ../
> > +  cp build/qemu_sbsa/debug/bl1.bin ../
> > +
> > +Building U-Boot
> > +---------------
> > +Set the CROSS_COMPILE environment variable as usual, and run:
> > +
> > +.. code-block:: bash
> > +
> > +    make qemu-arm-sbsa_defconfig
> > +    make
> > +
> > +Running U-Boot
> > +--------------
> > +The minimal QEMU command line to get U-Boot up and running is:
> > +
> > +.. code-block:: bash
> > +
> > +    qemu-system-aarch64 -machine sbsa-ref -nographic -cpu cortex-a57 \
> > +                        -pflash secure-world.rom \
> > +                        -pflash unsecure-world.rom
> > +
> > +Note that for some odd reason qemu-system-aarch64 needs to be explicitly
> > +told to use a 64-bit CPU or it will boot in 32-bit mode. The -nographic argument
> > +ensures that output appears on the terminal. Use Ctrl-A X to quit.
> > +
> > +Booting distros
> > +---------------
> > +
> > +It is possible to install and boot a standard Linux distribution using
> > +sbsa by setting up a root disk::
> > +
> > +.. code-block:: bash
> > +
> > +    qemu-img create root.img 20G
> > +
> > +then using the installer to install. For example, with Debian 12::
> > +
> > +.. code-block:: bash
> > +
> > +    qemu-system-aarch64 \
> > +      -machine sbsa-ref -cpu cortex-a57 -m 4G -smp 4 \
> > +      -pflash secure-world.rom \
> > +      -pflash unsecure-world.rom \
> > +      -device virtio-rng-pci \
> > +      -device usb-kbd -device usb-tablet \
> > +      -cdrom debian-12.0.0-arm64-netinst.iso \
> > +      -hda root.img
> > +
> > +Debug UART
> > +----------
> > +
> > +The debug UART on the ARM sbsa board uses these settings::
> > +
> > +    CONFIG_DEBUG_UART=y
> > diff --git a/doc/develop/driver-model/virtio.rst b/doc/develop/driver-model/virtio.rst
> > index 8ac9c94caf..31b94d0467 100644
> > --- a/doc/develop/driver-model/virtio.rst
> > +++ b/doc/develop/driver-model/virtio.rst
> > @@ -34,6 +34,7 @@ The following QEMU targets are supported.
> >
> >    - qemu_arm_defconfig
> >    - qemu_arm64_defconfig
> > +  - qemu-arm-sbsa_defconfig
> >    - qemu-riscv32_defconfig
> >    - qemu-riscv64_defconfig
> >    - qemu-x86_defconfig
> > diff --git a/include/configs/qemu-sbsa.h b/include/configs/qemu-sbsa.h
> > new file mode 100644
> > index 0000000000..aff78160e1
> > --- /dev/null
> > +++ b/include/configs/qemu-sbsa.h
> > @@ -0,0 +1,89 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright (c) 2024 9elements GmbH
> > + */
> > +
> > +#ifndef __CONFIG_H
> > +#define __CONFIG_H
> > +
> > +/* Physical memory map */
> > +
> > +/* SECURE_FLASH */
> > +#define SBSA_SECURE_FLASH_BASE_ADDR    0x00000000
> > +#define SBSA_SECURE_FLASH_LENGTH       0x10000000
> > +
> > +/* FLASH */
> > +#define SBSA_FLASH_BASE_ADDR           0x10000000
> > +#define SBSA_FLASH_LENGTH              0x10000000
> > +
> > +/* PERIPH */
> > +#define SBSA_PERIPH_BASE_ADDR          0x40000000
> > +
> > +/* GIC_DIST */
> > +#define SBSA_GIC_DIST_BASE_ADDR                0x40060000
> > +#define SBSA_GIC_DIST_LENGTH           0x00020000
> > +
> > +#define SBSA_GIC_VBASE_ADDR            0x2c020000
> > +#define SBSA_GIC_VBASE_LENGTH          0x00010000
> > +
> > +#define SBSA_GIC_HBASE_ADDR            0x2c010000
> > +#define SBSA_GIC_HBASE_LENGTH          0x00010000
> > +
> > +/* GIC_REDIST */
> > +#define SBSA_GIC_REDIST_BASE_ADDR      0x40080000
> > +#define SBSA_GIC_REDIST_LENGTH         0x04000000
> > +
> > +/* GIC_ITS */
> > +#define SBSA_GIC_ITS_BASE_ADDR         0x44081000
> > +
> > +/* UART */
> > +#define SBSA_UART_BASE_ADDR            0x60000000
> > +#define SBSA_UART_LENGTH               0x00001000
> > +
> > +/* SMMU */
> > +#define SBSA_SMMU_BASE_ADDR            0x60050000
> > +
> > +/* SATA */
> > +#define SBSA_AHCI_BASE_ADDR            0x60100000
> > +#define SBSA_AHCI_LENGTH               0x00010000
> > +
> > +/* xHCI */
> > +#define SBSA_XHCI_BASE_ADDR            0x60110000
> > +#define SBSA_XHCI_LENGTH               0x00010000
> > +
> > +/* PIO */
> > +#define SBSA_PIO_BASE_ADDR             0x7fff0000
> > +#define SBSA_PIO_LENGTH                        0x00010000
> > +
> > +/* PCIE_MMIO */
> > +#define SBSA_PCIE_MMIO_BASE_ADDR       0x80000000
> > +#define SBSA_PCIE_MMIO_LENGTH          0x70000000
> > +#define SBSA_PCIE_MMIO_END             0xefffffff
> > +
> > +/* PCIE_ECAM */
> > +#define SBSA_PCIE_ECAM_BASE_ADDR       0xf0000000
> > +#define SBSA_PCIE_ECAM_LENGTH          0x10000000
> > +#define SBSA_PCIE_ECAM_END             0xffffffff
> > +
> > +/* PCIE_MMIO_HIGH */
> > +#ifdef __ACPI__
> > +#define SBSA_PCIE_MMIO_HIGH_BASE_ADDR  0x100000000
> > +#define SBSA_PCIE_MMIO_HIGH_LENGTH     0xFF00000000
> > +#define SBSA_PCIE_MMIO_HIGH_END                0xFFFFFFFFFF
> > +#else
> > +#define SBSA_PCIE_MMIO_HIGH_BASE_ADDR  0x100000000ULL
> > +#define SBSA_PCIE_MMIO_HIGH_LENGTH     0xFF00000000ULL
> > +#define SBSA_PCIE_MMIO_HIGH_END                0xFFFFFFFFFFULL
> > +#endif
> > +
> > +/* MEM */
> > +#ifdef __ACPI__
> > +#define SBSA_MEM_BASE_ADDR             0x10000000000
> > +#else
> > +#define SBSA_MEM_BASE_ADDR             0x10000000000ULL
> > +#endif
> > +
> > +#define CFG_SYS_INIT_RAM_ADDR          SBSA_MEM_BASE_ADDR
> > +#define CFG_SYS_INIT_RAM_SIZE          0x1000000
> > +
> > +#endif /* __CONFIG_H */
> > --
> > 2.46.2
> >
>
> Thanks,
> Moritz


More information about the U-Boot mailing list