§ Демонстрация работы обработчика исключения страничного нарушения
Для того, чтобы показать, как реально работает обработчик исключения страничного нарушения, в нашем примере введены следующие элементы:Сегмент большого размера Big_segment - он расположен по адресу 3f0000h, т.е. почти в конце 4-го мегабайта и имеет размер больше 4Мб, благодаря чему этот сегмент отображается в трёх таблицах страниц и использование этого обработчик сегмента заставит обработчик использовать текущую таблицу страниц и создать две новых, т.е. функционально он будет задействован полностью. Big_segment создаётся следующим образом:
1 mov eax,3f0000h ; Начало сегмента по адресу < 4Мб. 2 mov cx,8092h ; Сегмент данных со страничной гранулярностью. 3 mov edx,1100 ; Предел сегмента равен 1100 страниц, 4 ; т.е. более 4Мб. 5 call set_descriptor ; Big_segment.Стек определён как обычный сегмент данных
1 lea dx,Stack_seg_start 2 add eax,edx 3 mov dx,1024 4 mov cl,10010010b ; Для "обычного" стека здесь должно 5 ; было быть не 10010010b, а 10010110b. 6 call set_descriptor ; StackДля него зарезервирован 1 Кб в конце программы:
1Stack_seg_start: ; Отсюда будет расти стек. 2 db 1024 dup (?) ; Зарезервировано для стека.При инициализации стека (сразу после входа в защищённый режим), в SP записывается новое значение вершины стека:
1 mov ax,Stack_selector 2 mov ss,ax 3 mov sp,1020При переходе в защищённый режим в образе CR0 перед его загрузкой сбрасываются все флаги, кроме эмуляции сопроцессора (он может быть установлен или сброшен, но в нашем примере не используется):
1 mov eax,cr0 2 and eax,10h ; Сбрасываем все биты, кроме ME (эмуляция 3 ; сопроцессора может быть включена). 4 or al,1 5 mov cr0,eaxПосле инициализации защищённого режима и вывода строки "Entering to protected mode..." в программе производятся следующие действия:
1 call get_phys_mem_size ; Определяем количество физической 2 ; памяти, установленной в компьютере. 3 mov phys_mem_size,eax 4 5; Выводим сообщение о количестве памяти: 6 7 mov text_color,1fh 8 lea bx,Memory_size 9 mov dx,0600h 10 call put_zs 11 12 call put_dd_num 13 14 lea bx,_bytes_ 15 call put_zs 16 17 call create_UPMM ; Создаём UPMM.Демонстрация работы обработчика исключения страничного нарушения происходит в цикле, в котором сегмент Big_segment весь последовательно заполняется, причём чем - не важно. При попытке доступа в неотображённую страницу процессор генерирует исключение и его обработчик отображает страницу и весь этот процесс прозрачен для программы:
1; Заполняем сегмент Big_segment и выводим текущий адрес в нём на экран: 2 3 mov ax,Big_segment 4 mov es,ax 5 xor edi,edi ; ES:EDI указывает на начало сегмента. 6 7 mov dx,0a20h 8 lea bx,_page_ 9 call put_zs ; Вывод строки "Page: ". 10 11 mov dx,0a00h ; Y вывода = 10, X = 0. 12 lea bx,_current_addr_ 13 call put_zs ; Выводим строку "Current address: ". 14 15 mov ecx,1100 * 1024 16 17; ECX = 1100 * 1024 - Мы будем записывать двойными словами. Сегмент 18; Big_segment лежит в трёх таблицах страниц и заполнение его числами 19; демонстрирует не только работу обработчика страничного нарушения по 20; отображению страниц но также и динамическое создание новых таблиц 21; страниц. 22 23 mov dh,0ah ; Y вывода на экран. 24 25 cld 26 27paging_demo: 28 mov dl,11h ; X вывода. 29 mov eax,edi 30 call put_dd_num 31 32 db 67h ; Атрибут размера операнда - stosd по EDI. 33 stosd 34 35 db 67h ; Атрибут размера операнда - цикл по ECX. 36 loop paging_demo 37 38 jmp Return_to_R_ModeНа этом заканчивается раздел, посвящённый управлению памятью, но сама тема ещё будет продолжена. 32-разрядные процессоры, начиная с Pentium-а предоставляют возможность использования страниц, размером 2 и 4 мегабайта, 36-разрядную шину данных, позволяющую адресовать до 64Гб памяти и множество дополнительных средств, призванных повысить производительность работы компьютера, однако, рассмотрение этих технологий требует знания некоторых других - буферов TLB и регистров MSR (и MTRR). Продолжение этой темы см. в разделе "Расширенное управление памятью".