Intel IA-32 User Manual
Page 154
4-24 Vol. 3A
PROTECTION
Each task must define up to 4 stacks: one for applications code (running at privilege level 3) and
one for each of the privilege levels 2, 1, and 0 that are used. (If only two privilege levels are used
[3 and 0], then only two stacks must be defined.) Each of these stacks is located in a separate
segment and is identified with a segment selector and an offset into the stack segment (a stack
pointer).
The segment selector and stack pointer for the privilege level 3 stack is located in the SS and
ESP registers, respectively, when privilege-level-3 code is being executed and is automatically
stored on the called procedure’s stack when a stack switch occurs.
Pointers to the privilege level 0, 1, and 2 stacks are stored in the TSS for the currently running
task (see Figure 6-2). Each of these pointers consists of a segment selector and a stack pointer
(loaded into the ESP register). These initial pointers are strictly read-only values. The processor
does not change them while the task is running. They are used only to create new stacks when
calls are made to more privileged levels (numerically lower privilege levels). These stacks are
disposed of when a return is made from the called procedure. The next time the procedure is
called, a new stack is created using the initial stack pointer. (The TSS does not specify a stack
for privilege level 3 because the processor does not allow a transfer of program control from a
procedure running at a CPL of 0, 1, or 2 to a procedure running at a CPL of 3, except on a return.)
The operating system is responsible for creating stacks and stack-segment descriptors for all the
privilege levels to be used and for loading initial pointers for these stacks into the TSS. Each
stack must be read/write accessible (as specified in the type field of its segment descriptor) and
must contain enough space (as specified in the limit field) to hold the following items:
•
The contents of the SS, ESP, CS, and EIP registers for the calling procedure.
•
The parameters and temporary variables required by the called procedure.
•
The EFLAGS register and error code, when implicit calls are made to an exception or
interrupt handler.
The stack will need to require enough space to contain many frames of these items, because
procedures often call other procedures, and an operating system may support nesting of multiple
interrupts. Each stack should be large enough to allow for the worst case nesting scenario at its
privilege level.
(If the operating system does not use the processor’s multitasking mechanism, it still must create
at least one TSS for this stack-related purpose.)
When a procedure call through a call gate results in a change in privilege level, the processor
performs the following steps to switch stacks and begin execution of the called procedure at a
new privilege level:
1.
Uses the DPL of the destination code segment (the new CPL) to select a pointer to the new
stack (segment selector and stack pointer) from the TSS.
2.
Reads the segment selector and stack pointer for the stack to be switched to from the
current TSS. Any limit violations detected while reading the stack-segment selector, stack
pointer, or stack-segment descriptor cause an invalid TSS (#TS) exception to be generated.
3.
Checks the stack-segment descriptor for the proper privileges and type and generates an
invalid TSS (#TS) exception if violations are detected.