0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Normal World与Secure World的地址空间隔离是如何实现的

jf_EksNQtU6 来源:谈思实验室 2023-09-05 09:36 次阅读

前言

众所周知,Normal World的用户态与内核态的地址空间隔离是基于MMU分页来实现的,那么Normal World与Secure World的地址空间隔离是如何实现的呢?

这篇文章将从CPU和OS的角度进行深入分析,并分析其中存在的安全风险。

硬件隔离机制

阅读ARM TrustZone手册可知,内存的隔离是由TZASC(TrustZone Address Space Controller)来控制 ,TZASC可以把外部DDR分成多个区域,每个区域可以单独配置为安全区域或非安全区域 ,Normal World的代码只能访问非安全区域。

5bd08582-4b09-11ee-97a6-92fbcf53809c.png

下面以TZC-380这款地址空间控制器来进行说明,其它型号控制器的原理也大同小异。

通过配置 TZASC的寄存器来设置不同属性的region,

•一个region表示 一段连续的物理地址空间,

•TZASC给每个region提供了一个可编程的安全属性域,

•只有在Secure状态下才允许修改这些寄存器,

•TZASC的基址不是固定的,不同厂商实现可能不同,但是每个寄存器的offset是固定的,如下所示:

5be95652-4b09-11ee-97a6-92fbcf53809c.png

CODE-TEEOS内存管理

下面结合【OP-TEE代码】[1]对配置 TZASC进行分析:

core/drivers/tzc380.c

通过对region对应的控制寄存器进行设置来配置安全内存地址空间:tzc_configure_region

/*
*`tzc_configure_region`isusedtoprogramregionsintotheTrustZone
*controller.
*/
voidtzc_configure_region(uint8_tregion,vaddr_tregion_base,uint32_tattr)
{
assert(tzc.base);

assert(region< tzc.num_regions);

    /*
     * For region 0, this high/low/size/en field is Read Only (RO).
     * So should not configure those field for region 0.
     */
    if (region) {
        // 设置Region Setup Low Register
//注意:regionn的基址寄存器的[14:0]永远为0,因为TZASC不允许regionsize小于32KB
tzc_write_region_base_low(tzc.base,region,
addr_low(region_base));
//设置RegionSetupHighRegister,第n个region基址的[63:32]位
//和上面的lowaddr拼成完整的region基址
tzc_write_region_base_high(tzc.base,region,
addr_high(region_base));
//设置RegionAttributesRegister
//控制permissions,regionsize,subregiondisable,andregionenable
tzc_write_region_attributes(tzc.base,region,attr);
}else{
//第0个region的基址不需要设置,只需要设置region的属性
tzc_write_region_attributes(tzc.base,region,
attr&TZC_ATTR_SP_MASK);
}
}
//设置RegionSetupLowRegister的值
staticvoidtzc_write_region_base_low(vaddr_tbase,uint32_tregion,
uint32_tval)
{
//定位到第region个Region对应的寄存器,即上图中的region_setup_low_n
//tzasc基址寄存器+regioncontrol寄存器的偏移(0x100)+regionn寄存器的size
io_write32(base+REGION_SETUP_LOW_OFF(region),val);
}

通过阅读代码可知,tzc_configure_region是对第n个region的基址、大小和属性进行设置 ,其中属性寄存器的格式如下:

5c0e0470-4b09-11ee-97a6-92fbcf53809c.png

•sp

: 第n个region的权限设置 ,当发生访问region时,sp控制TZASC是否允许访问region。

•size

:第n个region的大小 。

•subregion_disable

: region被划分为8个相同大小的sub-regions,第一位表示相应的subregion是否disabled。

•en

: 第n个region是否开启。

imx_configure_tzasc函数中对region进行了配置 :

