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