Что содержит физический адрес 0 в x86 Linux?

12

Я не уверен, должен ли этот вопрос идти здесь или в reverseengineering.stackexchange.com

Цитата из Википедии :

В процессоре 8086 таблица прерываний называется IVT (таблица векторов прерываний). IVT всегда находится в одном и том же месте в памяти, в диапазоне от 0x0000 до 0x03ff, и состоит из 256 четырехбайтовых дальних указателей реального режима (256 × 4 = 1024 байта памяти).

Вот что я нахожу в мониторе qemu:

(qemu) xp/128xw 0
0000000000000000: 0xf000ff53 0xf000ff53 0xf000e2c3 0xf000ff53
0000000000000010: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000020: 0xf000fea5 0xf000e987 0xf000d62c 0xf000d62c
0000000000000030: 0xf000d62c 0xf000d62c 0xf000ef57 0xf000d62c
0000000000000040: 0xc0005526 0xf000f84d 0xf000f841 0xf000e3fe
0000000000000050: 0xf000e739 0xf000f859 0xf000e82e 0xf000efd2
0000000000000060: 0xf000d648 0xf000e6f2 0xf000fe6e 0xf000ff53
0000000000000070: 0xf000ff53 0xf000ff53 0xf0006aa4 0xc0008930
0000000000000080: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000090: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000c0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000d0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000e0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000100: 0xf000ec59 0xf000ff53 0xf000ff53 0xc0006730
0000000000000110: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000120: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000130: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000140: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000150: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000160: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000170: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000180: 0x00000000 0x00000000 0x00000000 0x00000000
0000000000000190: 0x00000000 0x00000000 0x00000000 0xf000ff53
00000000000001a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001c0: 0xf000d611 0xf000ec4e 0xf000ec4e 0xf000ec4e
00000000000001d0: 0xf000d61a 0xf000d623 0xf000d608 0xf000ec4e
00000000000001e0: 0xf000ff53 0x00000000 0xf000ff53 0xf000ff53
00000000000001f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53

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

rhodeo
источник

Ответы:

9

Что бы ваша прошивка не оставила в нем.

В идеальной современной системе процессор вообще никогда не переходит в реальный режим, как я объяснил в этом SU Q & A под названием: В каком режиме современные 64-битные ПК с чипами Intel работают в загрузочном секторе? Первый КиБ физической памяти так же не имеет значения, как Йохан Мирен, и здесь он нашел другой ответ. Но многие современные прошивки (все еще) имеют поддержку совместимости , а это означает, что

  • они могут откатиться назад (да, назад , учитывая, что они перешли напрямую из нереального режима в защищенный режим) из защищенного режима в реальный режим, чтобы запускать системные программы, написанные для реального режима, такие как программы загрузки ПК / AT старого стиля в MBR и VBR; и
  • они предоставляют старые API встроенного программного обеспечения реального режима и устанавливают все структуры данных для этих API, на которые опираются вышеупомянутые системные программные средства.

Одной из таких структур данных является реальный режим IVT. Старые API встроенного программного обеспечения реального режима основаны на intинструкциях, а IVT реального режима заполняется встроенным программным обеспечением как часть его инициализации с указателями на различные процедуры обработки встроенного программного обеспечения для этих инструкций.

Системные программы защищенного режима не нуждаются в старых API встроенного ПО реального режима и никогда не запускают процессор в реальном режиме, поэтому IVT реального режима в первых 1 КБ физической памяти не используется. (Защищенный режим v8086 не обращается к физическому адресу 00000000 и выше, запомните. Он обращается к логическим адресам 00000000 и выше, которые преобразуются в таблицы страниц.) В современных системах EFI микропрограмма передает карту памяти физической памяти операционной системе. загрузчик, сообщая ему, какие части зарезервированы для микропрограммного обеспечения для собственных API-функций защищенного режима, а какие части операционная система может свободно использовать и использовать для своего пула физической памяти. Теоретически, первая страница физической памяти может быть в последней категории.

