Консультация № 178301
09.05.2010, 14:26
42.70 руб.
10.05.2010, 14:51
0 3 0
Доброго времени суток! Задание на тему Виртуальный режим процессора 80386Средства для отладки - tasm и tlink.
Модифицировать программу, приведенную в электронном приложении. Само задание: Эмулировать на экран передачу данных через последовательный порт COM1, запретив вывод через соответствующие порты в БКВВ. Воспользоваться функциями прерываний BIOS и DOS

Приложение:
; Монитор виртуального режима V86
; Ниже приведен полный текст монитора V86, запуск которого
;под MS-DOS в реальном режиме приведет к появлению на экране
;подсказки MS-DOS в той форме в которой она задана в файле AUTO-
;EXEC.BAT. В ответ на эту подсказку можно вводить программы ре-
;ального режима, написанные для процессоров i8086/i8088, и они
;будут выполнятся с той же скоростью что и в реальном режиме
;i80386.
; Код программы делится на две части: код инициализации и код
;монитора V86. Код инициализации осуществляет переход в защищен-
;ный режим, подготавливает необходимый кадр стека и с помощью
;команды IRETD переводит процессор из защищенного в виртуальный
;режим.При этом управление передается на метку vmstart. После
;чего средствами DOS выдается сообщение, что монитор установлен и
;программа заканчивает работу оставляя код монитора резидентно в
;памяти.
; Код монитора V86 в основном состоит из обработчиков преры-
;ваний и особых случаев, возникновение которых связано с работа-
;ющей под его управлением программой виртуального режима V86.
; Прерывания и особые случаи обрабатываются монитором V86 в
;зависимости от типа по следующей схеме:
; а) особые ситуации виртуального режима 0,1,2
; <шлюз в IDT> --> <fejmp> --> <intvm>
; б) особые ситуации 13 виртуального режима
; <шлюз в IDT> --> <fault13> --> <emulateint>
; в) аппаратные прерывания виртуального режима
; <шлюз в IDT> --> <hijmp> --> <intvm>
; Обработчики программных прерываний почти идентичны. Оба оп-
;ределяют какое прерывание могло быть выдано программе V86 и пе-
;редают его номер процедуре emulateint.
; Обработчик особой ситуации общей защиты fault13 проделывает
;небольшую трансляцию, прежде чем эмулирует программное прерыва-
;ние. Он сначала должен обратится к памяти пользователя с приме-
;нением дескриптора защищенного режима чтобы определить какая
;команда INT n, была использована. Это сделано с помощью деск-
;риптора AllMem_desc, определенного таким образом, чтобы он имел
;доступ ко всему 4-гигабайтноиу адресному пространству с помощью
;32-битных смещений,. Кодовый сегмент V86 и указатель команд,
;сохраненные в стеке, комбинируются с помощью метода ba-
;se*16+offset для порождения 32- битного адреса. Это смещение
;указывает на инструкцию, вызвавшую особую ситуацию. Производит-
;ся проверка, действительно ли это - команда INT n. Если так, то
;номер вектора извлекается из памяти и эмулируется прерывание.
; Обработчики особых ситуаций просто соотносят аппаратное
;прерывание со стандартным вектором DOS.
; Другие ошибки и особые ситуации используют intvm, чтобы
;послать прерывание к обработчику прерываний V86. Прерывания ,
;которые не могут быть обработаны таким способом. передаются
;процедуре fail, которая выводит на экран следующую информацию:
; Адрес
; команды es ds edi esi
;Fault/Exeption 13 @0048:0057 0000:0000:0060:0000:0000:0000:
;
; ebp esp ebx edx ecx Fault
;091C:0000:0212:0000: 008E:0500:0101:0000:0001:0000:800D:0000:
;
; eax eip cs eflags стек
;0106:0000:057:0000:0048:0000:3002:0001: 063E:0000:0081:0000:
;
;0008:0000:1AB2:0000:02C1:0000:7246:0002:0914:0000

MASM ; (1) Режим Турбо-ассемблера = MASM
.386P ; (2) Разрешение трансляции всех, в том
; числе привилегированных команд МП 386
; и 486
; Структура для описания дескрипторов сегментов
DESCRIPTOR STRUC ; (3)
seg_limit dw 0 ; (4) длина сегмента
base_lo_word dw 0 ; (5) физ. адрес (биты 0..15)
base_hi_byte db 0 ; (6) физ. адрес (биты 16..23)
acces_rights db 0 ; (7) байт прав доступа
db 0 ; (8) зарезервировано для 80386
base_top_byte db 0 ; (9)
DESCRIPTOR ENDS ; (10)

; Структура для описания дескрипторов прерываний
IDT_DESCRIPTOR STRUC ; (11)
int_offset dw 0 ; (12) точка входа в проц. обраб. прерывания
int_selector dw 0 ; (13) селектор дескриптора в GDT
db 0 ; (14)
int_ss db 0 ; (15) вид обработчика прерывания
dw 0 ; (16)
IDT_DESCRIPTOR ENDS ; (17)
; Константы, используемые в данной программе
inta00 equ 020h ; (18) Порты
inta01 equ 021h ; (19) контроллера 8259 #1 (ведущего)
intb00 equ 0A0h ; (20) Порты
intb01 equ 0A1h ; (21) контроллера 8259 #2 (ведомого)

