arm-hyp/tk1: add default SMMU translation for VM

This commit is contained in:
Yanyan Shen 2016-05-25 16:31:26 +10:00
parent 17ec138bf2
commit bb9e84e6ec
6 changed files with 84 additions and 18 deletions

View file

@ -241,6 +241,15 @@ config ARM_HYPERVISOR_SUPPORT
help
Support for TK1 SoC-specific SystemMMU
config ARM_SMMU_VM_DEFAULT_MAPPING
bool "Enable SystemMMU default mapping for guest VM"
depends on PLAT_TK1 && ARM_SMMU
help
Enable the default translation for guest VM: all
physical memory reserved for a VM is allowed to
be accessed with read/write/nonsecure permissions.
source "$KERNEL_PATH/src/arch/arm/Kconfig"
source "$KERNEL_PATH/src/plat/pc99/Kconfig"

View file

@ -43,6 +43,14 @@
#define VGICI_REQ_PADDR (ARM_PERIPHBASE + 0x4000) /* hyp view for requesting CPU */
#define VGICI_ALL_PADDR (ARM_PERIPHBASE + 0x5000) /* hyp view for all CPUs */
#define VGICI_VM_PADDR (ARM_PERIPHBASE + 0x6000) /* hyp view for VM view */
#define PCIE_0_CFG_PADDR (0x01000000) /* PCIE lane 0 config register */
#define PCIE_1_CFG_PADDR (0x01001000) /* PCIE lane 1 config register */
#define PCIE_PCA0_1_PADDR (0x01002000) /* PCA 0 and 1 */
#define PCIE_PADS_AFI_PADDR (0x01003000) /* Pads and AFI */
#define PCIE_A1_PADDR (0x01000000) /* 16 MB */
#define PCIE_A2_PADDR (0x02000000) /* 224 MB */
#define PCIE_A3_PADDR (0x10000000) /* 763 MB */
#define R8169_NIC_PADDR (0x13000000) /* r8169 NIC 1 MB */
#define GRAPH_HOST_PADDR (0x54000000) /* 16 MB */
#define GPU_PADDR (0x57000000) /* 144 MB */
#define UP_TAG_PADDR (0x60000000) /* 4 KB */
@ -83,7 +91,8 @@
#define HDA_PADDR (0x70030000) /* 64 KB */
#define MIOBFM_PADDR (0x70200000) /* 64 KB */
#define AUDIO_PADDR (0x70300000) /* 64 KB */
#define XUSB_HOST_PADDR (0x70090000) /* 40 KB */
#define XUSB_HOST_PADDR (0x70090000) /* 36 KB */
#define XUSB_PADCTL_PADDR (0x7009f000) /* 4 KB */
#define XUSB_DEV_PADDR (0x700d0000) /* 40 KB */
#define DDS_PADDR (0x700a0000) /* 8KB 4608 bytes */
#define SDMMC_1_PADDR (0x700b0000) /* 4KB 512 bytes */
@ -106,4 +115,9 @@
#define USB3_PADDR (0x7d008000) /* 8 KB region, 6 KB */
#define UARTA_PADDR (0x70006000)
/* physical memory regions allocated for virtual machines */
#define VM_HOST_PA_START 0xb0000000
#define VM_GUEST_PA_START 0x80000000
#define VM_HOST_PA_SIZE 0x40000000
#endif

View file

@ -33,13 +33,17 @@ block iopde_pt {
field_high address 22
}
-- adding a 2-bit padding before address is because
-- we do not support addressing more than 4 GiB memory
block iopde_4m {
field read 1
field write 1
field nonsecure 1
field page_size 1
padding 6
field_high address 12
padding 2
field_high address 10
padding 10
}
@ -50,5 +54,6 @@ block iopte {
field write 1
field nonsecure 1
padding 7
field_high address 22
padding 2
field_high address 20
}

View file

