AMD的 手册中(SVM部分)记录了这一模式,其实386就隐藏有这一模式,只能通过loadall指令来实现。386 loadall 指令操作码0xf,0x7,现在已被sysret指令占用。
loadall指令从ES:EDI(es:di)指定的内存中加载所有CPU状态值到CPU中。loadall指令不执行错误检测,CPL将设置为SS描述符条目的DPL。
LOADALL指令的详细介绍:
The LOADALL Instructionwww.rcollins.orgloadall指令使用的描述符格式:
使用loadall指令可以“创造”出一些奇特的模式,比如分页的实模式、32位实模式以及特权级3的实模式等等。这些奇他的模式都有一个问题:中断转移是按照实模式的中断方式进行的,栈指针使用SP,返回地址是按16位入栈的,EIP的高16位会被丢弃。不管那一种古怪的模式,有一点是不变的,那就是32位X86的保护机制是始终有效的。这些古怪的模式(包括实模式)都可以看做是保护模式的变种。
AMD的SVM在关闭嵌套页的情况下也支持一部分上面那些稀奇古怪的模式组合。有些组合在初始阶段还是挺有用。
暂时没有发现有什么模拟器能支持loadall指令,只能实机测试,AMD和intel的386基本上没问题,都支持。
;
; 386 loadall opcode=0x0f07
; 286 =0x0f05
; AMD64 0x0f07 = sysret
; nasm -fbin -o
;
section .text vstart=0x7c00
bits 16
start:
cli
xor cx,cx
mov ds,cx
mov es,cx
mov ss,cx
mov sp,sp0
main:
in al,0x92
or al,2
out 0x92,al
mov di,idt
mov cx,1024*2
xor ax,ax
cld
rep stosw
page_pde equ 0x5000
page_pte equ 0x6000
mov di,0x5000
mov eax,page_pte | 7
mov [di],eax
mov di,0x6000
mov eax,0x7
mov cx,1024
p0:
mov [di],eax
add eax,0x1000
lea di,[di+4]
loop p0
mov eax,page_pde
mov cr3,eax
mov si,idt
mov eax,intx00
mov ecx,17
ii0:
mov [si],eax
lea si,[si +4]
loop ii0
mov edi,load_area
call set_load
db 0xf,0x7 ;装载处理器状态,进入32位分页实模式。
hlt
bits 32
l_entry:
cld
call dump
mov esi,buff
mov edi,0xb8000 +160*6
call putc
; ud2
jmp $
dump:
mov esi,msg
mov edi,buff
mov eax,cr0
push eax
mov eax,cr3
push eax
jmp dump.1
dump.0:
stosb
dump.1:
lodsb
test al,al
jz dump.4
test al,0x80
jz dump.0
dump.2:
mov dl,al
pop eax
call hex32
test dl,8 ;0xa end line
jz dump.3
mov al,0xa
stosb
dump.3:
mov ax,0x2020
stosw
jmp dump.1
dump.4:
xor al,al
stosb
ret
putc.0:
mov ah,2
stosw
putc:
lodsb
test al,al
jnz putc.0
ret
hex32:
push eax
shr eax,16
call hex16
pop eax
hex16:
push eax
shr eax,8
call hex8
pop eax
hex8:
push eax
shr al,4
call hex81
pop eax
hex81:
and al,0fh
add al,30h
cmp al,39h
jbe hex82
add al,7h
hex82:
stosb
ret
intx00:
mov edi,0xb8000+160*8 - 32
mov eax,0x82418241
mov [edi],eax
jmp $
idtr dw 256*4 - 1
dd idt
bits 16
set_load:
mov word [di+l_cr0 + 2],0x8000 ;PG=1,PE=0
mov byte [di + l_eflag],2 ;IF = 0
mov ax,sp0
mov [di + l_esp],ax
mov ax,l_entry
mov [di + l_eip],ax ;入口
;
; CS.G=SS.B = 1 ,32位代码段和32位堆栈段
;
mov eax,0xc09300
mov [di + l_ss_ar],eax
mov [di + l_es_ar],eax
mov [di + l_ds_ar],eax
mov eax,0xc09b00
mov [di + l_cs_ar],eax
mov eax,-1
mov [di + l_cs_limit],eax
mov [di + l_ss_limit],eax
mov [di + l_es_limit],eax
mov [di + l_ds_limit],eax
mov ax,idt
mov [di + l_idt_base],ax
mov word [di + l_idt_limit],0x3ff
ret
msg:
db "CR0="
db 0x80
db "CR3="
db 0x80
db 0x80 | 8 ;打印控制字
db 0
times 510 - ($ - $$) db 0
dw 0xaa55
section .bss
idt:
resb 256*4
;
; loadall 占用512字节,不是强制要求4字节对齐
;
align 4
load_area:
l_cr0 equ 0
l_eflag equ 4
l_eip equ 8
l_edi equ 0xc
l_esi equ 0x10
l_ebp equ 0x14
l_esp equ 0x18
l_ebx equ 0x1c
l_edx equ 0x20
l_ecx equ 0x24
l_eax equ 0x28
l_dr6 equ 0x2c
l_dr7 equ 0x30
l_tss_sel equ 0x34 ;word
l_ldtr_sel equ 0x38 ;word
l_gs_sel equ 0x3c
l_fs_sel equ 0x40
l_ds_sel equ 0x44
l_ss_sel equ 0x48
l_cs_sel equ 0x4c
l_es_sel equ 0x50
l_tss_ar equ 0x54
l_tss_base equ 0x58
l_tss_limit equ 0x5c
l_idt_ar equ 0x60
l_idt_base equ 0x64
l_idt_limit equ 0x68
l_gdt_ar equ 0x6c
l_gdt_base equ 0x70
l_gdt_limit equ 0x74
l_ldt_ar equ 0x78
l_ldt_base equ 0x7c
l_ldt_limit equ 0x80
l_gs_ar equ 0x84
l_gs_base equ 0x88
l_gs_limit equ 0x8c
l_fs_ar equ 0x90
l_fs_base equ 0x94
l_fs_limit equ 0x98
l_ds_ar equ 0x9c
l_ds_base equ 0xa0
l_ds_limit equ 0xa4
l_ss_ar equ 0xa8
l_ss_base equ 0xac
l_ss_limit equ 0xb0
l_cs_ar equ 0xb4
l_cs_base equ 0xb8
l_cs_limit equ 0xbc
l_es_ar equ 0xc0
l_es_base equ 0xc4
l_es_limit equ 0xc8
resb 512 - ($ - load_area)
resb 0x1000
sp0:
buff: