Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
55
Добавлен:
21.05.2015
Размер:
108.03 Кб
Скачать

8

Лекция 16

6.1.7. Виртуальная память в компьютере Pentium II

Напомним, что в примерах мы рассматриваем 32-разрядный (защищенный) режим работы этого процессора. Pentium II имеет сложную систему виртуальной памяти, которая использует вызов страниц по требованию, чистую сегментацию и сегментацию с разбиением на страницы. Виртуальная память поддерживается двумя видами таблиц: LDT (Local Descriptor Table - локальная таблица дескрипторов) и GDT (Global Descriptor Table - глобальная таблица дескрипторов). Каждая программа имеет свою собственную LDT, а единственная GDT разделяется всеми выполняющимися программами. Таблица LDT описывает локальные сегменты каждой программы (ее код, данные, стек и т. д.), а таблица GDT описывает системные сегменты, в том числе саму операционную систему.

Чтобы получить доступ к сегменту, Pentium II вначале загружает селектор сегмента в один из сегментных регистров. Во вре­мя выполнения программы регистр CS содержит селектор сегмента кода, DS - селектор сегмента данных, SS – селектор сегмента стека и т. д. Каждый селектор представляет со­бой 16-битное число.

Биты 0-1 связаны с защитой (уровень привилегий). Бит 2 селектора показывает, является сегмент локальным или глобаль­ным (то есть к какой из двух таблиц он относится: 1~LDT, 0~GDT). Оставшиеся 13 битов определяют номер соответствующего эле­мента в таблице дескрипторов, поэтому объем каждой из двух таблиц ограничен величиной 213 = 8К сегментных дескрипторов.

Дескриптор с номером 0 недействителен и при попытке использования вызывает ловушку. Тем не менее его можно загрузить в ре­гистр, чтобы показать недоступность сегмента.

Когда селектор загружается в сегментный регистр, соответствующий дескрип­тор автоматически выбирается из LDT или GDT и сохраняется во внутренних регистрах контроллера управления памятью, поэтому к нему можно быстро получить доступ. Дескриптор состоит из 8 байтов. Здесь содержится базовый адрес сегмента, его размер и другая информация. Формат селектора подобран с целью упростить нахождение дескриптора в таблице. Сначала на основе бита 2 в селекторе выбирается локальная таблица дескрипторов LDT или глобальная таблица дескрипторов GDT. Затем селектор копируется во временный регистр контроллера управления памятью (MMU), а три млад­ших бита принимают значение 0, в результате 13-битный индекс селектора умножа­ется на 8 (это и есть длина дескриптора). Наконец, к нему прибавляется адрес LDT или GDT (он хранится в одноименных внутренних регистрах MMU), и в результате получается указатель на дескриптор. Например, селектор 72 = 0x48 обращается к элементу 9 в глобальной таб­лице дескрипторов, который находится в ячейке с адресом GDT+72.

Рассмотрим поля дескриптора сегмента.

31<--------------------------------------------- 32 бита -------------------------------------------->0

Адрес

Base 15-0

Lim 15-0

0

Base 31-24

G

D

X

U

Lim19-16

P

DPL

S

Type

A

Base 23-16

4

Здесь

Base - 32-битный начальный адрес сегмента в линейном физическом адресном простран-

стве (может быть невыровненным);

Lim (Limit) - 20-битный размер сегмента в элементах (см. G) минус 1;

G (Granularity) - бит гранулярности, задающий величину сегментного элемента:

0 ~ байт,

1 ~ cтраница (обычно 4 Кбайт); таким образом, максимальный размер

сегмента может составлять 1Mb байтов или 1Mb страниц (4Gb);

P (Present) - бит присутствия, содержащий 1 если сегмент находится в физической памяти;

DPL (Descriptor Privilege Level) - двубитное поле уровня привилегий, соответствующего

сегменту;

S (System) - признак системного объекта (0 ~ системный);

Type - 3 бита, определяющие целевое использование сегмента (данные, код, стек,

разрешение чтения и записи);

A (Accessed) - бит доступа, устанавливаемый при обращении к сегменту;

D (Default Size) - бит размера по умолчанию, который задает размер операндов в сегменте:

0 ~ 16 битов, 1 ~ 32 бита; в сегменте кода это соответствует 16-

битному коду 80286 и 32-битному Pentium;

X - зарезервированный бит;

U (User) - предназначен для использования программистами, процессор его игнорирует;

Pentium II поддерживает 4 уров­ня защиты памяти, где 0 - самый привилегированный, а 3 - наименее привилегированный. Любой сегмент в системе принадлежит определенному уровню (указывается в DPL). В каждый момент работающая программа также находится на определенном уровне привилегий. Уровень привилегий выполняющегося кода называется CPL (Code Privilege Level). Он копируется из DPL сегмента кода при загрузке регистра CS в его два младших разряда - поле RPL. Значение CPL можно считать текущим уровнем привилегий процессора.

Заметим, что ОС может использовать не все уровни защиты. Так UNIX и Windows NT используют 2 уровня , OS/2 – 3 уровня.

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

Бит S содержит признак системного объекта. Дело в том, что подобный механизм (таблица дескрипторов) используется не только для поддержки LDT и GDT. Аналогичную структуру имеет, например, таблица дескрипторов прерываний (IDT). Ее элементы определяют адреса обработчиков системных прерываний.

“Разбросанность” полей Base и Lim (их части – в двух словах) объясняется тем, что в ранних версиях процессоров (80286) эти поля были короче и затем расширялись с сохранением обратной совместимости. Во время работы процессора части полей объединяются.

Заданная в выполняемой команде пара {селектор, смещение} с использованием дескриптора сегмента трансформируется в линейный адрес. Если при этом сегмент отсутствует (P=0), то срабатывает ловушка и операционная система загружает сегмент в память. Проверяется также, не выходит ли смещение за пределы сегмента (если выходит, то также срабатывает ловушка). Если сегмент находится в памяти, а смещение не выходит за границу, Pentium II прибавляет величину Base из дескриптора к смещению, в ре­зультате чего получается линейный адрес памяти.

Далее действует страничная организация. Если разбиение на страницы отключено (это определяется битом PG в регист­ре глобального управления CR0), линейный адрес интерпретируется как физический адрес и отправляется в память для чтения или записи. Если разбиение на страницы используется, то линейный адрес рассматривается как виртуальный и отображается в физический адрес с ис­пользованием таблиц страниц. Дополнительная слож­ность здесь состоит в том, что при 32-битном виртуальном адресе и страницах по 4К сегмент теоретически может содержать 1 миллион страниц. Поэтому для сокращения размеров таб­лиц применяется двухуровневое отображение

каталог страниц (таблица таблиц) -> таблица страниц -> страничный кадр

Все таблицы имеют фиксированный размер, соответствующий величине одной страницы (1024 дескриптора по 32 разряда = 4Kb). Таким образом, таблицы сами могут загружаться и выгружаться. Одна таблица - каталог страниц - всегда находится в физической памяти. Ее абсолютный адрес содержится в регистре CR3.

Элемент таблицы страниц похож на элемент таблицы дескрипторов сегментов, но имеет более простую структуру. Он так же содержит базовый адрес (адрес страничного кадра - 20 битов, еще 12 младших считаются нулями), бит присутствия, бит обращения и т.д. Однако там нет полей типа и размера, т.к. все страницы одинаковы. Поле привилегий состоит всего из одного бита U/S (User - соответствует DPL = 3 / Supervisor - соответствует DPL = 0, 1, 2).

Линейный виртуальный адрес считается разбитым на три поля: DIR (биты 31-22, справа дополняются двумя нулями), PAGE (биты 21-12, также дополняются двумя нулями) и OFFSET (11-0). Поле DIR используется в качестве индекса в каталоге страниц для нахождения указателя на нужную таблицу страниц. Поле PAGE применяется как индекс в таблице страниц для нахождения физического адреса странич­ного кадра. Наконец, поле OFFSET прибавляется к адресу страничного кадра, и таким образом из линейного адреса полу­чается физический адрес нужного байта или слова.

Чтобы уменьшить количество повторных обращений к памяти, устройство управления па­мятью Pentium II (MMU) имеет аппаратную поддержку для хранения не­давно использовавшихся комбинаций DIR-PAGE и их отображения в физичес­кие адреса.

Взаимное расположение сегментов и страниц может быть произвольным. Сегменты могут пересекаться, начинаться с любого адреса. Сегмент может включать несколько страниц или содержаться внутри страницы. Страницы же всегда выровнены и расположены последовательно. Сегментация в 32-разрядном режиме Pentium действует всегда, в то время как страничное преобразование необязательно. Таким образом, страничная организация невозможна без сегментации. Если же некоторое приложение не нуждается в сегментации и до­вольствуется единым 32-битным адресным пространством со страничной органи­зацией, то это можно смоделировать. Все сегментные регистры могут быть заполнены од­ним и тем же селектором, дескриптор которого содержит поле Base=0, и поле Lim с максимальным значением. Смещения команд будут тогда линейными адресами в единственном адресном пространстве.

