qemu: Implement qemu_system_off via semihosting.
This makes the PSCI SYSTEM_OFF call work on QEMU. It assumes that QEMU has semihosting enabled, but that is already assumed by the image loader. Signed-off-by: Andrew Walbran <qwandor@google.com> Change-Id: I0fb7cf7909262b675c3143efeac07f4d60730b03
This commit is contained in:
parent
74464d5b51
commit
61cbd41d79
|
@ -23,6 +23,7 @@
|
||||||
#define SEMIHOSTING_SYS_REMOVE 0x0E
|
#define SEMIHOSTING_SYS_REMOVE 0x0E
|
||||||
#define SEMIHOSTING_SYS_SYSTEM 0x12
|
#define SEMIHOSTING_SYS_SYSTEM 0x12
|
||||||
#define SEMIHOSTING_SYS_ERRNO 0x13
|
#define SEMIHOSTING_SYS_ERRNO 0x13
|
||||||
|
#define SEMIHOSTING_SYS_EXIT 0x18
|
||||||
|
|
||||||
#define FOPEN_MODE_R 0x0
|
#define FOPEN_MODE_R 0x0
|
||||||
#define FOPEN_MODE_RB 0x1
|
#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_char(char character);
|
||||||
void semihosting_write_string(char *string);
|
void semihosting_write_string(char *string);
|
||||||
char semihosting_read_char(void);
|
char semihosting_read_char(void);
|
||||||
|
void semihosting_exit(uint32_t reason, uint32_t subcode);
|
||||||
|
|
||||||
#endif /* SEMIHOSTING_H */
|
#endif /* SEMIHOSTING_H */
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
long semihosting_call(unsigned long operation,
|
long semihosting_call(unsigned long operation,
|
||||||
void *system_block_address);
|
uintptr_t system_block_address);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *file_name;
|
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);
|
open_block.name_length = strlen(file_name);
|
||||||
|
|
||||||
return semihosting_call(SEMIHOSTING_SYS_OPEN,
|
return semihosting_call(SEMIHOSTING_SYS_OPEN,
|
||||||
(void *) &open_block);
|
(uintptr_t) &open_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
long semihosting_file_seek(long file_handle, ssize_t offset)
|
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;
|
seek_block.location = offset;
|
||||||
|
|
||||||
result = semihosting_call(SEMIHOSTING_SYS_SEEK,
|
result = semihosting_call(SEMIHOSTING_SYS_SEEK,
|
||||||
(void *) &seek_block);
|
(uintptr_t) &seek_block);
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0);
|
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;
|
read_block.length = *length;
|
||||||
|
|
||||||
result = semihosting_call(SEMIHOSTING_SYS_READ,
|
result = semihosting_call(SEMIHOSTING_SYS_READ,
|
||||||
(void *) &read_block);
|
(uintptr_t) &read_block);
|
||||||
|
|
||||||
if (result == *length) {
|
if (result == *length) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -112,7 +112,7 @@ long semihosting_file_write(long file_handle,
|
||||||
write_block.length = *length;
|
write_block.length = *length;
|
||||||
|
|
||||||
result = semihosting_call(SEMIHOSTING_SYS_WRITE,
|
result = semihosting_call(SEMIHOSTING_SYS_WRITE,
|
||||||
(void *) &write_block);
|
(uintptr_t) &write_block);
|
||||||
|
|
||||||
*length = result;
|
*length = result;
|
||||||
|
|
||||||
|
@ -122,28 +122,28 @@ long semihosting_file_write(long file_handle,
|
||||||
long semihosting_file_close(long file_handle)
|
long semihosting_file_close(long file_handle)
|
||||||
{
|
{
|
||||||
return semihosting_call(SEMIHOSTING_SYS_CLOSE,
|
return semihosting_call(SEMIHOSTING_SYS_CLOSE,
|
||||||
(void *) &file_handle);
|
(uintptr_t) &file_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
long semihosting_file_length(long file_handle)
|
long semihosting_file_length(long file_handle)
|
||||||
{
|
{
|
||||||
return semihosting_call(SEMIHOSTING_SYS_FLEN,
|
return semihosting_call(SEMIHOSTING_SYS_FLEN,
|
||||||
(void *) &file_handle);
|
(uintptr_t) &file_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
char semihosting_read_char(void)
|
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)
|
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)
|
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)
|
long semihosting_system(char *command_line)
|
||||||
|
@ -154,7 +154,7 @@ long semihosting_system(char *command_line)
|
||||||
system_block.command_length = strlen(command_line);
|
system_block.command_length = strlen(command_line);
|
||||||
|
|
||||||
return semihosting_call(SEMIHOSTING_SYS_SYSTEM,
|
return semihosting_call(SEMIHOSTING_SYS_SYSTEM,
|
||||||
(void *) &system_block);
|
(uintptr_t) &system_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
long semihosting_get_flen(const char *file_name)
|
long semihosting_get_flen(const char *file_name)
|
||||||
|
@ -216,3 +216,15 @@ semihosting_fail:
|
||||||
semihosting_file_close(file_handle);
|
semihosting_file_close(file_handle);
|
||||||
return ret;
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -10,10 +10,13 @@
|
||||||
#include <arch_helpers.h>
|
#include <arch_helpers.h>
|
||||||
#include <common/debug.h>
|
#include <common/debug.h>
|
||||||
#include <lib/psci/psci.h>
|
#include <lib/psci/psci.h>
|
||||||
|
#include <lib/semihosting.h>
|
||||||
#include <plat/common/platform.h>
|
#include <plat/common/platform.h>
|
||||||
|
|
||||||
#include "qemu_private.h"
|
#include "qemu_private.h"
|
||||||
|
|
||||||
|
#define ADP_STOPPED_APPLICATION_EXIT 0x20026
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The secure entry point to be used on warm reset.
|
* 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)
|
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();
|
panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,8 @@ ifeq (${ARM_ARCH_MAJOR},8)
|
||||||
BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \
|
BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \
|
||||||
lib/cpus/aarch64/cortex_a53.S \
|
lib/cpus/aarch64/cortex_a53.S \
|
||||||
lib/cpus/aarch64/cortex_a57.S \
|
lib/cpus/aarch64/cortex_a57.S \
|
||||||
|
lib/semihosting/semihosting.c \
|
||||||
|
lib/semihosting/${ARCH}/semihosting_call.S \
|
||||||
plat/common/plat_psci_common.c \
|
plat/common/plat_psci_common.c \
|
||||||
${PLAT_QEMU_COMMON_PATH}/qemu_pm.c \
|
${PLAT_QEMU_COMMON_PATH}/qemu_pm.c \
|
||||||
${PLAT_QEMU_COMMON_PATH}/topology.c \
|
${PLAT_QEMU_COMMON_PATH}/topology.c \
|
||||||
|
|
|
@ -71,6 +71,8 @@ QEMU_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \
|
||||||
BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \
|
BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \
|
||||||
lib/cpus/aarch64/cortex_a53.S \
|
lib/cpus/aarch64/cortex_a53.S \
|
||||||
lib/cpus/aarch64/cortex_a57.S \
|
lib/cpus/aarch64/cortex_a57.S \
|
||||||
|
lib/semihosting/semihosting.c \
|
||||||
|
lib/semihosting/${ARCH}/semihosting_call.S \
|
||||||
plat/common/plat_psci_common.c \
|
plat/common/plat_psci_common.c \
|
||||||
${PLAT_QEMU_COMMON_PATH}/qemu_pm.c \
|
${PLAT_QEMU_COMMON_PATH}/qemu_pm.c \
|
||||||
${PLAT_QEMU_COMMON_PATH}/topology.c \
|
${PLAT_QEMU_COMMON_PATH}/topology.c \
|
||||||
|
|
Loading…
Reference in New Issue