diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 36d3a6d6..e94ea733 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -172,6 +172,16 @@ genericarm64:
 generic-arm64:
   extends: .build
 
+sbsa-ref:
+  extends: .build
+  parallel:
+    matrix:
+      - KERNEL: [linux-yocto, linux-yocto-rt]
+        TOOLCHAINS: [gcc, clang]
+        TESTING: testimage
+      - KERNEL: linux-yocto-dev
+        TESTING: testimage
+
 juno:
   extends: .build
   parallel:
diff --git a/ci/sbsa-ref.yml b/ci/sbsa-ref.yml
new file mode 100644
index 00000000..23680bd1
--- /dev/null
+++ b/ci/sbsa-ref.yml
@@ -0,0 +1,10 @@
+header:
+  version: 14
+  includes:
+    - ci/base.yml
+
+machine: sbsa-ref
+
+target:
+  - core-image-sato
+  - sbsa-acs
diff --git a/meta-arm-bsp/conf/layer.conf b/meta-arm-bsp/conf/layer.conf
index 9013d11f..1a458400 100644
--- a/meta-arm-bsp/conf/layer.conf
+++ b/meta-arm-bsp/conf/layer.conf
@@ -26,3 +26,5 @@ BBFILES_DYNAMIC += " \
 "
 
 WARN_QA:append:layer-meta-arm-bsp = " patch-status"
+
+addpylib ${LAYERDIR}/lib oeqa
diff --git a/meta-arm-bsp/conf/machine/sbsa-ref.conf b/meta-arm-bsp/conf/machine/sbsa-ref.conf
new file mode 100644
index 00000000..ccfc45a8
--- /dev/null
+++ b/meta-arm-bsp/conf/machine/sbsa-ref.conf
@@ -0,0 +1,43 @@
+#@TYPE: Machine
+#@NAME: sbsa-ref
+#@DESCRIPTION: Reference SBSA machine in qemu-system-aarch64 on Neoverse N2
+
+require conf/machine/include/arm/armv9a/tune-neoversen2.inc
+require conf/machine/include/qemu.inc
+
+PREFERRED_PROVIDER_virtual/kernel ?= "linux-yocto"
+KERNEL_IMAGETYPE = "Image"
+MACHINE_EXTRA_RRECOMMENDS += "kernel-modules"
+
+MACHINE_FEATURES = " alsa bluetooth efi qemu-usermode rtc screen usbhost vfat wifi"
+
+IMAGE_FSTYPES += "wic.qcow2"
+
+# This unique WIC file is necessary because kernel boot args cannot be passed
+# because there is no default kernel (see below).  There is no default kernel
+# because QEMU will only allow firmware or kernel to be passed in as a
+# parameter, and we need the firmware.  So, to allow for "ip=dhcp" as a kernel
+# boot arg (which we need for testimage), we have to have a WIC file unique to
+# this platform.
+WKS_FILE = "qemu-efi-disk.wks.in"
+
+EFI_PROVIDER ?= "${@bb.utils.contains("DISTRO_FEATURES", "systemd", "systemd-boot", "grub-efi", d)}"
+
+SERIAL_CONSOLES ?= "115200;ttyAMA0 115200;hvc0"
+
+EXTRA_IMAGEDEPENDS += "edk2-firmware"
+
+QB_SYSTEM_NAME = "qemu-system-aarch64"
+QB_MACHINE = "-machine sbsa-ref"
+QB_CPU = "-cpu neoverse-n2"
+QB_MEM = "-m 1024"
+QB_DEFAULT_FSTYPE = "wic.qcow2"
+QB_NETWORK_DEVICE = "-device virtio-net-pci,netdev=net0,mac=@MAC@"
+QB_DRIVE_TYPE = "/dev/hd"
+QB_ROOTFS_OPT = "-drive file=@ROOTFS@,if=ide,format=qcow2"
+QB_DEFAULT_KERNEL = "none"
+QB_OPT_APPEND = "-device usb-tablet -device usb-kbd -pflash @DEPLOY_DIR_IMAGE@/SBSA_FLASH0.fd -pflash @DEPLOY_DIR_IMAGE@/SBSA_FLASH1.fd"
+QB_SERIAL_OPT = "-device virtio-serial-pci -chardev null,id=virtcon -device virtconsole,chardev=virtcon"
+QB_TCPSERIAL_OPT = "-device virtio-serial-pci -chardev socket,id=virtcon,port=@PORT@,host=127.0.0.1 -device virtconsole,chardev=virtcon"
+# sbsa-ref is a true virtual machine so can't use KVM
+QEMU_USE_KVM = "0"
diff --git a/meta-arm-bsp/lib/oeqa/runtime/cases/parselogs-ignores-sbsa-ref.txt b/meta-arm-bsp/lib/oeqa/runtime/cases/parselogs-ignores-sbsa-ref.txt
new file mode 100644
index 00000000..dd477996
--- /dev/null
+++ b/meta-arm-bsp/lib/oeqa/runtime/cases/parselogs-ignores-sbsa-ref.txt
@@ -0,0 +1,5 @@
+# The release of EDK2 after 202402 should fix this
+NUMA: Failed to initialise from firmware
+
+# TODO: we should be using bochsdrm over efifb?
+efifb: cannot reserve video memory at 0x80000000
diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-sbsa-ref.inc b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-sbsa-ref.inc
new file mode 100644
index 00000000..15061397
--- /dev/null
+++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-sbsa-ref.inc
@@ -0,0 +1,6 @@
+# sbsa-ref specific TF-A support
+
+COMPATIBLE_MACHINE = "sbsa-ref"
+
+TFA_PLATFORM       = "qemu_sbsa"
+TFA_INSTALL_TARGET = "bl1 fip"
diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_%.bbappend b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_%.bbappend
index cb482a6f..214996a9 100644
--- a/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_%.bbappend
+++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a_%.bbappend
@@ -7,6 +7,7 @@ MACHINE_TFA_REQUIRE:corstone1000 = "trusted-firmware-a-corstone1000.inc"
 MACHINE_TFA_REQUIRE:fvp-base = "trusted-firmware-a-fvp-base.inc"
 MACHINE_TFA_REQUIRE:juno = "trusted-firmware-a-juno.inc"
 MACHINE_TFA_REQUIRE:n1sdp = "trusted-firmware-a-n1sdp.inc"
