From 508e87477f8c2bdd0933919a4b896288d432813d Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Tue, 17 May 2016 12:16:34 +1000 Subject: [PATCH] arm/tk1: connect objects with SMMU invocations --- .../arch/arm/arch/32/mode/object/structures.h | 7 ++ include/arch/arm/arch/kernel/vspace.h | 2 + .../arch_include/arm/sel4/arch/objecttype.h | 7 ++ src/arch/arm/32/kernel/vspace.c | 30 +++++++- src/arch/arm/32/object/objecttype.c | 69 +++++++++++++++++-- src/arch/arm/object/iospace.c | 4 ++ 6 files changed, 112 insertions(+), 7 deletions(-) diff --git a/include/arch/arm/arch/32/mode/object/structures.h b/include/arch/arm/arch/32/mode/object/structures.h index b561a4c5a..831800cd5 100644 --- a/include/arch/arm/arch/32/mode/object/structures.h +++ b/include/arch/arm/arch/32/mode/object/structures.h @@ -63,6 +63,10 @@ typedef word_t vm_rights_t; #define PT_BITS 8 #endif /* ARM_HYP */ +/* NOTE: the macros are defined based on Tegra K1 SMMU page table sizes */ +#define ARM_IOPTE_SIZE_BITS 2 +#define ARM_IOPT_BITS 10 + #define PDE_PTR(r) ((pde_t *)(r)) #define PDE_REF(p) ((unsigned int)p) @@ -366,6 +370,9 @@ cap_get_archCapPtr(cap_t cap) return VCPU_PTR(cap_vcpu_cap_get_capVCPUPtr(cap)); #endif + case cap_io_page_table_cap: + return (void *)(cap_io_page_table_cap_get_capIOPTBasePtr(cap)); + default: /* Unreachable, but GCC can't figure that out */ return NULL; diff --git a/include/arch/arm/arch/kernel/vspace.h b/include/arch/arm/arch/kernel/vspace.h index 3dbf8ab86..2043b736b 100644 --- a/include/arch/arm/arch/kernel/vspace.h +++ b/include/arch/arm/arch/kernel/vspace.h @@ -95,4 +95,6 @@ exception_t decodeARMMMUInvocation(word_t invLabel, word_t length, cptr_t cptr, word_t *buffer); +bool_t CONST isIOSpaceFrame(cap_t cap); + #endif diff --git a/libsel4/arch_include/arm/sel4/arch/objecttype.h b/libsel4/arch_include/arm/sel4/arch/objecttype.h index be0393b84..aa8451b1a 100644 --- a/libsel4/arch_include/arm/sel4/arch/objecttype.h +++ b/libsel4/arch_include/arm/sel4/arch/objecttype.h @@ -20,11 +20,18 @@ typedef enum _object { seL4_ARM_PageDirectoryObject, #ifdef ARM_HYP seL4_ARM_VCPUObject, +#endif +#ifdef CONFIG_ARM_SMMU + seL4_ARM_IOPageTableObject, #endif seL4_ObjectTypeCount } seL4_ArchObjectType; typedef seL4_Word object_t; +#ifndef CONFIG_ARM_SMMU +#define seL4_ARM_IOPageTableObject 0xffff +#endif + #endif /* __ARCH_OBJECTTYPE_H */ diff --git a/src/arch/arm/32/kernel/vspace.c b/src/arch/arm/32/kernel/vspace.c index 9a51df9fe..6b82b8e14 100644 --- a/src/arch/arm/32/kernel/vspace.c +++ b/src/arch/arm/32/kernel/vspace.c @@ -26,6 +26,7 @@ #include #include #include +#include /* ARM uses multiple identical mappings in a page table / page directory to construct * large mappings. In both cases it happens to be 16 entries, which can be calculated by @@ -1131,6 +1132,16 @@ isValidVTableRoot(cap_t cap) cap_page_directory_cap_get_capPDIsMapped(cap); } +bool_t CONST +isIOSpaceFrame(cap_t cap) +{ +#ifdef CONFIG_ARM_SMMU + return cap_get_capType(cap) == cap_small_frame_cap && cap_small_frame_cap_get_capFIsIOSpace(cap); +#else + return false; +#endif +} + void setVMRoot(tcb_t *tcb) { @@ -2547,6 +2558,13 @@ decodeARMFrameInvocation(word_t invLabel, word_t length, vm_page_size_t frameSize; vm_attributes_t attr; + if (isIOSpaceFrame(cap)) { + userError("ARMFrameRemap: Attempting to remap frame mapped into an IOSpace"); + current_syscall_error.type = seL4_IllegalOperation; + + return EXCEPTION_SYSCALL_ERROR; + } + if (unlikely(length < 2 || excaps.excaprefs[0] == NULL)) { current_syscall_error.type = seL4_TruncatedMessage; @@ -2647,8 +2665,16 @@ decodeARMFrameInvocation(word_t invLabel, word_t length, } case ARMPageUnmap: { - setThreadState(ksCurThread, ThreadState_Restart); - return performPageInvocationUnmap(cap, cte); + if (isIOSpaceFrame(cap)) { + return decodeARMIOUnMapInvocation(invLabel, length, cte, cap, excaps); + } else { + setThreadState(ksCurThread, ThreadState_Restart); + return performPageInvocationUnmap(cap, cte); + } + } + + case ARMPageMapIO: { + return decodeARMIOMapInvocation(invLabel, length, cte, cap, excaps, buffer); } case ARMPageClean_Data: diff --git a/src/arch/arm/32/object/objecttype.c b/src/arch/arm/32/object/objecttype.c index 08dc69477..5f987a4dc 100644 --- a/src/arch/arm/32/object/objecttype.c +++ b/src/arch/arm/32/object/objecttype.c @@ -74,6 +74,20 @@ Arch_deriveCap(cte_t *slot, cap_t cap) return ret; #endif + case cap_io_space_cap: + ret.cap = cap; + ret.status = EXCEPTION_NONE; + + case cap_io_page_table_cap: + if (cap_io_page_table_cap_get_capIOPTIsMapped(cap)) { + ret.cap = cap; + ret.status = EXCEPTION_NONE; + } else { + current_syscall_error.type = seL4_IllegalOperation; + ret.cap = cap_null_cap_new(); + ret.status = EXCEPTION_SYSCALL_ERROR; + } + return ret; default: /* This assert has no equivalent in haskell, * as the options are restricted by type */ @@ -140,6 +154,10 @@ Arch_finaliseCap(cap_t cap, bool_t final) case cap_small_frame_cap: if (cap_small_frame_cap_get_capFMappedASID(cap)) { + if (isIOSpaceFrame(cap)) { + unmapIOPage(cap); + break; + } unmapPage(ARMSmallPage, cap_small_frame_cap_get_capFMappedASID(cap), cap_small_frame_cap_get_capFMappedAddress(cap), @@ -163,6 +181,18 @@ Arch_finaliseCap(cap_t cap, bool_t final) } break; #endif + + case cap_io_space_cap: + break; + + case cap_io_page_table_cap: + if (final && cap_io_page_table_cap_get_capIOPTIsMapped(cap)) { + deleteIOPageTable(cap); + } + break; + + default: + break; } return cap_null_cap_new(); @@ -270,6 +300,15 @@ Arch_recycleCap(bool_t is_final, cap_t cap) return cap; #endif + case cap_io_space_cap: + Arch_finaliseCap(cap, is_final); + return cap; + + case cap_io_page_table_cap: + clearMemory((void *)cap_get_capPtr(cap), cap_get_capSizeBits(cap)); + Arch_finaliseCap(cap, is_final); + return cap; + default: fail("Arch_recycleCap: invalid cap type"); } @@ -344,6 +383,19 @@ Arch_sameRegionAs(cap_t cap_a, cap_t cap_b) break; #endif + case cap_io_space_cap: + if (cap_get_capType(cap_b) == cap_io_space_cap) { + return cap_io_space_cap_get_capModuleID(cap_a) == + cap_io_space_cap_get_capModuleID(cap_b); + } + break; + + case cap_io_page_table_cap: + if (cap_get_capType(cap_b) == cap_io_page_table_cap) { + return cap_io_page_table_cap_get_capIOPTBasePtr(cap_a) == + cap_io_page_table_cap_get_capIOPTBasePtr(cap_b); + } + break; } return false; @@ -390,6 +442,8 @@ Arch_getObjectSize(word_t t) return PTE_SIZE_BITS + PT_BITS; case seL4_ARM_PageDirectoryObject: return PDE_SIZE_BITS + PD_BITS; + case seL4_ARM_IOPageTableObject: + return ARM_IOPTE_SIZE_BITS + ARM_IOPT_BITS; #ifdef ARM_HYP case seL4_ARM_VCPUObject: return VCPU_SIZE_BITS; @@ -516,13 +570,18 @@ Arch_decodeInvocation(word_t invLabel, word_t length, cptr_t cptr, cte_t *slot, cap_t cap, extra_caps_t excaps, word_t *buffer) { + switch (cap_get_capType(cap)) { + case cap_io_space_cap: + return decodeARMIOSpaceInvocation(invLabel, cap); + case cap_io_page_table_cap: + return decodeARMIOPTInvocation(invLabel, length, slot, cap, excaps, buffer); #ifdef ARM_HYP - if (cap_get_capType(cap) == cap_vcpu_cap) { - return decodeARMVCPUInvocation(invLabel, length, cptr, slot, cap, excaps, buffer); - + case cap_vcpu_cap: + return decodeARMVCPUInvocation(invLabel, length, cptr, slot, cap, excaps, buffer); +#endif /* end of ARM_HYP */ + default: + return decodeARMMMUInvocation(invLabel, length, cptr, slot, cap, excaps, buffer); } -#endif /* ARM_HYP */ - return decodeARMMMUInvocation(invLabel, length, cptr, slot, cap, excaps, buffer); } void diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index 446b1ef0a..a98645c60 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -329,7 +329,9 @@ decodeARMIOMapInvocation( 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; @@ -421,7 +423,9 @@ decodeARMIOUnMapInvocation( { unmapIOPage(slot->cap); slot->cap = cap_small_frame_cap_set_capFMappedAddress(slot->cap, 0); +#ifdef CONFIG_ARM_SMMU slot->cap = cap_small_frame_cap_set_capFIsIOSpace(slot->cap, 0); +#endif slot->cap = cap_small_frame_cap_set_capFMappedASID(slot->cap, asidInvalid); setThreadState(ksCurThread, ThreadState_Restart);