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

Fix: YDL 4.0 network boot on Xserve G5



Some months ago, I asked about the trouble I had using yaboot
to boot an Xserve G5 over the network.  I found the problem some
time ago, but have only just found the time to report back.
My apologies to anyone who had the same problem and was waiting
(though I suspect that's the empty set).

The fundamental problem is that
a.  yaboot wants to read yaboot.conf from the same place whence
came yaboot itself; so it fetches the boot-path string with a
PROM call and parses it to get appropriate strings and numbers
to feed to a PROM call to open a new file.
b.  Different parsing is required for disk and network files,
so yaboot used a heuristic: if "enet" or "ethernet" appears
anywhere in the boot path, it's a network name.
c.  The Xserve G5 violates that heuristic by substituting in
the physical name for the network de4vice; for example, on the
system I'm working with,
	boot enet:0,yaboot
yields the pathname
	/ht@0,f20000000/pci@2/bcom5704@4:207.46.245.92,yaboot
(I have replaced the real IP address of my TFTP server with
207.46.245.92.)

Apparently bcom is what the network interface is called on my
machine, but yaboot doesn't know that (and why should it?), so
the string is mis-parsed as if yaboot was booted from disk, and
yaboot.conf cannot be opened.

I've worked around this by changing the heuristic: the path
is treated as a network address if

(a) it contains the string "ethernet" or "enet"
(b) the string after the leftmost colon begins with
zero or more digits followed by a dot; i.e. is more likely
to be an IP address than a simple disk partition number.

Of course this just replaces one possibly-weak heuristic with
another possibly-weak heuristic.  Since I don't have any other
Apple systems on which to test it, I don't know whether the new
heuristic violates some different assumption.  So although this
fixes my problem, use at your own risk unless approved by someone
more expert than me.  (Comments from such experts are welcome,
of course.)

Patch to yaboot 1.3.13 appended below.

Norman Wilson
Systems research lab, Department of Computer Science
University of Toronto

diff -rc ../yaboot-1.3.13-orig/second/file.c ./second/file.c
*** ../yaboot-1.3.13-orig/second/file.c	2003-02-10 04:18:13.000000000 -0500
--- ./second/file.c	2005-01-25 15:46:04.000000000 -0500
***************
*** 64,69 ****
--- 64,100 ----
      - hd:2,\\:tbxi <- no filename will be detected due to the extra :
      - enet:192.168.2.1,bootme,c-iaddr,g-iaddr,subnet-mask,bootp-retries,tftp-retries */
  
+ /*
+  * subfunction:
+  * is ipath a network string?
+  * yes if
+  *	-- contains "ethernet" or "enet"
+  *	-- mix of both digits and `.' following the colon,
+  *	i.e. probably an IP address and certainly not a partition number
+  * the former evidently is the rule on older Macs;
+  * the latter is required for (at least) Xserve G5, where
+  * 	boot enet:0,yaboot
+  * is turned by the prom into
+  *	/ht@0,f2000000/pci@2/bcom5704@4:192.168.2.1,yaboot
+  */
+ static int
+ networkdev(char *ipath)
+ {
+     char *p;
+ 
+     if (strstr(ipath, "ethernet") != NULL || strstr(ipath, "enet") != NULL)
+ 	return (1);
+     if ((p = strchr(ipath, ':')) == NULL)
+ 	return (0);
+     for (p++; *p && *p != ','; p++) {
+ 	if (*p == '.')
+ 	    return (1);
+         if (!isdigit(*p))
+ 	    return (0);
+     }
+     return (0);
+ }
+ 
  int
  parse_device_path(char *imagepath, char *defdevice, int defpart,
  		  char *deffile, struct boot_fspec_t *result)
***************
*** 106,119 ****
  	       }
  	  }
       }
! 
!      if (strstr(ipath, "ethernet") || strstr(ipath, "enet"))
! 	  if ((ptr = strstr(ipath, "bootp")) != NULL) { /* `n' key booting boots enet:bootp */
  	       *ptr = 0;
  	       result->dev = strdup(ipath);
  	  } else
  	       result->dev = strdup(ipath);
!      else if ((ptr = strchr(ipath, ':')) != NULL) {
  	  *ptr = 0;
  	  result->dev = strdup(ipath);
  	  if (*(ptr+1))
--- 137,149 ----
  	       }
  	  }
       }
!      if (networkdev(ipath)) {
!  	  if ((ptr = strstr(ipath, "bootp")) != NULL) { /* `n' key booting boots enet:bootp */
  	       *ptr = 0;
  	       result->dev = strdup(ipath);
  	  } else
  	       result->dev = strdup(ipath);
!      } else if ((ptr = strchr(ipath, ':')) != NULL) {
  	  *ptr = 0;
  	  result->dev = strdup(ipath);
  	  if (*(ptr+1))