快乐虾
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的状态。
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内核编程
本文通过整理之前研发的一个项目(ARM7TDMI + uCLinux),分析内核启动过程及需要修改的文件,以供内核移植者参考。整理过程中也同时参考了众多网友的帖子,在此谢过。由于整理过程匆忙,难免错误及讲解的不够清楚之处...
如何交叉编译 uClinux 内核如何交叉编译 uClinux 内核如何交叉编译 uClinux 内核如何交叉编译 uClinux 内核
如何交叉编译uclinux内核—屏幕录像:现场操作,肯定比看书时的印象来的深刻!
这是一款介绍uclinux内核编译的傻瓜教程,轻松教会你ulinx内核编译
uclinux内核编译傻瓜教程.pdf,对于初及linux内核人员来说非常实用。
uClinux系统下载过程(编译内核),PDF格式
这篇文章主要讨论了bfin-uclinux-2008r1-rc8中的console实现。 适用的CPU为ADSP-BF561。 还不是很完整,仅供参考。 .......
uclinux内核配置与编程傻瓜教程 ,新手入门,老手入门.uclinux内核配置与编程傻瓜教程 ,新手入门,老手入门.
Uclinux的配置和裁减也是利用的华恒科技提供的源码包(用于hhbf531学习板)。我们使用的开发板信息如下: CPU:BF533 FLASH:S29AL004D-512KB SDRAM:HY57V281620-16MB 这里我不敢说“uclinux的移植”,而只是以...
uclinux内核编译[参考].pdf
这个工程用于将uclinux内核的部分代码移植到vs2008下编译并模拟其运行,包括内存管理,设备管理和文件系统这三个部分的代码,删除了进程管理之类的功能。希望它能帮助对uclinux内核中这三个部分结构和算法的理解!
嵌入式uClinux的内核结构和开发环境.doc 嵌入式uClinux的内核结构和开发环境.doc 嵌入式uClinux的内核结构和开发环境.doc
怎样编译一个uclinux内核
Skyeye-1.3.3运行uclinux-2011 过程详细
AXD + Multi-ICE进行裸机程序的功效相信已经为大家所接受。uClinux内核比较裸机程序,有较大的不同。这里简单介绍如何用AXD源代码级调试uClinux内核。
uClinux编译方法
这份文档是学习uclinux内核存储管理部分的笔记,适用于 uclinux-2008r1-rc8 adsp-bf561 内核移植到VDSP5。
uclinux 内核编译 与根文件系统制作
uClinux 內核配置,主要讲解uCLinux内核的配置选项