From 879d9724c13a3aac9d460ef28515f46569ae09e9 Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Fri, 13 May 2016 16:42:53 +1000 Subject: [PATCH 01/18] arm/tk1: a checkpoint for SMMU implementation --- .../arm/arch/32/mode/object/structures.bf | 21 +- .../arch/arm/arch/32/mode/object/structures.h | 4 + include/arch/arm/arch/object/iospace.h | 28 ++ include/plat/tk1/plat/machine/devices.h | 2 + include/plat/tk1/plat/machine/smmu.h | 148 +++++++++ .../arch_include/arm/interfaces/sel4arch.xml | 13 + libsel4/arch_include/arm/sel4/arch/types.h | 3 + libsel4/include/sel4/bootinfo_types.h | 1 + libsel4/tools/syscall_stub_gen.py | 2 + src/arch/arm/32/kernel/vspace.c | 3 + src/arch/arm/32/object/objecttype.c | 6 +- src/arch/arm/kernel/boot.c | 4 + src/arch/arm/object/Makefile | 2 +- src/arch/arm/object/iospace.c | 299 ++++++++++++++++++ src/arch/arm/object/vcpu.c | 8 + src/plat/tk1/machine/Makefile | 3 +- src/plat/tk1/machine/hardware.c | 18 +- src/plat/tk1/machine/smmu.c | 206 ++++++++++++ 18 files changed, 760 insertions(+), 11 deletions(-) create mode 100644 include/arch/arm/arch/object/iospace.h create mode 100644 include/plat/tk1/plat/machine/smmu.h create mode 100644 src/arch/arm/object/iospace.c create mode 100644 src/plat/tk1/machine/smmu.c diff --git a/include/arch/arm/arch/32/mode/object/structures.bf b/include/arch/arm/arch/32/mode/object/structures.bf index 35e4ee304..771f166db 100644 --- a/include/arch/arm/arch/32/mode/object/structures.bf +++ b/include/arch/arm/arch/32/mode/object/structures.bf @@ -8,6 +8,7 @@ -- @TAG(GD_GPL) -- +#include -- Default base size: uint32_t base 32 @@ -25,7 +26,12 @@ block small_frame_cap { field capFVMRights 2 field_high capFMappedAddress 20 +#ifdef CONFIG_ARM_SMMU + field capFIsIOSpace 1 + field capFMappedASIDHigh 7 +#else field capFMappedASIDHigh 8 +#endif field_high capFBasePtr 20 field capType 4 } @@ -127,14 +133,15 @@ block io_page_directory_cap (capType, capIOPDIsMapped, capIOPDASID, capIOPDBaseP field capType 8 } -block io_page_table_cap (capType, capIOPTIsMapped, capIOPTASID, capIOPTBasePtr) { - field_high capIOPTBasePtr 20 - padding 12 +block io_page_table_cap (capType, capIOPTIsMapped, capIOPTASID, capIOPTBasePtr, capIOPTMappedAddress) { + field_high capIOPTBasePtr 20 + padding 12 - padding 16 - field capIOPTASID 7 - field capIOPTIsMapped 1 - field capType 8 + field_high capIOPTMappedAddress 10 + padding 6 + field capIOPTASID 7 + field capIOPTIsMapped 1 + field capType 8 } -- NB: odd numbers are arch caps (see isArchCap()) diff --git a/include/arch/arm/arch/32/mode/object/structures.h b/include/arch/arm/arch/32/mode/object/structures.h index 92fbe63d2..b561a4c5a 100644 --- a/include/arch/arm/arch/32/mode/object/structures.h +++ b/include/arch/arm/arch/32/mode/object/structures.h @@ -112,7 +112,11 @@ struct user_data { typedef struct user_data user_data_t; enum asidSizeConstants { +#ifdef CONFIG_ARM_SMMU + asidHighBits = 7, +#else asidHighBits = 8, +#endif asidLowBits = 10 }; diff --git a/include/arch/arm/arch/object/iospace.h b/include/arch/arm/arch/object/iospace.h new file mode 100644 index 000000000..09c26708e --- /dev/null +++ b/include/arch/arm/arch/object/iospace.h @@ -0,0 +1,28 @@ +/* + * Copyright 2016, General Dynamics C4 Systems + * + * This software may be distributed and modified according to the terms of + * the GNU General Public License version 2. Note that NO WARRANTY is provided. + * See "LICENSE_GPLv2.txt" for details. + * + * @TAG(GD_GPL) + */ + +#ifndef __ARCH_OBJECT_IOSPACE_H +#define __ARCH_OBJECT_IOSPACE_H + +#include +#include +#include + + +seL4_SlotRegion create_iospace_caps(cap_t root_cnode_cap); +exception_t decodeARMIOPTInvocation(word_t invLabel, uint32_t length, cte_t* slot, cap_t cap, extra_caps_t excaps, word_t* buffer); +exception_t decodeARMIOMapInvocation(word_t invLabel, uint32_t length, cte_t* slot, cap_t cap, extra_caps_t excaps, word_t* buffer); +exception_t decodeARMIOUnMapInvocation(word_t invLabel, uint32_t length, cte_t* slot, cap_t cap, extra_caps_t excaps); +exception_t decodeARMIOSpaceInvocation(word_t invLabel, cap_t cap); +void unmapIOPage(cap_t cap); +void deleteIOPageTable(cap_t cap); + +#endif + diff --git a/include/plat/tk1/plat/machine/devices.h b/include/plat/tk1/plat/machine/devices.h index c24d5569e..a8973fbc2 100644 --- a/include/plat/tk1/plat/machine/devices.h +++ b/include/plat/tk1/plat/machine/devices.h @@ -21,6 +21,8 @@ #define GIC_CONTROLLER_PPTR 0xfff04000 /* HYP mode kernel devices */ #define GIC_VCPUCTRL_PPTR 0xfff06000 +/* SMMU registers */ +#define SMMU_PPTR 0Xfff07000 #define GIC_PL390_CONTROLLER_PPTR GIC_CONTROLLER_PPTR #define GIC_PL390_DISTRIBUTOR_PPTR GIC_DISTRIBUTOR_PPTR diff --git a/include/plat/tk1/plat/machine/smmu.h b/include/plat/tk1/plat/machine/smmu.h new file mode 100644 index 000000000..a4b1e9187 --- /dev/null +++ b/include/plat/tk1/plat/machine/smmu.h @@ -0,0 +1,148 @@ +/* + * Copyright 2016, General Dynamics C4 Systems + * + * This software may be distributed and modified according to the terms of + * the GNU General Public License version 2. Note that NO WARRANTY is provided. + * See "LICENSE_GPLv2.txt" for details. + * + * @TAG(GD_GPL) + */ + +#ifndef __PLAT_SMMU_H +#define __PLAT_SMMU_H + +#include + +#define IOASID_SIZE_BITS 7 + + + +/* The SystemMMU control registers are part of memory controller */ + +typedef struct { + uint32_t intstatus; /* 0x00 */ + uint32_t intmask; /* 0x04 */ + uint32_t err_status; /* 0x08 */ + uint32_t err_adr; /* 0x0c */ + uint32_t smmu_config; /* 0x10 */ + uint32_t smmu_tlb_config; /* 0x14 */ + 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 smmu_tlb_flush; /* 0x30 */ + uint32_t smmu_ptc_flush; /* 0x34 */ + uint32_t rev3[124]; + uint32_t smmu_translation_enable_0; /* 0x228 */ + uint32_t smmu_translation_enable_1; /* 0x22c */ + uint32_t smmu_translation_enable_2; /* 0x230 */ + uint32_t smmu_translation_enable_3; /* 0x234 */ + uint32_t smmu_afi_asid; /* 0x238 */ + 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 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 smmu_msenc_asid; /* 0x264 */ + uint32_t smmu_nv_asid; /* 0x268 */ + uint32_t smmu_nv2_asid; /* 0x26c */ + uint32_t smmu_ppcs_asid; /* 0x270 */ + uint32_t smmu_sata_asid; /* 0x274 */ + uint32_t smmu_vde_asid; /* 0x27c */ + uint32_t smmu_vi_asid; /* 0x280 */ + 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 smmu_tsec_asid; /* 0x294 */ + uint32_t smmu_ppcs1_asid; /* 0x298 */ + uint32_t rev9[217]; + uint32_t smmu_tlb_set_sel_mask; /* 0x600 */ + uint32_t rev10[237]; + uint32_t smmu_ptc_flush_1; /* 0x9b8 */ + uint32_t rev11[51]; + uint32_t smmu_dc1_asid; /* 0xa88 */ + uint32_t rev12; /* 0xa8c */ + uint32_t rev13; /* 0xa90 */ + uint32_t smmu_sdmmc1a_asid; /* 0xa94 */ + uint32_t smmu_sdmmc2a_asid; /* 0xa98 */ + uint32_t smmu_sdmmc3a_asid; /* 0xa9c */ + uint32_t smmu_sdmmc4a_asid; /* 0xaa0 */ + uint32_t smmu_isp2b_asid; /* 0xaa4 */ + uint32_t smmu_gpu_asid; /* 0xaa8 */ + uint32_t smmu_gpub_asid; /* 0xaac */ + uint32_t smmu_ppcs2_asid; /* 0xab0 */ +} tk1_mc_regs_t; + +/* we start to allocate IO ASIDs from 1, and each module's ASID + * is fixed (i.e. users are not allowed to dynamically allocate + * ASIDs and assign them to devices). + */ +#define SMMU_FIRST_ASID 1 +#define SMMU_AFI_ASID 1 +#define SMMU_AVPC_ASID 2 +#define SMMU_DC_ASID 3 +#define SMMU_DCB_ASID 4 +#define SMMU_HC_ASID 5 +#define SMMU_HDA_ASID 6 +#define SMMU_ISP2_ASID 7 +#define SMMU_MSENC_ASID 8 +#define SMMU_NV_ASID 9 +#define SMMU_NV2_ASID 10 +#define SMMU_PPCS_ASID 11 +#define SMMU_SATA_ASID 12 +#define SMMU_VDE_ASID 13 +#define SMMU_VI_ASID 14 +#define SMMU_VIC_ASID 15 +#define SMMU_XUSB_HOST_ASID 16 +#define SMMU_XUSB_DEV_ASID 17 +#define SMMU_TSEC_ASID 18 +#define SMMU_PPCS1_ASID 19 +#define SMMU_DC1_ASID 20 +#define SMMU_SDMMC1A_ASID 21 +#define SMMU_SDMMC2A_ASID 22 +#define SMMU_SDMMC3A_ASID 23 +#define SMMU_SDMMC4A_ASID 24 +#define SMMU_ISP2B_ASID 25 +#define SMMU_GPU_ASID 26 +#define SMMU_GPUB_ASID 27 +#define SMMU_PPCS2_ASID 28 +#define SMMU_LAST_ASID 28 + +#define ARM_PLAT_NUM_SMMU 28 + +#define SMMU_PD_BITS 12 +#define SMMU_PT_BITS 12 + +#define SMMU_IOPD_INDEX_MASK 0xffc00000 +#define SMMU_IOPD_INDEX_SHIFT 20 +#define SMMU_IOPT_INDEX_MASK 0x3ff000 +#define SMMU_IOPT_INDEX_SHIFT 12 + +inline static uint32_t +plat_smmu_iopd_index(word_t io_address) +{ + uint32_t ret = (io_address & SMMU_IOPD_INDEX_MASK) >> SMMU_IOPD_INDEX_SHIFT; + return ret; +} + +inline static uint32_t +plat_smmu_iopt_index(word_t io_address) +{ + uint32_t ret = (io_address & SMMU_IOPT_INDEX_MASK) >> SMMU_IOPT_INDEX_SHIFT; + return ret; +} + +int plat_smmu_init(void); +void plat_smmu_tlb_flush_all(void); +void plat_smmu_ptc_flush_all(void); +iopde_t *plat_smmu_lookup_iopd_by_asid(uint32_t asid); + +#endif diff --git a/libsel4/arch_include/arm/interfaces/sel4arch.xml b/libsel4/arch_include/arm/interfaces/sel4arch.xml index 6c3ed354a..a1575aac6 100644 --- a/libsel4/arch_include/arm/interfaces/sel4arch.xml +++ b/libsel4/arch_include/arm/interfaces/sel4arch.xml @@ -18,6 +18,14 @@ + + + + + + + + @@ -31,6 +39,11 @@ + + + + + diff --git a/libsel4/arch_include/arm/sel4/arch/types.h b/libsel4/arch_include/arm/sel4/arch/types.h index 2b7019124..8e3316913 100644 --- a/libsel4/arch_include/arm/sel4/arch/types.h +++ b/libsel4/arch_include/arm/sel4/arch/types.h @@ -20,5 +20,8 @@ typedef seL4_CPtr seL4_ARM_PageDirectory; typedef seL4_CPtr seL4_ARM_ASIDControl; typedef seL4_CPtr seL4_ARM_ASIDPool; typedef seL4_CPtr seL4_ARM_VCPU; +typedef seL4_CPtr seL4_ARM_IOSpace; +typedef seL4_CPtr seL4_ARM_IOPageTable; + #endif /* __ARCH_SEL4TYPES_H__ */ diff --git a/libsel4/include/sel4/bootinfo_types.h b/libsel4/include/sel4/bootinfo_types.h index 5b302022f..06ae109c0 100644 --- a/libsel4/include/sel4/bootinfo_types.h +++ b/libsel4/include/sel4/bootinfo_types.h @@ -57,6 +57,7 @@ typedef struct { seL4_SlotRegion userImageFrames; /* userland-image frame caps */ seL4_SlotRegion userImagePaging; /* userland-image paging structure caps */ seL4_SlotRegion untyped; /* untyped-object caps (untyped caps) */ + seL4_SlotRegion ioSpaceCaps; /* IOSpace caps for ARM SMMU */ seL4_PAddr untypedPaddrList [CONFIG_MAX_NUM_BOOTINFO_UNTYPED_CAPS]; /* physical address of each untyped cap */ seL4_Uint8 untypedSizeBitsList[CONFIG_MAX_NUM_BOOTINFO_UNTYPED_CAPS]; /* size (2^n) bytes of each untyped cap */ seL4_Uint8 initThreadCNodeSizeBits; /* initial thread's root CNode size (2^n slots) */ diff --git a/libsel4/tools/syscall_stub_gen.py b/libsel4/tools/syscall_stub_gen.py index 5327a750f..a7af603f2 100644 --- a/libsel4/tools/syscall_stub_gen.py +++ b/libsel4/tools/syscall_stub_gen.py @@ -242,6 +242,8 @@ def InitTypes(): CapType("seL4_ARM_ASIDControl"), CapType("seL4_ARM_ASIDPool"), CapType("seL4_ARM_VCPU"), + CapType("seL4_ARM_IOSpace"), + CapType("seL4_ARM_IOPageTable"), StructType("seL4_UserContext", WORD_SIZE_BITS * 17), ], diff --git a/src/arch/arm/32/kernel/vspace.c b/src/arch/arm/32/kernel/vspace.c index ebdc40cc9..9a51df9fe 100644 --- a/src/arch/arm/32/kernel/vspace.c +++ b/src/arch/arm/32/kernel/vspace.c @@ -513,6 +513,9 @@ create_it_frame_cap(pptr_t pptr, vptr_t vptr, asid_t asid, bool_t use_large) ASID_LOW(asid), /* capFMappedASIDLow */ wordFromVMRights(VMReadWrite), /* capFVMRights */ vptr, /* capFMappedAddress */ +#ifdef CONFIG_ARM_SMMU + 0, /* IOSpace */ +#endif ASID_HIGH(asid), /* capFMappedASIDHigh */ pptr /* capFBasePtr */ ); diff --git a/src/arch/arm/32/object/objecttype.c b/src/arch/arm/32/object/objecttype.c index 0cac096b4..08dc69477 100644 --- a/src/arch/arm/32/object/objecttype.c +++ b/src/arch/arm/32/object/objecttype.c @@ -417,7 +417,11 @@ Arch_createObject(object_t t, void *regionBase, word_t userSize) return cap_small_frame_cap_new( ASID_LOW(asidInvalid), VMReadWrite, - 0, ASID_HIGH(asidInvalid), + 0, +#ifdef CONFIG_ARM_SMMU + 0, +#endif + ASID_HIGH(asidInvalid), (word_t)regionBase); case seL4_ARM_LargePageObject: diff --git a/src/arch/arm/kernel/boot.c b/src/arch/arm/kernel/boot.c index b7296891e..8d45b5ce1 100644 --- a/src/arch/arm/kernel/boot.c +++ b/src/arch/arm/kernel/boot.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -234,6 +235,9 @@ try_init_kernel( return false; } + if (config_set(CONFIG_ARM_SMMU)) { + create_iospace_caps(root_cnode_cap); + } /* Construct an initial address space with enough virtual addresses * to cover the user image + ipc buffer and bootinfo frames */ it_pd_cap = create_it_address_space(root_cnode_cap, it_v_reg); diff --git a/src/arch/arm/object/Makefile b/src/arch/arm/object/Makefile index 3c259eb96..13aa54560 100644 --- a/src/arch/arm/object/Makefile +++ b/src/arch/arm/object/Makefile @@ -10,7 +10,7 @@ DIRECTORIES += src/arch/arm/object -ARCH_C_SOURCES += object/interrupt.c object/tcb.c +ARCH_C_SOURCES += object/interrupt.c object/tcb.c object/iospace.c ifneq (ARM_HYP,) ARCH_C_SOURCES += object/vcpu.c diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c new file mode 100644 index 000000000..820ee7905 --- /dev/null +++ b/src/arch/arm/object/iospace.c @@ -0,0 +1,299 @@ +/* + * Copyright 2016, General Dynamics C4 Systems + * + * This software may be distributed and modified according to the terms of + * the GNU General Public License version 2. Note that NO WARRANTY is provided. + * See "LICENSE_GPLv2.txt" for details. + * + * @TAG(GD_GPL) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef struct lookupIOPDSlot_ret { + exception_t status; + iopde_t *iopdSlot; +} lookupIOPDSlot_ret_t; + +typedef struct lookupIOPTSlot_ret { + exception_t status; + iopte_t *ioptSlot; +} lookupIOPTSlot_ret_t; + +static lookupIOPDSlot_ret_t +lookupIOPDSlot(iopde_t *iopd, word_t io_address) +{ + lookupIOPDSlot_ret_t ret; + uint32_t index = plat_smmu_iopd_index(io_address); + ret.status = EXCEPTION_NONE; + ret.iopdSlot = iopd + index; + return ret; +} + +static lookupIOPTSlot_ret_t +lookupIOPTSlot(iopde_t *iopd, word_t io_address) +{ + lookupIOPTSlot_ret_t pt_ret; + uint32_t index; + iopte_t *pt; + + lookupIOPDSlot_ret_t pd_ret = lookupIOPDSlot(iopd, io_address); + if (pd_ret.status != EXCEPTION_NONE) { + pt_ret.status = EXCEPTION_LOOKUP_FAULT; + pt_ret.ioptSlot = 0; + return pt_ret; + } + index = plat_smmu_iopt_index(io_address); + pt = (iopte_t *)paddr_to_pptr(iopde_iopde_pt_ptr_get_address(pd_ret.iopdSlot)); + pt_ret.status = EXCEPTION_NONE; + pt_ret.ioptSlot = pt + index; + return pt_ret; +} + +BOOT_CODE seL4_SlotRegion +create_iospace_caps(cap_t root_cnode_cap) +{ + seL4_SlotPos start = ndks_boot.slot_pos_cur; + seL4_SlotPos end = 0; + cap_t io_space_cap; + int i = 0; + int num_smmu = plat_smmu_init(); + + if (num_smmu == 0) { + printf("SMMU init failuer\n"); + return (seL4_SlotRegion) S_REG_EMPTY; + } + + for (i = 0; i < num_smmu; i++) { + io_space_cap = cap_io_space_cap_new(i, i); + if (!provide_cap(root_cnode_cap, io_space_cap)) { + return (seL4_SlotRegion) S_REG_EMPTY; + } + } + return (seL4_SlotRegion) {start, end}; +} + + +exception_t +decodeARMIOPTInvocation( + word_t invLabel, + uint32_t length, + cte_t* slot, + cap_t cap, + extra_caps_t excaps, + word_t* buffer +) +{ + cap_t io_space; + word_t io_address; + uint16_t module_id; + (void)io_address; + + if (invLabel == ARMIOPageTableUnmap) { + deleteIOPageTable(slot->cap); + slot->cap = cap_io_page_table_cap_set_capIOPTIsMapped(slot->cap, 0); + + setThreadState(ksCurThread, ThreadState_Restart); + return EXCEPTION_NONE; + } + + if (excaps.excaprefs[0] == NULL || length < 1) { + current_syscall_error.type = seL4_TruncatedMessage; + return EXCEPTION_SYSCALL_ERROR; + } + + if (invLabel != ARMIOPageTableMap ) { + current_syscall_error.type = seL4_IllegalOperation; + return EXCEPTION_SYSCALL_ERROR; + } + + io_space = excaps.excaprefs[0]->cap; + io_address = getSyscallArg(0, buffer) & ~MASK(PAGE_BITS); + + if (cap_io_page_table_cap_get_capIOPTIsMapped(cap)) { + 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) { + current_syscall_error.type = seL4_InvalidCapability; + current_syscall_error.invalidCapNumber = 0; + return EXCEPTION_SYSCALL_ERROR; + } + + module_id= cap_io_space_cap_get_capModuleID(io_space); + if (module_id == asidInvalid) { + current_syscall_error.type = seL4_InvalidCapability; + current_syscall_error.invalidCapNumber = 0; + + return EXCEPTION_SYSCALL_ERROR; + } + + + slot->cap = cap; + + setThreadState(ksCurThread, ThreadState_Restart); + return EXCEPTION_NONE; +} + +exception_t +decodeARMIOMapInvocation( + word_t invLabel, + uint32_t length, + cte_t* slot, + cap_t cap, + extra_caps_t excaps, + word_t* buffer +) +{ + cap_t io_space; + paddr_t io_address; + paddr_t paddr; + uint32_t module_id; + (void)paddr; + (void)io_address; + + if (excaps.excaprefs[0] == NULL || length < 2) { + current_syscall_error.type = seL4_TruncatedMessage; + return EXCEPTION_SYSCALL_ERROR; + } + + if (cap_frame_cap_get_capFSize(cap) != ARMSmallPage) { + current_syscall_error.type = seL4_InvalidCapability; + current_syscall_error.invalidCapNumber = 0; + return EXCEPTION_SYSCALL_ERROR; + } + + if (cap_frame_cap_get_capFMappedASID(cap) != asidInvalid) { + current_syscall_error.type = seL4_InvalidCapability; + current_syscall_error.invalidCapNumber = 0; + return EXCEPTION_SYSCALL_ERROR; + } + + io_space = excaps.excaprefs[0]->cap; + io_address = getSyscallArg(1, buffer) & ~MASK(PAGE_BITS); + paddr = pptr_to_paddr((void*)cap_frame_cap_get_capFBasePtr(cap)); + + if (cap_get_capType(io_space) != cap_io_space_cap) { + current_syscall_error.type = seL4_InvalidCapability; + current_syscall_error.invalidCapNumber = 0; + return EXCEPTION_SYSCALL_ERROR; + } + + module_id = cap_io_space_cap_get_capModuleID(io_space); + + if (module_id == asidInvalid) { + current_syscall_error.type = seL4_InvalidCapability; + current_syscall_error.invalidCapNumber = 0; + return EXCEPTION_SYSCALL_ERROR; + } + + slot->cap = cap; + + setThreadState(ksCurThread, ThreadState_Restart); + return EXCEPTION_NONE; +} + +void deleteIOPageTable(cap_t io_pt_cap) +{ + + uint32_t asid; + iopde_t *pd; + lookupIOPDSlot_ret_t lu_ret; + word_t io_address; + if (cap_io_page_table_cap_get_capIOPTIsMapped(io_pt_cap)) { + io_pt_cap = cap_io_page_table_cap_set_capIOPTIsMapped(io_pt_cap, 0); + asid = cap_io_page_table_cap_get_capIOPTASID(io_pt_cap); + pd = (iopde_t *)plat_smmu_lookup_iopd_by_asid(asid); + io_address = cap_io_page_table_cap_get_capIOPTMappedAddress(io_pt_cap); + + if (pd == 0) { + } + + lu_ret = lookupIOPDSlot(pd, io_address); + if (lu_ret.status != EXCEPTION_NONE) { + + } + + if (iopde_iopde_pt_ptr_get_address(lu_ret.iopdSlot) != cap_io_page_table_cap_get_capIOPTBasePtr(io_pt_cap)) { + return; + } + + iopde_iopde_pt_ptr_new(lu_ret.iopdSlot, 0, 0, 0, 0); + cleanCacheRange_RAM((word_t)lu_ret.iopdSlot, + ((word_t)lu_ret.iopdSlot) + sizeof(iopde_t), + addrFromPPtr(lu_ret.iopdSlot)); + + + /* TODO flush by address and asid */ + plat_smmu_tlb_flush_all(); + plat_smmu_ptc_flush_all(); + } +} + +void unmapIOPage(cap_t cap) +{ + lookupIOPTSlot_ret_t lu_ret; + iopde_t *pd; + word_t io_address; + uint32_t asid; + + io_address = cap_frame_cap_get_capFMappedAddress(cap); + asid = cap_frame_cap_get_capFMappedASID(cap); + pd = (iopde_t *)plat_smmu_lookup_iopd_by_asid(asid); + + if (pd == 0) { + return; + } + + lu_ret = lookupIOPTSlot(pd, io_address); + + if (lu_ret.status != EXCEPTION_NONE) { + return; + } + if (iopte_ptr_get_address(lu_ret.ioptSlot) != cap_frame_cap_get_capFBasePtr(cap)) { + return; + } + + iopte_ptr_new(lu_ret.ioptSlot, 0, 0, 0, 0); + 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(); + return; +} + +exception_t +decodeARMIOUnMapInvocation( + word_t invLabel, + uint32_t length, + cte_t* slot, + cap_t cap, + extra_caps_t excaps +) +{ + setThreadState(ksCurThread, ThreadState_Restart); + return EXCEPTION_NONE; +} + +exception_t decodeARMIOSpaceInvocation(word_t invLabel, cap_t cap) +{ + userError("IOSpace capability has no invocations"); + current_syscall_error.type = seL4_IllegalOperation; + return EXCEPTION_SYSCALL_ERROR; +} + diff --git a/src/arch/arm/object/vcpu.c b/src/arch/arm/object/vcpu.c index ae9343812..6f3287e46 100644 --- a/src/arch/arm/object/vcpu.c +++ b/src/arch/arm/object/vcpu.c @@ -43,9 +43,17 @@ #define HCR_SWIO BIT( 1) /* set/way invalidate override */ #define HCR_VM BIT( 0) /* Virtualization MMU enable */ +#ifdef CONFIG_ARM_SMMU +/* Trap WFI/WFE/SMC and override CPSR.AIF */ +#define HCR_COMMON ( HCR_TWE | HCR_TWI | HCR_AMO | HCR_IMO \ + | HCR_FMO | HCR_DC | HCR_VM) +#else + /* 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) + +#endif /* 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/Makefile b/src/plat/tk1/machine/Makefile index 1af784eaf..346ecd7ad 100644 --- a/src/plat/tk1/machine/Makefile +++ b/src/plat/tk1/machine/Makefile @@ -11,7 +11,8 @@ DIRECTORIES += src/plat/$(PLAT)/machine PLAT_C_SOURCES += machine/hardware.c \ - machine/l2cache.c + machine/l2cache.c \ + machine/smmu.c ifdef DEBUG PLAT_C_SOURCES += machine/io.c diff --git a/src/plat/tk1/machine/hardware.c b/src/plat/tk1/machine/hardware.c index ef2063dfb..dc43fec1f 100644 --- a/src/plat/tk1/machine/hardware.c +++ b/src/plat/tk1/machine/hardware.c @@ -23,7 +23,8 @@ const p_region_t BOOT_RODATA avail_p_regs[] = { // { .start = 0x80000000, .end = 0xf0000000 } - { .start = 0x80000000, .end = 0xb0000000 } + //{ .start = 0x80000000, .end = 0xb0000000 } + { .start = 0x80000000, .end = 0xa7f00000 } }; BOOT_CODE int get_num_avail_p_regs(void) @@ -81,7 +82,9 @@ const p_region_t BOOT_RODATA dev_p_regs[] = { { TSENSOR_PADDR, TSENSOR_PADDR + PAGE_SIZE }, /* 4 KB */ { CEC_PADDR, CEC_PADDR + PAGE_SIZE }, /* 4 KB */ { ATOMICS_PADDR, ATOMICS_PADDR + (PAGE_SIZE * 2) }, /* 8 KB */ +#ifndef CONFIG_ARM_SMMU { MC_PADDR, MC_PADDR + PAGE_SIZE }, /* 4 KB */ +#endif { EMC_PADDR, EMC_PADDR + PAGE_SIZE }, /* 4 KB */ { SATA_PADDR, SATA_PADDR + (PAGE_SIZE * 16) }, /* 64 KB */ { HDA_PADDR, HDA_PADDR + (PAGE_SIZE * 16) }, /* 64 KB */ @@ -178,6 +181,19 @@ map_kernel_devices(void) ); } + if (config_set(CONFIG_ARM_SMMU)) { + map_kernel_frame( + MC_PADDR, + SMMU_PPTR, + VMKernelOnly, + vm_attributes_new( + false, + false, + false + ) + ); + } + #if defined DEBUG || defined RELEASE_PRINTF /* map kernel device: UART */ map_kernel_frame( diff --git a/src/plat/tk1/machine/smmu.c b/src/plat/tk1/machine/smmu.c new file mode 100644 index 000000000..ab405b36e --- /dev/null +++ b/src/plat/tk1/machine/smmu.c @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include +#include + + +static volatile tk1_mc_regs_t *smmu_regs = (volatile tk1_mc_regs_t *)(SMMU_PPTR); + + +void printkk(void); +void +printkk(void) +{ + volatile uint32_t *reg = (volatile uint32_t *)(0x70006300); + int i = 'a'; + for (; i < 'z'; i++) { + *reg = i; + } +} + +#define SMMU_CONFIG_OFFSET 0x10 + +static void +__smmu_enable(void) +{ + volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET); + *config = 1; +} + +static void +__smmu_disable(void) +{ + volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET); + *config = 0; +} + + +static inline void +smmu_disable(void) +{ + /* we need physical address here */ + uint32_t addr = (uint32_t)&__smmu_disable; + addr -= 0x60000000; + asm (".arch_extension sec\n"); + asm volatile ("mov r0, %0\n\t" + "dsb\nisb\n" + "smc #0\n" + ::"r"(addr)); + + return; +} + +static inline void +smmu_enable(void) +{ + uint32_t addr = (uint32_t)&__smmu_enable; + addr -= 0x60000000; + asm (".arch_extension sec\n"); + asm volatile ("mov r0, %0\n\t" + "dsb\nisb\n" + "smc #0\n" + ::"r"(addr)); + + return; +} + + +#define PTB_DATA_BASE_SHIFT 12 +#define PTB_DATA_READ (1ul << 31) +#define PTB_DATA_WRITE (1ul << 30) +#define PTB_DATA_NONSECURE (1ul << 29) +#define PTB_DATA_BASE_PD_MASK 0x3fffff + +#define MODULE_ASID_ENABLE (1ul << 31) + +static uint32_t +make_ptb_data(uint32_t pd_base, bool_t read, bool_t write, bool_t nonsecure) +{ + uint32_t ret = 0; + ret = (pd_base >> PTB_DATA_BASE_SHIFT); + + if (read) { + ret |= PTB_DATA_READ; + } + if (write) { + ret |= PTB_DATA_WRITE; + } + if (nonsecure) { + ret |= PTB_DATA_NONSECURE; + } + + return ret; +} + +static uint32_t +ptb_data_get_pd_base(uint32_t data) +{ + uint32_t ret = data; + ret &= PTB_DATA_BASE_PD_MASK; + ret <<= PTB_DATA_BASE_SHIFT; + return ret; +} + +#define PTC_FLUSH_ALL 0 +#define PTC_FLUSH_ADR 1 + +void +plat_smmu_ptc_flush_all(void) +{ + uint32_t cmd = PTC_FLUSH_ALL; + smmu_regs->smmu_ptc_flush = cmd; +} + +#define TLB_ASID_MATCH (1ul << 31) +#define TLB_FLUSH_ALL (0) +#define TLB_FLUSH_SECTION (2) +#define TLB_FLUSH_GROUP (3) + +void +plat_smmu_tlb_flush_all(void) +{ + uint32_t cmd = TLB_FLUSH_ALL; + smmu_regs->smmu_tlb_flush = cmd; +} + +BOOT_CODE int +plat_smmu_init(void) +{ + int asid = 1; + int i = 0; + (void) (smmu_regs); + (void) (asid); + 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)); + 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++; + } + printf("Total %d IOASID set up\n", (asid - 1)); + + /* now assign IOASID to each module */ + smmu_regs->smmu_afi_asid = SMMU_AFI_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_avpc_asid = SMMU_AVPC_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_dc_asid = SMMU_DC_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_dcb_asid = SMMU_DCB_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_hc_asid = SMMU_HC_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_hda_asid = SMMU_HDA_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_isp2_asid = SMMU_ISP2_ASID | MODULE_ASID_ENABLE; + 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_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; + smmu_regs->smmu_vic_asid = SMMU_VIC_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_xusb_host_asid = SMMU_XUSB_HOST_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_xusb_dev_asid = SMMU_XUSB_DEV_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_tsec_asid = SMMU_TSEC_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_ppcs1_asid = SMMU_PPCS1_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_sdmmc1a_asid = SMMU_SDMMC1A_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_sdmmc2a_asid = SMMU_SDMMC2A_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_sdmmc3a_asid = SMMU_SDMMC3A_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_sdmmc4a_asid = SMMU_SDMMC4A_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_isp2b_asid = SMMU_ISP2B_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_gpu_asid = SMMU_GPU_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_gpub_asid = SMMU_GPUB_ASID | MODULE_ASID_ENABLE; + smmu_regs->smmu_ppcs2_asid = SMMU_PPCS2_ASID | MODULE_ASID_ENABLE; + + /* flush page table cache */ + plat_smmu_ptc_flush_all(); + /* flush TLB */ + plat_smmu_tlb_flush_all(); + smmu_enable(); + printf("smmu enabled\n"); + + return ARM_PLAT_NUM_SMMU; +} + + +iopde_t * +plat_smmu_lookup_iopd_by_asid(uint32_t asid) +{ + iopde_t *pd = 0; + uint32_t data = 0; + if (asid < SMMU_FIRST_ASID || asid > SMMU_LAST_ASID) { + return 0; + } + + smmu_regs->smmu_ptb_asid = asid; + data = smmu_regs->smmu_ptb_data; + pd = (iopde_t *)(paddr_to_pptr(ptb_data_get_pd_base(data))); + return pd; +} + From 55e58e1a416f006b2ac44d7a2c18f9e68b291500 Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Fri, 13 May 2016 22:40:13 +1000 Subject: [PATCH 02/18] arm/tk1: a checkpoint for iospace.c --- include/plat/tk1/plat/machine/hardware.bf | 6 +- include/plat/tk1/plat/machine/smmu.h | 12 ++ src/arch/arm/object/iospace.c | 150 +++++++++++++++++++++- 3 files changed, 159 insertions(+), 9 deletions(-) diff --git a/include/plat/tk1/plat/machine/hardware.bf b/include/plat/tk1/plat/machine/hardware.bf index b20c6fa6b..d0c32d2ce 100644 --- a/include/plat/tk1/plat/machine/hardware.bf +++ b/include/plat/tk1/plat/machine/hardware.bf @@ -27,7 +27,7 @@ tagged_union iopde page_size { block iopde_pt { field read 1 field write 1 - field secure 1 + field nonsecure 1 field page_size 1 padding 6 field_high address 22 @@ -36,7 +36,7 @@ block iopde_pt { block iopde_4m { field read 1 field write 1 - field secure 1 + field nonsecure 1 field page_size 1 padding 6 field_high address 12 @@ -48,7 +48,7 @@ block iopde_4m { block iopte { field read 1 field write 1 - field secure 1 + field nonsecure 1 padding 7 field_high address 22 } diff --git a/include/plat/tk1/plat/machine/smmu.h b/include/plat/tk1/plat/machine/smmu.h index a4b1e9187..91f185df0 100644 --- a/include/plat/tk1/plat/machine/smmu.h +++ b/include/plat/tk1/plat/machine/smmu.h @@ -140,6 +140,18 @@ plat_smmu_iopt_index(word_t io_address) return ret; } +inline static uint32_t +plat_smmu_get_asid_by_module_id(uint32_t mid) +{ + if (mid < SMMU_FIRST_ASID || mid > SMMU_LAST_ASID) { + return asidInvalid; + } + + /* we have one-to-one mapping from module id to ASID */ + return mid; + +} + int plat_smmu_init(void); void plat_smmu_tlb_flush_all(void); void plat_smmu_ptc_flush_all(void); diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index 820ee7905..446b1ef0a 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -54,8 +54,16 @@ lookupIOPTSlot(iopde_t *iopd, word_t io_address) pt_ret.ioptSlot = 0; return pt_ret; } + index = plat_smmu_iopt_index(io_address); pt = (iopte_t *)paddr_to_pptr(iopde_iopde_pt_ptr_get_address(pd_ret.iopdSlot)); + + if (pt == 0) { + pt_ret.status = EXCEPTION_LOOKUP_FAULT; + pt_ret.ioptSlot = 0; + return pt_ret; + } + pt_ret.status = EXCEPTION_NONE; pt_ret.ioptSlot = pt + index; return pt_ret; @@ -97,8 +105,11 @@ decodeARMIOPTInvocation( { cap_t io_space; word_t io_address; + word_t paddr; uint16_t module_id; - (void)io_address; + uint32_t asid; + iopde_t *pd; + lookupIOPDSlot_ret_t lu_ret; if (invLabel == ARMIOPageTableUnmap) { deleteIOPageTable(slot->cap); @@ -134,13 +145,50 @@ decodeARMIOPTInvocation( } module_id= cap_io_space_cap_get_capModuleID(io_space); - if (module_id == asidInvalid) { + asid = plat_smmu_get_asid_by_module_id(module_id); + if (asid == asidInvalid) { current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } + paddr = pptr_to_paddr((void *)cap_io_page_table_cap_get_capIOPTBasePtr(cap)); + pd = (iopde_t *)plat_smmu_lookup_iopd_by_asid(asid); + + if (pd == 0) { + current_syscall_error.type = seL4_InvalidCapability; + current_syscall_error.invalidCapNumber = 0; + + return EXCEPTION_SYSCALL_ERROR; + } + + lu_ret = lookupIOPDSlot(pd, io_address); + if (lu_ret.status != EXCEPTION_NONE) { + current_syscall_error.type = seL4_InvalidCapability; + current_syscall_error.invalidCapNumber = 0; + + return EXCEPTION_SYSCALL_ERROR; + } + + iopde_iopde_pt_ptr_new( + lu_ret.iopdSlot, + 1, /* read */ + 1, /* write */ + 1, /* nonsecure */ + paddr /* address */ + ); + + cleanCacheRange_RAM((word_t)lu_ret.iopdSlot, + ((word_t)lu_ret.iopdSlot) + sizeof(iopde_t), + addrFromPPtr(lu_ret.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; @@ -162,8 +210,11 @@ decodeARMIOMapInvocation( paddr_t io_address; paddr_t paddr; uint32_t module_id; - (void)paddr; - (void)io_address; + uint32_t asid; + iopde_t *pd; + 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) { current_syscall_error.type = seL4_TruncatedMessage; @@ -193,13 +244,94 @@ decodeARMIOMapInvocation( } module_id = cap_io_space_cap_get_capModuleID(io_space); + asid = plat_smmu_get_asid_by_module_id(module_id); - if (module_id == asidInvalid) { + if (asid == asidInvalid) { current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } + pd = (iopde_t *)plat_smmu_lookup_iopd_by_asid(asid); + if (pd == 0) { + current_syscall_error.type = seL4_InvalidCapability; + current_syscall_error.invalidCapNumber = 0; + return EXCEPTION_SYSCALL_ERROR; + } + + lu_ret = lookupIOPTSlot(pd, io_address); + if (lu_ret.status != EXCEPTION_NONE) { + current_syscall_error.type = seL4_FailedLookup; + current_syscall_error.failedLookupWasSource = false; + return EXCEPTION_SYSCALL_ERROR; + } + + frame_cap_rights = cap_frame_cap_get_capFVMRights(cap); + dma_cap_rights_mask = rightsFromWord(getSyscallArg(0, buffer)); + + 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, + 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 + ); + } 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 + ); + } else { + current_syscall_error.type = seL4_InvalidArgument; + current_syscall_error.invalidArgumentNumber = 0; + return EXCEPTION_SYSCALL_ERROR; + } + + } else { + /* VMKernelOnly */ + 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(); + + cap = cap_small_frame_cap_set_capFIsIOSpace(cap, 1); + 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); @@ -220,11 +352,12 @@ void deleteIOPageTable(cap_t io_pt_cap) io_address = cap_io_page_table_cap_get_capIOPTMappedAddress(io_pt_cap); if (pd == 0) { + return; } lu_ret = lookupIOPDSlot(pd, io_address); if (lu_ret.status != EXCEPTION_NONE) { - + return; } if (iopde_iopde_pt_ptr_get_address(lu_ret.iopdSlot) != cap_io_page_table_cap_get_capIOPTBasePtr(io_pt_cap)) { @@ -286,6 +419,11 @@ decodeARMIOUnMapInvocation( extra_caps_t excaps ) { + unmapIOPage(slot->cap); + slot->cap = cap_small_frame_cap_set_capFMappedAddress(slot->cap, 0); + slot->cap = cap_small_frame_cap_set_capFIsIOSpace(slot->cap, 0); + slot->cap = cap_small_frame_cap_set_capFMappedASID(slot->cap, asidInvalid); + setThreadState(ksCurThread, ThreadState_Restart); return EXCEPTION_NONE; } From 508e87477f8c2bdd0933919a4b896288d432813d Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Tue, 17 May 2016 12:16:34 +1000 Subject: [PATCH 03/18] 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); From cbdd9c86e129c22a0fac190b4b5ad8c0fe24ec91 Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Thu, 19 May 2016 11:13:22 +1000 Subject: [PATCH 04/18] arm-hyp/tk1: disable/enable SMMU in secure mode --- src/plat/tk1/machine/smmu.c | 43 +++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/plat/tk1/machine/smmu.c b/src/plat/tk1/machine/smmu.c index ab405b36e..c3215d4af 100644 --- a/src/plat/tk1/machine/smmu.c +++ b/src/plat/tk1/machine/smmu.c @@ -40,29 +40,40 @@ __smmu_disable(void) static inline void smmu_disable(void) { - /* we need physical address here */ - uint32_t addr = (uint32_t)&__smmu_disable; - addr -= 0x60000000; - asm (".arch_extension sec\n"); - asm volatile ("mov r0, %0\n\t" - "dsb\nisb\n" - "smc #0\n" - ::"r"(addr)); + 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 -= 0x60000000; + 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; + } + return; } static inline void smmu_enable(void) { - uint32_t addr = (uint32_t)&__smmu_enable; - addr -= 0x60000000; - asm (".arch_extension sec\n"); - asm volatile ("mov r0, %0\n\t" - "dsb\nisb\n" - "smc #0\n" - ::"r"(addr)); - + if (config_set(ARM_HYP)) { + uint32_t addr = (uint32_t)&__smmu_enable; + addr -= 0x60000000; + asm (".arch_extension sec\n"); + asm volatile ("mov r0, %0\n\t" + "dsb\nisb\n" + "smc #0\n" + ::"r"(addr)); + } else { + smmu_regs->smmu_config = 1; + } + return; } From 851fccc2db738edbdabc287b2f95d495e0222430 Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Thu, 19 May 2016 14:03:06 +1000 Subject: [PATCH 05/18] arm-hyp/tk1: put iospace caps to bootinfo --- src/arch/arm/kernel/boot.c | 3 ++- src/arch/arm/object/iospace.c | 8 +++++++- src/plat/tk1/machine/smmu.c | 12 ------------ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/arch/arm/kernel/boot.c b/src/arch/arm/kernel/boot.c index 8d45b5ce1..7abea71ad 100644 --- a/src/arch/arm/kernel/boot.c +++ b/src/arch/arm/kernel/boot.c @@ -236,8 +236,9 @@ try_init_kernel( } if (config_set(CONFIG_ARM_SMMU)) { - create_iospace_caps(root_cnode_cap); + ndks_boot.bi_frame->ioSpaceCaps = create_iospace_caps(root_cnode_cap); } + /* Construct an initial address space with enough virtual addresses * to cover the user image + ipc buffer and bootinfo frames */ it_pd_cap = create_it_address_space(root_cnode_cap, it_v_reg); diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index a98645c60..f0e3f28cf 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -83,12 +83,18 @@ create_iospace_caps(cap_t root_cnode_cap) return (seL4_SlotRegion) S_REG_EMPTY; } - for (i = 0; i < num_smmu; i++) { + /* the 0 is reserved as an invalidASID, + * assuming each module is assigned an unique ASID + * and the ASIDs are contiguous + * */ + for (i = 1; i <= num_smmu; i++) { io_space_cap = cap_io_space_cap_new(i, i); if (!provide_cap(root_cnode_cap, io_space_cap)) { return (seL4_SlotRegion) S_REG_EMPTY; } } + end = ndks_boot.slot_pos_cur; + printf("Region [%x to %x) for SMMU caps\n", (unsigned int)start, (unsigned int)end); return (seL4_SlotRegion) {start, end}; } diff --git a/src/plat/tk1/machine/smmu.c b/src/plat/tk1/machine/smmu.c index ab405b36e..c6d5a79e1 100644 --- a/src/plat/tk1/machine/smmu.c +++ b/src/plat/tk1/machine/smmu.c @@ -8,18 +8,6 @@ static volatile tk1_mc_regs_t *smmu_regs = (volatile tk1_mc_regs_t *)(SMMU_PPTR); - -void printkk(void); -void -printkk(void) -{ - volatile uint32_t *reg = (volatile uint32_t *)(0x70006300); - int i = 'a'; - for (; i < 'z'; i++) { - *reg = i; - } -} - #define SMMU_CONFIG_OFFSET 0x10 static void From a861e1357694a04ed8bfdf84c40e3ed9485d0b6d Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Thu, 19 May 2016 14:26:23 +1000 Subject: [PATCH 06/18] arm-hyp/tk1: add the missing return --- src/arch/arm/32/object/objecttype.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/arch/arm/32/object/objecttype.c b/src/arch/arm/32/object/objecttype.c index 5f987a4dc..6dfdc3cc0 100644 --- a/src/arch/arm/32/object/objecttype.c +++ b/src/arch/arm/32/object/objecttype.c @@ -77,6 +77,7 @@ Arch_deriveCap(cte_t *slot, cap_t cap) case cap_io_space_cap: ret.cap = cap; ret.status = EXCEPTION_NONE; + return ret; case cap_io_page_table_cap: if (cap_io_page_table_cap_get_capIOPTIsMapped(cap)) { From 11720f23ad3fc2b3f822d87d47548106ae799b1c Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Fri, 20 May 2016 00:00:46 +1000 Subject: [PATCH 07/18] arm-hyp/tk1: fix bugs found during testing --- .../arch/arm/arch/32/mode/object/structures.h | 4 + include/arch/arm/arch/machine.h | 7 ++ include/arch/arm/arch/object/iospace.h | 1 + .../aarch32/sel4/sel4_arch/constants.h | 1 + src/arch/arm/32/object/objecttype.c | 17 +++- src/arch/arm/object/iospace.c | 82 ++++++++++++++++--- 6 files changed, 99 insertions(+), 13 deletions(-) diff --git a/include/arch/arm/arch/32/mode/object/structures.h b/include/arch/arm/arch/32/mode/object/structures.h index 831800cd5..a6c4dd5e9 100644 --- a/include/arch/arm/arch/32/mode/object/structures.h +++ b/include/arch/arm/arch/32/mode/object/structures.h @@ -64,6 +64,8 @@ typedef word_t vm_rights_t; #endif /* ARM_HYP */ /* NOTE: the macros are defined based on Tegra K1 SMMU page table sizes */ +#define ARM_IOPDE_SIZE_BITS 2 +#define ARM_IOPD_BITS 10 #define ARM_IOPTE_SIZE_BITS 2 #define ARM_IOPT_BITS 10 @@ -333,6 +335,8 @@ cap_get_archCapSizeBits(cap_t cap) case cap_vcpu_cap: return VCPU_SIZE_BITS; #endif + case cap_io_page_table_cap: + return seL4_IOPageTableBits; default: /* Unreachable, but GCC can't figure that out */ diff --git a/include/arch/arm/arch/machine.h b/include/arch/arm/arch/machine.h index 473020ca9..4631bc91d 100644 --- a/include/arch/arm/arch/machine.h +++ b/include/arch/arm/arch/machine.h @@ -45,6 +45,13 @@ static inline void clearMemory(word_t* ptr, word_t bits) cleanCacheRange_PoU((word_t)ptr, (word_t)ptr + BIT(bits) - 1, addrFromPPtr(ptr)); } + +static inline void clearMemoryRAM(word_t* ptr, word_t bits) +{ + memzero(ptr, BIT(bits)); + cleanCacheRange_RAM((word_t)ptr, (word_t)ptr + BIT(bits) - 1, + addrFromPPtr(ptr)); +} #endif /* __ASSEMBLER__ */ #endif /* __ARCH_MACHINE_H */ diff --git a/include/arch/arm/arch/object/iospace.h b/include/arch/arm/arch/object/iospace.h index 09c26708e..f51870103 100644 --- a/include/arch/arm/arch/object/iospace.h +++ b/include/arch/arm/arch/object/iospace.h @@ -23,6 +23,7 @@ exception_t decodeARMIOUnMapInvocation(word_t invLabel, uint32_t length, cte_t* exception_t decodeARMIOSpaceInvocation(word_t invLabel, cap_t cap); void unmapIOPage(cap_t cap); void deleteIOPageTable(cap_t cap); +void clearIOPageDirectory(cap_t cap); #endif diff --git a/libsel4/sel4_arch_include/aarch32/sel4/sel4_arch/constants.h b/libsel4/sel4_arch_include/aarch32/sel4/sel4_arch/constants.h index 708abd448..3fd946324 100644 --- a/libsel4/sel4_arch_include/aarch32/sel4/sel4_arch/constants.h +++ b/libsel4/sel4_arch_include/aarch32/sel4/sel4_arch/constants.h @@ -29,6 +29,7 @@ enum { #define seL4_PageDirBits 14 #define seL4_ASIDPoolBits 12 #define seL4_ARM_VCPUBits 12 +#define seL4_IOPageTableBits 12 /* word size */ #define seL4_WordBits (sizeof(seL4_Word) * 8) diff --git a/src/arch/arm/32/object/objecttype.c b/src/arch/arm/32/object/objecttype.c index 6dfdc3cc0..c665cf6bc 100644 --- a/src/arch/arm/32/object/objecttype.c +++ b/src/arch/arm/32/object/objecttype.c @@ -184,6 +184,9 @@ Arch_finaliseCap(cap_t cap, bool_t final) #endif case cap_io_space_cap: + if (final) { + clearIOPageDirectory(cap); + } break; case cap_io_page_table_cap: @@ -213,6 +216,8 @@ resetMemMapping(cap_t cap) case cap_page_directory_cap: /* We don't need to worry about clearing ASID and Address here, only whether it is mapped */ return cap_page_directory_cap_set_capPDIsMapped(cap, 0); + case cap_io_page_table_cap: + return cap_io_page_table_cap_set_capIOPTIsMapped(cap, 0); } return cap; @@ -302,13 +307,13 @@ Arch_recycleCap(bool_t is_final, cap_t cap) #endif case cap_io_space_cap: - Arch_finaliseCap(cap, is_final); + Arch_finaliseCap(cap, true); return cap; case cap_io_page_table_cap: - clearMemory((void *)cap_get_capPtr(cap), cap_get_capSizeBits(cap)); + clearMemoryRAM((void *)cap_get_capPtr(cap), cap_get_capSizeBits(cap)); Arch_finaliseCap(cap, is_final); - return cap; + return resetMemMapping(cap); default: fail("Arch_recycleCap: invalid cap type"); @@ -556,6 +561,12 @@ Arch_createObject(object_t t, void *regionBase, word_t userSize) return cap_vcpu_cap_new(VCPU_REF(regionBase)); #endif + case seL4_ARM_IOPageTableObject: + memzero(regionBase, 1 << seL4_IOPageTableBits); + cleanCacheRange_RAM((word_t)regionBase, + (word_t)regionBase + (1 << seL4_IOPageTableBits) - 1, + addrFromPPtr(regionBase)); + return cap_io_page_table_cap_new(0, asidInvalid, (word_t)regionBase, 0); default: /* * This is a conflation of the haskell error: "Arch.createNewCaps diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index f0e3f28cf..3ae7723f4 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -31,6 +31,31 @@ typedef struct lookupIOPTSlot_ret { iopte_t *ioptSlot; } lookupIOPTSlot_ret_t; + +#define IOPDE_VALID_MASK 0xe0000000 +#define IOPTE_EMPTY_MASK 0xe0000000 + +static bool_t +isIOPDEValid(iopde_t *iopde) +{ + assert(iopde != 0); + if ((iopde->words[0] & IOPDE_VALID_MASK) == 0) { + return false; + } + return true; +} + +static bool_t +isIOPTEEmpty(iopte_t *iopte) +{ + assert(iopte != 0); + if ((iopte->words[0] & IOPTE_EMPTY_MASK) == 0) { + return true; + } + return false; +} + + static lookupIOPDSlot_ret_t lookupIOPDSlot(iopde_t *iopd, word_t io_address) { @@ -55,6 +80,13 @@ lookupIOPTSlot(iopde_t *iopd, word_t io_address) return pt_ret; } + if (!isIOPDEValid(pd_ret.iopdSlot) || + iopde_ptr_get_page_size(pd_ret.iopdSlot) != iopde_iopde_pt) { + pt_ret.status = EXCEPTION_LOOKUP_FAULT; + pt_ret.ioptSlot = 0; + return pt_ret; + } + index = plat_smmu_iopt_index(io_address); pt = (iopte_t *)paddr_to_pptr(iopde_iopde_pt_ptr_get_address(pd_ret.iopdSlot)); @@ -114,7 +146,7 @@ decodeARMIOPTInvocation( word_t paddr; uint16_t module_id; uint32_t asid; - iopde_t *pd; + iopde_t *pd; lookupIOPDSlot_ret_t lu_ret; if (invLabel == ARMIOPageTableUnmap) { @@ -177,6 +209,11 @@ decodeARMIOPTInvocation( return EXCEPTION_SYSCALL_ERROR; } + if (isIOPDEValid(lu_ret.iopdSlot)) { + current_syscall_error.type = seL4_DeleteFirst; + return EXCEPTION_SYSCALL_ERROR; + } + iopde_iopde_pt_ptr_new( lu_ret.iopdSlot, 1, /* read */ @@ -227,13 +264,13 @@ decodeARMIOMapInvocation( return EXCEPTION_SYSCALL_ERROR; } - if (cap_frame_cap_get_capFSize(cap) != ARMSmallPage) { + if (generic_frame_cap_get_capFSize(cap) != ARMSmallPage) { current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } - if (cap_frame_cap_get_capFMappedASID(cap) != asidInvalid) { + if (cap_small_frame_cap_get_capFMappedASID(cap) != asidInvalid) { current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; @@ -241,7 +278,7 @@ decodeARMIOMapInvocation( io_space = excaps.excaprefs[0]->cap; io_address = getSyscallArg(1, buffer) & ~MASK(PAGE_BITS); - paddr = pptr_to_paddr((void*)cap_frame_cap_get_capFBasePtr(cap)); + paddr = pptr_to_paddr((void*)cap_small_frame_cap_get_capFBasePtr(cap)); if (cap_get_capType(io_space) != cap_io_space_cap) { current_syscall_error.type = seL4_InvalidCapability; @@ -272,7 +309,11 @@ decodeARMIOMapInvocation( return EXCEPTION_SYSCALL_ERROR; } - frame_cap_rights = cap_frame_cap_get_capFVMRights(cap); + if (!isIOPTEEmpty(lu_ret.ioptSlot)) { + current_syscall_error.type = seL4_DeleteFirst; + return EXCEPTION_SYSCALL_ERROR; + } + frame_cap_rights = cap_small_frame_cap_get_capFVMRights(cap); dma_cap_rights_mask = rightsFromWord(getSyscallArg(0, buffer)); if ((frame_cap_rights == VMReadOnly) && cap_rights_get_capAllowRead(dma_cap_rights_mask)) { @@ -346,6 +387,7 @@ decodeARMIOMapInvocation( return EXCEPTION_NONE; } + void deleteIOPageTable(cap_t io_pt_cap) { @@ -368,7 +410,9 @@ void deleteIOPageTable(cap_t io_pt_cap) return; } - if (iopde_iopde_pt_ptr_get_address(lu_ret.iopdSlot) != cap_io_page_table_cap_get_capIOPTBasePtr(io_pt_cap)) { + if (isIOPDEValid(lu_ret.iopdSlot) && + iopde_ptr_get_page_size(lu_ret.iopdSlot) == iopde_iopde_pt && + iopde_iopde_pt_ptr_get_address(lu_ret.iopdSlot) != (pptr_to_paddr((void *)cap_io_page_table_cap_get_capIOPTBasePtr(io_pt_cap)))) { return; } @@ -378,7 +422,7 @@ void deleteIOPageTable(cap_t io_pt_cap) addrFromPPtr(lu_ret.iopdSlot)); - /* TODO flush by address and asid */ + /* nice to have: flush by address and asid */ plat_smmu_tlb_flush_all(); plat_smmu_ptc_flush_all(); } @@ -391,8 +435,8 @@ void unmapIOPage(cap_t cap) word_t io_address; uint32_t asid; - io_address = cap_frame_cap_get_capFMappedAddress(cap); - asid = cap_frame_cap_get_capFMappedASID(cap); + io_address = cap_small_frame_cap_get_capFMappedAddress(cap); + asid = cap_small_frame_cap_get_capFMappedASID(cap); pd = (iopde_t *)plat_smmu_lookup_iopd_by_asid(asid); if (pd == 0) { @@ -404,7 +448,7 @@ void unmapIOPage(cap_t cap) if (lu_ret.status != EXCEPTION_NONE) { return; } - if (iopte_ptr_get_address(lu_ret.ioptSlot) != cap_frame_cap_get_capFBasePtr(cap)) { + if (iopte_ptr_get_address(lu_ret.ioptSlot) != pptr_to_paddr((void *)cap_small_frame_cap_get_capFBasePtr(cap))) { return; } @@ -418,6 +462,24 @@ void unmapIOPage(cap_t cap) return; } +void clearIOPageDirectory(cap_t cap) +{ + iopde_t *pd; + uint32_t asid = cap_io_space_cap_get_capModuleID(cap); + word_t size = BIT((ARM_IOPDE_SIZE_BITS + ARM_IOPD_BITS)); + pd = (iopde_t *)plat_smmu_lookup_iopd_by_asid(asid); + + if (pd == 0) { + return; + } + memset((void *)pd, 0, size); + cleanCacheRange_RAM((word_t)pd, (word_t)pd + size, addrFromPPtr(pd)); + + plat_smmu_tlb_flush_all(); + plat_smmu_ptc_flush_all(); + return; +} + exception_t decodeARMIOUnMapInvocation( word_t invLabel, From b1e4f92fbd9707e796f50dc58fa0928b745150f3 Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Fri, 20 May 2016 12:23:51 +1000 Subject: [PATCH 08/18] arm-hyp/tk1: reserve the SMMU interrupt --- include/plat/tk1/plat/machine.h | 2 ++ src/arch/arm/kernel/boot.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/include/plat/tk1/plat/machine.h b/include/plat/tk1/plat/machine.h index d46e31212..e94483b87 100644 --- a/include/plat/tk1/plat/machine.h +++ b/include/plat/tk1/plat/machine.h @@ -216,6 +216,8 @@ enum IRQConstants { #define INTERRUPT_NS_PGPT INTERRUPT_PPI_14 #define INTERRUPT_VGPT INTERRUPT_PPI_11 #define INTERRUPT_HGPT INTERRUPT_PPI_10 +#define INTERRUPT_SMMU INTERRUPT_MC + /* the kernel runs in secure supervisor mode by default */ diff --git a/src/arch/arm/kernel/boot.c b/src/arch/arm/kernel/boot.c index 7abea71ad..88859b99f 100644 --- a/src/arch/arm/kernel/boot.c +++ b/src/arch/arm/kernel/boot.c @@ -135,6 +135,9 @@ init_irqs(cap_t root_cnode_cap) if (config_set(ARM_HYP)) { setIRQState(IRQReserved, INTERRUPT_VGIC_MAINTENANCE); } + if (config_set(CONFIG_ARM_SMMU)) { + setIRQState(IRQReserved, INTERRUPT_SMMU); + } /* provide the IRQ control cap */ write_slot(SLOT_PTR(pptr_of_cap(root_cnode_cap), seL4_CapIRQControl), cap_irq_control_cap_new()); From 17ec138bf21dcef0c25662f64518c8de6879364a Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Fri, 20 May 2016 17:05:44 +1000 Subject: [PATCH 09/18] arm-hyp/tk1: enable SMMU interrupts --- include/plat/tk1/plat/machine/smmu.h | 1 + src/plat/tk1/machine/hardware.c | 5 ++ src/plat/tk1/machine/smmu.c | 90 ++++++++++++++++++++++++++-- 3 files changed, 92 insertions(+), 4 deletions(-) diff --git a/include/plat/tk1/plat/machine/smmu.h b/include/plat/tk1/plat/machine/smmu.h index 91f185df0..d989449cd 100644 --- a/include/plat/tk1/plat/machine/smmu.h +++ b/include/plat/tk1/plat/machine/smmu.h @@ -156,5 +156,6 @@ int plat_smmu_init(void); void plat_smmu_tlb_flush_all(void); void plat_smmu_ptc_flush_all(void); iopde_t *plat_smmu_lookup_iopd_by_asid(uint32_t asid); +void plat_smmu_handle_interrupt(void); #endif diff --git a/src/plat/tk1/machine/hardware.c b/src/plat/tk1/machine/hardware.c index dc43fec1f..e4fe255e7 100644 --- a/src/plat/tk1/machine/hardware.c +++ b/src/plat/tk1/machine/hardware.c @@ -140,6 +140,11 @@ handleReservedIRQ(irq_t irq) return; } + if (config_set(CONFIG_ARM_SMMU) && (irq == INTERRUPT_SMMU)) { + plat_smmu_handle_interrupt(); + return; + } + printf("Received reserved IRQ: %d\n", (int)irq); } diff --git a/src/plat/tk1/machine/smmu.c b/src/plat/tk1/machine/smmu.c index d6f4d7d83..2a05b643d 100644 --- a/src/plat/tk1/machine/smmu.c +++ b/src/plat/tk1/machine/smmu.c @@ -124,13 +124,21 @@ 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 + BOOT_CODE int plat_smmu_init(void) { int asid = 1; int i = 0; - (void) (smmu_regs); - (void) (asid); + smmu_disable(); printf("smmu disabled\n"); @@ -159,7 +167,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; @@ -183,7 +191,11 @@ plat_smmu_init(void) 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) | + BIT(MC_DECERR_VPR_BIT) | BIT(MC_ARBITRATION_EMEM_BIT) | + BIT(MC_SECURITY_BIT) | BIT(MC_DECERR_EMEM_BIT); return ARM_PLAT_NUM_SMMU; } @@ -203,3 +215,73 @@ plat_smmu_lookup_iopd_by_asid(uint32_t asid) return pd; } +#define MC_ERR_ID_MASK 0x7f +#define MC_ERR_ADR_MASK 0x7000 +#define MC_ERR_RW_MASK 0x10000 +#define MC_ERR_SEC_MASK 0x20000 +#define MC_ERR_SWAP_MASK 0x40000 +#define MC_ERR_ADR_HI_MASK 0x300000 +#define MC_ERR_INVALID_SMMU_PAGE_NONSECURE_MASK 0x2000000 +#define MC_ERR_INVALID_SMMU_PAGE_WRITE_MASK 0x4000000 +#define MC_ERR_INVALID_SMMU_PAGE_READ_MASK 0x8000000 +#define MC_ERR_TYPE_MASK 0x70000000 +#define MC_ERR_TYPE_SHIFT 28 + +#define MC_ERR_TYPE_RSVD 0 +#define MC_ERR_TYPE_DECERR_EMEM 2 +#define MC_ERR_TYPE_SECURITY 3 +#define MC_ERR_TYPE_SECURITY_CARVEOUT 4 +#define MC_ERR_TYPE_INVALID_SMMU_PAGE 6 + +void +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); + } + if (status & BIT(MC_SECERR_SEC_BIT)) { + clear_status |= BIT(MC_SECERR_SEC_BIT); + } + if (status & BIT(MC_DECERR_VPR_BIT)) { + clear_status |= BIT(MC_DECERR_VPR_BIT); + } + if (status & BIT(MC_ARBITRATION_EMEM_BIT)) { + clear_status |= BIT(MC_ARBITRATION_EMEM_BIT); + } + if (status & BIT(MC_SECURITY_BIT)) { + clear_status |= BIT(MC_SECURITY_BIT); + } + if (status & BIT(MC_DECERR_EMEM_BIT)) { + clear_status |= BIT(MC_DECERR_EMEM_BIT); + } + if (status & BIT(MC_APB_ASID_UPDATE_BIT)) { + clear_status |= BIT(MC_APB_ASID_UPDATE_BIT); + } + + /* we only care about SMMU translation failures */ + if (status & BIT(MC_SMMU_PAGE_BIT)) { + 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 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); + uint32_t nonsecure = (err_status & MC_ERR_INVALID_SMMU_PAGE_NONSECURE_MASK); + uint32_t type = (err_status & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT; + + 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); + + clear_status |= BIT(MC_SMMU_PAGE_BIT); + } + + /* write 1 to clear the interrupt */ + smmu_regs->intstatus = clear_status; +} + From bb9e84e6ec9bc9b4d64c45b6d45aae90d7fc512b Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Wed, 25 May 2016 16:31:26 +1000 Subject: [PATCH 10/18] arm-hyp/tk1: add default SMMU translation for VM --- Kconfig | 9 +++++ include/plat/tk1/plat/machine/devices.h | 16 ++++++++- include/plat/tk1/plat/machine/hardware.bf | 9 +++-- src/arch/arm/object/iospace.c | 9 +++-- src/plat/tk1/machine/hardware.c | 16 +++++---- src/plat/tk1/machine/smmu.c | 43 +++++++++++++++++++---- 6 files changed, 84 insertions(+), 18 deletions(-) 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); } From 5650a8fa8447147120fe1300390d07afee47ab6f Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Wed, 25 May 2016 16:35:02 +1000 Subject: [PATCH 11/18] arm-hyp/tk1: make style --- include/arch/arm/arch/32/mode/machine_pl2.h | 5 +- include/arch/arm/arch/object/vcpu.h | 2 +- include/plat/tk1/plat/machine/smmu.h | 14 +-- src/arch/arm/32/object/objecttype.c | 16 +-- src/arch/arm/object/iospace.c | 106 ++++++++++---------- src/plat/tk1/machine/hardware.c | 32 +++--- src/plat/tk1/machine/smmu.c | 76 +++++++------- 7 files changed, 128 insertions(+), 123 deletions(-) diff --git a/include/arch/arm/arch/32/mode/machine_pl2.h b/include/arch/arm/arch/32/mode/machine_pl2.h index 33edb75d0..29d8430ec 100644 --- a/include/arch/arm/arch/32/mode/machine_pl2.h +++ b/include/arch/arm/arch/32/mode/machine_pl2.h @@ -188,7 +188,10 @@ static inline void setCurrentPDPL2(paddr_t pa) {} static inline void invalidateHypTLB(void) {} static inline void writeContextIDPL2(word_t pd) {} static inline void writeContextIDAndPD(word_t id, word_t pd) {} -static inline paddr_t addressTranslateS1CPR(vptr_t vaddr) { return vaddr; } +static inline paddr_t addressTranslateS1CPR(vptr_t vaddr) +{ + return vaddr; +} #endif /* !ARM_HYP */ #endif /* __ARCH_MACHINE_PL2_32_H */ diff --git a/include/arch/arm/arch/object/vcpu.h b/include/arch/arm/arch/object/vcpu.h index 906bf5dee..80e01a961 100644 --- a/include/arch/arm/arch/object/vcpu.h +++ b/include/arch/arm/arch/object/vcpu.h @@ -72,7 +72,7 @@ exception_t invokeVCPUSetTCB(vcpu_t *vcpu, tcb_t *tcb); #else /* end of ARM_HYP */ /* used in boot.c with a guard, use a marco to avoid exposing vcpu_t */ -#define vcpu_restore(x) +#define vcpu_restore(x) #define vcpu_switch(x) static inline void VGICMaintenance(void) {} diff --git a/include/plat/tk1/plat/machine/smmu.h b/include/plat/tk1/plat/machine/smmu.h index d989449cd..fa7543aeb 100644 --- a/include/plat/tk1/plat/machine/smmu.h +++ b/include/plat/tk1/plat/machine/smmu.h @@ -30,11 +30,11 @@ typedef struct { uint32_t smmu_ptb_asid; /* 0x1c */ uint32_t smmu_ptb_data; /* 0x20 */ uint32_t rev0; /* 0x24 */ - uint32_t rev1; /* 0x28 */ + uint32_t rev1; /* 0x28 */ uint32_t rev2; /* 0x2c */ uint32_t smmu_tlb_flush; /* 0x30 */ uint32_t smmu_ptc_flush; /* 0x34 */ - uint32_t rev3[124]; + uint32_t rev3[124]; uint32_t smmu_translation_enable_0; /* 0x228 */ uint32_t smmu_translation_enable_1; /* 0x22c */ uint32_t smmu_translation_enable_2; /* 0x230 */ @@ -52,7 +52,7 @@ typedef struct { uint32_t rev7; /* 0x260 */ uint32_t smmu_msenc_asid; /* 0x264 */ uint32_t smmu_nv_asid; /* 0x268 */ - uint32_t smmu_nv2_asid; /* 0x26c */ + uint32_t smmu_nv2_asid; /* 0x26c */ uint32_t smmu_ppcs_asid; /* 0x270 */ uint32_t smmu_sata_asid; /* 0x274 */ uint32_t smmu_vde_asid; /* 0x27c */ @@ -65,9 +65,9 @@ typedef struct { uint32_t smmu_ppcs1_asid; /* 0x298 */ uint32_t rev9[217]; uint32_t smmu_tlb_set_sel_mask; /* 0x600 */ - uint32_t rev10[237]; + uint32_t rev10[237]; uint32_t smmu_ptc_flush_1; /* 0x9b8 */ - uint32_t rev11[51]; + uint32_t rev11[51]; uint32_t smmu_dc1_asid; /* 0xa88 */ uint32_t rev12; /* 0xa8c */ uint32_t rev13; /* 0xa90 */ @@ -116,7 +116,7 @@ typedef struct { #define SMMU_PPCS2_ASID 28 #define SMMU_LAST_ASID 28 -#define ARM_PLAT_NUM_SMMU 28 +#define ARM_PLAT_NUM_SMMU 28 #define SMMU_PD_BITS 12 #define SMMU_PT_BITS 12 @@ -126,7 +126,7 @@ typedef struct { #define SMMU_IOPT_INDEX_MASK 0x3ff000 #define SMMU_IOPT_INDEX_SHIFT 12 -inline static uint32_t +inline static uint32_t plat_smmu_iopd_index(word_t io_address) { uint32_t ret = (io_address & SMMU_IOPD_INDEX_MASK) >> SMMU_IOPD_INDEX_SHIFT; diff --git a/src/arch/arm/32/object/objecttype.c b/src/arch/arm/32/object/objecttype.c index c665cf6bc..e5060d110 100644 --- a/src/arch/arm/32/object/objecttype.c +++ b/src/arch/arm/32/object/objecttype.c @@ -583,16 +583,16 @@ Arch_decodeInvocation(word_t invLabel, word_t length, cptr_t cptr, 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); + 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 - case 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); + default: + return decodeARMMMUInvocation(invLabel, length, cptr, slot, cap, excaps, buffer); } } diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index 7eef7206f..66f01955a 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -81,7 +81,7 @@ lookupIOPTSlot(iopde_t *iopd, word_t io_address) } if (!isIOPDEValid(pd_ret.iopdSlot) || - iopde_ptr_get_page_size(pd_ret.iopdSlot) != iopde_iopde_pt) { + iopde_ptr_get_page_size(pd_ret.iopdSlot) != iopde_iopde_pt) { pt_ret.status = EXCEPTION_LOOKUP_FAULT; pt_ret.ioptSlot = 0; return pt_ret; @@ -97,7 +97,7 @@ lookupIOPTSlot(iopde_t *iopd, word_t io_address) } pt_ret.status = EXCEPTION_NONE; - pt_ret.ioptSlot = pt + index; + pt_ret.ioptSlot = pt + index; return pt_ret; } @@ -120,14 +120,16 @@ create_iospace_caps(cap_t root_cnode_cap) * and the ASIDs are contiguous * */ for (i = 1; i <= num_smmu; i++) { - io_space_cap = cap_io_space_cap_new(i, i); + io_space_cap = cap_io_space_cap_new(i, i); if (!provide_cap(root_cnode_cap, io_space_cap)) { return (seL4_SlotRegion) S_REG_EMPTY; } } end = ndks_boot.slot_pos_cur; printf("Region [%x to %x) for SMMU caps\n", (unsigned int)start, (unsigned int)end); - return (seL4_SlotRegion) {start, end}; + return (seL4_SlotRegion) { + start, end + }; } @@ -182,7 +184,7 @@ decodeARMIOPTInvocation( return EXCEPTION_SYSCALL_ERROR; } - module_id= cap_io_space_cap_get_capModuleID(io_space); + module_id = cap_io_space_cap_get_capModuleID(io_space); asid = plat_smmu_get_asid_by_module_id(module_id); if (asid == asidInvalid) { current_syscall_error.type = seL4_InvalidCapability; @@ -215,16 +217,16 @@ decodeARMIOPTInvocation( } iopde_iopde_pt_ptr_new( - lu_ret.iopdSlot, - 1, /* read */ - 1, /* write */ - 1, /* nonsecure */ - paddr /* address */ - ); + lu_ret.iopdSlot, + 1, /* read */ + 1, /* write */ + 1, /* nonsecure */ + paddr /* address */ + ); cleanCacheRange_RAM((word_t)lu_ret.iopdSlot, - ((word_t)lu_ret.iopdSlot) + sizeof(iopde_t), - addrFromPPtr(lu_ret.iopdSlot)); + ((word_t)lu_ret.iopdSlot) + sizeof(iopde_t), + addrFromPPtr(lu_ret.iopdSlot)); plat_smmu_tlb_flush_all(); plat_smmu_ptc_flush_all(); @@ -319,43 +321,43 @@ 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 - ); + 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)) { + !cap_rights_get_capAllowWrite(dma_cap_rights_mask)) { /* read only */ iopte_ptr_new( - lu_ret.ioptSlot, - 1, /* read */ - 0, /* write */ - 1, /* nonsecure */ - paddr - ); + lu_ret.ioptSlot, + 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)) { + cap_rights_get_capAllowWrite(dma_cap_rights_mask)) { /* write only */ iopte_ptr_new( - lu_ret.ioptSlot, - 0, - 1, - 1, - paddr - ); + lu_ret.ioptSlot, + 0, + 1, + 1, + 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 - ); + lu_ret.ioptSlot, + 1, + 1, + 1, + paddr + ); } else { current_syscall_error.type = seL4_InvalidArgument; current_syscall_error.invalidArgumentNumber = 0; @@ -370,8 +372,8 @@ decodeARMIOMapInvocation( } cleanCacheRange_RAM((word_t)lu_ret.ioptSlot, - ((word_t)lu_ret.ioptSlot) + sizeof(iopte_t), - addrFromPPtr(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(); @@ -400,7 +402,7 @@ deleteIOPageTable(cap_t io_pt_cap) io_pt_cap = cap_io_page_table_cap_set_capIOPTIsMapped(io_pt_cap, 0); asid = cap_io_page_table_cap_get_capIOPTASID(io_pt_cap); pd = (iopde_t *)plat_smmu_lookup_iopd_by_asid(asid); - io_address = cap_io_page_table_cap_get_capIOPTMappedAddress(io_pt_cap); + io_address = cap_io_page_table_cap_get_capIOPTMappedAddress(io_pt_cap); if (pd == 0) { return; @@ -410,19 +412,19 @@ deleteIOPageTable(cap_t io_pt_cap) if (lu_ret.status != EXCEPTION_NONE) { return; } - + if (isIOPDEValid(lu_ret.iopdSlot) && - iopde_ptr_get_page_size(lu_ret.iopdSlot) == iopde_iopde_pt && - iopde_iopde_pt_ptr_get_address(lu_ret.iopdSlot) != (pptr_to_paddr((void *)cap_io_page_table_cap_get_capIOPTBasePtr(io_pt_cap)))) { + iopde_ptr_get_page_size(lu_ret.iopdSlot) == iopde_iopde_pt && + iopde_iopde_pt_ptr_get_address(lu_ret.iopdSlot) != (pptr_to_paddr((void *)cap_io_page_table_cap_get_capIOPTBasePtr(io_pt_cap)))) { return; } iopde_iopde_pt_ptr_new(lu_ret.iopdSlot, 0, 0, 0, 0); - cleanCacheRange_RAM((word_t)lu_ret.iopdSlot, - ((word_t)lu_ret.iopdSlot) + sizeof(iopde_t), - addrFromPPtr(lu_ret.iopdSlot)); + cleanCacheRange_RAM((word_t)lu_ret.iopdSlot, + ((word_t)lu_ret.iopdSlot) + sizeof(iopde_t), + addrFromPPtr(lu_ret.iopdSlot)); + - /* nice to have: flush by address and asid */ plat_smmu_tlb_flush_all(); plat_smmu_ptc_flush_all(); @@ -455,9 +457,9 @@ unmapIOPage(cap_t cap) } iopte_ptr_new(lu_ret.ioptSlot, 0, 0, 0, 0); - cleanCacheRange_RAM((word_t)lu_ret.ioptSlot, - ((word_t)lu_ret.ioptSlot) + sizeof(iopte_t), - addrFromPPtr(lu_ret.ioptSlot)); + 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(); diff --git a/src/plat/tk1/machine/hardware.c b/src/plat/tk1/machine/hardware.c index 2d4f27b6f..9fa00ea0c 100644 --- a/src/plat/tk1/machine/hardware.c +++ b/src/plat/tk1/machine/hardware.c @@ -179,27 +179,27 @@ map_kernel_devices(void) if (config_set(ARM_HYP)) { map_kernel_frame( - GIC_VCPUCTRL_PADDR, - GIC_VCPUCTRL_PPTR, - VMKernelOnly, - vm_attributes_new( - false, - false, - false - ) + GIC_VCPUCTRL_PADDR, + GIC_VCPUCTRL_PPTR, + VMKernelOnly, + vm_attributes_new( + false, + false, + false + ) ); } if (config_set(CONFIG_ARM_SMMU)) { map_kernel_frame( - MC_PADDR, - SMMU_PPTR, - VMKernelOnly, - vm_attributes_new( - false, - false, - false - ) + MC_PADDR, + SMMU_PPTR, + VMKernelOnly, + vm_attributes_new( + false, + false, + false + ) ); } diff --git a/src/plat/tk1/machine/smmu.c b/src/plat/tk1/machine/smmu.c index e3bc0bd25..300e52c7e 100644 --- a/src/plat/tk1/machine/smmu.c +++ b/src/plat/tk1/machine/smmu.c @@ -7,22 +7,22 @@ #include -static volatile tk1_mc_regs_t *smmu_regs = (volatile tk1_mc_regs_t *)(SMMU_PPTR); +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) { - volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET); - *config = 1; + volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET); + *config = 1; } static void __smmu_disable(void) { - volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET); - *config = 0; + volatile uint32_t *config = (volatile uint32_t *)(MC_PADDR + SMMU_CONFIG_OFFSET); + *config = 0; } @@ -36,10 +36,10 @@ smmu_disable(void) addr -= 0x60000000; asm (".arch_extension sec\n"); asm volatile ("mov r0, %0\n\t" - "dsb\nisb\n" - "smc #0\n" - ::"r"(addr)); - + "dsb\nisb\n" + "smc #0\n" + ::"r"(addr)); + } else { /* in secure mode, can enable it directly */ smmu_regs->smmu_config = 0; @@ -56,9 +56,9 @@ smmu_enable(void) addr -= 0x60000000; asm (".arch_extension sec\n"); asm volatile ("mov r0, %0\n\t" - "dsb\nisb\n" - "smc #0\n" - ::"r"(addr)); + "dsb\nisb\n" + "smc #0\n" + ::"r"(addr)); } else { smmu_regs->smmu_config = 1; } @@ -88,7 +88,7 @@ make_ptb_data(uint32_t pd_base, bool_t read, bool_t write, bool_t nonsecure) ret |= PTB_DATA_WRITE; } if (nonsecure) { - ret |= PTB_DATA_NONSECURE; + ret |= PTB_DATA_NONSECURE; } return ret; @@ -98,7 +98,7 @@ static uint32_t ptb_data_get_pd_base(uint32_t data) { uint32_t ret = data; - ret &= PTB_DATA_BASE_PD_MASK; + ret &= PTB_DATA_BASE_PD_MASK; ret <<= PTB_DATA_BASE_SHIFT; return ret; } @@ -145,12 +145,12 @@ plat_smmu_vm_mapping(word_t iopd, word_t gpa, word_t pa, word_t size) while (size > 0) { word_t index = gpa >> IOPDE_4M_INDEX_SHIFT; iopde_iopde_4m_ptr_new( - iopde + index, - 1, - 1, - 1, - pa - ); + iopde + index, + 1, + 1, + 1, + pa + ); gpa += BIT(IOPDE_4M_INDEX_SHIFT); pa += BIT(IOPDE_4M_INDEX_SHIFT); size -= BIT(IOPDE_4M_INDEX_SHIFT); @@ -166,28 +166,28 @@ plat_smmu_init(void) smmu_disable(); for (i = 0; i < ARM_PLAT_NUM_SMMU; i++) { - iopde_t *pd = (iopde_t *)alloc_region(SMMU_PD_BITS); + 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; - } + 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)); + 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; + 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++; + /* 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++; } - printf("Total %d IOASID set up\n", (asid - 1)); - + printf("Total %d IOASID set up\n", (asid - 1)); + /* now assign IOASID to each module */ smmu_regs->smmu_afi_asid = SMMU_AFI_ASID | MODULE_ASID_ENABLE; smmu_regs->smmu_avpc_asid = SMMU_AVPC_ASID | MODULE_ASID_ENABLE; @@ -236,7 +236,7 @@ iopde_t * plat_smmu_lookup_iopd_by_asid(uint32_t asid) { iopde_t *pd = 0; - uint32_t data = 0; + uint32_t data = 0; if (asid < SMMU_FIRST_ASID || asid > SMMU_LAST_ASID) { return 0; } From 98d4cf7df5e32cd06a0af6890b5cd0748c753f11 Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Wed, 25 May 2016 17:02:36 +1000 Subject: [PATCH 12/18] arm-hyp/tk1: remove const number --- src/plat/tk1/machine/smmu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plat/tk1/machine/smmu.c b/src/plat/tk1/machine/smmu.c index 300e52c7e..4bb07a168 100644 --- a/src/plat/tk1/machine/smmu.c +++ b/src/plat/tk1/machine/smmu.c @@ -25,7 +25,6 @@ __smmu_disable(void) *config = 0; } - static inline void smmu_disable(void) { @@ -33,7 +32,7 @@ smmu_disable(void) /* in hyp mode, we need call the hook in monitor mode */ /* we need physical address here */ uint32_t addr = (uint32_t)&__smmu_disable; - addr -= 0x60000000; + addr -= physMappingOffset; asm (".arch_extension sec\n"); asm volatile ("mov r0, %0\n\t" "dsb\nisb\n" @@ -53,7 +52,7 @@ smmu_enable(void) { if (config_set(ARM_HYP)) { uint32_t addr = (uint32_t)&__smmu_enable; - addr -= 0x60000000; + addr -= physMappingOffset; asm (".arch_extension sec\n"); asm volatile ("mov r0, %0\n\t" "dsb\nisb\n" From 13ae16a76bfc8e5a9516f14b05c2233a6b6bf149 Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Wed, 25 May 2016 17:03:32 +1000 Subject: [PATCH 13/18] arm-hyp/tk1: should trap SMC from guest kernel --- src/arch/arm/object/vcpu.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/arch/arm/object/vcpu.c b/src/arch/arm/object/vcpu.c index 6f3287e46..996987604 100644 --- a/src/arch/arm/object/vcpu.c +++ b/src/arch/arm/object/vcpu.c @@ -43,17 +43,10 @@ #define HCR_SWIO BIT( 1) /* set/way invalidate override */ #define HCR_VM BIT( 0) /* Virtualization MMU enable */ -#ifdef CONFIG_ARM_SMMU -/* Trap WFI/WFE/SMC and override CPSR.AIF */ -#define HCR_COMMON ( HCR_TWE | HCR_TWI | HCR_AMO | HCR_IMO \ - | HCR_FMO | HCR_DC | HCR_VM) -#else - /* 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) -#endif /* 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) From 27ecdffe3c42e9c4b7ec89021415ee0ff5e1194f Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Fri, 27 May 2016 00:16:53 +1000 Subject: [PATCH 14/18] arm-hyp/tk1: address review comments. --- include/plat/tk1/plat/machine/smmu.h | 34 +++--- src/arch/arm/32/object/objecttype.c | 3 +- src/arch/arm/kernel/boot.c | 4 + src/arch/arm/object/iospace.c | 161 ++++++++++++++++----------- src/arch/arm/object/vcpu.c | 1 - src/plat/tk1/machine/smmu.c | 42 +++---- 6 files changed, 145 insertions(+), 100 deletions(-) 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); From 55f8b14417ca36c460786a3ecf86c9f3f2b0a6fb Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Fri, 27 May 2016 11:00:01 +1000 Subject: [PATCH 15/18] arm-hyp/tk1: address review comments. --- .../arch/arm/arch/32/mode/object/structures.h | 6 - src/arch/arm/32/object/objecttype.c | 2 +- src/arch/arm/object/iospace.c | 2 +- src/plat/tk1/machine/smmu.c | 121 +++++++++--------- 4 files changed, 64 insertions(+), 67 deletions(-) diff --git a/include/arch/arm/arch/32/mode/object/structures.h b/include/arch/arm/arch/32/mode/object/structures.h index a6c4dd5e9..21e7942a6 100644 --- a/include/arch/arm/arch/32/mode/object/structures.h +++ b/include/arch/arm/arch/32/mode/object/structures.h @@ -63,12 +63,6 @@ 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_IOPDE_SIZE_BITS 2 -#define ARM_IOPD_BITS 10 -#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) diff --git a/src/arch/arm/32/object/objecttype.c b/src/arch/arm/32/object/objecttype.c index 793315de0..8a4e3f421 100644 --- a/src/arch/arm/32/object/objecttype.c +++ b/src/arch/arm/32/object/objecttype.c @@ -450,7 +450,7 @@ Arch_getObjectSize(word_t t) case seL4_ARM_PageDirectoryObject: return PDE_SIZE_BITS + PD_BITS; case seL4_ARM_IOPageTableObject: - return ARM_IOPTE_SIZE_BITS + ARM_IOPT_BITS; + return seL4_IOPageTableBits; #ifdef ARM_HYP case seL4_ARM_VCPUObject: return VCPU_SIZE_BITS; diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index 6b56ae6f2..cc351ed0a 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -501,7 +501,7 @@ void clearIOPageDirectory(cap_t cap) { iopde_t *pd; uint32_t asid = cap_io_space_cap_get_capModuleID(cap); - word_t size = BIT((ARM_IOPDE_SIZE_BITS + ARM_IOPD_BITS)); + word_t size = BIT((SMMU_PD_BITS)); pd = (iopde_t *)plat_smmu_lookup_iopd_by_asid(asid); if (pd == 0) { diff --git a/src/plat/tk1/machine/smmu.c b/src/plat/tk1/machine/smmu.c index 14d45af77..8c8580de9 100644 --- a/src/plat/tk1/machine/smmu.c +++ b/src/plat/tk1/machine/smmu.c @@ -7,9 +7,56 @@ #include -static volatile tk1_mc_regs_t *smmu_regs = (volatile tk1_mc_regs_t *)(SMMU_PPTR); -#define SMMU_CONFIG_OFFSET 0x10 +#define SMMU_CONFIG_OFFSET 0x10 + +#define PTB_DATA_BASE_SHIFT 12 +#define PTB_DATA_READ BIT(31) +#define PTB_DATA_WRITE BIT(30) +#define PTB_DATA_NONSECURE BIT(29) +#define PTB_DATA_BASE_PD_MASK 0x3fffff + +#define MODULE_ASID_ENABLE BIT(31) + +#define PTC_FLUSH_ALL 0 +#define PTC_FLUSH_ADR 1 + +#define TLB_ASID_MATCH BIT(31) +#define TLB_FLUSH_ALL (0) +#define TLB_FLUSH_SECTION (2) +#define TLB_FLUSH_GROUP (3) + +#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 + + +#define MC_ERR_ID_MASK 0x7f +#define MC_ERR_ADR_MASK 0x7000 +#define MC_ERR_RW_MASK 0x10000 +#define MC_ERR_SEC_MASK 0x20000 +#define MC_ERR_SWAP_MASK 0x40000 +#define MC_ERR_ADR_HI_MASK 0x300000 +#define MC_ERR_INVALID_SMMU_PAGE_NONSECURE_MASK 0x2000000 +#define MC_ERR_INVALID_SMMU_PAGE_WRITE_MASK 0x4000000 +#define MC_ERR_INVALID_SMMU_PAGE_READ_MASK 0x8000000 +#define MC_ERR_TYPE_MASK 0x70000000 +#define MC_ERR_TYPE_SHIFT 28 + +#define MC_ERR_TYPE_RSVD 0 +#define MC_ERR_TYPE_DECERR_EMEM 2 +#define MC_ERR_TYPE_SECURITY 3 +#define MC_ERR_TYPE_SECURITY_CARVEOUT 4 +#define MC_ERR_TYPE_INVALID_SMMU_PAGE 6 + +#define IOPDE_4M_INDEX_SHIFT 22 + +static volatile tk1_mc_regs_t *smmu_regs = (volatile tk1_mc_regs_t *)(SMMU_PPTR); static void do_smmu_enable(void) @@ -63,14 +110,6 @@ smmu_enable(void) } -#define PTB_DATA_BASE_SHIFT 12 -#define PTB_DATA_READ (1ul << 31) -#define PTB_DATA_WRITE (1ul << 30) -#define PTB_DATA_NONSECURE (1ul << 29) -#define PTB_DATA_BASE_PD_MASK 0x3fffff - -#define MODULE_ASID_ENABLE (1ul << 31) - static uint32_t make_ptb_data(uint32_t pd_base, bool_t read, bool_t write, bool_t nonsecure) { @@ -99,9 +138,6 @@ ptb_data_get_pd_base(uint32_t data) return ret; } -#define PTC_FLUSH_ALL 0 -#define PTC_FLUSH_ADR 1 - void plat_smmu_ptc_flush_all(void) { @@ -109,11 +145,6 @@ plat_smmu_ptc_flush_all(void) smmu_regs->smmu_ptc_flush = cmd; } -#define TLB_ASID_MATCH BIT(31) -#define TLB_FLUSH_ALL (0) -#define TLB_FLUSH_SECTION (2) -#define TLB_FLUSH_GROUP (3) - void plat_smmu_tlb_flush_all(void) { @@ -121,15 +152,6 @@ plat_smmu_tlb_flush_all(void) smmu_regs->smmu_tlb_flush = cmd; } -#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. @@ -140,7 +162,6 @@ plat_smmu_tlb_flush_all(void) * 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) { @@ -250,24 +271,6 @@ plat_smmu_lookup_iopd_by_asid(uint32_t asid) return pd; } -#define MC_ERR_ID_MASK 0x7f -#define MC_ERR_ADR_MASK 0x7000 -#define MC_ERR_RW_MASK 0x10000 -#define MC_ERR_SEC_MASK 0x20000 -#define MC_ERR_SWAP_MASK 0x40000 -#define MC_ERR_ADR_HI_MASK 0x300000 -#define MC_ERR_INVALID_SMMU_PAGE_NONSECURE_MASK 0x2000000 -#define MC_ERR_INVALID_SMMU_PAGE_WRITE_MASK 0x4000000 -#define MC_ERR_INVALID_SMMU_PAGE_READ_MASK 0x8000000 -#define MC_ERR_TYPE_MASK 0x70000000 -#define MC_ERR_TYPE_SHIFT 28 - -#define MC_ERR_TYPE_RSVD 0 -#define MC_ERR_TYPE_DECERR_EMEM 2 -#define MC_ERR_TYPE_SECURITY 3 -#define MC_ERR_TYPE_SECURITY_CARVEOUT 4 -#define MC_ERR_TYPE_INVALID_SMMU_PAGE 6 - void plat_smmu_handle_interrupt(void) { @@ -298,20 +301,20 @@ 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; - 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); - uint32_t nonsecure = (err_status & MC_ERR_INVALID_SMMU_PAGE_NONSECURE_MASK); - uint32_t type = (err_status & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT; + if (config_set(DEBUG)) { + uint32_t err_status = smmu_regs->err_status; + uint32_t UNUSED err_adr = smmu_regs->err_adr; + uint32_t UNUSED id = err_status & MC_ERR_ID_MASK; + uint32_t UNUSED rw = (err_status & MC_ERR_RW_MASK); + uint32_t UNUSED read = (err_status & MC_ERR_INVALID_SMMU_PAGE_READ_MASK); + uint32_t UNUSED write = (err_status & MC_ERR_INVALID_SMMU_PAGE_WRITE_MASK); + uint32_t UNUSED nonsecure = (err_status & MC_ERR_INVALID_SMMU_PAGE_NONSECURE_MASK); + uint32_t UNUSED type = (err_status & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT; - 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 + 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); + } clear_status |= BIT(MC_SMMU_PAGE_BIT); } From b783eeccf91a167f5982ea186261c6c643421001 Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Fri, 27 May 2016 11:29:16 +1000 Subject: [PATCH 16/18] arm-hyp/tk1: make style --- src/arch/arm/kernel/boot.c | 2 +- src/arch/arm/object/iospace.c | 40 +++++++++++++++++------------------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/arch/arm/kernel/boot.c b/src/arch/arm/kernel/boot.c index ec43aa375..7363ca65c 100644 --- a/src/arch/arm/kernel/boot.c +++ b/src/arch/arm/kernel/boot.c @@ -241,7 +241,7 @@ 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) { + ndks_boot.bi_frame->ioSpaceCaps.end == 0) { return false; } } diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index cc351ed0a..19437dbd8 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -247,10 +247,10 @@ decodeARMIOPTInvocation( } iopde = iopde_iopde_pt_new( - 1, /* read */ - 1, /* write */ - 1, /* nonsecure */ - paddr + 1, /* read */ + 1, /* write */ + 1, /* nonsecure */ + paddr ); setThreadState(ksCurThread, ThreadState_Restart); @@ -368,38 +368,38 @@ decodeARMIOMapInvocation( if ((frame_cap_rights == VMReadOnly) && cap_rights_get_capAllowRead(dma_cap_rights_mask)) { /* read only */ iopte = iopte_new( - 1, /* read */ - 0, /* write */ - 1, /* nonsecure */ - paddr + 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 + 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 = iopte_new( - 0, /* read */ - 1, /* write */ - 1, /* nonsecure */ - paddr + 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 = iopte_new( - 1, /* read */ - 1, /* write */ - 1, /* nonsecure */ - paddr + 1, /* read */ + 1, /* write */ + 1, /* nonsecure */ + paddr ); } else { userError("IOMap: Invalid argument."); From 1009034c601250e0f74b16f90b030428518bba06 Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Fri, 27 May 2016 12:41:39 +1000 Subject: [PATCH 17/18] arm-hyp/tk1: remove unnecessary check --- src/arch/arm/object/iospace.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/arch/arm/object/iospace.c b/src/arch/arm/object/iospace.c index 19437dbd8..d931bb3e5 100644 --- a/src/arch/arm/object/iospace.c +++ b/src/arch/arm/object/iospace.c @@ -233,15 +233,9 @@ decodeARMIOPTInvocation( } lu_ret = lookupIOPDSlot(pd, io_address); - if (lu_ret.status != EXCEPTION_NONE) { - current_syscall_error.type = seL4_InvalidCapability; - current_syscall_error.invalidCapNumber = 1; - - return EXCEPTION_SYSCALL_ERROR; - } if (isIOPDEValid(lu_ret.iopdSlot)) { - userError("IOPTMap: Delet first."); + userError("IOPTMap: Delete first."); current_syscall_error.type = seL4_DeleteFirst; return EXCEPTION_SYSCALL_ERROR; } From eee71654b2c7e13ff282109845073794b337b060 Mon Sep 17 00:00:00 2001 From: Yanyan Shen Date: Fri, 27 May 2016 12:45:51 +1000 Subject: [PATCH 18/18] arm-hyp/tk1: add ARM_HYP as a dependency --- Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kconfig b/Kconfig index 55213e7f0..88f83e1e2 100644 --- a/Kconfig +++ b/Kconfig @@ -243,7 +243,7 @@ config ARM_HYPERVISOR_SUPPORT config ARM_SMMU_VM_DEFAULT_MAPPING bool "Enable SystemMMU default mapping for guest VM" - depends on PLAT_TK1 && ARM_SMMU + depends on PLAT_TK1 && ARM_SMMU && ARM_HYPERVISOR_SUPPORT help Enable the default translation for guest VM: all physical memory reserved for a VM is allowed to