diff --git a/docs/plat/qemu.rst b/docs/plat/qemu.rst index 4ebe64b85..a4c5bec71 100644 --- a/docs/plat/qemu.rst +++ b/docs/plat/qemu.rst @@ -10,6 +10,10 @@ loop to be released by normal world via PSCI. 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/include/lib/semihosting.h b/include/lib/semihosting.h index 006c7b750..24b030cfd 100644 --- a/include/lib/semihosting.h +++ b/include/lib/semihosting.h @@ -23,6 +23,7 @@ #define SEMIHOSTING_SYS_REMOVE 0x0E #define SEMIHOSTING_SYS_SYSTEM 0x12 #define SEMIHOSTING_SYS_ERRNO 0x13 +#define SEMIHOSTING_SYS_EXIT 0x18 #define FOPEN_MODE_R 0x0 #define FOPEN_MODE_RB 0x1 @@ -54,5 +55,6 @@ long semihosting_download_file(const char *file_name, void semihosting_write_char(char character); void semihosting_write_string(char *string); char semihosting_read_char(void); +void semihosting_exit(uint32_t reason, uint32_t subcode); #endif /* SEMIHOSTING_H */ diff --git a/lib/semihosting/semihosting.c b/lib/semihosting/semihosting.c index 051dd008b..60fc52a00 100644 --- a/lib/semihosting/semihosting.c +++ b/lib/semihosting/semihosting.c @@ -15,7 +15,7 @@ #endif long semihosting_call(unsigned long operation, - void *system_block_address); + uintptr_t system_block_address); typedef struct { const char *file_name; @@ -53,7 +53,7 @@ long semihosting_file_open(const char *file_name, size_t mode) open_block.name_length = strlen(file_name); return semihosting_call(SEMIHOSTING_SYS_OPEN, - (void *) &open_block); + (uintptr_t) &open_block); } long semihosting_file_seek(long file_handle, ssize_t offset) @@ -65,7 +65,7 @@ long semihosting_file_seek(long file_handle, ssize_t offset) seek_block.location = offset; result = semihosting_call(SEMIHOSTING_SYS_SEEK, - (void *) &seek_block); + (uintptr_t) &seek_block); if (result) result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0); @@ -86,7 +86,7 @@ long semihosting_file_read(long file_handle, size_t *length, uintptr_t buffer) read_block.length = *length; result = semihosting_call(SEMIHOSTING_SYS_READ, - (void *) &read_block); + (uintptr_t) &read_block); if (result == *length) { return -EINVAL; @@ -112,7 +112,7 @@ long semihosting_file_write(long file_handle, write_block.length = *length; result = semihosting_call(SEMIHOSTING_SYS_WRITE, - (void *) &write_block); + (uintptr_t) &write_block); *length = result; @@ -122,28 +122,28 @@ long semihosting_file_write(long file_handle, long semihosting_file_close(long file_handle) { return semihosting_call(SEMIHOSTING_SYS_CLOSE, - (void *) &file_handle); + (uintptr_t) &file_handle); } long semihosting_file_length(long file_handle) { return semihosting_call(SEMIHOSTING_SYS_FLEN, - (void *) &file_handle); + (uintptr_t) &file_handle); } char semihosting_read_char(void) { - return semihosting_call(SEMIHOSTING_SYS_READC, NULL); + return semihosting_call(SEMIHOSTING_SYS_READC, 0); } void semihosting_write_char(char character) { - semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character); + semihosting_call(SEMIHOSTING_SYS_WRITEC, (uintptr_t) &character); } void semihosting_write_string(char *string) { - semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string); + semihosting_call(SEMIHOSTING_SYS_WRITE0, (uintptr_t) string); } long semihosting_system(char *command_line) @@ -154,7 +154,7 @@ long semihosting_system(char *command_line) system_block.command_length = strlen(command_line); return semihosting_call(SEMIHOSTING_SYS_SYSTEM, - (void *) &system_block); + (uintptr_t) &system_block); } long semihosting_get_flen(const char *file_name) @@ -216,3 +216,15 @@ semihosting_fail: semihosting_file_close(file_handle); return ret; } + +void semihosting_exit(uint32_t reason, uint32_t subcode) +{ +#ifdef __aarch64__ + uint64_t parameters[] = {reason, subcode}; + + (void) semihosting_call(SEMIHOSTING_SYS_EXIT, (uintptr_t) ¶meters); +#else + /* The subcode is not supported on AArch32. */ + (void) semihosting_call(SEMIHOSTING_SYS_EXIT, reason); +#endif +} diff --git a/plat/qemu/common/qemu_bl2_setup.c b/plat/qemu/common/qemu_bl2_setup.c index 166d2454e..3e289fc6b 100644 --- a/plat/qemu/common/qemu_bl2_setup.c +++ b/plat/qemu/common/qemu_bl2_setup.c @@ -51,7 +51,7 @@ static void security_setup(void) 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 @@ static int qemu_bl2_handle_post_image_load(unsigned int image_id) * 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 @@ static int qemu_bl2_handle_post_image_load(unsigned int image_id) 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/common/qemu_pm.c b/plat/qemu/common/qemu_pm.c index a199688df..116211c51 100644 --- a/plat/qemu/common/qemu_pm.c +++ b/plat/qemu/common/qemu_pm.c @@ -10,10 +10,13 @@ #include #include #include +#include #include #include "qemu_private.h" +#define ADP_STOPPED_APPLICATION_EXIT 0x20026 + /* * The secure entry point to be used on warm reset. */ @@ -191,7 +194,8 @@ void qemu_pwr_domain_suspend_finish(const psci_power_state_t *target_state) ******************************************************************************/ static void __dead2 qemu_system_off(void) { - ERROR("QEMU System Off: operation not handled.\n"); + semihosting_exit(ADP_STOPPED_APPLICATION_EXIT, 0); + ERROR("QEMU System Off: semihosting call unexpectedly returned.\n"); panic(); } diff --git a/plat/qemu/qemu/platform.mk b/plat/qemu/qemu/platform.mk index 5fda2cd47..b95bf5a51 100644 --- a/plat/qemu/qemu/platform.mk +++ b/plat/qemu/qemu/platform.mk @@ -151,6 +151,8 @@ ifeq (${ARM_ARCH_MAJOR},8) BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ + lib/semihosting/semihosting.c \ + lib/semihosting/${ARCH}/semihosting_call.S \ plat/common/plat_psci_common.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_pm.c \ ${PLAT_QEMU_COMMON_PATH}/topology.c \ @@ -186,5 +188,13 @@ endif # 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 0d6047da1..51832d0ff 100644 --- a/plat/qemu/qemu_sbsa/platform.mk +++ b/plat/qemu/qemu_sbsa/platform.mk @@ -71,6 +71,8 @@ QEMU_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \ BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ + lib/semihosting/semihosting.c \ + lib/semihosting/${ARCH}/semihosting_call.S \ plat/common/plat_psci_common.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_pm.c \ ${PLAT_QEMU_COMMON_PATH}/topology.c \ @@ -97,5 +99,13 @@ PRELOADED_BL33_BASE ?= 0x10000000 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