summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-09-10 13:43:54 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-09-10 13:43:54 +0100
commit7a7379aae55b17e0c9525b60d5cdee83769e7d3a (patch)
treeacb3f71c7779e94cad11b1900f2066a5fc7d0cee
parent05f7921b1d89aa8178d9d33e6ff8c7f592ebedc5 (diff)
semihosting tests: Add test of EXIT_EXTENDED
Add a minimal test of EXIT_EXTENDED if the implementation provides it. Since using it at all exits the test, this is not really possible to test properly in this single-binary test setup, so we just use it for the final exit-success if we can. Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--semihosting.c15
-rw-r--r--semihosting.h4
-rw-r--r--usertest.c22
3 files changed, 41 insertions, 0 deletions
diff --git a/semihosting.c b/semihosting.c
index 9c284af..7a0ee0c 100644
--- a/semihosting.c
+++ b/semihosting.c
@@ -176,6 +176,21 @@ void semi_exit(int subcode)
while(1); /* should not be reached */
}
+void semi_exit_extended(int subcode)
+{
+ /* If present, this always allows a subcode to be reported. */
+ struct {
+ intptr_t reason;
+ intptr_t subcode;
+ } args;
+
+ args.reason = REPORTEXC_REASON_APP_EXIT;
+ args.subcode = subcode;
+ __semi_call(SYS_EXIT_EXTENDED, &args);
+
+ while(1); /* should not be reached */
+}
+
void semi_fatal(char const *message)
{
semi_write0(message);
diff --git a/semihosting.h b/semihosting.h
index f8c4e7b..06cda8d 100644
--- a/semihosting.h
+++ b/semihosting.h
@@ -36,6 +36,7 @@
#define SYS_GET_CMDLINE 0x15
#define SYS_REPORTEXC 0x18
#define REPORTEXC_REASON_APP_EXIT 0x20026
+#define SYS_EXIT_EXTENDED 0x20
#define SEMIHOSTING_SVC 0x123456 /* SVC comment field for semihosting */
#define FEATURE_DETECT_FILE ":semihosting-features"
@@ -43,6 +44,8 @@
#define SHFB_MAGIC_1 0x48
#define SHFB_MAGIC_2 0x46
#define SHFB_MAGIC_3 0x42
+#define SH_EXT_EXIT_EXTENDED (1 << 0)
+#define SH_EXT_STDOUT_STDERR (1 << 1)
#ifndef __ASSEMBLER__
@@ -61,6 +64,7 @@ int semi_get_cmdline(char *buffer, int size, int *length);
int semi_reportexc(int reason, int subcode);
void semi_fatal(char const *message);
void semi_exit(int subcode);
+void semi_exit_extended(int subcode);
/*
* semi_load_file:
* On entry *dest should be the buffer to write the data to, and
diff --git a/usertest.c b/usertest.c
index de915b7..ce0f61d 100644
--- a/usertest.c
+++ b/usertest.c
@@ -43,6 +43,9 @@ const char file[] = "Small file of text data for test.\n";
#define TESTWRITE_FILE "tempdata.txt"
const char writedata[] = "Data to write to temporary file.\n";
+int has_exit_extended;
+int has_stdout_stderr;
+
static int test_istty(void)
{
int fd;
@@ -245,6 +248,20 @@ static int test_feature_detect(void)
semi_write0("PASS semihosting features file read successfully\n");
+ /* Capture the feature flags we care about here for later tests */
+ if (filebuf[4] & SH_EXT_EXIT_EXTENDED) {
+ semi_write0("INFO implementation supports EXIT_EXTENDED\n");
+ has_exit_extended++;
+ }
+ if (filebuf[4] & SH_EXT_STDOUT_STDERR) {
+ semi_write0("INFO implementation supports STDOUT_STDERR\n");
+ has_stdout_stderr++;
+ }
+ if (filebuf[4] & ~(SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR)) {
+ semi_write0("INFO implementation supports extensions "
+ "this test doesn't know about\n");
+ }
+
if (semi_istty(fd)) {
semi_write0("FAIL semihosting features file is a TTY?\n");
} else {
@@ -350,6 +367,11 @@ int main(void)
}
semi_write0("ALL TESTS PASSED\n");
+
+ /* If we have EXIT_EXTENDED then use it */
+ if (has_exit_extended) {
+ semi_exit_extended(0);
+ }
semi_exit(0);
/* not reached */
}