1 #define PXENV_UNDI_CLEANUP 0x02
2 #define PXENV_UNDI_SHUTDOWN 0x05
3 #define PXENV_STOP_UNDI 0x15
4 #define PXENV_UNLOAD_STACK 0x70
5 #define PXENV_STOP_BASE 0x76
7 #define PXE_STACK_MAGIC 0x57ac /* 'STac' */
13 .section ".prefix", "ax", @progbits
14 /*****************************************************************************
15 * Entry point: set cs, ds, bp, print welcome message
16 *****************************************************************************
18 jmp $0x7c0, $code_start
21 /* Preserve registers for return to PXE stack */
30 pushw $PXE_STACK_MAGIC /* PXE stack magic marker */
31 /* Set up stack just below 0x7c00 */
38 pushw %es /* Save old PXE stack pointer */
40 /* Set up our other segment registers */
43 movw $0x40, %ax /* BIOS data segment access */
45 /* Print welcome message */
49 /*****************************************************************************
50 * Detect type of PXE available (!PXE, PXENV+ or none)
51 *****************************************************************************
54 les %es:54(%di), %di /* !PXE structure */
55 cmpl $0x45585021, %es:(%di) /* '!PXE' signature */
61 cmpl $0x4e455850, %es:(%bx) /* 'PXEN' signature */
63 cmpw $0x2b56, %es:4(%bx) /* 'V+' signature */
69 jmp finished_with_error
72 detected_pxenv: /* es:bx points to PXENV+ structure */
75 pushw %es:0x24(%bx) /* UNDI code segment */
76 pushw %es:0x26(%bx) /* UNDI code size */
77 pushw %es:0x20(%bx) /* UNDI data segment */
78 pushw %es:0x22(%bx) /* UNDI data size */
79 les %es:0x0a(%bx), %di /* Entry point to %es:%di */
84 detected_pxe: /* es:di points to !PXE structure */
87 pushw %es:0x30(%di) /* UNDI code segment */
88 pushw %es:0x36(%di) /* UNDI code size */
89 pushw %es:0x28(%di) /* UNDI data segment */
90 pushw %es:0x2e(%di) /* UNDI data size */
91 les %es:0x10(%di), %di /* Entry point to %es:%di */
97 movw %es, pxe_entry_segment
98 movw %di, pxe_entry_offset
100 popw undi_data_segment
102 popw undi_code_segment
105 popw %es /* Exit with %es:%di containing structure address */
107 /*****************************************************************************
108 * Print information about located structure
109 *****************************************************************************
111 print_structure_information:
112 call print_segoff /* %es:%di contains address of structure */
113 les pxe_entry_segoff, %di
115 les undi_code_segoff, %di
117 les undi_data_segoff, %di
120 /*****************************************************************************
121 * Unload PXE base code and UNDI driver
122 *****************************************************************************
124 #ifdef PXELOADER_KEEP_ALL
125 xorw %ax, %ax /* Force zero flag to show success */
126 jmp do_not_free_base_mem /* Skip the unloading */
127 #endif /* PXELOADER_KEEP_ALL */
130 movw $PXENV_UNLOAD_STACK, %bx
132 movw $PXENV_STOP_UNDI, %bx
134 pushfw /* Ignore PXENV_UNDI_CLEANUP errors */
135 movw $PXENV_UNDI_CLEANUP, %bx
138 /* On exit, zero flag is set iff all calls were successful */
140 /*****************************************************************************
142 *****************************************************************************
145 jnz do_not_free_base_mem /* Using zero flag from unload_pxe */
147 movw undi_code_segment, %bx
148 movw undi_data_segment, %cx
149 movw undi_code_size, %ax
153 movw undi_data_size, %ax
154 1: addw $0x0f, %ax /* Round up to next segment */
156 addw %bx, %ax /* Highest segment address into %ax */
157 addw $(1024 / 16 - 1), %ax /* Round up to next kb */
158 shrw $6, %ax /* New free basemem size in %ax */
159 movw %fs:(0x13), %bx /* Old free base memory in %bx */
160 movw %ax, %fs:(0x13) /* Store new free base memory size */
162 /* Note that zero_mem_loop will also zero out our stack, so make
163 * sure the stack is empty at this point.
166 subw %bx, %dx /* numberof kb to zero in %dx */
167 shlw $6, %bx /* Segment address into %bx */
169 movw %bx, %es /* kB boundary into %es:00 */
173 rep stosb /* fill kB with zeroes */
174 addw $(1024 / 16), %bx
177 /* Will exit here with zero flag set, so no need to set it explicitly
178 * in order to indicate success.
181 do_not_free_base_mem:
182 pushfw /* Save success (zero) flag status */
183 movw %fs:(0x13), %ax /* Free base memory in %ax */
184 call print_hex_word /* Print free base memory */
185 popfw /* Restore success (zero) flag */
187 /*****************************************************************************
189 * Jump to finished with the zero flag set to indicate success, or to
190 * finished_with_error to always report an error
191 *****************************************************************************
204 /*****************************************************************************
205 * Subroutine: print character in %al (with LF -> LF,CR translation)
206 *****************************************************************************
209 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
210 movb $0x0e, %ah /* write char, tty mode */
211 cmpb $0x0a, %al /* '\n'? */
218 /*****************************************************************************
219 * Subroutine: print a zero-terminated message starting at %si
220 *****************************************************************************
230 /*****************************************************************************
231 * Subroutine: print hex word in %ax
232 *****************************************************************************
239 /* Courtesy of Norbert Juffa <norbert.juffa@amd.com> */
249 /*****************************************************************************
250 * Subroutine: print segment:offset address in %es:%di
251 *****************************************************************************
258 movb $0x3a,%al /* ':' */
262 movb $0x20, %al /* ' ' */
266 /*****************************************************************************
267 * Make a PXE API call. Works with either !PXE or PXENV+ API.
268 * Opcode in %bx. pxe_parameter_structure always used.
269 * Returns status code (not exit code) in %bx and prints it.
270 * ORs status code with overall status code in pxe_overall_status, returns
271 * with zero flag set iff all PXE API calls have been successful.
272 *****************************************************************************
275 /* Set up registers for PXENV+ API. %bx already set up */
278 movw $pxe_parameter_structure, %di
279 /* Set up stack for !PXE API */
283 /* Make the API call */
284 lcall *pxe_entry_segoff
285 /* Reset the stack */
287 movw pxe_parameter_structure, %ax
290 movw $0x20, %ax /* ' ' */
293 orw %bx, pxe_overall_status
296 /*****************************************************************************
297 * PXE data structures
298 *****************************************************************************
301 pxe_overall_status: .word 0
304 pxe_entry_offset: .word 0
305 pxe_entry_segment: .word 0
308 undi_code_size: .word 0
309 undi_code_segment: .word 0
312 undi_data_size: .word 0
313 undi_data_segment: .word 0
315 pxe_parameter_structure:
319 /*****************************************************************************
320 * Run Etherboot main code
321 *****************************************************************************
324 /* Install Etherboot */
327 /* Jump to .text16 segment with %ds pointing to .data16*/
332 .section ".text16", "ax", @progbits
334 /* Original PXE stack pointer to es:di. We must hold it in
335 * registers, because our current stack may be vapourised by
336 * the time main() returns. (main() will still be able to
337 * return, because prot_call() transfers the return address to
338 * the internal stack and back again).
343 /* Run main program */
347 popl %eax /* discard */
349 /* If original PXE stack is intact, return via PXE, else via INT 18 */
350 cmpw $PXE_STACK_MAGIC, %es:0(%di)
352 exit_via_pxe: /* Stack OK, return to PXE */
353 movw $exit_via_pxe_message, %si
354 call print_exit_message
355 pushw %es /* Restore original PXE stack */
358 popw %ax /* discard PXE_STACK_MAGIC */
359 popw %ax /* discard %cs */
360 popw %ax /* discard %ss */
367 xorw %ax, %ax /* Return PXENV_STATUS_SUCCESS */
369 exit_via_int18: /* Stack damaged, do int 18 */
370 movw $exit_via_int18_message, %si
371 call print_exit_message
375 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
376 movb $0x0e, %ah /* write char, tty mode */
384 .section ".data16", "aw", @progbits
385 exit_via_pxe_message:
387 exit_via_int18_message:
388 .asciz "EB->BIOS\r\n"