(1)RT_Thread内核实现 之 线程的定义与实现

线程的定义与实现

在这里插入图片描述
在这里插入图片描述

/*初始化一个列表*/
rt_inline void rt_list_init(rt_list_t *l)
{
    l->next = l->prev = l;
}
/*初始化线程调度器*/
void rt_system_scheduler_init(void)
{
	register rt_base_t offset;
	/*线程就绪列表初始化*/
	for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)(2)
	{
		rt_list_init(&rt_thread_priority_table[offset]);
	}
	/*初始化当前线程控制块指针*/
	rt_current_thread = RT_NULL;
}

rt_err_t rt_thread_init(struct rt_thread *thread,
						void (*entry)(void *parameter),
						void *parameter,
						void *stack_start,
						rt_uint32_t stack_size)
{
	rt_list_init(&(thread->tlist));
	thread->entry =(void *)entry;
	thread->parameter = parameter;
	thread->stack_addr = stack_start;
	thread->stack_size = stack_size;
	/*初始化线程栈,并返回线程栈指针*/
	thread->sp = 
	(void *)rt_hw_stack_init(thread->entry,
							thread->parameter,
							(void *)((char *)thread->stack_addr + thread->stack_size_ 4))return RT_EOK;
}

rt_uint8_t *rt_hw_stack_init(void *tentry,
							void *parameter,
							rt_uint8_t *stack_addr)
{
	struct stack_frame *stack_frame;
	rt_uint8_t *stk;
	unsigned long i;
	/*获取栈顶指针调用 rt_hw_stack_init()时,传给 stack_addr 的是(栈顶指针-4)*/
	stk = stack_addr + sizeof(rt_uint32_t);
	/*让 stk 指针向下 8 字节对齐*/
	stk =(rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
	/* stk 指针继续向下移动 sizeof(struct stack_frame)个偏移量*/
	stk-= sizeof(struct stack_frame);
	/*将 stk 指针强制转化为 stack_frame 类型后存储到 stack_frame 中*/
	stack_frame =(struct stack_frame *)stk;
	/*以stack_frame 为起始地址,将栈空间里面的sizeof(struct stack_frame)个内存地址初始化为 Oxdeadbeef */
	for (i = 0; i <sizeof(struct stack_frame)/ sizeof(rt_uint32_t); i ++)
	{
		((rt_uint32_t *)stack_frame)[i]= Oxdeadbeef;
	}
	/*初始化异常发生时自动保存的寄存器*/
	stack_frame->exception_stack_frame.r0 =(unsigned long)parameter;/* ro :argument */
	stack_frame->exception_stack_frame.r1 = 0;
	stack_frame->exception_stack_frame.r2 = 0;
	stack_frame->exception_stack_frame.r3 = 0;
	stack_frame->exception_stack_frame.r12 = 0;
	stack_frame->exception_stack_frame.1r = 0/*暂时初始化为 0*/
	stack_frame->exception_stack_frame.pc =(unsigned long)tentry;/* entry point, pc*/
	stack_frame->exception_stack_frame.par = 0x01000000L;
	
	/*返回线程栈指针*/
	return stk;
}

void rt_system_scheduler_start(void)
{
    register struct rt_thread *to_thread;

    /* get switch to thread */
    to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                              struct rt_thread,
                              tlist);

    rt_current_thread = to_thread;

    /* switch to new thread */
    rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);

    /* never come back */
}

;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; * this fucntion is used to perform the first thread switch
; */
rt_hw_context_switch_to    PROC
    EXPORT rt_hw_context_switch_to
    ; set to thread
    LDR     r1, =rt_interrupt_to_thread
    STR     r0, [r1]

    ; set from thread to 0
    LDR     r1, =rt_interrupt_from_thread
    MOV     r0, #0x0
    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, =NVIC_SYSPRI2
    LDR     r1, =NVIC_PENDSV_PRI
    LDR.W   r2, [r0,#0x00]       ; read
    ORR     r1,r1,r2             ; modify
    STR     r1, [r0]             ; write-back

    ; trigger the PendSV exception (causes context switch)
    LDR     r0, =NVIC_INT_CTRL
    LDR     r1, =NVIC_PENDSVSET
    STR     r1, [r0]

    ; restore MSP
    LDR     r0, =SCB_VTOR
    LDR     r0, [r0]
    LDR     r0, [r0]
    MSR     msp, r0

    ; enable interrupts at processor level
    CPSIE   F
    CPSIE   I

    ; never reach here!
    ENDP

; compatible with old version
rt_hw_interrupt_thread_switch PROC
    EXPORT rt_hw_interrupt_thread_switch
    BX      lr
    ENDP

    IMPORT rt_hw_hard_fault_exception
    EXPORT HardFault_Handler
HardFault_Handler    PROC

    ; get current context
    TST     lr, #0x04               ; if(!EXC_RETURN[2])
    ITE     EQ
    MRSEQ   r0, msp                 ; [2]=0 ==> Z=1, get fault context from handler.
    MRSNE   r0, psp                 ; [2]=1 ==> Z=0, get fault context from thread.

    STMFD   r0!, {r4 - r11}         ; push r4 - r11 register
    STMFD   r0!, {lr}               ; push exec_return register

    TST     lr, #0x04               ; if(!EXC_RETURN[2])
    ITE     EQ
    MSREQ   msp, r0                 ; [2]=0 ==> Z=1, update stack pointer to MSP.
    MSRNE   psp, r0                 ; [2]=1 ==> Z=0, update stack pointer to PSP.

    PUSH    {lr}
    BL      rt_hw_hard_fault_exception
    POP     {lr}

    ORR     lr, lr, #0x04
    BX      lr
    ENDP

    ALIGN   4

    END

; r0 --> switch from thread stack
; r1 --> switch to thread stack
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
PendSV_Handler   PROC
    EXPORT 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, #0x00
    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
    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

    LDMFD   r1!, {r4 - r11}         ; pop r4 - r11 register
    MSR     psp, r1                 ; update stack pointer

pendsv_exit
    ; restore interrupt
    MSR     PRIMASK, r2

    ORR     lr, lr, #0x04
    BX      lr
    ENDP

;/*
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
; * r0 --> from
; * r1 --> to
; */
rt_hw_context_switch_interrupt
    EXPORT rt_hw_context_switch_interrupt
rt_hw_context_switch    PROC
    EXPORT rt_hw_context_switch

    ; set rt_thread_switch_interrupt_flag to 1
    LDR     r2, =rt_thread_switch_interrupt_flag
    LDR     r3, [r2]
    CMP     r3, #1
    BEQ     _reswitch
    MOV     r3, #1
    STR     r3, [r2]

    LDR     r2, =rt_interrupt_from_thread   ; set rt_interrupt_from_thread
    STR     r0, [r2]

_reswitch
    LDR     r2, =rt_interrupt_to_thread     ; set rt_interrupt_to_thread
    STR     r1, [r2]

    LDR     r0, =NVIC_INT_CTRL              ; trigger the PendSV exception (causes context switch)
    LDR     r1, =NVIC_PENDSVSET
    STR     r1, [r0]
    BX      LR
    ENDP
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值