Защищенный режим
Так вот, не могу найти ошибку. Когда такое может происходить?
Программа из учебника Рудакова и Финогенова №70_1.
Команду, вызывающую исключение, пометил символами =>, чтоб было легче найти :)
.586P
;Структура для описания дескрипторов сегментов
descr struc
lim dw 0 ;Граница сегмента (биты 0...15)
base_l dw 0 ;База сегмента (биты 0...15)
base_m db 0 ;База сегмента (биты 16...23)
attr_1 db 0 ;Байт атрибутов 1
attr_2 db 0 ;Граница (биты 16...19) и атрибуты 2
base_h db 0 ;База (биты 24...31)
descr ends
;Структура для описания шлюза ловушек
trap struc
offs_l dw 0 ;Смещение обработчика (биты 0...15)
sel dw 16 ;Селектор сегмента команд
cntr db 0 ;Не используется
dtype db 8Fh ;Тип шлюза - ловушка 80386 и выше
offs_h dw 0 ;Смещение обработчика (биты 16...31)
trap ends
;Сегмент данных
data segment use16
;Таблица глобальных дескрипторов GDT
gdt_null descr <0, 0, 0, 0, 0, 0>
gdt_data descr <data_size-1, 0, 0, 92h, 0, 0>
gdt_code descr <code_size-1, 0, 0, 98h, 0, 0>
gdt_stack descr <599, 0h, 0, 92h, 0, 0>
gdt_screen descr <3999, 8000h, 0Bh, 92h, 0, 0>
gdt_text1 descr <text1_size-1, 0, 0, 9Ah, 0, 0>
gdt_text2 descr <text2_size-1, 0, 0, 9Ah, 0, 0>
gdt_tss0 descr <103, 0, 0, 89h, 0, 0>
gdt_tss1 descr <103, 0, 0, 89h, 0, 0>
gdt_tss2 descr <103, 0, 0, 89h, 0, 0>
;Размер GDT
gdt_size=$-gdt_null
;Начало таблицы дескрипторов исключений
idt label word
;Таблица дескрипторов исключений
trap 10 dup (<dummy>)
trap <exc10>
trap <exc11>
trap <exc12>
trap <exc13>
trap 18 dup (<dummy>)
;Размер таблицы дескрипторов исключений
idt_size=$-idt
;Псевдодескриптор для команды lgdt
pdescr df 0
;Шаблон диагностической строки
string db '**** ****-**** ****-**** ****'
;Длина строки
len=$-string
;TSS нулевой задачи
tss0 dw 52 dup (0)
;TSS первой задачи
tss1 dw 52 dup (0)
;TSS второй задачи
tss2 dw 52 dup (0)
task1_offs dw 0
task1_sel dw 64
task2_offs dw 0
task2_sel dw 72
;Размер сегмента данных
data_size=$-data
data ends
;Сегмент кода
text segment use16
assume cs:text, ds:data
;Подпрограмма преобразования слова
;При вызове преобразумое число в ax, ds:si = адрес поля для результата
wrd_asc proc
pusha
mov bx, 0F000h
mov dl, 12
mov cx, 4
cccc:
push cx
push ax
and ax, bx
mov cl, dl
shr ax, cl
call bin_asc
mov byte ptr [si], al
inc si
pop ax
shr bx, 4
sub dl, 4
pop cx
loop cccc
popa
ret
wrd_asc endp
;Подпрограмма преобразования 16-ричной цифры
;Преобразуемая четверка битов в младшей половине al, результат в al
bin_asc proc
cmp al, 9
ja lettr
add al, 30h
jmp ok
lettr:
add al, 37h
ok:
ret
bin_asc endp
;Обработчик исключения 10
exc10 proc
mov ax, 8
mov ds, ax
pop eax
pop eax
mov si, offset string+5
call wrd_asc
mov ax, 10
jmp home
exc10 endp
;Обработчик исключения 11
exc11 proc
mov ax, 8
mov ds, ax
pop eax
pop eax
mov si, offset string+5
call wrd_asc
mov ax, 11
jmp home
exc11 endp
;Обработчик исключения 12
exc12 proc
mov ax, 8
mov ds, ax
pop eax
pop eax
mov si, offset string+5
call wrd_asc
mov ax, 12
jmp home
exc12 endp
;Обработчик исключения 13
exc13 proc
mov ax, 8
mov ds, ax
pop eax
pop eax
mov si, offset string+5
call wrd_asc
mov ax, 13
jmp home
exc13 endp
;Обработчик остальных исключений
dummy proc
mov ax, 8
mov ds, ax
mov ax, 5555h
jmp home
dummy endp
;Главная функция
main proc
;Загружаем в ds сегментный адрес сегмента данных
xor eax, eax
mov ax, data
mov ds, ax
;Вычислим и загрузим в GDT линейный адрес сегмента данных
shl eax, 4
mov ebp, eax
mov bx, offset gdt_data
mov [bx].base_l, ax
shr eax, 16
mov [bx].base_m, al
;Вычислим и загрузим в GDT линейный адрес сегмента команд text
xor eax, eax
mov ax, cs
shl eax, 4
mov bx, offset gdt_code
mov [bx].base_l, ax
shr eax, 16
mov [bx].base_m, al
;Вычислим и загрузим в GDT линейный адрес сегмента команд text1
xor eax, eax
mov ax, text1
shl eax, 4
mov bx, offset gdt_text1
mov [bx].base_l, ax
shr eax, 16
mov [bx].base_m, al
;Вычислим и загрузим в GDT линейный адрес сегмента команд text2
xor eax, eax
mov ax, text2
shl eax, 4
mov bx, offset gdt_text2
mov [bx].base_l, ax
shr eax, 16
mov [bx].base_m, al
;Вычислим и загрузим в GDT линейный адрес сегмента стека
xor eax, eax
mov ax, ss
shl eax, 4
mov bx, offset gdt_stack
mov [bx].base_l, ax
shr eax, 16
mov [bx].base_m, al
;Вычислим и загрузим в GDT линейный адрес TSS0
mov eax, ebp
add ax, offset tss0
mov bx, offset gdt_tss0
mov [bx].base_l, ax
shr eax, 16
mov [bx].base_m, al
;Вычислим и загрузим в GDT линейный адрес TSS1
mov eax, ebp
add ax, offset tss1
mov bx, offset gdt_tss1
mov [bx].base_l, ax
shr eax, 16
mov [bx].base_m, al
;Вычислим и загрузим в GDT линейный адрес TSS2
mov eax, ebp
add ax, offset tss2
mov bx, offset gdt_tss2
mov [bx].base_l, ax
shr eax, 16
mov [bx].base_m, al
;Подготовим псевдодескриптор и загрузим регистр GDTR
mov dword ptr pdescr+2, ebp
mov word ptr pdescr, gdt_size-1
lgdt pdescr
cli
;Инициализируем TSS1
mov tss1+4Ch, 40
mov tss1+20h, offset task1
mov tss1+50h, 24
mov tss1+38h, 200
mov tss1+54h, 40
mov tss1+48h, 32
;Инициализируем TSS2
mov tss2+4Ch, 48
mov tss2+20h, offset task2
mov tss2+50h, 24
mov tss2+38h, 400
mov tss2+54h, 48
mov tss2+48h, 32
;Загрузим IDTR
mov word ptr pdescr, idt_size-1
xor eax, eax
mov ax, offset idt
add eax, ebp
mov dword ptr pdescr+2, eax
lidt pdescr
;Переходим в защищенный режим
mov eax, CR0
or eax, 1
mov CR0, eax
;Теперь процессор работает в защищенном режиме
;Загружаем в cs:ip селектор:смещение точки continue
db 0EAh
dw offset continue
dw 16
continue:
;Делаем адресуемыми данные
mov ax, 8
mov ds, ax
;Делаем адресуемыми стек
mov ax, 24
mov ss, ax
;Инициализируем es
mov ax, 32
mov es, ax
;Загрузим регистр задачи TR селектором TSS главной задачи
mov ax, 56
ltr ax
;Выполним переключение задач
call dword ptr task1_offs
call dword ptr task2_offs
mov ax, 0FFFFh
home:
mov si, offset string
call wrd_asc
;Выведем на экран диагностическую строку
mov si, offset string
mov cx, len
mov ah, 74h
mov di, 1280
scrn1:
lodsb
stosw
loop scrn1
cli
;Вернемся в реальный режим
mov gdt_data.lim, 0FFFFh
mov gdt_code.lim, 0FFFFh
mov gdt_stack.lim, 0FFFFh
mov gdt_screen.lim, 0FFFFh
push ds
pop ds
push ss
pop ss
push es
pop es
db 0EAh
dw offset go
dw 16
;Переключим режим процессора
go:
mov eax, CR0
and eax, 0FFFFFFFEh
mov CR0, eax
db 0EAh
dw offset return
dw text
;Теперь процессор работает в реальном режиме
return:
;Восстановим вычислительную среду реального режима
mov ax, data
mov ds, ax
mov ax, stk
mov ss, ax
mov sp, 600
;Восстановим состояние регистра IDTR реального режима
mov ax, 3FFh
mov word ptr pdescr, ax
mov eax, 0
mov dword ptr pdescr+2, eax
lidt pdescr
sti
;Работаем в реальном режиме
mov ah, 4Ch
int 21h
main endp
;Размер сегмента команд
code_size=$-text
text ends
;Сегмент стека
stk segment stack use16
db 600 dup ('^')
stk ends
;Сегмент команд задачи 1
text1 segment use16
assume cs:text1
task1 proc
mov ah, 1Eh
mov si, offset msg1
mov di, 1600
mov cx, 20
c1:
lodsb
stosw
loop c1
=> iret
msg1 db 'Task1 is working....'
task1 endp
;Размер сегмента задачи 1
text1_size=$-task1
text1 ends
;Сегмент команд задачи 2
text2 segment use16
assume cs:text2
task2 proc
mov ah, 1Eh
mov si, offset msg2
mov di, 1630
mov cx, 20
c2:
lodsb
stosw
loop c2
iret
msg2 db 'Task2 is working....'
task2 endp
;Размер сегмента задачи 1
text2_size=$-task2
text2 ends
end main
вавр
Вобщем по-прежнему нужна помощь, а то уже спать хоцца :)
Если что еще вспомнишь, пиши....уже несколько дней убил.
А также посмотри что у тебя в регистре флагов (если не используешь вложенные задачи)
В документации написано, что по команде iret переключаться можно только на занятую задачу. Так что бит B должен быть установлен.
А почему собственно IRET ?
Вроде команда CALL не засовывала в стек флаги, а только селектор и смещение. А IRET пытается снять со стека и регистр флагов тоже.
Может надо использовать простой ret far (код 0CBh) ? Он флагов не снимает.
В документации написано, что по команде iret переключаться можно только на занятую задачу. Так что бит B должен быть установлен.
А ты попробуй.
Знаешь сколько я видел опечаток в документации - видимо не видимо.
Например в одних книгах свободнай TSS путают с шлюзом задачи - 1001 и 0101
А ты попробуй.
Знаешь сколько я видел опечаток в документации - видимо не видимо.
Например в одних книгах свободнай TSS путают с шлюзом задачи - 1001 и 0101
Дык, когда переключаешься на задачу, то задача помечается как занятая, и поэтому и возращаться только на занятую можно, и здесь нет никаких опечаток, а проблемма, как было заявлено, в следующей команде после iret, т.е в переключении на 2-ую задачу.
А вот в чём проблемма хм....
Дык, когда переключаешься на задачу, то задача помечается как занятая, и поэтому и возращаться только на занятую можно, и здесь нет никаких опечаток, а проблемма, как было заявлено, в следующей команде после iret, т.е в переключении на 2-ую задачу.
А вот в чём проблемма хм....
Нет, проблема в команде iret. Исключение вылетает в первой задаче именно на команде iret!
При переключении на TSS1 FS и GS = 0 и переключается без ошибок (видимо проверяется только выход за пределы GDT).
А при возврате в TSS0 ??? А там значение селекторов были сохранены в TSS при выполнении CALL. А откуда они были сохранены ??? Из регистров!!! А как они попали в регистры ??? GS и FS ты явно не загружаешь, значит там значения забитые операционной системой при загрузке программы. А что могла туда засунуть операционная система ??? @$#%$#@ !!!
Вобщем я просто загрузил FS и GS до первого CALL'а и стало работать.
При переключении проверяются все селекторы: SS, CS, DS, ES, FS и GS !!!
При переключении на TSS1 FS и GS = 0 и переключается без ошибок (видимо проверяется только выход за пределы GDT).
А при возврате в TSS0 ??? А там значение селекторов были сохранены в TSS при выполнении CALL. А откуда они были сохранены ??? Из регистров!!! А как они попали в регистры ??? GS и FS ты явно не загружаешь, значит там значения забитые операционной системой при загрузке программы. А что могла туда засунуть операционная система ??? @$#%$#@ !!!
Вобщем я просто загрузил FS и GS до первого CALL'а и стало работать.
Не мог бы ты выслать мне всю твою работающую программу на [email]Sega_444@freemail.ru[/email]. У меня даже после этого не хочет работать. Может быть ты еще чего правил? И ты запускал на эмуляторе или на настоящем железе?
При переключении проверяются все селекторы: SS, CS, DS, ES, FS и GS !!!
При переключении на TSS1 FS и GS = 0 и переключается без ошибок (видимо проверяется только выход за пределы GDT).
А при возврате в TSS0 ??? А там значение селекторов были сохранены в TSS при выполнении CALL. А откуда они были сохранены ??? Из регистров!!! А как они попали в регистры ??? GS и FS ты явно не загружаешь, значит там значения забитые операционной системой при загрузке программы. А что могла туда засунуть операционная система ??? @$#%$#@ !!!
Вобщем я просто загрузил FS и GS до первого CALL'а и стало работать.
Вобщем я запустил на чистом железе, заработало :) Наконец-то :)) ОСОБАЯ благодарность Sanya DLR :) При запуске на Microsoft Virtual PC опять выскакивает #GP на команде iret при выходе из первой задачи!!! Вобщем, в итоге, два бага: сегментные регистры и MICROSOFT Virtual PC :)) Люди, может посоветуете нормальный эмулятор :))
Bochs, VmWare
Bochs консольный - неинтересно :) Вобщем на WMWare все заработало.
;Делаем адресуемыми данные
mov ax, 8
mov ds, ax
;Делаем адресуемыми стек
mov ax, 24
mov ss, ax
;Инициализируем es
mov ax, 32
mov es, ax
mov fs,ax
mov gs,ax
на реальном pentium2