--- netboot/main.c	Sat Oct 10 23:02:07 1998
+++ xboot/main.c	Mon Jun  7 15:30:42 1999
@@ -9,10 +9,16 @@
 /* #define MDEBUG */
 
 #include "netboot.h"
+#include <elf.h>
 
 int	jmp_bootmenu[10];
 
-struct	exec head;
+union {
+	struct	exec	aout;
+	Elf32_Ehdr	elf;
+	char		pad[PAGE_SIZE];
+} hdr;
+char	symwork[PAGE_SIZE];
 char	*loadpoint;
 char	*kernel;
 char	kernel_buf[128];
@@ -31,6 +37,12 @@
 extern	int packetlen, rpc_id;
 char	broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
+char *	/* return the last loaded address (a.k.a. bootinfo.bi_esymtab) */
+load_elfsymtab( Elf32_Ehdr *elf32, Elf32_Phdr *phdr, char *loadaddr);
+#ifdef MDEBUG
+void exit(int);
+#endif /* MDEBUG */
+
 /**************************************************************************
 MAIN - Kick off routine
 **************************************************************************/
@@ -66,6 +78,8 @@
 		exit(0);
 	}
 	kernel = DEFAULT_BOOTFILE;
+	sprintf(&nfsdiskless.myif.ifra_name,eth_driver);
+	sprintf(&nfsdiskless.root_hostnam,"");
 	while (1) {
 		if (setjmp(jmp_bootmenu))
 			bootmenu();
@@ -74,6 +88,16 @@
 	}
 }
 
+#ifdef MDEBUG
+void
+exit(i)
+	int i;
+{
+	printf("\r\n=>>"); getchar(); printf("\r\n");
+	mexit(i);
+}
+#endif
+
 void
 nfsload(length)
 {
@@ -112,6 +136,8 @@
 	long	addr, broadcast;
 	int	swsize;
 	unsigned long pad;
+	int	remain;
+	char	*lastaddr;
 
 	config_buffer[0]='\0'; /* clear; bootp might fill this up */
 /* Initialize this early on */
@@ -142,7 +168,7 @@
 		arptable[ARP_GATEWAY].ipaddr);
 
 #ifdef MDEBUG
-	printf("\n=>>"); getchar();
+	printf("\r\n=>>"); getchar(); printf("\r\n");
 #endif
 
 	/*** check if have got info from bootp ***/
@@ -159,7 +185,11 @@
 	sprintf(cfg,"/tftpboot/cfg.%I",arptable[ARP_CLIENT].ipaddr);
 	if (tftp(cfg) || tftp(cfg+10))
 		goto cfg_done;
+
 #endif
+	if (nfsdiskless.root_hostnam[0] != '\0')
+		goto cfg_done;
+
 	/* not found; using default values... */
 	sprintf(config_buffer,"rootfs %I:/usr/diskless_root",
 		arptable[ARP_SERVER].ipaddr);
@@ -168,7 +198,7 @@
 
 cfg_done:
 #ifdef MDEBUG
-	printf("\n=>>"); getchar();
+	printf("\r\n=>>"); getchar(); printf("\r\n");
 #endif
 
 	p = config_buffer;
@@ -182,7 +212,7 @@
 	}
 
 #ifdef MDEBUG
-	printf("\n=>>"); getchar();
+	printf("\r\n=>>"); getchar(); printf("\r\n");
 #endif
 
 		/* Check to make sure we've got a rootfs */
@@ -192,7 +222,7 @@
 	}
 
 		/* Fill in nfsdiskless.myif */
-	sprintf(&nfsdiskless.myif.ifra_name,eth_driver);
+	/* sprintf(&nfsdiskless.myif.ifra_name,eth_driver); */
         nfsdiskless.myif.ifra_addr.sa_len = sizeof(struct sockaddr);
         nfsdiskless.myif.ifra_addr.sa_family = AF_INET;
 	addr = htonl(arptable[ARP_CLIENT].ipaddr);
@@ -283,62 +313,246 @@
 		/* Load the kernel using NFS */
 	printf("Loading %s...\r\n",kernel);
 	if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, &kernel_handle, 0,
