Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: PXE entry invalid, so PXE boot hangs



On Fri, Mar 27, 2015 at 09:46:54AM +0000, Stephen Borrill wrote:
> I'm trying to PXE boot an x86 box. The setup works fine on all my other kit,
> but on the problem one I see:
> 
> booting netbsd - starting in 0 seconds.
> pxe_init: bad cksum (0xbc) for PXENV+ at 0x900d8
> PXE BIOS Version 2.1
> *hang*
> 
> I'm prepared for a flaky BIOS, but it does boot pxelinux and Citrix
> Provisioning Services OK.
> 
> Adding a few printfs, I see it found PXENV+ at two locations: 0x900d8
> (rejected as bad checksum) and 0x8bb52. PXE+ was found at 0x8baf2. As it's
> PXE BIOS 2.1, it ignores the PXENV+ info. The hang is because it never
> returns from this call:
> 
> pxe_call(PXENV_GET_CACHED_INFO);
> 
> http://nxr.netbsd.org/xref/src/sys/arch/i386/stand/pxeboot/pxe.c#380
> 
> pxelinux uses 5 methods in priority order to find the pxe structure. NetBSD
> only uses a memory scan which is combination of its final 2 (it calls these
> plans D and E).
> 
> pxelinux prints:
> !PXE entry point found (we hope) at 8A44:0100 via plan A
> 
> http://git.kernel.org/cgit/boot/syslinux/syslinux.git/tree/core/fs/pxe/bios.c?id=a7f5892c4d85f3685708b8efb237c9c73a8b1ddf#n240
> 
> These addresses correspond to bangpxe_seg and bangpxe_off:
> http://nxr.netbsd.org/xref/src/sys/arch/i386/stand/pxeboot/pxe.c#360
> 
> Printing these shows that bangpxe_reg is 0, not 0x8a44. Hardwiring
> bangpxe_reg to 0x8a44 gets the machine booting (well, the kernel panics
> later on, but that's a different story).
> 
> Therefore, it looks like the structure found by memory scanning is incorrect
> and perhaps we should implement Linux's plans A and B (C being the int 0x1a
> function 0x5650 that we explicitly choose not to support). These involve
> reading points from offsets relative to InitStack. Where does this
> correspond to in NetBSD?

Is InitStack = 0xfffc ?

Untested patch attached...

Cheers,

Patrick
diff --git a/pxe.c b/pxe.c
index 3a094bf..650d74c 100644
--- a/pxe.c
+++ b/pxe.c
@@ -276,6 +276,21 @@ extern uint16_t pxenv_off, pxenv_seg;
 
 static struct btinfo_netif bi_netif;
 
+static int
+check_pxe(const uint8_t *pxe, const uint8_t pxelen, const char *msg)
+{
+	uint8_t i, cksum;
+
+	for (i = 0, cksum = 0; i < pxelen; i++)
+		cksum += pxe[i];
+	if (cksum != 0) {
+		printf("pxe_init: bad cksum (0x%x) for %s at 0x%lx\n",
+			cksum, msg, (u_long) pxe);
+	}
+
+	return (cksum == 0);
+}
+
 int
 pxe_init(void)
 {
@@ -284,8 +299,7 @@ pxe_init(void)
 	pxenv_t *pxenv;
 	pxe_t *pxe;
 	char *cp;
-	int i;
-	uint8_t cksum, *ucp;
+	SEGOFF16_t *bangpxe_addr;
 
 	/*
 	 * Checking for the presence of PXE is a machine-dependent
@@ -299,46 +313,51 @@ pxe_init(void)
 	 * to a deprecated structure (PXENV+).
 	 */
 
+	/*
+	 * The above comment is presumably taken from 3.1 p40 of spec v2.1.
+	 * As we are a "Network Bootstrap Program" (NBP), we don't need
+	 * the above installation check procedures as according to 4.4.5 p88,
+	 * we can use:
+	 *
+	 *  !PXE structure at SS:[SP+4]
+	 *
+	 *  PXENV+ structure at ES:BX (obsolete)
+	 *
+	 * and from pxe_start.S, SS:SP=0xfffc
+	 */
+
 	pxenv = NULL;
 	pxe = NULL;
 
-	for (cp = (char *)0xa0000; cp > (char *)0x10000; cp -= 2) {
-		if (pxenv == NULL) {
-			pxenv = (pxenv_t *)cp;
-			if (MEMSTRCMP(pxenv->Signature, "PXENV+"))
-				pxenv = NULL;
-			else {
-				for (i = 0, ucp = (uint8_t *)cp, cksum = 0;
-				     i < pxenv->Length; i++)
-					cksum += ucp[i];
-				if (cksum != 0) {
-					printf("pxe_init: bad cksum (0x%x) "
-					    "for PXENV+ at 0x%lx\n", cksum,
-					    (u_long) cp);
+	bangpxe_addr = (SEGOFF16_t *)(0xfffc + 4);
+	pxe = (pxe_t *)(bangpxe_addr->segment * 0x10 + bangpxe_addr->offset);
+	if (!check_pxe((uint8_t *)pxe, pxe->StructLength, "NBP !PXE")) {
+		pxe = NULL;
+		for (cp = (char *)0xa0000; cp > (char *)0x10000; cp -= 2) {
+			if (pxenv == NULL) {
+				pxenv = (pxenv_t *)cp;
+				if (MEMSTRCMP(pxenv->Signature, "PXENV+"))
 					pxenv = NULL;
+				else {
+					if (!check_pxe((uint8_t *)pxenv,
+					               pxenv->Length, "PXENV+"))
+						pxenv = NULL;
 				}
 			}
-		}
 
-		if (pxe == NULL) {
-			pxe = (pxe_t *)cp;
-			if (MEMSTRCMP(pxe->Signature, "!PXE"))
-				pxe = NULL;
-			else {
-				for (i = 0, ucp = (uint8_t *)cp, cksum = 0;
-				     i < pxe->StructLength; i++)
-					cksum += ucp[i];
-				if (cksum != 0) {
-					printf("pxe_init: bad cksum (0x%x) "
-					    "for !PXE at 0x%lx\n", cksum,
-					    (u_long) cp);
+			if (pxe == NULL) {
+				pxe = (pxe_t *)cp;
+				if (MEMSTRCMP(pxe->Signature, "!PXE"))
 					pxe = NULL;
-				}
+				else
+					if (!check_pxe((uint8_t *)pxe,
+					             pxe->StructLength, "!PXE"))
+						pxe = NULL;
 			}
-		}
 
-		if (pxe != NULL && pxenv != NULL)
-			break;
+			if (pxe != NULL && pxenv != NULL)
+				break;
+		}
 	}
 
 	if (pxe == NULL && pxenv == NULL) {


Home | Main Index | Thread Index | Old Index