semihosting: Create semihost_sys_poll_one
This will be used for implementing the xtensa select_one system call. Choose "poll" over "select" so that we can reuse Glib's g_poll constants and to avoid struct timeval. Reviewed-by: Luc Michel <lmichel@kalray.eu> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
2d010c2719
commit
1b9177f749
@ -53,4 +53,20 @@ int qemu_semihosting_console_write(void *buf, int len);
|
|||||||
*/
|
*/
|
||||||
int qemu_semihosting_log_out(const char *s, int len);
|
int qemu_semihosting_log_out(const char *s, int len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* qemu_semihosting_console_block_until_ready:
|
||||||
|
* @cs: CPUState
|
||||||
|
*
|
||||||
|
* If no data is available we suspend the CPU and will re-execute the
|
||||||
|
* instruction when data is available.
|
||||||
|
*/
|
||||||
|
void qemu_semihosting_console_block_until_ready(CPUState *cs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qemu_semihosting_console_ready:
|
||||||
|
*
|
||||||
|
* Return true if characters are available for read; does not block.
|
||||||
|
*/
|
||||||
|
bool qemu_semihosting_console_ready(void);
|
||||||
|
|
||||||
#endif /* SEMIHOST_CONSOLE_H */
|
#endif /* SEMIHOST_CONSOLE_H */
|
||||||
|
@ -69,4 +69,7 @@ void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
|
|||||||
void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
|
void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||||
target_ulong tv_addr, target_ulong tz_addr);
|
target_ulong tv_addr, target_ulong tz_addr);
|
||||||
|
|
||||||
|
void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||||
|
int fd, GIOCondition cond, int timeout);
|
||||||
|
|
||||||
#endif /* SEMIHOSTING_SYSCALLS_H */
|
#endif /* SEMIHOSTING_SYSCALLS_H */
|
||||||
|
@ -77,10 +77,17 @@ static void console_read(void *opaque, const uint8_t *buf, int size)
|
|||||||
c->sleeping_cpus = NULL;
|
c->sleeping_cpus = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
|
bool qemu_semihosting_console_ready(void)
|
||||||
|
{
|
||||||
|
SemihostingConsole *c = &console;
|
||||||
|
|
||||||
|
g_assert(qemu_mutex_iothread_locked());
|
||||||
|
return !fifo8_is_empty(&c->fifo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_semihosting_console_block_until_ready(CPUState *cs)
|
||||||
{
|
{
|
||||||
SemihostingConsole *c = &console;
|
SemihostingConsole *c = &console;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
g_assert(qemu_mutex_iothread_locked());
|
g_assert(qemu_mutex_iothread_locked());
|
||||||
|
|
||||||
@ -92,6 +99,14 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
|
|||||||
cpu_loop_exit(cs);
|
cpu_loop_exit(cs);
|
||||||
/* never returns */
|
/* never returns */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
|
||||||
|
{
|
||||||
|
SemihostingConsole *c = &console;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
qemu_semihosting_console_block_until_ready(cs);
|
||||||
|
|
||||||
/* Read until buffer full or fifo exhausted. */
|
/* Read until buffer full or fifo exhausted. */
|
||||||
do {
|
do {
|
||||||
|
@ -520,6 +520,21 @@ static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
|
|||||||
unlock_user(p, tv_addr, sizeof(struct gdb_timeval));
|
unlock_user(p, tv_addr, sizeof(struct gdb_timeval));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||||
|
GuestFD *gf, GIOCondition cond, int timeout)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Since this is only used by xtensa in system mode, and stdio is
|
||||||
|
* handled through GuestFDConsole, and there are no semihosting
|
||||||
|
* system calls for sockets and the like, that means this descriptor
|
||||||
|
* must be a normal file. Normal files never block and are thus
|
||||||
|
* always ready.
|
||||||
|
*/
|
||||||
|
complete(cs, cond & (G_IO_IN | G_IO_OUT), 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Static file semihosting syscall implementations.
|
* Static file semihosting syscall implementations.
|
||||||
*/
|
*/
|
||||||
@ -628,6 +643,34 @@ static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
|
|||||||
complete(cs, ret ? -1 : 0, ret ? -ret : 0);
|
complete(cs, ret ? -1 : 0, ret ? -ret : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
static void console_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||||
|
GuestFD *gf, GIOCondition cond, int timeout)
|
||||||
|
{
|
||||||
|
/* The semihosting console does not support urgent data or errors. */
|
||||||
|
cond &= G_IO_IN | G_IO_OUT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since qemu_semihosting_console_write never blocks, we can
|
||||||
|
* consider output always ready -- leave G_IO_OUT alone.
|
||||||
|
* All that remains is to conditionally signal input ready.
|
||||||
|
* Since output ready causes an immediate return, only block
|
||||||
|
* for G_IO_IN alone.
|
||||||
|
*
|
||||||
|
* TODO: Implement proper timeout. For now, only support
|
||||||
|
* indefinite wait or immediate poll.
|
||||||
|
*/
|
||||||
|
if (cond == G_IO_IN && timeout < 0) {
|
||||||
|
qemu_semihosting_console_block_until_ready(cs);
|
||||||
|
/* We returned -- input must be ready. */
|
||||||
|
} else if ((cond & G_IO_IN) && !qemu_semihosting_console_ready()) {
|
||||||
|
cond &= ~G_IO_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
complete(cs, cond, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Syscall entry points.
|
* Syscall entry points.
|
||||||
*/
|
*/
|
||||||
@ -906,3 +949,30 @@ void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
|
|||||||
host_gettimeofday(cs, complete, tv_addr, tz_addr);
|
host_gettimeofday(cs, complete, tv_addr, tz_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||||
|
int fd, GIOCondition cond, int timeout)
|
||||||
|
{
|
||||||
|
GuestFD *gf = get_guestfd(fd);
|
||||||
|
|
||||||
|
if (!gf) {
|
||||||
|
complete(cs, G_IO_NVAL, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (gf->type) {
|
||||||
|
case GuestFDGDB:
|
||||||
|
complete(cs, G_IO_NVAL, 1);
|
||||||
|
break;
|
||||||
|
case GuestFDHost:
|
||||||
|
host_poll_one(cs, complete, gf, cond, timeout);
|
||||||
|
break;
|
||||||
|
case GuestFDConsole:
|
||||||
|
console_poll_one(cs, complete, gf, cond, timeout);
|
||||||
|
break;
|
||||||
|
case GuestFDStatic:
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user