4.1. Программная модель пользователя

4.2. Адресация памяти

4.3. Программная модель системного программиста

4.4. Поддержка архитектуры IA-32

4.1. Программная модель пользователя

64-разрядный микропроцессор фирмы Intel ITANIUM (Itanium II) представляет RISC-процессор, имеющий большое число внутренних регистров, фиксированный формат машинной команды и ряд других особенностей, характеризующих процессоры данного вида. Фиксированный формат машинной команды позволяет эффективно организовать конвейер команд за счет однотипности действий процессора. Большое число регистров и особенности их использования позволяют свести до минимума количество обращений к оперативной памяти. Это приводит к увеличению быстродействия процессора.

Архитектурно Itanium не похож на 32-разрядные процессоры предыдущих поколений (имеются в виду процессоры фирмы Intel). Itanium поддерживает программную модель и систему команд 32-разрядных процессоров (IA-32 архитектура). В любой момент процессор может выполнять либо базовый поток команд Itanium, либо поток команд IA-32. Для переключения с одного потока команд на другой есть специальные команды. Команда jmpe (команда IA-32) переключает процессор на базовый поток команд, а команда br.ia (базового потока – «branch IA») – на поток IA-32. При выполнении потока IA-32 процессор ассоциирует часть своих внутренних регистров с регистрами процессора класса Pentium III (смотри разд. 4.5), переходя на программную модель 32-разрядного процессора. Операционную систему (ОС), предназначенную для Itanium, можно написать в одном из трех вариантов:

- поддерживает только поток команд IA-32;

- поддерживает только базовый поток команд;

- поддерживает микширование потоков.

На Itanium можно использовать ОС: Windows 95, 98, 2000,...XP… Команды базового потока совсем не похожи на хорошо известный Ассемблер 16- и 32-разрядных процессоров. Например, привычный для нас фрагмент кода на обычном Ассемблере

        cmp eax, ebx

        jne m1

        add ebx, 7

        jmp m2

m1: add ebx,10

m2:  ………

; сравнить содержимое регистров

; если не равно – прыжок на m1

; если равно – прибавить к ebx 7

; прыжок на m2

; если не равно – прибавить к ebx 10

в системе команд Itanium может выглядеть примерно так:

cmp.ne р1,р2  =  r1,r2

(р2) add r4  =  r2, 7

(p1) add r4  =  r2, 10

// сравнить содержимое регистров r1 //   // иr2, по результатам сравнения // установить значения предикатов р1 // и р2 (р2 = 1, если r1 = r2, а p1 – в // противном случае)

// выполняется, если р2 = 1, результат в // r4

// выполняется, если р1 = 1, результат в // r4

Как и в других процессорах, в Itanium можно выделить программную модель пользователя и программную модель системного программиста.

Регистры пользователя доступны на любом уровне привилегий, хотя для некоторых из них на любом уровне привилегий доступны только определенные поля, а не весь регистр в целом. Системные регистры доступны только на 0-м уровне привилегий.

Набор внутренних регистров Itanium очень велик, поэтому не представляется возможным отобразить их на одном рисунке. Ограничимся их перечислением и кратким описанием. Рассмотрим регистры, составляющие программную модель пользователя  (Application Register Model).

Регистры общего назначения (General Registers). Таких регистров 128. На модели они обозначаются GR0 GR127, а в ассемблерных командах r0 – r127. Формат этих регистров – 64 значащих бита, кроме того, с каждым таким регистром ассоциирован еще один добавочный бит, называемый NaT (Not a Thing – «не вещь»). Этот бит используется для отслеживания отсроченных спекулятивных особых случаев.

Регистры общего назначения разбиты на два подмножества. Регистры GR0 – GR31 называются статическими, и они доступны любым программам и подпрограммам. В регистре GR0 навсегда «зашит» 0. Это удобно, поскольку довольно часто приходится оперировать с нулем. Статические регистры GR16 – GR31 составляют, так называемый Регистровый банк (Banked Registers). В процессоре два набора регистров GR16 – GR31. Один из этих наборов называется Банк0, другой ‑ Банк1. В любой момент доступны регистры только одного банка, регистры другого банка в это время сохраняют свое состояние. Переключение с одного банка на другой происходит при прерывании, при возврате из прерывания по команде rfi (return from interruption) или по команде bsw (bank switch).

