Дескрипторы сегментов
Linux использует следующие дескрипторы сегментов:
· Сегмент кода ядра
· Сегмент данных ядра
· Сегмент кода пользователя
· Сегмент данных пользователя
· Сегмент TSS
· Сегмент LDT по умолчанию
Дескриптор сегмента кода ядра в GDT имеет следующие значения:
· Base = 0x00000000
· Limit = 0xffffffff (232-1) = 4GB
· G (флаг единицы сегментирования) = 1 для размера сегмента, выраженного в страницах
· S = 1 для обычного сегмента кода или данных
· Type = 0xa для сегмента кода, который можно прочитать и выполнить
· Значение DPL = 0 для режима ядра
Линейный адрес для этого сегмента равен 4 GB. S =1 и type = 0xa обозначают сегмент кода. Селектор находится в регистре cs. Доступ к соответствующему селектору сегмента в Linux осуществляется через макрос _KERNEL_CS.
Дескриптор сегмента данных ядра имеет аналогичные значения за исключением поля Type, значение которого установлено в 2. Это указывает на то, что сегмент является сегментом данных и селектор хранится в регистре ds. Доступ к соответствующему селектору сегмента в Linux осуществляется через макрос _KERNEL_DS.
Сегмент кода пользователя используется совместно всеми процессами в пользовательском режиме. Соответствующий дескриптор сегмента, хранящийся в GDT, имеет следующие значения:
· Base = 0x00000000
· Limit = 0xffffffff
· G = 1
· S = 1
· Type = 0xa для сегмента кода, который можно прочитать и выполнить
· DPL = 3 для пользовательского режима
Доступ к соответствующему селектору сегмента в Linux осуществляется через макрос _USER_CS.
В дескрипторе сегмента данных пользователя есть только одно изменение по сравнению с предыдущим дескриптором - поле Type установлено в 2 и определяет сегмент данных, которые можно прочитать и записать. Доступ к соответствующему селектору сегмента в Linux осуществляется через макрос _USER_DS.
Кроме этих дескрипторов сегментов GDT содержит два дополнительных дескриптора сегментов для каждого созданного процесса - для сегментов TSS и LDT.
Каждый дескриптор сегмента TSS указывает на отдельный процесс. TSS хранит информацию об аппаратном контексте для каждого CPU, который принимает участие в переключении контекста. Например, при переключении режимов U->K x86 CPU получает адрес стека режима ядра из TSS.
Каждый процесс имеет свой собственный TSS-дескриптор, хранящийся в GDT. Значения этого дескриптора таковы:
· Base = &tss (адрес поля TSS дескриптора соответствующего процесса; например, &tss_struct), который определен в файле schedule.h ядра Linux
· Limit = 0xeb (сегмент TSS занимает 236 байт)
· Type = 9 или 11
· DPL = 0. Пользовательский режим не обращается к TSS. Флаг G очищен
Все процессы совместно используют сегмент LDT по умолчанию. По умолчанию он содержит нулевой дескриптор сегмента. Этот дескриптор сегмента LDT по умолчанию хранится в GDT. Сгенерированный ядром Linux LDT занимает 24 байта. По умолчанию всегда присутствуют три записи:
LDT[0] = null
LDT[1] = сегмент кода пользователя
LDT[2] = дескриптор сегмента данных/стека пользователя
Вычисление TASKS
Знание NR_TASKS (переменной, определяющей количество одновременных процессов, поддерживаемых в Linux. Ее значение по умолчанию в исходном коде ядра равно 512, что позволяет иметь 256 одновременных подключений к одному экземпляру) необходимо для вычисления максимального количества разрешенных записей в GDT.
Максимальное количество разрешенных в GDT записей может быть определено по следующей формуле:
Общее количество записей в GDT = 12 + 2 * NR_TASKS.
Возможное количество записей в GDT = 2^13 -1 = 8192.
Из 8192 дескрипторов сегментов Linux использует 6 дескрипторов сегментов, еще 4 дополнительных для APM-функций (функции расширенного управления питанием), а 4 записи в GDT остаются не использованными. Таким образом, конечное число возможных записей в GDT равно 8192 - 14, или 8180.
В любой момент времени нельзя иметь более чем 8180 записей в GDT, следовательно:
2 * NR_TASKS = 8180 и NR_TASKS = 8180/2 = 4090
Дата добавления: 2015-03-26; просмотров: 956;