Initial revision
[people/andreif/gpxe.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         /* Switch to virtual addresses */
133         call    _phys_to_virt
134
135         /* Fixup the va_list pointer */
136         movl    virt_offset, %ebp
137         subl    %ebp, IC_OFFSET_VA_LIST_PTR(%esp)
138
139         /* Check opcode for EB_USE_INTERNAL_STACK flag */
140         movl    IC_OFFSET_OPCODE(%esp), %eax
141         testl   $EB_USE_INTERNAL_STACK, %eax
142         je      2f
143         /* Use internal stack flag set */
144         /* Check %esp is not already in internal stack range */
145         leal    _stack, %esi            /* %esi = bottom of internal stack */
146         leal    _estack, %edi           /* %edi = top of internal stack */
147         cmpl    %esi, %esp
148         jb      1f
149         cmpl    %edi, %esp
150         jbe     2f
151 1:      /* %esp not currently in internal stack range */
152         movl    %esp, %esi              /* %esi = original stack */
153         movl    $IC_OFFSET_OPCODE_E, %ecx /* %ecx = length to transfer */
154         subl    %ecx, %edi              /* %edi = internal stack pos */
155         movl    %edi, %esp              /*  = new %esp */
156         rep movsb                       /* Copy data to internal stack */
157 2:
158
159         /* Call to C code */
160         call    i386_in_call
161
162         /* Set %eax (return code from C) in registers structure on
163          * stack, so that we return it to the caller.
164          */
165         movl    %eax, (IC_OFFSET_REGISTERS + 28)(%esp)
166
167         /* Calculate physical continuation address */
168         movl    virt_offset, %ebp
169         movzwl  (IC_OFFSET_SEG_REGS + 0)(%esp), %eax    /* %cs */
170         movzwl  (IC_OFFSET_SEG_REGS + 2)(%esp), %ebx    /* %ss */
171         pushl   %eax                    /* Continuation segment */
172         leal    1f(%ebp), %eax
173         pushl   %eax                    /* Continuation offset */
174         
175         /* Restore caller's GDT */
176         cli                             /* Temporarily disable interrupts */
177         lgdt    (8+IC_OFFSET_GDT)(%esp)
178         /* Reset %ss and adjust %esp */
179         movw    %bx, %ss
180         addl    %ebp, %esp
181         lret                            /* Reload %cs:eip, flush prefetch */
182 1:
183
184         /* Skip va_list ptr */
185         popl    %eax
186         /* Reload general-purpose registers to be returned */
187         popal
188         /* Reload segment registers as passed in from caller */
189         popw    %gs
190         popw    %fs
191         popw    %es
192         popw    %ds
193         addl    $(4+8), %esp    /* Skip %cs, %ss and GDT (already reloaded) */
194         /* Restore flags (including revert of interrupt status) */
195         popfl
196
197         /* Restore physical %esp from entry.  It will only be
198          * different if EB_USE_INTERNAL_STACK was specified.
199          */
200         movl    ( 12 + IC_OFFSET_REGISTERS - IC_OFFSET_RETADDR )(%esp), %esp
201                 
202         /* Check for EB_SKIP_OPCODE */
203         pushfl
204         testl   $EB_SKIP_OPCODE, 12(%esp)
205         jnz     1f
206         /* Normal return */
207         popfl
208         lret
209 1:      /* Return and skip opcode */
210         popfl
211         lret    $4
212         
213 /**************************************************************************
214 RELOCATE_TO - relocate etherboot to the specified address
215 **************************************************************************/
216         .globl relocate_to
217 relocate_to:
218         /* Save the callee save registers */
219         pushl   %ebp
220         pushl   %esi
221         pushl   %edi
222
223         /* Compute the virtual destination address */
224         movl    16(%esp), %edi  # dest
225         subl    virt_offset, %edi
226         
227
228         /* Compute the new value of virt_offset */
229         movl    16(%esp), %ebp  # virt_offset
230         subl    $_text, %ebp
231
232         /* Fixup the gdt */
233         pushl   $_pmcs
234         pushl   %ebp            # virt_offset
235         call    set_seg_base
236         addl    $8, %esp
237
238         /* Fixup gdtarg */
239         leal    _gdt(%ebp), %eax
240         movl    %eax, gdtarg +2
241
242         /* Fixup virt_offset */
243         movl    %ebp, virt_offset
244
245         /* Load the move parameters */
246         movl    $_text, %esi
247         movl    $_end, %ecx
248         subl    %esi, %ecx
249
250         /* Move etherboot uses %esi, %edi, %ecx */
251         rep 
252         movsb
253
254         /* Reload the gdt */
255         cs
256         lgdt    gdtarg
257
258         /* Reload %cs */
259         ljmp    $KERN_CODE_SEG, $1f
260 1:
261         /* reload other segment registers */
262         movl    $KERN_DATA_SEG, %eax
263         movl    %eax,%ds
264         movl    %eax,%es
265         movl    %eax,%ss
266         movl    %eax,%fs
267         movl    %eax,%gs
268
269         /* Restore the callee save registers */
270         popl    %edi
271         popl    %esi
272         popl    %ebp
273
274         /* return */
275         ret
276
277 /**************************************************************************
278 XSTART32 - Transfer control to the kernel just loaded
279 **************************************************************************/
280         .globl xstart32
281 xstart32:
282         /* Save the callee save registers */
283         movl    %ebp, os_regs + 32
284         movl    %esi, os_regs + 36
285         movl    %edi, os_regs + 40
286         movl    %ebx, os_regs + 44
287
288         /* save the return address */
289         popl    %eax
290         movl    %eax, os_regs + 48
291
292         /* save the stack pointer */
293         movl    %esp, os_regs + 52
294
295         /* Get the new destination address */
296         popl    %ecx
297
298         /* Store the physical address of xend on the stack */
299         movl    $xend32, %ebx
300         addl    virt_offset, %ebx
301         pushl   %ebx
302
303         /* Store the destination address on the stack */
304         pushl   $FLAT_CODE_SEG
305         pushl   %ecx
306
307         /* Cache virt_offset */
308         movl    virt_offset, %ebp
309         
310         /* Switch to using physical addresses */
311         call    _virt_to_phys
312
313         /* Save the target stack pointer */
314         movl    %esp, os_regs + 12(%ebp)
315         leal    os_regs(%ebp), %esp
316
317         /* Store the pointer to os_regs */
318         movl    %esp, os_regs_ptr(%ebp)
319
320         /* Load my new registers */
321         popal
322         movl    (-32 + 12)(%esp), %esp
323
324         /* Jump to the new kernel
325          * The lret switches to a flat code segment
326          */
327         lret
328
329         .balign 4
330         .globl xend32
331 xend32:
332         /* Fixup %eflags */
333         nop
334         cli
335         cld
336         
337         /* Load %esp with &os_regs + virt_offset */
338         .byte   0xbc /* movl $0, %esp */
339 os_regs_ptr:
340         .long   0
341
342         /* Save the result registers */
343         addl    $32, %esp
344         pushal
345
346         /* Compute virt_offset */
347         movl    %esp, %ebp
348         subl    $os_regs, %ebp
349         
350         /* Load the stack pointer */
351         movl    52(%esp), %esp
352
353         /* Enable the virtual addresses */
354         leal    _phys_to_virt(%ebp), %eax
355         call    *%eax
356
357         /* Restore the callee save registers */
358         movl    os_regs + 32, %ebp
359         movl    os_regs + 36, %esi
360         movl    os_regs + 40, %edi
361         movl    os_regs + 44, %ebx
362         movl    os_regs + 48, %edx
363         movl    os_regs + 52, %esp
364
365         /* Get the C return value */
366         movl    os_regs + 28, %eax
367
368         jmpl    *%edx
369
370 #ifdef CONFIG_X86_64
371         .arch   sledgehammer
372 /**************************************************************************
373 XSTART_lm - Transfer control to the kernel just loaded in long mode
374 **************************************************************************/
375         .globl xstart_lm
376 xstart_lm:
377         /* Save the callee save registers */
378         pushl   %ebp
379         pushl   %esi
380         pushl   %edi
381         pushl   %ebx
382
383         /* Cache virt_offset && (virt_offset & 0xfffff000) */
384         movl    virt_offset, %ebp
385         movl    %ebp, %ebx
386         andl    $0xfffff000, %ebx
387
388         /* Switch to using physical addresses */
389         call    _virt_to_phys
390
391         /* Initialize the page tables */
392         /* Level 4 */
393         leal    0x23 + pgt_level3(%ebx), %eax
394         leal    pgt_level4(%ebx), %edi
395         movl    %eax, (%edi)
396
397         /* Level 3 */
398         leal    0x23 + pgt_level2(%ebx), %eax
399         leal    pgt_level3(%ebx), %edi
400         movl    %eax, 0x00(%edi)
401         addl    $4096, %eax
402         movl    %eax, 0x08(%edi)
403         addl    $4096, %eax
404         movl    %eax, 0x10(%edi)
405         addl    $4096, %eax
406         movl    %eax, 0x18(%edi)
407
408         /* Level 2 */
409         movl    $0xe3, %eax
410         leal    pgt_level2(%ebx), %edi
411         leal    16384(%edi), %esi
412 pgt_level2_loop:
413         movl    %eax, (%edi)
414         addl    $8, %edi
415         addl    $0x200000, %eax
416         cmp     %esi, %edi
417         jne     pgt_level2_loop
418
419         /* Point at the x86_64 page tables */
420         leal    pgt_level4(%ebx), %edi
421         movl    %edi, %cr3
422
423
424         /* Setup for the return from 64bit mode */
425         /* 64bit align the stack */
426         movl    %esp, %ebx              /* original stack pointer + 16 */
427         andl    $0xfffffff8, %esp
428
429         /* Save original stack pointer + 16 */
430         pushl   %ebx
431
432         /* Save virt_offset */
433         pushl   %ebp
434
435         /* Setup for the jmp to 64bit long mode */
436         leal    start_lm(%ebp), %eax
437         movl    %eax, 0x00 + start_lm_addr(%ebp)
438         movl    $LM_CODE_SEG, %eax
439         movl    %eax, 0x04 + start_lm_addr(%ebp)
440
441         /* Setup for the jump out of 64bit long mode */
442         leal    end_lm(%ebp), %eax
443         movl    %eax, 0x00 + end_lm_addr(%ebp)
444         movl    $FLAT_CODE_SEG, %eax
445         movl    %eax, 0x04 + end_lm_addr(%ebp)
446
447         /* Enable PAE mode */
448         movl    %cr4, %eax
449         orl     $X86_CR4_PAE, %eax
450         movl    %eax, %cr4
451
452         /* Enable long mode */
453         movl    $MSR_K6_EFER, %ecx
454         rdmsr
455         orl     $EFER_LME, %eax
456         wrmsr
457
458         /* Start paging, entering 32bit compatiblity mode */
459         movl    %cr0, %eax
460         orl     $CR0_PG, %eax
461         movl    %eax, %cr0
462
463         /* Enter 64bit long mode */
464         ljmp    *start_lm_addr(%ebp)
465         .code64
466 start_lm:
467         /* Load 64bit data segments */
468         movl    $LM_DATA_SEG, %eax
469         movl    %eax, %ds
470         movl    %eax, %es
471         movl    %eax, %ss
472
473         andq    $0xffffffff, %rbx
474         /* Get the address to jump to */
475         movl    20(%rbx), %edx
476         andq    $0xffffffff, %rdx
477         
478         /* Get the argument pointer */
479         movl    24(%rbx), %ebx
480         andq    $0xffffffff, %rbx
481
482         /* Jump to the 64bit code */
483         call    *%rdx
484
485         /* Preserve the result */
486         movl    %eax, %edx
487
488         /* Fixup %eflags */
489         cli
490         cld
491
492         /* Switch to 32bit compatibility mode */
493         ljmp    *end_lm_addr(%rip)
494
495         .code32
496 end_lm:
497         /* Disable paging */
498         movl    %cr0, %eax
499         andl    $~CR0_PG, %eax
500         movl    %eax, %cr0
501
502         /* Disable long mode */
503         movl    $MSR_K6_EFER, %ecx
504         rdmsr
505         andl    $~EFER_LME, %eax
506         wrmsr
507
508         /* Disable PAE */
509         movl    %cr4, %eax
510         andl    $~X86_CR4_PAE, %eax
511         movl    %eax, %cr4
512         
513         /* Compute virt_offset */
514         popl    %ebp
515
516         /* Compute the original stack pointer + 16 */
517         popl    %ebx
518         movl    %ebx, %esp
519
520         /* Enable the virtual addresses */
521         leal    _phys_to_virt(%ebp), %eax
522         call    *%eax
523
524         /* Restore the callee save registers */
525         popl    %ebx
526         popl    %esi
527         popl    %edi
528         popl    %ebp
529
530         /* Get the C return value */
531         movl    %edx, %eax
532
533         /* Return */
534         ret
535
536         .arch i386
537 #endif /* CONFIG_X86_64 */
538
539 /**************************************************************************
540 SETJMP - Save stack context for non-local goto
541 **************************************************************************/
542         .globl  setjmp
543 setjmp:
544         movl    4(%esp),%ecx            /* jmpbuf */
545         movl    0(%esp),%edx            /* return address */
546         movl    %edx,0(%ecx)
547         movl    %ebx,4(%ecx)
548         movl    %esp,8(%ecx)
549         movl    %ebp,12(%ecx)
550         movl    %esi,16(%ecx)
551         movl    %edi,20(%ecx)
552         movl    $0,%eax
553         ret
554
555 /**************************************************************************
556 LONGJMP - Non-local jump to a saved stack context
557 **************************************************************************/
558         .globl  longjmp
559 longjmp:
560         movl    4(%esp),%edx            /* jumpbuf */
561         movl    8(%esp),%eax            /* result */
562         movl    0(%edx),%ecx
563         movl    4(%edx),%ebx
564         movl    8(%edx),%esp
565         movl    12(%edx),%ebp
566         movl    16(%edx),%esi
567         movl    20(%edx),%edi
568         cmpl    $0,%eax
569         jne     1f
570         movl    $1,%eax
571 1:      movl    %ecx,0(%esp)
572         ret
573
574 /**************************************************************************
575 _VIRT_TO_PHYS - Transition from virtual to physical addresses
576                 Preserves all preservable registers and flags
577 **************************************************************************/
578         .globl _virt_to_phys
579 _virt_to_phys:
580         pushfl
581         pushl   %ebp
582         pushl   %eax
583         movl    virt_offset, %ebp       /* Load virt_offset */
584         addl    %ebp, 12(%esp)          /* Adjust the return address */
585
586         /* reload the code segment */
587         pushl   $FLAT_CODE_SEG
588         leal    1f(%ebp), %eax
589         pushl   %eax
590         lret
591
592 1:
593         /* reload other segment registers */
594         movl    $FLAT_DATA_SEG, %eax
595         movl    %eax, %ds
596         movl    %eax, %es       
597         movl    %eax, %ss       
598         addl    %ebp, %esp              /* Adjust the stack pointer */
599         movl    %eax, %fs       
600         movl    %eax, %gs
601
602         popl    %eax
603         popl    %ebp
604         popfl
605         ret
606
607
608 /**************************************************************************
609 _PHYS_TO_VIRT - Transition from using physical to virtual addresses
610                 Preserves all preservable registers and flags
611 **************************************************************************/
612         .globl _phys_to_virt
613 _phys_to_virt:
614         pushfl
615         pushl   %ebp
616         pushl   %eax
617
618         call    1f
619 1:      popl    %ebp
620         subl    $1b, %ebp
621         movl    %ebp, virt_offset(%ebp)
622
623         /* Fixup the gdt */
624         leal    _pmcs(%ebp), %eax
625         pushl   %eax
626         pushl   %ebp
627         call    set_seg_base
628         addl    $8, %esp
629
630         /* Fixup gdtarg */
631         leal    _gdt(%ebp), %eax
632         movl    %eax, (gdtarg+2)(%ebp)
633
634         /* Load the global descriptor table */
635         cli
636         lgdt    %cs:gdtarg(%ebp)
637         ljmp    $KERN_CODE_SEG, $1f
638 1:
639         /* reload other segment regsters */
640         movl    $KERN_DATA_SEG, %eax
641         movl    %eax, %ds
642         movl    %eax, %es       
643         movl    %eax, %ss       
644         subl    %ebp, %esp      /* Adjust the stack pointer */
645         movl    %eax, %fs       
646         movl    %eax, %gs
647
648         subl    %ebp, 12(%esp)  /* Adjust the return address */
649         popl    %eax
650         popl    %ebp
651         popfl
652         ret
653         
654
655 /**************************************************************************
656 SET_SEG_BASE - Set the base address of a segment register
657 **************************************************************************/
658         .globl set_seg_base
659 set_seg_base:
660         pushl   %eax
661         pushl   %ebx
662         movl    12(%esp), %eax          /* %eax = base address */
663         movl    16(%esp), %ebx          /* %ebx = &code_descriptor */
664         movw    %ax, (0+2)(%ebx)        /* CS base bits 0-15 */
665         movw    %ax, (8+2)(%ebx)        /* DS base bits 0-15 */
666         shrl    $16, %eax
667         movb    %al, (0+4)(%ebx)        /* CS base bits 16-23 */
668         movb    %al, (8+4)(%ebx)        /* DS base bits 16-23 */
669         movb    %ah, (0+7)(%ebx)        /* CS base bits 24-31 */
670         movb    %ah, (8+7)(%ebx)        /* DS base bits 24-31 */
671         popl    %ebx
672         popl    %eax
673         ret
674         
675 /**************************************************************************
676 GLOBAL DESCRIPTOR TABLE
677 **************************************************************************/
678         .data
679         .align  4
680
681         .globl  _gdt
682         .globl  gdtarg
683 _gdt:
684 gdtarg:
685         .word   _gdt_end - _gdt - 1     /* limit */
686         .long   _gdt                    /* addr */
687         .word   0
688
689         .globl  _pmcs
690 _pmcs:
691         /* 32 bit protected mode code segment */
692         .word   0xffff,0
693         .byte   0,0x9f,0xcf,0
694
695 _pmds:
696         /* 32 bit protected mode data segment */
697         .word   0xffff,0
698         .byte   0,0x93,0xcf,0
699
700 _rmcs:
701         /* 16 bit real mode code segment */
702         .word   0xffff,(0&0xffff)
703         .byte   (0>>16),0x9b,0x00,(0>>24)
704
705 _rmds:
706         /* 16 bit real mode data segment */
707         .word   0xffff,(0&0xffff)
708         .byte   (0>>16),0x93,0x00,(0>>24)
709
710 _pmcs2:
711         /* 32 bit protected mode code segment, base 0 */
712         .word   0xffff,0
713         .byte   0,0x9f,0xcf,0
714
715 _pmds2:
716         /* 32 bit protected mode data segment, base 0 */
717         .word   0xffff,0
718         .byte   0,0x93,0xcf,0
719
720 #ifdef CONFIG_X86_64
721 _lmcs:
722         /* 64bit long mode code segment, base 0 */
723         .word   0xffff, 0
724         .byte   0x00, 0x9f, 0xaf , 0x00
725 _lmds:
726         /* 64bit long mode data segment, base 0 */
727         .word   0xffff, 0
728         .byte   0x00, 0x93, 0xcf, 0x00
729 #endif
730 _gdt_end:
731
732         /* The initial register contents */
733         .balign 4
734         .globl initial_regs
735 initial_regs:
736         .fill 8, 4, 0
737
738         /* The virtual address offset  */       
739         .globl virt_offset
740 virt_offset:
741         .long   0
742
743         .section ".stack"
744         .p2align 3
745         /* allocate a 4K stack in the stack segment */
746         .globl  _stack
747 _stack:
748         .space 4096
749         .globl  _estack
750 _estack:
751 #ifdef CONFIG_X86_64
752         .section ".bss"
753         .p2align 12
754         /* Include a dummy space in case we are loaded badly aligned */
755         .space 4096
756         /* Reserve enough space for a page table convering 4GB with 2MB pages */
757 pgt_level4:     
758         .space 4096
759 pgt_level3:     
760         .space 4096
761 pgt_level2:     
762         .space 16384
763 start_lm_addr:
764         .space  8
765 end_lm_addr:
766         .space  8
767 #endif