uclinux第一个内核线程的运行
来源:互联网 发布:mac apache 下载 编辑:程序博客网 时间:2024/04/29 00:22
快乐虾 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_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)
- uclinux第一个内核线程的运行
- uclinux内核线程的创建
- Skyeye模拟uClinux上运行的第一个程序:Hello World
- uclinux第一个用户程序的加载
- 我的第一个uClinux驱动程序
- 从fork_init看uclinux内核的线程数量限制
- uclinux创建内核线程的几种方式
- uclinux创建内核线程的几种方式
- uclinux内核的container_of
- uclinux内核的console
- uclinux内核的文件系统类型
- uclinux内核的任务切换
- 编译自己的uclinux内核
- java开发系统内核:运行第一个应用程序
- 如果在uClinux中让自己的应用程序在内核启动的时候自动运行
- 第一个linux内核模块的编写
- 编译出你的第一个内核
- 我的第一个内核模块
- EtherNet/IP
- 培训教材
- CSS BUG编成了顺口溜
- mysql命令
- Web 2.0 with Oracle ADF Faces - Ajax Without Ajax
- uclinux第一个内核线程的运行
- linux 下 apache2.2.2+svn 1.3.1安装
- C#.NET 怎样连接数据库
- 初学java
- CSS基本语法及用法
- 硬件防火墙与软件防火墙的区别
- C#数据访问类
- 面试随想
- 突然想写点,小小总结