Fixes for ARM and aarch64.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.13 (GNU/Linux)
 
 iQIcBAABAgAGBQJSEoS0AAoJEBvWZb6bTYbyE/8P/izUr1XtKBqtVuqVBMewEkeB
 SBgvJ2w681f4d+1waVAEPqWVGKHDvSOQC54sG6Y3fWHKijKGLiQhLaY3Y1WaLlO1
 B+duREwCwHaApjrpYoKhkyGQVpgyIfHBVe8d2TM9Q2bRuYNZEEcOtfdXk+Qfr6WR
 2kN+67ivJzAXvjs0uuRyJtXXq9cemcOnngsAfBlJz+j6UbiEdQ3l569D3wQU1jS2
 lUxxCEdtBDKDXkJUbTYvtJNYR48caqVXhYBTjpmY04207iSHmacUytOXO3rRA3OL
 fFhm/QeKVZND0XrJDUOMFzosWdUVdP5Qd5PtYoV/gEydNJMMpPs+dFKv+RXzrWlm
 2S2PWbFlkFT8yM+xwh6uKnLQ1aj614dkK2vKlp9GwDuwWiaod71C8ouTJvanNHGt
 pWgktFlfD+npSc3QDeXG5QB78pTSeyJfZBeVvA+U/etX+vjdfFWZ3bHMScrAE4DX
 xsdvtfamo0m9v2yZsnKzRWtCQq9No5FRb/c31w7yUzSXNBtyNR0Vft9gmiLo4HYa
 FQ0wC2UPyaKbfYtX0orpWnN3u4vaylGw2HuzK+2Mwi2HL+AMI6Piu//nrTbqb/i+
 1a6OARWvv9BQdbcuzBqznUdcllbmRl94kA5zXPvAz0dOBPQFU4X/t6dkxxH+8JFj
 mA/c2PHEyOtuFDOoqZxE
 =RlHG
 -----END PGP SIGNATURE-----

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm

Pull kvm fixes from Paolo Bonzini:
 "Fixes for ARM and aarch64.

  This pull request is coming a bit later than I would have preferred,
  because I and Gleb happened to have holidays around the same weeks of
  August...  sorry about that"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: ARM: Squash len warning
  arm64: KVM: use 'int' instead of 'u32' for variable 'target' in kvm_host.h.
  arm64: KVM: add missing dsb before invalidating Stage-2 TLBs
  arm64: KVM: perform save/restore of PAR_EL1
  arm64: KVM: fix 2-level page tables unmapping
  ARM: KVM: Fix unaligned unmap_range leak
  ARM: KVM: Fix 64-bit coprocessor handling
This commit is contained in:
Linus Torvalds 2013-08-21 16:35:37 -07:00
commit 69bbe136a9
9 changed files with 71 additions and 38 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;
} }
} }

View File

@ -42,14 +42,15 @@
#define TPIDR_EL1 18 /* Thread ID, Privileged */ #define TPIDR_EL1 18 /* Thread ID, Privileged */
#define AMAIR_EL1 19 /* Aux Memory Attribute Indirection Register */ #define AMAIR_EL1 19 /* Aux Memory Attribute Indirection Register */
#define CNTKCTL_EL1 20 /* Timer Control Register (EL1) */ #define CNTKCTL_EL1 20 /* Timer Control Register (EL1) */
#define PAR_EL1 21 /* Physical Address Register */
/* 32bit specific registers. Keep them at the end of the range */ /* 32bit specific registers. Keep them at the end of the range */
#define DACR32_EL2 21 /* Domain Access Control Register */ #define DACR32_EL2 22 /* Domain Access Control Register */
#define IFSR32_EL2 22 /* Instruction Fault Status Register */ #define IFSR32_EL2 23 /* Instruction Fault Status Register */
#define FPEXC32_EL2 23 /* Floating-Point Exception Control Register */ #define FPEXC32_EL2 24 /* Floating-Point Exception Control Register */
#define DBGVCR32_EL2 24 /* Debug Vector Catch Register */ #define DBGVCR32_EL2 25 /* Debug Vector Catch Register */
#define TEECR32_EL1 25 /* ThumbEE Configuration Register */ #define TEECR32_EL1 26 /* ThumbEE Configuration Register */
#define TEEHBR32_EL1 26 /* ThumbEE Handler Base Register */ #define TEEHBR32_EL1 27 /* ThumbEE Handler Base Register */
#define NR_SYS_REGS 27 #define NR_SYS_REGS 28
/* 32bit mapping */ /* 32bit mapping */
#define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */ #define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
@ -69,6 +70,8 @@
#define c5_AIFSR (AFSR1_EL1 * 2) /* Auxiliary Instr Fault Status R */ #define c5_AIFSR (AFSR1_EL1 * 2) /* Auxiliary Instr Fault Status R */
#define c6_DFAR (FAR_EL1 * 2) /* Data Fault Address Register */ #define c6_DFAR (FAR_EL1 * 2) /* Data Fault Address Register */
#define c6_IFAR (c6_DFAR + 1) /* Instruction Fault Address Register */ #define c6_IFAR (c6_DFAR + 1) /* Instruction Fault Address Register */
#define c7_PAR (PAR_EL1 * 2) /* Physical Address Register */
#define c7_PAR_high (c7_PAR + 1) /* PAR top 32 bits */
#define c10_PRRR (MAIR_EL1 * 2) /* Primary Region Remap Register */ #define c10_PRRR (MAIR_EL1 * 2) /* Primary Region Remap Register */
#define c10_NMRR (c10_PRRR + 1) /* Normal Memory Remap Register */ #define c10_NMRR (c10_PRRR + 1) /* Normal Memory Remap Register */
#define c12_VBAR (VBAR_EL1 * 2) /* Vector Base Address Register */ #define c12_VBAR (VBAR_EL1 * 2) /* Vector Base Address Register */

