Подтвердить что ты не робот

Как именно виртуальные адреса ядра преобразуются в физическую память?

На поверхности это кажется глупым вопросом. Некоторое терпение, пожалуйста..:-) Структурируем это qs на 2 части:

Часть 1: Я полностью понимаю, что RAM платформы отображается в сегмент ядра; esp на 64-битных системах это будет работать хорошо. Таким образом, каждый виртуальный адрес ядра действительно является просто смещением от физической памяти (DRAM).

Кроме того, я понимаю, что поскольку Linux - это современная операционная память, все адреса рассматриваются как виртуальные адреса и должны "идти" через аппаратное обеспечение - TLB/MMU - во время выполнения, а затем переводить TLB/MMU через таблицы подкачки ячеек. Опять же, это легко понять для процессов пользовательского режима.

ОДНАКО, как насчет виртуальных адресов ядра? Для эффективности было бы проще просто направить их (и отображение идентичности действительно настроено с PAGE_OFFSET и далее). Но все же, во время выполнения, виртуальный адрес ядра должен проходить через TLB/MMU и получить перевод правильно??? Это на самом деле? Или это виртуальный перевод ядра только для расчета смещения?? (Но как это может быть, поскольку мы должны пройти через аппаратное обеспечение TLB/MMU?). В качестве простого примера рассмотрим:

char *kptr = kmalloc(1024, GFP_KERNEL);

Теперь kptr - это виртуальный адрес ядра. Я понимаю, что virt_to_phys() может выполнять расчет смещения и возвращать физический адрес DRAM. Но здесь реальный вопрос: это невозможно сделать с помощью программного обеспечения - это было бы патетически медленным! Итак, вернемся к моему предыдущему моменту: он должен быть переведен через аппаратное обеспечение (TLB/MMU). Это действительно так?

Часть 2: Хорошо, скажем так, и мы используем подкачку в ядре, чтобы сделать это, мы должны, конечно, настроить таблицы подкачки ядра; Я понимаю, что это связано с swapper_pg_dir.

(Я также понимаю, что vmalloc() в отличие от kmalloc() - это особый случай - это чистый виртуальный регион, который подкрепляется физическими кадрами только при ошибке страницы).

Если (в части 1) мы заключаем, что преобразование виртуального адреса ядра выполняется через таблицы подкачки ячеек, то как именно таблица подкачки ядра (swapper_pg_dir) получает "присоединенную" или "сопоставленную" к процессу пользовательского режима?? Это должно произойти в коде контекстного переключения? Как? Где?

Eg. На x86_64 2 процесса A и B являются живыми, 1 процессор. A работает, поэтому он имеет более высокий канонический addr 0xFFFF8000 00000000 through 0xFFFFFFFF FFFFFFFF "карта" к сегменту ядра, а нижний канонический адр 0x0 through 0x00007FFF FFFFFFFF сопоставить с ним частное пользовательское пространство.

Теперь, если мы переводим контекст A- > B, то нижний канонический регион B процесса является уникальным. Но он должен "отображать" одно ядро! Как именно это происходит? Как мы "автоматически" ссылаемся на таблицу подкачки ядра, когда в режиме ядра? Или это неправильное утверждение?

Спасибо за ваше терпение, действительно оценил бы хорошо продуманный ответ!

4b9b3361

Ответ 1

Сначала немного фона.

Это область, где существует много потенциальных изменений между но оригинальные плакаты указали, что он в основном заинтересованы в x86 и ARM, которые имеют несколько характеристик:

  • нет сегментов оборудования или аналогичного раздела виртуального адресного пространства (при использовании Linux)
  • табличная таблица страниц
  • несколько размеров страниц
  • физически помеченные кеши (по крайней мере, на современных ARM)

Итак, если мы ограничимся этими системами, это упростит ситуацию.

Как только MMU включен, он никогда не отключается. Итак, весь процессор адреса являются виртуальными и будут переведены на физические адреса используя MMU. MMU сначала ищет виртуальный адрес в TLB, и только если он не найдет его в TLB, он будет ссылаться на page table - TLB - это кеш таблицы страниц, и поэтому мы можем игнорируйте TLB для этого обсуждения.

Таблица страниц описывает все виртуальное 32 или 64-разрядное адресное пространство и включает в себя информация вроде:

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

Linux делит виртуальное адресное пространство на два: нижняя часть используется для пользовательских процессов, и существует другое виртуальное отображение для каждого процесса. Верхняя часть используется для ядра, и отображение является одинаковым даже при переключении между разными пользователями процессы. Это упрощает, поскольку адрес однозначно в пользователя или ядра, таблицу страниц не нужно изменять, если ввода или выхода из ядра, и ядро ​​может просто разыменовывать указатели в пользовательское пространство для текущий пользовательский процесс. Как правило, на 32-битных процессорах разделение составляет 3G user/1G, хотя это может различаться. Страницы для части ядра адресного пространства будет помечено как доступное только тогда, когда процессор находится в режиме ядра, чтобы они не были доступны для пользовательских процессов. Часть адресного пространства ядра, которое является идентификатором, отображаемым в ОЗУ (логические адреса ядра) будут отображаться с использованием больших страниц, когда это возможно, что может привести к тому, что таблица страниц будет меньше, но что более важно уменьшает количество пропусков TLB.

Когда ядро ​​запускается, он создает для себя одну страницу таблицы (swapper_pg_dir), который просто описывает часть ядра виртуального адресного пространства и без сопоставлений для пользовательской части адресное пространство. Затем каждый раз, когда пользовательский процесс создает новую страницу для этого процесса будет создана таблица, часть, которая описывает память ядра будет одинаковой в каждой из этих таблиц. Это должно быть сделанное копированием всей соответствующей части swapper_pg_dir, но поскольку таблицы страниц обычно являются древовидными структурами, ядро часто способным трансплантировать часть дерева, которая описывает адресное пространство ядра от swapper_pg_dir в таблицах страниц для каждого пользовательский процесс, просто скопировав несколько записей на верхнем уровне структура таблицы страниц. Кроме того, что он более эффективен в памяти (и, возможно, кеш), упрощает согласование сопоставлений. Эта является одной из причин, по которой разделение между ядром и пользователем виртуальным адресные пространства могут встречаться только на определенных адресах.

Чтобы узнать, как это делается для конкретной архитектуры, посмотрите на реализация pgd_alloc(). Например, ARM (arch/arm/mm/pgd.c) использует:

pgd_t *pgd_alloc(struct mm_struct *mm)
{
    ...
    init_pgd = pgd_offset_k(0);
    memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD,
               (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
    ...
}

или x86 (arch/x86/mm/pgtable.c) pgd_alloc() вызывает pgd_ctor():

static void pgd_ctor(struct mm_struct *mm, pgd_t *pgd)
{
    /* If the pgd points to a shared pagetable level (either the
       ptes in non-PAE, or shared PMD in PAE), then just copy the
       references from swapper_pg_dir. */
        ...
        clone_pgd_range(pgd + KERNEL_PGD_BOUNDARY,
                swapper_pg_dir + KERNEL_PGD_BOUNDARY,
                KERNEL_PGD_PTRS);
    ...
}

Итак, вернемся к исходным вопросам:

Часть 1: действительно ли виртуальные адреса ядра переведены TLB/MMU?

Да.

Часть 2: как swapper_pg_dir "прикреплен" к процессу пользовательского режима.

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

Ответ 2

Ядро, адресное пространство которого сопоставляется с разделом каждого процесса, например, с отображением 3: 1 после адреса 0xC0000000. Если код пользователя пытается получить доступ к этому адресному пространству, он приведет к сбою страницы и будет защищен ядром. Адресное пространство ядра разделено на 2 части, логическое адресное пространство и виртуальное адресное пространство. Он определяется константой VMALLOC_START. Процессор использует MMU все время, в пространстве пользователя и в пространстве ядра (не может включать/выключать). Виртуальное адресное пространство ядра отображается так же, как отображение пространства пользователя. Логическое адресное пространство является непрерывным, и его просто перевести на физическое, чтобы его можно было выполнять по требованию с помощью исключения сбоя MMU. То есть ядро ​​пытается получить доступ к адресу, генерировать ошибку MMU, обработчик ошибок отображает страницу с помощью макросов __pa, __va и меняет регистр CPU pc на предыдущую инструкцию до того, как произошла ошибка, теперь все в порядке. Этот процесс на самом деле зависит от платформы, и в некоторых аппаратных архитектурах он отображается так же, как и пользователь (поскольку ядро ​​не использует много памяти).