Annotation of prex-old/sys/arch/i386/i386/context.c, Revision 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