staticTEE_Resultimx_configure_tzasc(void)
{
vaddr_taddr[2]={0};
intend=1;
inti=0;
//TZASC基址
addr[0]=core_mmu_get_va(TZASC_BASE,MEM_AREA_IO_SEC);
......

for(i=0;i< end; i++) {
        uint8_t region = 1;
        // 从tzasc的配置寄存器中读取配置信息,包括region数量、地址总线宽度等 
        tzc_init(addr[i]);
        // tzc_auto_configure调用tzc_configure_region按regions_size对齐,并对内存空间进行属性设置
        //第1个region配置为CFG_DRAM_BASE起始的CFG_DDR_SIZE大小的非安全/安全状态可读写的内存
        region = tzc_auto_configure(CFG_DRAM_BASE, CFG_DDR_SIZE,
                 TZC_ATTR_SP_NS_RW, region);
        // 第2个region配置为CFG_TZDRAM_START起始的CFG_TZDRAM_SIZE大小 的安全状态可读写的内存(即安全内存)
        region = tzc_auto_configure(CFG_TZDRAM_START, CFG_TZDRAM_SIZE,
                 TZC_ATTR_SP_S_RW, region);
        // 第3个region配置为CFG_SHMEM_START起始的CFG_SHMEM_SIZE大小 的非安全/安全状态下可读写的内存(即共享内存)
        region = tzc_auto_configure(CFG_SHMEM_START, CFG_SHMEM_SIZE,
                 TZC_ATTR_SP_ALL, region);
        tzc_dump_state();
        if (tzc_regions_lockdown() != TEE_SUCCESS)
            panic("Region lockdown failed!");
    }
    return TEE_SUCCESS;
}

Region 0用来设置整个地址空间的默认属性,它的基址为0,Size是由AXI_ADDRESS_MSB来配置,因此Region 0除了安全属性字段之外,其它字段不允许设置。

下面以第一个region为例,对安全属性进行分析: 第一个region的属性为TZC_ATTR_SP_NS_RW:

#defineTZC_SP_NS_WBIT(0)
#defineTZC_SP_NS_RBIT(1)
#defineTZC_SP_S_WBIT(2)
#defineTZC_SP_S_RBIT(3)

#defineTZC_ATTR_SP_SHIFT28//属性位[28:31]

#defineTZC_ATTR_SP_NS_RW((TZC_SP_NS_W|TZC_SP_NS_R)<< 
                TZC_ATTR_SP_SHIFT)

根据手册可知,TZC_SP_NS_W(b0001)是Non-secure write和 Secure write,TZC_SP_NS_R(b0010)是Non-secure read和Secure read,所以TZC_ATTR_SP_NS_RW 表示 Non-secure和Secure状态可读写,即配置了DRAM地址空间的属性为非安全和安全状态都可以读写。

5c299dca-4b09-11ee-97a6-92fbcf53809c.png

总结:

以上代码配置了CFG_TZDRAM_START开始的CFG_TZDRAM_SIZE大小的地址空间为安全内存,即只有安全状态下(TCR.NS=0)可以访问。

CFG_DRAM_BASE开始的CFG_DRAM_SIZE大小的地址空间为普通内存,安全和非安全状态下都可以访问

CFG_SHMEM_START开始的CFG_SHMEM_SIZE大小的地址空间为共享内存,安全和非安全状态都可以 访问 。

【OP-TEE物理内存布局:】[2]

core/arch/arm/include/mm/generic_ram_layout.h

*TEERAMlayoutwithoutCFG_WITH_PAGER
*_
*+----------------------------------+<-- CFG_TZDRAM_START
 *  | TEE core secure RAM (TEE_RAM)    |
 *  +----------------------------------+
 *  | Trusted Application RAM (TA_RAM) |
 *  +----------------------------------+
 *  | SDP test memory (optional)       |
 *  +----------------------------------+ <-- CFG_TZDRAM_START + CFG_TZDRAM_SIZE
 *
 *  +----------------------------------+ <-- CFG_SHMEM_START
 *  | Non-secure static SHM            |
 *  +----------------------------------+ <-- CFG_SHMEM_START + CFG_SHMEM_SIZE

至此,已经完成了安全内存的配置,接下来我们再来看下安全OS是如何使用这些物理内存的。

CODE-TEEOS内存管理

core/arch/arm/kernel/entry_a64.S

【TEE OS启动时会调用core_init_mmu_map对安全内存地址空间进行映射 :】[3]

