KVM/ARM Fixes for the Linux 3.11 release

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQEcBAABAgAGBQJSCF9GAAoJEEtpOizt6ddyQWYH/0tkZWu/wM3UZDmskyHBbeg1
 b4K6ll9g6ZVofaifeIjZsUtQRjYOqHKP1EKq82z7/bGCF0WyovNz3c4Yqg1zcZRr
 DYf2SH6euGYRIfN5f4ijbKIXyBn2aUMkE2WpwqHM8Z04UmRsz5L9IlvEJzI43Sjc
 aV7qxx9l95wgwwPmaHHm4wYqhA6FEGtIhGU3hyWF1zDKNHBNACMPTl7Tl+E8RWT2
 pjHMsOm9sRP8N+ElzhZ3mDHwA/u3ex2rUyHDO1/4oqzKEK+KxsA6HUNdu7Or0EN6
 BgBmScwjE6cyo1wBND8FerDvwK/hYC55nnG7Wm9lrtUvSIhtxunmhpxbaZTrPXw=
 =9RBK
 -----END PGP SIGNATURE-----

Merge tag 'kvm-arm-fixes-3.11' of git://git.linaro.org/people/cdall/linux-kvm-arm into kvm-master

KVM/ARM Fixes for the Linux 3.11 release
This commit is contained in:
Paolo Bonzini 2013-08-12 09:44:16 +02:00
commit c566ccfcb3
5 changed files with 44 additions and 30 deletions

View File

