线程的定义与实现
/*初始化一个列表*/
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