#ifdefCFG_CORE_ASLR
movx0,x20
blget_aslr_seed#x0用来保存开启aslr的seed
#else
movx0,#0
#endif

adrx1,boot_mmu_config
blcore_init_mmu_map#记录PA和VA的对应关系,并初始化页表

......

bl__get_core_pos
blenable_mmu#设置ttbr0_el1、tcr_el1,开启分页,在开启页之前,VA==PA

core_init_mmu_map函数根据编译时注册的物理内存地址信息对页表进行初始化,也就是对物理内存进行内存映射:

void__weakcore_init_mmu_map(unsignedlongseed,structcore_mmu_config*cfg)
{
#ifndefCFG_VIRTUALIZATION
//__nozi_start在链接脚本中指定,一级页表的地址
vaddr_tstart=ROUNDDOWN((vaddr_t)__nozi_start,SMALL_PAGE_SIZE);
#else
vaddr_tstart=ROUNDDOWN((vaddr_t)__vcore_nex_rw_start,
SMALL_PAGE_SIZE);
#endif
vaddr_tlen=ROUNDUP((vaddr_t)__nozi_end,SMALL_PAGE_SIZE)-start;
structtee_mmap_region*tmp_mmap=get_tmp_mmap();
unsignedlongoffs=0;
//检查安全和非安全区域是否有重叠,如果有重叠,则系统panic
check_sec_nsec_mem_config();
//static_memory_map记录mmap_region的PA、VA,用来PA/VA转换
//第一个mmap_region记录的是一级页表的PA和VA
static_memory_map[0]=(structtee_mmap_region){
.type=MEM_AREA_TEE_RAM,//region的内存类型
.region_size=SMALL_PAGE_SIZE,//内存粒度
.pa=start,
.va=start,
.size=len,
.attr=core_mmu_type_to_attr(MEM_AREA_IDENTITY_MAP_RX),
};

COMPILE_TIME_ASSERT(CFG_MMAP_REGIONS>=13);
//初始化内存信息表,即记录下各region的PA/VA,用来PV/VA转换
//后面也会根据这些信息对页表进行初始化
offs=init_mem_map(tmp_mmap,ARRAY_SIZE(static_memory_map),seed);

check_mem_map(tmp_mmap);
core_init_mmu(tmp_mmap);//初始化页表,进行内存映射
dump_xlat_table(0x0,1);
core_init_mmu_regs(cfg);//记录页表基址,用来设置TTBR0
cfg->load_offset=offs;
memcpy(static_memory_map,tmp_mmap,sizeof(static_memory_map));
}

上面函数首先调用init_mem_map初始化一个内存信息表,记录下各Region的PA和VA,此表用来物理地址和虚拟地址转换,后面页表初始化时也会根据此表进行填充。

