对应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
记录下自己的思路,如果有不正确的地方欢迎指出