Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / amd64 / switch.S
1         .globl  entry, __switch_context, __exit_context, halt
2
3         .text
4         .align  4
5
6 /*
7  * Entry point
8  * We start execution from here.
9  * It is assumed that CPU is in 32-bit protected mode and
10  * all segments are 4GB and base zero (flat model).
11  */
12 entry:
13         /* Save boot context and switch to our main context.
14          * Main context is statically defined in C.
15          */
16         pushl   %cs
17         call    __switch_context
18
19         /* We get here when the main context switches back to
20          * the boot context.
21          * Return to previous bootloader.
22          */
23         ret
24
25 /*
26  * Switch execution context
27  * This saves registers, segments, and GDT in the stack, then
28  * switches the stack, and restores everything from the new stack.
29  * This function takes no argument. New stack pointer is
30  * taken from global variable __context, and old stack pointer
31  * is also saved to __context. This way we can just jump to
32  * this routine to get back to the original context.
33  *
34  * Call this routine with lcall or pushl %cs; call.
35  */
36 __switch_context:
37         /* Save everything in current stack */
38         pushfl              /* 56 */
39         pushl   %ds         /* 52 */
40         pushl   %es         /* 48 */
41         pushl   %fs         /* 44 */
42         pushl   %gs         /* 40 */
43         pushal              /* 8 */
44         subl    $8, %esp
45         movw    %ss, (%esp) /* 0 */
46         sgdt    2(%esp)     /* 2 */
47
48 #if 0
49         /* Swap %cs and %eip on the stack, so lret will work */
50         movl    60(%esp), %eax
51         xchgl   %eax, 64(%esp)
52         movl    %eax, 60(%esp)
53 #endif
54
55         /* At this point we don't know if we are on flat segment
56          * or relocated. So compute the address offset from %eip.
57          * Assuming CS.base==DS.base==SS.base.
58          */
59         call    1f
60 1:      popl    %ebx
61         subl    $1b, %ebx
62
63         /* Interrupts are not allowed... */
64         cli
65
66         /* Current context pointer is our stack pointer */
67         movl    %esp, %esi
68
69         /* Normalize the ctx pointer */
70         subl    %ebx, %esi
71
72         /* Swap it with new value */
73         xchgl   %esi, __context(%ebx)
74
75         /* Adjust new ctx pointer for current address offset */
76         addl    %ebx, %esi
77
78         /* Load new %ss and %esp to temporary */
79         movzwl  (%esi), %edx
80         movl    20(%esi), %eax
81
82         /* Load new GDT */
83         lgdt    2(%esi)
84
85         /* Load new stack segment with new GDT */
86         movl    %edx, %ss
87
88         /* Set new stack pointer, but we have to adjust it because
89          * pushal saves %esp value before pushal, and we want the value
90          * after pushal.
91          */
92         leal    -32(%eax), %esp
93
94         /* Load the rest from new stack */
95         popal
96         popl    %gs
97         popl    %fs
98         popl    %es
99         popl    %ds
100         popfl
101
102         /* Finally, load new %cs and %eip */
103         lret
104
105 __exit_context:
106         /* Get back to the original context */
107         pushl   %cs
108         call    __switch_context
109
110         /* We get here if the other context attempt to switch to this
111          * dead context. This should not happen. */
112
113 halt:
114         cli
115         hlt
116         jmp     halt