staticunsignedlonginit_mem_map(structtee_mmap_region*memory_map,
size_tnum_elems,unsignedlongseed)
{
/*
*@id_map_startand@id_map_enddescribesaphysicalmemoryrange
*thatmustbemappedRead-OnlyeXecutableatidenticalvirtual
*addresses.
*/
vaddr_tid_map_start=(vaddr_t)__identity_map_init_start;
vaddr_tid_map_end=(vaddr_t)__identity_map_init_end;
unsignedlongoffs=0;
size_tlast=0;
//根据已注册的物理地址空间信息来设置memory_map中tee_mmap_region的物理地址范围(即PA、SIZE)
last=collect_mem_ranges(memory_map,num_elems);
//设置memory_map中tee_mmap_region的region_size(内存粒度)
//如果是tee侧的安全内存,则设置region_size为SMALL_PAGE_SIZE(4K)
assign_mem_granularity(memory_map);

/*
*Toeasemappingandloweruseofxlattables,sortmapping
*descriptionmovingsmall-pageregionsafterthepgdirregions.
*/
qsort(memory_map,last,sizeof(structtee_mmap_region),
cmp_init_mem_map);
//添加一个MEM_AREA_PAGER_VASPACE类型的tee_mmap_region
add_pager_vaspace(memory_map,num_elems,&last);
if(IS_ENABLED(CFG_CORE_ASLR)&&seed){
//如果开启了ASLR,则将安全内存起始地址加上一个随机值
vaddr_tbase_addr=TEE_RAM_START+seed;
constunsignedintva_width=get_va_width();
constvaddr_tva_mask=GENMASK_64(va_width-1,
SMALL_PAGE_SHIFT);
vaddr_tba=base_addr;
size_tn=0;

for(n=0;n< 3; n++) {
            if (n)
                ba = base_addr ^ BIT64(va_width - n);
            ba &= va_mask;  // 得到一个有效的VA,按页对齐并且高位无效位清零
            if (assign_mem_va(ba, memory_map) && // 设置memory_map中PA对应的VA为ba,已经随机化
                mem_map_add_id_map(memory_map, num_elems, &last, 
                           id_map_start, id_map_end)) { //// 向memory_map数组中添加一个region, PA为id_map_start
                offs = ba - TEE_RAM_START;
                DMSG("Mapping core at %#"PRIxVA" offs %#lx",
                     ba, offs);
                goto out;
            } else {
                DMSG("Failed to map core at %#"PRIxVA, ba);
            }
        }
        EMSG("Failed to map core with seed %#lx", seed);
    }
    // 未开启ASLR,则设置memory_map中PA对应的VA为TEE_RAM_START,即PA==VA
    // 注意,va和size必须以region_size对齐,memory_map中region的PA可能不是连续的,
    // 但是VA地址空间是连续的
    if (!assign_mem_va(TEE_RAM_START, memory_map))
        panic();

out:
    qsort(memory_map, last, sizeof(struct tee_mmap_region),
          cmp_mmap_by_lower_va);

    dump_mmap_table(memory_map);

    return offs;
}

其中,collect_mem_ranges根据编译时保存到phys_mem_map节中物理内存信息来设置memory_map中tee_mmap_region的物理地址范围 。

//根据已注册的物理地址空间信息设置memory_map数组中tee_mmap_region的物理地址范围
staticsize_tcollect_mem_ranges(structtee_mmap_region*memory_map,
size_tnum_elems)
{
conststructcore_mmu_phys_mem*mem=NULL;
size_tlast=0;
//根据phys_mem_map设置memory_map(用于记录region的PA/VA的对应关系)的PA、SIZE和attr
//phys_mem_map_begin是phys_mem_map数组的起始地址
for(mem=phys_mem_map_begin;mem< phys_mem_map_end; mem++) {
        struct core_mmu_phys_mem m = *mem;

        /* Discard null size entries */
        if (!m.size)
            continue;

        /* Only unmapped virtual range may have a null phys addr */
        assert(m.addr || !core_mmu_type_to_attr(m.type));
        // 根据phy_mem_map设置memory_map的物理地址范围及属性
        add_phys_mem(memory_map, num_elems, &m, &last);
    }

#ifdef CFG_SECURE_DATA_PATH
    // 首先检查 phys_sdp_mem地址空间是否有重叠
    // 然后检查 memory_map与phys_sdp_mem的地址空间是否有重叠,有重叠则panic
    verify_special_mem_areas(memory_map, num_elems, phys_sdp_mem_begin,
                 phys_sdp_mem_end, "SDP");
    check_sdp_intersection_with_nsec_ddr();
#endif
    // 检查memory_map与非安全地址空间phys_nsec_addr是否有重叠
    verify_special_mem_areas(memory_map, num_elems, phys_nsec_ddr_begin,
                 phys_nsec_ddr_end, "NSEC DDR");

    // 插入到memory_map中一个MEM_AREA_RES_VASPACE类型的map_region
    // memory_map中的map_region按type从小到大进行了排序 
    add_va_space(memory_map, num_elems, MEM_AREA_RES_VASPACE,
             CFG_RESERVED_VASPACE_SIZE, &last);

    add_va_space(memory_map, num_elems, MEM_AREA_SHM_VASPACE,
             SHM_VASPACE_SIZE, &last);

    memory_map[last].type = MEM_AREA_END;

    return last;
}

通过 register_phys_mem 这个宏将TEE、非安全的共享内存的物理地址空间编译到phys_mem_map这个section。

