mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-10-03 23:38:35 +00:00
kvm tools: Add SPAPR PPC64 HV console
This adds the console code, plus VIO HV terminal nodes are added to the device tree so the guest kernel will pick it up. Signed-off-by: Matt Evans <matt@ozlabs.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
@@ -136,6 +136,7 @@ ifeq ($(uname_M), ppc64)
|
||||
OBJS += powerpc/kvm-cpu.o
|
||||
OBJS += powerpc/spapr_hcall.o
|
||||
OBJS += powerpc/spapr_rtas.o
|
||||
OBJS += powerpc/spapr_hvcons.o
|
||||
# We use libfdt, but it's sometimes not packaged 64bit. It's small too,
|
||||
# so just build it in:
|
||||
CFLAGS += -I../../scripts/dtc/libfdt
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "cpu_info.h"
|
||||
|
||||
#include "spapr.h"
|
||||
#include "spapr_hvcons.h"
|
||||
|
||||
#include <linux/kvm.h>
|
||||
|
||||
@@ -133,6 +134,8 @@ void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size)
|
||||
/* FIXME: SPAPR-specific */
|
||||
hypercall_init();
|
||||
register_core_rtas();
|
||||
/* Now that hypercalls are initialised, register a couple for the console: */
|
||||
spapr_hvcons_init();
|
||||
}
|
||||
|
||||
void kvm__arch_delete_ram(struct kvm *kvm)
|
||||
@@ -151,6 +154,12 @@ void kvm__irq_trigger(struct kvm *kvm, int irq)
|
||||
kvm__irq_line(kvm, irq, 0);
|
||||
}
|
||||
|
||||
void kvm__arch_periodic_poll(struct kvm *kvm)
|
||||
{
|
||||
/* FIXME: Should register callbacks to platform-specific polls */
|
||||
spapr_hvcons_poll(kvm);
|
||||
}
|
||||
|
||||
int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline)
|
||||
{
|
||||
void *p;
|
||||
@@ -266,6 +275,13 @@ static void setup_fdt(struct kvm *kvm)
|
||||
_FDT(fdt_property(fdt, "linux,initrd-end",
|
||||
&ird_end_prop, sizeof(ird_end_prop)));
|
||||
}
|
||||
|
||||
/*
|
||||
* stdout-path: This is assuming we're using the HV console. Also, the
|
||||
* address is hardwired until we do a VIO bus.
|
||||
*/
|
||||
_FDT(fdt_property_string(fdt, "linux,stdout-path",
|
||||
"/vdevice/vty@30000000"));
|
||||
_FDT(fdt_end_node(fdt));
|
||||
|
||||
/*
|
||||
@@ -352,6 +368,23 @@ static void setup_fdt(struct kvm *kvm)
|
||||
}
|
||||
_FDT(fdt_end_node(fdt));
|
||||
|
||||
/*
|
||||
* VIO: See comment in linux,stdout-path; we don't yet represent a VIO
|
||||
* bus/address allocation so addresses are hardwired here.
|
||||
*/
|
||||
_FDT(fdt_begin_node(fdt, "vdevice"));
|
||||
_FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
|
||||
_FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
|
||||
_FDT(fdt_property_string(fdt, "device_type", "vdevice"));
|
||||
_FDT(fdt_property_string(fdt, "compatible", "IBM,vdevice"));
|
||||
_FDT(fdt_begin_node(fdt, "vty@30000000"));
|
||||
_FDT(fdt_property_string(fdt, "name", "vty"));
|
||||
_FDT(fdt_property_string(fdt, "device_type", "serial"));
|
||||
_FDT(fdt_property_string(fdt, "compatible", "hvterm1"));
|
||||
_FDT(fdt_property_cell(fdt, "reg", 0x30000000));
|
||||
_FDT(fdt_end_node(fdt));
|
||||
_FDT(fdt_end_node(fdt));
|
||||
|
||||
/* Finalise: */
|
||||
_FDT(fdt_end_node(fdt)); /* Root node */
|
||||
_FDT(fdt_finish(fdt));
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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(CONSOLE_HV, &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 (term_readable(CONSOLE_HV, 0)) {
|
||||
iov.iov_base = data.buf;
|
||||
iov.iov_len = 16;
|
||||
|
||||
*len = term_getc_iov(CONSOLE_HV, &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(CONSOLE_HV, 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);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPAPR HV console
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef spapr_hvcons_H
|
||||
#define spapr_hvcons_H
|
||||
|
||||
#include "kvm/kvm.h"
|
||||
|
||||
void spapr_hvcons_init(void);
|
||||
void spapr_hvcons_poll(struct kvm *kvm);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user