免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3001 | 回复: 0
打印 上一主题 下一主题

[FreeBSD] freebsd9.2-线程切换阶段02-硬件上下文的切换-cpu_switch函数 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-06-23 02:53 |只看该作者 |倒序浏览
本帖最后由 71v5 于 2014-06-25 21:17 编辑

当mi_switch函数调用调度程序相关的sched_switch函数时,函数sched_switch在选择要运行的新thread后,就会调用cpu_switch函数完成线程
硬件上下文的切换,线程硬件上下文保存在struct pcb类型的数据对象中。当cpu_switch函数执行完后,新线程就开始运行。
调用cpu_switch函数时,线程oldtd的内核栈布局如下(运行一段时间的新thread的内核栈类似):
  1. ******************************* 内核栈顶部 高地址方向
  2. *                             *
  3. *   struct pcb对象            *
  4. *                             *
  5. *                             *
  6. ******************************* <--struct thread的td_pcb成员指向这里
  7. *                             *
  8. *   16bytes for vm            *
  9. ******************************* <--- 当进行线程切换时,TSS的esp0成员指向这里,内核栈的栈顶                     
  10. *                             *
  11. *                             *
  12. *                             *
  13. *  struct trapframe 对象      *
  14. *                             *
  15. ******************************* <-- struct thread的td_frame成员指向这里                       
  16. *                             *
  17. *                             *
  18. *                             *
  19. *                             *
  20. *                             *
  21. *                             *
  22. *                             *
  23. *                             *
  24. *                             *
  25. *                             *
  26. *******************************
  27. *      newlock                *
  28. ******************************* esp+12                        
  29. *      newtd                  *
  30. ******************************* esp+8                           
  31. *      oldtd                  *
  32. ******************************* esp+4                           
  33. *                             *
  34. * cpu_switch(return address)  *
  35. *******************************调用cpu_switch函数时,esp指向这里,当oldtd_thread再次被调度运行时,esp将指向这里
  36. *                             *  
  37. *                             *
  38. *                             *
  39. *******************************------ 内核栈底部 低地址方向----
复制代码
[新创建的线程的内核栈如下所示]:
  1. ******************************* 内核栈顶部 高地址方向
  2. *                             *
  3. *   struct pcb对象            *
  4. *                             *
  5. *                             *
  6. ******************************* <--struct thread的td_pcb成员指向这里
  7. *                             *
  8. *   16bytes for vm            *       
  9. *******************************                           
  10. *                             *
  11. *                             *
  12. *                             *
  13. *                             *
  14. *                             *
  15. *                             *
  16. *                             *
  17. *                             *
  18. *                             *
  19. *  硬件上下文                 *
  20. *  通过struct trapframe对象   *
  21. *  访问                       *
  22. *                             *
  23. *                             *
  24. *                             *
  25. *                             *
  26. *                             *
  27. *                             *
  28. *                             *
  29. *                             *
  30. ******************************* <-- struct thread的td_frame成员指向这里
  31. *  sizeof(void *)             *           
  32. *                             *           
  33. ******************************* <--pcb_esp指向这里         
  34. *                             *
  35. *                             *
  36. *                             *
  37. *                             *
  38. *                             *
  39. *                             *  
  40. *                             *
  41. *                             *
  42. *******************************------ 内核栈底部 低地址方向----
复制代码
将和oldtd相关联的struct pcb对象记为oldtd_pcb。
将和newtd相关联的struct pcb对象记为newtd_pcb。

将和oldtd相关联的struct pmap对象记为oldtd_pmap。
将和newtd相关联的struct pmap对象记为newtd_pmap。

将和oldtd相关联的struct proc对象记为oldtd_proc。
将和newtd相关联的struct proc对象记为newtd_proc。

将和oldtd相关联的struct thread对象记为oldtd_thread。
将和newtd相关联的struct thread对象记为newtd_thread。

将和oldtd相关联的struct vmspace对象记为oldtd_vmspace。
将和newtd相关联的struct vmspace对象记为newtd_vmspace。

运行oldtd时,cr3寄存器中的值为oldtd_cr3.
运行newtd时,cr3寄存器中的值为newtd_cr3.

和oldtd相关联的td_lock为oldtd_td_lock。
和newtd相关联的td_lock为newtd_td_lock。

oldtd使用的struct pcb_ext对象记为oldtd_pcb_ext。
newtd使用的struct pcb_ext对象记为newtd_pcb_ext。

