特权级之间的转换包括代码段之间的转换和数据段之间的转换。对于数据段之间的转换,只检查选择子中RPL和段中DPL的值,如果RPL<=DPL则可以转换,而对于代码段之间的转换,情况会稍微复杂。
代码段之间特权级的转换主要通过jmp和call指令实现,jmp和call的操作数可以直接是选择子,但注意在用call时,要记得ret。call的操作数还可以是一个调用门或者是一个包含选择子的TSS或者是一个包含TSS的任务门。对于门,其实质就是描述符,与代码段和数据段描述符不同,它是系统描述符,所以其s=0。暂时接触到的门共有四种:调用门、中断门、陷阱门和任务门。调用门只能放在GDT或LDT中,不能在IDT中,中断门和陷阱门则只能放在IDT中,而任务门既可以放在GDT中也可以放在LDT和IDT中。
这次碰到的问题有:
1.GDT中第四项(代码中为调用门)的索引为0x18,开始写为0x10了~
2.ret时,会检查被调用者的cs,eip等值,所以如果没有保存的话,系统会崩溃
- org 0x7c00
- mov ax,cs
- mov ds,ax
- ;initgdt
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,display
- mov word [gdt+10],ax
- shr eax,16
- mov byte [gdt+12],al
- mov byte [gdt+15],ah
- lgdt [gdt_addr]
- cli
- ;a20
- in al,0x92
- or al,00000010b
- out 0x92,al
- ;cr0 开CR0!
- mov eax,cr0
- or eax,0x1
- mov cr0,eax
- ;jmp dword codeselector:0
- call gateselector:0
- jmp $;死循环 否则没有代码执行系统会崩溃
- gdt:
- dw 0,0,0,0
- dw 0x07ff
- dw 0x0000
- dw 0x9a00
- dw 0x00cf
- dw 0x07ff
- dw 0x8000
- dw 0x920B
- dw 0x00cf
- ;gate 调用门可以放在GDT或LDT中 但不能放在IDT中
- dw 0x0000
- dw 0x0008
- dw 0xec00
- dw 0x0000
- ;选择子
- codeselector: equ 0x08
- videoselector: equ 0x10
- gateselector: equ 0x18;第四项为0x18!!!
- ;GDT地址
- gdt_addr:
- dw 0x07ff
- dw gdt,0
- ;Gate
- ;gate:
- [BITS 32]
- display:
- mov ax,videoselector
- mov gs,ax
- mov edi,(80*0+0)*2
- mov ah,0x0c
- mov al,'A'
- mov [gs:edi],ax
- jmp $;retf出问题 没保存堆栈?
- times 510-($-$) db 0
- dw 0xaa55