summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/semihosting/console.h12
-rw-r--r--linux-user/semihost.c10
-rw-r--r--semihosting/arm-compat-semi.c11
-rw-r--r--semihosting/console.c16
4 files changed, 34 insertions, 15 deletions
diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index 27f8e9ae2e..39dbf1b062 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -38,19 +38,21 @@ int qemu_semihosting_console_outs(CPUArchState *env, target_ulong s);
void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
/**
- * qemu_semihosting_console_inc:
+ * qemu_semihosting_console_read:
* @cs: CPUState
+ * @buf: host buffer
+ * @len: buffer size
*
- * Receive single character from debug console. As this call may block
- * if no data is available we suspend the CPU and will re-execute the
+ * Receive at least one character from debug console. As this call may
+ * block if no data is available we suspend the CPU and will re-execute the
* instruction when data is there. Therefore two conditions must be met:
*
* - CPUState is synchronized before calling this function
* - pc is only updated once the character is successfully returned
*
- * Returns: character read OR cpu_loop_exit!
+ * Returns: number of characters read, OR cpu_loop_exit!
*/
-target_ulong qemu_semihosting_console_inc(CPUState *cs);
+int qemu_semihosting_console_read(CPUState *cs, void *buf, int len);
/**
* qemu_semihosting_log_out:
diff --git a/linux-user/semihost.c b/linux-user/semihost.c
index f14c6ae21d..2029fb674c 100644
--- a/linux-user/semihost.c
+++ b/linux-user/semihost.c
@@ -56,21 +56,23 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
* program is expecting more normal behaviour. This is slow but
* nothing using semihosting console reading is expecting to be fast.
*/
-target_ulong qemu_semihosting_console_inc(CPUState *cs)
+int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
{
- uint8_t c;
+ int ret;
struct termios old_tio, new_tio;
/* Disable line-buffering and echo */
tcgetattr(STDIN_FILENO, &old_tio);
new_tio = old_tio;
new_tio.c_lflag &= (~ICANON & ~ECHO);
+ new_tio.c_cc[VMIN] = 1;
+ new_tio.c_cc[VTIME] = 0;
tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
- c = getchar();
+ ret = fread(buf, 1, len, stdin);
/* restore config */
tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
- return (target_ulong) c;
+ return ret;
}
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 40f3730778..fdb143ace8 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -428,8 +428,15 @@ void do_common_semihosting(CPUState *cs)
break;
case TARGET_SYS_READC:
- ret = qemu_semihosting_console_inc(cs);
- common_semi_set_ret(cs, ret);
+ {
+ uint8_t ch;
+ int ret = qemu_semihosting_console_read(cs, &ch, 1);
+ if (ret == 1) {
+ common_semi_cb(cs, ch, 0);
+ } else {
+ common_semi_cb(cs, -1, EIO);
+ }
+ }
break;
case TARGET_SYS_ISERROR:
diff --git a/semihosting/console.c b/semihosting/console.c
index 17ece6bdca..e5ac3f20ba 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -144,12 +144,14 @@ static void console_read(void *opaque, const uint8_t *buf, int size)
c->sleeping_cpus = NULL;
}
-target_ulong qemu_semihosting_console_inc(CPUState *cs)
+int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
{
- uint8_t ch;
SemihostingConsole *c = &console;
+ int ret = 0;
g_assert(qemu_mutex_iothread_locked());
+
+ /* Block if the fifo is completely empty. */
if (fifo8_is_empty(&c->fifo)) {
c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, cs);
cs->halted = 1;
@@ -157,8 +159,14 @@ target_ulong qemu_semihosting_console_inc(CPUState *cs)
cpu_loop_exit(cs);
/* never returns */
}
- ch = fifo8_pop(&c->fifo);
- return (target_ulong) ch;
+
+ /* Read until buffer full or fifo exhausted. */
+ do {
+ *(char *)(buf + ret) = fifo8_pop(&c->fifo);
+ ret++;
+ } while (ret < len && !fifo8_is_empty(&c->fifo));
+
+ return ret;
}
void qemu_semihosting_console_init(void)