Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Jun 2015 17:31:19 GMT
From:      mihai@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r287542 - in soc2015/mihai/bhyve-on-arm-head/sys: arm/vmm modules/vmm-arm
Message-ID:  <201506241731.t5OHVJoU028966@socsvn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mihai
Date: Wed Jun 24 17:31:19 2015
New Revision: 287542
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=287542

Log:
  soc2015: mihai: bhyve-on-arm-head: sys: arm: vmm: add support for create HYP mappings and initialization code

Added:
  soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.h
  soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/init.S
  soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/mmu.c
  soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/mmu.h
Modified:
  soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.c
  soc2015/mihai/bhyve-on-arm-head/sys/modules/vmm-arm/Makefile

Modified: soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.c
==============================================================================
--- soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.c	Wed Jun 24 17:17:53 2015	(r287541)
+++ soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.c	Wed Jun 24 17:31:19 2015	(r287542)
@@ -1,12 +1,56 @@
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/smp.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/vmm.h>
+#include <machine/vmm_dev.h>
+
+#include "mmu.h"
+#include "arm.h"
+
+static MALLOC_DEFINE(M_HYP, "ARM VMM HYP", "ARM VMM HYP");
+
+lpae_pd_entry_t hyp_l1pd[2 * LPAE_L1_ENTRIES];
+extern void _hypervisor_stub_trap(void *vect_addr);
+char *stack = NULL;
+
 static int
 arm_init(int ipinum)
 {
+	char *stack_top, *hyp_code;
+
+	stack = malloc(PAGE_SIZE, M_HYP);
+	stack_top = stack + PAGE_SIZE;
+
+	lpae_vmmmap_set(NULL, stack, ptophys(stack), PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE);
+
+	/* Allocate a PAGE for the HYP code to be sure it's PAGE_SIZE aligned and doesn't cross a page boundary */
+	hyp_code = malloc(PAGE_SIZE, M_HYP);
+	memcpy(hyp_code, _hyp_code_start, _hyp_code_stop - _hyp_code_start);
+
+	/* Create two mappings:
+	 * - one identity - VA == PA
+	 * - one normal mappings to HYP pagetable */
+	lpae_vmmmap_set(NULL, hyp_code, ptophys(hyp_code), PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE);
+	lpae_vmmmap_set(NULL, ptophys(hyp_code), ptophys(hyp_code), PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE);
+
+	vmm_call_hyp(NULL, stack_top, &hyp_l1pd[0], &hyp_l1pd[0]);
 	return 0;
 }
 
 static void
-arm_vmcleanup(void *arg)
+arm_cleanup(void *arg)
 {
+	lpae_vmcleanup(NULL);
 }
 
 static void

Added: soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/arm.h	Wed Jun 24 17:31:19 2015	(r287542)
@@ -0,0 +1,9 @@
+#include "mmu.h"
+
+struct hyp {
+	lpae_pd_entry_t l1pd[2 * LPAE_L1_ENTRIES];
+	struct vm	*vm;
+};
+
+uint64_t vmm_call_hyp(void *hyp_func_addr, ...);
+