status_port equ 064h ; (22) порт сотстояния 8042
key_port_a equ 060h ; (23) порты клавиатуры
key_port_b equ 061h ; (24)
cmos_port equ 070h ; (25) порт доступа к CMOS памяти
code_seg_access equ 10011010b ; (26) байт права доступа для
; сегмента кода
data_seg_access equ 10010011b ; (27) байт права доступа для
; сегмента данных
task_seg_state equ 10001001b ; (28) байт прав доступа для
; свободного TSS 386
ldt_seg_access equ 10000010b ; (29) байт прав доступа для LDT
task_gate equ 10000101b ; (30) шлюз задачи
trap_gate equ 10001111b ; (31) шлюз спец. прерывания
interrupt_gate equ 10001110b ; (32) шлюз прерывания
disable_bit20 equ 11011101b ; (33) код 8042 для закрывания A20
enable_bit20 equ 11011111b ; (34) код 8042 для открывания A20
shut_cmd equ 0FEh ; (35) команда 8042 отключения
; компьютера
;*********************************************************
;* макрокоманда межсегментного перехода *
;* Jump_Offset - смещение *
;* Jump_Segment - сегмент *
;*********************************************************
JUMPFAR MACRO jumpfar1,jumpfar2 ; (36)
db 0eah ; (37) Код ком. дал. перехода
dw (offset jumpfar1) ; (38)
dw jumpfar2 ; (39)
ENDM ; (40)
;********************************************************
;* макрокоманда заполнения дескриптора *
;* Seg_Addr - сегмент *
;* Offset_Addr - смещение *
;* Descr - дескриптор *
;********************************************************
FILLDESCR MACRO seg_addr,offset_addr,descr ; (41)
xor edx,edx ; (42) Очистка регистров
xor ecx,ecx ; (43) edx и ecx
mov dx,seg_addr ; (44) dx содержит номер
; сегмента
mov cx,offset offset_addr ; (45) cx содержит
; внутрисегментное смещение
call form_24bit_address ; (46) Вызов процедуры формиров.
; 24-бит. адреса
mov &descr.base_lo_word,dx ; (47) Заполнение адресных
mov &descr.base_hi_byte,cl ; (48) полей дескриптора
xor edx,edx ; (49) Очистка регистров
xor ecx,ecx ; (50) edx и ecx
ENDM ; (51)

;********************************************************
;* макрокоманда подготовки к сбросу процессора *
;********************************************************
READY_FOR_RESET MACRO ; (52)
mov dx,bios_data_seg ; (53) Настроим fs на область
mov fs,dx ; (54) данных BIOS
mov fs:[io_rom_seg],cs ; (55) Сегмент точки возврата
mov fs:[io_rom_init],offset real ; (56) Смещение точки возврата
; в реальный режим
mov al,08fh ; (57) Подготовка к
out cmos_port,al ; (58) сбросу процессора
jmp short $+2 ; (59)
mov al,5 ; (60)
out cmos_port+1,al ; (61)
ENDM ; (62)

;********************************************************
;* макрокоманда сброса процессора *
;********************************************************
RESET MACRO ; (63)
mov al,shut_cmd ; (64) Команда отключения
out status_port,al ; (65) Возврат в реальный режим
m_40: hlt ; (66) Останов процессора до
jmp short m_40 ; (67) окончания сброса
ENDM

BIOS_DATA_SEG SEGMENT USE16 AT 0040h ; (68) Сегмент(область) данных
ORG 0067h ; (69) BIOS-используется для сброса процессора
io_rom_init dw ? ; (70) Смещение точки возврата
io_rom_seg dw ? ; (71) Сегмент точки возврата в реал. режим
BIOS_DATA_SEG ENDS ; (72) после сброса процессора

CSEG SEGMENT USE16 PARA PUBLIC 'CODE' ; (73) Сегмент данной
ASSUME CS:CSEG ; (74) .COM - программы
ORG 100h ; (75) Резервирование места под PSP
START: jmp MAIN ; (76) Переход на секцию инициализации

EVEN ; (77) Выравнивание счетчика размещения на
; ближайший четный адрес
;-----------------------------------------------------------------
; Таблица глобальных дескрипторов GDT
;-----------------------------------------------------------------
GDT LABEL WORD ; (78) GDT=адрес(смещение) структуры GDT0
NULL_DESC EQU 0 ; (79) NULL_DESC=0
GDT0 descriptor<> ; (80) Нулевой дескриптор
;*************************************************************
;* описание GDT как сегмента данных
;*************************************************************
GDT_DESC EQU (($-gdt)/8)*8+0000000000000000b ; (81) GDT_DESC=0008h
GDT1 descriptor <gdt_leng-1,,,data_seg_access,> ; (82)
;*************************************************************
;* дескриптор описывающий CSEG как сегмент кода
;*************************************************************
CS_CODE EQU (($-gdt)/8)*8+0000000000000000b ; (83) CS_CODE=0010h
GDT2 descriptor<cseg_leng,,,code_seg_access,> ; (84)
;*************************************************************
;* дескриптор описывающий CSEG как сегмент данных
;*************************************************************
CS_DATA EQU (($-gdt)/8)*8+0000000000000000b ; (83) CS_DATA=0018h
GDT3 descriptor<cseg_leng,,,data_seg_access,> ; (86)
;*************************************************************
;* дескриптор описывающий CSEG как сегмент данных
;*************************************************************
SS_DSEG EQU (($-gdt)/8)*8+0000000000000000b ; (87) SS_DSEG=0020h
GDT4 descriptor<0fffeh,,,data_seg_access,> ; (88)
;*************************************************************
;* дескриптор описывающий IDT как сегмент данных
;*************************************************************
IDT_POINTER descriptor<idt_leng-1,,,data_seg_access> ; (89) у IDT_POINTER
; селектор=0028h=40d
;*************************************************************
;* дескриптор описывающий видеопамять как сегмент данных
;*************************************************************
VIDEO_DESC EQU (($-gdt)/8)*8+0000000000000000b ; (90) VIDEO_DESC=0030h
GDT5 descriptor<8000h,8000h,0bh,data_seg_access> ; (91)
;*************************************************************
;* дескриптор описывающий сегмент данных монитора V86
;*************************************************************
V86_DATA EQU (($-gdt)/8)*8+0000000000000000b ; (92) V86_DATA=0038h
GDT6 descriptor<end_rezident,,,data_seg_access> ; (93)
;*************************************************************
;* дескриптор описывающий сегмент кода монитора V86
;*************************************************************
V86_DESC EQU (($-gdt)/8)*8+0000000000000000b ; (94) V86_DESC=0040h
GDT7 descriptor<end_rezident,,,code_seg_access> ; (95)
;*************************************************************
;* дескриптор TSS монитора V86
;*************************************************************
V86_SEL EQU (($-gdt)/8)*8+0000000000000000b ; (96) V86_SEL=0048h
GDT8 descriptor<V86TSS_len-1,,,task_seg_state> ; (97)
;*************************************************************
;* дескриптор описывающий всю память PC
;*************************************************************
AllMem_desc EQU (($-gdt)/8)*8+0000000000000000b ; (98) AllMem_desc=0050h
GDT9 descriptor<0ffffh,,,data_seg_access,80h>; (99) g=1
GDT_LENG EQU $ - GDT ; (100) Длина таблицы GDT = GDT_LENG=0058h

