semihosting: Expand qemu_semihosting_console_inc to read

Allow more than one character to be read at one time.
Will be used by m68k and nios2 semihosting for stdio.

Reviewed-by: Luc Michel <lmichel@kalray.eu>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2022-05-01 12:31:08 -07:00
parent 3367d452b0
commit e7fb6f3205
4 changed files with 34 additions and 15 deletions

View File

@ -38,19 +38,21 @@ int qemu_semihosting_console_outs(CPUArchState *env, target_ulong s);
void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c); void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
/** /**
* qemu_semihosting_console_inc: * qemu_semihosting_console_read:
* @cs: CPUState * @cs: CPUState
* @buf: host buffer
* @len: buffer size
* *
* Receive single character from debug console. As this call may block * Receive at least one character from debug console. As this call may
* if no data is available we suspend the CPU and will re-execute the * 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: * instruction when data is there. Therefore two conditions must be met:
* *
* - CPUState is synchronized before calling this function * - CPUState is synchronized before calling this function
* - pc is only updated once the character is successfully returned * - 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: * qemu_semihosting_log_out:

View File

@ -56,21 +56,23 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
* program is expecting more normal behaviour. This is slow but * program is expecting more normal behaviour. This is slow but
* nothing using semihosting console reading is expecting to be fast. * 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; struct termios old_tio, new_tio;
/* Disable line-buffering and echo */ /* Disable line-buffering and echo */
tcgetattr(STDIN_FILENO, &old_tio); tcgetattr(STDIN_FILENO, &old_tio);
new_tio = old_tio; new_tio = old_tio;
new_tio.c_lflag &= (~ICANON & ~ECHO); new_tio.c_lflag &= (~ICANON & ~ECHO);
new_tio.c_cc[VMIN] = 1;
new_tio.c_cc[VTIME] = 0;
tcsetattr(STDIN_FILENO, TCSANOW, &new_tio); tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
c = getchar(); ret = fread(buf, 1, len, stdin);
/* restore config */ /* restore config */
tcsetattr(STDIN_FILENO, TCSANOW, &old_tio); tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
return (target_ulong) c; return ret;
} }

View File

@ -428,8 +428,15 @@ void do_common_semihosting(CPUState *cs)
break; break;
case TARGET_SYS_READC: 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; break;
case TARGET_SYS_ISERROR: case TARGET_SYS_ISERROR:

View File

@ -144,12 +144,14 @@ static void console_read(void *opaque, const uint8_t *buf, int size)
c->sleeping_cpus = NULL; 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; SemihostingConsole *c = &console;
int ret = 0;
g_assert(qemu_mutex_iothread_locked()); g_assert(qemu_mutex_iothread_locked());
/* Block if the fifo is completely empty. */
if (fifo8_is_empty(&c->fifo)) { if (fifo8_is_empty(&c->fifo)) {
c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, cs); c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, cs);
cs->halted = 1; cs->halted = 1;
@ -157,8 +159,14 @@ target_ulong qemu_semihosting_console_inc(CPUState *cs)
cpu_loop_exit(cs); cpu_loop_exit(cs);
/* never returns */ /* 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) void qemu_semihosting_console_init(void)