diff --git a/hw/xtensa/sim.c b/hw/xtensa/sim.c index b27e28d802..5521e9184a 100644 --- a/hw/xtensa/sim.c +++ b/hw/xtensa/sim.c @@ -114,6 +114,9 @@ static void xtensa_sim_init(MachineState *machine) xtensa_create_memory_regions(&sysram, "xtensa.sysram"); } + if (serial_hds[0]) { + xtensa_sim_open_console(serial_hds[0]); + } if (kernel_filename) { uint64_t elf_entry; uint64_t elf_lowaddr; @@ -136,6 +139,7 @@ static void xtensa_sim_machine_init(MachineClass *mc) mc->is_default = true; mc->init = xtensa_sim_init; mc->max_cpus = 4; + mc->no_serial = 1; } DEFINE_MACHINE("sim", xtensa_sim_machine_init) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index ecca17d45d..ee29fb1a14 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -483,6 +483,7 @@ void xtensa_translate_init(void); void xtensa_breakpoint_handler(CPUState *cs); void xtensa_finalize_config(XtensaConfig *config); void xtensa_register_core(XtensaConfigList *node); +void xtensa_sim_open_console(Chardev *chr); void check_interrupts(CPUXtensaState *s); void xtensa_irq_init(CPUXtensaState *env); void *xtensa_get_extint(CPUXtensaState *env, unsigned extint); diff --git a/target/xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c index ffcaf8d0ac..32e2bd7f1d 100644 --- a/target/xtensa/xtensa-semi.c +++ b/target/xtensa/xtensa-semi.c @@ -27,9 +27,14 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "chardev/char-fe.h" #include "exec/helper-proto.h" #include "exec/semihost.h" +#include "qapi/error.h" #include "qemu/log.h" +#include "sysemu/sysemu.h" + +static CharBackend *xtensa_sim_console; enum { TARGET_SYS_exit = 1, @@ -148,6 +153,15 @@ static uint32_t errno_h2g(int host_errno) } } +void xtensa_sim_open_console(Chardev *chr) +{ + static CharBackend console; + + qemu_chr_fe_init(&console, chr, &error_abort); + qemu_chr_fe_set_handlers(&console, NULL, NULL, NULL, NULL, NULL, true); + xtensa_sim_console = &console; +} + void HELPER(simcall)(CPUXtensaState *env) { CPUState *cs = CPU(xtensa_env_get_cpu(env)); @@ -181,10 +195,25 @@ void HELPER(simcall)(CPUXtensaState *env) if (buf) { vaddr += io_sz; len -= io_sz; - io_done = is_write ? - write(fd, buf, io_sz) : - read(fd, buf, io_sz); - regs[3] = errno_h2g(errno); + if (fd < 3 && xtensa_sim_console) { + if (is_write && (fd == 1 || fd == 2)) { + io_done = qemu_chr_fe_write_all(xtensa_sim_console, + buf, io_sz); + regs[3] = errno_h2g(errno); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s fd %d is not supported with chardev console\n", + is_write ? + "writing to" : "reading from", fd); + io_done = -1; + regs[3] = TARGET_EBADF; + } + } else { + io_done = is_write ? + write(fd, buf, io_sz) : + read(fd, buf, io_sz); + regs[3] = errno_h2g(errno); + } if (io_done == -1) { error = true; io_done = 0; @@ -256,10 +285,6 @@ void HELPER(simcall)(CPUXtensaState *env) uint32_t target_tvv[2]; struct timeval tv = {0}; - fd_set fdset; - - FD_ZERO(&fdset); - FD_SET(fd, &fdset); if (target_tv) { cpu_memory_rw_debug(cs, target_tv, @@ -267,12 +292,25 @@ void HELPER(simcall)(CPUXtensaState *env) tv.tv_sec = (int32_t)tswap32(target_tvv[0]); tv.tv_usec = (int32_t)tswap32(target_tvv[1]); } - regs[2] = select(fd + 1, - rq == SELECT_ONE_READ ? &fdset : NULL, - rq == SELECT_ONE_WRITE ? &fdset : NULL, - rq == SELECT_ONE_EXCEPT ? &fdset : NULL, - target_tv ? &tv : NULL); - regs[3] = errno_h2g(errno); + if (fd < 3 && xtensa_sim_console) { + if ((fd == 1 || fd == 2) && rq == SELECT_ONE_WRITE) { + regs[2] = 1; + } else { + regs[2] = 0; + } + regs[3] = 0; + } else { + fd_set fdset; + + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + regs[2] = select(fd + 1, + rq == SELECT_ONE_READ ? &fdset : NULL, + rq == SELECT_ONE_WRITE ? &fdset : NULL, + rq == SELECT_ONE_EXCEPT ? &fdset : NULL, + target_tv ? &tv : NULL); + regs[3] = errno_h2g(errno); + } } break;