register_phys_mem(MEM_AREA_TEE_RAM,TEE_RAM_START,TEE_RAM_PH_SIZE);
register_phys_mem(MEM_AREA_TA_RAM,TA_RAM_START,TA_RAM_SIZE);
register_phys_mem(MEM_AREA_NSEC_SHM,TEE_SHMEM_START,TEE_SHMEM_SIZE);
register_sdp_mem(CFG_TEE_SDP_MEM_BASE,CFG_TEE_SDP_MEM_SIZE);
register_phys_mem_ul(MEM_AREA_TEE_RAM_RW,VCORE_UNPG_RW_PA,VCORE_UNPG_RW_SZ);
.....

register_phys_mem这个宏使用关键字”section”将修饰的变量按照core_mmu_phys_mem结构体编译到phys_mem_map这个section中。

phys_mem_map_begin指向phys_mem_map这个section的起始地址 。

collect_mem_ranges会根据这个section的信息初始化static_memory_map内存信息数组,这个数组用来 记录各region的PA、VA、内存属性、地址空间范围等信息。

#defineregister_phys_mem(type,addr,size)
__register_memory(#addr,(type),(addr),(size),
phys_mem_map)

#define__register_memory(_name,_type,_addr,_size,_section)
SCATTERED_ARRAY_DEFINE_ITEM(_section,structcore_mmu_phys_mem)=
{.name=(_name),.type=(_type),.addr=(_addr),
.size=(_size)}

值得注意的是,上面注册的TEE_RAM_START开始的物理地址空间就是TZC-380配置的Region 2,即安全内存地址空间。

#defineTEE_RAM_STARTTZDRAM_BASE
#defineTEE_RAM_PH_SIZETEE_RAM_VA_SIZE
#defineTZDRAM_BASECFG_TZDRAM_START
#defineTZDRAM_SIZECFG_TZDRAM_SIZE

接下来, core_init_mmu调用core_init_mmu_ptn来对整个注册的内存地址空间进行VA到PA的映射,即根据PA和VA填充页表。

voidcore_init_mmu_prtn(structmmu_partition*prtn,structtee_mmap_region*mm)
{
size_tn;

assert(prtn&&mm);

for(n=0;!core_mmap_is_end_of_table(mm+n);n++){
debug_print("%010"PRIxVA"%010"PRIxPA"%10zx%x",
mm[n].va,mm[n].pa,mm[n].size,mm[n].attr);

if(!IS_PAGE_ALIGNED(mm[n].pa)||!IS_PAGE_ALIGNED(mm[n].size))
panic("unalignedregion");
}

/*Cleartablebeforeuse*/
memset(prtn->l1_tables,0,sizeof(l1_xlation_table));

for(n=0;!core_mmap_is_end_of_table(mm+n);n++)
//如果不是动态虚拟地址空间,则进行填充页表(映射内存)
if(!core_mmu_is_dynamic_vaspace(mm+n))
//根据PA/VA填充页表,即做内存映射
core_mmu_map_region(prtn,mm+n);

/*
*Primarymappingtableisreadyatindex`get_core_pos()`
*whosevaluemaynotbeZERO.Takethisindexascopysource.
*/
//根据已设置的页表设置所有核的页表
for(n=0;n< CFG_TEE_CORE_NB_CORE; n++) {
        if (n == get_core_pos())
            continue;

        memcpy(prtn->l1_tables[0][n],
prtn->l1_tables[0][get_core_pos()],
XLAT_ENTRY_SIZE*NUM_L1_ENTRIES);
}
}

到这里,TEE侧OS已经完成了对物理内存的映射,包括安全内存和共享内存。在开启分页后,TEEOS就可以访问这些虚拟内存地址空间了。

CODE-安全侧地址校验

下面以符合GP规范的TEE接口为例,简单介绍下CA和TA的通信流程:

5c50e718-4b09-11ee-97a6-92fbcf53809c.png

篇幅所限,这里仅分析Secure World侧的调用流程,重点关注TA_InvokeCommandEntryPoint调用流程,此函数用来处理所有来自Normal World侧的请求,安全侧可信应用的漏洞挖掘也是从这个函数开始入手,这里我们只分析地址校验相关流程