EVEN ; (101) Выравнивание счетчика размещения на
; ближайший четный адрес
;------------------------------------------------------------------------
; Таблица дескрипторов прерываний (исключений) IDT

; С помощью блоков повторения создаются дескрипторы прерываний,
; которые адресуют точки программы, помеченные метками fault00..fault14,
; fault??,fault16,inthw00..inthw09,inthw0a..inthw0f.
; Т.о. при возникновении прерываний (исключений) управление будет
; передаваться на вышеуказанные точки программы
;------------------------------------------------------------------------
IDT LABEL WORD ; (102) IDT=015Ch
;......................................................
IRP z,<00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,??,16> ; (103)
idt_descriptor<offset fault&z,v86_desc,,interrupt_gate>; (104)
ENDM ; (105)
;......................................................
IRP z,<??,??,??,??,??,??,??,??,??,??,??,??,??,??,??> ; (106)
idt_descriptor<offset fault&z,v86_desc,,interrupt_gate> ; (107)
ENDM ; (108)
;......................................................
IRP z,<00,01,02,03,04,05,06,07,08,09,0a,0b,0c,0d,0e,0f> ; (109)
idt_descriptor<offset inthw&z,v86_desc,,interrupt_gate> ; (110)
ENDM ; (111)


;......................................................
IDT_LENG EQU $-IDT ; (112) Длина таблицы IDT

CS_SEG dw ? ; (113) Ячейка для хранения адреса сегмента кода
i8259_1 DB ? ; (114) Ячейки для хранения исходного состояния
i8259_2 DB ? ; (115) ведущего и ведомого контроллеров прерываний
gate_failure db "Address line A20 failed to Gate open$" ; (116) Сообщения,
SUCCESS db 'Virtual Mashine 8086 is established' ; (117) используемые
db '!!!!!! ',36,10,13 ; (118) в
Fault13_mes db 'Данная строка напечатана из обработчика исключения #13',36,10,13,0 ; (119)
crush db 'Произошел сброс - монитор НЕ активен !!!',0 ; (120) программе


Tss_Stencil386 STRUC ; (121) Шаблон сегмента TSS i386
LINK Dw 0 ; (122) селектор возврата
Dw 0 ; (123)
ESP0 Dd 0 ; (124) значение ESP для стека
; уровня 0
SS0 Dw 0 ; (125) значение SS для стека
Dw 0 ; (126) уровня 0
ESP1 Dd 0 ; (127) значение ESP для стека
; уровня 1
SS1 Dw 0 ; (128) значение SS для стека
Dw 0 ; (129) уровня 1
ESP2 Dd 0 ; (130) значение ESP для стека
; уровня 2
SS2 Dw 0 ; (131) значение SS для стека
Dw 0 ; (132) уровня 2
CR3_ Dd 0 ; (133) значение регистра CR3
EIP_ Dw 0 ; (134) значение регистра EIP
Dw 0 ; (135)
EFLAGS Dd 0 ; (136) значение регистра EFLAGS
EAX_ Dd 0 ; (137) значение регистра EAX
ECX_ Dd 0 ; (138) значение регистра ECX
EDX_ Dd 0 ; (139) значение регистра EDX
EBX_ Dd 0 ; (140) значение регистра EBX
ESP_ Dd 0 ; (141) значение регистра ESP
EBP_ Dd 0 ; (142) значение регистра EBP
ESI_ Dd 0 ; (143) значение регистра ESI
EDI_ Dd 0 ; (144) значение регистра EDI
ES_ Dw 0 ; (145) значение регистра ES
Dw 0 ; (146)
CS_ Dw 0 ; (147) значение регистра CS
Dw 0 ; (148)
SS_ Dw 0 ; (149) значение регистра SS
Dw 0 ; (150)
DS_ Dw 0 ; (151) значение регистра DS
Dw 0 ; (152)
FS_ Dw 0 ; (153) значение регистра FS
Dw 0 ; (154)
GS_ Dw 0 ; (155) значение регистра GS
Dw 0 ; (156)
LDTR_ Dw 0 ; (157) значение регистра LDTR
Dw 0 ; (158)
Dw 0 ; (159) бит 0 - бит ловушки Т
BaseMapIO Dw 104 ; (160) относительный адрес БКВВ
Tss_Stencil386 ENDS ; (161)

DW 512 DUP (?) ; (162) стек для кода уровня 0
stack0 LABEL WORD ; (163) Для настройки sp (уровня 0)
DW 512 DUP(?) ; (164) Стек для монитора V86
DOS_STACK LABEL WORD ; (165) Для настройки sp монитора V86
V86TSS TSS_stencil386<> ; (166) TSS для задачи V86

;i_redirect_map db 32 dup(0) ; (167) Битовая карта перенаправления прерываний
; (используется для процессоров Pentium)

; db 2 dup(0) ; Другой вариант битовой карты перенаправления
; db 01h ; прерываний, в которой бит, соответствующий
; db 0 ; прерыванию N16 (16d=10h=прерывание BIOS)
; db 28 dup(0) ; установлен в 1

iomap db 8192 dup(0) ; (168) Карта ввода-вывода
ioend dw 0FFFFh ; (169) Завершающий код карты ввода-вывода
; db 256 dup(0) ; Карту ввода-вывода можно было
; dd -1 ; описать и так
V86TSS_len equ $-OFFSET V86TSS

cursor LABEL WORD ; (170) Курсор для экрана
cury DB 10 ; (171) столбец
curx DB 10 ; (172) строка
fault DB 'Fault/Exception# ',0 ; (173) Заголовок сообщения об
; ошибке
buffer DB 10 DUP (?) ; (174) Буфер для отображаемого числа

hex_xlt DB '0','1','2','3','4','5','6','7','8','9' ; (175) Таблица
DB 'A','B','C','D','E','F' ; (176) трансляции
stepflag DW 0 ; (177) флаг пошагового режима
rezident_size DW end_rezident ; (178) Ячейка для хранения размера
; резидентной части программы
;--------------------------------------------------------------
datseg DW V86_data ; (179) Ячейка для хранения сегментного
; адреса сегмента данных
crtseg DW video_desc ; (180) ... сегмента видеопамяти
pcseg DW AllMem_desc ; (181) ... сегмента, описывающего
; все адресное пространство PC
;--------------------------------------------------------------
;EQUATES для emulateint, fault13 и intvm
Zgs EQU [bp+40] ; (182) V86 gs из шлюза прерывания
Zfs EQU [bp+36] ; (183) fs
Zds EQU [bp+32] ; (184) ds
Zes EQU [bp+28] ; (185) es
Zss EQU [bp+24] ; (186) ss
Zsp EQU [bp+20] ; (187) sp
Zflags EQU [bp+16] ; (188) flags
Zcs EQU [bp+12] ; (189) cs
Zip EQU [bp+8] ; (190) ip
Zdword EQU [bp+4] ; (191) код ошибки для fault 13 или
; (192) вектор для intvm
Zebp EQU [bp] ; (193) сохраненный ebp в стеке
Zeax EQU [bp-4] ; (194) eax
Zfs EQU [bp-8] ; (195) ebx
;--------------------------------------------------------------

;Макро для обработчиков ошибок, особых ситуаций и прерываний.
fejmp macro lbl,nptr,jump ; (196)
fault&lbl: ; (197) Формирование метки
; через макроподстановку
push dword ptr nptr ; (198) Сохранение в стеке ур.0 номера
; исключения
jmp jump ; (199) Переход в заданную точку
endm ; (200) программы
;Макро для аппаратных прерываний
hijmp macro lbl,nptr,jump ; (201)
inthw&lbl: ; (202) Формирование метки
; через макроподстановку
push dword ptr nptr ; (203) Сохранение в стеке ур.0 номера
; требуемого прерывания DOS
jmp jump ; (204) Переход в заданную точку
endm ; (205) программы

ASSUME DS:V86_DATA,ES:V86_DATA ; (206)
; emulateint() эмулирует прерывания, подставляя в стек значение вектора
; из таблицы прерываний DOS и выполняя затем команду iretd. Вход: стек -
; Int_gate,dword,ebp,eax,ebx. ebx = вектор.
emulateint: ; (207)
sub eax,eax ; (208)
mov ebx,fs:[ebx*4+eax] ; (209) получаем вектор DOS
mov ax,bx ; (210) помещаем смещение в AX
shr ebx,16 ; (211) вычисляем сегмент
xchg bx,[Zcs] ; (212) извлекаем текущий сегмент
; (213) сохраняем новый сегмент
xchg ax,[Zip] ; (214) извлекаем текущее смещение
; (215) сохраняем новое смещение
shl ebx,16 ; (216)
mov bx,ax ; (217) ebx = сегмент:смещение
sub word ptr [Zsp],6 ; (218) готовим пространство в стеке
mov ax,[Zss] ; (219) сегмент стека (старшие биты
; eax уже 0)
shl eax,4 ; (220) пересчет из параграфов
add eax,[Zsp] ; (221) указатель стека
mov fs:[eax],ebx ; (222) сегмент:смещение
mov bx,[Zflags] ; (223) получаем текущее значение flags

mov fs:[eax+4],bx ; (224) сохраняем в стеке.Сброс TF,RF,IF
and dword ptr [Zflags], NOT((1 SHL 8)OR(1 SHL 9)OR(1 SHL 16))
mov bx,v86_data ; (225)
mov fs,bx ; (226) Восстановление
pop ebx ; (227) использовавшихся
pop eax ; (228) регистров
pop ebp ; (229)
add esp,4 ; (230) убираем код ошибки или вектор
btr fs:[stepflag],0 ; (231) нужен пошаговый режим?
; через fault13
jc fault01 ; (232) ДА ВЫПОЛНИТЬ ЭТО ТОЛЬКО СО
; СТЕКОМ int_gate
iretd ; (233)
;--------------------------------------------------------------
;intvm обрабатывает int для использования. Сначала проверка на
;РМ(ошибки 0..4)
;Вход: переход int_gate с номером вектора в стеке
;Кадр стека: Intgate,dword,ebp,eax,ebx
intvm: test BYTE PTR [esp+12+2],1 SHL 1 ; (234) Проверка flags: пришли из VM?
jz fail ; (235) мы в PM(ошибки 0..4)
; В данной точке программы (после возникновения аппарат. прерывания)
; регистр esp(уровня 0) указывает на номер вектора
; прерывания(Intgate) в стеке ур.0
push ebp ; (236) для использования здесь
mov ebp,esp ; (237) ebp -> на сохр. ebp
push eax ; (238) esp -> на сохр. eax
push ebx ; (239) esp -> на сохр. ebx
mov ebx,[Zdword] ; (240) берем номер вектора из стека
mov fs,[pcseg] ; (241) адресное пространство pc
jmp emulateint ; (242) к эмулятору прерываний

;-------------------------------------------------------------
;fault13-обработчик общей ошибки защиты для виртуального режима
; V86
fault13: ; (243)

; push ecx ; Организация задержки, подтверждающей,
; mov ecx,0FFFF00h ; что мы находимся в обрабочике
; ll: db 67h ; исключения N13
; loop ll
; pop ecx

test BYTE PTR [esp+12+2],2 ; (244) проверка-VM или нет
jz faultgp ; (245) общая ошибка защиты в РМ
; В данной точке программы (после возникновения исключения N13 - например,)
; после выполнения команды int n ) регистр esp(уровня 0) указывает
; на код ошибки в стеке ур.0
push ebp ; (246) для использования здесь
mov ebp,esp ; (247) ebp -> на сохр. ebp
push eax ; (248) esp -> на сохр. eax
push ebx ; (249) esp -> на сохр. ebx
mov fs,[pcseg] ; (250) адресное пространство рс
movzx eax,word ptr [Zcs] ; (251) рабочее значение cs
shl eax,4 ; (252) base*16
add eax,[Zip] ; (253) + offset
movzx ebx,word ptr fs:[eax] ; (254) извлекаем команду(2 байта)
cmp bl,0cdh ; (255) Код команды int_n?
jnz other ; (256) Нет -> переход на метку other
shr ebx,8 ; (257) Да, удаляем 0cdh
; (258) помещаем вектор в bl
add word ptr [Zip],2 ; (259) пропускаем команду int_n -> управление
; передается на команду, следующую за int_n
btr word ptr [Zflags],8 ; (260) сбрасываем TF
push ds ; (261) Сохрание ds
push v86_data ; (262)
pop ds ; (263) ds:=v86_data

setc byte ptr ds:[stepflag] ; (264) если TF был установлен, то нам
; нужен пошаговый режим -> установка
; флага пошагового режима
pop ds ; (265) Восстановление ds
jmp emulateint ; (266) Переход на emulateint
; ( эмуляция int_n )
;--------------------------------------------------------------
;$other может обрабатывать команды int3/int0/out/in...
; Сейчас только генерирует общую ошибку защиты
;--------------------------------------------------------------
other: ; (267)
pop ebx ; (268) Восстановление
pop eax ; (269) сохраненных
pop ebp ; (270) регистров
jmp faultgp ; (271) Переход на faultgp
; (общая ошибка защиты)


;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; Далее создаются фрагменты программы (с помощью макросов), на которые
; при возникновении прерываний будет передаваться управление (при помощи
; дескрипторной таблицы прерываний IDT)

;--------------------------------------------------------------
;обработка ошибок отличных от GP13
;Т. к. ошибки 00..02 поддерживаются BIOS, то они
;и перенаправляются на обработку в BIOS (см. метку intvm)
;int 3 и int4 перенаправляются fault13, который
;генерирует информацию об ошибке с помощью fail
;--------------------------------------------------------------

fejmp 00,0,intvm ; (272) ошибка деления
fejmp 01,1,intvm ; (273) особая ситуация отладки
fejmp 02,2,intvm ; (274) NMI
fejmp 03,3,fail ; (275) точка прерывания
fejmp 04,4,fail ; (276) прерывание по переполнению
fejmp 05,5,fail ; (277) выход за границу массива
fejmp 06,6,fail ; (278) недопустимый код команды
fejmp 07,7,fail ; (279) сопроцессор отсутствует
fejmp 08,8,fail ; (280) двойная ошибка
fejmp 09,9,fail ; (281) выход сопроцессора за предел
; сегмента
fejmp 10,10,failec ; (282) неверный TSS
fejmp 11,11,failec ; (283) сегмент отсутствует в памяти
fejmp 12,12,failec ; (284) ошибка стека
fejmp gp,13,failec ; (285) общая ошибка защи

Обсуждение

давно
Посетитель
7438
7205
10.05.2010, 12:22
общий
ItGirl:
В какой кодировке Ваш текст?
Если не получается сделать нормальный текст, то лучше сархивируйте и загрузите в Мои файлы. Дайте ссылку.
Разберемся...
А от, чего-то не сильно хочется ковыряться в Вашем коде без коментариев...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
10.05.2010, 14:54
общий
ItGirl:
Кодировку-то я подправил, только вот вопрос: код оборван, не до конца приведен.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
10.05.2010, 16:08
общий
Прошу прощения, видимо, количество строк недопустимое ) Вот окончание
fejmp gp,13,failec ; (285) общая ошибка защиты
fejmp 14,14,failec ; (286) страничная ошибка
fejmp 16,16,fail ; (287) ошибка сопроцессора
fejmp ??,32,fail ; (288) неизвестная особая ситуация

;--------------------------------------------------------------
;Аппратные прерывания
;ПРЕРЫВАНИЯ :
hijmp 00,08h,intvm ; (289) от таймера
hijmp 01,09h,intvm ; (290) от клавиатуры
hijmp 02,0ah,intvm ; (291) от подчиненного контроллера
hijmp 03,0bh,intvm ; (292) от порта сом1
hijmp 04,0ch,intvm ; (293) от порта сом2
hijmp 05,0dh,intvm ; (294) от порта lpt2
hijmp 06,0eh,intvm ; (295) от флоппи-диска
hijmp 07,0fh,intvm ; (296) от порта lpt1
hijmp 08,70h,intvm ; (297) от rtc
hijmp 09,71h,intvm ; (298) от преренаправленного irq2
hijmp 0a,72h,intvm ; (299) дополнительное прерывание
hijmp 0b,73h,intvm ; (300) дополнительное прерывание
hijmp 0c,74h,intvm ; (301) дополнительное прерывание
hijmp 0d,75h,intvm ; (302) от сопроцессора
hijmp 0e,76h,intvm ; (303) от жесткого диска
hijmp 0f,77h,intvm ; (304) дополнительное прерывание
;--------------------------------------------------------------
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!





; ********** ФОРМИРОВАНИЕ СООБЩЕНИЯ О НАРУШЕНИИ ОБЩЕЙ ЗАЩИТЫ *************
; Адрес
; команды es ds edi esi
;Fault/Exeption 13 @0048:0057 0000:0000:0060:0000:0000:0000:
;
; ebp esp ebx edx ecx Fault
;091C:0000:0212:0000: 008E:0500:0101:0000:0001:0000:800D:0000:
;
; eax eip cs eflags стек ур.0 (до регистра eflags)
;0106:0000:057:0000:0048:0000:3002:0001: 063E:0000:0081:0000:
;
;0008:0000:1AB2:0000:02C1:0000:7246:0002:0914:0000

failec: ; (305)
; В данной точке программы esp -> на номер особ. ситуации, сохр.
; в стеке ур.0 (см. макросы fejmp и hijmp), поэтому esp+4 -> код ошибки

xchg [esp+4],eax ; (306) Теперь в eax - код ошибки, а
; в [esp+4] - сохраняется eax
shl eax,16 ; (307)
or ax,word ptr [esp] ; (308) OR с номером особой ситуации
xchg [esp+4],eax ; (309) Теперь в eax - прежнее значение eax, а
; в [esp+4] - номер вектора особ. ситуации
; + код ошибки
add esp,4 ; (310) Исключаем старый #особой ситуации,
; теперь esp -> #особ. ситуации + код ошибки

fail: ; (311)
xchg [esp],eax ; (312) Окончательно: esp -> eax, а #особ.
; ситуации + код ошибки лежит в eax
pushad ; (313) Сохр. всех РОН (в eax лежит #особ.
; ситуации + код ошибки)
push ds ; (314) Сохр. ds для вывода в сообщении
push es ; (315) Сохр. es для вывода в сообщении
mov ebp,esp ; (316)
mov ds,[datseg] ; (317)
mov es,[datseg] ; (318)
mov si,OFFSET fault ; (319) сообщение об ошибке
push eax ; (320)
push ax ; (321)
call showmsg ; (322) вывести заголовок
pop ax ; (323) В ax - номер исключения
aam ; (324) преобразуем al в
; десятичную форму
add ax,('0'SHL 8)+'0' ; (325) в ascii
xchg al,ah ; (326)
call SHOWCHAR ; (327) Вывод старшей цифры
xchg al,ah ; (328)
call showchar ; (329) Вывод младшей цифры
mov al,'' ; (330)
call showchar ; (331)
pop eax ; (332)
test ax,1 SHL 15 ; (333) есть код ошибки?
jz F1 ; (334)
mov al,'(' ; (335) Вывод
call showchar ; (336) кода
shr eax,16 ; (337) ошибки
call showwordh ; (338)
mov al,')' ; (339)
call showchar ; (340)
mov al,'' ; (341)
call showchar ; (342)
F1: mov al,'@' ; (343) Нет кода ошибки
call showchar ; (344)
mov ax,[bp+44] ; (345) cs для вывода
call showwordh ; (346)
mov al,':' ; (347)
call showchar ; (348)
mov ax,[bp+40] ; (349) ip для вывода
call showwordh ; (350)
mov al,'' ; (351)
call showchar ; (352)
mov cx,40 ; (353) показать последние
; 40слов памяти
mov si,bp ; (354) вершина стека
B1: lodsw ; (355)
call showwordh ; (356)
mov al,':' ; (357)
call showchar ; (358)
loop B1 ; (359)
RESET ; (360) СБРОС ПРОЦЕССОРА !

;****************************************************************


;--------------------------------------------------------------
; покаэывает слово в 16-ричном формате
;--------------------------------------------------------------
showwordh: ; (361)
push si ; (362)
mov dx,ax ; (363)
mov DI,offset buffer ; (364) указать на буфер
mov si,di ; (365)
mov bx,offset hex_xlt ; (366) указать на таблицу
; трансляции
call wordh ; (367) помещаем слово в буфер
mov byte ptr es:[di],0 ; (368) закончить строку
call showmsg ; (369) вывести ее
pop si ; (370)
ret ; (371)
wordh: mov al,dh ; (372) сначала старший байт
call byteh ; (373)
mov al,dl ; (374) младший
byteh: push ax ; (375)
shr al,4 ; (376)
xlat ; (377) переводим в ASCII
stosb ; (378)
pop ax ; (379)
and al,0fh ; (380)
xlat ; (381) переводим в ASCII
stosb ; (382)
ret ; (383)
;--------------------------------------------------------------
; отображает символ
showchar: push ax ; (384)
push es ; (385)
call getpos ; (386) получить позицию курсора в ES:DI
mov ah,7 ; (387) атрибут
stosw ; (388)
call setpos ; (389) установить новую позицию
pop es ; (390)
pop ax ; (391)
ret ; (392)

;--------------------------------------------------------------
;выводит сообщение в текущей позиции курсора
showmsg: push es ; (393)
call getpos ; (394) получить позицию курсора
mov ah,7 ; (395) атрибут
jmp short shst ; (396)
B2: stosw ; (397)
shst: lodsb ; (398) вывод ASCIIZ строки
or al,al ; (399)
jnz B2 ; (400)
call setpos ; (401) если конец то
; установить новую позицию
pop es ; (402) курсора
ret ; (403)

;**************************************************************
;x,y->es:di
;--------------------------------------------------------------
getpos: push ax ; (404)
mov es,[crtseg] ; (405)
mov al,[cury] ; (406) Y курсора
mov ah,80*2 ; (407) байт/строку
mul ah ; (408)ax начало строки
mov di,ax ; (409)
movzx ax,[curx] ; (410) X курсора
shl ax,1 ; (411) умножить на 2
add di,ax ; (412) в DI смещение
pop ax ; (413)
ret ; (414)

;--------------------------------------------------------------
; устанавливает курсор по ES:DI
setpos:
push cx ds ; (415)
shr di,1 ; (416) к символам
mov ax,di ; (417)
mov cl,80 ; (418) символов/строку
div cl ; (419)
push v86_data ; (420)
pop ds ; (421)
mov ds:[cursor],ax ; (422) сохраняем курсор
pop ds cx ; (423)
ret ; (424)


;**************************************************************
;****** сюда происходит передача управления после сброса ******
real: mov dx,cs ; (425) восстановление
mov ds,dx ; (426) сементных адресов
mov ss,dx ; (427) рельного режима
mov al,i8259_1 ; (428) восстановление состояния
out inta01,al ; (429) контроллеров прерываний
mov al,i8259_2 ; (430)
out intb01,al ; (431)
sti ; (432) разрешение прерываний
mov ah,9 ; (433) Вывод сообщения о нарушении
mov dx,offset crush ; (434) работы
INT 21h ; (435) монитора
int 20h ; (436) Завершение работы программы
END_REZIDENT equ $ ; (437) Конец резидентной части программы

MAIN PROC ; (438) Главная процедура (секция
; инициализации), на которую передается
; управление в начале работы программы
assume ds:cseg ; (439)
mov ax,cs ; (440) запоминание адреса
mov [cs_seg],ax ; (441) сегмента кода
call set_protect ; (442) процедура перехода в
; (443) защищенный режим
mov ax,offset stack0 ; (444) настройка стека
mov sp,ax ; (445) для монитора V86
mov ax,v86_data ; (446)
mov ss,ax ; (447)
mov dx,V86_sel ; (448) загрузка селектора
ltr dx ; (449) задач
xor eax,eax ; (450) таблицы LDT нет
lldt ax ; (451)

;** подготовка кадра стека для перехода в виртуальный режим **
movzx eax,[cs_seg] ; (452) адрес сегмента CSEG
push eax ; (453) gs
push eax ; (454) fs
push eax ; (455) ds
push eax ; (456) es
push eax ; (457) ss
xor ebx,ebx ; (458)
mov bx,offset dos_stack ; (459)
push ebx ; (460) sp
push dword ptr 23000h ; (461) vm=1,iopl=3
; push dword ptr 22000h ; vm=1,iopl=2
push eax ; (462) cs
xor eax,eax ; (463)
mov ax,offset vmstart ; (464)
push eax ; (465) eip
clts ; (466) Очистка флага TS
push dword ptr 0 ; (467)
popfd ; (468)

; mov eax,cr4 ; Установка флага VME в 1 для включения
; or eax,1 ; расширенных возможностей процессора Pentium
; mov cr4,eax ; по обработке виртуальных прерываний

; *********** переход в виртуальный режим *************

iretd ; (469)

assume cs:cseg ; (470)
; ** сюда передается управление после перехода в режим V86 ****
vmstart: xor al,al ; (471) разрешение прерываний
out 21h,al ; (472)
out 0a1h,al ; (473)
sti ; (474)
mov ah,9 ; (475)
mov dx,offset SUCCESS ; (476) выдача сообщения об
int 21h ; (477) установке монитора V86

; Выведем на экран символ средствами BIOS
mov AH,0Eh ; (478) Функция вывода символа
mov AL,0Fh ; (479) Код символа
int 10h ; (480) Прерывание BIOS

mov dx,[rezident_size] ; (481) закончить работу и оставить
inc dx ; (482) монитор резидентным
int 27h ; (483)

MAIN ENDP ; (484)


;--------------------------------------------------------------
;Управление прохождением сигнала A20
; ВХОД: (AH)=0DDH A20 всегда равен 0
; (AH)=0DFh адресный разряд A20 открыт
; ВЫХОД: (AL)=0 8042 принял команду
; (AH)=2 сбой
;--------------------------------------------------------------
gate_a20 PROC ; (485)
cli ; (486) Запрет прерываний
call empty_8042 ; (487) Ждать пока буфер 8042 не опустеет
jnz g_1 ; (488)
mov al,0d1h ; (489) Код управления линией A20
out status_port,al ; (490) в порт сотстояния 8042
call empty_8042 ; (491) Ждать пока буфер 8042 не опустеет
jnz g_1 ; (492)
mov al,ah ; (493) В al помещаем вход. значение ah
out key_port_a,al ; (494) AL -> в порт клавиатуры
call empty_8042 ; (495) Ждать пока буфер 8042 не опустеет
g_1: ret ; (496) Возврат
gate_a20 ENDP ; (497)

