arm/tk1: a checkpoint for SMMU implementation
This commit is contained in:
parent
c4692926a8
commit
879d9724c1
18 changed files with 760 additions and 11 deletions
|
|
@ -8,6 +8,7 @@
|
|||
-- @TAG(GD_GPL)
|
||||
--
|
||||
|
||||
#include <config.h>
|
||||
-- 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())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
28
include/arch/arm/arch/object/iospace.h
Normal file
28
include/arch/arm/arch/object/iospace.h
Normal file
|
|
@ -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 <types.h>
|
||||
#include <api/failures.h>
|
||||
#include <object/structures.h>
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
148
include/plat/tk1/plat/machine/smmu.h
Normal file
148
include/plat/tk1/plat/machine/smmu.h
Normal file
|
|
@ -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 <types.h>
|
||||
|
||||
#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
|
||||
|
|
@ -18,6 +18,14 @@
|
|||
<method id="ARMPageTableUnmap" name="Unmap">
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="seL4_ARM_IOPageTable">
|
||||
<method id="ARMIOPageTableMap" name="Map">
|
||||
<param dir="in" name="iospace" type="seL4_ARM_IOSpace"/>
|
||||
<param dir="in" name="ioaddr" type="seL4_Word"/>
|
||||
</method>
|
||||
<method id="ARMIOPageTableUnmap" name="Unmap">
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="seL4_ARM_Page">
|
||||
<method id="ARMPageMap" name="Map">
|
||||
<param dir="in" name="pd" type="seL4_ARM_PageDirectory"/>
|
||||
|
|
@ -31,6 +39,11 @@
|
|||
<param dir="in" name="attr" type="seL4_ARM_VMAttributes"/>
|
||||
</method>
|
||||
<method id="ARMPageUnmap" name="Unmap"/>
|
||||
<method id="ARMPageMapIO" name="MapIO">
|
||||
<param dir="in" name="iospace" type="seL4_ARM_IOSpace"/>
|
||||
<param dir="in" name="rights" type="seL4_CapRights"/>
|
||||
<param dir="in" name="ioaddr" type="seL4_Word"/>
|
||||
</method>
|
||||
<method id="ARMPageClean_Data" name="Clean_Data">
|
||||
<param dir="in" name="start_offset" type="seL4_Word"/>
|
||||
<param dir="in" name="end_offset" type="seL4_Word"/>
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <arch/kernel/vspace.h>
|
||||
#include <arch/benchmark.h>
|
||||
#include <arch/user_access.h>
|
||||
#include <arch/object/iospace.h>
|
||||
#include <arch/linker.h>
|
||||
#include <plat/machine/hardware.h>
|
||||
#include <machine.h>
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
299
src/arch/arm/object/iospace.c
Normal file
299
src/arch/arm/object/iospace.c
Normal file
|
|
@ -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 <config.h>
|
||||
|
||||
#include <api/syscall.h>
|
||||
#include <machine/io.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <arch/api/invocation.h>
|
||||
#include <arch/object/iospace.h>
|
||||
#include <arch/model/statedata.h>
|
||||
#include <object/structures.h>
|
||||
#include <arch/linker.h>
|
||||
#include <plat/machine/smmu.h>
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
206
src/plat/tk1/machine/smmu.c
Normal file
206
src/plat/tk1/machine/smmu.c
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
#include <types.h>
|
||||
#include <plat/machine/smmu.h>
|
||||
#include <arch/linker.h>
|
||||
#include <plat/machine/devices.h>
|
||||
#include <plat/machine/hardware.h>
|
||||
#include <object/structures.h>
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue