[#59873] cortex-a53-gicv3: Support multi-core configuration
diff --git a/platforms/cpus/cortex-a53-gicv3.repl b/platforms/cpus/cortex-a53-gicv3.repl
index c1b2e12..19a1d94 100644
--- a/platforms/cpus/cortex-a53-gicv3.repl
+++ b/platforms/cpus/cortex-a53-gicv3.repl
@@ -1,6 +1,7 @@
 cpu: CPU.ARMv8A @ sysbus
     cpuType: "cortex-a53"
     genericInterruptController: gic
+    cpuId: 0
 
 timer: Timers.ARM_GenericTimer @ cpu
     frequency: 62500000
diff --git a/platforms/cpus/cortex-a53-gicv3_smp.repl b/platforms/cpus/cortex-a53-gicv3_smp.repl
new file mode 100644
index 0000000..321f160
--- /dev/null
+++ b/platforms/cpus/cortex-a53-gicv3_smp.repl
@@ -0,0 +1,57 @@
+using "./cortex-a53-gicv3.repl"
+
+cpu1: CPU.ARMv8A @ sysbus
+    cpuType: "cortex-a53"
+    genericInterruptController: gic
+    cpuId: 1
+    init:
+        IsHalted true
+
+cpu2: CPU.ARMv8A @ sysbus
+    cpuType: "cortex-a53"
+    genericInterruptController: gic
+    cpuId: 2
+    init:
+        IsHalted true
+
+cpu3: CPU.ARMv8A @ sysbus
+    cpuType: "cortex-a53"
+    genericInterruptController: gic
+    cpuId: 3
+    init:
+        IsHalted true
+
+timer1: Timers.ARM_GenericTimer @ cpu1
+    frequency: 62500000
+    EL3PhysicalTimerIRQ -> gic#1@29
+    EL1PhysicalTimerIRQ -> gic#1@30
+    EL1VirtualTimerIRQ -> gic#1@27
+    NonSecureEL2PhysicalTimerIRQ -> gic#1@26
+    NonSecureEL2VirtualTimerIRQ -> gic#1@28
+
+timer2: Timers.ARM_GenericTimer @ cpu2
+    frequency: 62500000
+    EL3PhysicalTimerIRQ -> gic#2@29
+    EL1PhysicalTimerIRQ -> gic#2@30
+    EL1VirtualTimerIRQ -> gic#2@27
+    NonSecureEL2PhysicalTimerIRQ -> gic#2@26
+    NonSecureEL2VirtualTimerIRQ -> gic#2@28
+
+timer3: Timers.ARM_GenericTimer @ cpu3
+    frequency: 62500000
+    EL3PhysicalTimerIRQ -> gic#3@29
+    EL1PhysicalTimerIRQ -> gic#3@30
+    EL1VirtualTimerIRQ -> gic#3@27
+    NonSecureEL2PhysicalTimerIRQ -> gic#3@26
+    NonSecureEL2VirtualTimerIRQ -> gic#3@28
+
+gic: @ {
+        sysbus new Bus.BusMultiRegistration { address: 0x8000000; size: 0x010000; region: "distributor" };
+        sysbus new IRQControllers.ArmGicRedistributorRegistration { attachedCPU: cpu; address: 0x80a0000 };
+        sysbus new IRQControllers.ArmGicRedistributorRegistration { attachedCPU: cpu1; address: 0x80c0000 };
+        sysbus new IRQControllers.ArmGicRedistributorRegistration { attachedCPU: cpu2; address: 0x80e0000 };
+        sysbus new IRQControllers.ArmGicRedistributorRegistration { attachedCPU: cpu3; address: 0x8100000 }
+    }
+    [4-7]   -> cpu1@[0-3]
+    [8-11]  -> cpu2@[0-3]
+    [12-15] -> cpu3@[0-3]
diff --git a/scripts/single-node/cortex-a53-linux.resc b/scripts/single-node/cortex-a53-linux.resc
index f4f12d8..201ce1a 100644
--- a/scripts/single-node/cortex-a53-linux.resc
+++ b/scripts/single-node/cortex-a53-linux.resc
@@ -1,16 +1,44 @@
 :name: Cortex-A53
 :description: This script runs Linux (with Coreboot and ATF) on a 64-bit ARM Cortex-A53.
 
-$bin?=@https://dl.antmicro.com/projects/renode/coreboot-linux-armv8a-gicv3.rom-s_67108864-2348c80d6b871b9ac1916dfe0fd590125559ef73
+$bin?=@https://dl.antmicro.com/projects/renode/coreboot-linux-armv8a-gicv3-multicore.rom-s_67108864-02cf8d5b31d105603e63306ac07517a48134bfed
 $name?="ARM Cortex-A53"
 
 using sysbus
 mach create $name
 
-machine LoadPlatformDescription @platforms/cpus/cortex-a53-gicv3.repl
+machine LoadPlatformDescription @platforms/cpus/cortex-a53-gicv3_smp.repl
 
 showAnalyzer uart0
 
+# Based on https://github.com/ARM-software/arm-trusted-firmware/blob/5436047a0e1f32543042d6de9f1f6a3edcd47591/plat/qemu/qemu/include/platform_def.h#L107C1-L115C35
+set py_virt_trusted_mailbox_hook
+"""
+from Antmicro.Renode.Peripherals.CPU import RegisterValue
+
+PLAT_VIRT_TRUSTED_MAILBOX_BASE = 0x0e000000
+PLAT_VIRT_HOLD_BASE = PLAT_VIRT_TRUSTED_MAILBOX_BASE + 0x8
+PLAT_VIRT_HOLD_ENTRY_SIZE = 0x8
+
+PLAT_VIRT_HOLD_STATE_WAIT = 0
+PLAT_VIRT_HOLD_STATE_GO = 1
+
+_cpus = filter(lambda cpu: str(type(cpu)) == "<type 'ARMv8A'>", emulationManager.Instance.CurrentEmulation.Machines[0].SystemBus.GetCPUs())
+cpus = {cpu.Id: cpu for cpu in _cpus}
+
+idx = (address - PLAT_VIRT_HOLD_BASE) // PLAT_VIRT_HOLD_ENTRY_SIZE
+
+secure_entrypoint = self.ReadQuadWord(PLAT_VIRT_TRUSTED_MAILBOX_BASE);
+
+if value == PLAT_VIRT_HOLD_STATE_GO:
+    cpus[idx].PC = RegisterValue.Create(secure_entrypoint, 64)
+    cpus[idx].IsHalted = False
+    cpu.InfoLog("CPU %d started at PC: 0x%x" % (idx, secure_entrypoint))
+elif value == PLAT_VIRT_HOLD_STATE_WAIT:
+    cpus[idx].IsHalted = True
+    cpu.InfoLog("CPU %d halted")
+"""
+
 macro reset
 """
     # Preconfigure UART to see Coreboot and ATF boot logs.
@@ -18,5 +46,16 @@
     uart0 WriteDoubleWord 0x2c 0x40
 
     sysbus LoadBinary $bin 0x0
+
+    sysbus LoadSymbolsFrom @https://dl.antmicro.com/projects/renode/coreboot-bootblock-armv8a-gicv3-multicore.elf-s_45992-e566f9ef7c7f1357a6a5f4e433b42eae686b2773
+    sysbus LoadSymbolsFrom @https://dl.antmicro.com/projects/renode/coreboot-romstage-armv8a-gicv3-multicore.elf-s_53824-78204652d3be096534a1e3036f308ff0c93f5423
+    sysbus LoadSymbolsFrom @https://dl.antmicro.com/projects/renode/coreboot-ramstage-armv8a-gicv3-multicore.elf-s_147352-4d8d77fcee90f90eceebef782140189b21169778
+    sysbus LoadSymbolsFrom @https://dl.antmicro.com/projects/renode/bl31-atf-armv8a-gicv3-multicore.elf-s_1259192-f31a6120e8881925b3290ddd7ac2bc008f56460a
+    sysbus LoadSymbolsFrom @https://dl.antmicro.com/projects/renode/vmlinux-armv8a-gicv3-multicore-s_14825032-9d3f0ca4dc4b246cc648bb45bb36d8c2317bc41b
+
+    sysbus AddWatchpointHook 0x0e000008 QuadWord Write $py_virt_trusted_mailbox_hook # CPU 0 Mailbox 
+    sysbus AddWatchpointHook 0x0e000010 QuadWord Write $py_virt_trusted_mailbox_hook # CPU 1 Mailbox 
+    sysbus AddWatchpointHook 0x0e000018 QuadWord Write $py_virt_trusted_mailbox_hook # CPU 2 Mailbox 
+    sysbus AddWatchpointHook 0x0e000020 QuadWord Write $py_virt_trusted_mailbox_hook # CPU 3 Mailbox 
 """
 runMacro $reset
diff --git a/tests/platforms/ARMv8A-Linux.robot b/tests/platforms/ARMv8A-Linux.robot
index 645493e..d6a3e61 100644
--- a/tests/platforms/ARMv8A-Linux.robot
+++ b/tests/platforms/ARMv8A-Linux.robot
@@ -1,6 +1,7 @@
 *** Variables ***
 ${UART}                           sysbus.uart0
 ${URI}                            @https://dl.antmicro.com/projects/renode
+${LINUX_PROMPT}                   \#${SPACE}
 
 # DTBs are embedded in Coreboot+Linux ROMs. Built with Coreboot v4.20.1, ATF v2.9.0, Linux v6.3 and Buildroot 2023.08-rc1.
 ${COREBOOT_ARMv8A_ROM}                ${URI}/coreboot-without-payload-armv8a.rom-s_16777216-b5c6df85cfb8d240d31fe3cd1d055a3106d2fadb
@@ -39,6 +40,17 @@
     Create Terminal Tester        ${UART}  defaultPauseEmulation=true
     Execute Command               showAnalyzer ${UART}
 
+Create Multicore Machine
+    Execute Command                 include @scripts/single-node/cortex-a53-linux.resc
+    Create Terminal Tester          ${UART}
+
+Boot Linux And Login
+    # Verify that SMP works
+    Wait For Line On Uart           SMP: Total of 4 processors activated  includeUnfinishedLine=true
+    Wait For Prompt On Uart         buildroot login:  timeout=50
+    Write Line To Uart              root
+    Wait For Prompt On Uart         ${LINUX_PROMPT}
+
 Configure UART For Boot Logs
     [Arguments]    ${uart}
 
@@ -339,3 +351,12 @@
 
     Wait For Services And Enter Shell   with_network=True
     Shell Should Handle Basic Commands
+
+Should Boot And Login
+    Create Multicore Machine
+
+    Boot Linux And Login
+
+    # Check if we see other CPUs
+    Write Line To Uart              nproc
+    Wait For Line On Uart           4
\ No newline at end of file