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 */
23 /* %ax here is the default return type... */
24 movw $5, %ax /* Keep PXE+UNDI */
33 movw $0x40, %ax /* BIOS data segment access */
37 /* Record PXENV+ and !PXE nominal addresses */
38 movw %es, pxenv_segment
39 movw %bx, pxenv_offset
41 movw %ss, return_stack_segment
42 movl %esp, return_stack_offset
44 movl %eax, ppxe_segoff /* !PXE address */
45 /* Set up stack just below 0x7c00 */
49 /* Clear direction flag, for the sake of sanity */
51 /* Print welcome message */
54 .section ".prefix.data"
58 /*****************************************************************************
59 * Verify PXENV+ structure and record parameters of interest
60 *****************************************************************************
65 cmpl $0x4e455850, %es:(%di) /* 'PXEN' signature */
67 cmpw $0x2b56, %es:4(%di) /* 'V+' signature */
69 /* Record entry point and UNDI segments */
70 pushl %es:0x0a(%di) /* Entry point */
72 pushw %es:0x24(%di) /* UNDI code segment */
73 pushw %es:0x26(%di) /* UNDI code size */
75 pushw %es:0x20(%di) /* UNDI data segment */
76 pushw %es:0x22(%di) /* UNDI data size */
78 /* Print "PXENV+ at <address>" */
86 .section ".prefix.data"
87 10: .asciz " PXENV+ at "
92 movl %eax, pxenv_segoff
96 /*****************************************************************************
97 * Verify !PXE structure and record parameters of interest
98 *****************************************************************************
101 /* Signature check */
103 cmpl $0x45585021, %es:(%di) /* '!PXE' signature */
105 /* Record structure address, entry point, and UNDI segments */
108 movw %di, ppxe_offset
109 pushl %es:0x10(%di) /* Entry point */
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>" */
124 .section ".prefix.data"
125 10: .asciz " !PXE at "
130 movl %eax, ppxe_segoff
134 /*****************************************************************************
135 * Sanity check: we must have an entry point
136 *****************************************************************************
139 /* Check for entry point */
140 movl entry_segoff, %eax
143 /* No entry point: print message and skip everything else */
147 .section ".prefix.data"
148 10: .asciz " No PXE stack found!\n"
152 /*****************************************************************************
153 * Calculate base memory usage by UNDI
154 *****************************************************************************
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
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 */
171 addw $((1024 / 16) - 1), %cx /* Round up to next kB */
173 movw %cx, undi_fbms_end
175 /*****************************************************************************
176 * Print information about detected PXE stack
177 *****************************************************************************
179 print_structure_information:
180 /* Print entry point */
183 les entry_segoff, %di
185 .section ".prefix.data"
186 10: .asciz " entry point at "
188 /* Print UNDI code segment */
191 les undi_code_segoff, %di
193 .section ".prefix.data"
194 10: .asciz "\n UNDI code segment "
196 /* Print UNDI data segment */
199 les undi_data_segoff, %di
201 .section ".prefix.data"
202 10: .asciz ", data segment "
204 /* Print UNDI memory usage */
207 movw undi_fbms_start, %ax
211 movw undi_fbms_end, %ax
215 .section ".prefix.data"
220 /*****************************************************************************
221 * Determine physical device
222 *****************************************************************************
225 /* Issue PXENV_UNDI_GET_NIC_TYPE */
226 movw $PXENV_UNDI_GET_NIC_TYPE, %bx
230 jmp no_physical_device
231 1: /* Determine physical device type */
232 movb ( pxe_parameter_structure + 0x02 ), %al
234 je pci_physical_device
235 jmp no_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
245 call print_pci_busdevfn
249 .section ".prefix.data"
250 10: .asciz " UNDI device is PCI "
254 /* No device found, or device type not understood */
257 .section ".prefix.data"
258 10: .asciz " Unable to determine UNDI physical device\n"
263 /*****************************************************************************
264 * Leave NIC in a safe state
265 *****************************************************************************
267 #ifndef PXELOADER_KEEP_UNDI
269 /* Issue PXENV_UNDI_SHUTDOWN */
270 movw $PXENV_UNDI_SHUTDOWN, %bx
276 /*****************************************************************************
277 * Unload PXE base code
278 *****************************************************************************
281 /* Issue PXENV_UNLOAD_STACK */
282 movw $PXENV_UNLOAD_STACK, %bx
287 1: /* Free base memory used by PXE base code */
289 movw undi_fbms_start, %di
293 /*****************************************************************************
295 *****************************************************************************
299 /* Issue PXENV_STOP_UNDI */
300 movw $PXENV_STOP_UNDI, %bx
305 1: /* Free base memory used by UNDI */
306 movw undi_fbms_start, %si
307 movw undi_fbms_end, %di
309 /* Clear UNDI_FL_STARTED */
310 andw $~UNDI_FL_STARTED, flags
313 /*****************************************************************************
314 * Print remaining free base memory
315 *****************************************************************************
324 .section ".prefix.data"
326 20: .asciz "kB free base memory after PXE unload\n"
328 #endif /* PXELOADER_KEEP_UNDI */
330 /*****************************************************************************
332 *****************************************************************************
337 /*****************************************************************************
338 * Subroutine: print segment:offset address
341 * %es:%di : segment:offset address to print
344 *****************************************************************************
347 /* Preserve registers */
349 /* Print "<segment>:offset" */
356 /* Restore registers and return */
360 /*****************************************************************************
361 * Subroutine: print decimal word
364 * %ax : word to print
367 *****************************************************************************
370 /* Preserve registers */
375 /* Build up digit sequence on stack */
384 /* Print digit sequence */
386 call print_hex_nibble
388 /* Restore registers and return */
395 /*****************************************************************************
396 * Subroutine: print PCI bus:dev.fn
399 * %ax : PCI bus:dev.fn to print
402 *****************************************************************************
405 /* Preserve registers */
423 call print_hex_nibble
424 /* Restore registers and return */
428 /*****************************************************************************
429 * Subroutine: zero 1kB block of base memory
432 * %si : block to zero (in kB)
435 *****************************************************************************
438 /* Preserve registers */
451 /* Restore registers and return */
458 /*****************************************************************************
459 * Subroutine: free and zero base memory
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)
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
473 *****************************************************************************
476 /* Zero base memory */
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 */
489 1: movw %ax, %fs:(0x13)
492 /*****************************************************************************
493 * Subroutine: make a PXE API call. Works with either !PXE or PXENV+ API.
496 * %bx : PXE API call number
497 * %ds:pxe_parameter_structure : Parameters for PXE API call
499 * %ax : PXE status code (not exit code)
500 * CF set if %ax is non-zero
501 *****************************************************************************
504 /* Preserve registers */
507 /* Set up registers for PXENV+ API. %bx already set up */
510 movw $pxe_parameter_structure, %di
511 /* Set up stack for !PXE API */
515 /* Make the API call */
517 /* Reset the stack */
519 movw pxe_parameter_structure, %ax
524 1: /* Restore registers and return */
529 /*****************************************************************************
530 * Subroutine: print PXE API call error message
533 * %ax : PXE status code
534 * %bx : PXE API call number
537 *****************************************************************************
553 .section ".prefix.data"
554 10: .asciz " UNDI API call "
555 20: .asciz " failed: status code "
559 /*****************************************************************************
560 * PXE data structures
561 *****************************************************************************
564 pxe_parameter_structure: .fill 20
567 undi_code_size: .word 0
568 undi_code_segment: .word 0
571 undi_data_size: .word 0
572 undi_data_segment: .word 0
574 /* The following fields are part of a struct undi_device */
579 pxenv_offset: .word 0
580 pxenv_segment: .word 0
584 ppxe_segment: .word 0
587 entry_offset: .word 0
588 entry_segment: .word 0
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
605 flags: .word UNDI_FL_STARTED
607 .equ undi_device_size, ( . - undi_device )
609 /*****************************************************************************
610 * Run Etherboot main code
611 *****************************************************************************
614 /* Install Etherboot */
617 /* Set up real-mode stack */
621 #ifdef PXELOADER_KEEP_UNDI
622 /* Copy our undi_device structure to the preloaded_undi variable */
624 movw $preloaded_undi, %di
625 movw $undi_device, %si
626 movw $undi_device_size, %cx
630 /* Jump to .text16 segment with %ds pointing to .data16 */
635 .section ".text16", "ax", @progbits
637 /* Run main program */
641 popl %eax /* discard */
643 #ifdef PXELOADER_KEEP_UNDI
644 /* Boot next device */
647 movw $preloaded_undi,%bx
650 movw %ss:return_type-undi_device(%bx),%ax
651 lssl %ss:return_stack_segoff-undi_device(%bx), %esp
653 movw %ax,38(%bp) /* Overwrite return AX value */
654 popw %fs:0x13 /* 0 */
659 popal /* 10, 14, 18, 22, 26, 30, 34, 38 */