1 #define PXENV_UNDI_SHUTDOWN 0x05
2 #define PXENV_STOP_UNDI 0x15
3 #define PXENV_UNLOAD_STACK 0x70
5 #define PXE_STACK_MAGIC 0x57ac /* 'STac' */
11 .section ".prefix", "ax", @progbits
12 /*****************************************************************************
13 * Entry point: set cs, ds, bp, print welcome message
14 *****************************************************************************
16 jmp $0x7c0, $code_start
19 /* Preserve registers for return to PXE stack */
28 pushw $PXE_STACK_MAGIC /* PXE stack magic marker */
29 /* Set up stack just below 0x7c00 */
36 pushw %es /* Save old PXE stack pointer */
38 /* Set up our other segment registers */
41 movw $0x40, %ax /* BIOS data segment access */
43 /* Print welcome message */
47 /*****************************************************************************
48 * Detect type of PXE available (!PXE, PXENV+ or none)
49 *****************************************************************************
52 les %es:54(%di), %di /* !PXE structure */
53 cmpl $0x45585021, %es:(%di) /* '!PXE' signature */
59 cmpl $0x4e455850, %es:(%bx) /* 'PXEN' signature */
61 cmpw $0x2b56, %es:4(%bx) /* 'V+' signature */
67 jmp finished_with_error
70 detected_pxenv: /* es:bx points to PXENV+ structure */
73 pushw %es:0x24(%bx) /* UNDI code segment */
74 pushw %es:0x26(%bx) /* UNDI code size */
75 pushw %es:0x20(%bx) /* UNDI data segment */
76 pushw %es:0x22(%bx) /* UNDI data size */
77 les %es:0x0a(%bx), %di /* Entry point to %es:%di */
82 detected_pxe: /* es:di points to !PXE structure */
85 pushw %es:0x30(%di) /* UNDI code segment */
86 pushw %es:0x36(%di) /* UNDI code size */
87 pushw %es:0x28(%di) /* UNDI data segment */
88 pushw %es:0x2e(%di) /* UNDI data size */
89 les %es:0x10(%di), %di /* Entry point to %es:%di */
95 movw %es, pxe_entry_segment
96 movw %di, pxe_entry_offset
98 popw undi_data_segment
100 popw undi_code_segment
103 popw %es /* Exit with %es:%di containing structure address */
105 /*****************************************************************************
106 * Print information about located structure
107 *****************************************************************************
109 print_structure_information:
110 call print_segoff /* %es:%di contains address of structure */
111 les pxe_entry_segoff, %di
113 les undi_code_segoff, %di
115 les undi_data_segoff, %di
118 /*****************************************************************************
119 * Calculate base memory usage by UNDI
120 *****************************************************************************
122 find_undi_basemem_usage:
123 movw undi_code_segment, %ax
124 movw undi_code_size, %bx
125 movw undi_data_segment, %cx
126 movw undi_data_size, %dx
131 1: /* %ax:%bx now describes the lower region, %cx:%dx the higher */
132 shrw $6, %ax /* Round down to nearest kB */
133 movw %ax, undi_fbms_start
134 addw $0x0f, %dx /* Round up to next segment */
137 addw $((1024 / 16) - 1), %cx /* Round up to next kB */
139 movw %cx, undi_fbms_end
141 /*****************************************************************************
142 * Leave NIC in a safe state
143 *****************************************************************************
146 movw $PXENV_UNDI_SHUTDOWN, %bx
149 /*****************************************************************************
150 * Unload PXE base code
151 *****************************************************************************
154 movw $PXENV_UNLOAD_STACK, %bx
156 jnz do_not_free_base_code
159 movw undi_fbms_start, %di
161 do_not_free_base_code:
163 /*****************************************************************************
165 *****************************************************************************
168 movw $PXENV_STOP_UNDI, %bx
170 #ifndef PXELOADER_KEEP_UNDI
173 movw undi_fbms_start, %si
174 movw undi_fbms_end, %di
177 #endif /* PXELOADER_KEEP_UNDI */
179 /*****************************************************************************
181 *****************************************************************************
185 movw pxe_overall_status, %ax
196 /*****************************************************************************
197 * Subroutine: print character in %al (with LF -> LF,CR translation)
198 *****************************************************************************
201 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
202 movb $0x0e, %ah /* write char, tty mode */
203 cmpb $0x0a, %al /* '\n'? */
210 /*****************************************************************************
211 * Subroutine: print a zero-terminated message starting at %si
212 *****************************************************************************
222 /*****************************************************************************
223 * Subroutine: print hex word in %ax
224 *****************************************************************************
231 /* Courtesy of Norbert Juffa <norbert.juffa@amd.com> */
241 /*****************************************************************************
242 * Subroutine: print segment:offset address in %es:%di
243 *****************************************************************************
250 movb $0x3a,%al /* ':' */
254 movb $0x20, %al /* ' ' */
258 /*****************************************************************************
259 * Subroutine: free and zero base memory from %si kB to %di kB
260 *****************************************************************************
263 movw %fs:(0x13), %ax /* Current FBMS to %ax */
264 cmpw %ax, %si /* Update FBMS only if "old" value */
265 jne 1f /* is correct */
269 movw %si, %ax /* Zero kB at %si */
276 incw %si /* Move to next kB */
278 jne zero_kb /* Loop until done */
279 movw %fs:(0x13), %ax /* Print free base memory */
281 movb $0x20, %al /* ' ' */
285 /*****************************************************************************
286 * Make a PXE API call. Works with either !PXE or PXENV+ API.
287 * Opcode in %bx. pxe_parameter_structure always used.
289 * Returns status code (not exit code) in %bx and prints it. Returns
290 * with zero flag set if status code is zero (PXENV_STATUS_SUCCESS).
291 *****************************************************************************
294 /* Set up registers for PXENV+ API. %bx already set up */
297 movw $pxe_parameter_structure, %di
298 /* Set up stack for !PXE API */
302 /* Make the API call */
303 lcall *pxe_entry_segoff
304 /* Reset the stack */
306 movw pxe_parameter_structure, %ax
309 movw $0x20, %ax /* ' ' */
312 orw %bx, pxe_overall_status
316 /*****************************************************************************
317 * PXE data structures
318 *****************************************************************************
322 pxe_entry_offset: .word 0
323 pxe_entry_segment: .word 0
326 undi_code_size: .word 0
327 undi_code_segment: .word 0
330 undi_data_size: .word 0
331 undi_data_segment: .word 0
333 undi_fbms_start: .word 0
334 undi_fbms_end: .word 0
336 pxe_parameter_structure:
340 pxe_overall_status: .word 0
342 /*****************************************************************************
343 * Run Etherboot main code
344 *****************************************************************************
347 /* Install Etherboot */
350 /* Jump to .text16 segment with %ds pointing to .data16*/
355 .section ".text16", "ax", @progbits
357 /* Original PXE stack pointer to es:di. We must hold it in
358 * registers, because our current stack may be vapourised by
359 * the time main() returns. (main() will still be able to
360 * return, because prot_call() transfers the return address to
361 * the internal stack and back again).
366 /* Run main program */
370 popl %eax /* discard */
372 /* If original PXE stack is intact, return via PXE, else via INT 18 */
373 cmpw $PXE_STACK_MAGIC, %es:0(%di)
375 exit_via_pxe: /* Stack OK, return to PXE */
376 movw $exit_via_pxe_message, %si
377 call print_exit_message
378 pushw %es /* Restore original PXE stack */
381 popw %ax /* discard PXE_STACK_MAGIC */
382 popw %ax /* discard %cs */
383 popw %ax /* discard %ss */
390 xorw %ax, %ax /* Return PXENV_STATUS_SUCCESS */
392 exit_via_int18: /* Stack damaged, do int 18 */
393 movw $exit_via_int18_message, %si
394 call print_exit_message
398 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
399 movb $0x0e, %ah /* write char, tty mode */
407 .section ".data16", "aw", @progbits
408 exit_via_pxe_message:
410 exit_via_int18_message:
411 .asciz "EB->BIOS\r\n"