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

Для того, чтобы показать, как реально работает обработчик исключения страничного нарушения, в нашем примере введены следующие элементы:
Сегмент большого размера Big_segment - он расположен по адресу 3f0000h, т.е. почти в конце 4-го мегабайта и имеет размер больше 4Мб, благодаря чему этот сегмент отображается в трёх таблицах страниц и использование этого обработчик сегмента заставит обработчик использовать текущую таблицу страниц и создать две новых, т.е. функционально он будет задействован полностью. Big_segment создаётся следующим образом:
	mov	eax,3f0000h	; Начало сегмента по адресу < 4Мб.
	mov	cx,8092h	; Сегмент данных со страничной гранулярностью.
	mov	edx,1100	; Предел сегмента равен 1100 страниц,
				;  т.е. более 4Мб.
	call	set_descriptor		; Big_segment.
Стек определён как обычный сегмент данных
	lea	dx,Stack_seg_start
	add	eax,edx
	mov	dx,1024
	mov	cl,10010010b	;    Для "обычного" стека здесь должно
				; было быть не 10010010b, а 10010110b.
	call	set_descriptor		; Stack
Для него зарезервирован 1 Кб в конце программы:
Stack_seg_start:	; Отсюда будет расти стек.
	db	1024 dup (?)	; Зарезервировано для стека.
При инициализации стека (сразу после входа в защищённый режим), в SP записывается новое значение вершины стека:
	mov	ax,Stack_selector
	mov	ss,ax
	mov	sp,1020
При переходе в защищённый режим в образе CR0 перед его загрузкой сбрасываются все флаги, кроме эмуляции сопроцессора (он может быть установлен или сброшен, но в нашем примере не используется):
	mov	eax,cr0
	and	eax,10h	;    Сбрасываем все биты, кроме ME (эмуляция
				; сопроцессора может быть включена).
	or	al,1
	mov	cr0,eax
После инициализации защищённого режима и вывода строки "Entering to protected mode..." в программе производятся следующие действия:
	call	get_phys_mem_size	;    Определяем количество физической
					; памяти, установленной в компьютере.
	mov	phys_mem_size,eax

; Выводим сообщение о количестве памяти:

	mov	text_color,1fh
	lea	bx,Memory_size
	mov	dx,0600h
	call	put_zs

	call	put_dd_num

	lea	bx,_bytes_
	call	put_zs

	call	create_UPMM		; Создаём UPMM.
Демонстрация работы обработчика исключения страничного нарушения происходит в цикле, в котором сегмент Big_segment весь последовательно заполняется, причём чем - не важно. При попытке доступа в неотображённую страницу процессор генерирует исключение и его обработчик отображает страницу и весь этот процесс прозрачен для программы:
; Заполняем сегмент Big_segment и выводим текущий адрес в нём на экран:

	mov	ax,Big_segment
	mov	es,ax
	xor	edi,edi		; ES:EDI указывает на начало сегмента.

	mov	dx,0a20h
	lea	bx,_page_
	call	put_zs		; Вывод строки "Page: ".

	mov	dx,0a00h	; Y вывода = 10, X = 0.
	lea	bx,_current_addr_
	call	put_zs		; Выводим строку "Current address: ".

	mov	ecx,1100 * 1024

;    ECX = 1100 * 1024 - Мы будем записывать двойными словами. Сегмент
; Big_segment лежит в трёх таблицах страниц и заполнение его числами
; демонстрирует не только работу обработчика страничного нарушения по
; отображению страниц но также и динамическое создание новых таблиц
; страниц.

	mov	dh,0ah		; Y вывода на экран.

	cld

paging_demo:
	mov	dl,11h		; X вывода.
	mov	eax,edi
	call	put_dd_num

	db	67h		; Атрибут размера операнда - stosd по EDI.
	stosd

	db	67h		; Атрибут размера операнда - цикл по ECX.
	loop	paging_demo

	jmp	Return_to_R_Mode
На этом заканчивается раздел, посвящённый управлению памятью, но сама тема ещё будет продолжена. 32-разрядные процессоры, начиная с Pentium-а предоставляют возможность использования страниц, размером 2 и 4 мегабайта, 36-разрядную шину данных, позволяющую адресовать до 64Гб памяти и множество дополнительных средств, призванных повысить производительность работы компьютера, однако, рассмотрение этих технологий требует знания некоторых других - буферов TLB и регистров MSR (и MTRR). Продолжение этой темы см. в разделе "Расширенное управление памятью".