+MACHINE_TFA_REQUIRE:sbsa-ref = "trusted-firmware-a-sbsa-ref.inc"
 MACHINE_TFA_REQUIRE:sgi575 = "trusted-firmware-a-sgi575.inc"
 MACHINE_TFA_REQUIRE:tc = "trusted-firmware-a-tc.inc"
 
diff --git a/meta-arm-bsp/recipes-bsp/uefi/edk2-firmware-sbsa-ref.inc b/meta-arm-bsp/recipes-bsp/uefi/edk2-firmware-sbsa-ref.inc
new file mode 100644
index 00000000..450f6af2
--- /dev/null
+++ b/meta-arm-bsp/recipes-bsp/uefi/edk2-firmware-sbsa-ref.inc
@@ -0,0 +1,19 @@
+COMPATIBLE_MACHINE:sbsa-ref = "sbsa-ref"
+
+DEPENDS:append:sbsa-ref     = " trusted-firmware-a coreutils-native"
+
+EDK2_PLATFORM:sbsa-ref      = "SbsaQemu"
+EDK2_PLATFORM_DSC:sbsa-ref  = "Platform/Qemu/SbsaQemu/SbsaQemu.dsc"
+EDK2_BIN_NAME:sbsa-ref      = "SBSA_FLASH0.fd"
+
+do_compile:prepend:sbsa-ref() {
+    mkdir -p ${B}/Platform/Qemu/Sbsa/
+    cp ${RECIPE_SYSROOT}/firmware/bl1.bin ${B}/Platform/Qemu/Sbsa/
+    cp ${RECIPE_SYSROOT}/firmware/fip.bin ${B}/Platform/Qemu/Sbsa/
+}
+
+do_install:append:sbsa-ref() {
+    install ${B}/Build/${EDK2_PLATFORM}/${EDK2_BUILD_MODE}_${EDK_COMPILER}/FV/SBSA_FLASH*.fd ${D}/firmware/
+    # QEMU requires that the images be minimum of 256M in size
+    truncate -s 256M ${D}/firmware/SBSA_FLASH*.fd
+}
diff --git a/meta-arm-bsp/recipes-bsp/uefi/edk2-firmware_%.bbappend b/meta-arm-bsp/recipes-bsp/uefi/edk2-firmware_%.bbappend
index e5018bb0..cba48460 100644
--- a/meta-arm-bsp/recipes-bsp/uefi/edk2-firmware_%.bbappend
+++ b/meta-arm-bsp/recipes-bsp/uefi/edk2-firmware_%.bbappend
@@ -4,6 +4,7 @@ MACHINE_EDK2_REQUIRE ?= ""
 
 MACHINE_EDK2_REQUIRE:fvp-base = "edk2-firmware-fvp-base.inc"
 MACHINE_EDK2_REQUIRE:juno = "edk2-firmware-juno.inc"
