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);
/**
* 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:

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
* 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;
}

View file

@ -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:

View file

@ -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)