Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / 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 )
9
10 /* Drag in local definitions */
11 #include "librm.h"
12
13 /* For switches to/from protected mode */
14 #define CR0_PE 1
15
16 /* Size of various C data structures */
17 #define SIZEOF_I386_SEG_REGS    12
18 #define SIZEOF_I386_REGS        32
19 #define SIZEOF_REAL_MODE_REGS   ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
20 #define SIZEOF_I386_FLAGS       4
21 #define SIZEOF_I386_ALL_REGS    ( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS )
22         
23         .arch i386
24
25 /****************************************************************************
26  * Global descriptor table
27  *
28  * Call init_librm to set up the GDT before attempting to use any
29  * protected-mode code.
30  *
31  * NOTE: This must be located before prot_to_real, otherwise gas
32  * throws a "can't handle non absolute segment in `ljmp'" error due to
33  * not knowing the value of REAL_CS when the ljmp is encountered.
34  *
35  * Note also that putting ".word gdt_end - gdt - 1" directly into
36  * gdt_limit, rather than going via gdt_length, will also produce the
37  * "non absolute segment" error.  This is most probably a bug in gas.
38  ****************************************************************************
39  */
40         .section ".data16", "aw", @progbits
41         .align 16
42 gdt:
43 gdtr:           /* The first GDT entry is unused, the GDTR can fit here. */
44 gdt_limit:              .word gdt_length - 1
45 gdt_base:               .long 0
46                         .word 0 /* padding */
47
48         .org    gdt + VIRTUAL_CS, 0
49 virtual_cs:     /* 32 bit protected mode code segment, virtual addresses */
50         .word   0xffff, 0
51         .byte   0, 0x9f, 0xcf, 0
52
53         .org    gdt + VIRTUAL_DS, 0
54 virtual_ds:     /* 32 bit protected mode data segment, virtual addresses */
55         .word   0xffff, 0
56         .byte   0, 0x93, 0xcf, 0
57         
58         .org    gdt + PHYSICAL_CS, 0
59 physical_cs:    /* 32 bit protected mode code segment, physical addresses */
60         .word   0xffff, 0
61         .byte   0, 0x9f, 0xcf, 0
62
63         .org    gdt + PHYSICAL_DS, 0
64 physical_ds:    /* 32 bit protected mode data segment, physical addresses */
65         .word   0xffff, 0
66         .byte   0, 0x93, 0xcf, 0        
67
68         .org    gdt + REAL_CS, 0
69 real_cs:        /* 16 bit real mode code segment */
70         .word   0xffff, 0
71         .byte   0, 0x9b, 0x00, 0
72
73         .org    gdt + REAL_DS   
74 real_ds:        /* 16 bit real mode data segment */
75         .word   0xffff, ( REAL_DS << 4 )
76         .byte   0, 0x93, 0x00, 0
77
78 gdt_end:
79         .equ    gdt_length, gdt_end - gdt
80
81 /****************************************************************************
82  * init_librm (real-mode far call, 16-bit real-mode far return address)
83  *
84  * Initialise the GDT ready for transitions to protected mode.
85  *
86  * Parameters:
87  *   %cs : .text16 segment
88  *   %ds : .data16 segment
89  *   %edi : Physical base of protected-mode code (virt_offset)
90  ****************************************************************************
91  */
92         .section ".text16", "ax", @progbits
93         .code16
94         .globl init_librm
95 init_librm:
96         /* Preserve registers */
97         pushl   %eax
98         pushl   %ebx
99
100         /* Store virt_offset and set up virtual_cs and virtual_ds segments */
101         movl    %edi, %eax
102         movw    $virtual_cs, %bx
103         call    set_seg_base
104         movw    $virtual_ds, %bx
105         call    set_seg_base    
106         movl    %edi, rm_virt_offset
107
108         /* Negate virt_offset */
109         negl    %edi
110                 
111         /* Store rm_cs and text16, set up real_cs segment */
112         xorl    %eax, %eax
113         movw    %cs, %ax
114         movw    %ax, %cs:rm_cs
115         shll    $4, %eax
116         movw    $real_cs, %bx
117         call    set_seg_base
118         addr32 leal     (%eax, %edi), %ebx
119         movl    %ebx, rm_text16
120
121         /* Store rm_ds and data16 */
122         xorl    %eax, %eax
123         movw    %ds, %ax
124         movw    %ax, %cs:rm_ds
125         shll    $4, %eax
126         addr32 leal     (%eax, %edi), %ebx
127         movl    %ebx, rm_data16
128
129         /* Set GDT base */
130         movl    %eax, gdt_base
131         addl    $gdt, gdt_base
132
133         /* Initialise IDT */
134         pushl   $init_idt
135         pushw   %cs
136         call    prot_call
137         popl    %eax /* discard */
138
139         /* Restore registers */
140         negl    %edi
141         popl    %ebx
142         popl    %eax
143         lret
144
145         .section ".text16", "ax", @progbits
146         .code16
147 set_seg_base:
148 1:      movw    %ax, 2(%bx)
149         rorl    $16, %eax
150         movb    %al, 4(%bx)
151         movb    %ah, 7(%bx)
152         roll    $16, %eax
153         ret
154
155 /****************************************************************************
156  * real_to_prot (real-mode near call, 32-bit virtual return address)
157  *
158  * Switch from 16-bit real-mode to 32-bit protected mode with virtual
159  * addresses.  The real-mode %ss:sp is stored in rm_ss and rm_sp, and
160  * the protected-mode %esp is restored from the saved pm_esp.
161  * Interrupts are disabled.  All other registers may be destroyed.
162  *
163  * The return address for this function should be a 32-bit virtual
164  * address.
165  *
166  * Parameters: 
167  *   %ecx : number of bytes to move from RM stack to PM stack
168  *
169  ****************************************************************************
170  */
171         .section ".text16", "ax", @progbits
172         .code16
173 real_to_prot:
174         /* Enable A20 line */
175         call    enable_a20
176         /* A failure at this point is fatal, and there's nothing we
177          * can do about it other than lock the machine to make the
178          * problem immediately visible.
179          */
180 1:      jc      1b
181
182         /* Make sure we have our data segment available */
183         movw    %cs:rm_ds, %ax
184         movw    %ax, %ds
185
186         /* Add virt_offset, text16 and data16 to stack to be
187          * copied, and also copy the return address.
188          */
189         pushl   rm_virt_offset
190         pushl   rm_text16
191         pushl   rm_data16
192         addw    $16, %cx /* %ecx must be less than 64kB anyway */
193
194         /* Real-mode %ss:%sp => %ebp:%edx and virtual address => %esi */
195         xorl    %ebp, %ebp
196         movw    %ss, %bp
197         movzwl  %sp, %edx
198         movl    %ebp, %eax
199         shll    $4, %eax
200         addr32 leal (%eax,%edx), %esi
201         subl    rm_virt_offset, %esi
202
203         /* Load protected-mode global descriptor table */
204         data32 lgdt gdtr
205
206         /* Zero segment registers.  This wastes around 12 cycles on
207          * real hardware, but saves a substantial number of emulated
208          * instructions under KVM.
209          */
210         xorw    %ax, %ax
211         movw    %ax, %ds
212         movw    %ax, %es
213         movw    %ax, %fs
214         movw    %ax, %gs
215         movw    %ax, %ss
216
217         /* Switch to protected mode */
218         cli
219         movl    %cr0, %eax
220         orb     $CR0_PE, %al
221         movl    %eax, %cr0
222         data32 ljmp     $VIRTUAL_CS, $r2p_pmode
223         .section ".text", "ax", @progbits
224         .code32
225 r2p_pmode:
226         /* Set up protected-mode data segments and stack pointer */
227         movw    $VIRTUAL_DS, %ax
228         movw    %ax, %ds
229         movw    %ax, %es
230         movw    %ax, %fs
231         movw    %ax, %gs
232         movw    %ax, %ss
233         movl    pm_esp, %esp
234
235         /* Load protected-mode interrupt descriptor table */
236         lidt    idtr
237
238         /* Record real-mode %ss:sp (after removal of data) */
239         movw    %bp, rm_ss
240         addl    %ecx, %edx
241         movw    %dx, rm_sp
242
243         /* Move data from RM stack to PM stack */
244         subl    %ecx, %esp
245         movl    %esp, %edi
246         rep movsb
247
248         /* Publish virt_offset, text16 and data16 for PM code to use */
249         popl    data16
250         popl    text16
251         popl    virt_offset
252
253         /* Return to virtual address */
254         ret
255
256 /****************************************************************************
257  * prot_to_real (protected-mode near call, 32-bit real-mode return address)
258  *
259  * Switch from 32-bit protected mode with virtual addresses to 16-bit
260  * real mode.  The protected-mode %esp is stored in pm_esp and the
261  * real-mode %ss:sp is restored from the saved rm_ss and rm_sp.  The
262  * high word of the real-mode %esp is set to zero.  All real-mode data
263  * segment registers are loaded from the saved rm_ds.  Interrupts are
264  * *not* enabled, since we want to be able to use prot_to_real in an
265  * ISR.  All other registers may be destroyed.
266  *
267  * The return address for this function should be a 32-bit (sic)
268  * real-mode offset within .code16.
269  *
270  * Parameters: 
271  *   %ecx : number of bytes to move from PM stack to RM stack
272  *   %esi : real-mode global and interrupt descriptor table registers
273  *
274  ****************************************************************************
275  */
276         .section ".text", "ax", @progbits
277         .code32
278 prot_to_real:
279         /* Copy real-mode global descriptor table register to RM code segment */
280         movl    text16, %edi
281         leal    rm_gdtr(%edi), %edi
282         movsw
283         movsl
284
285         /* Load real-mode interrupt descriptor table register */
286         lidt    (%esi)
287
288         /* Add return address to data to be moved to RM stack */
289         addl    $4, %ecx
290         
291         /* Real-mode %ss:sp => %ebp:edx and virtual address => %edi */
292         movzwl  rm_ss, %ebp
293         movzwl  rm_sp, %edx
294         subl    %ecx, %edx
295         movl    %ebp, %eax
296         shll    $4, %eax
297         leal    (%eax,%edx), %edi
298         subl    virt_offset, %edi
299         
300         /* Move data from PM stack to RM stack */
301         movl    %esp, %esi
302         rep movsb
303         
304         /* Record protected-mode %esp (after removal of data) */
305         movl    %esi, pm_esp
306
307         /* Load real-mode segment limits */
308         movw    $REAL_DS, %ax
309         movw    %ax, %ds
310         movw    %ax, %es
311         movw    %ax, %fs
312         movw    %ax, %gs
313         movw    %ax, %ss
314         ljmp    $REAL_CS, $p2r_rmode
315         .section ".text16", "ax", @progbits
316         .code16
317 p2r_rmode:
318         /* Load real-mode GDT */
319         data32 lgdt %cs:rm_gdtr
320         /* Switch to real mode */
321         movl    %cr0, %eax
322         andb    $0!CR0_PE, %al
323         movl    %eax, %cr0
324 p2r_ljmp_rm_cs:
325         ljmp    $0, $1f
326 1:
327         /* Set up real-mode data segments and stack pointer */
328         movw    %cs:rm_ds, %ax
329         movw    %ax, %ds
330         movw    %ax, %es
331         movw    %ax, %fs
332         movw    %ax, %gs
333         movw    %bp, %ss
334         movl    %edx, %esp
335
336         /* Return to real-mode address */
337         data32 ret
338
339
340         /* Real-mode code and data segments.  Assigned by the call to
341          * init_librm.  rm_cs doubles as the segment part of the jump
342          * instruction used by prot_to_real.  Both are located in
343          * .text16 rather than .data16: rm_cs since it forms part of
344          * the jump instruction within the code segment, and rm_ds
345          * since real-mode code needs to be able to locate the data
346          * segment with no other reference available.
347          */
348         .globl rm_cs
349         .equ    rm_cs, ( p2r_ljmp_rm_cs + 3 )
350
351         .section ".text16.data", "aw", @progbits
352         .globl rm_ds
353 rm_ds:  .word 0
354
355         /* Real-mode global and interrupt descriptor table registers */
356         .section ".text16.data", "aw", @progbits
357 rm_gdtr:
358         .word 0 /* Limit */
359         .long 0 /* Base */
360
361 /****************************************************************************
362  * prot_call (real-mode far call, 16-bit real-mode far return address)
363  *
364  * Call a specific C function in the protected-mode code.  The
365  * prototype of the C function must be
366  *   void function ( struct i386_all_regs *ix86 ); 
367  * ix86 will point to a struct containing the real-mode registers
368  * at entry to prot_call.  
369  *
370  * All registers will be preserved across prot_call(), unless the C
371  * function explicitly overwrites values in ix86.  Interrupt status
372  * and GDT will also be preserved.  Gate A20 will be enabled.
373  *
374  * Note that prot_call() does not rely on the real-mode stack
375  * remaining intact in order to return, since everything relevant is
376  * copied to the protected-mode stack for the duration of the call.
377  * In particular, this means that a real-mode prefix can make a call
378  * to main() which will return correctly even if the prefix's stack
379  * gets vapourised during the Etherboot run.  (The prefix cannot rely
380  * on anything else on the stack being preserved, so should move any
381  * critical data to registers before calling main()).
382  *
383  * Parameters:
384  *   function : virtual address of protected-mode function to call
385  *
386  * Example usage:
387  *      pushl   $pxe_api_call
388  *      call    prot_call
389  *      addw    $4, %sp
390  * to call in to the C function
391  *      void pxe_api_call ( struct i386_all_regs *ix86 );
392  ****************************************************************************
393  */
394
395 #define PC_OFFSET_GDT ( 0 )
396 #define PC_OFFSET_IDT ( PC_OFFSET_GDT + 6 )
397 #define PC_OFFSET_IX86 ( PC_OFFSET_IDT + 6 )
398 #define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
399 #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
400 #define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 )
401
402         .section ".text16", "ax", @progbits
403         .code16
404         .globl prot_call
405 prot_call:
406         /* Preserve registers, flags and GDT on external RM stack */
407         pushfl
408         pushal
409         pushw   %gs
410         pushw   %fs
411         pushw   %es
412         pushw   %ds
413         pushw   %ss
414         pushw   %cs
415         subw    $PC_OFFSET_IX86, %sp
416         movw    %sp, %bp
417         sidt    PC_OFFSET_IDT(%bp)
418         sgdt    PC_OFFSET_GDT(%bp)
419
420         /* For sanity's sake, clear the direction flag as soon as possible */
421         cld
422
423         /* Switch to protected mode and move register dump to PM stack */
424         movl    $PC_OFFSET_END, %ecx
425         pushl   $pc_pmode
426         jmp     real_to_prot
427         .section ".text", "ax", @progbits
428         .code32
429 pc_pmode:
430         /* Call function */
431         leal    PC_OFFSET_IX86(%esp), %eax
432         pushl   %eax
433         call    *(PC_OFFSET_FUNCTION+4)(%esp)
434         popl    %eax /* discard */
435
436         /* Switch to real mode and move register dump back to RM stack */
437         movl    $PC_OFFSET_END, %ecx
438         movl    %esp, %esi
439         pushl   $pc_rmode
440         jmp     prot_to_real
441         .section ".text16", "ax", @progbits
442         .code16
443 pc_rmode:
444         /* Restore registers and flags and return */
445         addw    $( PC_OFFSET_IX86 + 4 /* also skip %cs and %ss */ ), %sp
446         popw    %ds
447         popw    %es
448         popw    %fs
449         popw    %gs
450         popal
451         /* popal skips %esp.  We therefore want to do "movl -20(%sp),
452          * %esp", but -20(%sp) is not a valid 80386 expression.
453          * Fortunately, prot_to_real() zeroes the high word of %esp, so
454          * we can just use -20(%esp) instead.
455          */
456         addr32 movl -20(%esp), %esp
457         popfl
458         lret
459
460 /****************************************************************************
461  * real_call (protected-mode near call, 32-bit virtual return address)
462  *
463  * Call a real-mode function from protected-mode code.
464  *
465  * The non-segment register values will be passed directly to the
466  * real-mode code.  The segment registers will be set as per
467  * prot_to_real.  The non-segment register values set by the real-mode
468  * function will be passed back to the protected-mode caller.  A
469  * result of this is that this routine cannot be called directly from
470  * C code, since it clobbers registers that the C ABI expects the
471  * callee to preserve.
472  *
473  * librm.h defines a convenient macro REAL_CODE() for using real_call.
474  * See librm.h and realmode.h for details and examples.
475  *
476  * Parameters:
477  *   (32-bit) near pointer to real-mode function to call
478  *
479  * Returns: none
480  ****************************************************************************
481  */
482
483 #define RC_OFFSET_PRESERVE_REGS ( 0 )
484 #define RC_OFFSET_RETADDR ( RC_OFFSET_PRESERVE_REGS + SIZEOF_I386_REGS )
485 #define RC_OFFSET_FUNCTION ( RC_OFFSET_RETADDR + 4 )
486 #define RC_OFFSET_END ( RC_OFFSET_FUNCTION + 4 )
487
488         .section ".text", "ax", @progbits
489         .code32
490         .globl real_call
491 real_call:
492         /* Create register dump and function pointer copy on PM stack */
493         pushal
494         pushl   RC_OFFSET_FUNCTION(%esp)
495
496         /* Switch to real mode and move register dump to RM stack  */
497         movl    $( RC_OFFSET_RETADDR + 4 /* function pointer copy */ ), %ecx
498         pushl   $rc_rmode
499         movl    $rm_default_gdtr_idtr, %esi
500         jmp     prot_to_real
501         .section ".text16", "ax", @progbits
502         .code16
503 rc_rmode:
504         /* Call real-mode function */
505         popl    rc_function
506         popal
507         call    *rc_function
508         pushal
509
510         /* For sanity's sake, clear the direction flag as soon as possible */
511         cld
512
513         /* Switch to protected mode and move register dump back to PM stack */
514         movl    $RC_OFFSET_RETADDR, %ecx
515         pushl   $rc_pmode
516         jmp     real_to_prot
517         .section ".text", "ax", @progbits
518         .code32
519 rc_pmode:
520         /* Restore registers and return */
521         popal
522         ret
523
524
525         /* Function vector, used because "call xx(%sp)" is not a valid
526          * 16-bit expression.
527          */
528         .section ".data16", "aw", @progbits
529 rc_function:    .word 0, 0
530
531         /* Default real-mode global and interrupt descriptor table registers */
532         .section ".data", "aw", @progbits
533 rm_default_gdtr_idtr:
534         .word 0         /* Global descriptor table limit */
535         .long 0         /* Global descriptor table base */
536         .word 0x03ff    /* Interrupt descriptor table limit */
537         .long 0         /* Interrupt descriptor table base */
538
539 /****************************************************************************
540  * flatten_real_mode (real-mode near call)
541  *
542  * Switch to flat real mode
543  *
544  ****************************************************************************
545  */
546         .section ".text16", "ax", @progbits
547         .code16
548         .globl flatten_real_mode
549 flatten_real_mode:
550         /* Modify GDT to use flat real mode */
551         movb    $0x8f, real_cs + 6
552         movb    $0x8f, real_ds + 6
553         /* Call dummy protected-mode function */
554         pushl   $flatten_dummy
555         pushw   %cs
556         call    prot_call
557         addw    $4, %sp
558         /* Restore GDT */
559         movb    $0x00, real_cs + 6
560         movb    $0x00, real_ds + 6
561         /* Return */
562         ret
563
564         .section ".text", "ax", @progbits
565         .code32
566 flatten_dummy:
567         ret
568
569 /****************************************************************************
570  * Interrupt wrapper
571  *
572  * Used by the protected-mode interrupt vectors to call the
573  * interrupt() function.
574  *
575  * May be entered with either physical or virtual stack segment.
576  ****************************************************************************
577  */
578         .globl interrupt_wrapper
579 interrupt_wrapper:
580         /* Preserve segment registers and original %esp */
581         pushl   %ds
582         pushl   %es
583         pushl   %fs
584         pushl   %gs
585         pushl   %ss
586         pushl   %esp
587
588         /* Switch to virtual addressing */
589         call    _intr_to_virt
590
591         /* Expand IRQ number to whole %eax register */
592         movzbl  %al, %eax
593
594         /* Call interrupt handler */
595         call    interrupt
596
597         /* Restore original stack and segment registers */
598         lss     (%esp), %esp
599         popl    %ss
600         popl    %gs
601         popl    %fs
602         popl    %es
603         popl    %ds
604
605         /* Restore registers and return */
606         popal
607         iret
608
609 /****************************************************************************
610  * Stored real-mode and protected-mode stack pointers
611  *
612  * The real-mode stack pointer is stored here whenever real_to_prot
613  * is called and restored whenever prot_to_real is called.  The
614  * converse happens for the protected-mode stack pointer.
615  *
616  * Despite initial appearances this scheme is, in fact re-entrant,
617  * because program flow dictates that we always return via the point
618  * we left by.  For example:
619  *    PXE API call entry
620  *  1   real => prot
621  *        ...
622  *        Print a text string
623  *          ...
624  *  2       prot => real
625  *            INT 10
626  *  3       real => prot
627  *          ...
628  *        ...
629  *  4   prot => real
630  *    PXE API call exit
631  *
632  * At point 1, the RM mode stack value, say RPXE, is stored in
633  * rm_ss,sp.  We want this value to still be present in rm_ss,sp when
634  * we reach point 4.
635  *
636  * At point 2, the RM stack value is restored from RPXE.  At point 3,
637  * the RM stack value is again stored in rm_ss,sp.  This *does*
638  * overwrite the RPXE that we have stored there, but it's the same
639  * value, since the code between points 2 and 3 has managed to return
640  * to us.
641  ****************************************************************************
642  */
643         .section ".data", "aw", @progbits
644         .globl rm_sp
645 rm_sp:  .word 0
646         .globl rm_ss
647 rm_ss:  .word 0
648 pm_esp: .long _estack
649
650 /****************************************************************************
651  * Virtual address offsets
652  *
653  * These are used by the protected-mode code to map between virtual
654  * and physical addresses, and to access variables in the .text16 or
655  * .data16 segments.
656  ****************************************************************************
657  */
658         /* Internal copies, created by init_librm (which runs in real mode) */
659         .section ".data16", "aw", @progbits
660 rm_virt_offset: .long 0
661 rm_text16:      .long 0
662 rm_data16:      .long 0
663
664         /* Externally-visible copies, created by real_to_prot */
665         .section ".data", "aw", @progbits
666         .globl virt_offset
667 virt_offset:    .long 0 
668         .globl text16
669 text16:         .long 0
670         .globl data16
671 data16:         .long 0