@ -388,7 +388,8 @@ decodeARMIOMapInvocation(
}
void deleteIOPageTable(cap_t io_pt_cap)
void
deleteIOPageTable(cap_t io_pt_cap)
{
uint32_t asid;
@ -428,7 +429,8 @@ void deleteIOPageTable(cap_t io_pt_cap)
}
}
void unmapIOPage(cap_t cap)
void
unmapIOPage(cap_t cap)
{
lookupIOPTSlot_ret_t lu_ret;
iopde_t *pd;
@ -500,7 +502,8 @@ decodeARMIOUnMapInvocation(
return EXCEPTION_NONE;
}
exception_t decodeARMIOSpaceInvocation(word_t invLabel, cap_t cap)
exception_t
decodeARMIOSpaceInvocation(word_t invLabel, cap_t cap)
{
userError("IOSpace capability has no invocations");
current_syscall_error.type = seL4_IllegalOperation;

View file

@ -21,9 +21,8 @@
/* Available physical memory regions on platform (RAM minus kernel image). */
/* NOTE: Regions are not allowed to be adjacent! */
/* 1 MiB starting from 0xa7f00000 is reserved by the elfloader for monitor mode hooks */
const p_region_t BOOT_RODATA avail_p_regs[] = {
// { .start = 0x80000000, .end = 0xf0000000 }
//{ .start = 0x80000000, .end = 0xb0000000 }
{ .start = 0x80000000, .end = 0xa7f00000 }
};
@ -41,13 +40,17 @@ BOOT_CODE p_region_t get_avail_p_reg(word_t i)
#define PAGE_SIZE (1 << PAGE_BITS)
#define SECTION_SIZE (1 << SECTION_BITS)
#define VM_PA_START 0xb0000000
#define VM_PA_SIZE 0x10000000
const p_region_t BOOT_RODATA dev_p_regs[] = {
{ VM_PA_START, VM_PA_START + VM_PA_SIZE },
{ VM_HOST_PA_START, VM_HOST_PA_START + VM_HOST_PA_SIZE },
{ VGICI_VM_PADDR, VGICI_VM_PADDR + PAGE_SIZE },
{ PCIE_0_CFG_PADDR, PCIE_0_CFG_PADDR + PAGE_SIZE },
{ PCIE_1_CFG_PADDR, PCIE_1_CFG_PADDR + PAGE_SIZE },
{ PCIE_PCA0_1_PADDR, PCIE_PCA0_1_PADDR + PAGE_SIZE },
{ PCIE_PADS_AFI_PADDR, PCIE_PADS_AFI_PADDR + PAGE_SIZE },
{ PCIE_A2_PADDR, PCIE_A2_PADDR + SECTION_SIZE },
{ R8169_NIC_PADDR, R8169_NIC_PADDR + SECTION_SIZE},
{ GRAPH_HOST_PADDR, GRAPH_HOST_PADDR + (SECTION_SIZE * 16) }, /* 16 MB */
{ GPU_PADDR, GPU_PADDR + (SECTION_SIZE * 144) }, /* 144 MB */
{ UP_TAG_PADDR, UP_TAG_PADDR + PAGE_SIZE }, /* 4 KB */
@ -90,7 +93,8 @@ const p_region_t BOOT_RODATA dev_p_regs[] = {
{ HDA_PADDR, HDA_PADDR + (PAGE_SIZE * 16) }, /* 64 KB */
{ MIOBFM_PADDR, MIOBFM_PADDR + (PAGE_SIZE * 16) }, /* 64 KB */
{ AUDIO_PADDR, AUDIO_PADDR + (PAGE_SIZE * 16) }, /* 64 KB */
{ XUSB_HOST_PADDR, XUSB_HOST_PADDR + (PAGE_SIZE * 10) }, /* 40 KB */
{ XUSB_HOST_PADDR, XUSB_HOST_PADDR + (PAGE_SIZE * 9) }, /* 36 KB */
{ XUSB_PADCTL_PADDR, XUSB_PADCTL_PADDR + PAGE_SIZE }, /* 4 KB */
{ XUSB_DEV_PADDR, XUSB_DEV_PADDR + (PAGE_SIZE * 10) }, /* 40 KB */
{ DDS_PADDR, DDS_PADDR + (PAGE_SIZE * 2) }, /* 8KB 4608 bytes */
{ SDMMC_1_PADDR, SDMMC_1_PADDR + PAGE_SIZE }, /* 4KB 512 bytes */

View file

@ -1,4 +1,5 @@
#include <types.h>
#include <config.h>
#include <plat/machine/smmu.h>
#include <arch/linker.h>
#include <plat/machine/devices.h>
@ -133,6 +134,29 @@ plat_smmu_tlb_flush_all(void)
#define MC_SECURITY_BIT 8
#define MC_DECERR_EMEM_BIT 6
/* using 4 MiB mapping for the Linxu guest VM */
#define IOPDE_4M_INDEX_SHIFT 22
static void
plat_smmu_vm_mapping(word_t iopd, word_t gpa, word_t pa, word_t size)
{
iopde_t *iopde = (iopde_t *)iopd;
while (size > 0) {
word_t index = gpa >> IOPDE_4M_INDEX_SHIFT;
iopde_iopde_4m_ptr_new(
iopde + index,
1,
1,
1,
pa
);
gpa += BIT(IOPDE_4M_INDEX_SHIFT);
pa += BIT(IOPDE_4M_INDEX_SHIFT);
size -= BIT(IOPDE_4M_INDEX_SHIFT);
}
}
BOOT_CODE int
plat_smmu_init(void)
{
@ -140,16 +164,24 @@ plat_smmu_init(void)
int i = 0;
smmu_disable();
printf("smmu disabled\n");
for (i = 0; i < ARM_PLAT_NUM_SMMU; i++) {
iopde_t *pd = (iopde_t *)alloc_region(SMMU_PD_BITS);
if (pd == 0) {
printf("Failed to allocate SMMU IOPageDirectory for ASID %d\n", asid);
return 0;
}
memset(pd, 0, BIT(SMMU_PD_BITS));
if (config_set(CONFIG_ARM_SMMU_VM_DEFAULT_MAPPING)) {
plat_smmu_vm_mapping((word_t)pd, VM_GUEST_PA_START, VM_HOST_PA_START, VM_HOST_PA_SIZE);
}
cleanCacheRange_RAM((word_t)pd, ((word_t)pd + BIT(SMMU_PD_BITS)),
addrFromPPtr(pd));
smmu_regs->smmu_ptb_asid = asid;
/* make it read/write/nonsecure but all translation entries are invalid */
smmu_regs->smmu_ptb_data = make_ptb_data(pptr_to_paddr(pd), true, true, true);
asid++;
@ -167,7 +199,7 @@ plat_smmu_init(void)
smmu_regs->smmu_msenc_asid = SMMU_MSENC_ASID | MODULE_ASID_ENABLE;
smmu_regs->smmu_nv_asid = SMMU_NV_ASID | MODULE_ASID_ENABLE;
smmu_regs->smmu_nv2_asid = SMMU_NV2_ASID | MODULE_ASID_ENABLE;
//smmu_regs->smmu_ppcs_asid = SMMU_PPCS_ASID | MODULE_ASID_ENABLE;
smmu_regs->smmu_ppcs_asid = SMMU_PPCS_ASID | MODULE_ASID_ENABLE;
smmu_regs->smmu_sata_asid = SMMU_SATA_ASID | MODULE_ASID_ENABLE;
smmu_regs->smmu_vde_asid = SMMU_VDE_ASID | MODULE_ASID_ENABLE;
smmu_regs->smmu_vi_asid = SMMU_VI_ASID | MODULE_ASID_ENABLE;
@ -190,7 +222,7 @@ plat_smmu_init(void)
/* flush TLB */
plat_smmu_tlb_flush_all();
smmu_enable();
printf("smmu enabled\n");
/* also need to unmask interrupts */
smmu_regs->intmask = BIT(MC_APB_ASID_UPDATE_BIT) | BIT(MC_SMMU_PAGE_BIT) |
BIT(MC_DECERR_MTS_BIT) | BIT(MC_SECERR_SEC_BIT) |
@ -238,8 +270,6 @@ plat_smmu_handle_interrupt(void)
{
uint32_t status = smmu_regs->intstatus;
uint32_t clear_status = 0;
printf("status %x addr %x %x\n", status, smmu_regs->err_status, smmu_regs->err_adr);
if (status & BIT(MC_DECERR_MTS_BIT)) {
clear_status |= BIT(MC_DECERR_MTS_BIT);
@ -265,6 +295,7 @@ plat_smmu_handle_interrupt(void)
/* we only care about SMMU translation failures */
if (status & BIT(MC_SMMU_PAGE_BIT)) {
#ifdef DEBUG
uint32_t err_status = smmu_regs->err_status;
uint32_t err_adr = smmu_regs->err_adr;
int id = err_status & MC_ERR_ID_MASK;
@ -277,7 +308,7 @@ plat_smmu_handle_interrupt(void)
printf("SMMU Address translation error:\n");
printf("ID: %d address: 0x%x type: %d direction: 0x%x\n", id, err_adr, type, rw);
printf("IOPT permission: read 0x%x write 0x%x nonsecure 0x%x\n", read, write, nonsecure);
#endif
clear_status |= BIT(MC_SMMU_PAGE_BIT);
}