View File

@ -129,7 +129,7 @@ struct kvm_vcpu_arch {
struct kvm_mmu_memory_cache mmu_page_cache; struct kvm_mmu_memory_cache mmu_page_cache;
/* Target CPU and feature flags */ /* Target CPU and feature flags */
u32 target; int target;
DECLARE_BITMAP(features, KVM_VCPU_MAX_FEATURES); DECLARE_BITMAP(features, KVM_VCPU_MAX_FEATURES);
/* Detect first run of a vcpu */ /* Detect first run of a vcpu */

View File

@ -214,6 +214,7 @@ __kvm_hyp_code_start:
mrs x21, tpidr_el1 mrs x21, tpidr_el1
mrs x22, amair_el1 mrs x22, amair_el1
mrs x23, cntkctl_el1 mrs x23, cntkctl_el1
mrs x24, par_el1
stp x4, x5, [x3] stp x4, x5, [x3]
stp x6, x7, [x3, #16] stp x6, x7, [x3, #16]
@ -225,6 +226,7 @@ __kvm_hyp_code_start:
stp x18, x19, [x3, #112] stp x18, x19, [x3, #112]
stp x20, x21, [x3, #128] stp x20, x21, [x3, #128]
stp x22, x23, [x3, #144] stp x22, x23, [x3, #144]
str x24, [x3, #160]
.endm .endm
.macro restore_sysregs .macro restore_sysregs
@ -243,6 +245,7 @@ __kvm_hyp_code_start:
ldp x18, x19, [x3, #112] ldp x18, x19, [x3, #112]
ldp x20, x21, [x3, #128] ldp x20, x21, [x3, #128]
ldp x22, x23, [x3, #144] ldp x22, x23, [x3, #144]
ldr x24, [x3, #160]
msr vmpidr_el2, x4 msr vmpidr_el2, x4
msr csselr_el1, x5 msr csselr_el1, x5
@ -264,6 +267,7 @@ __kvm_hyp_code_start:
msr tpidr_el1, x21 msr tpidr_el1, x21
msr amair_el1, x22 msr amair_el1, x22
msr cntkctl_el1, x23 msr cntkctl_el1, x23
msr par_el1, x24
.endm .endm
.macro skip_32bit_state tmp, target .macro skip_32bit_state tmp, target
@ -600,6 +604,8 @@ END(__kvm_vcpu_run)
// void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa); // void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
ENTRY(__kvm_tlb_flush_vmid_ipa) ENTRY(__kvm_tlb_flush_vmid_ipa)
dsb ishst
kern_hyp_va x0 kern_hyp_va x0
ldr x2, [x0, #KVM_VTTBR] ldr x2, [x0, #KVM_VTTBR]
msr vttbr_el2, x2 msr vttbr_el2, x2
@ -621,6 +627,7 @@ ENTRY(__kvm_tlb_flush_vmid_ipa)
ENDPROC(__kvm_tlb_flush_vmid_ipa) ENDPROC(__kvm_tlb_flush_vmid_ipa)
ENTRY(__kvm_flush_vm_context) ENTRY(__kvm_flush_vm_context)
dsb ishst
tlbi alle1is tlbi alle1is
ic ialluis ic ialluis
dsb sy dsb sy
@ -753,6 +760,10 @@ el1_trap:
*/ */
tbnz x1, #7, 1f // S1PTW is set tbnz x1, #7, 1f // S1PTW is set
/* Preserve PAR_EL1 */
mrs x3, par_el1
push x3, xzr
/* /*
* Permission fault, HPFAR_EL2 is invalid. * Permission fault, HPFAR_EL2 is invalid.
* Resolve the IPA the hard way using the guest VA. * Resolve the IPA the hard way using the guest VA.
@ -766,6 +777,8 @@ el1_trap:
/* Read result */ /* Read result */
mrs x3, par_el1 mrs x3, par_el1
pop x0, xzr // Restore PAR_EL1 from the stack
msr par_el1, x0
tbnz x3, #0, 3f // Bail out if we failed the translation tbnz x3, #0, 3f // Bail out if we failed the translation
ubfx x3, x3, #12, #36 // Extract IPA ubfx x3, x3, #12, #36 // Extract IPA
lsl x3, x3, #4 // and present it like HPFAR lsl x3, x3, #4 // and present it like HPFAR

View File

@ -211,6 +211,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
/* FAR_EL1 */ /* FAR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000), { Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000),
NULL, reset_unknown, FAR_EL1 }, NULL, reset_unknown, FAR_EL1 },
/* PAR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b0111), CRm(0b0100), Op2(0b000),
NULL, reset_unknown, PAR_EL1 },
/* PMINTENSET_EL1 */ /* PMINTENSET_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001), { Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),