arm64_linux head.S的执行流程(3.18)- 3.stext之el2_setup

本文解析了高通8996平台下kernel版本3.18.31中head.S文件的el2_setup流程。该流程根据当前是否处于EL2模式进行不同处理,包括设置大小端模式、配置计数器、初始化GIC等。

1.前言

本文基于高通8996平台,kernel版本为3.18.31。
本文主要介绍head.S的el2_setup执行流程

2. el2_setup

/*
 * If we're fortunate enough to boot at EL2, 
 * ensure that the world is sane before dropping to EL1.
 *
 * Returns either BOOT_CPU_MODE_EL1 or BOOT_CPU_MODE_EL2 in x20 if
 * booted in EL1 or EL2 respectively.
 */
ENTRY(el2_setup)
//当前的exception level保存在PSTATE中,
//程序可以通过MRS或者MSR来访问PSTATE,
//CurrentEL就是获取PSTATE中current exception level域的特殊寄存器。
    mrs    x0, CurrentEL
    
// #define CurrentEL_EL2        (2 << 2)  
//判断当前是否处于EL2   
    cmp    x0, #CurrentEL_EL2
    
//当cpu不处于EL2时跳转到标号1     
    b.ne    1f
    
// 读取EL2状态的系统控制寄存器,该寄存器可以控制整个系统的行为             
    mrs    x0, sctlr_el2
    
