Project

General

Profile

Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / bsp / hal / x86 / arch / context.c @ 03e9c04a

History | View | Annotate | Download (5.76 KB)

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
}