On Tue, Aug 09, 2011 at 06:39:29PM +0200, Alexander Graf wrote: > When running PR style KVM, we need to tell the kernel that we want > to run in PAPR mode now. This means that we need to pass some more > register information down and enable papr mode. We also need to align > the HTAB to htab_size boundary. > > Using this patch, -M pseries works with kvm even on non-hv kvm > implementations, as long as the preceding kernel patches are in. > > Signed-off-by: Alexander Graf <ag...@suse.de> > --- > hw/spapr.c | 14 ++++++++++++- > target-ppc/kvm.c | 53 > ++++++++++++++++++++++++++++++++++++++++++++++++++ > target-ppc/kvm_ppc.h | 5 ++++ > 3 files changed, 71 insertions(+), 1 deletions(-) > > diff --git a/hw/spapr.c b/hw/spapr.c > index 07b2165..d56697a 100644 > --- a/hw/spapr.c > +++ b/hw/spapr.c > @@ -38,6 +38,9 @@ > #include "hw/spapr_vio.h" > #include "hw/xics.h" > > +#include "kvm.h" > +#include "kvm_ppc.h" > + > #include <libfdt.h> > > #define KERNEL_LOAD_ADDR 0x00000000 > @@ -336,12 +339,21 @@ static void ppc_spapr_init(ram_addr_t ram_size, > * later we should probably make it scale to the size of guest > * RAM */ > spapr->htab_size = 1ULL << (pteg_shift + 7); > - spapr->htab = qemu_malloc(spapr->htab_size); > + spapr->htab = qemu_memalign(spapr->htab_size, spapr->htab_size); > > for (env = first_cpu; env != NULL; env = env->next_cpu) { > env->external_htab = spapr->htab; > env->htab_base = -1; > env->htab_mask = spapr->htab_size - 1; > + > + /* Tell KVM that we're in PAPR mode */ > + env->spr[SPR_SDR1] = (unsigned long)spapr->htab | > + ((pteg_shift + 7) - 18); > + env->spr[SPR_HIOR] = 0; > + > + if (kvm_enabled()) { > + kvmppc_set_papr(env); > + } > } > > filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); > diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c > index 219e7a7..02f958f 100644 > --- a/target-ppc/kvm.c > +++ b/target-ppc/kvm.c > @@ -29,6 +29,10 @@ > #include "cpu.h" > #include "device_tree.h" > > +#include "hw/sysbus.h" > +#include "hw/spapr.h" > +#include "hw/spapr_vio.h" > + > //#define DEBUG_KVM > > #ifdef DEBUG_KVM > @@ -455,6 +459,14 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run > *run) > dprintf("handle halt\n"); > ret = kvmppc_handle_halt(env); > break; > +#if defined(CONFIG_FDT) && defined(TARGET_PPC64)
We should hack up configure to give us a CONFIG_PSERIES variable, instead of duplicating this horrid logic in multiple places (especially since it will later become CONFIG_FDT && TARGET_PPC64 && CONFIG_IOMMU. > + case KVM_EXIT_PAPR_HCALL: > + dprintf("handle PAPR hypercall\n"); > + run->papr_hcall.ret = spapr_hypercall(env, run->papr_hcall.nr, > + run->papr_hcall.args); > + ret = 1; > + break; > +#endif > default: > fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); > ret = -1; > @@ -606,6 +618,47 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, > int buf_len) > return 0; > } > > +void kvmppc_set_papr(CPUState *env) > +{ > + struct kvm_enable_cap cap; > + struct kvm_sregs sregs; > + int ret; > + > + memset(&cap, 0, sizeof(cap)); > + cap.cap = KVM_CAP_PPC_PAPR; > + ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap); > + > + if (ret) { > + goto fail; > + } > + > + /* > + * XXX We set HIOR here. It really should be a qdev property of > + * the CPU node, but we don't have CPUs converted to qdev yet. > + * > + * Once we have qdev CPUs, move HIOR to a qdev property and > + * remove this chunk. > + */ > + memset(&sregs, 0, sizeof(sregs)); > + ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); > + if (ret) { > + goto fail; > + } > + > + sregs.u.s.flags |= KVM_SREGS_S_HIOR; > + sregs.u.s.hior = env->spr[SPR_HIOR]; > + sregs.u.s.sdr1 = env->spr[SPR_SDR1]; > + ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); > + if (ret) { > + goto fail; > + } > + > + return; > + > +fail: > + cpu_abort(env, "This KVM version does not support PAPR\n"); > +} > + > bool kvm_arch_stop_on_emulation_error(CPUState *env) > { > return true; > diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h > index 76f98d9..809b8b4 100644 > --- a/target-ppc/kvm_ppc.h > +++ b/target-ppc/kvm_ppc.h > @@ -17,6 +17,7 @@ uint32_t kvmppc_get_tbfreq(void); > uint64_t kvmppc_get_clockfreq(void); > int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); > int kvmppc_set_interrupt(CPUState *env, int irq, int level); > +void kvmppc_set_papr(CPUState *env); > > #else > > @@ -40,6 +41,10 @@ static inline int kvmppc_set_interrupt(CPUState *env, int > irq, int level) > return -1; > } > > +static void kvmppc_set_papr(CPUState *env) > +{ Shouldn't this have a cpu_error or assert or something, since it should never be called if !kvm_enabled(). > +} > + > #endif > > #ifndef CONFIG_KVM -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson