§ Демонстрация работы обработчика исключения страничного нарушения

Для того, чтобы показать, как реально работает обработчик исключения страничного нарушения, в нашем примере введены следующие элементы:
Сегмент большого размера 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). Продолжение этой темы см. в разделе "Расширенное управление памятью".