structtss_struct { long back_link; /* 16 high bits zero */ long esp0; long ss0; /* 16 high bits zero */ long esp1; long ss1; /* 16 high bits zero */ long esp2; long ss2; /* 16 high bits zero */ long cr3; long eip; long eflags; long eax,ecx,edx,ebx; long esp; long ebp; long esi; long edi; long es; /* 16 high bits zero */ long cs; /* 16 high bits zero */ long ss; /* 16 high bits zero */ long ds; /* 16 high bits zero */ long fs; /* 16 high bits zero */ long gs; /* 16 high bits zero */ long ldt; /* 16 high bits zero */ long trace_bitmap; /* bits: trace 0, bitmap 16-31 */ structi387_structi387; };
tss_struct 也会被记录在 task_struct 中:
1 2 3 4 5
structtask_struct { ...... /* tss for this task */ structtss_structtss; };
GDT(Global Descriptor Table)是 x86 处理器中的一个全局数据表,用于描述进程的内存空间:
! ok, the read went well so we get current cursor position and save it for ! posterity.
mov ax,#INITSEG ! this is done in bootsect already, but... mov ds,ax mov ah,#0x03 ! read cursor pos xor bh,bh int 0x10 ! save it in known place, con_init fetches mov [0],dx ! it from 0x90000. ...... end_move: mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-) mov ds,ax lidt idt_48 ! load idt with 0,0 lgdt gdt_48 ! load gdt with whatever appropriate
这段代码的前半部分在 Lab1 中已经分析过了,我们只需要看最后两段代码:
1 2
lidt idt_48 ! load idt with 0,0 lgdt gdt_48 ! load gdt with whatever appropriate
lea idt,%edi mov $256,%ecx rp_sidt: movl %eax,(%edi) movl %edx,4(%edi) addl $8,%edi dec %ecx jne rp_sidt lidt idt_descr ret
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
.align 2 .word 0 idt_descr:/* 前(低)16位是IDT的界限值,后(高)32位是IDT的基地址 */ .word 256*8-1 # idt contains 256 entries .long idt .align 2 .word 0 gdt_descr: /* 前(低)16位是GDT的界限值,后(高)32位是GDT的基地址 */ .word 256*8-1 # so does gdt (not that that's any .long gdt # magic number, but it works for me :^)
.align 8 idt: .fill 256,8,0 # idt is uninitialized
gdt: .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x00c09a0000000fff /* 16Mb */ .quad 0x00c0920000000fff /* 16Mb */ .quad 0x0000000000000000 /* TEMPORARY - don't use */ .fill 252,8,0 /* space for LDT's and TSS's etc */
structtask_struct { /* these are hardcoded - don't touch */ long state; /* -1 unrunnable, 0 runnable, >0 stopped */ long counter; long priority; long kernelstack; /* 用于记录内核栈顶地址(相当于task_struct->tss.esp0) */ long signal; structsigactionsigaction[32]; long blocked; /* bitmap of masked signals */ ...... };
state = 0# these are offsets into the task-struct. counter = 4 priority = 8 KERNEL_STACK = 12 signal = 12+4 sigaction = 16+4 # MUST be 16 (=len of sigaction) blocked = (32*16+4)
.align 2 first_return_kernel: popl %edx popl %edi popl %esi pop %gs pop %fs pop %es pop %ds iret /* 从中断中返回,并设置cs:eip,eflags,ss:esp */
指令 iret 执行以后,进程将恢复到用户态进程
最后修改一下 schedule 中关于 switch_to 的调用即可:
1 2 3 4 5 6 7 8 9 10 11 12
while (1) { ...... while (--i) { if (!*--p) continue; if ((*p)->state == TASK_RUNNING && (*p)->counter > c) c = (*p)->counter, next = i ,pnext = *p; } ...... } // switch_to(next); switch_to(pnext,_LDT(next));