+MACHINE_EDK2_REQUIRE:sbsa-ref = "edk2-firmware-sbsa-ref.inc"
 MACHINE_EDK2_REQUIRE:sgi575 = "edk2-firmware-sgi575.inc"
 MACHINE_EDK2_REQUIRE:n1sdp = "edk2-firmware-n1sdp.inc"
 
diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc
index 2856b461..933acc3e 100644
--- a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc
+++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc
@@ -100,3 +100,10 @@ KCONFIG_MODE:sgi575 = "--alldefconfig"
 COMPATIBLE_MACHINE:tc = "(tc0|tc1)"
 KBUILD_DEFCONFIG:tc = "defconfig"
 KCONFIG_MODE:tc = "--alldefconfig"
+
+#
+# sbsa-ref KMACHINE
+#
+COMPATIBLE_MACHINE:sbsa-ref = "sbsa-ref"
+KBUILD_DEFCONFIG:sbsa-ref = "defconfig"
+KCONFIG_MODE:sbsa-ref = "--alldefconfig"
diff --git a/meta-arm-bsp/recipes-security/optee/optee-ftpm_%.bbappend b/meta-arm-bsp/recipes-security/optee/optee-ftpm_%.bbappend
new file mode 100644
index 00000000..6e46c371
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/optee-ftpm_%.bbappend
@@ -0,0 +1 @@
+COMPATIBLE_MACHINE:sbsa-ref = "sbsa-ref"
diff --git a/meta-arm-bsp/recipes-security/optee/optee-os-sbsa-ref.inc b/meta-arm-bsp/recipes-security/optee/optee-os-sbsa-ref.inc
new file mode 100644
index 00000000..6e46c371
--- /dev/null
+++ b/meta-arm-bsp/recipes-security/optee/optee-os-sbsa-ref.inc
@@ -0,0 +1 @@
+COMPATIBLE_MACHINE:sbsa-ref = "sbsa-ref"
diff --git a/meta-arm-bsp/recipes-security/optee/optee-os_4.%.bbappend b/meta-arm-bsp/recipes-security/optee/optee-os_4.%.bbappend
index 788a23ef..ee0945d9 100644
--- a/meta-arm-bsp/recipes-security/optee/optee-os_4.%.bbappend
+++ b/meta-arm-bsp/recipes-security/optee/optee-os_4.%.bbappend
@@ -3,5 +3,6 @@
 MACHINE_OPTEE_OS_REQUIRE ?= ""
 MACHINE_OPTEE_OS_REQUIRE:corstone1000 = "optee-os-corstone1000-common.inc"
 MACHINE_OPTEE_OS_REQUIRE:n1sdp = "optee-os-n1sdp.inc"
+MACHINE_OPTEE_OS_REQUIRE:sbsa-ref = "optee-os-sbsa-ref.inc"
 
 require ${MACHINE_OPTEE_OS_REQUIRE}