6.1.8. Виртуальная память UltraSPARC II

UltraSPARC II поддерживает виртуальную память со страничной организацией и с 64-битными адресами. По ряду причин программы не могут использовать полное 64-бит­ное виртуальное адресное пространство, и для адресов используются только 44 бита. Допустимая виртуальная память делится на 2 зоны по 243 байтов каждая, одна из которых находится в верхней час­ти виртуального адресного пространства, а другая - в нижней. Между ними нахо­дится “пустота” с неиспользуемыми адресами. Максимально возможная физическая память компьютера UltraSPARC II составляет 241 бай­тов (2200 Гбайт). Поддерживаются 4 размера страниц: 8 Кбайт, 64 Кбайт, 512 Кбайт и 4 Мбайт.

Из-за огромного виртуального адресного пространства использование обычных таблиц стра­ниц (подобно Pentium II) было бы непрактичным. В UltraSPARC II применяется другой подход. Устройство управления памятью содержит таблицу - TLB (Translation Lookaside Buffer - буфер быстрого преобразова­ния адреса). Эта таблица отображает номера виртуальных страниц в номера фи­зических страничных кадров. Для страниц размером в 8К существует 231 номеров виртуальных страниц, то есть более двух миллиардов. Поскольку все они не мо­гут быть отображены, TLB содержит лишь номера самых последних использованных вирту­альных страниц. Страницы команд и данных обрабатываются отдельно. Для каждой из двух категорий в TLB хранятся номера 64-х последних виртуальных страниц. Элемент TLB содержит номер виртуальной страницы и соответствующий ему номер физического страничного кадра.

Каждый работающий процесс имеет собственный номер контекста. При обращении к памяти ее виртуальный адрес (вместе с номером контекста) передается контрол­леру управления памятью. По этому адресу он вычисляет номер содержащей его виртуальной страницы и смещение в ней. Затем с помощью специальной микросхемы он сравнивает номер виртуальной страницы одновременно со всеми элементами TLB (для контекста данного процесса). Если обнаруживается совпаде­ние, то из TLB выбирается соответствующий номер страничного кадра, который объединяется с полученным ранее смещением, чтобы получить 41-битный физический адрес и обработать некоторые флаги (например, биты защиты).

Если совпадение не обнаружилось (происходит промах в TLB), то вызы­вается ловушка в операционной системе. Обрабатывать такую ошибку должна сама ОС. Заметим, что данный промах отличается от ошибки отсут­ствия страницы. Промах буфера TLB может также произойти, если нужная страница присутствует в памяти, но давно не использовалась. В обоих случаях можно заново загрузить страницу в память и сформировать новый элемент TLB. Теоретически это может сделать сама операционная система, но для ускорения данной операции к работе обычно подключается аппаратное обеспечение. Для определения удаляемого элемента буфера TLB аппаратура применяет алгоритм LRU. Другой путь при промахе TLB - использовать дополнительные таблицы.

Операционная система может также сохранять наиболее часто используемые эле­менты буфера TLB в таблице под названием TSB (Translation Storage Buffer - буфер хранения преобразований). Эта таблица работает для виртуальных страниц подобно кэш-памяти прямого отображения (см. п. 4.3.1). Каждый 16-байтный элемент данной таблицы указывает на одну виртуальную страницу и содержит определенную информацию о ней (бит достоверности, номер контекста, тег виртуального адреса, номер физической страницы и несколько флаговых битов). Пусть, например, размер TSB составляет 8192 элемента (213). Тогда все виртуальные страницы, у которых младшие 13 битов виртуального адреса равны 0000000000000, будут претендовать в TSB на элемент 0. Аналогично страницы с последними цифрами адреса 0000000000001 соответствуют элементу 1 и т. д. Размер этой таблицы опреде­ляется программным обеспечением и передается в контроллер управления памя­тью через специальные регистры, доступные только операционной системе.

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

Операционная система может использовать для хранения информации о загруженных страницах другие дополнительные таблицы, не поддерживаемые непосредственно аппаратурой. Обращение к ним может происходить при промахах TSB. Это позволяет уменьшить количество повторных загрузок страниц в физическую память.

6.2. Файлы

Набор команд уровня операционной системы предоставляет возможности ввода-вывода. С другой стороны, ввод-вывод возможен также и на уровне системы команд. Это пересечение, но не дублирование, т.к. ввод-вывод на двух указанных уровнях существенно отличается. Разработка ввода-вывода на уровне ОС преследует две основные цели: упрощение доступа к внешним устройствам и защита информации. По аналогии с памятью, ввод-вывод на уровне ОС также можно назвать виртуальным.

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

  1. Аппаратура диска не смогла выполнить позиционирование.

  2. В качестве буфера определен несуществующий элемент памяти.

  3. Процесс ввода-вывода начался до того, как закончился предыдущий.

  4. Ошибка синхронизации при считывании.

  5. Обращение к несуществующему диску.

  6. Обращение к несуществующему цилиндру.

  7. Обращение к несуществующему сектору.

  8. Ошибка проверки записи после операции записи.

При наличии одной из этих ошибок устанавливается соответствующий бит в регистре устройства.

Один из способов организации виртуального ввода-вывода - использование абстракции под названием файл. Файл состоит из последовательности байтов, записанных на устройство ввода-вывода. Для устройств, которые являются устройствами хранения информации (например, диск), файлы можно считывать и записывать. Для некоторых устройств файлы можно только считывать (клавиатура) или только записывать (принтер). Хранимые файлы имеют содержимое разной структуры, длины и обладают различными свойствами.

Ввод-вывод файла на уровне ОС осуществляется с помощью сис­темных вызовов для открытия, чтения, записи и закрытия файлов. Перед обменом информацией файл нужно открыть. Процесс открытия файла позволяет операци­онной системе найти файл на диске и передать в память информацию, необходи­мую для доступа к нему. Системный вызов для считыва­ния/записи должен иметь как минимум следующие параметры:

  • какой именно открытый файл нужно считывать/записывать;

  • буфер в памяти для обмена данными;

  • количество считываемых/записываемых байтов.

Подобный системный вызов помещает данные из внешней памяти в буфер (или обратно). Обычно он возвращает число считанных/записанных байтов (оно может оказаться меньше запрашиваемого). С каждым открытым файлом связан указатель текущей позиции. Он сообщает, какой байт может считываться (или записываться) следующим. После команды read/write указатель передвигается на чис­ло считанных/записанных байтов, поэтому последовательные команды read считывают по­следовательные блоки данных из файла. Когда программа заканчивает считывание файла, она может закрыть его (этим она сооб­щает системе, что больше не будет использовать данный файл).

В современных операционных системах файл может быть устроен сложнее, чем просто последовательность байтов. Он может быть последова­тельностью логических записей, каждая из которых имеет определенную структуру. Некоторые ОС различают файлы, в которых все эле­менты имеют одинаковую структуру, и файлы, содержащие разные типы данных. Стандартная виртуальная команда ввода считывает очередную запись из нужно­го файла и помещает ее в основную память, начиная с определенного адреса. Стандартная виртуальная команда вывода записывает логическую запись из па­мяти в файл.

Один из основных вопросов реализации файлов - распределе­ние дисковой памяти. Единичный блок файла чаще всего со­стоит из нескольких смежных секторов. Последовательно расположенными файлами легко управлять, но если максимальный размер файла неизвестен заранее, то эту техноло­гию использовать нельзя. Обычной нормой для жестких дисков является фрагментированное расположение блоков файла. Таким образом, прикладной программист воспринимает файл как линей­ную последовательность байтов или логических записей, в то время как ОС рассматривает его как упорядоченный (необязательно последовательный) набор единичных блоков на диске. Поэтому для правильного позиционирования внутри файла ОС поддерживает специальную структуру (индекс файла), которая ставит в соответствие единичным блокам или логическим записям файла их физические адреса на диске. Индекс файла организуется в виде таблицы (UNIX) или связного списка (Windows 98) и хранится в основной памяти. Существуют и более сложные файловые системы.

Иногда каждая логическая запись имеет ключ, и программы могут обращать­ся к записи по этому ключу, а не по номеру. В этом случае каждый элемент таблицы должен содержать не только информацию о местона­хождении записи на диске, но и ее ключ.

Чтобы распределить для файла пространство на диске, операционная система должна следить, какие блоки доступны, а какие уже заняты другими файлами. Один из способов - ­хранить список всех неиспользованных пространств, состоящих из смежных единичных блоков. Он называется списком свободной памяти. Альтернативный подход - сохранить битовое отображение, один бит на еди­ничный блок. Бит со значением 1 показывает, что соответствующий блок занят, а бит со значением 0 показывает, что блок свободен. Первый подход позволяет легко находить промежуток определенной длины, зато битовая карта имеет постоянный размер. Оба метода требуют, чтобы при записи или удалении файла поддерживающая структура (список раз­мещения или битовая карта) обновлялась.

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

