Skip to content

Commit

Permalink
Merge tag 'signed-for-3.16' of git://github.com/agraf/linux-2.6 into …
Browse files Browse the repository at this point in the history
…kvm-master

Patch queue for 3.16 - 2014-07-08

A few bug fixes to make 3.16 work well with KVM on PowerPC:

  - Fix ppc32 module builds
  - Fix Little Endian hosts
  - Fix Book3S HV HPTE lookup with huge pages in guest
  - Fix BookE lock leak
  • Loading branch information
bonzini committed Jul 8, 2014
2 parents 9242b5b + 19a44ec commit bb18b52
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 58 deletions.
19 changes: 17 additions & 2 deletions arch/powerpc/include/asm/kvm_book3s_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,10 @@ static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
return rb;
}

static inline unsigned long hpte_page_size(unsigned long h, unsigned long l)
static inline unsigned long __hpte_page_size(unsigned long h, unsigned long l,
bool is_base_size)
{

int size, a_psize;
/* Look at the 8 bit LP value */
unsigned int lp = (l >> LP_SHIFT) & ((1 << LP_BITS) - 1);
Expand All @@ -214,14 +216,27 @@ static inline unsigned long hpte_page_size(unsigned long h, unsigned long l)
continue;

a_psize = __hpte_actual_psize(lp, size);
if (a_psize != -1)
if (a_psize != -1) {
if (is_base_size)
return 1ul << mmu_psize_defs[size].shift;
return 1ul << mmu_psize_defs[a_psize].shift;
}
}

}
return 0;
}

static inline unsigned long hpte_page_size(unsigned long h, unsigned long l)
{
return __hpte_page_size(h, l, 0);
}

static inline unsigned long hpte_base_page_size(unsigned long h, unsigned long l)
{
return __hpte_page_size(h, l, 1);
}

static inline unsigned long hpte_rpn(unsigned long ptel, unsigned long psize)
{
return ((ptel & HPTE_R_RPN) & ~(psize - 1)) >> PAGE_SHIFT;
Expand Down
2 changes: 2 additions & 0 deletions arch/powerpc/include/asm/ppc_asm.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ GLUE(.,name):
.globl n; \
n:

#define _GLOBAL_TOC(name) _GLOBAL(name)

#define _KPROBE(n) \
.section ".kprobes.text","a"; \
.globl n; \
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/kvm/book3s_64_mmu_hv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1562,7 +1562,7 @@ static ssize_t kvm_htab_write(struct file *file, const char __user *buf,
goto out;
}
if (!rma_setup && is_vrma_hpte(v)) {
unsigned long psize = hpte_page_size(v, r);
unsigned long psize = hpte_base_page_size(v, r);
unsigned long senc = slb_pgsize_encoding(psize);
unsigned long lpcr;

Expand Down
7 changes: 2 additions & 5 deletions arch/powerpc/kvm/book3s_hv_rm_mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -814,13 +814,10 @@ long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr, unsigned long slb_v,
r = hpte[i+1];

/*
* Check the HPTE again, including large page size
* Since we don't currently allow any MPSS (mixed
* page-size segment) page sizes, it is sufficient
* to check against the actual page size.
* Check the HPTE again, including base page size
*/
if ((v & valid) && (v & mask) == val &&
hpte_page_size(v, r) == (1ul << pshift))
hpte_base_page_size(v, r) == (1ul << pshift))
/* Return with the HPTE still locked */
return (hash << 3) + (i >> 1);

Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/kvm/book3s_hv_rmhandlers.S
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
*
* LR = return address to continue at after eventually re-enabling MMU
*/
_GLOBAL(kvmppc_hv_entry_trampoline)
_GLOBAL_TOC(kvmppc_hv_entry_trampoline)
mflr r0
std r0, PPC_LR_STKOFF(r1)
stdu r1, -112(r1)
Expand Down
4 changes: 4 additions & 0 deletions arch/powerpc/kvm/book3s_interrupts.S
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@
#include <asm/exception-64s.h>

#if defined(CONFIG_PPC_BOOK3S_64)
#if defined(_CALL_ELF) && _CALL_ELF == 2
#define FUNC(name) name
#else
#define FUNC(name) GLUE(.,name)
#endif
#define GET_SHADOW_VCPU(reg) addi reg, r13, PACA_SVCPU

#elif defined(CONFIG_PPC_BOOK3S_32)
Expand Down
6 changes: 5 additions & 1 deletion arch/powerpc/kvm/book3s_rmhandlers.S
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@

#if defined(CONFIG_PPC_BOOK3S_64)

#if defined(_CALL_ELF) && _CALL_ELF == 2
#define FUNC(name) name
#else
#define FUNC(name) GLUE(.,name)
#endif

#elif defined(CONFIG_PPC_BOOK3S_32)

Expand Down Expand Up @@ -146,7 +150,7 @@ kvmppc_handler_skip_ins:
* On entry, r4 contains the guest shadow MSR
* MSR.EE has to be 0 when calling this function
*/
_GLOBAL(kvmppc_entry_trampoline)
_GLOBAL_TOC(kvmppc_entry_trampoline)
mfmsr r5
LOAD_REG_ADDR(r7, kvmppc_handler_trampoline_enter)
toreal(r7)
Expand Down
65 changes: 18 additions & 47 deletions arch/powerpc/kvm/book3s_rtas.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,33 @@ static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
u32 irq, server, priority;
int rc;

if (args->nargs != 3 || args->nret != 1) {
if (be32_to_cpu(args->nargs) != 3 || be32_to_cpu(args->nret) != 1) {
rc = -3;
goto out;
}

irq = args->args[0];
server = args->args[1];
priority = args->args[2];
irq = be32_to_cpu(args->args[0]);
server = be32_to_cpu(args->args[1]);
priority = be32_to_cpu(args->args[2]);

rc = kvmppc_xics_set_xive(vcpu->kvm, irq, server, priority);
if (rc)
rc = -3;
out:
args->rets[0] = rc;
args->rets[0] = cpu_to_be32(rc);
}

static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
{
u32 irq, server, priority;
int rc;

if (args->nargs != 1 || args->nret != 3) {
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 3) {
rc = -3;
goto out;
}

irq = args->args[0];
irq = be32_to_cpu(args->args[0]);

server = priority = 0;
rc = kvmppc_xics_get_xive(vcpu->kvm, irq, &server, &priority);
Expand All @@ -58,48 +58,48 @@ static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
goto out;
}

args->rets[1] = server;
args->rets[2] = priority;
args->rets[1] = cpu_to_be32(server);
args->rets[2] = cpu_to_be32(priority);
out:
args->rets[0] = rc;
args->rets[0] = cpu_to_be32(rc);
}