Регистры GR32 – GR127 составляют Регистровый стек (Stacked Registers). Смысл его в максимальном уменьшении количества обращений к памяти при вызове подпрограмм и возврате из них. Программа (или подпрограмма) с помощью команды alloc выделяет в Регистровом стеке «окно» (frame), в которое входят локальные и выходные регистры. Не важно, в какой области Стека будет физически выделено это окно. Для текущей программы окно всегда начинается с GR32. Допустим, программа (подпрограмма) затребовала 8 регистров и ей выделили физически регистры GR40 – GR47. Процессор при этом автоматически установит указатель начала Стека на GR40 и этот регистр получит временное имя GR32. Остальные регистры Стека также получат временные имена:

GR41 à GR33 ……GR39 à GR127.

При вызове подпрограммы процессор автоматически проворачивает Стек таким образом, что новой подпрограмме оказываются видны только выходные регистры родительской программы (подпрограммы), а локальные регистры родительской программы оказываются недоступны. Подпрограмма может запросить свое окно в Стеке и это окно будет включать выходные регистры родительской программы. При возврате из подпрограммы окно родительской программы автоматически восстанавливается. Таким образом, в подпрограмме не надо сохранять значения регистров родительской программы (локальные регистры) и легко организовать обмен параметрами между родительской программой и подпрограммой через выходные регистры. Регистровый стек можно использовать и в качестве вращаемых регистров.

Предикаты (Predicate Registers).

Набор из 64 однобитных регистров PR0 – PR63 используется для фиксации результата в командах сравнения. Все эти регистры доступны любым программам на любом  уровне привилегий. Предикаты разбиты на два подмножества: статические предикаты (PR0 – PR15) и «вращаемые» предикаты (PR16 – PR63) (Rotation Predicate Registers). В PR0 навсегда «зашита» единица, что соответствует значению «истина». Вращаемые предикаты можно программным образом (с помощью команды alloc) переименовывать, назначая им временные номера. Используется вращение предикатов (и не только предикатов, но и других регистров) при ускоренном выполнении циклов, когда на исполнение, благодаря конвейеру, запускаются сразу несколько итераций цикла (modulo scheduling loops). Возникает необходимость для каждой итерации использовать наборы регистров, являющихся физически различными, но имеющими одинаковые временные имена, в том числе и регистры условий.

Регистры с плавающей точкой (Floating Point Registers).

Набор из 128 (82-разрядных) регистров FR0 – FR127. Регистры доступны на любом уровне привилегий. Набор разбит на два подмножества: статические регистры (FR0 – FR31) и вращаемые регистры (FR31 – FR127). В FR0 навсегда зашито 0.0, а в FR11.0. Назначение вращаемых регистров аналогично назначению вращаемых предикатов.

Регистры переходов (Branch Registers).

Восемь 64-разрядных регистров, в которые можно записать целевые адреса для косвенных переходов. Доступны на любом уровне привилегий.

Указатель команды (Instruction Pointer).

64-битный регистр (IP), сохраняющий адрес командной группы (bundle), в которой содержится выполняемая в данный момент команда. Процессор всегда считывает из памяти командную группу, содержащую три команды (по 41 биту на команду) и 5-битовое поле ‑ шаблон. Последнее задает дополнительные сведения о выполнении входящих в данную группу команд. Поскольку группа всегда 16-байтовая и всегда выровнена по соответствующей границе, младшие 4 бита IP всегда равны нулю. Содержимое IP можно прочитать с помощью команды mov ip.

Маркер текущего окна (Current Frame Marker).

38-битовый регистр CFM. Задает текущее окно в Регистровом стеке. Содержит размер окна, размер области локальных регистров и указатели на регистр общего назначения, регистр с плавающей точкой и предикат, переименованные, соответственно, в GR32, FR32 и PR16. При выполнении команды br.call (вызов подпрограммы) содержимое CFM автоматически копируется в поле Маркер предыдущего окна (Previous Frame Marker) в регистре Предыдущее функциональное состояние (Previous Function State Register), а в CFM записывается новая информация, описывающая новое окно без локальных и вращаемых регистров, но с выходными регистрами родительской программы.

Первый выходной регистр родительской программы при этом переименовывается в GR32. При возврате из подпрограммы по команде br.ret родительское окно автоматически восстанавливается, поскольку информация из PFM переписывается в CFM. Прямая запись в CFM или прямое чтение CFM невозможны.

Маска пользователя (User Mask).

6-битовое поле в Processor Status Register (см. разд. 4.5), доступное приложениям. Содержит пять флагов, определяющих способы контроля выравнивания, мониторинга производительности и др.

Регистры данных мониторинга производительности (Performance Monitor Data Registers).

Эти регистры представляют собой счетчики аппаратных и программных событий, происходящих в системе. Любая модель Itanium содержит минимум 4 пары счетчиков производительности PCM/PMD. PCM (Performance monitor configuration registers) относятся к программной модели системного программиста и доступны только ОС. В PCM задается, какие события будет подсчитывать соответствующий PMD. Сами счетчики (PMD) могут быть доступны пользователю, если имеется соответствующее разрешение ОС.

Регистры идентификации процессора (Processor identifiers).

Обозначаются CPUID0 – CPUIDN, т.е. для различных моделей число этих регистров различно. CPUID0 – CPUID4 существуют обязательно. Сколько всего регистров CPUID содержит данный процессор, задается в соответствующем поле (биты 7 – 0) CPUID3. В CPUID0 – CPUID1 в ASCII-коде задаются сведения о производителе. CPUID2 зарезервирован. В CPUID3 задаются номера семейства и модели. В CPUID4 задаются особенности, которые поддерживает данный процессор.

Регистры приложений (Application registers).

Регистровый файл AR0 – AR127 содержит самые разнообразные регистры специального назначения. В частности, в состав файла входят Регистры ядра (KR0 – KR7), через которые ОС может поставлять приложению разнообразную информацию, Интервальный таймер (ITC) и другие. Часть регистров в файле зарезервированы, а часть используется для IA-32-архитектуры.

4.2. Адресация памяти

Первым широкоизвестным процессором фирмы Intel был процессор i580. Механизм формирования физического адреса оперативной памяти (Аф) в этом процессоре был прост и понятен. Адрес брался из пары регистров или из команды. То есть программист, написав в команде адрес 0777h, мог быть уверен, что процессор обратится именно к ячейке памяти с адресом 0777h и ни к какой другой. Для программиста это удобно, но при написании ОС это приводило к неразрешимым проблемам, поскольку абсолютная адресация в корне противоречит концепции загрузки программы в произвольное место оперативной памяти.

Для преодоления этого недостатка, начиная с 16-разрядного процессора i8086, был введен сегментный механизм формирования физического адреса оперативной памяти. Теперь адрес, задаваемый в регистре или команде, представлял собой не физический адрес памяти, а смещение в некоем сегменте относительно начального (базового) адреса этого сегмента. Начальные адреса всех используемых в данный момент сегментов задавались процессору в специальных сегментных регистрах. Поскольку загрузка информации в эти сегментные регистры возлагалась в основном на ОС, никаких особых проблем при перемещении программы в памяти не возникало. Программа загружалась в первое свободное место памяти, а ОС соответствующим образом заполняла сегментные регистры. Сегментный механизм, претерпевая определенные модификации, просуществовал почти три десятилетия, вплоть до создания Pentium IV.

С появлением 32-разрядных процессоров и ОC Windows выяснилось, что и сегментный механизм, с точки зрения простоты реализации ОС, имеет существенные недостатки. При этом основная проблема была связана с реализацией концепции «виртуальной памяти», которая предполагает, что часть сегментов текущего процесса (задачи) находится в оперативной памяти, а другая часть – на жестком диске, подкачиваясь по мере необходимости. Реализация алгоритмов подкачки сегментов с диска приводила к существенным трудностям, поскольку, в общем случае, сегменты являлись разноразмерными и могли быть очень большими (превышающими имеющийся объем оперативной памяти). Попытка устранения этого недостатка привела, начиная с процессора i386, к появлению страничного механизма формирования физического адреса оперативной памяти. При этом считается, что вся память разбита на страницы фиксированного (как правило, небольшого) размера и для формирования Аф надо знать начальный адрес (или номер) страницы и внутристраничное смещение.

Страничный механизм в 32-разрядных процессорах фирмы Intel является надстройкой над сегментным механизмом. Процесс формирования физического адреса памяти можно при этом описать следующим образом:

- сначала работает сегментный механизм, формирующий так называемый линейный адрес, который является входным параметром для страничного механизма;

- страничный механизм, используя буфер TLB (translation lookaside buffer) или, если начального адреса нужной страницы в буфере нет, находящиеся в ОП таблицы страниц, транслирует полученный линейный адрес в физический.

Как следует из этого краткого экскурса, страничный механизм практически, в определенном смысле, дублирует сегментный механизм, и именно поэтому, в Itanium нет сегментного механизма, а оставлен только страничный, причем довольно серьезно модифицированный по сравнению с 32-разрядными процессорами.

Современные ОС поддерживают различные модели распределения адресного пространства. Без учета различных нюансов все эти модели можно разделить на два типа.

1. Multiple Address Space (MAS) – разделение адресного пространства между процессами. В такой модели каждому процессу выделяется уникальная область адресного пространства памяти, недоступная другим процессам.

2. Single Address Space (SAS) – единое адресное пространство. Здесь все процессы разделяют единое адресное пространство, а защита от влияния процессов друг на друга осуществляется на уровне доменов (например, страниц или групп страниц).

Механизм адресации процессора Itanium разработан с учетом аппаратной поддержки обоих типов моделей адресного пространства. Для поддержки MAS используются Регистры регионов, идентифицирующие Virtual Regions (виртуальные регионы) внутри адресного пространства. Для поддержки SAS используются механизмы защиты домена (Protection Domain mechanisms).

Формирование физического адреса памяти в Itanium происходит по следующей схеме. Из регистра общего назначения (GRi) берется 64-разрядный адрес, который называют виртуальным (Virtual Address). В соответствии с этим адресом определяется Регистр региона, содержащий Идентификатор региона. По идентификатору региона и нашему виртуальному адресу в TLB производится поиск соответствующей Записи (Запись содержит начальный адрес искомой страницы). В описании фирмы Intel Запись называют Translation Entry – элемент трансляции.

Предположим, что искомый элемент трансляции в TLB найден. Процессор проводит ряд проверок (права доступа, соответствие атрибутам страницы и другие) и, если все они прошли успешно, к начальному адресу страницы, взятому из элемента трансляции, пристыковывается внутристраничное смещение, взятое из виртуального адреса. Это и будет искомый Аф.

Если нужная Запись в TLB отсутствует, процессор может (если соответствующий механизм включен) произвести поиск искомого элемента трансляции в Хэш-таблице (VHPTVirtual Hash Page Table). Эта таблица создается в оперативной памяти операционной системой и ее местоположение процессору известно.

Если нужный элемент трансляции в Хэш-таблице найден, процессор помещает его в TLB и так далее. Если же нужный элемент трансляции отсутствует и в Хэш-таблице, то генерируется особый случай TLB Miss fault. Обработчик этого особого случая, являющийся частью ОС, может найти нужный элемент трансляции в таблицах страниц ОС и поместить его в TLB или в Хэш-таблицу. После этого происходит рестарт отказавшей команды. Этот процесс упрощенно показан на рис. 4.1.

Адресуемая процессором оперативная память представляет собой виртуальный линейный массив объемом 264 байта. Этот массив разбивается на 8 регионов объемом 261 байта каждый. Каждому из регионов присваивается 24-битовый Идентификатор региона, который записывается в один из восьми Регистров региона.

Старшие три бита (63‑61) виртуального адреса и осуществляют выбор Регистра региона, из которого будет взят Идентификатор.

Используя последовательные Идентификаторы регионов, ОС может «сливать» соседние Регионы в одно целое, образуя Регионы большего объема (до 264 байтов при слиянии всех восьми Регионов).

Адресное пространство Региона разбивается на страницы, размер которых для каждого конкретного Региона задает ОС (4 Кбайт, 8 Кбайт, 16 Кбайт, 64 Кбайт, 256 Кбайт, 1 Мбайт, 4 Мбайт, 16 Мбайт, 64 Мбайт или 256 Мбайт).

Рис. 4.1

Виртуальный адрес, взятый из 64-разрядного регистра общего назначения, условно разбивается на три поля. Разряды 63‑61 содержат Номер виртуального региона и, как уже отмечалось, задают Регистр региона, из которого считывается Идентификатор региона. Младшие биты (сколько конкретно – зависит от размера страницы) задают смещение в странице. Это смещение проходит через процесс трансляции без изменений. Оставшиеся биты содержат Номер виртуальной страницы. Процессор производит поиск нужной Записи в TLB, сравнивая соответствующие поля всех Записей с найденным Идентификатором региона и Номером виртуальной страницы.

Если нужная Запись найдена, то начинает работать Механизм защиты домена. Для работы этого механизма каждой Виртуальной странице ставится в соответствие уникальный Ключ защиты (Protection Key).

При запуске нового процесса, ОС записывает все необходимые для данного процесса Ключи защиты в специальный массив регистров (Protection Key Registers). Когда идет обращение к Виртуальной странице и нужная Запись в TLB найдена, процессор достает из этой Записи прописанный в ней Ключ защиты и сравнивает его с содержимым всех регистров массива.

