]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/lguest/x86/switcher_32.S
Move i386 part of core.c to x86/core.c.
[net-next-2.6.git] / drivers / lguest / x86 / switcher_32.S
1 /*P:900 This is the Switcher: code which sits at 0xFFC00000 to do the low-level
2  * Guest<->Host switch.  It is as simple as it can be made, but it's naturally
3  * very specific to x86.
4  *
5  * You have now completed Preparation.  If this has whet your appetite; if you
6  * are feeling invigorated and refreshed then the next, more challenging stage
7  * can be found in "make Guest". :*/
8
9 /*S:100
10  * Welcome to the Switcher itself!
11  *
12  * This file contains the low-level code which changes the CPU to run the Guest
13  * code, and returns to the Host when something happens.  Understand this, and
14  * you understand the heart of our journey.
15  *
16  * Because this is in assembler rather than C, our tale switches from prose to
17  * verse.  First I tried limericks:
18  *
19  *      There once was an eax reg,
20  *      To which our pointer was fed,
21  *      It needed an add,
22  *      Which asm-offsets.h had
23  *      But this limerick is hurting my head.
24  *
25  * Next I tried haikus, but fitting the required reference to the seasons in
26  * every stanza was quickly becoming tiresome:
27  *
28  *      The %eax reg
29  *      Holds "struct lguest_pages" now:
30  *      Cherry blossoms fall.
31  *
32  * Then I started with Heroic Verse, but the rhyming requirement leeched away
33  * the content density and led to some uniquely awful oblique rhymes:
34  *
35  *      These constants are coming from struct offsets
36  *      For use within the asm switcher text.
37  *
38  * Finally, I settled for something between heroic hexameter, and normal prose
39  * with inappropriate linebreaks.  Anyway, it aint no Shakespeare.
40  */
41
42 // Not all kernel headers work from assembler
43 // But these ones are needed: the ENTRY() define
44 // And constants extracted from struct offsets
45 // To avoid magic numbers and breakage:
46 // Should they change the compiler can't save us
47 // Down here in the depths of assembler code.
48 #include <linux/linkage.h>
49 #include <asm/asm-offsets.h>
50 #include <asm/page.h>
51 #include <asm/segment.h>
52 #include <asm/lguest.h>
53
54 // We mark the start of the code to copy
55 // It's placed in .text tho it's never run here
56 // You'll see the trick macro at the end
57 // Which interleaves data and text to effect.
58 .text
59 ENTRY(start_switcher_text)
60
61 // When we reach switch_to_guest we have just left
62 // The safe and comforting shores of C code
63 // %eax has the "struct lguest_pages" to use
64 // Where we save state and still see it from the Guest
65 // And %ebx holds the Guest shadow pagetable:
66 // Once set we have truly left Host behind.
67 ENTRY(switch_to_guest)
68         // We told gcc all its regs could fade,
69         // Clobbered by our journey into the Guest
70         // We could have saved them, if we tried
71         // But time is our master and cycles count.
72
73         // Segment registers must be saved for the Host
74         // We push them on the Host stack for later
75         pushl   %es
76         pushl   %ds
77         pushl   %gs
78         pushl   %fs
79         // But the compiler is fickle, and heeds
80         // No warning of %ebp clobbers
81         // When frame pointers are used.  That register
82         // Must be saved and restored or chaos strikes.
83         pushl   %ebp
84         // The Host's stack is done, now save it away
85         // In our "struct lguest_pages" at offset
86         // Distilled into asm-offsets.h
87         movl    %esp, LGUEST_PAGES_host_sp(%eax)
88
89         // All saved and there's now five steps before us:
90         // Stack, GDT, IDT, TSS
91         // And last of all the page tables are flipped.
92
93         // Yet beware that our stack pointer must be
94         // Always valid lest an NMI hits
95         // %edx does the duty here as we juggle
96         // %eax is lguest_pages: our stack lies within.
97         movl    %eax, %edx
98         addl    $LGUEST_PAGES_regs, %edx
99         movl    %edx, %esp
100
101         // The Guest's GDT we so carefully
102         // Placed in the "struct lguest_pages" before
103         lgdt    LGUEST_PAGES_guest_gdt_desc(%eax)
104
105         // The Guest's IDT we did partially
106         // Move to the "struct lguest_pages" as well.
107         lidt    LGUEST_PAGES_guest_idt_desc(%eax)
108
109         // The TSS entry which controls traps
110         // Must be loaded up with "ltr" now:
111         // For after we switch over our page tables
112         // It (as the rest) will be writable no more.
113         // (The GDT entry TSS needs
114         // Changes type when we load it: damn Intel!)
115         movl    $(GDT_ENTRY_TSS*8), %edx
116         ltr     %dx
117
118         // Look back now, before we take this last step!
119         // The Host's TSS entry was also marked used;
120         // Let's clear it again, ere we return.
121         // The GDT descriptor of the Host
122         // Points to the table after two "size" bytes
123         movl    (LGUEST_PAGES_host_gdt_desc+2)(%eax), %edx
124         // Clear the type field of "used" (byte 5, bit 2)
125         andb    $0xFD, (GDT_ENTRY_TSS*8 + 5)(%edx)
126
127         // Once our page table's switched, the Guest is live!
128         // The Host fades as we run this final step.
129         // Our "struct lguest_pages" is now read-only.
130         movl    %ebx, %cr3
131
132         // The page table change did one tricky thing:
133         // The Guest's register page has been mapped
134         // Writable onto our %esp (stack) --
135         // We can simply pop off all Guest regs.
136         popl    %ebx
137         popl    %ecx
138         popl    %edx
139         popl    %esi
140         popl    %edi
141         popl    %ebp
142         popl    %gs
143         popl    %eax
144         popl    %fs
145         popl    %ds
146         popl    %es
147
148         // Near the base of the stack lurk two strange fields
149         // Which we fill as we exit the Guest
150         // These are the trap number and its error
151         // We can simply step past them on our way.
152         addl    $8, %esp
153
154         // The last five stack slots hold return address
155         // And everything needed to change privilege
156         // Into the Guest privilege level of 1,
157         // And the stack where the Guest had last left it.
158         // Interrupts are turned back on: we are Guest.
159         iret
160
161 // There are two paths where we switch to the Host
162 // So we put the routine in a macro.
163 // We are on our way home, back to the Host
164 // Interrupted out of the Guest, we come here.
165 #define SWITCH_TO_HOST                                                  \
166         /* We save the Guest state: all registers first                 \
167          * Laid out just as "struct lguest_regs" defines */             \
168         pushl   %es;                                                    \
169         pushl   %ds;                                                    \
170         pushl   %fs;                                                    \
171         pushl   %eax;                                                   \
172         pushl   %gs;                                                    \
173         pushl   %ebp;                                                   \
174         pushl   %edi;                                                   \
175         pushl   %esi;                                                   \
176         pushl   %edx;                                                   \
177         pushl   %ecx;                                                   \
178         pushl   %ebx;                                                   \
179         /* Our stack and our code are using segments                    \
180          * Set in the TSS and IDT                                       \
181          * Yet if we were to touch data we'd use                        \
182          * Whatever data segment the Guest had.                         \
183          * Load the lguest ds segment for now. */                       \
184         movl    $(LGUEST_DS), %eax;                                     \
185         movl    %eax, %ds;                                              \
186         /* So where are we?  Which CPU, which struct?                   \
187          * The stack is our clue: our TSS starts                        \
188          * It at the end of "struct lguest_pages".                      \
189          * Or we may have stumbled while restoring                      \
190          * Our Guest segment regs while in switch_to_guest,             \
191          * The fault pushed atop that part-unwound stack.               \
192          * If we round the stack down to the page start                 \
193          * We're at the start of "struct lguest_pages". */              \
194         movl    %esp, %eax;                                             \
195         andl    $(~(1 << PAGE_SHIFT - 1)), %eax;                        \
196         /* Save our trap number: the switch will obscure it             \
197          * (The Guest regs are not mapped here in the Host)             \
198          * %ebx holds it safe for deliver_to_host */                    \
199         movl    LGUEST_PAGES_regs_trapnum(%eax), %ebx;                  \
200         /* The Host GDT, IDT and stack!                                 \
201          * All these lie safely hidden from the Guest:                  \
202          * We must return to the Host page tables                       \
203          * (Hence that was saved in struct lguest_pages) */             \
204         movl    LGUEST_PAGES_host_cr3(%eax), %edx;                      \
205         movl    %edx, %cr3;                                             \
206         /* As before, when we looked back at the Host                   \
207          * As we left and marked TSS unused                             \
208          * So must we now for the Guest left behind. */                 \
209         andb    $0xFD, (LGUEST_PAGES_guest_gdt+GDT_ENTRY_TSS*8+5)(%eax); \
210         /* Switch to Host's GDT, IDT. */                                \
211         lgdt    LGUEST_PAGES_host_gdt_desc(%eax);                       \
212         lidt    LGUEST_PAGES_host_idt_desc(%eax);                       \
213         /* Restore the Host's stack where it's saved regs lie */        \
214         movl    LGUEST_PAGES_host_sp(%eax), %esp;                       \
215         /* Last the TSS: our Host is complete */                        \
216         movl    $(GDT_ENTRY_TSS*8), %edx;                               \
217         ltr     %dx;                                                    \
218         /* Restore now the regs saved right at the first. */            \
219         popl    %ebp;                                                   \
220         popl    %fs;                                                    \
221         popl    %gs;                                                    \
222         popl    %ds;                                                    \
223         popl    %es
224
225 // Here's where we come when the Guest has just trapped:
226 // (Which trap we'll see has been pushed on the stack).
227 // We need only switch back, and the Host will decode
228 // Why we came home, and what needs to be done.
229 return_to_host:
230         SWITCH_TO_HOST
231         iret
232
233 // An interrupt, with some cause external
234 // Has ajerked us rudely from the Guest's code
235 // Again we must return home to the Host
236 deliver_to_host:
237         SWITCH_TO_HOST
238         // But now we must go home via that place
239         // Where that interrupt was supposed to go
240         // Had we not been ensconced, running the Guest.
241         // Here we see the cleverness of our stack:
242         // The Host stack is formed like an interrupt
243         // With EIP, CS and EFLAGS layered.
244         // Interrupt handlers end with "iret"
245         // And that will take us home at long long last.
246
247         // But first we must find the handler to call!
248         // The IDT descriptor for the Host
249         // Has two bytes for size, and four for address:
250         // %edx will hold it for us for now.
251         movl    (LGUEST_PAGES_host_idt_desc+2)(%eax), %edx
252         // We now know the table address we need,
253         // And saved the trap's number inside %ebx.
254         // Yet the pointer to the handler is smeared
255         // Across the bits of the table entry.
256         // What oracle can tell us how to extract
257         // From such a convoluted encoding?
258         // I consulted gcc, and it gave
259         // These instructions, which I gladly credit:
260         leal    (%edx,%ebx,8), %eax
261         movzwl  (%eax),%edx
262         movl    4(%eax), %eax
263         xorw    %ax, %ax
264         orl     %eax, %edx
265         // Now the address of the handler's in %edx
266         // We call it now: its "iret" takes us home.
267         jmp     *%edx
268
269 // Every interrupt can come to us here
270 // But we must truly tell each apart.
271 // They number two hundred and fifty six
272 // And each must land in a different spot,
273 // Push its number on stack, and join the stream.
274
275 // And worse, a mere six of the traps stand apart
276 // And push on their stack an addition:
277 // An error number, thirty two bits long
278 // So we punish the other two fifty
279 // And make them push a zero so they match.
280
281 // Yet two fifty six entries is long
282 // And all will look most the same as the last
283 // So we create a macro which can make
284 // As many entries as we need to fill.
285
286 // Note the change to .data then .text:
287 // We plant the address of each entry
288 // Into a (data) table for the Host
289 // To know where each Guest interrupt should go.
290 .macro IRQ_STUB N TARGET
291         .data; .long 1f; .text; 1:
292  // Trap eight, ten through fourteen and seventeen
293  // Supply an error number.  Else zero.
294  .if (\N <> 8) && (\N < 10 || \N > 14) && (\N <> 17)
295         pushl   $0
296  .endif
297         pushl   $\N
298         jmp     \TARGET
299         ALIGN
300 .endm
301
302 // This macro creates numerous entries
303 // Using GAS macros which out-power C's.
304 .macro IRQ_STUBS FIRST LAST TARGET
305  irq=\FIRST
306  .rept \LAST-\FIRST+1
307         IRQ_STUB irq \TARGET
308   irq=irq+1
309  .endr
310 .endm
311
312 // Here's the marker for our pointer table
313 // Laid in the data section just before
314 // Each macro places the address of code
315 // Forming an array: each one points to text
316 // Which handles interrupt in its turn.
317 .data
318 .global default_idt_entries
319 default_idt_entries:
320 .text
321         // The first two traps go straight back to the Host
322         IRQ_STUBS 0 1 return_to_host
323         // We'll say nothing, yet, about NMI
324         IRQ_STUB 2 handle_nmi
325         // Other traps also return to the Host
326         IRQ_STUBS 3 31 return_to_host
327         // All interrupts go via their handlers
328         IRQ_STUBS 32 127 deliver_to_host
329         // 'Cept system calls coming from userspace
330         // Are to go to the Guest, never the Host.
331         IRQ_STUB 128 return_to_host
332         IRQ_STUBS 129 255 deliver_to_host
333
334 // The NMI, what a fabulous beast
335 // Which swoops in and stops us no matter that
336 // We're suspended between heaven and hell,
337 // (Or more likely between the Host and Guest)
338 // When in it comes!  We are dazed and confused
339 // So we do the simplest thing which one can.
340 // Though we've pushed the trap number and zero
341 // We discard them, return, and hope we live.
342 handle_nmi:
343         addl    $8, %esp
344         iret
345
346 // We are done; all that's left is Mastery
347 // And "make Mastery" is a journey long
348 // Designed to make your fingers itch to code.
349
350 // Here ends the text, the file and poem.
351 ENTRY(end_switcher_text)