[librm] Preserve FPU, MMX and SSE state across calls to virt_call()
[ipxe.git] / src / arch / x86 / transitions / librm.S
1 /*
2  * librm: a library for interfacing to real-mode code
3  *
4  * Michael Brown <mbrown@fensystems.co.uk>
5  *
6  */
7
8 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
9
10 /* Drag in local definitions */
11 #include "librm.h"
12
13 /* CR0: protection enabled */
14 #define CR0_PE ( 1 << 0 )
15
16 /* CR0: paging */
17 #define CR0_PG ( 1 << 31 )
18
19 /* CR4: physical address extensions */
20 #define CR4_PAE ( 1 << 5 )
21
22 /* Extended feature enable MSR (EFER) */
23 #define MSR_EFER 0xc0000080
24
25 /* EFER: long mode enable */
26 #define EFER_LME ( 1 << 8 )
27
28 /* Page: present */
29 #define PG_P 0x01
30
31 /* Page: read/write */
32 #define PG_RW 0x02
33
34 /* Page: user/supervisor */
35 #define PG_US 0x04
36
37 /* Page: page size */
38 #define PG_PS 0x80
39
40 /* Size of various paging-related data structures */
41 #define SIZEOF_PTE_LOG2 3
42 #define SIZEOF_PTE ( 1 << SIZEOF_PTE_LOG2 )
43 #define SIZEOF_PT_LOG2 12
44 #define SIZEOF_PT ( 1 << SIZEOF_PT_LOG2 )
45 #define SIZEOF_4KB_PAGE_LOG2 12
46 #define SIZEOF_4KB_PAGE ( 1 << SIZEOF_4KB_PAGE_LOG2 )
47 #define SIZEOF_2MB_PAGE_LOG2 21
48 #define SIZEOF_2MB_PAGE ( 1 << SIZEOF_2MB_PAGE_LOG2 )
49 #define SIZEOF_LOW_4GB_LOG2 32
50 #define SIZEOF_LOW_4GB ( 1 << SIZEOF_LOW_4GB_LOG2 )
51
52 /* Size of various C data structures */
53 #define SIZEOF_I386_SEG_REGS    12
54 #define SIZEOF_I386_REGS        32
55 #define SIZEOF_REAL_MODE_REGS   ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
56 #define SIZEOF_I386_FLAGS       4
57 #define SIZEOF_I386_ALL_REGS    ( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS )
58 #define SIZEOF_X86_64_REGS      128
59
60 /* Size of an address */
61 #ifdef __x86_64__
62 #define SIZEOF_ADDR 8
63 #else
64 #define SIZEOF_ADDR 4
65 #endif
66
67 /* Default code size */
68 #ifdef __x86_64__
69 #define CODE_DEFAULT code64
70 #else
71 #define CODE_DEFAULT code32
72 #endif
73
74 /* Selectively assemble code for 32-bit/64-bit builds */
75 #ifdef __x86_64__
76 #define if32 if 0
77 #define if64 if 1
78 #else
79 #define if32 if 1
80 #define if64 if 0
81 #endif
82
83 /****************************************************************************
84  * Global descriptor table
85  *
86  * Call init_librm to set up the GDT before attempting to use any
87  * protected-mode code.
88  *
89  * NOTE: This must be located before prot_to_real, otherwise gas
90  * throws a "can't handle non absolute segment in `ljmp'" error due to
91  * not knowing the value of REAL_CS when the ljmp is encountered.
92  *
93  * Note also that putting ".word gdt_end - gdt - 1" directly into
94  * gdt_limit, rather than going via gdt_length, will also produce the
95  * "non absolute segment" error.  This is most probably a bug in gas.
96  ****************************************************************************
97  */
98         .section ".data16.gdt", "aw", @progbits
99         .align 16
100 gdt:
101 gdtr:           /* The first GDT entry is unused, the GDTR can fit here. */
102 gdt_limit:              .word gdt_length - 1
103 gdt_base:               .long 0
104                         .word 0 /* padding */
105
106         .org    gdt + VIRTUAL_CS, 0
107 virtual_cs:     /* 32 bit protected mode code segment, virtual addresses */
108         .word   0xffff, 0
109         .byte   0, 0x9f, 0xcf, 0
110
111         .org    gdt + VIRTUAL_DS, 0
112 virtual_ds:     /* 32 bit protected mode data segment, virtual addresses */
113         .word   0xffff, 0
114         .byte   0, 0x93, 0xcf, 0
115         
116         .org    gdt + PHYSICAL_CS, 0
117 physical_cs:    /* 32 bit protected mode code segment, physical addresses */
118         .word   0xffff, 0
119         .byte   0, 0x9f, 0xcf, 0
120
121         .org    gdt + PHYSICAL_DS, 0
122 physical_ds:    /* 32 bit protected mode data segment, physical addresses */
123         .word   0xffff, 0
124         .byte   0, 0x93, 0xcf, 0        
125
126         .org    gdt + REAL_CS, 0
127 real_cs:        /* 16 bit real mode code segment */
128         .word   0xffff, 0
129         .byte   0, 0x9b, 0x00, 0
130
131         .org    gdt + REAL_DS, 0
132 real_ds:        /* 16 bit real mode data segment */
133         .word   0xffff, 0
134         .byte   0, 0x93, 0x00, 0
135
136         .org    gdt + P2R_DS, 0
137 p2r_ds:         /* 16 bit real mode data segment for prot_to_real transition */
138         .word   0xffff, ( P2R_DS << 4 )
139         .byte   0, 0x93, 0x00, 0
140
141         .org    gdt + LONG_CS, 0
142 long_cs:        /* 64 bit long mode code segment */
143         .word   0, 0
144         .byte   0, 0x9a, 0x20, 0
145
146 gdt_end:
147         .equ    gdt_length, gdt_end - gdt
148
149 /****************************************************************************
150  * Stored real-mode and protected-mode stack pointers
151  *
152  * The real-mode stack pointer is stored here whenever real_to_prot
153  * is called and restored whenever prot_to_real is called.  The
154  * converse happens for the protected-mode stack pointer.
155  *
156  * Despite initial appearances this scheme is, in fact re-entrant,
157  * because program flow dictates that we always return via the point
158  * we left by.  For example:
159  *    PXE API call entry
160  *  1   real => prot
161  *        ...
162  *        Print a text string
163  *          ...
164  *  2       prot => real
165  *            INT 10
166  *  3       real => prot
167  *          ...
168  *        ...
169  *  4   prot => real
170  *    PXE API call exit
171  *
172  * At point 1, the RM mode stack value, say RPXE, is stored in
173  * rm_ss,sp.  We want this value to still be present in rm_ss,sp when
174  * we reach point 4.
175  *
176  * At point 2, the RM stack value is restored from RPXE.  At point 3,
177  * the RM stack value is again stored in rm_ss,sp.  This *does*
178  * overwrite the RPXE that we have stored there, but it's the same
179  * value, since the code between points 2 and 3 has managed to return
180  * to us.
181  ****************************************************************************
182  */
183         .section ".bss.rm_ss_sp", "aw", @nobits
184         .globl rm_sp
185 rm_sp:  .word 0
186         .globl rm_ss
187 rm_ss:  .word 0
188
189         .section ".data.pm_esp", "aw", @progbits
190 pm_esp: .long VIRTUAL(_estack)
191
192 /****************************************************************************
193  * Temporary static data buffer
194  *
195  * This is used to reduce the amount of real-mode stack space consumed
196  * during mode transitions, since we are sometimes called with very
197  * little real-mode stack space available.
198  ****************************************************************************
199  */
200         /* Temporary static buffer usage by virt_call */
201         .struct 0
202 VC_TMP_GDT:             .space  6
203 VC_TMP_IDT:             .space  6
204 VC_TMP_PAD:             .space  4 /* for alignment */
205 .if64
206 VC_TMP_CR3:             .space  4
207 VC_TMP_CR4:             .space  4
208 VC_TMP_EMER:            .space  8
209 .endif
210 VC_TMP_FXSAVE:          .space  512
211 VC_TMP_END:
212         .previous
213
214         /* Temporary static buffer usage by real_call */
215         .struct 0
216 RC_TMP_FUNCTION:        .space  4
217 RC_TMP_END:
218         .previous
219
220         /* Shared temporary static buffer */
221         .section ".bss16.rm_tmpbuf", "aw", @nobits
222         .align 16
223 rm_tmpbuf:
224         .space  VC_TMP_END
225         .size   rm_tmpbuf, . - rm_tmpbuf
226
227 /****************************************************************************
228  * Virtual address offsets
229  *
230  * These are used by the protected-mode code to map between virtual
231  * and physical addresses, and to access variables in the .text16 or
232  * .data16 segments.
233  ****************************************************************************
234  */
235         .struct 0
236 VA_VIRT_OFFSET: .space  SIZEOF_ADDR
237 VA_TEXT16:      .space  SIZEOF_ADDR
238 VA_DATA16:      .space  SIZEOF_ADDR
239 VA_SIZE:
240         .previous
241
242         /* Internal copies, used only by librm itself */
243         .section ".bss16.rm_virt_addrs", "aw", @nobits
244 rm_virt_addrs:  .space  VA_SIZE
245         .equ    rm_virt_offset, ( rm_virt_addrs + VA_VIRT_OFFSET )
246         .equ    rm_text16, ( rm_virt_addrs + VA_TEXT16 )
247         .equ    rm_data16, ( rm_virt_addrs + VA_DATA16 )
248
249         /* Externally visible variables, used by C code */
250         .section ".bss.virt_addrs", "aw", @nobits
251 virt_addrs:     .space  VA_SIZE
252         .globl  virt_offset
253         .equ    virt_offset, ( virt_addrs + VA_VIRT_OFFSET )
254         .globl  text16
255         .equ    text16, ( virt_addrs + VA_TEXT16 )
256         .globl  data16
257         .equ    data16, ( virt_addrs + VA_DATA16 )
258
259 /****************************************************************************
260  * init_librm (real-mode far call, 16-bit real-mode far return address)
261  *
262  * Initialise the GDT ready for transitions to protected mode.
263  *
264  * Parameters:
265  *   %cs : .text16 segment
266  *   %ds : .data16 segment
267  *   %edi : Physical base of protected-mode code
268  ****************************************************************************
269  */
270         .section ".text16.init_librm", "ax", @progbits
271         .code16
272         .globl init_librm
273 init_librm:
274         /* Preserve registers */
275         pushl   %eax
276         pushl   %ebx
277         pushl   %edi
278
279         /* Store rm_virt_offset and set up virtual_cs and virtual_ds segments */
280         subl    $VIRTUAL(_textdata), %edi
281         movl    %edi, rm_virt_offset
282 .if64 ; setae   (rm_virt_offset+4) ; .endif
283         movl    %edi, %eax
284         movw    $virtual_cs, %bx
285         call    set_seg_base
286         movw    $virtual_ds, %bx
287         call    set_seg_base
288
289         /* Store rm_cs and rm_text16, set up real_cs segment */
290         xorl    %eax, %eax
291         movw    %cs, %ax
292         movw    %ax, %cs:rm_cs
293         shll    $4, %eax
294         movw    $real_cs, %bx
295         call    set_seg_base
296 .if32 ; subl    %edi, %eax ; .endif
297         movl    %eax, rm_text16
298
299         /* Store rm_ds and rm_data16, set up real_ds segment and GDT base */
300         xorl    %eax, %eax
301         movw    %ds, %ax
302         movw    %ax, %cs:rm_ds
303         shll    $4, %eax
304         movw    $real_ds, %bx
305         call    set_seg_base
306         movl    %eax, gdt_base
307         addl    $gdt, gdt_base
308 .if32 ; subl    %edi, %eax ; .endif
309         movl    %eax, rm_data16
310
311         /* Configure virt_call for protected mode, if applicable */
312 .if64 ; movl    $VIRTUAL(vc_pmode), %cs:vc_jmp_offset ; .endif
313
314         /* Switch to protected mode */
315         virtcall init_librm_pmode
316         .section ".text.init_librm", "ax", @progbits
317         .code32
318 init_librm_pmode:
319
320         /* Store virt_offset, text16, and data16 */
321         pushw   %ds
322         movw    $REAL_DS, %ax
323         movw    %ax, %ds
324         movl    $rm_virt_addrs, %esi
325         movl    $VIRTUAL(virt_addrs), %edi
326         movl    $( VA_SIZE / 4 ), %ecx
327         rep movsl
328         popw    %ds
329
330 .if64 ; /* Initialise long mode, if applicable */
331         movl    VIRTUAL(virt_offset), %edi
332         leal    VIRTUAL(p2l_ljmp_target)(%edi), %eax
333         movl    %eax, VIRTUAL(p2l_ljmp_offset)
334         call    init_pages
335 .endif
336         /* Return to real mode */
337         ret
338         .section ".text16.init_librm", "ax", @progbits
339         .code16
340 init_librm_rmode:
341
342         /* Configure virt_call for long mode, if applicable */
343 .if64 ; movl    $VIRTUAL(vc_lmode), %cs:vc_jmp_offset ; .endif
344
345         /* Initialise IDT */
346         virtcall init_idt
347
348         /* Restore registers */
349         popl    %edi
350         popl    %ebx
351         popl    %eax
352         lret
353
354         .section ".text16.set_seg_base", "ax", @progbits
355         .code16
356 set_seg_base:
357 1:      movw    %ax, 2(%bx)
358         rorl    $16, %eax
359         movb    %al, 4(%bx)
360         movb    %ah, 7(%bx)
361         roll    $16, %eax
362         ret
363
364 /****************************************************************************
365  * real_to_prot (real-mode near call, 32-bit virtual return address)
366  *
367  * Switch from 16-bit real-mode to 32-bit protected mode with virtual
368  * addresses.  The real-mode %ss:sp is stored in rm_ss and rm_sp, and
369  * the protected-mode %esp is restored from the saved pm_esp.
370  * Interrupts are disabled.  All other registers may be destroyed.
371  *
372  * The return address for this function should be a 32-bit virtual
373  * address.
374  *
375  * Parameters: 
376  *   %ecx : number of bytes to move from RM stack to PM stack
377  *   %edx : number of bytes to copy from RM temporary buffer to PM stack
378  *
379  ****************************************************************************
380  */
381         .section ".text16.real_to_prot", "ax", @progbits
382         .code16
383 real_to_prot:
384         /* Enable A20 line */
385         call    enable_a20
386         /* A failure at this point is fatal, and there's nothing we
387          * can do about it other than lock the machine to make the
388          * problem immediately visible.
389          */
390 1:      jc      1b
391
392         /* Make sure we have our data segment available */
393         movw    %cs:rm_ds, %ds
394
395         /* Add protected-mode return address to length of data to be copied */
396         addw    $4, %cx /* %ecx must be less than 64kB anyway */
397
398         /* Real-mode %ss:%sp => %ebp and virtual address => %esi */
399         xorl    %eax, %eax
400         movw    %ss, %ax
401         shll    $4, %eax
402         movzwl  %sp, %ebp
403         addr32 leal (%eax,%ebp), %esi
404         subl    rm_virt_offset, %esi
405         shll    $12, %eax
406         orl     %eax, %ebp
407
408         /* Real-mode data segment virtual address => %ebx */
409         movl    rm_data16, %ebx
410 .if64 ; subl    rm_virt_offset, %ebx ; .endif
411
412         /* Load protected-mode global descriptor table */
413         data32 lgdt gdtr
414
415         /* Zero segment registers.  This wastes around 12 cycles on
416          * real hardware, but saves a substantial number of emulated
417          * instructions under KVM.
418          */
419         xorw    %ax, %ax
420         movw    %ax, %ds
421         movw    %ax, %es
422         movw    %ax, %fs
423         movw    %ax, %gs
424         movw    %ax, %ss
425
426         /* Switch to protected mode (with paging disabled if applicable) */
427         cli
428         movl    %cr0, %eax
429 .if64 ; andl    $~CR0_PG, %eax ; .endif
430         orb     $CR0_PE, %al
431         movl    %eax, %cr0
432         data32 ljmp     $VIRTUAL_CS, $VIRTUAL(r2p_pmode)
433         .section ".text.real_to_prot", "ax", @progbits
434         .code32
435 r2p_pmode:
436         /* Set up protected-mode data segments and stack pointer */
437         movw    $VIRTUAL_DS, %ax
438         movw    %ax, %ds
439         movw    %ax, %es
440         movw    %ax, %fs
441         movw    %ax, %gs
442         movw    %ax, %ss
443         movl    VIRTUAL(pm_esp), %esp
444
445         /* Load protected-mode interrupt descriptor table */
446         lidt    VIRTUAL(idtr32)
447
448         /* Record real-mode %ss:sp (after removal of data) */
449         addl    %ecx, %ebp
450         movl    %ebp, VIRTUAL(rm_sp)
451
452         /* Move data from RM stack to PM stack */
453         subl    %edx, %esp
454         subl    %ecx, %esp
455         movl    %esp, %edi
456         rep movsb
457
458         /* Copy data from RM temporary buffer to PM stack */
459         leal    rm_tmpbuf(%ebx), %esi
460         movl    %edx, %ecx
461         rep movsb
462
463         /* Return to virtual address */
464         ret
465
466 /****************************************************************************
467  * prot_to_real (protected-mode near call, 32-bit real-mode return address)
468  *
469  * Switch from 32-bit protected mode with virtual addresses to 16-bit
470  * real mode.  The protected-mode %esp is stored in pm_esp and the
471  * real-mode %ss:sp is restored from the saved rm_ss and rm_sp.  The
472  * high word of the real-mode %esp is set to zero.  All real-mode data
473  * segment registers are loaded from the saved rm_ds.  Interrupts are
474  * *not* enabled, since we want to be able to use prot_to_real in an
475  * ISR.  All other registers may be destroyed.
476  *
477  * The return address for this function should be a 32-bit (sic)
478  * real-mode offset within .code16.
479  *
480  * Parameters: 
481  *   %ecx : number of bytes to move from PM stack to RM stack
482  *   %edx : number of bytes to move from PM stack to RM temporary buffer
483  *   %esi : real-mode global and interrupt descriptor table registers
484  *
485  ****************************************************************************
486  */
487         .section ".text.prot_to_real", "ax", @progbits
488         .code32
489 prot_to_real:
490         /* Copy real-mode global descriptor table register to RM code segment */
491         movl    VIRTUAL(text16), %edi
492 .if64 ; subl    VIRTUAL(virt_offset), %edi ; .endif
493         leal    rm_gdtr(%edi), %edi
494         movsw
495         movsl
496
497         /* Load real-mode interrupt descriptor table register */
498         lidt    (%esi)
499
500         /* Add return address to data to be moved to RM stack */
501         addl    $4, %ecx
502
503         /* Real-mode %ss:sp => %ebp and virtual address => %edi */
504         movl    VIRTUAL(rm_sp), %ebp
505         subl    %ecx, %ebp
506         movzwl  VIRTUAL(rm_ss), %eax
507         shll    $4, %eax
508         movzwl  %bp, %edi
509         addl    %eax, %edi
510         subl    VIRTUAL(virt_offset), %edi
511
512         /* Move data from PM stack to RM stack */
513         movl    %esp, %esi
514         rep movsb
515
516         /* Move data from PM stack to RM temporary buffer */
517         movl    VIRTUAL(data16), %edi
518 .if64 ; subl    VIRTUAL(virt_offset), %edi ; .endif
519         addl    $rm_tmpbuf, %edi
520         movl    %edx, %ecx
521         rep movsb
522
523         /* Record protected-mode %esp (after removal of data) */
524         movl    %esi, VIRTUAL(pm_esp)
525
526         /* Load real-mode segment limits */
527         movw    $P2R_DS, %ax
528         movw    %ax, %ds
529         movw    %ax, %es
530         movw    %ax, %fs
531         movw    %ax, %gs
532         movw    %ax, %ss
533         ljmp    $REAL_CS, $p2r_rmode
534         .section ".text16.prot_to_real", "ax", @progbits
535         .code16
536 p2r_rmode:
537         /* Load real-mode GDT */
538         data32 lgdt %cs:rm_gdtr
539         /* Switch to real mode */
540         movl    %cr0, %eax
541         andb    $0!CR0_PE, %al
542         movl    %eax, %cr0
543 p2r_ljmp_rm_cs:
544         ljmp    $0, $1f
545 1:
546         /* Set up real-mode data segments and stack pointer */
547         movw    %cs:rm_ds, %ax
548         movw    %ax, %ds
549         movw    %ax, %es
550         movw    %ax, %fs
551         movw    %ax, %gs
552         movl    %ebp, %eax
553         shrl    $16, %eax
554         movw    %ax, %ss
555         movzwl  %bp, %esp
556
557         /* Return to real-mode address */
558         data32 ret
559
560
561         /* Real-mode code and data segments.  Assigned by the call to
562          * init_librm.  rm_cs doubles as the segment part of the jump
563          * instruction used by prot_to_real.  Both are located in
564          * .text16 rather than .data16: rm_cs since it forms part of
565          * the jump instruction within the code segment, and rm_ds
566          * since real-mode code needs to be able to locate the data
567          * segment with no other reference available.
568          */
569         .globl rm_cs
570         .equ    rm_cs, ( p2r_ljmp_rm_cs + 3 )
571
572         .section ".text16.data.rm_ds", "aw", @progbits
573         .globl rm_ds
574 rm_ds:  .word 0
575
576         /* Real-mode global and interrupt descriptor table registers */
577         .section ".text16.data.rm_gdtr", "aw", @progbits
578 rm_gdtr:
579         .word 0 /* Limit */
580         .long 0 /* Base */
581
582 /****************************************************************************
583  * phys_to_prot (protected-mode near call, 32-bit physical return address)
584  *
585  * Switch from 32-bit protected mode with physical addresses to 32-bit
586  * protected mode with virtual addresses.  %esp is adjusted to a
587  * virtual address.  All other registers are preserved.
588  *
589  * The return address for this function should be a 32-bit physical
590  * (sic) address.
591  *
592  ****************************************************************************
593  */
594         .section ".text.phys_to_prot", "ax", @progbits
595         .code32
596         .globl phys_to_prot
597 phys_to_prot:
598         /* Preserve registers */
599         pushl   %eax
600         pushl   %ebp
601
602         /* Switch to virtual code segment */
603         cli
604         ljmp    $VIRTUAL_CS, $VIRTUAL(1f)
605 1:
606         /* Switch to virtual data segment and adjust %esp */
607         movw    $VIRTUAL_DS, %ax
608         movw    %ax, %ds
609         movw    %ax, %es
610         movw    %ax, %fs
611         movw    %ax, %gs
612         movw    %ax, %ss
613         movl    VIRTUAL(virt_offset), %ebp
614         subl    %ebp, %esp
615
616         /* Adjust return address to a virtual address */
617         subl    %ebp, 8(%esp)
618
619         /* Restore registers and return */
620         popl    %ebp
621         popl    %eax
622         ret
623
624 .if32   /* Expose as _phys_to_virt for use by COMBOOT, if applicable */
625         .globl  _phys_to_virt
626         .equ    _phys_to_virt, phys_to_prot
627 .endif
628
629 /****************************************************************************
630  * prot_to_phys (protected-mode near call, 32-bit virtual return address)
631  *
632  * Switch from 32-bit protected mode with virtual addresses to 32-bit
633  * protected mode with physical addresses.  %esp is adjusted to a
634  * physical address.  All other registers are preserved.
635  *
636  * The return address for this function should be a 32-bit virtual
637  * (sic) address.
638  *
639  ****************************************************************************
640  */
641         .section ".text.prot_to_phys", "ax", @progbits
642         .code32
643 prot_to_phys:
644         /* Preserve registers */
645         pushl   %eax
646         pushl   %ebp
647
648         /* Adjust return address to a physical address */
649         movl    VIRTUAL(virt_offset), %ebp
650         addl    %ebp, 8(%esp)
651
652         /* Switch to physical code segment */
653         cli
654         pushl   $PHYSICAL_CS
655         leal    VIRTUAL(1f)(%ebp), %eax
656         pushl   %eax
657         lret
658 1:
659         /* Switch to physical data segment and adjust %esp */
660         movw    $PHYSICAL_DS, %ax
661         movw    %ax, %ds
662         movw    %ax, %es
663         movw    %ax, %fs
664         movw    %ax, %gs
665         movw    %ax, %ss
666         addl    %ebp, %esp
667
668         /* Restore registers and return */
669         popl    %ebp
670         popl    %eax
671         ret
672
673 .if32   /* Expose as _virt_to_phys for use by COMBOOT, if applicable */
674         .globl  _virt_to_phys
675         .equ    _virt_to_phys, prot_to_phys
676 .endif
677
678 /****************************************************************************
679  * intr_to_prot (protected-mode near call, 32-bit virtual return address)
680  *
681  * Switch from 32-bit protected mode with a virtual code segment and
682  * either a physical or virtual stack segment to 32-bit protected mode
683  * with normal virtual addresses.  %esp is adjusted if necessary to a
684  * virtual address.  All other registers are preserved.
685  *
686  * The return address for this function should be a 32-bit virtual
687  * address.
688  *
689  ****************************************************************************
690  */
691         .section ".text.intr_to_prot", "ax", @progbits
692         .code32
693         .globl intr_to_prot
694 intr_to_prot:
695         /* Preserve registers */
696         pushl   %eax
697
698         /* Check whether stack segment is physical or virtual */
699         movw    %ss, %ax
700         cmpw    $VIRTUAL_DS, %ax
701         movw    $VIRTUAL_DS, %ax
702
703         /* Reload data segment registers */
704         movw    %ax, %ds
705         movw    %ax, %es
706         movw    %ax, %fs
707         movw    %ax, %gs
708
709         /* Reload stack segment and adjust %esp if necessary */
710         je      1f
711         movw    %ax, %ss
712         subl    VIRTUAL(virt_offset), %esp
713 1:
714         /* Restore registers and return */
715         popl    %eax
716         ret
717
718         /* Expose as _intr_to_virt for use by GDB */
719         .globl  _intr_to_virt
720         .equ    _intr_to_virt, intr_to_prot
721
722 /****************************************************************************
723  * prot_to_long (protected-mode near call, 32-bit virtual return address)
724  *
725  * Switch from 32-bit protected mode with virtual addresses to 64-bit
726  * long mode.  The protected-mode %esp is adjusted to a physical
727  * address.  All other registers are preserved.
728  *
729  * The return address for this function should be a 32-bit (sic)
730  * virtual address.
731  *
732  ****************************************************************************
733  */
734         .if64
735
736         .section ".text.prot_to_long", "ax", @progbits
737         .code32
738 prot_to_long:
739         /* Preserve registers */
740         pushl   %eax
741         pushl   %ecx
742         pushl   %edx
743
744         /* Set up PML4 */
745         movl    VIRTUAL(pml4), %eax
746         movl    %eax, %cr3
747
748         /* Enable PAE */
749         movl    %cr4, %eax
750         orb     $CR4_PAE, %al
751         movl    %eax, %cr4
752
753         /* Enable long mode */
754         movl    $MSR_EFER, %ecx
755         rdmsr
756         orw     $EFER_LME, %ax
757         wrmsr
758
759         /* Enable paging */
760         movl    %cr0, %eax
761         orl     $CR0_PG, %eax
762         movl    %eax, %cr0
763
764         /* Restore registers */
765         popl    %edx
766         popl    %ecx
767         popl    %eax
768
769         /* Construct 64-bit return address */
770         pushl   (%esp)
771         movl    $0xffffffff, 4(%esp)
772 p2l_ljmp:
773         /* Switch to long mode (using a physical %rip) */
774         ljmp    $LONG_CS, $0
775         .code64
776 p2l_lmode:
777         /* Adjust and zero-extend %esp to a physical address */
778         addl    virt_offset, %esp
779
780         /* Use long-mode IDT */
781         lidt    idtr64
782
783         /* Return to virtual address */
784         ret
785
786         /* Long mode jump offset and target.  Required since an ljmp
787          * in protected mode will zero-extend the offset, and so
788          * cannot reach an address within the negative 2GB as used by
789          * -mcmodel=kernel.  Assigned by the call to init_librm.
790          */
791         .equ    p2l_ljmp_offset, ( p2l_ljmp + 1 )
792         .equ    p2l_ljmp_target, p2l_lmode
793
794         .endif
795
796 /****************************************************************************
797  * long_to_prot (long-mode near call, 64-bit virtual return address)
798  *
799  * Switch from 64-bit long mode to 32-bit protected mode with virtual
800  * addresses.  The long-mode %rsp is adjusted to a virtual address.
801  * All other registers are preserved.
802  *
803  * The return address for this function should be a 64-bit (sic)
804  * virtual address.
805  *
806  ****************************************************************************
807  */
808         .if64
809
810         .section ".text.long_to_prot", "ax", @progbits
811         .code64
812 long_to_prot:
813         /* Switch to protected mode */
814         ljmp    *l2p_vector
815         .code32
816 l2p_pmode:
817         /* Adjust %esp to a virtual address */
818         subl    VIRTUAL(virt_offset), %esp
819
820         /* Preserve registers */
821         pushl   %eax
822         pushl   %ecx
823         pushl   %edx
824
825         /* Disable paging */
826         movl    %cr0, %eax
827         andl    $~CR0_PG, %eax
828         movl    %eax, %cr0
829
830         /* Disable PAE (in case external non-PAE-aware code enables paging) */
831         movl    %cr4, %eax
832         andb    $~CR4_PAE, %al
833         movl    %eax, %cr4
834
835         /* Disable long mode */
836         movl    $MSR_EFER, %ecx
837         rdmsr
838         andw    $~EFER_LME, %ax
839         wrmsr
840
841         /* Restore registers */
842         popl    %edx
843         popl    %ecx
844         popl    %eax
845
846         /* Use protected-mode IDT */
847         lidt    VIRTUAL(idtr32)
848
849         /* Return */
850         ret     $4
851
852         /* Long mode jump vector.  Required since there is no "ljmp
853          * immediate" instruction in long mode.
854          */
855         .section ".data.l2p_vector", "aw", @progbits
856 l2p_vector:
857         .long   VIRTUAL(l2p_pmode), VIRTUAL_CS
858
859         .endif
860
861 /****************************************************************************
862  * long_save_regs (long-mode near call, 64-bit virtual return address)
863  *
864  * Preserve registers that are accessible only in long mode.  This
865  * includes %r8-%r15 and the upper halves of %rax, %rbx, %rcx, %rdx,
866  * %rsi, %rdi, and %rbp.
867  *
868  ****************************************************************************
869  */
870         .if64
871
872         .section ".text.long_preserve_regs", "ax", @progbits
873         .code64
874 long_preserve_regs:
875         /* Preserve registers */
876         pushq   %rax
877         pushq   %rcx
878         pushq   %rdx
879         pushq   %rbx
880         pushq   %rsp
881         pushq   %rbp
882         pushq   %rsi
883         pushq   %rdi
884         pushq   %r8
885         pushq   %r9
886         pushq   %r10
887         pushq   %r11
888         pushq   %r12
889         pushq   %r13
890         pushq   %r14
891         pushq   %r15
892
893         /* Return */
894         jmp     *SIZEOF_X86_64_REGS(%rsp)
895
896         .endif
897
898 /****************************************************************************
899  * long_restore_regs (long-mode near call, 64-bit virtual return address)
900  *
901  * Restore registers that are accessible only in long mode.  This
902  * includes %r8-%r15 and the upper halves of %rax, %rbx, %rcx, %rdx,
903  * %rsi, %rdi, and %rbp.
904  *
905  ****************************************************************************
906  */
907         .if64
908
909         .section ".text.long_restore_regs", "ax", @progbits
910         .code64
911 long_restore_regs:
912         /* Move return address above register dump */
913         popq    SIZEOF_X86_64_REGS(%rsp)
914
915         /* Restore registers */
916         popq    %r15
917         popq    %r14
918         popq    %r13
919         popq    %r12
920         popq    %r11
921         popq    %r10
922         popq    %r9
923         popq    %r8
924         movl    %edi, (%rsp)
925         popq    %rdi
926         movl    %esi, (%rsp)
927         popq    %rsi
928         movl    %ebp, (%rsp)
929         popq    %rbp
930         leaq    8(%rsp), %rsp /* discard */
931         movl    %ebx, (%rsp)
932         popq    %rbx
933         movl    %edx, (%rsp)
934         popq    %rdx
935         movl    %ecx, (%rsp)
936         popq    %rcx
937         movl    %eax, (%rsp)
938         popq    %rax
939
940         /* Return */
941         ret
942
943         .endif
944
945 /****************************************************************************
946  * virt_call (real-mode near call, 16-bit real-mode near return address)
947  *
948  * Call a specific C function in 32-bit protected mode or 64-bit long
949  * mode (as applicable).  The prototype of the C function must be
950  *   void function ( struct i386_all_regs *ix86 ); 
951  * ix86 will point to a struct containing the real-mode registers
952  * at entry to virt_call().
953  *
954  * All registers will be preserved across virt_call(), unless the C
955  * function explicitly overwrites values in ix86.  Interrupt status
956  * and GDT will also be preserved.  Gate A20 will be enabled.
957  *
958  * Note that virt_call() does not rely on the real-mode stack
959  * remaining intact in order to return, since everything relevant is
960  * copied to the protected-mode stack for the duration of the call.
961  * In particular, this means that a real-mode prefix can make a call
962  * to main() which will return correctly even if the prefix's stack
963  * gets vapourised during the Etherboot run.  (The prefix cannot rely
964  * on anything else on the stack being preserved, so should move any
965  * critical data to registers before calling main()).
966  *
967  * Parameters:
968  *   function : 32-bit virtual address of function to call
969  *
970  * Example usage:
971  *      pushl   $pxe_api_call
972  *      call    virt_call
973  * to call in to the C function
974  *      void pxe_api_call ( struct i386_all_regs *ix86 );
975  ****************************************************************************
976  */
977         .struct 0
978 VC_OFFSET_IX86:         .space  SIZEOF_I386_ALL_REGS
979 VC_OFFSET_PADDING:      .space  2 /* for alignment */
980 VC_OFFSET_RETADDR:      .space  2
981 VC_OFFSET_PARAMS:
982 VC_OFFSET_FUNCTION:     .space  4
983 VC_OFFSET_END:
984         .previous
985
986         .section ".text16.virt_call", "ax", @progbits
987         .code16
988         .globl virt_call
989 virt_call:
990         /* Preserve registers and flags on external RM stack */
991         pushw   %ss /* padding */
992         pushfl
993         pushal
994         pushw   %gs
995         pushw   %fs
996         pushw   %es
997         pushw   %ds
998         pushw   %ss
999         pushw   %cs
1000
1001         /* Claim ownership of temporary static buffer */
1002         cli
1003
1004         /* Preserve FPU, MMX and SSE state in temporary static buffer */
1005         movw    %cs:rm_ds, %ds
1006         fxsave  ( rm_tmpbuf + VC_TMP_FXSAVE )
1007
1008         /* Preserve GDT and IDT in temporary static buffer */
1009         sidt    ( rm_tmpbuf + VC_TMP_IDT )
1010         sgdt    ( rm_tmpbuf + VC_TMP_GDT )
1011
1012 .if64 ; /* Preserve control registers, if applicable */
1013         movl    $MSR_EFER, %ecx
1014         rdmsr
1015         movl    %eax, ( rm_tmpbuf + VC_TMP_EMER + 0 )
1016         movl    %edx, ( rm_tmpbuf + VC_TMP_EMER + 4 )
1017         movl    %cr4, %eax
1018         movl    %eax, ( rm_tmpbuf + VC_TMP_CR4 )
1019         movl    %cr3, %eax
1020         movl    %eax, ( rm_tmpbuf + VC_TMP_CR3 )
1021 .endif
1022         /* For sanity's sake, clear the direction flag as soon as possible */
1023         cld
1024
1025         /* Switch to protected mode and move register dump to PM stack */
1026         movl    $VC_OFFSET_END, %ecx
1027         movl    $VC_TMP_END, %edx
1028         pushl   $VIRTUAL(vc_pmode)
1029 vc_jmp: jmp     real_to_prot
1030         .section ".text.virt_call", "ax", @progbits
1031         .code32
1032 vc_pmode:
1033         /* Call function (in protected mode) */
1034         pushl   %esp
1035         call    *(VC_OFFSET_FUNCTION+4)(%esp)
1036         popl    %eax /* discard */
1037
1038 .if64 ; /* Switch to long mode */
1039         jmp     1f
1040 vc_lmode:
1041         call    prot_to_long
1042         .code64
1043
1044         /* Call function (in long mode) */
1045         movq    %rsp, %rdi
1046         movslq  VC_OFFSET_FUNCTION(%rsp), %rax
1047         callq   *%rax
1048
1049         /* Switch to protected mode */
1050         call    long_to_prot
1051 1:      .code32
1052 .endif
1053         /* Switch to real mode and move register dump back to RM stack */
1054         movl    $VC_OFFSET_END, %ecx
1055         movl    $VC_TMP_END, %edx
1056         leal    VC_TMP_GDT(%esp, %ecx), %esi
1057         pushl   $vc_rmode
1058         jmp     prot_to_real
1059         .section ".text16.virt_call", "ax", @progbits
1060         .code16
1061 vc_rmode:
1062 .if64 ; /* Restore control registers, if applicable */
1063         movw    %sp, %bp
1064         movl    ( rm_tmpbuf + VC_TMP_CR3 ), %eax
1065         movl    %eax, %cr3
1066         movl    ( rm_tmpbuf + VC_TMP_CR4 ), %eax
1067         movl    %eax, %cr4
1068         movl    ( rm_tmpbuf + VC_TMP_EMER + 0 ), %eax
1069         movl    ( rm_tmpbuf + VC_TMP_EMER + 4 ), %edx
1070         movl    $MSR_EFER, %ecx
1071         wrmsr
1072 .endif
1073         /* Restore FPU, MMX and SSE state from temporary static buffer */
1074         fxrstor ( rm_tmpbuf + VC_TMP_FXSAVE )
1075
1076         /* Restore registers and flags and return */
1077         popl    %eax /* skip %cs and %ss */
1078         popw    %ds
1079         popw    %es
1080         popw    %fs
1081         popw    %gs
1082         popal
1083         /* popal skips %esp.  We therefore want to do "movl -20(%sp),
1084          * %esp", but -20(%sp) is not a valid 80386 expression.
1085          * Fortunately, prot_to_real() zeroes the high word of %esp, so
1086          * we can just use -20(%esp) instead.
1087          */
1088         addr32 movl -20(%esp), %esp
1089         popfl
1090         popw    %ss /* padding */
1091
1092         /* Return and discard function parameters */
1093         ret     $( VC_OFFSET_END - VC_OFFSET_PARAMS )
1094
1095
1096         /* Protected-mode jump target */
1097         .equ    vc_jmp_offset, ( vc_jmp - 4 )
1098
1099 /****************************************************************************
1100  * real_call (protected-mode near call, 32-bit virtual return address)
1101  * real_call (long-mode near call, 64-bit virtual return address)
1102  *
1103  * Call a real-mode function from protected-mode or long-mode code.
1104  *
1105  * The non-segment register values will be passed directly to the
1106  * real-mode code.  The segment registers will be set as per
1107  * prot_to_real.  The non-segment register values set by the real-mode
1108  * function will be passed back to the protected-mode or long-mode
1109  * caller.  A result of this is that this routine cannot be called
1110  * directly from C code, since it clobbers registers that the C ABI
1111  * expects the callee to preserve.
1112  *
1113  * librm.h defines a convenient macro REAL_CODE() for using real_call.
1114  * See librm.h and realmode.h for details and examples.
1115  *
1116  * Parameters:
1117  *   function : offset within .text16 of real-mode function to call
1118  *
1119  * Returns: none
1120  ****************************************************************************
1121  */
1122         .struct 0
1123 RC_OFFSET_REGS:         .space  SIZEOF_I386_REGS
1124 RC_OFFSET_REGS_END:
1125 RC_OFFSET_FUNCTION_COPY:.space  4
1126 .if64
1127 RC_OFFSET_LREGS:        .space  SIZEOF_X86_64_REGS
1128 RC_OFFSET_LREG_RETADDR: .space  SIZEOF_ADDR
1129 .endif
1130 RC_OFFSET_RETADDR:      .space  SIZEOF_ADDR
1131 RC_OFFSET_PARAMS:
1132 RC_OFFSET_FUNCTION:     .space  SIZEOF_ADDR
1133 RC_OFFSET_END:
1134         .previous
1135
1136         .section ".text.real_call", "ax", @progbits
1137         .CODE_DEFAULT
1138         .globl real_call
1139 real_call:
1140 .if64 ; /* Preserve registers and switch to protected mode, if applicable */
1141         call    long_preserve_regs
1142         call    long_to_prot
1143         .code32
1144 .endif
1145         /* Create register dump and function pointer copy on PM stack */
1146         pushl   ( RC_OFFSET_FUNCTION - RC_OFFSET_FUNCTION_COPY - 4 )(%esp)
1147         pushal
1148
1149         /* Switch to real mode and move register dump to RM stack  */
1150         movl    $RC_OFFSET_REGS_END, %ecx
1151         movl    $RC_TMP_END, %edx
1152         pushl   $rc_rmode
1153         movl    $VIRTUAL(rm_default_gdtr_idtr), %esi
1154         jmp     prot_to_real
1155         .section ".text16.real_call", "ax", @progbits
1156         .code16
1157 rc_rmode:
1158         /* Call real-mode function */
1159         popal
1160         call    *( rm_tmpbuf + RC_TMP_FUNCTION )
1161         pushal
1162
1163         /* For sanity's sake, clear the direction flag as soon as possible */
1164         cld
1165
1166         /* Switch to protected mode and move register dump back to PM stack */
1167         movl    $RC_OFFSET_REGS_END, %ecx
1168         xorl    %edx, %edx
1169         pushl   $VIRTUAL(rc_pmode)
1170         jmp     real_to_prot
1171         .section ".text.real_call", "ax", @progbits
1172         .code32
1173 rc_pmode:
1174         /* Restore registers */
1175         popal
1176
1177 .if64 ; /* Switch to long mode and restore registers, if applicable */
1178         call    prot_to_long
1179         .code64
1180         call    long_restore_regs
1181 .endif
1182         /* Return and discard function parameters */
1183         ret     $( RC_OFFSET_END - RC_OFFSET_PARAMS )
1184
1185
1186         /* Default real-mode global and interrupt descriptor table registers */
1187         .section ".data.rm_default_gdtr_idtr", "aw", @progbits
1188 rm_default_gdtr_idtr:
1189         .word 0         /* Global descriptor table limit */
1190         .long 0         /* Global descriptor table base */
1191         .word 0x03ff    /* Interrupt descriptor table limit */
1192         .long 0         /* Interrupt descriptor table base */
1193
1194 /****************************************************************************
1195  * phys_call (protected-mode near call, 32-bit virtual return address)
1196  * phys_call (long-mode near call, 64-bit virtual return address)
1197  *
1198  * Call a function with flat 32-bit physical addressing
1199  *
1200  * The non-segment register values will be passed directly to the
1201  * function.  The segment registers will be set for flat 32-bit
1202  * physical addressing.  The non-segment register values set by the
1203  * function will be passed back to the caller.
1204  *
1205  * librm.h defines a convenient macro PHYS_CODE() for using phys_call.
1206  *
1207  * Parameters:
1208  *   function : virtual (sic) address of function to call
1209  *
1210  ****************************************************************************
1211  */
1212         .struct 0
1213 .if64
1214 PHC_OFFSET_LREGS:       .space  SIZEOF_X86_64_REGS
1215 PHC_OFFSET_LREG_RETADDR:.space  SIZEOF_ADDR
1216 .endif
1217 PHC_OFFSET_RETADDR:     .space  SIZEOF_ADDR
1218 PHC_OFFSET_PARAMS:
1219 PHC_OFFSET_FUNCTION:    .space  SIZEOF_ADDR
1220 PHC_OFFSET_END:
1221         .previous
1222
1223         .section ".text.phys_call", "ax", @progbits
1224         .CODE_DEFAULT
1225         .globl phys_call
1226 phys_call:
1227 .if64 ; /* Preserve registers and switch to protected mode, if applicable */
1228         call    long_preserve_regs
1229         call    long_to_prot
1230         .code32
1231 .endif
1232         /* Adjust function pointer to a physical address */
1233         pushl   %ebp
1234         movl    VIRTUAL(virt_offset), %ebp
1235         addl    %ebp, ( PHC_OFFSET_FUNCTION + 4 /* saved %ebp */ )(%esp)
1236         popl    %ebp
1237
1238         /* Switch to physical addresses */
1239         call    prot_to_phys
1240
1241         /* Call function */
1242         call    *PHC_OFFSET_FUNCTION(%esp)
1243
1244         /* For sanity's sake, clear the direction flag as soon as possible */
1245         cld
1246
1247         /* Switch to virtual addresses */
1248         call    phys_to_prot
1249
1250 .if64 ; /* Switch to long mode and restore registers, if applicable */
1251         call    prot_to_long
1252         .code64
1253         call    long_restore_regs
1254 .endif
1255         /* Return and discard function parameters */
1256         ret     $( PHC_OFFSET_END - PHC_OFFSET_PARAMS )
1257
1258 /****************************************************************************
1259  * phys_to_long (protected-mode near call, 32-bit physical return address)
1260  *
1261  * Used by COMBOOT.
1262  *
1263  ****************************************************************************
1264  */
1265         .if64
1266
1267         .section ".text.phys_to_long", "ax", @progbits
1268         .code32
1269 phys_to_long:
1270
1271         /* Switch to virtual addresses */
1272         call    phys_to_prot
1273
1274         /* Convert to 32-bit virtual return address */
1275         pushl   %eax
1276         movl    VIRTUAL(virt_offset), %eax
1277         subl    %eax, 4(%esp)
1278         popl    %eax
1279
1280         /* Switch to long mode and return */
1281         jmp     prot_to_long
1282
1283         /* Expose as _phys_to_virt for use by COMBOOT */
1284         .globl  _phys_to_virt
1285         .equ    _phys_to_virt, phys_to_long
1286
1287         .endif
1288
1289 /****************************************************************************
1290  * long_to_phys (long-mode near call, 64-bit virtual return address)
1291  *
1292  * Used by COMBOOT.
1293  *
1294  ****************************************************************************
1295  */
1296         .if64
1297
1298         .section ".text.long_to_phys", "ax", @progbits
1299         .code64
1300 long_to_phys:
1301
1302         /* Switch to protected mode */
1303         call    long_to_prot
1304         .code32
1305
1306         /* Convert to 32-bit virtual return address */
1307         popl    (%esp)
1308
1309         /* Switch to physical addresses and return */
1310         jmp     prot_to_phys
1311
1312         /* Expose as _virt_to_phys for use by COMBOOT */
1313         .globl  _virt_to_phys
1314         .equ    _virt_to_phys, long_to_phys
1315
1316         .endif
1317
1318 /****************************************************************************
1319  * flatten_real_mode (real-mode near call)
1320  *
1321  * Switch to flat real mode
1322  *
1323  ****************************************************************************
1324  */
1325         .section ".text16.flatten_real_mode", "ax", @progbits
1326         .code16
1327         .globl flatten_real_mode
1328 flatten_real_mode:
1329         /* Modify GDT to use flat real mode */
1330         movb    $0x8f, real_cs + 6
1331         movb    $0x8f, real_ds + 6
1332         /* Call dummy protected-mode function */
1333         virtcall flatten_dummy
1334         /* Restore GDT */
1335         movb    $0x00, real_cs + 6
1336         movb    $0x00, real_ds + 6
1337         /* Return */
1338         ret
1339
1340         .section ".text.flatten_dummy", "ax", @progbits
1341         .CODE_DEFAULT
1342 flatten_dummy:
1343         ret
1344
1345 /****************************************************************************
1346  * Interrupt wrapper
1347  *
1348  * Used by the protected-mode and long-mode interrupt vectors to call
1349  * the interrupt() function.
1350  *
1351  * May be entered with either physical or virtual stack segment.
1352  ****************************************************************************
1353  */
1354         .section ".text.interrupt_wrapper", "ax", @progbits
1355         .code32
1356         .globl interrupt_wrapper
1357 interrupt_wrapper:
1358         /* Preserve registers (excluding already-saved %eax and
1359          * otherwise unused registers which are callee-save for both
1360          * 32-bit and 64-bit ABIs).
1361          */
1362         pushl   %ebx
1363         pushl   %ecx
1364         pushl   %edx
1365         pushl   %esi
1366         pushl   %edi
1367
1368         /* Expand IRQ number to whole %eax register */
1369         movzbl  %al, %eax
1370
1371 .if64 ; /* Skip transition to long mode, if applicable */
1372         movw    %cs, %bx
1373         cmpw    $LONG_CS, %bx
1374         je      1f
1375 .endif
1376         /* Preserve segment registers and original %esp */
1377         pushl   %ds
1378         pushl   %es
1379         pushl   %fs
1380         pushl   %gs
1381         pushl   %ss
1382         pushl   %esp
1383
1384         /* Switch to virtual addressing */
1385         call    intr_to_prot
1386 .if64
1387         /* Switch to long mode */
1388         call    prot_to_long
1389         .code64
1390
1391 1:      /* Preserve long-mode caller-save registers */
1392         pushq   %r8
1393         pushq   %r9
1394         pushq   %r10
1395         pushq   %r11
1396
1397         /* Expand IRQ number to whole %rdi register */
1398         movl    %eax, %edi
1399 .endif
1400         /* Call interrupt handler */
1401         call    interrupt
1402 .if64
1403         /* Restore long-mode caller-save registers */
1404         popq    %r11
1405         popq    %r10
1406         popq    %r9
1407         popq    %r8
1408
1409         /* Skip transition back to protected mode, if applicable */
1410         cmpw    $LONG_CS, %bx
1411         je      1f
1412
1413         /* Switch to protected mode */
1414         call    long_to_prot
1415         .code32
1416         cmpw    $LONG_CS, %bx
1417 .endif
1418         /* Restore segment registers and original %esp */
1419         lss     (%esp), %esp
1420         popl    %ss
1421         popl    %gs
1422         popl    %fs
1423         popl    %es
1424         popl    %ds
1425
1426 1:      /* Restore registers */
1427         popl    %edi
1428         popl    %esi
1429         popl    %edx
1430         popl    %ecx
1431         popl    %ebx
1432         popl    %eax
1433
1434         /* Return from interrupt (with REX prefix if required) */
1435 .if64 ; jne 1f ; .byte 0x48 ; .endif
1436 1:      iret
1437
1438 /****************************************************************************
1439  * Page tables
1440  *
1441  ****************************************************************************
1442  */
1443         .section ".pages", "aw", @nobits
1444         .align  SIZEOF_PT
1445
1446         /* Page map level 4 entries (PML4Es)
1447          *
1448          * This comprises
1449          *
1450          * - PML4E[0x000] covering [0x0000000000000000-0x0000007fffffffff]
1451          * - PML4E[0x1ff] covering [0xffffff8000000000-0xffffffffffffffff]
1452          *
1453          * These point to the PDPT.  This creates some aliased
1454          * addresses within unused portions of the 64-bit address
1455          * space, but allows us to use just a single PDPT.
1456          *
1457          * - PDE[...] covering arbitrary 2MB portions of I/O space
1458          *
1459          * These are 2MB pages created by ioremap() to cover I/O
1460          * device addresses.
1461          */
1462 pml4e:
1463         .space  SIZEOF_PT
1464         .size   pml4e, . - pml4e
1465
1466         .globl  io_pages
1467         .equ    io_pages, pml4e
1468
1469         /* Page directory pointer table entries (PDPTEs)
1470          *
1471          * This comprises:
1472          *
1473          * - PDPTE[0x000] covering [0x0000000000000000-0x000000003fffffff]
1474          * - PDPTE[0x001] covering [0x0000000040000000-0x000000007fffffff]
1475          * - PDPTE[0x002] covering [0x0000000080000000-0x00000000bfffffff]
1476          * - PDPTE[0x003] covering [0x00000000c0000000-0x00000000ffffffff]
1477          *
1478          * These point to the appropriate page directories (in pde_low)
1479          * used to identity-map the whole of the 32-bit address space.
1480          *
1481          * - PDPTE[0x004] covering [0x0000000100000000-0x000000013fffffff]
1482          *
1483          * This points back to the PML4, allowing the PML4 to be
1484          * (ab)used to hold 2MB pages used for I/O device addresses.
1485          *
1486          * - PDPTE[0x1ff] covering [0xffffffffc0000000-0xffffffffffffffff]
1487          *
1488          * This points back to the PDPT itself, allowing the PDPT to be
1489          * (ab)used to hold PDEs covering .textdata.
1490          *
1491          * - PDE[N-M] covering [_textdata,_end)
1492          *
1493          * These are used to point to the page tables (in pte_textdata)
1494          * used to map our .textdata section.  Note that each PDE
1495          * covers 2MB, so we are likely to use only a single PDE in
1496          * practice.
1497          */
1498 pdpte:
1499         .space  SIZEOF_PT
1500         .size   pdpte, . - pdpte
1501         .equ    pde_textdata, pdpte /* (ab)use */
1502
1503         /* Page directory entries (PDEs) for the low 4GB
1504          *
1505          * This comprises 2048 2MB pages to identity-map the whole of
1506          * the 32-bit address space.
1507          */
1508 pde_low:
1509         .equ    PDE_LOW_PTES, ( SIZEOF_LOW_4GB / SIZEOF_2MB_PAGE )
1510         .equ    PDE_LOW_PTS, ( ( PDE_LOW_PTES * SIZEOF_PTE ) / SIZEOF_PT )
1511         .space  ( PDE_LOW_PTS * SIZEOF_PT )
1512         .size   pde_low, . - pde_low
1513
1514         /* Page table entries (PTEs) for .textdata
1515          *
1516          * This comprises enough 4kB pages to map the whole of
1517          * .textdata.  The required number of PTEs is calculated by
1518          * the linker script.
1519          *
1520          * Note that these mappings do not cover the PTEs themselves.
1521          * This does not matter, since code running with paging
1522          * enabled never needs to access these PTEs.
1523          */
1524 pte_textdata:
1525         /* Allocated by linker script; must be at the end of .textdata */
1526
1527         .section ".bss.pml4", "aw", @nobits
1528 pml4:   .long   0
1529
1530 /****************************************************************************
1531  * init_pages (protected-mode near call)
1532  *
1533  * Initialise the page tables ready for long mode.
1534  *
1535  * Parameters:
1536  *   %edi : virt_offset
1537  ****************************************************************************
1538  */
1539         .section ".text.init_pages", "ax", @progbits
1540         .code32
1541 init_pages:
1542         /* Initialise PML4Es for low 4GB and negative 2GB */
1543         leal    ( VIRTUAL(pdpte) + ( PG_P | PG_RW | PG_US ) )(%edi), %eax
1544         movl    %eax, VIRTUAL(pml4e)
1545         movl    %eax, ( VIRTUAL(pml4e) + SIZEOF_PT - SIZEOF_PTE )
1546
1547         /* Initialise PDPTE for negative 1GB */
1548         movl    %eax, ( VIRTUAL(pdpte) + SIZEOF_PT - SIZEOF_PTE )
1549
1550         /* Initialise PDPTE for I/O space */
1551         leal    ( VIRTUAL(pml4e) + ( PG_P | PG_RW | PG_US ) )(%edi), %eax
1552         movl    %eax, ( VIRTUAL(pdpte) + ( PDE_LOW_PTS * SIZEOF_PTE ) )
1553
1554         /* Initialise PDPTEs for low 4GB */
1555         movl    $PDE_LOW_PTS, %ecx
1556         leal    ( VIRTUAL(pde_low) + ( PDE_LOW_PTS * SIZEOF_PT ) + \
1557                   ( PG_P | PG_RW | PG_US ) )(%edi), %eax
1558 1:      subl    $SIZEOF_PT, %eax
1559         movl    %eax, ( VIRTUAL(pdpte) - SIZEOF_PTE )(,%ecx,SIZEOF_PTE)
1560         loop    1b
1561
1562         /* Initialise PDEs for low 4GB */
1563         movl    $PDE_LOW_PTES, %ecx
1564         leal    ( 0 + ( PG_P | PG_RW | PG_US | PG_PS ) ), %eax
1565 1:      subl    $SIZEOF_2MB_PAGE, %eax
1566         movl    %eax, ( VIRTUAL(pde_low) - SIZEOF_PTE )(,%ecx,SIZEOF_PTE)
1567         loop    1b
1568
1569         /* Initialise PDEs for .textdata */
1570         movl    $_textdata_pdes, %ecx
1571         leal    ( VIRTUAL(_etextdata) + ( PG_P | PG_RW | PG_US ) )(%edi), %eax
1572         movl    $VIRTUAL(_textdata), %ebx
1573         shrl    $( SIZEOF_2MB_PAGE_LOG2 - SIZEOF_PTE_LOG2 ), %ebx
1574         andl    $( SIZEOF_PT - 1 ), %ebx
1575 1:      subl    $SIZEOF_PT, %eax
1576         movl    %eax, (VIRTUAL(pde_textdata) - SIZEOF_PTE)(%ebx,%ecx,SIZEOF_PTE)
1577         loop    1b
1578
1579         /* Initialise PTEs for .textdata */
1580         movl    $_textdata_ptes, %ecx
1581         leal    ( VIRTUAL(_textdata) + ( PG_P | PG_RW | PG_US ) )(%edi), %eax
1582         addl    $_textdata_paged_len, %eax
1583 1:      subl    $SIZEOF_4KB_PAGE, %eax
1584         movl    %eax, ( VIRTUAL(pte_textdata) - SIZEOF_PTE )(,%ecx,SIZEOF_PTE)
1585         loop    1b
1586
1587         /* Record PML4 physical address */
1588         leal    VIRTUAL(pml4e)(%edi), %eax
1589         movl    %eax, VIRTUAL(pml4)
1590
1591         /* Return */
1592         ret