Сказка о двух размерах адреса
Сказка о двух размерах адреса
Появление новых RISC-моделей с полностью 64-разрядными аппаратными адресами устранило большинство проблем, связанных со смешением 64- и 48-разрядной адресации в предыдущих моделях. Чтобы понять, почему 64-разрядный аппаратный адрес так важен, рассмотрим первоначальную 48-разрядную реализацию.
48-разрядный адрес появился в результате компромисса. Проектировщики ОС System/38 планировали адрес размером в 64 бита. После того, как размер указателя был определен в 16 байтов, для 64-разрядного адреса появилось достаточно места. Проблемы возникли на аппаратном уровне. Чем больше разрядов в адресе, тем больше размер регистров процессора. Больший размер регистров требовал большего числа цепей и повышал стоимость аппаратных средств.
Техническим менеджером System/38 был Рей Клотц, не видевший надобности в таком большом адресе. Его многократно пытались уговорить, но Рей так и не поддался на уверения, что 64-разрядного адреса хватит навечно. В середине 70-х годов подразделение IBM по мэйнфреймам собиралось объявить о новом большом адресе для System/370, получившем название расширенной адресации (XA). С применением ХА адрес System/370 должен был вырасти с 24 до 31 разряда. Рей обвинял нас в желании непременно превзойти System/370 и утешал тем, что 32 разряда все равно больше чем 31. «Вы побьете их и одним разрядом, а больше и не надо», — как бы говорил он. Мы, в свою очередь, утверждали, что 32-разрядный адрес не будет работать с одноуровневой памятью System/38, и что нужны 64 разряда. Когда стало очевидным, что спор зашел в тупик, мы поступили так, как будто торговались о цене подержанной машины: поделили пополам разницу между 32 и 64. Таким образом, получился 48-разрядный адрес.
Для поддержки сегментированной памяти 48-разрядный адрес разделяется надвое. Старшие разряды задают сегмент, а младшие, называемые смещением — байт внутри сегмента. Мы решили использовать для задания сегмента старшие 32 разряда, а для смещения — младшие 16, назвав все это адресом 32/16. 16 разрядов смещения означали размер сегмента в 64 КБ (216 = 64 КБ).
Оригинальная аппаратура процессора System/38 имела 16-разрядный тракт данных и 16-разрядный сумматор для вычислений. Смысл использования адреса форматом 32/16 был в том, чтобы смещение адреса не выходило за размер тракта данных, так как очень часто обновлялось. Мы решили обрабатывать 32-разрядный идентификатор сегмента не в тракте данных процессора, а вне его, в отдельном наборе сегментных регистров. К этим сегментным регистрам был возможен доступ со стороны процессора, но они не могли обновляться «на месте».
Программисты, отвечавшие за ПО ОС ниже MI (первоначально VMC) не были согласны с такой адресацией (32/16), так как считали, что размер сегмента в 64 КБ слишком мал. Первоначально они предполагали создать сегментные группы, каждая из которых содержала бы один или несколько таких 64-килобайтных сегментов, но, в конце концов, решили, что сегментная группа всегда должна состоять из 256 сегментов. При выделении нового сегмента как части вновь создаваемого объекта его размер всегда будет равен 16 МБ (256 Г 64 КБ = 16 МБ). С этого момента мы говорили о 64-килобайтных и 16-мегабайтных сегментах, впрочем, называя иногда вторые сегментной группой. Этот разнобой в терминологии продолжался до появления процессоров PowerPC и SLIC. Если Вы возьмете в руки калькулятор или таблицу степеней двойки, то поймете, почему программисты VMC, имевшие дело с 16-мегабайтными сегментами, рассматривали 48-разрядный адрес как имеющий 24-разрядный идентификатор сегмента и 24-разрядное смещение (ведь 224 = 16 МБ).
Представление адреса 24/24, использовавшееся VMC, не совпадало с представлением 32/16, использовавшимся аппаратурой. Возник вопрос: каким способом обрабатывать переполненное поле смещения адреса? Рассматривая объекты, мы говорили, что они состоят из одного или нескольких несмежных сегментов, и что ни один сегмент не может содержать части более чем одного объекта. Очевидно, что смещение адреса за границу сегмента в следующий сегмент нежелательно, так как последний может относиться к другому объекту. Следовательно, такое смещение, например, адреса в пространственном указателе за пределы ассоциированного пространства объекта, надо предотвратить. Определяется такое переполнение адреса следующим способом: после каждого увеличения адреса проверяется, не было ли переноса из разрядов смещения в разряды идентификатора сегмента. Такой перенос и означает попытку обратиться к следующему сегменту.
Подобные ошибки переполнения могут легко отслеживаться аппаратно, для чего используется механизм прерываний[ 66 ]. Прерывания будут рассмотрены в главе 9, но одно из них мы обсудим прямо сейчас: переполнение эффективного адреса (ЕАО).
Разберем ситуацию, возникавшую в System/38 при переполнении 16-разрядного смещения. В этом случае аппаратура не увеличивала 32-разрядную сегментную часть адреса. Вместо этого об исключительной ситуации сообщалось VMC, который в каждом конкретном случае заново оценивал ситуацию. VMC рассматривал сегменты, как имеющие длину 16 МБ и состоящие из 256 аппаратных сегментов меньшего размера, и поэтому переполнение 64-килобайтного сегмента в середине 16-мегабайтного сегмента переполнением не считал. С его точки зрения — представления адреса 24/ 24 — переполнением считался только перенос из младших 24 разрядов в старшие 24.
При каждом прерывании по ЕАО VMC увеличивал 32-разрядный аппаратный идентификатор сегмента, проверял, нет ли переноса в старшие 24 разряда, и если обнаруживал, что все в порядке, управление возвращалось аппаратуре. Таким образом, мы постоянно сталкивались с несовпадением схем 32/16 и 24/24.
Когда с течением времени ширина тракта данных процессора выросла с первоначальных 16 до 32, а затем до 48 разрядов, разделение регистров сегмента и смещения в аппаратуре стали менее важны. В IMPI-моделях AS/400 были добавлены команды для поддержки адреса 24/24, что исключило необходимость программной обработки переполнений. Однако в целях совместимости с оригинальным VMC, представление 32/ 16 было в IMPI сохранено.
Эта проблема с адресами была не единственной в оригинальном VMC. Он должен был поддерживать 64-разрядный адрес в указателе MI на аппаратуре с 48-разрядным адресом. Можно было бы попытаться рассматривать 64-разрядные адреса как виртуальные адреса большего размера, которые каким-то образом отображаются в меньшие 48-разрядные виртуальные адреса, но такое решение было отвергнуто. Вместо этого, старшие 16 разрядов 64-разрядного адреса стали рассматриваться как отдельное значение. Мы назвали это 16-разрядное поле расширением идентификатора сегмента, обозначив его номером IPL. При всякой перезагрузке системы номер IPL увеличивался на единицу, что каждый раз давало новое 48-разрядное адресное пространство. На рисунке 8.2 показаны поля, составляющие 64-разрядный адрес в указателе MI.
Рисунок 8.2. Оригинальный формат адреса указателя MI
Первоначально заголовок сегмента, описанный в главе 5, содержал поле с 16-разрядным расширением идентификатора этого сегмента. Когда программа MI пыталась использовать указатель на System/38 и на ранних моделях AS/400, для проверки битов тега и загрузки 48-разрядного адреса в процессорный регистр, использовалась специальная команда IMPI под названием «Загрузить и проверить теги» («lvt»). Команда «lvt» аналогична «lq» на RISC-процессорах, но у первой была дополнительная задача. Она должна была сравнить старшие 16 разрядов адреса в указателе с полем расширения идентификатора в заголовке сегмента и гарантировать их совпадение с адресом сегмента. После первого обращения для доступа к сегменту использовался только 48-разрядный адрес.
Как уже говорилось, всякий раз при увеличении номера IPL мы получали новое адресное пространство для временных объектов. Временные объекты разрушаются при выполнении IPL, в отличие от постоянных, продолжающих существовать и после перезагрузки. Так как аппаратура использовала только 48 разрядов, один и тот же 48-разрядный адрес не мог быть задействован для постоянных объектов повторно, за исключением случая, когда постоянный объект по этому адресу был явно удален во время предыдущего сеанса работы ОС. Тогда от него оставались только заголовки, что обнаруживалось при первом использовании полного 64-разрядного адреса, начальные 16 разрядов которого содержат номер IPL. Так как номера IPL различались, то при повторном использовании 48-разрядного адреса конфликтов не возникало. Еще раз подчеркну, что заголовки сохраняются только при разрушении постоянных объектов — при разрушении временного объекта не остается ничего.