Я думаю, что прочитал около дюжины вопросов, которые в основном дублируют этот, но я до сих пор не нашел решения.
Желаемый результат - войти в защищенный режим и остановиться без сбоев. Проблема, с которой я столкнулся, - это тройная ошибка после выполнения межсегментного jmp
с 6-байтовым немедленным значением.
вот мой код, который вызывает ошибку в DOSBox и на ПК с Pentium II под управлением MS-DOS 7. Ассемблер - MASM 5.10
single segment stack
assume cs:single,ds:single
gdt dq 0
c_limit_lo dw 0ffffh
c_base_lo dw 0
c_base_mid db 0
c_priv db 10011110b ;present set, highest priv, type set, conforming, read
c_limit_hi db 11001111b ;granularity set, operand size 32
c_base_hi db 0
d_limit_lo dw 0ffffh
d_base_lo dw 0
d_base_mid db 0
d_priv db 10010010b ;present set, highest priv, type clr, expand dn, write
d_limit_hi db 11001111b ;granularity set, big set
d_base_hi db 0
gdt_end:
gdt_limit dw gdt_end-offset gdt-1
gdt_addr dd ?
start:
mov ax, cs
mov ds, ax
;calc phys address of current code segment and
;insert it into code and data descriptors
.386p
xor eax, eax
mov ax, cs
mov cl, 4
shl eax, cl ;multiply cs by 16 to get phys address of seg
mov edx, eax
mov c_base_lo, ax
mov d_base_lo, ax ;low word
mov cl, 16
shr eax, cl
mov c_base_mid, al
mov d_base_mid, al ;middle byte
mov c_base_hi, ah
mov d_base_hi, ah ;high byte
add edx, offset gdt ;add offset of gdt
mov gdt_addr, edx ;gdt address set
;attempt to enter protected mode
cli ;disable interrupts
in al, 70h
or al, 80h
out 70h, al ;turn off nonmasked interrupts
in al, 92h
or al, 2
out 92h, al ;enable A20 line
lgdt [gdt_limit]
mov eax, cr0
or eax, 1
mov cr0, eax ;enter protected mode
db 66h ;specify 32-bit operand
jmp_op db 0eah ;manually encoded "jmp 8h:enter_32" TRIPLE FAULT
jmp_loc_lo dw offset enter_32
jmp_loc_hi dw 0
jmp_sel dw 8
enter_32:
mov eax, 0ffffffffh ;sometimes doesn't triple fault on infinite jump or hlt instruction
back:jmp back ;but always triple faults on mov
the_stack db 64 dup (0ffh) ;64 byte stack
single ends
end start
Тройная ошибка кажется в какой-то степени «везением». Определенные конфигурации префиксов 0x67 и nop
s после дальнего перехода заставляют процессор вести себя так, как будто он остановлен. Я не совсем понимаю.
Я думаю, что создаю неправильную цель для прыжка.
Обновление: это не ошибка с однобайтовыми инструкциями (инструкции с одной кодировкой независимо от режима процессора). Я думаю, что попробую перейти в сегмент, определенный USE32.
Этот код не является ошибкой:
jmp_op db 0eah
jmp_loc_lo dw offset enter_32
jmp_loc_hi dw 0
jmp_sel dw 8
enter_32:
aaa
daa
cmc
cld
cli
stc
nop
aaa
daa
cmc
cld
cli
stc
nop
hlt
mov eax, 0ffffffffh
имеет префикс66h
в 16-битных режимах, но не в 32-битном режиме. То же самое для инструкцииjmp back
. - person fuz   schedule 13.05.2020