summaryrefslogtreecommitdiffstats
path: root/sys/i386/boot/netboot
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1994-10-17 17:55:31 +0000
committerphk <phk@FreeBSD.org>1994-10-17 17:55:31 +0000
commit3636a6db90729528acb82dbb4612983e7a4e1988 (patch)
treeeb4baacdcdcce1af9c3e2cab56ba99f776dc5f74 /sys/i386/boot/netboot
parent071d10f334b2e0094018c4b2027c8e3e73833bc1 (diff)
downloadFreeBSD-src-3636a6db90729528acb82dbb4612983e7a4e1988.zip
FreeBSD-src-3636a6db90729528acb82dbb4612983e7a4e1988.tar.gz
Netboot TNG. I have seen this compile, I don't know if it works.
I have put it here, because I belive we could share some code among the various kinds of boot-code, whenever we get the time to look at it. Submitted by: Martin Renters
Diffstat (limited to 'sys/i386/boot/netboot')
-rw-r--r--sys/i386/boot/netboot/Makefile61
-rw-r--r--sys/i386/boot/netboot/bootmenu.c229
-rw-r--r--sys/i386/boot/netboot/ether.c479
-rw-r--r--sys/i386/boot/netboot/ether.h178
-rw-r--r--sys/i386/boot/netboot/main.c525
-rw-r--r--sys/i386/boot/netboot/makerom.c42
-rw-r--r--sys/i386/boot/netboot/misc.c261
-rw-r--r--sys/i386/boot/netboot/netboot.doc42
-rw-r--r--sys/i386/boot/netboot/netboot.h237
-rw-r--r--sys/i386/boot/netboot/rpc.c187
-rw-r--r--sys/i386/boot/netboot/start2.S332
11 files changed, 2573 insertions, 0 deletions
diff --git a/sys/i386/boot/netboot/Makefile b/sys/i386/boot/netboot/Makefile
new file mode 100644
index 0000000..d4661ac
--- /dev/null
+++ b/sys/i386/boot/netboot/Makefile
@@ -0,0 +1,61 @@
+# Makefile for NETBOOT
+#
+# Options:
+# -DASK_BOOT - Ask "Boot from Network (Y/N) ?" at startup
+# -DSMALL_ROM - Compile for 8K ROMS
+# -DROMSIZE - Size of EPROM - Must be set (even for .COM files)
+# -DRELOC - Relocation address (usually 0x90000)
+# -DINCLUDE_WD - Include Western Digital/SMC support
+# -DINCLUDE_NE - Include NE1000/NE2000 support
+# -DNE_BASE - Base I/O address for NE1000/NE2000
+# -DWD_DEFAULT_MEM- Default memory location for WD/SMC cards
+#
+ROMSIZE=16384
+RELOCADDR=0x90000
+#CFLAGS= -O2 -DNFS -DINCLUDE_WD -DINCLUDE_NE -DROMSIZE=$(ROMSIZE) \
+# -DRELOC=$(RELOCADDR) -DNE_BASE=0x320 -DWD_DEFAULT_MEM=0xD0000
+CFLAGS= -O2 -DNFS -DINCLUDE_WD -DROMSIZE=$(ROMSIZE) \
+ -DRELOC=$(RELOCADDR) -DNE_BASE=0x320 -DWD_DEFAULT_MEM=0xD0000
+
+HDRS=netboot.h
+COBJS=main.o misc.o ether.o bootmenu.o rpc.o
+SSRCS=start2.S
+SOBJS=start2.o
+
+.SUFFIXES: .c .S .s .o
+
+all: netboot.com netboot.rom
+
+makerom: makerom.c
+ cc -o makerom -DROMSIZE=$(ROMSIZE) makerom.c
+
+netboot.com: $(COBJS) $(SSRCS)
+ cc -c $(CFLAGS) $(SSRCS)
+ ld -e _start -T $(RELOCADDR) -N $(SOBJS) $(COBJS)
+ strip a.out
+ size a.out
+ dd ibs=32 skip=1 <a.out >netboot.com
+
+netboot.rom: $(COBJS) $(SSRCS) makerom
+ cc -c $(CFLAGS) -DBOOTROM $(SSRCS)
+ ld -e _start -T $(RELOCADDR) -N $(SOBJS) $(COBJS)
+ strip a.out
+ size a.out
+ dd ibs=32 skip=1 <a.out >netboot.rom
+ ./makerom netboot.rom
+
+test: netboot.com
+ mount -t pcfs /dev/fd0a /msdos
+ cp netboot.com /msdos/netboot.com
+ cp netboot.rom /msdos/netboot.rom
+ umount /msdos
+clean:
+ rm -f $(COBJS) $(SOBJS) *.s netboot.com netboot.rom a.out makerom
+
+.c.o: Makefile $(HDRS)
+ cc $(CFLAGS) -c $<
+
+.c.s: Makefile $(HDRS)
+ cc $(CFLAGS) -S $<
+
+
diff --git a/sys/i386/boot/netboot/bootmenu.c b/sys/i386/boot/netboot/bootmenu.c
new file mode 100644
index 0000000..7313dc7
--- /dev/null
+++ b/sys/i386/boot/netboot/bootmenu.c
@@ -0,0 +1,229 @@
+/**************************************************************************
+NETBOOT - BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+ Date: Dec/93
+
+**************************************************************************/
+#include "netboot.h"
+
+extern struct nfs_diskless nfsdiskless;
+extern int hostnamelen;
+extern unsigned long netmask;
+
+int cmd_ip(), cmd_server(), cmd_kernel(), cmd_help(), exit();
+int cmd_rootfs(), cmd_swapfs(), cmd_interface(), cmd_hostname();
+int cmd_netmask();
+
+#ifdef SMALL_ROM
+struct bootcmds_t {
+ char *name;
+ int (*func)();
+} bootcmds[] = {
+ {"ip", cmd_ip},
+ {"server", cmd_server},
+ {"bootfile", cmd_bootfile},
+ {"diskboot", exit},
+ {"autoboot", NULL},
+ {NULL, NULL}
+};
+
+#else /* !SMALL ROM */
+
+struct bootcmds_t {
+ char *name;
+ int (*func)();
+ char *help;
+} bootcmds[] = {
+ {"help", cmd_help, " this list"},
+ {"ip", cmd_ip, "<addr> set my IP addr"},
+ {"server", cmd_server, "<addr> set TFTP server IP addr"},
+ {"netmask", cmd_netmask, "<addr> set network mask"},
+ {"hostname", cmd_hostname, " set hostname"},
+ {"kernel", cmd_kernel, "<file> set boot filename"},
+ {"rootfs", cmd_rootfs, " set root filesystem"},
+ {"swapfs", cmd_swapfs, " set swap filesystem"},
+ {"diskboot", exit, " boot from disk"},
+ {"autoboot", NULL, " continue"},
+ {NULL, NULL, NULL}
+};
+
+/**************************************************************************
+CMD_HELP - Display help screen - NOT FOR SMALL ROMS
+**************************************************************************/
+cmd_help()
+{
+ struct bootcmds_t *cmd = bootcmds;
+ printf("\r\n");
+ while (cmd->name) {
+ printf("%s %s\n\r",cmd->name,cmd->help);
+ cmd++;
+ }
+}
+#endif /* SMALL ROM */
+
+/**************************************************************************
+CMD_IP - Set my IP address
+**************************************************************************/
+cmd_ip(p)
+ char *p;
+{
+ int i;
+ if (!setip(p, &arptable[ARP_CLIENT].ipaddr)) {
+ printf("IP address is %I\r\n",
+ arptable[ARP_CLIENT].ipaddr);
+ }
+}
+
+/**************************************************************************
+CMD_SERVER - Set server's IP address
+**************************************************************************/
+cmd_server(p)
+ char *p;
+{
+ int i;
+ if (!setip(p, &arptable[ARP_SERVER].ipaddr)) {
+ printf("Server IP address is %I\r\n",
+ arptable[ARP_SERVER].ipaddr);
+ } else /* Need to clear arp entry if we change IP address */
+ for (i=0; i<6; i++) arptable[ARP_SERVER].node[i] = 0;
+}
+
+/**************************************************************************
+CMD_NETMASK - Set network mask
+**************************************************************************/
+cmd_netmask(p)
+ char *p;
+{
+ int i;
+ if (!setip(p, &netmask)) {
+ netmask = ntohl(netmask);
+ printf("netmask is %I\r\n",
+ arptable[ARP_SERVER].ipaddr);
+ }
+ netmask = htonl(netmask);
+}
+
+extern char kernel_buf[], *kernel;
+/**************************************************************************
+CMD_KERNEL - set kernel filename
+**************************************************************************/
+cmd_kernel(p)
+ char *p;
+{
+ if (*p) sprintf(kernel = kernel_buf,"%s",p);
+ printf("Bootfile is: %s\r\n", kernel);
+}
+
+
+/**************************************************************************
+CMD_ROOTFS - Set root filesystem name
+**************************************************************************/
+cmd_rootfs(p)
+ char *p;
+{
+ if (!setip(p, &arptable[ARP_ROOTSERVER].ipaddr)) {
+ printf("Root filesystem is %I:%s\r\n",
+ nfsdiskless.root_saddr.sin_addr,
+ nfsdiskless.root_hostnam);
+ } else {
+ bcopy(&arptable[ARP_ROOTSERVER].ipaddr,
+ &nfsdiskless.root_saddr.sin_addr, 4);
+ while (*p && (*p != ':')) p++;
+ if (*p == ':') p++;
+ sprintf(&nfsdiskless.root_hostnam, "%s", p);
+ }
+}
+
+/**************************************************************************
+CMD_SWAPFS - Set root filesystem name
+**************************************************************************/
+cmd_swapfs(p)
+ char *p;
+{
+ if (!setip(p, &arptable[ARP_SWAPSERVER].ipaddr)) {
+ printf("Swap filesystem is %I:%s\r\n",
+ nfsdiskless.swap_saddr.sin_addr,
+ nfsdiskless.swap_hostnam);
+ } else {
+ bcopy(&arptable[ARP_SWAPSERVER].ipaddr,
+ &nfsdiskless.swap_saddr.sin_addr, 4);
+ while (*p && (*p != ':')) p++;
+ if (*p == ':') p++;
+ sprintf(&nfsdiskless.swap_hostnam, "%s", p);
+ }
+}
+
+/**************************************************************************
+CMD_HOSTNAME - Set my hostname
+**************************************************************************/
+cmd_hostname(p)
+ char *p;
+{
+ if (*p)
+ hostnamelen = ((sprintf(&nfsdiskless.my_hostnam,"%s",p) -
+ (char*)&nfsdiskless.my_hostnam) + 3) & ~3;
+ else printf("Hostname is: %s\r\n",nfsdiskless.my_hostnam);
+}
+
+
+/**************************************************************************
+EXECUTE - Decode command
+**************************************************************************/
+execute(buf)
+ char *buf;
+{
+ char *p, *q;
+ struct bootcmds_t *cmd = bootcmds;
+ if ((!(*buf)) || (*buf == '#')) return(0);
+ while(cmd->name) {
+ p = buf;
+ q = cmd->name;
+ while (*q && (*(q++) == *(p++))) ;
+ if ((!(*q)) && ((*p == ' ') || (!(*p)))) {
+ if (!cmd->func) return(1);
+ while (*p == ' ') p++;
+ (cmd->func)(p);
+ return(0);
+ } else
+ cmd++;
+ }
+#ifdef SMALL_ROM
+ printf("invalid command\n\r");
+#else
+ printf("bad command - type 'help' for list\n\r");
+#endif
+ return(0);
+}
+
+/**************************************************************************
+BOOTMENU - Present boot options
+**************************************************************************/
+bootmenu()
+{
+ char cmd[80];
+ int ptr, c;
+ printf("\r\n");
+ while (1) {
+ ptr = 0;
+ printf("boot> ");
+ while (ptr < 80) {
+ c = getchar();
+ if (c == '\r')
+ break;
+ else if (c == '\b') {
+ if (ptr > 0) {
+ ptr--;
+ printf("\b \b");
+ }
+ } else {
+ cmd[ptr++] = c;
+ putchar(c);
+ }
+ }
+ cmd[ptr] = 0;
+ printf("\r\n");
+ if (execute(cmd)) break;
+ }
+ eth_reset();
+}
diff --git a/sys/i386/boot/netboot/ether.c b/sys/i386/boot/netboot/ether.c
new file mode 100644
index 0000000..41d0680
--- /dev/null
+++ b/sys/i386/boot/netboot/ether.c
@@ -0,0 +1,479 @@
+
+/**************************************************************************
+NETBOOT - BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+ Date: May/94
+
+ This code is based heavily on David Greenman's if_ed.c driver
+
+ Copyright (C) 1993-1994, David Greenman, Martin Renters.
+ This software may be used, modified, copied, distributed, and sold, in
+ both source and binary form provided that the above copyright and these
+ terms are retained. Under no circumstances are the authors responsible for
+ the proper functioning of this software, nor do the authors assume any
+ responsibility for damages incurred with its use.
+
+
+**************************************************************************/
+
+#include "netboot.h"
+#include "ether.h"
+
+unsigned short eth_nic_base;
+unsigned short eth_asic_base;
+unsigned char eth_tx_start;
+unsigned char eth_laar;
+unsigned char eth_flags;
+unsigned char eth_vendor;
+unsigned char eth_memsize;
+unsigned char *eth_bmem;
+unsigned char *eth_node_addr;
+
+/**************************************************************************
+The following two variables are used externally
+**************************************************************************/
+char packet[ETH_MAX_PACKET];
+int packetlen;
+
+/**************************************************************************
+ETH_PROBE - Look for an adapter
+**************************************************************************/
+eth_probe()
+{
+ int i;
+ struct wd_board *brd;
+ char *name;
+ unsigned short chksum;
+ unsigned char c;
+
+ eth_vendor = VENDOR_NONE;
+
+#ifdef INCLUDE_WD
+ /******************************************************************
+ Search for WD/SMC cards
+ ******************************************************************/
+ for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
+ eth_asic_base += 0x20) {
+ chksum = 0;
+ for (i=8; i<16; i++)
+ chksum += inb(i+eth_asic_base);
+ if ((chksum & 0x00FF) == 0x00FF)
+ break;
+ }
+ if (eth_asic_base <= WD_HIGH_BASE) { /* We've found a board */
+ eth_vendor = VENDOR_WD;
+ eth_nic_base = eth_asic_base + WD_NIC_ADDR;
+ c = inb(eth_asic_base+WD_BID); /* Get board id */
+ for (brd = wd_boards; brd->name; brd++)
+ if (brd->id == c) break;
+ if (!brd->name) {
+ printf("\r\nUnknown Ethernet type %x\r\n", c);
+ return(0); /* Unknown type */
+ }
+ eth_flags = brd->flags;
+ eth_memsize = brd->memsize;
+ eth_tx_start = 0;
+ if ((c == TYPE_WD8013EP) &&
+ (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
+ eth_flags = FLAG_16BIT;
+ eth_memsize = MEM_16384;
+ }
+ if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
+ eth_bmem = (char *)(0x80000 |
+ ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
+ } else
+ eth_bmem = (char *)WD_DEFAULT_MEM;
+ outb(eth_asic_base + WD_MSR, 0x80); /* Reset */
+ printf("\r\n%s base 0x%x, memory 0x%X, addr ",
+ brd->name, eth_asic_base, eth_bmem);
+ for (i=0; i<6; i++)
+ printf("%b",(int)(arptable[ARP_CLIENT].node[i] =
+ inb(i+eth_asic_base+WD_LAR)));
+ if (eth_flags & FLAG_790) {
+ outb(eth_asic_base+WD_MSR, WD_MSR_MENB);
+ outb(eth_asic_base+0x04, (inb(eth_asic_base+0x04) |
+ 0x80));
+ outb(eth_asic_base+0x0B,
+ (((unsigned)eth_bmem >> 13) & 0x0F) |
+ (((unsigned)eth_bmem >> 11) & 0x40) |
+ (inb(eth_asic_base+0x0B) & 0xB0));
+ outb(eth_asic_base+0x04, (inb(eth_asic_base+0x04) &
+ ~0x80));
+ } else {
+ outb(eth_asic_base+WD_MSR,
+ (((unsigned)eth_bmem >> 13) & 0x3F) | 0x40);
+ }
+ if (eth_flags & FLAG_16BIT) {
+ if (eth_flags & FLAG_790) {
+ eth_laar = inb(eth_asic_base + WD_LAAR);
+ outb(eth_asic_base + WD_LAAR, WD_LAAR_M16EN);
+ inb(0x84);
+ } else {
+ outb(eth_asic_base + WD_LAAR, (eth_laar =
+ WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
+ }
+ }
+ printf("\r\n");
+
+ }
+#endif
+#ifdef INCLUDE_NE
+ /******************************************************************
+ Search for NE1000/2000 if no WD/SMC cards
+ ******************************************************************/
+ if (eth_vendor != VENDOR_WD) {
+ char romdata[16], testbuf[32];
+ char test[] = "NE1000/2000 memory";
+ eth_bmem = (char *)0; /* No shared memory */
+ eth_asic_base = NE_BASE + NE_ASIC_OFFSET;
+ eth_nic_base = NE_BASE;
+ eth_vendor = VENDOR_NOVELL;
+ eth_flags = FLAG_PIO;
+ eth_memsize = MEM_16384;
+ eth_tx_start = 32;
+ c = inb(eth_asic_base + NE_RESET);
+ outb(eth_asic_base + NE_RESET, c);
+ inb(0x84);
+ outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_STP |
+ D8390_COMMAND_RD2);
+ outb(eth_nic_base + D8390_P0_RCR, D8390_RCR_MON);
+ outb(eth_nic_base + D8390_P0_DCR, D8390_DCR_FT1 | D8390_DCR_LS);
+ outb(eth_nic_base + D8390_P0_PSTART, MEM_8192);
+ outb(eth_nic_base + D8390_P0_PSTOP, MEM_16384);
+ eth_pio_write(test, 8192, sizeof(test));
+ eth_pio_read(8192, testbuf, sizeof(test));
+ if (!bcompare(test, testbuf, sizeof(test))) {
+ eth_flags |= FLAG_16BIT;
+ eth_memsize = MEM_32768;
+ eth_tx_start = 64;
+ outb(eth_nic_base + D8390_P0_DCR, D8390_DCR_WTS |
+ D8390_DCR_FT1 | D8390_DCR_LS);
+ outb(eth_nic_base + D8390_P0_PSTART, MEM_16384);
+ outb(eth_nic_base + D8390_P0_PSTOP, MEM_32768);
+ eth_pio_write(test, 16384, sizeof(test));
+ eth_pio_read(16384, testbuf, sizeof(test));
+ if (!bcompare(testbuf, test, sizeof(test))) return(0);
+ }
+ eth_pio_read(0, romdata, 16);
+ printf("\r\nNE1000/NE2000 base 0x%x, addr ", eth_nic_base);
+ for (i=0; i<6; i++)
+ printf("%b",(int)(arptable[ARP_CLIENT].node[i] = romdata[i
+ + ((eth_flags & FLAG_16BIT) ? i : 0)]));
+ printf("\r\n");
+ }
+#endif
+ if (eth_vendor == VENDOR_NONE) return(0);
+
+ eth_node_addr = arptable[ARP_CLIENT].node;
+ eth_reset();
+ return(eth_vendor);
+}
+
+/**************************************************************************
+ETH_RESET - Reset adapter
+**************************************************************************/
+eth_reset()
+{
+ int i;
+ if (eth_flags & FLAG_790)
+ outb(eth_nic_base+D8390_P0_COMMAND,
+ D8390_COMMAND_PS0 | D8390_COMMAND_STP);
+ else
+ outb(eth_nic_base+D8390_P0_COMMAND,
+ D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+ D8390_COMMAND_STP);
+ if (eth_flags & FLAG_16BIT)
+ outb(eth_nic_base+D8390_P0_DCR, 0x49);
+ else
+ outb(eth_nic_base+D8390_P0_DCR, 0x48);
+ outb(eth_nic_base+D8390_P0_RBCR0, 0);
+ outb(eth_nic_base+D8390_P0_RBCR1, 0);
+ outb(eth_nic_base+D8390_P0_RCR, 4); /* allow broadcast frames */
+ outb(eth_nic_base+D8390_P0_TCR, 2);
+ outb(eth_nic_base+D8390_P0_TPSR, eth_tx_start);
+ outb(eth_nic_base+D8390_P0_PSTART, eth_tx_start + D8390_TXBUF_SIZE);
+ if (eth_flags & FLAG_790) outb(eth_nic_base + 0x09, 0);
+ outb(eth_nic_base+D8390_P0_PSTOP, eth_memsize);
+ outb(eth_nic_base+D8390_P0_BOUND, eth_tx_start + D8390_TXBUF_SIZE);
+ outb(eth_nic_base+D8390_P0_ISR, 0xFF);
+ outb(eth_nic_base+D8390_P0_IMR, 0);
+ if (eth_flags & FLAG_790)
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1 |
+ D8390_COMMAND_STP);
+ else
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STP);
+ for (i=0; i<6; i++)
+ outb(eth_nic_base+D8390_P1_PAR0+i, eth_node_addr[i]);
+ for (i=0; i<6; i++)
+ outb(eth_nic_base+D8390_P1_MAR0+i, 0xFF);
+ outb(eth_nic_base+D8390_P1_CURR, eth_tx_start + D8390_TXBUF_SIZE+1);
+ if (eth_flags & FLAG_790)
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_STA);
+ else
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STA);
+ outb(eth_nic_base+D8390_P0_ISR, 0xFF);
+ outb(eth_nic_base+D8390_P0_TCR, 0);
+ return(1);
+}
+
+/**************************************************************************
+ETH_TRANSMIT - Transmit a frame
+**************************************************************************/
+eth_transmit(d,t,s,p)
+ char *d; /* Destination */
+ unsigned short t; /* Type */
+ unsigned short s; /* size */
+ char *p; /* Packet */
+{
+ unsigned char c;
+#ifdef INCLUDE_WD
+ if (eth_vendor == VENDOR_WD) { /* Memory interface */
+ if (eth_flags & FLAG_16BIT) {
+ outb(eth_asic_base + WD_LAAR, eth_laar | WD_LAAR_M16EN);
+ inb(0x84);
+ }
+ if (eth_flags & FLAG_790) {
+ outb(eth_asic_base + WD_MSR, WD_MSR_MENB);
+ inb(0x84);
+ }
+ inb(0x84);
+ bcopy(d, eth_bmem, 6); /* dst */
+ bcopy(eth_node_addr, eth_bmem+6, ETHER_ADDR_SIZE); /* src */
+ *(eth_bmem+12) = t>>8; /* type */
+ *(eth_bmem+13) = t;
+ bcopy(p, eth_bmem+14, s);
+ s += 14;
+ while (s < ETH_MIN_PACKET) *(eth_bmem+(s++)) = 0;
+ if (eth_flags & FLAG_790) {
+ outb(eth_asic_base + WD_MSR, 0);
+ inb(0x84);
+ }
+ if (eth_flags & FLAG_16BIT) {
+ outb(eth_asic_base + WD_LAAR, eth_laar & ~WD_LAAR_M16EN);
+ inb(0x84);
+ }
+ }
+#endif
+#ifdef INCLUDE_NE
+ if (eth_vendor == VENDOR_NOVELL) { /* Programmed I/O */
+ unsigned short type;
+ type = (t >> 8) | (t << 8);
+ eth_pio_write(d, eth_tx_start<<8, 6);
+ eth_pio_write(eth_node_addr, (eth_tx_start<<8)+6, 6);
+ eth_pio_write(&type, (eth_tx_start<<8)+12, 2);
+ eth_pio_write(p, (eth_tx_start<<8)+14, s);
+ s += 14;
+ if (s < ETH_MIN_PACKET) s = ETH_MIN_PACKET;
+ }
+#endif
+ twiddle();
+ if (eth_flags & FLAG_790)
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_STA);
+ else
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STA);
+ outb(eth_nic_base+D8390_P0_TPSR, eth_tx_start);
+ outb(eth_nic_base+D8390_P0_TBCR0, s);
+ outb(eth_nic_base+D8390_P0_TBCR1, s>>8);
+ if (eth_flags & FLAG_790)
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_TXP | D8390_COMMAND_STA);
+ else
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
+ D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
+ D8390_COMMAND_STA);
+ return(0);
+}
+
+/**************************************************************************
+ETH_POLL - Wait for a frame
+**************************************************************************/
+eth_poll()
+{
+ int ret = 0;
+ unsigned short type = 0;
+ unsigned char bound,curr,rstat;
+ unsigned short len;
+ unsigned short pktoff;
+ unsigned char *p;
+ struct ringbuffer pkthdr;
+ rstat = inb(eth_nic_base+D8390_P0_RSR);
+ if (rstat & D8390_RSTAT_OVER) {
+ eth_reset();
+ return(0);
+ }
+ if (!(rstat & D8390_RSTAT_PRX)) return(0);
+ bound = inb(eth_nic_base+D8390_P0_BOUND)+1;
+ if (bound == eth_memsize) bound = eth_tx_start + D8390_TXBUF_SIZE;
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1);
+ curr = inb(eth_nic_base+D8390_P1_CURR);
+ outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0);
+ if (curr == eth_memsize) curr=eth_tx_start + D8390_TXBUF_SIZE;
+ if (curr == bound) return(0);
+ if (eth_vendor == VENDOR_WD) {
+ if (eth_flags & FLAG_16BIT) {
+ outb(eth_asic_base + WD_LAAR, eth_laar | WD_LAAR_M16EN);
+ inb(0x84);
+ }
+ if (eth_flags & FLAG_790) {
+ outb(eth_asic_base + WD_MSR, WD_MSR_MENB);
+ inb(0x84);
+ }
+ inb(0x84);
+ }
+ pktoff = (bound << 8);
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, &pkthdr, 4);
+ else
+ bcopy(eth_bmem + pktoff, &pkthdr, 4);
+ len = pkthdr.len - 4; /* sub CRC */
+ pktoff += 4;
+ if (len > 1514) len = 1514;
+ bound = pkthdr.bound; /* New bound ptr */
+ if ( (pkthdr.status & D8390_RSTAT_PRX) && (len > 14) && (len < 1518)) {
+ p = packet;
+ packetlen = len;
+ len = (eth_memsize << 8) - pktoff;
+ if (packetlen > len) { /* We have a wrap-around */
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, p, len);
+ else
+ bcopy(eth_bmem + pktoff, p, len);
+ pktoff = (eth_tx_start + D8390_TXBUF_SIZE) << 8;
+ p += len;
+ packetlen -= len;
+ }
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, p, packetlen);
+ else
+ bcopy(eth_bmem + pktoff, p, packetlen);
+
+ type = (packet[12]<<8) | packet[13];
+ ret = 1;
+ }
+ if (eth_vendor == VENDOR_WD) {
+ if (eth_flags & FLAG_790) {
+ outb(eth_asic_base + WD_MSR, 0);
+ inb(0x84);
+ }
+ if (eth_flags & FLAG_16BIT) {
+ outb(eth_asic_base + WD_LAAR, eth_laar &
+ ~WD_LAAR_M16EN);
+ inb(0x84);
+ }
+ inb(0x84);
+ }
+ if (bound == (eth_tx_start + D8390_TXBUF_SIZE))
+ bound = eth_memsize;
+ outb(eth_nic_base+D8390_P0_BOUND, bound-1);
+ if (ret && (type == ARP)) {
+ struct arprequest *arpreq;
+ unsigned long reqip;
+ arpreq = (struct arprequest *)&packet[ETHER_HDR_SIZE];
+ convert_ipaddr(&reqip, arpreq->tipaddr);
+ if ((ntohs(arpreq->opcode) == ARP_REQUEST) &&
+ (reqip == arptable[ARP_CLIENT].ipaddr)) {
+ arpreq->opcode = htons(ARP_REPLY);
+ bcopy(arpreq->sipaddr, arpreq->tipaddr, 4);
+ bcopy(arpreq->shwaddr, arpreq->thwaddr, 6);
+ bcopy(arptable[ARP_CLIENT].node, arpreq->shwaddr, 6);
+ convert_ipaddr(arpreq->sipaddr, &reqip);
+ eth_transmit(arpreq->thwaddr, ARP, sizeof(struct arprequest),
+ arpreq);
+ return(0);
+ }
+ }
+ return(ret);
+}
+
+#ifdef INCLUDE_NE
+/**************************************************************************
+NE1000/NE2000 Support Routines
+**************************************************************************/
+static inline unsigned short inw(unsigned short a)
+{
+ unsigned short d;
+ asm volatile( "inw %1, %0" : "=a" (d) : "d" (a));
+ return d;
+}
+
+static inline void outw(unsigned short a, unsigned short d)
+{
+ asm volatile( "outw %0, %1" : : "a" (d), "d" (a));
+}
+
+/**************************************************************************
+ETH_PIO_READ - Read a frame via Programmed I/O
+**************************************************************************/
+eth_pio_read(src, dst, cnt, init)
+ unsigned short src;
+ unsigned char *dst;
+ unsigned short cnt;
+ int init;
+{
+ if (cnt & 1) cnt++;
+ outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD2 |
+ D8390_COMMAND_STA);
+ outb(eth_nic_base + D8390_P0_RBCR0, cnt);
+ outb(eth_nic_base + D8390_P0_RBCR1, cnt>>8);
+ outb(eth_nic_base + D8390_P0_RSAR0, src);
+ outb(eth_nic_base + D8390_P0_RSAR1, src>>8);
+ outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD0 |
+ D8390_COMMAND_STA);
+ if (eth_flags & FLAG_16BIT) {
+ while (cnt) {
+ *((unsigned short *)dst) = inw(eth_asic_base + NE_DATA);
+ dst += 2;
+ cnt -= 2;
+ }
+ }
+ else {
+ while (cnt--)
+ *(dst++) = inb(eth_asic_base + NE_DATA);
+ }
+}
+
+/**************************************************************************
+ETH_PIO_WRITE - Write a frame via Programmed I/O
+**************************************************************************/
+eth_pio_write(src, dst, cnt, init)
+ unsigned char *src;
+ unsigned short dst;
+ unsigned short cnt;
+ int init;
+{
+ outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD2 |
+ D8390_COMMAND_STA);
+ outb(eth_nic_base + D8390_P0_ISR, D8390_ISR_RDC);
+ outb(eth_nic_base + D8390_P0_RBCR0, cnt);
+ outb(eth_nic_base + D8390_P0_RBCR1, cnt>>8);
+ outb(eth_nic_base + D8390_P0_RSAR0, dst);
+ outb(eth_nic_base + D8390_P0_RSAR1, dst>>8);
+ outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD1 |
+ D8390_COMMAND_STA);
+ if (eth_flags & FLAG_16BIT) {
+ if (cnt & 1) cnt++; /* Round up */
+ while (cnt) {
+ outw(eth_asic_base + NE_DATA, *((unsigned short *)src));
+ src += 2;
+ cnt -= 2;
+ }
+ }
+ else {
+ while (cnt--)
+ outb(eth_asic_base + NE_DATA, *(src++));
+ }
+ while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
+ != D8390_ISR_RDC);
+}
+#else
+/**************************************************************************
+ETH_PIO_READ - Dummy routine when NE2000 not compiled in
+**************************************************************************/
+eth_pio_read() {}
+#endif
diff --git a/sys/i386/boot/netboot/ether.h b/sys/i386/boot/netboot/ether.h
new file mode 100644
index 0000000..586a35c
--- /dev/null
+++ b/sys/i386/boot/netboot/ether.h
@@ -0,0 +1,178 @@
+/**************************************************************************
+NETBOOT - BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+ Date: Jun/94
+
+**************************************************************************/
+
+#define TRUE 1
+#define FALSE 0
+
+#define ETH_MIN_PACKET 64
+#define ETH_MAX_PACKET 1518
+
+#define VENDOR_NONE 0
+#define VENDOR_WD 1
+#define VENDOR_NOVELL 2
+
+#define FLAG_PIO 0x01
+#define FLAG_16BIT 0x02
+#define FLAG_790 0x04
+
+#define MEM_8192 32
+#define MEM_16384 64
+#define MEM_32768 128
+
+/**************************************************************************
+Western Digital/SMC Board Definitions
+**************************************************************************/
+#define WD_LOW_BASE 0x200
+#define WD_HIGH_BASE 0x3e0
+#ifndef WD_DEFAULT_MEM
+#define WD_DEFAULT_MEM 0xD0000
+#endif
+#define WD_NIC_ADDR 0x10
+
+/**************************************************************************
+Western Digital/SMC ASIC Addresses
+**************************************************************************/
+#define WD_MSR 0x00
+#define WD_ICR 0x01
+#define WD_IAR 0x02
+#define WD_BIO 0x03
+#define WD_IRR 0x04
+#define WD_LAAR 0x05
+#define WD_IJR 0x06
+#define WD_GP2 0x07
+#define WD_LAR 0x08
+#define WD_BID 0x0E
+
+#define WD_ICR_16BIT 0x01
+
+#define WD_MSR_MENB 0x40
+
+#define WD_LAAR_L16EN 0x40
+#define WD_LAAR_M16EN 0x80
+
+#define WD_SOFTCONFIG 0x20
+
+/**************************************************************************
+Western Digital/SMC Board Types
+**************************************************************************/
+#define TYPE_WD8003S 0x02
+#define TYPE_WD8003E 0x03
+#define TYPE_WD8013EBT 0x05
+#define TYPE_WD8003W 0x24
+#define TYPE_WD8003EB 0x25
+#define TYPE_WD8013W 0x26
+#define TYPE_WD8013EP 0x27
+#define TYPE_WD8013WC 0x28
+#define TYPE_WD8013EPC 0x29
+#define TYPE_SMC8216T 0x2a
+#define TYPE_SMC8216C 0x2b
+#define TYPE_SMC8013EBP 0x2c
+
+#ifdef INCLUDE_WD
+struct wd_board {
+ char *name;
+ char id;
+ char flags;
+ char memsize;
+} wd_boards[] = {
+ {"WD8003S", TYPE_WD8003S, 0, MEM_8192},
+ {"WD8003E", TYPE_WD8003E, 0, MEM_8192},
+ {"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384},
+ {"WD8003W", TYPE_WD8003W, 0, MEM_8192},
+ {"WD8003EB", TYPE_WD8003EB, 0, MEM_8192},
+ {"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384},
+ {"WD8003EP/WD8013EP",
+ TYPE_WD8013EP, 0, MEM_8192},
+ {"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384},
+ {"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384},
+ {"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384},
+ {"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384},
+ {"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384},
+ {NULL, 0, 0}
+};
+#endif
+
+/**************************************************************************
+NE1000/2000 definitions
+**************************************************************************/
+#ifndef NE_BASE
+#define NE_BASE 0x320
+#endif
+#define NE_ASIC_OFFSET 0x10
+#define NE_RESET 0x0F /* Used to reset card */
+#define NE_DATA 0x00 /* Used to read/write NIC mem */
+
+/**************************************************************************
+8390 Register Definitions
+**************************************************************************/
+#define D8390_P0_COMMAND 0x00
+#define D8390_P0_PSTART 0x01
+#define D8390_P0_PSTOP 0x02
+#define D8390_P0_BOUND 0x03
+#define D8390_P0_TSR 0x04
+#define D8390_P0_TPSR 0x04
+#define D8390_P0_TBCR0 0x05
+#define D8390_P0_TBCR1 0x06
+#define D8390_P0_ISR 0x07
+#define D8390_P0_RSAR0 0x08
+#define D8390_P0_RSAR1 0x09
+#define D8390_P0_RBCR0 0x0A
+#define D8390_P0_RBCR1 0x0B
+#define D8390_P0_RSR 0x0C
+#define D8390_P0_RCR 0x0C
+#define D8390_P0_TCR 0x0D
+#define D8390_P0_DCR 0x0E
+#define D8390_P0_IMR 0x0F
+#define D8390_P1_COMMAND 0x00
+#define D8390_P1_PAR0 0x01
+#define D8390_P1_PAR1 0x02
+#define D8390_P1_PAR2 0x03
+#define D8390_P1_PAR3 0x04
+#define D8390_P1_PAR4 0x05
+#define D8390_P1_PAR5 0x06
+#define D8390_P1_CURR 0x07
+#define D8390_P1_MAR0 0x08
+
+#define D8390_COMMAND_PS0 0x0 /* Page 0 select */
+#define D8390_COMMAND_PS1 0x40 /* Page 1 select */
+#define D8390_COMMAND_PS2 0x80 /* Page 2 select */
+#define D8390_COMMAND_RD2 0x20 /* Remote DMA control */
+#define D8390_COMMAND_RD1 0x10
+#define D8390_COMMAND_RD0 0x08
+#define D8390_COMMAND_TXP 0x04 /* transmit packet */
+#define D8390_COMMAND_STA 0x02 /* start */
+#define D8390_COMMAND_STP 0x01 /* stop */
+
+#define D8390_RCR_MON 0x20 /* monitor mode */
+
+#define D8390_DCR_FT1 0x40
+#define D8390_DCR_LS 0x08 /* Loopback select */
+#define D8390_DCR_WTS 0x01 /* Word transfer select */
+
+#define D8390_ISR_PRX 0x01 /* successful recv */
+#define D8390_ISR_PTX 0x02 /* successful xmit */
+#define D8390_ISR_RXE 0x04 /* receive error */
+#define D8390_ISR_TXE 0x08 /* transmit error */
+#define D8390_ISR_OVW 0x10 /* Overflow */
+#define D8390_ISR_CNT 0x20 /* Counter overflow */
+#define D8390_ISR_RDC 0x40 /* Remote DMA complete */
+#define D8390_ISR_RST 0x80 /* reset */
+
+#define D8390_RSTAT_PRX 0x01 /* successful recv */
+#define D8390_RSTAT_CRC 0x02 /* CRC error */
+#define D8390_RSTAT_FAE 0x04 /* Frame alignment error */
+#define D8390_RSTAT_OVER 0x08 /* overflow */
+
+#define D8390_TXBUF_SIZE 6
+#define D8390_RXBUF_END 32
+
+struct ringbuffer {
+ unsigned char status;
+ unsigned char bound;
+ unsigned short len;
+};
diff --git a/sys/i386/boot/netboot/main.c b/sys/i386/boot/netboot/main.c
new file mode 100644
index 0000000..35a2248
--- /dev/null
+++ b/sys/i386/boot/netboot/main.c
@@ -0,0 +1,525 @@
+/**************************************************************************
+NETBOOT - BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+ Date: Dec/93
+
+**************************************************************************/
+
+#include "netboot.h"
+
+int jmp_bootmenu[10];
+
+struct exec head;
+char *loadpoint;
+char *kernel;
+char kernel_buf[128];
+void (*kernelentry)();
+struct nfs_diskless nfsdiskless;
+int hostnamelen;
+char config_buffer[512]; /* Max TFTP packet */
+struct bootinfo_t bootinfo;
+unsigned long netmask;
+
+extern char packet[];
+extern int packetlen, rpc_id;
+char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/**************************************************************************
+MAIN - Kick off routine
+**************************************************************************/
+main()
+{
+ int c;
+ char *p;
+ extern char edata[], end[];
+ for (p=edata; p<end; p++) *p = 0; /* Zero BSS */
+#ifdef ASK_BOOT
+ while (1) {
+ printf("\n\rBoot from Network (Y/N) ? ");
+ c = getchar();
+ if ((c >= 'a') && (c <= 'z')) c &= 0x5F;
+ if (c == '\r') break;
+ putchar(c);
+ if (c == 'N')
+ exit(0);
+ if (c == 'Y')
+ break;
+ printf(" - bad response\n\r");
+ }
+#endif
+ gateA20();
+ printf("\r\nBOOTP/TFTP/NFS bootstrap loader ESC for menu\n\r");
+ printf("\r\nSearching for adapter...");
+ if (!eth_probe()) {
+ printf("No adapter found.\r\n");
+ exit(0);
+ }
+ kernel = DEFAULT_BOOTFILE;
+ while (1) {
+ if (setjmp(jmp_bootmenu))
+ bootmenu();
+ else
+ load();
+ }
+}
+
+/**************************************************************************
+LOAD - Try to get booted
+**************************************************************************/
+load()
+{
+ char *p,*q;
+ char cfg[64];
+ int root_nfs_port;
+ int root_mount_port;
+ int swap_nfs_port;
+ int swap_mount_port;
+ char kernel_handle[32];
+ char cmd_line[80];
+ int err, offset, read_size;
+ long addr, broadcast;
+
+ /* Find a server to get BOOTP reply from */
+ if (!arptable[ARP_CLIENT].ipaddr || !arptable[ARP_SERVER].ipaddr) {
+ printf("\r\nSearching for server...\r\n");
+ if (!bootp()) {
+ printf("No Server found.\r\n");
+ longjmp(jmp_bootmenu,1);
+ }
+ }
+ printf("IP address %I, Server IP address %I\r\n",
+ arptable[ARP_CLIENT].ipaddr,
+ arptable[ARP_SERVER].ipaddr);
+
+ /* Now use TFTP to load configuration file */
+ sprintf(cfg,"/tftpboot/cfg.%I",arptable[ARP_CLIENT].ipaddr);
+ printf("Loading %s...\r\n",cfg);
+ if (!tftp(cfg)) {
+ printf("Unable to load config file.\r\n");
+ longjmp(jmp_bootmenu,1);
+ }
+ /* Execute commands in config file */
+ p = config_buffer;
+ while(*p) {
+ q = cmd_line;
+ while ((*p != '\n') && (*p)) *(q++) = *(p++);
+ *q = 0;
+ printf("%s\r\n",cmd_line);
+ execute(cmd_line);
+ if (*p) p++;
+ }
+
+ /* Check to make sure we've got a rootfs */
+ if (!arptable[ARP_ROOTSERVER].ipaddr) {
+ printf("No ROOT filesystem server!\r\n");
+ longjmp(jmp_bootmenu,1);
+ }
+
+ /* Fill in nfsdiskless.myif */
+ sprintf(&nfsdiskless.myif.ifra_name,"ed0");
+ nfsdiskless.myif.ifra_addr.sa_len = sizeof(struct sockaddr);
+ nfsdiskless.myif.ifra_addr.sa_family = AF_INET;
+ addr = htonl(arptable[ARP_CLIENT].ipaddr);
+ bcopy(&addr, &nfsdiskless.myif.ifra_addr.sa_data[2], 4);
+ if (!netmask) {
+ int net = nfsdiskless.myif.ifra_addr.sa_data[2];
+ if (net <= 127)
+ netmask = htonl(0xff000000);
+ else if (net < 192)
+ netmask = htonl(0xffff0000);
+ else
+ netmask = htonl(0xffffff00);
+ }
+ broadcast = (addr & netmask) | ~netmask;
+ nfsdiskless.myif.ifra_broadaddr.sa_len = sizeof(struct sockaddr);
+ nfsdiskless.myif.ifra_broadaddr.sa_family = AF_INET;
+ bcopy(&broadcast, &nfsdiskless.myif.ifra_broadaddr.sa_data[2], 4);
+ nfsdiskless.myif.ifra_mask.sa_len = sizeof(struct sockaddr);
+ nfsdiskless.myif.ifra_mask.sa_family = AF_UNSPEC;
+ bcopy(&netmask, &nfsdiskless.myif.ifra_mask.sa_data[2], 4);
+
+ rpc_id = currticks();
+
+ /* Lookup NFS/MOUNTD ports for SWAP using PORTMAP */
+ if (arptable[ARP_SWAPSERVER].ipaddr) {
+ swap_nfs_port = rpclookup(ARP_SWAPSERVER, PROG_NFS, 2);
+ swap_mount_port = rpclookup(ARP_SWAPSERVER, PROG_MOUNT, 1);
+ if ((swap_nfs_port == -1) || (swap_mount_port == -1)) {
+ printf("Unable to get SWAP NFS/MOUNT ports\r\n");
+ longjmp(jmp_bootmenu,1);
+ }
+ nfsdiskless.swap_saddr.sin_len = sizeof(struct sockaddr_in);
+ nfsdiskless.swap_saddr.sin_family = AF_INET;
+ nfsdiskless.swap_saddr.sin_port = root_nfs_port;
+ nfsdiskless.swap_saddr.sin_addr.s_addr =
+ htonl(arptable[ARP_SWAPSERVER].ipaddr);
+ nfsdiskless.swap_args.sotype = SOCK_DGRAM;
+ nfsdiskless.swap_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE);
+ nfsdiskless.swap_args.timeo = 10;
+ nfsdiskless.swap_args.retrans = 100;
+ nfsdiskless.swap_args.rsize = 8192;
+ nfsdiskless.swap_args.wsize = 8192;
+ }
+
+ /* Lookup NFS/MOUNTD ports for ROOT using PORTMAP */
+ root_nfs_port = rpclookup(ARP_ROOTSERVER, PROG_NFS, 2);
+ root_mount_port = rpclookup(ARP_ROOTSERVER, PROG_MOUNT, 1);
+ if ((root_nfs_port == -1) || (root_mount_port == -1)) {
+ printf("Unable to get ROOT NFS/MOUNT ports\r\n");
+ longjmp(jmp_bootmenu,1);
+ }
+ if (err = nfs_mount(ARP_ROOTSERVER, root_mount_port,
+ nfsdiskless.root_hostnam, &nfsdiskless.root_fh)) {
+ printf("Unable to mount ROOT filesystem: ");
+ nfs_err(err);
+ longjmp(jmp_bootmenu,1);
+ }
+ nfsdiskless.root_saddr.sin_len = sizeof(struct sockaddr_in);
+ nfsdiskless.root_saddr.sin_family = AF_INET;
+ nfsdiskless.root_saddr.sin_port = root_nfs_port;
+ nfsdiskless.root_saddr.sin_addr.s_addr =
+ htonl(arptable[ARP_ROOTSERVER].ipaddr);
+ nfsdiskless.root_args.sotype = SOCK_DGRAM;
+ nfsdiskless.root_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE);
+ nfsdiskless.root_args.timeo = 10;
+ nfsdiskless.root_args.retrans = 100;
+ nfsdiskless.root_args.rsize = 8192;
+ nfsdiskless.root_args.wsize = 8192;
+ nfsdiskless.root_time = 0;
+
+ if (err = nfs_lookup(ARP_ROOTSERVER, root_nfs_port,
+ &nfsdiskless.root_fh, kernel, &kernel_handle)) {
+ printf("Unable to open %s: ",kernel);
+ nfs_err(err);
+ longjmp(jmp_bootmenu,1);
+ }
+
+ /* 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) {
+ 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 *)0x100000;
+ offset = N_TXTOFF(head);
+ printf("text=0x%X, ",head.a_text);
+ while (head.a_text > 0) {
+ read_size = head.a_text > NFS_READ_SIZE ?
+ NFS_READ_SIZE : head.a_text;
+ if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port,
+ &kernel_handle, offset, read_size, loadpoint)) !=
+ read_size) {
+ if (err < 0) {
+ printf("Unable to read text: ");
+ nfs_err(err);
+ }
+ longjmp(jmp_bootmenu, 1);
+ }
+ loadpoint += err;
+ head.a_text -= err;
+ offset += err;
+ }
+ while (((int)loadpoint) & CLOFSET)
+ *(loadpoint++) = 0;
+ printf("data=0x%X, ",head.a_data);
+ while (head.a_data > 0) {
+ read_size = head.a_data > NFS_READ_SIZE ?
+ NFS_READ_SIZE : head.a_data;
+ if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port,
+ &kernel_handle, offset, read_size, loadpoint)) !=
+ read_size) {
+ if (err < 0) {
+ printf("Unable to read data: ");
+ nfs_err(err);
+ }
+ longjmp(jmp_bootmenu, 1);
+ }
+ loadpoint += err;
+ head.a_data -= err;
+ offset += err;
+ }
+ printf("bss=0x%X, ",head.a_bss);
+ while(head.a_bss--) *(loadpoint++) = 0;
+
+
+ /* Jump to kernel */
+ bootinfo.version = 1;
+ bootinfo.kernelname = kernel;
+ bootinfo.nfs_diskless = &nfsdiskless;
+ kernelentry = (void *)(head.a_entry & 0x00FFFFFF);
+ (*kernelentry)(0,NODEV,0,0,0,&bootinfo,0,0,0);
+ printf("*** %s execute failure ***\n",kernel);
+}
+
+/**************************************************************************
+POLLKBD - Check for Interrupt from keyboard
+**************************************************************************/
+pollkbd()
+{
+ if (iskey() && (getchar() == ESC)) longjmp(jmp_bootmenu,1);
+}
+
+/**************************************************************************
+UDP_TRANSMIT - Send a UDP datagram
+**************************************************************************/
+udp_transmit(destip, srcsock, destsock, len, buf)
+ unsigned long destip;
+ unsigned short srcsock, destsock;
+ int len;
+ char *buf;
+{
+ struct iphdr *ip;
+ struct udphdr *udp;
+ struct arprequest arpreq;
+ int arpentry, i;
+ unsigned long time;
+ int retry = MAX_ARP_RETRIES;
+
+ ip = (struct iphdr *)buf;
+ udp = (struct udphdr *)(buf + sizeof(struct iphdr));
+ ip->verhdrlen = 0x45;
+ ip->service = 0;
+ ip->len = htons(len);
+ ip->ident = 0;
+ ip->frags = 0;
+ ip->ttl = 60;
+ ip->protocol = IP_UDP;
+ ip->chksum = 0;
+ convert_ipaddr(ip->src, &arptable[ARP_CLIENT].ipaddr);
+ convert_ipaddr(ip->dest, &destip);
+ ip->chksum = ipchksum(buf, sizeof(struct iphdr));
+ udp->src = htons(srcsock);
+ udp->dest = htons(destsock);
+ udp->len = htons(len - sizeof(struct iphdr));
+ udp->chksum = 0;
+ if (destip == IP_BROADCAST) {
+ eth_transmit(broadcast, IP, len, buf);
+ } else {
+ for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
+ if (arptable[arpentry].ipaddr == destip) break;
+ if (arpentry == MAX_ARP) {
+ printf("%I is not in my arp table!\n");
+ return(0);
+ }
+ for (i = 0; i<ETHER_ADDR_SIZE; i++)
+ if (arptable[arpentry].node[i]) break;
+ if (i == ETHER_ADDR_SIZE) { /* Need to do arp request */
+ arpreq.hwtype = htons(1);
+ arpreq.protocol = htons(IP);
+ arpreq.hwlen = ETHER_ADDR_SIZE;
+ arpreq.protolen = 4;
+ arpreq.opcode = htons(ARP_REQUEST);
+ bcopy(arptable[ARP_CLIENT].node, arpreq.shwaddr,
+ ETHER_ADDR_SIZE);
+ convert_ipaddr(arpreq.sipaddr,
+ &arptable[ARP_CLIENT].ipaddr);
+ bzero(arpreq.thwaddr, ETHER_ADDR_SIZE);
+ convert_ipaddr(arpreq.tipaddr, &destip);
+ while (retry--) {
+ eth_transmit(broadcast, ARP, sizeof(arpreq),
+ &arpreq);
+ if (await_reply(AWAIT_ARP, arpentry,
+ arpreq.tipaddr)) goto xmit;
+ }
+ return(0);
+ }
+xmit: eth_transmit(arptable[arpentry].node, IP, len, buf);
+ }
+ return(1);
+}
+
+/**************************************************************************
+TFTP - Try to load configuation file
+**************************************************************************/
+tftp(name)
+ char *name;
+{
+ struct tftp_t *tr;
+ int retry = MAX_TFTP_RETRIES;
+ static unsigned short isocket = 2000;
+ unsigned short osocket = TFTP;
+ unsigned short len, block=1;
+ struct tftp_t tp;
+ int code;
+ isocket++;
+ tp.opcode = htons(TFTP_RRQ);
+ len = (sprintf((char *)tp.u.rrq,"%s%c%s",name,0,"octet")
+ - ((char *)&tp)) + 1;
+ while(retry--) {
+ if (!udp_transmit(arptable[ARP_SERVER].ipaddr, isocket, osocket,
+ len, &tp)) return(0);
+ if (await_reply(AWAIT_TFTP, isocket, NULL)) {
+ tr = (struct tftp_t *)&packet[ETHER_HDR_SIZE];
+ if (tr->opcode == ntohs(TFTP_ERROR)) {
+ printf("TFTP error %d (%s)\r\n",
+ ntohs(tr->u.err.errcode),
+ tr->u.err.errmsg);
+ return(0);
+ } /* ACK PACKET */
+ if (tr->opcode != ntohs(TFTP_DATA)) return(0);
+ tp.opcode = htons(TFTP_ACK);
+ tp.u.ack.block = tr->u.data.block;
+ udp_transmit(arptable[ARP_SERVER].ipaddr, isocket,
+ osocket, TFTP_MIN_PACKET_SIZE, &tp);
+ len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
+ if (len >= 512) {
+ printf("Config file too large.\r\n");
+ config_buffer[0] = 0;
+ return(0);
+ } else {
+ bcopy(tr->u.data.download, config_buffer, len);
+ config_buffer[len] = 0;
+ }
+ return(1);
+ }
+ }
+ return(0);
+}
+
+/**************************************************************************
+BOOTP - Get my IP address and load information
+**************************************************************************/
+bootp()
+{
+ int retry = MAX_BOOTP_RETRIES;
+ struct bootp_t bp;
+ unsigned long starttime;
+ bzero(&bp, sizeof(struct bootp_t));
+ bp.bp_op = BOOTP_REQUEST;
+ bp.bp_htype = 1;
+ bp.bp_hlen = ETHER_ADDR_SIZE;
+ bp.bp_xid = starttime = currticks();
+ bcopy(arptable[ARP_CLIENT].node, bp.bp_hwaddr, ETHER_ADDR_SIZE);
+ while(retry--) {
+ udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER,
+ sizeof(struct bootp_t), &bp);
+ if (await_reply(AWAIT_BOOTP, 0, NULL))
+ return(1);
+ bp.bp_secs = htons((currticks()-starttime)/20);
+ }
+ return(0);
+}
+
+
+/**************************************************************************
+AWAIT_REPLY - Wait until we get a response for our request
+**************************************************************************/
+await_reply(type, ival, ptr)
+ int type, ival;
+ char *ptr;
+{
+ unsigned long time;
+ struct iphdr *ip;
+ struct udphdr *udp;
+ struct arprequest *arpreply;
+ struct bootp_t *bootpreply;
+ struct rpc_t *rpc;
+
+ int protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) +
+ sizeof(struct udphdr);
+ time = currticks() + TIMEOUT;
+ while(time > currticks()) {
+ pollkbd();
+ if (eth_poll()) { /* We have something! */
+ /* Check for ARP - No IP hdr */
+ if ((type == AWAIT_ARP) &&
+ (packetlen >= ETHER_HDR_SIZE +
+ sizeof(struct arprequest)) &&
+ (((packet[12] << 8) | packet[13]) == ARP)) {
+ arpreply = (struct arprequest *)
+ &packet[ETHER_HDR_SIZE];
+ if ((arpreply->opcode == ntohs(ARP_REPLY)) &&
+ bcompare(arpreply->sipaddr, ptr, 4)) {
+ bcopy(arpreply->shwaddr,
+ arptable[ival].node,
+ ETHER_ADDR_SIZE);
+ return(1);
+ }
+ continue;
+ }
+
+ /* Anything else has IP header */
+ if ((packetlen < protohdrlen) ||
+ (((packet[12] << 8) | packet[13]) != IP)) continue;
+ ip = (struct iphdr *)&packet[ETHER_HDR_SIZE];
+ if ((ip->verhdrlen != 0x45) ||
+ ipchksum(ip, sizeof(struct iphdr)) ||
+ (ip->protocol != IP_UDP)) continue;
+ udp = (struct udphdr *)&packet[ETHER_HDR_SIZE +
+ sizeof(struct iphdr)];
+
+ /* BOOTP ? */
+ bootpreply = (struct bootp_t *)&packet[ETHER_HDR_SIZE];
+ if ((type == AWAIT_BOOTP) &&
+ (packetlen >= (ETHER_HDR_SIZE +
+ sizeof(struct bootp_t))) &&
+ (ntohs(udp->dest) == BOOTP_CLIENT) &&
+ (bootpreply->bp_op == BOOTP_REPLY)) {
+ convert_ipaddr(&arptable[ARP_CLIENT].ipaddr,
+ bootpreply->bp_yiaddr);
+ convert_ipaddr(&arptable[ARP_SERVER].ipaddr,
+ bootpreply->bp_siaddr);
+ bzero(arptable[ARP_SERVER].node,
+ ETHER_ADDR_SIZE); /* Kill arp */
+ if (bootpreply->bp_file[0]) {
+ bcopy(bootpreply->bp_file,
+ kernel_buf, 128);
+ kernel = kernel_buf;
+ }
+ return(1);
+ }
+
+ /* TFTP ? */
+ if ((type == AWAIT_TFTP) &&
+ (ntohs(udp->dest) == ival)) return(1);
+
+ /* RPC */
+ rpc = (struct rpc_t *)&packet[ETHER_HDR_SIZE];
+ if ((type == AWAIT_RPC) &&
+ (ntohs(udp->dest) == RPC_SOCKET) &&
+ (ntohl(rpc->u.reply.id) == ival) &&
+ (ntohl(rpc->u.reply.type) == MSG_REPLY)) {
+ rpc_id++;
+ return(1);
+ }
+ }
+ }
+ return(0);
+}
+
+/**************************************************************************
+IPCHKSUM - Checksum IP Header
+**************************************************************************/
+ipchksum(ip, len)
+ unsigned short *ip;
+ int len;
+{
+ unsigned long sum = 0;
+ len >>= 1;
+ while (len--) {
+ sum += *(ip++);
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ }
+ return((~sum) & 0x0000FFFF);
+}
+
+
+/**************************************************************************
+CONVERT_IPADDR - Convert IP address from net to machine order
+**************************************************************************/
+convert_ipaddr(d, s)
+ char *d,*s;
+{
+ *(d+3) = *s;
+ *(d+2) = *(s+1);
+ *(d+1) = *(s+2);
+ *d = *(s+3);
+}
diff --git a/sys/i386/boot/netboot/makerom.c b/sys/i386/boot/netboot/makerom.c
new file mode 100644
index 0000000..98cc651
--- /dev/null
+++ b/sys/i386/boot/netboot/makerom.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <fcntl.h>
+
+unsigned char rom[ROMSIZE];
+unsigned int sum;
+
+main(argc,argv)
+ int argc; char *argv[];
+{
+ int i, fd;
+ if (argc < 1) {
+ fprintf(stderr,"usage: %s rom-file\n",argv[0]);
+ exit(2);
+ }
+ if ((fd = open(argv[1], O_RDWR)) < 0) {
+ perror("unable to open file");
+ exit(2);
+ }
+ bzero(rom, ROMSIZE);
+ if (read(fd, rom, ROMSIZE) < 0) {
+ perror("read error");
+ exit(2);
+ }
+ rom[5] = 0;
+ for (i=0,sum=0; i<ROMSIZE; i++)
+ sum += rom[i];
+ rom[5] = -sum;
+ for (i=0,sum=0; i<ROMSIZE; i++);
+ sum += rom[i];
+ if (sum)
+ printf("checksum fails.\n");
+ if (lseek(fd, 0L, SEEK_SET) < 0) {
+ perror("unable to seek");
+ exit(2);
+ }
+ if (write(fd, rom, ROMSIZE) < 0) {
+ perror("unable to write");
+ exit(2);
+ }
+ close(fd);
+ exit(0);
+}
diff --git a/sys/i386/boot/netboot/misc.c b/sys/i386/boot/netboot/misc.c
new file mode 100644
index 0000000..814ddbf
--- /dev/null
+++ b/sys/i386/boot/netboot/misc.c
@@ -0,0 +1,261 @@
+/**************************************************************************
+MISC Support Routines
+**************************************************************************/
+
+#include "netboot.h"
+
+#define NO_SWITCH /* saves space */
+
+/**************************************************************************
+TWIDDLE
+**************************************************************************/
+twiddle()
+{
+ static int count=0;
+ char tiddles[]="-\\|/";
+ putchar(tiddles[(count++)&3]);
+ putchar('\b');
+}
+
+/**************************************************************************
+BCOPY
+**************************************************************************/
+bcopy(s,d,n)
+ char *s, *d;
+ int n;
+{
+ while ((n--) > 0) {
+ *(d++) = *(s++);
+ }
+}
+
+/**************************************************************************
+BZERO
+**************************************************************************/
+bzero(d,n)
+ char *d;
+ int n;
+{
+ while ((n--) > 0) {
+ *(d++) = 0;
+ }
+}
+
+/**************************************************************************
+BCOMPARE
+**************************************************************************/
+bcompare(d,s,n)
+ char *d,*s;
+ int n;
+{
+ while ((n--) > 0) {
+ if (*(d++) != *(s++)) return(0);
+ }
+ return(1);
+}
+
+/**************************************************************************
+PRINTF and friends
+
+ Formats:
+ %X - 4 byte ASCII (8 hex digits)
+ %x - 2 byte ASCII (4 hex digits)
+ %b - 1 byte ASCII (2 hex digits)
+ %d - decimal
+ %c - ASCII char
+ %s - ASCII string
+ %I - Internet address in x.x.x.x notation
+ %L - Binary long
+ %S - String (multiple of 4 bytes) preceded with 4 byte
+ binary length
+ %M - Copy memory. Takes two args, len and ptr
+**************************************************************************/
+static char hex[]="0123456789ABCDEF";
+char *do_printf(buf, fmt, dp)
+ char *buf, *fmt;
+ int *dp;
+{
+ register char *p;
+ char tmp[16];
+ while (*fmt) {
+ if (*fmt == '%') { /* switch() uses more space */
+ fmt++;
+ if (*fmt == 'L') {
+ register int h = *(dp++);
+ *(buf++) = h>>24;
+ *(buf++) = h>>16;
+ *(buf++) = h>>8;
+ *(buf++) = h;
+ }
+ if (*fmt == 'S') {
+ register int len = 0;
+ char *lenptr = buf;
+ p = (char *)*dp++;
+ buf += 4;
+ while (*p) {
+ *(buf++) = *p++;
+ len ++;
+ }
+ *(lenptr++) = len>>24;
+ *(lenptr++) = len>>16;
+ *(lenptr++) = len>>8;
+ *lenptr = len;
+ while (len & 3) {
+ *(buf++) = 0;
+ len ++;
+ }
+ }
+ if (*fmt == 'M') {
+ register int len = *(dp++);
+ bcopy((char *)*dp++, buf, len);
+ buf += len;
+ }
+ if (*fmt == 'X') {
+ register int h = *(dp++);
+ *(buf++) = hex[(h>>28)& 0x0F];
+ *(buf++) = hex[(h>>24)& 0x0F];
+ *(buf++) = hex[(h>>20)& 0x0F];
+ *(buf++) = hex[(h>>16)& 0x0F];
+ *(buf++) = hex[(h>>12)& 0x0F];
+ *(buf++) = hex[(h>>8)& 0x0F];
+ *(buf++) = hex[(h>>4)& 0x0F];
+ *(buf++) = hex[h& 0x0F];
+ }
+ if (*fmt == 'x') {
+ register int h = *(dp++);
+ *(buf++) = hex[(h>>12)& 0x0F];
+ *(buf++) = hex[(h>>8)& 0x0F];
+ *(buf++) = hex[(h>>4)& 0x0F];
+ *(buf++) = hex[h& 0x0F];
+ }
+ if (*fmt == 'b') {
+ register int h = *(dp++);
+ *(buf++) = hex[(h>>4)& 0x0F];
+ *(buf++) = hex[h& 0x0F];
+ }
+ if (*fmt == 'd') {
+ register int dec = *(dp++);
+ p = tmp;
+ if (dec < 0) {
+ *(buf++) = '-';
+ dec = -dec;
+ }
+ do {
+ *(p++) = '0' + (dec%10);
+ dec = dec/10;
+ } while(dec);
+ while ((--p) >= tmp) *(buf++) = *p;
+ }
+ if (*fmt == 'I') {
+ buf = sprintf(buf,"%d.%d.%d.%d",
+ (*(dp)>>24) & 0x00FF,
+ (*(dp)>>16) & 0x00FF,
+ (*(dp)>>8) & 0x00FF,
+ *dp & 0x00FF);
+ dp++;
+ }
+ if (*fmt == 'c')
+ *(buf++) = *(dp++);
+ if (*fmt == 's') {
+ p = (char *)*dp++;
+ while (*p) *(buf++) = *p++;
+ }
+ } else *(buf++) = *fmt;
+ fmt++;
+ }
+ *buf = 0;
+ return(buf);
+}
+
+char *sprintf(buf, fmt, data)
+ char *fmt, *buf;
+ int data;
+{
+ return(do_printf(buf,fmt, &data));
+}
+
+printf(fmt,data)
+ char *fmt;
+ int data;
+{
+ char buf[80],*p;
+ p = buf;
+ do_printf(buf,fmt,&data);
+ while (*p) putchar(*p++);
+}
+
+/**************************************************************************
+SETIP - Convert an ascii x.x.x.x to binary form
+**************************************************************************/
+setip(p, i)
+ char *p;
+ unsigned *i;
+{
+ unsigned ip = 0;
+ int val;
+ if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+ if (*p != '.') return(0);
+ p++;
+ ip = val;
+ if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+ if (*p != '.') return(0);
+ p++;
+ ip = (ip << 8) | val;
+ if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+ if (*p != '.') return(0);
+ p++;
+ ip = (ip << 8) | val;
+ if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
+ *i = (ip << 8) | val;
+ return(1);
+}
+
+getdec(ptr)
+ char **ptr;
+{
+ char *p = *ptr;
+ int ret=0;
+ if ((*p < '0') || (*p > '9')) return(-1);
+ while ((*p >= '0') && (*p <= '9')) {
+ ret = ret*10 + (*p - '0');
+ p++;
+ }
+ *ptr = p;
+ return(ret);
+}
+
+
+#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
+#define K_STATUS 0x64 /* keyboard status */
+#define K_CMD 0x64 /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL 0x01 /* output buffer full */
+#define K_IBUF_FUL 0x02 /* input buffer full */
+
+#define KC_CMD_WIN 0xd0 /* read output port */
+#define KC_CMD_WOUT 0xd1 /* write output port */
+#define KB_A20 0x9f /* enable A20,
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+
+/*
+ * Gate A20 for high memory
+ */
+unsigned char x_20 = KB_A20;
+gateA20()
+{
+#ifdef IBM_L40
+ outb(0x92, 0x2);
+#else IBM_L40
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ while (inb(K_STATUS) & K_OBUF_FUL)
+ (void)inb(K_RDWR);
+
+ outb(K_CMD, KC_CMD_WOUT);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ outb(K_RDWR, x_20);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+#endif IBM_L40
+}
+
diff --git a/sys/i386/boot/netboot/netboot.doc b/sys/i386/boot/netboot/netboot.doc
new file mode 100644
index 0000000..d9d261e
--- /dev/null
+++ b/sys/i386/boot/netboot/netboot.doc
@@ -0,0 +1,42 @@
+
+Configuring FreeBSD to run diskless Oct 15/1994
+===================================
+
+1) Find a machine that will be your server. This machine will require
+ enough disk space to hold the FreeBSD 2.0 binaries and have bootp and
+ tftp services available.
+
+2) Create a bootptab entry for the diskless FreeBSD machine.
+
+ sample entry:
+
+ diskless:\
+ :ht=ether:\
+ :ha=0000c01f848a:\
+ :sm=255.255.255.0:\
+ :hn:\
+ :ds=192.1.2.3:\
+ :ip=192.1.2.4:\
+ :vm=rfc1048:
+
+
+3) Create a cfg.x.x.x.x file for your diskless machine. This is now an
+ ASCII file with netboot commands in it.
+
+ sample cfg.x.x.x.x:
+
+ hostname diskless.freebsd.com
+ rootfs server.freebsd.com:/var/rootfs/diskless
+ swapfs server.freebsd.com:/var/swap/diskless
+
+4) On the server, export the root and swap filesystems to the client. This
+ usually involves putting them in the /etc/exports file and one some
+ machines running /usr/etc/exportfs -av
+
+5) Make a BOOTROM by copying netboot.rom to an EPROM, or copy netboot.com to
+ a DOS diskette.
+
+6) Boot the diskless machine and run netboot.com if you're using DOS.
+
+
+Martin Renters martin@innovus.com
diff --git a/sys/i386/boot/netboot/netboot.h b/sys/i386/boot/netboot/netboot.h
new file mode 100644
index 0000000..e6d949d
--- /dev/null
+++ b/sys/i386/boot/netboot/netboot.h
@@ -0,0 +1,237 @@
+
+/**************************************************************************
+NETBOOT - BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+ Date: Dec/93
+
+**************************************************************************/
+
+#include <sys/types.h>
+#include <a.out.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <nfs/nfsv2.h>
+#include <nfs/nfsdiskless.h>
+#include <machine/bootinfo.h>
+
+#define ESC 0x1B
+
+#ifndef DEFAULT_BOOTFILE
+#define DEFAULT_BOOTFILE "kernel"
+#endif
+
+#ifndef MAX_TFTP_RETRIES
+#define MAX_TFTP_RETRIES 20
+#endif
+
+#ifndef MAX_BOOTP_RETRIES
+#define MAX_BOOTP_RETRIES 20
+#endif
+
+#ifndef MAX_ARP_RETRIES
+#define MAX_ARP_RETRIES 20
+#endif
+
+#ifndef MAX_RPC_RETRIES
+#define MAX_RPC_RETRIES 20
+#endif
+
+#ifndef TIMEOUT /* Inter-packet retry in ticks 18/sec */
+#define TIMEOUT 20
+#endif
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define ETHER_ADDR_SIZE 6 /* Size of Ethernet address */
+#define ETHER_HDR_SIZE 14 /* Size of ethernet header */
+
+#define ARP_CLIENT 0
+#define ARP_SERVER 1
+#define ARP_GATEWAY 2
+#define ARP_NS 3
+#define ARP_ROOTSERVER 4
+#define ARP_SWAPSERVER 5
+#define MAX_ARP ARP_SWAPSERVER+1
+
+#define IP 0x0800
+#define ARP 0x0806
+
+#define BOOTP_SERVER 67
+#define BOOTP_CLIENT 68
+#define TFTP 69
+#define SUNRPC 111
+
+#define RPC_SOCKET 620 /* Arbitrary */
+
+#define IP_UDP 17
+#define IP_BROADCAST 0xFFFFFFFF
+
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+
+#define BOOTP_REQUEST 1
+#define BOOTP_REPLY 2
+
+#define TFTP_RRQ 1
+#define TFTP_WRQ 2
+#define TFTP_DATA 3
+#define TFTP_ACK 4
+#define TFTP_ERROR 5
+
+#define TFTP_CODE_EOF 1
+#define TFTP_CODE_MORE 2
+#define TFTP_CODE_ERROR 3
+#define TFTP_CODE_BOOT 4
+#define TFTP_CODE_CFG 5
+
+#define PROG_PORTMAP 100000
+#define PROG_NFS 100003
+#define PROG_MOUNT 100005
+
+#define MSG_CALL 0
+#define MSG_REPLY 1
+
+#define PORTMAP_LOOKUP 3
+
+#define MOUNT_ADDENTRY 1
+#define NFS_LOOKUP 4
+#define NFS_READ 6
+
+#define NFS_READ_SIZE 1024
+
+
+#define AWAIT_ARP 0
+#define AWAIT_BOOTP 1
+#define AWAIT_TFTP 2
+#define AWAIT_RPC 3
+
+struct arptable_t {
+ unsigned long ipaddr;
+ unsigned char node[6];
+} arptable[MAX_ARP];
+
+struct arprequest {
+ unsigned short hwtype;
+ unsigned short protocol;
+ char hwlen;
+ char protolen;
+ unsigned short opcode;
+ char shwaddr[6];
+ char sipaddr[4];
+ char thwaddr[6];
+ char tipaddr[4];
+};
+
+struct iphdr {
+ char verhdrlen;
+ char service;
+ unsigned short len;
+ unsigned short ident;
+ unsigned short frags;
+ char ttl;
+ char protocol;
+ unsigned short chksum;
+ char src[4];
+ char dest[4];
+};
+
+struct udphdr {
+ unsigned short src;
+ unsigned short dest;
+ unsigned short len;
+ unsigned short chksum;
+};
+
+struct bootp_t {
+ struct iphdr ip;
+ struct udphdr udp;
+ char bp_op;
+ char bp_htype;
+ char bp_hlen;
+ char bp_hops;
+ unsigned long bp_xid;
+ unsigned short bp_secs;
+ unsigned short unused;
+ char bp_ciaddr[4];
+ char bp_yiaddr[4];
+ char bp_siaddr[4];
+ char bp_giaddr[4];
+ char bp_hwaddr[16];
+ char bp_sname[64];
+ char bp_file[128];
+ char bp_vend[64];
+};
+
+struct tftp_t {
+ struct iphdr ip;
+ struct udphdr udp;
+ unsigned short opcode;
+ union {
+ char rrq[512];
+ struct {
+ unsigned short block;
+ char download[512];
+ } data;
+ struct {
+ unsigned short block;
+ } ack;
+ struct {
+ unsigned short errcode;
+ char errmsg[512];
+ } err;
+ } u;
+};
+
+struct rpc_t {
+ struct iphdr ip;
+ struct udphdr udp;
+ union {
+ char data[1400];
+ struct {
+ long id;
+ long type;
+ long rstatus;
+ long verifier;
+ long v2;
+ long astatus;
+ long data[1];
+ } reply;
+ } u;
+};
+
+#define TFTP_MIN_PACKET_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr) + 4)
+
+static inline unsigned char inb(a)
+ unsigned short a;
+{
+ unsigned char d;
+ asm volatile( "inb %1, %0" : "=a" (d) : "d" (a));
+ return d;
+}
+
+static inline void outb(a,d)
+ unsigned short a;
+ unsigned char d;
+{
+ asm volatile( "outb %0, %1" : : "a" (d), "d" (a));
+}
+
+/***************************************************************************
+RPC Functions
+***************************************************************************/
+#define PUTLONG(val) {\
+ register int lval = val; \
+ *(rpcptr++) = ((lval) >> 24); \
+ *(rpcptr++) = ((lval) >> 16); \
+ *(rpcptr++) = ((lval) >> 8); \
+ *(rpcptr++) = (lval); \
+ rpclen+=4; }
+
+char *sprintf();
diff --git a/sys/i386/boot/netboot/rpc.c b/sys/i386/boot/netboot/rpc.c
new file mode 100644
index 0000000..f035248
--- /dev/null
+++ b/sys/i386/boot/netboot/rpc.c
@@ -0,0 +1,187 @@
+/***********************************************************************
+
+Remote Procedure Call Support Routines
+
+Author: Martin Renters
+ Date: Oct/1994
+
+***********************************************************************/
+
+#include "netboot.h"
+
+int rpc_id;
+extern char packet[];
+extern struct nfs_diskless nfsdiskless;
+extern int hostnamelen;
+/***************************************************************************
+
+RPCLOOKUP: Lookup RPC Port numbers
+
+***************************************************************************/
+rpclookup(addr, prog, ver)
+ int addr, prog, ver;
+{
+ struct rpc_t buf, *rpc;
+ char *rpcptr;
+ int retries = MAX_RPC_RETRIES;
+ rpcptr = sprintf(&buf.u.data,"%L%L%L%L%L%L%L%L%L%L%L%L%L%L",
+ rpc_id, MSG_CALL, 2, PROG_PORTMAP, 2, PORTMAP_LOOKUP,
+ 0, 0, 0, 0, prog, ver, IP_UDP, 0);
+ while(retries--) {
+ udp_transmit(arptable[addr].ipaddr, RPC_SOCKET,
+ SUNRPC, rpcptr - (char *)&buf, &buf);
+ if (await_reply(AWAIT_RPC, rpc_id, NULL)) {
+ rpc = (struct rpc_t *)&packet[ETHER_HDR_SIZE];
+ if (rpc->u.reply.rstatus == rpc->u.reply.verifier ==
+ rpc->u.reply.astatus == 0)
+ return(ntohl(rpc->u.reply.data[0]));
+ else {
+ rpc_err(rpc);
+ return(-1);
+ }
+ }
+ }
+ return(-1);
+}
+
+/***************************************************************************
+
+NFS_MOUNT: Mount an NFS Filesystem
+
+***************************************************************************/
+nfs_mount(server, port, path, fh)
+ int server;
+ int port;
+ char *path;
+ char *fh;
+{
+ struct rpc_t buf, *rpc;
+ char *rpcptr;
+ int retries = MAX_RPC_RETRIES;
+ rpcptr = sprintf(&buf.u.data,"%L%L%L%L%L%L%L%L%L%S%L%L%L%L%L%L%L%S",
+ rpc_id, MSG_CALL, 2, PROG_MOUNT, 1, MOUNT_ADDENTRY,
+ 1, hostnamelen + 28,0,&nfsdiskless.my_hostnam,0,0,2,0,0,0,0,
+ path);
+ while(retries--) {
+ udp_transmit(arptable[server].ipaddr, RPC_SOCKET,
+ port, rpcptr - (char *)&buf, &buf);
+ if (await_reply(AWAIT_RPC, rpc_id, NULL)) {
+ rpc = (struct rpc_t *)&packet[ETHER_HDR_SIZE];
+ if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
+ rpc->u.reply.astatus || rpc->u.reply.data[0]) {
+ rpc_err(rpc);
+ return(-(ntohl(rpc->u.reply.data[0])));
+ } else {
+ bcopy(&rpc->u.reply.data[1],fh, 32);
+ return(0);
+ }
+ }
+ }
+ return(-1);
+}
+
+
+/***************************************************************************
+
+NFS_LOOKUP: Lookup Pathname
+
+***************************************************************************/
+nfs_lookup(server, port, fh, path, file_fh)
+ int server;
+ int port;
+ char *fh;
+ char *path;
+ char *file_fh;
+{
+ struct rpc_t buf, *rpc;
+ char *rpcptr;
+ int retries = MAX_RPC_RETRIES;
+ rpcptr = sprintf(&buf.u.data,"%L%L%L%L%L%L%L%L%L%S%L%L%L%L%L%L%L%M%S",
+ rpc_id, MSG_CALL, 2, PROG_NFS, 2, NFS_LOOKUP,
+ 1, hostnamelen + 28,0,&nfsdiskless.my_hostnam,0,0,2,0,0,0,0,
+ 32, fh, path);
+ while(retries--) {
+ udp_transmit(arptable[server].ipaddr, RPC_SOCKET,
+ port, rpcptr - (char *)&buf, &buf);
+ if (await_reply(AWAIT_RPC, rpc_id, NULL)) {
+ rpc = (struct rpc_t *)&packet[ETHER_HDR_SIZE];
+ if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
+ rpc->u.reply.astatus || rpc->u.reply.data[0]) {
+ rpc_err(rpc);
+ return(-(ntohl(rpc->u.reply.data[0])));
+ } else {
+ bcopy(&rpc->u.reply.data[1],file_fh, 32);
+ return(0);
+ }
+ }
+ }
+ return(-1);
+}
+
+/***************************************************************************
+
+NFS_READ: Read File
+
+***************************************************************************/
+nfs_read(server, port, fh, offset, len, buffer)
+ int server;
+ int port;
+ char *fh;
+ int offset, len;
+ char *buffer;
+{
+ struct rpc_t buf, *rpc;
+ char *rpcptr;
+ int retries = MAX_RPC_RETRIES;
+ int rlen;
+ rpcptr = sprintf(&buf.u.data,
+ "%L%L%L%L%L%L%L%L%L%S%L%L%L%L%L%L%L%M%L%L%L",
+ rpc_id, MSG_CALL, 2, PROG_NFS, 2, NFS_READ,
+ 1, hostnamelen + 28,0,&nfsdiskless.my_hostnam,0,0,2,0,0,0,0,
+ 32, fh, offset, len, 0);
+ while(retries--) {
+ udp_transmit(arptable[server].ipaddr, RPC_SOCKET,
+ port, rpcptr - (char *)&buf, &buf);
+ if (await_reply(AWAIT_RPC, rpc_id, NULL)) {
+ rpc = (struct rpc_t *)&packet[ETHER_HDR_SIZE];
+ if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||
+ rpc->u.reply.astatus || rpc->u.reply.data[0]) {
+ rpc_err(rpc);
+ return(-(ntohl(rpc->u.reply.data[0])));
+ } else {
+ rlen = ntohl(rpc->u.reply.data[18]);
+ if (len < rlen) rlen = len;
+ if (len > rlen) printf("short read\r\n");
+ bcopy(&rpc->u.reply.data[19], buffer, rlen);
+ return(rlen);
+ }
+ }
+ }
+ return(-1);
+}
+
+/***************************************************************************
+
+RPC_ERR - Print RPC Errors
+
+***************************************************************************/
+rpc_err(rpc)
+ struct rpc_t *rpc;
+{
+ int err = ntohl(rpc->u.reply.data[0]);
+ printf("***RPC Error: (%d,%d,%d):\r\n ",
+ ntohl(rpc->u.reply.rstatus),
+ ntohl(rpc->u.reply.verifier),
+ ntohl(rpc->u.reply.astatus));
+}
+
+nfs_err(err)
+ int err;
+{
+ err = -err;
+ if (err == NFSERR_PERM) printf("Not owner");
+ else if (err == NFSERR_NOENT) printf("No such file or directory");
+ else if (err == NFSERR_ACCES) printf("Permission denied");
+ else printf("Error %d",err);
+ printf("\r\n");
+}
diff --git a/sys/i386/boot/netboot/start2.S b/sys/i386/boot/netboot/start2.S
new file mode 100644
index 0000000..dd249c7
--- /dev/null
+++ b/sys/i386/boot/netboot/start2.S
@@ -0,0 +1,332 @@
+
+#define STACKADDR 0xe000 /* Needs to be end of bss + stacksize */
+#define KERN_CODE_SEG 0x08
+#define KERN_DATA_SEG 0x10
+#define REAL_MODE_SEG 0x18
+#define CR0_PE 1
+
+#define opsize .byte 0x66
+#define addrsize .byte 0x67
+
+/* At entry, the processor is in 16 bit real mode and the code is being
+ * executed from an address it was not linked to. Code must be pic and
+ * 32 bit sensitive until things are fixed up.
+ */
+#ifdef BOOTROM
+ .word 0xaa55 /* bios extension signature */
+ .byte (ROMSIZE>>9) /* no. of 512B blocks */
+ jmp 1f /* enter from bios here */
+ .byte 0 /* checksum */
+1: push %eax
+ push %ds
+ xor %eax,%eax
+ mov %ax,%ds
+ .byte 0xa1 /* MOV 0x304,%ax */
+ .word 0x304
+ .byte 0x3d /* CMP $0x4d52, %ax == 'MR' */
+ .word 0x4d52
+ jz 2f
+ .byte 0xa1 /* MOV 0x64, %ax */
+ .word 0x64
+ .byte 0xa3 /* MOV %ax, 0x300 */
+ .word 0x300
+ .byte 0xa1 /* MOV 0x66, %ax */
+ .word 0x66
+ .byte 0xa3 /* MOV %ax, 0x302 */
+ .word 0x302
+ .byte 0xb8 /* MOV $_start-RELOCADDR, %ax */
+ .word (_start-RELOC)
+ .byte 0xa3 /* MOV %ax, 0x64 */
+ .word 0x64
+ mov %cs,%ax
+ .byte 0xa3 /* MOV %ax, 0x66 */
+ .word 0x66
+ .byte 0xb8 /* MOV 'MR',%ax */
+ .word 0x4d52
+ .byte 0xa3 /* MOV %ax, 0x304 */
+ .word 0x304
+2: pop %ds
+ pop %eax
+ lret
+#endif
+
+/**************************************************************************
+START - Where all the fun begins....
+**************************************************************************/
+ .globl _start
+_start:
+ cli
+ cld
+#ifdef BOOTROM /* relocate ourselves */
+ xor %esi, %esi /* zero for ROMs */
+#else
+ .byte 0xbe /* MOV $0x100,%si -- 100h for .COM */
+ .word 0x100
+#endif
+ xor %edi,%edi
+ .byte 0xb8 /* MOV $RELOCADDR>>4, %ax */
+ .word (RELOC>>4)
+ mov %ax, %es
+ .byte 0xb9 /* MOV $ROMSIZE, %cx */
+ .word ROMSIZE
+ cs
+ rep
+ movsb
+ opsize
+ ljmp $(RELOC>>4),$1f-RELOC /* Jmp to RELOC:1f */
+1:
+ nop
+ mov %cs,%ax
+ mov %ax,%ds
+ mov %ax,%es
+ mov %ax,%ss
+ .byte 0xb8 /* MOV $STACKADDR, %ax */
+ .word STACKADDR
+ mov %eax,%esp
+ opsize
+ call _real_to_prot
+ call _main
+ .globl _exit
+_exit:
+ call _prot_to_real
+#ifdef BOOTROM
+ xor %eax,%eax
+ mov %ax,%ds
+ .byte 0xa1 /* MOV 0x302, %ax */
+ .word 0x302
+ push %eax
+ .byte 0xa1 /* MOV 0x300, %ax */
+ .word 0x300
+ push %eax
+ lret
+#else
+ int $0x19
+#endif
+
+/**************************************************************************
+CURRTICKS - Get Time
+**************************************************************************/
+ .globl _currticks
+_currticks:
+ push %ebp
+ mov %esp,%ebp
+ push %ecx
+ push %edx
+ xor %edx,%edx
+ call _prot_to_real
+ xor %eax,%eax
+ int $0x1a
+ opsize
+ call _real_to_prot
+ xor %eax,%eax
+ shl $16,%ecx
+ mov %edx,%eax
+ or %ecx,%eax
+ pop %edx
+ pop %ecx
+ pop %ebp
+ ret
+
+/**************************************************************************
+PUTCHAR - Print a character
+**************************************************************************/
+ .globl _putchar
+_putchar:
+ push %ebp
+ mov %esp,%ebp
+ push %ecx
+ push %ebx
+ movb 8(%ebp),%cl
+ call _prot_to_real
+ opsize
+ mov $1,%ebx
+ movb $0x0e,%ah
+ movb %cl,%al
+ int $0x10
+ opsize
+ call _real_to_prot
+ pop %ebx
+ pop %ecx
+ pop %ebp
+ ret
+
+/**************************************************************************
+GETCHAR - Get a character
+**************************************************************************/
+ .globl _getchar
+_getchar:
+ push %ebp
+ mov %esp,%ebp
+ push %ebx
+ call _prot_to_real
+ movb $0x0,%ah
+ int $0x16
+ movb %al,%bl
+ opsize
+ call _real_to_prot
+ xor %eax,%eax
+ movb %bl,%al
+ pop %ebx
+ pop %ebp
+ ret
+
+/**************************************************************************
+ISKEY - Check for keyboard interrupt
+**************************************************************************/
+ .globl _iskey
+_iskey:
+ push %ebp
+ mov %esp,%ebp
+ push %ebx
+ call _prot_to_real
+ xor %ebx,%ebx
+ movb $0x1,%ah
+ int $0x16
+ opsize
+ jz 1f
+ movb %al,%bl
+1:
+ opsize
+ call _real_to_prot
+ xor %eax,%eax
+ movb %bl,%al
+ pop %ebx
+ pop %ebp
+ ret
+
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * setjmp(a)
+ * by restoring registers from the stack.
+ * The previous signal state is restored.
+ */
+
+ .globl _setjmp
+_setjmp:
+ movl 4(%esp),%ecx
+ movl 0(%esp),%edx
+ movl %edx, 0(%ecx)
+ movl %ebx, 4(%ecx)
+ movl %esp, 8(%ecx)
+ movl %ebp,12(%ecx)
+ movl %esi,16(%ecx)
+ movl %edi,20(%ecx)
+ movl %eax,24(%ecx)
+ movl $0,%eax
+ ret
+
+ .globl _longjmp
+_longjmp:
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ movl 0(%edx),%ecx
+ movl 4(%edx),%ebx
+ movl 8(%edx),%esp
+ movl 12(%edx),%ebp
+ movl 16(%edx),%esi
+ movl 20(%edx),%edi
+ cmpl $0,%eax
+ jne 1f
+ movl $1,%eax
+1: movl %ecx,0(%esp)
+ ret
+
+/**************************************************************************
+___MAIN - Dummy to keep GCC happy
+**************************************************************************/
+ .globl ___main
+___main:
+ ret
+
+/**************************************************************************
+REAL_TO_PROT - Go from REAL mode to Protected Mode
+**************************************************************************/
+ .globl _real_to_prot
+_real_to_prot:
+ cli
+ cs
+ addrsize
+ lgdt gdtarg-RELOC
+ mov %cr0, %eax
+ opsize
+ or $CR0_PE, %eax
+ mov %eax, %cr0 /* turn on protected mode */
+
+ /* jump to relocation, flush prefetch queue, and reload %cs */
+ opsize
+ ljmp $KERN_CODE_SEG, $1f
+1:
+ /* reload other segment registers */
+ movl $KERN_DATA_SEG, %eax
+ movl %ax, %ds
+ movl %ax, %es
+ movl %ax, %ss
+ add $RELOC,%esp /* Fix up stack pointer */
+ pop %eax /* Fix up return Address */
+ add $RELOC,%eax
+ push %eax
+ ret
+
+
+/**************************************************************************
+PROT_TO_REAL - Go from Protected Mode to REAL Mode
+**************************************************************************/
+ .globl _prot_to_real
+_prot_to_real:
+ pop %eax
+ sub $RELOC,%eax /* Adjust return address */
+ push %eax
+ sub $RELOC,%esp /* Adjust stack pointer */
+ ljmp $REAL_MODE_SEG, $1f /* jump to a 16 bit segment */
+1:
+ /* clear the PE bit of CR0 */
+ mov %cr0, %eax
+ opsize
+ andl $0!CR0_PE, %eax
+ mov %eax, %cr0
+
+ /* make intersegment jmp to flush the processor pipeline
+ * and reload CS register
+ */
+ opsize
+ ljmp $(RELOC)>>4, $2f-RELOC
+2:
+ /* we are in real mode now
+ * set up the real mode segment registers : DS, SS, ES
+ */
+ mov %cs, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %ss
+ sti
+ opsize
+ ret
+
+/**************************************************************************
+GLOBAL DESCRIPTOR TABLE
+**************************************************************************/
+ .align 4
+gdt:
+ .word 0, 0
+ .byte 0, 0x00, 0x00, 0
+
+ /* code segment */
+ .word 0xffff, 0
+ .byte 0, 0x9f, 0xcf, 0
+
+ /* data segment */
+ .word 0xffff, 0
+ .byte 0, 0x93, 0xcf, 0
+
+ /* 16 bit real mode */
+ .word 0xffff, 0
+ .byte 0, 0x9b, 0x0f, 0
+
+ .align 4
+gdtarg:
+ .word 0x1f /* limit */
+ .long gdt /* addr */
OpenPOWER on IntegriCloud