286复位后处于实模式:
8086复位后的状态:
80286引入描述符cache,描述符缓存寄存器对程序是不可见的,没有指令存储它们的内容,它们只在加载段寄存器时更改(所有的远分支指令、LDS、LES、 mov、pop指令)。关于描述符缓存的详细介绍看这里。
80286 Access Right 格式:
286上电或复位时,描述符缓存会加载固定的默认值:CPU处于实模式、关中断、所有段的界限等于0xFFFF、所有段的access right没有公布。CS.base和IP决定了CPU运行在0xFFFFF0处。286手册上对于实模式下加载任何段寄存器时,仅介绍了地址计算,没有说明描述符cache是怎么装载的:
实模式下装载描述符缓存在loadall指令有介绍:
任何后续的段寄存器加载指令都将根据CPU的操作模式以正常方式重新加载关联的描述符高速缓存寄存器。在实模式下,基址的低4位和高4位设置为零。段落ID插入基地址的
位19-4。段限制重设为FFFFH,访问权限更改为可写段。
PCEM V15是按照这个标准模拟的80286,但是实机与这一段不符。
哈里斯286上测试实模式下描述符缓存:
;
;masm 6.0
;
.286p
cseg segment use16
assume cs:cseg,ds:cseg,ss:cseg
start:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,offset sp0
;
; 计算CS的物理地址,CS=DS=SS
;
mov dx,16
mul dx
mov word ptr [l_ss_desc],ax
mov byte ptr [l_ss_desc + 2],dl
mov word ptr [l_ds_desc],ax
mov byte ptr [l_ds_desc + 2],dl
mov word ptr [l_cs_desc],ax
mov byte ptr [l_cs_desc + 2],dl
add ax,offset idt
adc dx,0
mov word ptr [l_idtr],ax
mov byte ptr [l_idtr + 2],dl
xor di,di
mov ax,offset int0x0
mov bx,offset idt
mov cx,17
i0:
mov [bx + si],ax
add si,4
add ax,4
loop i0
cli
;
; 保存dos预留的loadall指令区域,(DOS3.3 - 4.0这个区域是保留出来的)
;
mov ax,80h
mov ds,ax
mov ax,cs
mov es,ax
xor si,si
mov di,offset s_data
mov cx,102/2
cld
rep movsw
;
; 将loadall 初始化值复制到物理地址0x800
;
mov ax,cs
mov ds,ax
mov ax,80h
mov es,ax
mov si,offset l_data
xor di,di
mov cx,102/2
rep movsw
db 0fh,05h ;LOADALL
hlt ;不可能到这里
;
; GDTR未设置,不开中断。
; loadall指令到达这里
;
ent:
mov ax,0b800h ;ES描述符的AR,界限=0
mov es,ax ;按手册的说明,这里应该按实模式
mov di,160*5 ;兼容值装载到描述符缓存.但是实机上
mov ax,0661h ; 这里只装载了基地址!
mov es:[di],ax ;触发GP,ES的描述符设置为空
r_dos:
mov ax,seg cseg
mov ds,ax
mov es,ax
mov ss,ax
mov sp,offset sp0
lidt fword ptr [r_idtr]
jmp far ptr r_dos1
r_dos1:
;
; 恢复DOS的loadall区
;
mov ax,80h
mov es,ax
mov cx,102/2
mov si,offset s_data
xor di,di
cld
rep movsw
sti
mov ah,4ch
int 21h
s_data db 102 dup (0)
;
; loadall memory area format
; 0x800 - 0x865
; 102 bytes
;
l_data df 0 ;RSV
l_msw dw 0fff0h ;0x806
dd 0 ;0x808
dd 0
df 0
l_tr dw 0 ;0x816
l_flag dw 2 ;0x818
l_ip dw offset ent ;0x81a
l_ldtr dw 0 ;0x81c
l_ds dw 0 ;0x81e
l_ss dw 0
l_cs dw 0
l_es dw 0
l_di dw 0
l_si dw 0
l_bp dw 0
l_sp dw offset sp0
l_bx dw 0
l_dx dw 0
l_cx dw 0
l_ax dw 0
;0x836
;
;ES AR和界限都是零,引用与ES段相关的内存都将触发GP
;
l_es_desc:
dw 0 ;base 15 - 0
db 0 ;base addr 23 -16
db 0 ;access
dw 0 ;16 bits limit
l_cs_desc df 0ffff93000000h
l_ss_desc df 0ffff92000000h
l_ds_desc df 0ffff92000000h
l_gdtr dw 0 ;24bit base address
db 0
db 0 ;NULL
dw 0 ;16bit limit
l_ldt_desc df 0
l_idtr dw 0 ;base 15 - 0
db 0 ;base 23 - 16
db 0 ;NULL
dw 3ffh ;16bit limit
l_tss_desc df 0
;
; real mode IDTR
;
r_idtr dw 3ffh
dd 0
int0x0:
push 0
jmp exc
push 1
jmp exc
push 2
jmp exc
push 3
jmp exc
push 4
jmp exc
push 5
jmp exc
push 6
jmp exc
push 7
jmp exc
push 8
jmp exc
push 9
jmp exc
push 10
jmp exc
push 11
jmp exc
push 12
jmp exc
push 13
jmp exc
push 14
jmp exc
push 15
jmp exc
push 16
exc:
mov bp,sp
mov ax,cseg
mov ds,ax
mov si,offset msg1
xor di,di
cld
mov cx,4
pr:
mov ax,[bp + di]
call hex16
add si,3
add di,2
loop pr
mov bx,160*10
mov si,offset msg
call puts
xor ax,ax
mov ds,ax
mov ax,-1
mov bx,83ah
mov word ptr [bx],ax
db 0fh,05h ;LOADALL
alltrap:
jmp r_dos
hex16:
push ax
shr ax,8
call hexa8
pop ax
hexa8:
push ax
shr al,4
call hexa81
pop ax
hexa81:
and al,0fh
add al,30h
cmp al,39h
jbe hexa82
add al,7h
hexa82:
mov [si],al
inc si
ret
put0:
cmp al,0ah
jne put2
push ax
mov ax,bx
mov dl,160
div dl
and ax,0ffh
mul dl
add ax,160
mov bx,ax
pop ax
jmp puts
put2:
mov ah,2
push ds
push ax
mov ax,0b800h
mov ds,ax
pop ax
mov [bx],ax
add bx,2
pop ds
puts:
lodsb
test al,al
jnz put0
ret
msg db "EXC_NO IP CS FLAGS"
db 0ah
msg1 db "1234h 1234h 1234h 1234h"
db 0
idt:
rept 256
dw offset alltrap
dw seg cseg
endm
db 4096 dup (0)
sp0:
cseg ends
end start