Защищенный режим процессоров Intel


Использование функций DPMI - часть 2


Пользуемся выводом через // эмулируемое прерывание реального режима DOS textcolor(BLACK); textbackground(LIGHTGRAY); clrscr(); pm_printf(" Установлен защищённый режим работы процессора!\n\r" " ----------------------------------------------\n\r\n\r"); // Выводим текущую информацию о распределении памяти mi_show(); pm_printf("\n\r\n\r\n\r Для продолжения нажмите любую клавишу..."); getch(); clrscr(); // Получаем селектор для непосредственного доступа к видеопамяти alloc_videosel(); pm_printf("\n\r\n\r\n\r Для продолжения нажмите любую клавишу..."); getch(); clrscr(); // Выводим сообщения, пользуясь непосредственным доступом // к видеопамяти vi_hello_msg(); vi_print(0, 3, " Для возврата в реальный режим нажмите любую клавишу", 0x7f); getch(); // Освобождаем полученный селектор free_videosel(); textcolor(LIGHTGRAY); textbackground(BLACK); clrscr(); // Завершаем работу программы выходом в DOS dos_exit(0); } // ------------------------------------------------- // Процедура для завершения работы программы // ------------------------------------------------- void dos_exit(unsigned err) { asm mov ax, err asm mov ah, 04ch asm int 21h } // ------------------------------------------------- // Инициализация для работы с DPMI // ------------------------------------------------- union REGS inregs, outregs; struct SREGS segregs; void (far *pm_entry)(); unsigned hostdata_seg, hostdata_size, dpmi_flags; void dpmi_init(void) { // Проверяем доступность и параметры сервера DPMI inregs.x.ax = 0x1687; int86x(0x2F, &inregs, &outregs, &segregs); if(outregs.x.ax != 0) { printf("Сервер DPMI не активен."); exit(-1); } // Определяем версию сервера DPMI printf("Версия сервера DPMI: \t\t\t%d.%d\n", outregs.h.dh, outregs.h.dl); // Определяем тип процессора printf("Тип процессора:\t\t\t\t"); if(outregs.h.cl == 2) printf("80286"); else if(outregs.h.cl == 3) printf("80386"); else if(outregs.h.cl == 4) printf("80486"); // Определяем возможность работы с 32-разрядными // программами dpmi_flags = outregs.x.bx; printf("\nПоддержка 32-разрядных программ:\t"); if(dpmi_flags && 1) printf("ПРИСУТСТВУЕТ"); else printf("ОТСУТСТВУЕТ"); // Определяем размер области памяти для сервера DPMI hostdata_size = outregs.x.si; printf("\nРазмер памяти для сервера DPMI:\t\t%d байт", hostdata_size * 16); // Определяем адрес точки входа в защищённый режим FP_SEG(pm_entry) = segregs.es; FP_OFF(pm_entry) = outregs.x.di; printf("\nАдрес точки входа в защищённый режим: \t%Fp\n", pm_entry); // Заказываем память для сервера DPMI if(hostdata_size) { if(_dos_allocmem(hostdata_size, &hostdata_seg) != 0) { printf("Мало стандартной памяти"); exit(-1); } } } // ------------------------------------------------ // Процедура для установки защищённого режима // ------------------------------------------------ void set_pmode() { // Входим в защищённый режим asm { mov ax, hostdata_seg mov es, ax mov ax, dpmi_flags } (*pm_entry)(); } // ------------------------------------------- // Процедура вывода символа на экран в // защищённом режиме // ------------------------------------------- void pm_putch(int chr) { // Структура для вызова прерывания должна // быть определена как статическая static RM_INT_CALL regs; static RM_INT_CALL far *pregs = (void far *) 0; // В первый раз инициализируем структуру // и указатель на неё if (!pregs) { pregs = &regs; memset(pregs, 0, sizeof(RM_INT_CALL)); regs.eax = 0x0200; } regs.edx = chr; // Вызываем прерывание DOS для вывода символа rm_int(0x21, 0, pregs); } // ------------------------------------------- // Процедура вывода строки на экран в // защищённом режиме // ------------------------------------------- void pm_puts(char *str_ptr) { while (*str_ptr) { pm_putch(*str_ptr); str_ptr++; } } // ------------------------------------------- // Процедура вывода строки на экран в // защищённом режиме, аналог функции printf() // ------------------------------------------- void cdecl pm_printf(const char *fmt, ...) { char buffer[512], *sptr=buffer; va_list marker; va_start(marker, fmt); vsprintf(buffer, fmt, marker); va_end(marker); while (*sptr) pm_putch(*sptr++); } // -------------------------------------------- // Процедура вызова прерывания реального режима // -------------------------------------------- int rm_int(unsigned int_number, // номер прерывания unsigned params, // количество слов параметров, // передаваемых через стек RM_INT_CALL far *rm_call) // адрес структуры // для вызова прерывания { asm { push di push bx push cx mov ax, 0300h // функция вызова прерывания mov bx, int_number mov cx, params; les di, rm_call // запись в ES:DI адреса структуры int 31h // вызов сервера DPMI jc error mov ax, 0 // нормальное завершение jmp short rm_int_end } error: asm mov ax, 0 // завершение с ошибкой rm_int_end: asm pop cx asm pop bx asm pop di } // ----------------------------------------------------- // Процедура отображает текущее состояние памяти // ----------------------------------------------------- int mi_show(void) { PMI minfo, far *minfoptr = &minfo; unsigned long psize, far *psizeptr=&psize; unsigned sel; void far *fp; get_mi(minfoptr); pm_printf(" Информация об использовании памяти\n\r" " ----------------------------------\n\r" "\r\n Размер максимального доступного блока:\t\t%ld байт" "\r\n Доступно незафиксированных страниц:\t\t%ld", minfo.avail_block, minfo.max_page); pm_printf("\r\n Доступно зафиксированных страниц:\t\t%ld" "\r\n Размер линейного адресного пространства:\t%ld страниц" "\r\n Всего имеется незафиксированных страниц:\t%ld", minfo.max_locked, minfo.linadr_space, minfo.total_unlocked); pm_printf("\r\n Количество свободных страниц:\t\t\t%ld" "\r\n Общее количество физических страниц:\t\t%ld", minfo.free_pages, minfo.tot_phys_pages); pm_printf("\r\n Свободное линейное адресное пространство:\t%ld страниц" "\r\n Размер файла/раздела для страничного обмена:\t%ld страниц", minfo.free_linspace, minfo.size_fp); get_page_size(psizeptr); pm_printf("\r\n Размер страницы:\t\t\t\t%ld байт\r\n", psize); // Выводим текущие значения регистров CS и DS asm mov sel,cs pm_printf("\n\r CS = %04.4X, ",sel); asm mov sel,ds pm_printf("DS = %04.4X",sel); // Выводим значение текущего приоритетного кольца fp = (void far *) main; sel = FP_SEG(fp) & 3; pm_printf("\n\r Номер приоритетного кольца = %d\n\r",sel); } // ----------------------------------------------- // Процедура для получения информации об // использовании памяти // ----------------------------------------------- int get_mi(PMI far *minfo) { asm { mov ax, 0500h les di, minfo // ES:DI = адрес структуры DMI int 31h jc error mov ax, 0 jmp short get_mi_end } error: asm mov ax, 1 get_mi_end: } // ------------------------------------------------ // Процедура для получения размера страницы памяти // ------------------------------------------------ int get_page_size(long far *page_size) { asm { mov ax, 0604h int 31h jc error les di, page_size // ES:DI = адрес page_size mov es:[di], cx mov es:[di+2], bx mov ax, 0 jmp short gps_end } error: asm mov ax, 1 gps_end: } // -------------------------------------------------- // Определение сегментного адреса видеопамяти // -------------------------------------------------- unsigned crt_mode, crt_seg; int video_init(void) { union REGS r; // Определяем текущий видеорежим r.h.ah=15; int86(0x10,&r,&r); crt_mode = r.h.al; if(crt_mode == MONO_MODE) crt_seg = 0xb000; else if(crt_mode == BW_80_MODE crt_mode == COLOR_80_MODE) crt_seg = 0xb800; else { printf("\nИзвините, этот видеорежим недопустим."); exit(-1); } } // --------------------------------------------------- // Получение селектора для адресации видеопамяти // --------------------------------------------------- char far *vid_ptr; DESCRIPTOR d; unsigned ldtsel; int alloc_videosel(void) { void far *fp; unsigned long addr; FP_SEG(vid_ptr) = crt_seg; FP_OFF(vid_ptr) = 0; pm_printf(" Адрес видеопамяти реального режима:\t %Fp\r\n", vid_ptr); // Получаем свободный LDT-селектор if (! (ldtsel = get_sel())) { pm_printf(" Ошибка при получении селектора"); dos_exit(-1); } pm_printf(" Получен селектор:\t\t\t%04.4X\n\r", ldtsel); // Подготавливаем дескриптор для полученного селектора d.limit = 0x2000; addr = ABSADDR(crt_seg, 0); d.addr_lo = addr & 0xFFFF; d.addr_hi = addr >> 16; d.access.accessed = 0; // не использовался d.access.read_write = 1; // разрешены чтение/запись d.access.conf_exp = 0; // не стек d.access.code = 0; // это сегмент данных d.access.xsystem = 1; // не системный дескриптор d.access.dpl = 3; // приоритетное кольцо 3 d.access.present = 1; // сегмент присутствует в памяти d.reserved = 0; // Устанавливаем дескриптор if (!set_descriptor(ldtsel, &d)) { pm_printf(" Ошибка при установке дескриптора"); getch(); dos_exit(-1); } // Выводим на экран адрес видеопамяти FP_SEG(vid_ptr) = ldtsel; FP_OFF(vid_ptr) = 0; pm_printf(" Адрес видеопамяти защищённого режима:\t%Fp\r\n", vid_ptr); } // -------------------------------------------------- // Освобождение селектора видеопамяти // -------------------------------------------------- int free_videosel(void) { if (!sel_free(ldtsel)) { pm_printf(" Ошибка при освобождении селектора"); dos_exit(-1); } } // ---------------------------------------------- // Получить один селектор в LDT // ---------------------------------------------- unsigned get_sel(void) { asm { mov ax, 0 // получить селектор mov cx, 1 // нужен один селектор int 31h jc error jmp short gs_end // AX содержит новый LDT-селектор } error: asm mov ax, 0 // произошла ошибка gs_end: } // -------------------------------------------------- // Установить дескриптор для LDT-селектора // -------------------------------------------------- int set_descriptor(unsigned pm_sel, DESCRIPTOR far *desc) { asm { push di push bx mov ax, 000Ch mov bx, pm_sel les di, desc int 31h jc error mov ax, 1 jmp short sd_end } error: asm mov ax, 0 sd_end: asm pop bx asm pop di } // -------------------------------------------------- // Освободить LDT-селектор // -------------------------------------------------- int sel_free(unsigned pmodesel) { asm { mov ax, 0001h mov bx, pmodesel int 31h jc error mov ax, 1 jmp short done } error: asm mov ax, 0 done: } // ------------------------------------------------------- // Вывод символа непосредственной записью в видеопамять // ------------------------------------------------------- void vi_putch(unsigned int x, unsigned int y ,char c, char attr) { register unsigned int offset; char far *vid_ptr; offset=(y*160) + (x*2); vid_ptr=MK_FP(ldtsel, offset); *vid_ptr++=c; *vid_ptr=attr; } // ------------------------------------------------------- // Вывод строки непосредственной записью в видеопамять // ------------------------------------------------------- void vi_print(unsigned int x, unsigned int y, char *s, char attr) { while(*s) vi_putch(x++, y, *s++, attr); } // ------------------------------------------------------- // Вывод сообщения непосредственной записью в видеопамять // ------------------------------------------------------- void vi_hello_msg(void) { vi_print(0, 0, " Демонстрация работы с интерфейсом " "DPMI ¦ © Frolov A.V., 1992 ", 0x30); }


- Начало -  - Назад -  - Вперед -