1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
/* tag: x86 context switching
*
* 2003-10 by SONE Takeshi
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "config.h"
#include "kernel/kernel.h"
#include "segment.h"
#include "context.h"
#include "libopenbios/bindings.h"
#include "libopenbios/initprogram.h"
#include "libopenbios/sys_info.h"
#include "boot.h"
#include "openbios.h"
#define MAIN_STACK_SIZE 16384
#define IMAGE_STACK_SIZE 4096
#define debug printk
static void start_main(void); /* forward decl. */
void __exit_context(void); /* assembly routine */
/*
* Main context structure
* It is placed at the bottom of our stack, and loaded by assembly routine
* to start us up.
*/
static struct context main_ctx __attribute__((section (".initctx"))) = {
.gdt_base = (uint32_t) gdt,
.gdt_limit = GDT_LIMIT,
.cs = FLAT_CS,
.ds = FLAT_DS,
.es = FLAT_DS,
.fs = FLAT_DS,
.gs = FLAT_DS,
.ss = FLAT_DS,
.esp = (uint32_t) ESP_LOC(&main_ctx),
.eip = (uint32_t) start_main,
.return_addr = (uint32_t) __exit_context,
};
/* This is used by assembly routine to load/store the context which
* it is to switch/switched. */
struct context * volatile __context = &main_ctx;
/* Client program context */
static struct context *client_ctx;
/* Stack for loaded ELF image */
static uint8_t image_stack[IMAGE_STACK_SIZE];
/* Pointer to startup context (physical address) */
unsigned long __boot_ctx;
/*
* Main starter
* This is the C function that runs first.
*/
static void start_main(void)
{
int retval;
/* Save startup context, so we can refer to it later.
* We have to keep it in physical address since we will relocate. */
__boot_ctx = virt_to_phys(__context);
init_exceptions();
/* Set up client context */
client_ctx = init_context(image_stack, sizeof image_stack, 1);
__context = client_ctx;
/* Start the real fun */
retval = openbios();
/* Pass return value to startup context. Bootloader may see it. */
boot_ctx->eax = retval;
/* Returning from here should jump to __exit_context */
__context = boot_ctx;
}
/* Setup a new context using the given stack.
*/
struct context *
init_context(uint8_t *stack, uint32_t stack_size, int num_params)
{
struct context *ctx;
ctx = (struct context *)
(stack + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t)));
memset(ctx, 0, sizeof(*ctx));
return ctx;
}
/* init-program */
int
arch_init_program(void)
{
struct context volatile *ctx = __context;
ucell type, entry, param;
/* Fill in reasonable default for flat memory model */
ctx->gdt_base = virt_to_phys(gdt);
ctx->gdt_limit = GDT_LIMIT;
ctx->cs = FLAT_CS;
ctx->ds = FLAT_DS;
ctx->es = FLAT_DS;
ctx->fs = FLAT_DS;
ctx->gs = FLAT_DS;
ctx->ss = FLAT_DS;
ctx->esp = virt_to_phys(ESP_LOC(ctx));
ctx->return_addr = virt_to_phys(__exit_context);
/* Set param */
feval("load-state >ls.param @");
param = POP();
ctx->param[0] = param;
/* Only elf-boot type has a param */
feval("load-state >ls.file-type @");
type = POP();
if (type == 0) {
ctx->eax = 0xe1fb007;
ctx->ebx = param;
}
/* Set entry point */
feval("load-state >ls.entry @");
entry = POP();
ctx->eip = entry;
return 0;
}
/* Switch to another context. */
struct context *switch_to(struct context *ctx)
{
struct context *save, *ret;
debug("switching to new context:\n");
save = __context;
__context = ctx;
asm ("pushl %cs; call __switch_context");
ret = __context;
__context = save;
return ret;
}
/* Start ELF Boot image */
unsigned int start_elf(void)
{
volatile struct context *ctx = __context;
ctx = switch_to((struct context *)ctx);
return ctx->eax;
}
|