Task Switching and TSS in Linux in x86 System

Source: Internet
Author: User

This article mainly introduces the x86 SystemLinuxInTask SwitchingAndTSSI believe that you will have a deeper understanding of the Linux system.

Example of the role of TSS: to save the registers used by tasks at different privileged levels, especially esp, because, for example, when a task is interrupted and involves a special switch (one task switch ), first, we need to switch the stack. This stack is obviously the kernel stack. So how can we find the stack address? This must be obtained from the tss segment, in this way, subsequent execution will be relied on (on x86 machines, C function calls are implemented through stacks ). As long as the task switches from the Local Privilege ring to the high privilege ring, the stack corresponding to the high privilege ring needs to be found. Therefore, esp2, esp1, and esp0 must have at least three esp instances, however, only esp0 is used in Linux.

What is TSS: TSS is a segment and the segment is x86. In protection mode, the segment selector participates in addressing, and the segment selector is in the segment register, the tss segment is in the tr register.

Intel's suggestion: Prepare an independent TSS segment for each process. During process switching, switch the tr register to point it to the corresponding TSS segment of the process, then, when the task is switched (for example, an interrupt that involves a privileged-level switch), all registers are retained using this segment.

Linux practices:

1. Linux does not prepare a tss segment for each process. Instead, each cpu uses a tss segment and the tr register saves the segment. During process switching, only the esp0 field in the unique tss segment is updated to the kernel stack of the new process.

2. in the tss segment of Linux, only fields such as esp0 and iomap are used, instead of storing registers. When a user process is interrupted and enters ring0, esp0 is extracted from the tss and then switched to esp0, other registers are stored on the kernel stack indicated by esp0 instead of the tss.

3. As a result, each cpu in Linux has only one tss segment, and the tr register always points to it. It complies with the x86 processor usage specifications, but does not follow intel's recommendations. The consequence is that the overhead is lower because you do not have to switch the tr register.

Linux implementation:

1. Define tss:

struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS };(arch/i386/kernel/init_task.c)

INIT_TSS is defined:

 
 
  1. #define INIT_TSS  {                              
  2. .esp0        = sizeof(init_stack) + (long)&init_stack,      
  3. .ss0        = __KERNEL_DS,                      
  4. .esp1        = sizeof(init_tss[0]) + (long)&init_tss[0],      
  5. .ss1        = __KERNEL_CS,                      
  6. .ldt        = GDT_ENTRY_LDT,                  
  7. .io_bitmap_base    = INVALID_IO_BITMAP_OFFSET,              
  8. .io_bitmap    = { [ 0 ... IO_BITMAP_LONGS] = ~0 },          

2. initialize tss:

 
 
  1. struct tss_struct * t = init_tss + cpu;  
  2. ...  
  3. load_esp0(t, thread);  
  4. set_tss_desc(cpu,t);  
  5. cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;  
  6. load_TR_desc();  

Related functions or macros are:

 
 
  1. #define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8))  
  2. static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr)  
  3. {  
  4. _set_tssldt_desc(&cpu_gdt_table[cpu][entry], (int)addr,  
  5. offsetof(struct tss_struct, __cacheline_filler) - 1, 0x89);  
  6. }  
  7. #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) 

After the above initialization, tr always points to the unique tss segment. However, esp0 and iomap In the tss segment are constantly changing with the process switching.
3. During process switching, you can switch esp0 and iomap in the globally unique tss segment:
In _ switch_to:

 
 
  1. struct tss_struct *tss = init_tss + cpu;  
  2. ...  
  3. load_esp0(tss, next); 

This changes the esp0 of the tss.
In this case, if the process is interrupted in the user State, the machine switches to ring0, extracts the unique tss segment from tr, finds its esp0, and switches the stack to another one, then, all other registers are stored in the kernel indicated by the current esp0 In the tss, that is, the ring0 stack.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.