mirror of https://gitlab.com/qemu-project/qemu
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:
parent
3367d452b0
commit
e7fb6f3205
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue