From 5134ac931af08fbbc84b8887c417e1178402585a Mon Sep 17 00:00:00 2001 From: Adam Sampson Date: Wed, 8 Aug 2018 22:45:04 +0100 Subject: [PATCH] WIP: ARP + TX implemented --- conf/network | 6 +- src/system/deuna.defs1 | 104 +++++++------- src/system/ether.1 | 317 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 354 insertions(+), 73 deletions(-) diff --git a/conf/network b/conf/network index e2f5e182..7311e0de 100644 --- a/conf/network +++ b/conf/network @@ -1,9 +1,9 @@ # Network configuration for ITS. Note: for now, the two-letter ITS # name is hardcoded to DB, which is short for DistriBution. HOSTNAME=DB-ITS.EXAMPLE.COM -IP=192.168.1.100 -GW=192.168.0.45 -NETMASK=255,255,255,248 +IP=10.0.2.15 +GW=10.0.2.2 +NETMASK=255,255,255,0 CHAOS=no #Or octal Chaosnet address CHAFRIENDS=chip=3150/no.nocrew.org \ chip=3143/up.update.uu.se \ diff --git a/src/system/deuna.defs1 b/src/system/deuna.defs1 index 98d1df11..cd4fc419 100644 --- a/src/system/deuna.defs1 +++ b/src/system/deuna.defs1 @@ -43,31 +43,30 @@ DEFSYM %UNVEC==120 ;Interrupt vector DEFSYM %UNBAS==3,,774510 ;Base of Unibus register address space DEFSYM %UNR0==%UNBAS ;PCSR0 -.BEGIN %UN0 -;FIXME stop using DEFSYM -DEFSYM SERI==1_15. ;status error -DEFSYM PCEI==1_14. ;port command error -DEFSYM RXI==1_13. ;receive interrupt -DEFSYM TXI==1_12. ;transmit interrupt -DEFSYM DNI==1_11. ;done interrupt -DEFSYM RCBI==1_10. ;receive buffer unavailable interrupt -DEFSYM FATL==1_9. ;fatal internal error -DEFSYM USCI==1_8. ;unsolicited state change -DEFSYM ALLINT== -DEFSYM INTR==1_7. ;or of bits 15-8 -DEFSYM INTE==1_6. ;interrupt enable -DEFSYM RSET==1_5. ;reset +.BEGIN %UN0 ;Bits in PCSR0 + SERI==1_15. ;status error + PCEI==1_14. ;port command error + RXI==1_13. ;receive interrupt + TXI==1_12. ;transmit interrupt + DNI==1_11. ;done interrupt + RCBI==1_10. ;receive buffer unavailable interrupt + FATL==1_9. ;fatal internal error + USCI==1_8. ;unsolicited state change + ALLINT== + INTR==1_7. ;or of bits 15-8 + INTE==1_6. ;interrupt enable + RSET==1_5. ;reset .END %UN0 -.BEGIN %UNCMD -DEFSYM NOP==0 -DEFSYM GETPCB==1 -DEFSYM GETCMD==2 -DEFSYM SLFTST==3 -DEFSYM START==4 -DEFSYM BOOT==5 -DEFSYM PDMD==10 ;polling demand -DEFSYM HALT==16 -DEFSYM STOP==17 +.BEGIN %UNCMD ;Command field in PCSR0 + NOP==0 + GETPCB==1 + GETCMD==2 + SLFTST==3 + START==4 + BOOT==5 + PDMD==10 ;polling demand + HALT==16 + STOP==17 .END %UNCMD DEFSYM %UNR1==%UNBAS+2 ;PCSR1 @@ -76,33 +75,36 @@ DEFSYM %UNR2==%UNBAS+4 ;PCSR2 DEFSYM %UNR3==%UNBAS+6 ;PCSR3 -.BEGIN %UNAF ;ancillary function codes in PCB -DEFSYM NOP==0 -DEFSYM START==1 ;start microcode at -DEFSYM RDDPA==2 ;read default physical address -DEFSYM RDPA==4 ;read physical address -DEFSYM WRPA==5 ;write " -DEFSYM RDMAL==6 ;read multicast address list -DEFSYM WRMAL==7 ;write " -DEFSYM RDDRF==10 ;read descriptor ring format -DEFSYM WRDRF==11 ;write " -DEFSYM RDCTRS==12 ;read counters -DEFSYM RCCTRS==13 ;read and clear counters -DEFSYM RDMODE==14 ;read mode register -DEFSYM WRMODE==15 ;write " -DEFSYM RDSTAT==16 ;read status -DEFSYM RCSTAT==17 ;read and clear status -DEFSYM RDMEM==20 ;read internal memory -DEFSYM WRMEM==21 ;write " -DEFSYM RDSID==22 ;read system ID parameters -DEFSYM WRSID==23 ;write " -DEFSYM RDLSA==24 ;read load server address -DEFSYM WRLSA==25 ;write " +.BEGIN %UNAF ;Ancillary function codes in PCB + NOP==0 + START==1 ;start microcode at + RDDPA==2 ;read default physical address + RDPA==4 ;read physical address + WRPA==5 ;write " + RDMAL==6 ;read multicast address list + WRMAL==7 ;write " + RDDRF==10 ;read descriptor ring format + WRDRF==11 ;write " + RDCTRS==12 ;read counters + RCCTRS==13 ;read and clear counters + RDMODE==14 ;read mode register + WRMODE==15 ;write " + RDSTAT==16 ;read status + RCSTAT==17 ;read and clear status + RDMEM==20 ;read internal memory + WRMEM==21 ;write " + RDSID==22 ;read system ID parameters + WRSID==23 ;write " + RDLSA==24 ;read load server address + WRLSA==25 ;write " .END %UNAF -.BEGIN %UNTD ;bits in transmit/receive descriptors -DEFSYM OWN==<1_15.> -DEFSYM ERRS==<1_14.> +.BEGIN %UNTD ;Bits in transmit/receive descriptors + OWN==<1_15.> + ERRS==<1_14.> + OFLO==<1_13.> + STF==<1_9.> + ENF==<1_8.> .END %UNTD ;Layout of memory shared with DEUNA. @@ -129,7 +131,7 @@ IFG %UNRDR+<%UNNRB*8>-<1000*4>, .ERR DEUNA first half-page full ;buffers. DEFSYM %UNNPG==1+<%UNNTB/2>+<%UNNRB/2> DEFSYM %UNBSZ==2048. -DEFSYM %UNBOF==2 ;Padding at start, so the packet - ;data starts on a PDP-10 word +DEFSYM %UNBOF==2 ;Padding at start, so the packet + ;data starts on a PDP-10 word IFN $$TEMP,EXPUNG DEFSYM diff --git a/src/system/ether.1 b/src/system/ether.1 index 0475565f..a628c8ec 100644 --- a/src/system/ether.1 +++ b/src/system/ether.1 @@ -15,8 +15,226 @@ ;;; You should have received a copy of the GNU General Public License ;;; along with this program. If not, see . +;;; Generic Ethernet support + +%NE32==37777777777 +%NE16==177777 +%NE8==377 + +.BEGIN %NEH ;Fields in the Ethernet header + LENGTH==<2+6+6+2> + WORDS== + + PAD==<.BP <%NE16_20.>,0> +;FIXME Would all the MAC stuff be easier if this was 3 16-bit fields? + DMAC0==<.BP <%NE16_4>,0> + DMAC12==<.BP <%NE32_4>,1> + SMAC01==<.BP <%NE32_4>,2> + SMAC2==<.BP <%NE16_20.>,3> + TYPE==<.BP <%NE16_4>,3> ;see %NETYP +.END %NEH + +.BEGIN %NETYP ;Ethernet frame types + IP==4000 + ARP==4006 +.END %NETYP + +.BEGIN %NEAH ;Fields in an Ethernet+IPv4 ARP packet + LENGTH==<2+2+1+1+2+6+4+6+4> ;should be this long + WORDS==</4> + + HRD==<.BP <%NE16_20.>,0> ;see %NEAHR + PRO==<.BP <%NE16_4>,0> ;see %NETYP + HLN==<.BP <%NE8_28.>,1> ;must be 6 for Ethernet MAC + PLN==<.BP <%NE8_20.>,1> ;must be 4 for IPv4 address + OP==<.BP <%NE16_4>,1> ;see %NEAOP + SHA01==<.BP <%NE32_4>,2> + SHA2==<.BP <%NE16_20.>,3> + SPA0==<.BP <%NE16_4>,3> ;SPA split across words + SPA1==<.BP <%NE16_20.>,4> + THA0==<.BP <%NE16_4>,4> + THA12==<.BP <%NE32_4>,5> + TPA==<.BP <%NE32_4>,6> +.END %NEAH + +.BEGIN %NEAHR ;ARP hardware type + ETHER==1 +.END %NEAHR + +.BEGIN %NEAOP ;ARP operation + REQ==1 + REPLY==2 +.END %NEAOP + +%NEATS==64. ;Max number of ARP table entries +.BEGIN %NEAT ;ARP table entry + WORDS==3 + + HA01==<.BP <%NE32>,0> ;MAC address + HA2==<.BP <%NE16>,1> + PA==<.BP <%NE32>,2> ;IPv4 address +.END %NEAT + +EBLK + +ETHME: BLOCK %NEAT"WORDS ;Our MAC address, as ARP table entry + ;(device driver must initialise this) + +ETHHBF: BLOCK %NEH"WORDS ;Ethernet header unpacked +ETHABF: BLOCK %NEAH"WORDS ;ARP packet unpacked + +ETHAT: BLOCK <%NEATS*%NEAT"WORDS> ;ARP table +ETHATS: 0 ;Number of entries in ARP table + +BBLK + +;Process a received packet. +;R is buffer. Length in bytes is I. May clobber A-I, R. +; +ETHRX: MOVEI TT,ETHHBF ;Unpack Ethernet header into ETHHBF + HRL TT,R + BLTUB TT, + SUBI I,%NEH"LENGTH ;I now contains data length + ADDI R,%NEH"WORDS ;R points to data + + LDB A,[%NEH"TYPE+ETHHBF] + BUG INFO,[etype=],OCT,A + CAIN A,%NETYP"IP + JRST ETHRXI + CAIN A,%NETYP"ARP + JRST ETHRXA + BUG INFO,[Unknown Ethernet type],OCT,A + POPJ P, + +;Process an ARP packet. +; +ETHRXA: CAIN I,%NEAH"LENGTH ;Check size first + JRST ETHRAS + + MOVEI TT,ETHABF ;Unpack packet into ETHABF + HRL TT,R + BLTUB TT, + + LDB A,[%NEAH"HRD+ETHABF] + LDB B,[%NEAH"HLN+ETHABF] + HRL B,A + CAME B,[%NEAHR"ETHER,,6] + JRST ETHRAH + + LDB A,[%NEAH"PRO+ETHABF] + LDB B,[%NEAH"PLN+ETHABF] + HRL B,A + CAME B,[%NETYP"IP,,4] + JRST ETHRAP + + LDB A,[%NEAH"SPA0+ETHABF] ;Get source IP address + LSH A,16. + LDB B,[%NEAH"SPA1+ETHABF] + IOR A,B + BUG INFO,[ARP source addr ],OCT,A + + MOVE E,ETHATS ;Is the IP address in the table already? + SOS E +ETHRX1: JUMPL E,ETHRX2 ;Any more entries to check? + LDB B,[%NEAT"PA+ETHAT(E)] + BUG INFO,[ARP table entry ],OCT,E,[ of ],OCT,ETHATS,[ is ],OCT,B + CAMN A,B ;Match? + JRST ETHRX3 ; Yes - update it + SOJA E,ETHRX1 ;Prev entry + +ETHRX2: MOVE E,ETHATS ;Not found in table - add new entry + CAIL E,%NEATS ;Table full? + JRST [ MOVEI E,1 ; Yes - flush it and start over + MOVEM E,ETHATS ; FIXME remove a random entry instead + SETZM E + JRST ETHRX3] + AOS ETHATS + +ETHRX3: DPB A,[%NEAT"PA+ETHAT(E)] ;Store IP address + LDB C,[%NEAH"SHA01+ETHABF] ;Get sender's MAC + LDB D,[%NEAH"SHA2+ETHABF] + DPB C,[%NEAT"HA01+ETHAT(E)] ;Store MAC + DPB D,[%NEAT"HA2+ETHAT(E)] + BUG INFO,[Set ARP table entry ],OCT,E,[ to ip ],OCT,A,[ mac ],OCT,C,[ ],OCT,D + + LDB E,[%NEAH"OP+ETHABF] ;Get op + BUG INFO,[ARP op ],OCT,E + CAIE E,%NEAOP"REQ ;Is this a request? + POPJ P, ;No - nothing more to do + + LDB B,[%NEAH"TPA+ETHABF] ;Get the target PA + CAME B,[ETHUS] ;Is it our address? + POPJ P, ;No - nothing more to do + + BUG INFO,[ARP reply] + MOVEI E,%NEAOP"REPLY ;Construct reply packet + DPB E,[%NEAH"OP+ETHABF] + DPB A,[%NEAH"TPA+ETHABF] ;Set sender PA as target PA + DPB B,[%NEAH"SPA1+ETHABF] ;Set our PA as source PA + LSH B,-16. + DPB B,[%NEAH"SPA0+ETHABF] + MOVE E,C ;Reshuffle sender's MAC from 01/2 to 0/12 form + LSH C,-16. + LSH E,16. + IOR D,E + DPB C,[%NEAH"THA0+ETHABF] ;Set as target HA + DPB D,[%NEAH"THA12+ETHABF] + DPB C,[%NEH"DMAC0+ETHHBF] ;Set as destination MAC in header + DPB D,[%NEH"DMAC12+ETHHBF] + LDB C,[%NEAT"HA01+ETHME] ;Get our HA + LDB D,[%NEAT"HA2+ETHME] + DPB C,[%NEAH"SHA01+ETHABF] ;Set as source HA + DPB D,[%NEAH"SHA2+ETHABF] + + MOVEI R,ETHABF ;Send it! + MOVEI I,%NEAH"LENGTH + JRST ETHTX + +ETHRAS: BUG INFO,[ARP wrong size packet ],OCT,I + POPJ P, +ETHRAH: BUG INFO,[ARP wrong hardware type ],OCT,B + POPJ P, +ETHRAP: BUG INFO,[ARP wrong protocol ],OCT,B + POPJ P, + +;Process an IPv4 packet. +; +ETHRXI: + BUG INFO,[IP] + POPJ P, + +;Send an Ethernet packet (if possible). +;Unpacked header is in ETHHBF. R contains pointer to unpacked data. +;I contains data length in bytes. +; +;FIXME IFN UNAP,... +ETHTX: BUG INFO,[ethtx ptr ],OCT,R,[ len ],OCT,I + PUSHJ P,UNAFF ;Find a free transmit buffer + POPJ P, ;None left. Give up. + BUG INFO,[ethtx buf ],OCT,B,[ desc ],OCT,D,[ len ],OCT,I + + MOVE TT,B ;Convert header + HRLI TT,ETHHBF + BLTBU TT,<%NEH"WORDS-1>(B) + + ADDI B,%NEH"WORDS ;Convert data + MOVE TT,B + HRL TT,R + MOVE A,I + ADDI A,3 + IDIVI A,4 + ADD A,B + MOVE C,TT + BUG INFO,[ethtx bltbu tt ],OCT,C,[ a ],OCT,A + BLTBU TT,(A) + + ADDI I,%NEH"LENGTH ;Add length of header + BUG INFO,[ethtx end buf ],OCT,B,[ desc ],OCT,D,[ len ],OCT,I + JRST UNATX ;Transmit it + ;Check whether the interface is able to send a packet. ;Skip-return if it is. +; ETHCTS: ;FIXME check if we have an ARP entry, and if not, send a request AOS (P) @@ -36,6 +254,7 @@ EBLK ;that allocated and mapped a page, returning the PDP-10 ;address and the two Unibus addresses. We could then ;allocate on the fly while setting up the rings. +;FIXME The setup stuff might also be cleaner with byte ptrs as above. UNPAGS: BLOCK %UNNPG ;PDP-10 pages: 0,,addr UNPAGU: BLOCK %UNNPG ;Unibus pages: first-addr,,second-addr @@ -129,15 +348,26 @@ UNAIN1: PUSHJ P,TCALL ;Allocate a page of unshuffleable low core MOVEI A,%UN0"DNI+%UNCMD"GETPCB ;Ack DNI as it's on after reset PUSHJ P,UNACMD ;We've really returned to the caller here -IFN 1,[ - ;Read, and display, the MAC address + ;Get the MAC address for ARP to use MOVE A,UNPAGS MOVSI TT,%UNAF"RDDPA MOVEM TT,0(A) MOVEI A,%UNCMD"GETCMD PUSHJ P,UNACMD PUSHJ P,UNDPCB ;Show results -] + MOVEI TT,ETHHBF ;Unpack MAC address into ETHHBF + HRL TT,UNPAGS + BLTUB TT,ETHHBF+1 + MOVE TT,[.BP <%NE16_4.>,ETHHBF] + LDB A,TT + LSH A,16. + ILDB B,TT + IOR A,B + BUG INFO,[my MAC 01 =],OCT,A + DPB A,[%NEAT"HA01+ETHME] + ILDB A,TT + BUG INFO,[my MAC 2 =],OCT,A + DPB A,[%NEAT"HA2+ETHME] ;Set up transmit and receive rings MOVE D,UNPAGS ;Point to TDR (RDR follows) @@ -151,7 +381,7 @@ UNAIN2: MOVE TT,C ;Work out index into UNPAGS/UNPAGU HLRZ B,UNPAGU(TT) ;Get Unibus addr. Even on the left... TRNE C,1 HRRZ B,UNPAGU(TT) ;... and odd on the right - ADDI B,%UNBOF ;Add padding at start + ADDI B,%UNBOF ;Add word-aligning padding at start ;FIXME This bit for now, until I rewrite this whole section.. HRLM D,UNTXRP(C) ;Descriptor pointer @@ -257,7 +487,7 @@ UNABRK: 0 JSR UTCSAV IORDI H,%UNR0 ;Read status - BUG INFO,[DEUNA interrupt, PCSR0=],OCT,H,[ UNADNI=],OCT,UNADNI + ;BUG INFO,[DEUNA interrupt, PCSR0=],OCT,H,[ UNADNI=],OCT,UNADNI TRNE H,%UN0"SERI+%UN0"PCEI+%UN0"FATL+%UN0"USCI BUG HALT,[DEUNA error, PCSR0=],OCT,H ;FIXME do something better! @@ -287,44 +517,93 @@ UNABRK: 0 ; UNARX: MOVSI W,<-%UNNRB> ;W = -Number to check,,buffer index HRR W,UNRXRI - SETOM UNRXRI ;Haven't found an empty slot yet + SETOM UNRXRI ;Haven't found an empty buffer yet UNARX1: HRRZ A,W ;Wrap index around CAIL A,%UNNRB HLLZS W HLRZ J,UNRXRP(W) ;Descriptor - HRRZ R,UNRXRP(W) ;Buffer - MOVE Q,1(J) ;Is there a packet in this slot? (OWN=0) - BUG INFO,[check rx slot],OCT,W,[desc],OCT,J,[buf],OCT,R,[flags],OCT,Q + MOVE Q,1(J) ;Is there a packet in this buffer? (OWN=0) TLNE Q,%UNTD"OWN - JRST [ SKIPGE UNRXRI ;No. First empty slot we've found? + JRST [ SKIPGE UNRXRI ;No. First empty buffer we've found? HRRZM W,UNRXRI ; Yes, start here next time JRST UNARX2] - MOVE A,0(R) - MOVE B,1(R) - MOVE C,2(R) - BUG INFO,[got packet],OCT,W,[data],OCT,A,[ ],OCT,B,[ ],OCT,C + TLNE Q,%UNTD"STF ;STF+ENF should always be true, but check... + TLNN Q,%UNTD"ENF + JRST UNARSF - ;FIXME process + TLNE Q,%UNTD"ERRS+%UNTD"OFLO + JRST UNARER - TLO Q,%UNTD"OWN ;Set OWN=1 to mark as free + HRRZ R,UNRXRP(W) ;Buffer + LDB I,[.BP 7777,1(J)] ;Get MLEN + PUSHJ P,ETHRX + +UNARX3: TLO Q,%UNTD"OWN ;Set OWN=1 to mark as free MOVEM Q,1(J) SKIPE UNARCB ;Have we had an RCB interrupt? - JRST [ SETZM UNARCB ;Yes. Tell the DEUNA there's a free slot now. + JRST [ SETZM UNARCB ;Yes. Tell the DEUNA there's a free buffer now. MOVEI A,%UN0"INTE+%UNCMD"PDMD IOWRI A,%UNR0 JRST UNARX2] -UNARX2: AOBJN W,UNARX1 ;Repeat if we haven't looked at all slots - SKIPGE UNRXRI ;Repeat if we haven't found a free slot +UNARX2: AOBJN W,UNARX1 ;Repeat if we haven't looked at all buffers + SKIPGE UNRXRI ;Repeat if we haven't found a free buffer JRST UNARX1 ; FIXME: Or maybe HRRZM W,UNRXRI ? POPJ P, +;These are only here because you can't use BUG inside []... +UNARSF: BUG INFO,[DEUNA split frame ],OCT,Q + JRST UNARX3 +UNARER: BUG INFO,[DEUNA frame with errors ],OCT,Q + JRST UNARX3 + +;Find an empty buffer in the transmit ring. +;On success, skip return with descriptor in D, buffer in B. +;On failure (the ring is full), normal return. +;Clobbers A-TT. +; +UNAFF: MOVSI E,<-%UNNTB> ;E = -Number to check,,buffer index + HRR E,UNTXRI + +UNAFF1: HRRZ A,E ;Wrap index around + CAIL A,%UNNTB + HLLZS E + + HLRZ D,UNTXRP(E) ;Descriptor + MOVE A,1(D) ;Is this buffer free? (OWN=0) + BUG INFO,[unaff checking slot ],OCT,E,[ status ],OCT,A + TLNE A,%UNTD"OWN + JRST [ AOBJN E,UNAFF1 ;Try the next one + POPJ P,] ;No buffers free. + + HRRZM E,UNTXRI ;Yes. Start at this buffer + 1 next time. + AOS UNTXRI ; (Doesn't matter if it wraps.) + + HRRZ B,UNTXRP(E) ;Buffer + BUG INFO,[unaff found free buffer ],OCT,E,[ desc ],OCT,D,[ buff ],OCT,B + AOS (P) ;Skip return + POPJ P, + +;Transmit a packet from a buffer obtained by UNAFF. +;Descriptor in D, buffer in B, data length in bytes in I. +;Clobbers A. +; +UNATX: BUG INFO,[unatx desc ],OCT,D,[ buff ],OCT,B,[ length ],OCT,I + HRLM I,0(D) ;Set SLEN + MOVSI A,%UNTD"OWN+%UNTD"STF+%UNTD"ENF + IORM A,1(D) ;Set flags + + MOVEI A,%UN0"INTE+%UNCMD"PDMD ;Tell the DEUNA to check the ring + IOWRI A,%UNR0 + + POPJ P, + ;FIXME ;Stylewise, trying to match IMP... ;See: