bug-grub
[Top][All Lists]
Advanced

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

OpenBSD+GRUB+PXE patches


From: Cedric Berger
Subject: OpenBSD+GRUB+PXE patches
Date: Wed, 14 Mar 2001 14:36:20 -0800

To fulfill my GPL obligations and to the benefit of OpenBSD/GRUB hackers,
Here is a set of patch to boot a diskless OpenBSD using GRUB and a PXE
compatible Ethernet Card (tested with Intel EtherExpress 10/100 pro). The
GRUB patch is *not* a general purpose fix for booting OpenBSD with GRUB.

The GRUP patch is made of two files: a diff from the 0.5.95 cvs version and a
new openbsd.c file that must be put inside the stage2 directory.
With this patch, GRUB will try to load the kernel from one of the following 
files
on the server default tftp directory "bsd", "obsd", "bsd.old".

The OpenBSD patch is optional. Its purpose is to pass some additional
information from GRUB to the OpenBSD kernel, in order to:
  1) remove the RARP step, which is a pain to setup on the server, and which
      is redundant since PXE/GRUB use DHCP anyway
  2) support multi-homed hosts
  3) better support for subnetting

Notes:
  1) GRUB *requires* a recent Redhat Linux to compile. OpenBSD 2.8,
     FreeBSD 4.2 will refuse to compile it.
  2) use "--enable-diskless --enable-eepro100" to configure GRUB.
  2) I've been unable to compile with the latest GRUB 0.5.96.1, but "porting"
     the patch is straitforward.
  3) I'm *not* on the bug-grub mailing list.

Cedric

Index: netboot/main.c
===================================================================
RCS file: /cvsroot/grub/grub/netboot/main.c,v
retrieving revision 1.10
diff -u -r1.10 main.c
--- netboot/main.c      2000/06/07 15:35:18     1.10
+++ netboot/main.c      2001/03/14 22:07:36
@@ -52,7 +52,8 @@
 struct rom_info rom;
 
 static int vendorext_isvalid;
-static unsigned long netmask;
+unsigned long netmask = 0;
+unsigned long mybcast = 0;
 static struct bootpd_t bootp_data;
 static unsigned long xid;
 static unsigned char *end_of_rfc1533 = NULL;
@@ -164,15 +165,16 @@
     grub_printf ("Not initialized yet.\n");
   else
     {
-      char me[16], my_mask[16], server[16], gw[16];
+      char me[16], my_mask[16], my_bcast[16], server[16], gw[16];
 
       sprint_ip_addr (me, arptable[ARP_CLIENT].ipaddr.s_addr);
       sprint_ip_addr (my_mask, netmask);
+      sprint_ip_addr (my_bcast, mybcast);
       sprint_ip_addr (server, arptable[ARP_SERVER].ipaddr.s_addr);
       sprint_ip_addr (gw, arptable[ARP_GATEWAY].ipaddr.s_addr);
                       
-      grub_printf ("Address: %s    Netmask: %s\nServer: %s    Gateway: %s\n",
-                  me, my_mask, server, gw);
+      grub_printf ("Address: %s    Netmask: %s    Broadcast: %s"
+             "\nServer: %s    Gateway: %s\n", me, my_mask, my_bcast, server, 
gw);
     }
 }
 
@@ -321,6 +323,10 @@
   struct tftp_t tp;
   int rc;
   int packetsize = TFTP_DEFAULTSIZE_PACKET;
+
+  /* don't send absolute TFTP requeses */
+  if(*name == '/')
+       name++;
   
   /* Clear out the Rx queue first.  It contains nothing of interest,
    * except possibly ARP requests from the DHCP/TFTP server.  We use
@@ -935,6 +941,10 @@
            {
              end_of_rfc1533 = endp = p;
              continue;
+           }
+         else if (c == RFC1533_INTBROADCAST)
+           {
+             grub_memmove ((char *) &mybcast, p + 2, sizeof (in_addr));
            }
          else if (c == RFC1533_NETMASK)
            {
Index: stage2/boot.c
===================================================================
RCS file: /cvsroot/grub/grub/stage2/boot.c,v
retrieving revision 1.21
diff -u -r1.21 boot.c
--- stage2/boot.c       2000/05/04 22:15:20     1.21
+++ stage2/boot.c       2001/03/14 22:07:38
@@ -609,6 +609,11 @@
  */
 
 
+#if SUPPORT_DISKLESS // replace this code by OpenBSD hack
+#define obsd_diskless_boot bsd_boot
+#include "openbsd.c"
+#else
+
 void
 bsd_boot (kernel_t type, int bootdev, char *arg)
 {
@@ -748,3 +753,4 @@
                     extended_memory, mbi.mem_lower);
     }
 }
+#endif
Index: stage2/common.c
===================================================================
RCS file: /cvsroot/grub/grub/stage2/common.c,v
retrieving revision 1.12
diff -u -r1.12 common.c
--- stage2/common.c     2000/05/29 16:11:08     1.12
+++ stage2/common.c     2001/03/14 22:07:38
@@ -273,6 +273,11 @@
   saved_drive = boot_drive;
   saved_partition = install_partition;
 
+#ifdef SUPPORT_DISKLESS
+  //@@@ Direct OpenBSD start if possible
+  obsd_main();
+#endif
+
   /* Start main routine here.  */
   cmain ();
 }

Attachment: openbsd.c
Description: application/unknown-content-type-c_file

Index: sys/arch/i386/i386/bios.c
===================================================================
RCS file: /export/CVSroot/openbsd/sys/arch/i386/i386/bios.c,v
retrieving revision 1.42
diff -u -r1.42 bios.c
--- bios.c      2001/02/28 19:16:06     1.42
+++ bios.c      2001/03/14 22:25:41
@@ -65,6 +65,7 @@
 #include "apm.h"
 #include "pcibios.h"
 #include "pci.h"
+#include "ether.h"
 
 struct bios_softc {
        struct  device sc_dev;
@@ -95,6 +96,12 @@
 u_int32_t      bios_cksumlen;
 struct bios32_entry bios32_entry;
 
+#if defined(NFSCLIENT) && (NETHER > 0 || NFDDI > 0)
+bios_ip4info_t  *bios_ip4info;
+u_int32_t       bios_ip4info_nvec;
+bios_linkaddr_t *bios_linkaddr;
+#endif // NFSCLIENT
+
 bios_diskinfo_t *bios_getdiskinfo __P((dev_t));
 
 int
@@ -338,6 +345,47 @@
                                cnset(cdp->consdev);
                        }
                        break;
+
+#if defined(NFSCLIENT) && (NETHER > 0 || NFDDI > 0)
+               case BOOTARG_IP4INFO:
+                   bios_ip4info = (bios_ip4info_t*)q->ba_arg;
+                   bios_ip4info_nvec = (q->ba_size - sizeof(bootarg_t) +
+                           sizeof(q->ba_arg)) / sizeof(u_int32_t);
+#ifdef BIOS_DEBUG
+                   if(bios_ip4info_nvec >= 1 && bios_ip4info->ip4_myaddr)
+                       printf(" myip4addr %08X", bios_ip4info->ip4_myaddr);
+                   if(bios_ip4info_nvec >= 2 && bios_ip4info->ip4_mymask)
+                       printf(" myip4mask %08X", bios_ip4info->ip4_mymask);
+                   if(bios_ip4info_nvec >= 3 && bios_ip4info->ip4_mybcast)
+                       printf(" myip4bcast %08X", bios_ip4info->ip4_mybcast);
+#endif 
+               break;
+               case BOOTARG_LINKADDR:
+                   if (q->ba_size >= sizeof(bios_linkaddr_t))
+                   {
+#ifdef BIOS_DEBUG
+                       int i;
+#endif
+                       bios_linkaddr = (bios_linkaddr_t*)q->ba_arg;
+#ifdef BIOS_DEBUG
+                       printf(" linkaddr");
+#endif
+                       if (bios_linkaddr->la_alen > q->ba_size - 2) {
+#ifdef BIOS_DEBUG
+                               printf(" INVALID");
+#endif
+                               bios_linkaddr = NULL;
+                               break;
+                       }
+#ifdef BIOS_DEBUG
+                       printf(" %d", bios_linkaddr->la_alen);
+                       for (i = 0; i < bios_linkaddr->la_alen; i++)
+                               
printf("%c%02X",(i?':':'/'),bios_linkaddr->la_addr[i]);
+#endif
+                   }
+                   break;
+#endif //NFSCLIENT
+
 
                default:
 #ifdef BIOS_DEBUG
Index: sys/arch/i386/include/biosvar.h
===================================================================
RCS file: /export/CVSroot/openbsd/sys/arch/i386/include/biosvar.h,v
retrieving revision 1.38
diff -u -r1.38 biosvar.h
--- biosvar.h   2001/02/28 16:45:25     1.38
+++ biosvar.h   2001/03/14 22:25:41
@@ -197,6 +197,43 @@
        int     conspeed;
 } bios_consdev_t;
 
+/*
+ * our IP address as discovered by the bootstrap NIC 
+ */
+#define BOOTARG_IP4INFO 6
+typedef struct _bios_ip4info {
+    u_int32_t  ip4_myaddr;     /* if != 0, my IP address, as used by boot */
+    u_int32_t  ip4_mymask;     /* if != 0, my IP netmask, as used by boot */
+    u_int32_t  ip4_mybcast;    /* if != 0, my IP broadcast address */
+} bios_ip4info_t;
+extern bios_ip4info_t *bios_ip4info;
+extern u_int32_t       bios_ip4info_nvec;
+
+/*
+ * this macro is called by the NFS diskless code in nfs/nfs_boot.c
+ */
+#define BOOT_GETIP4INFO(addr, mask, bcast) do {          \
+    (addr) = (bios_ip4info && bios_ip4info_nvec >=1) ?   \
+       bios_ip4info->ip4_myaddr : 0;                    \
+    (mask) = (bios_ip4info && bios_ip4info_nvec >=2) ?   \
+       bios_ip4info->ip4_mymask : 0;                    \
+    (bcast) = (bios_ip4info && bios_ip4info_nvec >=3) ?  \
+       bios_ip4info->ip4_mybcast : 0;                   \
+} while(0)  
+
+/*
+ * the link address of the bootstrap NIC 
+ */
+#define BOOTARG_LINKADDR 7
+typedef struct _bios_linkaddr {
+       u_int8_t        la_type;
+       u_int8_t        la_alen;
+       u_int8_t        la_addr[6];
+} bios_linkaddr_t;
+extern bios_linkaddr_t *bios_linkaddr;
+#define BOOT_LINKADDR bios_linkaddr
+
+
 #if defined(_KERNEL) || defined (_STANDALONE)
 
 #ifdef _LOCORE
Index: sys/nfs/nfs_boot.c
===================================================================
RCS file: /export/CVSroot/openbsd/sys/nfs/nfs_boot.c,v
retrieving revision 1.11
diff -u -r1.11 nfs_boot.c
--- nfs_boot.c  1999/01/03 10:07:19     1.11
+++ nfs_boot.c  2001/03/14 22:25:46
@@ -41,6 +41,7 @@
 #include <sys/socketvar.h>
 
 #include <net/if.h>
+#include <net/if_dl.h>
 #include <net/route.h>
 
 #include <netinet/in.h>
@@ -56,6 +57,11 @@
 
 #include "ether.h"
 
+#ifdef i386
+#include <machine/biosvar.h>
+#endif
+
+
 #if !defined(NFSCLIENT) || (NETHER == 0 && NFDDI == 0)
 
 int
@@ -86,7 +92,7 @@
  * so we might as well take advantage of it for bootparam too.
  *
  * The diskless boot sequence goes as follows:
- * (1) Use RARP to get our interface address
+ * (1) Get BOOT parameters or Use RARP to get our interface address
  * (2) Use RPC/bootparam/whoami to get our hostname,
  *     our IP address, and the server's IP address.
  * (3) Use RPC/bootparam/getfile to get the root path