// Set the EE bit for EL2 // 大端置位EE位     
CPU_BE(    orr    x0, x0, #(1 << 25)    ) 
// Clear the EE bit for EL2 // 小端清除EE位     
CPU_LE(    bic    x0, x0, #(1 << 25)    )
// 写入EL2状态的系统控制寄存器    
    msr    sctlr_el2, x0
    b    2f
    
1:  // 当前是EL1状态,读取EL1状态的系统控制寄存器  
    mrs    x0, sctlr_el1 
    
// Set the EE and E0E bits for EL1 // 大端置位EE位和EOE位    
CPU_BE(    orr    x0, x0, #(3 << 24)    ) 
// Clear the EE and E0E bits for EL1 // 小端清除EE位和EOE位   
CPU_LE(    bic    x0, x0, #(3 << 24)    )
// 写入EL1状态的系统控制寄存器    
    msr    sctlr_el1, x0
    
// This cpu booted in EL1 
// #define BOOT_CPU_MODE_EL1    (0xe11) 
// 将BOOT_CPU_MODE_EL1保存到通用寄存器w20     
    mov    w20, #BOOT_CPU_MODE_EL1        
    isb // 指令同步屏障,确保之前的指令已执行完成
    ret // 当cpu处于EL1,在这里就返回了

    /* Hyp configuration. */
2:    
    mov    x0, #(1 << 31) // 64-bit EL1
// Hypervisor  Configuration  Register 
// Controls virtualization settings and trapping of exceptions to  EL2    
    msr    hcr_el2, x0 
    /* Generic timers. */ 
    mrs    x0, cnthctl_el2 // Counter-timer Hyp Control register
    orr    x0, x0, #3      // Enable EL1 physical timers
    msr    cnthctl_el2, x0
    msr    cntvoff_el2, xzr // Clear virtual offset 
                            // Counter-timer Virtual Offset register 
                            // xzr零寄存器,顾名思义值为0

#ifdef CONFIG_ARM_GIC_V3
    /* GICv3 system register access */
// AArch64 Processor Feature Register 0 
    mrs    x0, id_aa64pfr0_el1
// ubfx: ARM位域提取指令,取x0的[27:24]bit 
    ubfx    x0, x0, #24, #4
// 判断是否支持GIC V3和GIC V4
    cmp    x0, #1
// 不支持的话,跳转到标号3 
    b.ne    3f

// Interrupt Controller System Register Enable register (EL2)
    mrs_s    x0, ICC_SRE_EL2 
// Set ICC_SRE_EL2.SRE==1 // 通过system register方式访问GIC    
    orr    x0, x0, #ICC_SRE_EL2_SRE
// Set ICC_SRE_EL2.Enable==1 // EL1可以直接访问GIC        
    orr    x0, x0, #ICC_SRE_EL2_ENABLE    
    msr_s    ICC_SRE_EL2, x0
// Make sure SRE is now set 
// 指令同步屏障,确保之前的指令已执行完成    
    isb
// Reset ICC_HCR_EL2 to defaults                        
    msr_s    ICH_HCR_EL2, xzr        

3:
#endif

    /* Populate ID registers. */
// Main ID Register 描述PE信息的寄存器 
// PE: Processing Element, 处理单元    
    mrs    x0, midr_el1
// Multiprocessor Affinity Register     
    mrs    x1, mpidr_el1
// 将Main ID Register 写入到对应的virtual processor的寄存器     
    msr    vpidr_el2, x0 
    msr    vmpidr_el2, x1

    /* sctlr_el1 */
// Set/clear RES{1,0} bits    
    mov    x0, #0x0800
// Set EE and E0E on BE systems // 大端0x33d00800                
CPU_BE(    movk    x0, #0x33d0, lsl #16    )
// Clear EE and E0E on LE systems // 小端0x30d00800   
CPU_LE(    movk    x0, #0x30d0, lsl #16    )
// 除了EE和EOE,其他几位都没查到,囧!    
    msr    sctlr_el1, x0 

    /* Coprocessor traps. */
    mov    x0, #0x33ff
    msr    cptr_el2, x0 // Disable copro. traps to EL2 
                       // Architectural Feature Trap Register

// 是否支持64位kernel上运行32位的application
#ifdef CONFIG_COMPAT 
    msr    hstr_el2, xzr // Disable CP15 traps to EL2
#endif

    /* Stage-2 translation */
 // Virtualization Translation Table Base Register    
    msr    vttbr_el2, xzr

    /* Hypervisor stub */
// 读取__hyp_stub_vectors相对于当前PC的地址,页对齐    
    adrp    x0, __hyp_stub_vectors 
// 处理页内偏移    
    add    x0, x0, #:lo12:__hyp_stub_vectors 
// 设置EL2的异常向量表的基地址    
    msr    vbar_el2, x0 

    /* spsr */
    mov    x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
              PSR_MODE_EL1h)
// 设置SPSR_EL2,Saved Program Status Register (EL2)的缺省值              
    msr    spsr_el2, x0 
// 设置Exception Link Register (EL2)的缺省值    
    msr    elr_el2, lr 
// This CPU booted in EL2     
// 将BOOT_CPU_MODE_EL2保存到通用寄存器w20
    mov    w20, #BOOT_CPU_MODE_EL2        
             
// eret指令是用来返回发生exception的现场,
//执行该指令会使得CPU返回EL1状态,并且将spsr_el2的值赋给PSTATE,elr_el2的值赋给pc                               
    eret 
ENDPROC(el2_setup)

补充知识
MRS Move to Register from State register, MSR Move from State register to Register, 分别用于对状态寄存器(AARCH64对应PSTATE,AARCH32对应CPSP)进行读写。

3. 总结

el2_setup主要做的工作是区分当前处于EL1还是EL2模式,根据所处模式的不同有不同的行为。
如果处于EL1模式,则设置大小端后返回;
如果处于EL2模式,设置大小端外,还做了其他一些操作,如清零计数器,设置GIC等。

参考文档

1.https://blog.youkuaiyun.com/xichangbao/article/details/51568782
2.https://www.cnblogs.com/smartjourneys/diary/2017/04/27/6774121.html
3.http://www.wowotech.net/armv8a_arch/arm64_initialize_1.html ARM64的启动过程之(一):内核第一个脚印
3.http://www.wowotech.net/armv8a_arch/create_page_tables.html ARM64的启动过程之(二):创建启动阶段的页表
4.http://www.wowotech.net/armv8a_arch/__cpu_setup.html ARM64的启动过程之(三):为打开MMU而进行的CPU初始化
5.http://www.wowotech.net/armv8a_arch/turn-on-mmu.html ARM64的启动过程之(四):打开MMU
6.https://blog.youkuaiyun.com/xichangbao/article/details/51568782 Kernel启动流程源码解析 1 head.S
7.https://blog.youkuaiyun.com/xichangbao/article/details/51605462 Kernel启动流程源码解析 2 head.S

FORM frm_crt_basic USING is_mara TYPE zplm1000s0001 it_24 TYPE tt_24 CHANGING et_ret TYPE zplm1000tt0001_o. DATA: ls_bapihead TYPE bapimathead, ls_bapimara TYPE bapi_mara, ls_bapimarax TYPE bapi_marax. DATA: ls_ret TYPE bapiret2. DATA: lt_bapimakt TYPE STANDARD TABLE OF bapi_makt. DATA: lt_bapimarm TYPE STANDARD TABLE OF bapi_marm, lt_bapimarmx TYPE STANDARD TABLE OF bapi_marmx. DATA: lt_old TYPE TABLE OF tline, lt_new TYPE TABLE OF tline, ls_header TYPE thead. DATA: lv_exist TYPE char1. DATA: lt_materiallongtext TYPE bapi_mltx OCCURS 0 WITH HEADER LINE. "Long texts "主数据长文本 DATA: BEGIN OF tab OCCURS 0, stext(100) TYPE c, END OF tab. CLEAR: ls_bapihead,ls_bapimara,ls_bapimarax,ls_ret. FREE: lt_bapimakt,lt_bapimarm,lt_bapimarmx. *----------------add by sylvia 20210910 start READ TABLE et_ret TRANSPORTING NO FIELDS WITH KEY type = &#39;E&#39; matnr = is_mara-matnr. IF sy-subrc = 0. RETURN. ENDIF. *----------------add by sylvia 20210910 end SELECT SINGLE matnr,mtart INTO @DATA(ls_mara) FROM mara WHERE matnr = @is_mara-matnr. IF sy-subrc = 0. lv_exist = abap_true. ELSE. CLEAR lv_exist. ENDIF. ls_bapihead = VALUE #( material = is_mara-matnr ind_sector = &#39;M&#39; basic_view = abap_true * storage_view = abap_true ). ls_bapimara = VALUE #( matl_group = is_mara-matkl base_uom = is_mara-meins size_dim = is_mara-groes net_weight = is_mara-ntgew unit_of_wt = is_mara-gewei std_descr = is_mara-normt basic_matl = is_mara-wrkst prod_memo = is_mara-ferth * old_mat_no = is_mara-matnr_ref ). ls_bapimarax = VALUE #( matl_group = abap_true base_uom = SWITCH #( lv_exist WHEN abap_true THEN space ELSE abap_true ) size_dim = abap_true net_weight = abap_true unit_of_wt = abap_true std_descr = abap_true basic_matl = abap_true prod_memo = abap_true * old_mat_no = abap_true ). FREE: lt_bapimarm,lt_bapimarmx. IF lv_exist IS INITIAL. lt_bapimarm = VALUE #( ( alt_unit = is_mara-meins alt_unit_iso = is_mara-meins unit_of_wt = is_mara-gewei numerator = 1 denominatr = 1 ) ). lt_bapimarmx = VALUE #( ( alt_unit = is_mara-meins alt_unit_iso = is_mara-meins unit_of_wt = abap_true numerator = abap_true denominatr = abap_true ) ). ENDIF. * CLEAR lv_exist. IF lv_exist IS INITIAL. LOOP AT it_24 INTO DATA(ls_24) WHERE matkl = is_mara-matkl. IF ls_24-zwlhqfs <> &#39;ALL&#39; AND ( ( ls_24-zwlhqfs = &#39;1&#39; AND is_mara-zprocessdiv <> &#39;自制&#39; ) OR ( ls_24-zwlhqfs = &#39;2&#39; AND is_mara-zprocessdiv <> &#39;外协&#39; ) OR ( ls_24-zwlhqfs = &#39;3&#39; AND is_mara-zprocessdiv <> &#39;外购&#39; ) ). CONTINUE. ENDIF. * IF ls_24-mtart <> is_mara-mtart. * CONTINUE. * ENDIF. IF ls_24-zgyyxdj <> &#39;ALL&#39; AND ls_24-zgyyxdj <> is_mara-zppimplv. CONTINUE. ENDIF. IF ls_24-zbmdm <> &#39;ALL&#39; AND ls_24-zbmdm <> space AND ls_24-zbmdm <> &#39;ALL&#39; AND ls_24-zbmdm <> is_mara-zappldept. CONTINUE. ENDIF. "运输组 * LS_BAPIMARA-TRANS_GRP = LS_24-TRAGR. ls_bapimara-trans_grp = &#39;0001&#39;. "MODIFY BY LIKE 改为固定值0001 2023.7.1 ls_bapimarax-trans_grp = abap_true. * 序列化级 IF ls_24-serlv IS NOT INITIAL. ls_bapimara-serialization_level = ls_24-serlv. ls_bapimarax-serialization_level = abap_true. ls_bapihead-storage_view = abap_true. ENDIF. *-->MODIFY BY LIKE 注销 2023.7.7 ** 产品组 * LS_BAPIMARA-DIVISION = LS_24-SPART. * LS_BAPIMARAX-DIVISION = ABAP_TRUE. ** 普通项目类别组 * LS_BAPIMARA-ITEM_CAT = LS_24-MTPOS_MARA. * LS_BAPIMARAX-ITEM_CAT = ABAP_TRUE. * * LS_BAPIHEAD-MATL_TYPE = LS_24-MTART. * LS_MARA-MTART = LS_24-MTART. *-->END OF LINES. EXIT. ENDLOOP. *-->ADD BY LIKE 2023.7.7 SELECT SINGLE * FROM zmm1000t051 AS a INTO @DATA(gs_t051) WHERE matkl = @is_mara-matkl. IF gs_t051 IS NOT INITIAL AND sy-subrc = 0. * 产品组 ls_bapimara-division = gs_t051-spart. ls_bapimarax-division = abap_true. * 普通项目类别组 ls_bapimara-item_cat = gs_t051-mtpos_mara. ls_bapimarax-item_cat = abap_true. * 物料类型 ls_bapihead-matl_type = gs_t051-mtart. ls_mara-mtart = gs_t051-mtart. ELSE. et_ret = VALUE #( BASE et_ret ( matnr = is_mara-matnr type = &#39;E&#39; message = |物料组{ gs_t051-matkl }的集团级参数配置表未维护| ) ). RETURN. ENDIF. *-->END OF LINES. ENDIF. IF ls_mara-mtart = &#39;F001&#39;. ls_bapimara-stor_conds = &#39;01&#39;. ls_bapimarax-stor_conds = abap_true. ls_bapihead-storage_view = abap_true. ENDIF. * STOR_CONDS IF is_mara-maktx_zh IS NOT INITIAL. lt_bapimakt = VALUE #( BASE lt_bapimakt ( langu = &#39;1&#39; matl_desc = is_mara-maktx_zh ) ). ENDIF. IF is_mara-maktx_en IS NOT INITIAL. lt_bapimakt = VALUE #( BASE lt_bapimakt ( langu = &#39;E&#39; matl_desc = is_mara-maktx_en ) ). ELSE. lt_bapimakt = VALUE #( BASE lt_bapimakt ( langu = &#39;E&#39; matl_desc = is_mara-maktx_zh ) ). ENDIF. PERFORM frm_wait_unlock USING ls_bapihead-material. "保存前读取修改前长文本 "Begin Of Add 2025-01-03 SELECT SINGLE * FROM stxh INTO CORRESPONDING FIELDS OF @ls_header WHERE tdobject = &#39;MATERIAL&#39; AND tdname = @is_mara-matnr AND tdid = &#39;GRUN&#39; AND tdspras = &#39;M&#39;. lt_old = zcl_comm_tools=>get_mat_longtxt( EXPORTING iv_tdobject = ls_header-tdobject iv_tdid = ls_header-tdid iv_tdspras = ls_header-tdspras iv_tdname = ls_header-tdname ). "End Of Add 2025-01-03 *长文本 PERFORM frm_fill_bapi_longtextdata TABLES lt_materiallongtext USING is_mara. SET UPDATE TASK LOCAL. CALL FUNCTION &#39;BAPI_MATERIAL_SAVEDATA&#39; EXPORTING headdata = ls_bapihead clientdata = ls_bapimara clientdatax = ls_bapimarax IMPORTING return = ls_ret TABLES materialdescription = lt_bapimakt unitsofmeasure = lt_bapimarm unitsofmeasurex = lt_bapimarmx materiallongtext = lt_materiallongtext. IF ls_ret-type = &#39;E&#39; OR ls_ret-type = &#39;A&#39;. CALL FUNCTION &#39;BAPI_TRANSACTION_ROLLBACK&#39;. et_ret = VALUE #( BASE et_ret ( matnr = is_mara-matnr type = &#39;E&#39; message = zcl_comm_tools=>conv_bapiret2_to_string( VALUE bapiret2_t( ( ls_ret ) ) ) ) ). ELSE. CALL FUNCTION &#39;BAPI_TRANSACTION_COMMIT&#39; EXPORTING wait = abap_true. et_ret = VALUE #( BASE et_ret ( matnr = is_mara-matnr type = &#39;S&#39; message = &#39;基础视图更新成功&#39; ) ). IF is_mara-zprocessdiv = &#39;自制&#39;. TRY . DATA(ls_tcn) = VALUE tcnrfp( rfpnt = is_mara-matnr ). DATA(ls_tcnt) = VALUE tcnrfpt( spras = &#39;1&#39; rfpnt = is_mara-matnr ktext = is_mara-maktx_zh ). SELECT COUNT( * ) FROM tcnrfp WHERE rfpnt = is_mara-matnr. IF sy-subrc <> 0. MODIFY tcnrfp FROM ls_tcn. MODIFY tcnrfpt FROM ls_tcnt. COMMIT WORK. ENDIF. CATCH cx_root. ENDTRY. ENDIF. ENDIF. "回写长文本修改日志 "Begin Of Add 2025-01-03 IF lv_exist = abap_false. SELECT SINGLE * FROM stxh INTO CORRESPONDING FIELDS OF @ls_header WHERE tdobject = &#39;MATERIAL&#39; AND tdname = @is_mara-matnr AND tdid = &#39;GRUN&#39; AND tdspras = &#39;M&#39;. ENDIF. lt_new = zcl_comm_tools=>get_mat_longtxt( EXPORTING iv_tdobject = ls_header-tdobject iv_tdid = ls_header-tdid iv_tdspras = ls_header-tdspras iv_tdname = ls_header-tdname ). PERFORM frm_write_longtext_log TABLES lt_old lt_new USING ls_header. CLEAR: ls_header,lt_new[],lt_old[]. "End Of Add 2025-01-03 ENDFORM.这段代码里面ls_24是在哪里定义的?
最新发布
09-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值