socsvn commit: r287542 - in soc2015/mihai/bhyve-on-arm-head/sys: arm/vmm modules/vmm-arm
mihai at FreeBSD.org
mihai at FreeBSD.org
Wed Jun 24 17:31:22 UTC 2015
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>
More information about the svn-soc-all
mailing list