| /* |
| * SPAPR HV console |
| * |
| * Borrowed lightly from QEMU's spapr_vty.c, Copyright (c) 2010 David Gibson, |
| * IBM Corporation. |
| * |
| * Copyright (c) 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 as published |
| * by the Free Software Foundation. |
| */ |
| |
| #include "kvm/term.h" |
| #include "kvm/kvm.h" |
| #include "kvm/kvm-cpu.h" |
| #include "kvm/util.h" |
| #include "spapr.h" |
| #include "spapr_hvcons.h" |
| |
| #include <stdio.h> |
| #include <sys/uio.h> |
| #include <errno.h> |
| |
| #include <linux/byteorder.h> |
| |
| union hv_chario { |
| struct { |
| uint64_t char0_7; |
| uint64_t char8_15; |
| } a; |
| uint8_t buf[16]; |
| }; |
| |
| static unsigned long h_put_term_char(struct kvm_cpu *vcpu, unsigned long opcode, unsigned long *args) |
| { |
| /* To do: Read register from args[0], and check it. */ |
| unsigned long len = args[1]; |
| union hv_chario data; |
| struct iovec iov; |
| |
| if (len > 16) { |
| return H_PARAMETER; |
| } |
| data.a.char0_7 = cpu_to_be64(args[2]); |
| data.a.char8_15 = cpu_to_be64(args[3]); |
| |
| iov.iov_base = data.buf; |
| iov.iov_len = len; |
| do { |
| int ret; |
| |
| ret = term_putc_iov(&iov, 1, 0); |
| if (ret < 0) { |
| die("term_putc_iov error %d!\n", errno); |
| } |
| iov.iov_base += ret; |
| iov.iov_len -= ret; |
| } while (iov.iov_len > 0); |
| |
| return H_SUCCESS; |
| } |
| |
| |
| static unsigned long h_get_term_char(struct kvm_cpu *vcpu, unsigned long opcode, unsigned long *args) |
| { |
| /* To do: Read register from args[0], and check it. */ |
| unsigned long *len = args + 0; |
| unsigned long *char0_7 = args + 1; |
| unsigned long *char8_15 = args + 2; |
| union hv_chario data; |
| struct iovec iov; |
| |
| if (vcpu->kvm->cfg.active_console != CONSOLE_HV) |
| return H_SUCCESS; |
| |
| if (term_readable(0)) { |
| iov.iov_base = data.buf; |
| iov.iov_len = 16; |
| |
| *len = term_getc_iov(vcpu->kvm, &iov, 1, 0); |
| *char0_7 = be64_to_cpu(data.a.char0_7); |
| *char8_15 = be64_to_cpu(data.a.char8_15); |
| } else { |
| *len = 0; |
| } |
| |
| return H_SUCCESS; |
| } |
| |
| void spapr_hvcons_poll(struct kvm *kvm) |
| { |
| if (term_readable(0)) { |
| /* |
| * We can inject an IRQ to guest here if we want. The guest |
| * will happily poll, though, so not required. |
| */ |
| } |
| } |
| |
| void spapr_hvcons_init(void) |
| { |
| spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); |
| spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); |
| } |