Сегмент состояния задачи ( TSS ) — это структура на компьютерах на базе x86 , которая содержит информацию о задаче . Она используется ядром операционной системы для управления задачами. В частности, в TSS хранится следующая информация:
Вся эта информация должна храниться в определенных местах в TSS, как указано в руководствах IA-32 .
TSS может находиться в любом месте памяти . Регистр сегмента, называемый регистром задачи (TR), содержит селектор сегмента , который указывает на допустимый дескриптор сегмента TSS, который находится в GDT (дескриптор TSS не может находиться в LDT ). Поэтому для использования TSS ядро операционной системы должно выполнить следующие действия:
В целях безопасности TSS следует размещать в памяти, доступной только ядру .
Регистр TR — это 16-битный регистр, который содержит селектор сегмента для TSS. Он может быть загружен с помощью инструкции LTR . LTR — это привилегированная инструкция, которая действует аналогично другим загрузкам сегментных регистров. Регистр задач состоит из двух частей: видимой и доступной программисту части и невидимой части, которая автоматически загружается из дескриптора TSS.
TSS может содержать сохраненные значения всех регистров x86 . Это используется для переключения задач . Операционная система может загрузить TSS со значениями регистров, которые требуются новой задаче, и после выполнения аппаратного переключения задач (например, с помощью инструкции IRET) процессор x86 загрузит сохраненные значения из TSS в соответствующие регистры. Обратите внимание, что некоторые современные операционные системы, такие как Windows и Linux [1], не используют эти поля в TSS, поскольку они реализуют программное переключение задач.
Обратите внимание, что во время переключения аппаратных задач некоторые поля старого TSS обновляются текущим содержимым регистра ЦП до того, как будут прочитаны значения из нового TSS. Таким образом, некоторые поля TSS доступны для чтения/записи, а другие — только для чтения:
EAX
, EBX
, ECX
, EDX
, ESI
, EDI
, EBP
, ESP
);CS
, DS
, ES
, FS
, GS
, SS
);EIP
, EFlags
);Link
в новом TSS, если переключение задач произошло из-за CALL
или, INT
а не из-за JMP
.CR3
), также известный как базовый регистр каталога страниц ( PDBR
).LDTR
);SS0:ESP0
, SS1:ESP1
, SS2:ESP2
);CALL
или INT
для создания нового стека.IOPB
) и сама битовая карта порта ввода-вывода;IN
, OUT
, INS
или , чтобы подтвердить, что инструкция является допустимой (см. разрешения порта ввода-вывода ниже).OUTS
CPL > IOPL
PDBR
Фактически это поле является самым первым, считываемым из нового TSS: поскольку аппаратное переключение задач также может переключиться на совершенно другое отображение таблицы страниц, все остальные поля (особенно LDTR
) относятся к новому отображению.
TSS содержит 16-битный указатель на битовую карту разрешений порта ввода-вывода для текущей задачи . Эта битовая карта, обычно настраиваемая операционной системой при запуске задачи, определяет отдельные порты, к которым программа должна иметь доступ. Битовая карта ввода-вывода представляет собой битовый массив разрешений доступа к портам; если у программы есть разрешение на доступ к порту, в соответствующем индексе бита сохраняется «0», а если у программы нет разрешения, там сохраняется «1». Если предел сегмента TSS меньше полной битовой карты, все отсутствующие биты считаются равными «1».
Функция работает следующим образом: когда программа выдает инструкцию порта ввода-вывода x86, например IN или OUT (см. списки инструкций x86 — и обратите внимание, что существуют версии длиной в байт, слово и двойное слово), оборудование выполнит проверку уровня привилегий ввода-вывода (IOPL), чтобы узнать, имеет ли программа доступ ко всем портам ввода-вывода. Если текущий уровень привилегий (CPL) программы численно больше уровня привилегий ввода-вывода (IOPL) (программа имеет меньшие привилегии, чем указано в IOPL), программа не имеет доступа ко всем портам ввода-вывода. Затем оборудование проверит битовую карту разрешений ввода-вывода в TSS, чтобы узнать, может ли эта программа получить доступ к определенному порту(ам) в инструкции IN или OUT. Если (все) соответствующие биты в битовой карте разрешений порта ввода-вывода сброшены, программе разрешен доступ к порту(ам), и инструкция может быть выполнена. Если (любой из) соответствующих битов установлен или если (любой из) битов выходит за пределы сегментного лимита TSS, программа не имеет доступа, и процессор генерирует общую ошибку защиты . Эта функция позволяет операционным системам предоставлять пользовательский программам выборочный доступ к порту.
TSS содержит 6 полей для указания нового указателя стека при изменении уровня привилегий. Поле SS0 содержит селектор сегмента стека для CPL=0, а поле ESP0/RSP0 содержит новое значение ESP/RSP для CPL=0. Когда прерывание происходит в защищенном (32-битном) режиме, процессор x86 будет искать в TSS SS0 и ESP0 и загружать их значения в SS и ESP соответственно. Это позволяет ядру использовать другой стек, чем пользовательская программа, а также сделать этот стек уникальным для каждой пользовательской программы.
Новая функция, представленная в расширениях AMD64 , называется таблицей стека прерываний (IST), которая также находится в TSS и содержит логические (сегмент+смещение) указатели стека. Если таблица дескрипторов прерываний указывает запись IST для использования (их 7), процессор вместо этого загрузит новый стек из IST. Это позволяет использовать заведомо исправные стеки в случае серьезных ошибок ( например, NMI или двойная ошибка ). Ранее запись для исключения или прерывания в IDT указывала на шлюз задачи, заставляя процессор переключаться на задачу, на которую указывает шлюз задачи. Исходные значения регистров сохранялись в TSS, текущем на момент возникновения прерывания или исключения. Затем процессор устанавливал регистры, включая SS:ESP, на известное значение, указанное в TSS, и сохранял селектор в предыдущем TSS. Проблема здесь в том, что аппаратное переключение задач не поддерживается в AMD64.
Это 16-битный селектор, который позволяет связать этот TSS с предыдущим. Он используется только для переключения аппаратных задач. Подробности см. в руководствах IA-32 .
Хотя TSS может быть создан для каждой задачи, запущенной на компьютере, ядро Linux создает только один TSS для каждого ЦП и использует их для всех задач. Этот подход был выбран, поскольку он обеспечивает более легкую переносимость на другие архитектуры (например, архитектура AMD64 не поддерживает аппаратные переключатели задач), а также повышает производительность и гибкость. Linux использует только битовую карту разрешений порта ввода-вывода и функции внутреннего стека TSS; другие функции необходимы только для аппаратных переключателей задач, которые ядро Linux не использует. [2]
Вектор исключения x86 10 называется исключением Invalid TSS (#TS). Он выдается процессором всякий раз, когда что-то идет не так с доступом к TSS. Например, если прерывание происходит в CPL=3 и передает управление в CPL=0, TSS используется для извлечения SS0 и ESP0/RSP0 для переключения стека. Если регистр задачи содержит неверный селектор TSS, будет сгенерирована ошибка #TS. Исключение Invalid TSS никогда не должно возникать во время нормальной работы операционной системы и всегда связано с ошибками ядра или аппаратным сбоем.
Более подробную информацию об исключениях TSS см. в главе 6 тома 3a руководства IA-32 . [3]
Архитектура x86-64 не поддерживает аппаратные переключения задач. Однако TSS все еще может использоваться на машине, работающей в 64-битных расширенных режимах. В этих режимах TSS все еще полезен, поскольку он хранит:
Кроме того, в этих режимах регистр задач расширяется, чтобы иметь возможность хранить 64-битный базовый адрес.