Если сравнения не произошло, то возникает особый случай Key Miss fault. Если в каком-то регистре обнаружен совпадающий ключ защиты, то процессор производит дополнительную проверку на «защиту от записи», «защиту от выполнения» и «защиту от чтения». Атрибуты для этой проверки процессор берет из регистра, в котором обнаружен Ключ.

Если эта проверка оказывается неудачной, то возникает особый случай Key Permission fault.

Если все проверки прошли успешно из Записи считывается Номер физической страницы (по сути это старшие разряды физического адреса страницы) и к нему пристыковывается смещение в странице, взятое из Виртуального адреса.

В состав процессора входят два TLB: TLB команд (ITLB) и TLB данных (DTLB). Первый используется при выборке из памяти очередной команды (вернее, очередной командной группы), второй – при обращении к данным.

Каждый из этих TLB делится на два подмножества: Регистры трансляции (Translation Registers) и Кэш-трансляции (Translation Cache). Граница этих подмножеств в общем случае плавающая, т.е. ОС может сама задавать, сколько элементов TLB будут рассматриваться в качестве Регистров, сколько в качестве Кэша. Основная разница между Регистрами и Кэшем заключается в том, что Записи, хранящиеся в Регистрах меняются крайне редко, а в Кэше, если он заполнен, ‑ при каждом кэш-промахе. То есть в Регистрах ОС «зашивает» Записи, относящиеся к «критическим» областям памяти (например, область ядра ОС), а в КэшеЗаписи для «обычных» областей памяти.

4.3. Программная модель системного программиста

Модель включает в себя все рассмотренные регистры пользователя, а также регистры, доступные только на нулевом уровне привилегий.

Регистр статуса процессора (Processor Status RegisterPSR). 64-разрядный регистр, содержащит управляющую информацию для выполняемого в данный момент процесса и задает тем самым текущую конфигурацию системы. В частности, биты 33 – 31 этого регистра задают текущий уровень привилегий CPL.

Изменить CPL можно только на нулевом уровне, т.е. это прерогатива ОС.

Регистры управления (Control Registers). Регистровый файл, состоящий из большого числа (порядка восьмидесяти) 64-разрядных регистров, в котором фиксируется состояние процессора при прерывании и специфицируются глобальные процессорные параметры для прерываний и управления памятью.

Регистры отладки (Debug Breakpoint RegistersDBR/IBR). 64-разрядные регистры, в которых задаются контрольные точки останова по командам (IBR) и по данным (DBR). Контрольная точка при этом представляет собой виртуальный или физический адрес некоторого диапазона памяти. В состав процессора входят не менее четырех пар таких регистров.

Регистры конфигурации мониторинга производительности (Performance Monitor Configuration Registers PMC). Рассматривались выше (см. разд. 4.2).

Регистры регионов (Region Registers ‑ RR). Введены для поддержки MAS модели памяти (см. разд. 4.3).

Регистры ключей защиты (Protection Key Registers PKR). Введены для поддержки SAS модели памяти (см. разд. 4.3).

Буфер TLB (см. разд. 4.3).

4.4. Поддержка архитектуры IA-32

Itanium поддерживает архитектурную модель процессора класса Pentium III. Выполняя код IA-32, Itanium ассоциирует (картирует) часть своих внутренних регистров с регистрами 32-разрядных процессоров. Схема этого картирования приведена в табл. 4.1.

Таблица 4.1

Itanium

IA-32

Примечание

GR8

EAX

Разряды 31‑0 GR

GR9

ECX

-//-

GR10

EDX

-//-

GR11

EBX

-//-

GR12

ESP

-//-

GR13

EBP

-//-

GR14

ESI

-//-

GR15

EDI

-//-

GR16

DS

Разряды 15‑0 GR; видимая часть DS

GR16

ES

Разряды 31‑16; видимая часть

GR16

FS

Разряды 47‑32; видимая часть

GR16

GS

Разряды  63‑48; видимая часть

GR17

CS

Разряды 15‑0; видимая часть

GR17

SS

Разряды 31‑16; видимая часть

GR17

LDTR

Разряды 47‑32; видимая часть

GR17

TR

Разряды  63‑48; видимая часть

GR24

ES

Теневая часть ES

GR27

DS

-//-

GR28

FS

-//-

GR29

GS

-//-

GR30

LDTR

-//-

GR31

GDTR

-//-

IP

EIP

Разряды 31‑0 IP

AR24 (EFLAG)

EF

Разряды 31‑0 AR

AR25 (CSD)

CS

Теневая часть CS

AR26 (SSD)

SS

-//-

AR27 (CFLG)

CR0/CR4

-//-