-		sizeof(struct exec), &head)) < 0) {
+		sizeof(hdr), &hdr)) < 0) {
 		printf("Unable to read %s: ",kernel);
 		nfs_err(err);
 		longjmp(jmp_bootmenu,1);
 	}
-	if (N_BADMAG(head)) {
-		printf("Bad executable format!\r\n");
-		longjmp(jmp_bootmenu, 1);
-	}
-	loadpoint = (char *)(head.a_entry & 0x00FFFFFF);
-	offset = N_TXTOFF(head);
-	printf("text=0x%X, ",head.a_text);
-	nfsload(head.a_text);
-	while (((int)loadpoint) & PAGE_MASK)
-		*(loadpoint++) = 0;
+	printf( "kernel type is: ");
+	if(IS_ELF(hdr.elf)) {
+		Elf32_Ehdr	*elf32= &hdr.elf;
+		Elf32_Phdr	*phdr;
+		printf( "ELF\r\n");
+		if (elf32->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */
+		    elf32->e_ident[EI_DATA] != ELF_TARG_DATA ||
+		    elf32->e_ident[EI_VERSION] != EV_CURRENT ||   /* Version ? */
+		    elf32->e_version != EV_CURRENT ||
+		    elf32->e_machine != ELF_TARG_MACH) {          /* Machine ? */
+			printf("Bad ELF target architecture!\r\n");
+			longjmp(jmp_bootmenu, 1);
+		}
 
-	printf("data=0x%X, ",head.a_data);
-	nfsload(head.a_data);
+		if( (elf32->e_phoff + elf32->e_phnum * sizeof(*phdr))
+		    > sizeof(hdr)) {
+			printf("program header not within first page\n");
+			longjmp(jmp_bootmenu, 1);
+		}
 
-	printf("bss=0x%X, ",head.a_bss);
-	while(head.a_bss--) *(loadpoint++) = 0;
+		lastaddr = 0;
+		loadpoint = (char *)(elf32->e_entry & 0x00FFFFFF);
+		phdr = (Elf32_Phdr*)((char*)&hdr + elf32->e_phoff);
 
-	while (((int)loadpoint) & PAGE_MASK)
-		*(loadpoint++) = 0;
+		for( i= 0; i< elf32->e_phnum; i++) {
+			if( phdr[i].p_type != PT_LOAD) {
+				continue;
+			}
+			printf("phdr[%d]: load=0x%X, ", i, phdr[i].p_vaddr);
+#ifdef ELF_VERBOSE
+			printf("Segment: 0x%X@0x%X -> 0x%X-0x%X",
+			       (long)phdr[i].p_filesz, (long)phdr[i].p_offset,
+			       (long)(phdr[i].p_vaddr),
+			    (long)(phdr[i].p_vaddr + phdr[i].p_memsz - 1));
+#else
+			if ((phdr[i].p_flags & PF_W) == 0) {
+				printf("text=0x%X\r\n", (long)phdr[i].p_filesz);
+			} else {
+				printf("data=0x%X", (long)phdr[i].p_filesz);
+				if (phdr[i].p_filesz < phdr[i].p_memsz)
+					printf("+0x%X",
+				      (long)(phdr[i].p_memsz -phdr[i].p_filesz));
+				printf("\r\n");
+			}
+#endif
+			loadpoint = (char*)(phdr[i].p_vaddr & 0x00FFFFFF);
+			offset = phdr[i].p_offset;
+			nfsload(phdr[i].p_filesz);
+
+			if (phdr[i].p_filesz < phdr[i].p_memsz) {
+				printf(" (bss: 0x%X-0x%X)\r\n",
+				       (long)(phdr[i].p_vaddr
+					      + phdr[i].p_filesz),
+				       (long)(phdr[i].p_vaddr
+					      + phdr[i].p_memsz - 1));
 
-	bootinfo.bi_symtab = (u_int32_t)loadpoint;
+				remain= phdr[i].p_memsz - phdr[i].p_filesz;
+				while(remain--) *(loadpoint++) = 0;
+			}
+			if( lastaddr == 0 || lastaddr < loadpoint) {
+				lastaddr = loadpoint;
+				/* round up */
+#ifdef MDEBUG
+		printf("\r\nround: %d\r\n", (size_t)lastaddr % sizeof(long));
+#endif /* MDEBUG */
+				if( (size_t)lastaddr % sizeof(long)) {
+					lastaddr += sizeof(long);
+					lastaddr -= ((size_t)lastaddr % sizeof(long));
+				}
+			}
+		}
 
-	p = (char*)&head.a_syms;
-	for (i=0;i<sizeof(head.a_syms);i++)
-		*loadpoint++ = *p++;
+		/* load symbol tables. */
+		bootinfo.bi_symtab = (u_int32_t)lastaddr;
+		bootinfo.bi_esymtab= (u_int32_t)load_elfsymtab(
+			elf32, phdr, lastaddr);
 
-	printf("symbols=[+0x%x+0x%x", sizeof(head.a_syms), head.a_syms);
+		if( bootinfo.bi_symtab == bootinfo.bi_esymtab) {
+			bootinfo.bi_symtab = bootinfo.bi_esymtab = 0;
+		}
+
+		printf("symbols=[+0x%x+0x%x]\r\n",
+		       bootinfo.bi_symtab,
+		       bootinfo.bi_esymtab);
+		printf("entry=0x%X.\n\r",elf32->e_entry);
+
+		kernelentry = (void *)(elf32->e_entry & 0x00FFFFFF);
+	}
+	else if (!N_BADMAG(hdr.aout)) {
+		struct exec *head= &hdr.aout;
+		printf( "a.out\r\n");
+		loadpoint = (char *)(head->a_entry & 0x00FFFFFF);
+		offset = N_TXTOFF(*head);
+		printf("text=0x%X, ",head->a_text);
+		nfsload(head->a_text);
+		while (((int)loadpoint) & PAGE_MASK)
+			*(loadpoint++) = 0;
+
+		printf("data=0x%X, ",head->a_data);
+		nfsload(head->a_data);
+
+		printf("bss=0x%X, ",head->a_bss);
+		while(head->a_bss--) *(loadpoint++) = 0;
+
+		while (((int)loadpoint) & PAGE_MASK)
+			*(loadpoint++) = 0;
+
+		bootinfo.bi_symtab = (u_int32_t)loadpoint;
+
+		p = (char*)&head->a_syms;
+		for (i=0;i<sizeof(head->a_syms);i++)
+			*loadpoint++ = *p++;
+
+		printf("symbols=[+0x%x+0x%x", sizeof(head->a_syms), head->a_syms);
 	
-	nfsload(head.a_syms);
-	i = sizeof(int);
-	p = loadpoint;
-	nfsload(i);
-	i = *(int*)p;
-	printf("+0x%x]\n", i);
-	i -= sizeof(int);
-	nfsload(i);
-	bootinfo.bi_esymtab = (u_int32_t)loadpoint;
+		nfsload(head->a_syms);
+		i = sizeof(int);
+		p = loadpoint;
+		nfsload(i);
+		i = *(int*)p;
+		printf("+0x%x]\r\n", i);
+		i -= sizeof(int);
+		nfsload(i);
+		bootinfo.bi_esymtab = (u_int32_t)loadpoint;
 
-	printf("entry=0x%X.\n\r",head.a_entry);
+		printf("entry=0x%X.\r\n",head->a_entry);
 
+		kernelentry = (void *)(head->a_entry & 0x00FFFFFF);
+	}
+	else {
+		printf("Bad executable format!\r\n");
+		longjmp(jmp_bootmenu, 1);
+	}
+#ifdef MDEBUG
+	printf("\r\n=>>"); getchar(); printf("\r\n");
+#endif
 		/* Jump to kernel */
 	bootinfo.bi_version = BOOTINFO_VERSION;
 	bootinfo.bi_kernelname = (u_int32_t)kernel;
 	bootinfo.bi_nfs_diskless = (u_int32_t)&nfsdiskless;
 	bootinfo.bi_size = sizeof bootinfo;
-	kernelentry = (void *)(head.a_entry & 0x00FFFFFF);
 	(*kernelentry)(howto|RB_BOOTINFO,NODEV,0,0,0,&bootinfo,0,0,0);
 	printf("*** %s execute failure ***\n",kernel);
 }
 
 /**************************************************************************
+load_elfsymtab - load the elf symbol tables
+**************************************************************************/
+char *	/* return the last loaded address (a.k.a. bootinfo.bi_esymtab) */
+load_elfsymtab( elf32, phdr, loadaddr)
+	Elf32_Ehdr	*elf32;
+	Elf32_Phdr	*phdr;
+	char		*loadaddr;
+{
+	Elf32_Shdr	*shdr;
+	int	shsize;
+	int	symstrindex;
+	int	symtabindex;
+	int	i, j;
+	long	wrksize;
+	char	*lastaddr = loadaddr;
+
+
+	printf("loading symbol header.\r\n");
+
+	shsize = elf32->e_shnum * elf32->e_shentsize;
+	if( shsize == 0 || elf32->e_shoff == 0) {
+		return lastaddr;
+	}
+	if( shsize > sizeof( symwork) ) {
+		printf("symbol header(0x%x) exceeds page size.\n", shsize);
+		return lastaddr;
+		/* longjmp(jmp_bootmenu, 1); */
+	}
+	loadpoint = symwork;
+	offset = elf32->e_shoff;
+	nfsload(shsize);
+
+	shdr = (Elf32_Shdr*)&symwork;
+	symtabindex = -1;
+	symstrindex = -1;
+	for( i = 0; i < elf32->e_shnum; i++) {
+		if( shdr[i].sh_type != SHT_SYMTAB)
+			continue;
+		for( j= 0; j < elf32->e_phnum; j++) {
+			if( phdr[j].p_type != PT_LOAD)
+				continue;
+			if (shdr[i].sh_offset >= phdr[j].p_offset &&
+			    (shdr[i].sh_offset + shdr[i].sh_size <=
+			     phdr[j].p_offset + phdr[j].p_filesz)) {
+				shdr[i].sh_offset = 0;
+				shdr[i].sh_size = 0;
+				break;
+			}
+		}
+		if ( shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
+			continue;
+
+		symtabindex = i;
+		symstrindex = shdr[i].sh_link;
+	}
+
+	if( symtabindex < 0 || symstrindex < 0)
+		return lastaddr;
+
+
+	for (i = symtabindex; i >= 0; i = symstrindex) {
+		printf("shdr[%d]: load=0x%X off=0x%X size=0x%X\r\n",
+			i, lastaddr,
+			shdr[i].sh_offset, shdr[i].sh_size);
+
+		*(long*)lastaddr = shdr[i].sh_size;
+		lastaddr += sizeof(long);
+
+
+		offset = shdr[i].sh_offset;
+		loadpoint = lastaddr;
+		nfsload(shdr[i].sh_size);
+		lastaddr = loadpoint;
+
+		/* round up */
+#ifdef MDEBUG
+		printf("round: %d\r\n", (size_t)lastaddr % sizeof(long));
+#endif /* MDEBUG */
+		if( (size_t)lastaddr % sizeof(long)) {
+			lastaddr += sizeof(long);
+			lastaddr -= ((size_t)lastaddr % sizeof(long));
+		}
+		if( i == symtabindex)		symtabindex = -1;
+		else if ( i == symstrindex)	symstrindex = -1;
+	}
+	return lastaddr;
+}
+
+/**************************************************************************
 POLLKBD - Check for Interrupt from keyboard
 **************************************************************************/
 pollkbd()
@@ -661,8 +875,10 @@
 			case 131:       /* swap mount options */
 				bootp_string("swapopts", p);
 				break;
-			case 132:       /* any other options */
-			case 133:
+			case 132:       /* interface name */
+				bootp_string("interface", p);
+				break;
+			case 133:       /* any other options */
 			case 134:
 			case 135:
 			case 136:
--- netboot/bootmenu.c	Tue Jun 30 20:10:26 1998
+++ xboot/bootmenu.c	Mon May 24 10:54:35 1999
@@ -28,10 +28,11 @@
 	{"help",	cmd_help,	"              this list"},
 	{"ip",		cmd_ip,		"<addr>          set my IP addr"},
 	{"server",	cmd_server,	"<addr>      set TFTP server IP addr"},
-	{"gateway",	cmd_gateway,	"<addr>      set default router"},
+	{"gateway",	cmd_gateway,	"<addr>     set default router"},
 	{"netmask",	cmd_netmask,	"<addr>     set network mask"},
 	{"hostname",	cmd_hostname,	"<name>    set hostname"},
 	{"kernel",	cmd_kernel,	"<file>      set boot filename"},
+	{"interface",	cmd_interface,	"<name>   set default interface"},
 	{"rootfs",	cmd_rootfs,	"[ip:]/fs    set root filesystem"},
 	{"swapfs",	cmd_swapfs,	"[ip:]/fs    set swap filesystem"},
 	{"swapsize",	cmd_swapsize,	"<nblks>   set swap size"},
@@ -40,7 +41,7 @@
 	{"diskboot",	exit,		"          boot from disk"},
 	{"autoboot",	NULL,		"          continue"},
         {"trans",       cmd_aui,        "<on|off>     turn transceiver on|off"},
-	{"flags",       cmd_flags,      "[bcdghsv] set boot flags"},
+	{"flags",       cmd_flags,      "[bcdghsv]    set boot flags"},
 	{NULL,		NULL,		NULL}
 };
 
@@ -153,6 +154,15 @@
 	printf("Bootfile is: %s\r\n", kernel);
 }
 
+/**************************************************************************
+CMD_INTERFACE - set interface name
+**************************************************************************/
+cmd_interface(p)
+	char *p;
+{
+	if (*p) sprintf(nfsdiskless.myif.ifra_name,"%s",p);
+	printf("Interface is: %s\r\n",nfsdiskless.myif.ifra_name);
+}
 
 /**************************************************************************
 CMD_ROOTFS - Set root filesystem name
@@ -165,7 +175,8 @@
 		    &arptable[ARP_ROOTSERVER].ipaddr, 4);
 	} else if (!setip(p, &arptable[ARP_ROOTSERVER].ipaddr)) {
 		printf("Root filesystem is %I:%s\r\n",
-			nfsdiskless.root_saddr.sin_addr,
+			arptable[ARP_ROOTSERVER].ipaddr,
+		/* - swap byte order - nfsdiskless.root_saddr.sin_addr, */
 			nfsdiskless.root_hostnam);
 		return;
 	} else {
@@ -327,7 +338,7 @@
 		} else
 			cmd++;
 	}
-	printf("bad command - type 'help' for list\n\r");
+	printf("%s: bad command - type 'help' for list\n\r", buf);
 	return(0);
 }
 
