aboutsummaryrefslogtreecommitdiffstats
path: root/gpxe/src/arch/i386
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/arch/i386')
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/ibft.c56
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_call.c20
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_entry.S8
-rw-r--r--gpxe/src/arch/i386/prefix/pxeprefix.S147
4 files changed, 175 insertions, 56 deletions
diff --git a/gpxe/src/arch/i386/interface/pcbios/ibft.c b/gpxe/src/arch/i386/interface/pcbios/ibft.c
index ffa65964..43d1f85f 100644
--- a/gpxe/src/arch/i386/interface/pcbios/ibft.c
+++ b/gpxe/src/arch/i386/interface/pcbios/ibft.c
@@ -137,6 +137,17 @@ static void ibft_set_ipaddr_option ( struct ibft_ipaddr *ipaddr,
}
/**
+ * Read IP address from iBFT (for debugging)
+ *
+ * @v strings iBFT string block descriptor
+ * @v string String field
+ * @ret ipaddr IP address string
+ */
+static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) {
+ return inet_ntoa ( ipaddr->in );
+}
+
+/**
* Allocate a string within iBFT
*
* @v strings iBFT string block descriptor
@@ -215,6 +226,18 @@ static int ibft_set_string_option ( struct ibft_string_block *strings,
}
/**
+ * Read string from iBFT (for debugging)
+ *
+ * @v strings iBFT string block descriptor
+ * @v string String field
+ * @ret data String content (or "<empty>")
+ */
+static const char * ibft_string ( struct ibft_string_block *strings,
+ struct ibft_string *string ) {
+ return ( ( ( char * ) strings->table ) + string->offset );
+}
+
+/**
* Fill in NIC portion of iBFT
*
* @v nic NIC portion of iBFT
@@ -231,11 +254,16 @@ static int ibft_fill_nic ( struct ibft_nic *nic,
/* Extract values from DHCP configuration */
ibft_set_ipaddr_option ( &nic->ip_address, &ip_setting );
+ DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) );
ibft_set_ipaddr_option ( &nic->gateway, &gateway_setting );
+ DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
ibft_set_ipaddr_option ( &nic->dns[0], &dns_setting );
+ DBG ( "iBFT NIC DNS = %s\n", ibft_ipaddr ( &nic->dns[0] ) );
if ( ( rc = ibft_set_string_option ( strings, &nic->hostname,
&hostname_setting ) ) != 0 )
return rc;
+ DBG ( "iBFT NIC hostname = %s\n",
+ ibft_string ( strings, &nic->hostname ) );
/* Derive subnet mask prefix from subnet mask */
fetch_ipv4_setting ( NULL, &netmask_setting, &netmask_addr );
@@ -245,11 +273,15 @@ static int ibft_fill_nic ( struct ibft_nic *nic,
netmask_addr.s_addr >>= 1;
}
nic->subnet_mask_prefix = netmask_count;
+ DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix );
/* Extract values from net-device configuration */
memcpy ( nic->mac_address, netdev->ll_addr,
sizeof ( nic->mac_address ) );
+ DBG ( "iBFT NIC MAC = %s\n",
+ netdev->ll_protocol->ntoa ( nic->mac_address ) );
nic->pci_bus_dev_func = netdev->dev->desc.location;
+ DBG ( "iBFT NIC PCI = %04x\n", nic->pci_bus_dev_func );
return 0;
}
@@ -269,6 +301,8 @@ static int ibft_fill_initiator ( struct ibft_initiator *initiator,
if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
initiator_iqn ) ) != 0 )
return rc;
+ DBG ( "iBFT initiator hostname = %s\n",
+ ibft_string ( strings, &initiator->initiator_name ) );
return 0;
}
@@ -286,17 +320,23 @@ static int ibft_fill_target_chap ( struct ibft_target *target,
struct iscsi_session *iscsi ) {
int rc;
- if ( ! iscsi->initiator_username )
+ if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_FORWARD_REQUIRED ) )
return 0;
+
+ assert ( iscsi->initiator_username );
assert ( iscsi->initiator_password );
target->chap_type = IBFT_CHAP_ONE_WAY;
if ( ( rc = ibft_set_string ( strings, &target->chap_name,
iscsi->initiator_username ) ) != 0 )
return rc;
+ DBG ( "iBFT target username = %s\n",
+ ibft_string ( strings, &target->chap_name ) );
if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
iscsi->initiator_password ) ) != 0 )
return rc;
+ DBG ( "iBFT target password = <redacted>\n" );
+
return 0;
}
@@ -313,19 +353,25 @@ static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
struct iscsi_session *iscsi ) {
int rc;
- if ( ! iscsi->target_username )
+ if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) )
return 0;
- assert ( iscsi->target_password );
+
assert ( iscsi->initiator_username );
assert ( iscsi->initiator_password );
+ assert ( iscsi->target_username );
+ assert ( iscsi->target_password );
target->chap_type = IBFT_CHAP_MUTUAL;
if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name,
iscsi->target_username ) ) != 0 )
return rc;
+ DBG ( "iBFT target reverse username = %s\n",
+ ibft_string ( strings, &target->chap_name ) );
if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret,
iscsi->target_password ) ) != 0 )
return rc;
+ DBG ( "iBFT target reverse password = <redacted>\n" );
+
return 0;
}
@@ -346,10 +392,14 @@ static int ibft_fill_target ( struct ibft_target *target,
/* Fill in Target values */
ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
+ DBG ( "iBFT target IP = %s\n", ibft_ipaddr ( &target->ip_address ) );
target->socket = ntohs ( sin_target->sin_port );
+ DBG ( "iBFT target port = %d\n", target->socket );
if ( ( rc = ibft_set_string ( strings, &target->target_name,
iscsi->target_iqn ) ) != 0 )
return rc;
+ DBG ( "iBFT target name = %s\n",
+ ibft_string ( strings, &target->target_name ) );
if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 )
return rc;
if ( ( rc = ibft_fill_target_reverse_chap ( target, strings,
diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_call.c b/gpxe/src/arch/i386/interface/pxe/pxe_call.c
index 04aaf3b2..06dee25c 100644
--- a/gpxe/src/arch/i386/interface/pxe/pxe_call.c
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_call.c
@@ -433,22 +433,24 @@ void pxe_init_structures ( void ) {
* @ret rc Return status code
*/
int pxe_start_nbp ( void ) {
- int discard_b, discard_c;
+ int discard_b, discard_c, discard_d, discard_D;
uint16_t rc;
/* Far call to PXE NBP */
- __asm__ __volatile__ ( REAL_CODE ( "pushw %%cx\n\t"
- "pushw %%ax\n\t"
- "movw %%cx, %%es\n\t"
+ __asm__ __volatile__ ( REAL_CODE ( "movw %%cx, %%es\n\t"
+ "pushw %%es\n\t"
+ "pushw %%di\n\t"
"sti\n\t"
"lcall $0, $0x7c00\n\t"
"addw $4, %%sp\n\t" )
: "=a" ( rc ), "=b" ( discard_b ),
- "=c" ( discard_c )
- : "a" ( __from_text16 ( &ppxe ) ),
- "b" ( __from_text16 ( &pxenv ) ),
- "c" ( rm_cs )
- : "edx", "esi", "edi", "ebp", "memory" );
+ "=c" ( discard_c ), "=d" ( discard_d ),
+ "=D" ( discard_D )
+ : "a" ( 0 ), "b" ( __from_text16 ( &pxenv ) ),
+ "c" ( rm_cs ),
+ "d" ( virt_to_phys ( &pxenv ) ),
+ "D" ( __from_text16 ( &ppxe ) )
+ : "esi", "ebp", "memory" );
return rc;
}
diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S
index 68b7374f..22ef4181 100644
--- a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S
@@ -178,6 +178,7 @@ pxe_entry_common:
* Returns:
* %ax : 0x564e
* %es:bx : Far pointer to the PXENV+ structure
+ * %edx : Physical address of the PXENV+ structure
* CF cleared
* Corrupts:
* none
@@ -191,9 +192,12 @@ pxe_int_1a:
cmpw $0x5650, %ax
jne 1f
/* INT 1A,5650 - PXE installation check */
- pushw %cs
- popw %es
+ xorl %edx, %edx
+ movw %cs, %dx
+ movw %dx, %es
movw $pxenv, %bx
+ shll $4, %edx
+ addl $pxenv, %edx
movw $0x564e, %ax
popfw
clc
diff --git a/gpxe/src/arch/i386/prefix/pxeprefix.S b/gpxe/src/arch/i386/prefix/pxeprefix.S
index ee0f4d94..b3b7947f 100644
--- a/gpxe/src/arch/i386/prefix/pxeprefix.S
+++ b/gpxe/src/arch/i386/prefix/pxeprefix.S
@@ -31,18 +31,10 @@
pushl $STACK_MAGIC
movw %ss, %cs:pxe_ss
movl %esp, %cs:pxe_esp
- movw %sp, %bp
- movl (10*4+4*2+4)(%bp),%ebp /* !PXE address */
- /* Set up %ds */
+ /* Set up segments */
movw %cs, %ax
movw %ax, %ds
- /* Record PXENV+ and !PXE nominal addresses */
- movw %es, pxenv_segment /* PXENV+ address */
- movw %bx, pxenv_offset
- movl %ebp, ppxe_segoff /* !PXE address */
- /* Set up %es and %fs */
- movw %ax, %es
movw $0x40, %ax /* BIOS data segment access */
movw %ax, %fs
/* Set up stack just below 0x7c00 */
@@ -60,16 +52,57 @@
.previous
/*****************************************************************************
- * Verify PXENV+ structure and record parameters of interest
+ * Find us a usable !PXE or PXENV+ entry point
*****************************************************************************
*/
-detect_pxenv:
- /* Signature check */
- les pxenv_segoff, %bx
- cmpl $0x4e455850, %es:(%bx) /* 'PXEN' signature */
- jne no_pxenv
- cmpw $0x2b56, %es:4(%bx) /* 'V+' signature */
- jne no_pxenv
+detect_pxe:
+ /* Plan A: !PXE pointer from the stack */
+ lgsl pxe_esp, %ebp /* %gs:%bp -> original stack */
+ lesw %gs:52(%bp), %bx
+ call is_valid_ppxe
+ je have_ppxe
+
+ /* Plan B: PXENV+ pointer from initial ES:BX */
+ movw %gs:32(%bp),%bx
+ movw %gs:8(%bp),%es
+ call is_valid_pxenv
+ je have_pxenv
+
+ /* Plan C: PXENV+ structure via INT 1Ah */
+ movw $0x5650, %ax
+ int $0x1a
+ jc 1f
+ cmpw $0x564e, %ax
+ jne 1f
+ call is_valid_pxenv
+ je have_pxenv
+1:
+ /* Plan D: scan base memory for !PXE */
+ call memory_scan_ppxe
+ je have_ppxe
+
+ /* Plan E: scan base memory for PXENV+ */
+ call memory_scan_pxenv
+ jne stack_not_found
+
+have_pxenv:
+ movw %bx, pxenv_offset
+ movw %es, pxenv_segment
+
+ cmpw $0x201, %es:6(%bx) /* API version >= 2.01 */
+ jb 1f
+ cmpb $0x2c, %es:8(%bx) /* ... and structure long enough */
+ jb 2f
+
+ lesw %es:0x28(%bx), %bx /* Find !PXE from PXENV+ */
+ call is_valid_ppxe
+ je have_ppxe
+2:
+ call memory_scan_ppxe /* We are *supposed* to have !PXE... */
+ je have_ppxe
+1:
+ lesw pxenv_segoff, %bx /* Nope, we're stuck with PXENV+ */
+
/* Record entry point and UNDI segments */
pushl %es:0x0a(%bx) /* Entry point */
popl entry_segoff
@@ -79,36 +112,22 @@ detect_pxenv:
pushw %es:0x20(%bx) /* UNDI data segment */
pushw %es:0x22(%bx) /* UNDI data size */
popl undi_data_segoff
+
/* Print "PXENV+ at <address>" */
movw $10f, %si
call print_message
call print_segoff
movb $( ',' ), %al
call print_character
- jmp 99f
+ jmp check_have_stack
.section ".prefix.data", "aw", @progbits
10: .asciz " PXENV+ at "
.previous
-no_pxenv:
- xorl %eax, %eax
- movl %eax, pxenv_segoff
-
-99:
-
-/*****************************************************************************
- * Verify !PXE structure and record parameters of interest
- *****************************************************************************
- */
-detect_ppxe:
- /* Signature check */
- les ppxe_segoff, %bx
- cmpl $0x45585021, %es:(%bx) /* '!PXE' signature */
- jne no_ppxe
- /* Record structure address, entry point, and UNDI segments */
- pushw %es
- popw ppxe_segment
+have_ppxe:
movw %bx, ppxe_offset
+ movw %es, ppxe_segment
+
pushl %es:0x10(%bx) /* Entry point */
popl entry_segoff
pushw %es:0x30(%bx) /* UNDI code segment */
@@ -123,17 +142,60 @@ detect_ppxe:
call print_segoff
movb $( ',' ), %al
call print_character
- jmp 99f
+ jmp check_have_stack
.section ".prefix.data", "aw", @progbits
10: .asciz " !PXE at "
.previous
-no_ppxe:
- xorl %eax, %eax
- movl %eax, ppxe_segoff
+is_valid_ppxe:
+ cmpl $0x45585021, %es:(%bx)
+ jne 1f
+ movzbw %es:4(%bx), %cx
+ cmpw $0x58, %cx
+ jae is_valid_checksum
+1:
+ ret
+
+is_valid_pxenv:
+ cmpl $0x4e455850, %es:(%bx)
+ jne 1b
+ cmpw $0x2b56, %es:4(%bx)
+ jne 1b
+ movzbw %es:8(%bx), %cx
+ cmpw $0x28, %cx
+ jb 1b
+
+is_valid_checksum:
+ pushw %ax
+ movw %bx, %si
+ xorw %ax, %ax
+2:
+ es lodsb
+ addb %al, %ah
+ loopw 2b
+ popw %ax
+ ret
+
+memory_scan_ppxe:
+ movw $is_valid_ppxe, %dx
+ jmp memory_scan_common
-99:
+memory_scan_pxenv:
+ movw $is_valid_pxenv, %dx
+memory_scan_common:
+ movw %fs:(0x13), %ax
+ shlw $6, %ax
+ decw %ax
+1: incw %ax
+ cmpw $( 0xa000 - 1 ), %ax
+ ja 2f
+ movw %ax, %es
+ xorw %bx, %bx
+ call *%dx
+ jne 1b
+2: ret
+
/*****************************************************************************
* Sanity check: we must have an entry point
*****************************************************************************
@@ -144,6 +206,7 @@ check_have_stack:
testl %eax, %eax
jnz 99f
/* No entry point: print message and skip everything else */
+stack_not_found:
movw $10f, %si
call print_message
jmp finished
@@ -529,8 +592,8 @@ print_pxe_error:
*/
.section ".prefix.data"
-pxe_ss: .word 0
pxe_esp: .long 0
+pxe_ss: .word 0
pxe_parameter_structure: .fill 20