汇编是如何调用众所周知的main()函数的?

    搜索 @note_pic 可查看绘制的全部字符图
    搜索 @note_why 是尚未看明白的地方,有看明白的,请Pull Request完善
    搜索 @note_thinking 是一些的思考和建议
    搜索 @note_#if0 是由第三方项目提供不在内核源码中定义的极为重要结构体,为方便理解而添加的。
    搜索 @note_good 是给源码点赞的地方
上级 62bb97d7
......@@ -144,8 +144,24 @@ STATIC UINT32 g_nextExcWaitCpu = INVALID_CPUID;
#define IS_VALID_ADDR(ptr) (((ptr) >= g_minAddr) && \
((ptr) <= g_maxAddr) && \
(IS_ALIGNED((ptr), sizeof(CHAR *))))
//6种异常情况下对应的栈,每一种异常模式都有其独立的堆栈,用不同的堆栈指针来索引,这样当ARM进入异常模式的时候,
STATIC const StackInfo g_excStack[] = {//程序就可以把一般通用寄存器压入堆栈,返回时再出栈,保证了各种模式下程序的状态的完整性
/******************************************************************************
6种异常情况下对应的栈,每一种异常模式都有其独立的堆栈,用不同的堆栈指针来索引,
这样当ARM进入异常模式的时候,程序就可以把一般通用寄存器压入堆栈,返回时再出栈,
保证了各种模式下程序的状态的完整性
用户模式,运行应用程序的普通模式。限制你的内存访问并且不能直接读取硬件设备。
超级用户模式(SVC 模式),主要用于 SWI(软件中断)和 OS(操作系统)。这个模式有额外的特权,
允许你进一步控制计算机。例如,你必须进入超级用户模式来读取一个插件(podule)。
这不能在用户模式下完成。
中断模式(IRQ 模式),用来处理发起中断的外设。这个模式也是有特权的。导致 IRQ 的设备有
键盘、 VSync (在发生屏幕刷新的时候)、IOC 定时器、串行口、硬盘、软盘、等等...
快速中断模式(FIQ 模式),用来处理发起快速中断的外设。这个模式是有特权的。导致 FIQ 的设备有
处理数据的软盘,串行端口。
IRQ 和 FIQ 之间的区别是对于 FIQ 你必须尽快处理你事情并离开这个模式。
IRQ 可以被 FIQ 所中断但 IRQ 不能中断 FIQ
******************************************************************************/
STATIC const StackInfo g_excStack[] = {
{ &__undef_stack, OS_EXC_UNDEF_STACK_SIZE, "udf_stack" }, //512 未定义的指令模式堆栈
{ &__abt_stack, OS_EXC_ABT_STACK_SIZE, "abt_stack" }, //512 中止模式堆栈,用于数据中止,可以将处理程序设置为在触发异常终止时运行
{ &__fiq_stack, OS_EXC_FIQ_STACK_SIZE, "fiq_stack" }, //64 FIQ中断模式堆栈.快速中断(FIQ)可能会在IRQ期间发生-它们就像优先级较高的IRQ.在FIQ中,FIQ和IRQ被禁用.
......
......@@ -248,7 +248,7 @@ _osKernelExceptPrefetchAbortHdl:
#endif
@ Description: Data abort exception handler
_osExceptDataAbortHdl:
_osExceptDataAbortHdl: @数据异常处理,缺页就属于数据异常
#ifdef LOSCFG_GDB
#if __LINUX_ARM_ARCH__ >= 7
GDB_HANDLE OsDataAbortExcHandleEntry
......@@ -261,11 +261,11 @@ _osExceptDataAbortHdl:
MOV R0, #OS_EXCEPT_DATA_ABORT @ Set exception ID to OS_EXCEPT_DATA_ABORT.
B _osExcPageFault
B _osExcPageFault @跳到缺页异常处理
#endif
@ Description: Address abort exception handler
_osExceptAddrAbortHdl:
_osExceptAddrAbortHdl: @地址异常处理
SUB LR, LR, #8 @ LR offset to return from this exception: -8.
STMFD SP, {R0-R7} @ Push working registers, but don`t change SP.
......@@ -274,7 +274,7 @@ _osExceptAddrAbortHdl:
B _osExceptDispatch @ Branch to global exception handler.
@ Description: Fast interrupt request exception handler
_osExceptFiqHdl:
_osExceptFiqHdl: @快中断异常处理
SUB LR, LR, #4 @ LR offset to return from this exception: -4.
STMFD SP, {R0-R7} @ Push working registers.
......@@ -282,7 +282,7 @@ _osExceptFiqHdl:
B _osExceptDispatch @ Branch to global exception handler.
_osExcPageFault:
_osExcPageFault: @缺页异常处理函数
SUB R3, SP, #(8 * 4) @ Save the start address of working registers.
MSR CPSR_c, #(CPSR_INT_DISABLE | CPSR_SVC_MODE) @ Switch to SVC mode, and disable all interrupts
MOV R2, SP
......@@ -322,12 +322,12 @@ _osExcPageFault:
BEQ _OsExcReturn
MOV R0, R5 @ exc type
B _osExceptionSwi
B _osExceptionSwi @跳到软中断执行,系统调用就是通过软中断实现
@ Description: Exception handler
@ Parameter : R0 Exception Type
@ Regs Hold : R3 Exception`s CPSR
_osExceptDispatch:
@ Parameter : R0 Exception Type 异常类型
@ Regs Hold : R3 Exception`s CPSR 发生异常时的CPSR @note_thinking 鸿蒙官方的注释错了,应该是Regs Hold: R2
_osExceptDispatch: @处理异常分发
MRS R2, SPSR @ Save CPSR before exception.
MOV R1, LR @ Save PC before exception.
SUB R3, SP, #(8 * 4) @ Save the start address of working registers.
......@@ -344,27 +344,27 @@ _osExceptDispatch:
STMFD SP!, {R4-R11}
STMFD SP!, {R2} @ Push task`s CPSR (i.e. exception SPSR).
CMP R0, #OS_EXCEPT_DATA_ABORT
BNE 1f
MRC P15, 0, R8, C6, C0, 0
MRC P15, 0, R9, C5, C0, 0
B 3f
1: CMP R0, #OS_EXCEPT_PREFETCH_ABORT
BNE 2f
MRC P15, 0, R8, C6, C0, 2
MRC P15, 0, R9, C5, C0, 1
B 3f
CMP R0, #OS_EXCEPT_DATA_ABORT @是数据异常吗?
BNE 1f @不是跳到 锚点1
MRC P15, 0, R8, C6, C0, 0 @R8=C6(内存失效的地址) 0(访问数据失效)
MRC P15, 0, R9, C5, C0, 0 @R9=C5(内存失效的状态) 0(无效整个指令cache)
B 3f @跳到锚点3处执行
1: CMP R0, #OS_EXCEPT_PREFETCH_ABORT @是预取异常吗?
BNE 2f @不是跳到 锚点2
MRC P15, 0, R8, C6, C0, 2 @R8=C6(内存失效的地址) 2(访问指令失效)
MRC P15, 0, R9, C5, C0, 1 @R9=C5(内存失效的状态) 1(虚拟地址)
B 3f @跳到锚点3处执行
2: MOV R8, #0
MOV R9, #0
3: AND R2, R2, #CPSR_MASK_MODE
3: AND R2, R2, #CPSR_MASK_MODE
CMP R2, #CPSR_USER_MODE @ User mode
BNE 4f
BNE 4f @不是用户模式
STMFD SP, {R13, R14}^ @ save user mode sp and lr
4:
SUB SP, SP, #(4 * 2)
SUB SP, SP, #(4 * 2) @sp=sp-(4*2)
_osExceptionSwi:
_osExceptionSwi: @软中断的处理,系统调用就是由软中断实现的
MOV R1, SP @ The second argument to the exception
MRC P15, 0, R4, C0, C0, 5
......@@ -375,7 +375,7 @@ _osExceptionSwi:
LDR R4, [R3]
CMP R4, #0
BNE _osExceptionGetSP @ BNE: 不相等则跳转
BNE _osExceptionGetSP @不相等则跳转
LDR R3, =g_intCount @ Judge the exception is occur in task stack or system stack
ADD R3, R3, R2
......@@ -398,10 +398,10 @@ _OsExcReturn:
LDR R0, [SP, #(2 * 4)]
AND R0, R0, #CPSR_MASK_MODE
CMP R0, #CPSR_USER_MODE @ User mode
BNE _OsExcReturnToKernel
BNE _OsExcReturnToKernel @非用户模式跳转执行
LDMFD SP, {R13, R14}^ @ load user mode sp and lr
_OsExcReturnToKernel:
_OsExcReturnToKernel:
ADD SP, SP, #(2 * 4)
LDMFD SP!, {R1}
MSR SPSR_cxsf, R1 @ Set the return mode SPSR
......
......@@ -39,15 +39,23 @@
/******************************************************************************
CPU下异常向量表
指令名 功能描述
DMB 数据存储器隔离。DMB 指令保证: 仅当所有在它前面的存储器访问操作
都执行完毕后,才提交(commit)在它后面的存储器访问操作。
DSB 数据同步隔离。比 DMB 严格: 仅当所有在它前面的存储器访问操作
都执行完毕后,才执行在它后面的指令(亦即任何指令都要等待存储器访问操作)
ISB 指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执
行完毕之后,才执行它后面的指令。
******************************************************************************/
.global __exc_stack_top
.global __exc_stack_top @注意这个top并不是栈顶的意思,而是栈的地址高位,恰恰说的是栈底的位置
.global __irq_stack_top
.global __fiq_stack_top
.global __svc_stack_top
.global __abt_stack_top
.global __undef_stack_top
.global __exc_stack
.global __exc_stack
.global __irq_stack
.global __fiq_stack
.global __svc_stack
......@@ -116,7 +124,7 @@ __exception_handlers:
/* Startup code which will get the machine into supervisor mode */
.global reset_vector
.type reset_vector,function
reset_vector:
reset_vector: @重置异常向量表
/* do some early cpu setup: i/d cache disable, mmu disabled */
mrc p15, 0, r0, c1, c0, 0
bic r0, #(1<<12)
......@@ -152,7 +160,7 @@ reloc_img_to_bottom_loop:
reloc_img_to_bottom_done:
ldr r4, =g_firstPageTable /* r4: physical address of translation table and clear it */
add r4, r4, r11
bl page_table_clear
bl page_table_clear @清除页表
PAGE_TABLE_SET SYS_MEM_BASE, KERNEL_VMM_BASE, KERNEL_VMM_SIZE, MMU_DESCRIPTOR_KERNEL_L1_PTE_FLAGS
PAGE_TABLE_SET SYS_MEM_BASE, UNCACHED_VMM_BASE, UNCACHED_VMM_SIZE, MMU_INITIAL_MAP_STRONGLY_ORDERED
......@@ -185,9 +193,9 @@ reloc_img_to_bottom_done:
cmp r11, #0
bne excstatck_loop_done
excstatck_loop:
excstatck_loop: @清除中断和异常堆栈,并设置魔法数字用于检查溢出
/* clear out the interrupt and exception stack and set magic num to check the overflow */
ldr r0, =__undef_stack
ldr r0, =__undef_stack
ldr r1, =__exc_stack_top
bl stack_init
......@@ -199,41 +207,41 @@ excstatck_loop:
STACK_MAGIC_SET __exc_stack, #OS_EXC_STACK_SIZE, OS_STACK_MAGIC_WORD
excstatck_loop_done:
warm_reset:
warm_reset: @初始化5大中断/异常环境
/* initialize interrupt/exception environments */
mov r0, #(CPSR_IRQ_DISABLE |CPSR_FIQ_DISABLE|CPSR_IRQ_MODE)
msr cpsr, r0
EXC_SP_SET __irq_stack_top, #OS_EXC_IRQ_STACK_SIZE
mov r0, #(CPSR_IRQ_DISABLE |CPSR_FIQ_DISABLE|CPSR_IRQ_MODE) @计划切到IRQ模式,并屏蔽IRQFIQ中断
msr cpsr, r0 @执行切换计划,执行完成后CPU将切换到IRQ栈运行
EXC_SP_SET __irq_stack_top, #OS_EXC_IRQ_STACK_SIZE @设置IRQSP
mov r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_UNDEF_MODE)
msr cpsr, r0
EXC_SP_SET __undef_stack_top, #OS_EXC_UNDEF_STACK_SIZE
mov r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_UNDEF_MODE) @计划切到UNDEF模式,并屏蔽IRQFIQ中断
msr cpsr, r0 @执行切换计划,执行完成后CPU将切换到UNDEF栈运行
EXC_SP_SET __undef_stack_top, #OS_EXC_UNDEF_STACK_SIZE @设置UNDEFSP
mov r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_ABT_MODE)
mov r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_ABT_MODE) @同上
msr cpsr, r0
EXC_SP_SET __abt_stack_top, #OS_EXC_ABT_STACK_SIZE
mov r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_FIQ_MODE)
mov r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_FIQ_MODE) @同上
msr cpsr, r0
EXC_SP_SET __fiq_stack_top, #OS_EXC_FIQ_STACK_SIZE
/* initialize CPSR (machine state register) */
mov r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SVC_MODE)
msr cpsr, r0
/* initialize CPSR (machine state register) */ @初始化CPSR(机器状态寄存器)
mov r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SVC_MODE) @计划切到SVC模式,并屏蔽IRQFIQ中断
msr cpsr, r0 @执行切换计划,执行完成后CPU将切换到SVC栈运行
/* Note: some functions in LIBGCC1 will cause a "restore from SPSR"!! */
msr spsr, r0
msr spsr, r0 @保存程序状态寄存器值,用于后续的恢复
@设置SVC栈,每个CPU都有自己的SVC
/* set svc stack, every cpu has OS_EXC_SVC_STACK_SIZE stack */
ldr r0, =__svc_stack_top
ldr r0, =__svc_stack_top @
mov r2, #OS_EXC_SVC_STACK_SIZE
mul r2, r2, r11
sub r0, r0, r2
mov sp, r0
mul r2, r2, r11 @r2 = OS_EXC_SVC_STACK_SIZE * r11(存放了CPUID)
sub r0, r0, r2 @r0=r0-r2,此时r2是偏移量,计算出SP的位置
mov sp, r0 @改变SP的值
/* enable fpu+neon */
MRC p15, 0, r0, c1, c1, 2
ORR r0, r0, #0xC00
MRC p15, 0, r0, c1, c1, 2 @r0 = c1
ORR r0, r0, #0xC00 @r0 =|0xC00
BIC r0, r0, #0xC000
MCR p15, 0, r0, c1, c1, 2
......@@ -246,16 +254,16 @@ warm_reset:
LDR r0, =__exception_handlers
MCR p15, 0, r0, c12, c0, 0
cmp r11, #0
bne cpu_start
cmp r11, #0 @是否为0CPU,注意0CPU为主寄存器
bne cpu_start @不是0号时,跳到cpu_start启动次级CPU
clear_bss:
ldr r1, =__bss_start
ldr r2, =__bss_end
mov r0, #0
ldr r1, =__bss_start @r1=__bss_start
ldr r2, =__bss_end @r2=__bss_end
mov r0, #0 @r0=0
bss_loop:
cmp r1, r2
cmp r1, r2 @比较R1R2
strlo r0, [r1], #4
blo bss_loop
......@@ -271,21 +279,39 @@ bss_loop:
.word 0xe7ffdeff
#endif
bl main /*子程序跳转,执行main..\platform\main.c*/
bl main /*子程序跳转,执行大家熟悉的main函数*/
_start_hang:
_start_hang: @悬停在此,死循环了
b _start_hang
/******************************************************************************
ARM协处理器CP15寄存器
MCR{cond} coprocopcode1RdCRnCRmopcode2
MRC {cond} coprocopcode1RdCRnCRmopcode2
coproc 指令操作的协处理器名.标准名为pn,n,为0~15
opcode1 协处理器的特定操作码. 对于CP15寄存器来说,opcode1永远为0,不为0时,操作结果不可预知
CRd 作为目标寄存器的协处理器寄存器.
CRn 存放第1个操作数的协处理器寄存器.
CRm 存放第2个操作数的协处理器寄存器. (用来区分同一个编号的不同物理寄存器,当不需要提供附加信息时,指定为C0
opcode2 可选的协处理器特定操作码. (用来区分同一个编号的不同物理寄存器,当不需要提供附加信息时,指定为0
C2 :存储保护和控制 地址转换表基地址
C3 :存储保护和控制 域访问控制位
C7 :高速缓存和写缓存控制
C8 :TLB 控制
C9 :高速缓存锁定
C10:TLB 锁定
******************************************************************************/
mmu_setup: //安装MMU
mov r12, #0
mcr p15, 0, r12, c8, c7, 0 /* Set c8 to control the TLB and set the mapping to invalid *//*设置8号寄存器以控制TLB将映射设置为无效*/
mov r12, #0 @r12=0 ,这么做的目的是为了下一条语句,C15协处理只能通过寄存器赋值
mcr p15, 0, r12, c8, c7, 0 /* Set c8 to control the TLB and set the mapping to invalid *//*设置C8,C7=0以控制TLB,将映射设置为无效*/
isb
mcr p15, 0, r12, c2, c0, 2 /* Initialize the c2 register *///初始化C2寄存器
mcr p15, 0, r12, c2, c0, 2 /* Initialize the c2 register *///初始化C2,C0=0
isb
orr r12, r4, #MMU_TTBRx_FLAGS
mcr p15, 0, r12, c2, c0, 0 /* Set attributes and set temp page table */
orr r12, r4, #MMU_TTBRx_FLAGS @r12 =| MMU_TTBRx_FLAGS
mcr p15, 0, r12, c2, c0, 0 /* Set attributes and set temp page table */ @设置页表属性
isb
mov r12, #0x7 /* 0b0111 */
......@@ -321,15 +347,15 @@ reset_platform:
#ifdef A7SEM_HAL_ROM_MONITOR
/* initialize CPSR (machine state register) */
mov r0, #(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SVC_MODE)
msr cpsr, r0
b warm_reset
msr cpsr, r0 @切到SVC模式,禁止中断
b warm_reset
#else
mov r0, #0
mov pc, r0 /* Jump to reset vector */
#endif
cpu_start: /* 启动CPU */
bl secondary_cpu_start /* 启动次级CPU */
b .
cpu_start: /* 启动次级CPU */
bl secondary_cpu_start @此处用了BL,说明执行完后要回到这里继续执行
b . @B为无条件跳转,跳到当前地址,意思就是进入死循环
......@@ -344,17 +370,17 @@ sp_set:
bx lr /* set sp */ @跳回去继续执行
/*
* r4: page table base address
* r5 and r6 will be used as variable
* r4: page table base address 页表基地址
* r5 and r6 will be used as variable r5r6将用作变量
*/
page_table_clear:
mov r5, #0
mov r6, #0
page_table_clear: @清除页表
mov r5, #0 @r5 = 0
mov r6, #0 @r6 = 0
0:
str r5, [r4, r6, lsl #2]
add r6, #1
add r6, #1 @r6++
cmp r6, #0x1000 /* r6 < 4096 */
blt 0b
blt 0b @小于 跳转到0,相当于条件循环
bx lr
/*
......@@ -365,7 +391,7 @@ page_table_clear:
* r10: flags
* r9 and r12 will be used as variable
*/
page_table_build:
page_table_build: @构建页面
mov r9, r6
bfc r9, #20, #12 /* r9: pa % MB */
add r8, r8, r9
......
......@@ -146,8 +146,11 @@ LITE_OS_SEC_TEXT_INIT VOID release_secondary_cores(VOID)//调动次级CPU干活
}
#endif /* LOSCFG_TEE_ENABLE */
#endif /* LOSCFG_KERNEL_SMP */
//内核入口函数,由汇编调用
LITE_OS_SEC_TEXT_INIT INT32 main(VOID)//由主CPU执行,默认 0号 为主CPU
/******************************************************************************
内核入口函数,由汇编调用,见于reset_vector_up.S 和 reset_vector_mp.S
up指单核CPU, mp指多核CPU
******************************************************************************/
LITE_OS_SEC_TEXT_INIT INT32 main(VOID)//由主CPU执行,默认 0号为主CPU
{
UINT32 uwRet = LOS_OK;
......
git add -A
git commit -m 'CPU有哪几种工作模式?每种模式都有独立堆栈,如何用汇编初始化这些栈?
git commit -m '汇编是如何调用众所周知的main()函数的?
搜索 @note_pic 可查看绘制的全部字符图
搜索 @note_why 是尚未看明白的地方,有看明白的,请Pull Request完善
搜索 @note_thinking 是一些的思考和建议
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册