Annotation of prex-old/sys/arch/i386/i386/context.c, Revision 1.1.1.1
1.1 nbrk 1: /*-
2: * Copyright (c) 2005, Kohsuke Ohtani
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. Neither the name of the author nor the names of any co-contributors
14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: */
29:
30: /*
31: * context.c - context management routines
32: */
33:
34: /*
35: * The context consists of kernel/user mode registers, and
36: * kernel stack. The user mode registers are always saved to the
37: * kernel stack when processor enters kernel mode by H/W or S/W events.
38: *
39: * The user mode registers are located in the interrupt/trap frame
40: * at the top of the kernel stack. Before the control returns to user
41: * mode next time, these register value will be restored automatically.
42: *
43: * All thread owns its context to keep its execution state. The
44: * scheduler will switch the context to change an active thread.
45: */
46:
47: #include <kernel.h>
48: #include <cpu.h>
49: #include <locore.h>
50:
51: /*
52: * Exception frame - stack layout for exception handler
53: */
54: struct exc_frame {
55: void *ret; /* Return address */
56: u_long code; /* Argument 1 */
57: struct cpu_regs *uregs; /* Argument 2 */
58: };
59:
60: /*
61: * Initialize specified context.
62: * @ctx: context id (pointer)
63: * @kstack: kernel stack for the context
64: *
65: * All thread will start at syscall_ret().
66: * In this time, the interrupt and I/O access are enabled.
67: */
68: void
69: context_init(context_t ctx, u_long kstack)
70: {
71: struct kern_regs *k;
72: struct cpu_regs *u;
73:
74: ctx->uregs = (struct cpu_regs *)(kstack - sizeof(struct cpu_regs));
75: ctx->esp0 = kstack;
76:
77: /* Initialize kernel mode registers */
78: k = &ctx->kregs;
79: k->eip = (u_long)syscall_ret;
80: k->esp = (u_long)ctx->uregs - sizeof(u_long);
81:
82: /* Reset minimum user mode registers */
83: u = ctx->uregs;
84: u->eax = 0;
85: u->eflags = EFL_IF | EFL_IOPL_KERN;
86: }
87:
88: /*
89: * Set data to the specific register stored in context.
90: * @type: register type to be set
91: * @val: register value to be set
92: *
93: * Note: When user mode program counter is set, all register
94: * values except stack pointer are reset to default value.
95: */
96: void
97: context_set(context_t ctx, int type, u_long val)
98: {
99: struct kern_regs *k;
100: struct cpu_regs *u;
101:
102: switch (type) {
103: case CTX_UENTRY: /* User mode program counter */
104: u = ctx->uregs;
105: u->eax = u->ebx = u->ecx = u->edx =
106: u->edi = u->esi = u->ebp = 0;
107: u->cs = USER_CS | 3;
108: u->ds = u->es = USER_DS | 3;
109: u->eflags = EFL_IF | EFL_IOPL_KERN;
110: u->eip = val;
111: break;
112: case CTX_USTACK: /* User mode stack pointer */
113: u = ctx->uregs;
114: u->esp = val;
115: u->ss = USER_DS | 3;
116: break;
117: case CTX_KENTRY: /* Kernel mode program counter */
118: k = &ctx->kregs;
119: k->eip = val;
120: break;
121: case CTX_KARG: /* Kernel mode argument */
122: k = &ctx->kregs;
123: *(u_long *)(k->esp + sizeof(u_long) * 2) = val;
124: break;
125: }
126: }
127:
128: /*
129: * Switch to new context
130: *
131: * Kernel mode registers and kernel stack pointer are switched to the
132: * next context.
133: *
134: * We don't use x86 task switch mechanism to minimize the context space.
135: * The system has only one TSS(task state segment), and the context
136: * switching is done by changing the register value in this TSS. Processor
137: * will reload them automatically when it enters to the kernel mode in
138: * next time.
139: *
140: * It is assumed all interrupts are disabled by caller.
141: *
142: * TODO: FPU context is not switched as of now.
143: */
144: void
145: context_switch(context_t prev, context_t next)
146: {
147: /* Set kernel stack pointer in TSS (esp0). */
148: tss_set((u_long)next->esp0);
149:
150: /* Save the previous context, and restore the next context */
151: cpu_switch(&prev->kregs, &next->kregs);
152: }
153:
154: /*
155: * Save user mode context to handle exceptions.
156: * @exc: exception code passed to the exception handler
157: *
158: * Copy current user mode registers in the kernel stack to the user
159: * mode stack. The user stack pointer is adjusted for this area.
160: * So that the exception handler can get the register state of
161: * the target thread.
162: *
163: * It builds arguments for the exception handler in the following
164: * format.
165: *
166: * void exception_handler(int exc, void *regs);
167: */
168: void
169: context_save(context_t ctx, int exc)
170: {
171: struct cpu_regs *cur, *sav;
172: struct exc_frame *frm;
173:
174: /* Copy current register context into user mode stack */
175: cur = ctx->uregs;
176: sav = (struct cpu_regs *)(cur->esp - sizeof(struct cpu_regs));
177: memcpy(sav, cur, sizeof(struct cpu_regs));
178:
179: /* Setup exception frame for exception handler */
180: frm = (struct exc_frame *)(sav - sizeof(struct exc_frame));
181: frm->uregs = sav;
182: frm->code = exc;
183: frm->ret = NULL;
184: cur->esp = (u_long)frm;
185: }
186:
187: /*
188: * Restore register context to return from the exception handler.
189: * @regs: pointer to user mode register context.
190: */
191: void
192: context_restore(context_t ctx, void *regs)
193: {
194: struct cpu_regs *cur;
195:
196: /* Restore user mode context */
197: cur = ctx->uregs;
198: memcpy(cur, regs, sizeof(struct cpu_regs));
199:
200: /* Correct some registers for fail safe */
201: cur->cs = USER_CS | 3;
202: cur->ss = cur->ds = cur->es = USER_DS | 3;
203: cur->eflags |= EFL_IF;
204:
205: ASSERT(cur->eip && user_area(cur->eip));
206: ASSERT(cur->esp && user_area(cur->esp));
207: }
CVSweb