快乐虾
http://blog.csdn.net/lights_joy/
本文适用于
ADSP-BF561
uclinux-2008r1.5-RC3(移植到vdsp5)
Visual DSP++ 5.0(update 5)
欢迎转载,但请保留作者信息
kernel_init是内核中创建的第一个内核线程,此时DSP处于中断15的状态。当内核第一次执行schedule的时候,这个线程将开始执行。
看看上下文切换的代码:
ENTRY(_resume)
/*
* Beware - when entering resume, prev (the current task) is
* in r0, next (the new task) is in r1.
*/
p0 = r0;
p1 = r1;
[--sp] = rets;
[--sp] = fp;
[--sp] = (r7:4, p5:3);
/* save usp */
p2 = usp;
[p0+(TASK_THREAD+THREAD_USP)] = p2;
/* save current kernel stack pointer */
[p0+(TASK_THREAD+THREAD_KSP)] = sp;
/* save program counter */
r1.l = _new_old_task;
r1.h = _new_old_task;
[p0+(TASK_THREAD+THREAD_PC)] = r1;
/* restore the kernel stack pointer */
sp = [p1+(TASK_THREAD+THREAD_KSP)];
/* restore user stack pointer */
p0 = [p1+(TASK_THREAD+THREAD_USP)];
usp = p0;
/* restore pc */
p0 = [p1+(TASK_THREAD+THREAD_PC)];
jump (p0);
/*
* Following code actually lands up in a new (old) task.
*/
_new_old_task:
(r7:4, p5:3) = [sp++];
fp = [sp++];
rets = [sp++];
/*
* When we come out of resume, r0 carries "old" task, becuase we are
* in "new" task.
*/
rts;
ENDPROC(_resume)
此时传递进来的prev是初始线程的task_struct,而next则是kernel_init这一内核线程的task_struct。此时新线程的PC指向的是_ret_from_fork这一汇编写的函数,因此DSP将跳转到这个地方执行,注意此时仍然处于中断15的状态,且SP已经切换到新线程的stack上。
ENTRY(_ret_from_fork)
SP += -12;
call _schedule_tail;
SP += 12;
r0 = [sp + PT_IPEND];
cc = bittst(r0,1);
if cc jump .Lin_kernel;
RESTORE_CONTEXT
rti;
.Lin_kernel:
bitclr(r0,1);
[sp + PT_IPEND] = r0;
/* do a 'fake' RTI by jumping to [RETI]
* to avoid clearing supervisor mode in child
*/
r0 = [sp + PT_PC];
[sp + PT_P0] = r0;
RESTORE_ALL_SYS
jump (p0);
ENDPROC(_ret_from_fork)
当跳转到这个入口时,SP已经切换到了新线程的stack,由于是内核线程,此时将跳转到.Lin_kernel执行。由于在kernel_init这一内核线程创建时,将struct pt_regs放在了栈的底部,因此在这里可以通过[sp + ???]这样的方式来访问结构体的成员。
r0 = [sp + PT_PC];
[sp + PT_P0] = r0;
这两行代码将线程创建时设置好的PC入口放在了struct pt_regs::p0这个成员中,它将指向kernel_thread_helper这个地址,当执行完
RESTORE_ALL_SYS
这个宏时,所有寄存器的值都被恢复出来,最后就可以跳转到kernel_thread_helper开始执行了,看看kernel_thread_helper。
/*
* This gets run with P1 containing the
* function to call, and R1 containing
* the "args". Note P0 is clobbered on the way here.
*/
void kernel_thread_helper(void);
__asm__(".section .text\n"
".align 4\n"
"_kernel_thread_helper:\n\t"
"\tsp += -12;\n\t"
"\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous;");
调用这段代码的时候,p1里面存放的是回调函数的地址,在这里就是kernel_init函数,而r1里面则放了给kernel_init的参数。
注意此时DSP仍然处于中断15的状态。
uclinux内核线程的创建(2009-4-23)
从fork_init看uclinux内核的线程数量限制(2009-4-22)
uclinux内核的任务优先级及其load_weight(2009-4-22)
init_thread_union猜想(2009-1-17)
uclinux2.6(bf561)内核中的current_thread_info(2008/5/12)