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
9 .section ".prefix", "ax", @progbits
10 .section ".prefix.data", "aw", @progbits
13 /*****************************************************************************
14 * Entry point: set operating context, print welcome message
15 *****************************************************************************
18 /* Set up our non-stack segment registers */
22 movw $0x40, %ax /* BIOS data segment access */
24 /* Record PXENV+ and !PXE nominal addresses */
25 movw %es, %ax /* PXENV+ address */
26 movw %ax, pxenv_segment
27 movw %bx, pxenv_offset
28 popl %eax /* Discard return address */
29 popl ppxe_segoff /* !PXE address */
30 /* Set up stack just below 0x7c00 */
34 /* Clear direction flag, for the sake of sanity */
36 /* Print welcome message */
39 .section ".prefix.data"
43 /*****************************************************************************
44 * Verify PXENV+ structure and record parameters of interest
45 *****************************************************************************
50 cmpl $0x4e455850, %es:(%di) /* 'PXEN' signature */
52 cmpw $0x2b56, %es:4(%di) /* 'V+' signature */
54 /* Record entry point and UNDI segments */
55 pushl %es:0x0a(%di) /* Entry point */
57 pushw %es:0x24(%di) /* UNDI code segment */
58 pushw %es:0x26(%di) /* UNDI code size */
60 pushw %es:0x20(%di) /* UNDI data segment */
61 pushw %es:0x22(%di) /* UNDI data size */
63 /* Print "PXENV+ at <address>" */
70 .section ".prefix.data"
71 10: .asciz " PXENV+ at "
75 /*****************************************************************************
76 * Verify !PXE structure and record parameters of interest
77 *****************************************************************************
82 cmpl $0x45585021, %es:(%di) /* '!PXE' signature */
84 /* Record structure address, entry point, and UNDI segments */
88 pushl %es:0x10(%di) /* Entry point */
90 pushw %es:0x30(%di) /* UNDI code segment */
91 pushw %es:0x36(%di) /* UNDI code size */
93 pushw %es:0x28(%di) /* UNDI data segment */
94 pushw %es:0x2e(%di) /* UNDI data size */
96 /* Print "!PXE at <address>" */
102 .section ".prefix.data"
103 10: .asciz " !PXE at "
107 /*****************************************************************************
108 * Sanity check: we must have an entry point
109 *****************************************************************************
112 /* Check for entry point */
113 movl entry_segoff, %eax
116 /* No entry point: print message and skip everything else */
120 .section ".prefix.data"
121 10: .asciz " No PXE stack found!\n"
125 /*****************************************************************************
126 * Calculate base memory usage by UNDI
127 *****************************************************************************
129 find_undi_basemem_usage:
130 movw undi_code_segment, %ax
131 movw undi_code_size, %bx
132 movw undi_data_segment, %cx
133 movw undi_data_size, %dx
138 1: /* %ax:%bx now describes the lower region, %cx:%dx the higher */
139 shrw $6, %ax /* Round down to nearest kB */
140 movw %ax, undi_fbms_start
141 addw $0x0f, %dx /* Round up to next segment */
144 addw $((1024 / 16) - 1), %cx /* Round up to next kB */
146 movw %cx, undi_fbms_end
148 /*****************************************************************************
149 * Print information about detected PXE stack
150 *****************************************************************************
152 print_structure_information:
153 /* Print entry point */
156 les entry_segoff, %di
158 .section ".prefix.data"
159 10: .asciz " entry point at "
161 /* Print UNDI code segment */
164 les undi_code_segoff, %di
166 .section ".prefix.data"
167 10: .asciz "\n UNDI code segment "
169 /* Print UNDI data segment */
172 les undi_data_segoff, %di
174 .section ".prefix.data"
175 10: .asciz ", data segment "
177 /* Print UNDI memory usage */
180 movw undi_fbms_start, %ax
184 movw undi_fbms_end, %ax
188 .section ".prefix.data"
193 /*****************************************************************************
194 * Determine physical device
195 *****************************************************************************
198 /* Issue PXENV_UNDI_GET_NIC_TYPE */
199 movw $PXENV_UNDI_GET_NIC_TYPE, %bx
203 jmp no_physical_device
204 1: /* Determine physical device type */
205 movb ( pxe_parameter_structure + 0x02 ), %al
207 je pci_physical_device
208 jmp no_physical_device
211 /* Record PCI bus:dev.fn */
212 movw ( pxe_parameter_structure + 0x0b ), %ax
213 movw %ax, pci_busdevfn
216 call print_pci_busdevfn
220 .section ".prefix.data"
221 10: .asciz " UNDI device is PCI "
225 /* No device found, or device type not understood */
228 .section ".prefix.data"
229 10: .asciz " Unable to determine UNDI physical device\n"
234 /*****************************************************************************
235 * Leave NIC in a safe state
236 *****************************************************************************
239 /* Issue PXENV_UNDI_SHUTDOWN */
240 movw $PXENV_UNDI_SHUTDOWN, %bx
246 /*****************************************************************************
247 * Unload PXE base code
248 *****************************************************************************
251 /* Issue PXENV_UNLOAD_STACK */
252 movw $PXENV_UNLOAD_STACK, %bx
257 1: /* Free base memory used by PXE base code */
259 movw undi_fbms_start, %di
263 /*****************************************************************************
265 *****************************************************************************
268 /* Issue PXENV_STOP_UNDI */
269 movw $PXENV_STOP_UNDI, %bx
274 1: /* Free base memory used by UNDI */
275 #ifndef PXELOADER_KEEP_UNDI
276 movw undi_fbms_start, %si
277 movw undi_fbms_end, %di
279 #endif /* PXELOADER_KEEP_UNDI */
282 /*****************************************************************************
283 * Print remaining free base memory
284 *****************************************************************************
293 .section ".prefix.data"
295 20: .asciz "kB free base memory after PXE unload\n"
298 /*****************************************************************************
300 *****************************************************************************
305 /*****************************************************************************
306 * Subroutine: print character (with LF -> LF,CR translation)
309 * %al : character to print
312 *****************************************************************************
315 /* Preserve registers */
319 /* Print character */
320 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
321 movb $0x0e, %ah /* write char, tty mode */
322 cmpb $0x0a, %al /* '\n'? */
327 /* Restore registers and return */
333 /*****************************************************************************
334 * Subroutine: print a NUL-terminated string
337 * %ds:%si : string to print
340 *****************************************************************************
343 /* Preserve registers */
352 2: /* Restore registers and return */
357 /*****************************************************************************
358 * Subroutine: print hex digit
361 * %al (low nibble) : digit to print
364 *****************************************************************************
367 /* Preserve registers */
369 /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
375 /* Restore registers and return */
379 /*****************************************************************************
380 * Subroutine: print hex byte
383 * %al : byte to print
386 *****************************************************************************
390 call print_hex_nibble
392 call print_hex_nibble
395 /*****************************************************************************
396 * Subroutine: print hex word
399 * %ax : word to print
402 *****************************************************************************
411 /*****************************************************************************
412 * Subroutine: print segment:offset address
415 * %es:%di : segment:offset address to print
418 *****************************************************************************
421 /* Preserve registers */
423 /* Print "<segment>:offset" */
430 /* Restore registers and return */
434 /*****************************************************************************
435 * Subroutine: print decimal word
438 * %ax : word to print
441 *****************************************************************************
444 /* Preserve registers */
449 /* Build up digit sequence on stack */
458 /* Print digit sequence */
460 call print_hex_nibble
462 /* Restore registers and return */
469 /*****************************************************************************
470 * Subroutine: print PCI bus:dev.fn
473 * %ax : PCI bus:dev.fn to print
476 *****************************************************************************
479 /* Preserve registers */
497 call print_hex_nibble
498 /* Restore registers and return */
502 /*****************************************************************************
503 * Subroutine: zero 1kB block of base memory
506 * %si : block to zero (in kB)
509 *****************************************************************************
512 /* Preserve registers */
525 /* Restore registers and return */
532 /*****************************************************************************
533 * Subroutine: free and zero base memory
536 * %si : Expected current free base memory counter (in kB)
537 * %di : Desired new free base memory counter (in kB)
538 * %fs : BIOS data segment (0x40)
540 * %ax : Actual new free base memory counter (in kB)
542 * The base memory from %si kB to %di kB is unconditionally zeroed.
543 * It will be freed if and only if the expected current free base
544 * memory counter (%si) matches the actual current free base memory
545 * counter in 0x40:0x13; if this does not match then the memory will
547 *****************************************************************************
550 /* Zero base memory */
558 /* Free base memory */
559 movw %fs:(0x13), %ax /* Current FBMS to %ax */
560 cmpw %ax, %si /* Update FBMS only if "old" value */
561 jne 1f /* is correct */
563 1: movw %ax, %fs:(0x13)
566 /*****************************************************************************
567 * Subroutine: make a PXE API call. Works with either !PXE or PXENV+ API.
570 * %bx : PXE API call number
571 * %ds:pxe_parameter_structure : Parameters for PXE API call
573 * %ax : PXE status code (not exit code)
574 * CF set if %ax is non-zero
575 *****************************************************************************
578 /* Preserve registers */
581 /* Set up registers for PXENV+ API. %bx already set up */
584 movw $pxe_parameter_structure, %di
585 /* Set up stack for !PXE API */
589 /* Make the API call */
591 /* Reset the stack */
593 movw pxe_parameter_structure, %ax
598 1: /* Restore registers and return */
603 /*****************************************************************************
604 * Subroutine: print PXE API call error message
607 * %ax : PXE status code
608 * %bx : PXE API call number
611 *****************************************************************************
627 .section ".prefix.data"
628 10: .asciz " UNDI API call "
629 20: .asciz " failed: status code "
633 /*****************************************************************************
634 * PXE data structures
635 *****************************************************************************
638 pxe_parameter_structure: .fill 20
641 undi_code_size: .word 0
642 undi_code_segment: .word 0
645 undi_data_size: .word 0
646 undi_data_segment: .word 0
648 /* The following fields are part of a struct undi_device */
653 pxenv_offset: .word 0
654 pxenv_segment: .word 0
658 ppxe_segment: .word 0
661 entry_offset: .word 0
662 entry_segment: .word 0
664 undi_fbms_start: .word 0
665 undi_fbms_end: .word 0
667 pci_busdevfn: .word 0xffff
668 isapnp_csn: .word 0xffff
669 isapnp_read_port: .word 0xffff
671 .equ undi_device_size, ( . - undi_device )
673 /*****************************************************************************
674 * Run Etherboot main code
675 *****************************************************************************
678 /* Install Etherboot */
681 #ifdef PXELOADER_KEEP_UNDI
682 /* Copy our undi_device structure to the preloaded_undi variable */
684 movw $preloaded_undi, %di
685 movw $undi_device, %si
686 movw $undi_device_size, %cx
690 /* Jump to .text16 segment with %ds pointing to .data16 */
695 .section ".text16", "ax", @progbits
697 /* Run main program */
701 popl %eax /* discard */
703 /* Boot next device */