На практике, во-первых, прошивки часто отмечают первую страницу физической памяти как «код сервисов загрузки», что означает, что операционная система может требовать его и просто использовать его как часть своего пула физической памяти, но только после загрузки. временные службы встроенного программного обеспечения EFI были закрыты операционной системой, а встроенное программное обеспечение сокращено до предоставления только его служб времени выполнения. Пример этого можно увидеть в журнале ядра Linux (с add_efi_memmapопцией), показанном Финнбарром П. Мерфи:

[0.000000] efi: mem00: type = 3, attr = 0xf, range = [0x0000000000000000-0x0000000000001000) (0 МБ)
который XE декодирует с другой программой в более удобочитаемой форме, как:

[# 00] Тип: EfiBootServicesCode Attr: 0xF
      Физический: 0000000000000000-0000000000001000
      Вирт: 0000000000000000-0000000000001000

На практике, во-вторых, Linux явно игнорирует этот диапазон физической памяти, даже если прошивка говорит, что может его использовать. Вы обнаружите, что как в EFI, так и в прошивках не-EFI, когда у Linux есть карта физической памяти, она исправляет ее ( в функции с именемtrim_bios_range ), что приводит к сообщениям журнала ядра, таким как:

[0.000000] e820: обновление [mem 0x00000000-0x00000fff] можно использовать ==> зарезервировано

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

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

И в вашей системе прошивка заполнила записи реального режима IVT. Разумеется, записи в реальном режиме IVT - это всего лишь 16:16 дальних указателей, и если вы посмотрите на свою память, используя 2-байтовый шестнадцатеричный код, вы действительно сможете увидеть это довольно четко. Несколько примеров:

  • Большинство ваших записей IVT указывают на F000: FF53, адрес в области ROM встроенного ПО реального режима. Это, вероятно, фиктивная рутина, которая не делает ничего, кроме как iret.
  • Запись 1Е IVT указывает на F000: 6AA4, таблицу в той же области ПЗУ.
  • Запись IVT 1F указывает на C000: 8930, таблицу в области встроенного программного обеспечения ПЗУ в реальном режиме.
  • Запись 43 IVT указывает на C000: 6730, еще одну таблицу в области встроенного программного обеспечения ПЗУ видео в реальном режиме.

дальнейшее чтение

JdeBP
источник
Нет, я имею в виду то, что я написал. Руководство для разработчиков программного обеспечения для архитектуры Intel, том 3, глава 20, § 2.
JdeBP
Ну, у вас есть сейчас, потому что это так; как объясняет первое предложение этого раздела. Исходя из этого, я подозреваю, что непризнание общей аббревиатуры "v8086" - это своего рода шибболет. (-:
JdeBP
Вам нужно научиться читать атрибутивные существительные. Или научиться жить без грибного супа.
JdeBP
7

Исходная архитектура процессора 8086 (реализованная в реальном режиме в процессорах 80286+) не имеет отношения к Linux, который работает в защищенном режиме. Нет таблицы векторов прерываний по физическому адресу 0, вместо этого используется таблица дескрипторов прерываний, содержащая дескрипторы прерываний. IDT может быть расположен где угодно в памяти.

Ядро Linux получает карту физической памяти из встроенного программного обеспечения (BIOS или EFI), которая сообщает, какие фреймы страницы физической памяти можно использовать, а какие зарезервированы или отсутствуют. Диапазон используемых рамок страницы не является смежным, но обычно имеет огромные дыры. Традиционно ядро ​​x86 Linux пропустило начало физической памяти, даже если оно помечено как пригодное для использования. Таким образом, физический адрес 0 не используется ядром Linux.

Йохан Мирен
источник
Это имеет смысл. Есть идеи, откуда взялся остаток на этой неиспользованной странице?
Родео
Поиск в Google 53 ffпоказывает, что это, скорее всего, на самом деле таблица векторов прерываний реального режима 8086, созданная микропрограммой или загрузчиком.
Йохан Мирен
4

Сброс памяти

Вот альтернативный способ выгрузки содержимого памяти внутри системы вместо необходимости делать это внешне:

$ head /dev/mem | hexdump -C
00000000  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
00000010  53 ff 00 f0 53 ff 00 f0  cc e9 00 f0 53 ff 00 f0  |S...S.......S...|
00000020  a5 fe 00 f0 87 e9 00 f0  53 ff 00 f0 46 e7 00 f0  |........S...F...|
00000030  46 e7 00 f0 46 e7 00 f0  57 ef 00 f0 53 ff 00 f0  |F...F...W...S...|
00000040  22 00 00 c0 4d f8 00 f0  41 f8 00 f0 fe e3 00 f0  |"...M...A.......|
00000050  39 e7 00 f0 59 f8 00 f0  2e e8 00 f0 d4 ef 00 f0  |9...Y...........|
00000060  a4 f0 00 f0 f2 e6 00 f0  6e fe 00 f0 53 ff 00 f0  |........n...S...|
00000070  ed ef 00 f0 53 ff 00 f0  c7 ef 00 f0 ed 57 00 c0  |....S........W..|
00000080  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
...
...
000afea0  00 00 00 00 00 00 00 00  aa aa aa 00 aa aa aa 00  |................|
000afeb0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000b0000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
000c0000  55 aa 40 e9 62 0a 00 00  00 00 00 00 00 00 00 00  |U.@.b...........|
000c0010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 49 42  |..............IB|

Анализ

Верхняя часть выше 000c0000 может быть связана с загрузчиком. Зачем мне это подозревать? Код 55aah на месте 000c0000обычно может быть меткой в ​​памяти для таких вещей, как триггер для BIOS для запуска вторичного загрузчика.

Ссылка: Boot Signature - BIOS

  сс # 1

Однако, учитывая, что 55aah происходит в диапазоне c0000h-effffh, более вероятно, что эта часть является заголовком расширения PNP:

Справка: спецификация загрузки BIOS

3.3 Устройства с заголовками расширения PnP

Все устройства IPL с дополнительными ПЗУ должны содержать действительный заголовок дополнительного ПЗУ, который находится между адресами системной памяти C0000h и EFFFFh на границе 2К и начинается с 55AAh. Загрузка устройства может контролироваться только при наличии заголовка расширения PnP. Заголовок расширения, адрес которого находится в заголовке стандартного дополнительного ПЗУ со смещением + 1Ah, содержит важную информацию, используемую для настройки устройства. Он также содержит указатели на код в дополнительном ПЗУ устройства (BCV или BEV), которое BIOS будет вызывать для загрузки с устройства. См. Приложение A для структуры заголовка расширения PnP. Существует два способа загрузки устройства IPL с заголовком расширения PnP. Он должен содержать BCV или BEV.

53ff ...

Что касается 53ffh данных, которые находятся в начале. Мне неясно, что это на самом деле. Дальнейшее изучение этого вопроса, вероятно, было написано ядром Linux после того, как загрузка BIOS MBR была передана ядру Linux для загрузки.

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

Копая дальше, я смог найти этот абзац в исследовательской работе под названием: « Инъекция вредоносного кода через / dev / mem :

1 Устройство памяти

/ dev / mem - интерфейс драйвера для физически адресуемой памяти. Первоначальная цель mem и kmem заключалась в том, чтобы помочь отладить ядро. Мы можем использовать устройство как обычное символьное устройство, используя lseek () для выбора смещения адреса. Устройство kmem аналогично, но предоставляет образ памяти ядра в контексте виртуальной адресации. Сервер Xorg использует устройство mem для доступа к видеопамяти VESA, а также таблицу векторов прерываний ПЗУ BIOS (IVT), расположенную по физическому адресу 0x00000000, для управления режимами видео в режиме VM86. DOSEMU также использует это для доступа к BIOS IVT, чтобы иметь возможность создавать прерывания BIOS для различных задач (чтение с диска, печать на консоль и т. Д.).

Ссылки

SLM
источник