whitespace + minor typo fixes
[etherboot.git] / src / arch / i386 / core / start32.S
1 /* #defines because ljmp wants a number, probably gas bug */
2 /*      .equ    KERN_CODE_SEG,_pmcs-_gdt        */
3 #define KERN_CODE_SEG   0x08
4         .equ    KERN_DATA_SEG,_pmds-_gdt
5 /*      .equ    REAL_CODE_SEG,_rmcs-_gdt        */
6 #define REAL_CODE_SEG   0x18
7         .equ    REAL_DATA_SEG,_rmds-_gdt
8         .equ    FLAT_CODE_SEG,_pmcs2-_gdt
9         .equ    FLAT_DATA_SEG,_pmds2-_gdt
10         .equ    CR0_PE,1
11 #ifdef CONFIG_X86_64
12         .equ    LM_CODE_SEG,  _lmcs-_gdt
13         .equ    LM_DATA_SEG,  _lmds-_gdt
14 #endif
15
16         .equ    MSR_K6_EFER,   0xC0000080
17         .equ    EFER_LME,      0x00000100
18         .equ    X86_CR4_PAE,   0x00000020
19         .equ    CR0_PG,        0x80000000
20
21 #ifdef  GAS291
22 #define DATA32 data32;
23 #define ADDR32 addr32;
24 #define LJMPI(x)        ljmp    x
25 #else
26 #define DATA32 data32
27 #define ADDR32 addr32
28 /* newer GAS295 require #define LJMPI(x)        ljmp    *x */
29 #define LJMPI(x)        ljmp    x
30 #endif
31
32 #define BOCHSBP xchgw %bx, %bx
33
34 #include "callbacks.h"
35 #define NUM_PUSHA_REGS (8)
36 #define NUM_SEG_REGS (6)
37
38 /*
39  * NOTE: if you write a subroutine that is called from C code (gcc/egcs),
40  * then you only have to take care of %ebx, %esi, %edi and %ebp.  These
41  * registers must not be altered under any circumstance.  All other registers
42  * may be clobbered without any negative side effects.  If you don't follow
43  * this rule then you'll run into strange effects that only occur on some
44  * gcc versions (because the register allocator may use different registers).
45  *
46  * All the data32 prefixes for the ljmp instructions are necessary, because
47  * the assembler emits code with a relocation address of 0.  This means that
48  * all destinations are initially negative, which the assembler doesn't grok,
49  * because for some reason negative numbers don't fit into 16 bits. The addr32
50  * prefixes are there for the same reasons, because otherwise the memory
51  * references are only 16 bit wide.  Theoretically they are all superfluous.
52  * One last note about prefixes: the data32 prefixes on all call _real_to_prot
53  * instructions could be removed if the _real_to_prot function is changed to
54  * deal correctly with 16 bit return addresses.  I tried it, but failed.
55  */
56
57 /**************************************************************************
58  * START
59  *
60  * This file is no longer enterered from the top.  init.S will jump to
61  * either _in_call or _rm_in_call, depending on the processor mode
62  * when init.S was entered.
63  **************************************************************************/
64         .text
65         .arch i386
66         .code32
67
68 /**************************************************************************
69 _IN_CALL - make a call in to Etherboot.
70 **************************************************************************/
71
72 /* There are two 32-bit entry points: _in_call and _in_call_far, for
73  * near calls and far calls respectively.  Both should be called with
74  * flat physical addresses.  They will result in a call to the C
75  * routine in_call(); see there for API details.
76  *
77  * Note that this routine makes fairly heavy use of the stack and no
78  * use of fixed data areas.  This is because it must be re-entrant;
79  * there may be more than one concurrent call in to Etherboot.
80  */
81
82 #define IC_OFFSET_VA_LIST_PTR ( 0 )
83 #define IC_OFFSET_VA_LIST_PTR_E ( IC_OFFSET_VA_LIST_PTR + 4 )
84 #define IC_OFFSET_REGISTERS ( IC_OFFSET_VA_LIST_PTR_E )
85 #define IC_OFFSET_REGISTERS_E ( IC_OFFSET_REGISTERS + ( NUM_PUSHA_REGS * 4 ) )
86 #define IC_OFFSET_SEG_REGS ( IC_OFFSET_REGISTERS_E )
87 #define IC_OFFSET_SEG_REGS_E ( IC_OFFSET_SEG_REGS + ( NUM_SEG_REGS * 2 ) )
88 #define IC_OFFSET_GDT ( IC_OFFSET_SEG_REGS_E )
89 #define IC_OFFSET_GDT_E ( IC_OFFSET_GDT + 8 )
90 #define IC_OFFSET_FLAGS ( IC_OFFSET_GDT_E )
91 #define IC_OFFSET_FLAGS_E ( IC_OFFSET_FLAGS + 4 )
92 #define IC_OFFSET_RETADDR ( IC_OFFSET_FLAGS_E )
93 #define IC_OFFSET_RETADDR_E ( IC_OFFSET_RETADDR + 8 )
94 #define IC_OFFSET_ORIG_STACK ( IC_OFFSET_RETADDR )
95 #define IC_OFFSET_OPCODE ( IC_OFFSET_ORIG_STACK + 8 )
96 #define IC_OFFSET_OPCODE_E ( IC_OFFSET_OPCODE + 4 )
97 #define IC_OFFSET_VA_LIST ( IC_OFFSET_OPCODE_E )
98
99         .code32
100         .globl _in_call
101         .globl _in_call_far
102 _in_call:
103         /* Expand to far return address */
104         pushl   %eax                    /* Store %eax */
105         xorl    %eax, %eax
106         movw    %cs, %ax
107         xchgl   %eax, 4(%esp)           /* 4(%esp) = %cs, %eax = ret addr */
108         xchgl   %eax, 0(%esp)           /* 0(%esp) = ret addr, restore %eax */
109 _in_call_far:
110         /* Store flags */
111         pushfl
112         /* Store the GDT */
113         subl    $8, %esp
114         sgdt    0(%esp)
115         /* Store segment register values */
116         pushw   %gs
117         pushw   %fs
118         pushw   %es
119         pushw   %ds
120         pushw   %ss
121         pushw   %cs
122         /* Store general-purpose register values */
123         pushal
124         /* Replace %esp in store with physical %esp value on entry */
125         leal    (IC_OFFSET_ORIG_STACK - IC_OFFSET_REGISTERS)(%esp), %eax
126         movl    %eax, (IC_OFFSET_REGISTERS - IC_OFFSET_REGISTERS + 12)(%esp)
127         /* Store va_list pointer (physical address) */
128         leal    (IC_OFFSET_VA_LIST - IC_OFFSET_VA_LIST_PTR_E)(%esp), %eax
129         pushl   %eax
130         /* IC_OFFSET_*(%esp) are now valid */
131
132         /* Determine the offset between physical and virtual address */
133         call    1f
134 1:      popl    %ebp
135         subl    $1b, %ebp
136         movl    %ebp, virt_offset(%ebp)
137
138         /* Check opcode for EB_USE_INTERNAL_STACK flag */
139         movl    IC_OFFSET_OPCODE(%esp), %eax
140         testl   $EB_USE_INTERNAL_STACK, %eax
141         je      2f
142         /* Use internal stack flag set */
143         /* Check %esp is not already in internal stack range */
144         leal    _stack(%ebp), %esi      /* %esi = bottom of internal stack */
145         leal    _estack(%ebp), %edi     /* %edi = top of internal stack */
146         cmpl    %esi, %esp
147         jb      1f
148         cmpl    %edi, %esp
149         jbe     2f
150 1:      /* %esp not currently in internal stack range */
151         movl    %esp, %esi              /* %esi = original stack */
152         movl    $IC_OFFSET_OPCODE_E, %ecx /* %ecx = length to transfer */
153         subl    %ecx, %edi              /* %edi = internal stack pos */
154         movl    %edi, %esp              /*  = new %esp */
155         rep movsb                       /* Copy data to internal stack */
156 2:
157
158         /* Switch to virtual addresses */
159         call    _phys_to_virt
160
161         /* Fixup the va_list pointer */
162         movl    virt_offset, %ebp
163         subl    %ebp, IC_OFFSET_VA_LIST_PTR(%esp)
164
165         /* Call to C code */
166         call    i386_in_call
167
168         /* Set %eax (return code from C) in registers structure on
169          * stack, so that we return it to the caller.
170          */
171         movl    %eax, (IC_OFFSET_REGISTERS + 28)(%esp)
172
173         /* Calculate physical continuation address */
174         movl    virt_offset, %ebp
175         movzwl  (IC_OFFSET_SEG_REGS + 0)(%esp), %eax    /* %cs */
176         movzwl  (IC_OFFSET_SEG_REGS + 2)(%esp), %ebx    /* %ss */
177         pushl   %eax                    /* Continuation segment */
178         leal    1f(%ebp), %eax
179         pushl   %eax                    /* Continuation offset */
180
181         /* Restore caller's GDT */
182         cli                             /* Temporarily disable interrupts */
183         lgdt    (8+IC_OFFSET_GDT)(%esp)
184         /* Reset %ss and adjust %esp */
185         movw    %bx, %ss
186         addl    %ebp, %esp
187         lret                            /* Reload %cs:eip, flush prefetch */
188 1:
189
190         /* Skip va_list ptr */
191         popl    %eax
192         /* Reload general-purpose registers to be returned */
193         popal
194         /* Reload segment registers as passed in from caller */
195         popw    %gs
196         popw    %fs
197         popw    %es
198         popw    %ds
199         addl    $(4+8), %esp    /* Skip %cs, %ss and GDT (already reloaded) */
200         /* Restore flags (including revert of interrupt status) */
201         popfl
202
203         /* Restore physical %esp from entry.  It will only be
204          * different if EB_USE_INTERNAL_STACK was specified.
205          */
206         movl    ( 12 + IC_OFFSET_REGISTERS - IC_OFFSET_RETADDR )(%esp), %esp
207
208         /* Check for EB_SKIP_OPCODE */
209         pushfl
210         testl   $EB_SKIP_OPCODE, 12(%esp)
211         jnz     1f
212         /* Normal return */
213         popfl
214         lret
215 1:      /* Return and skip opcode */
216         popfl
217         lret    $4
218
219 /**************************************************************************
220 RELOCATE_TO - relocate etherboot to the specified address
221 **************************************************************************/
222         .globl relocate_to
223 relocate_to:
224         /* Save the callee save registers */
225         pushl   %ebp
226         pushl   %esi
227         pushl   %edi
228
229         /* Compute the virtual destination address */
230         movl    16(%esp), %edi  # dest
231         subl    virt_offset, %edi
232
233
234         /* Compute the new value of virt_offset */
235         movl    16(%esp), %ebp  # virt_offset
236         subl    $_text, %ebp
237
238         /* Fixup the gdt */
239         pushl   $_pmcs
240         pushl   %ebp            # virt_offset
241         call    set_seg_base
242         addl    $8, %esp
243
244         /* Fixup gdtarg */
245         leal    _gdt(%ebp), %eax
246         movl    %eax, gdtarg +2
247
248         /* Fixup virt_offset */
249         movl    %ebp, virt_offset
250
251         /* Load the move parameters */
252         movl    $_text, %esi
253         movl    $_end, %ecx
254         subl    %esi, %ecx
255
256         /* Move etherboot uses %esi, %edi, %ecx */
257         rep
258         movsb
259
260         /* Reload the gdt */
261         cs
262         lgdt    gdtarg
263
264         /* Reload %cs */
265         ljmp    $KERN_CODE_SEG, $1f
266 1:
267         /* reload other segment registers */
268         movl    $KERN_DATA_SEG, %eax
269         movl    %eax,%ds
270         movl    %eax,%es
271         movl    %eax,%ss
272         movl    %eax,%fs
273         movl    %eax,%gs
274
275         /* Restore the callee save registers */
276         popl    %edi
277         popl    %esi
278         popl    %ebp
279
280         /* return */
281         ret
282
283 /**************************************************************************
284 XSTART32 - Transfer control to the kernel just loaded
285 **************************************************************************/
286         .globl xstart32
287 xstart32:
288         /* Save the callee save registers */
289         movl    %ebp, os_regs + 32
290         movl    %esi, os_regs + 36
291         movl    %edi, os_regs + 40
292         movl    %ebx, os_regs + 44
293
294         /* save the return address */
295         popl    %eax
296         movl    %eax, os_regs + 48
297
298         /* save the stack pointer */
299         movl    %esp, os_regs + 52
300
301         /* Get the new destination address */
302         popl    %ecx
303
304         /* Store the physical address of xend on the stack */
305         movl    $xend32, %ebx
306         addl    virt_offset, %ebx
307         pushl   %ebx
308
309         /* Store the destination address on the stack */
310         pushl   $FLAT_CODE_SEG
311         pushl   %ecx
312
313         /* Cache virt_offset */
314         movl    virt_offset, %ebp
315
316         /* Switch to using physical addresses */
317         call    _virt_to_phys
318
319         /* Save the target stack pointer */
320         movl    %esp, os_regs + 12(%ebp)
321         leal    os_regs(%ebp), %esp
322
323         /* Store the pointer to os_regs */
324         movl    %esp, os_regs_ptr(%ebp)
325
326         /* Load my new registers */
327         popal
328         movl    (-32 + 12)(%esp), %esp
329
330         /* Jump to the new kernel
331          * The lret switches to a flat code segment
332          */
333         lret
334
335         .balign 4
336         .globl xend32
337 xend32:
338         /* Fixup %eflags */
339         nop
340         cli
341         cld
342
343         /* Load %esp with &os_regs + virt_offset */
344         .byte   0xbc /* movl $0, %esp */
345 os_regs_ptr:
346         .long   0
347
348         /* Save the result registers */
349         addl    $32, %esp
350         pushal
351
352         /* Compute virt_offset */
353         movl    %esp, %ebp
354         subl    $os_regs, %ebp
355
356         /* Load the stack pointer and convert it to physical address */
357         movl    52(%esp), %esp
358         addl    %ebp, %esp
359
360         /* Enable the virtual addresses */
361         leal    _phys_to_virt(%ebp), %eax
362         call    *%eax
363
364         /* Restore the callee save registers */
365         movl    os_regs + 32, %ebp
366         movl    os_regs + 36, %esi
367         movl    os_regs + 40, %edi
368         movl    os_regs + 44, %ebx
369         movl    os_regs + 48, %edx
370         movl    os_regs + 52, %esp
371
372         /* Get the C return value */
373         movl    os_regs + 28, %eax
374
375         jmpl    *%edx
376
377 #ifdef CONFIG_X86_64
378         .arch   sledgehammer
379 /**************************************************************************
380 XSTART_lm - Transfer control to the kernel just loaded in long mode
381 **************************************************************************/
382         .globl xstart_lm
383 xstart_lm:
384         /* Save the callee save registers */
385         pushl   %ebp
386         pushl   %esi
387         pushl   %edi
388         pushl   %ebx
389
390         /* Cache virt_offset && (virt_offset & 0xfffff000) */
391         movl    virt_offset, %ebp
392         movl    %ebp, %ebx
393         andl    $0xfffff000, %ebx
394
395         /* Switch to using physical addresses */
396         call    _virt_to_phys
397
398         /* Initialize the page tables */
399         /* Level 4 */
400         leal    0x23 + pgt_level3(%ebx), %eax
401         leal    pgt_level4(%ebx), %edi
402         movl    %eax, (%edi)
403
404         /* Level 3 */
405         leal    0x23 + pgt_level2(%ebx), %eax
406         leal    pgt_level3(%ebx), %edi
407         movl    %eax, 0x00(%edi)
408         addl    $4096, %eax
409         movl    %eax, 0x08(%edi)
410         addl    $4096, %eax
411         movl    %eax, 0x10(%edi)
412         addl    $4096, %eax
413         movl    %eax, 0x18(%edi)
414
415         /* Level 2 */
416         movl    $0xe3, %eax
417         leal    pgt_level2(%ebx), %edi
418         leal    16384(%edi), %esi
419 pgt_level2_loop:
420         movl    %eax, (%edi)
421         addl    $8, %edi
422         addl    $0x200000, %eax
423         cmp     %esi, %edi
424         jne     pgt_level2_loop
425
426         /* Point at the x86_64 page tables */
427         leal    pgt_level4(%ebx), %edi
428         movl    %edi, %cr3
429
430
431         /* Setup for the return from 64bit mode */
432         /* 64bit align the stack */
433         movl    %esp, %ebx              /* original stack pointer + 16 */
434         andl    $0xfffffff8, %esp
435
436         /* Save original stack pointer + 16 */
437         pushl   %ebx
438
439         /* Save virt_offset */
440         pushl   %ebp
441
442         /* Setup for the jmp to 64bit long mode */
443         leal    start_lm(%ebp), %eax
444         movl    %eax, 0x00 + start_lm_addr(%ebp)
445         movl    $LM_CODE_SEG, %eax
446         movl    %eax, 0x04 + start_lm_addr(%ebp)
447
448         /* Setup for the jump out of 64bit long mode */
449         leal    end_lm(%ebp), %eax
450         movl    %eax, 0x00 + end_lm_addr(%ebp)
451         movl    $FLAT_CODE_SEG, %eax
452         movl    %eax, 0x04 + end_lm_addr(%ebp)
453
454         /* Enable PAE mode */
455         movl    %cr4, %eax
456         orl     $X86_CR4_PAE, %eax
457         movl    %eax, %cr4
458
459         /* Enable long mode */
460         movl    $MSR_K6_EFER, %ecx
461         rdmsr
462         orl     $EFER_LME, %eax
463         wrmsr
464
465         /* Start paging, entering 32bit compatiblity mode */
466         movl    %cr0, %eax
467         orl     $CR0_PG, %eax
468         movl    %eax, %cr0
469
470         /* Enter 64bit long mode */
471         ljmp    *start_lm_addr(%ebp)
472         .code64
473 start_lm:
474         /* Load 64bit data segments */
475         movl    $LM_DATA_SEG, %eax
476         movl    %eax, %ds
477         movl    %eax, %es
478         movl    %eax, %ss
479
480         andq    $0xffffffff, %rbx
481         /* Get the address to jump to */
482         movl    20(%rbx), %edx
483         andq    $0xffffffff, %rdx
484
485         /* Get the argument pointer */
486         movl    24(%rbx), %ebx
487         andq    $0xffffffff, %rbx
488
489         /* Jump to the 64bit code */
490         call    *%rdx
491
492         /* Preserve the result */
493         movl    %eax, %edx
494
495         /* Fixup %eflags */
496         cli
497         cld
498
499         /* Switch to 32bit compatibility mode */
500         ljmp    *end_lm_addr(%rip)
501
502         .code32
503 end_lm:
504         /* Disable paging */
505         movl    %cr0, %eax
506         andl    $~CR0_PG, %eax
507         movl    %eax, %cr0
508
509         /* Disable long mode */
510         movl    $MSR_K6_EFER, %ecx
511         rdmsr
512         andl    $~EFER_LME, %eax
513         wrmsr
514
515         /* Disable PAE */
516         movl    %cr4, %eax
517         andl    $~X86_CR4_PAE, %eax
518         movl    %eax, %cr4
519
520         /* Compute virt_offset */
521         popl    %ebp
522
523         /* Compute the original stack pointer + 16 */
524         popl    %ebx
525         movl    %ebx, %esp
526
527         /* Enable the virtual addresses */
528         leal    _phys_to_virt(%ebp), %eax
529         call    *%eax
530
531         /* Restore the callee save registers */
532         popl    %ebx
533         popl    %esi
534         popl    %edi
535         popl    %ebp
536
537         /* Get the C return value */
538         movl    %edx, %eax
539
540         /* Return */
541         ret
542
543         .arch i386
544 #endif /* CONFIG_X86_64 */
545
546 /**************************************************************************
547 SETJMP - Save stack context for non-local goto
548 **************************************************************************/
549         .globl  setjmp
550 setjmp:
551         movl    4(%esp),%ecx            /* jmpbuf */
552         movl    0(%esp),%edx            /* return address */
553         movl    %edx,0(%ecx)
554         movl    %ebx,4(%ecx)
555         movl    %esp,8(%ecx)
556         movl    %ebp,12(%ecx)
557         movl    %esi,16(%ecx)
558         movl    %edi,20(%ecx)
559         movl    $0,%eax
560         ret
561
562 /**************************************************************************
563 LONGJMP - Non-local jump to a saved stack context
564 **************************************************************************/
565         .globl  longjmp
566 longjmp:
567         movl    4(%esp),%edx            /* jumpbuf */
568         movl    8(%esp),%eax            /* result */
569         movl    0(%edx),%ecx
570         movl    4(%edx),%ebx
571         movl    8(%edx),%esp
572         movl    12(%edx),%ebp
573         movl    16(%edx),%esi
574         movl    20(%edx),%edi
575         cmpl    $0,%eax
576         jne     1f
577         movl    $1,%eax
578 1:      movl    %ecx,0(%esp)
579         ret
580
581 /**************************************************************************
582 _VIRT_TO_PHYS - Transition from virtual to physical addresses
583                 Preserves all preservable registers and flags
584 **************************************************************************/
585         .globl _virt_to_phys
586 _virt_to_phys:
587         pushfl
588         pushl   %ebp
589         pushl   %eax
590         movl    virt_offset, %ebp       /* Load virt_offset */
591         addl    %ebp, 12(%esp)          /* Adjust the return address */
592
593         /* reload the code segment */
594         pushl   $FLAT_CODE_SEG
595         leal    1f(%ebp), %eax
596         pushl   %eax
597         lret
598
599 1:
600         /* reload other segment registers */
601         movl    $FLAT_DATA_SEG, %eax
602         movl    %eax, %ds
603         movl    %eax, %es
604         movl    %eax, %ss
605         addl    %ebp, %esp              /* Adjust the stack pointer */
606         movl    %eax, %fs
607         movl    %eax, %gs
608
609         popl    %eax
610         popl    %ebp
611         popfl
612         ret
613
614 /**************************************************************************
615 _PHYS_TO_VIRT - Transition from using physical to virtual addresses
616                 Preserves all preservable registers and flags
617 **************************************************************************/
618         .globl _phys_to_virt
619 _phys_to_virt:
620         pushfl
621         pushl   %ebp
622         pushl   %eax
623
624         call    1f
625 1:      popl    %ebp
626         subl    $1b, %ebp
627
628         /* Fixup the gdt */
629         leal    _pmcs(%ebp), %eax
630         pushl   %eax
631         pushl   %ebp
632         call    set_seg_base
633         addl    $8, %esp
634
635         /* Fixup gdtarg */
636         leal    _gdt(%ebp), %eax
637         movl    %eax, (gdtarg+2)(%ebp)
638
639         /* Load the global descriptor table */
640         cli
641         lgdt    %cs:gdtarg(%ebp)
642         ljmp    $KERN_CODE_SEG, $1f
643 1:
644         /* reload other segment regsters */
645         movl    $KERN_DATA_SEG, %eax
646         movl    %eax, %ds
647         movl    %eax, %es
648         movl    %eax, %ss
649         subl    %ebp, %esp      /* Adjust the stack pointer */
650         movl    %eax, %fs
651         movl    %eax, %gs
652
653         subl    %ebp, 12(%esp)  /* Adjust the return address */
654         popl    %eax
655         popl    %ebp
656         popfl
657         ret
658
659 /**************************************************************************
660 SET_SEG_BASE - Set the base address of a segment register
661 **************************************************************************/
662         .globl set_seg_base
663 set_seg_base:
664         pushl   %eax
665         pushl   %ebx
666         movl    12(%esp), %eax          /* %eax = base address */
667         movl    16(%esp), %ebx          /* %ebx = &code_descriptor */
668         movw    %ax, (0+2)(%ebx)        /* CS base bits 0-15 */
669         movw    %ax, (8+2)(%ebx)        /* DS base bits 0-15 */
670         shrl    $16, %eax
671         movb    %al, (0+4)(%ebx)        /* CS base bits 16-23 */
672         movb    %al, (8+4)(%ebx)        /* DS base bits 16-23 */
673         movb    %ah, (0+7)(%ebx)        /* CS base bits 24-31 */
674         movb    %ah, (8+7)(%ebx)        /* DS base bits 24-31 */
675         popl    %ebx
676         popl    %eax
677         ret
678
679 /**************************************************************************
680 GLOBAL DESCRIPTOR TABLE
681 **************************************************************************/
682         .data
683         .align  4
684
685         .globl  _gdt
686         .globl  gdtarg
687 _gdt:
688 gdtarg:
689         .word   _gdt_end - _gdt - 1     /* limit */
690         .long   _gdt                    /* addr */
691         .word   0
692
693         .globl  _pmcs
694 _pmcs:
695         /* 32 bit protected mode code segment */
696         .word   0xffff,0
697         .byte   0,0x9f,0xcf,0
698
699 _pmds:
700         /* 32 bit protected mode data segment */
701         .word   0xffff,0
702         .byte   0,0x93,0xcf,0
703
704 _rmcs:
705         /* 16 bit real mode code segment */
706         .word   0xffff,(0&0xffff)
707         .byte   (0>>16),0x9b,0x00,(0>>24)
708
709 _rmds:
710         /* 16 bit real mode data segment */
711         .word   0xffff,(0&0xffff)
712         .byte   (0>>16),0x93,0x00,(0>>24)
713
714 _pmcs2:
715         /* 32 bit protected mode code segment, base 0 */
716         .word   0xffff,0
717         .byte   0,0x9f,0xcf,0
718
719 _pmds2:
720         /* 32 bit protected mode data segment, base 0 */
721         .word   0xffff,0
722         .byte   0,0x93,0xcf,0
723
724 #ifdef CONFIG_X86_64
725 _lmcs:
726         /* 64bit long mode code segment, base 0 */
727         .word   0xffff, 0
728         .byte   0x00, 0x9f, 0xaf , 0x00
729 _lmds:
730         /* 64bit long mode data segment, base 0 */
731         .word   0xffff, 0
732         .byte   0x00, 0x93, 0xcf, 0x00
733 #endif
734 _gdt_end:
735
736         /* The initial register contents */
737         .balign 4
738         .globl initial_regs
739 initial_regs:
740         .fill 8, 4, 0
741
742         /* The virtual address offset  */
743         .globl virt_offset
744 virt_offset:
745         .long   0
746
747         .section ".stack"
748         .p2align 3
749         /* allocate a 4K stack in the stack segment */
750         .globl  _stack
751 _stack:
752         .space 4096
753         .globl  _estack
754 _estack:
755 #ifdef CONFIG_X86_64
756         .section ".bss"
757         .p2align 12
758         /* Include a dummy space in case we are loaded badly aligned */
759         .space 4096
760         /* Reserve enough space for a page table convering 4GB with 2MB pages */
761 pgt_level4:
762         .space 4096
763 pgt_level3:
764         .space 4096
765 pgt_level2:
766         .space 16384
767 start_lm_addr:
768         .space  8
769 end_lm_addr:
770         .space  8
771 #endif