Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / prefix / pxeprefix.S
1 FILE_LICENCE ( GPL2_OR_LATER )
2
3 #define PXENV_UNDI_SHUTDOWN             0x0005
4 #define PXENV_UNDI_GET_NIC_TYPE         0x0012
5 #define PXENV_UNDI_GET_IFACE_INFO       0x0013
6 #define PXENV_STOP_UNDI                 0x0015
7 #define PXENV_UNLOAD_STACK              0x0070
8 #define PXENV_GET_CACHED_INFO           0x0071
9 #define PXENV_PACKET_TYPE_DHCP_ACK              0x0002
10 #define PXENV_FILE_CMDLINE              0x00e8
11
12 #define PXE_HACK_EB54                   0x0001
13
14         .text
15         .arch i386
16         .org 0
17         .code16
18
19 #include <undi.h>
20
21 #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
22 #define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) )
23 #define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) )
24
25 /* Prefix memory layout:
26  *
27  *     iPXE binary image
28  *     Temporary stack
29  *     Temporary copy of DHCPACK packet
30  *     Temporary copy of command line
31  */
32 #define PREFIX_STACK_SIZE 2048
33 #define PREFIX_TEMP_DHCPACK PREFIX_STACK_SIZE
34 #define PREFIX_TEMP_DHCPACK_SIZE ( 1260 /* sizeof ( BOOTPLAYER_t ) */ )
35 #define PREFIX_TEMP_CMDLINE ( PREFIX_TEMP_DHCPACK + PREFIX_TEMP_DHCPACK_SIZE )
36 #define PREFIX_TEMP_CMDLINE_SIZE 4096
37
38 /*****************************************************************************
39  * Entry point: set operating context, print welcome message
40  *****************************************************************************
41  */
42         .section ".prefix", "ax", @progbits
43         .globl  _pxe_start
44 _pxe_start:
45         jmp     $0x7c0, $1f
46 1:
47         /* Preserve registers for possible return to PXE */
48         pushfl
49         pushal
50         pushw   %gs
51         pushw   %fs
52         pushw   %es
53         pushw   %ds
54
55         /* Store magic word on PXE stack and remember PXE %ss:esp */
56         pushl   $STACK_MAGIC
57         movw    %ss, %cs:pxe_ss
58         movl    %esp, %cs:pxe_esp
59
60         /* Set up segments */
61         movw    %cs, %ax
62         movw    %ax, %ds
63         movw    $0x40, %ax              /* BIOS data segment access */
64         movw    %ax, %fs
65         /* Set up temporary stack immediately after the iPXE image */
66         movw    %cs, %ax
67         addw    image_size_pgh, %ax
68         movw    %ax, %ss
69         movl    $PREFIX_STACK_SIZE, %esp
70         /* Clear direction flag, for the sake of sanity */
71         cld
72         /* Print welcome message */
73         movw    $10f, %si
74         xorw    %di, %di
75         call    print_message
76         .section ".prefix.data", "aw", @progbits
77 10:     .asciz  "PXE->EB:"
78         .previous
79
80         /* Image size (for stack placement calculation) */
81         .section ".prefix.data", "aw", @progbits
82 image_size_pgh:
83         .word   0
84         .previous
85         .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
86         .ascii  "ADDW"
87         .long   image_size_pgh
88         .long   16
89         .long   0
90         .previous
91
92 /*****************************************************************************
93  * Find us a usable !PXE or PXENV+ entry point
94  *****************************************************************************
95  */
96 detect_pxe:
97         /* Plan A: !PXE pointer from the stack */
98         lgsl    pxe_esp, %ebp           /* %gs:%bp -> original stack */
99         lesw    %gs:52(%bp), %bx
100         call    is_valid_ppxe
101         je      have_ppxe
102
103         /* Plan B: PXENV+ pointer from initial ES:BX */
104         movw    %gs:32(%bp),%bx
105         movw    %gs:8(%bp),%es
106         call    is_valid_pxenv
107         je      have_pxenv
108
109         /* Plan C: PXENV+ structure via INT 1Ah */
110         movw    $0x5650, %ax
111         int     $0x1a
112         jc      1f
113         cmpw    $0x564e, %ax
114         jne     1f
115         call    is_valid_pxenv
116         je      have_pxenv
117 1:
118         /* Plan D: scan base memory for !PXE */
119         call    memory_scan_ppxe
120         je      have_ppxe
121
122         /* Plan E: scan base memory for PXENV+ */
123         call    memory_scan_pxenv
124         jne     stack_not_found
125         
126 have_pxenv:
127         movw    %bx, pxenv_offset
128         movw    %es, pxenv_segment
129
130         cmpw    $0x201, %es:6(%bx)      /* API version >= 2.01 */
131         jb      1f
132         cmpb    $0x2c, %es:8(%bx)       /* ... and structure long enough */
133         jb      2f
134
135         lesw    %es:0x28(%bx), %bx      /* Find !PXE from PXENV+ */
136         call    is_valid_ppxe
137         je      have_ppxe
138 2:
139         call    memory_scan_ppxe        /* We are *supposed* to have !PXE... */
140         je      have_ppxe
141 1:
142         lesw    pxenv_segoff, %bx       /* Nope, we're stuck with PXENV+ */
143
144         /* Record entry point and UNDI segments */
145         pushl   %es:0x0a(%bx)           /* Entry point */
146         pushw   %es:0x24(%bx)           /* UNDI code segment */
147         pushw   %es:0x26(%bx)           /* UNDI code size */
148         pushw   %es:0x20(%bx)           /* UNDI data segment */
149         pushw   %es:0x22(%bx)           /* UNDI data size */
150
151         /* Print "PXENV+ at <address>" */
152         movw    $10f, %si
153         jmp     check_have_stack
154         .section ".prefix.data", "aw", @progbits
155 10:     .asciz  " PXENV+ at "
156         .previous
157
158 have_ppxe:
159         movw    %bx, ppxe_offset
160         movw    %es, ppxe_segment
161         
162         pushl   %es:0x10(%bx)           /* Entry point */
163         pushw   %es:0x30(%bx)           /* UNDI code segment */
164         pushw   %es:0x36(%bx)           /* UNDI code size */
165         pushw   %es:0x28(%bx)           /* UNDI data segment */
166         pushw   %es:0x2e(%bx)           /* UNDI data size */
167
168         /* Print "!PXE at <address>" */
169         movw    $10f, %si
170         jmp     check_have_stack
171         .section ".prefix.data", "aw", @progbits
172 10:     .asciz  " !PXE at "
173         .previous
174
175 is_valid_ppxe:
176         cmpl    $0x45585021, %es:(%bx)
177         jne     1f
178         movzbw  %es:4(%bx), %cx
179         cmpw    $0x58, %cx
180         jae     is_valid_checksum
181 1:
182         ret
183         
184 is_valid_pxenv:
185         cmpl    $0x4e455850, %es:(%bx)
186         jne     1b
187         cmpw    $0x2b56, %es:4(%bx)
188         jne     1b
189         movzbw  %es:8(%bx), %cx
190         cmpw    $0x28, %cx
191         jb      1b
192         
193 is_valid_checksum:
194         pushw   %ax
195         movw    %bx, %si
196         xorw    %ax, %ax
197 2:
198         es lodsb
199         addb    %al, %ah
200         loopw   2b
201         popw    %ax
202         ret
203
204 memory_scan_ppxe:
205         movw    $is_valid_ppxe, %dx
206         jmp     memory_scan_common
207
208 memory_scan_pxenv:
209         movw    $is_valid_pxenv, %dx
210
211 memory_scan_common:
212         movw    %fs:(0x13), %ax
213         shlw    $6, %ax
214         decw    %ax
215 1:      incw    %ax
216         cmpw    $( 0xa000 - 1 ), %ax
217         ja      2f
218         movw    %ax, %es
219         xorw    %bx, %bx
220         call    *%dx
221         jne     1b
222 2:      ret
223         
224 /*****************************************************************************
225  * Sanity check: we must have an entry point
226  *****************************************************************************
227  */
228 check_have_stack:
229         /* Save common values pushed onto the stack */
230         popl    undi_data_segoff
231         popl    undi_code_segoff
232         popl    entry_segoff
233
234         /* Print have !PXE/PXENV+ message; structure pointer in %es:%bx */
235         call    print_message
236         call    print_segoff
237         movb    $( ',' ), %al
238         call    print_character
239
240         /* Check for entry point */
241         movl    entry_segoff, %eax
242         testl   %eax, %eax
243         jnz     99f
244         /* No entry point: print message and skip everything else */
245 stack_not_found:
246         movw    $10f, %si
247         call    print_message
248         jmp     finished
249         .section ".prefix.data", "aw", @progbits
250 10:     .asciz  " No PXE stack found!\n"
251         .previous
252 99:     
253
254 /*****************************************************************************
255  * Calculate base memory usage by UNDI
256  *****************************************************************************
257  */
258 find_undi_basemem_usage:
259         movw    undi_code_segment, %ax
260         movw    undi_code_size, %bx
261         movw    undi_data_segment, %cx
262         movw    undi_data_size, %dx
263         cmpw    %ax, %cx
264         ja      1f
265         xchgw   %ax, %cx
266         xchgw   %bx, %dx
267 1:      /* %ax:%bx now describes the lower region, %cx:%dx the higher */
268         shrw    $6, %ax                 /* Round down to nearest kB */
269         movw    %ax, undi_fbms_start
270         addw    $0x0f, %dx              /* Round up to next segment */
271         shrw    $4, %dx
272         addw    %dx, %cx
273         addw    $((1024 / 16) - 1), %cx /* Round up to next kB */
274         shrw    $6, %cx
275         movw    %cx, undi_fbms_end
276
277 /*****************************************************************************
278  * Print information about detected PXE stack
279  *****************************************************************************
280  */
281 print_structure_information:
282         /* Print entry point */
283         movw    $10f, %si
284         call    print_message
285         les     entry_segoff, %bx
286         call    print_segoff
287         .section ".prefix.data", "aw", @progbits
288 10:     .asciz  " entry point at "
289         .previous
290         /* Print UNDI code segment */
291         movw    $10f, %si
292         call    print_message
293         les     undi_code_segoff, %bx
294         call    print_segoff
295         .section ".prefix.data", "aw", @progbits
296 10:     .asciz  "\n         UNDI code segment "
297         .previous
298         /* Print UNDI data segment */
299         movw    $10f, %si
300         call    print_message
301         les     undi_data_segoff, %bx
302         call    print_segoff
303         .section ".prefix.data", "aw", @progbits
304 10:     .asciz  ", data segment "
305         .previous
306         /* Print UNDI memory usage */
307         movw    $10f, %si
308         call    print_message
309         movw    undi_fbms_start, %ax
310         call    print_word
311         movb    $( '-' ), %al
312         call    print_character
313         movw    undi_fbms_end, %ax
314         call    print_word
315         movw    $20f, %si
316         call    print_message
317         .section ".prefix.data", "aw", @progbits
318 10:     .asciz  " ("
319 20:     .asciz  "kB)\n"
320         .previous
321
322 /*****************************************************************************
323  * Determine physical device
324  *****************************************************************************
325  */
326 get_physical_device:
327         /* Issue PXENV_UNDI_GET_NIC_TYPE */
328         movw    $PXENV_UNDI_GET_NIC_TYPE, %bx
329         call    pxe_call
330         jnc     1f
331         call    print_pxe_error
332         jmp     no_physical_device
333 1:      /* Determine physical device type */
334         movb    ( pxe_parameter_structure + 0x02 ), %al
335         cmpb    $2, %al
336         je      pci_physical_device
337         jmp     no_physical_device
338
339 pci_physical_device:
340         /* Record PCI bus:dev.fn and vendor/device IDs */
341         movl    ( pxe_parameter_structure + 0x03 ), %eax
342         movl    %eax, pci_vendor
343         movw    ( pxe_parameter_structure + 0x0b ), %ax
344         movw    %ax, pci_busdevfn
345         movw    $10f, %si
346         call    print_message
347         call    print_pci_busdevfn
348         jmp     99f
349         .section ".prefix.data", "aw", @progbits
350 10:     .asciz  "         UNDI device is PCI "
351         .previous
352
353 no_physical_device:
354         /* No device found, or device type not understood */
355         movw    $10f, %si
356         call    print_message
357         .section ".prefix.data", "aw", @progbits
358 10:     .asciz  "         Unable to determine UNDI physical device"
359         .previous
360
361 99:
362
363 /*****************************************************************************
364  * Determine interface type
365  *****************************************************************************
366  */
367 get_iface_type:
368         /* Issue PXENV_UNDI_GET_IFACE_INFO */
369         movw    $PXENV_UNDI_GET_IFACE_INFO, %bx
370         call    pxe_call
371         jnc     1f
372         call    print_pxe_error
373         jmp     99f
374 1:      /* Print interface type */
375         movw    $10f, %si
376         call    print_message
377         leaw    ( pxe_parameter_structure + 0x02 ), %si
378         call    print_message
379         .section ".prefix.data", "aw", @progbits
380 10:     .asciz  ", type "
381         .previous
382         /* Check for "Etherboot" interface type */
383         cmpl    $EB_MAGIC_1, ( pxe_parameter_structure + 0x02 )
384         jne     99f
385         cmpl    $EB_MAGIC_2, ( pxe_parameter_structure + 0x06 )
386         jne     99f
387         movw    $10f, %si
388         call    print_message
389         .section ".prefix.data", "aw", @progbits
390 10:     .asciz  " (workaround enabled)"
391         .previous
392         /* Flag Etherboot workarounds as required */
393         orw     $PXE_HACK_EB54, pxe_hacks
394
395 99:     movb    $0x0a, %al
396         call    print_character
397
398 /*****************************************************************************
399  * Get cached DHCP_ACK packet
400  *****************************************************************************
401  */
402 get_dhcpack:
403         /* Issue PXENV_GET_CACHED_INFO */
404         xorl    %esi, %esi
405         movw    %ss, %si
406         movw    %si, ( pxe_parameter_structure + 0x08 )
407         movw    $PREFIX_TEMP_DHCPACK, ( pxe_parameter_structure + 0x06 )
408         movw    $PREFIX_TEMP_DHCPACK_SIZE, ( pxe_parameter_structure +0x04 )
409         movw    $PXENV_PACKET_TYPE_DHCP_ACK, ( pxe_parameter_structure + 0x02 )
410         movw    $PXENV_GET_CACHED_INFO, %bx
411         call    pxe_call
412         jnc     1f
413         call    print_pxe_error
414         jmp     99f
415 1:      /* Store physical address of packet */
416         shll    $4, %esi
417         addl    $PREFIX_TEMP_DHCPACK, %esi
418         movl    %esi, pxe_cached_dhcpack
419 99:
420         .section ".prefix.data", "aw", @progbits
421 pxe_cached_dhcpack:
422         .long   0
423         .previous
424
425 /*****************************************************************************
426  * Check for a command line
427  *****************************************************************************
428  */
429 get_cmdline:
430         /* Issue PXENV_FILE_CMDLINE */
431         xorl    %esi, %esi
432         movw    %ss, %si
433         movw    %si, ( pxe_parameter_structure + 0x06 )
434         movw    $PREFIX_TEMP_CMDLINE, ( pxe_parameter_structure + 0x04 )
435         movw    $PREFIX_TEMP_CMDLINE_SIZE, ( pxe_parameter_structure + 0x02 )
436         movw    $PXENV_FILE_CMDLINE, %bx
437         call    pxe_call
438         jc      99f  /* Suppress errors; this is an iPXE extension API call */
439         /* Check for non-NULL command line */
440         movw    ( pxe_parameter_structure + 0x02 ), %ax
441         testw   %ax, %ax
442         jz      99f
443         /* Record command line */
444         shll    $4, %esi
445         addl    $PREFIX_TEMP_CMDLINE, %esi
446         movl    %esi, pxe_cmdline
447 99:
448         .section ".prefix.data", "aw", @progbits
449 pxe_cmdline:
450         .long   0
451         .previous
452
453 /*****************************************************************************
454  * Leave NIC in a safe state
455  *****************************************************************************
456  */
457 #ifndef PXELOADER_KEEP_PXE
458 shutdown_nic:
459         /* Issue PXENV_UNDI_SHUTDOWN */
460         movw    $PXENV_UNDI_SHUTDOWN, %bx
461         call    pxe_call
462         jnc     1f
463         call    print_pxe_error
464 1:
465 unload_base_code:
466         /* Etherboot treats PXENV_UNLOAD_STACK as PXENV_STOP_UNDI, so
467          * we must not issue this call if the underlying stack is
468          * Etherboot and we were not intending to issue a PXENV_STOP_UNDI.
469          */
470 #ifdef PXELOADER_KEEP_UNDI
471         testw   $PXE_HACK_EB54, pxe_hacks
472         jnz     99f
473 #endif /* PXELOADER_KEEP_UNDI */
474         /* Issue PXENV_UNLOAD_STACK */
475         movw    $PXENV_UNLOAD_STACK, %bx
476         call    pxe_call
477         jnc     1f
478         call    print_pxe_error
479         jmp     99f
480 1:      /* Free base memory used by PXE base code */
481         movw    undi_fbms_start, %ax
482         movw    %fs:(0x13), %bx
483         call    free_basemem
484 99:
485         andw    $~( UNDI_FL_INITIALIZED | UNDI_FL_KEEP_ALL ), flags
486 #endif /* PXELOADER_KEEP_PXE */
487
488 /*****************************************************************************
489  * Unload UNDI driver
490  *****************************************************************************
491  */
492 #ifndef PXELOADER_KEEP_UNDI
493 unload_undi:
494         /* Issue PXENV_STOP_UNDI */
495         movw    $PXENV_STOP_UNDI, %bx
496         call    pxe_call
497         jnc     1f
498         call    print_pxe_error
499         jmp     99f
500 1:      /* Free base memory used by UNDI */
501         movw    undi_fbms_end, %ax
502         movw    undi_fbms_start, %bx
503         call    free_basemem
504         /* Clear UNDI_FL_STARTED */
505         andw    $~UNDI_FL_STARTED, flags
506 99:     
507 #endif /* PXELOADER_KEEP_UNDI */
508
509 /*****************************************************************************
510  * Print remaining free base memory
511  *****************************************************************************
512  */
513 print_free_basemem:
514         movw    $10f, %si
515         call    print_message
516         movw    %fs:(0x13), %ax
517         call    print_word
518         movw    $20f, %si
519         call    print_message
520         .section ".prefix.data", "aw", @progbits
521 10:     .asciz  "         "
522 20:     .asciz  "kB free base memory after PXE unload\n"
523         .previous
524         
525 /*****************************************************************************
526  * Exit point
527  *****************************************************************************
528  */     
529 finished:
530         jmp     run_ipxe
531
532 /*****************************************************************************
533  * Subroutine: print segment:offset address
534  *
535  * Parameters:
536  *   %es:%bx : segment:offset address to print
537  *   %ds:di : output buffer (or %di=0 to print to console)
538  * Returns:
539  *   %ds:di : next character in output buffer (if applicable)
540  *****************************************************************************
541  */
542 print_segoff:
543         /* Preserve registers */
544         pushw   %ax
545         /* Print "<segment>:offset" */
546         movw    %es, %ax
547         call    print_hex_word
548         movb    $( ':' ), %al
549         call    print_character
550         movw    %bx, %ax
551         call    print_hex_word
552         /* Restore registers and return */
553         popw    %ax
554         ret
555
556 /*****************************************************************************
557  * Subroutine: print decimal word
558  *
559  * Parameters:
560  *   %ax : word to print
561  *   %ds:di : output buffer (or %di=0 to print to console)
562  * Returns:
563  *   %ds:di : next character in output buffer (if applicable)
564  *****************************************************************************
565  */
566 print_word:
567         /* Preserve registers */
568         pushw   %ax
569         pushw   %bx
570         pushw   %cx
571         pushw   %dx
572         /* Build up digit sequence on stack */
573         movw    $10, %bx
574         xorw    %cx, %cx
575 1:      xorw    %dx, %dx
576         divw    %bx, %ax
577         pushw   %dx
578         incw    %cx
579         testw   %ax, %ax
580         jnz     1b
581         /* Print digit sequence */
582 1:      popw    %ax
583         call    print_hex_nibble
584         loop    1b
585         /* Restore registers and return */
586         popw    %dx
587         popw    %cx
588         popw    %bx
589         popw    %ax
590         ret
591         
592 /*****************************************************************************
593  * Subroutine: zero 1kB block of base memory
594  *
595  * Parameters:
596  *   %bx : block to zero (in kB)
597  * Returns:
598  *   Nothing
599  *****************************************************************************
600  */
601 zero_kb:
602         /* Preserve registers */
603         pushw   %ax
604         pushw   %cx
605         pushw   %di
606         pushw   %es
607         /* Zero block */
608         movw    %bx, %ax
609         shlw    $6, %ax
610         movw    %ax, %es
611         movw    $0x400, %cx
612         xorw    %di, %di
613         xorw    %ax, %ax
614         rep stosb
615         /* Restore registers and return */
616         popw    %es
617         popw    %di
618         popw    %cx
619         popw    %ax
620         ret
621         
622 /*****************************************************************************
623  * Subroutine: free and zero base memory
624  *
625  * Parameters:
626  *   %ax : Desired new free base memory counter (in kB)
627  *   %bx : Expected current free base memory counter (in kB)
628  *   %fs : BIOS data segment (0x40)
629  * Returns:
630  *   None
631  *
632  * The base memory from %bx kB to %ax kB is unconditionally zeroed.
633  * It will be freed if and only if the expected current free base
634  * memory counter (%bx) matches the actual current free base memory
635  * counter in 0x40:0x13; if this does not match then the memory will
636  * be leaked.
637  *****************************************************************************
638  */
639 free_basemem:
640         /* Zero base memory */
641         pushw   %bx
642 1:      cmpw    %bx, %ax
643         je      2f
644         call    zero_kb
645         incw    %bx
646         jmp     1b
647 2:      popw    %bx
648         /* Free base memory */
649         cmpw    %fs:(0x13), %bx         /* Update FBMS only if "old" value  */
650         jne     1f                      /* is correct                       */
651 1:      movw    %ax, %fs:(0x13)
652         ret
653
654 /*****************************************************************************
655  * Subroutine: make a PXE API call.  Works with either !PXE or PXENV+ API.
656  *
657  * Parameters:
658  *   %bx : PXE API call number
659  *   %ds:pxe_parameter_structure : Parameters for PXE API call
660  * Returns:
661  *   %ax : PXE status code (not exit code)
662  *   CF set if %ax is non-zero
663  *****************************************************************************
664  */
665 pxe_call:
666         /* Preserve registers */
667         pushw   %di
668         pushw   %es
669         /* Set up registers for PXENV+ API.  %bx already set up */
670         pushw   %ds
671         popw    %es
672         movw    $pxe_parameter_structure, %di
673         /* Set up stack for !PXE API */
674         pushw   %es
675         pushw   %di
676         pushw   %bx
677         /* Make the API call */
678         lcall   *entry_segoff
679         /* Reset the stack */
680         addw    $6, %sp
681         movw    pxe_parameter_structure, %ax
682         clc
683         testw   %ax, %ax
684         jz      1f
685         stc
686 1:      /* Clear direction flag, for the sake of sanity */
687         cld
688         /* Restore registers and return */
689         popw    %es
690         popw    %di
691         ret
692
693 /*****************************************************************************
694  * Subroutine: print PXE API call error message
695  *
696  * Parameters:
697  *   %ax : PXE status code
698  *   %bx : PXE API call number
699  * Returns:
700  *   Nothing
701  *****************************************************************************
702  */
703 print_pxe_error:
704         pushw   %si
705         movw    $10f, %si
706         call    print_message
707         xchgw   %ax, %bx
708         call    print_hex_word
709         movw    $20f, %si
710         call    print_message
711         xchgw   %ax, %bx
712         call    print_hex_word
713         movw    $30f, %si
714         call    print_message
715         popw    %si
716         ret
717         .section ".prefix.data", "aw", @progbits
718 10:     .asciz  "         UNDI API call "
719 20:     .asciz  " failed: status code "
720 30:     .asciz  "\n"
721         .previous
722
723 /*****************************************************************************
724  * PXE data structures
725  *****************************************************************************
726  */
727         .section ".prefix.data"
728
729 pxe_esp:                .long 0
730 pxe_ss:                 .word 0
731
732 pxe_parameter_structure: .fill 64
733
734 undi_code_segoff:
735 undi_code_size:         .word 0
736 undi_code_segment:      .word 0
737
738 undi_data_segoff:
739 undi_data_size:         .word 0
740 undi_data_segment:      .word 0
741
742 pxe_hacks:              .word 0
743
744 /* The following fields are part of a struct undi_device */
745
746 undi_device:
747
748 pxenv_segoff:
749 pxenv_offset:           .word 0
750 pxenv_segment:          .word 0
751
752 ppxe_segoff:
753 ppxe_offset:            .word 0
754 ppxe_segment:           .word 0
755         
756 entry_segoff:
757 entry_offset:           .word 0
758 entry_segment:          .word 0
759
760 undi_fbms_start:        .word 0
761 undi_fbms_end:          .word 0
762
763 pci_busdevfn:           .word UNDI_NO_PCI_BUSDEVFN
764 isapnp_csn:             .word UNDI_NO_ISAPNP_CSN
765 isapnp_read_port:       .word UNDI_NO_ISAPNP_READ_PORT
766
767 pci_vendor:             .word 0
768 pci_device:             .word 0
769 flags:
770         .word ( UNDI_FL_INITIALIZED | UNDI_FL_STARTED | UNDI_FL_KEEP_ALL )
771
772         .equ undi_device_size, ( . - undi_device )
773
774 /*****************************************************************************
775  * Run iPXE main code
776  *****************************************************************************
777  */
778         .section ".prefix"
779 run_ipxe:
780         /* Install iPXE */
781         call    install
782
783         /* Set up real-mode stack */
784         movw    %bx, %ss
785         movw    $_estack16, %sp
786
787 #ifdef PXELOADER_KEEP_UNDI
788         /* Copy our undi_device structure to the preloaded_undi variable */
789         movw    %bx, %es
790         movw    $preloaded_undi, %di
791         movw    $undi_device, %si
792         movw    $undi_device_size, %cx
793         rep movsb
794 #endif
795
796         /* Retrieve PXE %ss:esp */
797         movw    pxe_ss, %di
798         movl    pxe_esp, %ebp
799
800         /* Retrieve PXE command line, if any */
801         movl    pxe_cmdline, %esi
802
803         /* Retrieve cached DHCPACK, if any */
804         movl    pxe_cached_dhcpack, %ecx
805
806         /* Jump to .text16 segment with %ds pointing to .data16 */
807         movw    %bx, %ds
808         pushw   %ax
809         pushw   $1f
810         lret
811         .section ".text16", "ax", @progbits
812 1:
813         /* Update the exit hook */
814         movw    %cs, ( pxe_exit_hook + 2 )
815
816         /* Store command-line pointer */
817         movl    %esi, cmdline_phys
818
819         /* Store cached DHCPACK pointer */
820         movl    %ecx, cached_dhcpack_phys
821
822         /* Run main program */
823         pushl   $main
824         pushw   %cs
825         call    prot_call
826         popl    %ecx /* discard */
827
828         /* Uninstall iPXE */
829         call    uninstall
830
831         /* Restore PXE stack */
832         movw    %di, %ss
833         movl    %ebp, %esp
834
835         /* Jump to hook if applicable */
836         ljmpw   *pxe_exit_hook
837
838         .section ".data16", "aw", @progbits
839         .globl  pxe_exit_hook
840 pxe_exit_hook:
841         .word   exit_ipxe, 0
842         .previous
843
844 exit_ipxe:
845         /* Check PXE stack magic */
846         popl    %eax
847         cmpl    $STACK_MAGIC, %eax
848         jne     1f
849
850         /* PXE stack OK: return to caller */
851         popw    %ds
852         popw    %es
853         popw    %fs
854         popw    %gs
855         popal
856         popfl
857         xorw    %ax, %ax        /* Return success */
858         lret
859
860 1:      /* PXE stack corrupt or removed: use INT 18 */
861         int     $0x18
862         .previous