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编辑  收藏  举报

导航