从实模式到保护模式-17.4练习题

对应429行

;-------------------------------------------------------------------------------
rtm_0x70_interrupt_handle:                  ;实时时钟中断处理过程

         pushad

         mov al,0x20                        ;中断结束命令EOI
         out 0xa0,al                        ;向8259A从片发送
         out 0x20,al                        ;向8259A主片发送

         mov al,0x0c                        ;寄存器C的索引。且开放NMI
         out 0x70,al
         in al,0x71                         ;读一下RTC的寄存器C,否则只发生一次中断
                                            ;此处不考虑闹钟和周期性中断的情况

;修改区域------------------------------------------------------------修改区域
         ;更新除当前任务外,所有任务TSS的busy位
         sgdt [pgdt]
         mov eax,tcb_chain 
         xor ecx,ecx 
         mov edx,[pgdt+2]
 .tss_no_busy:
         mov ebx,[eax]
         or ebx,ebx
         jz .stop_tcb
         cmp word [ebx+0x04],0xffff       ;是否为当前任务
         je .next_tcb
         mov cx,[ebx+0x18]        ;取TSS选择子
         shr cx,3          ;GDT索引
         and dword [edx+ecx*8+4],0xFFFFFDFF    ;TSS描述符B位置零
 .next_tcb:
         mov eax,ebx
         jmp .tss_no_busy
 .stop_tcb:       
         lgdt [pgdt]
;修改区域------------------------------------------------------------修改区域



         ;找当前任务(状态为忙的任务)在链表中的位置
         mov eax,tcb_chain                  
  .b0:                                      ;EAX=链表头或当前TCB线性地址
         mov ebx,[eax]                      ;EBX=下一个TCB线性地址
         or ebx,ebx
         jz .irtn                           ;链表为空,或已到末尾,从中断返回
         cmp word [ebx+0x04],0xffff         ;是忙任务(当前任务)?
         je .b1
         mov eax,ebx                        ;定位到下一个TCB(的线性地址)
         jmp .b0         

         ;将当前为忙的任务移到链尾
  .b1:
         mov ecx,[ebx]                      ;下游TCB的线性地址
         mov [eax],ecx                      ;将当前任务从链中拆除

  .b2:                                      ;此时,EBX=当前任务的线性地址
         mov edx,[eax]
         or edx,edx                         ;已到链表尾端?
         jz .b3
         mov eax,edx
         jmp .b2

  .b3:
         mov [eax],ebx                      ;将忙任务的TCB挂在链表尾端
         mov dword [ebx],0x00000000         ;将忙任务的TCB标记为链尾

         ;从链首搜索第一个空闲任务
         mov eax,tcb_chain
  .b4:
         mov eax,[eax]
         or eax,eax                         ;已到链尾(未发现空闲任务)
         jz .irtn                           ;未发现空闲任务,从中断返回
         cmp word [eax+0x04],0x0000         ;是空闲任务?
         jnz .b4

         ;将空闲任务和当前任务的状态都取反
         not word [eax+0x04]                ;设置空闲任务的状态为忙
         not word [ebx+0x04]                ;设置当前任务(忙)的状态为空闲


