00001 #include "userprog/tss.h" 00002 //110666441 00003 #include <debug.h> 00004 #include <stddef.h> 00005 #include "userprog/gdt.h" 00006 #include "threads/thread.h" 00007 #include "threads/palloc.h" 00008 #include "threads/vaddr.h" 00009 00010 /* The Task-State Segment (TSS). 00011 00012 Instances of the TSS, an x86-specific structure, are used to 00013 define "tasks", a form of support for multitasking built right 00014 into the processor. However, for various reasons including 00015 portability, speed, and flexibility, most x86 OSes almost 00016 completely ignore the TSS. We are no exception. 00017 00018 Unfortunately, there is one thing that can only be done using 00019 a TSS: stack switching for interrupts that occur in user mode. 00020 When an interrupt occurs in user mode (ring 3), the processor 00021 consults the ss0 and esp0 members of the current TSS to 00022 determine the stack to use for handling the interrupt. Thus, 00023 we must create a TSS and initialize at least these fields, and 00024 this is precisely what this file does. 00025 00026 When an interrupt is handled by an interrupt or trap gate 00027 (which applies to all interrupts we handle), an x86 processor 00028 works like this: 00029 00030 - If the code interrupted by the interrupt is in the same 00031 ring as the interrupt handler, then no stack switch takes 00032 place. This is the case for interrupts that happen when 00033 we're running in the kernel. The contents of the TSS are 00034 irrelevant for this case. 00035 00036 - If the interrupted code is in a different ring from the 00037 handler, then the processor switches to the stack 00038 specified in the TSS for the new ring. This is the case 00039 for interrupts that happen when we're in user space. It's 00040 important that we switch to a stack that's not already in 00041 use, to avoid corruption. Because we're running in user 00042 space, we know that the current process's kernel stack is 00043 not in use, so we can always use that. Thus, when the 00044 scheduler switches threads, it also changes the TSS's 00045 stack pointer to point to the new thread's kernel stack. 00046 (The call is in schedule_tail() in thread.c.) 00047 00048 See [IA32-v3a] 6.2.1 "Task-State Segment (TSS)" for a 00049 description of the TSS. See [IA32-v3a] 5.12.1 "Exception- or 00050 Interrupt-Handler Procedures" for a description of when and 00051 how stack switching occurs during an interrupt. */ 00052 struct tss 00053 { 00054 uint16_t back_link, :16; 00055 void *esp0; /* Ring 0 stack virtual address. */ 00056 uint16_t ss0, :16; /* Ring 0 stack segment selector. */ 00057 void *esp1; 00058 uint16_t ss1, :16; 00059 void *esp2; 00060 uint16_t ss2, :16; 00061 uint32_t cr3; 00062 void (*eip) (void); 00063 uint32_t eflags; 00064 uint32_t eax, ecx, edx, ebx; 00065 uint32_t esp, ebp, esi, edi; 00066 uint16_t es, :16; 00067 uint16_t cs, :16; 00068 uint16_t ss, :16; 00069 uint16_t ds, :16; 00070 uint16_t fs, :16; 00071 uint16_t gs, :16; 00072 uint16_t ldt, :16; 00073 uint16_t trace, bitmap; 00074 }; 00075 00076 /* Kernel TSS. */ 00077 static struct tss *tss; 00078 00079 /* Initializes the kernel TSS. */ 00080 void 00081 tss_init (void) 00082 { 00083 /* Our TSS is never used in a call gate or task gate, so only a 00084 few fields of it are ever referenced, and those are the only 00085 ones we initialize. */ 00086 tss = palloc_get_page (PAL_ASSERT | PAL_ZERO); 00087 tss->ss0 = SEL_KDSEG; 00088 tss->bitmap = 0xdfff; 00089 tss_update (); 00090 } 00091 00092 /* Returns the kernel TSS. */ 00093 struct tss * 00094 tss_get (void) 00095 { 00096 ASSERT (tss != NULL); 00097 return tss; 00098 } 00099 00100 /* Sets the ring 0 stack pointer in the TSS to point to the end 00101 of the thread stack. */ 00102 void 00103 tss_update (void) 00104 { 00105 ASSERT (tss != NULL); 00106 tss->esp0 = (uint8_t *) thread_current () + PGSIZE; 00107 }