Страничная память
Содержание:
Перемещаемые адреса: Формат машинного языка
Теперь рассмотрим форму представления перемещаемого адреса, состоящего из номера базового регистра и смещения, в машинном языке. Мы уже говорили, что команды этого языка состоят из двух полей: поля операции и поля операндов. Поле операндов подразделяется на два подполя, по одному на операнд; в случае команд формата RR в обоих подполях записаны номера регистров. В случае команд работы с памятью соответствующие подполя хранят информацию о базовом регистре и значении смещения. Такие подполя мы будем называтьадресными полями S-типа, так как они используются для представления перемещаемых адресов памяти (Storage).
Смещение в машинном языке определяется как 12-битовое целое без знака. Таким образом, минимальным смещением является 000, а максимальным FFF (числа даны в шестнадцатеричной системе). В десятичном представлении это 0 и 4095 соответственно.
Номер базового регистра задается в виде 4-разрядного двоичного целого от 00012 до 11112. что соответствует шестнадцатеричным числам от 1 до F.
Адресное поле S-типа имеет длину два байта. Первые четыре разряда определяют регистр, остальные — смещение. Символически базовый регистр изображается буквой В, а смещение — D. Эти буквы обычно дополняются числами, указывающими номер операнда, к которому данный перемещаемый адрес относится. Например, В1 — это базовый регистр, соответствующий первому операнду, a D2 — смещение для второго. В этих обозначениях
действительный адрес=0+(В)
Структура же адресного поля S-типа в машинном языке такова:
Сплошными вертикальными линиями изображены границы байтов. Прерывистые линии делят каждый байт на половины. Половина первого байта отведена для хранения номера базового регистра, остаток двухбайтового поля содержит значение смещения.
Предположим, что 12-й регистр используется в качестве базового, а значение смещения для имени LOOP равно 38. Тогда адресное поле S-типа, отвечающее операнду LOOP, будет содержать
Отметим, что заполняться должно все поле смещения, даже если оно не все требуется для записи действительного значения. В машинном языке не может быть «пробелов».
Регистр 0 запрещается использовать как базовый. Запись числа 0 в поле базового регистра указывает на отсутствие необходимости его использования; в качестве действительного адреса в этом случае выступает смещение. Таким образом, в Системе 360 возможна и абсолютная адресация, однако максимальный адрес, который можно указать таким образом, равен 4095, или FFF.
Вспомним, что четвертым шагом выполнения отдельной команды является шаг выборки операндов, на котором, если необходимо, вычисляются их адреса, и операнды выбираются и посылаются в соответствующие компоненты аппаратуры. Теперь мы знаем, что при вычислении адресов операндов производится сложение содержимого базового регистра со значением смещения.
Действительные адреса вычисляются специально предназначенной для этого схемой. Машинный адрес в конечном виде представляет собой 24-разрядное двоичное целое без знака, помещаемое в регистр адреса памяти (MAR). На шаге выборки операндов значение смещения посылается в регистр адреса памяти. Затем производится исследование подполя базового регистра S-поля. Если оно содержит 0, то содержимое регистра MAR остается неизменным, значение, хранящееся в нем, и является 24-разрядным действительным адресом. Если же в поле базового регистра не 0, то содержимое указанного регистра добавляется к значению, находящемуся в MAR. Результирующее содержимое регистра MAR определяет адрес, по которому будет произведена либо выборка операнда, либо запись.
Страничная организация виртуальной памяти
Основная статья: Страничная память
В большинстве современных операционных систем виртуальная память организуется с помощью страничной адресации. Оперативная память делится на страницы: области памяти фиксированной длины (например, 4096 байт), которые являются минимальной единицей выделяемой памяти (то есть даже запрос на 1 байт от приложения приведёт к выделению ему страницы памяти). Исполняемый процессором пользовательский поток обращается к памяти с помощью адреса виртуальной памяти, который делится на номер страницы и смещение внутри страницы. Процессор преобразует номер виртуальной страницы в адрес соответствующей ей физической страницы при помощи буфера ассоциативной трансляции (TLB). Если ему не удалось это сделать, то требуется дозаполнение буфера путём обращения к таблице страниц (так называемый Page Walk), что может сделать либо сам процессор, либо операционная система (в зависимости от архитектуры). Если страница была выгружена из оперативной памяти, то операционная система подкачивает страницу с жёсткого диска в ходе обработки события Page fault (см. свопинг, подкачка страниц). При запросе на выделение памяти операционная система может «сбросить» на жёсткий диск страницы, к которым давно не было обращений. Критические данные (например, код запущенных и работающих программ, код и память ядра системы) обычно находятся в оперативной памяти (исключения существуют, однако они не касаются тех частей, которые отвечают за обработку аппаратных прерываний, работу с таблицей страниц и использование файла подкачки).
Механизм работы
В самом простом и наиболее распространенном случае страничной организации памяти (или paging) как логическое адресное пространство, так и физическое представляются состоящими из наборов блоков или страниц одинакового размера. При этом образуются логические страницы(page), а соответствующие единицы в физической памяти называют физическими страницами или страничными кадрами (page frames).Страницы (и страничные кадры) имеют фиксированную длину, обычно являющуюся степенью числа 2, и не могут перекрываться. Каждый кадр содержит одну страницу данных. При такой организации внешняя фрагментация отсутствует, а потери из-за внутренней фрагментации, поскольку процесс занимает целое число страниц, ограничены частью последней страницы процесса.
Логический адрес в страничной системе – упорядоченная пара (p,d), где p – номер страницы в виртуальной памяти(селектор), а d – смещение в рамках страницы p, на которой размещается адресуемый элемент. Разбиение адресного пространства на страницы осуществляется вычислительной системой незаметно для программиста. Поэтому адрес является двумерным лишь с точки зрения операционной системы, а с точки зрения программиста адресное пространство процесса остается линейным. На самом деле адрес в памяти также можно указать другими способами — через константы и значения переменных, но всегда используется пара значений p и d, в явном или неявном виде. Каждый раз, при выполнении команды, процессор производит преобразование логического адреса в линейный адрес — 32-разрядный абсолютный адрес в памяти. После вычисления линейного адреса процессор преобразует его в физический адрес, по которому и производит обращение к памяти.

