博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux 内核--任务0的运行(切换到用户模式)move_to_user_mode
阅读量:6118 次
发布时间:2019-06-21

本文共 3692 字,大约阅读时间需要 12 分钟。

本文分析基于Linux 0.11内核,转载请标明出处,

在main.c的程序中,当设备初始化完毕后,程序将从内核模式切换到用户模式,也就是所说的任务0,执行fork()函数(该函数使用内嵌的汇

编,防止函数调用弄乱堆栈,造成写时复制COPY_ON_WRITE)切换到用户堆栈并执行任务0使用iret指令,首先将有关的值压入堆栈,然后执

行iret指令。将刚刚压入对堆栈的数据根据标志位弹入相应的寄存器。

[cpp]
  1.  切换到用户模式运行。   
  2. // 该函数利用iret 指令实现从内核模式切换到用户模式(初始任务0)。   
  3. #define move_to_user_mode() /   
  4. __asm__ ( "movl %%esp,%%eax/n/t" /   // 保存堆栈指针esp 到eax 寄存器中。   
  5. "pushl $0x17/n/t" /     // 首先将堆栈段选择符(SS)入栈。   
  6.   "pushl %%eax/n/t" /       // 然后将保存的堆栈指针值(esp)入栈。   
  7.   "pushfl/n/t" /        // 将标志寄存器(eflags)内容入栈。   
  8.   "pushl $0x0f/n/t" /       // 将内核代码段选择符(cs)入栈。   
  9.   "pushl $1f/n/t" /     // 将下面标号1 的偏移地址(eip)入栈。   
  10.   "iret/n" /            // 执行中断返回指令,则会跳转到下面标号1 处。   
  11.   "1:/tmovl $0x17,%%eax/n/t" /  // 此时开始执行任务0,   
  12.   "movw %%ax,%%ds/n/t" /    // 初始化段寄存器指向本局部表的数据段。   
  13. "movw %%ax,%%es/n/t" "movw %%ax,%%fs/n/t" "movw %%ax,%%gs":::"ax")  

 

执行iret前的堆栈如下:

一下这段话引用自

In Protected Mode, the action of the IRET instruction depends on the settings of the NT (nested task) and VM flags in the EFLAGS register and the VM flag in the EFLAGS image stored on the current stack. Depending on the setting of these flags, the processor performs the following types of interrupt returns:

  • Return from virtual-8086 mode.
  • Return to virtual-8086 mode.
  • Intra-privilege level return.
  • Inter-privilege level return.
  • Return from nested task (task switch).

If the NT flag (EFLAGS register) is cleared, the IRET instruction performs a far return from the interrupt procedure, without a task switch. The code segment being returned to must be equally or less privileged than the interrupt handler routine (as indicated by the RPL field of the code segment selector popped from the stack). As with a real-address mode interrupt return, the IRET instruction pops the return instruction pointer, return code segment selector, and EFLAGS image from the stack to the EIP, CS, and EFLAGS registers, respectively, and then resumes execution of the interrupted program or procedure. If the return is to another privilege level, the IRET instruction also pops the stack pointer and SS from the stack, before resuming program execution. If the return is to virtual-8086 mode, the processor also pops the data segment registers from the stack.

-----------------------------------

由于在sched_init()中已经设置了标志寄存器中的vm标志为0,所以iret掉用后不会发生任务切换,而是继续执行EIP指向的指令故继续执行

1标号的代码,开始执行任务0,任务0的堆栈段选择符为0x17,在sched_init()中已设置了任务0 的任务描述符和局部描述符为INIT_TASK

[cpp]
  1. set_tss_desc (gdt + FIRST_TSS_ENTRY, &(init_task.task.tss));  
  2. set_ldt_desc (gdt + FIRST_LDT_ENTRY, &(init_task.task.ldt));  

 