@@ -119,6 +125,7 @@
 {
        struct ifreq ireq;
        struct in_addr my_ip, gw_ip;
+       struct in_addr my_mask, my_bcast;
        struct sockaddr_in bp_sin;
        struct sockaddr_in *sin;
        struct ifnet *ifp;
@@ -139,6 +146,29 @@
         */
        if (nfsbootdevname)
                ifp = ifunit(nfsbootdevname);
+#ifdef BOOT_LINKADDR
+       else if(BOOT_LINKADDR) {
+                for (ifp = ifnet.tqh_first; ifp != 0; ifp = 
ifp->if_list.tqe_next)
+                        if ((ifp->if_flags &
+                             (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
+                       {
+                               struct ifaddr *ifa;
+                               struct sockaddr_dl *sdl;
+                               for(ifa = ifp->if_addrlist.tqh_first; ifa != 0;
+                                       ifa = ifa->ifa_list.tqe_next)
+                                               if ((sdl = (struct sockaddr_dl 
*)ifa->ifa_addr)
+                                               && sdl->sdl_family == AF_LINK
+                                               && sdl->sdl_type == 
BOOT_LINKADDR->la_type
+                                               && sdl->sdl_alen == 
BOOT_LINKADDR->la_alen
+                                               && !bcmp(LLADDR(sdl), 
BOOT_LINKADDR->la_addr, 
+                                                       BOOT_LINKADDR->la_alen))
+                                                       break;
+                               if(ifa != 0)
+                                       break;
+                       }
+       }
+
+#endif
        else
                for (ifp = ifnet.tqh_first; ifp != 0; ifp = 
ifp->if_list.tqe_next)
                        if ((ifp->if_flags &
@@ -167,25 +197,67 @@
                panic("nfs_boot: SIFFLAGS, error=%d", error);
 
        /*
-        * Do RARP for the interface address.
+        * If we're lucky, the boot already know who we are
+        * and we can get rid of the RARP step
         */
-       if ((error = revarpwhoami(&my_ip, ifp)) != 0)
+        #ifdef BOOT_GETIP4INFO
+        BOOT_GETIP4INFO(my_ip.s_addr, my_mask.s_addr, my_bcast.s_addr);
+        #else
+       my_ip.s_addr = my_mask.s_addr = my_bcast.s_addr = 0;
+        #endif
+       
+       if(my_ip.s_addr) {
+           printf("nfs_boot: client_addr=%s (boot)\n", inet_ntoa(my_ip));
+       } else {
+           /*
+            * Do RARP for the interface address.
+            */
+           if ((error = revarpwhoami(&my_ip, ifp)) != 0)
                panic("revarp failed, error=%d", error);
-       printf("nfs_boot: client_addr=%s\n", inet_ntoa(my_ip));
+           printf("nfs_boot: client_addr=%s (rarp)\n", inet_ntoa(my_ip));
+       }
 
        /*
         * Do enough of ifconfig(8) so that the chosen interface
-        * can talk to the servers.  (just set the address)
+        * can talk to the servers.
+        */
+        sin = (struct sockaddr_in *)&ireq.ifr_addr;
+        bzero((caddr_t)sin, sizeof(*sin));
+        sin->sin_len = sizeof(*sin);
+        sin->sin_family = AF_INET;
+
+        /*
+         * if we know our netmask, it's better to set it up before the
+        * IP address to prevent creating a bogus routing table entry when
+        * subnetting
+         */
+        if(my_mask.s_addr) {
+            printf("nfs_boot: client_mask=%s (boot)\n", inet_ntoa(my_mask));
+            sin->sin_addr.s_addr = my_mask.s_addr;
+            error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)&ireq, procp);
+            if (error)
+                panic("nfs_boot: set if mask, error=%d", error);
+        }
+
+       /*
+        * setup my IP address
         */
-       sin = (struct sockaddr_in *)&ireq.ifr_addr;
-       bzero((caddr_t)sin, sizeof(*sin));
-       sin->sin_len = sizeof(*sin);
-       sin->sin_family = AF_INET;
        sin->sin_addr.s_addr = my_ip.s_addr;
        error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp);
        if (error)
                panic("nfs_boot: set if addr, error=%d", error);
 
+       /*
+        * if we know our broadcast address, we can also set it up
+        */
+       if(my_bcast.s_addr) {
+           printf("nfs_boot: client_broadcast=%s (boot)\n", 
inet_ntoa(my_bcast));
+           sin->sin_addr.s_addr = my_bcast.s_addr;
+           error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)&ireq, procp);
+           if (error)
+               panic("nfs_boot: set if broadcast, error=%d", error);
+       }
+       
        soclose(so);
 
        /*

reply via email to

[Prev in Thread] Current Thread [Next in Thread]