···11+/*
22+ * Semihosting Console Support
33+ *
44+ * Copyright (c) 2015 Imagination Technologies
55+ * Copyright (c) 2019 Linaro Ltd
66+ *
77+ * This provides support for outputting to a semihosting console.
88+ *
99+ * While most semihosting implementations support reading and writing
1010+ * to arbitrary file descriptors we treat the console as something
1111+ * specifically for debugging interaction. This means messages can be
1212+ * re-directed to gdb (if currently being used to debug) or even
1313+ * re-directed elsewhere.
1414+ *
1515+ * SPDX-License-Identifier: GPL-2.0-or-later
1616+ */
1717+1818+#include "qemu/osdep.h"
1919+#include "cpu.h"
2020+#include "hw/semihosting/console.h"
2121+#include "exec/gdbstub.h"
2222+#include "qemu/log.h"
2323+2424+int qemu_semihosting_log_out(const char *s, int len)
2525+{
2626+ return write(STDERR_FILENO, s, len);
2727+}
2828+2929+/*
3030+ * A re-implementation of lock_user_string that we can use locally
3131+ * instead of relying on softmmu-semi. Hopefully we can deprecate that
3232+ * in time. We either copy len bytes if specified or until we find a NULL.
3333+ */
3434+static GString *copy_user_string(CPUArchState *env, target_ulong addr, int len)
3535+{
3636+ CPUState *cpu = ENV_GET_CPU(env);
3737+ GString *s = g_string_sized_new(len ? len : 128);
3838+ uint8_t c;
3939+ bool done;
4040+4141+ do {
4242+ if (cpu_memory_rw_debug(cpu, addr++, &c, 1, 0) == 0) {
4343+ s = g_string_append_c(s, c);
4444+ done = len ? s->len == len : c == 0;
4545+ } else {
4646+ qemu_log_mask(LOG_GUEST_ERROR,
4747+ "%s: passed inaccessible address " TARGET_FMT_lx,
4848+ __func__, addr);
4949+ done = true;
5050+ }
5151+ } while (!done);
5252+5353+ return s;
5454+}
5555+5656+static void semihosting_cb(CPUState *cs, target_ulong ret, target_ulong err)
5757+{
5858+ if (ret == (target_ulong) -1) {
5959+ qemu_log("%s: gdb console output failed ("TARGET_FMT_ld")",
6060+ __func__, err);
6161+ }
6262+}
6363+6464+int qemu_semihosting_console_out(CPUArchState *env, target_ulong addr, int len)
6565+{
6666+ GString *s = copy_user_string(env, addr, len);
6767+ int out = s->len;
6868+6969+ if (use_gdb_syscalls()) {
7070+ gdb_do_syscall(semihosting_cb, "write,2,%x,%x", addr, s->len);
7171+ } else {
7272+ out = qemu_semihosting_log_out(s->str, s->len);
7373+ }
7474+7575+ g_string_free(s, true);
7676+ return out;
7777+}
+38
include/hw/semihosting/console.h
···11+/*
22+ * Semihosting Console
33+ *
44+ * Copyright (c) 2019 Linaro Ltd
55+ *
66+ * SPDX-License-Identifier: GPL-2.0-or-later
77+ */
88+99+#ifndef _SEMIHOST_CONSOLE_H_
1010+#define _SEMIHOST_CONSOLE_H_
1111+1212+/**
1313+ * qemu_semihosting_console_out:
1414+ * @env: CPUArchState
1515+ * @s: host address of guest string
1616+ * @len: length of string or 0 (string is null terminated)
1717+ *
1818+ * Send a guest string to the debug console. This may be the remote
1919+ * gdb session if a softmmu guest is currently being debugged.
2020+ *
2121+ * Returns: number of bytes written.
2222+ */
2323+int qemu_semihosting_console_out(CPUArchState *env, target_ulong s, int len);
2424+2525+/**
2626+ * qemu_semihosting_log_out:
2727+ * @s: pointer to string
2828+ * @len: length of string
2929+ *
3030+ * Send a string to the debug output. Unlike console_out these strings
3131+ * can't be sent to a remote gdb instance as they don't exist in guest
3232+ * memory.
3333+ *
3434+ * Returns: number of bytes written
3535+ */
3636+int qemu_semihosting_log_out(const char *s, int len);
3737+3838+#endif /* _SEMIHOST_CONSOLE_H_ */