mirror of
https://github.com/torvalds/linux.git
synced 2024-11-01 01:31:44 +00:00
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:
commit
69bbe136a9
@ -146,7 +146,11 @@ static bool pm_fake(struct kvm_vcpu *vcpu,
|
||||
#define access_pmintenclr pm_fake
|
||||
|
||||
/* 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[] = {
|
||||
/* CSSELR: swapped by interrupt.S. */
|
||||
@ -154,8 +158,8 @@ static const struct coproc_reg cp15_regs[] = {
|
||||
NULL, reset_unknown, c0_CSSELR },
|
||||
|
||||
/* TTBR0/TTBR1: swapped by interrupt.S. */
|
||||
{ CRm( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
|
||||
{ CRm( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
|
||||
{ CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
|
||||
{ CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
|
||||
|
||||
/* TTBCR: swapped by interrupt.S. */
|
||||
{ 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 },
|
||||
|
||||
/* 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:
|
||||
@ -399,12 +403,13 @@ static bool index_to_params(u64 id, struct coproc_params *params)
|
||||
| KVM_REG_ARM_OPC1_MASK))
|
||||
return false;
|
||||
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);
|
||||
params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK)
|
||||
>> KVM_REG_ARM_OPC1_SHIFT);
|
||||
params->Op2 = 0;
|
||||
params->CRn = 0;
|
||||
params->CRm = 0;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -898,7 +903,14 @@ static u64 cp15_to_index(const struct coproc_reg *reg)
|
||||
if (reg->is_64) {
|
||||
val |= KVM_REG_SIZE_U64;
|
||||
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 {
|
||||
val |= KVM_REG_SIZE_U32;
|
||||
val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT);
|
||||
|
@ -135,6 +135,8 @@ static inline int cmp_reg(const struct coproc_reg *i1,
|
||||
return -1;
|
||||
if (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)
|
||||
return i1->CRm - i2->CRm;
|
||||
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 CRm(_x) .CRm = _x
|
||||
#define CRm64(_x) .CRn = _x, .CRm = 0
|
||||
#define Op1(_x) .Op1 = _x
|
||||
#define Op2(_x) .Op2 = _x
|
||||
#define is64 .is_64 = true
|
||||
|
@ -114,7 +114,11 @@ static bool access_l2ectlr(struct kvm_vcpu *vcpu,
|
||||
|
||||
/*
|
||||
* 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[] = {
|
||||
/* MPIDR: we use VMPIDR for guest access. */
|
||||
|
@ -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,
|
||||
struct kvm_exit_mmio *mmio)
|
||||
{
|
||||
unsigned long rt, len;
|
||||
unsigned long rt;
|
||||
int len;
|
||||
bool is_write, sign_extend;
|
||||
|
||||
if (kvm_vcpu_dabt_isextabt(vcpu)) {
|
||||
|
@ -85,6 +85,12 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc)
|
||||
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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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,
|
||||
unsigned long long start, u64 size)
|
||||
{
|
||||
@ -132,37 +126,37 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned long long addr = start, end = start + size;
|
||||
u64 range;
|
||||
u64 next;
|
||||
|
||||
while (addr < end) {
|
||||
pgd = pgdp + pgd_index(addr);
|
||||
pud = pud_offset(pgd, addr);
|
||||
if (pud_none(*pud)) {
|
||||
addr += PUD_SIZE;
|
||||
addr = pud_addr_end(addr, end);
|
||||
continue;
|
||||
}
|
||||
|
||||
pmd = pmd_offset(pud, addr);
|
||||
if (pmd_none(*pmd)) {
|
||||
addr += PMD_SIZE;
|
||||
addr = pmd_addr_end(addr, end);
|
||||
continue;
|
||||
}
|
||||
|
||||
pte = pte_offset_kernel(pmd, 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 (pte_empty(pte)) {
|
||||
if (page_empty(pte)) {
|
||||
clear_pmd_entry(kvm, pmd, addr);
|
||||
range = PMD_SIZE;
|
||||
if (pmd_empty(pmd)) {
|
||||
next = pmd_addr_end(addr, end);
|
||||
if (page_empty(pmd) && !page_empty(pud)) {
|
||||
clear_pud_entry(kvm, pud, addr);
|
||||
range = PUD_SIZE;
|
||||
next = pud_addr_end(addr, end);
|
||||
}
|
||||
}
|
||||
|
||||
addr += range;
|
||||
addr = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,14 +42,15 @@
|
||||
#define TPIDR_EL1 18 /* Thread ID, Privileged */
|
||||
#define AMAIR_EL1 19 /* Aux Memory Attribute Indirection Register */
|
||||
#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 */
|
||||
#define DACR32_EL2 21 /* Domain Access Control Register */
|
||||
#define IFSR32_EL2 22 /* Instruction Fault Status Register */
|
||||
#define FPEXC32_EL2 23 /* Floating-Point Exception Control Register */
|
||||
#define DBGVCR32_EL2 24 /* Debug Vector Catch Register */
|
||||
#define TEECR32_EL1 25 /* ThumbEE Configuration Register */
|
||||
#define TEEHBR32_EL1 26 /* ThumbEE Handler Base Register */
|
||||
#define NR_SYS_REGS 27
|
||||
#define DACR32_EL2 22 /* Domain Access Control Register */
|
||||
#define IFSR32_EL2 23 /* Instruction Fault Status Register */
|
||||
#define FPEXC32_EL2 24 /* Floating-Point Exception Control Register */
|
||||
#define DBGVCR32_EL2 25 /* Debug Vector Catch Register */
|
||||
#define TEECR32_EL1 26 /* ThumbEE Configuration Register */
|
||||
#define TEEHBR32_EL1 27 /* ThumbEE Handler Base Register */
|
||||
#define NR_SYS_REGS 28
|
||||
|
||||
/* 32bit mapping */
|
||||
#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 c6_DFAR (FAR_EL1 * 2) /* Data 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_NMRR (c10_PRRR + 1) /* Normal Memory Remap Register */
|
||||
#define c12_VBAR (VBAR_EL1 * 2) /* Vector Base Address Register */
|
||||
|
@ -129,7 +129,7 @@ struct kvm_vcpu_arch {
|
||||
struct kvm_mmu_memory_cache mmu_page_cache;
|
||||
|
||||
/* Target CPU and feature flags */
|
||||
u32 target;
|
||||
int target;
|
||||
DECLARE_BITMAP(features, KVM_VCPU_MAX_FEATURES);
|
||||
|
||||
/* Detect first run of a vcpu */
|
||||
|
@ -214,6 +214,7 @@ __kvm_hyp_code_start:
|
||||
mrs x21, tpidr_el1
|
||||
mrs x22, amair_el1
|
||||
mrs x23, cntkctl_el1
|
||||
mrs x24, par_el1
|
||||
|
||||
stp x4, x5, [x3]
|
||||
stp x6, x7, [x3, #16]
|
||||
@ -225,6 +226,7 @@ __kvm_hyp_code_start:
|
||||
stp x18, x19, [x3, #112]
|
||||
stp x20, x21, [x3, #128]
|
||||
stp x22, x23, [x3, #144]
|
||||
str x24, [x3, #160]
|
||||
.endm
|
||||
|
||||
.macro restore_sysregs
|
||||
@ -243,6 +245,7 @@ __kvm_hyp_code_start:
|
||||
ldp x18, x19, [x3, #112]
|
||||
ldp x20, x21, [x3, #128]
|
||||
ldp x22, x23, [x3, #144]
|
||||
ldr x24, [x3, #160]
|
||||
|
||||
msr vmpidr_el2, x4
|
||||
msr csselr_el1, x5
|
||||
@ -264,6 +267,7 @@ __kvm_hyp_code_start:
|
||||
msr tpidr_el1, x21
|
||||
msr amair_el1, x22
|
||||
msr cntkctl_el1, x23
|
||||
msr par_el1, x24
|
||||
.endm
|
||||
|
||||
.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);
|
||||
ENTRY(__kvm_tlb_flush_vmid_ipa)
|
||||
dsb ishst
|
||||
|
||||
kern_hyp_va x0
|
||||
ldr x2, [x0, #KVM_VTTBR]
|
||||
msr vttbr_el2, x2
|
||||
@ -621,6 +627,7 @@ ENTRY(__kvm_tlb_flush_vmid_ipa)
|
||||
ENDPROC(__kvm_tlb_flush_vmid_ipa)
|
||||
|
||||
ENTRY(__kvm_flush_vm_context)
|
||||
dsb ishst
|
||||
tlbi alle1is
|
||||
ic ialluis
|
||||
dsb sy
|
||||
@ -753,6 +760,10 @@ el1_trap:
|
||||
*/
|
||||
tbnz x1, #7, 1f // S1PTW is set
|
||||
|
||||
/* Preserve PAR_EL1 */
|
||||
mrs x3, par_el1
|
||||
push x3, xzr
|
||||
|
||||
/*
|
||||
* Permission fault, HPFAR_EL2 is invalid.
|
||||
* Resolve the IPA the hard way using the guest VA.
|
||||
@ -766,6 +777,8 @@ el1_trap:
|
||||
|
||||
/* Read result */
|
||||
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
|
||||
ubfx x3, x3, #12, #36 // Extract IPA
|
||||
lsl x3, x3, #4 // and present it like HPFAR
|
||||
|
@ -211,6 +211,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
/* FAR_EL1 */
|
||||
{ Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000),
|
||||
NULL, reset_unknown, FAR_EL1 },
|
||||
/* PAR_EL1 */
|
||||
{ Op0(0b11), Op1(0b000), CRn(0b0111), CRm(0b0100), Op2(0b000),
|
||||
NULL, reset_unknown, PAR_EL1 },
|
||||
|
||||
/* PMINTENSET_EL1 */
|
||||
{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
|
||||
|
Loading…
Reference in New Issue
Block a user