zoukankan      html  css  js  c++  java
  • 鸿蒙轻内核源码分析:MMU协处理器

    摘要:本系列首先了解下ARM CP15协处理器的知识,接着介绍下协处理器相关的汇编指令,最后分析下MMU相关汇编代码。

    本文分享自华为云社区《鸿蒙轻内核A核源码分析系列六 MMU协处理器》,作者:zhushy。

    1、 ARM C15 协处理器

    在ARM嵌入式应用系统中, 很多系统控制由ARM CP15协处理器来完成的。CP15协处理器包含编号0-15的16个32位的寄存器。例如,ARM处理器使用C15协处理器的寄存器来控制cache、TCM(Tightly-Coupled Memory)和存储器管理。CP15的各个寄存器的概要信息如下图,图片来自官方资料《ARM® Cortex™-A Series Version: 4.0 Programmer’s Guide》。

    在这些C15寄存器中和MMU关系较大的有C2、C7、C17寄存器,这些寄存器的作用,从上图可以看出,分别是:

    • CP15 C2寄存器

    Memory protection and control registers,内存保护和控制寄存器,包含Translation Table Base Register 0 (TTBR0)、Translation Table Base Register 1 (TTBR1)和Translation Table Base Control Register (TTBCR)。TTBR0、TTBR1是L1转换页表的基地址,TTCR控制TTBR0和TTBR1的使用。

    • CP15 C7寄存器

    Cache and branch predictor maintenance functions、Data and instruction barrier operations用于高速缓存和写缓存控制。

    • CP15 C13寄存器

    Context ID Register (CONTEXTIDR)、Software thread ID registers用于保存进程标识符(asid地址空间编号)。

    2、ARM C15 协处理器汇编指令

    访问CP15寄存器的指令主要是MCR和MRC这两个指令。本小节详细介绍下这2个汇编指令。先看下指令的含义,MCR是ARM处理器寄存器到协处理器寄存器的数据传送指令,英文为Move CPU register to coprocessor register,MRC是协处理器寄存器到ARM处理器寄存器的数据传送指令,英文为Move from coprocessor register to CPU register。这2个指令的语义格式如下,可以看出语义格式是一样的,但是读取写入含义会有差异。MCR是读取Rt寄存器写入协处理器寄存器CRn、CRm,而MRC是读取协处理器寄存器CRn、CRm写入Rt寄存器。

    MCR{cond} coproc, #opcode1, Rt, CRn, CRm{, #opcode2}
    MRC{cond} coproc, #opcode1, Rt, CRn, CRm{, #opcode2}

    MCR详细的语义介绍如下:

    Syntax
    MCR{cond} coproc, #opcode1, Rt, CRn, CRm{, #opcode2}
    
    where:
    cond
    is an optional condition code. 可选的条件码。
    coproc
    is the name of the coprocessor the instruction is for. The standard name is pn, where n is an integer in the range 0 to 15.协处理器的名称,标准名称为pn,其中n为0-15,例如p14、p15。
    opcode1
    is a 3-bit coprocessor-specific opcode. 3位的操作码。
    opcode2
    is an optional 3-bit coprocessor-specific opcode.可选的3位操作码。
    Rt
    is an ARM source register. Rt must not be PC. 要读取的ARM寄存器,不能为PC寄存器。
    CRn, CRm
    are coprocessor registers.要写入的协处理器寄存器。

    MRC详细的语义介绍如下:

    Syntax
    MRC{cond} coproc, #opcode1, Rt, CRn, CRm{, #opcode2}
    
    where:
    cond
    is an optional condition code.  可选的条件码。
    coproc
    is the name of the coprocessor the instruction is for. The standard name is pn, where n is an integer in the range 0 to 15.协处理器的名称,标准名称为pn,其中n为0-15,例如p14、p15。
    opcode1
    is a 3-bit coprocessor-specific opcode.3位的操作码。
    opcode2
    is an optional 3-bit coprocessor-specific opcode.可选的3位操作码
    Rt
    is the ARM destination register. Rt must not be PC.要写入的ARM寄存器,不能为PC寄存器。
    Rt can be APSR_nzcv. This means that the coprocessor executes an instruction that changes the value of the condition flags in the APSR. Rt也可以为APSR_nzcv。
    CRn, CRm
    are coprocessor registers.要读取的协处理器寄存器。

    3、MMU汇编代码

    在arch\arm\arm\include\arm.h文件中,封装了CP15协处理器相关的寄存器操作汇编函数。我们主要看下MMU相关的部分。

    3.1 CP15 C2 TTBR转换表基地址寄存器

    代码比较简单,结合下图,自行查看即可。该图来自《ARM Cortex-A9 Technical Reference Manual r4p1》CP15 system control registers grouped by CRn order部分。

    STATIC INLINE UINT32 OsArmReadTtbr(VOID)
    {
        UINT32 val;
        __asm__ volatile("mrc p15, 0, %0, c2,c0,0" : "=r"(val));
        return val;
    }
    
    STATIC INLINE VOID OsArmWriteTtbr(UINT32 val)
    {
        __asm__ volatile("mcr p15, 0, %0, c2,c0,0" ::"r"(val));
        __asm__ volatile("isb" ::: "memory");
    }
    
    STATIC INLINE UINT32 OsArmReadTtbr0(VOID)
    {
        UINT32 val;
        __asm__ volatile("mrc p15, 0, %0, c2,c0,0" : "=r"(val));
        return val;
    }
    
    STATIC INLINE VOID OsArmWriteTtbr0(UINT32 val)
    {
        __asm__ volatile("mcr p15, 0, %0, c2,c0,0" ::"r"(val));
        __asm__ volatile("isb" ::: "memory");
    }
    
    STATIC INLINE UINT32 OsArmReadTtbr1(VOID)
    {
        UINT32 val;
        __asm__ volatile("mrc p15, 0, %0, c2,c0,1" : "=r"(val));
        return val;
    }
    
    STATIC INLINE VOID OsArmWriteTtbr1(UINT32 val)
    {
        __asm__ volatile("mcr p15, 0, %0, c2,c0,1" ::"r"(val));
        __asm__ volatile("isb" ::: "memory");
    }
    
    STATIC INLINE UINT32 OsArmReadTtbcr(VOID)
    {
        UINT32 val;
        __asm__ volatile("mrc p15, 0, %0, c2,c0,2" : "=r"(val));
        return val;
    }
    
    STATIC INLINE VOID OsArmWriteTtbcr(UINT32 val)
    {
        __asm__ volatile("mcr p15, 0, %0, c2,c0,2" ::"r"(val));
        __asm__ volatile("isb" ::: "memory");
    }

    3.2 CP15 C7 高速缓存寄存器

    代码比较简单,结合下图,自行查看即可。该图是C7寄存器的部分截图。

    STATIC INLINE UINT32 OsArmReadBpiall(VOID)
    {
        UINT32 val;
        __asm__ volatile("mrc p15, 0, %0, c7,c5,6" : "=r"(val));
        return val;
    }
    
    STATIC INLINE VOID OsArmWriteBpiall(UINT32 val)
    {
        __asm__ volatile("mcr p15, 0, %0, c7,c5,6" ::"r"(val));
        __asm__ volatile("isb" ::: "memory");
    }
    
    STATIC INLINE UINT32 OsArmReadBpiallis(VOID)
    {
        UINT32 val;
        __asm__ volatile("mrc p15, 0, %0, c7,c1,6" : "=r"(val));
        return val;
    }
    
    STATIC INLINE VOID OsArmWriteBpiallis(UINT32 val)
    {
        __asm__ volatile("mcr p15, 0, %0, c7,c1,6" ::"r"(val));
        __asm__ volatile("isb" ::: "memory");
    }

    3.3 CP15 C13 进程标识符寄存器

    代码比较简单,结合下图,自行查看即可。

    STATIC INLINE UINT32 OsArmReadContextidr(VOID)
    {
        UINT32 val;
        __asm__ volatile("mrc p15, 0, %0, c13,c0,1" : "=r"(val));
        return val;
    }
    
    STATIC INLINE VOID OsArmWriteContextidr(UINT32 val)
    {
        __asm__ volatile("mcr p15, 0, %0, c13,c0,1" ::"r"(val));
        __asm__ volatile("isb" ::: "memory");
    }

    4 MMU上下文切换

    在之前的系列,我们了解到每个用户进程都有独立的进程空间。在进程切换时,MMU上下文也会切换,相应的函数为LOS_ArchMmuContextSwitch()。快速分析下该函数的代码。

    ⑴处读取TTBCR寄存器的状态值,如果传入参数archMmu不为空,执行⑵使能TTBR0,否则执行⑶使其失能TTBR0。⑷处把内核地址空间的进程空间标识符asid写入C13寄存器。⑸处更新TTB页表基地址和TTB状态信息到相应寄存器。⑹处把进程空间的进程标识符写入C13寄存器。

    VOID LOS_ArchMmuContextSwitch(LosArchMmu *archMmu)
    {
        UINT32 ttbr;
    ⑴   UINT32 ttbcr = OsArmReadTtbcr();
        if (archMmu) {
    ⑵      ttbr = MMU_TTBRx_FLAGS | (archMmu->physTtb);
            /* enable TTBR0 */
            ttbcr &= ~MMU_DESCRIPTOR_TTBCR_PD0;
        } else {
    ⑶      ttbr = 0;
            /* disable TTBR0 */
            ttbcr |= MMU_DESCRIPTOR_TTBCR_PD0;
        }
    
    #ifdef LOSCFG_KERNEL_VM
        /* from armv7a arm B3.10.4, we should do synchronization changes of ASID and TTBR. */
    ⑷  OsArmWriteContextidr(LOS_GetKVmSpace()->archMmu.asid);
        ISB;
    #endif
    ⑸  OsArmWriteTtbr0(ttbr);
        ISB;
        OsArmWriteTtbcr(ttbcr);
        ISB;
    #ifdef LOSCFG_KERNEL_VM
        if (archMmu) {
    ⑹      OsArmWriteContextidr(archMmu->asid);
            ISB;
        }
    #endif
    }

    小结

    本文介绍了ARM CP15协处理器的知识,接着介绍下协处理器相关的汇编指令,最后分析下MMU相关汇编代码。感谢阅读,有什么问题,请留言。

     

    点击关注,第一时间了解华为云新鲜技术~

  • 相关阅读:
    zabbix 配置发送邮件报警
    sql server 修改表结构语法大全
    SQL Server日期与字符串之间的转换
    Convert.ToDateTime(值),方法可以把一个值转化成DateTime类型。
    Oracle trunc()函数的用法
    Oracle job procedure 存储过程定时任务
    向数据库中插入一个DateTime类型的数据到一个Date类型的字段中,需要转换类型。TO_DATE('{0}','YYYY-MM-DD'))
    逗号分隔的字符串转换为行数据(collection)(续)
    Oracle中INSTR、SUBSTR和NVL的用法
    oracle中substr() instr() 用法
  • 原文地址:https://www.cnblogs.com/huaweiyun/p/15693240.html
Copyright © 2011-2022 走看看