OSDev Wiki
Advertisement

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

Набор механизмов определения объёмов памяти развивался вместе с ПК, однако происходило это довольно хаотично, поэтому на сегодняшний день имеется целый ряд способов для решения данной задачи.

История[]

Первые IBM PC обладали небольшим объемом памяти — от 16 или 32 килобайт и выше. Связано это было как с высокой стоимостью и низкой ёмкостью тогдашних микросхем ОЗУ, так и со скромными потребностями первых приложений, по большей части портированных с 8-разрядных персональных компьютеров.

Фирма IBM, разрабатывая свой ПК, предусмотрела для оперативной памяти диапазон адресов от нуля до 9FFFFh, то есть 640 килобайт — на рубеже 1970-80-х годов это казалось огромным объёмом, лишь мэйнфреймы и наиболее мощные мини-ЭВМ обладали большим размером ОЗУ. Впоследствии эту область памяти стали называть «базовой или стандартной памятью» (Conventional Memory или Base Memory).

Область адресов от A0000h до BFFFFh была отведена под видеопамять. Выше, от C0000h до FFFFFh, шла область ПЗУ различных устройств и BIOS. Как правило, почти все адреса в этих диапазонах были свободны.

С появлением микропроцессора 80286 физическое адресное пространство возросло до 16 Мбайт, однако доступна вся эта область была только в защищённом режиме. В то же время переключение процессора в защищённый режим делало его несовместимым с многочисленными программами реального режима, что предопределило его низкую популярность; фактически до самого появления микропроцессора 80386 защищённый режим использовался очень ограниченно.

При проектировании процессора 80286 инженерами Intel была допущена ошибка, из-за которой в реальном режиме не происходило «обрезание» адреса до 20 бит, и в результате появилась возможность адресации «лишней» памяти в области адресов 100000h-10FFEFh, общий объём которой составлял 64 Кбайта минус 16 байт. Этой областью, получившей название «Область верхней памяти» (HMA, High Memory Area), немедленно воспользовалась Microsoft: в неё помещалась изрядная часть MS DOS, оставляя свободной для нужд прикладных программ значительную часть базовой памяти. Ошибка же в процессоре была оставлена в целях совместимости с 80286, хотя её можно заблокировать с помощью специальной внешней схемы — вентиля адресной линии A20 (Gate A20), устанавливаемого на системных платах на тот случай, если потребуется обеспечить полную совместимость адресации с процессором 8086.

Микропроцессор 80386 расширил диапазон физических адресов до FFFFFFFFh (4 Гбайта), причём какую-то часть самых старших адресов занимает ПЗУ BIOS, отображающееся также частично и на старшие адреса младшего мегабайта.

В некоторых компьютерах на базе микропроцессора 80486 и во всех, начиная с Pentium, часть старших адресов занимают регистры улучшенного контроллера прерываний APIC (его конфигурационное пространство начинается с адреса FEC00000h и кончается адресом FECFFFFFh). Какая-то часть адресного пространства занята памятью режима управления системой (SMRAM) Кроме того, на адресное пространство памяти отображается ещё как минимум видеопамять, причём занимаемые ею адреса никак не стандартизированы и оставлены на усмотрение BIOS и операционной системы (исключением является область адресов A0000–BFFFF, отведённая под видеопамять ещё в первых ПК и сохраняемая для совместимости). Наконец, регистры внешних устройств, подключенных к шинам PCI, PCI Express и AGP, также могут отображаться на адресное пространство памяти, и опять-таки это оставлено на откуп BIOS и ОС.

Наконец, в старших моделях 32-разрядных микропроцессоров и во всех 64-разрядных (технологии AMD64 и Intel EM64T) объём физического адресного пространства превысил 4 Гбайта и составляет как минимум 64 Гбайта (гарантирована поддержка ширины физического адреса 36 бит, теоретический предел составляет 64 бита, а конкретная разрядность физического адреса зависит от модели процессора).

Подробнее о распределении адресного пространства памяти современных ПК можно прочитать в разделе Карта распределения памяти.

Способы определения объёма памяти[]

В процессе тестирования аппаратной конфигурации BIOS'ом объём оперативной памяти определяется считыванием служебной информации из самих модулей памяти. Однако использовать подобный способ в ОС не следует, потому что стандарты на подобные низкоуровневые механизмы могут изменяться. Например, сейчас общепринятым является стандарт SPD, однако фирма nVidia разработала свой — EPP, который расширяет возможности SPD и используется на тех материнских платах, которые его поддерживают (на всех прочих по-прежнему применяется SPD, а EPP-совместимые модули памяти всегда поддерживают и SPD). Естественно, BIOS материнской платы «знает» её аппаратные возможности, а поэтому теоретически способен правильно опознать любые поддерживаемые модули памяти (на практике некоторые BIOS'ы оказываются «капризными» и не всегда корректно определяют некоторые нестандартные модули), однако BIOS «заточен» под свою материнскую плату, а ОС должна быть универсальной.

BIOS предосталяет программам ряд вызовов, предназначенных для определения объёма и местоположения доступной оперативной памяти. На современных компьютерах практическую ценность имеют только два из них — один для определения объёма стандартной памяти и другой для определения объёма и местоположения всей памяти вообще.

Определение объёма стандартной памяти[]

Хотя физически все 640 Кбайт теоретически возможной стандартной памяти на любом современном компьютере имеются, пользоваться всей этой памятью без ограничений нельзя.

Во-первых, младший килобайт (адреса от нуля до 3FFh включительно) используется под векторы прерываний реального режима процессора, поэтому изменять эту область можно лишь с определёнными предосторожностями, точно понимая, что и для чего делается. В частности, не следует переопределять без особой нужды векторы для прерываний от 0 до 31 включительно (00h-1Fh), поскольку они установлены BIOS'ом и обеспечивают вызов его функций.

Во-вторых, сразу за первым килобайтом начинается 256-байтовая область данных BIOS, к которой примыкает ещё одна 256-байтовая область, используемая отдельными функциями BIOS (адреса от 400h до 5FFh включительно). Изменение информации в этих областях может привести к неработоспособности тех или иных функций BIOS, поэтому без особой нужды эти адреса лучше не трогать вообще, хотя, если имеется понимание, для чего служат те или иные байты в этих областях, их можно изменять для достижения каких-то своих целей.

Наконец, все современные BIOS имеют область расширенных данных реального режима, находящуюся в старших адресах стандартной памяти. Например, BIOS системной платы TYAN Tiger i7505 (чипсет Intel E7505, поддерживающий два 32-разрядных процессора Xeon семейства Pentium 4, Socket 603/604) резервирует для своих нужд 7 Кбайт, и их изменение приведёт к неработоспособности BIOS.

Наличие области расширенных данных BIOS заставляет программы определять старший адрес стандартной памяти, доступный для свободного использования. С этой целью используется функция INT 12h, существовавшая ещё на первых ПК, на которых она сообщала объём физически имеющейся оперативной памяти.

Функция INT 12h не имеет входных параметров. При возврате из неё в AX будет находиться объём стандартной памяти в килобайтах, начиная с адреса 0. Например, на упомянутой выше системной плате TYAN Tiger i7505 после вызова INT 12h в AX будет десятичное значение 633. Это означает, что программа может использовать под свои нужды стандартную память от адреса 0 до адреса 9E3FFh включительно (об ограничениях на использование адресов от 0 до 5FFh говорилось выше; эти ограничения не зависят от модели материнской платы), а адреса от 9E400h до 9FFFFh используются BIOS для своих нужд, и программа обращаться к ним не должна.

Определение объёма и карты памяти всего ОЗУ[]

Наиболее правильным методом для определения объёма и адресов имеющейся оперативной памяти на сегодняшний день является следование спецификации ACPI, которой удовлетворяют все сколько-нибудь современные ПК (её первая версия появилась в 1996 году). ACPI предусматривает три способа решения данной задачи, первый из которых предназначен для обычных ПК, второй — для компьютеров, соответствующих стандарту UEFI, а третий — для машин, обеспечивающих «горячее» добавление и удаление модулей памяти. Ниже речь будет идти только о первом способе, поскольку именно он является наиболее распространённым и поддерживается всеми существующими ПК.

Для определения объёма и карты распределения памяти спецификация ACPI предусматривает использование функции E820h прерывания INT 15h. Каждый вызов этой функции возвращает описание одного диапазона адресов оперативной памяти. Чтобы получить полную карту распределения памяти, необходимо вызывать эту функцию многократно, пока не будет получено описание последнего диапазона.

На входе в функцию E820h прерывания INT 15h передаются следующие параметры:

  • EAX — содержит код функции 0000E820h; Некоторые БИОСы требуют чтобы в верхней части eax были нули.
  • EBX — при первом вызове в этом регистре должен находиться нуль. В последующих вызовах здесь находится значение, возвращённое предыдущим вызовом функции и необходимое для продолжения её работы и возврата описания очередного диапазона адресов памяти. Это может быть начальный адрес очередной области, её порядковый номер или любое другое значение — точный смысл этой величины оставлен на усмотрение разработчиков BIOS;
  • ES:DI — указатель области памяти для сохранения очередного описателя диапазона адресов;
  • ECX — размер описателя диапазона адресов. Нынешняя версия стандарта определяет его длину в 24 байта; позже он может быть расширен. Минимально допустимый размер — 20 байтов;
  • EDX — сигнатура 'SMAP'. Используется BIOS'ом для проверки того, что программа действительно вызывает сервис ACPI.

На выходе функция возвращает следующие значения:

  • CF — если флаг сброшен, ошибок при выполнении не возникло. Обычно флаг CF устанавливается при вызове фукции уже после того, как она вернула описатель последнего диапазона адресов. Тем не менее, полагаться на это не стоит, поскольку может привести к странным ошибкам. Например, виртуальная машина Parallels просто-напросто «падала» при «лишнем» вызове этой функции;
  • EAX — сигнатура 'SMAP'. Программа должна её проверить, чтобы убедиться, что она имеет дело с ACPI-совместимым BIOS;
  • ES:DI — указатель на описатель диапазона адресов (то же самое значение, что и при вызове функции);
  • ECX — объём информации в байтах, записанной в описатель диапазона (минимум 20 байтов; не превышает длину области под описатель, указанную при вызове функции);
  • EBX — значение, необходимое для получения описателя следующего диапазона адресов; должно в неизменном виде передаваться на вход функции при её очередном вызове. Если при возврате из функции этот регистр содержит нуль, это означает, что получен описатель последнего диапазона адресов.

Формат описателя диапазона адресов, заполняемого функцией E820h прерывания INT 15h:

СмещениеОписание
0Начальный адрес диапазона, младшие 32 бита
4Начальный адрес диапазона, старшие 32 бита
8Длина диапазона, младшие 32 бита
12Длина диапазона, старшие 32 бита
16Тип диапазона (описаны ниже)
20Расширенные атрибуты диапазона (описаны ниже)

Нынешняя версия спецификации ACPI предусматривает следующие типы диапазонов памяти:

ЗначениеМнемоникаОписание
1AddressRangeMemoryДоступная оперативная память
2AddressRangeReservedЗарезервированная область памяти; использоваться программами не должна
3AddressRangeACPIОбласть памяти, занятая таблицами ACPI. Может использоваться операционной системой после того, как информация в этих таблицах станет для неё ненужной
4AddressRangeNVSЗарезервированная область памяти; использоваться программами не должна. В отличие от диапазона типа 2, эта область памяти должна сохраняться при «отходе ко сну» и восстанавливаться при «пробуждении»
5AddressRangeUnusableОбласть памяти, содержащая ошибки. Использоваться не должна
другоеUndefinedЗарезервировано для будущего использования. ОС должна рассматривать такие области как зарезервированные и не пытаться их использовать

Двойное слово расширенных атрибутов имеет следующий формат:

>
БитМнемоникаОписание
0AddressRangeEnabledЕсли содержит 0, ОС должна игнорировать этот описатель диапазона адресов (он содержит недействительную информацию)
1AddressRangeNonVolatileЕсли установлен, данный описатель соответствует устойчивой (non-volatile) памяти. Устойчивая память может потребовать уточнения своих характеристик, чтобы ОС могла понять, годится ли такая память для использования в качестве обычного ОЗУ
2-31ReservedЭти разряды зарезервированы для будущего использования

При использовании функции E820h прерывания INT 15h следует учитывать следующие соглашения и ограничения:

  • BIOS с помощью этой функции возвращает описатели только той памяти, что установлена на системной плате;
  • функция не описывает диапазоны адресного пространства памяти, занятые дополнительными ПЗУ устройств ISA и устройствами, поддерживающими технологию Plug and Play (к таковым отностся все устройства, подключаемые к шинам PCI, AGP и PCI Express, а также некоторые устройства для шины ISA), поскольку операционная система имеет другие способы узнать о существовании таких устройств и о занимаемых ими областях памяти;
  • «дыры» в адресном пространстве, предусмотренные чипсетом, но не используемые устройствами, этой функцией возвращаются как зарезервированные области памяти;
  • фиксированные (не настраиваемые с помощью Plug and Play) диапазоны адресов памяти, занимаемые регистрами устройств, установленных на системной плате (например, область, отведённая под APIC), возвращаются функцией как зарезервированные;
  • области адресов, занимаемые ПЗУ BIOS, возвращаются как зарезерированные;
  • функция не описывает стандартные диапазоны адресов, используемые в ПК для определённых целей. Например, она не описывает диапазон A0000–BFFFF, отведённый под видеопамять. Однако диапазон E0000–EFFFF может быть включён в список диапазонов, описываемых этой функцией;
  • вся стандартная («нижняя») память считается обычной, доступной для использования ОС, однако разработчик системы должен учитывать ограничения на её использование, описанные в предыдущем подразделе.

