Adding debian version 3.70~pre8+dfsg-1.
[syslinux-debian/hramrach.git] / gpxe / src / arch / i386 / prefix / pxeprefix.S
blobd7125b6176fb22cc2544f91c890a3f8fe06d45f4
1 #define PXENV_UNDI_SHUTDOWN             0x0005
2 #define PXENV_UNDI_GET_NIC_TYPE         0x0012
3 #define PXENV_STOP_UNDI                 0x0015
4 #define PXENV_UNLOAD_STACK              0x0070
5         
6         .text
7         .arch i386
8         .org 0
9         .section ".prefix", "ax", @progbits
10         .section ".prefix.data", "aw", @progbits
11         .code16
13 #include <undi.h>
15 /*****************************************************************************
16  * Entry point: set operating context, print welcome message
17  *****************************************************************************
18  */
19         .section ".prefix"
20         /* Set up our non-stack segment registers */
21         jmp     $0x7c0, $1f
22 1:      pushfl
23         /* %ax here is the default return type... */
24         movw    $5, %ax                 /* Keep PXE+UNDI */
25         pushal
26         pushw   %ds
27         pushw   %es
28         pushw   %fs
29         pushw   %gs
30         movw    %cs, %ax
31         movw    %ax, %ds
32         
33         movw    $0x40, %ax              /* BIOS data segment access */
34         movw    %ax, %fs
36         pushw   %fs:0x13
37         /* Record PXENV+ and !PXE nominal addresses */
38         movw    %es, pxenv_segment
39         movw    %bx, pxenv_offset
40         movw    %sp, %bp
41         movw    %ss, return_stack_segment
42         movl    %esp, return_stack_offset
43         movl    50(%bp), %eax
44         movl    %eax, ppxe_segoff       /* !PXE address */
45         /* Set up stack just below 0x7c00 */
46         xorw    %ax, %ax
47         movw    %ax, %ss
48         movw    $0x7c00, %sp
49         /* Clear direction flag, for the sake of sanity */
50         cld
51         /* Print welcome message */
52         movw    $10f, %si
53         call    print_message
54         .section ".prefix.data"
55 10:     .asciz  "PXE->EB:"
56         .previous
58 /*****************************************************************************
59  * Verify PXENV+ structure and record parameters of interest
60  *****************************************************************************
61  */
62 detect_pxenv:
63         /* Signature check */
64         les     pxenv_segoff, %di
65         cmpl    $0x4e455850, %es:(%di)  /* 'PXEN' signature */
66         jne     no_pxenv
67         cmpw    $0x2b56, %es:4(%di)     /* 'V+' signature */
68         jne     no_pxenv
69         /* Record entry point and UNDI segments */
70         pushl   %es:0x0a(%di)           /* Entry point */
71         popl    entry_segoff
72         pushw   %es:0x24(%di)           /* UNDI code segment */
73         pushw   %es:0x26(%di)           /* UNDI code size */
74         popl    undi_code_segoff
75         pushw   %es:0x20(%di)           /* UNDI data segment */
76         pushw   %es:0x22(%di)           /* UNDI data size */
77         popl    undi_data_segoff
78         /* Print "PXENV+ at <address>" */
79         movw    $10f, %si
80         call    print_message
81         movw    %bx, %di
82         call    print_segoff
83         movb    $',', %al
84         call    print_character
85         jmp     99f
86         .section ".prefix.data"
87 10:     .asciz  " PXENV+ at "
88         .previous
90 no_pxenv:
91         xorl    %eax, %eax
92         movl    %eax, pxenv_segoff
93         
94 99:
95         
96 /*****************************************************************************
97  * Verify !PXE structure and record parameters of interest
98  *****************************************************************************
99  */
100 detect_ppxe:
101         /* Signature check */
102         les     ppxe_segoff, %di
103         cmpl    $0x45585021, %es:(%di)  /* '!PXE' signature */
104         jne     no_ppxe
105         /* Record structure address, entry point, and UNDI segments */
106         pushw   %es
107         popw    ppxe_segment
108         movw    %di, ppxe_offset
109         pushl   %es:0x10(%di)           /* Entry point */
110         popl    entry_segoff
111         pushw   %es:0x30(%di)           /* UNDI code segment */
112         pushw   %es:0x36(%di)           /* UNDI code size */
113         popl    undi_code_segoff
114         pushw   %es:0x28(%di)           /* UNDI data segment */
115         pushw   %es:0x2e(%di)           /* UNDI data size */
116         popl    undi_data_segoff
117         /* Print "!PXE at <address>" */
118         movw    $10f, %si
119         call    print_message
120         call    print_segoff
121         movb    $',', %al
122         call    print_character
123         jmp     99f
124         .section ".prefix.data"
125 10:     .asciz  " !PXE at "
126         .previous
128 no_ppxe:
129         xorl    %eax, %eax
130         movl    %eax, ppxe_segoff
134 /*****************************************************************************
135  * Sanity check: we must have an entry point
136  *****************************************************************************
137  */
138 check_have_stack:
139         /* Check for entry point */
140         movl    entry_segoff, %eax
141         testl   %eax, %eax
142         jnz     99f
143         /* No entry point: print message and skip everything else */
144         movw    $10f, %si
145         call    print_message
146         jmp     finished
147         .section ".prefix.data"
148 10:     .asciz  " No PXE stack found!\n"
149         .previous
150 99:     
152 /*****************************************************************************
153  * Calculate base memory usage by UNDI
154  *****************************************************************************
155  */
156 find_undi_basemem_usage:
157         movw    undi_code_segment, %ax
158         movw    undi_code_size, %bx
159         movw    undi_data_segment, %cx
160         movw    undi_data_size, %dx
161         cmpw    %ax, %cx
162         ja      1f
163         xchgw   %ax, %cx
164         xchgw   %bx, %dx
165 1:      /* %ax:%bx now describes the lower region, %cx:%dx the higher */
166         shrw    $6, %ax                 /* Round down to nearest kB */
167         movw    %ax, undi_fbms_start
168         addw    $0x0f, %dx              /* Round up to next segment */
169         shrw    $4, %dx
170         addw    %dx, %cx
171         addw    $((1024 / 16) - 1), %cx /* Round up to next kB */
172         shrw    $6, %cx
173         movw    %cx, undi_fbms_end
175 /*****************************************************************************
176  * Print information about detected PXE stack
177  *****************************************************************************
178  */
179 print_structure_information:
180         /* Print entry point */
181         movw    $10f, %si
182         call    print_message
183         les     entry_segoff, %di
184         call    print_segoff
185         .section ".prefix.data"
186 10:     .asciz  " entry point at "
187         .previous
188         /* Print UNDI code segment */
189         movw    $10f, %si
190         call    print_message
191         les     undi_code_segoff, %di
192         call    print_segoff
193         .section ".prefix.data"
194 10:     .asciz  "\n         UNDI code segment "
195         .previous
196         /* Print UNDI data segment */
197         movw    $10f, %si
198         call    print_message
199         les     undi_data_segoff, %di
200         call    print_segoff
201         .section ".prefix.data"
202 10:     .asciz  ", data segment "
203         .previous
204         /* Print UNDI memory usage */
205         movw    $10f, %si
206         call    print_message
207         movw    undi_fbms_start, %ax
208         call    print_word
209         movb    $'-', %al
210         call    print_character
211         movw    undi_fbms_end, %ax
212         call    print_word
213         movw    $20f, %si
214         call    print_message
215         .section ".prefix.data"
216 10:     .asciz  " ("
217 20:     .asciz  "kB)\n"
218         .previous
220 /*****************************************************************************
221  * Determine physical device
222  *****************************************************************************
223  */
224 get_physical_device:
225         /* Issue PXENV_UNDI_GET_NIC_TYPE */
226         movw    $PXENV_UNDI_GET_NIC_TYPE, %bx
227         call    pxe_call
228         jnc     1f
229         call    print_pxe_error
230         jmp     no_physical_device
231 1:      /* Determine physical device type */
232         movb    ( pxe_parameter_structure + 0x02 ), %al
233         cmpb    $2, %al
234         je      pci_physical_device
235         jmp     no_physical_device
237 pci_physical_device:
238         /* Record PCI bus:dev.fn and vendor/device IDs */
239         movl    ( pxe_parameter_structure + 0x03 ), %eax
240         movl    %eax, pci_vendor
241         movw    ( pxe_parameter_structure + 0x0b ), %ax
242         movw    %ax, pci_busdevfn
243         movw    $10f, %si
244         call    print_message
245         call    print_pci_busdevfn
246         movb    $0x0a, %al
247         call    print_character
248         jmp     99f
249         .section ".prefix.data"
250 10:     .asciz  "         UNDI device is PCI "
251         .previous
253 no_physical_device:
254         /* No device found, or device type not understood */
255         movw    $10f, %si
256         call    print_message
257         .section ".prefix.data"
258 10:     .asciz  "         Unable to determine UNDI physical device\n"
259         .previous
263 /*****************************************************************************
264  * Leave NIC in a safe state
265  *****************************************************************************
266  */
267 #ifndef PXELOADER_KEEP_UNDI
268 shutdown_nic:
269         /* Issue PXENV_UNDI_SHUTDOWN */
270         movw    $PXENV_UNDI_SHUTDOWN, %bx
271         call    pxe_call
272         jnc     1f
273         call    print_pxe_error
276 /*****************************************************************************
277  * Unload PXE base code
278  *****************************************************************************
279  */
280 unload_base_code:
281         /* Issue PXENV_UNLOAD_STACK */
282         movw    $PXENV_UNLOAD_STACK, %bx
283         call    pxe_call
284         jnc     1f
285         call    print_pxe_error
286         jmp     99f
287 1:      /* Free base memory used by PXE base code */
288         movw    %fs:(0x13), %si
289         movw    undi_fbms_start, %di
290         call    free_basemem
293 /*****************************************************************************
294  * Unload UNDI driver
295  *****************************************************************************
296  */
298 unload_undi:
299         /* Issue PXENV_STOP_UNDI */
300         movw    $PXENV_STOP_UNDI, %bx
301         call    pxe_call
302         jnc     1f
303         call    print_pxe_error
304         jmp     99f
305 1:      /* Free base memory used by UNDI */
306         movw    undi_fbms_start, %si
307         movw    undi_fbms_end, %di
308         call    free_basemem
309         /* Clear UNDI_FL_STARTED */
310         andw    $~UNDI_FL_STARTED, flags
311 99:     
313 /*****************************************************************************
314  * Print remaining free base memory
315  *****************************************************************************
316  */
317 print_free_basemem:
318         movw    $10f, %si
319         call    print_message
320         movw    %fs:(0x13), %ax
321         call    print_word
322         movw    $20f, %si
323         call    print_message
324         .section ".prefix.data"
325 10:     .asciz  "         "
326 20:     .asciz  "kB free base memory after PXE unload\n"
327         .previous
328 #endif /* PXELOADER_KEEP_UNDI */
329         
330 /*****************************************************************************
331  * Exit point
332  *****************************************************************************
333  */     
334 finished:
335         jmp     run_etherboot
336         
337 /*****************************************************************************
338  * Subroutine: print segment:offset address
340  * Parameters:
341  *   %es:%di : segment:offset address to print
342  * Returns:
343  *   Nothing
344  *****************************************************************************
345  */
346 print_segoff:
347         /* Preserve registers */
348         pushw   %ax
349         /* Print "<segment>:offset" */
350         movw    %es, %ax
351         call    print_hex_word
352         movb    $':', %al
353         call    print_character
354         movw    %di, %ax
355         call    print_hex_word
356         /* Restore registers and return */
357         popw    %ax
358         ret
360 /*****************************************************************************
361  * Subroutine: print decimal word
363  * Parameters:
364  *   %ax : word to print
365  * Returns:
366  *   Nothing
367  *****************************************************************************
368  */
369 print_word:
370         /* Preserve registers */
371         pushw   %ax
372         pushw   %bx
373         pushw   %cx
374         pushw   %dx
375         /* Build up digit sequence on stack */
376         movw    $10, %bx
377         xorw    %cx, %cx
378 1:      xorw    %dx, %dx
379         divw    %bx, %ax
380         pushw   %dx
381         incw    %cx
382         testw   %ax, %ax
383         jnz     1b
384         /* Print digit sequence */
385 1:      popw    %ax
386         call    print_hex_nibble
387         loop    1b
388         /* Restore registers and return */
389         popw    %dx
390         popw    %cx
391         popw    %bx
392         popw    %ax
393         ret
394         
395 /*****************************************************************************
396  * Subroutine: print PCI bus:dev.fn
398  * Parameters:
399  *   %ax : PCI bus:dev.fn to print
400  * Returns:
401  *   Nothing
402  *****************************************************************************
403  */
404 print_pci_busdevfn:
405         /* Preserve registers */
406         pushw   %ax
407         /* Print bus */
408         xchgb   %al, %ah
409         call    print_hex_byte
410         /* Print ":" */
411         movb    $':', %al
412         call    print_character
413         /* Print device */
414         movb    %ah, %al
415         shrb    $3, %al
416         call    print_hex_byte
417         /* Print "." */
418         movb    $'.', %al
419         call    print_character
420         /* Print function */
421         movb    %ah, %al
422         andb    $0x07, %al
423         call    print_hex_nibble
424         /* Restore registers and return */
425         popw    %ax
426         ret     
428 /*****************************************************************************
429  * Subroutine: zero 1kB block of base memory
431  * Parameters:
432  *   %si : block to zero (in kB)
433  * Returns:
434  *   Nothing
435  *****************************************************************************
436  */
437 zero_kb:
438         /* Preserve registers */
439         pushw   %ax
440         pushw   %cx
441         pushw   %di
442         pushw   %es
443         /* Zero block */
444         movw    %si, %ax
445         shlw    $6, %ax
446         movw    %ax, %es
447         movw    $0x400, %cx
448         xorw    %di, %di
449         xorw    %ax, %ax
450         rep stosb
451         /* Restore registers and return */
452         popw    %es
453         popw    %di
454         popw    %cx
455         popw    %ax
456         ret
457         
458 /*****************************************************************************
459  * Subroutine: free and zero base memory
461  * Parameters:
462  *   %si : Expected current free base memory counter (in kB)
463  *   %di : Desired new free base memory counter (in kB)
464  *   %fs : BIOS data segment (0x40)
465  * Returns:
466  *   %ax : Actual new free base memory counter (in kB)
468  * The base memory from %si kB to %di kB is unconditionally zeroed.
469  * It will be freed if and only if the expected current free base
470  * memory counter (%si) matches the actual current free base memory
471  * counter in 0x40:0x13; if this does not match then the memory will
472  * be leaked.
473  *****************************************************************************
474  */
475 free_basemem:
476         /* Zero base memory */
477         pushw   %si
478 1:      cmpw    %si, %di
479         je      2f
480         call    zero_kb
481         incw    %si
482         jmp     1b
483 2:      popw    %si
484         /* Free base memory */
485         movw    %fs:(0x13), %ax         /* Current FBMS to %ax */
486         cmpw    %ax, %si                /* Update FBMS only if "old" value  */
487         jne     1f                      /* is correct                       */
488         movw    %di, %ax
489 1:      movw    %ax, %fs:(0x13)
490         ret
492 /*****************************************************************************
493  * Subroutine: make a PXE API call.  Works with either !PXE or PXENV+ API.
495  * Parameters:
496  *   %bx : PXE API call number
497  *   %ds:pxe_parameter_structure : Parameters for PXE API call
498  * Returns:
499  *   %ax : PXE status code (not exit code)
500  *   CF set if %ax is non-zero
501  *****************************************************************************
502  */
503 pxe_call:
504         /* Preserve registers */
505         pushw   %di
506         pushw   %es
507         /* Set up registers for PXENV+ API.  %bx already set up */
508         pushw   %ds
509         popw    %es
510         movw    $pxe_parameter_structure, %di
511         /* Set up stack for !PXE API */
512         pushw   %es
513         pushw   %di
514         pushw   %bx
515         /* Make the API call */
516         lcall   *entry_segoff
517         /* Reset the stack */
518         addw    $6, %sp
519         movw    pxe_parameter_structure, %ax
520         clc
521         testw   %ax, %ax
522         jz      1f
523         stc
524 1:      /* Restore registers and return */
525         popw    %es
526         popw    %di
527         ret
529 /*****************************************************************************
530  * Subroutine: print PXE API call error message
532  * Parameters:
533  *   %ax : PXE status code
534  *   %bx : PXE API call number
535  * Returns:
536  *   Nothing
537  *****************************************************************************
538  */
539 print_pxe_error:
540         pushw   %si
541         movw    $10f, %si
542         call    print_message
543         xchgw   %ax, %bx
544         call    print_hex_word
545         movw    $20f, %si
546         call    print_message
547         xchgw   %ax, %bx
548         call    print_hex_word
549         movw    $30f, %si
550         call    print_message
551         popw    %si
552         ret
553         .section ".prefix.data"
554 10:     .asciz  "         UNDI API call "
555 20:     .asciz  " failed: status code "
556 30:     .asciz  "\n"
557         .previous
559 /*****************************************************************************
560  * PXE data structures
561  *****************************************************************************
562  */
564 pxe_parameter_structure: .fill 20
566 undi_code_segoff:
567 undi_code_size:         .word 0
568 undi_code_segment:      .word 0
570 undi_data_segoff:
571 undi_data_size:         .word 0
572 undi_data_segment:      .word 0
574 /* The following fields are part of a struct undi_device */
576 undi_device:
578 pxenv_segoff:
579 pxenv_offset:           .word 0
580 pxenv_segment:          .word 0
582 ppxe_segoff:
583 ppxe_offset:            .word 0
584 ppxe_segment:           .word 0
585         
586 entry_segoff:
587 entry_offset:           .word 0
588 entry_segment:          .word 0
590 return_stack_segoff:
591 return_stack_offset:    .long 0
592 return_stack_segment:   .word 0
594 return_type:            .word 0         /* Default: unload PXE and boot next */
596 undi_fbms_start:        .word 0
597 undi_fbms_end:          .word 0
599 pci_busdevfn:           .word UNDI_NO_PCI_BUSDEVFN
600 isapnp_csn:             .word UNDI_NO_ISAPNP_CSN
601 isapnp_read_port:       .word UNDI_NO_ISAPNP_READ_PORT
603 pci_vendor:             .word 0
604 pci_device:             .word 0
605 flags:                  .word UNDI_FL_STARTED
607         .equ undi_device_size, ( . - undi_device )
609 /*****************************************************************************
610  * Run Etherboot main code
611  *****************************************************************************
612  */     
613 run_etherboot:
614         /* Install Etherboot */
615         call    install
617         /* Set up real-mode stack */
618         movw    %bx, %ss
619         movw    $_estack16, %sp
621 #ifdef PXELOADER_KEEP_UNDI
622         /* Copy our undi_device structure to the preloaded_undi variable */
623         movw    %bx, %es
624         movw    $preloaded_undi, %di
625         movw    $undi_device, %si
626         movw    $undi_device_size, %cx
627         rep movsb
628 #endif
630         /* Jump to .text16 segment with %ds pointing to .data16 */
631         movw    %bx, %ds
632         pushw   %ax
633         pushw   $1f
634         lret
635         .section ".text16", "ax", @progbits
637         /* Run main program */
638         pushl   $main
639         pushw   %cs
640         call    prot_call
641         popl    %eax /* discard */
643 #ifdef PXELOADER_KEEP_UNDI
644         /* Boot next device */
645         movw    $0x40, %ax
646         movw    %ax, %fs
647         movw    $preloaded_undi,%bx
648         
649         cli
650         movw    %ss:return_type-undi_device(%bx),%ax
651         lssl    %ss:return_stack_segoff-undi_device(%bx), %esp
652         movw    %sp,%bp
653         movw    %ax,38(%bp)     /* Overwrite return AX value */
654         popw    %fs:0x13        /* 0 */
655         popw    %gs             /* 2 */
656         popw    %fs             /* 4 */
657         popw    %es             /* 6 */
658         popw    %ds             /* 8 */
659         popal                   /* 10, 14, 18, 22, 26, 30, 34, 38 */
660         popfl                   /* 42 */
661         lret                    /* 46 */
662 #else
663         int     $0x18
664 #endif
666         .previous