Расскажу про назначение всех флагов для таблицы страниц:
PAGE_PRESENT - Страница присутствует в оперативной памяти, т.е. спроецированна. Если этого флага нет, остальные биты даже не анализируются, а сразу генерируется исключение Page Fault (#14). PAGE_WRITABLE - Страница доступна для записи. Если этого флага нет, то любая команда записи по этому адресу приведёт к Page fault. PAGE_USER -
Страница доступна для пользователя. Если этого флага нет, то любая команда доступа (не важно чтения или записи) к этой странице из кода с CPL = 3 спровоцирует Page Fault. PAGE_WRITE_THROUGH - Управлением кешем: разрешение сквозной записи. PAGE_CACHE_DISABLED - Управлением кешем: кеширование запрещено PAGE_ACCESSED - К странице было обращение. Процессор лишь устанавливает этот флаг, но не сбрасывает его. Это задача
самой ОС, если она использует этот бит для определения какие страницы редко используется, чтобы сбросить их в файл подкачки на диск.
Все предыдущие флаги применимы как к элементу каталога страниц (тогда это будут атрибуты целой таблицы, а не отдельной страницы), так и к элементу таблицы страниц. Следующие два флага касаются лишь элемента таблицы страниц:
PAGE_MODIFIED - Содержимое страницы было изменено. PAGE_ACCESSED обозначает лишь факт доступа к странице
(как чтение, так и запись), а этот флаг необходимо именно для определения доступа на запись. PAGE_GLOBAL - Глобальная страница. Элемент не выгружается из TLB при перезагрузке CR3. Полезный атрибут для страниц, содержащие системные структуры, общие для всех процессов системы. Например, в нашей ОС этот флаг можно применить для всех страниц из диапазона от 0x80000000 до 0xFFFFFFFF.
Пришло время так же рассказать про кеш элементов таблицы страниц
- TLB. Без него каждое обращение к памяти при страничном преобразовании превращалось в 3 обращения (обращение к каталогу страниц, обращение к таблице страниц, обращение к нужной переменной). Для ускорения работы результаты преобразования кешируются во внутренней очень быстрой памяти процессора, чтобы в следующий раз не вычислять адрес заново. Изменение значения CR3 приводит к очистке кеша, потому что такая команда подразумевает замену таблиц страниц на новые. Но, как правило,
ядро системы во всех адресных пространствах находится по одному и тому же адресу, поэтому нет смысла удалять эти записи из кеша, для этого и существует флаг глобальности страницы. Например, можно смонтировать с ним таблицу прерываний:
Из-за TLB изменение элемента таблицы страниц может не быть применено сразу, если до этого было обращение к нему и он до сих пор в кеше. Для принудительного удаления из кеша одного элемента существует ассемблерная инструкция INVLPG. Напишем специальную функцию для внутреннего использования менеджером памяти в memory_manager.c:
Теперь можно приступить к теории менеджера виртуальной памяти.
Для него есть понятие AddressSpace - регион виртуальной памяти, в пределах которого выделяются виртуальные адреса. У ядра есть свой AddressSpace (от KERNEL_MEMORY_BASE до KERNEL_MEMORY_END), у каждого приложения свой (в личном каталоге страниц от USER_MEMORY_START до USER_MEMORY_END).
Для поиска свободного региона используется список занятых, организованный в виде массива, который способен расширяться по мере необходимости.
Для
блока типа VMB_MEMORY был выделен блок физической памяти с помощью alloc_phys_pages, а для VMB_IO_MEMORY был указан конкретный физический адрес и освобождать его с помощью free_phys_pages не нужно.
В следующем выпуске мы рассмотрим конкретную реализацию функций alloc_virt_pages и free_virt_pages. До встречи!