oldtd运行时EFLAGS寄存器记为oldtd_eflags.
newtd运行时EFLAGS寄存器记为newtd_eflags
  1.    104        /*
  2.    105         * cpu_switch(old, new)
  3.    106         *
  4.    107         * Save the current thread state, then select the next thread to run
  5.    108         * and load its state.
  6.    109         * 0(%esp) = ret        cpu_switch函数的返回地址,被保存到oldtd_pcb的pcb_eip成员中
  7.    110         * 4(%esp) = oldtd      &oldtd_thread
  8.    111         * 8(%esp) = newtd      &newtd_thread
  9.    112         * 12(%esp) = newlock   oldtd_td_lock
  10.    113         */
  11.    114        ENTRY(cpu_switch)
  12.    115       
  13.    116               
  14. /*****************************************************
  15.   * Switch to new thread.  First, save context.
  16.                    117:ecx寄存器保存的是&oldtd_thread
  17.   **********************************/
  18.    117                movl        4(%esp),%ecx
  19.    118             
  20. /******************************************************
  21.    * 119-122:
  22.                   默认情况下,没有enable INVARIANTS,忽略。
  23.   *******************************/
  24.    119        #ifdef INVARIANTS
  25.    120                testl        %ecx,%ecx                        /* no thread? */
  26.    121                jz        badsw2                                /* no, panic */
  27.    122        #endif
  28.    123                /* 124:edx寄存器此时保存的是&oldtd_pcb */
  29.    124                movl        TD_PCB(%ecx),%edx
  30.    125                
  31. /************************************************************
  32.   * 127-133:
  33.                    保存oldtd_thread的硬件上下文,将其保存到oldtd_pcb中。
  34.                    126:eax寄存器保存的是cpu_switch(return address),即ret。
  35.                    127:更新oldtd_pcb的pcb_eip
  36.   ***************************/
  37.    126                movl        (%esp),%eax                        /* Hardware registers */
  38.    127                movl        %eax,PCB_EIP(%edx)
  39.    128                movl        %ebx,PCB_EBX(%edx)
  40.    129                movl        %esp,PCB_ESP(%edx)
  41.    130                movl        %ebp,PCB_EBP(%edx)
  42.    131                movl        %esi,PCB_ESI(%edx)
  43.    132                movl        %edi,PCB_EDI(%edx)
  44.    133                mov        %gs,PCB_GS(%edx)
  45. /***************************************************
  46. * 134-135:将old_eflags保存到oldtd_pcb的pcb_psl
  47.                             成员中。
  48. ************************/
  49.    134                pushfl                                        /* PSL */
  50.    135                popl        PCB_PSL(%edx)
  51.    136               
  52. /**********************************************************
  53. * Test if debug registers should be saved.
  54.                    #define PCB_DBREGS 0x02 process using debug registers

  55.                    137-152:如果oldtd_thread使用了调试寄存器,那么此时
  56.                             需要将oldtd_thread的调试寄存器上下文保存到
  57.                             oldtd_pcb中相应的成员中。
  58. *******************************/
  59.    137                testl        $PCB_DBREGS,PCB_FLAGS(%edx)
  60.    138                jz      1f                              /* no, skip over */
  61.    139                movl    %dr7,%eax                       /* yes, do the save */
  62.    140                movl    %eax,PCB_DR7(%edx)
  63.    141                andl    $0x0000fc00, %eax               /* disable all watchpoints */
  64.    142                movl    %eax,%dr7
  65.    143                movl    %dr6,%eax
  66.    144                movl    %eax,PCB_DR6(%edx)
  67.    145                movl    %dr3,%eax
  68.    146                movl    %eax,PCB_DR3(%edx)
  69.    147                movl    %dr2,%eax
  70.    148                movl    %eax,PCB_DR2(%edx)
  71.    149                movl    %dr1,%eax
  72.    150                movl    %eax,PCB_DR1(%edx)
  73.    151                movl    %dr0,%eax
  74.    152                movl    %eax,PCB_DR0(%edx)
  75.    153        1:
  76.    154               
  77. /***************************************************************
  78.   * 155-163:
  79.                     在编译了DEV_NPX选项时,检查是否保存浮点寄存器。
  80. **************************/
  81.    155        #ifdef DEV_NPX
  82.    156                /* have we used fp, and need a save? */
  83.    157                cmpl        %ecx,PCPU(FPCURTHREAD)
  84.    158                jne        1f
  85.    159                pushl        PCB_SAVEFPU(%edx)                /* h/w bugs make saving complicated */
  86.    160                call        npxsave                                /* do it in a big C function */
  87.    161                popl        %eax
  88.    162        1:
  89.    163        #endif
  90.    164       
  91.    165               
  92. /**************************************************************
  93.    * Save is done.  Now fire up new thread. Leave old vmspace.
  94.                    执行到这里的话,oldtd_thread的硬件上下文已经保存完毕。

  95.                    166:edi寄存器保存的是&oldtd_thread。
  96.                    167:ecx寄存器保存的是&newtd_thread。
  97.                    168:esi寄存器保存的是oldtd_td_lock。
  98.   *******************************/
  99.    166                movl        4(%esp),%edi
  100.    167                movl        8(%esp),%ecx                        /* New thread */
  101.    168                movl        12(%esp),%esi                        /* New lock */
  102.                 /* 169-171:同上 */
  103.    169        #ifdef INVARIANTS
  104.    170                testl        %ecx,%ecx                        /* no thread? */
  105.    171                jz        badsw3                                /* no, panic */
  106.    172        #endif
  107.                 /* edx寄存器此时保存的是&newtd_pcb */
  108.    173                movl        TD_PCB(%ecx),%edx
  109.    174       
  110.    175               
  111. /**************************************************************
  112.   * switch address space
  113.                    176:eax寄存器中保存的是newtd_cr3。
  114.                    177-181:是否运行在内核地址空间?典型的是newtd_thread是一个
  115.                             内核线程,比如idle,pagedaemon等内核线程,
  116.                             如果是,就跳转到sw0处。
  117. ********************************/
  118.    176                movl        PCB_CR3(%edx),%eax
  119.    177        #ifdef PAE
  120.    178                cmpl        %eax,IdlePDPT                        /* Kernel address space? */
  121.    179        #else
  122.    180                cmpl        %eax,IdlePTD                        /* Kernel address space? */
  123.    181        #endif
  124.    182                je        sw0
  125. /************************************************************
  126.   * 如果执行到这里,就表示newtd_thread不是一个内核线程。

  127.                    183-185:
  128.                    此时要检查newtd_thread和oldtd_thread是否共享一个地址空间,
  129.                    典型的是用RFMEM标志调用rfork函数创建的thread。
  130. ************************************/
  131.    183                READ_CR3(%ebx)                                /* The same address space? */
  132.    184                cmpl        %ebx,%eax
  133.    185                je        sw0
  134. /***********************************************************
  135.    * 如果执行到这里的话,就表示要安装一个单独的地址空间,即
  136.                    newtd_thread的地址空间。
  137.             
  138.                    #define LOAD_CR3(reg)   movl reg,%cr3;

  139.                    186:重新加载CR3控制寄存器,这个步骤执行后,就开始在
  140.                         newtd_thread的地址空间上操作。

  141.                    187:eax寄存器中保存的是oldtd_td_lock。
  142.                    188:esi寄存器中保存的当前cpu的logicl id。
  143.                    189:交换oldtd_td_lock和newtd_td_lock
  144.   ********************/
  145.    186                LOAD_CR3(%eax)                                /* new address space */
  146.    187                movl        %esi,%eax
  147.    188                movl        PCPU(CPUID),%esi
  148.    189                SETOP        %eax,TD_LOCK(%edi)                /* Switchout td_lock */
  149.    190       
  150.    191               
  151. /*********************************************************
  152.   * Release bit from old pmap->pm_active
  153.                    192:ebx寄存器保存的是&oldtd_pmap
  154.                    196:清除struct pcpu对象的pm_active成员的相应bit位。
  155.                         pm_active:一个cpu的位图,假设cpu的logical id为2,
  156.                         那么如果__pcpu[2]的pc_curpmap成员指向当前的
  157.                         struct pmap对象,那么pm_active的bit2就被设置为1,
  158.             否则相应的bit位为0.
  159.   *************************/
  160.    192        movl        PCPU(CURPMAP), %ebx
  161.    193        #ifdef SMP
  162.    194                lock
  163.    195        #endif
  164.    196                btrl        %esi, PM_ACTIVE(%ebx)                /* clear old */
  165.    197       
  166. /**********************************************************
  167.    * Set bit in new pmap->pm_active

  168.                            199:eax寄存器此时保存的是&newtd_proc。
  169.                    200:ebx寄存器此时保存的是&newtd_vmspace。
  170.                    201:ebx寄存器此时保存的是&newtd_pmap。
  171.                    202:更新当前cpu对应的struct pcpu对象的pc_curpmap成员。
  172.                    206:设置pc_curpmap成员的相应bit位。
  173.   ***************************/
  174.    199                movl        TD_PROC(%ecx),%eax                /* newproc */
  175.    200                movl        P_VMSPACE(%eax), %ebx
  176.    201                addl        $VM_PMAP, %ebx
  177.    202                movl        %ebx, PCPU(CURPMAP)
  178.    203        #ifdef SMP
  179.    204                lock
  180.    205        #endif
  181.    206                btsl        %esi, PM_ACTIVE(%ebx)                /* set new */
  182.    207                jmp        sw1
  183.    208       
  184.    209        sw0:
  185.    210                SETOP        %esi,TD_LOCK(%edi)                /* Switchout td_lock */
  186.    211        sw1:
  187.    212                BLOCK_SPIN(%ecx)
  188.                 /* 213-224:支持XEN时,忽略 */
  189.    213        #ifdef XEN
  190.    214                pushl        %eax
  191.    215                pushl        %ecx
  192.    216                pushl        %edx
  193.    217                call        xen_handle_thread_switch
  194.    218                popl        %edx
  195.    219                popl        %ecx
  196.    220                popl        %eax
  197.    221                /*
  198.    222                 * XXX set IOPL
  199.    223                 */
  200.    224        #else               
  201. /************************************************************************
  202.   * At this point, we've switched address spaces and are ready
  203.   * to load up the rest of the next context.
  204.      
  205.                    关于tss的说明,系统中至少要定义一个tss,关于tss的说明请参考
  206.                    intel IA-32中的描述,在freebsd中,为每一个cpu定义一个tss,在该
  207.                    cpu上运行的所有thread共用这一个tss,这个tss就为相应struct pcpu
  208.                    对象的pc_common_tss成员描述的tss,在初始化函数init386中,会用描述
  209.                    该tss的Tss Descriptor对应的Segment Selector加载TR,tss中一个重要
  210.                    的字段就是esp0字段,esp0始终指向当前运行的thread的内核栈的栈顶,
  211.                    在每次线程切换时,都会更新esp0,以使其指向相应thread的内核栈的栈顶。

  212.                    如果thread使用自己私有的tss,那么就要使用struct pcb_ext类型的数据对象
  213.                    来描述。

  214.                    此时edx寄存器保存的是&newtd_pcb。

  215.                    228:
  216.                    如果newtd_pcb的pcb_ext成员非空,就表示newtd_thread使用了私有
  217.                    的tss(任务状态段)。
  218. *************************************/
  219.    229                cmpl        $0, PCB_EXT(%edx)                /* has pcb extension? */
  220.    230                je        1f                                /* If not, use the default */
  221. /****************************************************************
  222.   * 如果执行到这里,就表示newtd_thread使用了私有的tss。
  223.                    231:将当前cpu对应的struct pcpu对象的pc_private_tss成员设置
  224.                         为1,表示当前正在运行的thread使用自己私有的tss。
  225.                    232:edi寄存器此时保存的是&newtd_pcb_ext。
  226. *************************/
  227.    231                movl        $1, PCPU(PRIVATE_TSS)                 /* mark use of private tss */
  228.    232                movl        PCB_EXT(%edx), %edi                /* new tss descriptor */
  229.    233                jmp        2f                                /* Load it up */
  230.    234       
  231.    235        1:       
  232. /************************************************************************
  233.   * Use the common default TSS instead of our own.
  234.   * Set our stack pointer into the TSS, it's set to just
  235.   * below the PCB.  In C, common_tss.tss_esp0 = &pcb - 16;
  236.                    如果执行到这里,就表示newtd_thread使用默认的tss。
  237.                    240:ebx寄存器此时保存的是newtd_thread内核栈的栈顶位置。
  238.                    241:更新默认tss的esp0成员,使其指向将要运行thread的内核栈
  239.                         的栈顶,这里就为newtd_thread的内核栈的栈顶。

  240.                    从上面可知,edx指向newtd_pcb,而newtd_pcb对象保存在newtd_thread的
  241.                    内核栈的顶部,而当cpu陷入内核时,cpu将用TSS描述符中esp0字段的
  242.                    值加载esp寄存器,即线程的内核栈的栈顶,240-241执行完后:

  243.                    ******************************* 内核栈顶部 高地址方向
  244.                    *                             *
  245.                    *   struct pcb对象            *
  246.                    *                             *
  247.                    *                             *
  248.                    ******************************* <--struct thread的td_pcb成员指向这里
  249.                    *                             *
  250.                    *   16bytes for vm            *
  251.                    ******************************* <--- PCPU(COMMON_TSS) + TSS_ESP0                     
  252.                    *                             *
  253.                    *                             *      
  254.   *************************************************/
  255.    240                leal        -16(%edx), %ebx                        /* leave space for vm86 */
  256.    241                movl        %ebx, PCPU(COMMON_TSS) + TSS_ESP0
  257.    242       
  258. /***********************************************************
  259.   * Test this CPU's  bit in the bitmap to see if this
  260.   * CPU was using a private TSS.

  261.        247:检查oldtd_thread是否使用了私有的tss。
  262.            cmpl结果非零,oldtd_thread使用了私有的tss。
  263.            cmpl结果为零,oldtd_thread使用了默认的tss。
  264. ***************************************/
  265.    247                cmpl        $0, PCPU(PRIVATE_TSS)                /* Already using the common? */
  266.    248                je        3f                                /* if so, skip reloading */
  267. /**********************************************************************
  268.   * 如果执行到这里的话,就表示newtd_thread使用的是默认的tss,
  269.    但是oldtd_thread使用的私有的tss,此时将当前cpu对应的
  270.    struct pcpu对象的pc_private_tss成员设置为0,因为newtd_thread
  271.     使用默认的tss。
  272. ***************************/
  273.    249                movl        $0, PCPU(PRIVATE_TSS)
  274.    250                PCPU_ADDR(COMMON_TSSD, %edi)
  275.    251        2:
  276. /*********************************************************************
  277.   * Move correct tss descriptor into GDT slot, then reload tr.
  278.                   
  279.                    253-259:
  280.                    如果执行到这里,包括下面两种情况:
  281.                    1:newtd_thread使用了私有的tss,上面233行的jmp指令直接跳转到这里。
  282.                    2:newtd_thread使用的是默认的tss,但是oldtd_thread使用的私有的tss。

  283.                    不管是上面哪一种情况,此时都要重新加载tr。

  284. ************************/
  285.    253                movl        PCPU(TSS_GDT), %ebx                /* entry in GDT */
  286.    254                movl        0(%edi), %eax
  287.    255                movl        4(%edi), %esi
  288.    256                movl        %eax, 0(%ebx)
  289.    257                movl        %esi, 4(%ebx)
  290.    258                movl        $GPROC0_SEL*8, %esi                /* GSEL(GPROC0_SEL, SEL_KPL) */
  291.    259                ltr        %si
  292.    260        3:
  293.    261       
  294. /*************************************************************
  295.    *  Copy the %fs and %gs selectors into this pcpu gdt
  296.                     在函数init386中,会将每个cpu对应的struct pcpu对象
  297.                     的pc_fsgs_gdt成员设置为相应GDT中fs Descriptor for user
  298.                     的描述符的地址,因为fs和gs相邻,所以通过
  299.                     pc_fsgs_gdt成员也可以访问%gs Descriptor for user。
  300.                     
  301.                     263-272:
  302.                     使用newtd_pcb对象中pcb_fsd和pcb_gsd两个成员的值重新
  303.                     加载:
  304.                     GDT中%fs Descriptor for user
  305.                     GDT中%gs Descriptor for user
  306.   ******************************/
  307.    263                leal        PCB_FSD(%edx), %esi
  308.    264                movl        PCPU(FSGS_GDT), %edi
  309.    265                movl        0(%esi), %eax                /* %fs selector */
  310.    266                movl        4(%esi), %ebx
  311.    267                movl        %eax, 0(%edi)
  312.    268                movl        %ebx, 4(%edi)
  313.    269                movl        8(%esi), %eax                /* %gs selector, comes straight after */
  314.    270                movl        12(%esi), %ebx
  315.    271                movl        %eax, 8(%edi)
  316.    272                movl        %ebx, 12(%edi)
  317.    273        #endif
  318. /*********************************************************************************
  319.   * Restore context.
  320.                    开始恢复newtd_thread的硬件上下文。
  321.                
  322.                    276:执行完后就开始在newtd的内核栈上操作。

  323.                    280-281:
  324.                    修改保存在newtd_thread内核栈上的返回地址:

  325.                    对于已经运行了一段时间的thread,返回地址为cpu_switch(return address),
  326.                    此时newtd_thread就开始从cpu_switch函数后面的代码开始执行。

  327.                    对于刚创建的thread,返回地址为fork_trampoline函数的地址,此时newtd_thread
  328.                    就开始执行fork_trampoline函数,在这种情况下,esi和ebx寄存器的值分下面几种
  329.                    情况:
  330.                    1:对于刚创建的thread:
  331.                       esi:fork_return函数的地址。
  332.                       ebx:child_thread对应的struct thread对象的地址。

  333.                    2:对于创建的idle线程:
  334.                       esi:sched_idletd函数的地址。
  335.                       ebx:NULL。

  336.                    3:对于1号线程:
  337.                       esi:start_init函数的地址。
  338.                       ebx:NULL。

  339.                    282-283:恢复newtd_thread的EFLAGS寄存器。
  340. *****************************************************/
  341.    275                movl        PCB_EBX(%edx),%ebx
  342.    276                movl        PCB_ESP(%edx),%esp
  343.    277                movl        PCB_EBP(%edx),%ebp
  344.    278                movl        PCB_ESI(%edx),%esi
  345.    279                movl        PCB_EDI(%edx),%edi
  346.    280                movl        PCB_EIP(%edx),%eax
  347.    281                movl        %eax,(%esp)
  348.    282                pushl        PCB_PSL(%edx)
  349.    283                popfl
  350. /*******************************************************
  351.   * ecx寄存器此时保存的是&newtd_thread。
  352.    edx寄存器此时保存的是&newtd_pcb。

  353.    285:当前cpu对应的srtuct pcpu对象的pc_curpcb成员
  354.          设置为&newtd_pcb。

  355.    287:当前cpu对应的srtuct pcpu对象的pc_curthread成员
  356.          设置为&newtd_thread;curthread宏的实现。
  357. ************/
  358.    285                movl        %edx, PCPU(CURPCB)
  359.    286                movl        TD_TID(%ecx),%eax
  360.    287                movl        %ecx, PCPU(CURTHREAD)                /* into next thread */
  361.    288       
  362. /*********************************************************************
  363. * Determine the LDT to use and load it if is the default one and
  364. * that is not the current one.
  365.     293-340:恢复LDT和调试寄存器,这里忽略。
  366. *************/
  367.    293                movl        TD_PROC(%ecx),%eax
  368.    294                cmpl    $0,P_MD+MD_LDT(%eax)
  369.    295                jnz        1f
  370.    296                movl        _default_ldt,%eax
  371.    297                cmpl        PCPU(CURRENTLDT),%eax
  372.    298                je        2f
  373.    299                LLDT(_default_ldt)
  374.    300                movl        %eax,PCPU(CURRENTLDT)
  375.    301                jmp        2f
  376.    302        1:
  377.    303                /* Load the LDT when it is not the default one. */
  378.    304                pushl        %edx                                /* Preserve pointer to pcb. */
  379.    305                addl        $P_MD,%eax                        /* Pointer to mdproc is arg. */
  380.    306                pushl        %eax
  381.    307                call        set_user_ldt
  382.    308                addl        $4,%esp
  383.    309                popl        %edx
  384.    310        2:
  385.    311       
  386.    312                /* This must be done after loading the user LDT. */
  387.    313                .globl        cpu_switch_load_gs
  388.    314        cpu_switch_load_gs:
  389.    315                mov        PCB_GS(%edx),%gs
  390.    316       
  391.    317                /* Test if debug registers should be restored. */
  392.    318                testl        $PCB_DBREGS,PCB_FLAGS(%edx)
  393.    319                jz      1f
  394.    320       
  395.    321                /*
  396.    322                 * Restore debug registers.  The special code for dr7 is to
  397.    323                 * preserve the current values of its reserved bits.
  398.    324                 */
  399.    325                movl    PCB_DR6(%edx),%eax
  400.    326                movl    %eax,%dr6
  401.    327                movl    PCB_DR3(%edx),%eax
  402.    328                movl    %eax,%dr3
  403.    329                movl    PCB_DR2(%edx),%eax
  404.    330                movl    %eax,%dr2
  405.    331                movl    PCB_DR1(%edx),%eax
  406.    332                movl    %eax,%dr1
  407.    333                movl    PCB_DR0(%edx),%eax
  408.    334                movl    %eax,%dr0
  409.    335                movl        %dr7,%eax
  410.    336                andl    $0x0000fc00,%eax
  411.    337                movl    PCB_DR7(%edx),%ecx
  412.    338                andl        $~0x0000fc00,%ecx
  413.    339                orl     %ecx,%eax
  414.    340                movl    %eax,%dr7
  415.    341        1:      /* 执行一个ret指令,返回啦 */
  416.    342                ret
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP