Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/hal/x86/arch/context.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. context_set
  2. context_switch
  3. context_save
  4. context_restore
  5. context_dump

   1 /*-
   2  * Copyright (c) 2005-2009, 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 kernel
  36  * stack. The user mode registers are always saved to the kernel
  37  * 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
  40  * frame at the top of the kernel stack. Before the control
  41  * returns to user mode next time, these register value will be
  42  * restored automatically.
  43  *
  44  * All thread owns its context to keep its execution state. The
  45  * scheduler will switch the context to change an active thread.
  46  */
  47 
  48 #include <kernel.h>
  49 #include <kmem.h>
  50 #include <cpu.h>
  51 #include <trap.h>
  52 #include <context.h>
  53 #include <locore.h>
  54 
  55 /*
  56  * Set user mode registers into the specific context.
  57  *
  58  * Note: When user mode program counter is set, all register
  59  * values except a stack pointer are reset to default value.
  60  */
  61 void
  62 context_set(context_t ctx, int type, register_t val)
  63 {
  64         struct kern_regs *k;
  65         struct cpu_regs *u;
  66         uint32_t *argp;
  67 
  68         k = &ctx->kregs;
  69 
  70         switch (type) {
  71         case CTX_KSTACK:
  72                 /* Set kernel mode stack pointer */
  73                 ctx->uregs = (struct cpu_regs *)
  74                                 ((uint32_t)val - sizeof(struct cpu_regs));
  75                 ctx->esp0 = (uint32_t)val;
  76 
  77                 k->eip = (uint32_t)&syscall_ret;
  78                 k->esp = (uint32_t)ctx->uregs - sizeof(uint32_t);
  79 
  80                 /* Reset minimum user mode registers */
  81                 u = ctx->uregs;
  82                 u->eax = 0;
  83                 u->eflags = (uint32_t)(EFL_IF | EFL_IOPL_KERN);
  84                 break;
  85 
  86         case CTX_KENTRY:
  87                 /* Kernel mode program counter */
  88                 k->eip = (uint32_t)val;
  89                 break;
  90 
  91         case CTX_KARG:
  92                 /* Kernel mode argument */
  93                 argp = (uint32_t *)(k->esp + sizeof(uint32_t) * 2);
  94                 *argp = (uint32_t)val;
  95                 break;
  96 
  97         case CTX_USTACK:
  98                 /* User mode stack pointer */
  99                 u = ctx->uregs;
 100                 u->esp = (uint32_t)val;
 101                 u->ss = (uint32_t)(USER_DS | 3); /* fail safe */
 102                 break;
 103 
 104         case CTX_UENTRY:
 105                 /* User mode program counter */
 106                 u = ctx->uregs;
 107                 u->eip = (uint32_t)val;
 108                 u->cs = (uint32_t)(USER_CS | 3);
 109                 u->ds = u->es = (uint32_t)(USER_DS | 3);
 110                 u->eflags = (uint32_t)(EFL_IF | EFL_IOPL_KERN);
 111                 u->eax = u->ebx = u->ecx = u->edx =
 112                         u->edi = u->esi = u->ebp = 0;
 113                 break;
 114 
 115         case CTX_UARG:
 116                 /* User mode argument */
 117                 u = ctx->uregs;
 118                 argp = (uint32_t *)(u->esp + sizeof(uint32_t));
 119                 copyout(&val, argp, sizeof(uint32_t));
 120                 break;
 121 
 122         default:
 123                 /* invalid */
 124                 break;
 125         }
 126 }
 127 
 128 /*
 129  * Switch to new context
 130  *
 131  * Kernel mode registers and kernel stack pointer are switched to
 132  * the next context.
 133  *
 134  * We don't use x86 task switch mechanism to minimize the context
 135  * space. The system has only one TSS(task state segment), and
 136  * the context switching is done by changing the register value
 137  * in this TSS. Processor will reload them automatically when it
 138  * enters to the kernel mode in 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((uint32_t)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  *
 157  * Copy current user mode registers in the kernel stack to the
 158  * user mode stack. The user stack pointer is adjusted for this
 159  * area. So that the exception handler can get the register
 160  * state of the target thread.
 161  *
 162  * It builds arguments for the exception handler in the following
 163  * format.
 164  *
 165  *   void exception_handler(int exc, void *regs);
 166  */
 167 void
 168 context_save(context_t ctx)
 169 {
 170         struct cpu_regs *cur, *sav;
 171 
 172         /* Copy current register context into user mode stack */
 173         cur = ctx->uregs;
 174         sav = (struct cpu_regs *)(cur->esp - sizeof(*sav));
 175         copyout(cur, sav, sizeof(*sav));
 176 
 177 
 178         ctx->saved_regs = sav;
 179 
 180         /* Adjust stack pointer */
 181         cur->esp = (uint32_t)sav - (sizeof(uint32_t) * 2);
 182 }
 183 
 184 /*
 185  * Restore register context to return from the exception handler.
 186  */
 187 void
 188 context_restore(context_t ctx)
 189 {
 190         struct cpu_regs *cur;
 191 
 192         /* Restore user mode context */
 193         cur = ctx->uregs;
 194         copyin(ctx->saved_regs, cur, sizeof(*cur));
 195 
 196         /* Correct some registers for fail safe */
 197         cur->cs = (uint32_t)(USER_CS | 3);
 198         cur->ss = cur->ds = cur->es = (uint32_t)(USER_DS | 3);
 199         cur->eflags |= EFL_IF;
 200 }
 201 
 202 void
 203 context_dump(context_t ctx)
 204 {
 205 
 206 #ifdef DEBUG
 207         trap_dump(ctx->uregs);
 208 #endif
 209 }

/* [<][>][^][v][top][bottom][index][help] */