//函数原型:版本号linux-3.0.8

struct task_struct *__switch_to(structtask_struct *,
struct thread_info *, struct thread_info *);

#define switch_to(prev,next,last)                                       \

do {                                                                   \

last =__switch_to(prev,task_thread_info(prev), task_thread_info(next));        \

} while (0)

//首先我们看一下以下的宏:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)

//以下事实上就是指向相应的struct成员

/*

CC_STACKPROTECT补丁是Tejun Heo在年给主线kernel提交的一个用来防止内核堆栈溢出的补丁。

默认的config是将这个选项关闭的,能够在编译内核的时候。改动.config文件为CONFIG_CC_STACKPROTECTOR=y

来启用。未来飞天内核能够将这个选项开启来防止利用内核stack溢出的day攻击。这个补丁的防

溢出原理是:在进程启动的时候,在每一个buffer的后面放置一个预先设置好的stack canary。你

能够把它理解成一个哨兵,当buffer发生缓冲区溢出的时候。肯定会破坏stack canary的值,当

stack canary的值被破坏的时候。内核就会直接当机。

那么是怎么推断stack canary被覆盖了呢?

事实上这个事情是gcc来做的,内核在编译的时候给gcc加了个-fstack-protector參数.

*/

DEFINE(TSK_STACK_CANARY,     offsetof(struct task_struct,stack_canary));

//task_struct

DEFINE(TI_TASK,              offsetof(struct thread_info, task));

//

/*

* Domain types

*/

/*

#define DOMAIN_NOACCESS 0

#define DOMAIN_CLIENT  1//是用户的域(运行程序,訪问数据),以及由所述接入加以防护

//个别章节和页面组成域的权限。

#ifdef CONFIG_CPU_USE_DOMAINS

#define DOMAIN_MANAGER 3//控制域的行为(当前域的sections和page。以及域訪问)。

#else

#define DOMAIN_MANAGER 1

#endif

*/

//相应图

//这个domain通过协处理器设置寄存器DomainAccess Control

DEFINE(TI_CPU_DOMAIN,        offsetof(struct thread_info,cpu_domain));

/*

struct cpu_context_save {

__u32   r4;

__u32   r5;

__u32   r6;

__u32   r7;

__u32   r8;

__u32   r9;

__u32   sl;

__u32   fp;

__u32   sp;

__u32   pc;

__u32   extra[2];               /* Xscale 'acc' register, etc */

};

*/

DEFINE(TI_CPU_SAVE,          offsetof(struct thread_info,cpu_context));

/*

在以下有个set_tls,相应我的平台set_tls_v6k

.macroset_tls_v6k, tp, tmp1, tmp2

mcr     p15, 0, \tp, c13, c0, 3         @ set TLS register

.endm

tp_value就是为了设置TLS register的值

在多线程应用程序。当中一个进程共享同样的地址空间中的全部线程。还有常常出现须要维护的数据是唯一

的一个线程。TLS或线程本地存储。由于你或许能够从它的名字如今弄清楚。是用于线程抽象的概念。它是

一种高速和有效的方式来存储每一个线程的本地数据。

线程的本地数据的偏移量是通过TLS寄存器(H / W或S

/ W块),它指向线程各自的线程控制块訪问。

之前ARM内核。甚至ARM9和ARM11核心的一些不具备这样的TLS注冊物理上可用。

操作系统(Linux从这里開始)

须要效仿的软件。新一代的ARM内核。Cortex-AX起,确实有这TLS的寄存器可用(CP15)。

内核对TLS须要做的事情是可以让用户态程序(一般是nptl——一个pthread的实现)在某个时刻可以设置

线程唯一的基址值到内核的线程信息结构内。

*/

DEFINE(TI_TP_VALUE,          offsetof(struct thread_info, tp_value));

/*

* These are the reasoncodes for the thread notifier.

*/

#define THREAD_NOTIFY_FLUSH    0

#define THREAD_NOTIFY_EXIT     1

#define THREAD_NOTIFY_SWITCH   2

#define THREAD_NOTIFY_COPY     3