--- netboot/start2.S	Fri Sep 18 03:43:18 1998
+++ xboot/start2.S	Wed May 26 04:58:55 1999
@@ -104,8 +104,13 @@
 	opsize
 	call	_real_to_prot
 	call	_main
+#ifdef MDEBUG
+	.globl	_mexit
+_mexit:
+#else /* MDEBUG */
 	.globl	_exit
 _exit:
+#endif /* MDEBUG */
 	call	_prot_to_real
 #ifdef BOOTROM
 	xor	%eax,%eax
@@ -118,7 +123,13 @@
 	push	%eax
 	lret
 #else
-	int	$0x19
+	movb	$0xfe,%al
+	outb	%al, $0x64
+2:
+	sti
+	hlt
+	opsize
+	jmp	2b
 #endif
 
 /**************************************************************************
@@ -420,7 +431,7 @@
 /**************************************************************************
 GLOBAL DESCRIPTOR TABLE
 **************************************************************************/
-	.align	4
+	.p2align	4
 gdt:
 	.word	0, 0
 	.byte	0, 0x00, 0x00, 0
@@ -441,7 +452,7 @@
 	.word	0xffff, RELOC & 0xffff
 	.byte	(RELOC>>16), 0x93, 0x00, (RELOC>>24)
 
-	.align	4
+	.p2align	4
 gdtarg:
 	.word	0x27			/* limit */
 	.long	gdt			/* addr */
