diff options
| -rw-r--r-- | sys/i386/boot/netboot/Makefile | 61 | ||||
| -rw-r--r-- | sys/i386/boot/netboot/bootmenu.c | 229 | ||||
| -rw-r--r-- | sys/i386/boot/netboot/ether.c | 479 | ||||
| -rw-r--r-- | sys/i386/boot/netboot/ether.h | 178 | ||||
| -rw-r--r-- | sys/i386/boot/netboot/main.c | 525 | ||||
| -rw-r--r-- | sys/i386/boot/netboot/makerom.c | 42 | ||||
| -rw-r--r-- | sys/i386/boot/netboot/misc.c | 261 | ||||
| -rw-r--r-- | sys/i386/boot/netboot/netboot.doc | 42 | ||||
| -rw-r--r-- | sys/i386/boot/netboot/netboot.h | 237 | ||||
| -rw-r--r-- | sys/i386/boot/netboot/rpc.c | 187 | ||||
| -rw-r--r-- | sys/i386/boot/netboot/start2.S | 332 |
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 000000000000..d4661ac24182 --- /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 000000000000..7313dc7d9ed0 --- /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 000000000000..41d06803cd01 --- /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 000000000000..586a35cb963b --- /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 000000000000..35a22489a682 --- /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 000000000000..98cc65130ec4 --- /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 000000000000..814ddbf63d96 --- /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 000000000000..d9d261e5610a --- /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 000000000000..e6d949dafc42 --- /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 000000000000..f03524871b89 --- /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 000000000000..dd249c742d16 --- /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 */ |
