RT-Thread内核机制 线程栈

int flag;

void cmp_val(int a,int b)
{
	volatile int tmp[10];
	tmp[0] = a;
	if(tmp[0] > b)
	{
		flag = 1;
	}else{
		flag = 0;
	}
}

int main()
{
	int a = 1;
	int b = ;
	cmp_val(a,b);
	return 0;
}

RT-Thread内核机制 线程栈_第1张图片
我们写好的程序会保存在Flash上。
RT-Thread内核机制 线程栈_第2张图片
其它类似汇编指令
SUB R0,R0,#4 R0 = R0-4
B LR 放入LR寄存器

局部变量保存在栈里。

RT-Thread内核机制 线程栈_第3张图片
SUB sp,sp,#0x28 sp=sp-40;
为什么要SP要减去40?数组是int类型,刚好有10个,所以是40。

STR r0,[sp,#0x00] 将r0的值保存进sp指针现在所指向的位置
C语言中的函数,传入的第一个参数就保存在R0中,第二个参数保存在R1中。

LDR r2,[sp,#0x00] 将sp指针现在指向的存储位置的值保存进入r2寄存器中。

CMP r2,r1 比较两个寄存器中的值,结果保存在PSR(程序状态寄存器)中。

BLE 0x08000166 如果比较结果小于等于,就跳转到地址0x08000166

MOVS r2,#0x00 把r2赋值为0
STR r2,[r3,#0x00] 把r2赋值给r3指向的变量(flag)

RT-Thread内核机制 线程栈_第4张图片
切换线程时要保存所有寄存器的值。
RT-Thread内核机制 线程栈_第5张图片
除了R13,其余都要保存,R13是栈,一般在其它地方中保存。(16个)

16个寄存器保存在栈中。

RT-Thread内核机制 线程栈_第6张图片

保存在线程的栈中。

RT-Thread内核机制 线程栈_第7张图片
线程A切换到线程B需要做的事情:

  1. 保存A的16个寄存器到A的栈。
  2. 从B的栈恢复16个寄存器到CPU。

发生Tick中断时,16个寄存器中有一些是硬件直接保存的,剩下的是软件保存。

上下文切换

rt_hw_context_switch((rt_ubase_t)&from_thread->sp, (rt_ubase_t)&to_thread->sp);
    .global rt_hw_context_switch_to
    .type rt_hw_context_switch_to, %function
rt_hw_context_switch_to:
    LDR     R1, =rt_interrupt_to_thread
    STR     R0, [R1]

    /* set from thread to 0 */
    LDR     R1, =rt_interrupt_from_thread
    MOV     R0, #0
    STR     R0, [R1]

    /* set interrupt flag to 1 */
    LDR     R1, =rt_thread_switch_interrupt_flag
    MOV     R0, #1
    STR     R0, [R1]

    /* set the PendSV exception priority */
    LDR     R0, =SHPR3
    LDR     R1, =PENDSV_PRI_LOWEST
    LDR.W   R2, [R0,#0]             /* read */
    ORR     R1, R1, R2              /* modify */
    STR     R1, [R0]                /* write-back */

    LDR     R0, =ICSR               /* trigger the PendSV exception (causes context switch) */ //触发一个PendSV异常,异常发生后,异常处理函数就会被调用
    LDR     R1, =PENDSVSET_BIT
    STR     R1, [R0]

    /* restore MSP */
    LDR     r0, =SCB_VTOR
    LDR     r0, [r0]
    LDR     r0, [r0]
    NOP
    MSR     msp, r0

    /* enable interrupts at processor level */
    CPSIE   F
    CPSIE   I
利用PendSV异常,来进行任务的切换
PendSV_Handler:
    /* disable interrupt to protect context switch */
    MRS     R2, PRIMASK
    CPSID   I

    /* get rt_thread_switch_interrupt_flag */
    LDR     R0, =rt_thread_switch_interrupt_flag
    LDR     R1, [R0]
    CBZ     R1, pendsv_exit         /* pendsv aLReady handled */

    /* clear rt_thread_switch_interrupt_flag to 0 */
    MOV     R1, #0
    STR     R1, [R0]

    LDR     R0, =rt_interrupt_from_thread
    LDR     R1, [R0]
    CBZ     R1, switch_to_thread    /* skip register save at the first time */

    MRS     R1, PSP                 /* get from thread stack pointer */ //获取线程A的栈
    STMFD   R1!, {R4 - R11}         /* push R4 - R11 register */ //软件保存剩余寄存器
    LDR     R0, [R0]
    STR     R1, [R0]                /* update from thread stack pointer */

switch_to_thread:
    LDR     R1, =rt_interrupt_to_thread
    LDR     R1, [R1]
    LDR     R1, [R1]                /* load thread stack pointer */ //获取线程B的栈

    LDMFD   R1!, {R4 - R11}         /* pop R4 - R11 register */ //从栈里恢复R4-R11,软件恢复
    MSR     PSP, R1                 /* update stack pointer */

STMFD:Store Multi Full Dec

中断时,硬件保存的寄存器
RT-Thread内核机制 线程栈_第8张图片
恢复时,软件恢复一部分寄存器,硬件恢复一部分寄存器。

RT-Thread内核机制 线程栈_第9张图片
创建线程时,分配一个栈空间,同时要为栈空间预存放的寄存器空间赋值。将PC寄存器存放的位置赋值为thread2_entry,当线程运行时,将栈空间存放的各个寄存器的值赋值到对应的寄存器,此时CPU就可以开始运行thread2_entry。

rt_uint8_t *rt_hw_stack_init(void       *tentry,
                             void       *parameter,
                             rt_uint8_t *stack_addr,
                             void       *texit)
{
    struct stack_frame *stack_frame;
    rt_uint8_t         *stk;
    unsigned long       i;

    stk  = stack_addr + sizeof(rt_uint32_t);
    stk  = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
    stk -= sizeof(struct stack_frame); //stk-64

    stack_frame = (struct stack_frame *)stk;

    /* init all register */
    for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
    {
        ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
    }

    stack_frame->exception_stack_frame.r0  = (unsigned long)parameter; /* r0 : argument */ //参数
    stack_frame->exception_stack_frame.r1  = 0;                        /* r1 */
    stack_frame->exception_stack_frame.r2  = 0;                        /* r2 */
    stack_frame->exception_stack_frame.r3  = 0;                        /* r3 */
    stack_frame->exception_stack_frame.r12 = 0;                        /* r12 */
    stack_frame->exception_stack_frame.lr  = (unsigned long)texit;     /* lr */
    stack_frame->exception_stack_frame.pc  = (unsigned long)tentry;    /* entry point, pc */ //函数入口地址
    stack_frame->exception_stack_frame.psr = 0x01000000L;              /* PSR */

    /* return task's current stack address */
    return stk;
}

首先栈要先减去stack_frame的空间

struct stack_frame
{
    /* r4 ~ r11 register */
    rt_uint32_t r4;
    rt_uint32_t r5;
    rt_uint32_t r6;
    rt_uint32_t r7;
    rt_uint32_t r8;
    rt_uint32_t r9;
    rt_uint32_t r10;
    rt_uint32_t r11;

    struct exception_stack_frame exception_stack_frame;
};

struct exception_stack_frame
{
    rt_uint32_t r0;
    rt_uint32_t r1;
    rt_uint32_t r2;
    rt_uint32_t r3;
    rt_uint32_t r12;
    rt_uint32_t lr;
    rt_uint32_t pc;
    rt_uint32_t psr;
};

你可能感兴趣的:(RT-Thread,RT-Thread)