static void kvm_rtas_int_off(struct kvm_vcpu *vcpu, struct rtas_args *args)
{
u32 irq;
int rc;

if (args->nargs != 1 || args->nret != 1) {
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
rc = -3;
goto out;
}

irq = args->args[0];
irq = be32_to_cpu(args->args[0]);

rc = kvmppc_xics_int_off(vcpu->kvm, irq);
if (rc)
rc = -3;
out:
args->rets[0] = rc;
args->rets[0] = cpu_to_be32(rc);
}

static void kvm_rtas_int_on(struct kvm_vcpu *vcpu, struct rtas_args *args)
{
u32 irq;
int rc;

if (args->nargs != 1 || args->nret != 1) {
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
rc = -3;
goto out;
}

irq = args->args[0];
irq = be32_to_cpu(args->args[0]);

rc = kvmppc_xics_int_on(vcpu->kvm, irq);
if (rc)
rc = -3;
out:
args->rets[0] = rc;
args->rets[0] = cpu_to_be32(rc);
}
#endif /* CONFIG_KVM_XICS */

Expand Down Expand Up @@ -205,32 +205,6 @@ int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp)
return rc;
}

static void kvmppc_rtas_swap_endian_in(struct rtas_args *args)
{
#ifdef __LITTLE_ENDIAN__
int i;

args->token = be32_to_cpu(args->token);
args->nargs = be32_to_cpu(args->nargs);
args->nret = be32_to_cpu(args->nret);
for (i = 0; i < args->nargs; i++)
args->args[i] = be32_to_cpu(args->args[i]);
#endif
}

static void kvmppc_rtas_swap_endian_out(struct rtas_args *args)
{
#ifdef __LITTLE_ENDIAN__
int i;

for (i = 0; i < args->nret; i++)
args->args[i] = cpu_to_be32(args->args[i]);
args->token = cpu_to_be32(args->token);
args->nargs = cpu_to_be32(args->nargs);
args->nret = cpu_to_be32(args->nret);
#endif
}

int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
{
struct rtas_token_definition *d;
Expand All @@ -249,22 +223,20 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
if (rc)
goto fail;

kvmppc_rtas_swap_endian_in(&args);

/*
* args->rets is a pointer into args->args. Now that we've
* copied args we need to fix it up to point into our copy,
* not the guest args. We also need to save the original
* value so we can restore it on the way out.
*/
orig_rets = args.rets;
args.rets = &args.args[args.nargs];
args.rets = &args.args[be32_to_cpu(args.nargs)];

mutex_lock(&vcpu->kvm->lock);

rc = -ENOENT;
list_for_each_entry(d, &vcpu->kvm->arch.rtas_tokens, list) {
if (d->token == args.token) {
if (d->token == be32_to_cpu(args.token)) {
d->handler->handler(vcpu, &args);
rc = 0;
break;
Expand All @@ -275,7 +247,6 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)

if (rc == 0) {
args.rets = orig_rets;
kvmppc_rtas_swap_endian_out(&args);
rc = kvm_write_guest(vcpu->kvm, args_phys, &args, sizeof(args));
if (rc)
goto fail;
Expand Down
3 changes: 2 additions & 1 deletion arch/powerpc/kvm/e500_mmu_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,8 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
if (printk_ratelimit())
pr_err("%s: pte not present: gfn %lx, pfn %lx\n",
__func__, (long)gfn, pfn);
return -EINVAL;
ret = -EINVAL;
goto out;
}
kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg);

Expand Down

0 comments on commit bb18b52

Please sign in to comment.