Added: soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/init.S
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/init.S	Wed Jun 24 17:31:19 2015	(r287542)
@@ -0,0 +1,134 @@
+#include "assym.s"
+#include <sys/syscall.h>
+#include <machine/asm.h>
+#include <machine/asmacros.h>
+#include <machine/armreg.h>
+#include <machine/sysreg.h>
+#include <machine/cpuconf.h>
+
+#define SYS_WRITE0	4
+
+.text
+	.globl	_hyp_code_start
+	.globl	_hyp_code_end
+	.globl	_hyp_vector
+	.globl	_init_hyp_vector
+
+_hyp_code_start:
+
+__semi_call:
+	svc     0x123456
+	mov pc, lr
+
+ASENTRY_NP(kvm_call_hyp)
+	hvc	#0
+	bx	lr
+END(kvm_call_hyp)
+
+	.align 5
+_init_hyp_vector:
+	.word 0			/* Reset */
+	.word 0			/* undev */
+	.word 0			/* SVC */
+	.word 0			/* PABT */
+	.word 0			/* DABT */
+	b	hyp_init_hvc	/* HYP-Mode */
+	.word 0			/* FIQ */
+	.word 0			/* IRQ */
+
+hyp_init_hvc:
+	mov     sp, r1		/* r1 contains the stack pointer */
+
+	/* Find the offset between the two vectors */
+	adr	r0, _init_hyp_vector
+	adr	r1, _hyp_vector
+	sub	r1, r1, r0
+
+	mrc	p15, 4, r0, c12, c0, 0	@ get current HVBAR
+	add	r0, r0, r1		@ find the address of the _hyp_vector
+	mcr     p15, 4, r0, c12, c0, 0  @ set HVBAR to the new vector
+
+	mcrr    p15, 4, r2, r3, c2 @ set the HTTBR (r2 is the low word, r3 is the low word)
+	isb
+
+	@ Flush the TLB of this page
+	adr	r1, _hyp_code_start
+	mcr	p15, 4, r0, c8, c7, 0   @ TLBIALLH
+	dsb	ish
+
+	eret
+
+	.align 5
+_hyp_vector:
+	b	hyp_reset	/* Reset */
+	b	hyp_undef	/* undef */
+	b	hyp_svc		/* SVC */
+	b	hyp_pabt	/* PABT */
+	b	hyp_dabt	/* DABT */
+	b	hyp_hvc		/* HYP-Mode */
+	b	hyp_fiq		/* FIQ */
+	b	hyp_irq		/* IRQ */
+
+	.align
+hyp_reset:
+	b loop
+
+	.align
+hyp_undef:
+	mov r0, #SYS_WRITE0
+	adr r1, und_die_str
+	bl __semi_call
+	mrs r0, ELR_hyp
+	b loop
+
+	.align
+hyp_svc:
+	mov r0, #SYS_WRITE0
+	adr r1, svc_die_str
+	bl __semi_call
+	mrs r0, ELR_hyp
+	b loop
+	.align
+
+hyp_pabt:
+	mov r0, #SYS_WRITE0
+	adr r1, pabt_die_str
+	bl __semi_call
+	mrs r0, ELR_hyp
+	mrc     p15, 4, r1, c5, c2, 0   @ HSR (syndrome register)
+	mrc     p15, 4, r2, c6, c0, 2   @ HIFAR (hyp instruction fault address)
+	b loop
+
+	.align
+hyp_dabt:
+	mov r0, #SYS_WRITE0
+	adr r1, dabt_die_str
+	bl __semi_call
+	mrs r0, ELR_hyp
+	mrc     p15, 4, r1, c5, c2, 0   @ HSR (syndrome register)
+	mrc     p15, 4, r2, c6, c0, 0   @ HDFAR (hyp data fault address)
+	b loop
+
+	.align
+hyp_hvc:
+	
+	.align
+hyp_fiq:
+	b loop
+	.align
+hyp_irq:
+	b loop
+	.align
+loop:
+	b loop
+
+und_die_str:
+	.ascii  "unexpected undefined exception in Hyp mode at r0: %#08x\n"
+pabt_die_str:
+	.ascii  "unexpected prefetch abort in Hyp mode at r0: %#08x\n"
+dabt_die_str:
+	.ascii  "unexpected data abort in Hyp mode at r0: %#08x\n"
+svc_die_str:
+	.ascii  "unexpected HVC/SVC trap in Hyp mode at r0: %#08x\n"
+
+_hyp_code_end:

