Ядро Linux в комментариях

       

Сегменты


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

Сегменты можно рассматривать просто как еще один механизм определения областей памяти, немного напоминающий страницы. Эти два метода могут перекрываться: адрес всегда принадлежит одной странице и может также находиться только в одном сегменте. В отличие от страниц сегменты могут иметь изменяющийся размер и даже могут увеличиваться и уменьшаться в течение срока своего существования. Как и страницы, сегменты могут быть защищены и эти средства защиты предписаны в аппаратном обеспечении; когда в архитектуре х86 возникает конфликт между защитой уровня сегмента и защитой уровня страницы для одного и того же адреса, побеждает сегмент.

Процессор Х86 следит за сегментами с помощью нескольких регистров и таблиц двух разных типов: таблицы глобальных дескрипторов (GDT) и таблиц локальных дескрипторов (LDT). Эти дескрипторы являются дескрипторами сегмента — 8-байтовыми объектами, которые хранят базовый адрес и размер сегмента, а также описывают защиту. В системе Linux существует только одна GDT, а таблицы LDT создаются для каждой задачи.

Ниже вкратце показано, как ядро использует эти таблицы для настройки сегментов. Само ядро имеет отдельные сегменты кода и данных, которые описаны во входах 2 и 3 таблицы GDT. Каждая задача также имеет отдельные сегменты кода и данных. Сегменты кода и данных текущей задачи описаны во входах 4 и 5 таблицы GDT, а также во входах 0 и 1 ее собственной таблицы LDT.

Каждая задача также использует два входа в GDT: один — для указания на ее LDT, а другой — для указания на ее TSS (сегмент состояния задания, вкратце описанный в предыдущей главе). Поскольку в процессоре х86 размер таблицы GDT ограничен 8192 входами и в Linux применяются два входа GDT для каждой задачи, ясно, что в системе нельзя иметь более 4096 задач — об этом лимите было упомянуто в . В действительности, максимальное число задач еще немного ниже, 4090, поскольку первый десяток входов GDT зарезервирован для других целей.

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

В заключение отметим, что для разработчиков, заинтересованных в глубоком изучении механизма поддержки сегментов процессора х86, нет лучшей возможности, кроме знакомства с документом Intel Architecture Software Developer's Manual Volume 3, который можно получить бесплатно с Web-сайта компании Intel ().



Содержание раздела