Segment de stare a sarcinii - Task state segment
Segmentul de stat sarcină ( TSS ) este o structură pe x86 computere bazate pe care deține informații despre o sarcină . Este folosit de kernelul sistemului de operare pentru gestionarea sarcinilor. În mod specific, următoarele informații sunt stocate în TSS:
- Starea registrului procesorului
- Permisiuni port I / O
- Indicatori de stivă la nivel interior
- Link TSS anterior
Toate aceste informații ar trebui stocate în locații specifice din TSS, așa cum se specifică în manualele IA-32 .
Locația TSS
TSS poate locui oriunde în memorie . Un registru de segmente numit registru de sarcini (TR) deține un selector de segmente care indică un descriptor valid de segment TSS care se află în GDT (un descriptor TSS poate să nu se afle în LDT ). Prin urmare, pentru a utiliza un TSS, kernelul sistemului de operare trebuie să facă următoarele:
- Creați o intrare descriptor TSS în GDT
- Încărcați TR cu selectorul de segmente pentru acel segment
- Adăugați informații la TSS în memorie, după cum este necesar
Din motive de securitate, TSS ar trebui să fie plasat în memoria accesibilă numai nucleului .
Registrul sarcinilor
Registrul TR este un registru pe 16 biți care deține un selector de segmente pentru TSS. Poate fi încărcat prin instrucțiunea LTR . LTR este o instrucțiune privilegiată și acționează într-un mod similar cu alte încărcări de registre de segmente. Registrul de sarcini are două părți: o porțiune vizibilă și accesibilă de către programator și una invizibilă care este încărcată automat din descriptorul TSS.
Înregistrați statele
TSS poate conține valori salvate ale tuturor registrelor x86 . Aceasta este utilizată pentru comutarea sarcinilor . Sistemul de operare poate încărca TSS cu valorile registrelor de care are nevoie noua sarcină și după executarea unui comutator de sarcină hardware (cum ar fi cu o instrucțiune IRET ) CPU x86 va încărca valorile salvate din TSS în registrele corespunzătoare. Rețineți că unele sisteme de operare moderne, cum ar fi Windows și Linux , nu folosesc aceste câmpuri în TSS, deoarece implementează comutare de sarcini software.
Rețineți că în timpul unui comutator de sarcini hardware, anumite câmpuri ale vechiului TSS sunt actualizate cu conținutul registrului curent al procesorului înainte de citirea valorilor din noul TSS. Astfel, unele câmpuri TSS sunt citite / scrise, în timp ce altele sunt doar în citire:
-
Câmpuri de citire / scriere : citite și scrise în timpul unui comutator de activitate hardware
- Toate registrele de uz general (
EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP); - Toate registrele de segment (
CS,DS,ES,FS,GS,SS); - Starea curentă de execuție (
EIP,EFlags); LinkCâmpul din nou TSS, în cazul în care comutatorul de sarcina a fost din cauza uneiCALLsauINTmai degrabă decât oJMP.
- Toate registrele de uz general (
-
Câmpuri numai în citire: citiți numai când este necesar, după cum se indică.
- Control Register 3 (
CR3), cunoscut și sub numele de Page Directory Register Register (PDBR).- Citiți în timpul unui comutator de sarcini hardware.
- Registrul Tabelului descriptorului local (
LDTR);- Citiți în timpul unui comutator de sarcini hardware.
- Perechile trei nivel privilegiu stiva (
SS0:ESP0,SS1:ESP1,SS2:ESP2);- Citiți în timpul unui nivel inter-nivel
CALLsauINTpentru a stabili o nouă stivă.
- Citiți în timpul unui nivel inter-nivel
- Pointerul IM Port Bitmap (
IOPB) și portul I / O Bitmap în sine;- Citește în timpul unei
IN,OUT,INSsauOUTSinstrucțiuni în cazul în careCPL > IOPLpentru a confirma instrucțiunea este legală ( a se vedea permisiunile de port I / O de mai jos).
- Citește în timpul unei
- Control Register 3 (
PDBRDomeniu este , de fapt , foarte prima citit din nou TSS: deoarece un comutator de sarcină hardware poate trece , de asemenea , la o mapare complet diferită de tabel de pagină, toate celelalte domenii ( în special LDTR) sunt în raport cu noua trasare.
Permisiuni port I / O
TSS conține un indicator de 16 biți către bitmap-ul permisiunilor portului I / O pentru sarcina curentă . Această bitmap, configurată de obicei de sistemul de operare la pornirea unei sarcini, specifică porturile individuale la care ar trebui să aibă acces programul. Bitmap-ul I / O este o serie de permisiuni de acces la port; dacă programul are permisiunea de a accesa un port, un „0” este stocat la indexul de biți corespunzător și dacă programul nu are permisiunea, un „1” este stocat acolo. Dacă limita de segment a TSS este mai mică decât harta de biți completă, se presupune că toți biții lipsă sunt „1”.
Funcția funcționează după cum urmează: când un program emite o instrucțiune de port I / O x86, cum ar fi IN sau OUT (consultați listele de instrucțiuni x86 - și rețineți că există versiuni cu lungime de octet, cuvânt și dword), hardware-ul va face o Nivelul de privilegiu I / O (IOPL) verifică dacă programul are acces la toate porturile I / O. Dacă nivelul de privilegiu curent (CPL) al programului este mai mare numeric decât nivelul de privilegiu I / O (IOPL) (programul este mai puțin privilegiat decât ceea ce specifică IOPL), programul nu are acces I / O la toate porturile porturi. Hardware-ul va verifica apoi bitmap-ul de permisiuni I / O în TSS pentru a vedea dacă acel program poate accesa portul (porturile) specific (e) în instrucțiunea IN sau OUT. Dacă (toți) bitii relevanți din bitmap-ul permisiunilor portului I / O sunt / sunt clare, programului i se permite accesul la porturi, iar instrucțiunea este permisă să se execute. Dacă (oricare dintre) biții relevanți sunt / sunt setați - sau dacă (oricare dintre) biții sunt / depășesc limita de segment TSS - programul nu are acces și procesorul generează o protecție generală vina . Această caracteristică permite sistemelor de operare să acorde acces selectiv de port la programele utilizatorilor.
Indicatori de stivă la nivel interior
TSS conține 6 câmpuri pentru specificarea noului indicator al stivei atunci când are loc o modificare a nivelului de privilegiu. Câmpul SS0 conține selectorul segmentului stivei pentru CPL = 0, iar câmpul ESP0 / RSP0 conține noua valoare ESP / RSP pentru CPL = 0. Când se produce o întrerupere în modul protejat (pe 32 de biți), CPU x86 va căuta în TSS SS0 și ESP0 și le va încărca valorile în SS și respectiv în ESP. Acest lucru permite nucleului să utilizeze o stivă diferită de cea a programului de utilizator și, de asemenea, să aibă această stivă să fie unică pentru fiecare program de utilizator.
O nouă caracteristică introdusă în extensiile AMD64 se numește Interrupt Stack Table (IST), care se află și în TSS și conține indicatori de stivă logici (segment + offset). Dacă un tabel descriptor de întrerupere specifică o intrare IST de utilizat (sunt 8), procesorul va încărca noua stivă din IST. Acest lucru permite utilizarea stivelor bune cunoscute în caz de erori grave ( NMI sau dublă defecțiune de exemplu). Anterior, intrarea pentru excepție sau întrerupere în IDT arăta spre o poartă de sarcină, determinând procesorul să treacă la sarcina indicată de poarta de sarcini. Valorile originale ale registrului au fost salvate în curentul TSS în momentul în care a avut loc întreruperea sau excepția. Procesorul a setat apoi registrele, inclusiv SS: ESP, la o valoare cunoscută specificată în TSS și a salvat selectorul în TSS-ul anterior. Problema aici este că comutarea sarcinilor hardware nu este acceptată pe AMD64.
Link TSS anterior
Acesta este un selector de 16 biți care permite conectarea acestui TSS cu cel anterior. Acesta este utilizat numai pentru comutarea sarcinilor hardware. Consultați manualele IA-32 pentru detalii.
Utilizarea TSS în Linux
Deși s-ar putea crea un TSS pentru fiecare activitate care rulează pe computer, nucleul Linux creează doar un TSS pentru fiecare procesor și le folosește pentru toate sarcinile. Această abordare a fost selectată deoarece oferă o portabilitate mai ușoară către alte arhitecturi (de exemplu, arhitectura AMD64 nu acceptă comutatoare de sarcini hardware) și performanță și flexibilitate îmbunătățite. Linux folosește numai bitmap-ul permisiune port I / O și caracteristicile stivei interioare ale TSS; celelalte caracteristici sunt necesare numai pentru comutatoarele de sarcini hardware, pe care nucleul Linux nu le folosește.
Vectorul de excepție x86 10 se numește excepție TSS nevalidă (#TS). Este emis de procesor ori de câte ori ceva nu merge bine cu accesul TSS. De exemplu, dacă se produce o întrerupere în CPL = 3 și transferă controlul la CPL = 0, TSS este utilizat pentru a extrage SS0 și ESP0 / RSP0 pentru comutatorul de stivă. Dacă registrul de sarcini deține un selector TSS defect, va fi generată o eroare #TS. Excepția TSS nevalidă nu ar trebui să se întâmple niciodată în timpul funcționării normale a sistemului de operare și este întotdeauna legată de erori ale nucleului sau de erori hardware.
Pentru mai multe detalii despre excepțiile TSS, consultați Volumul 3a, Capitolul 6 al manualului IA-32 .
TSS în modul x86-64
X86-64 Arhitectura nu are suport pentru switch - uri de sarcini hardware. Cu toate acestea, TSS poate fi încă utilizat într-o mașină care rulează în modurile extinse pe 64 de biți. În aceste moduri, TSS este încă util, deoarece stochează:
- Adresele indicatorului stivei pentru fiecare nivel de privilegiu.
- Adresele indicatorului pentru tabelul de stivă de întrerupere (Secțiunea indicatorului de stivă la nivel interior de mai sus, discută necesitatea acestui lucru).
- Adresa Offset a bitmap-ului permisiune IO.
De asemenea, registrul de sarcini este extins în aceste moduri pentru a putea deține o adresă de bază pe 64 de biți.