2012-12-10 23:35:24 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012,2013 - ARM Ltd
|
|
|
|
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __ARM64_KVM_MMU_H__
|
|
|
|
#define __ARM64_KVM_MMU_H__
|
|
|
|
|
|
|
|
#include <asm/page.h>
|
|
|
|
#include <asm/memory.h>
|
2015-11-16 19:28:18 +08:00
|
|
|
#include <asm/cpufeature.h>
|
2012-12-10 23:35:24 +08:00
|
|
|
|
|
|
|
/*
|
2015-01-29 21:50:34 +08:00
|
|
|
* As ARMv8.0 only has the TTBR0_EL2 register, we cannot express
|
2012-12-10 23:35:24 +08:00
|
|
|
* "negative" addresses. This makes it impossible to directly share
|
|
|
|
* mappings with the kernel.
|
|
|
|
*
|
|
|
|
* Instead, give the HYP mode its own VA region at a fixed offset from
|
|
|
|
* the kernel by just masking the top bits (which are all ones for a
|
2016-07-01 01:40:34 +08:00
|
|
|
* kernel address). We need to find out how many bits to mask.
|
2015-01-29 21:50:34 +08:00
|
|
|
*
|
2016-07-01 01:40:34 +08:00
|
|
|
* We want to build a set of page tables that cover both parts of the
|
|
|
|
* idmap (the trampoline page used to initialize EL2), and our normal
|
|
|
|
* runtime VA space, at the same time.
|
|
|
|
*
|
|
|
|
* Given that the kernel uses VA_BITS for its entire address space,
|
|
|
|
* and that half of that space (VA_BITS - 1) is used for the linear
|
|
|
|
* mapping, we can also limit the EL2 space to (VA_BITS - 1).
|
|
|
|
*
|
|
|
|
* The main question is "Within the VA_BITS space, does EL2 use the
|
|
|
|
* top or the bottom half of that space to shadow the kernel's linear
|
|
|
|
* mapping?". As we need to idmap the trampoline page, this is
|
|
|
|
* determined by the range in which this page lives.
|
|
|
|
*
|
|
|
|
* If the page is in the bottom half, we have to use the top half. If
|
|
|
|
* the page is in the top half, we have to use the bottom half:
|
|
|
|
*
|
|
|
|
* T = __virt_to_phys(__hyp_idmap_text_start)
|
|
|
|
* if (T & BIT(VA_BITS - 1))
|
|
|
|
* HYP_VA_MIN = 0 //idmap in upper half
|
|
|
|
* else
|
|
|
|
* HYP_VA_MIN = 1 << (VA_BITS - 1)
|
|
|
|
* HYP_VA_MAX = HYP_VA_MIN + (1 << (VA_BITS - 1)) - 1
|
|
|
|
*
|
|
|
|
* This of course assumes that the trampoline page exists within the
|
|
|
|
* VA_BITS range. If it doesn't, then it means we're in the odd case
|
|
|
|
* where the kernel idmap (as well as HYP) uses more levels than the
|
|
|
|
* kernel runtime page tables (as seen when the kernel is configured
|
|
|
|
* for 4k pages, 39bits VA, and yet memory lives just above that
|
|
|
|
* limit, forcing the idmap to use 4 levels of page tables while the
|
|
|
|
* kernel itself only uses 3). In this particular case, it doesn't
|
|
|
|
* matter which side of VA_BITS we use, as we're guaranteed not to
|
|
|
|
* conflict with anything.
|
|
|
|
*
|
|
|
|
* When using VHE, there are no separate hyp mappings and all KVM
|
|
|
|
* functionality is already mapped as part of the main kernel
|
|
|
|
* mappings, and none of this applies in that case.
|
2012-12-10 23:35:24 +08:00
|
|
|
*/
|
|
|
|
#define HYP_PAGE_OFFSET_SHIFT VA_BITS
|
|
|
|
#define HYP_PAGE_OFFSET_MASK ((UL(1) << HYP_PAGE_OFFSET_SHIFT) - 1)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Our virtual mapping for the idmap-ed MMU-enable code. Must be
|
|
|
|
* shared across all the page-tables. Conveniently, we use the last
|
|
|
|
* possible page, where no kernel mapping will ever exist.
|
|
|
|
*/
|
|
|
|
#define TRAMPOLINE_VA (HYP_PAGE_OFFSET_MASK & PAGE_MASK)
|
|
|
|
|
|
|
|
#ifdef __ASSEMBLY__
|
|
|
|
|
2015-01-29 21:50:34 +08:00
|
|
|
#include <asm/alternative.h>
|
|
|
|
#include <asm/cpufeature.h>
|
|
|
|
|
2012-12-10 23:35:24 +08:00
|
|
|
/*
|
|
|
|
* Convert a kernel VA into a HYP VA.
|
|
|
|
* reg: VA to be converted.
|
|
|
|
*/
|
|
|
|
.macro kern_hyp_va reg
|
2015-01-29 21:50:34 +08:00
|
|
|
alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
|
2012-12-10 23:35:24 +08:00
|
|
|
and \reg, \reg, #HYP_PAGE_OFFSET_MASK
|
2015-01-29 21:50:34 +08:00
|
|
|
alternative_else
|
|
|
|
nop
|
|
|
|
alternative_endif
|
2012-12-10 23:35:24 +08:00
|
|
|
.endm
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2014-10-10 18:14:28 +08:00
|
|
|
#include <asm/pgalloc.h>
|
2012-12-10 23:35:24 +08:00
|
|
|
#include <asm/cachetype.h>
|
|
|
|
#include <asm/cacheflush.h>
|
2015-03-20 00:42:28 +08:00
|
|
|
#include <asm/mmu_context.h>
|
|
|
|
#include <asm/pgtable.h>
|
2012-12-10 23:35:24 +08:00
|
|
|
|
2016-07-01 01:40:37 +08:00
|
|
|
#define KERN_TO_HYP(kva) ((unsigned long)kva & HYP_PAGE_OFFSET_MASK)
|
2012-12-10 23:35:24 +08:00
|
|
|
|
|
|
|
/*
|
2014-07-10 00:17:04 +08:00
|
|
|
* We currently only support a 40bit IPA.
|
2012-12-10 23:35:24 +08:00
|
|
|
*/
|
2014-07-10 00:17:04 +08:00
|
|
|
#define KVM_PHYS_SHIFT (40)
|
2012-12-10 23:35:24 +08:00
|
|
|
#define KVM_PHYS_SIZE (1UL << KVM_PHYS_SHIFT)
|
|
|
|
#define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1UL)
|
|
|
|
|
2016-03-22 22:16:52 +08:00
|
|
|
#include <asm/stage2_pgtable.h>
|
|
|
|
|
2016-06-13 22:00:45 +08:00
|
|
|
int create_hyp_mappings(void *from, void *to, pgprot_t prot);
|
2012-12-10 23:35:24 +08:00
|
|
|
int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
|
|
|
|
void free_boot_hyp_pgd(void);
|
|
|
|
void free_hyp_pgds(void);
|
|
|
|
|
2014-11-27 17:35:03 +08:00
|
|
|
void stage2_unmap_vm(struct kvm *kvm);
|
2012-12-10 23:35:24 +08:00
|
|
|
int kvm_alloc_stage2_pgd(struct kvm *kvm);
|
|
|
|
void kvm_free_stage2_pgd(struct kvm *kvm);
|
|
|
|
int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
|
2014-09-18 05:56:18 +08:00
|
|
|
phys_addr_t pa, unsigned long size, bool writable);
|
2012-12-10 23:35:24 +08:00
|
|
|
|
|
|
|
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
|
|
|
|
|
|
|
void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
|
|
|
|
|
|
|
|
phys_addr_t kvm_mmu_get_httbr(void);
|
|
|
|
phys_addr_t kvm_mmu_get_boot_httbr(void);
|
|
|
|
phys_addr_t kvm_get_idmap_vector(void);
|
arm64: kvm: allows kvm cpu hotplug
The current kvm implementation on arm64 does cpu-specific initialization
at system boot, and has no way to gracefully shutdown a core in terms of
kvm. This prevents kexec from rebooting the system at EL2.
This patch adds a cpu tear-down function and also puts an existing cpu-init
code into a separate function, kvm_arch_hardware_disable() and
kvm_arch_hardware_enable() respectively.
We don't need the arm64 specific cpu hotplug hook any more.
Since this patch modifies common code between arm and arm64, one stub
definition, __cpu_reset_hyp_mode(), is added on arm side to avoid
compilation errors.
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
[Rebase, added separate VHE init/exit path, changed resets use of
kvm_call_hyp() to the __version, en/disabled hardware in init_subsystems(),
added icache maintenance to __kvm_hyp_reset() and removed lr restore, removed
guest-enter after teardown handling]
Signed-off-by: James Morse <james.morse@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
2016-04-28 00:47:05 +08:00
|
|
|
phys_addr_t kvm_get_idmap_start(void);
|
2012-12-10 23:35:24 +08:00
|
|
|
int kvm_mmu_init(void);
|
|
|
|
void kvm_clear_hyp_idmap(void);
|
|
|
|
|
|
|
|
#define kvm_set_pte(ptep, pte) set_pte(ptep, pte)
|
2012-11-02 00:14:45 +08:00
|
|
|
#define kvm_set_pmd(pmdp, pmd) set_pmd(pmdp, pmd)
|
2012-12-10 23:35:24 +08:00
|
|
|
|
|
|
|
static inline void kvm_clean_pgd(pgd_t *pgd) {}
|
2014-10-10 18:14:28 +08:00
|
|
|
static inline void kvm_clean_pmd(pmd_t *pmd) {}
|
2012-12-10 23:35:24 +08:00
|
|
|
static inline void kvm_clean_pmd_entry(pmd_t *pmd) {}
|
|
|
|
static inline void kvm_clean_pte(pte_t *pte) {}
|
|
|
|
static inline void kvm_clean_pte_entry(pte_t *pte) {}
|
|
|
|
|
2016-04-14 00:57:37 +08:00
|
|
|
static inline pte_t kvm_s2pte_mkwrite(pte_t pte)
|
2012-12-10 23:35:24 +08:00
|
|
|
{
|
2016-04-14 00:57:37 +08:00
|
|
|
pte_val(pte) |= PTE_S2_RDWR;
|
|
|
|
return pte;
|
2012-12-10 23:35:24 +08:00
|
|
|
}
|
|
|
|
|
2016-04-14 00:57:37 +08:00
|
|
|
static inline pmd_t kvm_s2pmd_mkwrite(pmd_t pmd)
|
2012-11-02 00:14:45 +08:00
|
|
|
{
|
2016-04-14 00:57:37 +08:00
|
|
|
pmd_val(pmd) |= PMD_S2_RDWR;
|
|
|
|
return pmd;
|
2012-11-02 00:14:45 +08:00
|
|
|
}
|
|
|
|
|
2015-01-16 07:58:59 +08:00
|
|
|
static inline void kvm_set_s2pte_readonly(pte_t *pte)
|
|
|
|
{
|
2016-04-14 00:57:37 +08:00
|
|
|
pteval_t pteval;
|
|
|
|
unsigned long tmp;
|
|
|
|
|
|
|
|
asm volatile("// kvm_set_s2pte_readonly\n"
|
|
|
|
" prfm pstl1strm, %2\n"
|
|
|
|
"1: ldxr %0, %2\n"
|
|
|
|
" and %0, %0, %3 // clear PTE_S2_RDWR\n"
|
|
|
|
" orr %0, %0, %4 // set PTE_S2_RDONLY\n"
|
|
|
|
" stxr %w1, %0, %2\n"
|
|
|
|
" cbnz %w1, 1b\n"
|
|
|
|
: "=&r" (pteval), "=&r" (tmp), "+Q" (pte_val(*pte))
|
|
|
|
: "L" (~PTE_S2_RDWR), "L" (PTE_S2_RDONLY));
|
2015-01-16 07:58:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool kvm_s2pte_readonly(pte_t *pte)
|
|
|
|
{
|
|
|
|
return (pte_val(*pte) & PTE_S2_RDWR) == PTE_S2_RDONLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void kvm_set_s2pmd_readonly(pmd_t *pmd)
|
|
|
|
{
|
2016-04-14 00:57:37 +08:00
|
|
|
kvm_set_s2pte_readonly((pte_t *)pmd);
|
2015-01-16 07:58:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
|
|
|
|
{
|
2016-04-14 00:57:37 +08:00
|
|
|
return kvm_s2pte_readonly((pte_t *)pmd);
|
2014-10-10 18:14:28 +08:00
|
|
|
}
|
|
|
|
|
2014-05-10 05:31:31 +08:00
|
|
|
static inline bool kvm_page_empty(void *ptr)
|
|
|
|
{
|
|
|
|
struct page *ptr_page = virt_to_page(ptr);
|
|
|
|
return page_count(ptr_page) == 1;
|
|
|
|
}
|
|
|
|
|
2016-03-23 01:20:28 +08:00
|
|
|
#define hyp_pte_table_empty(ptep) kvm_page_empty(ptep)
|
2014-10-10 18:14:28 +08:00
|
|
|
|
|
|
|
#ifdef __PAGETABLE_PMD_FOLDED
|
2016-03-23 01:20:28 +08:00
|
|
|
#define hyp_pmd_table_empty(pmdp) (0)
|
2014-10-10 18:14:28 +08:00
|
|
|
#else
|
2016-03-23 01:20:28 +08:00
|
|
|
#define hyp_pmd_table_empty(pmdp) kvm_page_empty(pmdp)
|
2014-10-10 18:14:28 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __PAGETABLE_PUD_FOLDED
|
2016-03-23 01:20:28 +08:00
|
|
|
#define hyp_pud_table_empty(pudp) (0)
|
2014-05-10 05:31:31 +08:00
|
|
|
#else
|
2016-03-23 01:20:28 +08:00
|
|
|
#define hyp_pud_table_empty(pudp) kvm_page_empty(pudp)
|
2014-05-10 05:31:31 +08:00
|
|
|
#endif
|
|
|
|
|
2012-12-10 23:35:24 +08:00
|
|
|
struct kvm;
|
|
|
|
|
2014-01-15 03:13:10 +08:00
|
|
|
#define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l))
|
|
|
|
|
|
|
|
static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
|
2012-12-10 23:35:24 +08:00
|
|
|
{
|
2014-01-15 03:13:10 +08:00
|
|
|
return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
|
|
|
|
}
|
|
|
|
|
kvm: rename pfn_t to kvm_pfn_t
To date, we have implemented two I/O usage models for persistent memory,
PMEM (a persistent "ram disk") and DAX (mmap persistent memory into
userspace). This series adds a third, DAX-GUP, that allows DAX mappings
to be the target of direct-i/o. It allows userspace to coordinate
DMA/RDMA from/to persistent memory.
The implementation leverages the ZONE_DEVICE mm-zone that went into
4.3-rc1 (also discussed at kernel summit) to flag pages that are owned
and dynamically mapped by a device driver. The pmem driver, after
mapping a persistent memory range into the system memmap via
devm_memremap_pages(), arranges for DAX to distinguish pfn-only versus
page-backed pmem-pfns via flags in the new pfn_t type.
The DAX code, upon seeing a PFN_DEV+PFN_MAP flagged pfn, flags the
resulting pte(s) inserted into the process page tables with a new
_PAGE_DEVMAP flag. Later, when get_user_pages() is walking ptes it keys
off _PAGE_DEVMAP to pin the device hosting the page range active.
Finally, get_page() and put_page() are modified to take references
against the device driver established page mapping.
Finally, this need for "struct page" for persistent memory requires
memory capacity to store the memmap array. Given the memmap array for a
large pool of persistent may exhaust available DRAM introduce a
mechanism to allocate the memmap from persistent memory. The new
"struct vmem_altmap *" parameter to devm_memremap_pages() enables
arch_add_memory() to use reserved pmem capacity rather than the page
allocator.
This patch (of 18):
The core has developed a need for a "pfn_t" type [1]. Move the existing
pfn_t in KVM to kvm_pfn_t [2].
[1]: https://lists.01.org/pipermail/linux-nvdimm/2015-September/002199.html
[2]: https://lists.01.org/pipermail/linux-nvdimm/2015-September/002218.html
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-01-16 08:56:11 +08:00
|
|
|
static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu,
|
|
|
|
kvm_pfn_t pfn,
|
arm/arm64: KVM: Use kernel mapping to perform invalidation on page fault
When handling a fault in stage-2, we need to resync I$ and D$, just
to be sure we don't leave any old cache line behind.
That's very good, except that we do so using the *user* address.
Under heavy load (swapping like crazy), we may end up in a situation
where the page gets mapped in stage-2 while being unmapped from
userspace by another CPU.
At that point, the DC/IC instructions can generate a fault, which
we handle with kvm->mmu_lock held. The box quickly deadlocks, user
is unhappy.
Instead, perform this invalidation through the kernel mapping,
which is guaranteed to be present. The box is much happier, and so
am I.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
2015-01-06 05:13:24 +08:00
|
|
|
unsigned long size,
|
|
|
|
bool ipa_uncached)
|
2014-01-15 03:13:10 +08:00
|
|
|
{
|
arm/arm64: KVM: Use kernel mapping to perform invalidation on page fault
When handling a fault in stage-2, we need to resync I$ and D$, just
to be sure we don't leave any old cache line behind.
That's very good, except that we do so using the *user* address.
Under heavy load (swapping like crazy), we may end up in a situation
where the page gets mapped in stage-2 while being unmapped from
userspace by another CPU.
At that point, the DC/IC instructions can generate a fault, which
we handle with kvm->mmu_lock held. The box quickly deadlocks, user
is unhappy.
Instead, perform this invalidation through the kernel mapping,
which is guaranteed to be present. The box is much happier, and so
am I.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
2015-01-06 05:13:24 +08:00
|
|
|
void *va = page_address(pfn_to_page(pfn));
|
|
|
|
|
2014-11-17 22:58:52 +08:00
|
|
|
if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached)
|
arm/arm64: KVM: Use kernel mapping to perform invalidation on page fault
When handling a fault in stage-2, we need to resync I$ and D$, just
to be sure we don't leave any old cache line behind.
That's very good, except that we do so using the *user* address.
Under heavy load (swapping like crazy), we may end up in a situation
where the page gets mapped in stage-2 while being unmapped from
userspace by another CPU.
At that point, the DC/IC instructions can generate a fault, which
we handle with kvm->mmu_lock held. The box quickly deadlocks, user
is unhappy.
Instead, perform this invalidation through the kernel mapping,
which is guaranteed to be present. The box is much happier, and so
am I.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
2015-01-06 05:13:24 +08:00
|
|
|
kvm_flush_dcache_to_poc(va, size);
|
2014-01-15 03:13:10 +08:00
|
|
|
|
2012-12-10 23:35:24 +08:00
|
|
|
if (!icache_is_aliasing()) { /* PIPT */
|
arm/arm64: KVM: Use kernel mapping to perform invalidation on page fault
When handling a fault in stage-2, we need to resync I$ and D$, just
to be sure we don't leave any old cache line behind.
That's very good, except that we do so using the *user* address.
Under heavy load (swapping like crazy), we may end up in a situation
where the page gets mapped in stage-2 while being unmapped from
userspace by another CPU.
At that point, the DC/IC instructions can generate a fault, which
we handle with kvm->mmu_lock held. The box quickly deadlocks, user
is unhappy.
Instead, perform this invalidation through the kernel mapping,
which is guaranteed to be present. The box is much happier, and so
am I.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
2015-01-06 05:13:24 +08:00
|
|
|
flush_icache_range((unsigned long)va,
|
|
|
|
(unsigned long)va + size);
|
2012-12-10 23:35:24 +08:00
|
|
|
} else if (!icache_is_aivivt()) { /* non ASID-tagged VIVT */
|
|
|
|
/* any kind of VIPT cache */
|
|
|
|
__flush_icache_all();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-20 00:48:06 +08:00
|
|
|
static inline void __kvm_flush_dcache_pte(pte_t pte)
|
|
|
|
{
|
|
|
|
struct page *page = pte_page(pte);
|
|
|
|
kvm_flush_dcache_to_poc(page_address(page), PAGE_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void __kvm_flush_dcache_pmd(pmd_t pmd)
|
|
|
|
{
|
|
|
|
struct page *page = pmd_page(pmd);
|
|
|
|
kvm_flush_dcache_to_poc(page_address(page), PMD_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void __kvm_flush_dcache_pud(pud_t pud)
|
|
|
|
{
|
|
|
|
struct page *page = pud_page(pud);
|
|
|
|
kvm_flush_dcache_to_poc(page_address(page), PUD_SIZE);
|
|
|
|
}
|
|
|
|
|
2013-11-20 03:59:12 +08:00
|
|
|
#define kvm_virt_to_phys(x) __virt_to_phys((unsigned long)(x))
|
2012-12-10 23:35:24 +08:00
|
|
|
|
2014-12-20 00:05:31 +08:00
|
|
|
void kvm_set_way_flush(struct kvm_vcpu *vcpu);
|
|
|
|
void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled);
|
2014-01-15 20:50:23 +08:00
|
|
|
|
2015-03-20 00:42:28 +08:00
|
|
|
static inline bool __kvm_cpu_uses_extended_idmap(void)
|
|
|
|
{
|
|
|
|
return __cpu_uses_extended_idmap();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd,
|
|
|
|
pgd_t *hyp_pgd,
|
|
|
|
pgd_t *merged_hyp_pgd,
|
|
|
|
unsigned long hyp_idmap_start)
|
|
|
|
{
|
|
|
|
int idmap_idx;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the first entry to access the HYP mappings. It is
|
|
|
|
* guaranteed to be free, otherwise we wouldn't use an
|
|
|
|
* extended idmap.
|
|
|
|
*/
|
|
|
|
VM_BUG_ON(pgd_val(merged_hyp_pgd[0]));
|
|
|
|
merged_hyp_pgd[0] = __pgd(__pa(hyp_pgd) | PMD_TYPE_TABLE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create another extended level entry that points to the boot HYP map,
|
|
|
|
* which contains an ID mapping of the HYP init code. We essentially
|
|
|
|
* merge the boot and runtime HYP maps by doing so, but they don't
|
|
|
|
* overlap anyway, so this is fine.
|
|
|
|
*/
|
|
|
|
idmap_idx = hyp_idmap_start >> VA_BITS;
|
|
|
|
VM_BUG_ON(pgd_val(merged_hyp_pgd[idmap_idx]));
|
|
|
|
merged_hyp_pgd[idmap_idx] = __pgd(__pa(boot_hyp_pgd) | PMD_TYPE_TABLE);
|
|
|
|
}
|
|
|
|
|
2015-11-16 19:28:18 +08:00
|
|
|
static inline unsigned int kvm_get_vmid_bits(void)
|
|
|
|
{
|
|
|
|
int reg = read_system_reg(SYS_ID_AA64MMFR1_EL1);
|
|
|
|
|
2016-01-26 18:58:16 +08:00
|
|
|
return (cpuid_feature_extract_unsigned_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8;
|
2015-11-16 19:28:18 +08:00
|
|
|
}
|
|
|
|
|
2012-12-10 23:35:24 +08:00
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
#endif /* __ARM64_KVM_MMU_H__ */
|