Наконец, заметим, что в некоторых BIOS в этой функции встречались ошибки. Так, однажды, когда спецификация ACPI ещё только-только «поступала на вооружение», пришлось столкнуться с ситуацией, когда эта функция вообще не сообщила о наличии диапазона памяти от 0 до BFFFFh, хотя в соответствии со стандартом должна была бы описать его как доступный для использования (тип диапазона 1). Бывали случаи, когда эта функция не упоминала о диапазоне адресов, занимаемом APIC. Поэтому разработчикам ОС не следует полагаться на эту функцию для определения областей, назначение которых и так хорошо известно и не зависит от модели системной платы.

Альтернативные способы определения объёма памяти свыше 1 Мбайта[]

Хотя все сколько-нибудь современные ПК соответствуют стандарту ACPI, в «древних» моделях он не поддерживался. В такой ситуации определить объём ОЗУ свыше 1 Мбайта можно несколькими другими способами, кратко описанными ниже. Тем не менее, пользоваться ими следует только в том случае, если ACPI не поддерживается.

Заметим, что вызов перечисленных ниже функциях в ACPI-совместимых системах вполне возможен, однако они вернут объём памяти, в который не включены служебные области, отражённые функцией E820h как недоступные для использования операционной системой.

Функция 88h прерывания INT 15h сообщает объём имеющейся оперативной памяти свыше 1 Мбайта, т.е. начиная с адреса 100000h.

На входе:

  • AH — содержит код функции 88h.

На выходе:

  • CF — если функция выполнена успешно, будет сброшен;
  • AX — объём памяти свыше 1 Мбайта, выраженный в килобайтах.

Эта функция обычно сообщает объём памяти, лежащей в диапазоне от 1 Мбайта до 16 Мбайт, то есть в области адресов от 10000h до FFFFFFh включительно. Чтобы узнать объём памяти свыше 16 Мбайт, можно воспользоваться функцией C7h прерывания INT 15h.

Функция C7h прерывания INT 15h появилась в компьютерах IBM PS/2 поздних серий и является необязательной. Она возвращает карту распределения памяти.

На входе:

  • AH — код функции C7h;
  • DS:SI — адрес карты памяти (см. ниже).

На выходе:

  • CF — если функция завершилась успешно, будет сброшен.

Формат карты памяти:

СмещениеРазмерОписание
0WORDРазмер области, отведённой под карту памяти, не включая это слово
2DWORDОбъём в килобайтах локальной памяти в пределах от 1 до 16 Мбайт
6DWORDОбъём в килобайтах локальной памяти в пределах от 16 Мбайт до 4 Гбайт
10DWORDОбъём в килобайтах системной памяти в пределах от 1 до 16 Мбайт
14DWORDОбъём в килобайтах системной памяти в пределах от 16 Мбайт до 4 Гбайт
18DWORDОбъём в килобайтах кэшируемой памяти в пределах от 1 до 16 Мбайт
22DWORDОбъём в килобайтах кэшируемой памяти в пределах от 16 Мбайт до 4 Гбайт
26DWORDОбъём в килобайтах перед началом несистемной памяти в пределах от 1 до 16 Мбайт
30DWORDОбъём в килобайтах перед началом несистемной памяти в пределах от 16 Мбайт до 4 Гбайт
34WORDНачальный сегмент крупнейшего свободного блока в диапазоне адресов от C0000h до DFFFFh
36WORDРазмер крупнейшего свободного блока
38DWORDЗарезервировано

Функция E801h прерывания INT 15h является основной альтернативой описанному в предыдущем подразделе механизму определения памяти в ACPI-совместимых системах.

На входе:

  • AX — код функции E801h.

На выходе:

  • CF — сброшен, если функция выполнена успешно;
  • AX — размер памяти в диапазоне от 1 до 16 Мбайт, выраженный в килобайтах;
  • BX — размер памяти свыше 16 Мбайт, выраженный в блоках по 64 Кбайта;
  • CX — размер сконфигурированной памяти в диапазоне от 1 до 16 Мбайт, выраженный в килобайтах;
  • DX — размер сконфигурированной памяти свыше 16 Мбайт, выраженный в блоках по 64 Кбайта.

Некоторые BIOS возвращают в регистрах AX и BX нули; в этом случае следует пользоваться объёмом памяти, указанным в регистрах CX и DX.

Advertisement