From c7172468133f9f739b66d22f351b1934d1b6190e Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 5 Sep 2004 07:59:21 +0000 Subject: [PATCH] Add comments. --- src/userprog/gdt.c | 5 +++-- src/userprog/tss.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/userprog/gdt.c b/src/userprog/gdt.c index e3e1dde..c122849 100644 --- a/src/userprog/gdt.c +++ b/src/userprog/gdt.c @@ -44,7 +44,7 @@ gdt_init (void) gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3); gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (tss_get ()); - /* Load GDTR, TR. */ + /* Load GDTR, TR. See [IA32-v3] 2.4.1, 2.4.4, 6.2.3. */ gdtr_operand = make_gdtr_operand (sizeof gdt - 1, gdt); asm volatile ("lgdt %0" :: "m" (gdtr_operand)); asm volatile ("ltr %w0" :: "r" (SEL_TSS)); @@ -125,7 +125,8 @@ make_data_desc (int dpl) /* Returns a descriptor for an "available" 32-bit Task-State Segment with its base at the given linear address, a limit of - 0x67 bytes (the size of a 32-bit TSS), and a DPL of 0. */ + 0x67 bytes (the size of a 32-bit TSS), and a DPL of 0. + See [IA32-v3] 6.2.2. */ static uint64_t make_tss_desc (void *laddr) { diff --git a/src/userprog/tss.c b/src/userprog/tss.c index 37d075b..4b32d85 100644 --- a/src/userprog/tss.c +++ b/src/userprog/tss.c @@ -5,11 +5,52 @@ #include "mmu.h" #include "palloc.h" +/* The Task-State Segment (TSS). + + Instances of the TSS, an x86-specific structure, are used to + define "tasks", a form of support for multitasking built right + into the processor. However, for various reasons including + portability, speed, and flexibility, most x86 OSes almost + completely ignore the TSS. We are no exception. + + Unfortunately, there is one thing that can only be done using + a TSS: stack switching for interrupts that occur in user mode. + When an interrupt occurs in user mode (ring 3), the processor + consults the ss0 and esp0 members of the current TSS to + determine the stack to use for handling the interrupt. Thus, + we must create a TSS and initialize at least these fields, and + this is precisely what this file does. + + When an interrupt is handled by an interrupt or trap gate + (which applies to all interrupts we handle), an x86 processor + works like this: + + - If the code interrupted by the interrupt is in the same + ring as the interrupt handler, then no stack switch takes + place. This is the case for interrupts that happen when + we're running in the kernel. The contents of the TSS are + irrelevant for this case. + + - If the interrupted code is in a different ring from the + handler, then the processor switches to the stack + specified in the TSS for the new ring. This is the case + for interrupts that happen when we're in user space. It's + important that we switch to a stack that's not already in + use, to avoid corruption. Because we're running in user + space, we know that the current process's kernel stack is + not in use, so we can always use that. Thus, when the + scheduler switches threads, it also changes the TSS's + stack pointer to point to the new thread's kernel stack. + (The call is in schedule_tail() in thread.c.) + + See [IA32-v3] 6.2.1 for a description of the TSS and 5.12.1 + for a description of when and how stack switching occurs + during an interrupt. */ struct tss { uint16_t back_link, :16; - void *esp0; - uint16_t ss0, :16; + void *esp0; /* Ring 0 stack virtual address. */ + uint16_t ss0, :16; /* Ring 0 stack segment selector. */ void *esp1; uint16_t ss1, :16; void *esp2; @@ -29,8 +70,10 @@ struct tss uint16_t trace, bitmap; }; +/* Kernel TSS. */ static struct tss *tss; +/* Initializes the kernel TSS. */ void tss_init (void) { @@ -43,6 +86,7 @@ tss_init (void) tss->bitmap = 0xdfff; } +/* Returns the kernel TSS. */ struct tss * tss_get (void) { @@ -50,6 +94,7 @@ tss_get (void) return tss; } +/* Sets the ring 0 stack pointer in the TSS to ESP0. */ void tss_set_esp0 (uint8_t *esp0) { -- 2.30.2