diff mbox

[v4,02/10] ARM: KVM: Hypervisor identity mapping

Message ID 20110806103910.27198.11538.stgit@localhost6.localdomain6 (mailing list archive)
State New, archived
Headers show

Commit Message

Christoffer Dall Aug. 6, 2011, 10:39 a.m. UTC
Adds support in the identity mapping feature that allows KVM to setup
identity mapping for the Hyp mode with the AP[1] bit set as required by
the specification and also supports freeing created sub pmd's after
finished use.

These two functions:
 - hyp_identity_mapping_add(pgd, addr, end);
 - hyp_identity_mapping_del(pgd, addr, end);
are essentially calls the same function as the non-hyp versions but
with a different argument value. KVM calls these functions to setup
and teardown the identity mapping used to initialize the hypervisor.

Note, the hyp-version of the _del function actually frees the pmd's
pointed to by the pgd as opposed to the non-hyp version which just
clears them.

Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
---
 arch/arm/include/asm/pgtable-3level-hwdef.h |    1 +
 arch/arm/include/asm/pgtable.h              |    6 +++
 arch/arm/mm/idmap.c                         |   47 ++++++++++++++++++++++++++-
 3 files changed, 53 insertions(+), 1 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Avi Kivity Aug. 9, 2011, 9:20 a.m. UTC | #1
On 08/06/2011 01:39 PM, Christoffer Dall wrote:
> Adds support in the identity mapping feature that allows KVM to setup
> identity mapping for the Hyp mode with the AP[1] bit set as required by
> the specification and also supports freeing created sub pmd's after
> finished use.
>
> These two functions:
>   - hyp_identity_mapping_add(pgd, addr, end);
>   - hyp_identity_mapping_del(pgd, addr, end);
> are essentially calls the same function as the non-hyp versions but
> with a different argument value. KVM calls these functions to setup
> and teardown the identity mapping used to initialize the hypervisor.
>
> Note, the hyp-version of the _del function actually frees the pmd's
> pointed to by the pgd as opposed to the non-hyp version which just
> clears them.
>
>

These are for mapping host memory, not guest memory, right?
Catalin Marinas Aug. 9, 2011, 9:29 a.m. UTC | #2
On Tue, Aug 09, 2011 at 10:20:27AM +0100, Avi Kivity wrote:
> On 08/06/2011 01:39 PM, Christoffer Dall wrote:
> > Adds support in the identity mapping feature that allows KVM to setup
> > identity mapping for the Hyp mode with the AP[1] bit set as required by
> > the specification and also supports freeing created sub pmd's after
> > finished use.
> >
> > These two functions:
> >   - hyp_identity_mapping_add(pgd, addr, end);
> >   - hyp_identity_mapping_del(pgd, addr, end);
> > are essentially calls the same function as the non-hyp versions but
> > with a different argument value. KVM calls these functions to setup
> > and teardown the identity mapping used to initialize the hypervisor.
> >
> > Note, the hyp-version of the _del function actually frees the pmd's
> > pointed to by the pgd as opposed to the non-hyp version which just
> > clears them.
> >
> >
> 
> These are for mapping host memory, not guest memory, right?

Yes. There is some code that is built into the kernel image (and address
space) but it needs to run in Hypervisor mode which has its own MMU
translation tables.
Christoffer Dall Aug. 9, 2011, 9:29 a.m. UTC | #3
On Aug 9, 2011, at 11:20 AM, Avi Kivity wrote:

> On 08/06/2011 01:39 PM, Christoffer Dall wrote:
>> Adds support in the identity mapping feature that allows KVM to setup
>> identity mapping for the Hyp mode with the AP[1] bit set as required by
>> the specification and also supports freeing created sub pmd's after
>> finished use.
>> 
>> These two functions:
>>  - hyp_identity_mapping_add(pgd, addr, end);
>>  - hyp_identity_mapping_del(pgd, addr, end);
>> are essentially calls the same function as the non-hyp versions but
>> with a different argument value. KVM calls these functions to setup
>> and teardown the identity mapping used to initialize the hypervisor.
>> 
>> Note, the hyp-version of the _del function actually frees the pmd's
>> pointed to by the pgd as opposed to the non-hyp version which just
>> clears them.
>> 
>> 
> 
> These are for mapping host memory, not guest memory, right?

yes (or to be exact - hypervisor memory). The point is that there are special hardware requirements for translation tables used in Hyp-mode not otherwise satisfied by the normal page tables.

> 
> -- 
> error compiling committee.c: too many arguments to function
> 

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alexey Smirnov Aug. 9, 2011, 10:23 a.m. UTC | #4
Hi Christoffer,

>>
>> These are for mapping host memory, not guest memory, right?
>
> yes (or to be exact - hypervisor memory). The point is that there are special hardware requirements for translation tables used in Hyp-mode not otherwise satisfied by the normal page tables.