Added: soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/mmu.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/mmu.c	Wed Jun 24 17:31:19 2015	(r287542)
@@ -0,0 +1,191 @@
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/smp.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/param.h>
+#include <machine/cpufunc.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+
+#include <machine/vmm.h>
+#include "mmu.h"
+#include "arm.h"
+
+MALLOC_DECLARE(M_HYP);
+extern lpae_pd_entry_t hyp_l1pd[];
+/*
+ * create_lpae_mapping
+ * - l1pd - the level 1 address of the PD (NULL for the HYP mode PD)
+ * - virt_start - a 32 bit virtual address to be mapped
+ * - phys_start - a 64 bit physical address to map to
+ * - len - the desired length mapping, but it will be truncated to the virt_start 
+ *         alignment
+ * - prot - the FreeBSD mapping permissions
+ * - returns the actual length of the mapping
+ *
+ * An l1pd or l2pd will have a size of 8K (2 * LPAE_Lx_ENTRIES * sizeof(lpae_pd_entry_t)).
+ * The first 4K will include the bits for the MMU (physical addresses and bit permissions)
+ * and the second 4K will be a mirror of the first one but will include the virtual
+ * addresses of allocated page tables needed for walking and clean-up.
+ *
+ */
+static int create_lpae_mapping(lpae_pd_entry_t *l1pd,
+		    lpae_vm_vaddr_t virt_start,
+		    lpae_vm_paddr_t phys_start,
+		    size_t len,
+		    vm_prot_t prot)
+{
+	lpae_pd_entry_t *l2pd, *l3pd, *l1pd_shadow, *l2pd_shadow, *pd;
+	int l1_index, l2_index, l3_index;
+	int mapped_size = 0;
+	bool is_hyp_pd = false;
+
+	if (l1pd == NULL) {
+		l1pd = &hyp_l1pd[0];
+		is_hyp_pd = true;
+	}
+
+	l1_index = (virt_start >> LPAE_L1_SHIFT) & LPAE_L1_INDEX_MASK;
+	l2_index = (virt_start >> LPAE_L2_SHIFT) & LPAE_L2_INDEX_MASK;
+	l3_index = (virt_start >> LPAE_L3_SHIFT) & LPAE_L3_INDEX_MASK;
+
+	if ((virt_start & LPAE_L1_B_ADDR_MASK) == virt_start) {
+		if (len > LPAE_L1_SIZE) {
+			mapped_size = LPAE_L1_SIZE;
+		}
+	}
+	if(!mapped_size && (virt_start & LPAE_L2_B_ADDR_MASK) == virt_start) {
+		if (len > LPAE_L2_SIZE) {
+			mapped_size = LPAE_L2_SIZE;
+		}
+	}
+	if(!mapped_size) {
+		mapped_size = LPAE_L3_SIZE;
+	}
+
+	if (mapped_size == LPAE_L1_SIZE) {
+		pd = &l1pd[l1_index];
+		/* See if this PD is a link and fallback to the next level */
+		if ((*pd & LPAE_TYPE_LINK) == LPAE_TYPE_LINK)
+			mapped_size = LPAE_L2_SIZE;
+		else
+			goto set_prot;
+	}
+
+	l1pd_shadow = &l1pd[LPAE_L1_ENTRIES];
+
+	if (l1pd[l1_index] == 0) {
+		l2pd = malloc(2 * PAGE_SIZE, M_HYP, M_WAITOK | M_ZERO);
+		l2pd_shadow = &l2pd[LPAE_L2_ENTRIES];
+
+		l1pd[l1_index] = (lpae_pd_entry_t) vtophys(l2pd);
+		l1pd[l1_index] |= LPAE_TYPE_LINK;
+
+		l1pd_shadow[l1_index] = (lpae_pd_entry_t) l2pd;
+
+	} else {
+		l2pd = (lpae_pd_entry_t *) (l1pd_shadow[l1_index]);
+		l2pd_shadow = &l2pd[LPAE_L2_ENTRIES];
+	}
+
+	if (mapped_size == LPAE_L2_SIZE) {
+		pd = &l2pd[l2_index];
+		/* See if this PD is a link and fallback to the next level */
+		if ((*pd & LPAE_TYPE_LINK) == LPAE_TYPE_LINK)
+			mapped_size = LPAE_L3_SIZE;
+		else
+			goto set_prot;
+	}
+
+	if (l2pd[l2_index] == 0) {
+		l3pd = malloc(PAGE_SIZE, M_HYP, M_WAITOK | M_ZERO);
+		l2pd[l2_index] = vtophys(l3pd);
+		l2pd[l2_index] |= LPAE_TYPE_LINK;
+
+		l2pd_shadow[l2_index] = (lpae_pd_entry_t) l3pd;
+	} else {
+		l3pd = (lpae_pd_entry_t *) (l2pd_shadow[l2_index]);
+	}
+	
+	pd = &l3pd[l3_index];
+
+set_prot:
+	if (prot != VM_PROT_NONE) {
+		*pd = phys_start;
+		*pd |= LPAE_TYPE_BLOCK;
+
+		if (is_hyp_pd) { /* PL-2 stage-1 table */
+			if (prot & (VM_PROT_READ | VM_PROT_WRITE))
+				*pd |= LPAE_AP_HYP_RW;
+			else /* Map read-only*/
+				*pd |= LPAE_AP_HYP_RDONLY;
+		} else { /* VM stage-2 page table */
+			if (prot & VM_PROT_READ)
+				*pd |= LPAE_HAP_READ;
+			if (prot & VM_PROT_WRITE)
+				*pd |= LPAE_HAP_WRITE;
+		}
+	} else {
+		*pd = 0;
+	}
+
+	return mapped_size;
+}
+
+int lpae_vmmmap_set(void *arg,
+		    lpae_vm_vaddr_t virt_start,
+		    lpae_vm_paddr_t phys_start,
+		    size_t len,
+		    vm_prot_t prot)
+{
+	size_t n;
+	struct hyp *vm_hyp;
+	lpae_pd_entry_t *l1pd = NULL;
+	vm_hyp = arg;
+	if (arg)
+		l1pd = &vm_hyp->l1pd[0];
+
+	while (len > 0) {
+		n = create_lpae_mapping(l1pd, virt_start, phys_start, len, prot);
+		len -= n;
+		virt_start += n;
+		phys_start += n;
+	}
+	return (0);
+}
+
+void lpae_vmcleanup(void *arg)
+{
+	int i, j;
+	struct hyp *vm_hyp;
+	lpae_pd_entry_t *l1pd, *l1pd_shadow, *l2pd, *l2pd_shadow;
+
+	vm_hyp = arg;
+
+	if (arg)
+		l1pd = &vm_hyp->l1pd[0];
+	else 
+		l1pd = &hyp_l1pd[0];
+
+	l1pd_shadow = &l1pd[LPAE_L1_ENTRIES];
+
+	for (i = 0; i < LPAE_L1_ENTRIES; i++) {
+		if(l1pd_shadow[i]) {
+			l2pd = (lpae_pd_entry_t *) l1pd_shadow[i];
+			l2pd_shadow = &l2pd[LPAE_L2_ENTRIES];
+			for (j = 0; j < LPAE_L2_ENTRIES; j++) {
+				if (l2pd_shadow[j]) {
+					free((void *) l2pd_shadow[j], M_HYP);
+				}
+			}
+			free((void *) l1pd_shadow[i], M_HYP);
+		}
+	}
+}

