5-26 Vol. 3
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 7-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 descrip-
tors 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.