Linux x86: где отображается адресное пространство реального режима в защищенном режиме ядра?

В Linux, работающем на платформе x86, где адресное пространство реального режима отображается в защищенном режиме ядра? В режиме ядра поток может напрямую обращаться к адресному пространству ядра. Ядро находится в нижних 8 МБ, таблица страниц находится в определенной позиции и т. д. (как описано здесь). Но куда уходит адресное пространство реального режима? Можно ли получить к нему доступ напрямую? Например, BIOS и надстройки BIOS (см. здесь)?


person user3279360    schedule 29.03.2015    source источник


Ответы (2)


(Мой x86-fu немного слабоват. Я добавлю несколько тегов, чтобы другие люди могли (надеюсь) поправить меня, если я где-то лгу.)

Физические адреса одинаковы в реальном и защищенном режиме. Единственная разница заключается в том, как вы переходите от адреса (смещения), указанного в инструкции, к физическому адресу:

  • В реальном режиме физический адрес в основном (segment_reg << 4) + offset.

  • В защищенном режиме физический адрес translate_via_page_table([segment_reg] + offset).

Под [segment_reg] я подразумеваю базовый адрес сегмента, найденный в глобальной или локальной таблице дескрипторов. по смещению в segment_reg. translate_via_page_table() означает трансляцию адресов, выполненную посредством пейджинга (если она включена).

Глядя здесь, кажется, что ПЗУ BIOS находится по физическим адресам 0x000F0000-0x000FFFFF. Чтобы получить доступ к этой памяти в защищенном режиме с пейджингом, вам нужно будет сопоставить ее где-нибудь с виртуальным адресным пространством, настроив правильный таблица страниц записей. Если предположить, что страницы имеют размер 4 КБ (обычный случай), для сопоставления всего диапазона потребуется 16 ((0xFFFFF-0xF0000+1)/4096) записей.

Чтобы увидеть, как работает ядро ​​​​Linux, вы можете посмотреть, как, например. Реализован /dev/mem, позволяющий считывать произвольные физические адреса. Реализация находится в drivers/char/mem.c.

Следующая команда (например, из этого ответа) создаст дамп диапазона памяти 0xC0000-0xFFFFF (это означает, что она также включает видео BIOS, на карту памяти, указанную выше):

$ dd if=/dev/mem bs=1k skip=768 count=256 > bios

1024*768 = 0xC0000 и 1024*(768+256) - 1 = 0xFFFFF, что дает ожидаемый диапазон физической памяти.

Немного отслеживая ситуацию, read_mem() в drivers/char/mem.c вызывает xlate_dev_mem_ptr(), который имеет специфичную для x86 реализацию в arch/x86/mm/ioremap.c. Вызов ioremap_cache() в этой функции, по-видимому, отвечает за сопоставление на странице, если это необходимо.

Обратите внимание, что подпрограммы BIOS не будут работать в защищенном режиме. Они предполагают, что процессор работает в реальном режиме.

person Ulfalizer    schedule 29.03.2015

Для 32-разрядной версии Linux x86 первый 896MB физического ОЗУ сопоставляется с непрерывным блоком виртуальной памяти, начиная с виртуального адреса с 0xC0000000 по 0xF7FFFFFF. Виртуальные адреса от 0xF8000000 до 0xFFFFFFFF назначаются динамически различным частям физической памяти, поэтому ядро ​​может отображать окно 128MB в любую часть физической памяти за пределами 896MB.

Само ядро ​​загружается по физическому адресу 1 МБ и выше, оставляя первый МБ свободным. Этот первый МБ используется, например, для буферов DMA, которые необходимы ISA-устройствам, потому что они используют контроллер DMA 8237, который может быть сопоставлен только с такими адресами.

Таким образом, чтение с адреса виртуальной памяти 0xC0000000 на самом деле является чтением с физического адреса 0x00000000 (при условии, что ядро ​​пометило эту страницу как существующую).

person mcleod_ideafix    schedule 29.03.2015
comment
Можете ли вы указать на доказательство этого поведения в github.com/torvalds/linux вместо того, чтобы просто добавить куча поверьте мне чисел ? Я не говорю, что ты не прав. Я просто говорю, что мы кодеры, работающие с кодом, пожалуйста, будьте более конкретными - person xmojmr; 29.03.2015
comment
Ага, так что где-то там должен быть биос. - person user3279360; 29.03.2015
comment
Спасибо за информацию. Я собирался провести эксперимент с /dev/kmem (который похож на /dev/mem, но вместо этого использует виртуальную память ядра), но, к сожалению, ядро ​​на моей машине, кажется, скомпилировано без CONFIG_DEVKMEM, и я пошел спать. Если бы /dev/kmem был доступен, то я думаю, что проверка работоспособности должна была бы читать, например, из. 0xC00C0000 и посмотрите, получите ли вы те же данные, что и в примере /dev/mem (при условии 32-разрядной версии, если детали отличаются для 64-разрядной версии). Некоторый окончательный источник тоже был бы хорош. :) - person Ulfalizer; 29.03.2015
comment
@xmojmr: я никогда не копался в этой части ядра Linux. Я просто читал книги других людей, которые это сделали. Например, данные о загрузке ядра на границе 1 МБ взяты из книги LInux Kernel Internals, раздел 1.4 Загрузка: загрузочный сектор и настройка. Об ограничении в 896 МБ и других мелких деталях см. начало главы 2 книги «Понимание диспетчера виртуальной памяти Linux». - person mcleod_ideafix; 30.03.2015
comment
@Ulfaizer: для своих студентов я написал небольшой драйвер устройства, который давал процессу доступ к физической памяти. Это было для лабораторного занятия, на котором они (студенты) должны были показать графическую карту того, как карта памяти процесса строится ядром, показать, как две копии одной и той же переменной находятся по одному и тому же виртуальному адресу в каждом процессе. но по разным физическим адресам и т. д. У меня есть больше документации по этому поводу, но она вся на испанском языке. Именно из-за небольшого исследования, которое мне пришлось провести для создания этого лабораторного сеанса, я знаю об этих ограничениях и поведении памяти ядра. - person mcleod_ideafix; 30.03.2015
comment
@mcleod_ideafix: я быстро взломал модуль ядра на 32-битной виртуальной машине, которая у меня лежала, и несколько значений памяти %02X printk в диапазоне 0xC00C0000. Кажется, проверить! Он соответствует выходным данным команды dd. - person Ulfalizer; 30.03.2015
comment
@Ulfalizer К вашему сведению, это также описано здесь - kernel.org /doc/gorman/html/понять/. - person user3279360; 31.03.2015
comment
@user3279360: Спасибо за ссылку! - person Ulfalizer; 31.03.2015