[cpp]
  1. /* 
  2. * INIT_TASK is used to set up the first task table, touch at 
  3. * your own risk!. Base=0, limit=0x9ffff (=640kB) 
  4. */  
  5. /* 
  6. * INIT_TASK 用于设置第1 个任务表,若想修改,责任自负?! 
  7. * 基址Base = 0,段长limit = 0x9ffff(=640kB)。 
  8. */  
  9. // 对应上面任务结构的第1 个任务的信息。   
  10. #define INIT_TASK /   
  11. /* state etc */ { 0,15,15, /    // state, counter, priority   
  12. /* signals */ 0,  
  13. {  
  14.   {  
  15.   }  
  16. ,}  
  17. , 0, /              // signal, sigaction[32], blocked   
  18.                     /* ec,brk... */ 0, 0, 0, 0, 0, 0, /  
  19.                     // exit_code,start_code,end_code,end_data,brk,start_stack   
  20.                     /* pid etc.. */ 0, -1, 0, 0, 0, /  
  21.                     // pid, father, pgrp, session, leader   
  22.                     /* uid etc */ 0, 0, 0, 0, 0, 0, /  
  23.                     // uid, euid, suid, gid, egid, sgid   
  24.                     /* alarm */ 0, 0, 0, 0, 0, 0, /  
  25.                     // alarm, utime, stime, cutime, cstime, start_time   
  26.                 /* math */ 0, /  
  27.                 // used_math   
  28.                             /* fs info */ -1, 0022, NULL, NULL, NULL, 0, /  
  29.                             // tty,umask,pwd,root,executable,close_on_exec   
  30. /* filp */  
  31. {  
  32. NULL,}  
  33. , /             // filp[20]   
  34. {  
  35.   /             // ldt[3]   
  36.   {  
  37.   0, 0}  
  38.   ,  
  39. /* ldt */  
  40.   {  
  41.   0x9f, 0xc0fa00}  
  42.   , /               // 代码长640K,基址0x0,G=1,D=1,DPL=3,P=1 TYPE=0x0a   
  43.   {  
  44.   0x9f, 0xc0f200}  
  45.   , /               // 数据长640K,基址0x0,G=1,D=1,DPL=3,P=1 TYPE=0x02   
  46. }  
  47. ,  
  48. /*tss*/  
  49. {  
  50.   0, PAGE_SIZE + (long) &init_task, 0x10, 0, 0, 0, 0, (long) &pg_dir, / // tss   
  51.     0, 0, 0, 0, 0, 0, 0, 0,  
  52.     0, 0, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, _LDT (0), 0x80000000,  
  53.   {  
  54.   }  
  55. }  
  56. ,}  

 

转载于:https://www.cnblogs.com/hehehaha/archive/2013/04/15/6332885.html

你可能感兴趣的文章
自动检查点(Automatic Checkpointing)
查看>>
cache与负载均衡
查看>>
12.用学到的内存指针知识来分析下面的代码输出什么? 主要分析*ptr2
查看>>
CNCERT:2012年中国互联网网络安全态势综述
查看>>
《企业云桌面实施》-小技巧-03-vSAN6.5中SAS和SSD的使用建议
查看>>
***S 2012 高级图表类型 -- 气泡图与散点图
查看>>
Horizon View 6-虚拟桌面模板制作⑶
查看>>
使用Spring RestTemplate解析RESTful服务
查看>>
openstack云计算实践-老男孩架构师课程教案笔记分享
查看>>
Silverlight/Windows8/WPF/WP7/HTML5周学习导读(7月16日-7月22日)
查看>>
Lync 小技巧-41-Lync 2013-无法上载-PowerPoint
查看>>
Server 2008 R2 SP1 无法将Windows安装到磁盘X的分区Y 上
查看>>
使用openssl加密文件
查看>>
思科旗舰无线EA4500图赏
查看>>
变化的企业、不变的原则
查看>>
生于洞见 死于调查
查看>>
管理拯救不了企业
查看>>
IM3.0时代 移动互联网会发生什么变化
查看>>
Azure运维系列 5:国际版与中国版进行数据迁移
查看>>
SoapUI实践:自动化测试、压力测试、持续集成
查看>>