`
xiaoer_1982
  • 浏览: 1806642 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

uclinux第一个内核线程的运行

阅读更多

快乐虾

http://blog.csdn.net/lights_joy/

lights@hb165.com

本文适用于

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的状态。

1 参考资料

uclinux内核线程的创建(2009-4-23)

fork_inituclinux内核的线程数量限制(2009-4-22)

uclinux内核的任务优先级及其load_weight(2009-4-22)

init_thread_union猜想(2009-1-17)

uclinux2.6(bf561)内核中的current_thread_info(2008/5/12)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics