Ошибка: недопустимый тип дескриптора 0 для int 0

Я не могу переключиться в защищенный режим в программе DOS EXE, написанной на MASM.

При загрузке дескриптора DOSBox выдает ошибку:

Недопустимый тип дескриптора 0 int 0.

Я создал функцию для загрузки таблицы дескрипторов с 3 дескрипторами Null, Code, Data. И я даже включил линию А20. У меня возникли проблемы сразу после использования инструкции LGIT. Мой код:

.386p

GDT struct
limit_0_15 word ?
base_0_15  word ?
base_16_23 byte ?
access_byt byte ?
fl_limit   byte ?
base_24_31 byte ?
GDT ends

main_data segment use16
idt_start:
    db 800h dup (?)
idt_info:
    dw 2048
    dd idt_start

gdt_start:
nul_gdt GDT <0,0,0,0,0,0>
c32_gdt GDT <0,0,0,0,0,0>
d32_gdt GDT <0,0,0,0,0,0>
gdt_info:
    dw gdt_info - gdt_start - 1
    dd gdt_start

main_data ends

main_code segment use16
assume cs:main_code, ds:main_data, ss:stack16
_start:

mov  ax,main_data
mov  ds,ax
mov  ax,code16
mov  es,ax
call es:[Check_A20]
call es:[Set_A20]
call es:[Check_A20]
call es:[Create_GDT]

mov  bx,gdt_info
lgdt fword ptr[bx]

mov  bx,idt_info
lidt fword ptr[bx]

mov  eax,cr0
or   eax,1
mov  cr0,eax

jmp clear_prefetch_queue
nop
nop
clear_prefetch_queue:

mov  eax,0ffffh
mov  ebx,0fh
div  ebx

exit:
mov  ah,4ch
int  21h
main_code ends



code16 segment use16

Wait_8042_command proc ; wait for the kbd controller to get ready to take in commands
in   al,64h
test al,2
jnz  Wait_8042_command
ret
Wait_8042_command endp

Wait_8042_data proc   ; wait for the kbd controller to get ready to take in data
in   al,64h
test al,1
jz   Wait_8042_data
ret
Wait_8042_data endp

Check_A20 proc
pushf
push ds
push es
push di
push si

cli
xor  ax,ax
mov  es,ax
mov  di,500h
not  ax
mov  ds,ax
mov  si,510h

mov  al,byte ptr es:[di]
push ax
mov  al,byte ptr ds:[si]
push ax

mov  byte ptr es:[di],0
mov  byte ptr ds:[si],0ffh
cmp  byte ptr es:[di],0ffh

pop  ax
mov  byte ptr ds:[si],al
pop  ax
mov  byte ptr es:[di],al

mov  ax,0
je   check_a20_exit
mov  ax,1

check_a20_exit:
pop  si
pop  di
pop  es
pop  ds
popf
retf
Check_A20 endp

Set_A20 proc
cli
call Wait_8042_command
mov  al,0ADh             ;set command to disable kbd
out  64h,al

call Wait_8042_command
mov  al,0d0h
out  64h,al              ;read from input

call Wait_8042_data
in   al,60h              ;read input from kbd
push ax

call Wait_8042_command
mov  al,0d1h             ;write to output
out  64h,al

call Wait_8042_command
pop  ax
or   al,2
out  60h,al

call Wait_8042_command
mov  al,0AEh            ;enable kbd controller
out  64h,al

call Wait_8042_command
sti
retf
Set_A20 endp

Create_GDT proc
push ds
mov  ax,main_data
mov  ds,ax

;NULL Descriptor
;mov  cx,4
;rep  stosw
;code32 gdt initialized
mov  c32_gdt.limit_0_15, 0ffffh
mov  c32_gdt.base_0_15,  0h
mov  c32_gdt.base_16_23, 0h
mov  c32_gdt.access_byt, 9ah
mov  c32_gdt.fl_limit,   0cfh
mov  c32_gdt.base_24_31, 0h
;data32 gdt initialized
mov  d32_gdt.limit_0_15, 0ffffh
mov  d32_gdt.base_0_15,  0h
mov  d32_gdt.base_16_23, 0h
mov  d32_gdt.access_byt, 92h
mov  d32_gdt.fl_limit,   0cfh
mov  d32_gdt.base_24_31, 0h

pop  ds
retf
Create_GDT endp


code16 ends


code32 segment use32
mov  eax,0ffffh ;test garbage
mov  ebx,0fh
div  ebx
code32 ends

data32 segment use32

data32 ends


stack16 segment stack use16
    dw 200h dup (?)
stack16 ends

end _start