Преобразование адресов в страничной памяти
Описываемая схема позволяет загрузить процесс, даже если нет непрерывной области кадров, достаточной для размещения процесса целиком.
Число записей в одной таблице ограничено и зависит от размера записи и размера страницы. Используется многоуровневая организация таблиц, часто 2 или 3 уровня, иногда 4 уровня (для 64-разрядных архитектур).
Основное применение страничного преобразования адреса — организация виртуальной памяти. Виртуальная память позволяет использовать программы, требующие больший объем памяти, чем установленный на компьютере физический объем памяти. Остальная информация может быть сброшена на внешний носитель.
Управление страничным разбиением памяти обычно возлагается на специальную микросхему MMU (Memory Managment Unit — устройство управления памятью). В микропроцессоре i80486 и выше это устройство встроено в процессор.
Как и сегментация, страничная организация памяти связана с преобразованием виртуального адреса (в данном случае линейного) в физический. В страничном преобразовании базовым объектом памяти является блок фиксированного размера, называемый страницей (page).
В процессе страничного преобразования старшие 20 бит 32-х битного линейного адреса заменяются новым значением — номером физической страницы. Младшие же 12 бит линейного адреса определяют положение байта внутри страницы и остаются неизменными.
Для уменьшения размера таблицы страниц в микропроцессорах x86 предусмотрена двухуровневая схема преобразования адреса. Основой страничного преобразования служит регистр управления CR3, содержащий 20-ти битный физический базовый адрес каталога страниц текущей задачи. Предполагается, что каталог выровнен по границе страничного кадра, постоянно находится в памяти и не участвует в свопинге.
Корневая страница, называемая каталогом страниц, содержит 1024 32-х битных дескриптора, называемых элементами каталога страниц PDE (Page Directory Entry). Каждый из них адресует подчиненную таблицу страниц. Каждая из этих таблиц содержит 1024 32-х битных дескриптора, называемая элементами таблицы страниц. PTE (Page Table Entry). Каждый PTE содержит адрес страничного кадра в физической памяти.
Собственно преобразование линейных адресов в физические состоит из следующих действий:
- Старшие 10 бит 31 — 22 линейного адреса, дополненные двумя младшими нулями, служат индексом PDE.
- Средние 10 бит 21 — 12 линейного адреса, дополненные двумя младшими нулями, индексируют таблицу страниц PTE. Элемент PTE содержит 20-битный базовый адрес страничного кадра в физической памяти.
Этот базовый адрес из элемента PTE объединяется с младшими 12-ю битами линейного адреса, образуя 32-х битный физический адрес.
Meltdown
Во многих современных процессорах обнаружили уязвимость в этой системе виртуальных адресов и кэшей. Её назвали Meltdown.
Ещё немного о PML4
Перед тем как продолжить, рассмотрим немного подробнее таблицу PML4. В ней и в каждой подтаблице есть не только адрес следующей таблицы, но и биты с метаинформацией этой таблицы. Рассмотрим некоторые из них.
- P (Present) указывает на то, что далее идёт таблица следующего уровня. Если 0, то вместо указателя на следующую таблицу лежит указатель на физическую страницу без смещения. Если в PT будет лежать сразу указатель на физический сегмент, то такой сегмент будет размером 2 МБ. C 1 ГБ сегментами аналогично, только в PD-таблице.
- R/W (Read/Write) указывает на доступ для чтения. Если стоит 0, то разрешено только чтение.
- NX (No Execute) (самый левый), установленный в 1, запрещает исполнение данных как программный код.
- U/S (User/Supervisor), установленный в 0, запрещает использовать данные процессам (User, кольцо защиты 3), память может быть использована только ОС и драйверами (Supervisor, кольцо 0) (это по сути самый важный флаг для Meltdown).
- A (Accessed) указывает на то, была ли память, на которую указывает таблица, использована хотя бы раз.
Принцип работы
Наконец, перейдём к самому принципу работы уязвимости Metldown.
Ранее уже было написано о спекулятивном исполнении команд в статье об архитектуре процессора. Цитата из статьи: «Спекулятивное исполнение команд — это выполнение команды до того, как станет известно, понадобится эта команда или нет».
Суть атаки в том, что современные ОС всё своё адресное пространство отображают в адресном пространстве каждого пользователя (процесса). Другими словами добавляют в PML4-таблицу процесса указатели на подтаблицы ОС, но с флагом U/S, установленным в 0. Это сделано для того, чтобы при переключении контекста процесса уменьшить количество операций перезаписи CR3 и улучшить кэширование данных ОС с чистыми VIPT- или VIVP-кэшами (PML4 первого процесса → PML4 второго процесса вместо PML4 первого процесса → PML4 ОС → PML4 второго процесса), но эту защиту можно обойти в некоторых процессорах Intel и ARM (у AMD обнаружили только уязвимость Spectre, у которой другой принцип работы).
Некоторые ОС используют одну PML4-таблицу на всю систему, а при переключении контекста меняют только подтаблицы. Отсюда в той же Windows максимальный размер ОЗУ 256 ГБ — максимальный размер таблицы PDP.
При спекулятивном исполнении в уязвимых процессорах часть команд может выполниться до того, как будет проверено, стоит ли бит 0 в U/S флаге. Причём благодаря спекуляции код атаки может быть выполнен из недостижимого кода, например, в ветке else при всегда истинном условии в if, перед тем, как процессору станет известно, что этот код недостижим. После того, как процессор поймёт, что доступа к этой памяти нет, он обнулит результат команд доступа к памяти, сбросив соответствующие регистры, но TLB- и L1-кэш он сбрасывать не будет. А в них уже не хранится флаг U/S, поэтому процесс может получить полный доступ к успевшей закэшироваться закрытой памяти ядра ОС, ведь процессор, который нашёл нужную запись в L1 и TLB, не будет проверять её в PML4. Решается эта проблема либо аппаратно — добавлением флагов из PML4 в TLB, либо программно — удаление таблиц памяти ОС из PML4-процессов, что увеличит время смены контекста и системных вызовов.
Страничное прерывание

Обработка прерываний по отказу из-за недоступности данных.
Некоторые процессоры (MIPS) не имеют обращающегося к таблице микрокода, и генерируют отказ страницы сразу после неудачи поиска в TLB, обращение к таблице и её интерпретация возлагаются уже на обработчик отказа страницы. Это лишает таблицы страниц требования соответствовать жёстко заданному на уровне аппаратуры формату.
Причины отказа страницы (page fault):
- Не существует таблицы, отображающей данный регион
- PTE не имеет взведённого флага «страница отображена».
- Попытка обратиться из пользовательского режима к странице «только для ядра».
- Попытка записи в страницу «только для чтения».
- Попытка исполнения кода из страницы «исполнение запрещено».
Алгоритм работы страничного прерывания:
- Когда страница выгружается, ОС устанавливает бит присутствия (valid – является ли валидной ячейка) PTE=0. И там же в РТЕ записывает куда она была соответственно выгружена.
- Когда же процесс обращается к этой странице, то происходит исключение, т.к. Valid=0,т.е. бит валидности установлен в 0 – страница не использовалась.
- После того, как произошло исключение ОС передает управление обработчику страничного прерывания
- Обработчик находит то место, куда была выгружена страница
- Считывает эту страницу в фрейм физической памяти, обновляет РТЕ, ставит бит валидности (присутствия) в 1.
- В физической памяти появляется новая страница.
Обработчик отказов в ядре может загрузить нужную страницу из файла или же из области подкачки, может создать доступную на запись копию страницы «только для чтения», а может и возбудить исключительную ситуацию (в терминах UNIX — сигнал SIGSEGV) в данном процессе.
Особые случаи адресации
Перед выполнением обращения к памяти содержимое MAR проверяется для возможной фиксации ошибок, которые бывают двух типов. Ошибка первого типа фиксируется, если адреса, оказавшегося в MAR, вообще не существуют в системе, в которой выполняется программа. Крайне редко Системы 360 и 370 обеспечиваются полным набором блоков памяти, содержащим 16 777 216 байтов. Обычно объем памяти примерно равен миллиону байтов. Следовательно, в принципе возможна ситуация, когда в MAR содержится недопустимый адрес, так как максимальное значение, которое может храниться в 24-разряд- ном регистре MAR, превышает 16 миллионов. Когда окончательное значение MAR представляет адрес, не существующий в конкретной системе, фиксируется особый случай адресации и происходит прерывание выполнения программы.
Ошибка второго типа отмечается тогда, когда адрес в MAR, вообще говоря, существует в системе, но не должен быть доступен данной программе. Для программы, выполняющейся на определенном шаге задания, при подготовке этого шага к выполнению определяется область памяти, или зона, которой она может распоряжаться. В большинстве систем запись информации вне отведенной области запрещена. В некоторых системах запрещена даже выборка информации, хранящейся вне заданной зоны. Первое из этих ограничений называется защитой памяти от записи, второе — защитой памяти от записи и выборки. Эти ограничения введены для защиты операционной системы и программ пользователей от случайного или преднамеренного непредусмотренного влияния. При попытке обращения к не принадлежащей программе памяти фиксируется особый случай защиты и происходит прерывание выполнения программы.
Ошибки первого или второго типа обычно происходят вследствие неверного использования базового или индексного регистров.