;--------------------------------------------------------------
;Ждать пока буфер 8042 не опустеет
;Вход: нет
;Выход:(AL)=0 буфер пуст
; (AL)=2 не пуст
;--------------------------------------------------------------
empty_8042 PROC ; (498)
push cx ; (499) Сохраняем cx
sub cx,cx ; (500) След. значение
e_1: in al,status_port ; (501) счетчика будет 0FFFFh
and al,00000010b ; (502) al=0 ?
loopnz e_1 ; (503) Нет, переход на e_1
pop cx ; (504) Восстановление cx
ret ; (505) Возврат
empty_8042 ENDP ; (506)

;------------------------------------------------------------
;Перепрограммирование контроллера прерываний
; Вход : DX - порт контроллера
; AH - начальный номер прерывания
;------------------------------------------------------------
SET_INT PROC ; (507)
mov al,11h ; (508) УСИ1: будет УСИ3
out dx,al ; (509)
jmp short $+2 ; (510) Задержка
mov al,ah ; (511) al:=начал. номер прерывания
; (УСИ2 : базовый вектор)
inc dx ; (512) Второй порт контроллера
out dx,al ; (513)
jmp short $+2 ; (514) Задержка
cmp dx, intb01 ; (515) dx = 0A0h ? ( программируем
; ведомый контроллер прерываний ? )
jne l1 ; (516) Нет -> на l1
mov al,2 ; (517) Да -> УСИ3: ведомый контроллер
jmp l2 ; (518) подключен к уровню 2

l1: mov al,4 ; (519) УСИ3: ведомый контроллер
; подключен ко 2-му входу
; ведущего ПКП
l2: out dx,al ; (520)
jmp short $+2 ; (521) Задержка
mov al,1 ; (522) УСИ4: 80x86, требуется EOI
out dx,al ; (523)
jmp short $+2 ; (524) Задержка
mov al,0ffh ; (525) Маска прерываний
; (замаскируем все прерывания)
out dx,al ; (526)
dec dx ; (527) Вернем dx значение, которое он
; имел при входе в процедуру
ret ; (528) Возврат
SET_INT ENDP ; (529)

;--------------------------------------------------------------
;Вход: DX содержит номер сегмента
; CX содержит внутрисегментное смещение
;Выход: DX содержит значение BASE_LO_WORD
; CX содержит значение BASE_HI_BYTE
;--------------------------------------------------------------
FORM_24BIT_ADDRESS PROC ; (530)
shl edx,4 ; (531) edx := seg*16 +
add edx,ecx ; (532) + offset
; dx:=биты 00..15 адреса
mov ecx,edx ; (533) ecx:=edx
shr ecx,16 ; (534) cx:=биты 16..23 адреса
ret ; (535) Возврат
FORM_24BIT_ADDRESS ENDP ; (536)

SET_PROTECT PROC ; (537)
CLD ; (538) Движемся вперед
FILLDESCR cs,gdt,GDT1 ; (539) Заполнение
FILLDESCR CS,0,GDT2 ; (540) дескрипторов в GDT
FILLDESCR CS,0,GDT3 ; (541) ( инициализируем
FILLDESCR SS,0,GDT4 ; (542) адресную
FILLDESCR CS,IDT,IDT_POINTER ; (543) часть
FILLDESCR CS,0,GDT6 ; (544) дескрипторов )
FILLDESCR CS,0,GDT7 ; (545)
FILLDESCR CS,V86TSS,GDT8 ; (546)
; Настройка
mov V86TSS.SS0,V86_data ; (547) стека для
; монитора
mov V86TSS.ESP0,OFFSET STACK0 ; (548)
mov V86TSS.baseMapIO,105 ; (549)

; mov V86TSS.baseMapIO,136 ; Для Pentium (так как
; имеется битовая карта перенаправления прерываний (32 байта))

lidt idt_pointer ; (550) загрузка IDTR
lgdt gdt1 ; (551) загрузка GDTR
mov ah,enable_bit20 ; (552) открывание A20
call gate_a20 ; (553)
or al,al ; (554) Проверка al (если
; al=2, то произошел сбой;
; если al=0, то все в порядке)
jz m_10 ; (555) al=0 ?
mov dx,offset gate_failure ; (556) Нет, -> выдача
mov ah,9 ; (557) сообщения об
int 21h ; (558) ошибке
int 20h ; (559) Завершение работы программы

m_10: CLI ; (560) Запрет аппаратных прерываний
in al,inta01 ; (561) Сохранение состояния
mov i8259_1,al ; (562) контроллеров прерывания
in al,intb01 ; (563)
mov i8259_2,al ; (564)

READY_FOR_RESET ; (566) Подготовка к сбросу
mov dx,inta00 ; (567) Перепрограммирование
mov ah,32d ; (568) ведущего контроллера
call set_int ; (569) прерываний

mov dx,intb00 ; (570) Перепрограммирование
mov ah,28h ; = 40d ; (571) ведомого контроллера
call set_int ; (572) прерываний

mov eax,cr0 ; (573)
or ax,1 ; (574)
mov cr0,eax ; (575) переход в защищенный режим
jumpfar m_20,cs_code ; (576) настройка CS на сегмент кода
m_20: ;(577)
mov ax,ss_dseg ; (578) Инициализация сегментных
mov ss,ax ; (579) регистров
mov ax,cs_data ; (580)
mov ds,ax ; (581)
mov es,ax ; (582)
mov fs,ax ; (583)
ret ; (584) Возврат
SET_PROTECT ENDP ; (585)

cseg_leng EQU $ ; (586) Длина кодового сегмента
cseg ENDS ; (587)
end start ; (588)
Форма ответа