diff --git a/Kconfig b/Kconfig index ab9e308c5..55213e7f0 100644 --- a/Kconfig +++ b/Kconfig @@ -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" diff --git a/include/plat/tk1/plat/machine/devices.h b/include/plat/tk1/plat/machine/devices.h index a8973fbc2..c6df01268 100644 --- a/include/plat/tk1/plat/machine/devices.h +++ b/include/plat/tk1/plat/machine/devices.h @@ -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 diff --git a/include/plat/tk1/plat/machine/hardware.bf b/include/plat/tk1/plat/machine/hardware.bf index d0c32d2ce..3b00d75b9 100644 --- a/include/plat/tk1/plat/machine/hardware.bf +++ b/include/plat/tk1/plat/machine/hardware.bf @@ -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 } diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index 3ae7723f4..7eef7206f 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -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; diff --git a/src/plat/tk1/machine/hardware.c b/src/plat/tk1/machine/hardware.c index e4fe255e7..2d4f27b6f 100644 --- a/src/plat/tk1/machine/hardware.c +++ b/src/plat/tk1/machine/hardware.c @@ -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 */ diff --git a/src/plat/tk1/machine/smmu.c b/src/plat/tk1/machine/smmu.c index 2a05b643d..e3bc0bd25 100644 --- a/src/plat/tk1/machine/smmu.c +++ b/src/plat/tk1/machine/smmu.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -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); }