diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /sys/arch/i386/netboot |
initial import of NetBSD tree
Diffstat (limited to 'sys/arch/i386/netboot')
29 files changed, 5167 insertions, 0 deletions
diff --git a/sys/arch/i386/netboot/Makefile b/sys/arch/i386/netboot/Makefile new file mode 100644 index 00000000000..2e920904008 --- /dev/null +++ b/sys/arch/i386/netboot/Makefile @@ -0,0 +1,73 @@ +# $NetBSD: Makefile,v 1.4 1994/10/27 04:20:59 cgd Exp $ + +# uncomment one of these as appropriate for the board being used +#ETH_OBJ = ne2100.o +ETH_OBJ = wd80x3.o + +# set this to the size of the eprom (decimal) +ROM_SIZE = 16384 + +.SUFFIXES: .s .c .o .list +.c.list: + $(CC) $(CFLAGS) $(INC) -S $< + $(AS) $*.s -a -o /dev/null > $@ + rm $*.s + +.s.o: + @echo $(AS) -o $*.o $< [$(DEFINES)] + -@trap "/bin/rm -f $*.i X$*.c; exit 0" 0 1 2 3 10 15; \ + /bin/rm -f X$*.c; \ + ln $*.s X$*.c; \ + $(CC) -E $(CFLAGS) X$*.c > $*.i; \ + if [ $$? != 0 ]; then :; \ + else \ + $(AS) $*.i -o $@; \ + fi +.s.list: + @echo $(AS) -o $*.o $< [$(DEFINES)] + -@trap "/bin/rm -f $*.i X$*.c; exit 0" 0 1 2 3 10 15; \ + /bin/rm -f X$*.c; \ + ln $*.s X$*.c; \ + $(CC) -E $(CFLAGS) X$*.c > $*.i; \ + if [ $$? != 0 ]; then :; \ + else \ + $(AS) $*.i -a -o /dev/null > $@; \ + fi + +# the relocation address (hex) +RELOC = 98000 +CFLAGS = -O $(DEFINES) -nostdinc +DEFINES = -DRELOC=0x$(RELOC) -DROM_SIZE=$(ROM_SIZE) -DTRACE=0 -Dprinte=printf \ + -DDEBUG -DUSE_BOOTP -DUSE_RARP #-DPhysBcopy=bcopy -DPhysBzero=bzero + +OBJS = start.o main.o cga.o kbd.o packet.o tftp.o arp.o \ + $(ETH_OBJ) misc.o asm.o + +all: boot.bin + +boot.bin: $(OBJS) genprom + ${LD} -e _start -N -T ${RELOC} $(OBJS) + cp a.out boot.sym + rm -f $@ + strip a.out + dd if=a.out of=boot.v ibs=32 skip=1 obs=1024b + genprom <boot.v >$@ + rm -f a.out boot.v + +genprom: genprom.c + $(CC) -o $@ -DROM_SIZE=$(ROM_SIZE) genprom.c + +# copy to dos floppy for testing (faster than burning an eprom) +dostest: boot.bin + mcopy -n boot.bin a: + +TAGS: main.c cga.c kbd.c packet.c tftp.c arp.c wd80x3.c misc.c proto.h + etags main.c cga.c kbd.c packet.c tftp.c arp.c wd80x3.c misc.c proto.h + +clean: + rm -f *.o *.list *~ genprom + +cleandir: clean + rm -f boot.bin boot.sym + +.include <bsd.prog.mk> diff --git a/sys/arch/i386/netboot/README b/sys/arch/i386/netboot/README new file mode 100644 index 00000000000..5f58b127648 --- /dev/null +++ b/sys/arch/i386/netboot/README @@ -0,0 +1,183 @@ +$NetBSD: README,v 1.2 1994/10/27 04:21:00 cgd Exp $ + +Ethernet boot prom code. + +This is code that can be burned into an eprom and installed in an +ethernet card. It uses the extension facilities of the bios to to boot +a kernel via the network. + +Netboot uses bootp or rarp to determine its ip address and tftps a +designated kernel from a server. You should be running a daemon for +either bootp or rarp to service requests from this client. If you are +using bootp, the boot file name and the gateway (if necessary) will +also be transmitted to the client. If you use rarpd, the boot file +name is synthesized by this boot code from the eight hexadecimal +digits that comprise the IP address of the client and an extension of +"386bsd". If you use rarp, the rarp server must also be the tftp +server. + +If you have configured both bootp and rarpd into the boot prom, the +response from the first host to respond via either protocol will be +used. + +This code was developed using GNU as 2.1 and GNU cc version 2.3.3, +running under 386bsd. Pre 2.0 versions of GNU as might have trouble +with some syntax. Testing was done with a SMC Elite16 and 16k eproms. + + +Installation instructions: + +Check the configurable parameters in Makefile. + +Check the configurable parameters in the ethernet driver source for +the card you are using: +- in wd80x3.c: WD_BASEREG, WD_BASEMEM (irqs not used) + +Make. + +If you wish, you can test the binary (boot.bin) by copying it to a +floppy with the dosload.exe program and execute the boot code from the +floppy. + +Burn the resultant binary (boot.bin) into an eprom and install it in +the ethernet card. + +Decide which protocol (bootp or rarp) to use on a server; set up that +server. + +Setting up a bootp server entails creating a bootpd client +configuration file. The format is similar to that of printcap. An +entry looks something like: + +sams-1:\ + :bf=diskless_kernel.386bsd:\ + :gw=139.88.30.4:\ + :ht=ethernet:\ + :ha=0000c025e35b:\ + :ip=139.88.30.39:\ + :sm=255.255.255.0:\ + :to=18000: + +Setting up a rarpd server entails creating an ethernet/ip address +resolution file '/etc/ethers' with a line for each netboot client in +the form: + +00:00:c0:25:e3:5b sams-1.lerc.nasa.gov + +If you don't know the ethernet address, boot the client with the eprom +installed; the ethernet address of the card will be displayed. + +Set up tftpd on a server. Check '/etc/inetd.conf'; there should be a +line that starts something like: + +tftp dgram udp wait root ... + +perhaps commented out. + +Build a kernel that is capable of operating via NFS. Martin Renters +released some patches and a kernel configuration program that work +nicely (comp.os.386bsd.development around March 22, 1993); they should +be around somewhere. If you can't find them, I can email you a copy. + +Make the kernel available via tftp under one of the names which this +code will use to look for the kernel. If you are using bootp, you can +specify the name as a bootp client configuration parameter. If you +don't specify the name, or if you are using rarp the this code will +synthesize the name using its client's IP address. The hexadecimal +version of the client's IP address with the extension '.386bsd' is the +default choice. + +Create the exportable nfs mount points for which this kernel will use +and load them with necessary files (the base distribution, ...). +Export them so they can be mounted by this kernel when it boots from +the client IP address. + + +Usage instructions: + +At any time the escape key can be struck to gain entrance to the +interactive monitor. There is a menu of monitor commands that can be +invoked to customize a boot operation. + + +Notes: + +When Martin Renter's patches are applied to netbsd 0.8, there will be +one failure (pmap.c). Ignore it, the relevant code has already been +fixed. + +I had some small problems with getfh(2) as used in the nfs configuring +program - I suspect the problem is a bug in SunOS 4.1.1 - if you have +similar problems, I can email you my gross hack workaround. + +As noted by Mr. Renters, advisory flock()ing is not supported - this +breaks some programs. The first broken utility you will likely +encounter is vipw(1). The others: passwd, dump, ar, mail, tip, lpr, +sendmail. + +You should examine your rc script and make appropriate changes to the +boot up sequence. + +Here are the steps I took to bring netbsd 0.8 up for the client sams-1 +using the host dinah in the domain lerc.nasa.gov. + +- Create the /dev/vga device. + +- Create some ptys. + +- Create /etc/fstab to contain: + dinah:/home/386bsd-root / nfs rw + dinah:/home/386bsd-swap none swap rw +in it for the root and swap. + +- Edit /etc/rc; the line 'mount -a -t nonfs' is changed to: + mount -a -t nonfs,swap + +- Edit /etc/myname to contain + sams-1 + +- Edit /etc/hosts to contain: + 127.0.0.1 localhost loghost + 139.88.30.39 sams-1 +and delete the other stuff in it. + +- Create /etc/resolv.conf to contain: + domain lerc.nasa.gov + nameserver 128.156.1.43 + nameserver 139.88.76.3 +where the two addresses are those of some name servers in my domain. +There are, of course, the two alternatives of using just the /etc/hosts +file, or using named. + +- Create /etc/mygate to contain: + 139.88.30.4 +which is the IP address of my gateway. + +- Re-symlink /etc/localtime to the correct zone. + + +TBD: +-linux +-ne2100 +-handle small memory configuration +-USE_BIOS version +-return to bios correctly +-remove old Phys... stuff; relics of real mode prom version +-accept bootd extension items & pass as args, modify kernel to + init nfs_diskless from args. Need: + myif [local] [bootp] + mygateway [bootp] + swap_args [local] + swap_fh [bootp] + swap_saddr [local] [bootp] + swap_hostname [bootp] + root_args [local] + root_fh [bootp] + root_saddr [local] [bootp] + root_hostnam [bootp] + A tight squeeze, passing all necessary info in one bootp packet. + +Please send me any improvements you make to this code. It will be +appreciated. + +Jim McKim (mckim@lerc.nasa.gov) diff --git a/sys/arch/i386/netboot/arp.c b/sys/arch/i386/netboot/arp.c new file mode 100644 index 00000000000..53285cb1966 --- /dev/null +++ b/sys/arch/i386/netboot/arp.c @@ -0,0 +1,459 @@ +/* $NetBSD: arp.c,v 1.4 1994/10/27 04:21:01 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826). + * No doubt this code is overkill, but I had it lying around. + * + * Copyright (c) 1992 by Leendert van Doorn + */ + +#include "proto.h" +#include "assert.h" +#include "param.h" +#include "packet.h" +#include "ether.h" +#include "inet.h" +#include "arp.h" +#include "bootp.h" +#include "tftp.h" + +static u_char bcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +static arptab_t arptab[ARPTAB_SIZE]; + +extern u_char vendor_area[64]; +ipaddr_t ip_myaddr = IP_ANYADDR; +ipaddr_t ip_gateway = IP_ANYADDR; + +#ifdef USE_RARP +/* + * Broadcast a RARP request (i.e. who knows who I am) + */ +static void +RarpWhoAmI(void) { + arphdr_t *ap; + packet_t *pkt; + pkt = PktAlloc(sizeof(ethhdr_t)); + pkt->pkt_len = sizeof(arphdr_t); + ap = (arphdr_t *) pkt->pkt_offset; + ap->arp_hrd = htons(ARPHRD_ETHER); + ap->arp_pro = htons(ETHTYPE_IP); + ap->arp_hln = ETH_ADDRSIZE; + ap->arp_pln = sizeof(ipaddr_t); + ap->arp_op = htons(REVARP_REQUEST); + bcopy((char *)eth_myaddr, (char *)ap->arp_sha, ETH_ADDRSIZE); + bcopy((char *)eth_myaddr, (char *)ap->arp_tha, ETH_ADDRSIZE); + EtherSend(pkt, ETHTYPE_RARP, bcastaddr); + PktRelease(pkt); +} +#endif + + +#ifdef USE_BOOTP +static int saved_bootp_xid; /* from last bootp req */ +extern int time_zero; +/* + * Broadcast a BOOTP request (i.e. who knows who I am) + */ +static void +BootpWhoAmI(void) { + struct bootp *bp; + packet_t *pkt; + udphdr_t *up; + pkt = PktAlloc(sizeof(ethhdr_t)+sizeof(iphdr_t)); + pkt->pkt_len = sizeof(ethhdr_t) + sizeof(iphdr_t) + + sizeof(udphdr_t) +sizeof(struct bootp); + up = (udphdr_t *) pkt->pkt_offset; + bp = (struct bootp *) ((char *)up + sizeof(udphdr_t)); + up->uh_dport = htons(IPPORT_BOOTPS); + up->uh_len = htons(sizeof(udphdr_t) + sizeof(struct bootp)); + bp->bp_op = BOOTREQUEST; + bp->bp_htype = 1; + bp->bp_hlen = ETH_ADDRSIZE; + bp->bp_xid = saved_bootp_xid = rand(); + bp->bp_secs = htons(timer() - time_zero); + bcopy((char *)eth_myaddr, (char *)bp->bp_chaddr, ETH_ADDRSIZE); + IpSend(pkt, IP_BCASTADDR, IP_ANYADDR); + PktInit(); +} +#endif + +extern ipaddr_t tftp_gateway; +extern ipaddr_t tftp_server; + +#ifdef USE_RARP +/* + * Called when packet containing RARP is received + */ +static inline ipaddr_t +RarpInput(packet_t *pkt, ipaddr_t *server) { + ipaddr_t ipaddr; + ethhdr_t *ep; + ep = (ethhdr_t *)pkt->pkt_offset; + + /* is rarp? */ + if (pkt->pkt_len >= sizeof(arphdr_t) && + ntohs(ep->eth_proto) == ETHTYPE_RARP) { + ipaddr_t ipa; + arphdr_t *ap; + ap = (arphdr_t *) (pkt->pkt_offset + sizeof(ethhdr_t)); + if (ntohs(ap->arp_op) != REVARP_REPLY || + ntohs(ap->arp_pro) != ETHTYPE_IP) + return 0; + if (bcmp(ap->arp_tha, eth_myaddr, ETH_ADDRSIZE)) + return 0; + + bcopy((char *)ap->arp_tpa, (char *)&ipaddr, sizeof(ipaddr_t)); + printf("From RARP server "); + bcopy((char *)ap->arp_spa, (char *)&ipa, sizeof(ipaddr_t)); + IpPrintAddr(ipa); + printf(": using IP address "); + IpPrintAddr(ipaddr); + + if (server) { + bcopy((char *)ap->arp_spa, (char *)server, sizeof(ipaddr_t)); + printf(",\n tftp server "); + IpPrintAddr(*server); + } + + printf("\n"); + return ipaddr; + } + return 0; +} +#endif + +#ifdef USE_BOOTP +static inline ipaddr_t +BootpInput(packet_t *pkt, ipaddr_t *server, ipaddr_t *gateway, char *filename) { + ipaddr_t ipaddr; + ethhdr_t *ep; + ep = (ethhdr_t *)pkt->pkt_offset; + + + if (pkt->pkt_len < sizeof(iphdr_t)+sizeof(udphdr_t)+sizeof(struct bootp)) + return 0; + if (ntohs(ep->eth_proto) == ETHTYPE_IP) { + iphdr_t *ip; + udphdr_t *up; + struct bootp *bp; + ip = (iphdr_t *) ((char *)ep + sizeof(ethhdr_t)); + up = (udphdr_t *) ((char *)ip + sizeof(iphdr_t)); + bp = (struct bootp *) ((char *)up + sizeof(udphdr_t)); + +#if 0 +DUMP_STRUCT("eboot", ep, 100); +printf("pktlen %d of %d\n\n", pkt->pkt_len, sizeof(iphdr_t)+sizeof(udphdr_t)+sizeof(struct bootp)); +#endif + + if (ip->ip_p != IP_PROTO_UDP) { + return 0; + } + + if (up->uh_dport != htons(IPPORT_BOOTPC)) { + return 0; + } + + if (bp->bp_xid != saved_bootp_xid) { + return 0; + } + + /* passed all checks - is the packet we expected */ + ipaddr = bp->bp_yiaddr; + printf("From BOOTP server "); + IpPrintAddr(ip->ip_src); + printf(": using IP address "); + IpPrintAddr(bp->bp_yiaddr); + + if (server) { + *server = bp->bp_siaddr; + printf(",\n tftp server "); + IpPrintAddr(bp->bp_siaddr); + } + + if (bp->bp_giaddr) { + *gateway = bp->bp_giaddr; + printf(",\n gateway "); + IpPrintAddr(bp->bp_giaddr); + } + + if (*bp->bp_file) { + bcopy((char *)bp->bp_file, filename, MAX_FILE_NAME_LEN-1); + printf(",\n file '%s'", bp->bp_file); + } + + bcopy((char *)bp->bp_vend, (char *)vendor_area, sizeof(vendor_area)); + + printf("\n"); + + PktInit(); + return ipaddr; + } + return 0; +} +#endif + +/* + * Using the BOOTP and/or RARP request/reply exchange we try to obtain our + * internet address (see RFC 903). + */ +ipaddr_t +GetIpAddress(ipaddr_t *serv_addr, ipaddr_t *myaddr, ipaddr_t *gateway, char *filename) { + u_long time, current, timeout; + int retry; + packet_t *pkt; + int spin = 0; + +#if TRACE > 0 + printe("GetIpAddress: Requesting IP address for "); + EtherPrintAddr(eth_myaddr); + printe("\n"); +#endif + + timeout = 4; /* four seconds */ + for (retry = 0; retry < NRETRIES; retry++) { +#ifdef USE_RARP + RarpWhoAmI(); +#endif +#ifdef USE_BOOTP + BootpWhoAmI(); +#endif + printf("%c\b", "-\\|/"[spin++ % 4]); + + time = timer() + timeout; + do { + pkt = EtherReceive(); + if (pkt) { + *myaddr = 0; +#ifdef USE_RARP + *myaddr = RarpInput(pkt, serv_addr); +#endif +#ifdef USE_BOOTP + if (!*myaddr) + *myaddr = BootpInput(pkt, serv_addr, gateway, filename); +#endif + PktRelease(pkt); + if (*myaddr) { + return 1; + } + } + HandleKbdAttn(); + current = timer(); + } while (current < time); + EtherReset(); + timeout <<= 1; + } + printf("No response for " +#ifdef USE_BOOTP + "BOOTP " +#endif +#ifdef USE_RARP + "RARP " +#endif + "request\n"); + return IP_ANYADDR; +} + +/* + * Broadcast an ARP packet (i.e. ask who has address "addr") + */ +static void +ArpWhoHas(ipaddr_t addr) { + arphdr_t *ap; + packet_t *pkt; + + pkt = PktAlloc(sizeof(ethhdr_t)); + pkt->pkt_len = sizeof(arphdr_t); + ap = (arphdr_t *) pkt->pkt_offset; + ap->arp_hrd = htons(ARPHRD_ETHER); + ap->arp_pro = htons(ETHTYPE_IP); + ap->arp_hln = ETH_ADDRSIZE; + ap->arp_pln = sizeof(ipaddr_t); + ap->arp_op = htons(ARPOP_REQUEST); + bcopy((char *)eth_myaddr, (char *)ap->arp_sha, ETH_ADDRSIZE); + bcopy((char *)&ip_myaddr, (char *)ap->arp_spa, sizeof(ipaddr_t)); + bcopy((char *)&addr, (char *)ap->arp_tpa, sizeof(ipaddr_t)); +#if TRACE > 0 +printe("ArpWhoHas:\n"); +DUMP_STRUCT("arphdr_t", ap, sizeof(arphdr_t)); +#endif + EtherSend(pkt, ETHTYPE_ARP, bcastaddr); + PktRelease(pkt); +} + +/* + * Free an arptab entry + */ +static void +ArpTfree(arptab_t *at) { + if (at->at_hold) + PktRelease(at->at_hold); + at->at_hold = (packet_t *)0; + at->at_timer = at->at_flags = 0; + at->at_ipaddr = 0; +} + +/* + * Enter a new address in arptab, pushing out the oldest entry + * from the bucket if there is no room. + */ +static arptab_t * +ArpTnew(ipaddr_t addr) { + u_short n; + u_long oldest; + arptab_t *at, *ato; + + oldest = ~0; + ato = at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; + for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) { + if (at->at_flags == 0) + goto out; /* found an empty entry */ + if (at->at_timer < oldest) { + oldest = at->at_timer; + ato = at; + } + } + at = ato; + ArpTfree(at); + out: + at->at_ipaddr = addr; + at->at_flags = ATF_INUSE; + return at; +} + +/* + * Resolve an IP address into a hardware address. If success, + * destha is filled in and 1 is returned. If there is no entry + * in arptab, set one up and broadcast a request + * for the IP address; return 0. Hold onto this packet and + * resend it once the address is finally resolved. + */ +int +ArpResolve(packet_t *pkt, ipaddr_t destip, u_char *destha) { + arptab_t *at; + u_long lna = ntohl(destip) & 0xFF; + + if (lna == 0xFF || lna == 0x0) { /* broadcast address */ + bcopy((char *)bcastaddr, (char *)destha, ETH_ADDRSIZE); + return 1; + } + + ARPTAB_LOOK(at, destip); + if (at == 0) { + at = ArpTnew(destip); + at->at_hold = pkt; + ArpWhoHas(destip); + return 0; + } + + at->at_timer = timer(); /* restart the timer */ + if (at->at_flags & ATF_COM) { /* entry is complete */ + bcopy((char *)at->at_eaddr, (char *)destha, ETH_ADDRSIZE); + return 1; + } + + /* + * There is an arptab entry, but no hardware address + * response yet. Replace the held packet with this + * latest one. + */ + if (at->at_hold) + PktRelease(at->at_hold); + at->at_hold = pkt; + ArpWhoHas(destip); + return 0; +} + + +/* + * Called when packet containing ARP is received. + * Algorithm is that given in RFC 826. + */ +void +ArpInput(packet_t *pkt) { + arphdr_t *ap; + arptab_t *at; + packet_t *phold; + ipaddr_t isaddr, itaddr; + +#if 0 +T(ArpInput); +#endif + if (pkt->pkt_len < sizeof(arphdr_t)) { +#if 0 + printf("ArpInput: bad packet size %d\n", pkt->pkt_len); +#endif + return; + } + + ap = (arphdr_t *) (pkt->pkt_offset + sizeof(ethhdr_t)); +#if 0 +DUMP_STRUCT("arphdr_t", ap, sizeof(arphdr_t)); +#endif + if (ntohs(ap->arp_pro) != ETHTYPE_IP) { +#if 0 + printf("ArpInput: incorrect proto addr %x\n", ap->arp_pro); +#endif + return; + } + + bcopy((char *)ap->arp_spa, (char *)&isaddr, sizeof(ipaddr_t)); + bcopy((char *)ap->arp_tpa, (char *)&itaddr, sizeof(ipaddr_t)); + if (!bcmp(ap->arp_sha, eth_myaddr, ETH_ADDRSIZE)) { +#if 0 + printf("ArpInput: incorrect sender h/w addr "); + EtherPrintAddr(ap->arp_sha); + printf("/n"); +#endif + return; + } + + at = (arptab_t *)0; + ARPTAB_LOOK(at, isaddr); + if (at) { + bcopy((char *)ap->arp_sha, (char *)at->at_eaddr, ETH_ADDRSIZE); + at->at_flags |= ATF_COM; + if (at->at_hold) { + phold = at->at_hold; + at->at_hold = (packet_t *)0; +#if 0 + printf("ArpInput: found addr, releasing packet\n"); +#endif + EtherSend(phold, ETHTYPE_IP, at->at_eaddr); + PktRelease(phold); + } + } + + /* + * Only answer ARP request which are for me + */ + if (itaddr != ip_myaddr) { +#if 0 + printf("ArpInput: it addr "); + IpPrintAddr(itaddr); + printf(" somebody else\n"); +#endif + return; + } + + if (at == 0) { /* ensure we have a table entry */ + at = ArpTnew(isaddr); + bcopy((char *)ap->arp_sha, (char *)at->at_eaddr, ETH_ADDRSIZE); + at->at_flags |= ATF_COM; + } + if (ntohs(ap->arp_op) != ARPOP_REQUEST) { + printf("ArpInput: incorrect operation: 0x%x\n", ntohs(ap->arp_op)); + return; + } + bcopy((char *)ap->arp_sha, (char *)ap->arp_tha, ETH_ADDRSIZE); + bcopy((char *)ap->arp_spa, (char *)ap->arp_tpa, sizeof(ipaddr_t)); + bcopy((char *)eth_myaddr, (char *)ap->arp_sha, ETH_ADDRSIZE); + bcopy((char *)&itaddr, (char *)ap->arp_spa, sizeof(ipaddr_t)); + ap->arp_op = htons(ARPOP_REPLY); +#if 0 +printf("ArpInput: valid request rec'd, replying\n"); +#endif + EtherSend(pkt, ETHTYPE_ARP, ap->arp_tha); +} diff --git a/sys/arch/i386/netboot/arp.h b/sys/arch/i386/netboot/arp.h new file mode 100644 index 00000000000..8144b3184b3 --- /dev/null +++ b/sys/arch/i386/netboot/arp.h @@ -0,0 +1,64 @@ +/* $NetBSD: arp.h,v 1.3 1994/10/27 04:21:03 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * Ethernet Address Resolution Protocol (see RFC 826) + */ + +/* + * ARP packets are variable in size; the arphdr_t type defines the + * 10Mb Ethernet variant. Field names used correspond to RFC 826. + */ +typedef struct { + u_short arp_hrd; /* format of hardware address */ +#define ARPHRD_ETHER 1 /* ethernet hardware address */ + u_short arp_pro; /* format of proto. address */ + u_char arp_hln; /* length of hardware address */ + u_char arp_pln; /* length of protocol address */ + u_short arp_op; +#define ARPOP_REQUEST 1 /* request to resolve address */ +#define ARPOP_REPLY 2 /* response to previous request */ +#define REVARP_REQUEST 3 /* reverse ARP request */ +#define REVARP_REPLY 4 /* reverse ARP reply */ + u_char arp_sha[ETH_ADDRSIZE]; /* sender hardware address */ + u_char arp_spa[4]; /* sender protocol address */ + u_char arp_tha[ETH_ADDRSIZE]; /* target hardware address */ + u_char arp_tpa[4]; /* target protocol address */ +} arphdr_t; + +/* + * Internet to hardware address resolution table + */ +typedef struct { + ipaddr_t at_ipaddr; /* internet address */ + u_char at_eaddr[ETH_ADDRSIZE]; /* ethernet address */ + u_long at_timer; /* time when referenced */ + u_char at_flags; /* flags */ + packet_t *at_hold; /* ast packet until resolved/timeout */ +} arptab_t; + +/* at_flags field values */ +#define ATF_INUSE 1 /* entry in use */ +#define ATF_COM 2 /* completed entry (eaddr valid) */ + +#define ARPTAB_BSIZ 3 /* bucket size */ +#define ARPTAB_NB 2 /* number of buckets */ +#define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB) + +#define ARPTAB_HASH(a) \ + ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB) + +#define ARPTAB_LOOK(at, addr) { \ + register n; \ + at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \ + for (n = 0; n < ARPTAB_BSIZ; n++, at++) \ + if (at->at_ipaddr == addr) \ + break; \ + if (n >= ARPTAB_BSIZ) \ + at = 0; } + +ipaddr_t GetIpAddress(ipaddr_t *server, ipaddr_t *my_addr, ipaddr_t *gateway, char *filename); +void ArpInput(packet_t *); +int ArpResolve(packet_t *, ipaddr_t, u_char *); diff --git a/sys/arch/i386/netboot/asm.h b/sys/arch/i386/netboot/asm.h new file mode 100644 index 00000000000..b4441cb3a01 --- /dev/null +++ b/sys/arch/i386/netboot/asm.h @@ -0,0 +1,161 @@ +/* $NetBSD: asm.h,v 1.3 1994/10/27 04:21:04 cgd Exp $ */ + +/* + * source in this file came from + * the 386BSD boot blocks written by Julian Elsicher. + * + * Ported to Boot 386BSD by Julian Elsicher (julian@tfs.com) Sept. 1992 + * + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#define S_ARG0 4(%esp) +#define S_ARG1 8(%esp) +#define S_ARG2 12(%esp) +#define S_ARG3 16(%esp) + +#define FRAME pushl %ebp; movl %esp, %ebp +#define EMARF leave + +#define B_ARG0 8(%ebp) +#define B_ARG1 12(%ebp) +#define B_ARG2 16(%ebp) +#define B_ARG3 20(%ebp) + +#ifdef wheeze + +#define ALIGN 4 +#define EXT(x) x +#define LEXT(x) x: +#define LCL(x) ./**/x + +#define LB(x,n) ./**/x +#define LBb(x,n) ./**/x +#define LBf(x,n) ./**/x + +#define SVC lcall $7,$0 + +#define String .string +#define Value .value +#define Times(a,b) [a\*b] +#define Divide(a,b) [a\\b] + +#define INB inb (%dx) +#define OUTB outb (%dx) +#define INL inl (%dx) +#define OUTL outl (%dx) + +#else wheeze +/* #define ALIGN */ +#define ALIGN 4 +#define LCL(x) x + +#define LB(x,n) n +#ifdef __STDC__ +#define EXT(x) _ ## x +#define LEXT(x) _ ## x ## : + +#define LBb(x,n) n ## b +#define LBf(x,n) n ## f +#else __STDC__ +#define EXT(x) _/**/x +#define LEXT(x) _/**/x/**/: +#define LBb(x,n) n/**/b +#define LBf(x,n) n/**/f +#endif __STDC__ +#define SVC .byte 0x9a; .long 0; .word 0x7 + +#define String .ascii +#define Value .word +#define Times(a,b) (a*b) +#define Divide(a,b) (a/b) + +#define INB inb %dx, %al +#define OUTB outb %al, %dx +#define INL inl %dx, %eax +#define OUTL outl %eax, %dx + +#endif wheeze + +#define data32 .byte 0x66 +#define data16 .byte 0x66 +#define addr16 .byte 0x67 + + + +#ifdef GPROF +#ifdef __STDC__ + +#define MCOUNT .data; LB(x, 9); .long 0; .text; lea LBb(x, 9),%edx; call mcount +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ASENTRY(x) .globl x; .align ALIGN; x ## : ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; + +#else __STDC__ + +#define MCOUNT .data; LB(x, 9): .long 0; .text; lea LBb(x, 9),%edx; call mcount +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; .align ALIGN; x: ; \ + pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp; + +#endif __STDC__ +#else GPROF +#ifdef __STDC__ + +#define MCOUNT +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; .align ALIGN; x ## : + +#else __STDC__ + +#define MCOUNT +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) +#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \ + .align ALIGN; LEXT(x) LEXT(y) +#define ASENTRY(x) .globl x; .align ALIGN; x: + +#endif __STDC__ +#endif GPROF + +#define Entry(x) .globl EXT(x); .align ALIGN; LEXT(x) +#define DATA(x) .globl EXT(x); .align ALIGN; LEXT(x) + +CR0_PE = 0x00000001 + +KERN_CODE_SEG = 0x08 +KERN_DATA_SEG = 0x10 +BOOT_16_SEG = 0x18 + +#define opsize .byte 0x66 +#define addrsize .byte 0x67 diff --git a/sys/arch/i386/netboot/asm.s b/sys/arch/i386/netboot/asm.s new file mode 100644 index 00000000000..3fe9f70940f --- /dev/null +++ b/sys/arch/i386/netboot/asm.s @@ -0,0 +1,231 @@ +/* $NetBSD: asm.s,v 1.3 1994/10/27 04:21:05 cgd Exp $ */ + +/* + * source in this file came from + * the 386BSD boot blocks written by Julian Elischer. + * + * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * + * Mach Operating System + * Copyright (c) 1992, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + by Intel Corporation, Santa Clara, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Intel +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + .file "asm.s" + +#include "asm.h" + + .text + +ENTRY(StartProg) + /* void StartProg(u_long phyaddr, u_long *args) + * start the program in protected mode. phyaddr is the entry point. + */ + +#ifndef USE_BUFFER + push %ebp + mov %esp, %ebp + + # get things we need into registers + movl 0x8(%ebp), %ecx # entry offset + movl 0x0c(%ebp), %eax # &argv + + # make a new stack at 0:0xa0000 (big segs) + mov $KERN_DATA_SEG, %ebx + movw %bx, %ss + movl $0xa0000,%ebx + movl %ebx,%esp + + + # push some number of args onto the stack + pushl $0 # nominally a cyl offset in the boot. + pushl 0x8(%eax) # argv[2] = bootdev + pushl 0x4(%eax) # argv[1] = howto + pushl $0 # dummy 'return' address + + # push on our entry address + mov $KERN_CODE_SEG, %ebx # segment + pushl %ebx + pushl %ecx + + # convert over the other data segs + mov $KERN_DATA_SEG, %ebx + movw %bx, %ds + movw %bx, %es + + # convert the PC (and code seg) + lret +#else +/* test version - relocating, kernel move (TBD) */ + /* if necessary, move ourself out of the way + * move the copy of the kernel to its correct load point + * set up a stack and transfer args to it + * call the entry point + * this is best done in assembly as the potential relocation will + * have a bad effect on non-PIC code. + */ + /* get things we need into registers */ + movl 0x8(%ebp), %ecx # entry offset + movl 0x0c(%ebp), %eax # &argv + + /* relocate ourselves to <tmp_reloc_org> */ + # PhysBcopy(RELOC, tmp_reloc_org, WORK_AREA_SIZE); + mov $RELOC, %esi + mov $tmp_reloc_org, %edi + mov $WORK_AREA_SIZE, %ecx + mov %ds, %ax + mov %ax, %es + rep + movsb + + /* TBD - could probably also do this by munging a seg descriptor. + * would it be easier? + */ + ljmp $KERN_CODE_SEG, tmp_reloc_org+$1f +1: + /* now we are PIC - caveats */ + /* move the stack pointer to the new copy */ + add tmp_reloc_org-xxx, %esp + + /* push some number of args onto the stack */ + pushl $0 # nominally a cyl offset in the boot. + pushl 0x8(%eax) # argv[2] = bootdev + pushl 0x4(%eax) # argv[1] = howto + pushl $0 # dummy 'return' address + + /* push on our entry address */ + mov $0x08, %ebx # segment + pushl %ebx + pushl %ecx + + /* copy loaded file to its destination (TBD) */ + # PhysBcopy(kcopy, korg, ksize); + mov kern_copy_org, %esi + mov boot_area_org, %edi + mov xxxksize, %ecx + mov %ds, %ax + mov %ax, %es + rep + movsb + + /* convert the PC (and code seg) */ + lret +#endif + + +/* + * 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. + */ + +ENTRY(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 + +ENTRY(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 diff --git a/sys/arch/i386/netboot/assert.h b/sys/arch/i386/netboot/assert.h new file mode 100644 index 00000000000..4d22e64f7e3 --- /dev/null +++ b/sys/arch/i386/netboot/assert.h @@ -0,0 +1,19 @@ +/* $NetBSD: assert.h,v 1.3 1994/10/27 04:21:07 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * assert.h + */ + +#ifndef NDEBUG +#define assert(exp) \ + if (!(exp)) { \ + printf("Assertion \"%s\" failed: file %s, line %d\n", \ + #exp, __FILE__, __LINE__); \ + exit(1); \ + } +#else +#define assert(exp) /* */ +#endif /* _ASSERT_H */ diff --git a/sys/arch/i386/netboot/bootp.c b/sys/arch/i386/netboot/bootp.c new file mode 100644 index 00000000000..f6420b49028 --- /dev/null +++ b/sys/arch/i386/netboot/bootp.c @@ -0,0 +1,20 @@ +/* $NetBSD: bootp.c,v 1.3 1994/10/27 04:21:08 cgd Exp $ */ + +/* + * bootp functions + */ + +int BootpGetInfo(ipaddr_t *ip_servaddr, ipaddr_t *ip_myaddr, ipaddr_t *ip_gateway, char *file_name) { + /* zero a packet */ + bzero(xxx); + /* set dest to 255... */ + xxx = IP_BCASTADDR + /* set up udp ports */ + /* send it */ + /* wait for reply or timeout */ + /* do exp backoff and retry if timeout */ + /* give up after a minute or so */ + /* return success or failure */ +} + +/* tbd - set up incoming packet handler to handle bootp replies??? */ diff --git a/sys/arch/i386/netboot/bootp.h b/sys/arch/i386/netboot/bootp.h new file mode 100644 index 00000000000..aef88513ee3 --- /dev/null +++ b/sys/arch/i386/netboot/bootp.h @@ -0,0 +1,106 @@ +/* $NetBSD: bootp.h,v 1.3 1994/10/27 04:21:09 cgd Exp $ */ + +/* + * Bootstrap Protocol (BOOTP). RFC951 and RFC1048. + * + * + * This file specifies the "implementation-independent" BOOTP protocol + * information which is common to both client and server. + * + * + * Copyright 1988 by Carnegie Mellon. + * + * Permission to use, copy, modify, and distribute this program for any + * purpose and without fee is hereby granted, provided that this copyright + * and permission notice appear on all copies and supporting documentation, + * the name of Carnegie Mellon not be used in advertising or publicity + * pertaining to distribution of the program without specific prior + * permission, and notice be given in supporting documentation that copying + * and distribution is by permission of Carnegie Mellon and Stanford + * University. Carnegie Mellon makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + + +struct bootp { + unsigned char bp_op; /* packet opcode type */ + unsigned char bp_htype; /* hardware addr type */ + unsigned char bp_hlen; /* hardware addr length */ + unsigned char bp_hops; /* gateway hops */ + unsigned long bp_xid; /* transaction ID */ + unsigned short bp_secs; /* seconds since boot began */ + unsigned short bp_unused; + ipaddr_t bp_ciaddr; /* client IP address */ + ipaddr_t bp_yiaddr; /* 'your' IP address */ + ipaddr_t bp_siaddr; /* server IP address */ + ipaddr_t bp_giaddr; /* gateway IP address */ + unsigned char bp_chaddr[16]; /* client hardware address */ + unsigned char bp_sname[64]; /* server host name */ + unsigned char bp_file[128]; /* boot file name */ + unsigned char bp_vend[64]; /* vendor-specific area */ +}; + +/* + * UDP port numbers, server and client. + */ +#define IPPORT_BOOTPS 67 +#define IPPORT_BOOTPC 68 + +#define BOOTREPLY 2 +#define BOOTREQUEST 1 + + +/* + * Vendor magic cookie (v_magic) for CMU + */ +#define VM_CMU "CMU" + +/* + * Vendor magic cookie (v_magic) for RFC1048 + */ +#define VM_RFC1048 { 99, 130, 83, 99 } + + + +/* + * RFC1048 tag values used to specify what information is being supplied in + * the vendor field of the packet. + */ + +#define TAG_PAD ((unsigned char) 0) +#define TAG_SUBNET_MASK ((unsigned char) 1) +#define TAG_TIME_OFFSET ((unsigned char) 2) +#define TAG_GATEWAY ((unsigned char) 3) +#define TAG_TIME_SERVER ((unsigned char) 4) +#define TAG_NAME_SERVER ((unsigned char) 5) +#define TAG_DOMAIN_SERVER ((unsigned char) 6) +#define TAG_LOG_SERVER ((unsigned char) 7) +#define TAG_COOKIE_SERVER ((unsigned char) 8) +#define TAG_LPR_SERVER ((unsigned char) 9) +#define TAG_IMPRESS_SERVER ((unsigned char) 10) +#define TAG_RLP_SERVER ((unsigned char) 11) +#define TAG_HOSTNAME ((unsigned char) 12) +#define TAG_BOOTSIZE ((unsigned char) 13) +#define TAG_END ((unsigned char) 255) + + + +/* + * "vendor" data permitted for CMU bootp clients. + */ + +struct cmu_vend { + unsigned char v_magic[4]; /* magic number */ + unsigned long v_flags; /* flags/opcodes, etc. */ + ipaddr_t v_smask; /* Subnet mask */ + ipaddr_t v_dgate; /* Default gateway */ + ipaddr_t v_dns1, v_dns2; /* Domain name servers */ + ipaddr_t v_ins1, v_ins2; /* IEN-116 name servers */ + ipaddr_t v_ts1, v_ts2; /* Time servers */ + unsigned char v_unused[25]; /* currently unused */ +}; + + +/* v_flags values */ +#define VF_SMASK 1 /* Subnet mask field contains valid data */ diff --git a/sys/arch/i386/netboot/cga.c b/sys/arch/i386/netboot/cga.c new file mode 100644 index 00000000000..21ca95ce5d7 --- /dev/null +++ b/sys/arch/i386/netboot/cga.c @@ -0,0 +1,220 @@ +/* $NetBSD: cga.c,v 1.3 1994/10/27 04:21:10 cgd Exp $ */ + +/* netboot + * + * source in this file came from + * the original 386BSD boot block. + * + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cga.c 5.3 (Berkeley) 4/28/91 + */ + +#include "proto.h" + +#define COL 80 +#define ROW 25 +#define CHR 2 +#define MONO_BASE 0x3B4 +#define MONO_BUF 0xB0000 +#define CGA_BASE 0x3D4 +#define CGA_BUF 0xB8000 + +static u_char att = 0x7 ; +u_char *Crtat = (u_char *)CGA_BUF; + +static unsigned int addr_6845 = CGA_BASE; + +static void cursor(int pos) { + outb(addr_6845, 14); + outb(addr_6845+1, pos >> 8); + outb(addr_6845, 15); + outb(addr_6845+1, pos&0xff); +} + +void +putc(int c) { +#ifdef USE_BIOS + asm(" + movb %0, %%cl + call _prot_to_real + .byte 0x66 + mov $0x1, %%ebx + movb $0xe, %%ah + movb %%cl, %%al + sti + int $0x10 + cli + .byte 0x66 + call _real_to_prot + " : : "g" (ch)); +#else + static u_char *crtat = 0; + unsigned cursorat; u_short was; + u_char *cp; + + if (crtat == 0) { + + /* XXX probe to find if a color or monochrome display */ + was = *(u_short *)Crtat; + *(u_short *)Crtat = 0xA55A; + if (*(u_short *)Crtat != 0xA55A) { + Crtat = (u_char *) MONO_BUF; + addr_6845 = MONO_BASE; + } + *(u_short *)Crtat = was; + + /* Extract cursor location */ + outb(addr_6845,14); + cursorat = inb(addr_6845+1)<<8 ; + outb(addr_6845,15); + cursorat |= inb(addr_6845+1); + + if(cursorat <= COL*ROW) { + crtat = Crtat + cursorat*CHR; + /* att = crtat[1]; */ /* use current attribute present */ + } else crtat = Crtat; + + /* clean display */ + for (cp = crtat; cp < Crtat+ROW*COL*CHR; cp += 2) { + cp[0] = ' '; + cp[1] = att; + } + } + + switch (c) { + + case '\t': + do + putc(' '); + while ((int)crtat % (8*CHR)); + break; + + case '\010': + crtat -= CHR; + break; + + case '\r': + crtat -= (crtat - Crtat) % (COL*CHR); + break; + + case '\n': + crtat += COL*CHR ; + break; + + default: + crtat[0] = c; + crtat[1] = att; + crtat += CHR; + break ; + } + + /* implement a scroll */ + if (crtat >= Crtat+COL*ROW*CHR) { + /* move text up */ + bcopy((char *)(Crtat+COL*CHR), (char *)Crtat, COL*(ROW-1)*CHR); + + /* clear line */ + for (cp = Crtat+ COL*(ROW-1)*CHR; + cp < Crtat + COL*ROW*CHR ; cp += 2) + cp[0] = ' '; + + crtat -= COL*CHR ; + } + cursor((crtat-Crtat)/CHR); +#endif +} + +void +putchar(int c) +{ + if (c == '\n') + putc('\r'); + putc(c); +} + +/* printf - only handles %d as decimal, %c as char, %s as string */ + +void +printf(format,data) + const char *format; + int data; +{ + int *dataptr = &data; + char c; + while ((c = *format++)) { + if (c != '%') + putchar(c); + else { + switch (c = *format++) { + case 'd': { + int num = *dataptr++; + char buf[10], *ptr = buf; + if (num<0) { + num = -num; + putchar('-'); + } + do + *ptr++ = '0'+num%10; + while ((num /= 10)); + do + putchar(*--ptr); + while (ptr != buf); + break; + } + case 'x': { + int num = *dataptr++, dig; + char buf[8], *ptr = buf; + do + *ptr++ = (dig=(num&0xf)) > 9? + 'a' + dig - 10 : + '0' + dig; + while ((num >>= 4)); + do + putchar(*--ptr); + while (ptr != buf); + break; + } + case 'c': putchar((*dataptr++)&0xff); break; + case 's': { + char *ptr = (char *)*dataptr++; + while ((c = *ptr++)) + putchar(c); + break; + } + } + } + } +} diff --git a/sys/arch/i386/netboot/config.h b/sys/arch/i386/netboot/config.h new file mode 100644 index 00000000000..38586743818 --- /dev/null +++ b/sys/arch/i386/netboot/config.h @@ -0,0 +1,23 @@ +/* $NetBSD: config.h,v 1.3 1994/10/27 04:21:10 cgd Exp $ */ + +/* netboot + * + * source in this file came from + */ + +#if !defined(__config_h_) +#define __config_h_ + +/* + configuration items shared between .c and .s files + */ + +#define WORK_AREA_SIZE 0x10000L + +#define T(x) printf(" " #x ":\n") + +/* turn a near address into an integer + representing a linear physical addr */ +#define LA(x) ((u_long)(x)) + +#endif diff --git a/sys/arch/i386/netboot/dp8390.h b/sys/arch/i386/netboot/dp8390.h new file mode 100644 index 00000000000..2436d729bc7 --- /dev/null +++ b/sys/arch/i386/netboot/dp8390.h @@ -0,0 +1,166 @@ +/* $NetBSD: dp8390.h,v 1.3 1994/10/27 04:21:11 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * National Semiconductor DP8390 Network Interface Controller + */ + +/* page 0: for reading */ +#define DP_CR 0x00 /* read side of command register */ +#define DP_CLDA0 0x01 /* current local DMA address 0 */ +#define DP_CLDA1 0x02 /* current local DMA address 1 */ +#define DP_BNRY 0x03 /* boundary pointer */ +#define DP_TSR 0x04 /* transmit status register */ +#define DP_NCR 0x05 /* number of collisions register */ +#define DP_FIFO 0x06 /* FIFO */ +#define DP_ISR 0x07 /* interrupt status register */ +#define DP_CRDA0 0x08 /* current remote DMA address 0 */ +#define DP_CRDA1 0x09 /* current remote DMA address 1 */ +#define DP_RSR 0x0C /* receive status register */ +#define DP_CNTR0 0x0D /* tally counter 0 */ +#define DP_CNTR1 0x0E /* tally counter 1 */ +#define DP_CNTR2 0x0F /* tally counter 2 */ + +/* page 0: for writing */ +#define DP_CR 0x00 /* write side of command register */ +#define DP_PSTART 0x01 /* page start register */ +#define DP_PSTOP 0x02 /* page stop register */ +#define DP_BNRY 0x03 /* boundary pointer */ +#define DP_TPSR 0x04 /* transmit page start register */ +#define DP_TBCR0 0x05 /* transmit byte count register 0 */ +#define DP_TBCR1 0x06 /* transmit byte count register 1 */ +#define DP_ISR 0x07 /* interrupt status register */ +#define DP_RSAR0 0x08 /* remote start address register 0 */ +#define DP_RSAR1 0x09 /* remote start address register 1 */ +#define DP_RBCR0 0x0A /* remote byte count register 0 */ +#define DP_RBCR1 0x0B /* remote byte count register 1 */ +#define DP_RCR 0x0C /* receive configuration register */ +#define DP_TCR 0x0D /* transmit configuration register */ +#define DP_DCR 0x0E /* data configuration register */ +#define DP_IMR 0x0F /* interrupt mask register */ + +/* page 1: read/write */ +#define DP_CR 0x00 /* command register */ +#define DP_PAR0 0x01 /* physical address register 0 */ +#define DP_PAR1 0x02 /* physical address register 1 */ +#define DP_PAR2 0x03 /* physical address register 2 */ +#define DP_PAR3 0x04 /* physical address register 3 */ +#define DP_PAR4 0x05 /* physical address register 4 */ +#define DP_PAR5 0x06 /* physical address register 5 */ +#define DP_CURR 0x07 /* current page register */ +#define DP_MAR0 0x08 /* multicast address register 0 */ +#define DP_MAR1 0x09 /* multicast address register 1 */ +#define DP_MAR2 0x0A /* multicast address register 2 */ +#define DP_MAR3 0x0B /* multicast address register 3 */ +#define DP_MAR4 0x0C /* multicast address register 4 */ +#define DP_MAR5 0x0D /* multicast address register 5 */ +#define DP_MAR6 0x0E /* multicast address register 6 */ +#define DP_MAR7 0x0F /* multicast address register 7 */ + +/* bits in command register */ +#define CR_STP 0x01 /* stop: software reset */ +#define CR_STA 0x02 /* start: activate NIC */ +#define CR_TXP 0x04 /* transmit packet */ +#define CR_DMA 0x38 /* mask for DMA control */ +# define CR_DM_NOP 0x00 /* DMA: no operation */ +# define CR_DM_RR 0x08 /* DMA: remote read */ +# define CR_DM_RW 0x10 /* DMA: remote write */ +# define CR_DM_SP 0x18 /* DMA: send packet */ +# define CR_DM_ABORT 0x20 /* DMA: abort remote DMA operation */ +#define CR_PS 0xC0 /* mask for page select */ +# define CR_PS_P0 0x00 /* register page 0 */ +# define CR_PS_P1 0x40 /* register page 1 */ +# define CR_PS_T0 0x80 /* test mode register map */ +# define CR_SP_T1 0xC0 /* test mode register map */ + +/* bits in interrupt status register */ +#define ISR_PRX 0x01 /* packet received with no errors */ +#define ISR_PTX 0x02 /* packet transmitted with no errors */ +#define ISR_RXE 0x04 /* receive error */ +#define ISR_TXE 0x08 /* transmit error */ +#define ISR_OVW 0x10 /* overwrite warning */ +#define ISR_CNT 0x20 /* counter overflow */ +#define ISR_RDC 0x40 /* remote DMA complete */ +#define ISR_RST 0x80 /* reset status */ + +/* bits in interrupt mask register */ +#define IMR_PRXE 0x01 /* packet received ienable */ +#define IMR_PTXE 0x02 /* packet transmitted ienable */ +#define IMR_RXEE 0x04 /* receive error ienable */ +#define IMR_TXEE 0x08 /* transmit error ienable */ +#define IMR_OVWE 0x10 /* overwrite warning ienable */ +#define IMR_CNTE 0x20 /* counter overflow ienable */ +#define IMR_RDCE 0x40 /* DMA complete ienable */ + +/* bits in data control register */ +#define DCR_WTS 0x01 /* word transfer select */ +# define DCR_BYTEWIDE 0x00 /* WTS: byte wide transfers */ +# define DCR_WORDWIDE 0x01 /* WTS: word wide transfers */ +#define DCR_BOS 0x02 /* byte order select */ +# define DCR_LTLENDIAN 0x00 /* BOS: little endian */ +# define DCR_BIGENDIAN 0x02 /* BOS: big endian */ +#define DCR_LAS 0x04 /* long address select */ +#define DCR_BMS 0x08 /* burst mode select */ +#define DCR_AR 0x10 /* autoinitialize remote */ +#define DCR_FTS 0x60 /* FIFO threshold select */ +# define DCR_2BYTES 0x00 /* 2 bytes */ +# define DCR_4BYTES 0x40 /* 4 bytes */ +# define DCR_8BYTES 0x20 /* 8 bytes */ +# define DCR_12BYTES 0x60 /* 12 bytes */ + +/* bits in transmit configuration register */ +#define TCR_CRC 0x01 /* inhibit CRC */ +#define TCR_ELC 0x06 /* encoded loopback control */ +# define TCR_NORMAL 0x00 /* ELC: normal operation */ +# define TCR_INTERNAL 0x02 /* ELC: internal loopback */ +# define TCR_0EXTERNAL 0x04 /* ELC: external loopback LPBK=0 */ +# define TCR_1EXTERNAL 0x06 /* ELC: external loopback LPBK=1 */ +#define TCR_ATD 0x08 /* auto transmit */ +#define TCR_OFST 0x10 /* collision offset enable (be nice) */ + +/* bits in transmit status register */ +#define TSR_PTX 0x01 /* packet transmitted (without error)*/ +#define TSR_DFR 0x02 /* transmit deferred */ +#define TSR_COL 0x04 /* transmit collided */ +#define TSR_ABT 0x08 /* transmit aborted */ +#define TSR_CRS 0x10 /* carrier sense lost */ +#define TSR_FU 0x20 /* fifo underrun */ +#define TSR_CDH 0x40 /* CD heartbeat */ +#define TSR_OWC 0x80 /* out of window collision */ + +/* bits in receive configuration register */ +#define RCR_SEP 0x01 /* save errored packets */ +#define RCR_AR 0x02 /* accept runt packets */ +#define RCR_AB 0x04 /* accept broadcast */ +#define RCR_AM 0x08 /* accept multicast */ +#define RCR_PRO 0x10 /* physical promiscuous */ +#define RCR_MON 0x20 /* monitor mode */ + +/* bits in receive status register */ +#define RSR_PRX 0x01 /* packet received intact */ +#define RSR_CRC 0x02 /* CRC error */ +#define RSR_FAE 0x04 /* frame alignment error */ +#define RSR_FO 0x08 /* FIFO overrun */ +#define RSR_MPA 0x10 /* missed packet */ +#define RSR_PHY 0x20 /* multicast address match !! */ +#define RSR_DIS 0x40 /* receiver disabled */ + +/* dp8390 configuration information */ +typedef struct { + u_short dc_reg; /* dp8390 base address */ + u_long dc_mem; /* base memory */ + u_char dc_tpsr; /* transmit start page */ + u_char dc_pstart; /* receive start page */ + u_char dc_pstop; /* receive end page */ +} dpconf_t; + + +/* dp8390 receive header */ +typedef struct { + u_char dh_status; /* copy of rsr */ + u_char dh_next; /* pointer to next packet */ + u_char dh_rbcl; /* receive byte count low */ + u_char dh_rbch; /* receive byte count high */ +} dphdr_t; diff --git a/sys/arch/i386/netboot/ether.h b/sys/arch/i386/netboot/ether.h new file mode 100644 index 00000000000..fc215ff69f6 --- /dev/null +++ b/sys/arch/i386/netboot/ether.h @@ -0,0 +1,77 @@ +/* $NetBSD: ether.h,v 1.3 1994/10/27 04:21:12 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * Ethernet definitions + */ + +#define ETH_ADDRSIZE 6 /* address size */ + +/* + * Structure of an ethernet header + */ +typedef struct { + u_char eth_dst[ETH_ADDRSIZE]; /* destination address */ + u_char eth_src[ETH_ADDRSIZE]; /* source address */ + u_short eth_proto; /* protocol type */ +} ethhdr_t; + +/* protocol types */ +#define ETHTYPE_IP 0x0800 /* IP protocol */ +#define ETHTYPE_ARP 0x0806 /* ARP protocol */ +#define ETHTYPE_RARP 0x8035 /* Reverse ARP protocol */ + +extern u_char eth_myaddr[]; + +int EtherInit(void); +void EtherReset(void); +void EtherStop(void); +void EtherSend(packet_t *pkt, u_short proto, u_char *dest); +packet_t *EtherReceive(void); +void EtherPrintAddr(u_char *addr); + +/* TBD - move these elsewhere? */ + +static inline u_short +htons(u_short x) { + return ((x >> 8) & 0xff) + | ((x & 0xff) << 8); +} + +#if 0 +static inline u_short +ntohs(u_short x) { + return x >> 8 & 0xff + | (x & 0xff) << 8; +} +#else +static inline u_short +ntohs(u_short x) { + return htons(x); +} +#endif + +static inline u_long +htonl(u_long x) { + return (x >> 24 & 0xffL) + | (x >> 8 & 0xff00L) + | (x << 8 & 0xff0000L) + | (x << 24 & 0xff000000L); +} + +#if 0 +static inline u_long +ntohl(u_long x) { + return x >> 24 & 0xffL + | x >> 8 & 0xff00L + | x << 8 & 0xff0000L + | x << 24 & 0xff000000L; +} +#else +static inline u_long +ntohl(u_long x) { + return htonl(x); +} +#endif diff --git a/sys/arch/i386/netboot/genprom.c b/sys/arch/i386/netboot/genprom.c new file mode 100644 index 00000000000..ea8d56bfa0c --- /dev/null +++ b/sys/arch/i386/netboot/genprom.c @@ -0,0 +1,33 @@ +/* $NetBSD: genprom.c,v 1.3 1994/10/27 04:21:13 cgd Exp $ */ + +/* + * Read a binary image of a bios extension, generate the + * appropriate block count and checksum and write them + * into the rom image (replacing 2nd and 5th bytes) + * The binary image should be sized before being filtered + * through this routine. + */ + +#include <stdio.h> + +#define USE_SIZE ROM_SIZE +#define PROM_SIZE 0x10000 + +main() { + char w[PROM_SIZE], ck; + int i, sum; + memset(w, 0xff, PROM_SIZE); + i = fread(w, 1, PROM_SIZE, stdin); + fprintf(stderr, "bios extension size: %d (0x%x), read %d bytes\n", + USE_SIZE, USE_SIZE, i); + w[2] = USE_SIZE / 512; + for (sum=0, i=0; i<USE_SIZE; i++) { + sum += w[i]; + } + w[5] = -sum; + for (ck=0, i=0; i<USE_SIZE; i++) { + ck += w[i]; + } + fwrite(w, 1, PROM_SIZE, stdout); +} + diff --git a/sys/arch/i386/netboot/inet.h b/sys/arch/i386/netboot/inet.h new file mode 100644 index 00000000000..5d29ccf7ef5 --- /dev/null +++ b/sys/arch/i386/netboot/inet.h @@ -0,0 +1,59 @@ +/* $NetBSD: inet.h,v 1.3 1994/10/27 04:21:14 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * Various UDP/IP definitions (see RFC 768, and 791) + */ + +/* generic IP address */ +#define IP_ANYADDR (ipaddr_t)0 /* IP any address */ +#define IP_BCASTADDR (ipaddr_t)0xffffffff /* IP broadcast address */ + +/* some well defined protocols/ports */ +#define IP_PROTO_UDP 17 /* user datagram protocol */ +#define IP_PORT_TFTP 69 /* trivial FTP port */ + +/* internet address type */ +typedef u_long ipaddr_t; + +/* internet address type (only used for printing address) */ +typedef union { + ipaddr_t a; + struct { u_char a0, a1, a2, a3; } s; +} inetaddr_t; + +/* + * Structure of an internet header (without options) + */ +typedef struct { + u_char ip_vhl; /* version and header length */ +#define IP_VERSION 4 /* current version number */ + u_char ip_tos; /* type of service */ + u_short ip_len; /* total length */ + u_short ip_id; /* identification */ + u_short ip_off; /* fragment offset field */ + u_char ip_ttl; /* time to live */ +#define IP_FRAGTTL 60 /* time to live for frags */ + u_char ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + ipaddr_t ip_src; /* source address */ + ipaddr_t ip_dst; /* destination address */ +} iphdr_t; + +/* + * Structure of an UDP header + */ +typedef struct { + u_short uh_sport; /* source port */ + u_short uh_dport; /* destination port */ + u_short uh_len; /* udp length */ + u_short uh_sum; /* udp checksum */ +} udphdr_t; + +/* these are actually defined in arp.c */ +extern ipaddr_t ip_myaddr; /* my own IP address */ +extern ipaddr_t ip_gateway; /* gateway's IP address */ + +void IpPrintAddr(ipaddr_t); diff --git a/sys/arch/i386/netboot/kbd.c b/sys/arch/i386/netboot/kbd.c new file mode 100644 index 00000000000..6b6f33e1662 --- /dev/null +++ b/sys/arch/i386/netboot/kbd.c @@ -0,0 +1,363 @@ +/* $NetBSD: kbd.c,v 1.3 1994/10/27 04:21:15 cgd Exp $ */ + +/* netboot + * + * source in this file came from + * the original 386BSD boot blocks. + * + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kbd.c 7.4 (Berkeley) 5/4/91 + */ + +#include "proto.h" + +#define KBSTATP 0x64 /* kbd status port */ +#define KBS_INP_BUF_FUL 0x02 /* kbd char ready */ +#define KBDATAP 0x60 /* kbd data port */ + +#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 */ + +#define L 0x01 /* locking function */ +#define SHF 0x02 /* keyboard shift */ +#define ALT 0x04 /* alternate shift -- alternate chars */ +#define NUM 0x08 /* numeric shift cursors vs. numeric */ +#define CTL 0x10 /* control shift -- allows ctl function */ +#define CPS 0x20 /* caps shift -- swaps case of letter */ +#define ASCII 0x40 /* ascii code for this key */ +#define STP 0x80 /* stop output */ + +static u_char action[128] = { +0, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 0- 7 */ +ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 8-15 */ +ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 16-23 */ +ASCII, ASCII, ASCII, ASCII, ASCII, CTL, ASCII, ASCII, /* scan 24-31 */ +ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 32-39 */ +ASCII, ASCII, SHF , ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 40-47 */ +ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, SHF, ASCII, /* scan 48-55 */ + ALT, ASCII, CPS|L, 0, 0, ASCII, 0, 0, /* scan 56-63 */ + 0, 0, 0, 0, 0, NUM|L, STP|L, ASCII, /* scan 64-71 */ +ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 72-79 */ +ASCII, ASCII, ASCII, ASCII, 0, 0, 0, 0, /* scan 80-87 */ +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ; + +static u_char unshift[128] = { /* no shift */ +0, 033 , '1' , '2' , '3' , '4' , '5' , '6' , /* scan 0- 7 */ +'7' , '8' , '9' , '0' , '-' , '=' , 0177 ,'\t' , /* scan 8-15 */ + +'q' , 'w' , 'e' , 'r' , 't' , 'y' , 'u' , 'i' , /* scan 16-23 */ +'o' , 'p' , '[' , ']' , '\r' , CTL , 'a' , 's' , /* scan 24-31 */ + +'d' , 'f' , 'g' , 'h' , 'j' , 'k' , 'l' , ';' , /* scan 32-39 */ +'\'' , '`' , SHF , '\\' , 'z' , 'x' , 'c' , 'v' , /* scan 40-47 */ + +'b' , 'n' , 'm' , ',' , '.' , '/' , SHF , '*', /* scan 48-55 */ +ALT , ' ' , CPS|L, 0, 0, ' ' , 0, 0, /* scan 56-63 */ + + 0, 0, 0, 0, 0, NUM|L, STP|L, '7', /* scan 64-71 */ + '8', '9', '-', '4', '5', '6', '+', '1', /* scan 72-79 */ + + '2', '3', '0', '.', 0, 0, 0, 0, /* scan 80-87 */ +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ; + +static u_char shift[128] = { /* shift shift */ +0, 033 , '!' , '@' , '#' , '$' , '%' , '^' , /* scan 0- 7 */ +'&' , '*' , '(' , ')' , '_' , '+' , 0177 ,'\t' , /* scan 8-15 */ +'Q' , 'W' , 'E' , 'R' , 'T' , 'Y' , 'U' , 'I' , /* scan 16-23 */ +'O' , 'P' , '[' , ']' , '\r' , CTL , 'A' , 'S' , /* scan 24-31 */ +'D' , 'F' , 'G' , 'H' , 'J' , 'K' , 'L' , ':' , /* scan 32-39 */ +'"' , '~' , SHF , '|' , 'Z' , 'X' , 'C' , 'V' , /* scan 40-47 */ +'B' , 'N' , 'M' , '<' , '>' , '?' , SHF , '*', /* scan 48-55 */ +ALT , ' ' , CPS|L, 0, 0, ' ' , 0, 0, /* scan 56-63 */ + 0, 0, 0, 0, 0, NUM|L, STP|L, '7', /* scan 64-71 */ + '8', '9', '-', '4', '5', '6', '+', '1', /* scan 72-79 */ + '2', '3', '0', '.', 0, 0, 0, 0, /* scan 80-87 */ +0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ; + +static u_char ctl[128] = { /* CTL shift */ +0, 033 , '!' , 000 , '#' , '$' , '%' , 036 , /* scan 0- 7 */ +'&' , '*' , '(' , ')' , 037 , '+' , 034 ,'\177', /* scan 8-15 */ +021 , 027 , 005 , 022 , 024 , 031 , 025 , 011 , /* scan 16-23 */ +017 , 020 , 033 , 035 , '\r' , CTL , 001 , 013 , /* scan 24-31 */ +004 , 006 , 007 , 010 , 012 , 013 , 014 , ';' , /* scan 32-39 */ +'\'' , '`' , SHF , 034 , 032 , 030 , 003 , 026 , /* scan 40-47 */ +002 , 016 , 015 , '<' , '>' , '?' , SHF , '*', /* scan 48-55 */ +ALT , ' ' , CPS|L, 0, 0, ' ' , 0, 0, /* scan 56-63 */ +CPS|L, 0, 0, 0, 0, 0, 0, 0, /* scan 64-71 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* scan 72-79 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* scan 80-87 */ + 0, 0, 033, '7' , '4' , '1' , 0, NUM|L, /* scan 88-95 */ +'8' , '5' , '2' , 0, STP|L, '9' , '6' , '3' , /*scan 96-103*/ +'.' , 0, '*' , '-' , '+' , 0, 0, 0, /*scan 104-111*/ +0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ; + +static u_char shfts, ctls, alts, caps, num, stp; +static u_char chr; +static int is_chr_queued = 0; + +static int +ProcessKbdEvent(void) { + /* Returns 1 if event result is an ascii char, 0 otherwise (or no event). + * As a side effect, it digests keyboard events and queues bona fide + * characters for subsequent reading. + */ + u_char dt, brk, act; + if ((inb(KBSTATP) & 0x01) == 0) + return is_chr_queued; + dt = inb(KBDATAP); + brk = dt & 0x80; + dt = dt & 0x7f; + + act = action[dt]; + if (act & SHF) { + if (brk) + shfts = 0; + else + shfts = 1; + } + if (act & ALT) { + if (brk) + alts = 0; + else + alts = 1; + } + if (act & NUM) { + if (act & L) { + if (!brk) + num ^= 1; + } else + if(brk) + num = 0; + else + num = 1; + } + if (act & CTL) { + if (brk) + ctls = 0; + else + ctls = 1; + } + if (act & CPS) { + if (act & L) { + if (!brk) + caps ^= 1; + } else + if (brk) + caps = 0; + else + caps = 1; + } + if (act & STP) { + if (act & L) { + if (!brk) + stp ^= 1; + } else + if (brk) + stp = 0; + else + stp = 1; + } + if (ctls && alts && dt == 83) + exit(1); + if ((act & ASCII) && !brk) { + if (shfts) { + chr = shift[dt]; + } else { + if (ctls) { + chr = ctl[dt]; + } else { + chr = unshift[dt]; + } + } + if (caps && (chr >= 'a' && chr <= 'z')) { + chr -= 'a' - 'A' ; + } + is_chr_queued = 1; + } + return is_chr_queued; +} + +int +IsKbdCharReady(void) { +#ifdef USE_BIOS + int result; + asm(" + push %%ebx + call _prot_to_real + mov $1, %%ax + int $0x16 + setz %%bl + .byte 0x66 + call _real_to_prot + movsbl %%bl, %0 + pop %%ebx + " : "=g" (result)); + return result; +#else + return ProcessKbdEvent(); +#endif +} + +static int +scankbd(void) { + +#ifdef notdef + u_char c; + c = inb(KBDATAP); + if (c == 83) exit(); + /*if (c == 0xaa) return (0); + if (c == 0xfa) return (0);*/ + + if (bdt == 0) { bdt = c&0x7f; return(0); } + + if(odt) return(1); + + c &= 0x7f; + + if (bdt == c) return(0); + odt = c; +#endif + return 1; +} + +static void +kbdreset(void) { + u_char c; + + /* Enable interrupts and keyboard controller */ + while (inb(KBSTATP)&2); outb(KBSTATP,0x60); + while (inb(KBSTATP)&2); outb(KBDATAP,0x4D); + + /* Start keyboard stuff RESET */ + while (inb(KBSTATP)&2); /* wait input ready */ + outb(KBDATAP,0xFF); /* RESET */ + + while((c=inb(KBDATAP))!=0xFA) ; + + /* While we are here, defeat gatea20 */ + while (inb(KBSTATP)&2); /* wait input ready */ + outb(KBSTATP,0xd1); + while (inb(KBSTATP)&2); /* wait input ready */ + outb(KBDATAP,0xdf); + while (inb(KBSTATP)&2); /* wait input ready */ + inb(KBDATAP); +} + +/* TBD - what does this do?, used by ResetCpu() */ +void +KbdWait(int n) { + int v; + + v = 0; + while(n-- && (v = scankbd()) == 0); + if (v) kbdreset(); +} + +/* + * Gate A20 for high memory + */ +u_char x_20 = KB_A20; + +void +gateA20(void) { + 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); +} + +int +getc(void) { +#ifdef USE_BIOS + int rslt; + asm(" + push %%ebx + call _prot_to_real + movb $0x0, %%ah + sti + int $0x16 + cli + movb %%al, %%bl + .byte 0x66 + call _real_to_prot + xor %%eax, %%eax + movb %%bl, %0 + pop %%ebx + " : "=g" (rslt)); + return rslt; +#else + while (!is_chr_queued) { + ProcessKbdEvent(); + } + is_chr_queued = 0; + return chr; +#endif +} + +int +getchar(void) { + int c; + + if ((c=getc()) == '\r') + c = '\n'; + if (c == '\b') { + putchar('\b'); + putchar(' '); + } + putchar(c); + return c; +} diff --git a/sys/arch/i386/netboot/lance.h b/sys/arch/i386/netboot/lance.h new file mode 100644 index 00000000000..4cf39f74102 --- /dev/null +++ b/sys/arch/i386/netboot/lance.h @@ -0,0 +1,114 @@ +/* $NetBSD: lance.h,v 1.3 1994/10/27 04:21:16 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + */ + +/* RAP functions as a select for RDP */ +#define RDP_CSR0 0 +#define RDP_CSR1 1 +#define RDP_CSR2 2 +#define RDP_CSR3 3 + +/* contents of csr0 */ +#define CSR_ERR 0x8000 +#define CSR_BABL 0x4000 +#define CSR_CERR 0x2000 +#define CSR_MISS 0x1000 +#define CSR_MERR 0x0800 +#define CSR_RINT 0x0400 +#define CSR_TINT 0x0200 +#define CSR_IDON 0x0100 +#define CSR_INTR 0x0080 +#define CSR_INEA 0x0040 +#define CSR_RXON 0x0020 +#define CSR_TXON 0x0010 +#define CSR_TDMD 0x0008 +#define CSR_STOP 0x0004 +#define CSR_STRT 0x0002 +#define CSR_INIT 0x0001 + +/* csr1 contains low 16 bits of address of Initialization Block */ + +/* csr2 contains in low byte high 8 bits of address of InitBlock */ + +/* contents of csr3 */ +#define CSR3_BSWP 0x04 /* byte swap (for big endian) */ +#define CSR3_ACON 0x02 /* ALE control */ +#define CSR3_BCON 0x01 /* byte control */ + +/* + * The initialization block + */ +typedef struct { + u_short ib_mode; /* modebits, see below */ + char ib_padr[6]; /* physical 48bit Ether-address */ + u_short ib_ladrf[4]; /* 64bit hashtable for "logical" addresses */ + u_short ib_rdralow; /* low 16 bits of Receiver Descr. Ring addr */ + u_char ib_rdrahigh; /* high 8 bits of Receiver Descr. Ring addr */ + u_char ib_rlen; /* upper 3 bits are 2log Rec. Ring Length */ + u_short ib_tdralow; /* low 16 bits of Transm. Descr. Ring addr */ + u_char ib_tdrahigh; /* high 8 bits of Transm. Descr. Ring addr */ + u_char ib_tlen; /* upper 3 bits are 2log Transm. Ring Length */ +} initblock_t; + +/* bits in mode */ +#define IB_PROM 0x8000 +#define IB_INTL 0x0040 +#define IB_DRTY 0x0020 +#define IB_COLL 0x0010 +#define IB_DTCR 0x0008 +#define IB_LOOP 0x0004 +#define IB_DTX 0x0002 +#define IB_DRX 0x0001 + +/* + * A receive message descriptor entry + */ +typedef struct { + u_short rmd_ladr; /* low 16 bits of bufaddr */ + char rmd_hadr; /* high 8 bits of bufaddr */ + char rmd_flags; /* see below */ + short rmd_bcnt; /* two's complement of buffer byte count */ + u_short rmd_mcnt; /* message byte count */ +} rmde_t; + +/* bits in flags */ +#define RMD_OWN 0x80 +#define RMD_ERR 0x40 +#define RMD_FRAM 0x20 +#define RMD_OFLO 0x10 +#define RMD_CRC 0x08 +#define RMD_BUFF 0x04 +#define RMD_STP 0x02 +#define RMD_ENP 0x01 + +/* + * A transmit message descriptor entry + */ +typedef struct { + u_short tmd_ladr; /* low 16 bits of bufaddr */ + u_char tmd_hadr; /* high 8 bits of bufaddr */ + u_char tmd_flags; /* see below */ + short tmd_bcnt; /* two's complement of buffer byte count */ + u_short tmd_err; /* more error bits + TDR */ +} tmde_t; + +/* bits in flags */ +#define TMD_OWN 0x80 +#define TMD_ERR 0x40 +#define TMD_MORE 0x10 +#define TMD_ONE 0x08 +#define TMD_DEF 0x04 +#define TMD_STP 0x02 +#define TMD_ENP 0x01 + +/* bits in tmd_err */ +#define TMDE_BUFF 0x8000 +#define TMDE_UFLO 0x4000 +#define TMDE_LCOL 0x1000 +#define TMDE_LCAR 0x0800 +#define TMDE_RTRY 0x0400 +#define TMDE_TDR 0x003F /* mask for TDR */ + diff --git a/sys/arch/i386/netboot/main.c b/sys/arch/i386/netboot/main.c new file mode 100644 index 00000000000..c62ca8a9516 --- /dev/null +++ b/sys/arch/i386/netboot/main.c @@ -0,0 +1,639 @@ +/* $NetBSD: main.c,v 1.5 1994/10/27 04:21:17 cgd Exp $ */ + +/* + * source code in this file is from: + * 386BSD boot blocks by Julian Elischer (julian@tfs.com) + * 386BSD Adaptec 1542 SCSI boot blocks by Pace Willisson (pace@blitz.com) + * + * Mach Operating System + * Copyright (c) 1992, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + by Intel Corporation, Santa Clara, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Intel +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + + +#include "config.h" +#include "nbtypes.h" +#include "assert.h" +#include "param.h" +#include "packet.h" +#include "ether.h" +#include "inet.h" +#include "arp.h" +#include "tftp.h" + +#include "proto.h" + + +u_long work_area_org = RELOC; +u_long kernel_size; +u_short real_cs; +u_long howto = 0; +u_char vendor_area[64]; + +enum LoadErr { + load_success, + load_no_answer, + load_bad_format, + load_bad_size, +}; + +static inline enum LoadErr +LoadProgFromServer(ipaddr_t server, ipaddr_t gateway, char *file_name) { + /* TBD - fail (or at least warn) if we don't get the entire file */ + u_long start_addr; + u_long boot_area_org; + u_long tmp_reloc_org; + u_long kern_copy_org; + u_long kern_copy_p; + struct exec head; + u_long boot_argv[4]; +#if 1 /* ndef USE_BUFFER */ + u_char tmpbuf[4096]; /* we need to load the first 4k here */ +#endif + + SetTftpParms(server, gateway, file_name); + + /* TBD - heuristics about what we are loading - load linux, ... also */ + + if (Read(&head, sizeof(head)) != sizeof(head)) + return load_bad_size; + + if (N_GETMAGIC(head) != ZMAGIC) { + printf("Invalid format!\n"); + return load_bad_format; + } + + /* Load/tftp the executable to a temporary area beyond 640k - after + successful load, copy to correct area. If load fails or is interrrupted, + we can recover gracefully + */ + + start_addr = (u_long)head.a_entry; + boot_area_org = start_addr & 0x00f00000; /* some MEG boundary */ + tmp_reloc_org = 0x00100000; +#ifdef USE_BUFFER + kern_copy_org = tmp_reloc_org + WORK_AREA_SIZE; /* leave free for relocation */ +#else + kern_copy_org = boot_area_org; /* leave free for relocation */ +#endif + kern_copy_p = kern_copy_org; + kernel_size = head.a_text + head.a_data + head.a_bss; + + printf("Loading "); + IpPrintAddr(server); + printf(":%s @ 0x%x\n", file_name, boot_area_org); +#ifndef USE_BUFFER + if(boot_area_org < work_area_org) { + if((boot_area_org + head.a_text + head.a_data) > work_area_org) { + printf("kernel will not fit below loader\n"); + return load_bad_size; + } + if((boot_area_org + head.a_text + head.a_data + head.a_bss) > 0xa0000) { + printf("kernel too big, won't fit in 640K with bss\n"); + printf("Only hope is to link the kernel for > 1MB\n"); + return load_bad_size; + } + if(boot_area_org + kernel_size > work_area_org) { + printf("loader overlaps bss, kernel must bzero\n"); + } + } +#else + if(boot_area_org + kernel_size > 0xa0000) { + printf("kernel too big, won't fit in 640K with bss\n"); + printf("Only hope is to link the kernel for > 1MB\n"); + return load_bad_size; + } + /* check if too large for tmp buffer (TBD) */ +#endif + printf("text=0x%x", head.a_text); + +#if 01 + /* skip to first 4k boundry */ + Read(tmpbuf, 4096-sizeof(head)); +#endif + +#if 0 /* ndef USE_BUFFER */ + /********************************************************/ + /* LOAD THE TEXT SEGMENT */ + /* don't clobber the first 4k yet (BIOS NEEDS IT) */ + /********************************************************/ + Read(tmpbuf, sizeof(tmpbuf)); + kern_copy_p += sizeof(tmpbuf); + PhysRead(kern_copy_p, head.a_text - sizeof(tmpbuf)); + kern_copy_p += head.a_text - sizeof(tmpbuf); +#else + /********************************************************/ + /* LOAD THE TEXT SEGMENT */ + /********************************************************/ + PhysRead(kern_copy_p, head.a_text); + kern_copy_p += head.a_text; +#endif + + /********************************************************/ + /* Load the Initialised data after the text */ + /********************************************************/ +/* TBD - this is bogus - file system oriented */ +#define CLSIZE 1 +#define NBPG 4096 /* bytes/page */ +#define CLOFSET (CLSIZE*NBPG-1) /* for clusters, like PGOFSET */ + + while (kern_copy_p & CLOFSET) + *(char *)kern_copy_p++ = 0; + + printf(" data=0x%x", head.a_data); + PhysRead(kern_copy_p, head.a_data); + kern_copy_p += head.a_data; + + /********************************************************/ + /* Skip over the uninitialised data */ + /* (but clear it) */ + /********************************************************/ + printf(" bss=0x%x", head.a_bss); + if (kern_copy_p < RELOC && + (kern_copy_p + head.a_bss) > RELOC) { + PhysBzero(kern_copy_p, RELOC-(u_int)kern_copy_p); + } else { + PhysBzero(kern_copy_p, head.a_bss); + } + +#ifdef LOADSYMS /* not yet, haven't worked this out yet */ + if (kern_copy_p > 0x100000) { + /********************************************************/ + /*copy in the symbol header */ + /********************************************************/ + PhysBcopy(&head.a_syms, kern_copy_p, sizeof(head.a_syms)); + kern_copy_p += sizeof(head.a_syms); + + /********************************************************/ + /* READ in the symbol table */ + /********************************************************/ + printf(" symbols=[+0x%x", head.a_syms); + Read(kern_copy_p, head.a_syms); + kern_copy_p += head.a_syms; + + /********************************************************/ + /* Followed by the next integer (another header) */ + /* more debug symbols? */ + /********************************************************/ + read(&i, sizeof(u_int)); + PhysBcopy(&i, kern_copy_p, sizeof(u_int)); + i -= sizeof(u_int); + kern_copy_p += sizeof(u_int); + + /********************************************************/ + /* and that many bytes of (debug symbols?) */ + /********************************************************/ + printf("+0x%x]", i); + Read(kern_copy_p, i); + kern_copy_p += i; + } +#endif LOADSYMS + + /********************************************************/ + /* and note the end address of all this */ + /********************************************************/ + + printf(" total=0x%x",kern_copy_p - kern_copy_org); + + boot_argv[0] = 0; + boot_argv[1] = howto; + boot_argv[2] = 0; + boot_argv[3] = 0; + +/* TBD - place vendor_area on stack */ + + printf(" entry point=0x%x\n" ,((u_int)start_addr) & 0xffffff); + + if (howto) { + static char *rb_option_name[9] = { + "askname", + "single", + "nosync", + "halt", + "initname", + "dfltroot", + "kdb", + "rdonly", + "dump", + }; + int i; + printf("Starting kernel with options (0x%x): ", howto); + for (i=0; i<9; i++) { + if (howto & (1<<i)) { + printf("%s ", rb_option_name[i]); + } + } + printf("\n"); + } + +#if 0 /* ndef USE_BUFFER */ + PhysBcopy(tmpbuf, boot_area_org, sizeof(tmpbuf)); +#endif + + StartProg(start_addr & 0xffffff, boot_argv); + + return load_success; /* hah! */ +} + +int GetHex(int old) { + int r, c, ch; + r = 0; + ch = 0; + while((c=getchar()) != '\n') { + ch = 1; + if (c>='0' && c<='9') + r = r*16 + (c-'0'); + else if (c>='a' && c<='f') + r = r*16 + (c+10-'a'); + } + if (ch) + return r; + else + return old; +} + +static char +ToHex(int n) { + n &= 0x0F; + return n >= 10 ? n - 10 + 'A' : n + '0'; +} + +static char name_set[][9] = { + "xxxxxxxx", + "default", +}; + +static char *ext_set[] = { + ".netbsd", + ".netbsd.old", + ".386bsd", + ".386bsd.old", + ".vmunix", + ".vmunix.old", +}; + +static ipaddr_t server_set[2] = { + 0, + IP_BCASTADDR, +}; + +static inline void +TryToLoadSomething(void) { + int nserver; + for (nserver=0; nserver<nelt(server_set); nserver++) { + int nname; + char file_name[MAX_FILE_NAME_LEN+1]; + file_name[0] = '\0'; + if (GetIpAddress(&server_set[nserver], &ip_myaddr, &ip_gateway, file_name)) { + if (*file_name) { + LoadProgFromServer(server_set[nserver], ip_gateway, file_name); + } + else { + /* no file name supplied from server, synthesize one */ + inetaddr_t ip; + ip.a = ip_myaddr; + name_set[0][0] = ToHex(ip.s.a0 >> 4); + name_set[0][1] = ToHex(ip.s.a0); + name_set[0][2] = ToHex(ip.s.a1 >> 4); + name_set[0][3] = ToHex(ip.s.a1); + name_set[0][4] = ToHex(ip.s.a2 >> 4); + name_set[0][5] = ToHex(ip.s.a2); + name_set[0][6] = ToHex(ip.s.a3 >> 4); + name_set[0][7] = ToHex(ip.s.a3); + name_set[0][8] = 0; + for (nname=0; nname<nelt(name_set); nname++) { + int next; + for (next=0; next<nelt(ext_set); next++) { + strncpy(file_name, name_set[nname], MAX_FILE_NAME_LEN); + strncat(file_name, ext_set[next], MAX_FILE_NAME_LEN-strlen(file_name)); + LoadProgFromServer(server_set[nserver], ip_gateway, file_name); + } + } + } + } + } +} + + +static char * +DecimalToByte(char *s, u_char *n) { + for (*n = 0; *s >= '0' && *s <= '9'; s++) + *n = (*n * 10) + *s - '0'; + return s; +} + +static ipaddr_t +IpConvertAddr(char *p) { + inetaddr_t addr; + + if (p == (char *)0 || *p == '\0') + return IP_ANYADDR; + p = DecimalToByte(p, &addr.s.a0); + if (*p == '\0' || *p++ != '.') + return IP_ANYADDR; + p = DecimalToByte(p, &addr.s.a1); + if (*p == '\0' || *p++ != '.') + return IP_ANYADDR; + p = DecimalToByte(p, &addr.s.a2); + if (*p == '\0' || *p++ != '.') + return IP_ANYADDR; + p = DecimalToByte(p, &addr.s.a3); + if (*p != '\0') + return IP_ANYADDR; + return addr.a; +} + +static int +GetLine(char **argv, int argvsize) { + char *p, ch; + static char line[128]; + int argc; + + /* + * Read command line, implement some simple editing features + */ + p = line; + while ((ch = getchar()) != '\r' && ch != '\n' && (p-line) < sizeof(line)) { + if (ch == '\b') { + if (p > line) { + p--; + printf(" \b"); + } + } else + *p++ = ch; + } + *p = '\0'; + + /* + * Break command line up into an argument vector + */ + argc = 0; + for (p = line; *p == ' ' || *p == '\t'; p++) + /* skip white spaces */; + while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') { + if (argc > argvsize) break; + argv[(argc)++] = p; + for (; *p != ' ' && *p != '\t' && *p != '\n' && *p != '\0'; p++) + /* skip word */; + if (*p != '\0') *p++ ='\0'; + for (; *p == ' ' || *p == '\t'; p++) + /* skip white spaces */; + } + argv[(argc)] = (char *)0; + return argc; +} + +enum cmd_token_type { + CMD_GO, + CMD_HELP, + CMD_RESET, + CMD_AUTO, + CMD_WHO, + CMD_REBOOT, + CMD_DISKBOOT, + CMD_ADDRESS, + CMD_GATEWAY, + CMD_TFTP, + CMD_DEBUG, + CMD_SINGLE, + CMD_FILE, + CMD_SERVER, +}; + +struct commands { + enum cmd_token_type cmd_token; + char *cmd_name; + char *cmd_help; +} commands[] = { + {CMD_GO, "go", " start loaded binary"}, + {CMD_HELP, "help", " this help message"}, + {CMD_RESET, "reset", " reset ethernet board"}, + {CMD_AUTO, "auto", " continue with auto boot"}, + {CMD_WHO, "whoami", " get IP address"}, + {CMD_REBOOT, "reboot", " hard reboot"}, + {CMD_DISKBOOT, "diskboot", " soft reboot (from disk)"}, + {CMD_ADDRESS, "address", "[<addr>] set IP address"}, + {CMD_GATEWAY, "gateway", "[<addr>] set IP gateway"}, + {CMD_SERVER, "server", "[<addr>] set server IP address"}, + {CMD_FILE, "file", "[<name>] set boot file name"}, + {CMD_TFTP, "tftp", " TFTP download"}, + {CMD_DEBUG, "debug", " enter kernel debugger at boot"}, + {CMD_SINGLE, "single", " enter single user at boot"}, +}; + +#define ARGVECSIZE 100 + +/* + * A very simple and terse monitor + */ +static void +Monitor(void) { + char *argv[ARGVECSIZE]; + static char file_name[MAX_FILE_NAME_LEN+1] = "default.bsd386"; + int loaded, argc; + int i; + int token; + static ipaddr_t ip_servaddr = IP_ANYADDR; + + loaded = 0; + printf("\n" +#ifdef USE_BOOTP + "BOOTP/" +#endif +#ifdef USE_RARP + "RARP/" +#endif + "TFTP monitor mode\n"); + for (;;) { + char filename[MAX_FILE_NAME_LEN+1]; + ipaddr_t gateway; + printf("ethernet boot monitor: "); + if ((argc = GetLine(argv, ARGVECSIZE)) > 0) { + + for (token = -1, i = 0; i < nelt(commands); i++) { + if (strcmp(argv[0], commands[i].cmd_name) == 0) { + token = commands[i].cmd_token; + break; + } + } + switch (token) { + case CMD_HELP: + for (i = 0; i < nelt(commands); i++) + printf("%s %s\n", commands[i].cmd_name, commands[i].cmd_help); + break; + case CMD_RESET: + PktInit(); + EtherReset(); + break; + case CMD_REBOOT: + EtherStop(); + ResetCpu(); + break; + case CMD_DISKBOOT: + EtherStop(); + exit(0); + break; + case CMD_AUTO: + return; + case CMD_WHO: + (void) GetIpAddress(&ip_servaddr, &ip_myaddr, &gateway, filename); + break; + case CMD_ADDRESS: + if (argc != 2) { + printf("My IP address is "); + IpPrintAddr(ip_myaddr); + printf("\n"); + } else + ip_myaddr = IpConvertAddr(argv[1]); + break; + case CMD_SERVER: + if (argc != 2) { + printf("Server's IP address is "); + IpPrintAddr(ip_servaddr); + printf("\n"); + } else + ip_servaddr = IpConvertAddr(argv[1]); + break; + case CMD_FILE: + if (argc != 2) { + printf("File name is \"%s\"\n", file_name); + } else + strncpy(file_name, argv[1], MAX_FILE_NAME_LEN); + break; + case CMD_GATEWAY: + if (argc != 2) { + printf("Gateway IP address is "); + IpPrintAddr(ip_gateway); + printf("\n"); + } else + ip_gateway = IpConvertAddr(argv[1]); + break; + case CMD_DEBUG: + howto ^= RB_KDB; + break; + case CMD_SINGLE: + howto ^= RB_SINGLE; + break; + case CMD_TFTP: + if (ip_myaddr == IP_ANYADDR) { + printf("This machine's IP address must be set first.\n"); + goto complain; + } + loaded = LoadProgFromServer(ip_servaddr, ip_gateway, file_name); + printf("File could not be loaded, giving up.\n"); + break; + default: + goto complain; + } + } else + complain: + printf("Invalid or incorrect command. Type \"help\" for help.\n"); + } +} + +static jmp_buf jmp_env; + +void +HandleKbdAttn(void) { + if (IsKbdCharReady()) + if (getc() == 0x1b) { + EtherReset(); + PktInit(); + longjmp(jmp_env, 1); + } +} + +int time_zero; + +void +main(void) { + + extern char edata[], end[]; + char volatile * volatile p; + + /* clear bss */ + for (p = edata; p < end; p++) + *p = 0; + + printf( +#ifdef USE_BOOTP + "BOOTP/" +#endif +#ifdef USE_RARP + "RARP/" +#endif + "TFTP bootstrap loader @0x%x: %d/%d k of memory. ^] for attn.\n", + work_area_org, + GetMemSize(0), + GetMemSize(1)); + + gateA20(); + + PktInit(); + if (!EtherInit()) { + printf("No ethernet board found\n"); + exit(1); + } + srand((time_zero=timer()) ^ eth_myaddr[5]); + + printf("Ethernet address is "); + EtherPrintAddr(eth_myaddr); + printf("\n"); + + for (;;) { + if (setjmp(jmp_env)) + Monitor(); + else { + TryToLoadSomething(); + } + } +} + +#ifdef __GNUC__ +void +__main(void) { +} +#endif diff --git a/sys/arch/i386/netboot/misc.c b/sys/arch/i386/netboot/misc.c new file mode 100644 index 00000000000..13a28b540f5 --- /dev/null +++ b/sys/arch/i386/netboot/misc.c @@ -0,0 +1,225 @@ +/* $NetBSD: misc.c,v 1.3 1994/10/27 04:21:18 cgd Exp $ */ + +#include "proto.h" + +#if defined(DEBUG) + +void +DUMP_STRUCT(char *s, u_char *p, u_int ps) { + int i; + printf("struct %s (@0x%x %d bytes): ", s, p, ps); + for (i=0; i<ps; i++) + printf("%x ", *(p+i)); + printf("\n"); +} + +#else + +void +DUMP_STRUCT(char *s, u_char *p, u_int ps) { +} + + +#endif + + +char * +strncpy(char *dst, const char *src, int len) { + char *p=dst; + while (*src && len--) + *p++ = *src++; + *p = 0; + return dst; +} + + +int +strlen(const char *s) { + int len = 0; + while (*s++) + len++; + return len; +} + + +char * +strncat(char *s, const char *append, int len) { + int offset = strlen(s); + strncpy(s+offset, append, len); + return s; +} + + +int +strcmp(const char *s, const char *t) { + while (*s == *t++) + if (*s++ == '\0') + return 0; + return *s - *--t; +} + + +int +bcmp(const void *p, const void *q, int len) { + while (len--) + if (*((const char *)p)++ != *((const char *)q)++) + return 1; + return 0; +} + + +void volatile exit(int v) { +#ifdef DEBUG + L: goto L; +#else + ExitToBios(); +#endif +} + + +#define RTC_ADDR 0x70 +#define RTC_DATA 0x71 + +#define RTC_SECONDS 0x00 +#define RTC_MINUTES 0x02 +#define RTC_HOURS 0x04 +#define RTC_STATUS_A 0x0a +#define RTC_BASEMEM_LO 0x15 +#define RTC_BASEMEM_HI 0x16 +#define RTC_EXPMEM_LO 0x30 +#define RTC_EXPMEM_HI 0x31 + +static u_char +ReadRtcRam(u_short addr) { + for (;;) { + /* wait if updating */ + outb(RTC_ADDR, RTC_STATUS_A); + if (!(inb(RTC_DATA) & 0x80)) + break; + } + outb(RTC_ADDR, addr); + return inb(RTC_DATA); +} + +static void +getrtc(u_long *hrs, u_long *mins, u_long *secs) { +/* TBD - replace args with single arg - struct or sec of day */ + /* + * Get real time clock values (they are in BCD) + */ +#ifdef USE_BIOS + asm(" + call _prot_to_real + movb $0x02,%ah # read real time clock + int $0x1a + .byte 0x66 + call _real_to_prot + + xor %eax, %eax + movb %dh, %al + mov %%eax, %0 + movb %cl, %al + mov %eax, %1 + movb %ch, %al + mov %eax, %2 + " : "=g" (secs), "=g" (mins), "=g" (hrs)); +#else + *secs = ReadRtcRam(RTC_SECONDS); + *mins = ReadRtcRam(RTC_MINUTES); + *hrs = ReadRtcRam(RTC_HOURS); +#endif +} + +static inline u_long +bcd2dec(u_long arg) { + return ((arg & 0xF0) >> 4) * 10 + (arg & 0x0F); +} + + +u_long +timer(void) { +/* TBD - replace with StartCountdown()/CountdownAtZero() routines, + isolate the span-midnight problem to inside these routines + */ + /* + * Return the current time in seconds + */ + + u_long sec, min, hour; + + /* BIOS time is stored in bcd */ + getrtc(&hour, &min, &sec); + sec = bcd2dec(sec); + min = bcd2dec(min); + hour = bcd2dec(hour); +#if 0 +printe("time h%d m%d s%d = sum%d\n", hour, min, sec, hour * 3600L + min * 60L + sec); +#endif + return hour * 3600L + min * 60L + sec; +} + +/* + * Simple random generator + */ +static u_long next = 1; + +void +srand(u_int seed) { + next = seed; +} + +int +rand(void) { + next = next * 1103515245L + 12345; + return (u_int)(next / 65536) % 32768; +} + +u_short +GetMemSize(u_short s) { +#ifdef USE_BIOS + u_short result; + asm(" + push %%ebx + mov %1, %%ebx + call _prot_to_real + cmpb $0x1, %%bl + .byte 0x66 + je 1f + sti + int $0x12 + cli + .byte 0x66 + jmp 2f +1: movb $0x88, %%ah + sti + int $0x15 + cli +2: mov %%eax, %%ebx + .byte 0x66 + call _real_to_prot + mov %%bx, %0 + pop %%ebx + " : "=g" (result) : "g" (s)); + return result; +#else + u_long result; + if (s) + result = ((u_long)ReadRtcRam(RTC_EXPMEM_HI)<<8) + ReadRtcRam(RTC_EXPMEM_LO); + else + result = ((u_long)ReadRtcRam(RTC_BASEMEM_HI)<<8) + ReadRtcRam(RTC_BASEMEM_LO); + return result; +#endif +} + +void +ResetCpu(void) { +#ifdef USE_BIOS + asm(" + call _prot_to_real # enter real mode + int $0x19 + " ); +#else + while (inb(0x64)&2); /* wait input ready */ + outb(0x64, 0xFE); /* Reset Command */ +#endif +} diff --git a/sys/arch/i386/netboot/nbtypes.h b/sys/arch/i386/netboot/nbtypes.h new file mode 100644 index 00000000000..8a4c3ffbafe --- /dev/null +++ b/sys/arch/i386/netboot/nbtypes.h @@ -0,0 +1,95 @@ +/* $NetBSD: nbtypes.h,v 1.4 1994/10/27 04:21:19 cgd Exp $ */ + +/* + * source in this file came from + * various 386BSD system header files. + * The intent is to render these sources compilable from environments + * other than native 386bsd. + * + * Copyright (c) 1982, 1986, 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __nbtypes_h_ +#define __nbtypes_h_ + +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +#define _JBLEN 10 +typedef int jmp_buf[_JBLEN]; + +struct exec { + long a_midmag; /* magic number */ +unsigned long a_text; /* text segment size */ +unsigned long a_data; /* initialized data size */ +unsigned long a_bss; /* uninitialized data size */ +unsigned long a_syms; /* symbol table size */ +unsigned long a_entry; /* entry point */ +unsigned long a_trsize; /* text relocation size */ +unsigned long a_drsize; /* data relocation size */ +}; + +#define N_GETMAGIC(ex) \ + ( (((ex).a_midmag)&0xffff0000) ? (ntohl(((ex).a_midmag))&0xffff) : ((ex).a_midmag)) + +#define ZMAGIC 0413 /* demand load format */ + +#if 0 +typedef char *va_list; +#define __va_promote(type) \ + (((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int)) +#define va_start(ap, last) \ + (ap = ((char *)&(last) + __va_promote(last))) +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type) < sizeof(int) ? \ + (abort(), 0) : sizeof(type)))[-1] +#define va_end(ap) +#else +typedef char *va_list; +#define va_start(ap, parmN) ((ap) = (char *)(&parmN + 1)) +#define va_arg(ap, type) ((ap) += sizeof(type), ((type *)(ap))[-1]) +#define va_end(ap) +#endif + +#define RB_ASKNAME 0x01 /* ask for file name to reboot from */ +#define RB_SINGLE 0x02 /* reboot to single user only */ +#define RB_NOSYNC 0x04 /* dont sync before reboot */ +#define RB_HALT 0x08 /* don't reboot, just halt */ +#define RB_INITNAME 0x10 /* name given for /etc/init (unused) */ +#define RB_DFLTROOT 0x20 /* use compiled-in rootdev */ +#define RB_KDB 0x40 /* give control to kernel debugger */ +#define RB_RDONLY 0x80 /* mount root fs read-only */ +#define RB_DUMP 0x100 /* dump kernel memory before reboot */ + +#endif /* __types_h_ */ diff --git a/sys/arch/i386/netboot/ne2100.c b/sys/arch/i386/netboot/ne2100.c new file mode 100644 index 00000000000..3de6137ce68 --- /dev/null +++ b/sys/arch/i386/netboot/ne2100.c @@ -0,0 +1,328 @@ +/* $NetBSD: ne2100.c,v 1.3 1994/10/27 04:21:20 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * A very simple network driver for NE2100 boards that polls. + * + * Copyright (c) 1992 by Leendert van Doorn + */ + +#include "assert.h" +#include "nbtypes.h" +#include "packet.h" +#include "ether.h" +#include "lance.h" +#include "proto.h" + +/* configurable parameters */ +#define NE_BASEREG 0x300 /* base register */ +#define NE_DMACHANNEL 5 /* DMA channel */ + +/* Lance register offsets */ +#define LA_CSR (NE_BASEREG+0x10) +#define LA_CSR1 (NE_BASEREG+0x10) +#define LA_CSR2 (NE_BASEREG+0x10) +#define LA_CSR3 (NE_BASEREG+0x10) +#define LA_RAP (NE_BASEREG+0x12) + +/* + * Some driver specific constants. + * Take care when tuning, this program only has 32 Kb + */ +#define LANCEBUFSIZE 1518 /* plus 4 CRC bytes */ +#define MAXLOOP 1000000L /* arbitrary retry limit */ +#define LOG2NRCVRING 2 /* log2(NRCVRING) */ +#define NRCVRING (1 << LOG2NRCVRING) + +u_char eth_myaddr[ETH_ADDRSIZE]; + +static int next_rmd; /* next receive element */ +static initblock_t *initblock; /* initialization block */ +static tmde_t *tmd; /* transmit ring */ +static rmde_t *rmd; /* receive ring */ +static char rbuffer[NRCVRING][LANCEBUFSIZE]; /* receive buffers */ + +static char *top = (char *)RAMSIZE; +static char last; + +static char * +aalloc(size, align) + int size, align; +{ + register char *p; + register int mask; + + if (align == 0) + align = sizeof(int); + mask = align - 1; + assert((align & mask) == 0); + top = top - (size + align); + p = (char *)((int)top & ~mask); + assert(p > &last); + assert(p <= (char *) RAMSIZE); + return top = p; +} + +/* + * Program DMA channel 'chan' for cascade mode + */ +static void +dma_cascade(chan) + int chan; +{ + assert(chan >= 0); + assert(chan <= 7); + if (chan >= 0 && chan <= 3) { + outb(0x0B, 0xC0 | (chan & 03)); + outb(0x0A, chan & 03); + } else { + outb(0xD6, 0xC0 | ((chan - 4) & 03)); + outb(0xD4, (chan - 4) & 03); + } +} + +/* + * Reset ethernet board (i.e. after a timeout) + */ +void +EtherReset(void) { + long l; + u_long addr; + int i; + + /* program DMA chip */ + dma_cascade(NE_DMACHANNEL); + + /* stop the chip, and make sure it did */ + outw(LA_RAP, RDP_CSR0); + outw(LA_CSR, CSR_STOP); + for (l = 0; (inw(LA_CSR) & CSR_STOP) == 0; l++) { + if (l >= MAXLOOP) { + printf("Lance failed to stop\n"); + return; + } + } + + /* fill lance initialization block */ + bzero(initblock, sizeof(initblock_t)); + + /* set my ethernet address */ + initblock->ib_padr[0] = eth_myaddr[0]; + initblock->ib_padr[1] = eth_myaddr[1]; + initblock->ib_padr[2] = eth_myaddr[2]; + initblock->ib_padr[3] = eth_myaddr[3]; + initblock->ib_padr[4] = eth_myaddr[4]; + initblock->ib_padr[5] = eth_myaddr[5]; + + /* receive ring pointer */ + addr = LA(rmd); + initblock->ib_rdralow = (u_short)addr; + initblock->ib_rdrahigh = (u_char)(addr >> 16); + initblock->ib_rlen = LOG2NRCVRING << 5; + + /* transmit ring with one element */ + addr = LA(tmd); + initblock->ib_tdralow = (u_short)addr; + initblock->ib_tdrahigh = (u_char)(addr >> 16); + initblock->ib_tlen = 0 << 5; + + /* setup the receive ring entries */ + for (next_rmd = 0, i = 0; i < NRCVRING; i++) { + addr = LA(&rbuffer[i]); + rmd[i].rmd_ladr = (u_short)addr; + rmd[i].rmd_hadr = (u_char)(addr >> 16); + rmd[i].rmd_mcnt = 0; + rmd[i].rmd_bcnt = -LANCEBUFSIZE; + rmd[i].rmd_flags = RMD_OWN; + } + + /* zero transmit ring */ + bzero(tmd, sizeof(tmde_t)); + + /* give lance the init block */ + addr = LA(initblock); + outw(LA_RAP, RDP_CSR1); + outw(LA_CSR1, (u_short)addr); + outw(LA_RAP, RDP_CSR2); + outw(LA_CSR2, (char)(addr >> 16)); + outw(LA_RAP, RDP_CSR3); + outw(LA_CSR3, 0); + + /* and initialize it */ + outw(LA_RAP, RDP_CSR0); + outw(LA_CSR, CSR_INIT|CSR_STRT); + + /* wait for the lance to complete initialization and fire it up */ + for (l = 0; (inw(LA_CSR) & CSR_IDON) == 0; l++) { + if (l >= MAXLOOP) { + printf("Lance failed to initialize\n"); + break; + } + } + for (l=0; (inw(LA_CSR)&(CSR_TXON|CSR_RXON))!=(CSR_TXON|CSR_RXON); l++) { + if (l >= MAXLOOP) { + printf("Lance not started\n"); + break; + } + } +} + +/* + * Get ethernet address and compute checksum to be sure + * that there is a board at this address. + */ +int +EtherInit() +{ + u_short checksum, sum; + int i; + + for (i = 0; i < 6; i++) + eth_myaddr[i] = inb(NE_BASEREG + i); + + sum = 0; + for (i = 0x00; i <= 0x0B; i++) + sum += inb(NE_BASEREG + i); + for (i = 0x0E; i <= 0xF; i++) + sum += inb(NE_BASEREG + i); + checksum = inb(NE_BASEREG + 0x0C) | (inb(NE_BASEREG + 0x0D) << 8); + if (sum != checksum) + return 0; + + /* initblock, tmd, and rmd should be 8 byte aligned ! */ + initblock = (initblock_t *) aalloc(sizeof(initblock_t), 8); + tmd = (tmde_t *) aalloc(sizeof(tmde_t), 8); + rmd = (rmde_t *) aalloc(NRCVRING * sizeof(rmde_t), 8); + EtherReset(); + return 1; +} + +/* + * Disable DMA for channel 'chan' + */ +static void +dma_done(chan) + int chan; +{ + assert(chan >= 0); + assert(chan <= 7); + if (chan >= 0 && chan <= 3) + outb(0x0A, 0x04 | (chan & 03)); + else + outb(0xD4, 0x04 | ((chan - 4 ) & 03)); +} + +/* + * Stop ethernet board + */ +void +EtherStop() +{ + long l; + + /* stop chip and disable DMA access */ + outw(LA_RAP, RDP_CSR0); + outw(LA_CSR, CSR_STOP); + for (l = 0; (inw(LA_CSR) & CSR_STOP) == 0; l++) { + if (l >= MAXLOOP) { + printf("Lance failed to stop\n"); + break; + } + } + dma_done(NE_DMACHANNEL); +} + +/* + * Send an ethernet packet to destination 'dest' + */ +void +EtherSend(pkt, proto, dest) + packet_t *pkt; + u_short proto; + u_char *dest; +{ + ethhdr_t *ep; + long l; + u_long addr; + u_short csr; + + /* add ethernet header and fill in source & destination */ + pkt->pkt_len += sizeof(ethhdr_t); + pkt->pkt_offset -= sizeof(ethhdr_t); + ep = (ethhdr_t *) pkt->pkt_offset; + ep->eth_proto = htons(proto); + bcopy(dest, ep->eth_dst, ETH_ADDRSIZE); + bcopy(eth_myaddr, ep->eth_src, ETH_ADDRSIZE); + if (pkt->pkt_len < 60) + pkt->pkt_len = 60; + assert(pkt->pkt_len <= 1514); + + /* set up transmit ring element */ + assert((tmd->tmd_flags & TMD_OWN) == 0); + addr = LA(pkt->pkt_offset); + assert((addr & 1) == 0); + tmd->tmd_ladr = (u_short)addr; + tmd->tmd_hadr = (u_char)(addr >> 16); + tmd->tmd_bcnt = -pkt->pkt_len; + tmd->tmd_err = 0; + tmd->tmd_flags = TMD_OWN|TMD_STP|TMD_ENP; + + /* start transmission */ + outw(LA_CSR, CSR_TDMD); + + /* wait for interrupt and acknowledge it */ + for (l = 0; l < MAXLOOP; l++) { + if ((csr = inw(LA_CSR)) & CSR_TINT) { + outw(LA_CSR, CSR_TINT); + break; + } + } +} + +/* + * Poll the LANCE just see if there's an Ethernet packet + * available. If there is, its contents is returned in a + * pkt structure, otherwise a nil pointer is returned. + */ +packet_t * +EtherReceive(void) { + packet_t *pkt; + rmde_t *rp; + u_long addr; + u_short csr; + + pkt = (packet_t *)0; + if ((csr = inw(LA_CSR)) & CSR_RINT) { + outw(LA_CSR, CSR_RINT); + assert(next_rmd >= 0); + assert(next_rmd <= NRCVRING); + rp = &rmd[next_rmd]; + if ((rp->rmd_flags & ~RMD_OFLO) == (RMD_STP|RMD_ENP)) { + pkt = PktAlloc(0); + pkt->pkt_len = rp->rmd_mcnt - 4; + assert(pkt->pkt_len >= 0); + assert(pkt->pkt_len < PKT_DATASIZE); + bcopy(rbuffer[next_rmd], pkt->pkt_offset, pkt->pkt_len); + /* give packet back to the lance */ + rp->rmd_bcnt = -LANCEBUFSIZE; + rp->rmd_mcnt = 0; + rp->rmd_flags = RMD_OWN; + } + next_rmd = (next_rmd + 1) & (NRCVRING - 1); + } + return pkt; +} + +/* + * Print an ethernet address in human readable form + */ +void +EtherPrintAddr(addr) + u_char *addr; +{ + printf("%x:%x:%x:%x:%x:%x", + addr[0] & 0xFF, addr[1] & 0xFF, addr[2] & 0xFF, + addr[3] & 0xFF, addr[4] & 0xFF, addr[5] & 0xFF); +} diff --git a/sys/arch/i386/netboot/packet.c b/sys/arch/i386/netboot/packet.c new file mode 100644 index 00000000000..a292f699f32 --- /dev/null +++ b/sys/arch/i386/netboot/packet.c @@ -0,0 +1,59 @@ +/* $NetBSD: packet.c,v 1.3 1994/10/27 04:21:21 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * Packet allocation and deallocation routines. + * + * Copyright (c) 1992 by Leendert van Doorn + */ + +#include "proto.h" +#include "assert.h" +#include "param.h" +#include "packet.h" + +static packet_t *pool = (packet_t *)0; +static packet_t *last; + +void +PktInit(void) { + static packet_t s_pool[PKT_POOLSIZE]; + pool = s_pool; + bzero((char *)pool, PKT_POOLSIZE * sizeof(packet_t)); + last = pool; +} + +packet_t * +PktAlloc(u_long offset) { + int i; + + for (i = 0; i < PKT_POOLSIZE; i++) { + if (last->pkt_used == FALSE) { + bzero((char *)last->pkt_data, PKT_DATASIZE); + last->pkt_used = TRUE; + last->pkt_len = 0; + last->pkt_offset = last->pkt_data + offset; +#if 0 +printf("PktAlloc: used %x\n", last); +#endif + return last; + } + if (++last == &pool[PKT_POOLSIZE]) + last = pool; + } + printf("Pool out of free packets\n"); + exit(1); + return 0; /* silence warnings */ +} + +void +PktRelease(packet_t *pkt) { +#if 0 +printf("PktAlloc: freed %x\n", pkt); +#endif + assert(pkt >= &pool[0]); + assert(pkt < &pool[PKT_POOLSIZE]); + (last = pkt)->pkt_used = FALSE; +} diff --git a/sys/arch/i386/netboot/packet.h b/sys/arch/i386/netboot/packet.h new file mode 100644 index 00000000000..74480965369 --- /dev/null +++ b/sys/arch/i386/netboot/packet.h @@ -0,0 +1,27 @@ +/* $NetBSD: packet.h,v 1.3 1994/10/27 04:21:22 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * Packet layout definitions + */ + +/* implementation constants */ +#define PKT_POOLSIZE 5 +#define PKT_DATASIZE 1514 + +/* + * Structure of a packet. + * Each packet can hold exactly one ethernet message. + */ +typedef struct { + u_short pkt_used; /* whether this packet it used */ + u_short pkt_len; /* length of data */ + u_char *pkt_offset; /* current offset in data */ + u_char pkt_data[PKT_DATASIZE]; /* packet data */ +} packet_t; + +void PktInit(void); +packet_t *PktAlloc(u_long); +void PktRelease(packet_t *); diff --git a/sys/arch/i386/netboot/param.h b/sys/arch/i386/netboot/param.h new file mode 100644 index 00000000000..de2b454dfbb --- /dev/null +++ b/sys/arch/i386/netboot/param.h @@ -0,0 +1,26 @@ +/* $NetBSD: param.h,v 1.3 1994/10/27 04:21:23 cgd Exp $ */ + +/* + * Tunable parameters + */ + +/* + * RARP as well as TFTP uses a timeout mechanism which starts with four + * seconds and eventually go up as high as 4 << NRETRIES seconds. That + * is, the number of retry iterations. + */ +#define NRETRIES 6 + +#ifdef MONITOR +/* + * BIOS break interrupt. This interrupt is generated by the + * keyboard driver every time CTRL BREAK is pressed. We pick + * it up to jump into the monitor. + */ +#define BRK_INTR 0x1B + +/* + * Number of arguments in the users' command line + */ +#define ARGVECSIZE 5 +#endif /* MONITOR */ diff --git a/sys/arch/i386/netboot/proto.h b/sys/arch/i386/netboot/proto.h new file mode 100644 index 00000000000..381f0c487a6 --- /dev/null +++ b/sys/arch/i386/netboot/proto.h @@ -0,0 +1,146 @@ +/* $NetBSD: proto.h,v 1.3 1994/10/27 04:21:24 cgd Exp $ */ + +/* + * TBD - need for common typedefs - rethink? + * TBD - move config include into the source files - this is just expedient + */ + +#include "config.h" +#include "nbtypes.h" + +#define TRUE 1 +#define FALSE 0 +#define MDUMP 100 /* TBD - remove */ +#define MAX_FILE_NAME_LEN 128 +#define CRTBASE ((char *)0xb8000) +#define CHECKPOINT(x) (CRTBASE[0] = x) +#define nelt(x) (sizeof(x)/sizeof((x)[0])) + +void ENTER(char *); /* remove TBD */ +int IsKbdCharReady(void); +u_char GetKbdChar(void); +void HandleKbdAttn(void); +void KbdWait(int n); + +int bcmp(const void *, const void *, int); +void volatile exit(int); +void volatile ExitToBios(void); +void gateA20(void); +int getc(void); +int getchar(void); +u_short GetMemSize(u_short); +int gets(char *); +int ischar(void); +void longjmp(jmp_buf env, int val); +void printf( /* const char *, ... */ ); +void putc(int); +void putchar(int); +int rand(void); +void ResetCpu(void); +int setjmp(jmp_buf env); +void srand(u_int); +void StartProg(u_long phyaddr, u_long *args); +int strlen(const char *); +char *strncat(char *, const char *, int len); +char *strncpy(char *, const char *, int len); +int strcmp(const char *, const char *); +u_long timer(void); + +/* macros in pio.h, rewritten as in-line functions */ +/* TBD - define addr arg as long - short might result in extra +bit masking whereas longs simply get plonked down in %edx */ +#undef inb +#undef outb +#undef inw +#undef outw +#undef inl +#undef outl + +static inline u_char +inb(u_short addr) { + u_char datum; + asm volatile("inb %1, %0" : "=a" (datum) : "d" (addr)); + return datum; +} + +static inline void +outb(u_short addr, u_char datum) { + asm volatile("outb %0, %1" : : "a" (datum), "d" (addr)); +} + +static inline u_short +inw(u_short addr) { + u_short datum; + asm volatile(".byte 0x66; inl %1, %0" : "=a" (datum) : "d" (addr)); + return datum; +} + +static inline void +outw(u_short addr, u_short datum) { + asm volatile(".byte 0x66; outw %0, %1" : : "a" (datum), "d" (addr)); +} + +static inline u_long +inl(u_short addr) { + u_long datum; + asm volatile("inw %1, %0" : "=a" (datum) : "d" (addr)); + return datum; +} + +static inline void +outl(u_short addr, u_long datum) { + asm volatile("outw %0, %1" : : "a" (datum), "d" (addr)); +} + +#if __GCC__ >= 2 +/* fast versions of bcopy(), bzero() */ +static inline void +bcopy(const void *from, void *to, int len) { + /* assumes %es == %ds */ + asm(" + mov %0, %%esi + mov %1, %%edi + mov %2, %%ecx + cld + rep + movsb + " : : "g" (from), "g" (to), "g" (len) : "esi", "edi", "ecx"); +} + +static inline void +bzero(void *dest, int len) { + /* assumes %es == %ds */ + asm(" + mov %0, %%edi + mov %1, %%ecx + xor %%eax, %%eax + cld + rep + stosb + " : : "g" (dest), "g" (len) : "edi", "ecx", "eax"); +} +#else + +static inline void +bcopy(char *from, char *to, int len) +{ + while (len-- > 0) + *to++ = *from++; +} + +static inline void +bzero(char *to, int len) +{ + while (len-- > 0) + *to++ = '\0'; +} + +#endif + +static inline void PhysBcopy(u_long src, u_long dest, u_long nbytes) { + bcopy((void *)src, (void *)dest, nbytes); +} + +static inline void PhysBzero(u_long dest, u_long nbytes) { + bzero((void *)dest, nbytes); +} diff --git a/sys/arch/i386/netboot/start.s b/sys/arch/i386/netboot/start.s new file mode 100644 index 00000000000..0bc14e124d9 --- /dev/null +++ b/sys/arch/i386/netboot/start.s @@ -0,0 +1,292 @@ +/* $NetBSD: start.s,v 1.4 1994/10/27 04:21:25 cgd Exp $ */ + +#include "asm.h" + +/* 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. + */ + + .word 0xaa55 /* bios extension signature */ + .byte 0 /* no. of 512B blocks */ + jmp 1f /* enter from bios here */ + .byte 0 /* checksum */ +ENTRY(start) +1: + cli + # save the bios return address in these registers until protected + # mode %ds is set up + # mov (%esp), %edx + # mov 2(%esp), %ebp + pop %dx /* return offset */ + pop %ebp /* return segment */ + + /* save stack [, data] context in case we are under dos */ + mov %esp, %ecx + mov %ss, %ax + mov %eax, %ebx + + /* set up a usable stack */ + .byte 0xb8 /* (mov $0xa000, %ax) */ + .word 0xa000 + mov %ax, %ss + xor %esp, %esp + + push %ebp /* return segment */ + push %dx /* return offset */ + push %ds + +#if 0 + jmp ret16 +#endif + + +#ifdef CHECK_386 + # check if 386 or later + # from Intel i486 programmer\'s reference manual, section 22.10 + # Care must be taken with the first few instructions to ensure + # operations are compatible with 386 progenitors - no operand + # or address size overrides, all operations must be 16 bit. + # Real mode not well supported by gas so it looks a bit crufty + + # TBD - there is little stack space, although the routine below + # uses only two bytes; might set up new stack first thing, then + # check processor type - would mean carrying sp, ss in two gp + # registers for a while. also make alternate provisions for saving + # ds: below. + + pushf + pop %ebx + .byte 0x81, 0xe3 /* (and 0x0fff, %ebx) */ + .word 0x0fff + push %ebx + popf + pushf + pop %eax + .byte 0x25 /* (and 0xf000, %eax) */ + .word 0xf000 + .byte 0x3d /* (cmp 0xf000, %eax) */ + .word 0xf000 + jz Lwrong_cpu /* \'86 */ + .byte 0x81, 0xcb /* (or 0xf000, %ebx) */ + .word 0xf000 + push %ebx + popf + pushf + pop %eax + .byte 0x25 /* (and 0xf000, %eax) */ + .word 0xf000 + jnz Lcpu_ok /* else is \'286 */ + +Lwrong_cpu: + .byte 0xbb /* (mov bad_cpu_msg, %ebx) */ + .word bad_cpu_msg + .byte 0xe8 /* (call xputs) */ + .word xputs-.-2 + lret + +xputc: /* print byte in %al */ + data32 + pusha + .byte 0xbb /* (mov $0x1, %ebx) %bh=0, %bl=1 (blue) */ + .word 0x0001 + movb $0xe, %ah + # sti + int $0x10 /* display a byte */ + # cli + data32 + popa + ret + +xputs: /* print string pointed to by cs:bx */ + data32 + pusha +1: + cs + .byte 0x8a, 0x07 /* (mov (%ebx), %al) */ + cmpb $0, %al + jz 1f + push %ebx + .byte 0xe8 /* (call xputc) */ + .word xputc-.-2 + pop %ebx + inc %ebx + jmp 1b +1: + data32 + popa + ret + +bad_cpu_msg: .asciz "netboot: cpu cannot execute '386 instructions, net boot not done.\n\r" + +Lcpu_ok: + # at this point it is known this can execute 386 instructions + # so operand and address size prefixes are ok +#endif /* CHECK_386 */ + + /* copy rom to link addr, prepare for relocation */ + xor %esi, %esi /* source */ + opsize + mov $0, %edi /* destination */ + opsize + mov $(RELOC)>>4, %eax + mov %ax, %es + opsize + mov $(ROM_SIZE), %ecx /* count */ + cs + rep + movsb + + addrsize + cs + lgdt gdtarg-RELOC + + /* turn on protected mode */ + cli + mov %cr0, %eax + opsize + or $CR0_PE, %eax + mov %eax, %cr0 + + /* 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 + movl $0xa0000, %esp + call _main + call _exit + +_ExitToBios: + .globl _ExitToBios + /* set up a dummy stack frame for the second seg change. */ + mov $(RELOC)>>4, %eax + pushw %ax /* real cs */ + pushw $2f /* real pc */ + + /* Change to use16 mode. */ + ljmp $BOOT_16_SEG, $1f /* jump to a 16 bit segment */ +1: + /* clear the PE bit of CR0 */ + mov %cr0, %eax + opsize + and $0!CR0_PE, %eax + mov %eax, %cr0 + + /* make intersegment jmp to flush the processor pipeline + * using the fake stack frame set up earlier + * and reload CS register + */ + lret +2: + /* we are in real mode now + * set up the real mode segment registers : DS, SS, ES + */ + movw %cs, %ax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + +ret16: /* temporary label - remove (TBD) */ + /* now in dumbed down mode, caveats */ + /* restore old context and return to whatever called us */ + pop %ds + pop %dx + pop %ebp + + mov %ebx, %eax + mov %ax, %ss + mov %ecx, %esp + + push %ebp + push %dx + sti + lret + +#ifdef USE_BIOS +_real_to_prot: + .global _real_to_prot + + addrsize + cs + lgdt gdtarg-RELOC + cli + mov %cr0, %eax + opsize + or $CR0_PE, %eax + mov %eax, %cr0 + + /* jump to relocation, flush prefetch queue, and reload %cs */ + opsize + ljmp $KERN_CODE_SEG, $1f +1: + movl $KERN_DATA_SEG, %eax + movl %ax, %ds + movl %ax, %es + movl %ax, %ss + + ret +#endif + +#ifdef USE_BIOS +_prot_to_real: + .global _prot_to_real + + /* set up a dummy stack frame for the second seg change. */ + movl $(RELOC), %eax + sarl $4, %eax + pushw %ax /* real cs */ + pushw $2f /* real pc */ + + /* Change to use16 mode. */ + ljmp $BOOT_16_SEG, $1f /* jump to a 16 bit segment */ +1: + /* clear the PE bit of CR0 */ + mov %cr0, %eax + opsize + and $0!CR0_PE, %eax + mov %eax, %cr0 + + /* make intersegment jmp to flush the processor pipeline + * using the fake stack frame set up earlier + * and reload CS register + */ + lret +2: + /* we are in real mode now + * set up the real mode segment registers : DS, SS, ES + */ + movw %cs, %ax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + opsize + ret +#endif + + .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, 0x9e, 0x00, 0 + + .align 4 +gdtarg: + .word 0x1f /* limit */ + .long gdt /* addr */ diff --git a/sys/arch/i386/netboot/tftp.c b/sys/arch/i386/netboot/tftp.c new file mode 100644 index 00000000000..6725080aa5a --- /dev/null +++ b/sys/arch/i386/netboot/tftp.c @@ -0,0 +1,484 @@ +/* $NetBSD: tftp.c,v 1.3 1994/10/27 04:21:26 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * Trivial File Transfer Protocol (see RFC 783). + * + * Copyright (c) 1992 by Leendert van Doorn + */ + +#include "proto.h" +#include "assert.h" +#include "param.h" +#include "packet.h" +#include "ether.h" +#include "inet.h" +#include "tftp.h" +#include "arp.h" + +ipaddr_t tftp_server; /* IP address of TFTP server */ +ipaddr_t tftp_gateway; +static char tftp_file_name[100]; +static short block; /* current block */ +static int ctid, stid; /* UDP client and server TID (network order) */ + +extern u_long work_area_org; + +/* + * Print IP address in a readable form + */ +void +IpPrintAddr(ipaddr_t addr) { + inetaddr_t ip; + + ip.a = addr; + printf("%d.%d.%d.%d", ip.s.a0, ip.s.a1, ip.s.a2, ip.s.a3); +} + +/* + * Generic TFTP error routine + */ +static void +TftpFail(ipaddr_t fromaddr, ipaddr_t toaddr, char *filename, char *reason) { + printf("Tftp of file '%s' from ", filename); + IpPrintAddr(fromaddr); + printf(" failed, %s\n", reason); +} + +/* + * One complement check sum + */ +static u_short +InChecksum(char *cp, u_long count) { + u_short *sp; + u_long sum, oneword = 0x00010000; + + for (sum = 0, sp = (u_short *)cp, count >>= 1; count--; ) { + sum += *sp++; + if (sum >= oneword) { + /* wrap carry into low bit */ + sum -= oneword; + sum++; + } + } + return ~sum; +} + +/* + * Setup the standard IP header fields for a destination, + * and send packet (possibly using the gateway). + */ +void +IpSend(packet_t *pkt, ipaddr_t dst, ipaddr_t gateway) { + iphdr_t *ip; + u_char edst[ETH_ADDRSIZE]; + static int ipid = 0; +#if TRACE > 0 +DUMP_STRUCT("IpSend: pkt (front)", pkt, 100); +#endif + pkt->pkt_offset -= sizeof(iphdr_t); + pkt->pkt_len += sizeof(iphdr_t); + ip = (iphdr_t *) pkt->pkt_offset; + ip->ip_vhl = (IP_VERSION << 4) | (sizeof(*ip) >> 2); + ip->ip_tos = 0; + ip->ip_len = htons(pkt->pkt_len); + ip->ip_id = ipid++; + ip->ip_off = 0; + ip->ip_ttl = IP_FRAGTTL; + ip->ip_p = IP_PROTO_UDP; + ip->ip_src = ip_myaddr ? ip_myaddr : IP_ANYADDR; + ip->ip_dst = dst; + ip->ip_sum = 0; + ip->ip_sum = InChecksum((char *)ip, sizeof(*ip)); +#if 0 +/* DUMP_STRUCT("pkt (after)", pkt, 100); */ +DUMP_STRUCT("ip", ip, sizeof(iphdr_t)+pkt->pkt_len); +#endif + if (ArpResolve(pkt, gateway ? gateway : dst, edst)) { + EtherSend(pkt, ETHTYPE_IP, edst); + PktRelease(pkt); + } +} + +/* + * States which TFTP can be in + */ +enum TftpPacketStatus { + TFTP_RECD_GOOD_PACKET, + TFTP_RECD_BAD_PACKET, + TFTP_RECD_SERVER_ABORT, +}; + +/* + * Pseudo header to compute UDP checksum + */ +struct pseudoheader { + ipaddr_t ph_src; + ipaddr_t ph_dst; + u_char ph_zero; + u_char ph_prot; + u_short ph_length; +}; + +/* + * Determine whether this IP packet is the TFTP data packet + * we were expecting. When a broadcast TFTP request was made + * we'll set the TFTP server address as well. + */ +static enum TftpPacketStatus +TftpDigestPacket(packet_t *pkt, char *rbuf, u_long *rlen) { + iphdr_t *ip; + udphdr_t *up; + tftphdr_t *tp; + struct pseudoheader ph; + u_short oldsum, sum; + u_short udplength; + + /* check for minimum size tftp packet */ + if (pkt->pkt_len < (sizeof(ethhdr_t) + sizeof(iphdr_t) + + sizeof(udphdr_t) + sizeof(tftphdr_t))) { +#if 0 + printe("TftpDigestPacket: bad packet size %d\n", pkt->pkt_len); +#endif + return TFTP_RECD_BAD_PACKET; + } + + /* IP related checks */ + ip = (iphdr_t *) (pkt->pkt_offset + sizeof(ethhdr_t)); + if (tftp_server != IP_BCASTADDR && ip->ip_src != tftp_server) { +#if 0 + printe("TftpDigestPacket: incorrect ip source address 0x%x\n", ip->ip_src); +#endif + return TFTP_RECD_BAD_PACKET; + } + if (ntohs(ip->ip_len) < + sizeof(iphdr_t) + sizeof(udphdr_t) + sizeof(tftphdr_t)) { +#if 0 + printe("TftpDigestPacket: bad ip length %d\n", ip->ip_len); +#endif + return TFTP_RECD_BAD_PACKET; + } + if (ip->ip_p != IP_PROTO_UDP) { +#if 0 + printe("TftpDigestPacket: wrong ip protocol type 0x%x\n", ip->ip_p); +#endif + return TFTP_RECD_BAD_PACKET; + } + if (ip_myaddr && ip->ip_dst != ip_myaddr) { +#if 0 + printe("TftpDigestPacket: incorrect ip destination address %x\n", ip->ip_dst); +#endif + return TFTP_RECD_BAD_PACKET; + } + + /* UDP related checks */ + up = (udphdr_t *) ((char *)ip + sizeof(iphdr_t)); + if (block && up->uh_sport != stid) { +#if 0 + printe("TftpDigestPacket: wrong udp source port 0x%x\n", up->uh_sport); +#endif + return TFTP_RECD_BAD_PACKET; + } + *rlen = ntohs(up->uh_len) - sizeof(udphdr_t) - sizeof(tftphdr_t); + if (up->uh_dport != ctid) { +#if 0 + printe("TftpDigestPacket: wrong udp destination port 0x%x\n", up->uh_dport); +#endif + return TFTP_RECD_BAD_PACKET; + } + + /* compute UDP checksum if any */ + oldsum = up->uh_sum; + if (oldsum) { + udplength = ntohs(up->uh_len); + /* + * zero the byte past the last data byte because the + * checksum will be over an even number of bytes. + */ + if (udplength & 01) + ((char *)up)[udplength] = '\0'; + + /* set up the pseudo-header */ + ph.ph_src = ip->ip_src; + ph.ph_dst = ip->ip_dst; + ph.ph_zero = 0; + ph.ph_prot = ip->ip_p; + ph.ph_length = htons(udplength); + + up->uh_sum = ~InChecksum((char *)&ph, sizeof(ph)); + sum = InChecksum((char *)up, (u_long)((udplength + 1) & ~1)); + up->uh_sum = oldsum; /* put original back */ + if (oldsum == (u_short) -1) + oldsum = 0; + if (sum != oldsum) { +#if 0 + printe("TftpDigestPacket: Bad checksum %x != %x, length %d from ", + sum, oldsum, udplength); + IpPrintAddr(ip->ip_src); + printe("\n"); +#endif + return TFTP_RECD_BAD_PACKET; + } + } + + /* TFTP related checks */ + tp = (tftphdr_t *) ((char *)up + sizeof(udphdr_t)); + switch (ntohs(tp->th_op)) { + case TFTP_ERROR: + printf("Diagnostic from server: error #%d, %s\n", + ntohs(tp->th_code), &tp->th_msg); + return TFTP_RECD_SERVER_ABORT; + case TFTP_DATA: + break; + default: +#if 0 + printe("TftpDigestPacket: incorrect tftp packet type 0x%x\n", tp->th_op); +#endif + return TFTP_RECD_BAD_PACKET; + } + + /* reject old packets */ + if (ntohs(tp->th_block) != block + 1) { +#if 0 + printe("TftpDigestPacket: bad block no. %d\n", tp->th_block); +#endif + return TFTP_RECD_BAD_PACKET; + } + + /* some TFTP related check */ + if (block == 0) { + stid = up->uh_sport; + /* in case of a broadcast, remember server address */ + if (tftp_server == IP_BCASTADDR) { + tftp_server = ip->ip_src; +#if 0 + printe("Found TFTP server at "); + IpPrintAddr(tftp_server); + printe("\n"); +#endif + } + } + if (stid != up->uh_sport) { +#if 0 + printe("TftpDigestPacket: incorrect udp source port 0x%x\n", up->uh_sport); +#endif + return TFTP_RECD_BAD_PACKET; + } + + bcopy(&tp->th_data, rbuf, *rlen); + + /* advance to next block */ + block++; + return TFTP_RECD_GOOD_PACKET; +} + +enum TftpStatus { + TFTP_SUCCESS, + TFTP_FAILURE, +}; + +static enum TftpStatus +Tftp(char *rbuf, u_long *rlen) { + u_long time, current, timeout; + int retry, quit; + enum TftpStatus rc = TFTP_FAILURE; + + *rlen = 0; + timeout = 4; /* four seconds */ + for (retry=0, quit=0; ++retry < NRETRIES && !quit; ) { + /* + * Send out a TFTP request. On the first block (actually + * zero) we send out a read request. Every other block we + * just acknowledge. + */ + packet_t *pkt; + ethhdr_t *ep; + udphdr_t *up; + tftphdr_t *tp; +#if TRACE > 0 +printe("Tftp: block %d, try #%d\n", block, retry); +#endif + pkt = PktAlloc(sizeof(ethhdr_t) + sizeof(iphdr_t)); + up = (udphdr_t *) pkt->pkt_offset; + tp = (tftphdr_t *) (pkt->pkt_offset + sizeof(udphdr_t)); + if (block == 0) { /* <RRQ> | <filename> | 0 | "octet" | 0 */ + char *cp, *p; + + tp->th_op = htons(TFTP_RRQ); + cp = tp->th_stuff; + for (p = tftp_file_name; *p; ) + *cp++ = *p++; + *cp++ = '\0'; + *cp++ = 'o'; + *cp++ = 'c'; + *cp++ = 't'; + *cp++ = 'e'; + *cp++ = 't'; + *cp++ = '\0'; + pkt->pkt_len = sizeof(udphdr_t) + (cp - (char *)tp); + } else { /* else <ACK> | <block> */ + tp->th_op = htons(TFTP_ACK); + tp->th_block = htons(block); +#if 0 +printe("ack block %x %x\n", tp->th_block, block); +#endif + pkt->pkt_len = sizeof(udphdr_t) + sizeof(tftphdr_t); + } + up->uh_sport = ctid; + up->uh_dport = stid; + up->uh_sum = 0; + up->uh_len = htons(pkt->pkt_len); +#if 0 +DUMP_STRUCT("tftphdr_t", tp, sizeof(tftphdr_t)); +DUMP_STRUCT("udphdr_t", up, sizeof(udphdr_t)); +printe("Tftp: "); +#endif + IpSend(pkt, tftp_server, tftp_gateway); + + /* + * Receive TFTP data or ARP packets + */ + time = timer() + timeout; + do { + pkt = EtherReceive(); + if (pkt) { + static int spin = 0; + ep = (ethhdr_t *) pkt->pkt_offset; +#if 0 +DUMP_STRUCT("ethhdr_t", ep, sizeof(ethhdr_t)); +#endif + switch (ntohs(ep->eth_proto)) { + case ETHTYPE_ARP: + ArpInput(pkt); + break; + case ETHTYPE_IP: + switch (TftpDigestPacket(pkt, rbuf, rlen)) { + case TFTP_RECD_GOOD_PACKET: + if (block % 8 == 0) + printf("%c\b", "-\\|/"[spin++ % 4]); +#if 0 +DUMP_STRUCT("good tftp packet", pkt, 100); +printe("TBD - copy tftp packet #%d, len %d to buffer\n", block, *rlen); +#endif + rc = TFTP_SUCCESS; + quit = 1; + break; + case TFTP_RECD_SERVER_ABORT: + TftpFail(tftp_server, ip_myaddr, tftp_file_name, "aborted by server"); + + rc = TFTP_FAILURE; + quit = 1; + break; + default: + /* for anything else, retry */ +#if 0 +printe("Tftp: bogus IP packet rec'd, still waiting\n"); +#endif + break; + } + break; + default: +#if 0 +printe("Tftp: undesired ethernet packet (type 0x%x) rec'd, still waiting\n", + ep->eth_proto); +#endif + break; + } + PktRelease(pkt); + } + current = timer(); + HandleKbdAttn(); + } while (current < time && !quit); + +#if 0 +/* TBD - move */ + eth_reset(); +#endif + + if (current >= time) + timeout <<= 1; + } + + if (retry > NRETRIES) { + TftpFail(tftp_server, ip_myaddr, tftp_file_name, "timed Out"); + } + return rc; +} + +static int tftp_at_eof = 1; +static u_long tftp_unread_bytes_in_buffer = 0; + +void +SetTftpParms(ipaddr_t server, ipaddr_t gateway, char *file_name) { + block = 0; + strncpy(tftp_file_name, file_name, MAX_FILE_NAME_LEN); + tftp_server = server; + tftp_at_eof = 0; + tftp_unread_bytes_in_buffer = 0; + stid = htons(IP_PORT_TFTP); + ctid = htons(rand()); + printf("Attempting to tftp file '%s'", tftp_file_name); + if (tftp_server != IP_BCASTADDR) { + printf(" from server "); + IpPrintAddr(tftp_server); + } else + printf(" using IP broadcast"); + tftp_gateway = gateway; + if (tftp_gateway) { + printf(" using gateway "); + IpPrintAddr(tftp_gateway); + } + printf("\n"); +} + +u_long +Read(void *result, u_long n_req) { + static u_long bufp = 0; + static char buf[PKT_DATASIZE]; + u_long length; + u_long n_recd = 0; + while (n_req && !tftp_at_eof) { + if (tftp_unread_bytes_in_buffer) { + *((char *)result)++ = buf[bufp++]; + n_req--; + n_recd++; + tftp_unread_bytes_in_buffer--; + } else { + switch (Tftp(buf, &length)) { + case TFTP_SUCCESS: + tftp_unread_bytes_in_buffer = length; + bufp = 0; + if (length < SEGSIZE) + tftp_at_eof = 1; + break; + default: + /* anything else should cause this to abend */ + tftp_unread_bytes_in_buffer = 0; + tftp_at_eof = 1; + break; + } + } + } + return n_recd; +} + +u_long +PhysRead(u_long addr, u_long n_req) { + u_long n_recd = 0; + while (n_req) { + char buf[512]; + u_long nd = n_req<sizeof(buf) ? n_req : sizeof(buf); + u_long nr = Read(buf, nd); + if (nr == 0) { + /* problem, incomplete read */ + break; + } + PhysBcopy(LA(buf), addr, nr); + n_req -= nr; + n_recd += nr; + addr += nr; + } + return n_recd; +} diff --git a/sys/arch/i386/netboot/tftp.h b/sys/arch/i386/netboot/tftp.h new file mode 100644 index 00000000000..6abba940325 --- /dev/null +++ b/sys/arch/i386/netboot/tftp.h @@ -0,0 +1,43 @@ +/* $NetBSD: tftp.h,v 1.3 1994/10/27 04:21:27 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * Trivial File Transfer Protocol (see RFC 783) + */ + +#define SEGSIZE 512 /* data segment size */ + +/* + * Packet types + */ +#define TFTP_RRQ 01 /* read request */ +#define TFTP_WRQ 02 /* write request */ +#define TFTP_DATA 03 /* data packet */ +#define TFTP_ACK 04 /* acknowledgement */ +#define TFTP_ERROR 05 /* error code */ + +/* + * TFTP header structure + */ +typedef struct { + u_short th_op; /* packet type */ + union { + u_short tu_block; /* block # */ + u_short tu_code; /* error code */ + char tu_stuff[1]; /* request packet stuff */ + } th_u; +} tftphdr_t; + +/* for ease of reference */ +#define th_block th_u.tu_block +#define th_code th_u.tu_code +#define th_stuff th_u.tu_stuff +#define th_data th_stuff[2] +#define th_msg th_data + +void SetTftpParms(ipaddr_t server, ipaddr_t gateway, char *file_name); +u_long Read(void *result, u_long nbytes); +u_long PhysRead(u_long addr, u_long nbytes); +void IpSend(packet_t *pkt, ipaddr_t dst, ipaddr_t gateway); diff --git a/sys/arch/i386/netboot/wd80x3.c b/sys/arch/i386/netboot/wd80x3.c new file mode 100644 index 00000000000..3c4fe8b6b66 --- /dev/null +++ b/sys/arch/i386/netboot/wd80x3.c @@ -0,0 +1,432 @@ +/* $NetBSD: wd80x3.c,v 1.4 1994/10/27 04:21:28 cgd Exp $ */ + +/* + * source in this file came from + * the Mach ethernet boot written by Leendert van Doorn. + * + * A very simple network driver for WD80x3 boards that polls. + * + * Copyright (c) 1992 by Leendert van Doorn + */ + +#include "proto.h" +#include "assert.h" +#include "packet.h" +#include "ether.h" +#include "dp8390.h" + +/* configurable parameters */ +#define WD_BASEREG 0x280 /* base register */ +/* the base address doesn't have to be particularly accurate - the + board seems to pick up on addresses in the range a0000..effff. + */ +#define WD_BASEMEM 0xd0000 /* base ram */ + +/* bit definitions for board features */ +#define INTERFACE_CHIP 01 /* has an WD83C583 interface chip */ +#define BOARD_16BIT 02 /* 16 bit board */ +#define SLOT_16BIT 04 /* 16 bit slot */ + +/* register offset definitions */ +#define WD_MSR 0x00 /* control (w) and status (r) */ +#define WD_REG0 0x00 /* generic register definitions */ +#define WD_REG1 0x01 +#define WD_REG2 0x02 +#define WD_REG3 0x03 +#define WD_REG4 0x04 +#define WD_REG5 0x05 +#define WD_REG6 0x06 +#define WD_REG7 0x07 +#define WD_EA0 0x08 /* most significant addr byte */ +#define WD_EA1 0x09 +#define WD_EA2 0x0A +#define WD_EA3 0x0B +#define WD_EA4 0x0C +#define WD_EA5 0x0D /* least significant addr byte */ +#define WD_LTB 0x0E /* LAN type byte */ +#define WD_CHKSUM 0x0F /* sum from WD_EA0 upto here is 0xFF */ +#define WD_DP8390 0x10 /* natsemi chip */ + +/* bits in control register */ +#define WD_MSR_MEMMASK 0x3F /* memory enable bits mask */ +#define WD_MSR_MENABLE 0x40 /* memory enable */ +#define WD_MSR_RESET 0x80 /* software reset */ + +/* bits in bus size register */ +#define WD_BSR_16BIT 0x01 /* 16 bit bus */ + +/* bits in LA address register */ +#define WD_LAAR_A19 0x01 /* address lines for above 1Mb ram */ +#define WD_LAAR_LAN16E 0x40 /* enables 16bit shrd RAM for LAN */ +#define WD_LAAR_MEM16E 0x80 /* enables 16bit shrd RAM for host */ + +u_char eth_myaddr[ETH_ADDRSIZE]; + +static int boardid; +static dpconf_t dpc; + +/* + * Determine whether wd8003 hardware performs register aliasing + * (i.e. whether it is an old WD8003E board). + */ +static int +Aliasing(void) { + if (inb(WD_BASEREG + WD_REG1) != inb(WD_BASEREG + WD_EA1)) + return 0; + if (inb(WD_BASEREG + WD_REG2) != inb(WD_BASEREG + WD_EA2)) + return 0; + if (inb(WD_BASEREG + WD_REG3) != inb(WD_BASEREG + WD_EA3)) + return 0; + if (inb(WD_BASEREG + WD_REG4) != inb(WD_BASEREG + WD_EA4)) + return 0; + if (inb(WD_BASEREG + WD_REG7) != inb(WD_BASEREG + WD_CHKSUM)) + return 0; + return 1; +} + +/* + * This trick is stolen from the clarkson packet driver +TBD - this is _ugly_ bogus! should use system timer + */ +static void +LongPause(void) { + short i; + for (i = 1600; i > 0; i++) + (void) inb(0x61); +} + +/* + * Determine whether this board has 16-bit capabilities + */ +static int +BoardIs16Bit(void) { + u_char bsreg = inb(WD_BASEREG + WD_REG1); + + outb(WD_BASEREG + WD_REG1, bsreg ^ WD_BSR_16BIT); + LongPause(); + if (inb(WD_BASEREG + WD_REG1) == bsreg) { + /* + * Pure magic: LTB is 0x05 indicates that this is a WD8013EB board, + * 0x27 indicates that this is an WD8013 Elite board, and 0x29 + * indicates an SMC Elite 16 board. + */ + u_char tlb = inb(WD_BASEREG + WD_LTB); + return tlb == 0x05 || tlb == 0x27 || tlb == 0x29; + } + outb(WD_BASEREG + WD_REG1, bsreg); + return 1; +} + +/* + * Determine whether the 16 bit capable board is plugged + * into a 16 bit slot. + */ +static int +SlotIs16Bit(void) { + return inb(WD_BASEREG + WD_REG1) & WD_BSR_16BIT; +} + +/* + * Reset ethernet board after a timeout + */ +void +EtherReset(void) { + int dpreg = dpc.dc_reg; + /* initialize the board */ + outb(WD_BASEREG + WD_MSR, + WD_MSR_MENABLE | (((u_long)WD_BASEMEM >> 13) & WD_MSR_MEMMASK)); + + /* reset dp8390 ethernet chip */ + outb(dpreg + DP_CR, CR_STP|CR_DM_ABORT); + + /* initialize first register set */ + outb(dpreg + DP_IMR, 0); + outb(dpreg + DP_CR, CR_PS_P0|CR_STP|CR_DM_ABORT); + outb(dpreg + DP_TPSR, dpc.dc_tpsr); + outb(dpreg + DP_PSTART, dpc.dc_pstart); + outb(dpreg + DP_PSTOP, dpc.dc_pstop); + outb(dpreg + DP_BNRY, dpc.dc_pstart); + outb(dpreg + DP_RCR, RCR_MON); + outb(dpreg + DP_TCR, TCR_NORMAL|TCR_OFST); + if (boardid & SLOT_16BIT) + outb(dpreg + DP_DCR, DCR_WORDWIDE|DCR_8BYTES); + else + outb(dpreg + DP_DCR, DCR_BYTEWIDE|DCR_8BYTES); + outb(dpreg + DP_RBCR0, 0); + outb(dpreg + DP_RBCR1, 0); + outb(dpreg + DP_ISR, 0xFF); + + /* initialize second register set */ + outb(dpreg + DP_CR, CR_PS_P1|CR_DM_ABORT); + outb(dpreg + DP_PAR0, eth_myaddr[0]); + outb(dpreg + DP_PAR1, eth_myaddr[1]); + outb(dpreg + DP_PAR2, eth_myaddr[2]); + outb(dpreg + DP_PAR3, eth_myaddr[3]); + outb(dpreg + DP_PAR4, eth_myaddr[4]); + outb(dpreg + DP_PAR5, eth_myaddr[5]); + outb(dpreg + DP_CURR, dpc.dc_pstart+1); + + /* and back to first register set */ + outb(dpreg + DP_CR, CR_PS_P0|CR_DM_ABORT); + outb(dpreg + DP_RCR, RCR_AB); + + /* flush counters */ + (void) inb(dpreg + DP_CNTR0); + (void) inb(dpreg + DP_CNTR1); + (void) inb(dpreg + DP_CNTR2); + + /* and go ... */ + outb(dpreg + DP_CR, CR_STA|CR_DM_ABORT); +} + +/* + * Initialize the WD80X3 board + */ +int +EtherInit(void) { + unsigned sum; + int memsize; + /* reset the ethernet card */ + outb(WD_BASEREG + WD_MSR, WD_MSR_RESET); + LongPause(); + outb(WD_BASEREG + WD_MSR, 0); + + /* determine whether the controller is there */ + sum = inb(WD_BASEREG + WD_EA0) + inb(WD_BASEREG + WD_EA1) + + inb(WD_BASEREG + WD_EA2) + inb(WD_BASEREG + WD_EA3) + + inb(WD_BASEREG + WD_EA4) + inb(WD_BASEREG + WD_EA5) + + inb(WD_BASEREG + WD_LTB) + inb(WD_BASEREG + WD_CHKSUM); + if ((sum & 0xFF) != 0xFF) + return 0; + + /* + * Determine the type of board + */ + boardid = 0; + if (!Aliasing()) { + if (BoardIs16Bit()) { + boardid |= BOARD_16BIT; + if (SlotIs16Bit()) + boardid |= SLOT_16BIT; + } + } + memsize = (boardid & BOARD_16BIT) ? 0x4000 : 0x2000; /* 16 or 8 Kb */ + + /* special setup needed for WD8013 boards */ + if (boardid & SLOT_16BIT) + outb(WD_BASEREG + WD_REG5, WD_LAAR_A19|WD_LAAR_LAN16E); + + /* get ethernet address */ + eth_myaddr[0] = inb(WD_BASEREG + WD_EA0); + eth_myaddr[1] = inb(WD_BASEREG + WD_EA1); + eth_myaddr[2] = inb(WD_BASEREG + WD_EA2); + eth_myaddr[3] = inb(WD_BASEREG + WD_EA3); + eth_myaddr[4] = inb(WD_BASEREG + WD_EA4); + eth_myaddr[5] = inb(WD_BASEREG + WD_EA5); + + /* save settings for future use */ + dpc.dc_reg = WD_BASEREG + WD_DP8390; + dpc.dc_mem = WD_BASEMEM; + dpc.dc_tpsr = 0; + dpc.dc_pstart = 6; + dpc.dc_pstop = (memsize >> 8) & 0xFF; + + printf("Using wd80x3 board, port 0x%x, iomem 0x%x, iosiz %d\n", WD_BASEREG, WD_BASEMEM, memsize); + + EtherReset(); + return 1; +} + +/* + * Stop ethernet board + */ +void +EtherStop(void) { + /* stop dp8390, followed by a board reset */ + outb(dpc.dc_reg + DP_CR, CR_STP|CR_DM_ABORT); + outb(WD_BASEREG + WD_MSR, WD_MSR_RESET); + outb(WD_BASEREG + WD_MSR, 0); +} + +/* TBD - all users must take care to use the current "data seg" value +when moving data from/to the controller */ +static void +WdCopy(u_long src, u_long dst, u_long count) { +#if TRACE > 0 +printf("WdCopy from %x to %x for %d\n", src, dst, count); +#endif + assert(count <= 1514); + if (boardid & SLOT_16BIT) + outb(WD_BASEREG + WD_REG5, + WD_LAAR_MEM16E|WD_LAAR_LAN16E|WD_LAAR_A19); + PhysBcopy(src, dst, count); + if (boardid & SLOT_16BIT) + outb(WD_BASEREG + WD_REG5, WD_LAAR_LAN16E|WD_LAAR_A19); +} + +/* + * Send an ethernet packet to destination 'dest' + */ +void +EtherSend(packet_t *pkt, u_short proto, u_char *dest) { + ethhdr_t *ep; + + pkt->pkt_len += sizeof(ethhdr_t); + pkt->pkt_offset -= sizeof(ethhdr_t); + ep = (ethhdr_t *) pkt->pkt_offset; + ep->eth_proto = htons(proto); + bcopy((char *)dest, (char *)ep->eth_dst, ETH_ADDRSIZE); + bcopy((char *)eth_myaddr, (char *)ep->eth_src, ETH_ADDRSIZE); +#if 0 +DUMP_STRUCT("ethhdr_t", ep, sizeof(ethhdr_t)); +#endif + if (pkt->pkt_len < 60) + pkt->pkt_len = 60; + +#if TRACE > 0 + { + int i; +DUMP_STRUCT("EtherSend: pkt", pkt->pkt_offset, pkt->pkt_len); +#if 0 + for(i=0; i<(pkt->pkt_len<MDUMP?pkt->pkt_len:MDUMP); i++) printe("%x ", *((u_char*)(pkt->pkt_offset)+i)); + printe("\n"); +#endif + } +#endif + +#if 0 +printe("EtherSend: WdCopy from %x to %x for %d\n", LA(pkt->pkt_offset), dpc.dc_mem + (dpc.dc_tpsr << 8), (u_long)pkt->pkt_len); +#endif + WdCopy(LA(pkt->pkt_offset), + dpc.dc_mem + (dpc.dc_tpsr << 8), (u_long)pkt->pkt_len); + outb(dpc.dc_reg + DP_TPSR, dpc.dc_tpsr); + outb(dpc.dc_reg + DP_TBCR0, (pkt->pkt_len & 0xFF)); + outb(dpc.dc_reg + DP_TBCR1, (pkt->pkt_len >> 8) & 0xFF); + outb(dpc.dc_reg + DP_CR, CR_TXP); + +#if 0 + printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TPSR, dpc.dc_tpsr); + printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR0, (pkt->pkt_len & 0xFF)); + printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR1, (pkt->pkt_len >> 8) & 0xFF); + printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_CR, CR_TXP); +#endif +} + +/* + * Copy dp8390 packet header for observation + */ +static void +GetHeader(u_long haddr, dphdr_t *dph) { +#if TRACE > 0 +printe("GetHeader: WdCopy from %x to %x for %d\n", haddr, LA(dph), sizeof(dphdr_t)); +#endif + WdCopy(haddr, LA(dph), sizeof(dphdr_t)); +#if 0 +DUMP_STRUCT("GetHeader: dphdr_t", dph, sizeof(dphdr_t)); +#endif +} + +/* + * Poll the dp8390 just see if there's an Ethernet packet + * available. If there is, its contents is returned in a + * pkt structure, otherwise a nil pointer is returned. + */ +packet_t * +EtherReceive(void) { + u_char pageno, curpage, nextpage; + int dpreg = dpc.dc_reg; + packet_t *pkt; + dphdr_t dph; + u_long addr; + + pkt = (packet_t *)0; + if (inb(dpreg + DP_RSR) & RSR_PRX) { + /* get current page numbers */ + pageno = inb(dpreg + DP_BNRY) + 1; + if (pageno == dpc.dc_pstop) + pageno = dpc.dc_pstart; + outb(dpreg + DP_CR, CR_PS_P1); + curpage = inb(dpreg + DP_CURR); + outb(dpreg + DP_CR, CR_PS_P0); + if (pageno == curpage) + return (packet_t *) 0; + + /* get packet header */ + addr = dpc.dc_mem + (pageno << 8); + GetHeader(addr, &dph); + nextpage = dph.dh_next; + + /* allocate packet */ + pkt = PktAlloc(0); +#if 0 +printe("EtherReceive: allocated pkt %x\n", pkt); +#endif + pkt->pkt_len = ((dph.dh_rbch & 0xFF) << 8) | (dph.dh_rbcl & 0xFF); + pkt->pkt_len -= sizeof(dphdr_t); + if (pkt->pkt_len > 1514) /* bug in dp8390 */ + pkt->pkt_len = 1514; + +#if TRACE > 0 + { + int i; + printe("EtherReceive %d bytes: ", pkt->pkt_len); +#if 0 + for(i=0; i<(pkt->pkt_len<MDUMP?pkt->pkt_len:MDUMP); i++) printe("%x ", *((u_char*)pkt+i)); +#else + DUMP_STRUCT("", pkt, pkt->pkt_len); +#endif + printe("\n"); + } +#endif + + /* + * The dp8390 maintains a circular buffer of pages (256 bytes) + * in which incomming ethernet packets are stored. The following + * if detects wrap arounds, and copies the ethernet packet to + * our local buffer in two chunks if necesarry. + */ + assert(pkt->pkt_offset); + assert(pkt->pkt_len <= (6 << 8)); + if (nextpage < pageno && nextpage > dpc.dc_pstart) { + u_long nbytes = ((dpc.dc_pstop - pageno) << 8) - sizeof(dphdr_t); + + assert(nbytes <= (6 << 8)); +#if TRACE > 0 +printe("EtherReceive1: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt->pkt_offset), nbytes); +#endif + WdCopy(addr + sizeof(dphdr_t), + LA(pkt->pkt_offset), nbytes); + if ((pkt->pkt_len - nbytes) > 0) + /* TBD - this OK? */ +#if TRACE > 0 +printe("EtherReceive2: WdCopy from %x to %x for %x\n",dpc.dc_mem + (dpc.dc_pstart << 8), LA(pkt->pkt_offset) + nbytes, pkt->pkt_len - nbytes); +#endif + WdCopy(dpc.dc_mem + (dpc.dc_pstart << 8), + LA(pkt->pkt_offset) + nbytes, + pkt->pkt_len - nbytes); + } else { +#if TRACE > 0 +printe("EtherReceive3: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt->pkt_offset), (u_long)pkt->pkt_len); +#endif + WdCopy(addr + sizeof(dphdr_t), + LA(pkt->pkt_offset), (u_long)pkt->pkt_len); + } + + /* release occupied pages */ + if (nextpage == dpc.dc_pstart) + nextpage = dpc.dc_pstop; + outb(dpreg + DP_BNRY, nextpage - 1); + } + + return pkt; +} + +/* + * Print an ethernet address in human readable form + */ +void +EtherPrintAddr(u_char *addr) { + printf("%x:%x:%x:%x:%x:%x", + addr[0] & 0xFF, addr[1] & 0xFF, addr[2] & 0xFF, + addr[3] & 0xFF, addr[4] & 0xFF, addr[5] & 0xFF); +} |