ULK --- Chap3 Processes: Process Switch
To control the execution of process, the kernel must be able to suspend the execution of the process
running on the CPU and resume the execution of some other process previously suspended. This
activity goes variously by the names process switch, task_switch, or context switch.
Hardware Context
While each process can have its own address space, all processes have to share the CPU registers. So
before resuming the execution of a process, the kernel must ensure that each such register is loaded
with the value it has when the process is suspended.
The set of data that must be loaded into the registers before the process resumes its execution on the
CPU is called the hardware context. The hardware context is a subset of the process execution context,
which includes all infomation needed for the process execution. In Linux, a part of the hardware context
of a process is stored in the process descriptor, which the remaining part is saved in the Kernel Mode
Stack.
In the descriptor that follows, we will assume the prev local variable refers to the process descriptor of
the process being switched out and next refers to the one being switched in to replace it. We can thus
define a process switch as the activity consisting of saving the hardware context of prev and replacing
it with the hardware context of next. Because process switches occur quite often, it is important to
minimize the time spent in svaing and loading hardware contexts.
Old version of Linux took advantage of the hardware support offered by the 80x86 architecture and
performed a process switch through a far jmp instruction to the selector of the Task State Segment
Descriptor of the next process. While executing the instruction, the CPU performs a hardware context
switch by automatically saving old hardware context and loading a new one. But Linux 2.6 uses software
to perform a process witch for the following reasons:
Step-by-step switching performed through a sequence of mov instruction allows better control over
the validity of the data being loaded. In particular, it is possible to check the values of the ds and ss
segmentation registers, which might have been forged by a malicious user. This type of checking is not
possible when using a single far jmp instruction.
The amount of time required by the old approach and the new approach is about the same. However,
it is not possible to optimize a hardware context switch, while there might be room for improving the
current switching code.
Process swithing occurs only in Kernel Mode. The contents of all registers used by a process in User Mode
have already been saved on the Kernel Mode Stack before performing process switch. This includes the
contents of the ss and esp pair that specifies the User Mode stack pointer address.
Task State Segment
The 80x86 architecture includes a specific segment type called the Task State Segment (TSS), to store
hardware contexts. Although Linux doesn't use hardware context switches, it is nonetheless forced to set
up a TSS for each distinct CPU in the system. This is done for two reaons:
When an 80x86 CPU switches from User Mode to Kernel Mode, it fetches the address of the Kernel Mode
stack from the TSS.
When a User Mode process attempts to access an I/O port by means of an in or out instruction, the CPU
may need to access an I/O Permission Bitmap stored in the TSS to verify whether the process is allowed
to address the port.
More precisely, when a process executes an in or out I/O instruction in User Mode, the control unit performs
the following operations:
It checks the 2-bit IOPL field in the eflags register. If it is set to 3, the control unit executes the I/O instruction.
Otherwise, it performs the next check.
It accesses the tr register to determine the current TSS, and thus the proper I/O Permission Bitmap.
It checks the bit of the I/O Permission Bitmap corresponding to the I/O port specified in the I/O instruction. If
it is cleared, the instruction is executed; otherwise, the control unit raises a "General Protection" exception.
The tss_struct structure describes the format of the TSS. As already mentioned in Chapter 2, the init_tss
array stores one TSS for each CPU on the system. At each process switch, the kernel updates some fields of
the TSS so that the corresponding CPU's control unit may safely retrieve the information it needs. Thus, the
TSS reflects the privilege of the current porcess on the CPU, but there is no need to maintain TSSs for processes
when they are not running.
Each TSS has its own 8-byte Task State Segment Descriptor (TSSD). This descriptor includes a 32-bit base field
that points to the TSS starting address and a 20-bit Limit field. The S flag of a TSSD is cleared to denote the fact
that the corresponding TSS is a Sytem Segment.
The type field is set to either 9 or 11 to denote that the segment is actually a TSS. In the Intel's original design,
each process in the system should refer to its own TSS; the second least significant bit of the Type field is called
the Busy bit; it is set to 1 if the process is being executed by a CPU, and to 0 otherwise. In Linux design, there is
just one TSS for each CPU, so the Busy bit is always set to 1.
The TSSDs creatd by Linux are stored in the Global Descriptor Table (GDT), whose base address is stored in the
gdtr register of each CPU. The tr register of each CPU contains the TSSD Selector of the corresponding TSS. The
register also includes two hidden, nonprogrammable field; the Base and Limit fields of the TSSD. In this way, the
processor can address the TSS directly without having to retrieve the TSS address from the GDT.
The thread field
At every process switch, the hardware context of the process being replaced must be saved somewhere. It cannot
be saved on the TSS, as in the original Intel design, because Linux uses a single TSS for each processor, instead of
one for every process. Thus, each process descriptor includes a field called thead of type thread_struct, in which
the kernel saves the hardware context whenever the process is being switched out. As we will see later, this data
structure includes fields for most of the CPU registers, except the general-purpose register such as eax, ebx, etc.,
which are stored in the Kernel Mode Stack.
posted on 2015-11-13 06:32 Persistence 阅读(236) 评论(0) 编辑 收藏 举报