Added: soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/mmu.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2015/mihai/bhyve-on-arm-head/sys/arm/vmm/mmu.h	Wed Jun 24 17:31:19 2015	(r287542)
@@ -0,0 +1,54 @@
+#ifndef _VMM_MMU_H_
+#define	_VMM_MMU_H_
+
+typedef	uint64_t	lpae_pd_entry_t;		/* LPAE page directory entry */
+typedef	uint64_t	lpae_pt_entry_t;		/* LPAE page table entry */
+
+typedef	uint64_t	lpae_vm_paddr_t;		/* LPAE VM paddr */
+typedef	uint32_t	lpae_vm_vaddr_t;		/* LPAE VM vaddr */
+
+int lpae_vmmmap_set(void *arg,
+	    lpae_vm_vaddr_t virt_start,
+	    lpae_vm_paddr_t phys_start,
+	    size_t len,
+	    vm_prot_t prot);
+
+void lpae_vmcleanup(void *arg);
+
+#define LPAE_NLEVELS		3
+
+#define	LPAE_L1_TABLE_SIZE	0x1000				/* 4K */
+#define	LPAE_L1_ENTRIES		(LPAE_L1_TABLE_SIZE / 8)	/* 512 */
+
+#define	LPAE_L2_TABLE_SIZE	0x1000				/*  4K */
+#define	LPAE_L2_ENTRIES		(LPAE_L2_TABLE_SIZE / 8)	/* 512 */
+
+#define	LPAE_L3_TABLE_SIZE	0x1000				/*  4K */
+#define	LPAE_L3_ENTRIES		(LPAE_L3_TABLE_SIZE / 8)	/* 512 */
+
+#define	LPAE_L1_SHIFT		30
+#define	LPAE_L1_SIZE		(1 << 30)
+#define LPAE_L1_INDEX_MASK	0x3
+#define	LPAE_L1_T_ADDR_MASK	((uint64_t)0xFFFFFFF000)	/* phys	address	of L2 Table */
+#define	LPAE_L1_B_ADDR_MASK	((uint64_t)0xFFC0000000)	/* phys	address	of Phys Block */
+
+#define	LPAE_L2_SHIFT		21
+#define	LPAE_L2_SIZE		(1 << 21)
+#define LPAE_L2_INDEX_MASK	0x1FF
+#define	LPAE_L2_T_ADDR_MASK	((uint64_t)0xFFFFFFF000)/* phys	address	of L3 Table */
+#define	LPAE_L2_B_ADDR_MASK	((uint64_t)0xFFFFE00000)/* phys	address	of Phys Block */
+
+#define	LPAE_L3_SHIFT		12
+#define	LPAE_L3_SIZE		(1 << 12)
+#define LPAE_L3_INDEX_MASK	0x1FF
+
+#define	LPAE_TYPE_LINK		0x03
+#define	LPAE_TYPE_BLOCK		0x01
+#define	LPAE_TYPE_MASK		0x03			/* mask of type bits */
+
+#define	LPAE_AP_HYP_RW		(0x01 << 6)		/* RW permissions for PL-2 stage 1*/
+#define	LPAE_AP_HYP_RDONLY	(0x03 << 6)		/* RD permissions for PL-2 stage 1 */
+
+#define	LPAE_HAP_READ		(0x01 << 6)		/* read permissions for stage 2 */
+#define	LPAE_HAP_WRITE		(0x02 << 6)		/* write permissions for stage 2*/
+#endif

Modified: soc2015/mihai/bhyve-on-arm-head/sys/modules/vmm-arm/Makefile
==============================================================================
--- soc2015/mihai/bhyve-on-arm-head/sys/modules/vmm-arm/Makefile	Wed Jun 24 17:17:53 2015	(r287541)
+++ soc2015/mihai/bhyve-on-arm-head/sys/modules/vmm-arm/Makefile	Wed Jun 24 17:31:19 2015	(r287542)
@@ -9,7 +9,9 @@
 .PATH: ${.CURDIR}/../../arm/vmm
 SRCS+=	vmm.c		\
 	vmm_dev.c	\
-	vmm_stat.c
+	mmu.c		\
+	vmm_stat.c	\
+	init.S
 
 
 .include <bsd.kmod.mk>



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201506241731.t5OHVJoU028966>