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
15 /*****************************************************************************
16 * Entry point: set operating context, print welcome message
17 *****************************************************************************
20 /* Set up our non-stack segment registers */
24 movw $0x40, %ax /* BIOS data segment access */
26 /* Record PXENV+ and !PXE nominal addresses */
27 movw %es, %ax /* PXENV+ address */
28 movw %ax, pxenv_segment
29 movw %bx, pxenv_offset
30 popl %eax /* Discard return address */
31 popl ppxe_segoff /* !PXE address */
32 /* Set up stack just below 0x7c00 */
36 /* Clear direction flag, for the sake of sanity */
38 /* Print welcome message */
41 .section ".prefix.data"
45 /*****************************************************************************
46 * Verify PXENV+ structure and record parameters of interest
47 *****************************************************************************
52 cmpl $0x4e455850, %es:(%di) /* 'PXEN' signature */
54 cmpw $0x2b56, %es:4(%di) /* 'V+' signature */
56 /* Record entry point and UNDI segments */
57 pushl %es:0x0a(%di) /* Entry point */
59 pushw %es:0x24(%di) /* UNDI code segment */
60 pushw %es:0x26(%di) /* UNDI code size */
62 pushw %es:0x20(%di) /* UNDI data segment */
63 pushw %es:0x22(%di) /* UNDI data size */
65 /* Print "PXENV+ at <address>" */
73 .section ".prefix.data"
74 10: .asciz " PXENV+ at "
79 movl %eax, pxenv_segoff
83 /*****************************************************************************
84 * Verify !PXE structure and record parameters of interest
85 *****************************************************************************
90 cmpl $0x45585021, %es:(%di) /* '!PXE' signature */
92 /* Record structure address, entry point, and UNDI segments */
96 pushl %es:0x10(%di) /* Entry point */
98 pushw %es:0x30(%di) /* UNDI code segment */
99 pushw %es:0x36(%di) /* UNDI code size */
100 popl undi_code_segoff
101 pushw %es:0x28(%di) /* UNDI data segment */
102 pushw %es:0x2e(%di) /* UNDI data size */
103 popl undi_data_segoff
104 /* Print "!PXE at <address>" */
111 .section ".prefix.data"
112 10: .asciz " !PXE at "
117 movl %eax, ppxe_segoff
121 /*****************************************************************************
122 * Sanity check: we must have an entry point
123 *****************************************************************************
126 /* Check for entry point */
127 movl entry_segoff, %eax
130 /* No entry point: print message and skip everything else */
134 .section ".prefix.data"
135 10: .asciz " No PXE stack found!\n"
139 /*****************************************************************************
140 * Calculate base memory usage by UNDI
141 *****************************************************************************
143 find_undi_basemem_usage:
144 movw undi_code_segment, %ax
145 movw undi_code_size, %bx
146 movw undi_data_segment, %cx
147 movw undi_data_size, %dx
152 1: /* %ax:%bx now describes the lower region, %cx:%dx the higher */
153 shrw $6, %ax /* Round down to nearest kB */
154 movw %ax, undi_fbms_start
155 addw $0x0f, %dx /* Round up to next segment */
158 addw $((1024 / 16) - 1), %cx /* Round up to next kB */
160 movw %cx, undi_fbms_end
162 /*****************************************************************************
163 * Print information about detected PXE stack
164 *****************************************************************************
166 print_structure_information:
167 /* Print entry point */
170 les entry_segoff, %di
172 .section ".prefix.data"
173 10: .asciz " entry point at "
175 /* Print UNDI code segment */
178 les undi_code_segoff, %di
180 .section ".prefix.data"
181 10: .asciz "\n UNDI code segment "
183 /* Print UNDI data segment */
186 les undi_data_segoff, %di
188 .section ".prefix.data"
189 10: .asciz ", data segment "
191 /* Print UNDI memory usage */
194 movw undi_fbms_start, %ax
198 movw undi_fbms_end, %ax
202 .section ".prefix.data"
207 /*****************************************************************************
208 * Determine physical device
209 *****************************************************************************
212 /* Issue PXENV_UNDI_GET_NIC_TYPE */
213 movw $PXENV_UNDI_GET_NIC_TYPE, %bx
217 jmp no_physical_device
218 1: /* Determine physical device type */
219 movb ( pxe_parameter_structure + 0x02 ), %al
221 je pci_physical_device
222 jmp no_physical_device
225 /* Record PCI bus:dev.fn and vendor/device IDs */
226 movl ( pxe_parameter_structure + 0x03 ), %eax
227 movl %eax, pci_vendor
228 movw ( pxe_parameter_structure + 0x0b ), %ax
229 movw %ax, pci_busdevfn
232 call print_pci_busdevfn
236 .section ".prefix.data"
237 10: .asciz " UNDI device is PCI "
241 /* No device found, or device type not understood */
244 .section ".prefix.data"
245 10: .asciz " Unable to determine UNDI physical device\n"
250 /*****************************************************************************
251 * Leave NIC in a safe state
252 *****************************************************************************
255 /* Issue PXENV_UNDI_SHUTDOWN */
256 movw $PXENV_UNDI_SHUTDOWN, %bx
262 /*****************************************************************************
263 * Unload PXE base code
264 *****************************************************************************
267 /* Issue PXENV_UNLOAD_STACK */
268 movw $PXENV_UNLOAD_STACK, %bx
273 1: /* Free base memory used by PXE base code */
275 movw undi_fbms_start, %di
279 /*****************************************************************************
281 *****************************************************************************
283 #ifndef PXELOADER_KEEP_UNDI
285 /* Issue PXENV_STOP_UNDI */
286 movw $PXENV_STOP_UNDI, %bx
291 1: /* Free base memory used by UNDI */
292 movw undi_fbms_start, %si
293 movw undi_fbms_end, %di
295 /* Clear UNDI_FL_STARTED */
296 andw $~UNDI_FL_STARTED, flags
298 #endif /* PXELOADER_KEEP_UNDI */
300 /*****************************************************************************
301 * Print remaining free base memory
302 *****************************************************************************
311 .section ".prefix.data"
313 20: .asciz "kB free base memory after PXE unload\n"
316 /*****************************************************************************
318 *****************************************************************************
323 /*****************************************************************************
324 * Subroutine: print character (with LF -> LF,CR translation)
327 * %al : character to print
330 *****************************************************************************
333 /* Preserve registers */
337 /* Print character */
338 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
339 movb $0x0e, %ah /* write char, tty mode */
340 cmpb $0x0a, %al /* '\n'? */
345 /* Restore registers and return */
351 /*****************************************************************************
352 * Subroutine: print a NUL-terminated string
355 * %ds:%si : string to print
358 *****************************************************************************
361 /* Preserve registers */
370 2: /* Restore registers and return */
375 /*****************************************************************************
376 * Subroutine: print hex digit
379 * %al (low nibble) : digit to print
382 *****************************************************************************
385 /* Preserve registers */
387 /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
393 /* Restore registers and return */
397 /*****************************************************************************
398 * Subroutine: print hex byte
401 * %al : byte to print
404 *****************************************************************************
408 call print_hex_nibble
410 call print_hex_nibble
413 /*****************************************************************************
414 * Subroutine: print hex word
417 * %ax : word to print
420 *****************************************************************************
429 /*****************************************************************************
430 * Subroutine: print segment:offset address
433 * %es:%di : segment:offset address to print
436 *****************************************************************************
439 /* Preserve registers */
441 /* Print "<segment>:offset" */
448 /* Restore registers and return */
452 /*****************************************************************************
453 * Subroutine: print decimal word
456 * %ax : word to print
459 *****************************************************************************
462 /* Preserve registers */
467 /* Build up digit sequence on stack */
476 /* Print digit sequence */
478 call print_hex_nibble
480 /* Restore registers and return */
487 /*****************************************************************************
488 * Subroutine: print PCI bus:dev.fn
491 * %ax : PCI bus:dev.fn to print
494 *****************************************************************************
497 /* Preserve registers */
515 call print_hex_nibble
516 /* Restore registers and return */
520 /*****************************************************************************
521 * Subroutine: zero 1kB block of base memory
524 * %si : block to zero (in kB)
527 *****************************************************************************
530 /* Preserve registers */
543 /* Restore registers and return */
550 /*****************************************************************************
551 * Subroutine: free and zero base memory
554 * %si : Expected current free base memory counter (in kB)
555 * %di : Desired new free base memory counter (in kB)
556 * %fs : BIOS data segment (0x40)
558 * %ax : Actual new free base memory counter (in kB)
560 * The base memory from %si kB to %di kB is unconditionally zeroed.
561 * It will be freed if and only if the expected current free base
562 * memory counter (%si) matches the actual current free base memory
563 * counter in 0x40:0x13; if this does not match then the memory will
565 *****************************************************************************
568 /* Zero base memory */
576 /* Free base memory */
577 movw %fs:(0x13), %ax /* Current FBMS to %ax */
578 cmpw %ax, %si /* Update FBMS only if "old" value */
579 jne 1f /* is correct */
581 1: movw %ax, %fs:(0x13)
584 /*****************************************************************************
585 * Subroutine: make a PXE API call. Works with either !PXE or PXENV+ API.
588 * %bx : PXE API call number
589 * %ds:pxe_parameter_structure : Parameters for PXE API call
591 * %ax : PXE status code (not exit code)
592 * CF set if %ax is non-zero
593 *****************************************************************************
596 /* Preserve registers */
599 /* Set up registers for PXENV+ API. %bx already set up */
602 movw $pxe_parameter_structure, %di
603 /* Set up stack for !PXE API */
607 /* Make the API call */
609 /* Reset the stack */
611 movw pxe_parameter_structure, %ax
616 1: /* Restore registers and return */
621 /*****************************************************************************
622 * Subroutine: print PXE API call error message
625 * %ax : PXE status code
626 * %bx : PXE API call number
629 *****************************************************************************
645 .section ".prefix.data"
646 10: .asciz " UNDI API call "
647 20: .asciz " failed: status code "
651 /*****************************************************************************
652 * PXE data structures
653 *****************************************************************************
656 pxe_parameter_structure: .fill 20
659 undi_code_size: .word 0
660 undi_code_segment: .word 0
663 undi_data_size: .word 0
664 undi_data_segment: .word 0
666 /* The following fields are part of a struct undi_device */
671 pxenv_offset: .word 0
672 pxenv_segment: .word 0
676 ppxe_segment: .word 0
679 entry_offset: .word 0
680 entry_segment: .word 0
682 undi_fbms_start: .word 0
683 undi_fbms_end: .word 0
685 pci_busdevfn: .word UNDI_NO_PCI_BUSDEVFN
686 isapnp_csn: .word UNDI_NO_ISAPNP_CSN
687 isapnp_read_port: .word UNDI_NO_ISAPNP_READ_PORT
691 flags: .word UNDI_FL_STARTED
693 .equ undi_device_size, ( . - undi_device )
695 /*****************************************************************************
696 * Run Etherboot main code
697 *****************************************************************************
700 /* Install Etherboot */
703 /* Set up real-mode stack */
707 #ifdef PXELOADER_KEEP_UNDI
708 /* Copy our undi_device structure to the preloaded_undi variable */
710 movw $preloaded_undi, %di
711 movw $undi_device, %si
712 movw $undi_device_size, %cx
716 /* Jump to .text16 segment with %ds pointing to .data16 */
721 .section ".text16", "ax", @progbits
723 /* Run main program */
727 popl %eax /* discard */
729 /* Boot next device */