•1.在TEEC_OpenSession中会去加载TA的elf文件,并设置相应的函数操作表,最终调用目标TA的TA_OpenSessionEntryPoint。__tee_entry_std
-->entry_open_session
-->tee_ta_open_session
-->tee_ta_init_session-->tee_ta_init_user_session-->set_ta_ctx_ops
-->ctx->ops->enter_open_session(user_ta_enter_open_session)
-->user_ta_enter
-->tee_mmu_map_param
-->thread_enter_user_mode
-->__thread_enter_user_mode//返回到S_EL0,调用目标TA的TA_OpenSessionEntryPoint

•2.TA_InvokeCommandEntryPoint调用流程如下,在此函数中会对REE传入的地址进行校验。__tee_entry_std
-->entry_invoke_command
-->copy_in_param
-->set_tmem_param//如果是memref类型,则调用set_tmem_param分配共享内存
-->msg_param_mobj_from_nocontig
-->mobj_mapped_shm_alloc
-->mobj_reg_shm_alloc//最终会调用core_pbuf_is来检查RRE传入的PA是否在非安全内存地址范围内
-->tee_ta_get_session
-->tee_ta_invoke_command
-->check_params
-->sess->ctx->ops->enter_invoke_cmd(user_ta_enter_invoke_cmd)
-->user_ta_enter
-->tee_mmu_map_param//映射用户空间地址(S_EL0)
-->tee_ta_push_current_session
-->thread_enter_user_mode//返回S_EL0相应的TA中执行TA_InvokeCommandEntryPoint

通过以上代码分析可知,在调用TA的TA_InvokeCommandEntryPoint函数之前会对REE侧传入的参数类型进行检查 ,在TA代码中使用REE传入参数作为内存地址的场景下,如果未校验对应的参数类型或者参数类型为TEEC_VALUE_INPUT(与实际使用参数类型不匹配),则会绕过上面core_pbuf_is对REE传入PA的检查 ,可以传入任意值,这个值可以为安全内存PA,这样就可以导致以S_EL0权限读写任意安全内存。

总结

TEE作为可信执行环境,通常用于运行处理指纹、人脸、PIN码等关键敏感信息的可信应用,即使手机被ROOT,攻击者也无法获取这些敏感数据。

因此TEE侧程序的安全至关重要,本文深入分析了TRUSTZONE物理内存隔离、TEEOS内存管理及TEE侧对REE传入地址的校验。

在了解了这些原理之后,我们就可以进行漏洞挖掘了, 当然也能写出简单有效的FUZZ工具。只有对漏洞原理、攻击方法进行深入的理解 ,才能进行有效的防御。

FUZZ是一个模糊测试工具,用于在漏洞挖掘过程中进行重要的一步。它能够检查常见的漏洞,如缓冲区溢出、格式串漏洞、整数溢出等。

模糊测试是一种通过输入大量随机产生的数据来检测程序异常的自动化测试方法。在模糊测试中,测试用例是随机生成的,而不是手动创建的。这种方法可以帮助发现一些常见的问题,如边界条件错误、类型错误、内存泄漏等。

FUZZ-COV是另一个流行的模糊测试工具,它使用覆盖引导技术来提高模糊测试的效率。该工具能够检测出更多的漏洞,并且比其他工具更快。

除了FUZZ和FUZZ-COV,还有其他一些模糊测试工具,如BETA、BAP和LibFuzzer。这些工具在设计和实现上略有不同,但它们的目标是相同的,即发现程序中的漏洞。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 控制器
    +关注

    关注

    112

    文章

    15235

    浏览量

    171212
  • 寄存器
    +关注

    关注

    30

    文章

    5032

    浏览量

    117746
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10446

    浏览量

    206574
  • 内存管理
    +关注

    关注

    0

    文章

    163

    浏览量

    14057

原文标题:参考