В современных ОС файлы группируются в директории. Это позволяет избежать конфликтов имен файлов, присваивать группам файлов общие свойства (например, схемы защиты), легко выполнять групповые операции над файлами (перемещение, удаление, …).

Каждая директория обычно сама представляет собой файл и как таковая может быть вставлена в другую директорию, в результате чего получается дерево директорий. Большое количество директорий важно для програм­мистов, работающих над несколькими проектами. Директории - это также удобный способ делить файлы между членами рабочих групп.

6.3. Параллельная обработка

Интерес к параллельной обработке вызван потребностью повышения эффективности вычислений. Согласно законам физики, возможности увеличения производительности за счет быстродействия одного процессора ограничены. Однако решение многих задач можно разделить на независимые части, которые могут выполняться параллельно несколькими микросхемами. Параллельное выполнение соответствует организации реального мира, в котором задачи часто решаются коллективами специалистов. Даже имея один процессор, можно сэкономить время, если разделить задачи обмена данными (работает контроллер) и вычисления (работает процессор). В компьютере же с несколькими процессорами каждый из нескольких взаимодей­ствующих процессов можно приписать к одному определенному процессору, что­бы выполнять одновременно несколько действий.

Если имеется толь­ко один процессор, эффект параллельной обработки можно смоделировать. Для этого процессы будут выполняться по очереди, каждый понемногу. В этом случае говорят, что процессор разделяется несколькими процессами. Таким образом, можно разрабатывать программы, которые будут корректно работать как на одном, так и на нескольких процессорах, при этом во втором случае более эффективно. Для реализации этого механизма нужна поддержка операционной системы.

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

В современных ОС каждая программа выполняется как часть некоторого процесса. Этот процесс характеризуется текущим состоянием и адресным пространством, посредством которого можно получить доступ к программам и данным. Состояние включает счетчик команд, слово состояния программы, указатель стека, ре­гистры общего назначения и другую информацию. Большинство ОС позволяют одним процессам динамически формировать другие процессы. Для этого применяется системный вызов. В одних случаях исходный процесс сохраняет кон­троль над порожденным процессом. Виртуальные команды позволяют исходному процессу останавливать, запускать, проверять и завершать подчиненные процессы. В других случаях исходный процесс никак не контролирует порожден­ный процесс, тогда эти два процесса работают независимо друг от друга.

Многие операционные системы позволяют создавать параллельные линии выполнения в пределах одного процесса – потоки. В отличие от процессов, потоки одного процесса существуют в едином адресном пространстве и соответственно имеют широкие возможности для использования общих данных и процедур. Использование параллельных потоков существенно повышает сложность программирования и обычно требует самой высокой квалификации разработчика.

Во многих случаях параллельные процессы (потоки – тем более) должны взаимодействовать, и их работу нужно синхронизировать. Это требуется, например, при использовании ими разделяемых данных или кода. Многие ОС предоставляют различные средства синхронизации. Рассмотрим одно из них – семафоры (поддерживаются в Windows NT и UNIX). Данный способ синхронизации был предложен Э. Дейкстрой. Семафор – это переменная в памяти на уровне ОС, которая может содержать неотрицательные целые числа, причем задается также ее верхняя граница. Операционная система предоставляет два системных вызова, up и down, которые оперируют семафорами. Up прибавляет 1 к семафору, down - вычитает. Если операция down совершается над семафором, значение которого больше 0, этот семафор уменьшается на 1 и про­цесс продолжается. Если значение семафора равно 0, то операция down не может завершиться. Тогда данный процесс отключается до тех пор, пока другой процесс не выполнит операцию up над этим семафором.

Команда up проверяет, не равен ли семафор нулю. Если он равен 0 и другой процесс находится в режиме ожидания, то семафор увеличивается на 1. После это­го “спящий” процесс может завершить операцию down, установив семафор в 0. Теперь оба процесса могут продолжать работу. Если семафор не равен 0, ко­манда up просто увеличивает его на 1. У семафорных команд есть важное свойство: если один из процессов начал выполнять над ним команду, то другой процесс не может получить доступ к этому семафору до тех пор, пока пер­вый не завершит выполнение своей команды или не будет приостановлен при попытке выполнить команду down над 0. Другими словами, операции над семафором неделимы.

Соседние файлы в папке Архитектура ЭВМ