@ -146,7 +146,11 @@ static bool pm_fake(struct kvm_vcpu *vcpu,
#define access_pmintenclr pm_fake #define access_pmintenclr pm_fake
/* Architected CP15 registers. /* Architected CP15 registers.
* Important: Must be sorted ascending by CRn, CRM, Op1, Op2 * CRn denotes the primary register number, but is copied to the CRm in the
* user space API for 64-bit register access in line with the terminology used
* in the ARM ARM.
* Important: Must be sorted ascending by CRn, CRM, Op1, Op2 and with 64-bit
* registers preceding 32-bit ones.
*/ */
static const struct coproc_reg cp15_regs[] = { static const struct coproc_reg cp15_regs[] = {
/* CSSELR: swapped by interrupt.S. */ /* CSSELR: swapped by interrupt.S. */
@ -154,8 +158,8 @@ static const struct coproc_reg cp15_regs[] = {
NULL, reset_unknown, c0_CSSELR }, NULL, reset_unknown, c0_CSSELR },
/* TTBR0/TTBR1: swapped by interrupt.S. */ /* TTBR0/TTBR1: swapped by interrupt.S. */
{ CRm( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 }, { CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
{ CRm( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 }, { CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
/* TTBCR: swapped by interrupt.S. */ /* TTBCR: swapped by interrupt.S. */
{ CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32, { CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32,
@ -182,7 +186,7 @@ static const struct coproc_reg cp15_regs[] = {
NULL, reset_unknown, c6_IFAR }, NULL, reset_unknown, c6_IFAR },
/* PAR swapped by interrupt.S */ /* PAR swapped by interrupt.S */
{ CRn( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR }, { CRm64( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
/* /*
* DC{C,I,CI}SW operations: * DC{C,I,CI}SW operations:
@ -399,12 +403,13 @@ static bool index_to_params(u64 id, struct coproc_params *params)
| KVM_REG_ARM_OPC1_MASK)) | KVM_REG_ARM_OPC1_MASK))
return false; return false;
params->is_64bit = true; params->is_64bit = true;
params->CRm = ((id & KVM_REG_ARM_CRM_MASK) /* CRm to CRn: see cp15_to_index for details */
params->CRn = ((id & KVM_REG_ARM_CRM_MASK)
>> KVM_REG_ARM_CRM_SHIFT); >> KVM_REG_ARM_CRM_SHIFT);
params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK) params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK)
>> KVM_REG_ARM_OPC1_SHIFT); >> KVM_REG_ARM_OPC1_SHIFT);
params->Op2 = 0; params->Op2 = 0;
params->CRn = 0; params->CRm = 0;
return true; return true;
default: default:
return false; return false;
@ -898,7 +903,14 @@ static u64 cp15_to_index(const struct coproc_reg *reg)
if (reg->is_64) { if (reg->is_64) {
val |= KVM_REG_SIZE_U64; val |= KVM_REG_SIZE_U64;
val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT); val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT);
val |= (reg->CRm << KVM_REG_ARM_CRM_SHIFT); /*
* CRn always denotes the primary coproc. reg. nr. for the
* in-kernel representation, but the user space API uses the
* CRm for the encoding, because it is modelled after the
* MRRC/MCRR instructions: see the ARM ARM rev. c page
* B3-1445
*/
val |= (reg->CRn << KVM_REG_ARM_CRM_SHIFT);
} else { } else {
val |= KVM_REG_SIZE_U32; val |= KVM_REG_SIZE_U32;
val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT); val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT);

View File

@ -135,6 +135,8 @@ static inline int cmp_reg(const struct coproc_reg *i1,
return -1; return -1;
if (i1->CRn != i2->CRn) if (i1->CRn != i2->CRn)
return i1->CRn - i2->CRn; return i1->CRn - i2->CRn;
if (i1->is_64 != i2->is_64)
return i2->is_64 - i1->is_64;
if (i1->CRm != i2->CRm) if (i1->CRm != i2->CRm)
return i1->CRm - i2->CRm; return i1->CRm - i2->CRm;
if (i1->Op1 != i2->Op1) if (i1->Op1 != i2->Op1)
@ -145,6 +147,7 @@ static inline int cmp_reg(const struct coproc_reg *i1,
#define CRn(_x) .CRn = _x #define CRn(_x) .CRn = _x
#define CRm(_x) .CRm = _x #define CRm(_x) .CRm = _x
#define CRm64(_x) .CRn = _x, .CRm = 0
#define Op1(_x) .Op1 = _x #define Op1(_x) .Op1 = _x
#define Op2(_x) .Op2 = _x #define Op2(_x) .Op2 = _x
#define is64 .is_64 = true #define is64 .is_64 = true

View File

@ -114,7 +114,11 @@ static bool access_l2ectlr(struct kvm_vcpu *vcpu,
/* /*
* A15-specific CP15 registers. * A15-specific CP15 registers.
* Important: Must be sorted ascending by CRn, CRM, Op1, Op2 * CRn denotes the primary register number, but is copied to the CRm in the
* user space API for 64-bit register access in line with the terminology used
* in the ARM ARM.
* Important: Must be sorted ascending by CRn, CRM, Op1, Op2 and with 64-bit
* registers preceding 32-bit ones.
*/ */
static const struct coproc_reg a15_regs[] = { static const struct coproc_reg a15_regs[] = {
/* MPIDR: we use VMPIDR for guest access. */ /* MPIDR: we use VMPIDR for guest access. */

View File

@ -63,7 +63,8 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
struct kvm_exit_mmio *mmio) struct kvm_exit_mmio *mmio)
{ {
unsigned long rt, len; unsigned long rt;
int len;
bool is_write, sign_extend; bool is_write, sign_extend;
if (kvm_vcpu_dabt_isextabt(vcpu)) { if (kvm_vcpu_dabt_isextabt(vcpu)) {

View File

@ -85,6 +85,12 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc)
return p; return p;
} }
static bool page_empty(void *ptr)
{
struct page *ptr_page = virt_to_page(ptr);
return page_count(ptr_page) == 1;
}
static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr) static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr)
{ {
pmd_t *pmd_table = pmd_offset(pud, 0); pmd_t *pmd_table = pmd_offset(pud, 0);
@ -103,12 +109,6 @@ static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr)
put_page(virt_to_page(pmd)); put_page(virt_to_page(pmd));
} }
static bool pmd_empty(pmd_t *pmd)
{
struct page *pmd_page = virt_to_page(pmd);
return page_count(pmd_page) == 1;
}
static void clear_pte_entry(struct kvm *kvm, pte_t *pte, phys_addr_t addr) static void clear_pte_entry(struct kvm *kvm, pte_t *pte, phys_addr_t addr)
{ {
if (pte_present(*pte)) { if (pte_present(*pte)) {
@ -118,12 +118,6 @@ static void clear_pte_entry(struct kvm *kvm, pte_t *pte, phys_addr_t addr)
} }
} }
static bool pte_empty(pte_t *pte)
{
struct page *pte_page = virt_to_page(pte);
return page_count(pte_page) == 1;
}
static void unmap_range(struct kvm *kvm, pgd_t *pgdp, static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
unsigned long long start, u64 size) unsigned long long start, u64 size)
{ {
@ -132,37 +126,37 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
pmd_t *pmd; pmd_t *pmd;
pte_t *pte; pte_t *pte;
unsigned long long addr = start, end = start + size; unsigned long long addr = start, end = start + size;
u64 range; u64 next;
while (addr < end) { while (addr < end) {
pgd = pgdp + pgd_index(addr); pgd = pgdp + pgd_index(addr);
pud = pud_offset(pgd, addr); pud = pud_offset(pgd, addr);
if (pud_none(*pud)) { if (pud_none(*pud)) {
addr += PUD_SIZE; addr = pud_addr_end(addr, end);
continue; continue;
} }
pmd = pmd_offset(pud, addr); pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd)) { if (pmd_none(*pmd)) {
addr += PMD_SIZE; addr = pmd_addr_end(addr, end);
continue; continue;
} }
pte = pte_offset_kernel(pmd, addr); pte = pte_offset_kernel(pmd, addr);
clear_pte_entry(kvm, pte, addr); clear_pte_entry(kvm, pte, addr);
range = PAGE_SIZE; next = addr + PAGE_SIZE;
/* If we emptied the pte, walk back up the ladder */ /* If we emptied the pte, walk back up the ladder */
if (pte_empty(pte)) { if (page_empty(pte)) {
clear_pmd_entry(kvm, pmd, addr); clear_pmd_entry(kvm, pmd, addr);
range = PMD_SIZE; next = pmd_addr_end(addr, end);
if (pmd_empty(pmd)) { if (page_empty(pmd) && !page_empty(pud)) {
clear_pud_entry(kvm, pud, addr); clear_pud_entry(kvm, pud, addr);
range = PUD_SIZE; next = pud_addr_end(addr, end);
} }
} }
addr += range; addr = next;
} }
} }