arm/tk1: connect objects with SMMU invocations

This commit is contained in:
Yanyan Shen 2016-05-17 12:16:34 +10:00
parent 55e58e1a41
commit 508e87477f
6 changed files with 112 additions and 7 deletions

View file

@ -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;

View file

@ -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

View file

@ -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 */

View file

@ -26,6 +26,7 @@
#include <plat/machine/devices.h>
#include <plat/machine/hardware.h>
#include <armv/context_switch.h>
#include <arch/object/iospace.h>
/* 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:

View file

@ -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

View file

@ -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);