In function init_hyp_memory() you map some memory regions for vectors,
vcpu, stack, etc. using function create_hyp_mappings. Just wondering,
how do you make sure that guest will never map its own data into these
addresses? Since guest is not para-virtualized, it can use any VA it
wants, including these addresses.

 In your earlier KVM-arm paper you mentioned that such mappings were
write-protected, so whenever guest tried to access them you needed to
relocate such shared pages. Is the mechanism the same or you somehow
take advantage of virtualization extensions to avoid this problem?

Thanks,
Alexey
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoffer Dall Aug. 9, 2011, 11:23 a.m. UTC | #5
On Aug 9, 2011, at 12:23 PM, Alexey Smirnov wrote:

> Hi Christoffer,
> 
>>> 
>>> These are for mapping host memory, not guest memory, right?
>> 
>> yes (or to be exact - hypervisor memory). The point is that there are special hardware requirements for translation tables used in Hyp-mode not otherwise satisfied by the normal page tables.
> 
> In function init_hyp_memory() you map some memory regions for vectors,
> vcpu, stack, etc. using function create_hyp_mappings. Just wondering,
> how do you make sure that guest will never map its own data into these
> addresses? Since guest is not para-virtualized, it can use any VA it
> wants, including these addresses.
> 
> In your earlier KVM-arm paper you mentioned that such mappings were
> write-protected, so whenever guest tried to access them you needed to
> relocate such shared pages. Is the mechanism the same or you somehow
> take advantage of virtualization extensions to avoid this problem?

I take advantage of the virtualization extensions. These mappings are used only in Hyp-mode, which is only used to handle exceptions from the guest and to perform world-switches. Thus, these mappings are completely orthogonal to the 2nd stage translations used when running the VM.

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h
index 7c238a3..8ed298f 100644
--- a/arch/arm/include/asm/pgtable-3level-hwdef.h
+++ b/arch/arm/include/asm/pgtable-3level-hwdef.h
@@ -49,6 +49,7 @@ 
 #endif
 #define PMD_SECT_AP_WRITE	(_AT(pmdval_t, 0))
 #define PMD_SECT_AP_READ	(_AT(pmdval_t, 0))
+#define PMD_SECT_AP1		(_AT(pmdval_t, 1) << 6)
 #define PMD_SECT_TEX(x)		(_AT(pmdval_t, 0))
 
 /*
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 9645e52..da74cd1 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -409,6 +409,12 @@  static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 void identity_mapping_add(pgd_t *, unsigned long, unsigned long);
 void identity_mapping_del(pgd_t *, unsigned long, unsigned long);
 
+#ifdef CONFIG_KVM_ARM_HOST
+void hyp_identity_mapping_add(pgd_t *, unsigned long, unsigned long);
+void hyp_identity_mapping_del(pgd_t *pgd, unsigned long addr,
+			      unsigned long end);
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* CONFIG_MMU */
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index 24e0655..83dc20d 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -56,11 +56,16 @@  static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
 	} while (pud++, addr = next, addr != end);
 }
 
-void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
+static void __identity_mapping_add(pgd_t *pgd, unsigned long addr,
+				   unsigned long end, bool hyp_mapping)
 {
 	unsigned long prot, next;
 
 	prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF;
+
+	if (hyp_mapping)
+		prot |= PMD_SECT_AP1;
+
 	if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
 		prot |= PMD_BIT4;
 
@@ -71,6 +76,12 @@  void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
 	} while (pgd++, addr = next, addr != end);
 }
 
+void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+	__identity_mapping_add(pgd, addr, end, false);
+}
+
+
 #ifdef CONFIG_SMP
 static void idmap_del_pmd(pud_t *pud, unsigned long addr, unsigned long end)
 {
@@ -105,6 +116,40 @@  void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end)
 }
 #endif
 
+#ifdef CONFIG_KVM_ARM_HOST
+void hyp_identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+	__identity_mapping_add(pgd, addr, end, true);
+}
+
+static void hyp_idmap_del_pmd(pgd_t *pgd, unsigned long addr)
+{
+	pmd_t *pmd;
+
+	pmd = pmd_offset(pgd, addr);
+	pmd_free(NULL, pmd);
+}
+
+/*
+ * This version actually frees the underlying pmds for all pgds in range and
+ * clear the pgds themselves afterwards.
+ */
+void hyp_identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+	unsigned long next;
+	pgd_t *next_pgd;
+
+	do {
+		next = pgd_addr_end(addr, end);
+		next_pgd = pgd + pgd_index(addr);
+		if (!pgd_none_or_clear_bad(next_pgd)) {
+			hyp_idmap_del_pmd(next_pgd, addr);
+			pgd_clear(next_pgd);
+		}
+	} while (addr = next, addr < end);
+}
+#endif
+
 /*
  * In order to soft-boot, we need to insert a 1:1 mapping in place of
  * the user-mode pages.  This will then ensure that we have predictable