summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/arch/x86/entry.S
blob: 8f1e42eed1e1455b96e2a22155e0a605da96109f (plain)
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
	.globl	entry, __switch_context, __exit_context, halt, init_exceptions

	.text
	.align	4

/*
 * Entry point
 * We start execution from here.
 * It is assumed that CPU is in 32-bit protected mode and
 * all segments are 4GB and base zero (flat model).
 */
entry:
	/* Save boot context and switch to our main context.
	 * Main context is statically defined in C.
	 */
	pushl	%cs
	call	__switch_context

	/* We get here when the main context switches back to
	 * the boot context.
	 * Return to previous bootloader.
	 */
	ret

/*
 * Switch execution context
 * This saves registers, segments, and GDT in the stack, then
 * switches the stack, and restores everything from the new stack.
 * This function takes no argument. New stack pointer is
 * taken from global variable __context, and old stack pointer
 * is also saved to __context. This way we can just jump to
 * this routine to get back to the original context.
 *
 * Call this routine with lcall or pushl %cs; call.
 */
__switch_context:
	/* Save everything in current stack */
	pushfl		    /* 56 */
	pushl	%ds	    /* 52 */
	pushl	%es	    /* 48 */
	pushl	%fs	    /* 44 */
	pushl	%gs	    /* 40 */
	pushal		    /* 8 */
	subl	$8, %esp
	movw	%ss, (%esp) /* 0 */
	sgdt	2(%esp)	    /* 2 */

#if 0
	/* Swap %cs and %eip on the stack, so lret will work */
	movl	60(%esp), %eax
	xchgl	%eax, 64(%esp)
	movl	%eax, 60(%esp)
#endif

	/* At this point we don't know if we are on flat segment
	 * or relocated. So compute the address offset from %eip.
	 * Assuming CS.base==DS.base==SS.base.
	 */
	call	1f
1:	popl	%ebx
	subl	$1b, %ebx

	/* Interrupts are not allowed... */
	cli

	/* Current context pointer is our stack pointer */
	movl	%esp, %esi

	/* Normalize the ctx pointer */
	subl	%ebx, %esi

	/* Swap it with new value */
	xchgl	%esi, __context(%ebx)

	/* Adjust new ctx pointer for current address offset */
	addl	%ebx, %esi

	/* Load new %ss and %esp to temporary */
	movzwl	(%esi), %edx
	movl	20(%esi), %eax

	/* Load new GDT */
	lgdt	2(%esi)

	/* Load new stack segment with new GDT */
	movl	%edx, %ss

	/* Set new stack pointer, but we have to adjust it because
	 * pushal saves %esp value before pushal, and we want the value
	 * after pushal.
	 */
	leal	-32(%eax), %esp

	/* Load the rest from new stack */
	popal
	popl	%gs
	popl	%fs
	popl	%es
	popl	%ds
	popfl

	/* Finally, load new %cs and %eip */
	lret

__exit_context:
	/* Get back to the original context */
	pushl	%cs
	call	__switch_context

	/* We get here if the other context attempt to switch to this
	 * dead context. This should not happen. */

halt:
	cli
	hlt
	jmp	halt

/*
 * initialize exception handler. All exceptions end up in the same
 * C function.
 */

init_exceptions:
	pushl	%ebx
	pushl	%edi

        /* Initialize the Interrupt Descriptor table */
        leal    _idt, %edi
        leal    vec0, %ebx
        movl    $(0x08 << 16), %eax     /* cs selector */

1:      movw    %bx, %ax
        movl    %ebx, %edx
        movw    $0x8E00, %dx            /* Interrupt gate - dpl=0, present */
        movl    %eax, 0(%edi)
        movl    %edx, 4(%edi)
        addl    $6, %ebx
        addl    $8, %edi
        cmpl    $_idt_end, %edi
        jne     1b

        /* Load the Interrupt descriptor table */
        lidt    idtarg

	movl 	$0, %eax
	popl	%edi
	popl	%ebx
	ret

vec0:
        pushl   $0 /* error code */
        pushl   $0 /* vector */
        jmp int_hand
vec1:
        pushl   $0 /* error code */
        pushl   $1 /* vector */
        jmp int_hand

vec2:
        pushl   $0 /* error code */
        pushl   $2 /* vector */
        jmp int_hand

vec3:
        pushl   $0 /* error code */
        pushl   $3 /* vector */
        jmp     int_hand

vec4:
        pushl   $0 /* error code */
        pushl   $4 /* vector */
        jmp     int_hand

vec5:
        pushl   $0 /* error code */
        pushl   $5 /* vector */
        jmp     int_hand

vec6:
        pushl   $0 /* error code */
        pushl   $6 /* vector */
        jmp     int_hand
vec7:
        pushl   $0 /* error code */
        pushl   $7 /* vector */
        jmp     int_hand

vec8:
        /* error code */
        pushl   $8 /* vector */
        jmp     int_hand
        .word   0x9090

vec9:
        pushl   $0 /* error code */
        pushl   $9 /* vector */
        jmp int_hand

vec10:
        /* error code */
        pushl   $10 /* vector */
        jmp     int_hand
        .word   0x9090

vec11:
        /* error code */
        pushl   $11 /* vector */
        jmp     int_hand
        .word   0x9090

vec12:
        /* error code */
        pushl   $12 /* vector */
        jmp     int_hand
        .word   0x9090

vec13:
        /* error code */
        pushl   $13 /* vector */
        jmp     int_hand
        .word   0x9090

vec14:
        /* error code */
        pushl   $14 /* vector */
        jmp     int_hand
        .word   0x9090

vec15:
        pushl   $0 /* error code */
        pushl   $15 /* vector */
        jmp     int_hand

vec16:
        pushl   $0 /* error code */
        pushl   $16 /* vector */
        jmp     int_hand

vec17:
        /* error code */
        pushl   $17 /* vector */
        jmp     int_hand
        .word   0x9090

vec18:
        pushl   $0 /* error code */
        pushl   $18 /* vector */
        jmp     int_hand

vec19:
        pushl   $0 /* error code */
        pushl   $19 /* vector */
        jmp     int_hand

__divide_error:
        pushl   $0 /* error code */
        pushl   $20 /* vector */
        jmp     int_hand
        .global __divide_error

int_hand:
        /* At this point on the stack there is:
         *  0(%esp) vector
         *  4(%esp) error code
         *  8(%esp) eip
         * 12(%esp) cs
         * 16(%esp) eflags
         */
        pushl   %edi
        pushl   %esi
        pushl   %ebp
        /* Original stack pointer */
        leal    32(%esp), %ebp
        pushl   %ebp
        pushl   %ebx
        pushl   %edx
        pushl   %ecx
        pushl   %eax

        pushl   %esp    /* Pointer to structure on the stack */

        call    x86_exception
        pop     %eax    /* Drop the pointer */

        popl    %eax
        popl    %ecx
        popl    %edx
        popl    %ebx
        popl    %ebp /* Ignore saved %esp value */
        popl    %ebp
        popl    %esi
        popl    %edi

        addl    $8, %esp /* pop of the vector and error code */

        iret

idtarg:
        .word   _idt_end - _idt - 1     /* limit */
        .long   _idt
        .word   0
_idt:
        .fill   20, 8, 0        # idt is unitiailzed
_idt_end:

        .globl  arch_nvram_size, arch_nvram_get, arch_nvram_put
arch_nvram_size:
        xor     %eax, %eax
        ret

arch_nvram_get:
        ret

arch_nvram_put:
        ret