;修改区域↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓修改区域
         ;保存当前任务信息到TSS
         mov ecx,[ebx+0x14] 
         mov dx,gs
         mov [ecx+92],dx
         mov dx,fs
         mov [ecx+88],dx
         mov dx,ds
         mov [ecx+84],dx
         mov dx,ss
         mov [ecx+80],dx
         mov dx,cs
         mov [ecx+76],dx
         mov dx,es
         mov [ecx+72],dx
         pushfd
         pop edx
         mov [ecx+36],edx
         mov [ecx+56],esp
         mov dword [ecx+32],.irtn  ;从任务环境的中断中切换,因此要回到任务中断
  
        
         ltr [eax+0x18];加载新任务TSS的信息
         mov ecx,[eax+0x14]
         lldt [ecx+96]
         mov dx,[ecx+92]
         mov gs,dx
         mov dx,[ecx+88]
         mov fs,dx
         mov dx,[ecx+72]
         mov es,dx
         mov edi,[ecx+68]
         mov esi,[ecx+64]
         mov ebp,[ecx+60]
         mov ebx,[ecx+52]
         mov edx,[ecx+28]
         mov cr3,edx 

         ;切换场景
         ;1 切换到用户程序 
              ;更新CR3后,高2GB空间保持不变,低2G基于页表对应新的用户空间
              ;1.1 第一次切换到任务程序 - 此时要从0环返回到3环,模拟任务的0环栈,压入相关内容,然后返回到3环
              ;1.2 从中断返回任务 - 通过中断的iretf返回,这里的栈由处理切换,保持中断内的环境即可
         ;2 切换到内核
              ;模拟远调用即可,堆栈不切换都在0环
         test dword [eax+0x06],0x80000000  ;取下一个分配的地址进行判断
         jnz .rang0   ;下一个任务是操作系统

         ;判断是第一次执行,还是切换回来
         test word [ecx+76],0x3  ;取CS选择子低二位,如果是0则表示切换回来,如果是3表示第一执行
         jz .swith_to_task

         ;第一执行,CS为RPL为3,堆栈切换
         ;切换到新任务的0特权栈
         mov esp,[ecx+4]
         mov dx,[ecx+8]
         mov ss,dx

         ;模拟栈
         ;| EIP  |
         ;| 0|CS |
         ;| 参数  |
         ;| ESP  |
         ;| 0|SS |
         push dword [ecx+80] ;SS
         push dword [ecx+56] ;ESP
         push dword [ecx+76] ;CS
         push dword [ecx+32] ;EIP
         jmp .gogogo

 .swith_to_task:
         ;切换回来,CS为RPL为0,堆栈不切换
         mov esp,[ecx+56]
         mov dx,[ecx+80]
         mov ss,dx
         ;push dword [ecx+76] ;CS  跟当前环境使用相同的段,不改变也不影响
         push dword [ecx+32] ;EIP


 .gogogo:
         push dword [ecx+48];EDX
         push dword [ecx+44] ;ECX
         push dword [ecx+40] ;EAX
         push dword [ecx+36] ;EFlags

         mov dx,[ecx+84]
         mov ds,dx
         
         popfd
         pop eax
         pop ecx
         pop edx

         ;retf ;此时将当前任务busy位设置为1      压入CS时使用
         ret
 .rang0:
       ;切换到新任务的0特权栈
         mov esp,[ecx+56]
         mov dx,[ecx+80]
         mov ss,dx

         ;模拟栈
         ;| EIP  |
         ;| 0|CS | 
         ;push dword [ecx+76] ;CS   ;同上
         push dword [ecx+32] ;EIP

         push dword [ecx+48];EDX
         push dword [ecx+44] ;ECX
         push dword [ecx+40] ;EAX
         push dword [ecx+36] ;EFlags

         mov dx,[ecx+84]
         mov ds,dx
         
         popfd
         pop eax
         pop ecx
         pop edx
       
         ;retf ;此时将当前任务busy位设置为1 ;同上
         ret

;修改区域↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑修改区域


  .irtn:
         popad

         iretd

;-------------------------------------------------------------------------------

对应1020行

         ;在程序管理器的TSS中设置必要的项目 
         mov word [ebx+0],0                 ;反向链=0
         mov eax,cr3
         mov dword [ebx+28],eax             ;登记CR3(PDBR)
         mov word [ebx+96],0                ;没有LDT。处理器允许没有LDT的任务。
         mov word [ebx+100],0               ;T=0
         mov word [ebx+102],103             ;没有I/O位图。0特权级事实上不需要。

;修改区域↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓修改区域

         mov word [ebx+76],flat_4gb_code_seg_sel
         mov [core_tcb+0x14],ebx

;修改区域↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑修改区域
        
         
         ;创建程序管理器的TSS描述符,并安装到GDT中 
         mov eax,ebx                        ;TSS的起始线性地址
         mov ebx,103                        ;段长度(界限)
         mov ecx,0x00408900                 ;TSS描述符,特权级0
         call flat_4gb_code_seg_sel:make_seg_descriptor
         call flat_4gb_code_seg_sel:set_up_gdt_descriptor
         mov [core_tcb+0x18],cx             ;登记内核任务的TSS选择子到其TCB

 记录下自己的思路,如果有不正确的地方欢迎指出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值