From owner-freebsd-hackers Thu Oct 24 03:53:06 1996 Return-Path: owner-hackers Received: (from root@localhost) by freefall.freebsd.org (8.7.5/8.7.3) id DAA12265 for hackers-outgoing; Thu, 24 Oct 1996 03:53:06 -0700 (PDT) Received: from hq.icb.chel.su (hq.icb.chel.su [193.125.10.33]) by freefall.freebsd.org (8.7.5/8.7.3) with ESMTP id DAA11886; Thu, 24 Oct 1996 03:47:44 -0700 (PDT) Received: (babkin@localhost) by hq.icb.chel.su (8.7.5/8.6.5) id QAA09211; Thu, 24 Oct 1996 16:42:25 +0600 (ESD) From: "Serge A. Babkin" <babkin@hq.icb.chel.su> Message-Id: <199610241042.QAA09211@hq.icb.chel.su> Subject: Networking for PCEMU (2/2) To: hackers@freebsd.org, jkh@time.cdrom.com, wollman@freebsd.org, asami@freebsd.org Date: Thu, 24 Oct 1996 16:42:24 +0600 (ESD) X-Mailer: ELM [version 2.4 PL23] Content-Type: text Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk Part 2: (patch for PCEMU) *** README.NET Thu Oct 24 19:36:17 1996 --- README.NET Thu Oct 24 16:13:58 1996 *************** *** 0 **** --- 1,40 ---- + README.NET - guide for the FreeBSD PCEMU networking support + + To get the network support you'll need to do: + + 1. Install these networking patches for PCEMU + + 2. Install the loe driver and run PSEMU as described in + /usr/share/FAQ/Text/loe.FAQ + + Comments on internals. + + The packet drivers is on interrupt 0x60. If you look at the + sources you can see that this interrupt is installed twice. + The first time is used just to install the piece of code + used in the callback when getting a packet from network. It + is: + + callbios <nethandler_ret> + iret + + The second installs the real interrupt handler. It is: + + jmp short label + nop + db "PKT DRVR",0 + db "FreeBSD Loopback Ethernet",0 + callbios <nethandler> + <standard end-of-interrupt sequence> + + The interrupt 0x61 is used to call the callback function. This + interrupt is generated at receiving a packet from the network. + It is just: + + callbios <nethandler_call> + + It never returns directly because the handler sets the return + address to the address of "callbios <nethandler_ret>" and + jumps to the callback function. + + Serge A.Babkin <babkin@hq.icb.chel.su> *** network.c Thu Oct 24 19:36:17 1996 --- network.c Thu Oct 24 15:43:56 1996 *************** *** 0 **** --- 1,439 ---- + /* + * Copyright (c) 1996 + * Serge A. Babkin. 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. + * + * + * Network support for PCEMU + * + */ + + #include <stdio.h> + #include <fcntl.h> + #include <sys/types.h> + #include <unistd.h> + #include <errno.h> + #include <sys/param.h> + #include <sys/socket.h> + #include <sys/sockio.h> + #include <net/if.h> + + #include "global.h" + #include "network.h" + #include "cpu.h" + + #undef NETDEBUG + + #ifdef NETDEBUG + # define DFPRINT(x) fprintf x + #else + # define DFPRINT(x) + #endif + + static struct receivers { + unsigned short type; + short seg; + short off; + char inuse; + } + receivers[100]; + + int netretseg, netretoff; + + int hasnet=0; /* flag: do we have a network interface ? */ + int netfile; /* network interface file descriptor */ + + int network_pending=0; /* interrupt request on line 0x61 */ + + static char pktbuf[2000]; + static int pktlen=0; + static int netbufc= -1; + + static struct ifreq ifr; + static char broadaddr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; + + static WORD savewregs[8]; + static unsigned savesregs[4]; + + void + netinit(fname) + char *fname; + { + int c; + + if(( netfile=open(fname, O_RDWR) )<0) { + fprintf(stderr,"%s: ",progname); + perror("Unable to open network file"); + exit(1); + } + + if( fcntl(netfile, F_SETFL, O_NDELAY)<0 ) { + fprintf(stderr,"%s: ",progname); + perror("Unable to set nodelay mode"); + exit(1); + } + + if( ioctl(netfile, SIOCGIFADDR, &ifr)<0 ) { + fprintf(stderr,"%s: ",progname); + perror("Unable to get Ethernet address"); + exit(1); + } + DFPRINT((stderr,"%s: Ethernet address %s\n", progname, + ether_ntoa(ifr.ifr_addr.sa_data) )); + + for(c=0; c<100; c++) + receivers[c].inuse=0; + + hasnet=1; + } + + void + nethandler() + { + unsigned type; + int c; + register unsigned tmp, tmp1; + + + if(pktlen>0) + return; + + nextpacket: + + if(( pktlen=read(netfile,pktbuf,2000) )>0) { + type=*(unsigned short *)(pktbuf+12); + + DFPRINT((stderr,"%s: got %d bytes from network, type=0x%X\n", + progname,pktlen,ntohs(type) )); + + /* check if the packet is our own broadcast then drop it */ + if(!memcmp(pktbuf+6, ifr.ifr_addr.sa_data,6) + && !memcmp(pktbuf, broadaddr, 6) ) { + goto nextpacket; + } + + if(ntohs(type)<=0x5EE) { + DFPRINT((stderr,"%s: 802.3 packet converted to IPX\n",progname)); + type=htons(0xFFFF); + } + + for(c=0; c<100 && (!receivers[c].inuse || receivers[c].type!=type); + c++); + + if(c>=100) { + DFPRINT((stderr,"%s: no handler for this type\n",progname)); + goto nextpacket; /* no handler */ + } + + netbufc=c; + + if(type==0xffff) { /* PDIPX don't understand the broadcast address */ + DFPRINT((stderr,"%s: workaround for PDIPX\n",progname)); + for(c=0; c<6; c++) + pktbuf[c]=ifr.ifr_addr.sa_data[c]; + } + + DFPRINT((stderr,"%s: set up network interrupt\n",progname)); + network_pending=1; + } + + if(pktlen<0 && errno!=EAGAIN) { + fprintf(stderr,"%s: ",progname); + perror("reading network"); + fprintf(stderr,"%s: network disabled\n",progname); + hasnet=0; + close(netfile); + } + } + + void + nethandler_call() + { + unsigned type; + int tmp; + int c; + + if(pktlen==0) { + fprintf(stderr,"%s: erroneous call of nethandler_call\n",progname); + exit(1); + return; + } + + #if 0 + DFPRINT((stderr,"%s: SS=0x%x SP=0x%x\n",progname, + sregs[CS],ChangeE(wregs[SP]) )); + DFPRINT((stderr,"%s: return address in stack 0x%x:0x%x\n",progname, + GetMemW(c_stack,ChangeE(wregs[SP])+2), + GetMemW(c_stack,ChangeE(wregs[SP])) )); + #endif + + for(c=0; c<8; c++) + savewregs[c]=wregs[c]; + for(c=0; c<4; c++) + savesregs[c]=sregs[c]; + + /* set up parameters */ + wregs[BX]=netbufc; + wregs[AX]=0; + wregs[CX]=ChangeE(pktlen); + + /* set up return adress */ + tmp=(WORD)(ReadWord(&wregs[SP])-2); + PutMemW(c_stack,tmp, netretseg); + tmp-=2; + PutMemW(c_stack,tmp, ChangeE(netretoff)); + WriteWord(&wregs[SP],tmp); + + /* call receiver */ + sregs[CS]=receivers[netbufc].seg; + c_cs=SegToMemPtr(CS); + ip=ChangeE(receivers[netbufc].off); + + DFPRINT((stderr,"%s: called handler (1st)\n",progname)); + + PIC_EOI(); + } + + void + nethandler_ret() + { + int seg,off; + int c; + + if(pktlen==0) { + fprintf(stderr,"%s: erroneous call of nethandler_ret\n",progname); + exit(1); + return; + } + + disable(); + + #if 0 + DFPRINT((stderr,"%s: SS=0x%x SP=0x%x\n",progname, + sregs[CS],ChangeE(wregs[SP]) )); + DFPRINT((stderr,"%s: return address in stack 0x%x:0x%x\n",progname, + GetMemW(c_stack,ChangeE(wregs[SP])+2), + GetMemW(c_stack,ChangeE(wregs[SP])) )); + #endif + + if(netbufc>=0) { /* 1st return */ + DFPRINT((stderr,"%s: handler returned (1st)\n",progname)); + seg=sregs[ES] & 0xffff; + off=ChangeE(wregs[DI]) & 0xffff; + + if(seg==0 && off==0) { /* throw packet */ + pktlen=0; + netbufc= -1; + DFPRINT((stderr,"%s: handler requested to drop packet\n",progname)); + } else { + register unsigned tmp, tmp1; + + /* set up parameters */ + memcpy(memory+(seg<<4)+off, pktbuf, pktlen); + sregs[DS]=sregs[ES]; + c_ds=SegToMemPtr(DS); + wregs[SI]=wregs[DI]; + wregs[BX]=netbufc; + wregs[AX]=ChangeE(1); + wregs[CX]=ChangeE(pktlen); + + /* set up return adress */ + tmp=(WORD)(ReadWord(&wregs[SP])-2); + PutMemW(c_stack,tmp, netretseg); + tmp-=2; + PutMemW(c_stack,tmp, ChangeE(netretoff)); + WriteWord(&wregs[SP],tmp); + + /* call receiver */ + sregs[CS]=receivers[netbufc].seg; + c_cs=SegToMemPtr(CS); + ip=ChangeE(receivers[netbufc].off); + + /* mark state */ + netbufc= -1; + DFPRINT((stderr,"%s: called handler (2nd)\n",progname)); + } + } else { + pktlen=0; + + DFPRINT((stderr,"%s: handler returned (2nd)\n",progname)); + + for(c=0; c<8; c++) + wregs[c]=savewregs[c]; + for(c=0; c<4; c++) + sregs[c]=savesregs[c]; + + c_cs = SegToMemPtr(CS); + c_ds = SegToMemPtr(DS); + c_es = SegToMemPtr(ES); + c_stack = c_ss = SegToMemPtr(SS); + } + + enable(); + } + + void + int_pktdrv() + { + int error; + int c; + int type; + char wribuf[2000]; + unsigned wrilen; + + if(!hasnet) { + CF=1; + *bregs[DH]=PKT_BAD_COMMAND; + DFPRINT((stderr,"%s: no network, packet driver disabled\n",progname)); + return; + } + + DFPRINT((stderr,"%s: packet driver called (%d)\n",progname,*bregs[AH])); + switch(*bregs[AH]) { + case 1: /* driver_info */ + if(*bregs[AL]!=255) { + CF=1; + *bregs[DH]=PKT_BAD_COMMAND; + DFPRINT((stderr,"%s: bad command AL=0x%x\n",progname,*bregs[AL])); + } else { + CF=0; + wregs[BX]=ChangeE(1); /* version */ + *bregs[CH]=1; /* class */ + wregs[DX]=1; /* type */ + *bregs[CL]=1; /* number */ + sregs[DS]=sregs[CS]; /* name */ + c_ds=SegToMemPtr(DS); + *bregs[SI]=ChangeE( ip - (6+26) ); + *bregs[AL]=1; /* functionality */ + } + break; + case 2:/* access_type */ + error=0; + if(*bregs[AL]!=1 && *bregs[AL]!=11) { /* EthII or 802.3 */ + error=PKT_NO_CLASS; + DFPRINT((stderr,"%s: no class 0x%x\n",progname,*bregs[AL])); + } + #if 0 + if(wregs[BX]!=0 && wregs[BX]!=0xffff) { + error=PKT_NO_TYPE; + DFPRINT((stderr,"%s: no type 0x%x\n",progname,ChangeE(wregs[BX]) )); + } + if(*bregs[DL]!=0) { + error=PKT_NO_NUMBER; + DFPRINT((stderr,"%s: no card 0x%x\n",progname,*bregs[DL])); + } + #endif + if(wregs[CX]!=ChangeE(2)) { /* only 2-byte EtherII types */ + error=PKT_BAD_TYPE; + DFPRINT((stderr,"%s: %d-byte address is wrong\n",progname, + ChangeE(wregs[CX]) )); + } + + type=GetMemW(c_ds,ChangeE(wregs[SI])); + for(c=0; c<100 && !error; c++) + if(receivers[c].inuse && receivers[c].type==type) { + error=PKT_TYPE_INUSE; + DFPRINT((stderr,"%s: type 0x%x is already in use\n", + progname,ntohs(type) )); + } + + if(!error) { + for(c=0; c<100 && receivers[c].inuse; c++); + if(c>=100) { + error=PKT_NO_SPACE; + DFPRINT((stderr,"%s: no space\n", progname)); + } + } + + if(error) { + CF=1; + *bregs[DH]=error; + break; + } + + receivers[c].inuse=1; + receivers[c].type=type; + receivers[c].seg=sregs[ES]; + receivers[c].off=wregs[DI]; + + wregs[AX]=c; + CF=0; + DFPRINT((stderr,"%s: successfully bound type 0x%x\n", + progname,ntohs(type) )); + break; + case 3: /* release_type */ + c=wregs[BX]; + if(c<100 && c>=0 && receivers[c].inuse) { + receivers[c].inuse=0; + CF=0; + DFPRINT((stderr,"%s: successfully released type 0x%x\n", + progname,ntohs(receivers[c].type))); + } else { + CF=1; + *bregs[DH]=PKT_BAD_HANDLE; + DFPRINT((stderr,"%s: bad handle %d\n",progname,c)); + } + break; + case 4: /* send_pkt */ + wrilen=ChangeE(wregs[CX]); + if(wrilen>1518 || wrilen<14) { /* packet has wrong size for Ethernet */ + CF=1; + *bregs[DH]=PKT_CANT_SEND; + DFPRINT((stderr,"%s: packet size is wrong: %d bytes \n", + progname,wrilen)); + } + type=GetMemW(c_ds, ChangeE(wregs[SI]+12)); + if(type==0) { + PutMemW(c_ds, ChangeE(wregs[SI])+12, htons(wrilen-14) ); + DFPRINT((stderr,"%s: sending packet of type 0, converted to IPX \n", + progname)); + } + memcpy(wribuf, c_ds+ChangeE(wregs[SI]), wrilen); + if( write(netfile, wribuf, wrilen)<0 ) { + fprintf(stderr,"%s: ",progname); + perror("Cant' write to network"); + CF=1; + *bregs[DH]=PKT_CANT_SEND; + } else { + CF=0; + DFPRINT((stderr,"%s: send packet of %d bytes \n", + progname,wrilen)); + } + break; + case 5: /* terminate */ + CF=1; + *bregs[DH]=PKT_CANT_TERMINATE; + DFPRINT((stderr,"%s: can't terminate\n",progname)); + break; + case 6: /* get_address */ + if(ChangeE(wregs[CX])<6) { + CF=1; + *bregs[DH]=PKT_NO_SPACE; + DFPRINT((stderr,"%s: address needs more than %d bytes\n", + progname, ChangeE(wregs[CX]) )); + } else { + memcpy(c_es+ChangeE(wregs[DI]), ifr.ifr_addr.sa_data, 6); + wregs[CX]=ChangeE(6); + CF=0; + DFPRINT((stderr,"%s: successfully got address\n",progname)); + } + break; + case 7: /* reset_interface */ + CF=1; + *bregs[DH]=PKT_CANT_RESET; + break; + default: + CF=1; + *bregs[DH]=PKT_BAD_COMMAND; + DFPRINT((stderr,"%s: bad command\n",progname)); + break; + } + } *** network.h Thu Oct 24 19:36:17 1996 --- network.h Thu Oct 24 15:43:33 1996 *************** *** 0 **** --- 1,49 ---- + /* + * Copyright (c) 1996 + * Serge A. Babkin. 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. + * + * + * Network support for PCEMU + * + */ + + extern int hasnet; /* flag: do we have a network interface ? */ + extern int netfile; /* network interface file descriptor */ + + extern int netretseg, netretoff; /* address of network return routine */ + + extern int network_pending; /* intrrupt request on line 0x61 */ + + /* packet driver error codes */ + + #define PKT_BAD_HANDLE 1 + #define PKT_NO_CLASS 2 + #define PKT_NO_TYPE 3 + #define PKT_NO_NUMBER 4 + #define PKT_BAD_TYPE 5 + #define PKT_NO_MULTICAST 6 + #define PKT_CANT_TERMINATE 7 + #define PKT_BAD_MODE 8 + #define PKT_NO_SPACE 9 + #define PKT_TYPE_INUSE 10 + #define PKT_BAD_COMMAND 11 + #define PKT_CANT_SEND 12 + #define PKT_CANT_SET 13 + #define PKT_BAD_ADDRESS 14 + #define PKT_CANT_RESET 15 + + + void netinit(char *fname); + void nethandler(void); + void nethandler_call(void); + void nethandler_ret(void); + void int_pktdrv(void); *** Makefile Tue Oct 22 16:26:57 1996 --- Makefile Tue Oct 22 14:16:19 1996 *************** *** 66,87 **** LFLAGS = -L$(XROOT)/lib LIBRARIES = -lXext -lX11 OFILES = main.o cpu.o bios.o vga.o vgahard.o debugger.o xstuff.o \ ! hardware.o mfs.o PROGNAME = pcemu GLOBAL_DEP = Makefile global.h mytypes.h all: $(PROGNAME) cpu.o: $(GLOBAL_DEP) cpu.h instr.h debugger.h hardware.h ! main.o: $(GLOBAL_DEP) bios.h xstuff.h hardware.h bios.o: $(GLOBAL_DEP) bios.h cpu.h vga.h vgahard.h debugger.h hardware.h \ ! keytabs.h mfs_link.h vga.o: $(GLOBAL_DEP) bios.h cpu.h vga.h vgahard.h hardware.h vgahard.o: $(GLOBAL_DEP) vgahard.h xstuff.h hardware.h debugger.o: $(GLOBAL_DEP) cpu.h debugger.h disasm.h vgahard.h xstuff.o: $(GLOBAL_DEP) vgahard.h xstuff.h icon.h hardware.h ! hardware.o: $(GLOBAL_DEP) cpu.h vgahard.h debugger.h hardware.h mfs.o: $(GLOBAL_DEP) cpu.h mfs.h mfs_link.h .c.o: $(CC) $(CFLAGS) $(OPTIONS) -c $< --- 66,88 ---- LFLAGS = -L$(XROOT)/lib LIBRARIES = -lXext -lX11 OFILES = main.o cpu.o bios.o vga.o vgahard.o debugger.o xstuff.o \ ! hardware.o mfs.o network.o PROGNAME = pcemu GLOBAL_DEP = Makefile global.h mytypes.h all: $(PROGNAME) cpu.o: $(GLOBAL_DEP) cpu.h instr.h debugger.h hardware.h ! main.o: $(GLOBAL_DEP) bios.h xstuff.h hardware.h network.h bios.o: $(GLOBAL_DEP) bios.h cpu.h vga.h vgahard.h debugger.h hardware.h \ ! keytabs.h mfs_link.h network.h vga.o: $(GLOBAL_DEP) bios.h cpu.h vga.h vgahard.h hardware.h vgahard.o: $(GLOBAL_DEP) vgahard.h xstuff.h hardware.h debugger.o: $(GLOBAL_DEP) cpu.h debugger.h disasm.h vgahard.h xstuff.o: $(GLOBAL_DEP) vgahard.h xstuff.h icon.h hardware.h ! hardware.o: $(GLOBAL_DEP) cpu.h vgahard.h debugger.h hardware.h network.h mfs.o: $(GLOBAL_DEP) cpu.h mfs.h mfs_link.h + network.o: $(GLOBAL_DEP) network.h .c.o: $(CC) $(CFLAGS) $(OPTIONS) -c $< *** bios.c Fri Jun 24 17:39:47 1994 --- bios.c Tue Oct 22 14:38:23 1996 *************** *** 30,35 **** --- 30,36 ---- #include "debugger.h" #include "vgahard.h" #include "hardware.h" + #include "network.h" #define BIOS *************** *** 1114,1119 **** --- 1115,1131 ---- { 0x06,0x57,0x50,0xb8,0x0c,0x12,0xcd,0x2f,0x58,0x5f,0x07,0xcf }; + static BYTE pktdrvret[] = + { + 0xcf + }; + static BYTE pktdrvcode[] = + { + 0xeb,0x24,0x90,0x50,0x4b,0x54,0x20,0x44,0x52,0x56,0x52,0x00, + 0x46,0x72,0x65,0x65,0x42,0x53,0x44,0x20,0x4c,0x6f,0x6f,0x70, + 0x62,0x61,0x63,0x6b,0x20,0x45,0x74,0x68,0x65,0x72,0x6e,0x65, + 0x74,0x00 + }; unsigned equip = 0; int i; *************** *** 1173,1178 **** --- 1185,1197 ---- set_int(0x18, NULL, 0, int_basic, afterint, sizeof afterint); set_int(0x19, NULL, 0, int_reboot, afterint, sizeof afterint); set_int(0x1a, NULL, 0, int_time, afterint, sizeof afterint); + + netretseg=0xf000; + netretoff=pos; + set_int(0x60, NULL, 0, nethandler_ret, pktdrvret, sizeof pktdrvret); + set_int(0x60, pktdrvcode, sizeof pktdrvcode, int_pktdrv, + afterint, sizeof afterint); + set_int(0x61, NULL, 0, nethandler_call, NULL, 0); set_int(0xe6, NULL, 0, int_e6, afterint, sizeof afterint); set_int(0xe7, inte7code, sizeof inte7code, NULL, NULL, 0); *** hardware.c Wed Jun 22 20:24:50 1994 --- hardware.c Tue Oct 22 14:03:50 1996 *************** *** 23,28 **** --- 23,29 ---- #include "hardware.h" #include "cpu.h" #include "vgahard.h" + #include "network.h" #ifdef DEBUGGER # include "debugger.h" *************** *** 81,86 **** --- 82,99 ---- int_blocked = 9; } } + else if (network_pending) + { + PIC_inservice = PIC_NETWORK; + network_pending=0; + if (IF) + int_pending = 0x61; + else + { + D2(printf("INTR blocked: IF disabled\n");); + int_blocked = 0x61; + } + } } *************** *** 209,214 **** --- 222,230 ---- PIC_flagint(PIC_TIMER); int8_counter = TIMER_MULT; } + + if(hasnet) + nethandler(); PIC_interrupt(); *** main.c Tue Oct 22 16:26:55 1996 --- main.c Sun Oct 20 20:14:40 1996 *************** *** 27,32 **** --- 27,33 ---- #include "xstuff.h" #include "hardware.h" #include "vgahard.h" + #include "network.h" BYTE *memory; char *progname; *************** *** 112,120 **** void main(int argc, char **argv) { progname = (progname = strrchr(argv[0],'/')) ? progname : argv[0]; ! #ifndef BOOT FILE *f1; if (argc != 2) { --- 113,136 ---- void main(int argc, char **argv) { + int opt; + progname = (progname = strrchr(argv[0],'/')) ? progname : argv[0]; ! #ifdef BOOT ! while(( opt=getopt(argc,argv,"n:") )!=EOF) { ! switch(opt) { ! case 'n': ! netinit(optarg); ! break; ! default: ! fprintf(stderr,"Usage:\n %s [-n network-file]\n",progname); ! exit(1); ! } ! } ! argc-=optind; ! argv+=optind; ! #else FILE *f1; if (argc != 2) { *** hardware.h Wed Jun 22 20:24:50 1994 --- hardware.h Tue Oct 22 14:01:01 1996 *************** *** 19,24 **** --- 19,25 ---- #define PIC_TIMER 1 #define PIC_KEYBOARD 2 + #define PIC_NETWORK 4 #define TICKSPERSEC (1193180.0/65536.0)