/*
* Register switch for ARMv3 and ARMv4 processors
* r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
* previous and next are guaranteed not to be the same.
*/
ENTRY(__switch_to)
UNWIND(.fnstart )
UNWIND(.cantunwind )
//ip就是上一个线程的thread_info里面的cpu_context的地址
add ip, r1, #TI_CPU_SAVE
//r3里面存着下一个线程tp值
ldr r3, [r2, #TI_TP_VALUE]
//存储r4 - sl, fp, sp, lr到thread_info->cpu_context里。 分别使用arm和thumb实现
//这就是保存现场。
ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack
THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack
THUMB( str sp, [ip], #4 )
THUMB( str lr, [ip], #4 )
#ifdef CONFIG_CPU_USE_DOMAINS
//r6存着下一个线程的DOMAIN属性
ldr r6, [r2, #TI_CPU_DOMAIN]
#endif
//set_tls 上面已分析
set_tls r3, r4, r5
#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
ldr r7, [r2, #TI_TASK]//下一个线程的task_struct
ldr r8, =__stack_chk_guard//r8里面是__stack_chk_guard地址
ldr r7, [r7, #TSK_STACK_CANARY]//到这里。r7里面是stack_canary值
#endif
#ifdef CONFIG_CPU_USE_DOMAINS
//设置domain寄存器。
mcr p15, 0, r6, c3, c0, 0 @ Set domain register
#endif
//r5里面是上一个线程的task_struct
mov r5, r0
//r4就是下一个线程的thread_info里面的cpu_context的地址
add r4, r2, #TI_CPU_SAVE
//r4 r5仅仅是暂时保存一下 //以下的thread_notify_head通知链,以下样例说明
ldr r0, =thread_notify_head
mov r1, #THREAD_NOTIFY_SWITCH
bl atomic_notifier_call_chain
#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
str r7, [r8]//__stack_chk_guard = (next)threadinfo->task->stack_canary
#endif
THUMB( mov ip, r4 )//ip指向线程的thread_info里面的cpu_context的地址
mov r0, r5//r0从新指向上一个线程的task_struct
//以下相应了上面的保存现场,这里就是恢复现场。 pc相应了下个进程的cpu_context->pc
//从上面看到这个cpu_context->pc就是之前保存现场的lr,就是下个线程要运行的地方。
ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @ Load all regs saved previously
THUMB( ldmia ip!, {r4 - sl, fp} ) @ Load all regs saved previously
THUMB( ldr sp, [ip], #4 )
THUMB( ldr pc, [ip] )
UNWIND(.fnend )
ENDPROC(__switch_to)

实验代码:

#include <linux/kernel.h>
#include <linux/notifier.h>
#include <linux/module.h>
#include <asm/thread_notify.h> MODULE_LICENSE("GPL"); static int test_event(struct notifier_block *this, unsigned long event, void *ptr)
{
printk(KERN_INFO "In Event: Event Number is %ld\n",event); return NOTIFY_DONE;
} static struct notifier_block test_notifier =
{
.notifier_call = test_event,
}; static int __init reg_notifier(void)
{
int err = 0;
printk(KERN_INFO "Begin to register:\n"); err = thread_register_notifier(&test_notifier);
if (err)
{
printk(KERN_ERR "register test_notifier error\n"); goto fail1;
} printk(KERN_INFO "register reboot_notifier completed\n"); return 0; fail1:
return err;
} static void __exit unreg_notifier(void)
{
thread_unregister_notifier(&test_notifier); printk(KERN_INFO "Unregister finished\n");
} module_init(reg_notifier);
module_exit(unreg_notifier);

打印:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHh4eHhsbGxsbHhs/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

2都是THREAD_NOTIFY_SWITCH,当然会不断的切换!

最新文章

  1. php中抽象类与接口的概念以及区别
  2. Hibernate4.1之后关于占位符的问题
  3. VS2010 asp.net development server 无法展示svg图片
  4. eclipse安装spring插件
  5. SQL SERVER 2008安装时出现不能在控件上调用 Invoke 或 BeginInvoke错误 解决方法
  6. 关于在Android设置全局变量随时获取context
  7. su: /bin/bash: Permission denied
  8. K - Transformation-hdu 4578(多操作混合区间更新)线段树
  9. MSSQL2008 R2 数据库展开报错:值不能为空 参数名:viewInfo
  10. DAY 30 网络编程基础
  11. union: php/laravel command
  12. 《JavaScript高级程序设计》笔记:在HTML中使用Javascript(二)
  13. 创建.NET core的守护进程
  14. echo 命令详解
  15. session of express
  16. 由select/epoll返回的非阻塞connect还会是EINPROGRESS状态吗?
  17. json获取属性值的方式
  18. SEH
  19. HZ 和 usleep最小睡眠时间(低精度定时器)
  20. html5 的a标签是可以拨电话的,通过其Href属性来实现

热门文章

  1. 洛谷—— P1162 填涂颜色
  2. CF #261 div2 D. Pashmak and Parmida&amp;#39;s problem (树状数组版)
  3. linux 命令之 apt-get
  4. 早该知道的 7 个JavaScript 技巧[转]
  5. JS防止全局变量污染解决方案
  6. Impala基础认知与安装
  7. 洛谷 P1157 组合的输出
  8. cocos2d-x 3.x游戏开发学习笔记(1)--mac下配置cocos2d-x 3.x开发环境
  9. 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.
  10. C语言深度解剖读书笔记