switcher_32.S revision 4614a3a3b638dfd7a67d0237944f6a76331af61d
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 59ENTRY(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. 67ENTRY(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 %eax 137 popl %ebx 138 popl %ecx 139 popl %edx 140 popl %esi 141 popl %edi 142 popl %ebp 143 popl %gs 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 %gs; \ 172 pushl %ebp; \ 173 pushl %edi; \ 174 pushl %esi; \ 175 pushl %edx; \ 176 pushl %ecx; \ 177 pushl %ebx; \ 178 pushl %eax; \ 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. 229return_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 236deliver_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 319default_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. 342handle_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. 351ENTRY(end_switcher_text) 352