Скачиваний:
27
Добавлен:
15.09.2014
Размер:
24.17 Кб
Скачать

ЗАЩИЩЕННЫЙ РЕЖИМ Примеры программ Полный листинг программы переключения в защищенны режим МП i286 Данная программа запускается в реальном режиме в среде MS-DOS, переключает процессор в защищенный режим , выдает сообщение и ,через некоторое время, возвращает процессор в реальный режим и завершает свое выполнение. Программа подготовлена с помощью транслятора Borland TASM и использует режим IDEAL. Программу можно запускать на машине с процессором i80286, i80386, i80486, Pentium и только в режиме эмуляции Ms-DOS

IDEAL RADIX 16 P286 ; Используем модель памяти LARGE, при этом мы организуем ;несколько отдельных сегментов и для каждого сегмента создадим ;дескриптор в таблице GDT MODEL LARGE ;---------------------------------------- ; Определения структур данных и констант ;---------------------------------------- STRUC desc_struc ; структура дескриптора limit dw 0 ; Предел base_l dw 0 ; мл. слово адреса base_h db 0 ; ст. байт адреса access db 0 ; байт доступа rsrv dw 0 ; резерв ENDS desc_struc ; Биты байта доступа ACC_PRESENT EQU 10000000b ; Сегмент есть в памяти ACC_CSEG EQU 00011000b ; Сегмент кода ACC_DSEG EQU 00010000b ; Сегмент данных ACC_EXPDOWN EQU 00000100b ; Сегмент расширяется вниз ACC_CONFORM EQU 00000100b ; Согласованный сегмент ACC_DATAWR EQU 00000010b ; Разрешение записи ; Типы сегментов DATA_ACC = ACC_PRESENT OR ACC_DSEG OR ACC_DATAWR CODE_ACC = ACC_PRESENT OR ACC_CSEG OR ACC_CONFORM STACK_ACC = ACC_PRESENT OR ACC_DSEG OR ACC_DATAWR OR ACC_EXPDOWN ; Константы STACK_SIZE EQU 0400 ; Размер стека B_DATA_SIZE EQU 0300 ; Размер области данных BIOS B_DATA_ADDR EQU 0400 ; Адрес области данных BIOS MONO_SEG EQU 0b000 ; Сегмент видеопамяти ; монохромного видеоадаптера COLOR_SEG EQU 0b800 ; Сегмент видеопамяти ; цветного видеоадаптера CRT_SIZE EQU 4000 ; Размер сегмента видеопамяти ; цветного видеоадаптера MONO_SIZE EQU 1000 ; Размер сегмента видеопамяти ; монохромного видеоадаптера CRT_LOW EQU 8000 ; Мл. байт физ. адреса ; сегмента видеопамяти MONO_LOW EQU 0000 ; Мл. байт физ. адреса ; сегмента видеопамяти CRT_SEG EQU 0Bh ; Ст. байт физ. адреса ; сегмента видеопамяти ;Селекторы определенные в таблице GDT DS_DESCR = (gdt_ds - gdt_0) CS_DESCR = (gdt_cs - gdt_0) SS_DESCR = (gdt_ss - gdt_0) BIOS_DESCR = (gdt_bio - gdt_0) CRT_DESCR = (gdt_crt - gdt_0) MDA_DESCR = (gdt_mda - gdt_0) CMOS_PORT EQU 70h ; Порт для доступа к ; CMOS - памяти PORT_6845 EQU 0063h ; Адрес данных BIOS, где записано ; значение адреса ; порта контроллера 6845 COLOR_PORT EQU 03d4h ; Порт цветного видеоконтроллера MONO_PORT EQU 03d4h ; Порт монохромного видеоконтроллера STATUS_PORT EQU 64h ; Порт состояния клавиатуры SHUT_DOWN EQU 0feh ; Команда сброса процессора VIRTUAL_MODE EQU 0001h ; Бит перехода в защищенный режим A20_PORT EQU 0d1h ; Команда управления линией A20 A20_ON EQU 0dfh ; Открыть А20 A20_OFF EQU 0ddh ; Закрыть А20 KBD_PORT_A EQU 60h ; Адреса клавиатурных портов KBD_PORT_B EQU 61h INT_MASK_PORT EQU 21h ; Порт для маскирования прерываний STACK STACK_SIZE ; Сегмент стека DATASEG ; Начало сегмента данных DSEG_BEG = THIS WORD ; Память для сохранения регистров SS, ES, SP real_ss dw ? real_sp dw ? real_es dw ? ; Глобальная табл. деск. GDT содержит дескр-ры : ; gdt_0 - дескриптор для пустого селектора ; gdt_gdt - дескриптор для GDT ; gdt_ds - дескриптор для сегмента, адресуемого DS ; gdt_cs - дескриптор для сегмента кода ; gst_ss - дескриптор для сегмента стека ; gdt_bio - дескриптор для области данных BIOS ; gdt_crt - дескриптор для видеопамяти цветного дисплея ; gdt_mda - дескриптор для видеопамяти монохромного ; дисплея GDT_BEG = $ LABEL gdtr WORD gdt_0 desc_struc gdt_gdt desc_struc gdt_ds desc_struc gdt_cs desc_struc gdt_ss desc_struc gdt_bio desc_struc gdt_crt desc_struc gdt_mda desc_struc GDT_SIZE = ($-GDT_BEG) ;размер таблицы дескрипторов CODESEG ;сегмент кода PROC start ; Инициализируем регистр сегмента данных для реального режима mov ax,DGROUP mov ds,ax ; Определяем базовый адрес видеопамяти call set_crt_base ; Стираем экран дисплея (устанавливаем серый фон) mov bh,77h call clrscr ; Подготовка к переходу в защищенный режим и обеспечение ; возможности возврата в реальный режим call init_protected_mode ; Переключаемся в защищенный режим call set_protected_mode ; ----------- * Программа работает в защищенном режиме! * -- call write_hello_msg ; выводим сообщение на экран call pause ; ждем некоторое время ; Возвращаемся в реальный режим call set_real_mode ; ----------- * Программа работает в реальном режиме! * -- ; Стираем экран и возвращаемся в DOS mov bh,07h call clrscr mov ah,4Ch int 21h ENDP start ;---------------------------------------------------- ; Макрокоманда для записи в дескриптор 24-битового ; базового адреса сегмента ;---------------------------------------------------- MACRO setgdtentry mov [ (desc_struc bx).base_l ],ax mov [ (desc_struc bx).base_h ],dl ENDM ;---------------------------------------------- ; Процедура подготовки процессора к переходу ; в защ. режим ;---------------------------------------------- PROC init_protected_mode NEAR ; Заполняем GDT ; Вычисляем 24-битовый базовый адрес сегмента данных mov ax,DGROUP mov dl,ah shr dl,4 shl ax,4 ; Регистры dl:ax содержат базовый адрес, ; сохраняем его в di:si mov si,ax mov di,dx ; Подготавливаем дескриптор для GDT add ax,OFFSET gdtr adc dl,0 mov bx,OFFSET gdt_gdt setgdtentry ; Подготавливаем дескриптор для сегмента ds mov bx,OFFSET gdt_ds mov ax,si mov dx,di setgdtentry ; Подготавливаем дескриптор для сегмента cs mov bx,OFFSET gdt_cs mov ax,cs mov dl,ah shr dl,4 shl ax,4 setgdtentry ; Подготавливаем дескриптор для сегмента стека mov bx,OFFSET gdt_ss mov ax,ss mov dl,ah shr dl,4 shl ax,4 setgdtentry ; Записываем адрес возврата в реальный режим ; в область данных BIOS по адресу 0040h:0067h push ds mov ax,40 mov ds,ax mov [WORD 67],OFFSET shutdown_return mov [WORD 69],cs pop ds ; Mаскируем все прерывания, в том числе немаскируемые. ; Записываем в CMOS-память в ячейку 0Fh код 5, ; этот код обеспечит после выполнения сброса процессора ; передачу управления по адресу, подготовленному нами ; в области данных BIOS по адресу 0040h:0067h. ; Для того, чтобы немаскируемые прерывания были запрещены, ; устанавливаем в 1 старший бит при определении ячейки CMOS cli mov al,8f out CMOS_PORT,al jmp next1 ; небольшая задержка next1 : mov al,5 out CMOS_PORT+1,al ; код возврата ret ENDP init_protected_mode ;------------------------------------------------------------ ; Процедура переключает процессор в защищенный режим ;------------------------------------------------------------ PROC set_protected_mode NEAR mov ax,[rl_crt] ; записываем в es сегментный mov es,ax ; адрес видеопамяти call enable_a20 ; открываем адресную линию А20 mov [real_ss],ss ; запоминаем указатель стека mov [real_es],es ; для реального режима ; Загружаем регистр GDTR lgdt [QWORD gdt_gdt] ; Устанавливаем защищенный режим работы процессора mov ax,VIRTUAL_MODE lmsw ax ; Мы находимся в защищенном режиме ; Очищаем внутреннюю очередь команд процессора. ; Выполняем команду межсегментного перехода, ; в качестве селектора указываем селектор текущего ; сегмента кода, в качестве смещения - метку flush ; jmp far flush db 0ea dw OFFSET flush dw CS_DESCR LABEL flush FAR ; Загружаем сегментные регистры SS и DS селекторами mov ax,SS_DESCR mov ss,ax mov ax,DS_DESCR mov ds,ax ret ENDP set_protected_mode ;-------------------------------------- ; Возврат в реальный режим ;-------------------------------------- PROC set_real_mode NEAR ;Запоминаем содержимое ,т.к. после сброса ;процессора оно будет потеряно mov [real_sp],sp ;Выполняем сброс процессора mov al,SHUT_DOWN out STATUS_PORT,al ;Ожидаем сброса процессора wait_reset: hlt jmp wait_reset ;--> В это место мы попадаем после сброса процессора, ;теперь мы снова в реальном режиме LABEL shutdown_return FAR ;Инициализируем ds адресом сегмента данных mov ax,DGROUP mov ds,ax assume ds:DGROUP ;Восстанавливаем указатель стека mov ss,[real_ss] mov sp,[real_sp] ;восстанавливаем содержимое регистра es mov es,[real_es] ;Закрываем адресную линию А20 call disable_a20 ;Разрешаем все прерывания mov ax,000dh ;разрешаем немаскируемые ; прерывания out CMOS_PORT,al in al,INT_MASK_PORT ;разр. маскируемые ; прерывания and al,0 out INT_MASK_PORT,al sti ret ENDP set_real_mode ;------------------------------------------ ; Процедура открывает адресную линию А20 ;------------------------------------------ PROC enable_a20 NEAR mov al,A20_PORT out STATUS_PORT,al mov al,A20_ON out KBD_PORT_A,al ret ENDP enable_a20 ;------------------------------------------ ; Процедура закрывает адресную линию А20 ;------------------------------------------ PROC disable_a20 NEAR mov al,A20_PORT out STATUS_PORT,al mov al,A20_OFF out KBD_PORT_A,al ret ENDP disable_a20 ;------------------------------------------ ; Задержка ;------------------------------------------ PROC pause NEAR push cx mov cx,100 ploop0: push cx xor cx,cx ploop1: loop ploop1 pop cx loop ploop0 pop cx retENDP pause ;------------------------------------------------ ; Сегмент данных для обслуживания видеоадаптера ;------------------------------------------------ DATASEG columns db 80d ;количество столбцов на экране rows db 25d ;количество строк на экране rl_crt dw COLOR_SEG ;сегментный адрес видеобуфера vir_crt dw CRT_DESCR ;селектор видеобуфера curr_line dw 0d ;номер текущей строки CODESEG ;------------------------------------------------ ; Определение базового адреса видеобуфера ;------------------------------------------------ PROC set_crt_base NEAR ;Определяем количество столбцов на экране и ;записываем в переменную columns mov ax,40 mov es,ax mov bx,[WORD es:4a] mov [columns],bl ;То же для кол-ва строк mov bl,[BYTE es:84] inc bl mov [rows],bl ;Для того чтобы определить тип видеоконтроллера ; (цветной или монохромный), ;считываем адрес микросхемы 6845 mov bx,[WORD es:PORT_6845] cmp bx,COLOR_PORT je set_crt_exit ;Если видеоконтроллер монохромный, ;изменяем адрес сегмента и селектор, ;заданные по умолчанию mov [rl_crt],MONO_SEG mov [vir_crt],MDA_DESCR set_crt_exit: ret ENDP set_crt_base ;------------------------------------------------------- ; Вывод строки на экран ; Параметры: ; (ax,bx) - координаты (x,y) выводимой строки ; ds,si - адрес выводимой строки ; cx - длина выводимой строки ; dh - атрибут выводимой строки ; es - сегмент или селектор видеопамяти ;------------------------------------------------------- PROC writexy NEAR push si push di ;Вычисляем смещение в буферу для записи строки, ;используем формулу ( (y*columns)+x ) * 2 mov dl,[columns] mul dl add ax,bx shl ax,1 mov di,ax mov ah,dh ;записываем в ah байт атрибута ;Выполняем запись в видеобуфер wxy_write: lodsb ;очередной символ в al stosw ;записываем его в видеопамять loop wxy_write pop di pop si ret ENDP writexy ;---------------------------------------------------- ; Процедура стирания экрана ; (в bh атрибут для заполнения экрана) ;---------------------------------------------------- PROC clrscr NEAR xor cx,cx mov dl,[columns] mov dh,[rows] mov ax,0600h int 10h ret ENDP clrscr DATASEG hello_msg db " Protected mode monitor, for CPU i80286 " CODESEG ;------------------------------------------------- ; Процедура выводит сообщение в защищенном режиме ;------------------------------------------------- PROC write_hello_msg NEAR mov ax,[vir_crt] ;загружаем селектор mov es,ax ;видеопамяти в es ;Выводим сообщение в верхний левый угол экрана (x=y=0) mov bx,0 ;(x,y)=(ax,bx) mov ax,[curr_line] inc [curr_line] ;увеличиваем номер текущей ; строки ;Загружаем адрес выводимой строки и ее длину mov si,OFFSET hello_msg mov cx,SIZE hello_msg mov dh,30h ;атрибут - черный текст ; на голубом фоне call writexy pause 100 ret ENDP write_hello_msg CSEG_SIZE = ($-start) ;размер сегмента кода DATASEG DSEG_SIZE = ($-DSEG_BEG) ;размер сегмента данных END start Перевод в защищенный режим 386 Пример переключение в защищенный режим: mov ax,CR0 or ax,01h mov CR0,ax Пример возврата в реальный режим: mov ax,CR0 add ax,0FFFEh mov CR0,ax ;----------------------------------------------------------- ; Процедура выводит звуковое сообщение в защищенном режиме ;----------------------------------------------------------- DATASEG port_dinamik EQU 61h ; Определяем порт для управления ;тоном динамика CODESEG PROC cignal NEAR in al,port_dinamik ; Считаем содержимое порта в al mov cx,50 ; В cx длительность звукового ;сигнала dinamik_beg: push cx ; Сохраняем счетчик цикла or al,00000010b ; Устанавливаем бит 1 out port_dinamik,al ; Включаем динамик ; (бит 1 установлен) mov cx,500 ; Организуем паузу, в течение loop $ ;которой через динамик течет ;ток and al,11111101b ; Сбросим бит 1 out port_dinamik,al ; Выключим динамик ; (бит 1 сброшен) mov cx,500 ; Организуем паузу, в течение loop $ ;которой через динамик ток не ;течет pop cx ; Восстановим счетчик цикла loop dinamik_beg ; Повторять cx раз ret ENDP cignal Kод программы, выполняющей поиск таблиц дескрипторов в 32-битном защищенном режиме под Windows. ФАЙЛ TOOL32.H /*******************************************************/ /* Автор текста программы Евсеенко В. /* E-Mail: kapitan@thearmy.com /*******************************************************/ /*******************************************************/ /* So this method is my own discovery. It`s based on /* the proection of LDT from KERNEL. /*******************************************************/ WORD GetLDT(void) { WORD LDT = 0; DWORD dwL0 = (DWORD)(-1L); do { dwL0 += 8; _try { // Селектор не может присутствовать в памяти _asm { mov ebx,dwL0 push es lsl eax,ebx jnz next //переход если //не селектор cmp eax,ebx jna next //переход если //меньше селектора cmp eax,0FF00h ja next //переход если //не 16-битовое //смещение mov es,bx mov edi,ebx and edi,0FFF8h // очистить DPL маску // mov edx,es:[edi] cmp dx,ax jne next //переход если //relations pointer mov eax,es:[edi+5] cmp ax,0F3h jne next //jump if not //complay flags mov LDT,bx } } _except (EXCEPTION_EXECUTE_HANDLER) { continue; } next: _asm pop es; } while ((LDT==0)&&(dwL0

Соседние файлы в папке Учебник