文章出处:【微信号:谈思实验室,微信公众号:谈思实验室】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    隔离器按照封装形式分为在线型隔离器和自由空间隔离

    自由空间隔离器按照对输入光的偏振要求,又分为偏振相关隔离器和偏振无光隔离器。由于激光器输出光的偏振态是确定的,因此光组件中用量最大的是偏振相关自由空间隔离器。
    的头像 发表于 07-15 14:39 9859次阅读

    在armv8下如何在secure world里开发裸机驱动?

    使用的是Hikey开发板,现在需要在secure world里面开发一个驱动,去直接操作比如键盘什么的,但是不知道在状态为secure的时候,能不能访问这些硬件。不知道有没有大神做过,可否指点一下。谢谢!
    发表于 03-08 01:10

    Arduino Hello World实验

    `先来练习一个不需要其他辅助元件,只需要一块Arduino 和一根下载线的简单实验,让我们的Arduino 说出“Hello World!”,这是一个让Arduino和PC 机通信的实验,这也是一个
    发表于 08-06 09:06

    基于SAFERTOS系统的时间隔离实现

    SAFECheckpoints基于SAFERTOS的功能安全系统中,除了空间隔离外,针对不同的安全标准,可能还需要时间隔离功能,确保软件的时间处理需求。在单核处理器中,可以使用软件组件来检测对系统
    发表于 07-11 11:18

    【精彩回顾】HarmonyOS先行者技术沙龙—— Hello New World

    ,比如:一个完整的嵌入式系统都有什么?操作系统怎么“同时运行”多个任务?支持MMU的操作系统,怎么实现空间隔离?支持MMU的操作系统,怎么实现权限控制?移植一个最小系统要做什么事情?以及HDF驱动程序介绍
    发表于 10-27 15:49

    【HarmonyOS】HarmonyOS先行者技术沙龙—— Hello New World

    ,怎么实现空间隔离?支持MMU的操作系统,怎么实现权限控制?移植一个最小系统要做什么事情?以及HDF驱动程序介绍。精彩回顾(四)为OpenHarmony移植MCU芯片简介:中科院软件所智能软件研究中心
    发表于 10-27 19:35

    基于Nios II的hello world相关资料分享

    目录一、基于Nios II的hello world1、NiosII实现hello world1.1硬件设计1.2软件设计1.3下载硬件和软件一、基于Nios II的hello world
    发表于 12-27 08:13

    如何利用Niso ||实现hello world

    基于Nios || 的 hello world一、Qsys二、Nios ||介绍三、利用Niso ||实现hello world(一)硬件设计(二)软件设计(三)下载硬件和软件一、Qsys简介
    发表于 01-25 06:24

    如何在Arm计算平台中实现机密计算

    执行和数据访问方面,Realm 能与 Normal world 完全隔离。Arm CCA 通过将架构硬件扩展和固件相结合实现了这种隔离。在
    发表于 08-05 14:40

    Android开发之“hello World”的实现

    按照惯例,同时也是为了更好地引导读者进入精彩的Android世界,我们接下来要实现一个简单的“hello World”例子。
    发表于 08-24 11:20 5497次阅读
    Android开发之“hello <b class='flag-5'>World</b>”的<b class='flag-5'>实现</b>

    基于ARC SDE扩展World Wind Java空间检索能力的方法

    ARC SDE提供的空间数据检索函数开发的服务接口扩展实现World Wind Java的空间数据检索功能,并在北海区海洋综合信息一张图系统中进行了实际应用,验证了方法的有效性。
    发表于 11-27 17:23 0次下载

    基于Nios 的 hello world

    基于Nios || 的 hello world一、Qsys二、Nios ||介绍三、利用Niso ||实现hello world(一)硬件设计(二)软件设计(三)下载硬件和软件一、Qsys简介
    发表于 11-30 17:36 9次下载
    基于Nios  的 hello <b class='flag-5'>world</b>

    HELLO WORLD!

    HELLO WORLD
    发表于 12-03 16:21 8次下载
    HELLO <b class='flag-5'>WORLD</b>!

    STM32开发入门(二)——Hello World

    STM32开发入门(二)——Hello World
    发表于 12-07 18:51 11次下载
    STM32开发入门(二)——Hello <b class='flag-5'>World</b>

    Engineering-the-5G-World

    Engineering-the-5G-World,是德公司关于5G的理解和测试项解释。
    发表于 05-15 10:21 0次下载