qemu: Support ARM_LINUX_KERNEL_AS_BL33 to pass FDT address.

This lets the Linux kernel or any other image which expects an FDT in x0 be
loaded directly as BL33 without a separate bootloader on QEMU.

Signed-off-by: Andrew Walbran <qwandor@google.com>
Change-Id: Ia8eb4710a3d97cdd877af3b8aae36a2de7cfc654
diff --git a/docs/plat/qemu.rst b/docs/plat/qemu.rst
index 4ebe64b..a4c5bec 100644
--- a/docs/plat/qemu.rst
+++ b/docs/plat/qemu.rst
@@ -10,6 +10,10 @@
 BL2 edits the Flattened Device Tree, FDT, generated by QEMU at run-time to
 add a node describing PSCI and also enable methods for the CPUs.
 
+If ``ARM_LINUX_KERNEL_AS_BL33`` is set to 1 then this FDT will be passed to BL33
+via register x0, as expected by a Linux kernel. This allows a Linux kernel image
+to be booted directly as BL33 rather than using a bootloader.
+
 An ARM64 defconfig v4.5 Linux kernel is known to boot, FDT doesn't need to be
 provided as it's generated by QEMU.
 
diff --git a/plat/qemu/common/qemu_bl2_setup.c b/plat/qemu/common/qemu_bl2_setup.c
index 166d245..3e289fc 100644
--- a/plat/qemu/common/qemu_bl2_setup.c
+++ b/plat/qemu/common/qemu_bl2_setup.c
@@ -51,7 +51,7 @@
 static void update_dt(void)
 {
 	int ret;
-	void *fdt = (void *)(uintptr_t)PLAT_QEMU_DT_BASE;
+	void *fdt = (void *)(uintptr_t)ARM_PRELOADED_DTB_BASE;
 
 	ret = fdt_open_into(fdt, fdt, PLAT_QEMU_DT_MAX_SIZE);
 	if (ret < 0) {
@@ -172,12 +172,12 @@
 		 * OP-TEE expect to receive DTB address in x2.
 		 * This will be copied into x2 by dispatcher.
 		 */
-		bl_mem_params->ep_info.args.arg3 = PLAT_QEMU_DT_BASE;
+		bl_mem_params->ep_info.args.arg3 = ARM_PRELOADED_DTB_BASE;
 #else /* case AARCH32_SP_OPTEE */
 		bl_mem_params->ep_info.args.arg0 =
 					bl_mem_params->ep_info.args.arg1;
 		bl_mem_params->ep_info.args.arg1 = 0;
-		bl_mem_params->ep_info.args.arg2 = PLAT_QEMU_DT_BASE;
+		bl_mem_params->ep_info.args.arg2 = ARM_PRELOADED_DTB_BASE;
 		bl_mem_params->ep_info.args.arg3 = 0;
 #endif
 #endif
@@ -192,8 +192,23 @@
 		pager_mem_params->ep_info.lr_svc = bl_mem_params->ep_info.pc;
 #endif
 
+#if ARM_LINUX_KERNEL_AS_BL33
+		/*
+		 * According to the file ``Documentation/arm64/booting.txt`` of
+		 * the Linux kernel tree, Linux expects the physical address of
+		 * the device tree blob (DTB) in x0, while x1-x3 are reserved
+		 * for future use and must be 0.
+		 */
+		bl_mem_params->ep_info.args.arg0 =
+			(u_register_t)ARM_PRELOADED_DTB_BASE;
+		bl_mem_params->ep_info.args.arg1 = 0U;
+		bl_mem_params->ep_info.args.arg2 = 0U;
+		bl_mem_params->ep_info.args.arg3 = 0U;
+#else
 		/* BL33 expects to receive the primary CPU MPID (through r0) */
 		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+#endif
+
 		bl_mem_params->ep_info.spsr = qemu_get_spsr_for_bl33_entry();
 		break;
 	default:
diff --git a/plat/qemu/qemu/platform.mk b/plat/qemu/qemu/platform.mk
index 5fda2cd..eaeb72c 100644
--- a/plat/qemu/qemu/platform.mk
+++ b/plat/qemu/qemu/platform.mk
@@ -186,5 +186,13 @@
 # Process flags
 $(eval $(call add_define,BL32_RAM_LOCATION_ID))
 
+# Don't have the Linux kernel as a BL33 image by default
+ARM_LINUX_KERNEL_AS_BL33	:=	0
+$(eval $(call assert_boolean,ARM_LINUX_KERNEL_AS_BL33))
+$(eval $(call add_define,ARM_LINUX_KERNEL_AS_BL33))
+
+ARM_PRELOADED_DTB_BASE := PLAT_QEMU_DT_BASE
+$(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
+
 # Do not enable SVE
 ENABLE_SVE_FOR_NS	:=	0
diff --git a/plat/qemu/qemu_sbsa/platform.mk b/plat/qemu/qemu_sbsa/platform.mk
index 0d6047d..f34c7e1 100644
--- a/plat/qemu/qemu_sbsa/platform.mk
+++ b/plat/qemu/qemu_sbsa/platform.mk
@@ -97,5 +97,13 @@
 BL32_RAM_LOCATION_ID	= SEC_SRAM_ID
 $(eval $(call add_define,BL32_RAM_LOCATION_ID))
 
+# Don't have the Linux kernel as a BL33 image by default
+ARM_LINUX_KERNEL_AS_BL33	:=	0
+$(eval $(call assert_boolean,ARM_LINUX_KERNEL_AS_BL33))
+$(eval $(call add_define,ARM_LINUX_KERNEL_AS_BL33))
+
+ARM_PRELOADED_DTB_BASE := PLAT_QEMU_DT_BASE
+$(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
+
 # Do not enable SVE
 ENABLE_SVE_FOR_NS	:= 0