summaryrefslogtreecommitdiffstats
path: root/src/arch
diff options
context:
space:
mode:
authorMichael Brown2007-01-09 02:42:28 +0100
committerMichael Brown2007-01-09 02:42:28 +0100
commit47222d5ed8c7ca20c416dae03560651854942252 (patch)
tree32af643c83305d6f2c67ee88b5cf97457cad8cea /src/arch
parentUse fixed-width fields in struct undi_device, so that pxeprefix.S will be (diff)
downloadipxe-47222d5ed8c7ca20c416dae03560651854942252.tar.gz
ipxe-47222d5ed8c7ca20c416dae03560651854942252.tar.xz
ipxe-47222d5ed8c7ca20c416dae03560651854942252.zip
Call PXENV_UNDI_GET_NIC_TYPE to identify NIC physical device.
Record all information required for populating a struct undi_device. Make debugging output more human-readable.
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/i386/prefix/pxeprefix.S616
1 files changed, 480 insertions, 136 deletions
diff --git a/src/arch/i386/prefix/pxeprefix.S b/src/arch/i386/prefix/pxeprefix.S
index a34bf5f86..8b485e48f 100644
--- a/src/arch/i386/prefix/pxeprefix.S
+++ b/src/arch/i386/prefix/pxeprefix.S
@@ -1,22 +1,24 @@
-#define PXENV_UNDI_SHUTDOWN 0x05
-#define PXENV_STOP_UNDI 0x15
-#define PXENV_UNLOAD_STACK 0x70
+#define PXENV_UNDI_SHUTDOWN 0x0005
+#define PXENV_UNDI_GET_NIC_TYPE 0x0012
+#define PXENV_STOP_UNDI 0x0015
+#define PXENV_UNLOAD_STACK 0x0070
#define PXE_STACK_MAGIC 0x57ac /* 'STac' */
.text
- .code16
.arch i386
.org 0
.section ".prefix", "ax", @progbits
+ .section ".prefix.data", "aw", @progbits
+ .code16
+
/*****************************************************************************
- * Entry point: set cs, ds, bp, print welcome message
+ * Entry point: set operating context, print welcome message
*****************************************************************************
- */
- jmp $0x7c0, $code_start
-10: .asciz "PXE->EB "
-code_start:
- /* Preserve registers for return to PXE stack */
+ */
+ .section ".prefix"
+ jmp $0x7c0, $1f
+1: /* Preserve registers for return to PXE stack */
pushfl
pushal
pushw %gs
@@ -28,92 +30,110 @@ code_start:
pushw $PXE_STACK_MAGIC /* PXE stack magic marker */
/* Set up stack just below 0x7c00 */
pushw %ss
- popw %es
- movw %sp, %di
+ popw %gs
+ movw %sp, %bp /* %gs:%bp points to old PXE stack */
xorw %ax, %ax
movw %ax, %ss
movw $0x7c00, %sp
- pushw %es /* Save old PXE stack pointer */
- pushw %di
+ pushw %gs /* Save old PXE stack pointer */
+ pushw %bp
/* Set up our other segment registers */
pushw %cs
popw %ds
movw $0x40, %ax /* BIOS data segment access */
movw %ax, %fs
+ /* Clear direction flag, for the sake of sanity */
+ cld
/* Print welcome message */
- movw $10b, %si
+ movw $10f, %si
call print_message
+ .section ".prefix.data"
+10: .asciz "PXE->EB:"
+ .previous
/*****************************************************************************
- * Detect type of PXE available (!PXE, PXENV+ or none)
+ * Verify PXENV+ structure and record parameters of interest
*****************************************************************************
*/
-detect_pxe:
- les %es:54(%di), %di /* !PXE structure */
- cmpl $0x45585021, %es:(%di) /* '!PXE' signature */
- je detected_pxe
- movw $0x5650, %ax
- int $0x1a
- cmpw $0x564e, %ax
- jne detected_nothing
+detect_pxenv:
+ /* Signature check */
cmpl $0x4e455850, %es:(%bx) /* 'PXEN' signature */
- jne detected_nothing
+ jne 99f
cmpw $0x2b56, %es:4(%bx) /* 'V+' signature */
- je detected_pxenv
-
-detected_nothing:
- movw $10f, %si
- call print_message
- jmp finished_with_error
-10: .asciz "No PXE "
-
-detected_pxenv: /* es:bx points to PXENV+ structure */
+ jne 99f
+ /* Record structure address, entry point, and UNDI segments */
pushw %es
- pushw %bx
+ popw pxenv_segment
+ movw %bx, pxenv_offset
+ pushl %es:0x0a(%bx) /* Entry point */
+ popl entry_segoff
pushw %es:0x24(%bx) /* UNDI code segment */
pushw %es:0x26(%bx) /* UNDI code size */
+ popl undi_code_segoff
pushw %es:0x20(%bx) /* UNDI data segment */
pushw %es:0x22(%bx) /* UNDI data size */
- les %es:0x0a(%bx), %di /* Entry point to %es:%di */
+ popl undi_data_segoff
+ /* Print "PXENV+ at <address>" */
movw $10f, %si
- jmp pxe_setup_done
-10: .asciz "PXENV+ "
-
-detected_pxe: /* es:di points to !PXE structure */
+ call print_message
+ movw %bx, %di
+ call print_segoff
+ movb $',', %al
+ call print_character
+ .section ".prefix.data"
+10: .asciz " PXENV+ at "
+ .previous
+99:
+
+/*****************************************************************************
+ * Verify !PXE structure and record parameters of interest
+ *****************************************************************************
+ */
+detect_ppxe:
+ /* Signature check */
+ les %gs:54(%bp), %di /* !PXE structure */
+ cmpl $0x45585021, %es:(%di) /* '!PXE' signature */
+ jne 99f
+ /* Record structure address, entry point, and UNDI segments */
pushw %es
- pushw %di
+ popw ppxe_segment
+ movw %di, ppxe_offset
+ pushl %es:0x10(%di) /* Entry point */
+ popl entry_segoff
pushw %es:0x30(%di) /* UNDI code segment */
pushw %es:0x36(%di) /* UNDI code size */
+ popl undi_code_segoff
pushw %es:0x28(%di) /* UNDI data segment */
pushw %es:0x2e(%di) /* UNDI data size */
- les %es:0x10(%di), %di /* Entry point to %es:%di */
+ popl undi_data_segoff
+ /* Print "!PXE at <address>" */
movw $10f, %si
- jmp pxe_setup_done
-10: .asciz "!PXE "
-
-pxe_setup_done:
- movw %es, pxe_entry_segment
- movw %di, pxe_entry_offset
- popw undi_data_size
- popw undi_data_segment
- popw undi_code_size
- popw undi_code_segment
call print_message
- popw %di
- popw %es /* Exit with %es:%di containing structure address */
+ call print_segoff
+ movb $',', %al
+ call print_character
+ .section ".prefix.data"
+10: .asciz " !PXE at "
+ .previous
+99:
/*****************************************************************************
- * Print information about located structure
+ * Sanity check: we must have an entry point
*****************************************************************************
*/
-print_structure_information:
- call print_segoff /* %es:%di contains address of structure */
- les pxe_entry_segoff, %di
- call print_segoff
- les undi_code_segoff, %di
- call print_segoff
- les undi_data_segoff, %di
- call print_segoff
+check_have_stack:
+ /* Check for entry point */
+ movl entry_segoff, %eax
+ testl %eax, %eax
+ jnz 99f
+ /* No entry point: print message and skip everything else */
+ movw $10f, %si
+ call print_message
+ jmp finished
+ .section ".prefix.data"
+10: .asciz " No PXE stack found!\n"
+ .previous
+99:
/*****************************************************************************
* Calculate base memory usage by UNDI
@@ -139,65 +159,177 @@ find_undi_basemem_usage:
movw %cx, undi_fbms_end
/*****************************************************************************
+ * Print information about detected PXE stack
+ *****************************************************************************
+ */
+print_structure_information:
+ /* Print entry point */
+ movw $10f, %si
+ call print_message
+ les entry_segoff, %di
+ call print_segoff
+ .section ".prefix.data"
+10: .asciz " entry point at "
+ .previous
+ /* Print UNDI code segment */
+ movw $10f, %si
+ call print_message
+ les undi_code_segoff, %di
+ call print_segoff
+ .section ".prefix.data"
+10: .asciz "\n UNDI code segment "
+ .previous
+ /* Print UNDI data segment */
+ movw $10f, %si
+ call print_message
+ les undi_data_segoff, %di
+ call print_segoff
+ .section ".prefix.data"
+10: .asciz ", data segment "
+ .previous
+ /* Print UNDI memory usage */
+ movw $10f, %si
+ call print_message
+ movw undi_fbms_start, %ax
+ call print_word
+ movb $'-', %al
+ call print_character
+ movw undi_fbms_end, %ax
+ call print_word
+ movw $20f, %si
+ call print_message
+ .section ".prefix.data"
+10: .asciz " ("
+20: .asciz "kB)\n"
+ .previous
+
+/*****************************************************************************
+ * Determine physical device
+ *****************************************************************************
+ */
+get_physical_device:
+ /* Issue PXENV_UNDI_GET_NIC_TYPE */
+ movw $PXENV_UNDI_GET_NIC_TYPE, %bx
+ call pxe_call
+ jnc 1f
+ call print_pxe_error
+ jmp no_physical_device
+1: /* Determine physical device type */
+ movb ( pxe_parameter_structure + 0x02 ), %al
+ cmpb $2, %al
+ je pci_physical_device
+ jmp no_physical_device
+
+pci_physical_device:
+ /* Record PCI bus:dev.fn */
+ movw ( pxe_parameter_structure + 0x0b ), %ax
+ movw %ax, pci_busdevfn
+ movw $10f, %si
+ call print_message
+ call print_pci_busdevfn
+ movb $0x0a, %al
+ call print_character
+ jmp 99f
+ .section ".prefix.data"
+10: .asciz " UNDI device is PCI "
+ .previous
+
+no_physical_device:
+ /* No device found, or device type not understood */
+ movw $10f, %si
+ call print_message
+ .section ".prefix.data"
+10: .asciz " Unable to determine UNDI physical device\n"
+ .previous
+
+99:
+
+/*****************************************************************************
* Leave NIC in a safe state
*****************************************************************************
*/
shutdown_nic:
+ /* Issue PXENV_UNDI_SHUTDOWN */
movw $PXENV_UNDI_SHUTDOWN, %bx
call pxe_call
+ jnc 1f
+ call print_pxe_error
+1:
/*****************************************************************************
* Unload PXE base code
*****************************************************************************
*/
unload_base_code:
+ /* Issue PXENV_UNLOAD_STACK */
movw $PXENV_UNLOAD_STACK, %bx
call pxe_call
- jnz do_not_free_base_code
-free_base_code:
+ jnc 1f
+ call print_pxe_error
+ jmp 99f
+1: /* Free base memory used by PXE base code */
movw %fs:(0x13), %si
movw undi_fbms_start, %di
call free_basemem
-do_not_free_base_code:
+99:
/*****************************************************************************
* Unload UNDI driver
*****************************************************************************
*/
unload_undi:
+ /* Issue PXENV_STOP_UNDI */
movw $PXENV_STOP_UNDI, %bx
call pxe_call
+ jnc 1f
+ call print_pxe_error
+ jmp 99f
+1: /* Free base memory used by UNDI */
#ifndef PXELOADER_KEEP_UNDI
- jnz do_not_free_undi
-free_undi:
movw undi_fbms_start, %si
movw undi_fbms_end, %di
call free_basemem
-do_not_free_undi:
#endif /* PXELOADER_KEEP_UNDI */
+99:
/*****************************************************************************
- * Exit point
+ * Print remaining free base memory
*****************************************************************************
- */
-finished:
+ */
+print_free_basemem:
movw $10f, %si
- movw pxe_overall_status, %ax
- testw %ax, %ax
- jz 1f
-finished_with_error:
+ call print_message
+ movw %fs:(0x13), %ax
+ call print_word
movw $20f, %si
-1:
call print_message
+ .section ".prefix.data"
+10: .asciz " "
+20: .asciz "kB free base memory after PXE unload\n"
+ .previous
+
+/*****************************************************************************
+ * Exit point
+ *****************************************************************************
+ */
+finished:
jmp run_etherboot
-10: .asciz "ok\n"
-20: .asciz "err\n"
/*****************************************************************************
- * Subroutine: print character in %al (with LF -> LF,CR translation)
+ * Subroutine: print character (with LF -> LF,CR translation)
+ *
+ * Parameters:
+ * %al : character to print
+ * Returns:
+ * Nothing
*****************************************************************************
*/
print_character:
+ /* Preserve registers */
+ pushw %ax
+ pushw %bx
+ pushw %bp
+ /* Print character */
movw $0x0007, %bx /* page 0, attribute 7 (normal) */
movb $0x0e, %ah /* write char, tty mode */
cmpb $0x0a, %al /* '\n'? */
@@ -205,122 +337,318 @@ print_character:
int $0x10
movb $0x0d, %al
1: int $0x10
+ /* Restore registers and return */
+ popw %bp
+ popw %bx
+ popw %ax
ret
/*****************************************************************************
- * Subroutine: print a zero-terminated message starting at %si
+ * Subroutine: print a NUL-terminated string
+ *
+ * Parameters:
+ * %ds:%si : string to print
+ * Returns:
+ * Nothing
*****************************************************************************
*/
print_message:
+ /* Preserve registers */
+ pushw %ax
+ pushw %si
+ /* Print string */
1: lodsb
testb %al, %al
je 2f
call print_character
jmp 1b
-2: ret
+2: /* Restore registers and return */
+ popw %si
+ popw %ax
+ ret
/*****************************************************************************
- * Subroutine: print hex word in %ax
+ * Subroutine: print hex digit
+ *
+ * Parameters:
+ * %al (low nibble) : digit to print
+ * Returns:
+ * Nothing
*****************************************************************************
*/
-print_hex_word:
- movw $4, %cx
-1:
+print_hex_nibble:
+ /* Preserve registers */
pushw %ax
- shrw $12, %ax
- /* Courtesy of Norbert Juffa <norbert.juffa@amd.com> */
- cmpb $10, %al
+ /* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
+ andb $0x0f, %al
+ cmpb $10, %al
sbbb $0x69, %al
das
call print_character
+ /* Restore registers and return */
popw %ax
- shlw $4, %ax
- loop 1b
+ ret
+
+/*****************************************************************************
+ * Subroutine: print hex byte
+ *
+ * Parameters:
+ * %al : byte to print
+ * Returns:
+ * Nothing
+ *****************************************************************************
+ */
+print_hex_byte:
+ rorb $4, %al
+ call print_hex_nibble
+ rorb $4, %al
+ call print_hex_nibble
ret
-
+
/*****************************************************************************
- * Subroutine: print segment:offset address in %es:%di
+ * Subroutine: print hex word
+ *
+ * Parameters:
+ * %ax : word to print
+ * Returns:
+ * Nothing
+ *****************************************************************************
+ */
+print_hex_word:
+ xchgb %al, %ah
+ call print_hex_byte
+ xchgb %al, %ah
+ call print_hex_byte
+ ret
+
+/*****************************************************************************
+ * Subroutine: print segment:offset address
+ *
+ * Parameters:
+ * %es:%di : segment:offset address to print
+ * Returns:
+ * Nothing
*****************************************************************************
*/
print_segoff:
- pushw %di
- pushw %es
- popw %ax
+ /* Preserve registers */
+ pushw %ax
+ /* Print "<segment>:offset" */
+ movw %es, %ax
call print_hex_word
- movb $0x3a,%al /* ':' */
+ movb $':', %al
call print_character
- popw %ax
+ movw %di, %ax
call print_hex_word
- movb $0x20, %al /* ' ' */
- call print_character
+ /* Restore registers and return */
+ popw %ax
ret
/*****************************************************************************
- * Subroutine: free and zero base memory from %si kB to %di kB
+ * Subroutine: print decimal word
+ *
+ * Parameters:
+ * %ax : word to print
+ * Returns:
+ * Nothing
+ *****************************************************************************
+ */
+print_word:
+ /* Preserve registers */
+ pushw %ax
+ pushw %bx
+ pushw %cx
+ pushw %dx
+ /* Build up digit sequence on stack */
+ movw $10, %bx
+ xorw %cx, %cx
+1: xorw %dx, %dx
+ divw %bx, %ax
+ pushw %dx
+ incw %cx
+ testw %ax, %ax
+ jnz 1b
+ /* Print digit sequence */
+1: popw %ax
+ call print_hex_nibble
+ loop 1b
+ /* Restore registers and return */
+ popw %dx
+ popw %cx
+ popw %bx
+ popw %ax
+ ret
+
+/*****************************************************************************
+ * Subroutine: print PCI bus:dev.fn
+ *
+ * Parameters:
+ * %ax : PCI bus:dev.fn to print
+ * Returns:
+ * Nothing
+ *****************************************************************************
+ */
+print_pci_busdevfn:
+ /* Preserve registers */
+ pushw %ax
+ /* Print bus */
+ xchgb %al, %ah
+ call print_hex_byte
+ /* Print ":" */
+ movb $':', %al
+ call print_character
+ /* Print device */
+ movb %ah, %al
+ shrb $3, %al
+ call print_hex_byte
+ /* Print "." */
+ movb $'.', %al
+ call print_character
+ /* Print function */
+ movb %ah, %al
+ andb $0x07, %al
+ call print_hex_nibble
+ /* Restore registers and return */
+ popw %ax
+ ret
+
+/*****************************************************************************
+ * Subroutine: zero 1kB block of base memory
+ *
+ * Parameters:
+ * %si : block to zero (in kB)
+ * Returns:
+ * Nothing
*****************************************************************************
*/
-free_basemem:
- movw %fs:(0x13), %ax /* Current FBMS to %ax */
- cmpw %ax, %si /* Update FBMS only if "old" value */
- jne 1f /* is correct */
- movw %di, %fs:(0x13)
-1: movw %di, %bx
zero_kb:
- movw %si, %ax /* Zero kB at %si */
+ /* Preserve registers */
+ pushw %ax
+ pushw %cx
+ pushw %di
+ pushw %es
+ /* Zero block */
+ movw %si, %ax
shlw $6, %ax
movw %ax, %es
- xorw %ax, %ax
- xorw %di, %di
movw $0x400, %cx
+ xorw %di, %di
+ xorw %ax, %ax
rep stosb
- incw %si /* Move to next kB */
- cmpw %si, %bx
- jne zero_kb /* Loop until done */
- movw %fs:(0x13), %ax /* Print free base memory */
- call print_hex_word
- movb $0x20, %al /* ' ' */
- call print_character
+ /* Restore registers and return */
+ popw %es
+ popw %di
+ popw %cx
+ popw %ax
+ ret
+
+/*****************************************************************************
+ * Subroutine: free and zero base memory
+ *
+ * Parameters:
+ * %si : Expected current free base memory counter (in kB)
+ * %di : Desired new free base memory counter (in kB)
+ * %fs : BIOS data segment (0x40)
+ * Returns:
+ * %ax : Actual new free base memory counter (in kB)
+ *
+ * The base memory from %si kB to %di kB is unconditionally zeroed.
+ * It will be freed if and only if the expected current free base
+ * memory counter (%si) matches the actual current free base memory
+ * counter in 0x40:0x13; if this does not match then the memory will
+ * be leaked.
+ *****************************************************************************
+ */
+free_basemem:
+ /* Zero base memory */
+ pushw %si
+1: cmpw %si, %di
+ je 2f
+ call zero_kb
+ incw %si
+ jmp 1b
+2: popw %si
+ /* Free base memory */
+ movw %fs:(0x13), %ax /* Current FBMS to %ax */
+ cmpw %ax, %si /* Update FBMS only if "old" value */
+ jne 1f /* is correct */
+ movw %di, %ax
+1: movw %ax, %fs:(0x13)
ret
/*****************************************************************************
- * Make a PXE API call. Works with either !PXE or PXENV+ API.
- * Opcode in %bx. pxe_parameter_structure always used.
+ * Subroutine: make a PXE API call. Works with either !PXE or PXENV+ API.
*
- * Returns status code (not exit code) in %bx and prints it. Returns
- * with zero flag set if status code is zero (PXENV_STATUS_SUCCESS).
+ * Parameters:
+ * %bx : PXE API call number
+ * %ds:pxe_parameter_structure : Parameters for PXE API call
+ * Returns:
+ * %ax : PXE status code (not exit code)
+ * CF set if %ax is non-zero
*****************************************************************************
*/
pxe_call:
+ /* Preserve registers */
+ pushw %di
+ pushw %es
/* Set up registers for PXENV+ API. %bx already set up */
pushw %ds
popw %es
movw $pxe_parameter_structure, %di
/* Set up stack for !PXE API */
- pushw %cs
+ pushw %es
pushw %di
pushw %bx
/* Make the API call */
- lcall *pxe_entry_segoff
+ lcall *entry_segoff
/* Reset the stack */
addw $6, %sp
movw pxe_parameter_structure, %ax
- pushw %ax
+ clc
+ testw %ax, %ax
+ jz 1f
+ stc
+1: /* Restore registers and return */
+ popw %es
+ popw %di
+ ret
+
+/*****************************************************************************
+ * Subroutine: print PXE API call error message
+ *
+ * Parameters:
+ * %ax : PXE status code
+ * %bx : PXE API call number
+ * Returns:
+ * Nothing
+ *****************************************************************************
+ */
+print_pxe_error:
+ pushw %si
+ movw $10f, %si
+ call print_message
+ xchgw %ax, %bx
call print_hex_word
- movw $0x20, %ax /* ' ' */
- call print_character
- popw %bx
- orw %bx, pxe_overall_status
- testw %bx, %bx
+ movw $20f, %si
+ call print_message
+ xchgw %ax, %bx
+ call print_hex_word
+ movw $30f, %si
+ call print_message
+ popw %si
ret
+ .section ".prefix.data"
+10: .asciz " UNDI API call "
+20: .asciz " failed: status code "
+30: .asciz "\n"
+ .previous
/*****************************************************************************
* PXE data structures
*****************************************************************************
*/
-pxe_entry_segoff:
-pxe_entry_offset: .word 0
-pxe_entry_segment: .word 0
+pxe_parameter_structure: .fill 20
undi_code_segoff:
undi_code_size: .word 0
@@ -330,14 +658,30 @@ undi_data_segoff:
undi_data_size: .word 0
undi_data_segment: .word 0
+/* The following fields are part of a struct undi_device */
+
+undi_device:
+
+pxenv_segoff:
+pxenv_offset: .word 0
+pxenv_segment: .word 0
+
+ppxe_segoff:
+ppxe_offset: .word 0
+ppxe_segment: .word 0
+
+entry_segoff:
+entry_offset: .word 0
+entry_segment: .word 0
+
undi_fbms_start: .word 0
undi_fbms_end: .word 0
-pxe_parameter_structure:
- .word 0
- .word 0,0,0,0,0
+pci_busdevfn: .word 0xffff
+isapnp_csn: .word 0xffff
+isapnp_read_port: .word 0xffff
-pxe_overall_status: .word 0
+ .equ undi_device_size, ( . - undi_device )
/*****************************************************************************
* Run Etherboot main code