arm-hyp/tk1: address review comments.

This commit is contained in:
Yanyan Shen 2016-05-27 00:16:53 +10:00
parent 13ae16a76b
commit 27ecdffe3c
6 changed files with 145 additions and 100 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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