diff --git a/include/plat/tk1/plat/machine/smmu.h b/include/plat/tk1/plat/machine/smmu.h index fa7543aeb..cad5ef98a 100644 --- a/include/plat/tk1/plat/machine/smmu.h +++ b/include/plat/tk1/plat/machine/smmu.h @@ -29,12 +29,12 @@ typedef struct { uint32_t smmu_ptc_config; /* 0x18 */ uint32_t smmu_ptb_asid; /* 0x1c */ uint32_t smmu_ptb_data; /* 0x20 */ - uint32_t rev0; /* 0x24 */ - uint32_t rev1; /* 0x28 */ - uint32_t rev2; /* 0x2c */ + uint32_t reserved0; /* 0x24 */ + uint32_t reserved1; /* 0x28 */ + uint32_t reserved2; /* 0x2c */ uint32_t smmu_tlb_flush; /* 0x30 */ uint32_t smmu_ptc_flush; /* 0x34 */ - uint32_t rev3[124]; + uint32_t reserved3[124]; uint32_t smmu_translation_enable_0; /* 0x228 */ uint32_t smmu_translation_enable_1; /* 0x22c */ uint32_t smmu_translation_enable_2; /* 0x230 */ @@ -43,13 +43,13 @@ typedef struct { uint32_t smmu_avpc_asid; /* 0x23c */ uint32_t smmu_dc_asid; /* 0x240 */ uint32_t smmu_dcb_asid; /* 0x244 */ - uint32_t rev4; /* 0x248 */ - uint32_t rev5; /* 0x24c */ + uint32_t reserved4; /* 0x248 */ + uint32_t reserved5; /* 0x24c */ uint32_t smmu_hc_asid; /* 0x250 */ uint32_t smmu_hda_asid; /* 0x254 */ uint32_t smmu_isp2_asid; /* 0x258 */ - uint32_t rev6; /* 0x25c */ - uint32_t rev7; /* 0x260 */ + uint32_t reserved6; /* 0x25c */ + uint32_t reserved7; /* 0x260 */ uint32_t smmu_msenc_asid; /* 0x264 */ uint32_t smmu_nv_asid; /* 0x268 */ uint32_t smmu_nv2_asid; /* 0x26c */ @@ -60,17 +60,17 @@ typedef struct { uint32_t smmu_vic_asid; /* 0x284 */ uint32_t smmu_xusb_host_asid; /* 0x288 */ uint32_t smmu_xusb_dev_asid; /* 0x28c */ - uint32_t rev8; /* 0x290 */ + uint32_t reserved8; /* 0x290 */ uint32_t smmu_tsec_asid; /* 0x294 */ uint32_t smmu_ppcs1_asid; /* 0x298 */ - uint32_t rev9[217]; + uint32_t reserved9[217]; uint32_t smmu_tlb_set_sel_mask; /* 0x600 */ - uint32_t rev10[237]; + uint32_t reserved10[237]; uint32_t smmu_ptc_flush_1; /* 0x9b8 */ - uint32_t rev11[51]; + uint32_t reserved11[51]; uint32_t smmu_dc1_asid; /* 0xa88 */ - uint32_t rev12; /* 0xa8c */ - uint32_t rev13; /* 0xa90 */ + uint32_t reserved12; /* 0xa8c */ + uint32_t reserved13; /* 0xa90 */ uint32_t smmu_sdmmc1a_asid; /* 0xa94 */ uint32_t smmu_sdmmc2a_asid; /* 0xa98 */ uint32_t smmu_sdmmc3a_asid; /* 0xa9c */ @@ -152,9 +152,15 @@ plat_smmu_get_asid_by_module_id(uint32_t mid) } +/** MODIFIES: [*] */ int plat_smmu_init(void); + +/** MODIFIES: [*] */ void plat_smmu_tlb_flush_all(void); + +/** MODIFIES: [*] */ void plat_smmu_ptc_flush_all(void); + iopde_t *plat_smmu_lookup_iopd_by_asid(uint32_t asid); void plat_smmu_handle_interrupt(void); diff --git a/src/arch/arm/32/object/objecttype.c b/src/arch/arm/32/object/objecttype.c index e5060d110..793315de0 100644 --- a/src/arch/arm/32/object/objecttype.c +++ b/src/arch/arm/32/object/objecttype.c @@ -84,6 +84,7 @@ Arch_deriveCap(cte_t *slot, cap_t cap) ret.cap = cap; ret.status = EXCEPTION_NONE; } else { + userError("Deriving a IOPT cap without an assigned IOASID"); current_syscall_error.type = seL4_IllegalOperation; ret.cap = cap_null_cap_new(); ret.status = EXCEPTION_SYSCALL_ERROR; @@ -311,7 +312,7 @@ Arch_recycleCap(bool_t is_final, cap_t cap) return cap; case cap_io_page_table_cap: - clearMemoryRAM((void *)cap_get_capPtr(cap), cap_get_capSizeBits(cap)); + clearMemoryRAM(cap_get_capPtr(cap), cap_get_capSizeBits(cap)); Arch_finaliseCap(cap, is_final); return resetMemMapping(cap); diff --git a/src/arch/arm/kernel/boot.c b/src/arch/arm/kernel/boot.c index 88859b99f..ec43aa375 100644 --- a/src/arch/arm/kernel/boot.c +++ b/src/arch/arm/kernel/boot.c @@ -240,6 +240,10 @@ try_init_kernel( if (config_set(CONFIG_ARM_SMMU)) { ndks_boot.bi_frame->ioSpaceCaps = create_iospace_caps(root_cnode_cap); + if (ndks_boot.bi_frame->ioSpaceCaps.start == 0 && + ndks_boot.bi_frame->ioSpaceCaps.end == 0) { + return false; + } } /* Construct an initial address space with enough virtual addresses diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index 66f01955a..6b56ae6f2 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -132,6 +132,28 @@ create_iospace_caps(cap_t root_cnode_cap) }; } +static exception_t +performARMIOPTInvocationMap(cap_t cap, cte_t *slot, iopde_t *iopdSlot, + iopde_t iopde, uint32_t asid, paddr_t io_address) +{ + + + *iopdSlot = iopde; + cleanCacheRange_RAM((word_t)iopdSlot, + ((word_t)iopdSlot) + sizeof(iopde_t), + addrFromPPtr(iopdSlot)); + + plat_smmu_tlb_flush_all(); + plat_smmu_ptc_flush_all(); + + cap = cap_io_page_table_cap_set_capIOPTIsMapped(cap, 1); + cap = cap_io_page_table_cap_set_capIOPTASID(cap, asid); + cap = cap_io_page_table_cap_set_capIOPTMappedAddress(cap, io_address); + + slot->cap = cap; + return EXCEPTION_NONE; +} + exception_t decodeARMIOPTInvocation( @@ -149,6 +171,7 @@ decodeARMIOPTInvocation( uint16_t module_id; uint32_t asid; iopde_t *pd; + iopde_t iopde; lookupIOPDSlot_ret_t lu_ret; if (invLabel == ARMIOPageTableUnmap) { @@ -160,11 +183,13 @@ decodeARMIOPTInvocation( } if (excaps.excaprefs[0] == NULL || length < 1) { + userError("IOPTInvocation: Truncated message."); current_syscall_error.type = seL4_TruncatedMessage; return EXCEPTION_SYSCALL_ERROR; } if (invLabel != ARMIOPageTableMap ) { + userError("IOPTInvocation: Invalid operation."); current_syscall_error.type = seL4_IllegalOperation; return EXCEPTION_SYSCALL_ERROR; } @@ -173,22 +198,25 @@ decodeARMIOPTInvocation( io_address = getSyscallArg(0, buffer) & ~MASK(PAGE_BITS); if (cap_io_page_table_cap_get_capIOPTIsMapped(cap)) { + userError("IOPTMap: Cap already mapped."); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } if (cap_get_capType(io_space) != cap_io_space_cap) { + userError("IOPTMap: Invalid IOSpace cap."); current_syscall_error.type = seL4_InvalidCapability; - current_syscall_error.invalidCapNumber = 0; + current_syscall_error.invalidCapNumber = 1; return EXCEPTION_SYSCALL_ERROR; } module_id = cap_io_space_cap_get_capModuleID(io_space); asid = plat_smmu_get_asid_by_module_id(module_id); if (asid == asidInvalid) { + userError("IOPTMap: Invalid IOASID."); current_syscall_error.type = seL4_InvalidCapability; - current_syscall_error.invalidCapNumber = 0; + current_syscall_error.invalidCapNumber = 1; return EXCEPTION_SYSCALL_ERROR; } @@ -197,8 +225,9 @@ decodeARMIOPTInvocation( pd = (iopde_t *)plat_smmu_lookup_iopd_by_asid(asid); if (pd == 0) { + userError("IOPTMap: IOPD not found."); current_syscall_error.type = seL4_InvalidCapability; - current_syscall_error.invalidCapNumber = 0; + current_syscall_error.invalidCapNumber = 1; return EXCEPTION_SYSCALL_ERROR; } @@ -206,38 +235,47 @@ decodeARMIOPTInvocation( lu_ret = lookupIOPDSlot(pd, io_address); if (lu_ret.status != EXCEPTION_NONE) { current_syscall_error.type = seL4_InvalidCapability; - current_syscall_error.invalidCapNumber = 0; + current_syscall_error.invalidCapNumber = 1; return EXCEPTION_SYSCALL_ERROR; } if (isIOPDEValid(lu_ret.iopdSlot)) { + userError("IOPTMap: Delet first."); current_syscall_error.type = seL4_DeleteFirst; return EXCEPTION_SYSCALL_ERROR; } - iopde_iopde_pt_ptr_new( - lu_ret.iopdSlot, - 1, /* read */ - 1, /* write */ - 1, /* nonsecure */ - paddr /* address */ - ); + iopde = iopde_iopde_pt_new( + 1, /* read */ + 1, /* write */ + 1, /* nonsecure */ + paddr + ); - cleanCacheRange_RAM((word_t)lu_ret.iopdSlot, - ((word_t)lu_ret.iopdSlot) + sizeof(iopde_t), - addrFromPPtr(lu_ret.iopdSlot)); + setThreadState(ksCurThread, ThreadState_Restart); + return performARMIOPTInvocationMap(cap, slot, lu_ret.iopdSlot, iopde, asid, io_address); +} + +static exception_t +performARMIOMapInvocation(cap_t cap, cte_t *slot, iopte_t *ioptSlot, + iopte_t iopte, uint32_t asid, paddr_t io_address) +{ + *ioptSlot = iopte; + cleanCacheRange_RAM((word_t)ioptSlot, + ((word_t)ioptSlot) + sizeof(iopte_t), + addrFromPPtr(ioptSlot)); plat_smmu_tlb_flush_all(); plat_smmu_ptc_flush_all(); - cap = cap_io_page_table_cap_set_capIOPTIsMapped(cap, 1); - cap = cap_io_page_table_cap_set_capIOPTASID(cap, asid); - cap = cap_io_page_table_cap_set_capIOPTMappedAddress(cap, io_address); - +#ifdef CONFIG_ARM_SMMU + cap = cap_small_frame_cap_set_capFIsIOSpace(cap, 1); +#endif + cap = cap_small_frame_cap_set_capFMappedASID(cap, asid); + cap = cap_small_frame_cap_set_capFMappedAddress(cap, io_address); slot->cap = cap; - setThreadState(ksCurThread, ThreadState_Restart); return EXCEPTION_NONE; } @@ -257,22 +295,26 @@ decodeARMIOMapInvocation( uint32_t module_id; uint32_t asid; iopde_t *pd; + iopte_t iopte; vm_rights_t frame_cap_rights; cap_rights_t dma_cap_rights_mask; lookupIOPTSlot_ret_t lu_ret; if (excaps.excaprefs[0] == NULL || length < 2) { + userError("IOMap: Truncated message."); current_syscall_error.type = seL4_TruncatedMessage; return EXCEPTION_SYSCALL_ERROR; } if (generic_frame_cap_get_capFSize(cap) != ARMSmallPage) { + userError("IOMap: Invalid cap type."); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } if (cap_small_frame_cap_get_capFMappedASID(cap) != asidInvalid) { + userError("IOMap: Frame all ready mapped."); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; @@ -283,8 +325,9 @@ decodeARMIOMapInvocation( paddr = pptr_to_paddr((void*)cap_small_frame_cap_get_capFBasePtr(cap)); if (cap_get_capType(io_space) != cap_io_space_cap) { + userError("IOMap: Invalid IOSpace cap."); current_syscall_error.type = seL4_InvalidCapability; - current_syscall_error.invalidCapNumber = 0; + current_syscall_error.invalidCapNumber = 1; return EXCEPTION_SYSCALL_ERROR; } @@ -292,26 +335,30 @@ decodeARMIOMapInvocation( asid = plat_smmu_get_asid_by_module_id(module_id); if (asid == asidInvalid) { + userError("IOMap: Invalid IOSpace ASID."); current_syscall_error.type = seL4_InvalidCapability; - current_syscall_error.invalidCapNumber = 0; + current_syscall_error.invalidCapNumber = 1; return EXCEPTION_SYSCALL_ERROR; } pd = (iopde_t *)plat_smmu_lookup_iopd_by_asid(asid); if (pd == 0) { + userError("IOMap: Invalid IOSpace cap."); current_syscall_error.type = seL4_InvalidCapability; - current_syscall_error.invalidCapNumber = 0; + current_syscall_error.invalidCapNumber = 1; return EXCEPTION_SYSCALL_ERROR; } lu_ret = lookupIOPTSlot(pd, io_address); if (lu_ret.status != EXCEPTION_NONE) { + userError("IOMap: Lookup failed."); current_syscall_error.type = seL4_FailedLookup; current_syscall_error.failedLookupWasSource = false; return EXCEPTION_SYSCALL_ERROR; } if (!isIOPTEEmpty(lu_ret.ioptSlot)) { + userError("IOMap: Delete first."); current_syscall_error.type = seL4_DeleteFirst; return EXCEPTION_SYSCALL_ERROR; } @@ -320,45 +367,42 @@ decodeARMIOMapInvocation( if ((frame_cap_rights == VMReadOnly) && cap_rights_get_capAllowRead(dma_cap_rights_mask)) { /* read only */ - iopte_ptr_new( - lu_ret.ioptSlot, - 1, - 0, - 1, - paddr - ); - } else if (frame_cap_rights == VMReadWrite) { - if (cap_rights_get_capAllowRead(dma_cap_rights_mask) && - !cap_rights_get_capAllowWrite(dma_cap_rights_mask)) { - /* read only */ - iopte_ptr_new( - lu_ret.ioptSlot, + iopte = iopte_new( 1, /* read */ 0, /* write */ 1, /* nonsecure */ paddr - ); + ); + } else if (frame_cap_rights == VMReadWrite) { + if (cap_rights_get_capAllowRead(dma_cap_rights_mask) && + !cap_rights_get_capAllowWrite(dma_cap_rights_mask)) { + /* read only */ + iopte = iopte_new( + 1, /* read */ + 0, /* write */ + 1, /* nonsecure */ + paddr + ); } else if (!cap_rights_get_capAllowRead(dma_cap_rights_mask) && cap_rights_get_capAllowWrite(dma_cap_rights_mask)) { /* write only */ - iopte_ptr_new( - lu_ret.ioptSlot, - 0, - 1, - 1, - paddr - ); + iopte = iopte_new( + 0, /* read */ + 1, /* write */ + 1, /* nonsecure */ + paddr + ); } else if (cap_rights_get_capAllowRead(dma_cap_rights_mask) && cap_rights_get_capAllowWrite(dma_cap_rights_mask)) { /* read write */ - iopte_ptr_new( - lu_ret.ioptSlot, - 1, - 1, - 1, - paddr - ); + iopte = iopte_new( + 1, /* read */ + 1, /* write */ + 1, /* nonsecure */ + paddr + ); } else { + userError("IOMap: Invalid argument."); current_syscall_error.type = seL4_InvalidArgument; current_syscall_error.invalidArgumentNumber = 0; return EXCEPTION_SYSCALL_ERROR; @@ -366,27 +410,14 @@ decodeARMIOMapInvocation( } else { /* VMKernelOnly */ + userError("IOMap: Invalid argument."); current_syscall_error.type = seL4_InvalidArgument; current_syscall_error.invalidArgumentNumber = 0; return EXCEPTION_SYSCALL_ERROR; } - cleanCacheRange_RAM((word_t)lu_ret.ioptSlot, - ((word_t)lu_ret.ioptSlot) + sizeof(iopte_t), - addrFromPPtr(lu_ret.ioptSlot)); - - plat_smmu_tlb_flush_all(); - plat_smmu_ptc_flush_all(); - -#ifdef CONFIG_ARM_SMMU - cap = cap_small_frame_cap_set_capFIsIOSpace(cap, 1); -#endif - cap = cap_small_frame_cap_set_capFMappedASID(cap, asid); - cap = cap_small_frame_cap_set_capFMappedAddress(cap, io_address); - slot->cap = cap; - setThreadState(ksCurThread, ThreadState_Restart); - return EXCEPTION_NONE; + return performARMIOMapInvocation(cap, slot, lu_ret.ioptSlot, iopte, asid, io_address); } diff --git a/src/arch/arm/object/vcpu.c b/src/arch/arm/object/vcpu.c index 996987604..ae9343812 100644 --- a/src/arch/arm/object/vcpu.c +++ b/src/arch/arm/object/vcpu.c @@ -46,7 +46,6 @@ /* Trap WFI/WFE/SMC and override CPSR.AIF */ #define HCR_COMMON ( HCR_TSC | HCR_TWE | HCR_TWI | HCR_AMO | HCR_IMO \ | HCR_FMO | HCR_DC | HCR_VM) - /* Allow native tasks to run at PL1, but restrict access */ #define HCR_NATIVE ( HCR_COMMON | HCR_TGE | HCR_TVM | HCR_TTLB | HCR_TCACHE \ | HCR_TAC | HCR_SWIO) diff --git a/src/plat/tk1/machine/smmu.c b/src/plat/tk1/machine/smmu.c index 4bb07a168..14d45af77 100644 --- a/src/plat/tk1/machine/smmu.c +++ b/src/plat/tk1/machine/smmu.c @@ -12,14 +12,14 @@ static volatile tk1_mc_regs_t *smmu_regs = (volatile tk1_mc_regs_t *)(SMMU_PPTR) #define SMMU_CONFIG_OFFSET 0x10 static void -__smmu_enable(void) +do_smmu_enable(void) { volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET); *config = 1; } static void -__smmu_disable(void) +do_smmu_disable(void) { volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET); *config = 0; @@ -31,14 +31,12 @@ smmu_disable(void) if (config_set(ARM_HYP)) { /* in hyp mode, we need call the hook in monitor mode */ /* we need physical address here */ - uint32_t addr = (uint32_t)&__smmu_disable; - addr -= physMappingOffset; + paddr_t addr = addrFromPPtr(&do_smmu_disable); asm (".arch_extension sec\n"); asm volatile ("mov r0, %0\n\t" "dsb\nisb\n" "smc #0\n" ::"r"(addr)); - } else { /* in secure mode, can enable it directly */ smmu_regs->smmu_config = 0; @@ -51,8 +49,7 @@ static inline void smmu_enable(void) { if (config_set(ARM_HYP)) { - uint32_t addr = (uint32_t)&__smmu_enable; - addr -= physMappingOffset; + paddr_t addr = addrFromPPtr(&do_smmu_enable); asm (".arch_extension sec\n"); asm volatile ("mov r0, %0\n\t" "dsb\nisb\n" @@ -112,7 +109,7 @@ plat_smmu_ptc_flush_all(void) smmu_regs->smmu_ptc_flush = cmd; } -#define TLB_ASID_MATCH (1ul << 31) +#define TLB_ASID_MATCH BIT(31) #define TLB_FLUSH_ALL (0) #define TLB_FLUSH_SECTION (2) #define TLB_FLUSH_GROUP (3) @@ -124,18 +121,25 @@ plat_smmu_tlb_flush_all(void) smmu_regs->smmu_tlb_flush = cmd; } -#define MC_DECERR_MTS_BIT 16 -#define MC_SECERR_SEC_BIT 13 -#define MC_DECERR_VPR_BIT 12 -#define MC_APB_ASID_UPDATE_BIT 11 -#define MC_SMMU_PAGE_BIT 10 -#define MC_ARBITRATION_EMEM_BIT 9 -#define MC_SECURITY_BIT 8 -#define MC_DECERR_EMEM_BIT 6 +#define MC_DECERR_MTS_BIT 16u +#define MC_SECERR_SEC_BIT 13u +#define MC_DECERR_VPR_BIT 12u +#define MC_APB_ASID_UPDATE_BIT 11u +#define MC_SMMU_PAGE_BIT 10u +#define MC_ARBITRATION_EMEM_BIT 9u +#define MC_SECURITY_BIT 8u +#define MC_DECERR_EMEM_BIT 6u -/* using 4 MiB mapping for the Linxu guest VM */ +/* Using 4 MiB mapping for the Linxu guest VM. + * This is a temporary solution for enabling guest VM + * devices that need DMA while still providing some + * protections. Once the device untyped feature is done, + * this code should be replaced with proper user-mode + * VM initialisation code. + */ + #define IOPDE_4M_INDEX_SHIFT 22 static void plat_smmu_vm_mapping(word_t iopd, word_t gpa, word_t pa, word_t size) @@ -159,7 +163,7 @@ plat_smmu_vm_mapping(word_t iopd, word_t gpa, word_t pa, word_t size) BOOT_CODE int plat_smmu_init(void) { - int asid = 1; + uint32_t asid = 1; int i = 0; smmu_disable(); @@ -297,7 +301,7 @@ plat_smmu_handle_interrupt(void) #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; + uint32_t id = err_status & MC_ERR_ID_MASK; uint32_t rw = (err_status & MC_ERR_RW_MASK); uint32_t read = (err_status & MC_ERR_INVALID_SMMU_PAGE_READ_MASK); uint32_t write = (err_status & MC_ERR_INVALID_SMMU_PAGE_WRITE_MASK);