person Rajul    schedule 24.03.2019    source источник
comment
@MichaelPetch Извиняюсь, я удалил его из-за ограничения на количество слов, добавив сейчас   -  person Rajul    schedule 24.03.2019
comment
@MichaelPetch Я использую MASM, и он делает то же самое, не нужно указывать FAR JMP или что-то в этом роде, я добавил ссылку в код   -  person Rajul    schedule 24.03.2019
comment
Я думаю, что непосредственной причиной проблемы является то, что инструкция div вызывает ошибку переполнения, а IDT еще не инициализирован. (Div переполняется, потому что edx не равен нулю.)   -  person prl    schedule 24.03.2019
comment
Имейте в виду, что только то, что вы устанавливаете IDT с помощью LIDT, не делает его полезным. Вам нужно заполнить его шлюзами прерываний, прежде чем вы сможете включить прерывания. Находясь в защищенном режиме, вы не можете выполнять вызовы DOS или BIOS. Мой код просто выполняет HLT, чтобы перевести код защищенного режима в состояние ожидания бездействия. Как указывает prl, ваша инструкция DIV, скорее всего, завершится ошибкой с переполнением, если вы сначала не очистите EDX. Сбой приведет к сбою, поскольку в вашей IDT не определены шлюзы прерывания (включая шлюз прерывания, который обрабатывает исключения деления).   -  person Michael Petch    schedule 24.03.2019
comment
Ожидается ли #DE от div? Если вы используете это для проверки настройки IDT, вам следует убедиться, что EDX не равен нулю. Но если это неожиданно, то эта часть вопроса дублируется.   -  person Peter Cordes    schedule 24.03.2019
comment
@PeterCordes: на самом деле это не дубликат. Даже если бы у него был обработчик #DE, этот код все равно не работает, поскольку IDT загружается не с правильного адреса памяти. GDT также не загружается должным образом, и код неправильно входит в 32-битный защищенный режим, как говорит ОП, которого он пытается достичь. Он доходит только до квази-16-битного защищенного режима. Этот вопрос актуален в контексте написания программы DOS EXE (не COM или загрузчиков), которая может быть расположена в произвольных сегментах, и проблем с линейными адресами. Я голосую за повторное открытие, потому что могу дать разумный ответ   -  person Michael Petch    schedule 25.03.2019
comment
Этот вопрос является продолжением предыдущего вопроса ОП о загрузке GDT и т. Д. Понятно, что основная линия вопросов — это попытка ОП войти в защищенный режим из программы DOS EXE без использования интерфейса защищенного режима (например, VCPI / ДПМИ и др.)   -  person Michael Petch    schedule 25.03.2019
comment
@MichaelPetch: Да, сборка 8086 на DOSBox: ошибка с инструкцией idiv? в любом случае охватывала только то, что выявило неправильно настроенную IDT. Попытка сделать что-либо еще с машиной после переключения вскоре привела бы к аналогичным проблемам. Закрытие как дубликат для #DE было не самым полезным способом справиться с этим вопросом, если сделать SO полезным хранилищем вопросов и ответов.   -  person Peter Cordes    schedule 25.03.2019
comment
@PeterCordes: я признаю, что пытался решить, следует ли закрыть его как дубликат stackoverflow.com/q/54772558/ 3857942 . Это близко, но этот вопрос включает FASM, но, что более важно, в вопросе использовалась техника перемещения. Сегменты, созданные этой OP, дают ответ, который не использует перемещение, но изменяет базовый адрес некоторых дескрипторов GDT, чтобы он был ненулевым. Последняя причина — та, из-за которой я раньше не опустил молоток для обмана.   -  person Michael Petch    schedule 25.03.2019
comment
@MichaelPetch нам там любой справочный материал, который я должен прочитать. А насчет того, чтобы быть эффективнее, я еле-еле начал асм   -  person Rajul    schedule 25.03.2019
comment
То, что вы здесь делаете, непростое, требующее реального понимания того, как все работает, а также того, как справляться с проблемами, связанными с DOS, сегментацией и перемещением. Я знаю опытных разработчиков, знающих сборку x86, которые могут быть застигнуты врасплох проблемами, затронутыми в этом вопросе. Руководства Intel — это одно из мест, где можно получить подробную информацию о каждой инструкции. Я бы рекомендовал изучать сборку, делая что-то менее сложное. Загрузчик был бы даже более простой отправной точкой (и вы можете получить информацию о входе в защищенный режим на вики OSDev ).   -  person Michael Petch    schedule 25.03.2019
comment
Есть ли конкретная причина, по которой вы решили написать код (будучи новичком в ассемблере) для сложной задачи входа в защищенный режим именно из DOS?   -  person Michael Petch    schedule 25.03.2019
comment
@MichaelPetch Я сделал несколько собственных программ сборки, и я также использовал руководство Intel для защищенного режима, просто кто-то, кто меня учит, попросил меня об этом и сам придумал, и я много сталкивался с сегментацией, но это просто всегда что-то новое каждый раз, это означает, что мне не хватает знаний, поэтому я попросил какой-нибудь справочный материал. Я должен был сделать код анимации, поскольку я сделал код для печати bmp. И поверьте мне, этот человек один из лучших. Но мне нужно разобраться со своими проблемами   -  person Rajul    schedule 25.03.2019
comment
В реальном режиме всегда нужно помнить, что для каждого операнда памяти в инструкции есть неявный или явный сегмент. Сегмент и смещение операнда памяти объединяются вместе, чтобы сформировать указатель на конкретный физический/линейный адрес. Одно из лучших руководств по сегментации и связанным с ней расчетам можно найти здесь: thestarman.pcministry. com/asm/debug/Segments.html   -  person Michael Petch    schedule 25.03.2019
comment
Я знаком с сегментом и смещением реального режима и используемым 1 МБ памяти. Сделал много программ в реальном режиме, это была моя первая попытка с защищенным режимом, поэтому я думаю, что немного напортачил. Кстати, сердечно благодарен за ваше время и помощь :D   -  person Rajul    schedule 25.03.2019