From 47455df0da196dc5424988603baed6d2b39e724e Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 27 Mar 1997 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1997-03-27 --- boot/aux.c | 40 +- boot/boot.c | 23 +- boot/boot.h | 36 +- boot/doauthenticate.c | 2 +- carrera/clock.c | 45 +- carrera/devether.c | 94 +- carrera/devrtc.c | 101 +-- carrera/fns.h | 62 +- carrera/kbd.c | 2 + carrera/l.s | 90 +- carrera/main.c | 4 +- carrera/screen.c | 2 +- carrera/screen.h | 6 +- carrera/trap.c | 6 +- ip/devip.c | 940 ++++++++++++++++++++ ip/dial.c | 136 +++ ip/gre.c | 237 +++++ ip/icmp.c | 267 ++++++ ip/il.c | 1032 ++++++++++++++++++++++ ip/ip.c | 555 ++++++++++++ ip/ip.h | 248 ++++++ ip/ipaux.c | 247 ++++++ ip/kernel.h | 15 + ip/kio.c | 198 +++++ ip/netlog.c | 232 +++++ ip/tcp.c | 1937 +++++++++++++++++++++++++++++++++++++++++ ip/udp.c | 313 +++++++ pc/apbootstrap.s | 113 +++ pc/apic.c | 323 +++++++ pc/archgeneric.c | 162 +++- pc/archmp.c | 94 ++ pc/archncr3170.c | 49 -- pc/archnsx20.c | 188 ---- pc/audio.h | 3 + pc/cga.c | 260 ++---- pc/clock.c | 271 ++---- pc/dat.h | 153 ++-- pc/devastar.c | 85 +- pc/devata.c | 160 ++-- pc/devether.c | 405 ++++++--- pc/devfloppy.c | 423 +++------ pc/devi82365.c | 88 +- pc/devlpt.c | 94 +- pc/devrtc.c | 133 ++- pc/devvga.c | 282 ++---- pc/dma.c | 13 + pc/ether2000.c | 44 +- pc/ether4100.c | 100 --- pc/ether79c970.c | 603 +++++++------ pc/ether8003.c | 77 +- pc/ether82557.c | 469 +++++----- pc/ether8390.c | 694 ++++++++------- pc/ether8390.h | 71 ++ pc/etherelnk3.c | 283 +++--- pc/etherif.h | 38 +- pc/fault386.c | 45 - pc/floppy.h | 179 ++++ pc/fns.h | 111 +-- pc/i8253.c | 100 +++ pc/i8259.c | 149 ++++ pc/io.h | 195 +++-- pc/kbd.c | 436 +++------- pc/l.s | 1331 ++++++++++++++-------------- pc/main.c | 519 ++++------- pc/mem.h | 23 +- pc/memory.c | 480 ++++++++++ pc/mmu.c | 558 ++++-------- pc/mouse.c | 145 +++ pc/mp.c | 620 +++++++++++++ pc/mp.h | 226 +++++ pc/ns16552.h | 35 +- pc/pci.c | 489 ++++++++--- pc/screen.h | 23 +- pc/scsi.c | 9 +- pc/trap.c | 612 +++++-------- pc/u.h | 4 +- pc/vgaark2000pv.c | 22 +- pc/vgaclgd542x.c | 4 + pc/vgaet4000.c | 41 +- pc/vgamach32.c | 5 + pc/vgas3.c | 40 +- port/alarm.c | 2 +- port/auth.c | 10 +- port/cache.c | 2 + port/chan.c | 73 +- port/dev.c | 45 +- port/devXXX.c | 92 +- port/devaudio.c | 118 +-- port/devboot.c | 142 --- port/devcons.c | 230 ++--- port/devdup.c | 82 +- port/devenv.c | 74 +- port/devkprof.c | 125 ++- port/devlance.c | 95 +- port/devmnt.c | 105 +-- port/devmouse.c | 76 +- port/devns16552.c | 87 +- port/devpipe.c | 71 +- port/devproc.c | 80 +- port/devroot.c | 75 +- port/devsd.c | 79 +- port/devsrv.c | 71 +- port/devssl.c | 111 +-- port/devtinyfs.c | 86 +- port/fault.c | 26 +- port/netif.c | 24 +- port/netif.h | 11 +- port/pgrp.c | 6 +- port/portdat.h | 24 +- port/portfns.h | 52 +- port/proc.c | 17 +- port/qio.c | 563 +++++++++--- port/segment.c | 2 +- port/swap.c | 4 +- port/sysfile.c | 131 +-- port/sysproc.c | 8 +- port/taslock.c | 6 +- power/clock.c | 112 --- power/dat.h | 191 ---- power/devduart.c | 715 --------------- power/devrtc.c | 501 ----------- power/faultmips.c | 53 -- power/fns.h | 87 -- power/fptrap.c | 283 ------ power/io.h | 148 ---- power/l.s | 792 ----------------- power/lock.c | 165 ---- power/main.c | 730 ---------------- power/mem.h | 160 ---- power/mmu.c | 154 ---- power/segment.h | 16 - power/trap.c | 715 --------------- power/u.h | 25 - 133 files changed, 14674 insertions(+), 11927 deletions(-) create mode 100644 ip/devip.c create mode 100644 ip/dial.c create mode 100644 ip/gre.c create mode 100644 ip/icmp.c create mode 100644 ip/il.c create mode 100644 ip/ip.c create mode 100644 ip/ip.h create mode 100644 ip/ipaux.c create mode 100644 ip/kernel.h create mode 100644 ip/kio.c create mode 100644 ip/netlog.c create mode 100644 ip/tcp.c create mode 100644 ip/udp.c create mode 100644 pc/apbootstrap.s create mode 100644 pc/apic.c create mode 100644 pc/archmp.c delete mode 100644 pc/archncr3170.c delete mode 100644 pc/archnsx20.c delete mode 100644 pc/ether4100.c create mode 100644 pc/ether8390.h delete mode 100644 pc/fault386.c create mode 100644 pc/floppy.h create mode 100644 pc/i8253.c create mode 100644 pc/i8259.c create mode 100644 pc/memory.c create mode 100644 pc/mouse.c create mode 100644 pc/mp.c create mode 100644 pc/mp.h delete mode 100644 port/devboot.c delete mode 100644 power/clock.c delete mode 100644 power/dat.h delete mode 100644 power/devduart.c delete mode 100644 power/devrtc.c delete mode 100644 power/faultmips.c delete mode 100644 power/fns.h delete mode 100644 power/fptrap.c delete mode 100644 power/io.h delete mode 100644 power/l.s delete mode 100644 power/lock.c delete mode 100644 power/main.c delete mode 100644 power/mem.h delete mode 100644 power/mmu.c delete mode 100644 power/segment.h delete mode 100644 power/trap.c delete mode 100644 power/u.h diff --git a/boot/aux.c b/boot/aux.c index f69694acec067e6814254c015625c07ce5a4e464..75a8b48c7c85f5ea54ce89a9e438d6807ab5b3e9 100644 --- a/boot/aux.c +++ b/boot/aux.c @@ -172,31 +172,19 @@ outin(char *prompt, char *def, int len) return n; } -/* - * get second word of the terminal environment variable. If it - * ends in "boot", get rid of that part. - */ -void -getconffile(char *conffile, char *terminal) +int +parsefields(char *lp, char **fields, int n, char *sep) { - char *p, *q; - char *s; - int n; - - s = conffile; - *conffile = 0; - p = terminal; - if((p = strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) - return; - p++; - for(q = p; *q && *q != ' '; q++) - ; - while(p < q) - *conffile++ = *p++; - *conffile = 0; - - /* dump a trailing boot */ - n = strlen(s); - if(n > 4 && strcmp(s + n - 4, "boot") == 0) - *(s+n-4) = 0; + int i; + + for(i=0; lp && *lp && i #include "../boot/boot.h" -typedef struct Net Net; -typedef struct Flavor Flavor; - char cputype[NAMELEN]; -char terminal[NAMELEN]; char sys[2*NAMELEN]; char username[NAMELEN]; -char bootfile[3*NAMELEN]; -char conffile[NAMELEN]; char reply[256]; int printcol; int mflag; int fflag; int kflag; -int aflag; char *bargv[Nbarg]; int bargc; @@ -67,9 +60,6 @@ boot(int argc, char *argv[]) #endif DEBUG ARGBEGIN{ - case 'a': - aflag = 1; - break; case 'u': strcpy(username, ARGF()); break; @@ -85,8 +75,6 @@ boot(int argc, char *argv[]) }ARGEND readfile("#e/cputype", cputype, sizeof(cputype)); - readfile("#e/terminal", terminal, sizeof(cputype)); - getconffile(conffile, terminal); /* * pick a method and initialize it @@ -155,7 +143,7 @@ boot(int argc, char *argv[]) swapproc(); sprint(cmd, "/%s/init", cputype); - sprint(flags, "-%s%s%s", cpuflag ? "c" : "t", mflag ? "m" : "", aflag ? "a" : ""); + sprint(flags, "-%s%s", cpuflag ? "c" : "t", mflag ? "m" : ""); execl(cmd, "init", flags, 0); fatal(cmd); } @@ -218,14 +206,7 @@ rootserver(char *arg) outin(prompt, reply, sizeof(reply)); mp = findmethod(reply); if(mp){ - for(cp = reply; bargc < Nbarg-1 && *cp;){ - while(*cp && *cp != ' ') - cp++; - while(*cp == ' ') - *cp++ = 0; - if(*cp) - bargv[bargc++] = cp++; - } + bargc = parsefields(reply, bargv, Nbarg-1, " "); cp = strchr(reply, '!'); if(cp) strcpy(sys, cp+1); diff --git a/boot/boot.h b/boot/boot.h index 54ccc80f5110aa4e24fd127487ff6567136bd69c..decf26b32fc3017f13c6be86277876a534b6f26c 100644 --- a/boot/boot.h +++ b/boot/boot.h @@ -18,10 +18,7 @@ extern Method method[]; extern void (*pword)(int, Method*); extern char sys[]; extern uchar hostkey[]; -extern char terminal[]; extern char username[NAMELEN]; -extern char bootfile[]; -extern char conffile[]; enum { Nbarg= 16, @@ -32,13 +29,9 @@ extern char *bargv[Nbarg]; /* libc equivalent */ extern int cache(int); extern char* checkkey(Method*, char*, char*); -extern int dkauth(void); -extern int dkconnect(void); extern void fatal(char*); -extern void getconffile(char*, char*); extern void getpasswd(char*, int); extern void key(int, Method*); -extern void newkernel(void); extern int nop(int); extern int outin(char*, char*, int); extern int plumb(char*, char*, int*, char*); @@ -52,43 +45,16 @@ extern void userpasswd(int, Method*); extern void warning(char*); extern int writefile(char*, char*, int); extern void boot(int, char **); -extern void bboot(int, char **); extern void doauthenticate(int, Method*); +extern int parsefields(char*, char**, int, char*); /* methods */ -extern void configppp(Method*); -extern int authppp(void); -extern int connectppp(void); -extern void config9600(Method*); -extern int auth9600(void); -extern int connect9600(void); -extern void config19200(Method*); -extern int auth19200(void); -extern int connect19200(void); -extern void confighs(Method*); -extern int authhs(void); -extern int connecths(void); -extern void configincon(Method*); -extern int authincon(void); -extern int connectincon(void); -extern void configcincon(Method*); -extern int authcincon(void); -extern int connectcincon(void); extern void configil(Method*); extern int authil(void); extern int connectil(void); extern void configtcp(Method*); extern int authtcp(void); extern int connecttcp(void); -extern void configcyc(Method*); -extern int authcyc(void); -extern int connectcyc(void); extern void configlocal(Method*); extern int authlocal(void); extern int connectlocal(void); -extern void configbri(Method*); -extern int authbri(void); -extern int connectbri(void); -extern void confighybrid(Method*); -extern int authhybrid(void); -extern int connecthybrid(void); diff --git a/boot/doauthenticate.c b/boot/doauthenticate.c index 5c41444b25f0f36ba1dfa9b4fe3c38d26820d8ed..00984172c97404ae9511a80072ab622e27808f5c 100644 --- a/boot/doauthenticate.c +++ b/boot/doauthenticate.c @@ -1,7 +1,7 @@ #include #include #include -#include <../boot/boot.h> +#include "../boot/boot.h" static char *pbmsg = "AS protocol botch"; static char *ccmsg = "can't connect to AS"; diff --git a/carrera/clock.c b/carrera/clock.c index eca2692b58fa8e383fbd0d815b369971b05adbaa..888343bfde773f7784dbbc8359979bf20e1ae161 100644 --- a/carrera/clock.c +++ b/carrera/clock.c @@ -7,6 +7,33 @@ #include "ureg.h" +void (*kproftimer)(ulong); + +typedef struct Clock0link Clock0link; +typedef struct Clock0link { + void (*clock)(void); + Clock0link* link; +} Clock0link; + +static Clock0link *clock0link; +static Lock clock0lock; + +void +addclock0link(void (*clock)(void)) +{ + Clock0link *lp; + + if((lp = malloc(sizeof(Clock0link))) == 0){ + print("addclock0link: too many links\n"); + return; + } + ilock(&clock0lock); + lp->clock = clock; + lp->link = clock0link; + clock0link = lp; + iunlock(&clock0lock); +} + /* * delay for l milliseconds more or less. delayloop is set by * clockinit() to match the actual CPU speed. @@ -47,6 +74,8 @@ clockinit(void) void clock(Ureg *ur) { + Clock0link *lp; + wrcompare(rdcount()+(m->speed*1000000)/HZ); m->ticks++; @@ -54,10 +83,9 @@ clock(Ureg *ur) m->proc->pc = ur->pc; accounttime(); -/* - ifjab(); -*/ - kproftimer(ur->pc); + + if(kproftimer != nil) + kproftimer(ur->pc); kmapinval(); @@ -70,9 +98,12 @@ clock(Ureg *ur) } checkalarms(); - uartclock(); - mouseclock(); - randomclock(); + if(m->machno == 0){ + lock(&clock0lock); + for(lp = clock0link; lp; lp = lp->link) + lp->clock(); + unlock(&clock0lock); + } if(up == 0 || up->state != Running) return; diff --git a/carrera/devether.c b/carrera/devether.c index 5f5208f9dc06da1009999e252c8b18c056b474ae..405ffacb23990b781b9a85d4f76981dc41c1be08 100644 --- a/carrera/devether.c +++ b/carrera/devether.c @@ -241,14 +241,14 @@ struct Ether Netif; }; -Ether *ether[Nether]; +static Ether *ether[Nether]; #define NEXT(x, l) (((x)+1)%(l)) #define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1) #define LS16(addr) (PADDR(addr) & 0xFFFF) #define MS16(addr) ((PADDR(addr)>>16) & 0xFFFF) -void sonicswap(void*, int); +static void sonicswap(void*, int); static void wus(ushort *a, ushort v) @@ -400,7 +400,7 @@ reset(Ether *ctlr) WR(imr, AllIntr); } -void +static void sonicpkt(Ether *ctlr, RXpkt *r, Pbuf *p) { int len; @@ -606,7 +606,7 @@ initbufs(Ether *c) panic("sonic init"); } -void +static void etherreset(void) { Ether *ctlr; @@ -630,7 +630,7 @@ etherreset(void) memset(ctlr->ba, 0xFF, sizeof(ctlr->ba)); /* general network interface structure */ - netifinit(ether[0], "ether", Ntypes, 32*1024); + netifinit(ether[0], "ether0", Ntypes, 32*1024); ether[0]->alen = 6; memmove(ether[0]->addr, ether[0]->ea, 6); memmove(ether[0]->bcast, ctlr->ba, 6); @@ -638,12 +638,7 @@ etherreset(void) ether[0]->arg = ether[0]; } -void -etherinit(void) -{ -} - -Chan* +static Chan* etherattach(char *spec) { static int enable; @@ -657,31 +652,25 @@ etherattach(char *spec) return devattach('l', spec); } -Chan* -etherclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int etherwalk(Chan *c, char *name) { return netifwalk(ether[0], c, name); } -Chan* +static Chan* etheropen(Chan *c, int omode) { return netifopen(ether[0], c, omode); } -void +static void ethercreate(Chan *c, char *name, int omode, ulong perm) { USED(c, name, omode, perm); } -void +static void etherclose(Chan *c) { netifclose(ether[0], c); @@ -693,12 +682,6 @@ etherread(Chan *c, void *buf, long n, ulong offset) return netifread(ether[0], c, buf, n, offset); } -Block* -etherbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - static int etherloop(Etherpkt *p, long n) { @@ -731,7 +714,7 @@ etherloop(Etherpkt *p, long n) return !different; } -long +static long etherwrite(Chan *c, void *buf, long n, ulong offset) { Pbuf *p; @@ -792,25 +775,19 @@ etherwrite(Chan *c, void *buf, long n, ulong offset) return n; } -long -etherbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void +static void etherremove(Chan *c) { USED(c); } -void +static void etherstat(Chan *c, char *dp) { netifstat(ether[0], c, dp); } -void +static void etherwstat(Chan *c, char *dp) { netifwstat(ether[0], c, dp); @@ -818,7 +795,7 @@ etherwstat(Chan *c, char *dp) #define swiz(s) (s<<24)|((s>>8)&0xff00)|((s<<8)&0xff0000)|(s>>24) -void +static void sonicswap(void *a, int n) { ulong *p, t0, t1; @@ -834,3 +811,44 @@ sonicswap(void *a, int n) n -= 8; } } + +int +parseether(uchar *to, char *from) +{ + char nip[4]; + char *p; + int i; + + p = from; + for(i = 0; i < 6; i++){ + if(*p == 0) + return -1; + nip[0] = *p++; + if(*p == 0) + return -1; + nip[1] = *p++; + nip[2] = 0; + to[i] = strtoul(nip, 0, 16); + if(*p == ':') + p++; + } + return 0; +} + +Dev etherdevtab = { + etherreset, + devinit, + etherattach, + devclone, + etherwalk, + etherstat, + etheropen, + ethercreate, + etherclose, + etherread, + devbread, + etherwrite, + devbwrite, + etherremove, + etherwstat, +}; diff --git a/carrera/devrtc.c b/carrera/devrtc.c index 0fcc1e8d5ff727433f0a173adcf063e4e5f0c819..c3e43047fd35dd291e20480a2cbfec57a4797405 100644 --- a/carrera/devrtc.c +++ b/carrera/devrtc.c @@ -20,7 +20,7 @@ struct Rtc int mon; int year; }; -QLock rtclock; /* mutex on clock operations */ +static QLock rtclock; /* mutex on clock operations */ enum @@ -39,51 +39,33 @@ enum Nvsize = 4096, }; -#define NRTC 2 Dirtab rtcdir[]={ "nvram", {Qnvram, 0}, Nvsize, 0664, "rtc", {Qrtc, 0}, 0, 0664, }; -ulong rtc2sec(Rtc*); -void sec2rtc(ulong, Rtc*); -int *yrsize(int); +static ulong rtc2sec(Rtc*); +static void sec2rtc(ulong, Rtc*); -void -rtcreset(void) -{ -} - -void -rtcinit(void) -{ -} - -Chan* +static Chan* rtcattach(char *spec) { return devattach('r', spec); } -Chan* -rtcclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int rtcwalk(Chan *c, char *name) { - return devwalk(c, name, rtcdir, NRTC, devgen); + return devwalk(c, name, rtcdir, nelem(rtcdir), devgen); } -void +static void rtcstat(Chan *c, char *dp) { - devstat(c, dp, rtcdir, NRTC, devgen); + devstat(c, dp, rtcdir, nelem(rtcdir), devgen); } -Chan* +static Chan* rtcopen(Chan *c, int omode) { omode = openmode(omode); @@ -96,17 +78,10 @@ rtcopen(Chan *c, int omode) if(strcmp(up->user, eve)!=0) error(Eperm); } - return devopen(c, omode, rtcdir, NRTC, devgen); + return devopen(c, omode, rtcdir, nelem(rtcdir), devgen); } -void -rtccreate(Chan *c, char *name, int omode, ulong perm) -{ - USED(c, name, omode, perm); - error(Eperm); -} - -void +static void rtcclose(Chan *c) { USED(c); @@ -151,14 +126,14 @@ rtctime(void) return rtc2sec(&rtc); } -long +static long rtcread(Chan *c, void *buf, long n, ulong offset) { ulong t, ot; uchar *f, *to, *e; if(c->qid.path & CHDIR) - return devdirread(c, buf, n, rtcdir, NRTC, devgen); + return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen); switch(c->qid.path){ case Qrtc: @@ -185,12 +160,6 @@ rtcread(Chan *c, void *buf, long n, ulong offset) return 0; } -Block* -rtcbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - static void binary2bcd(int reg, uchar val) { @@ -201,7 +170,7 @@ binary2bcd(int reg, uchar val) } -long +static long rtcwrite(Chan *c, void *buf, long n, ulong offset) { Rtc rtc; @@ -255,25 +224,23 @@ rtcwrite(Chan *c, void *buf, long n, ulong offset) return 0; } -long -rtcbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -rtcremove(Chan *c) -{ - USED(c); - error(Eperm); -} - -void -rtcwstat(Chan *c, char *dp) -{ - USED(c, dp); - error(Eperm); -} +Dev rtcdevtab = { + devreset, + devinit, + rtcattach, + devclone, + rtcwalk, + rtcstat, + rtcopen, + devcreate, + rtcclose, + rtcread, + devbread, + rtcwrite, + devbwrite, + devremove, + devwstat, +}; #define SEC2MIN 60L #define SEC2HOUR (60L*SEC2MIN) @@ -294,7 +261,7 @@ static int ldmsize[] = /* * return the days/month for the given year */ -int * +static int* yrsize(int yr) { if((yr % 4) == 0) @@ -306,7 +273,7 @@ yrsize(int yr) /* * compute seconds since Jan 1 1970 */ -ulong +static ulong rtc2sec(Rtc *rtc) { ulong secs; @@ -341,7 +308,7 @@ rtc2sec(Rtc *rtc) /* * compute rtc from seconds since Jan 1 1970 */ -void +static void sec2rtc(ulong secs, Rtc *rtc) { int d; diff --git a/carrera/fns.h b/carrera/fns.h index 361e3d233db4ab3e084c71d141d9d76d4088d247..4c0a815db8a4f6d904ad9420a06015efe32c203f 100644 --- a/carrera/fns.h +++ b/carrera/fns.h @@ -1,28 +1,17 @@ #include "../port/portfns.h" -void DEBUG(void); - -void addportintr(int(*)(void)); -void allflush(void*, ulong); +void addclock0link(void (*)(void)); void arginit(void); int busprobe(ulong); void cleancache(void); void clearmmucache(void); void clock(Ureg*); void clockinit(void); -ulong confeval(char*); -void confprint(void); -void confread(void); -void confset(char*); -int conschar(void); -void consoff(void); -int consputc(int); +#define coherence() void dcflush(void*, ulong); void dcinvalidate(void*, ulong); void dmaend(int); long dmasetup(int, void*, long, int); -void epcenable(ulong); -void epcinit(int, int); void evenaddr(ulong); void faultmips(Ureg*, int, int); ulong fcr31(void); @@ -30,16 +19,10 @@ void firmware(int); #define flushpage(s) icflush((void*)(s), BY2PG) void fptrap(Ureg*); ulong getcallerpc(void*); -int getline(char*, int); -void getnveaddr(void*); -int getnvram(ulong, void *, int); ulong getstatus(void); void gettlb(int, ulong*); int gettlbp(ulong, ulong*); ulong gettlbvirt(int); -void gotopc(ulong); -void hinv(void); -void icdirty(void *, ulong); void icflush(void *, ulong); void intr(Ureg*); void ioinit(int); @@ -51,47 +34,26 @@ void kfault(Ureg*); KMap* kmap(Page*); void kmapinit(void); void kmapinval(void); -int kprint(char*, ...); -void kproftimer(ulong); void kunmap(KMap*); -void launchinit(void); -void launch(int); -void lightbits(int, int); -ulong machstatus(void); void mmunewpage(Page*); void mouseintr(void); -void mntdump(void); -void newstart(void); int newtlbpid(Proc*); -void nonettoggle(void); -void novme(int); void ns16552install(void); -void online(void); -Block* prepend(Block*, int); -void prflush(void); -ulong prid(void); -void printinit(void); #define procrestore(p) #define procsave(p) #define procsetup(p) ((p)->fpstate = FPinit) void purgetlb(int); -int putnvram(ulong, void*, int); Softtlb* putstlb(ulong, ulong); int puttlb(ulong, ulong, ulong); void puttlbx(int, ulong, ulong, ulong, int); -void* pxalloc(ulong); -void* pxspanalloc(ulong, int, ulong); void rdbginit(void); ulong rdcount(void); -int readlog(ulong, char*, ulong); ulong* reg(Ureg*, int); void restfpregs(FPsave*, ulong); void screeninit(void); void screenputs(char*, int); void seteisadma(int, void(*)(void)); long syscall(Ureg*); -void syslog(char*, int); -void sysloginit(void); int tas(ulong*); void tlbinit(void); ulong tlbvirt(void); @@ -102,11 +64,8 @@ void vector100(void); void vector180(void); void vmereset(void); void uartclock(void); -void uvst(void*, void*); -void uvld(void*, void*); void wbflush(void); void wrcompare(ulong); -void Xdelay(int); void serialinit(void); void ns16552special(int, int, Queue**, Queue**, int (*)(Queue*, int)); @@ -123,23 +82,6 @@ void enetaddr(uchar*); #define KADDR1(a) ((void*)((ulong)(a)|KSEG1)) #define PADDR(a) ((ulong)(a)&~KSEGM) -void ifwrite(void*, Block*, int); -void* ifinit(int); -void ifjab(void); -int ifgetsr(void); -ulong ifaddr(void*); -void filiput(Block*); -void fiberint(int); -void freset(void*); void audiosbintr(void); void audiodmaintr(void); -ulong fwblock(void*, void*, ulong); -ulong frblock(void*, void*, ulong); -void ifree(void*); -void ifflush(void*); -Block* iallocb(int); -void* ifroute(ulong); -ulong ifunroute(ulong); -void parseip(char*, char*); void mpegintr(void); -#define coherence() diff --git a/carrera/kbd.c b/carrera/kbd.c index e3b3f206c94cd8050359964bae6c95e59a10e7a4..d9759ca1d05c816a54f15e07a36a96fa14453971 100644 --- a/carrera/kbd.c +++ b/carrera/kbd.c @@ -6,6 +6,8 @@ #include "io.h" #include "../port/error.h" +#include +#include "screen.h" enum { diff --git a/carrera/l.s b/carrera/l.s index e2f301839f5f7002773a9bac34489fbc4b7143f0..f9c0da80966a353e4be16ee96e8a47aca375c6ec 100644 --- a/carrera/l.s +++ b/carrera/l.s @@ -123,6 +123,12 @@ TEXT spllo(SB), $0 TEXT spldone(SB), $0 RET +TEXT islo(SB), $0 + MOVW M(STATUS), R1 + AND $IE, R1 + WAIT + RET + TEXT wbflush(SB), $-4 RET @@ -138,18 +144,6 @@ TEXT gotolabel(SB), $-4 MOVW $1, R1 RET -TEXT gotopc(SB), $8 - MOVW R1, 0(FP) /* save arguments for later */ - MOVW $(64*1024), R7 - MOVW R7, 8(SP) - JAL icflush(SB) - MOVW 0(FP), R7 - MOVW _argc(SB), R4 - MOVW _argv(SB), R5 - MOVW _env(SB), R6 - MOVW R0, 4(SP) - JMP (R7) - TEXT puttlb(SB), $0 MOVW R1, M(TLBVIRT) MOVW 4(FP), R2 /* phys0 */ @@ -791,75 +785,3 @@ TEXT rdcount(SB), $0 TEXT wrcompare(SB), $0 MOVW R1, M(COMPARE) RET - -TEXT uvld(SB), $-4 /* uvld(address, dst) */ - MOVW 4(FP), R2 - MOVV 0(R1), R5 - MOVV R5, 0(R2) - RET - -TEXT uvst(SB), $-4 /* uvst(address, src) */ - MOVW 4(FP), R2 - MOVV 0(R2), R5 - MOVV R5, 0(R1) - RET - -TEXT fwblock(SB), $-4 /* fwblock(void*port, void *block, csum) */ - MOVW 4(FP), R2 - MOVW 8(FP), R6 - SLLV $32, R6 - SRLV $32, R6 /* zero extend */ - - MOVW $16, R4 -fwloop: - MOVV 0(R2), R5 - MOVV R5, 0(R1) - XOR R5, R6 - MOVV 8(R2), R7 - MOVV R7, 0(R1) - XOR R7, R6 - MOVV 16(R2), R8 - MOVV R8, 0(R1) - XOR R8, R6 - MOVV 24(R2), R9 - MOVV R9, 0(R1) - XOR R9, R6 - - ADD $32, R2 - SUB $1, R4 - BNE R4, fwloop - - MOVW R6, R1 - SRLV $32, R6 - XOR R6, R1 - RET - -TEXT frblock(SB), $-4 /* frblock(void*port, void *block, csum) */ - MOVW 4(FP), R2 - MOVW 8(FP), R6 - SLLV $32, R6 - SRLV $32, R6 /* zero extend */ - - MOVW $16, R4 -frloop: - MOVV 0(R1), R5 - MOVV R5, 0(R2) - XOR R5, R6 - MOVV 0(R1), R7 - MOVV R7, 8(R2) - XOR R7, R6 - MOVV 0(R1), R8 - MOVV R8, 16(R2) - XOR R8, R6 - MOVV 0(R1), R9 - MOVV R9, 24(R2) - XOR R9, R6 - - ADD $32, R2 - SUB $1, R4 - BNE R4, frloop - - MOVW R6, R1 - SRLV $32, R6 - XOR R6, R1 - RET diff --git a/carrera/main.c b/carrera/main.c index d046b50f120d8f0da22560437299377c505a7f77..9a4f29ce43d54ac8ea755df94f9c8e91cfbf98d4 100644 --- a/carrera/main.c +++ b/carrera/main.c @@ -108,7 +108,7 @@ arginit(void) */ if(*sysname == 0) for(av = _env; *av; av++) - for(i=0; i < sizeof bootenv/sizeof bootenv[0]; i++){ + for(i=0; i < nelem(bootenv); i++){ n = strlen(bootenv[i].name); if(strncmp(*av, bootenv[i].name, n) == 0){ strncpy(bootenv[i].val, (*av)+n, NAMELEN); @@ -328,7 +328,7 @@ init0(void) * Then early kproc's will have a root and dot. */ up->slash = namec("#/", Atodir, 0, 0); - up->dot = clone(up->slash, 0); + up->dot = cclone(up->slash, 0); chandevinit(); diff --git a/carrera/screen.c b/carrera/screen.c index 66f1627653f809dd43a694ac44e0f79fcd9079c3..14ba871ca945ec4612dd9fdbf477ea5efcd4a890 100644 --- a/carrera/screen.c +++ b/carrera/screen.c @@ -245,7 +245,7 @@ screenputs(char *s, int n) Rune r; char buf[4]; - if((getstatus() & IE) == 0) { + if(!islo()) { /* don't deadlock trying to print in interrupt */ if(!canlock(&screenlock)) return; diff --git a/carrera/screen.h b/carrera/screen.h index 566d43d1a733f04478c65108527728d56377620d..ef9a5e4a04b6215ef1f8417529661557196e5be2 100644 --- a/carrera/screen.h +++ b/carrera/screen.h @@ -8,8 +8,10 @@ struct Cursorinfo extern Cursorinfo cursor; -extern void mouseupdate(int); extern int cursoron(int); #define cursoroff(x) extern Point mousexy(void); -void setcursor(Cursor*); +void setcursor(Cursor*); + +void mousectl(char*); +void mousetrack(int, int, int); diff --git a/carrera/trap.c b/carrera/trap.c index eff3ac0ce67ca9d27f82cdaf743cc841e7f44825..0c375f37a278fd2fa783417a04ef39dbf6e7605c 100644 --- a/carrera/trap.c +++ b/carrera/trap.c @@ -482,7 +482,7 @@ dumpregs(Ureg *ur) print("registers for kernel\n"); l = &ur->status; - for(i=0; is = *((Sargs*)(sp+BY2WD)); up->psstate = sysctab[up->scallnr]; - ret = (*systab[up->scallnr])(up->s.args); + ret = systab[up->scallnr](up->s.args); poperror(); error: @@ -757,7 +757,7 @@ void linkproc(void) { spllo(); - (*up->kpfun)(up->kparg); + up->kpfun(up->kparg); } void diff --git a/ip/devip.c b/ip/devip.c new file mode 100644 index 0000000000000000000000000000000000000000..e295620cb2f052d5686e0a17ee3fcabd526b3ea5 --- /dev/null +++ b/ip/devip.c @@ -0,0 +1,940 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "../ip/ip.h" + +Fs fs; +Queue* qlog; + +enum +{ + Qtopdir= 1, /* top level directory */ + Qtopbase, + Qarp= Qtopbase, + Qipifc, + Qiproute, + Qlog, + + Qprotodir, /* directory for a protocol */ + Qprotobase, + Qclone= Qprotobase, + + Qconvdir, /* directory for a conversation */ + Qconvbase, + Qctl= Qconvbase, + Qdata, + Qerr, + Qlisten, + Qlocal, + Qremote, + Qstatus, +}; +#define TYPE(x) ((x).path & 0x1f) +#define CONV(x) (((x).path >> 5)&0xfff) +#define PROTO(x) (((x).path >> 17)&0xff) +#define QID(p, c, y) (((p)<<17) | ((c)<<5) | (y)) + +static char network[] = "network"; + +static int +ip3gen(Chan *c, int i, Dir *dp) +{ + Qid q; + Conv *cv; + char *p; + + cv = fs.p[PROTO(c->qid)]->conv[CONV(c->qid)]; + switch(i) { + default: + return -1; + case Qctl: + q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qctl), 0}; + devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); + return 1; + case Qdata: + q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qdata), 0}; + devdir(c, q, "data", qlen(cv->rq), cv->owner, cv->perm, dp); + return 1; + case Qerr: + q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qerr), 0}; + devdir(c, q, "err", qlen(cv->eq), cv->owner, cv->perm, dp); + return 1; + case Qlisten: + p = "listen"; + q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qlisten), 0}; + break; + case Qlocal: + p = "local"; + q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qlocal), 0}; + break; + case Qremote: + p = "remote"; + q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qremote), 0}; + break; + case Qstatus: + p = "status"; + q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qstatus), 0}; + break; + } + devdir(c, q, p, 0, cv->owner, 0444, dp); + return 1; +} + +static int +ip2gen(Chan *c, int i, Dir *dp) +{ + Qid q; + + switch(i) { + case Qclone: + q = (Qid){QID(PROTO(c->qid), 0, Qclone), 0}; + devdir(c, q, "clone", 0, network, 0444, dp); + return 1; + } + return -1; +} + +static int +ip1gen(Chan *c, int i, Dir *dp) +{ + Qid q; + char *p; + + switch(i) { + default: + return -1; + case Qarp: + p = "arp"; + q = (Qid){QID(0, 0, Qarp), 0}; + break; + case Qipifc: + p = "ipifc"; + q = (Qid){QID(0, 0, Qipifc), 0}; + break; + case Qiproute: + p = "iproute"; + q = (Qid){QID(0, 0, Qiproute), 0}; + break; + case Qlog: + p = "log"; + q = (Qid){QID(0, 0, Qlog), 0}; + break; + } + devdir(c, q, p, 0, network, 0444, dp); + return 1; +} + +static int +ipgen(Chan *c, Dirtab*, int, int s, Dir *dp) +{ + Qid q; + Conv *cv; + char name[16]; + + switch(TYPE(c->qid)) { + case Qtopdir: + if(s < fs.np) { + q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0}; + devdir(c, q, fs.p[s]->name, 0, network, CHDIR|0555, dp); + return 1; + } + s -= fs.np; + return ip1gen(c, s+Qtopbase, dp); + case Qarp: + case Qipifc: + case Qlog: + case Qiproute: + return ip1gen(c, TYPE(c->qid), dp); + case Qprotodir: + if(s < fs.p[PROTO(c->qid)]->ac) { + cv = fs.p[PROTO(c->qid)]->conv[s]; + sprint(name, "%d", s); + q = (Qid){QID(PROTO(c->qid), s, Qconvdir)|CHDIR, 0}; + devdir(c, q, name, 0, cv->owner, CHDIR|0555, dp); + return 1; + } + s -= fs.p[PROTO(c->qid)]->ac; + return ip2gen(c, s+Qprotobase, dp); + case Qclone: + return ip2gen(c, TYPE(c->qid), dp); + case Qconvdir: + return ip3gen(c, s+Qconvbase, dp); + case Qctl: + case Qdata: + case Qerr: + case Qlisten: + case Qlocal: + case Qremote: + case Qstatus: + return ip3gen(c, TYPE(c->qid), dp); + } + return -1; +} + +static void +ipreset(void) +{ +} + +static void +ipinit(void) +{ + int i; + extern void (*ipprotoinit[])(Fs*); + + initfrag(100); + for(i = 0; ipprotoinit[i]; i++) + ipprotoinit[i](&fs); + fmtinstall('i', eipconv); + fmtinstall('I', eipconv); + fmtinstall('E', eipconv); +} + +static Chan* +ipattach(char* spec) +{ + Chan *c; + + c = devattach('I', spec); + c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; + + return c; +} + +static Chan* +ipclone(Chan* c, Chan* nc) +{ + return devclone(c, nc); +} + +static int +ipwalk(Chan* c, char* name) +{ + Path *op; + + if(strcmp(name, "..") == 0){ + switch(TYPE(c->qid)){ + case Qtopdir: + case Qprotodir: + c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; + break; + case Qconvdir: + c->qid = (Qid){QID(0, 0, Qprotodir)|CHDIR, 0}; + break; + default: + panic("ipwalk %lux", c->qid.path); + } + op = c->path; + c->path = ptenter(&syspt, op, name); + decref(op); + return 1; + } + + return devwalk(c, name, nil, 0, ipgen); +} + +static void +ipstat(Chan* c, char* db) +{ + devstat(c, db, nil, 0, ipgen); +} + +static int +incoming(void* arg) +{ + Conv *conv; + + conv = arg; + return conv->incall != nil; +} + +static int m2p[] = { + [OREAD] 4, + [OWRITE] 2, + [ORDWR] 6 +}; + +static Chan* +ipopen(Chan* c, int omode) +{ + Conv *cv, *nc; + Proto *p; + int perm; + + omode &= 3; + perm = m2p[omode]; + + switch(TYPE(c->qid)) { + default: + break; + case Qlog: + netlogopen(); + break; + case Qtopdir: + case Qprotodir: + case Qconvdir: + case Qstatus: + case Qremote: + case Qlocal: + if(omode != OREAD) + error(Eperm); + break; + case Qclone: + p = fs.p[PROTO(c->qid)]; + cv = Fsprotoclone(p, up->user); + if(cv == nil) { + error(Enodev); + break; + } + c->qid = (Qid){QID(p->x, cv->x, Qctl), 0}; + break; + case Qdata: + case Qctl: + case Qerr: + p = fs.p[PROTO(c->qid)]; + lock(p); + cv = p->conv[CONV(c->qid)]; + lock(cv); + if(waserror()) { + unlock(cv); + unlock(p); + nexterror(); + } + if((perm & (cv->perm>>6)) != perm) { + if(strcmp(up->user, cv->owner) != 0) + error(Eperm); + if((perm & cv->perm) != perm) + error(Eperm); + + } + cv->inuse++; + if(cv->inuse == 1){ + memmove(cv->owner, up->user, NAMELEN); + cv->perm = 0660; + } + unlock(cv); + unlock(p); + poperror(); + break; + case Qlisten: + cv = fs.p[PROTO(c->qid)]->conv[CONV(c->qid)]; + if(cv->state != Announced) + error("not announced"); + + nc = nil; + while(nc == nil) { + qlock(&cv->listenq); + if(waserror()) { + qunlock(&cv->listenq); + nexterror(); + } + + sleep(&cv->listenr, incoming, cv); + + lock(cv); + nc = cv->incall; + if(nc != nil){ + cv->incall = nc->next; + c->qid = (Qid){QID(PROTO(c->qid), nc->x, Qctl), 0}; + memmove(cv->owner, up->user, NAMELEN); + } + unlock(cv); + + qunlock(&cv->listenq); + poperror(); + } + break; + } + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +static void +ipcreate(Chan*, char*, int, ulong) +{ + error(Eperm); +} + +static void +ipremove(Chan*) +{ + error(Eperm); +} + +static void +ipwstat(Chan*, char*) +{ + error(Eperm); +} + +static void +closeconv(Conv *cv) +{ + Conv *nc; + + lock(cv); + if(--cv->inuse > 0) { + unlock(cv); + return; + } + + /* close all incoming calls since no listen will ever happen */ + for(nc = cv->incall; nc; nc = cv->incall){ + cv->incall = nc->next; + closeconv(nc); + } + + strcpy(cv->owner, network); + cv->perm = 0660; + + /* The close routine will unlock the conv */ + cv->p->close(cv); +} + +static void +ipclose(Chan* c) +{ + switch(TYPE(c->qid)) { + default: + break; + case Qlog: + netlogclose(); + break; + case Qdata: + case Qctl: + case Qerr: + if(c->flag & COPEN) + closeconv(fs.p[PROTO(c->qid)]->conv[CONV(c->qid)]); + } +} + +static long +ipread(Chan *ch, void *a, long n, ulong offset) +{ + Conv *c; + Proto *x; + byte ip[4]; + char buf[256], *p, *statename; + + p = a; + switch(TYPE(ch->qid)) { + default: + error(Eperm); + case Qtopdir: + case Qprotodir: + case Qconvdir: + return devdirread(ch, a, n, 0, 0, ipgen); + case Qarp: + return arpread(a, offset, n); + case Qipifc: + return Mediaifcread(a, offset, n); + case Qiproute: + return routeread(a, offset, n); + case Qlog: + return netlogread(a, offset, n); + case Qctl: + sprint(buf, "%d", CONV(ch->qid)); + return readstr(offset, p, n, buf); + case Qremote: + c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; + hnputl(ip, c->raddr); + sprint(buf, "%I!%d\n", ip, c->rport); + return readstr(offset, p, n, buf); + case Qlocal: + c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; + if(media != nil && c->laddr == 0) + hnputl(ip, Mediagetaddr(media)); + else + hnputl(ip, c->laddr); + sprint(buf, "%I!%d\n", ip, c->lport); + return readstr(offset, p, n, buf); + case Qstatus: + x = fs.p[PROTO(ch->qid)]; + c = x->conv[CONV(ch->qid)]; + x->state(&statename, c); + sprint(buf, "%s/%d %d %s \n", c->p->name, c->x, c->inuse, statename); + return readstr(offset, p, n, buf); + case Qdata: + c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; + return qread(c->rq, a, n); + case Qerr: + c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; + return qread(c->eq, a, n); + } +} + +static Block* +ipbread(Chan* c, long n, ulong offset) +{ + return devbread(c, n, offset); +} + +static void +setladdr(Conv* c) +{ + byte rem[4]; + + hnputl(rem, c->raddr); + c->laddr = Mediagetsrc(rem); +} + +static void +setlport(Conv* c) +{ + Proto *p; + ushort *pp; + int x, found; + + p = c->p; + /* + * For compatibility with old Plan9/Brazil systems restrict + * the port number for now such that it can't sign-extend on + * the other end. + */ + while(p->nextport < 5000 || p->nextport >= (1<<15)) + p->nextport = nrand(1<<16); + + if(c->restricted) + pp = &p->nextrport; + else + pp = &p->nextport; + lock(p); + for(;;(*pp)++){ + if(*pp == 0 || *pp >= (1<<15)) { /* BSD hack */ + if(c->restricted) + *pp = 600; + else + *pp = 5000; + } + found = 0; + for(x = 0; x < p->nc; x++){ + if(p->conv[x] == nil) + break; + if(p->conv[x]->lport == *pp){ + found = 1; + break; + } + } + if(!found) + break; + } + c->lport = (*pp)++; + unlock(p); +} + +static void +setladdrport(Conv* c, char* str) +{ + char *p, addr[4]; + + p = strchr(str, '!'); + if(p == nil) { + p = str; + c->laddr = 0; + } + else { + *p++ = 0; + parseip(addr, str); + c->laddr = nhgetl((byte*)addr); + } + if(*p == '*') + c->lport = 0; + else { + c->lport = atoi(p); + if(c->lport == 0) + setlport(c); + } +} + +static char* +setraddrport(Conv* c, char* str) +{ + char *p, addr[4]; + + p = strchr(str, '!'); + if(p == nil) + return "malformed address"; + *p++ = 0; + parseip(addr, str); + c->raddr = nhgetl((byte*)addr); + c->rport = atoi(p); + p = strchr(p, '!'); + if(p){ + if(strcmp(p, "!r") == 0) + c->restricted = 1; + } + return nil; +} + +static int +connected(void* a) +{ + return ((Conv*)a)->state == Connected; +} + +static int +announced(void* a) +{ + return ((Conv*)a)->state == Announced; +} + +static long +ipwrite(Chan* ch, char* a, long n, ulong) +{ + Conv *c; + Proto *x; + int nfield; + char *p, *fields[10], buf[128]; + + switch(TYPE(ch->qid)){ + default: + error(Eperm); + case Qarp: + p = arpwrite(a, n); + if(p != nil) + error(p); + return n; + case Qipifc: + p = Mediaifcwrite(a, n); + if(p != nil) + error(p); + return n; + case Qiproute: + p = routewrite(a, n); + if(p != nil) + error(p); + return n; + case Qlog: + p = netlogctl(a, n); + if(p != nil) + error(p); + return n; + case Qctl: + x = fs.p[PROTO(ch->qid)]; + c = x->conv[CONV(ch->qid)]; + if(n > sizeof(buf)-1) + n = sizeof(buf)-1; + memmove(buf, a, n); + buf[n] = '\0'; + nfield = parsefields(buf, fields, 10, " "); + if(strcmp(fields[0], "connect") == 0){ + if(canqlock(&c->car) == 0) + error("connect/announce in progress"); + if(waserror()) { + qunlock(&c->car); + nexterror(); + } + c->state = Connecting; + c->cerr[0] = '\0'; + p = x->connect(c, fields, nfield); + if(p != nil) + error(p); + sleep(&c->cr, connected, c); + if(c->cerr[0] != '\0') + error(c->cerr); + qunlock(&c->car); + poperror(); + return n; + } + if(strcmp(fields[0], "announce") == 0){ + if(canqlock(&c->car) == 0) + error("connect/announce in progress"); + if(waserror()) { + qunlock(&c->car); + nexterror(); + } + switch(nfield){ + default: + error("bad args to announce"); + case 2: + setladdrport(c, fields[1]); + break; + } + c->state = Announcing; + c->cerr[0] = '\0'; + x->announce(c); + sleep(&c->cr, announced, c); + if(c->cerr[0] != '\0') + error(c->cerr); + qunlock(&c->car); + poperror(); + return n; + } + if(strcmp(fields[0], "bind") == 0){ + if(canqlock(&c->car) == 0) + error("connect/announce in progress"); + if(waserror()) { + qunlock(&c->car); + nexterror(); + } + switch(nfield){ + default: + error("bad args to bind"); + case 2: + setladdr(c); + c->lport = atoi(fields[1]); + if(c->lport == 0) + setlport(c); + break; + } + qunlock(&c->car); + poperror(); + return n; + } + if(strcmp(fields[0], "ttl") == 0){ + if(nfield < 2) + c->ttl = MAXTTL; + else + c->ttl = atoi(fields[1]); + return n; + } + if(x->ctl != nil) { + p = x->ctl(c, fields, nfield); + if(p != nil) + error(p); + return n; + } + error("unknown control request"); + case Qdata: + x = fs.p[PROTO(ch->qid)]; + c = x->conv[CONV(ch->qid)]; + + qwrite(c->wq, a, n); + x->kick(c, n); + } + return n; +} + +static long +ipbwrite(Chan* c, Block* bp, ulong offset) +{ + return devbwrite(c, bp, offset); +} + +Dev ipdevtab = { + ipreset, + ipinit, + ipattach, + ipclone, + ipwalk, + ipstat, + ipopen, + ipcreate, + ipclose, + ipread, + ipbread, + ipwrite, + ipbwrite, + ipremove, + ipwstat, +}; + +int +Fsproto(Fs *fs, Proto *p) +{ + if(fs->np >= Maxproto) + return -1; + + if(p->ipproto > 0){ + if(fs->t2p[p->ipproto] != nil) + return -1; + fs->t2p[p->ipproto] = p; + } + + p->qid.path = CHDIR|QID(fs->np, 0, Qprotodir); + p->conv = malloc(sizeof(Conv*)*(p->nc+1)); + if(p->conv == nil) + panic("Fsproto"); + + p->x = fs->np; + p->nextport = 0; + p->nextrport = 600; + fs->p[fs->np++] = p; + return 0; +} + +/* + * return true if this protocol is + * built in + */ +int +Fsbuiltinproto(Fs* fs, byte proto) +{ + return fs->t2p[proto] != nil; +} + +Conv* +Fsprotoclone(Proto *p, char *user) +{ + char *junk; + int unused; + Conv *c, **pp, **ep; + + c = nil; + lock(p); + if(waserror()) { + unlock(p); + nexterror(); + } + ep = &p->conv[p->nc]; + for(pp = p->conv; pp < ep; pp++) { + c = *pp; + if(c == nil){ + c = malloc(sizeof(Conv)); + if(c == nil) + error(Enomem); + lock(c); + c->p = p; + c->x = pp - p->conv; + c->ptcl = malloc(p->ptclsize); + if(c->ptcl == nil) { + free(c); + error(Enomem); + } + *pp = c; + p->ac++; + c->eq = qopen(1024, 1, 0, 0); + (*p->create)(c); + break; + } + if(canlock(c)){ + unused = p->state(&junk, c); + if(c->inuse == 0 && unused) + break; + + unlock(c); + } + } + if(pp >= ep) { + unlock(p); + poperror(); + return nil; + } + + c->inuse = 1; + strcpy(c->owner, user); + c->perm = 0660; + c->state = 0; + c->laddr = 0; + c->raddr = 0; + c->lport = 0; + c->rport = 0; + c->restricted = 0; + c->ttl = MAXTTL; + qreopen(c->rq); + qreopen(c->wq); + qreopen(c->eq); + + unlock(c); + unlock(p); + poperror(); + return c; +} + +int +Fsconnected(Fs*, Conv* c, char* msg) +{ + if(msg != nil && *msg != '\0') + strncpy(c->cerr, msg, ERRLEN-1); + + switch(c->state){ + + case Announcing: + c->state = Announced; + break; + + case Connecting: + c->state = Connected; + break; + } + + wakeup(&c->cr); + return 0; +} + +Proto* +Fsrcvpcol(Fs* fs, byte proto) +{ + return fs->t2p[proto]; +} + +Conv* +Fsnewcall(Fs*, Conv *c, Ipaddr raddr, ushort rport, Ipaddr laddr, ushort lport) +{ + Conv *nc; + Conv **l; + int i; + + lock(c); + i = 0; + for(l = &c->incall; *l; l = &(*l)->next) + i++; + if(i >= Maxincall) { + unlock(c); + return nil; + } + + /* find a free conversation */ + nc = Fsprotoclone(c->p, network); + if(nc == nil) { + unlock(c); + return nil; + } + nc->raddr = raddr; + nc->rport = rport; + nc->laddr = laddr; + nc->lport = lport; + nc->next = nil; + *l = nc; + unlock(c); + + wakeup(&c->listenr); + + return nc; +} + +int +Fspcolstats(char *buf, int len) +{ + Proto **p; + int n; + + n = 0; + for(p = fs.p; *p; p++) + n += snprint(buf + n, len - n, + "%s: csum %d hlen %d len %d order %d rexmit %d\n", + (*p)->name, (*p)->csumerr, (*p)->hlenerr, (*p)->lenerr, + (*p)->order, (*p)->rexmit); + return n; +} + +char* +Fsstdconnect(Conv *c, char *argv[], int argc) +{ + char *p; + + switch(argc) { + default: + return "bad args to connect"; + case 2: + p = setraddrport(c, argv[1]); + if(p != nil) + return p; + setladdr(c); + setlport(c); + break; + case 3: + p = setraddrport(c, argv[1]); + if(p != nil) + return p; + setladdr(c); + c->lport = atoi(argv[2]); + break; + } + return nil; +} diff --git a/ip/dial.c b/ip/dial.c new file mode 100644 index 0000000000000000000000000000000000000000..ab849d98fb4ba3d9fad6c20d12fd531ca11b1fa2 --- /dev/null +++ b/ip/dial.c @@ -0,0 +1,136 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "kernel.h" + +typedef struct DS DS; +static int call(char*, char*, DS*); +static void _dial_string_parse(char*, DS*); + +enum +{ + Maxstring= 128, + Maxpath= 256, +}; + +struct DS +{ + char buf[Maxstring]; /* dist string */ + char *netdir; + char *proto; + char *rem; + char *local; /* other args */ + char *dir; + int *cfdp; +}; + +/* + * the dialstring is of the form '[/net/]proto!dest' + */ +int +kdial(char *dest, char *local, char *dir, int *cfdp) +{ + DS ds; + char clone[Maxpath]; + + ds.local = local; + ds.dir = dir; + ds.cfdp = cfdp; + + _dial_string_parse(dest, &ds); + if(ds.netdir == 0) + ds.netdir = "/net"; + + /* no connection server, don't translate */ + snprint(clone, sizeof(clone), "%s/%s/clone", ds.netdir, ds.proto); + return call(clone, ds.rem, &ds); +} + +static int +call(char *clone, char *dest, DS *ds) +{ + int fd, cfd, n; + char name[3*NAMELEN+5], data[3*NAMELEN+10], *p; + + cfd = kopen(clone, ORDWR); + if(cfd < 0){ + kwerrstr("%s: %r", clone); + return -1; + } + + /* get directory name */ + n = kread(cfd, name, sizeof(name)-1); + if(n < 0){ + kclose(cfd); + return -1; + } + name[n] = 0; + for(p = name; *p == ' '; p++) + ; + sprint(name, "%d", strtoul(p, 0, 0)); + p = strrchr(clone, '/'); + *p = 0; + if(ds->dir) + snprint(ds->dir, 2*NAMELEN, "%s/%s", clone, name); + snprint(data, sizeof(data), "%s/%s/data", clone, name); + + /* connect */ + if(ds->local) + snprint(name, sizeof(name), "connect %s %s", dest, ds->local); + else + snprint(name, sizeof(name), "connect %s", dest); + if(kwrite(cfd, name, strlen(name)) < 0){ + kwerrstr("%s failed: %r", name); + kclose(cfd); + return -1; + } + + /* open data connection */ + fd = kopen(data, ORDWR); + if(fd < 0){ + kwerrstr("can't open %s: %r", data); + kclose(cfd); + return -1; + } + if(ds->cfdp) + *ds->cfdp = cfd; + else + kclose(cfd); + return fd; + +} + +/* + * parse a dial string + */ +static void +_dial_string_parse(char *str, DS *ds) +{ + char *p, *p2; + + strncpy(ds->buf, str, Maxstring); + ds->buf[Maxstring-1] = 0; + + p = strchr(ds->buf, '!'); + if(p == 0) { + ds->netdir = 0; + ds->proto = "net"; + ds->rem = ds->buf; + } else { + if(*ds->buf != '/'){ + ds->netdir = 0; + ds->proto = ds->buf; + } else { + for(p2 = p; *p2 != '/'; p2--) + ; + *p2++ = 0; + ds->netdir = ds->buf; + ds->proto = p2; + } + *p = 0; + ds->rem = p + 1; + } +} diff --git a/ip/gre.c b/ip/gre.c new file mode 100644 index 0000000000000000000000000000000000000000..4e82a7c41d79b6694785a5f93842c6d8859f9543 --- /dev/null +++ b/ip/gre.c @@ -0,0 +1,237 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "ip.h" + +#define DPRINT if(0)print + +enum +{ + GRE_IPHDRSIZE = 20, /* size of ip header */ + GRE_HDRSIZE = 4, /* minimum size of GRE header */ + IP_GREPROTO = 47, + + GRErxms = 200, + GREtickms = 100, + GREmaxxmit = 10, +}; + +typedef struct GREhdr +{ + /* ip header */ + byte vihl; /* Version and header length */ + byte tos; /* Type of service */ + byte len[2]; /* packet length (including headers) */ + byte id[2]; /* Identification */ + byte frag[2]; /* Fragment information */ + byte Unused; + byte proto; /* Protocol */ + byte cksum[2]; /* checksum */ + byte src[4]; /* Ip source */ + byte dst[4]; /* Ip destination */ + + /* gre header */ + byte flags[2]; + byte eproto[2]; /* encapsulation protocol */ +} GREhdr; + + Proto gre; +extern Fs fs; + int gredebug; + +static char* +greconnect(Conv *c, char **argv, int argc) +{ + Proto *p; + char *err; + Conv *tc, **cp, **ecp; + + err = Fsstdconnect(c, argv, argc); + if(err != nil) + return err; + + /* make sure noone's already connected to this other sys */ + p = c->p; + lock(p); + ecp = &p->conv[p->nc]; + for(cp = p->conv; cp < ecp; cp++){ + tc = *cp; + if(tc == nil) + break; + if(tc == c) + continue; + if(tc->rport == c->rport && tc->raddr == c->raddr){ + err = "already connected to that addr/proto"; + c->rport = 0; + c->raddr = 0; + break; + } + } + unlock(p); + + Fsconnected(&fs, c, err); + + return err; +} + +static int +grestate(char **msg, Conv *c) +{ + USED(c); + *msg = "Datagram"; + return 1; +} + +static void +grecreate(Conv *c) +{ + c->rq = qopen(64*1024, 0, 0, c); + c->wq = qopen(64*1024, 0, 0, 0); +} + +static void +greannounce(Conv *c) +{ + Fsconnected(&fs, c, "pktifc does not support announce"); +} + +static void +greclose(Conv *c) +{ + qclose(c->rq); + qclose(c->wq); + qclose(c->eq); + c->laddr = 0; + c->raddr = 0; + c->lport = 0; + c->rport = 0; + + unlock(c); +} + +int drop; + +static void +grekick(Conv *c, int l) +{ + GREhdr *ghp; + Block *bp, *f; + int dlen; + + USED(l); + + bp = qget(c->wq); + if(bp == nil) + return; + + /* Round packet up to even number of bytes */ + dlen = blocklen(bp); + if(dlen & 1) { + for(f = bp; f->next; f = f->next) + ; + if(f->wp >= f->lim) { + f->next = allocb(1); + f = f->next; + } + *f->wp++ = 0; + } + + /* Make space to fit ip header (gre header already there) */ + bp = padblock(bp, GRE_IPHDRSIZE); + if(bp == nil) + return; + + /* make sure the message has a GRE header */ + bp = pullupblock(bp, GRE_IPHDRSIZE+GRE_HDRSIZE); + if(bp == nil) + return; + + ghp = (GREhdr *)(bp->rp); + + ghp->proto = IP_GREPROTO; + hnputl(ghp->dst, c->raddr); + hnputl(ghp->src, c->laddr); + hnputs(ghp->eproto, c->rport); + + ipoput(bp, 0, c->ttl); +} + +static void +greiput(Block *bp) +{ + int len; + GREhdr *ghp; + Ipaddr addr; + Conv *c, **p; + ushort eproto; + + ghp = (GREhdr*)(bp->rp); + + eproto = nhgets(ghp->eproto); + addr = nhgetl(ghp->src); + + /* Look for a conversation structure for this port and address */ + c = nil; + for(p = gre.conv; *p; p++) { + c = *p; + if(c->inuse == 0) + continue; + if(c->raddr == addr && c->rport == eproto) + break; + } + + if(*p == nil) { + freeblist(bp); + return; + } + + /* + * Trim the packet down to data size + */ + len = nhgets(ghp->len) - GRE_IPHDRSIZE; + if(len < GRE_HDRSIZE){ + freeblist(bp); + return; + } + bp = trimblock(bp, GRE_IPHDRSIZE, len); + if(bp == nil){ + gre.lenerr++; + return; + } + + /* + * Can't delimit packet so pull it all into one block. + */ + if(qlen(c->rq) > 64*1024) + freeblist(bp); + else{ + bp = concatblock(bp); + if(bp == 0) + panic("greiput"); + qpass(c->rq, bp); + } +} + +void +greinit(Fs *fs) +{ + gre.name = "gre"; + gre.kick = grekick; + gre.connect = greconnect; + gre.announce = greannounce; + gre.state = grestate; + gre.create = grecreate; + gre.close = greclose; + gre.rcv = greiput; + gre.ctl = nil; + gre.advise = nil; + gre.ipproto = IP_GREPROTO; + gre.nc = 64; + gre.ptclsize = 0; + + Fsproto(fs, &gre); +} diff --git a/ip/icmp.c b/ip/icmp.c new file mode 100644 index 0000000000000000000000000000000000000000..9232135b92ec213e08c0f073bdbbf627c11818dd --- /dev/null +++ b/ip/icmp.c @@ -0,0 +1,267 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "ip.h" + +typedef struct Icmp { + byte vihl; /* Version and header length */ + byte tos; /* Type of service */ + byte length[2]; /* packet length */ + byte id[2]; /* Identification */ + byte frag[2]; /* Fragment information */ + byte ttl; /* Time to live */ + byte proto; /* Protocol */ + byte ipcksum[2]; /* Header checksum */ + byte src[4]; /* Ip source */ + byte dst[4]; /* Ip destination */ + byte type; + byte code; + byte cksum[2]; + byte icmpid[2]; + byte seq[2]; + byte data[1]; +} Icmp; + +enum { /* Packet Types */ + EchoReply = 0, + Unreachable = 3, + SrcQuench = 4, + EchoRequest = 8, + TimeExceed = 11, + Timestamp = 13, + TimestampReply = 14, + InfoRequest = 15, + InfoReply = 16, +}; + +enum { + IP_ICMPPROTO = 1, + ICMP_IPSIZE = 20, + ICMP_HDRSIZE = 8, +}; + + Proto icmp; +extern Fs fs; + +static char* +icmpconnect(Conv *c, char **argv, int argc) +{ + char *e; + + e = Fsstdconnect(c, argv, argc); + Fsconnected(&fs, c, e); + + return e; +} + +static int +icmpstate(char **s, Conv *c) +{ + USED(c); + *s = "Datagram"; + return 1; +} + +static void +icmpcreate(Conv *c) +{ + c->rq = qopen(64*1024, 0, 0, c); + c->wq = qopen(64*1024, 0, 0, 0); +} + +static void +icmpannounce(Conv *c) +{ + Fsconnected(&fs, c, nil); +} + +static void +icmpclose(Conv *c) +{ + qclose(c->rq); + qclose(c->wq); + c->laddr = 0; + c->lport = 0; + unlock(c); +} + +static void +icmpkick(Conv *c, int l) +{ + Icmp *p; + Block *bp; + + USED(l); + bp = qget(c->wq); + if(bp == nil) + return; + + if(blocklen(bp) < ICMP_IPSIZE + ICMP_HDRSIZE){ + freeblist(bp); + return; + } + p = (Icmp *)(bp->rp); + hnputl(p->dst, c->raddr); + hnputl(p->src, c->laddr); + p->proto = IP_ICMPPROTO; + hnputs(p->icmpid, c->lport); + memset(p->cksum, 0, sizeof(p->cksum)); + hnputs(p->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE)); + ipoput(bp, 0, MAXTTL); +} + + +static void +goticmpkt(Block *bp) +{ + Conv **c, *s; + Icmp *p; + Ipaddr dst; + ushort recid; + + p = (Icmp *) bp->rp; + dst = nhgetl(p->src); + recid = nhgets(p->icmpid); +netlog(Logicmp, "goticmpkt from %i to %d\n", dst, recid); + + for(c = icmp.conv; *c; c++) { + s = *c; +netlog(Logicmp, "conv %i %d %i %d\n", s->laddr, s->lport, s->raddr, s->rport); + if(s->lport == recid && s->raddr == dst){ + qpass(s->rq, bp); + return; + } + } + freeblist(bp); +} + +static Block * +mkechoreply(Block *bp) +{ + Icmp *q; + byte ip[4]; + + q = (Icmp *)bp->rp; + memmove(ip, q->src, sizeof(q->dst)); + memmove(q->src, q->dst, sizeof(q->src)); + memmove(q->dst, ip, sizeof(q->dst)); + q->type = EchoReply; + memset(q->cksum, 0, sizeof(q->cksum)); + hnputs(q->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE)); + return bp; +} + +static char *unreachcode[] = +{ +[0] "net unreachable", +[1] "host unreachable", +[2] "protocol unreachable", +[3] "port unreachable", +[4] "fragmentation needed and DF set", +[5] "source route failed", +}; + +static void +icmpiput(Block *bp) +{ + int n, iplen; + Icmp *p; + Block *r; + Proto *pr; + char *msg; + char m2[128]; + + p = (Icmp *)bp->rp; + netlog(Logicmp, "icmpiput %d %d\n", p->type, p->code); + n = blocklen(bp); + if(n < ICMP_IPSIZE+ICMP_HDRSIZE){ + icmp.hlenerr++; + goto raise; + } + iplen = nhgets(p->length); + if(iplen > n || (iplen % 1)){ + icmp.lenerr++; + goto raise; + } + if(ptclcsum(bp, ICMP_IPSIZE, iplen - ICMP_IPSIZE)){ + icmp.csumerr++; + goto raise; + } + switch(p->type) { + case EchoRequest: + r = mkechoreply(bp); + ipoput(r, 0, MAXTTL); + break; + case Unreachable: + if(p->code > 5 || p->code < 0) + msg = unreachcode[1]; + else + msg = unreachcode[p->code]; + + bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE; + if(blocklen(bp) < 8){ + icmp.lenerr++; + goto raise; + } + p = (Icmp *)bp->rp; + pr = Fsrcvpcol(&fs, p->proto); + if(pr != nil && pr->advise != nil) { + (*pr->advise)(bp, msg); + return; + } + + bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE; + goticmpkt(bp); + break; + case TimeExceed: + if(p->code == 0){ + sprint(m2, "ttl exceeded at %I", p->src); + + bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE; + if(blocklen(bp) < 8){ + icmp.lenerr++; + goto raise; + } + p = (Icmp *)bp->rp; + pr = Fsrcvpcol(&fs, p->proto); + if(pr != nil && pr->advise != nil) { + (*pr->advise)(bp, m2); + return; + } + } + + goticmpkt(bp); + break; + default: + goticmpkt(bp); + break; + } + return; + +raise: + freeblist(bp); +} + +void +icmpinit(Fs *fs) +{ + icmp.name = "icmp"; + icmp.kick = icmpkick; + icmp.connect = icmpconnect; + icmp.announce = icmpannounce; + icmp.state = icmpstate; + icmp.create = icmpcreate; + icmp.close = icmpclose; + icmp.rcv = icmpiput; + icmp.ctl = nil; + icmp.advise = nil; + icmp.ipproto = IP_ICMPPROTO; + icmp.nc = 16; + icmp.ptclsize = 0; + + Fsproto(fs, &icmp); +} diff --git a/ip/il.c b/ip/il.c new file mode 100644 index 0000000000000000000000000000000000000000..4fb800f3c96ffe7cc40094f3af52d5984f44ec7b --- /dev/null +++ b/ip/il.c @@ -0,0 +1,1032 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "ip.h" + +char *ilstates[] = +{ + "Closed", + "Syncer", + "Syncee", + "Established", + "Listening", + "Closing" +}; + +char *iltype[] = +{ + "sync", + "data", + "dataquerey", + "ack", + "querey", + "state", + "close" +}; +static char *etime = "connection timed out"; + +enum /* Packet types */ +{ + Ilsync, + Ildata, + Ildataquery, + Ilack, + Ilquerey, + Ilstate, + Ilclose, +}; + +enum /* Connection state */ +{ + Ilclosed, + Ilsyncer, + Ilsyncee, + Ilestablished, + Illistening, + Ilclosing, +}; + +typedef struct Ilcb Ilcb; +struct Ilcb /* Control block */ +{ + int state; /* Connection state */ + Conv *conv; + QLock ackq; /* Unacknowledged queue */ + Block *unacked; + Block *unackedtail; + QLock outo; /* Out of order packet queue */ + Block *outoforder; + ulong next; /* Id of next to send */ + ulong recvd; /* Last packet received */ + ulong start; /* Local start id */ + ulong rstart; /* Remote start id */ + int timeout; /* Time out counter */ + int slowtime; /* Slow time counter */ + int fasttime; /* Retransmission timer */ + int acktime; /* Acknowledge timer */ + int querytime; /* Query timer */ + int deathtime; /* Time to kill connection */ + int rtt; /* Average round trip time */ + ulong rttack; /* The ack we are waiting for */ + ulong ackms; /* Time we issued */ + int window; /* Maximum receive window */ +}; + +enum +{ + IL_IPSIZE = 20, + IL_HDRSIZE = 18, + IL_LISTEN = 0, + IL_CONNECT = 1, + IP_ILPROTO = 40, +}; + +typedef struct Ilhdr Ilhdr; +struct Ilhdr +{ + byte vihl; /* Version and header length */ + byte tos; /* Type of service */ + byte length[2]; /* packet length */ + byte id[2]; /* Identification */ + byte frag[2]; /* Fragment information */ + byte ttl; /* Time to live */ + byte proto; /* Protocol */ + byte cksum[2]; /* Header checksum */ + byte src[4]; /* Ip source */ + byte dst[4]; /* Ip destination */ + byte ilsum[2]; /* Checksum including header */ + byte illen[2]; /* Packet length */ + byte iltype; /* Packet type */ + byte ilspec; /* Special */ + byte ilsrc[2]; /* Src port */ + byte ildst[2]; /* Dst port */ + byte ilid[4]; /* Sequence id */ + byte ilack[4]; /* Acked sequence */ +}; + +/* Always Acktime < Fasttime < Slowtime << Ackkeepalive */ +enum +{ + Seconds = 1000, + Iltickms = 100, /* time base */ + + Ackkeepalive = 6000*Iltickms, + Acktime = 2*Iltickms, /* max time twixt message rcvd & ack sent */ + + Slowtime = 90*Seconds, /* min time waiting for an ack before hangup */ + Fasttime = 4*Iltickms, /* min time between rexmit */ + Querytime = 5*Seconds, /* time between subsequent queries */ + Keepalivetime = 60*Seconds, /* time before first query */ + Deathtime = 120*Seconds, /* time between first query and hangup */ + + Defaultwin = 20, + ILgain = 8, +}; + +void ilrcvmsg(Conv*, Block*); +void ilsendctl(Conv*, Ilhdr*, int, ulong, ulong); +void ilackq(Ilcb*, Block*); +void ilprocess(Conv*, Ilhdr*, Block*); +void ilpullup(Conv*); +void ilhangup(Conv*, char*); +void ilfreeq(Ilcb*); +void ilrexmit(Ilcb*); +void ilbackoff(Ilcb*); +void iltimers(Ilcb*); +char* ilstart(Conv*, int, int); +void ilackproc(); +void iloutoforder(Conv*, Ilhdr*, Block*); +void iliput(Block*); +void iladvise(Block*, char*); + +#define DBG(x) if((logmask & Logilmsg) && (iponly == 0 || x == iponly))netlog + + Proto il; + int ilcksum = 1; +static int initseq = 25001; +extern Fs fs; + +static char* +ilconnect(Conv *c, char **argv, int argc) +{ + char *e; + + e = ilstart(c, IL_CONNECT, 20); + if(e != nil) + return e; + return Fsstdconnect(c, argv, argc); +} + +int +ilstate(char **msg, Conv *c) +{ + Ilcb *ic; + int isclose; + + ic = (Ilcb*)(c->ptcl); + + isclose = 0; + if(ic->state == Ilclosed) + isclose = 1; + + *msg = ilstates[ic->state]; + return isclose; +} + +/* called with c locked */ +static void +ilannounce(Conv *c) +{ + char *e; + + e = ilstart(c, IL_LISTEN, 20); + Fsconnected(&fs, c, e); +} + +static void +ilclose(Conv *c) +{ + Ilcb *ic; + + ic = (Ilcb*)c->ptcl; + + qclose(c->rq); + qclose(c->wq); + qclose(c->eq); + + switch(ic->state) { + case Ilclosing: + case Ilclosed: + break; + case Ilsyncer: + case Ilsyncee: + case Ilestablished: + ilfreeq(ic); + ic->state = Ilclosing; + ilsendctl(c, nil, Ilclose, ic->next, ic->recvd); + break; + case Illistening: + ic->state = Ilclosed; + c->laddr = 0; + c->lport = 0; + break; + } + unlock(c); +} + +void +ilkick(Conv *c, int l) +{ + Ilhdr *ih; + Ilcb *ic; + int dlen; + ulong id; + Block *bp; + + USED(l); + + ic = (Ilcb*)c->ptcl; + + bp = qget(c->wq); + if(bp == nil) + return; + + switch(ic->state) { + case Ilclosed: + case Illistening: + case Ilclosing: + freeblist(bp); + qhangup(c->rq, nil); + return; + } + + dlen = blocklen(bp); + + /* Make space to fit il & ip */ + bp = padblock(bp, IL_IPSIZE+IL_HDRSIZE); + ih = (Ilhdr *)(bp->rp); + + /* Ip fields */ + ih->frag[0] = 0; + ih->frag[1] = 0; + hnputl(ih->dst, c->raddr); + hnputl(ih->src, c->laddr); + ih->proto = IP_ILPROTO; + + /* Il fields */ + hnputs(ih->illen, dlen+IL_HDRSIZE); + hnputs(ih->ilsrc, c->lport); + hnputs(ih->ildst, c->rport); + + qlock(&ic->ackq); + id = ic->next++; + hnputl(ih->ilid, id); + + hnputl(ih->ilack, ic->recvd); + ih->iltype = Ildata; + ih->ilspec = 0; + ih->ilsum[0] = 0; + ih->ilsum[1] = 0; + + /* Checksum of ilheader plus data (not ip & no pseudo header) */ + if(ilcksum) + hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, dlen+IL_HDRSIZE)); + + ilackq(ic, bp); + qunlock(&ic->ackq); + + /* Start the round trip timer for this packet if the timer is free */ + if(ic->rttack == 0) { + ic->rttack = id; + ic->ackms = msec; + } + ic->acktime = Ackkeepalive; + + ipoput(bp, 0, c->ttl); +} + +static void +ilcreate(Conv *c) +{ + c->rq = qopen(64*1024, 0, 0, c); + c->wq = qopen(64*1024, 0, 0, 0); +} + +void +ilinit(Fs *fs) +{ + il.name = "il"; + il.kick = ilkick; + il.connect = ilconnect; + il.announce = ilannounce; + il.state = ilstate; + il.create = ilcreate; + il.close = ilclose; + il.rcv = iliput; + il.ctl = nil; + il.advise = iladvise; + il.ipproto = IP_ILPROTO; + il.nc = Nchans; + il.ptclsize = sizeof(Ilcb); + + kproc("ilack", ilackproc, 0); + + Fsproto(fs, &il); +} + +void +ilackq(Ilcb *ic, Block *bp) +{ + Block *np; + + /* Enqueue a copy on the unacked queue in case this one gets lost */ + np = copyblock(bp, blocklen(bp)); + if(ic->unacked) + ic->unackedtail->list = np; + else { + /* Start timer since we may have been idle for some time */ + iltimers(ic); + ic->unacked = np; + } + ic->unackedtail = np; + np->list = nil; +} + +void +ilackto(Ilcb *ic, ulong ackto) +{ + Ilhdr *h; + Block *bp; + ulong id, t; + + if(ic->rttack == ackto) { + t = msec - ic->ackms; + /* Guard against the ulong zero wrap of MACHP(0)->ticks */ + if(t < 120000) + ic->rtt = (ic->rtt*(ILgain-1)+t)/ILgain; + if(ic->rtt < Iltickms) + ic->rtt = Iltickms; + } + + /* Cancel if we lost the packet we were interested in */ + if(ic->rttack <= ackto) + ic->rttack = 0; + + qlock(&ic->ackq); + while(ic->unacked) { + h = (Ilhdr *)ic->unacked->rp; + id = nhgetl(h->ilid); + if(ackto < id) + break; + + bp = ic->unacked; + ic->unacked = bp->list; + bp->list = nil; + freeblist(bp); + } + qunlock(&ic->ackq); +} + +void +iliput(Block *bp) +{ + char *st; + Ilcb *ic; + Ilhdr *ih; + Ipaddr dst; + ushort sp, dp, csum; + int plen, illen; + Conv *s, **p, *new, *spec, *gen; + + ih = (Ilhdr *)bp->rp; + plen = blocklen(bp); + if(plen < IL_IPSIZE+IL_HDRSIZE){ + netlog(Logil, "il: hlenerr\n"); + il.hlenerr++; + goto raise; + } + + illen = nhgets(ih->illen); + if(illen+IL_IPSIZE > plen){ + netlog(Logil, "il: lenerr\n"); + il.lenerr++; + goto raise; + } + + sp = nhgets(ih->ildst); + dp = nhgets(ih->ilsrc); + dst = nhgetl(ih->src); + + if(ilcksum && (csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) { + if(ih->iltype < 0 || ih->iltype > Ilclose) + st = "?"; + else + st = iltype[ih->iltype]; + il.csumerr++; + netlog(Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %i/%d->%d)\n", + csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), dst, sp, dp); + goto raise; + } + + for(p = il.conv; *p; p++) { + s = *p; + if(s->lport == sp && s->rport == dp && s->raddr == dst) { + ilprocess(s, ih, bp); + return; + } + } + + if(ih->iltype != Ilsync){ + if(ih->iltype < 0 || ih->iltype > Ilclose) + st = "?"; + else + st = iltype[ih->iltype]; + netlog(Logil, "il: no channel, pkt(%s id %lud ack %lud %i/%ud->%ud)\n", + st, nhgetl(ih->ilid), nhgetl(ih->ilack), dst, sp, dp); + goto raise; + } + + gen = nil; + spec = nil; + for(p = il.conv; *p; p++) { + s = *p; + ic = (Ilcb*)s->ptcl; + if(ic->state != Illistening) + continue; + + if(s->rport == 0 && s->raddr == 0) { + if(s->lport == sp) { + spec = s; + break; + } + if(s->lport == 0) + gen = s; + } + } + + if(spec) + s = spec; + else + if(gen) + s = gen; + else + goto raise; + + new = Fsnewcall(&fs, s, nhgetl(ih->src), dp, nhgetl(ih->dst), sp); + if(new == nil){ + netlog(Logil, "il: bad newcall %i/%ud->%ud\n", dst, sp, dp); + ilsendctl(nil, ih, Ilclose, 0, nhgetl(ih->ilid)); + goto raise; + } + + ic = (Ilcb*)new->ptcl; + ic->conv = new; + ic->state = Ilsyncee; + initseq += msec; + ic->start = initseq & 0xffffff; + ic->next = ic->start+1; + ic->recvd = 0; + ic->rstart = nhgetl(ih->ilid); + ic->slowtime = Slowtime; + ic->rtt = Iltickms; + ic->querytime = Keepalivetime; + ic->deathtime = Deathtime; + ic->window = Defaultwin; + + ilprocess(new, ih, bp); + return; + +raise: + freeblist(bp); + return; +} + +int sdataquery; /* temporary counters for measuring */ +int squery; + +void +_ilprocess(Conv *s, Ilhdr *h, Block *bp) +{ + Ilcb *ic; + ulong id, ack; + + id = nhgetl(h->ilid); + ack = nhgetl(h->ilack); + + ic = (Ilcb*)s->ptcl; + + ic->querytime = Keepalivetime; + ic->deathtime = Deathtime; + + switch(ic->state) { + default: + netlog(Logil, "il: unknown state %d\n", ic->state); + case Ilclosed: + freeblist(bp); + break; + case Ilsyncer: + switch(h->iltype) { + default: + break; + case Ilsync: + if(ack != ic->start) + ilhangup(s, "connection rejected"); + else { + ic->recvd = id; + ic->rstart = id; + ilsendctl(s, nil, Ilack, ic->next, ic->recvd); + ic->state = Ilestablished; + Fsconnected(&fs, s, nil); + ilpullup(s); + iltimers(ic); + } + break; + case Ilclose: + if(ack == ic->start) + ilhangup(s, "remote close"); + break; + } + freeblist(bp); + break; + case Ilsyncee: + switch(h->iltype) { + default: + break; + case Ilsync: + if(id != ic->rstart || ack != 0) + ic->state = Ilclosed; + else { + ic->recvd = id; + ilsendctl(s, nil, Ilsync, ic->start, ic->recvd); + iltimers(ic); + } + break; + case Ilack: + if(ack == ic->start) { + ic->state = Ilestablished; + ilpullup(s); + iltimers(ic); + } + break; + case Ilclose: + if(ack == ic->start) + ilhangup(s, "remote close"); + break; + } + freeblist(bp); + break; + case Ilestablished: + switch(h->iltype) { + case Ilsync: + if(id != ic->rstart) + ilhangup(s, "remote close"); + else { + ilsendctl(s, nil, Ilack, ic->next, ic->rstart); + iltimers(ic); + } + freeblist(bp); + break; + case Ildata: + iltimers(ic); + ilackto(ic, ack); + ic->acktime = Acktime; + iloutoforder(s, h, bp); + ilpullup(s); + break; + case Ildataquery: +sdataquery++; + iltimers(ic); + ilackto(ic, ack); + ic->acktime = Acktime; + iloutoforder(s, h, bp); + ilpullup(s); + ilsendctl(s, nil, Ilstate, ic->next, ic->recvd); + break; + case Ilack: + ilackto(ic, ack); + iltimers(ic); + freeblist(bp); + break; + case Ilquerey: +squery++; + ilackto(ic, ack); + ilsendctl(s, nil, Ilstate, ic->next, ic->recvd); + iltimers(ic); + freeblist(bp); + break; + case Ilstate: + ilackto(ic, ack); + ilrexmit(ic); + iltimers(ic); + freeblist(bp); + break; + case Ilclose: + freeblist(bp); + if(ack < ic->start || ack > ic->next) + break; + ilsendctl(s, nil, Ilclose, ic->next, ic->recvd); + ic->state = Ilclosing; + ilfreeq(ic); + iltimers(ic); + break; + } + break; + case Illistening: + freeblist(bp); + break; + case Ilclosing: + switch(h->iltype) { + case Ilclose: + ic->recvd = id; + ilsendctl(s, nil, Ilclose, ic->next, ic->recvd); + if(ack == ic->next) + ilhangup(s, nil); + iltimers(ic); + break; + default: + break; + } + freeblist(bp); + break; + } +} + +void +ilrexmit(Ilcb *ic) +{ + Ilhdr *h; + Block *nb; + + nb = nil; + qlock(&ic->ackq); + if(ic->unacked) + nb = copyblock(ic->unacked, blocklen(ic->unacked)); + qunlock(&ic->ackq); + + if(nb == nil) + return; + + h = (Ilhdr*)nb->rp; +/* netlog(Logil, "il: rxmit %ux %d\n", nb, nhgetl(h->ilid)); */ + + h->iltype = Ildataquery; + hnputl(h->ilack, ic->recvd); + h->ilsum[0] = 0; + h->ilsum[1] = 0; + if(ilcksum) + hnputs(h->ilsum, ptclcsum(nb, IL_IPSIZE, nhgets(h->illen))); + + il.rexmit++; + ipoput(nb, 0, ic->conv->ttl); +} + +/* DEBUG */ +void +ilprocess(Conv *s, Ilhdr *h, Block *bp) +{ + Ilcb *ic; + + ic = (Ilcb*)s->ptcl; + + USED(ic); + DBG(s->raddr)(Logilmsg, "%11s rcv %d/%d snt %d/%d pkt(%s id %d ack %d %d->%d) ", + ilstates[ic->state], ic->rstart, ic->recvd, ic->start, + ic->next, iltype[h->iltype], nhgetl(h->ilid), + nhgetl(h->ilack), nhgets(h->ilsrc), nhgets(h->ildst)); + + _ilprocess(s, h, bp); + + DBG(s->raddr)(Logilmsg, "%11s rcv %d snt %d\n", ilstates[ic->state], ic->recvd, ic->next); +} + +void +ilhangup(Conv *s, char *msg) +{ + Ilcb *ic; + int callout; + + netlog(Logil, "il: hangup! %i %d/%d\n", s->raddr, s->lport, s->rport); + + ic = (Ilcb*)s->ptcl; + callout = ic->state == Ilsyncer; + ic->state = Ilclosed; + + qhangup(s->rq, msg); + qhangup(s->wq, msg); + + if(callout) + Fsconnected(&fs, s, msg); +} + +void +ilpullup(Conv *s) +{ + Ilcb *ic; + Ilhdr *oh; + Block *bp; + ulong oid, dlen; + + ic = (Ilcb*)s->ptcl; + if(ic->state != Ilestablished) + return; + + qlock(&ic->outo); + while(ic->outoforder) { + bp = ic->outoforder; + oh = (Ilhdr*)bp->rp; + oid = nhgetl(oh->ilid); + if(oid <= ic->recvd) { + ic->outoforder = bp->list; + freeblist(bp); + continue; + } + if(oid != ic->recvd+1) + break; + + ic->recvd = oid; + ic->outoforder = bp->list; + + bp->list = nil; + dlen = nhgets(oh->illen)-IL_HDRSIZE; + bp = trimblock(bp, IL_IPSIZE+IL_HDRSIZE, dlen); + /* + * Upper levels don't know about multiple-block + * messages so copy all into one (yick). + */ + bp = concatblock(bp); + if(bp == 0) + panic("ilpullup"); + qpass(s->rq, bp); + } + qunlock(&ic->outo); +} + +void +iloutoforder(Conv *s, Ilhdr *h, Block *bp) +{ + Ilcb *ic; + byte *lid; + Block *f, **l; + ulong id, newid; + + ic = (Ilcb*)s->ptcl; + bp->list = nil; + + id = nhgetl(h->ilid); + /* Window checks */ + if(id <= ic->recvd || id > ic->recvd+ic->window) { + netlog(Logil, "il: message outside window %ud <%ud-%ud>: %i %d/%d\n", + id, ic->recvd, ic->recvd+ic->window, s->raddr, s->lport, s->rport); + freeblist(bp); + return; + } + + /* Packet is acceptable so sort onto receive queue for pullup */ + qlock(&ic->outo); + if(ic->outoforder == nil) + ic->outoforder = bp; + else { + l = &ic->outoforder; + for(f = *l; f; f = f->list) { + lid = ((Ilhdr*)(f->rp))->ilid; + newid = nhgetl(lid); + if(id <= newid) { + if(id == newid) { + qunlock(&ic->outo); + freeblist(bp); + return; + } + bp->list = f; + *l = bp; + qunlock(&ic->outo); + return; + } + l = &f->list; + } + *l = bp; + } + qunlock(&ic->outo); +} + +void +ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack) +{ + Ilhdr *ih; + Ilcb *ic; + Block *bp; + int ttl; + + bp = allocb(IL_IPSIZE+IL_HDRSIZE); + bp->wp += IL_IPSIZE+IL_HDRSIZE; + + ih = (Ilhdr *)(bp->rp); + + /* Ip fields */ + ih->proto = IP_ILPROTO; + hnputs(ih->illen, IL_HDRSIZE); + ih->frag[0] = 0; + ih->frag[1] = 0; + if(inih) { + hnputl(ih->dst, nhgetl(inih->src)); + hnputl(ih->src, nhgetl(inih->dst)); + hnputs(ih->ilsrc, nhgets(inih->ildst)); + hnputs(ih->ildst, nhgets(inih->ilsrc)); + hnputl(ih->ilid, nhgetl(inih->ilack)); + hnputl(ih->ilack, nhgetl(inih->ilid)); + ttl = MAXTTL; + } + else { + hnputl(ih->dst, ipc->raddr); + hnputl(ih->src, ipc->laddr); + hnputs(ih->ilsrc, ipc->lport); + hnputs(ih->ildst, ipc->rport); + hnputl(ih->ilid, id); + hnputl(ih->ilack, ack); + ic = (Ilcb*)ipc->ptcl; + ic->acktime = Ackkeepalive; + ttl = ipc->ttl; + } + ih->iltype = type; + ih->ilspec = 0; + ih->ilsum[0] = 0; + ih->ilsum[1] = 0; + + if(ilcksum) + hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE)); + + if(ipc){ + DBG(ipc->raddr)(Logilmsg, "ctl(%s id %d ack %d %d->%d)\n", + iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack), + nhgets(ih->ilsrc), nhgets(ih->ildst)); + } + + ipoput(bp, 0, ttl); +} + +void +ilackproc() +{ + Ilcb *ic; + Conv **s, *p; + static Rendez ilr; + +loop: + tsleep(&ilr, return0, 0, Iltickms); + for(s = il.conv; s && *s; s++) { + p = *s; + ic = (Ilcb*)p->ptcl; + + ic->timeout += Iltickms; + switch(ic->state) { + case Ilclosed: + case Illistening: + break; + case Ilclosing: + if(ic->timeout >= ic->fasttime) { + ilsendctl(p, nil, Ilclose, ic->next, ic->recvd); + ilbackoff(ic); + } + if(ic->timeout >= ic->slowtime) + ilhangup(p, nil); + break; + case Ilsyncee: + case Ilsyncer: + if(ic->timeout >= ic->fasttime) { + ilsendctl(p, nil, Ilsync, ic->start, ic->recvd); + ilbackoff(ic); + } + if(ic->timeout >= ic->slowtime) + ilhangup(p, etime); + break; + case Ilestablished: + ic->acktime -= Iltickms; + if(ic->acktime <= 0) + ilsendctl(p, nil, Ilack, ic->next, ic->recvd); + + ic->querytime -= Iltickms; + if(ic->querytime <= 0){ + ic->deathtime -= Querytime; + if(ic->deathtime < 0){ + netlog(Logil, "il: hangup due to deathtime (%d) < 0 \n", ic->deathtime); + ilhangup(p, etime); + break; + } + ilsendctl(p, nil, Ilquerey, ic->next, ic->recvd); + ic->querytime = Querytime; + } + if(ic->unacked == nil) { + ic->timeout = 0; + break; + } + if(ic->timeout >= ic->fasttime) { + ilrexmit(ic); + ilbackoff(ic); + } + if(ic->timeout >= ic->slowtime) { + netlog(Logil, "il: hangup due to timeout (%d) >= slowtime (%d)\n", ic->timeout, ic->slowtime); + ilhangup(p, etime); + break; + } + break; + } + } + goto loop; +} + +void +ilbackoff(Ilcb *ic) +{ + if(ic->fasttime < Slowtime/2) + ic->fasttime += Fasttime; + else + ic->fasttime = (ic->fasttime)*3/2; +} + +char* +ilstart(Conv *c, int type, int window) +{ + char *e; + Ilcb *ic; + + ic = (Ilcb*)c->ptcl; + ic->conv = c; + + e = nil; + + if(ic->state != Ilclosed) + return e; + + ic->unacked = nil; + ic->outoforder = nil; + ic->slowtime = Slowtime; + ic->rtt = Iltickms; + iltimers(ic); + + initseq += msec; + ic->start = initseq & 0xffffff; + ic->next = ic->start+1; + ic->recvd = 0; + ic->window = window; + + switch(type) { + default: + netlog(Logil, "il: start: type %d\n", type); + break; + case IL_LISTEN: + ic->state = Illistening; + break; + case IL_CONNECT: + ic->state = Ilsyncer; + ilsendctl(c, nil, Ilsync, ic->start, ic->recvd); + break; + } + + return e; +} + +void +ilfreeq(Ilcb *ic) +{ + Block *bp, *next; + + qlock(&ic->ackq); + for(bp = ic->unacked; bp; bp = next) { + next = bp->list; + freeblist(bp); + } + ic->unacked = nil; + qunlock(&ic->ackq); + + qlock(&ic->outo); + for(bp = ic->outoforder; bp; bp = next) { + next = bp->list; + freeblist(bp); + } + ic->outoforder = nil; + qunlock(&ic->outo); +} + +void +iltimers(Ilcb *ic) +{ + ic->timeout = 0; + ic->fasttime = (Fasttime*ic->rtt)/Iltickms; + ic->slowtime = (Slowtime*ic->rtt)/Iltickms; +} + +void +iladvise(Block *bp, char *msg) +{ + Ilhdr *h; + Ilcb *ic; + Ipaddr source, dest; + ushort psource; + Conv *s, **p; + + h = (Ilhdr*)(bp->rp); + + dest = nhgetl(h->dst); + source = nhgetl(h->src); + psource = nhgets(h->ilsrc); + + + /* Look for a connection, unfortunately the destination port is missing */ + for(p = il.conv; *p; p++) { + s = *p; + if(s->laddr == source && s->lport == psource) + if(s->raddr == dest){ + ic = (Ilcb*)s->ptcl; + switch(ic->state){ + case Ilsyncer: + ilhangup(s, msg); + break; + } + break; + } + } + freeblist(bp); +} diff --git a/ip/ip.c b/ip/ip.c new file mode 100644 index 0000000000000000000000000000000000000000..d5f506fb6c05afd3b1bbf165aba5fc8d78614c35 --- /dev/null +++ b/ip/ip.c @@ -0,0 +1,555 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "ip.h" + +typedef struct Iphdr Iphdr; +typedef struct Fragment Fragment; +typedef struct Ipfrag Ipfrag; + +enum +{ + IPHDR = 20, /* sizeof(Iphdr) */ + IP_VER = 0x40, /* Using IP version 4 */ + IP_HLEN = 0x05, /* Header length in characters */ + IP_DF = 0x4000, /* Don't fragment */ + IP_MF = 0x2000, /* More fragments */ + IP_MAX = (32*1024), /* Maximum Internet packet size */ +}; + +struct Iphdr +{ + byte vihl; /* Version and header length */ + byte tos; /* Type of service */ + byte length[2]; /* packet length */ + byte id[2]; /* Identification */ + byte frag[2]; /* Fragment information */ + byte ttl; /* Time to live */ + byte proto; /* Protocol */ + byte cksum[2]; /* Header checksum */ + byte src[4]; /* Ip source */ + byte dst[4]; /* Ip destination */ +}; + +struct Fragment +{ + QLock; + Block* blist; + Fragment* next; + Ipaddr src; + Ipaddr dst; + ushort id; + ulong age; +}; + +struct Ipfrag +{ + ushort foff; + ushort flen; +}; + +Fragment* flisthead; +Fragment* fragfree; +QLock fraglock; +ulong Id; +int iprouting; /* true if we route like a gateway */ +ulong ipcsumerr; +ulong ipin, ippin; /* bytes, packets in */ +ulong ipout, ippout; /* bytes, packets out */ + +#define BLKIP(xp) ((Iphdr*)((xp)->rp)) +/* + * This sleazy macro relies on the media header size being + * larger than sizeof(Ipfrag). ipreassemble checks this is true + */ +#define BKFG(xp) ((Ipfrag*)((xp)->base)) + +ushort ipcsum(byte*); +Block* ipreassemble(int, Block*, Iphdr*); +void ipfragfree(Fragment*, int); +Fragment* ipfragallo(void); + +void +ipoput(Block *bp, int gating, int ttl) +{ + Media *m; + byte gate[4]; + ushort fragoff; + Block *xp, *nb; + Iphdr *eh, *feh; + int lid, len, seglen, chunk, dlen, blklen, offset, medialen; + + /* Fill out the ip header */ + eh = (Iphdr *)(bp->rp); + + /* Number of bytes in data and ip header to write */ + len = blocklen(bp); + ipout += len; + ippout++; + if(gating){ + chunk = nhgets(eh->length); + if(chunk > len){ + netlog(Logip, "short gated packet\n"); + goto raise; + } + if(chunk < len) + len = chunk; + } + if(len >= IP_MAX) { + netlog(Logip, "exceeded ip max size %I\n", eh->dst); + goto raise; + } + + m = Mediaroute(eh->dst, gate); + if(m == nil){ + netlog(Logip, "no interface %I\n", eh->dst); + goto raise; + } + + if(!gating){ + eh->vihl = IP_VER|IP_HLEN; + eh->tos = 0; + eh->ttl = ttl; + } + + /* If we dont need to fragment just send it */ + medialen = m->maxmtu-m->hsize; + if(len <= medialen) { + if(!gating) + hnputs(eh->id, Id++); + hnputs(eh->length, len); + eh->frag[0] = 0; + eh->frag[1] = 0; + eh->cksum[0] = 0; + eh->cksum[1] = 0; + hnputs(eh->cksum, ipcsum(&eh->vihl)); + + Mediawrite(m, bp, gate); + return; + } + + if(eh->frag[0] & (IP_DF>>8)){ + netlog(Logip, "%I: eh->frag[0] & (IP_DF>>8)", eh->dst); + goto raise; + } + + seglen = (medialen - IPHDR) & ~7; + if(seglen < 8){ + netlog(Logip, "%I seglen < 8\n", eh->dst); + goto raise; + } + + dlen = len - IPHDR; + xp = bp; + if(gating) + lid = nhgets(eh->id); + else + lid = Id++; + + offset = IPHDR; + while(xp != nil && offset && offset >= BLEN(xp)) { + offset -= BLEN(xp); + xp = xp->next; + } + xp->rp += offset; + + for(fragoff = 0; fragoff < dlen; fragoff += seglen) { + nb = allocb(IPHDR+seglen); + feh = (Iphdr*)(nb->rp); + + memmove(nb->wp, eh, IPHDR); + nb->wp += IPHDR; + + if((fragoff + seglen) >= dlen) { + seglen = dlen - fragoff; + hnputs(feh->frag, fragoff>>3); + } + else + hnputs(feh->frag, (fragoff>>3)|IP_MF); + + hnputs(feh->length, seglen + IPHDR); + hnputs(feh->id, lid); + + /* Copy up the data area */ + chunk = seglen; + while(chunk) { + if(!xp) { + freeblist(nb); + netlog(Logip, "!xp: chunk %d\n", chunk); + goto raise; + } + blklen = chunk; + if(BLEN(xp) < chunk) + blklen = BLEN(xp); + memmove(nb->wp, xp->rp, blklen); + nb->wp += blklen; + xp->rp += blklen; + chunk -= blklen; + if(xp->rp == xp->wp) + xp = xp->next; + } + + feh->cksum[0] = 0; + feh->cksum[1] = 0; + hnputs(feh->cksum, ipcsum(&feh->vihl)); + Mediawrite(m, nb, gate); + } + +raise: + freeblist(bp); +} + +void +initfrag(int size) +{ + Fragment *fq, *eq; + + fragfree = (Fragment*)malloc(sizeof(Fragment) * size); + if(fragfree == nil) + panic("initfrag"); + + eq = &fragfree[size]; + for(fq = fragfree; fq < eq; fq++) + fq->next = fq+1; + + fragfree[size-1].next = nil; +} + +void (*ipextprotoiput)(Block*); + +void +ipiput(Block *bp) +{ + Iphdr *h; + Proto *p; + ushort frag; + int notforme; + +/* h = (Iphdr *)(bp->rp); + netlog(Logip, "ipiput %I %I len %d proto %d\n", h->src, h->dst, BLEN(bp), h->proto);*/ + + /* Ensure we have enough data to process */ + if(BLEN(bp) < IPHDR) { + bp = pullupblock(bp, IPHDR); + if(bp == nil) + return; + } + h = (Iphdr *)(bp->rp); + + /* Look to see if its for me before we waste time checksumming it */ + notforme = Mediaforme(h->dst) == 0; + if(notforme && !iprouting) { + netlog(Logip, "ip: pkt not for me\n"); + freeblist(bp); + return; + } + + if(ipcsum(&h->vihl)) { + ipcsumerr++; + netlog(Logip, "ip: checksum error %I\n", h->src); + freeblist(bp); + return; + } + + /* Check header length and version */ + if(h->vihl != (IP_VER|IP_HLEN)) { + netlog(Logip, "ip: %I bad hivl %ux\n", h->src, h->vihl); + freeblist(bp); + return; + } + frag = nhgets(h->frag); + if(frag) { + h->tos = 0; + if(frag & IP_MF) + h->tos = 1; + bp = ipreassemble(frag, bp, h); + if(bp == nil) + return; + h = (Iphdr *)(bp->rp); + } + + ipin += blocklen(bp); + ippin++; + + if(iprouting) { + /* gate */ + if(notforme){ + if(h->ttl == 0) + freeblist(bp); + else + ipoput(bp, 1, h->ttl - 1); + return; + } + } + + p = Fsrcvpcol(&fs, h->proto); + if(p != nil && p->rcv != nil) + (*p->rcv)(bp); + else if(ipextprotoiput != nil) + ipextprotoiput(bp); + else + freeblist(bp); +} + +int +ipstats(char *buf, int len) +{ + int n; + + n = snprint(buf, len, "ip: csum %d inb %d outb %d inp %d outp %d\n", + ipcsumerr, ipin, ipout, ippin, ippout); + return n; +} + +QLock iplock; + +Block* +ipreassemble(int offset, Block *bp, Iphdr *ip) +{ + int fend; + ushort id; + Fragment *f, *fnext; + Ipaddr src, dst; + Block *bl, **l, *last, *prev; + int ovlap, len, fragsize, pktposn; + + src = nhgetl(ip->src); + dst = nhgetl(ip->dst); + id = nhgets(ip->id); + + /* + * block lists are too hard, pullupblock into a single block + */ + if(bp->next){ + bp = pullupblock(bp, blocklen(bp)); + ip = (Iphdr *)(bp->rp); + } + + qlock(&iplock); + + /* + * find a reassembly queue for this fragment + */ + qlock(&fraglock); + for(f = flisthead; f; f = fnext){ + fnext = f->next; /* because ipfragfree changes the list */ + if(f->src == src && f->dst == dst && f->id == id) + break; + if(f->age > msec && canqlock(f)) + ipfragfree(f, 0); + } + qunlock(&fraglock); + + /* + * if this isn't a fragmented packet, accept it + * and get rid of any fragments that might go + * with it. + */ + if(!ip->tos && (offset & ~(IP_MF|IP_DF)) == 0) { + if(f != nil) { + qlock(f); + ipfragfree(f, 1); + } + qunlock(&iplock); + return bp; + } + + if(bp->base+sizeof(Ipfrag) >= bp->rp) + panic("ipreassemble"); + + BKFG(bp)->foff = offset<<3; + BKFG(bp)->flen = nhgets(ip->length)-IPHDR; + + /* First fragment allocates a reassembly queue */ + if(f == nil) { + f = ipfragallo(); + qlock(f); + f->id = id; + f->src = src; + f->dst = dst; + + f->blist = bp; + + qunlock(f); + qunlock(&iplock); + return nil; + } + qlock(f); + + /* + * find the new fragment's position in the queue + */ + prev = nil; + l = &f->blist; + bl = f->blist; + while(bl != nil && BKFG(bp)->foff > BKFG(bl)->foff) { + prev = bl; + l = &bl->next; + bl = bl->next; + } + + /* Check overlap of a previous fragment - trim away as necessary */ + if(prev) { + ovlap = BKFG(prev)->foff + BKFG(prev)->flen - BKFG(bp)->foff; + if(ovlap > 0) { + if(ovlap >= BKFG(bp)->flen) { + freeblist(bp); + qunlock(f); + qunlock(&iplock); + return nil; + } + BKFG(prev)->flen -= ovlap; + } + } + + /* Link onto assembly queue */ + bp->next = *l; + *l = bp; + + /* Check to see if succeeding segments overlap */ + if(bp->next) { + l = &bp->next; + fend = BKFG(bp)->foff + BKFG(bp)->flen; + /* Take completely covered segments out */ + while(*l) { + ovlap = fend - BKFG(*l)->foff; + if(ovlap <= 0) + break; + if(ovlap < BKFG(*l)->flen) { + BKFG(*l)->flen -= ovlap; + BKFG(*l)->foff += ovlap; + /* move up ip hdrs */ + memmove((*l)->rp + ovlap, (*l)->rp, IPHDR); + (*l)->rp += ovlap; + break; + } + last = (*l)->next; + (*l)->next = nil; + freeblist(*l); + *l = last; + } + } + + /* + * look for a complete packet. if we get to a fragment + * without IP_MF set, we're done. + */ + pktposn = 0; + for(bl = f->blist; bl; bl = bl->next) { + if(BKFG(bl)->foff != pktposn) + break; + if((BLKIP(bl)->frag[0]&(IP_MF>>8)) == 0) { + bl = f->blist; + len = nhgets(BLKIP(bl)->length); + bl->wp = bl->rp + len; + + /* Pullup all the fragment headers and + * return a complete packet + */ + for(bl = bl->next; bl; bl = bl->next) { + fragsize = BKFG(bl)->flen; + len += fragsize; + bl->rp += IPHDR; + bl->wp = bl->rp + fragsize; + } + + bl = f->blist; + f->blist = nil; + ipfragfree(f, 1); + ip = BLKIP(bl); + hnputs(ip->length, len); + qunlock(&iplock); + return bl; + } + pktposn += BKFG(bl)->flen; + } + qunlock(f); + qunlock(&iplock); + return nil; +} + +/* + * ipfragfree - Free a list of fragments, fragment list must be locked + */ +void +ipfragfree(Fragment *frag, int lockq) +{ + Fragment *fl, **l; + + if(frag->blist) + freeblist(frag->blist); + + frag->src = 0; + frag->id = 0; + frag->blist = nil; + qunlock(frag); + + if(lockq) + qlock(&fraglock); + + l = &flisthead; + for(fl = *l; fl; fl = fl->next) { + if(fl == frag) { + *l = frag->next; + break; + } + l = &fl->next; + } + + frag->next = fragfree; + fragfree = frag; + + if(lockq) + qunlock(&fraglock); +} + +/* + * ipfragallo - allocate a reassembly queue + */ +Fragment * +ipfragallo(void) +{ + Fragment *f; + + qlock(&fraglock); + while(fragfree == nil) { + for(f = flisthead; f; f = f->next) + if(canqlock(f)) { + ipfragfree(f, 0); + break; + } + } + f = fragfree; + fragfree = f->next; + f->next = flisthead; + flisthead = f; + f->age = msec + 30000; + + qunlock(&fraglock); + return f; +} + +ushort +ipcsum(byte *addr) +{ + int len; + ulong sum; + + sum = 0; + len = (addr[0]&0xf)<<2; + + while(len > 0) { + sum += addr[0]<<8 | addr[1] ; + len -= 2; + addr += 2; + } + + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + + return (sum^0xffff); +} diff --git a/ip/ip.h b/ip/ip.h new file mode 100644 index 0000000000000000000000000000000000000000..8195c4bb824d39369c80fc0863b9b78b6f0eb27d --- /dev/null +++ b/ip/ip.h @@ -0,0 +1,248 @@ +typedef ulong Ipaddr; +typedef uchar byte; +typedef struct Conv Conv; +typedef struct Fs Fs; +typedef union Hwaddr Hwaddr; +typedef struct Iproute Iproute; +typedef struct Media Media; +typedef struct Proto Proto; +typedef struct Pstate Pstate; +typedef struct Tcpc Tcpc; + +enum +{ + Addrlen= 64, + Maxproto= 20, + Nhash= 64, + Maxincall= 5, + Nchans= 256, + + MAXTTL= 255, + + Ipbcast= 0xffffffff, /* ip broadcast address */ + Ipbcastobs= 0, /* obsolete (but still used) ip broadcast addr */ +}; + +enum +{ + Announcing= 1, + Announced= 2, + Connecting= 3, + Connected= 4, +}; + +/* + * contained in each conversation + */ +struct Conv +{ + Lock; + + int x; /* conversation index */ + Proto* p; + + Ipaddr laddr; /* local IP address */ + Ipaddr raddr; /* remote IP address */ + int restricted; /* remote port is restricted */ + ushort lport; /* local port number */ + ushort rport; /* remote port number */ + uint ttl; /* max time to live */ + + char owner[NAMELEN]; /* protections */ + int perm; + int inuse; /* opens of listen/data/ctl */ + int length; + int state; + + /* udp specific */ + int headers; /* data src/dst headers in udp */ + int reliable; /* true if reliable udp */ + + Conv* incall; /* calls waiting to be listened for */ + Conv* next; + + Queue* rq; /* queued data waiting to be read */ + Queue* wq; /* queued data waiting to be written */ + Queue* eq; /* returned error packets */ + + QLock car; + Rendez cr; + char cerr[ERRLEN]; + + QLock listenq; + Rendez listenr; + + void* ptcl; /* protocol specific stuff */ +}; + +union Hwaddr +{ + byte ether[6]; +}; + +enum +{ + METHER, /* Media types */ + MFDDI, + MPACKET, +}; + +struct Media +{ + int type; /* Media type */ + Chan* mchan; /* Data channel */ + Chan* achan; /* Arp channel */ + char* dev; /* device mfd points to */ + Ipaddr myip[5]; + Ipaddr mymask; + Ipaddr mynetmask; + Ipaddr remip; /* Address of remote side */ + byte netmyip[4]; /* In Network byte order */ + int arping; /* true if we mus arp */ + int maxmtu; /* Maximum transfer unit */ + int minmtu; /* Minumum tranfer unit */ + int hsize; /* Media header size */ + Hwaddr; + ulong in, out; /* message statistics */ + ulong inerr, outerr; /* ... */ + int inuse; + Conv *c; /* for packet interface */ + + Media* link; +}; +int Mediaforme(byte*); +int Mediaforpt2pt(byte*); +Ipaddr Mediagetsrc(byte*); +void Mediaclose(Media*); +char* Mediaopen(int, char*, Conv*, Ipaddr, Ipaddr, Ipaddr, int, Media**); +Media* Mediaroute(byte*, byte*); +void Mediasetaddr(Media*, Ipaddr, Ipaddr); +void Mediasetraddr(Media*, Ipaddr); +Ipaddr Mediagetaddr(Media*); +Ipaddr Mediagetraddr(Media*); +void Mediawrite(Media*, Block*, byte*); +int Mediaifcread(byte*, ulong, int); +char* Mediaifcwrite(char*, int); +void Mediaresolver(Media*); +void Mediaread(Media*); +int Mediaarp(Media*, Block*, byte*, Hwaddr*); +Media* Mediafind(Iproute*); + +/* + * one per multiplexed protocol + */ +struct Proto +{ + Lock; + char* name; /* protocol name */ + int x; /* protocol index */ + int ipproto; /* ip protocol type */ + + void (*kick)(Conv*, int); + char* (*connect)(Conv*, char**, int); + void (*announce)(Conv*); + int (*state)(char**, Conv*); + void (*create)(Conv*); + void (*close)(Conv*); + void (*rcv)(Block*); + char* (*ctl)(Conv*, char**, int); + void (*advise)(Block*, char*); + + Conv **conv; /* array of conversations */ + int ptclsize; /* size of per protocol ctl block */ + int nc; /* number of conversations */ + int ac; + Qid qid; /* qid for protocol directory */ + ushort nextport; + ushort nextrport; + + ulong csumerr; /* checksum errors */ + ulong hlenerr; /* header length error */ + ulong lenerr; /* short packet */ + ulong order; /* out of order */ + ulong rexmit; /* retransmissions */ +}; + +struct Fs +{ + Lock; + + int np; + Proto* p[Maxproto+1]; /* list of supported protocols */ + Proto* t2p[256]; /* vector of all ip protocol handlers */ +}; +int Fsconnected(Fs*, Conv*, char*); +Conv* Fsnewcall(Fs*, Conv*, Ipaddr, ushort, Ipaddr, ushort); +int Fspcolstats(char*, int); +int Fsproto(Fs*, Proto*); +int Fsbuiltinproto(Fs*, byte); +Conv* Fsprotoclone(Proto*, char*); +Proto* Fsrcvpcol(Fs*, byte); +char* Fsstdconnect(Conv*, char**, int); + +/* log flags */ +enum +{ + Logip= 1<<1, + Logtcp= 1<<2, + Logfs= 1<<3, + Logil= 1<<4, + Logicmp= 1<<5, + Logudp= 1<<6, + Logcompress= 1<<7, + Logilmsg= 1<<8, + Loggre= 1<<9, + Logppp= 1<<10, + Logtcpmsg= 1<<11, +}; + +extern int logmask; /* mask of things to debug */ +extern Ipaddr iponly; /* ip address to print debugging for */ + +void netlogopen(void); +void netlogclose(void); +char* netlogctl(char*, int); +long netlogread(void*, ulong, long); +void netlog(int, char*, ...); + +#define msec TK2MS(MACHP(0)->ticks) + +/* Globals */ +extern int debug; +extern Fs fs; +extern Media* media; +extern int iprouting; /* true if routing turned on */ + +int arpread(byte*, ulong, int); +char* arpwrite(char*, int); +Ipaddr defmask(Ipaddr); +int eipconv(va_list*, Fconv*); +int equivip(byte*, byte*); +void fatal(byte*, ...); +void hnputl(byte*, ulong); +void hnputs(byte*, ushort); +void initfrag(int); +ushort ipcsum(byte*); +void (*ipextprotoiput)(Block*); +Ipaddr ipgetsrc(byte*); +void ipiput(Block*); +void ipoput(Block*, int, int); +int ipstats(char*, int); +byte* logctl(byte*); +void maskip(byte*, byte*, byte*); +ulong nhgetl(byte*); +ushort nhgets(byte*); +void (*pktifcrcv)(Conv*, Block*); +ushort ptclcsum(Block*, int, int); +int pullblock(Block**, int); +Block* pullupblock(Block*, int); +char* routeadd(Ipaddr, Ipaddr, Ipaddr); +void routedelete(ulong, ulong); +int routeread(byte*, ulong, int); +char* routewrite(char*, int); + +/* + * ipaux.c + */ +int myetheraddr(uchar*, char*); +ulong parseip(char*, char*); diff --git a/ip/ipaux.c b/ip/ipaux.c new file mode 100644 index 0000000000000000000000000000000000000000..7abb3f1a55d9ee12ef68d040f11dfa94d0a7376d --- /dev/null +++ b/ip/ipaux.c @@ -0,0 +1,247 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "kernel.h" +#include "ip.h" + +static short endian = 1; +static byte* aendian = (byte*)&endian; +#define LITTLE *aendian + +ushort +ptclbsum(byte *addr, int len) +{ + ulong losum, hisum, mdsum, x; + ulong t1, t2; + + losum = 0; + hisum = 0; + mdsum = 0; + + x = 0; + if((ulong)addr & 1) { + if(len) { + hisum += addr[0]; + len--; + addr++; + } + x = 1; + } + while(len >= 16) { + t1 = *(ushort*)(addr+0); + t2 = *(ushort*)(addr+2); mdsum += t1; + t1 = *(ushort*)(addr+4); mdsum += t2; + t2 = *(ushort*)(addr+6); mdsum += t1; + t1 = *(ushort*)(addr+8); mdsum += t2; + t2 = *(ushort*)(addr+10); mdsum += t1; + t1 = *(ushort*)(addr+12); mdsum += t2; + t2 = *(ushort*)(addr+14); mdsum += t1; + mdsum += t2; + len -= 16; + addr += 16; + } + while(len >= 2) { + mdsum += *(ushort*)addr; + len -= 2; + addr += 2; + } + if(x) { + if(len) + losum += addr[0]; + if(LITTLE) + losum += mdsum; + else + hisum += mdsum; + } else { + if(len) + hisum += addr[0]; + if(LITTLE) + hisum += mdsum; + else + losum += mdsum; + } + + losum += hisum >> 8; + losum += (hisum & 0xff) << 8; + while(hisum = losum>>16) + losum = hisum + (losum & 0xffff); + + return losum & 0xffff; +} + +ushort +ptclcsum(Block *bp, int offset, int len) +{ + byte *addr; + ulong losum, hisum; + ushort csum; + int odd, blocklen, x; + + /* Correct to front of data area */ + while(bp != nil && offset && offset >= BLEN(bp)) { + offset -= BLEN(bp); + bp = bp->next; + } + if(bp == nil) + return 0; + + addr = bp->rp + offset; + blocklen = BLEN(bp) - offset; + + if(bp->next == nil) { + if(blocklen < len) + len = blocklen; + return ~ptclbsum(addr, len) & 0xffff; + } + + losum = 0; + hisum = 0; + + odd = 0; + while(len) { + x = blocklen; + if(len < x) + x = len; + + csum = ptclbsum(addr, x); + if(odd) + hisum += csum; + else + losum += csum; + odd = (odd+x) & 1; + len -= x; + + bp = bp->next; + if(bp == nil) + break; + blocklen = BLEN(bp); + addr = bp->rp; + } + + losum += hisum>>8; + losum += (hisum&0xff)<<8; + while((csum = losum>>16) != 0) + losum = csum + (losum & 0xffff); + + return ~losum & 0xffff; +} + +Ipaddr +defmask(Ipaddr ip) +{ + switch(ip>>30){ + default: + return 0xff000000; + case 2: + return 0xffff0000; + case 3: + return 0xffffff00; + } +} + +int +myetheraddr(uchar *to, char *dev) +{ + int n, fd; + char buf[256], *ptr; + + /* Make one exist */ + if(*dev == '/' || *dev == '#') + sprint(buf, "%s/clone", dev); + else + sprint(buf, "/net/%s/clone", dev); + + fd = kopen(buf, ORDWR); + if(fd >= 0) + kclose(fd); + + if(*dev == '/' || *dev == '#') + sprint(buf, "%s/0/stats", dev); + else + sprint(buf, "/net/%s/0/stats", dev); + fd = kopen(buf, OREAD); + if(fd < 0) + return -1; + + n = kread(fd, buf, sizeof(buf)-1); + kclose(fd); + if(n <= 0) + return -1; + buf[n] = 0; + + ptr = strstr(buf, "addr: "); + if(!ptr) + return -1; + ptr += 6; + + parseether(to, ptr); + return 0; +} + +int +eipconv(va_list *arg, Fconv *f) +{ + char buf[64]; + static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux"; + static char *ifmt = "%d.%d.%d.%d"; + uchar *p, ip[4]; + + switch(f->chr) { + case 'E': /* Ethernet address */ + p = va_arg(*arg, uchar*); + sprint(buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]); + break; + case 'I': /* Ip address */ + p = va_arg(*arg, uchar*); + sprint(buf, ifmt, p[0], p[1], p[2], p[3]); + break; + case 'i': + hnputl(ip, va_arg(*arg, ulong)); + sprint(buf, ifmt, ip[0], ip[1], ip[2], ip[3]); + break; + default: + strcpy(buf, "(eipconv)"); + } + strconv(buf, f); + return sizeof(uchar*); +} + +#define CLASS(p) ((*(uchar*)(p))>>6) + +ulong +parseip(char *to, char *from) +{ + int i; + char *p; + + p = from; + memset(to, 0, 4); + for(i = 0; i < 4 && *p; i++){ + to[i] = strtoul(p, &p, 0); + if(*p == '.') + p++; + } + switch(CLASS(to)){ + case 0: /* class A - 1 byte net */ + case 1: + if(i == 3){ + to[3] = to[2]; + to[2] = to[1]; + to[1] = 0; + } else if (i == 2){ + to[3] = to[1]; + to[1] = 0; + } + break; + case 2: /* class B - 2 byte net */ + if(i == 3){ + to[3] = to[2]; + to[2] = 0; + } + break; + } + return nhgetl((uchar*)to); +} diff --git a/ip/kernel.h b/ip/kernel.h new file mode 100644 index 0000000000000000000000000000000000000000..206f391f2e79a50ef78df3ddbc39be18a309bfe0 --- /dev/null +++ b/ip/kernel.h @@ -0,0 +1,15 @@ +extern long kclose(int); +extern int kdial(char*, char*, char*, int*); +extern void kerrstr(char*); +extern void kgerrstr(char*); +extern long kopen(char*, int); +extern long kread(int, void*, long); +extern long kseek(int, int, int); +extern long kwrite(int, void*, long); +extern void kwerrstr(char *, ...); + +extern char* strdup(char*); +extern char* strrchr(char*, char); +extern char* strstr(char*, char*); + +extern int newfd(Chan*); diff --git a/ip/kio.c b/ip/kio.c new file mode 100644 index 0000000000000000000000000000000000000000..6f683ba1c894f790c430639a9201816d4217ad0a --- /dev/null +++ b/ip/kio.c @@ -0,0 +1,198 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "kernel.h" + +#define validaddr(a, b, c) + +long +kclose(int fd) +{ + if(waserror()) + return -1; + /* + * Take no reference on the chan because we don't really need the + * data structure, and are calling fdtochan only for error checks. + * fdclose takes care of processes racing through here. + */ + fdtochan(fd, -1, 0, 0); + fdclose(fd, 0); + + poperror(); + return 0; +} + +long +kopen(char *path, int mode) +{ + int fd; + Chan *c = 0; + + if(waserror()) { + if(c) + cclose(c); + return -1; + } + + openmode(mode); + validaddr((ulong)path, 1, 0); + c = namec(path, Aopen, mode, 0); + fd = newfd(c); + + poperror(); + return fd; +} + +long +kread(int fd, void *va, long n) +{ + int dir; + Chan *c; + + if(waserror()) + return -1; + + validaddr((ulong)va, n, 1); + c = fdtochan(fd, OREAD, 1, 1); + if(waserror()) { + cclose(c); + nexterror(); + } + + dir = c->qid.path&CHDIR; + if(dir) { + n -= n%DIRLEN; + if(c->offset%DIRLEN || n==0) + error(Etoosmall); + } + + if(dir && c->mnt) + n = unionread(c, va, n); + else if(devchar[c->type] != L'M') + n = devtab[c->type]->read(c, va, n, c->offset); + else + n = mntread9p(c, va, n, c->offset); + + lock(c); + c->offset += n; + unlock(c); + + poperror(); + cclose(c); + + poperror(); + return n; +} + +long +kseek(int fd, int offset, int whence) +{ + Chan *c; + char buf[DIRLEN]; + Dir dir; + long off; + + if(waserror()) + return -1; + + c = fdtochan(fd, -1, 1, 1); + if(waserror()) { + cclose(c); + nexterror(); + } + if(c->qid.path & CHDIR) + error(Eisdir); + + if(devchar[c->type] == '|') + error(Eisstream); + + off = 0; + switch(whence) { + case 0: + off = c->offset = offset; + break; + case 1: + lock(c); /* lock for read/write update */ + c->offset += offset; + off = c->offset; + unlock(c); + break; + case 2: + devtab[c->type]->stat(c, buf); + convM2D(buf, &dir); + c->offset = dir.length + offset; + off = c->offset; + break; + } + poperror(); + cclose(c); + poperror(); + return off; +} + +long +kwrite(int fd, void *va, long n) +{ + Chan *c; + + if(waserror()) + return -1; + + validaddr((ulong)va, n, 0); + c = fdtochan(fd, OWRITE, 1, 1); + if(waserror()) { + cclose(c); + nexterror(); + } + + if(c->qid.path & CHDIR) + error(Eisdir); + + n = devtab[c->type]->write(c, va, n, c->offset); + + lock(c); + c->offset += n; + unlock(c); + + poperror(); + cclose(c); + + poperror(); + return n; +} + +/* Set kernel error string */ +void +kerrstr(char *err) +{ + if(up != nil) + strncpy(up->error, err, ERRLEN); +} + +/* Get kernel error string */ +void +kgerrstr(char *err) +{ + char *s; + + s = ""; + if(up != nil) + s = up->error; + strncpy(err, s, ERRLEN); +} + +/* Set kernel error string, using formatted print */ +void +kwerrstr(char *fmt, ...) +{ + va_list arg; + char buf[256]; + + va_start(arg, fmt); + doprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + strncpy(up->error, buf, ERRLEN); +} diff --git a/ip/netlog.c b/ip/netlog.c new file mode 100644 index 0000000000000000000000000000000000000000..8672b7af0c2b44803298b04b82239c8c348e3194 --- /dev/null +++ b/ip/netlog.c @@ -0,0 +1,232 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "../ip/ip.h" + +int logmask; /* mask of things to debug */ +Ipaddr iponly; /* ip address to print debugging for */ + +enum { + Nlog = 4*1024, +}; + +/* + * action log + */ +typedef struct Log { + Lock; + int opens; + char* buf; + char *end; + char *rptr; + int len; + + QLock; + Rendez; +} Log; +static Log alog; + +typedef struct Logflag { + char* name; + int mask; +} Logflag; +static Logflag flags[] = +{ + { "ppp", Logppp, }, + { "ip", Logip, }, + { "fs", Logfs, }, + { "tcp", Logtcp, }, + { "il", Logil, }, + { "icmp", Logicmp, }, + { "udp", Logudp, }, + { "compress", Logcompress, }, + { "ilmsg", Logil|Logilmsg, }, + { "gre", Loggre, }, + { "tcpmsg", Logtcp|Logtcpmsg, }, + { nil, 0, }, +}; + +static char Ebadnetctl[] = "unknown netlog ctl message"; + +void +netlogopen(void) +{ + lock(&alog); + if(waserror()){ + unlock(&alog); + nexterror(); + } + if(alog.opens == 0){ + if(alog.buf == nil) + alog.buf = malloc(Nlog); + alog.rptr = alog.buf; + alog.end = alog.buf + Nlog; + } + alog.opens++; + unlock(&alog); + poperror(); +} + +void +netlogclose(void) +{ + lock(&alog); + if(waserror()){ + unlock(&alog); + nexterror(); + } + alog.opens--; + if(alog.opens == 0){ + free(alog.buf); + alog.buf = nil; + } + unlock(&alog); + poperror(); +} + +static int +netlogready(void*) +{ + return alog.len; +} + +long +netlogread(void* a, ulong, long n) +{ + int i, d; + char *p, *rptr; + + qlock(&alog); + if(waserror()){ + qunlock(&alog); + nexterror(); + } + + for(;;){ + lock(&alog); + if(alog.len){ + if(n > alog.len) + n = alog.len; + d = 0; + rptr = alog.rptr; + alog.rptr += n; + if(alog.rptr >= alog.end){ + d = alog.rptr - alog.end; + alog.rptr = alog.buf + d; + } + alog.len -= n; + unlock(&alog); + + i = n; + p = a; + if(d){ + memmove(p, rptr, d); + i -= d; + p += d; + rptr = alog.buf; + } + memmove(p, rptr, i); + break; + } + else + unlock(&alog); + + sleep(&alog, netlogready, 0); + } + + qunlock(&alog); + poperror(); + + return n; +} + +char* +netlogctl(char* s, int len) +{ + int i, n, set; + Logflag *f; + char *fields[10], *p, addr[4], buf[256]; + + if(len == 0) + return Ebadnetctl; + + if(len >= sizeof(buf)) + len = sizeof(buf)-1; + strncpy(buf, s, len); + buf[len] = 0; + if(len > 0 && buf[len-1] == '\n') + buf[len-1] = 0; + + n = parsefields(buf, fields, 10, " "); + if(n < 2) + return Ebadnetctl; + + if(strcmp("set", fields[0]) == 0) + set = 1; + else if(strcmp("clear", fields[0]) == 0) + set = 0; + else if(strcmp("only", fields[0]) == 0){ + iponly = parseip(addr, fields[1]); + return nil; + } else + return Ebadnetctl; + + p = strchr(fields[n-1], '\n'); + if(p) + *p = 0; + + for(i = 1; i < n; i++){ + for(f = flags; f->name; f++) + if(strcmp(f->name, fields[i]) == 0) + break; + if(f->name == nil) + continue; + if(set) + logmask |= f->mask; + else + logmask &= ~f->mask; + } + + return nil; +} + +void +netlog(int mask, char *fmt, ...) +{ + char buf[128], *t, *f; + int i, n; + va_list arg; + + if(alog.opens == 0 || !(logmask & mask)) + return; + + va_start(arg, fmt); + n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; + va_end(arg); + + if(alog.opens == 0) + return; + + lock(&alog); + i = alog.len + n - Nlog; + if(i > 0){ + alog.len -= i; + alog.rptr += i; + if(alog.rptr >= alog.end) + alog.rptr = alog.buf + (alog.rptr - alog.end); + } + t = alog.rptr + alog.len; + f = buf; + alog.len += n; + while(n-- > 0){ + if(t >= alog.end) + t = alog.buf + (t - alog.end); + *t++ = *f++; + } + unlock(&alog); + + wakeup(&alog); +} diff --git a/ip/tcp.c b/ip/tcp.c new file mode 100644 index 0000000000000000000000000000000000000000..2cf9aeffb9d699f6bedf88cd7685c531d546ab40 --- /dev/null +++ b/ip/tcp.c @@ -0,0 +1,1937 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "ip.h" + +enum +{ + QMAX = 64*1024-1, + IP_TCPPROTO = 6, + TCP_IPLEN = 8, + TCP_PHDRSIZE = 12, + TCP_HDRSIZE = 20, + TCP_PKT = TCP_IPLEN+TCP_PHDRSIZE, + TimerOFF = 0, + TimerON = 1, + TimerDONE = 2, + MAX_TIME = (1<<20), /* Forever */ + TCP_ACK = 50, /* Timed ack sequence in ms */ + + URG = 0x20, /* Data marked urgent */ + ACK = 0x10, /* Acknowledge is valid */ + PSH = 0x08, /* Whole data pipe is pushed */ + RST = 0x04, /* Reset connection */ + SYN = 0x02, /* Pkt. is synchronise */ + FIN = 0x01, /* Start close down */ + + EOLOPT = 0, + NOOPOPT = 1, + MAXBACKOFF = 20, + MSSOPT = 2, + MSS_LENGTH = 4, /* Mean segment size */ + MSL2 = 10, + MSPTICK = 50, /* Milliseconds per timer tick */ + DEF_MSS = 1024, /* Default mean segment */ + DEF_RTT = 150, /* Default round trip */ + TCP_LISTEN = 0, /* Listen connection */ + TCP_CONNECT = 1, /* Outgoing connection */ + + FORCE = 1, + CLONE = 2, + RETRAN = 4, + ACTIVE = 8, + SYNACK = 16, + ACKED = 32, + + LOGAGAIN = 3, + LOGDGAIN = 2, + Closed = 0, /* Connection states */ + Listen, + Syn_sent, + Syn_received, + Established, + Finwait1, + Finwait2, + Close_wait, + Closing, + Last_ack, + Time_wait +}; + +/* Must correspond to the enumeration above */ +char *tcpstates[] = +{ + "Closed", "Listen", "Syn_sent", "Syn_received", + "Established", "Finwait1", "Finwait2", "Close_wait", + "Closing", "Last_ack", "Time_wait" +}; + +typedef struct Timer Timer; +struct Timer +{ + Timer *next; + Timer *prev; + int state; + int start; + int count; + void (*func)(void*); + void *arg; +}; + +typedef struct Tcphdr Tcphdr; +struct Tcphdr +{ + byte vihl; /* Version and header length */ + byte tos; /* Type of service */ + byte length[2]; /* packet length */ + byte id[2]; /* Identification */ + byte frag[2]; /* Fragment information */ + byte Unused; + byte proto; + byte tcplen[2]; + byte tcpsrc[4]; + byte tcpdst[4]; + byte tcpsport[2]; + byte tcpdport[2]; + byte tcpseq[4]; + byte tcpack[4]; + byte tcpflag[2]; + byte tcpwin[2]; + byte tcpcksum[2]; + byte tcpurg[2]; + /* Options segment */ + byte tcpopt[2]; + byte tcpmss[2]; +}; + +typedef struct Tcp Tcp; +struct Tcp +{ + ushort source; + ushort dest; + ulong seq; + ulong ack; + byte flags; + ushort wnd; + ushort urg; + ushort mss; +}; + +typedef struct Reseq Reseq; +struct Reseq +{ + Reseq *next; + Tcp seg; + Block *bp; + ushort length; +}; + +typedef struct Tcpctl Tcpctl; +struct Tcpctl +{ + QLock; + byte state; /* Connection state */ + byte type; /* Listening or active connection */ + byte code; /* Icmp code */ + struct { + ulong una; /* Unacked data pointer */ + ulong nxt; /* Next sequence expected */ + ulong ptr; /* Data pointer */ + ushort wnd; /* Tcp send window */ + ulong urg; /* Urgent data pointer */ + ulong wl1; + ulong wl2; + } snd; + struct { + ulong nxt; /* Receive pointer to next byte slot */ + ushort wnd; /* Receive window incoming */ + ulong urg; /* Urgent pointer */ + int blocked; + } rcv; + ulong iss; /* Initial sequence number */ + ushort cwind; /* Congestion window */ + ushort ssthresh; /* Slow start threshold */ + int resent; /* Bytes just resent */ + int irs; /* Initial received squence */ + ushort mss; /* Mean segment size */ + int rerecv; /* Overlap of data rerecevived */ + ushort window; /* Recevive window */ + int max_snd; /* Max send */ + ulong last_ack; /* Last acknowledege received */ + byte backoff; /* Exponential backoff counter */ + byte flags; /* State flags */ + ulong sndcnt; /* Amount of data in send queue */ + Reseq *reseq; /* Resequencing queue */ + Timer timer; /* Activity timer */ + Timer acktimer; /* Acknowledge timer */ + Timer rtt_timer; /* Round trip timer */ + ulong rttseq; /* Round trip sequence */ + int srtt; /* Shortened round trip */ + int mdev; /* Mean deviation of round trip */ + int kacounter; /* count down for keep alive */ + int f2counter; /* count down for finwait2 state */ + uint sndsyntime; /* time syn sent */ + char ascstate[128]; +}; + +#define DBG(x) if((logmask & Logtcpmsg) && (iponly == 0 || x == iponly))netlog + +Proto tcp; +int tcp_irtt = DEF_RTT; /* Initial guess at round trip time */ +ushort tcp_mss = DEF_MSS; /* Maximum segment size to be sent */ +Timer *timers; /* List of active timers */ +QLock tl; /* Protect timer list */ + +void addreseq(Tcpctl*, Tcp*, Block*, ushort); +void getreseq(Tcpctl*, Tcp*, Block**, ushort*); +void localclose(Conv*, char*); +void procsyn(Conv*, Tcp*); +void tcpiput(Block*); +void tcpoutput(Conv*); +int tcptrim(Tcpctl*, Tcp*, Block**, ushort*); +void tcpstart(Conv*, int, ushort); +void tcptimeout(void*); +void tcpsndsyn(Tcpctl*); +void tcprcvwin(Conv*); +void tcpacktimer(Conv*); + +void +tcpsetstate(Conv *s, byte newstate) +{ + Tcpctl *tcb; + byte oldstate; + + tcb = (Tcpctl*)s->ptcl; + + oldstate = tcb->state; + if(oldstate == newstate) + return; + + /* + print("%d/%d %s->%s\n", s->lport, s->rport, + tcpstates[oldstate], tcpstates[newstate]); + /**/ + + tcb->state = newstate; + + switch(newstate) { + case Closed: + qclose(s->rq); + qclose(s->wq); + qclose(s->eq); + s->lport = 0; /* This connection is toast */ + s->rport = 0; + s->raddr = 0; + + case Close_wait: /* Remote closes */ + qhangup(s->rq, nil); + break; + } + + if(oldstate == Syn_sent) + Fsconnected(&fs, s, nil); +} + +static char* +tcpconnect(Conv *c, char **argv, int argc) +{ + char *rv; + + rv = Fsstdconnect(c, argv, argc); + if(rv) + return rv; + tcpstart(c, TCP_CONNECT, QMAX); + return rv; +} + +int +tcpstate(char **msg, Conv *c) +{ + Tcpctl *s; + int isclose; + + s = (Tcpctl*)(c->ptcl); + + isclose = 0; + if(s->state == Closed) + isclose = 1; + +/* snprint(s->ascstate, sizeof(s->ascstate), + "tcnt %d tnxt %lux tuna %lux twnd %d rack %lux rnxt %lux rwnd %d", + s->sndcnt, s->snd.nxt, s->snd.una, s->snd.wnd, + s->last_ack, s->rcv.nxt, s->rcv.wnd);*/ + snprint(s->ascstate, sizeof(s->ascstate), + "%s srtt %d mdev %d timer.start %d timer.count %d\n", + tcpstates[s->state], s->srtt, s->mdev, + s->timer.start, s->timer.count); + + *msg = s->ascstate; + return isclose; +} + +static void +tcpannounce(Conv *c) +{ + tcpstart(c, TCP_LISTEN, QMAX); + Fsconnected(&fs, c, nil); +} + +static void +tcpclose(Conv *c) +{ + Tcpctl *tcb; + + tcb = (Tcpctl*)c->ptcl; + + qhangup(c->rq, nil); + qhangup(c->wq, nil); + qhangup(c->eq, nil); + + unlock(c); + + switch(tcb->state) { + case Listen: + /* + * reset any incoming calls to this listener + */ + Fsconnected(&fs, c, "Hangup"); + + qlock(tcb); + localclose(c, nil); + break; + case Closed: + case Syn_sent: + qlock(tcb); + localclose(c, nil); + break; + case Syn_received: + case Established: + qlock(tcb); + tcb->sndcnt++; + tcb->snd.nxt++; + tcpsetstate(c, Finwait1); + tcpoutput(c); + break; + case Close_wait: + qlock(tcb); + tcb->sndcnt++; + tcb->snd.nxt++; + tcpsetstate(c, Last_ack); + tcpoutput(c); + break; + } + qunlock(tcb); +} + +void +tcpkick(Conv *s, int len) +{ + Tcpctl *tcb; + + tcb = (Tcpctl*)s->ptcl; + + + switch(tcb->state) { + case Listen: + tcb->flags |= ACTIVE; + tcpsndsyn(tcb); + tcpsetstate(s, Syn_sent); + /* No break */ + case Syn_sent: + case Syn_received: + case Established: + case Close_wait: + /* + * Push data + */ + qlock(tcb); + tcb->sndcnt += len; + tcprcvwin(s); + tcpoutput(s); + qunlock(tcb); + break; + default: + localclose(s, "Hangup"); + } +} + +/* + * get remote sender going if it was flow controlled due to a closed window + */ +static void +deltimer(Timer *t) +{ + if(timers == t) + timers = t->next; + if(t->next) + t->next->prev = t->prev; + if(t->prev) + t->prev->next = t->next; +} + +void +tcprcvwin(Conv *s) /* Call with tcb locked */ +{ + int w; + Tcpctl *tcb; + + tcb = (Tcpctl*)s->ptcl; + w = QMAX - qlen(s->rq); + if(w < 0) + w = 0; + tcb->rcv.wnd = w; + if(w == 0) + tcb->rcv.blocked = 1; +} + +void +tcpacktimer(Conv *s) +{ + Tcpctl *tcb; + + tcb = (Tcpctl*)s->ptcl; + + qlock(tcb); + tcb->flags |= FORCE; + tcprcvwin(s); + tcpoutput(s); + qunlock(tcb); +} + +static void +tcpcreate(Conv *c) +{ + c->rq = qopen(QMAX, 0, tcpacktimer, c); + c->wq = qopen(QMAX, 0, 0, 0); +} + +void +tcpackproc(void*) +{ + Timer *t, *tp, *timeo; + static Rendez tcpr; + + for(;;) { + tsleep(&tcpr, return0, 0, MSPTICK); + + qlock(&tl); + timeo = nil; + for(t = timers; t != nil; t = tp) { + tp = t->next; + if(t->state == TimerON) { + t->count--; + if(t->count == 0) { + deltimer(t); + t->state = TimerDONE; + t->next = timeo; + timeo = t; + } + } + } + qunlock(&tl); + + for(;;) { + t = timeo; + if(t == nil) + break; + + timeo = t->next; + if(t->state == TimerDONE && t->func != nil) + (*t->func)(t->arg); + } + } +} + +void +tcpgo(Timer *t) +{ + if(t == nil || t->start == 0) + return; + + qlock(&tl); + t->count = t->start; + if(t->state != TimerON) { + t->state = TimerON; + t->prev = nil; + t->next = timers; + if(t->next) + t->next->prev = t; + timers = t; + } + qunlock(&tl); +} + +void +tcphalt(Timer *t) +{ + if(t == nil) + return; + + qlock(&tl); + if(t->state == TimerON) + deltimer(t); + t->state = TimerOFF; + qunlock(&tl); +} + +int +backoff(int n) +{ + if(n < 5) + return 1 << n; + + return 64; +} + +void +localclose(Conv *s, char *reason) /* called with tcb locked */ +{ + Tcpctl *tcb; + Reseq *rp,*rp1; + + tcb = (Tcpctl*)s->ptcl; + + tcphalt(&tcb->timer); + tcphalt(&tcb->rtt_timer); + + /* Flush reassembly queue; nothing more can arrive */ + for(rp = tcb->reseq; rp != nil; rp = rp1) { + rp1 = rp->next; + freeblist(rp->bp); + free(rp); + } + + if(tcb->state == Syn_sent) + Fsconnected(&fs, s, reason); + + qhangup(s->rq, reason); + qhangup(s->wq, reason); + + tcb->reseq = nil; + tcpsetstate(s, Closed); +} + +void +inittcpctl(Conv *s) +{ + Tcpctl *tcb; + + tcb = (Tcpctl*)s->ptcl; + + memset(tcb, 0, sizeof(Tcpctl)); + + tcb->cwind = tcp_mss; + tcb->mss = tcp_mss; + tcb->ssthresh = 65535; + tcb->srtt = 0; + + tcb->timer.start = tcp_irtt / MSPTICK; + tcb->timer.func = tcptimeout; + tcb->timer.arg = s; + tcb->rtt_timer.start = MAX_TIME; + tcb->acktimer.start = TCP_ACK / MSPTICK; + tcb->acktimer.func = tcpacktimer; + tcb->acktimer.arg = s; +} + +/* mtu (- TCP + IP hdr len) of 1st hop */ +int +tcpmtu(Conv *s) +{ + Media *m; + byte dst[4], dummy[4]; + int mtu; + + mtu = 0; + hnputl(dst, s->raddr); + m = Mediaroute(dst, dummy); + if(m != nil) + mtu = m->maxmtu - m->hsize - (TCP_PKT + TCP_HDRSIZE); + if(mtu < 4) + mtu = DEF_MSS; + return mtu; +} + +void +tcpstart(Conv *s, int mode, ushort window) +{ + Tcpctl *tcb; + + tcb = (Tcpctl*)s->ptcl; + + inittcpctl(s); + tcb->window = window; + tcb->rcv.wnd = window; + + switch(mode) { + case TCP_LISTEN: + tcb->flags |= CLONE; + tcpsetstate(s, Listen); + break; + + case TCP_CONNECT: + /* Send SYN, go into SYN_SENT state */ + qlock(tcb); + tcb->flags |= ACTIVE; + tcpsndsyn(tcb); + tcpsetstate(s, Syn_sent); + tcpoutput(s); + qunlock(tcb); + break; + } +} + +static char* +tcpflag(ushort flag) +{ + static char buf[128]; + + sprint(buf, "%d", flag>>10); /* Head len */ + if(flag & URG) + strcat(buf, " URG"); + if(flag & ACK) + strcat(buf, " ACK"); + if(flag & PSH) + strcat(buf, " PSH"); + if(flag & RST) + strcat(buf, " RST"); + if(flag & SYN) + strcat(buf, " SYN"); + if(flag & FIN) + strcat(buf, " FIN"); + + return buf; +} + +Block * +htontcp(Tcp *tcph, Block *data, Tcphdr *ph) +{ + int dlen; + Tcphdr *h; + ushort csum; + ushort hdrlen; + + hdrlen = TCP_HDRSIZE; + if(tcph->mss) + hdrlen += MSS_LENGTH; + + if(data) { + dlen = blocklen(data); + data = padblock(data, hdrlen + TCP_PKT); + if(data == nil) + return nil; + } + else { + dlen = 0; + data = allocb(hdrlen + TCP_PKT); + if(data == nil) + return nil; + data->wp += hdrlen + TCP_PKT; + } + + + memmove(data->rp, ph, TCP_PKT); + + h = (Tcphdr *)(data->rp); + h->proto = IP_TCPPROTO; + h->frag[0] = 0; + h->frag[1] = 0; + hnputs(h->tcplen, hdrlen + dlen); + hnputs(h->tcpsport, tcph->source); + hnputs(h->tcpdport, tcph->dest); + hnputl(h->tcpseq, tcph->seq); + hnputl(h->tcpack, tcph->ack); + hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags); + hnputs(h->tcpwin, tcph->wnd); + h->tcpcksum[0] = 0; + h->tcpcksum[1] = 0; + h->Unused = 0; + hnputs(h->tcpurg, tcph->urg); + + if(tcph->mss != 0){ + h->tcpopt[0] = MSSOPT; + h->tcpopt[1] = MSS_LENGTH; + hnputs(h->tcpmss, tcph->mss); + } + csum = ptclcsum(data, TCP_IPLEN, hdrlen+dlen+TCP_PHDRSIZE); + hnputs(h->tcpcksum, csum); + + DBG(nhgetl(h->tcpdst))(Logtcpmsg, "%d > %d s %l8.8ux a %8.8lux %s w %.4ux l %d\n", + tcph->source, tcph->dest, + tcph->seq, tcph->ack, tcpflag((hdrlen<<10)|tcph->flags), + tcph->wnd, dlen); + + return data; +} + +int +ntohtcp(Tcp *tcph, Block **bpp) +{ + Tcphdr *h; + byte *optr; + ushort hdrlen; + ushort i, optlen; + + *bpp = pullupblock(*bpp, TCP_PKT+TCP_HDRSIZE); + if(*bpp == nil) + return -1; + + h = (Tcphdr *)((*bpp)->rp); + tcph->source = nhgets(h->tcpsport); + tcph->dest = nhgets(h->tcpdport); + tcph->seq = nhgetl(h->tcpseq); + tcph->ack = nhgetl(h->tcpack); + + hdrlen = (h->tcpflag[0] & 0xf0)>>2; + if(hdrlen < TCP_HDRSIZE) { + freeblist(*bpp); + return -1; + } + + tcph->flags = h->tcpflag[1]; + tcph->wnd = nhgets(h->tcpwin); + tcph->urg = nhgets(h->tcpurg); + tcph->mss = 0; + + *bpp = pullupblock(*bpp, hdrlen+TCP_PKT); + if(*bpp == nil) + return -1; + + DBG(nhgetl(h->tcpsrc))(Logtcpmsg, "%d > %d s %l8.8ux a %8.8lux %s w %.4ux l %d\n", + tcph->source, tcph->dest, + tcph->seq, tcph->ack, tcpflag((hdrlen<<10)|tcph->flags), + tcph->wnd, nhgets(h->length)-hdrlen-TCP_PKT); + + optr = h->tcpopt; + for(i = TCP_HDRSIZE; i < hdrlen;) { + switch(*optr++) { + case EOLOPT: + return hdrlen; + case NOOPOPT: + i++; + break; + case MSSOPT: + optlen = *optr++; + if(optlen == MSS_LENGTH) + tcph->mss = nhgets(optr); + i += optlen; + break; + } + } + return hdrlen; +} + +/* Generate an initial sequence number and put a SYN on the send queue */ +void +tcpsndsyn(Tcpctl *tcb) +{ + tcb->iss = (nrand(1<<16)<<16)|nrand(1<<16); + tcb->rttseq = tcb->iss; + tcb->snd.wl2 = tcb->iss; + tcb->snd.una = tcb->iss; + tcb->snd.ptr = tcb->rttseq; + tcb->snd.nxt = tcb->rttseq; + tcb->sndcnt++; + tcb->flags |= FORCE; + tcb->sndsyntime = msec; +} + +void +sndrst(Ipaddr source, Ipaddr dest, ushort length, Tcp *seg) +{ + ushort tmp; + Tcphdr ph; + Block *hbp; + byte rflags; + + if(seg->flags & RST) + return; + + + hnputl(ph.tcpsrc, dest); + hnputl(ph.tcpdst, source); + ph.proto = IP_TCPPROTO; + hnputs(ph.tcplen, TCP_HDRSIZE); + + /* Swap port numbers */ + tmp = seg->dest; + seg->dest = seg->source; + seg->source = tmp; + + rflags = RST; + + /* convince the other end that this reset is in band */ + if(seg->flags & ACK) { + seg->seq = seg->ack; + seg->ack = 0; + } + else { + rflags |= ACK; + seg->ack = seg->seq; + seg->seq = 0; + if(seg->flags & SYN) + seg->ack++; + seg->ack += length; + if(seg->flags & FIN) + seg->ack++; + } + seg->flags = rflags; + seg->wnd = 0; + seg->urg = 0; + seg->mss = 0; + hbp = htontcp(seg, nil, &ph); + if(hbp == nil) + return; + + ipoput(hbp, 0, MAXTTL); +} + +/* + * flush an incoming call; send a reset to the remote side and close the + * conversation + */ +void +tcpflushincoming(Conv *s) +{ + Tcp seg; + byte dst[4]; + Tcpctl *tcb; + + tcb = (Tcpctl*)s->ptcl; + + seg.source = s->rport; + seg.dest = s->lport; + seg.flags = ACK; + seg.seq = tcb->snd.ptr; + tcb->last_ack = tcb->rcv.nxt; + seg.ack = tcb->rcv.nxt; + + if(s->laddr == 0) { + hnputl(dst, s->raddr); + s->laddr = Mediagetsrc(dst); + } + sndrst(s->raddr, s->laddr, 0, &seg); + localclose(s, nil); +} + +/* + * send a reset to the remote side and close the conversation + */ +char* +tcphangup(Conv *s) +{ + Tcp seg; + byte dst[4]; + Tcpctl *tcb; + Tcphdr ph; + Block *hbp; + + tcb = (Tcpctl*)s->ptcl; + if(waserror()){ + qunlock(tcb); + return up->error; + } + qlock(tcb); + if(s->raddr != 0) { + seg.source = s->lport; + seg.dest = s->rport; + seg.flags = RST | ACK; + seg.ack = tcb->rcv.nxt; + seg.seq = tcb->snd.ptr; + seg.wnd = 0; + seg.urg = 0; + seg.mss = 0; + tcb->last_ack = tcb->rcv.nxt; + if(s->laddr == 0) { + hnputl(dst, s->raddr); + s->laddr = Mediagetsrc(dst); + } + hnputl(ph.tcpsrc, s->laddr); + hnputl(ph.tcpdst, s->raddr); + ph.proto = IP_TCPPROTO; + hnputs(ph.tcplen, TCP_HDRSIZE); + hbp = htontcp(&seg, nil, &ph); + ipoput(hbp, 0, s->ttl); + } + localclose(s, nil); + poperror(); + qunlock(tcb); + return nil; +} + +Conv* +tcpincoming(Conv *s, Tcp *segp, Ipaddr src, Ipaddr dst) +{ + Conv *new; + Tcpctl *tcb; + + new = Fsnewcall(&fs, s, src, segp->source, dst, segp->dest); + if(new == nil) + return nil; + + memmove(new->ptcl, s->ptcl, sizeof(Tcpctl)); + tcb = (Tcpctl*)new->ptcl; + tcb->flags &= ~CLONE; + tcb->timer.arg = new; + tcb->timer.state = TimerOFF; + tcb->acktimer.arg = new; + tcb->acktimer.state = TimerOFF; + + return new; +} + +int +seq_within(ulong x, ulong low, ulong high) +{ + if(low <= high){ + if(low <= x && x <= high) + return 1; + } + else { + if(low >= x && x >= high) + return 1; + } + return 0; +} + +int +seq_lt(ulong x, ulong y) +{ + return x < y; +} + +int +seq_le(ulong x, ulong y) +{ + return x <= y; +} + +int +seq_gt(ulong x, ulong y) +{ + return x > y; +} + +int +seq_ge(ulong x, ulong y) +{ + return x >= y; +} + +/* + * use the time between the first SYN and it's ack as the + * initial round trip time + */ +void +tcpsynackrtt(Conv *s) +{ + Tcpctl *tcb; + int delta; + + tcb = (Tcpctl*)s->ptcl; + + delta = msec - tcb->sndsyntime; + tcb->srtt = delta<mdev = delta<rtt_timer); +} + +void +update(Conv *s, Tcp *seg) +{ + int rtt, delta; + Tcpctl *tcb; + ushort acked, expand; + + tcb = (Tcpctl*)s->ptcl; + + tcb->kacounter = MAXBACKOFF; /* keep alive count down */ + + if(seq_gt(seg->ack, tcb->snd.nxt)) { + tcb->flags |= FORCE; + return; + } + + if(seq_ge(seg->ack,tcb->snd.wl2)) + if(seq_gt(seg->seq,tcb->snd.wl1) || (seg->seq == tcb->snd.wl1)) { + if(seg->wnd != 0 && tcb->snd.wnd == 0) + tcb->snd.ptr = tcb->snd.una; + + tcb->snd.wnd = seg->wnd; + tcb->snd.wl1 = seg->seq; + tcb->snd.wl2 = seg->ack; + } + + if(!seq_gt(seg->ack, tcb->snd.una)) + return; + + /* something new was acked in this packet */ + tcb->flags |= ACKED; + + /* Compute the new send window size */ + acked = seg->ack - tcb->snd.una; + if(tcb->cwind < tcb->snd.wnd) { + if(tcb->cwind < tcb->ssthresh) { + expand = tcb->mss; + if(acked < expand) + expand = acked; + } + else + expand = ((int)tcb->mss * tcb->mss) / tcb->cwind; + + if(tcb->cwind + expand < tcb->cwind) + expand = 65535 - tcb->cwind; + if(tcb->cwind + expand > tcb->snd.wnd) + expand = tcb->snd.wnd - tcb->cwind; + if(expand != 0) + tcb->cwind += expand; + } + + /* Adjust the timers according to the round trip time */ + if(tcb->rtt_timer.state == TimerON && seq_ge(seg->ack, tcb->rttseq)) { + tcphalt(&tcb->rtt_timer); + if((tcb->flags&RETRAN) == 0) { + tcb->backoff = 0; + rtt = tcb->rtt_timer.start - tcb->rtt_timer.count; + if(rtt == 0) + rtt = 1; /* otherwise all close systems will rexmit in 0 time */ + rtt *= MSPTICK; + if (tcb->srtt == 0) { + tcb->srtt = rtt << LOGAGAIN; + tcb->mdev = rtt << LOGDGAIN; + } else { + delta = rtt - (tcb->srtt>>LOGAGAIN); + tcb->srtt += delta; + if(tcb->srtt <= 0) + tcb->srtt = 1; + + delta = abs(delta) - (tcb->mdev>>LOGDGAIN); + tcb->mdev += delta; + if(tcb->mdev <= 0) + tcb->mdev = 1; + } + } + } + + if((tcb->flags & SYNACK) == 0) { + tcb->flags |= SYNACK; + acked--; + tcb->sndcnt--; + } + + qdiscard(s->wq, acked); + + tcb->sndcnt -= acked; + tcb->snd.una = seg->ack; + if(seq_gt(seg->ack, tcb->snd.urg)) + tcb->snd.urg = seg->ack; + + tcphalt(&tcb->timer); + if(tcb->snd.una != tcb->snd.nxt) + tcpgo(&tcb->timer); + + if(seq_lt(tcb->snd.ptr, tcb->snd.una)) + tcb->snd.ptr = tcb->snd.una; + + tcb->flags &= ~RETRAN; + tcb->backoff = 0; +} + +void +tcpiput(Block *bp) +{ + Tcp seg; + Tcphdr *h; + int hdrlen; + Tcpctl *tcb; + ushort length; + Ipaddr source, dest; + Conv *spec, *gen, *s, **p; + + h = (Tcphdr*)(bp->rp); + + dest = nhgetl(h->tcpdst); + source = nhgetl(h->tcpsrc); + length = nhgets(h->length); + + h->Unused = 0; + hnputs(h->tcplen, length-TCP_PKT); + if(ptclcsum(bp, TCP_IPLEN, length-TCP_IPLEN)) { + tcp.csumerr++; + netlog(Logtcp, "bad tcp proto cksum\n"); + freeblist(bp); + return; + } + + hdrlen = ntohtcp(&seg, &bp); + if(hdrlen < 0){ + tcp.hlenerr++; + netlog(Logtcp, "bad tcp hdr len\n"); + return; + } + + /* trim the packet to the size claimed by the datagram */ + length -= hdrlen+TCP_PKT; + bp = trimblock(bp, hdrlen+TCP_PKT, length); + if(bp == nil){ + tcp.lenerr++; + netlog(Logtcp, "tcp len < 0 after trim\n"); + return; + } + + + /* Look for a connection. failing that look for a listener. */ + for(p = tcp.conv; *p; p++) { + s = *p; + if(s->rport == seg.source && + s->lport == seg.dest && s->raddr == source) + break; + } + s = *p; + if(s){ + /* can't send packets to a listener */ + tcb = (Tcpctl*)s->ptcl; + if(tcb->state == Listen){ + freeblist(bp); + return; + } + } + if(s == nil && (seg.flags & SYN)) { + /* + * dump packets with bogus flags + */ + if(seg.flags & RST){ + freeblist(bp); + return; + } + if(seg.flags & ACK) { + sndrst(source, dest, length, &seg); + freeblist(bp); + return; + } + + /* + * find a listener specific to this port (spec) or, + * failing that, a general one (gen) + */ + gen = nil; + spec = nil; + for(p = tcp.conv; *p; p++) { + s = *p; + tcb = (Tcpctl*)s->ptcl; + if((tcb->flags & CLONE) == 0) + continue; + if(tcb->state != Listen) + continue; + if(s->rport == 0 && s->raddr == 0) { + if(s->lport == seg.dest){ + spec = s; + break; + } + if(s->lport == 0) + gen = s; + } + } + s = nil; + if(spec != nil) + s = tcpincoming(spec, &seg, source, dest); + else + if(gen != nil) + s = tcpincoming(gen, &seg, source, dest); + } + if(s == nil) { + freeblist(bp); + sndrst(source, dest, length, &seg); + return; + } + + /* The rest of the input state machine is run with the control block + * locked and implements the state machine directly out of the RFC. + * Out-of-band data is ignored - it was always a bad idea. + */ + tcb = (Tcpctl*)s->ptcl; + qlock(tcb); + + switch(tcb->state) { + case Closed: + sndrst(source, dest, length, &seg); + goto raise; + case Listen: + if(seg.flags & SYN) { + procsyn(s, &seg); + tcpsndsyn(tcb); + tcpsetstate(s, Syn_received); + if(length != 0 || (seg.flags & FIN)) + break; + } + goto raise; + case Syn_sent: + if(seg.flags & ACK) { + if(!seq_within(seg.ack, tcb->iss+1, tcb->snd.nxt)) { + sndrst(source, dest, length, &seg); + goto raise; + } + } + if(seg.flags & RST) { + if(seg.flags & ACK) + localclose(s, Econrefused); + goto raise; + } + + if(seg.flags & SYN) { + procsyn(s, &seg); + if(seg.flags & ACK){ + update(s, &seg); + tcpsynackrtt(s); + tcpsetstate(s, Established); + } + else + tcpsetstate(s, Syn_received); + + if(length != 0 || (seg.flags & FIN)) + break; + + freeblist(bp); + goto output; + } + else + freeblist(bp); + + qunlock(tcb); + return; + case Syn_received: + /* doesn't matter if it's the correct ack, we're just trying to set timing */ + if(seg.flags & ACK) + tcpsynackrtt(s); + break; + } + + /* Cut the data to fit the receive window */ + if(tcptrim(tcb, &seg, &bp, &length) == -1) { + netlog(Logtcp, "tcp len < 0, %lux\n", seg.seq); + update(s, &seg); + if(tcb->sndcnt == 0 && tcb->state == Closing) { + tcpsetstate(s, Time_wait); + tcb->timer.start = MSL2*(1000 / MSPTICK); + tcpgo(&tcb->timer); + } + if(!(seg.flags & RST)) { + tcb->flags |= FORCE; + goto output; + } + qunlock(tcb); + return; + } + + /* Cannot accept so answer with a rst */ + if(length && tcb->state == Closed) { + sndrst(source, dest, length, &seg); + goto raise; + } + + /* The segment is beyond the current receive pointer so + * queue the data in the resequence queue + */ + if(seg.seq != tcb->rcv.nxt) + if(length != 0 || (seg.flags & (SYN|FIN))) { + update(s, &seg); + addreseq(tcb, &seg, bp, length); + tcb->flags |= FORCE; + goto output; + } + + /* + * keep looping till we've processed this packet plus any + * adjacent packets in the resequence queue + */ + for(;;) { + if(seg.flags & RST) { + localclose(s, Econrefused); + goto raise; + } + + if((seg.flags&ACK) == 0) + goto raise; + + switch(tcb->state) { + case Syn_received: + if(!seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){ + sndrst(source, dest, length, &seg); + goto raise; + } + update(s, &seg); + tcpsetstate(s, Established); + case Established: + case Close_wait: + update(s, &seg); + break; + case Finwait1: + update(s, &seg); + if(tcb->sndcnt == 0){ + tcb->f2counter = MAXBACKOFF; + tcpsetstate(s, Finwait2); + tcb->timer.start = MSL2 * (1000 / MSPTICK); + tcpgo(&tcb->timer); + } + break; + case Finwait2: + update(s, &seg); + break; + case Closing: + update(s, &seg); + if(tcb->sndcnt == 0) { + tcpsetstate(s, Time_wait); + tcb->timer.start = MSL2*(1000 / MSPTICK); + tcpgo(&tcb->timer); + } + break; + case Last_ack: + update(s, &seg); + if(tcb->sndcnt == 0) { + localclose(s, nil); + goto raise; + } + case Time_wait: + tcb->flags |= FORCE; + if(tcb->timer.state != TimerON) + tcpgo(&tcb->timer); + } + + if((seg.flags&URG) && seg.urg) { + if(seq_gt(seg.urg + seg.seq, tcb->rcv.urg)) { + tcb->rcv.urg = seg.urg + seg.seq; + pullblock(&bp, seg.urg); + } + } + else + if(seq_gt(tcb->rcv.nxt, tcb->rcv.urg)) + tcb->rcv.urg = tcb->rcv.nxt; + + if(length == 0) { + if(bp != nil) + freeblist(bp); + } + else { + switch(tcb->state){ + default: + /* Ignore segment text */ + if(bp != nil) + freeblist(bp); + break; + + case Syn_received: + case Established: + case Finwait1: + /* If we still have some data place on + * receive queue + */ + if(bp) { + qpass(s->rq, bp); + bp = nil; + } + tcb->rcv.nxt += length; + tcprcvwin(s); + if(tcb->acktimer.state != TimerON) + tcpgo(&tcb->acktimer); + + /* force an ack if there's a lot of unacked data */ + if(tcb->rcv.nxt-tcb->last_ack > (QMAX>>4)) + tcb->flags |= FORCE; + + break; + case Finwait2: + /* no process to read the data, send a reset */ + if(bp != nil) + freeblist(bp); + sndrst(source, dest, length, &seg); + qunlock(tcb); + return; + } + } + + if(seg.flags & FIN) { + tcb->flags |= FORCE; + + switch(tcb->state) { + case Syn_received: + case Established: + tcb->rcv.nxt++; + tcpsetstate(s, Close_wait); + break; + case Finwait1: + tcb->rcv.nxt++; + if(tcb->sndcnt == 0) { + tcpsetstate(s, Time_wait); + tcb->timer.start = MSL2*(1000/MSPTICK); + tcpgo(&tcb->timer); + } + else + tcpsetstate(s, Closing); + break; + case Finwait2: + tcb->rcv.nxt++; + tcpsetstate(s, Time_wait); + tcb->timer.start = MSL2 * (1000/MSPTICK); + tcpgo(&tcb->timer); + break; + case Close_wait: + case Closing: + case Last_ack: + break; + case Time_wait: + tcpgo(&tcb->timer); + break; + } + } + + /* + * get next adjacent segment from the resequence queue. + * dump/trim any overlapping segments + */ + for(;;) { + if(tcb->reseq == nil) + goto output; + + if(seq_ge(tcb->rcv.nxt, tcb->reseq->seg.seq) == 0) + goto output; + + getreseq(tcb, &seg, &bp, &length); + + if(tcptrim(tcb, &seg, &bp, &length) == 0) + break; + } + } +output: + tcpoutput(s); + qunlock(tcb); + return; +raise: + qunlock(tcb); + freeblist(bp); + tcpkick(s, 0); +} + +/* + * always enters and exits with the tcb locked + */ +void +tcpoutput(Conv *s) +{ + int x; + Tcp seg; + int msgs; + Tcphdr ph; + Tcpctl *tcb; + Block *hbp, *bp; + int sndcnt, n, first; + ulong ssize, dsize, usable, sent; + + tcb = (Tcpctl*)s->ptcl; + + switch(tcb->state) { + case Listen: + case Closed: + case Finwait2: + return; + } + + /* force an ack when a window has opened up */ + if(tcb->rcv.blocked && tcb->rcv.wnd > 0){ + tcb->rcv.blocked = 0; + tcb->flags |= FORCE; + } + + first = tcb->snd.ptr == tcb->snd.una; + for(msgs = 0; msgs < 100; msgs++) { + sndcnt = tcb->sndcnt; + sent = tcb->snd.ptr - tcb->snd.una; + + /* Don't send anything else until our SYN has been acked */ + if(sent != 0 && (tcb->flags & (SYNACK|FORCE)) == 0) + break; + + /* Compute usable segment based on offered window and limit + * window probes to one + */ + if(tcb->snd.wnd == 0){ + if(sent != 0) { + if ((tcb->flags&FORCE) == 0) + break; + tcb->snd.ptr = tcb->snd.una; + } + usable = 1; + } + else { + usable = tcb->cwind; + if(tcb->snd.wnd < usable) + usable = tcb->snd.wnd; + usable -= sent; + + /* + * hold small pieces in the hopes that more will come along. + * this is pessimal in synchronous communications so go ahead + * and send if: + * - all previous xmits are acked + * - we've forced to send anyways + * - we've just gotten an ACK for a previous packet + */ + if(!first) + if(!(tcb->flags&(FORCE|ACKED))) + if((sndcnt-sent) < tcb->mss) + usable = 0; + } + tcb->flags &= ~ACKED; + + ssize = sndcnt-sent; + if(usable < ssize) + ssize = usable; + if(tcb->mss < ssize) + ssize = tcb->mss; + dsize = ssize; + seg.urg = 0; + + if(ssize == 0) + if((tcb->flags&FORCE) == 0) + break; + + tcphalt(&tcb->acktimer); + + tcb->flags &= ~FORCE; + tcprcvwin(s); + + /* By default we will generate an ack */ + seg.source = s->lport; + seg.dest = s->rport; + seg.flags = ACK; + seg.mss = 0; + + switch(tcb->state){ + case Syn_sent: + seg.flags = 0; + /* No break */ + case Syn_received: + if(tcb->snd.ptr == tcb->iss){ + seg.flags |= SYN; + dsize--; + seg.mss = tcpmtu(s); + } + break; + } + tcb->last_ack = tcb->rcv.nxt; + seg.seq = tcb->snd.ptr; + seg.ack = tcb->rcv.nxt; + seg.wnd = tcb->rcv.wnd; + + /* Pull out data to send */ + bp = nil; + if(dsize != 0) { + bp = qcopy(s->wq, dsize, sent); + if(BLEN(bp) != dsize) { + seg.flags |= FIN; + dsize--; + } + netlog(Logtcp, "qcopy: dlen %d blen %d sndcnt %d qlen %d sent %d rp[0] %d\n", + dsize, BLEN(bp), sndcnt, qlen(s->wq), sent, bp->rp[0]); + } + + if(sent+dsize == sndcnt) + seg.flags |= PSH; + + /* keep track of balance of resent data */ + if(tcb->snd.ptr < tcb->snd.nxt) { + n = tcb->snd.nxt - tcb->snd.ptr; + if(ssize < n) + n = ssize; + tcb->resent += n; + } + + tcb->snd.ptr += ssize; + + /* Pull up the send pointer so we can accept acks + * for this window + */ + if(seq_gt(tcb->snd.ptr,tcb->snd.nxt)) + tcb->snd.nxt = tcb->snd.ptr; + + /* Fill in fields of pseudo IP header */ + hnputl(ph.tcpdst, s->raddr); + if(s->laddr == 0) + s->laddr = Mediagetsrc(ph.tcpdst); + + hnputl(ph.tcpsrc, s->laddr); + hnputs(ph.tcpsport, s->lport); + hnputs(ph.tcpdport, s->rport); + + /* Build header, link data and compute cksum */ + hbp = htontcp(&seg, bp, &ph); + if(hbp == nil) { + freeblist(bp); + return; + } + + /* Start the transmission timers if there is new data and we + * expect acknowledges + */ + if(ssize != 0){ + x = backoff(tcb->backoff) * + (tcb->mdev + (tcb->srtt>>LOGAGAIN) + MSPTICK) / MSPTICK; + if(x > (10000/MSPTICK)) + x = 10000/MSPTICK; + tcb->timer.start = x; + + if(tcb->timer.state != TimerON) + tcpgo(&tcb->timer); + + /* If round trip timer isn't running, start it */ + if(tcb->rtt_timer.state != TimerON) { + tcpgo(&tcb->rtt_timer); + tcb->rttseq = tcb->snd.ptr; + } + } + + ipoput(hbp, 0, s->ttl); + } +} + +/* + * the BSD convention (hack?) for keep alives. resend last byte acked. + */ +void +tcpkeepalive(Conv *s) +{ + Tcp seg; + Tcphdr ph; + Tcpctl *tcb; + Block *hbp,*dbp; + + tcb = (Tcpctl*)s->ptcl; + + + dbp = nil; + seg.urg = 0; + seg.source = s->lport; + seg.dest = s->rport; + seg.flags = ACK|PSH; + seg.mss = 0; + seg.seq = tcb->snd.una-1; + seg.ack = tcb->rcv.nxt; + seg.wnd = tcb->rcv.wnd; + tcb->last_ack = tcb->rcv.nxt; + if(tcb->state == Finwait2){ + seg.flags |= FIN; + } else { + dbp = allocb(1); + dbp->wp++; + } + + /* Fill in fields of pseudo IP header */ + hnputl(ph.tcpdst, s->raddr); + if(s->laddr == 0) + s->laddr = Mediagetsrc(ph.tcpdst); + hnputl(ph.tcpsrc, s->laddr); + hnputs(ph.tcpsport, s->lport); + hnputs(ph.tcpdport, s->rport); + + /* Build header, link data and compute cksum */ + hbp = htontcp(&seg, dbp, &ph); + if(hbp == nil) { + freeblist(dbp); + return; + } + + ipoput(hbp, 0, s->ttl); +} + +void +tcprxmit(Conv *s) +{ + Tcpctl *tcb; + + tcb = (Tcpctl*)s->ptcl; + + + qlock(tcb); + tcb->flags |= RETRAN|FORCE; + tcb->snd.ptr = tcb->snd.una; + + /* Pull window down to a single packet and halve the slow + * start threshold + */ + tcb->ssthresh = tcb->cwind / 2; + tcb->ssthresh = tcb->ssthresh; + if(tcb->mss > tcb->ssthresh) + tcb->ssthresh = tcb->mss; + + tcb->cwind = tcb->mss; + tcpoutput(s); + + tcp.rexmit++; + + qunlock(tcb); +} + +void +tcptimeout(void *arg) +{ + Conv *s; + Tcpctl *tcb; + int maxback; + + s = (Conv*)arg; + tcb = (Tcpctl*)s->ptcl; + + + switch(tcb->state){ + default: + tcb->backoff++; + if(tcb->state == Syn_sent) + maxback = (3*MAXBACKOFF)/4; + else + maxback = MAXBACKOFF; + if(tcb->backoff >= maxback) { + localclose(s, Etimedout); + break; + } + tcprxmit(s); + break; + case Finwait2: + if(--(tcb->f2counter) <= 0) + localclose(s, Etimedout); + else { + qlock(tcb); + tcpkeepalive(s); + qunlock(tcb); + tcpgo(&tcb->timer); + } + break; + case Time_wait: + localclose(s, nil); + break; + } +} + +int +inwindow(Tcpctl *tcb, int seq) +{ + return seq_within(seq, tcb->rcv.nxt, tcb->rcv.nxt+tcb->rcv.wnd-1); +} + +void +procsyn(Conv *s, Tcp *seg) +{ + Tcpctl *tcb; + int mtu; + + tcb = (Tcpctl*)s->ptcl; + tcb->flags |= FORCE; + + tcb->rcv.nxt = seg->seq + 1; + tcb->rcv.urg = tcb->rcv.nxt; + tcb->snd.wl1 = seg->seq; + tcb->irs = seg->seq; + tcb->snd.wnd = seg->wnd; + + if(seg->mss != 0) + tcb->mss = seg->mss; + + tcb->max_snd = seg->wnd; + + mtu = tcpmtu(s); + if(tcb->mss > mtu) + tcb->mss = mtu; + tcb->cwind = tcb->mss; +} + +void +addreseq(Tcpctl *tcb, Tcp *seg, Block *bp, ushort length) +{ + Reseq *rp, *rp1; + + rp = malloc(sizeof(Reseq)); + if(rp == nil){ + freeblist(bp); /* bp always consumed by add_reseq */ + return; + } + + rp->seg = *seg; + rp->bp = bp; + rp->length = length; + + /* Place on reassembly list sorting by starting seq number */ + rp1 = tcb->reseq; + if(rp1 == nil || seq_lt(seg->seq, rp1->seg.seq)) { + rp->next = rp1; + tcb->reseq = rp; + return; + } + + for(;;) { + if(rp1->next == nil || seq_lt(seg->seq, rp1->next->seg.seq)) { + rp->next = rp1->next; + rp1->next = rp; + break; + } + rp1 = rp1->next; + } +} + +void +getreseq(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length) +{ + Reseq *rp; + + rp = tcb->reseq; + if(rp == nil) + return; + + tcb->reseq = rp->next; + + *seg = rp->seg; + *bp = rp->bp; + *length = rp->length; + + free(rp); +} + +int +tcptrim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length) +{ + ushort len; + Block *nbp; + byte accept; + int dupcnt, excess; + + accept = 0; + len = *length; + if(seg->flags & SYN) + len++; + if(seg->flags & FIN) + len++; + + if(tcb->rcv.wnd == 0) { + if(len == 0 && seg->seq == tcb->rcv.nxt) + return 0; + } + else { + /* Some part of the segment should be in the window */ + if(inwindow(tcb,seg->seq)) + accept++; + else + if(len != 0) { + if(inwindow(tcb, seg->seq+len-1) || + seq_within(tcb->rcv.nxt, seg->seq,seg->seq+len-1)) + accept++; + } + } + if(!accept) { + freeblist(*bp); + return -1; + } + dupcnt = tcb->rcv.nxt - seg->seq; + if(dupcnt > 0){ + tcb->rerecv += dupcnt; + if(seg->flags & SYN){ + seg->flags &= ~SYN; + seg->seq++; + + if (seg->urg > 1) + seg->urg--; + else + seg->flags &= ~URG; + dupcnt--; + } + if(dupcnt > 0){ + pullblock(bp, (ushort)dupcnt); + seg->seq += dupcnt; + *length -= dupcnt; + + if (seg->urg > dupcnt) + seg->urg -= dupcnt; + else { + seg->flags &= ~URG; + seg->urg = 0; + } + } + } + excess = seg->seq + *length - (tcb->rcv.nxt + tcb->rcv.wnd); + if(excess > 0) { + tcb->rerecv += excess; + *length -= excess; + nbp = copyblock(*bp, *length); + freeblist(*bp); + *bp = nbp; + seg->flags &= ~FIN; + } + return 0; +} + +void +tcpadvise(Block *bp, char *msg) +{ + Tcphdr *h; + Tcpctl *tcb; + Ipaddr source, dest; + ushort psource, pdest; + Conv *s, **p; + + h = (Tcphdr*)(bp->rp); + + dest = nhgetl(h->tcpdst); + source = nhgetl(h->tcpsrc); + psource = nhgets(h->tcpsport); + pdest = nhgets(h->tcpdport); + + /* Look for a connection */ + for(p = tcp.conv; *p; p++) { + s = *p; + if(s->rport == pdest && s->lport == psource) + if(s->raddr == dest && s->laddr == source){ + tcb = (Tcpctl*)s->ptcl; + qlock(tcb); + switch(tcb->state){ + case Syn_sent: + localclose(s, msg); + break; + } + qunlock(tcb); + break; + } + } + freeblist(bp); +} + +char* +tcpctl(Conv* c, char** f, int n) +{ + if(n == 1 && strcmp(f[0], "hangup") == 0) + return tcphangup(c); + return "unknown control request"; +} + +void +tcpinit(Fs *fs) +{ + tcp.name = "tcp"; + tcp.kick = tcpkick; + tcp.connect = tcpconnect; + tcp.announce = tcpannounce; + tcp.ctl = tcpctl; + tcp.state = tcpstate; + tcp.create = tcpcreate; + tcp.close = tcpclose; + tcp.rcv = tcpiput; + tcp.advise = tcpadvise; + tcp.ipproto = IP_TCPPROTO; + tcp.nc = Nchans; + tcp.ptclsize = sizeof(Tcpctl); + + kproc("tcpack", tcpackproc, 0); + + Fsproto(fs, &tcp); +} diff --git a/ip/udp.c b/ip/udp.c new file mode 100644 index 0000000000000000000000000000000000000000..ae694d42c4623112478d34774e5b480d3ab7cd75 --- /dev/null +++ b/ip/udp.c @@ -0,0 +1,313 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "ip.h" + +#define DPRINT if(0)print + +enum +{ + UDP_PHDRSIZE = 12, + UDP_HDRSIZE = 20, + UDP_IPHDR = 8, + IP_UDPPROTO = 17, + UDP_USEAD = 6, + UDP_RELSIZE = 16, + + Udprxms = 200, + Udptickms = 100, + Udpmaxxmit = 10, +}; + +typedef struct Udphdr Udphdr; +struct Udphdr +{ + /* ip header */ + byte vihl; /* Version and header length */ + byte tos; /* Type of service */ + byte length[2]; /* packet length */ + byte id[2]; /* Identification */ + byte frag[2]; /* Fragment information */ + byte Unused; + byte udpproto; /* Protocol */ + byte udpplen[2]; /* Header plus data length */ + byte udpsrc[4]; /* Ip source */ + byte udpdst[4]; /* Ip destination */ + + /* udp header */ + byte udpsport[2]; /* Source port */ + byte udpdport[2]; /* Destination port */ + byte udplen[2]; /* data length */ + byte udpcksum[2]; /* Checksum */ +}; + +/* + * protocol specific part of Conv + */ +typedef struct Udpcb Udpcb; +struct Udpcb +{ + QLock; + byte headers; +}; + + Proto udp; + int udpsum; + uint generation; +extern Fs fs; + int udpdebug; + +static char* +udpconnect(Conv *c, char **argv, int argc) +{ + char *e; + + e = Fsstdconnect(c, argv, argc); + Fsconnected(&fs, c, e); + + return e; +} + +int +udpstate(char **s, Conv *c) +{ + USED(c); + *s = "Datagram"; + return 1; +} + +static void +udpannounce(Conv *c) +{ + Fsconnected(&fs, c, nil); +} + +static void +udpcreate(Conv *c) +{ + c->rq = qopen(16*1024, 1, 0, 0); + c->wq = qopen(16*1024, 0, 0, 0); +} + +static void +udpclose(Conv *c) +{ + Udpcb *ucb; + + qclose(c->rq); + qclose(c->wq); + qclose(c->eq); + c->laddr = 0; + c->raddr = 0; + c->lport = 0; + c->rport = 0; + + ucb = (Udpcb*)c->ptcl; + ucb->headers = 0; + + unlock(c); +} + +void +udpkick(Conv *c, int l) +{ + Udphdr *uh; + ushort port; + Ipaddr addr; + Block *bp, *f; + Udpcb *ucb; + int dlen, ptcllen; + + USED(l); + + bp = qget(c->wq); + if(bp == nil) + return; + + ucb = (Udpcb*)c->ptcl; + if(ucb->headers) { + /* get user specified addresses */ + bp = pullupblock(bp, UDP_USEAD); + if(bp == nil) { + freeblist(bp); + return; + } + addr = nhgetl(bp->rp); + bp->rp += 4; + port = nhgets(bp->rp); + bp->rp += 2; + } else { + addr = 0; + port = 0; + } + + /* Round packet up to even number of bytes */ + dlen = blocklen(bp); + if(dlen & 1) { + for(f = bp; f->next; f = f->next) + ; + if(f->wp >= f->lim) { + f->next = allocb(1); + f = f->next; + } + *f->wp++ = 0; + dlen++; + } + + /* Make space to fit udp & ip header */ + bp = padblock(bp, UDP_IPHDR+UDP_HDRSIZE); + if(bp == nil) + return; + + uh = (Udphdr *)(bp->rp); + + ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE); + uh->Unused = 0; + uh->udpproto = IP_UDPPROTO; + uh->frag[0] = 0; + uh->frag[1] = 0; + hnputs(uh->udpplen, ptcllen); + if(ucb->headers) { + hnputl(uh->udpdst, addr); + hnputs(uh->udpdport, port); + + /* pick the closest source address (best we can do) */ + hnputl(uh->udpsrc, Mediagetsrc(uh->udpdst)); + } else { + hnputl(uh->udpdst, c->raddr); + hnputs(uh->udpdport, c->rport); + hnputl(uh->udpsrc, c->laddr); + } + hnputs(uh->udpsport, c->lport); + hnputs(uh->udplen, ptcllen); + uh->udpcksum[0] = 0; + uh->udpcksum[1] = 0; + + hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_HDRSIZE)); + + ipoput(bp, 0, c->ttl); +} + +void +udpiput(Block *bp) +{ + int len; + Udphdr *uh; + Ipaddr addr; + Conv *c, **p; + Udpcb *ucb; + ushort dport, sport; + + uh = (Udphdr*)(bp->rp); + + /* Put back pseudo header for checksum */ + uh->Unused = 0; + len = nhgets(uh->udplen); + hnputs(uh->udpplen, len); + + addr = nhgetl(uh->udpsrc); + + if(udpsum && nhgets(uh->udpcksum)) { + if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) { + udp.csumerr++; + netlog(Logudp, "udp: checksum error %I\n", uh->udpsrc); + freeblist(bp); + return; + } + } + + dport = nhgets(uh->udpdport); + sport = nhgets(uh->udpsport); + + /* Look for a conversation structure for this port */ + c = nil; + for(p = udp.conv; *p; p++) { + c = *p; + if(c->inuse == 0) + continue; + if(c->lport == dport && (c->rport == 0 || c->rport == sport)) + break; + } + + if(*p == nil) { + freeblist(bp); + return; + } + + /* + * Trim the packet down to data size + */ + len -= (UDP_HDRSIZE-UDP_PHDRSIZE); + bp = trimblock(bp, UDP_IPHDR+UDP_HDRSIZE, len); + if(bp == nil){ + udp.lenerr++; + return; + } + + ucb = (Udpcb*)c->ptcl; + + if(ucb->headers) { + /* pass the src address */ + bp = padblock(bp, UDP_USEAD); + hnputl(bp->rp, addr); + hnputs(bp->rp+4, sport); + } else { + /* connection oriented udp */ + if(c->raddr == 0){ + /* save the src address in the conversation */ + c->raddr = addr; + c->rport = sport; + + /* reply with the same ip address (if not broadcast) */ + if(Mediaforme(uh->udpdst) > 0) + c->laddr = nhgetl(uh->udpdst); + } + } + if(bp->next) + bp = concatblock(bp); + + if(qfull(c->rq)) + freeblist(bp); + else + qpass(c->rq, bp); +} + +char* +udpctl(Conv *c, char **f, int n) +{ + Udpcb *ucb; + + ucb = (Udpcb*)c->ptcl; + if(n == 1 && strcmp(f[0], "headers") == 0){ + ucb->headers = 1; + return nil; + } + if(n == 1 && strcmp(f[0], "debug") == 0){ + udpdebug = 1; + return nil; + } + return "unknown control request"; +} + +void +udpinit(Fs *fs) +{ + udp.name = "udp"; + udp.kick = udpkick; + udp.connect = udpconnect; + udp.announce = udpannounce; + udp.ctl = udpctl; + udp.state = udpstate; + udp.create = udpcreate; + udp.close = udpclose; + udp.rcv = udpiput; + udp.ipproto = IP_UDPPROTO; + udp.nc = 16; + udp.ptclsize = sizeof(Udpcb); + + Fsproto(fs, &udp); +} diff --git a/pc/apbootstrap.s b/pc/apbootstrap.s new file mode 100644 index 0000000000000000000000000000000000000000..eb6567e63fad15dcf52a390c4b5421d5bae88554 --- /dev/null +++ b/pc/apbootstrap.s @@ -0,0 +1,113 @@ +#include "mem.h" + +#define NOP BYTE $0x90 /* NOP */ +#define LGDT(gdtptr) BYTE $0x0F; /* LGDT */ \ + BYTE $0x01; BYTE $0x16; \ + WORD $gdtptr +#define FARJUMP16(s, o) BYTE $0xEA; /* far jump to ptr16:16 */ \ + WORD $o; WORD $s; \ + NOP; NOP; NOP +#define FARJUMP32(s, o) BYTE $0x66; /* far jump to ptr32:16 */ \ + BYTE $0xEA; LONG $o; WORD $s + +#define DELAY BYTE $0xEB; /* JMP .+2 */ \ + BYTE $0x00 +#define INVD BYTE $0x0F; BYTE $0x08 +#define WBINVD BYTE $0x0F; BYTE $0x09 + +#define PADDR(a) ((a) & ~KZERO) + +/* + * Macros for calculating offsets within the page directory base + * and page tables. Note that these are assembler-specific hence + * the '<<2'. + */ +#define PDO(a) (((((a))>>22) & 0x03FF)<<2) +#define PTO(a) (((((a))>>12) & 0x03FF)<<2) + +/* + * Start an Application Processor. This must be placed on a 4KB boundary + * somewhere in the 1st MB of conventional memory (APBOOTSTRAP). However, + * due to some shortcuts below it's restricted further to within the 1st + * 64KB. The AP starts in real-mode, with + * CS selector set to the startup memory address/16; + * CS base set to startup memory address; + * CS limit set to 64KB; + * CPL and IP set to 0. + */ +TEXT apbootstrap(SB), $0 + FARJUMP16(0, _apbootstrap(SB)) +TEXT _apvector(SB), $0 /* address APBOOTSTRAP+0x08 */ + LONG $0 +TEXT _appdb(SB), $0 /* address APBOOTSTRAP+0x0C */ + LONG $0 +TEXT _apapic(SB), $0 /* address APBOOTSTRAP+0x10 */ + LONG $0 +TEXT _apbootstrap(SB), $0 /* address APBOOTSTRAP+0x14 */ + MOVW CS, AX + MOVW AX, DS /* initialise DS */ + + LGDT(gdtptr(SB)) /* load a basic gdt */ + + MOVL CR0, AX + ORL $1, AX + MOVL AX, CR0 /* turn on protected mode */ + DELAY /* JMP .+2 */ + + BYTE $0xB8; WORD $SELECTOR(1, SELGDT, 0)/* MOVW $SELECTOR(1, SELGDT, 0), AX */ + MOVW AX, DS + MOVW AX, ES + MOVW AX, FS + MOVW AX, GS + MOVW AX, SS + + FARJUMP32(SELECTOR(2, SELGDT, 0), _ap32-KZERO(SB)) + +/* + * There's a little mystery here - the Pentium Pro appears to need an identity + * mmu map for the switch to virtual mode. The manual doesn't say this is necessary + * and it isn't required on the Pentium. + * To this end double map KZERO at virtual 0 and undo the mapping once virtual + * nirvana has been obtained. + */ +TEXT _ap32(SB), $0 + MOVL _appdb-KZERO(SB), CX /* physical address of PDB */ + MOVL (PDO(KZERO))(CX), DX /* double-map KZERO at 0 */ + MOVL DX, (PDO(0))(CX) + MOVL CX, CR3 /* load and flush the mmu */ + + MOVL CR0, DX + ORL $0x80010000, DX /* PG|WP */ + ANDL $~0x6000000A, DX /* ~(CD|NW|TS|MP) */ + + MOVL $_appg(SB), AX + MOVL DX, CR0 /* turn on paging */ + JMP* AX + +TEXT _appg(SB), $0 + MOVL CX, AX /* physical address of PDB */ + ORL $KZERO, AX + MOVL $0, (PDO(0))(AX) /* undo double-map of KZERO at 0 */ + MOVL CX, CR3 /* load and flush the mmu */ + + MOVL $(MACHADDR+MACHSIZE-4), SP + + MOVL $0, AX + PUSHL AX + POPFL + + MOVL _apapic(SB), AX + MOVL AX, (SP) + MOVL _apvector(SB), AX + CALL* AX +_aphalt: + HLT + JMP _aphalt + +TEXT gdt(SB), $0 + LONG $0x0000; LONG $0 + LONG $0xFFFF; LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW) + LONG $0xFFFF; LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) +TEXT gdtptr(SB), $0 + WORD $(3*8) + LONG $gdt-KZERO(SB) diff --git a/pc/apic.c b/pc/apic.c new file mode 100644 index 0000000000000000000000000000000000000000..212314f93baa646f1440eb1243bd107929228b4c --- /dev/null +++ b/pc/apic.c @@ -0,0 +1,323 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "mp.h" + +enum { /* Local APIC registers */ + LapicID = 0x0020, /* ID */ + LapicVER = 0x0030, /* Version */ + LapicTPR = 0x0080, /* Task Priority */ + LapicAPR = 0x0090, /* Arbitration Priority */ + LapicPPR = 0x00A0, /* Processor Priority */ + LapicEOI = 0x00B0, /* EOI */ + LapicLDR = 0x00D0, /* Logical Destination */ + LapicDFR = 0x00E0, /* Destination Format */ + LapicSVR = 0x00F0, /* Spurious Interrupt Vector */ + LapicISR = 0x0100, /* Interrupt Status (8 registers) */ + LapicTMR = 0x0180, /* Trigger Mode (8 registers) */ + LapicIRR = 0x0200, /* Interrupt Request (8 registers) */ + LapicESR = 0x0280, /* Error Status */ + LapicICRLO = 0x0300, /* Interrupt Command */ + LapicICRHI = 0x0310, /* Interrupt Command [63:32] */ + LapicTIMER = 0x0320, /* Local Vector Table 0 (TIMER) */ + LapicPCINT = 0x0340, /* Performance COunter LVT */ + LapicLINT0 = 0x0350, /* Local Vector Table 1 (LINT0) */ + LapicLINT1 = 0x0360, /* Local Vector Table 2 (LINT1) */ + LapicERROR = 0x0370, /* Local Vector Table 3 (ERROR) */ + LapicTICR = 0x0380, /* Timer Initial Count */ + LapicTCCR = 0x0390, /* Timer Current Count */ + LapicTDCR = 0x03E0, /* Timer Divide Configuration */ +}; + +enum { /* LapicSVR */ + LapicENABLE = 0x00000100, /* Unit Enable */ + LapicFOCUS = 0x00000200, /* Focus Processor Checking Disable */ +}; + +enum { /* LapicICRLO */ + /* [14] IPI Trigger Mode Level (RW) */ + LapicDEASSERT = 0x00000000, /* Deassert level-sensitive interrupt */ + LapicASSERT = 0x00004000, /* Assert level-sensitive interrupt */ + + /* [17:16] Remote Read Status */ + LapicINVALID = 0x00000000, /* Invalid */ + LapicWAIT = 0x00010000, /* In-Progress */ + LapicVALID = 0x00020000, /* Valid */ + + /* [19:18] Destination Shorthand */ + LapicFIELD = 0x00000000, /* No shorthand */ + LapicSELF = 0x00040000, /* Self is single destination */ + LapicALLINC = 0x00080000, /* All including self */ + LapicALLEXC = 0x000C0000, /* All Excluding self */ +}; + +enum { /* LapicESR */ + LapicSENDCS = 0x00000001, /* Send CS Error */ + LapicRCVCS = 0x00000002, /* Receive CS Error */ + LapicSENDACCEPT = 0x00000004, /* Send Accept Error */ + LapicRCVACCEPT = 0x00000008, /* Receive Accept Error */ + LapicSENDVECTOR = 0x00000020, /* Send Illegal Vector */ + LapicRCVVECTOR = 0x00000040, /* Receive Illegal Vector */ + LapicREGISTER = 0x00000080, /* Illegal Register Address */ +}; + +enum { /* LapicTIMER */ + /* [17] Timer Mode (RW) */ + LapicONESHOT = 0x00000000, /* One-shot */ + LapicPERIODIC = 0x00020000, /* Periodic */ + + /* [19:18] Timer Base (RW) */ + LapicCLKIN = 0x00000000, /* use CLKIN as input */ + LapicTMBASE = 0x00040000, /* use TMBASE */ + LapicDIVIDER = 0x00080000, /* use output of the divider */ +}; + +enum { /* LapicTDCR */ + LapicX2 = 0x00000000, /* divide by 2 */ + LapicX4 = 0x00000001, /* divide by 4 */ + LapicX8 = 0x00000002, /* divide by 8 */ + LapicX16 = 0x00000003, /* divide by 16 */ + LapicX32 = 0x00000008, /* divide by 32 */ + LapicX64 = 0x00000009, /* divide by 64 */ + LapicX128 = 0x0000000A, /* divide by 128 */ + LapicX1 = 0x0000000B, /* divide by 1 */ +}; + +static ulong* lapicbase; + +static int +lapicr(int r) +{ + return *(lapicbase+(r/sizeof(*lapicbase))); +} + +static void +lapicw(int r, int data) +{ + *(lapicbase+(r/sizeof(*lapicbase))) = data; + data = *(lapicbase+(LapicID/sizeof(*lapicbase))); + USED(data); +} + +void +lapiconline(int clkin) +{ + /* + * Reload the timer to de-synchronise the processors, + * then lower the task priority to allow interrupts to be + * accepted by the APIC. + */ + microdelay((TK2MS(1)*1000/conf.nmach) * m->machno); + lapicw(LapicTICR, clkin/HZ); + lapicw(LapicTIMER, LapicCLKIN|LapicPERIODIC|VectorTIMER); + + lapicw(LapicTPR, 0); +} + +static int +lapictimerinit(void) +{ + ulong hi, lo, v; + + v = m->cpumhz*1000; + lapicw(LapicTDCR, LapicX1); + lapicw(LapicTIMER, ApicIMASK|LapicCLKIN|LapicONESHOT|VectorTIMER); + + lapicw(LapicTICR, v); + wrmsr(0x10, 0, 0); + + do{ + rdmsr(0x10, &hi, &lo); + }while(lo < v); + + return ((v-lapicr(LapicTCCR)+500)/1000)*1000*1000; +} + +int +lapicinit(Apic* apic) +{ + ulong clkin, r, lvt; + + if(lapicbase == 0) + lapicbase = apic->addr; + + lapicw(LapicDFR, 0xFFFFFFFF); + r = (lapicr(LapicID)>>24) & 0xFF; + lapicw(LapicLDR, (1<cpuidax & 0xFFF){ + case 0x526: /* stepping cB1 */ + case 0x52B: /* stepping E0 */ + case 0x52C: /* stepping cC0 */ + wrmsr(0x0E, 0, 1<<14); /* TR12 */ + break; + } + lapicw(LapicLINT0, apic->lintr[0]); + lapicw(LapicLINT1, apic->lintr[1]); + lvt = (lapicr(LapicVER)>>16) & 0xFF; + if(lvt >= 4) + lapicw(LapicPCINT, ApicIMASK); + lapicw(LapicERROR, VectorERROR); + lapicw(LapicESR, 0); + lapicr(LapicESR); + + /* + * Issue an INIT Level De-Assert to synchronise arbitration ID's. + */ + lapicw(LapicICRHI, 0); + lapicw(LapicICRLO, LapicALLINC|ApicLEVEL|LapicDEASSERT|ApicINIT); + while(lapicr(LapicICRLO) & ApicDELIVS) + ; + + /* + * Do not allow acceptance of interrupts until all initialisation + * for this processor is done. For the bootstrap processor this can be + * early duing initialisation. For the application processors this should + * be after the bootstrap processor has lowered priority and is accepting + * interrupts. + lapicw(LapicTPR, 0); + */ + + return clkin; +} + +void +lapicstartap(Apic* apic, int v) +{ + int crhi, i; + + crhi = apic->apicno<<24; + lapicw(LapicICRHI, crhi); + lapicw(LapicICRLO, LapicFIELD|ApicLEVEL|LapicASSERT|ApicINIT); + microdelay(200); + lapicw(LapicICRLO, LapicFIELD|ApicLEVEL|LapicDEASSERT|ApicINIT); + delay(10); + + for(i = 0; i < 2; i++){ + lapicw(LapicICRHI, crhi); + lapicw(LapicICRLO, LapicFIELD|ApicEDGE|ApicSTARTUP|(v/BY2PG)); + microdelay(200); + } +} + +void +lapicerror(Ureg*, void*) +{ + int esr; + + lapicw(LapicESR, 0); + esr = lapicr(LapicESR); + switch(m->cpuidax & 0xFFF){ + case 0x526: /* stepping cB1 */ + case 0x52B: /* stepping E0 */ + case 0x52C: /* stepping cC0 */ + return; + } + print("cpu%d: lapicerror: 0x%8.8luX\n", m->machno, esr); +} + +void +lapicspurious(Ureg*, void*) +{ + print("cpu%d: lapicspurious\n", m->machno); +} + +int +lapicisr(int v) +{ + int isr; + + isr = lapicr(LapicISR + (v/32)); + + return isr & (1<<(v%32)); +} + +int +lapiceoi(int v) +{ + lapicw(LapicEOI, 0); + + return v; +} + +void +lapicicrw(int hi, int lo) +{ + lapicw(LapicICRHI, hi); + lapicw(LapicICRLO, lo); +} + +static int ioapicvecbase = VectorPIC; + +void +ioapicrdtr(Apic* apic, int sel, int* hi, int* lo) +{ + ulong *iowin; + + iowin = apic->addr+(0x10/sizeof(ulong)); + sel = IoapicRDT + 2*sel; + + lock(apic); + *apic->addr = sel+1; + *hi = *iowin; + *apic->addr = sel; + *lo = *iowin; + unlock(apic); +} + +void +ioapicrdtw(Apic* apic, int sel, int hi, int lo) +{ + ulong *iowin; + + iowin = apic->addr+(0x10/sizeof(ulong)); + sel = IoapicRDT + 2*sel; + + lock(apic); + *apic->addr = sel+1; + *iowin = hi; + *apic->addr = sel; + *iowin = lo; + unlock(apic); +} + +void +ioapicinit(Apic* apic, int apicno) +{ + int hi, lo, v; + ulong *iowin; + + /* + * Initialise the I/O APIC. + * The MultiProcessor Specification says it is the responsibility + * of the O/S to set the APIC id. + * Make sure interrupts are all masked off for now. + */ + iowin = apic->addr+(0x10/sizeof(ulong)); + lock(apic); + *apic->addr = IoapicVER; + apic->mre = (*iowin>>16) & 0xFF; + + apic->vecbase = ioapicvecbase; + ioapicvecbase += apic->mre+1; + + *apic->addr = IoapicID; + *iowin = apicno<<24; + unlock(apic); + + hi = 0; + lo = ApicIMASK; + for(v = 0; v <= apic->mre; v++) + ioapicrdtw(apic, v, hi, lo); +} diff --git a/pc/archgeneric.c b/pc/archgeneric.c index e826527af6ace1203c15169195b79dc948c74571..031a14154ace608c63312ad86dc66452928967ad 100644 --- a/pc/archgeneric.c +++ b/pc/archgeneric.c @@ -5,21 +5,159 @@ #include "fns.h" #include "io.h" +static int +unimplemented(int) +{ + return 0; +} + static void -genericreset(void) +nop(void) { - print("Reset the machine!\n"); - for(;;); } -PCArch generic = +void (*coherence)(void) = nop; + +PCArch* arch; +extern PCArch* knownarch[]; + +PCArch archgeneric = { + "generic", /* id */ + 0, /* ident */ + i8042reset, /* reset */ + unimplemented, /* serialpower */ + unimplemented, /* modempower */ + + i8259init, /* intrinit */ + i8259enable, /* intrenable */ + + i8253enable, /* clockenable */ +}; + +typedef struct { + int family; + int model; + int aalcycles; + char* name; +} X86type; + +static X86type x86type[] = { - "generic", - i8042reset, - 0, - 0, - 0, - 0, - 0, - 0, + { 4, 0, 22, "486DX", }, /* known chips */ + { 4, 1, 22, "486DX50", }, + { 4, 2, 22, "486SX", }, + { 4, 3, 22, "486DX2", }, + { 4, 4, 22, "486SL", }, + { 4, 5, 22, "486SX2", }, + { 4, 7, 22, "DX2WB", }, /* P24D */ + { 4, 8, 22, "DX4", }, + { 4, 9, 22, "DX4WB", }, + { 5, 0, 23, "P5", }, + { 5, 1, 23, "P5", }, + { 5, 2, 23, "P54C", }, + { 5, 3, 23, "P24T", }, /* PODP5V83 */ + { 5, 4, 23, "PODP54", }, + { 5, 5, 23, "PODDX4", }, + { 5, 6, 23, "PODP5", }, + { 6, 4, 23, "P55CT", }, + { 6, 1, 16, "PentiumPro", },/* determined by trial and error */ + + { 3, -1, 32, "386", }, /* family defaults */ + { 4, -1, 22, "486", }, + { 5, -1, 23, "Pentium", }, + { 6, -1, 16, "PentiumPro", }, + + { -1, -1, 23, "unknown", }, /* total default */ }; + +void +cpuidprint(void) +{ + int i; + char buf[128]; + + i = sprint(buf, "cpu%d: %dMHz ", m->machno, m->cpumhz); + if(m->cpuidid[0]) + i += sprint(buf+i, "%s ", m->cpuidid); + sprint(buf+i, "%s (cpuid: AX 0x%4.4luX DX 0x%4.4luX)\n", + m->cpuidtype, m->cpuidax, m->cpuiddx); + print(buf); +} + +int +cpuidentify(void) +{ + int family, model; + X86type *t; + ulong cr4, mct[2]; + + cpuid(m->cpuidid, &m->cpuidax, &m->cpuiddx); + family = X86FAMILY(m->cpuidax); + model = X86MODEL(m->cpuidax); + for(t = x86type; t->name; t++){ + if((t->family == family && t->model == model) + || (t->family == family && t->model == -1) + || (t->family == -1)) + break; + } + m->cpuidtype = t->name; + i8253init(t->aalcycles); + + /* + * If machine check exception or page size extensions are supported + * enable them in CR4 and clear any other set extensions. + * If machine check was enabled clear out any lingering status. + */ + if(m->cpuiddx & 0x88){ + cr4 = 0; + if(m->cpuiddx & 0x08) + cr4 |= 0x10; /* page size extensions */ + if(m->cpuiddx & 0x80) + cr4 |= 0x40; /* machine check enable */ + putcr4(cr4); + if(m->cpuiddx & 0x80) + rdmsr(0x01, &mct[1], &mct[0]); + } + + return t->family; +} + +void +archinit(void) +{ + PCArch **p; + + arch = 0; + for(p = knownarch; *p; p++){ + if((*p)->ident && (*p)->ident() == 0){ + arch = *p; + break; + } + } + if(arch == 0) + arch = &archgeneric; + else{ + if(arch->id == 0) + arch->id = archgeneric.id; + if(arch->reset == 0) + arch->reset = archgeneric.reset; + if(arch->serialpower == 0) + arch->serialpower = archgeneric.serialpower; + if(arch->modempower == 0) + arch->modempower = archgeneric.modempower; + + if(arch->intrinit == 0) + arch->intrinit = archgeneric.intrinit; + if(arch->intrenable == 0) + arch->intrenable = archgeneric.intrenable; + } + + /* + * Decide whether to use copy-on-reference (386 and mp). + */ + if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1) + conf.copymode = 1; + + if(X86FAMILY(m->cpuidax) == 6 /*&& conf.nmach > 1*/) + coherence = wbflush; +} diff --git a/pc/archmp.c b/pc/archmp.c new file mode 100644 index 0000000000000000000000000000000000000000..482aabb756883f03f1218eaba2cb0cf1d609e425 --- /dev/null +++ b/pc/archmp.c @@ -0,0 +1,94 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "mp.h" + +_MP_ *_mp_; + +static _MP_* +mpscan(uchar *addr, int len) +{ + uchar *e, *p, sum; + int i; + + e = addr+len; + for(p = addr; p < e; p += sizeof(_MP_)){ + if(memcmp(p, "_MP_", 4)) + continue; + sum = 0; + for(i = 0; i < sizeof(_MP_); i++) + sum += p[i]; + if(sum == 0) + return (_MP_*)p; + } + return 0; +} + +static _MP_* +mpsearch(void) +{ + uchar *bda; + ulong p; + _MP_ *mp; + + /* + * Search for the MP Floating Pointer Structure: + * 1) in the first KB of the EBDA; + * 2) in the last KB of system base memory; + * 3) in the BIOS ROM between 0xE0000 and 0xFFFFF. + */ + bda = KADDR(0x400); + if((p = (bda[0x0F]<<8)|bda[0x0E])){ + if(mp = mpscan(KADDR(p), 1024)) + return mp; + } + else{ + p = ((bda[0x14]<<8)|bda[0x13])*1024; + if(mp = mpscan(KADDR(p-1024), 1024)) + return mp; + } + return mpscan(KADDR(0xF0000), 0x10000); +} + +static int +identify(void) +{ + PCMP *pcmp; + uchar *p, sum; + ulong length; + + /* + * Search for an MP configuration table. For now, + * don't accept the default configurations (physaddr == 0). + * Calculate the checksum. + * To do: check extended table checksum. + */ + if((_mp_ = mpsearch()) == 0 || _mp_->physaddr == 0) + return 1; + + pcmp = KADDR(_mp_->physaddr); + length = pcmp->length; + + sum = 0; + for(p = (uchar*)pcmp; length; length--) + sum += *p++; + + return sum; +} + +PCArch archmp = { + "_MP_", /* id */ + identify, /* ident */ + mpshutdown, /* reset */ + 0, /* serialpower */ + 0, /* modempower */ + + mpinit, /* intrinit */ + mpintrenable, /* intrenable */ + + 0, /* clockenable */ +}; diff --git a/pc/archncr3170.c b/pc/archncr3170.c deleted file mode 100644 index 685ab7faad3164537be272fa4943616e68316f9f..0000000000000000000000000000000000000000 --- a/pc/archncr3170.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" - -enum -{ - Pindex= 0x198, - Pdata= 0x199, -}; - -static Lock pmulock; -static int -pmuwrbit(int index, int bit, int pos) -{ - uchar x; - - lock(&pmulock); - outb(Pindex, index); - x = inb(Pdata); - if(bit) - x |= 1< 1000) - return -1; - return 0; -} - -/* - * return when pmu busy - */ -static int -pmubusy(void) -{ - int tries; - - for(tries = 0; !(inb(Pmucsr) & Busy); tries++) - if(tries > 1000) - return -1; - return 0; -} - -/* - * set a bit in the PMU - */ -static Lock pmulock; -static int -pmuwrbit(int index, int bit, int pos) -{ - lock(&pmulock); - outb(Pmucsr, 0x02); /* next is command request */ - if(pmuready() < 0){ - unlock(&pmulock); - return -1; - } - outb(Pmudata, (2<<4) | index); /* send write bit command */ - outb(Pmucsr, 0x01); /* send available */ - if(pmubusy() < 0){ - unlock(&pmulock); - return -1; - } - outb(Pmucsr, 0x01); /* next is data */ - if(pmuready() < 0){ - unlock(&pmulock); - return -1; - } - outb(Pmudata, (bit<<3) | pos); /* send bit to write */ - outb(Pmucsr, 0x01); /* send available */ - if(pmubusy() < 0){ - unlock(&pmulock); - return -1; - } - unlock(&pmulock); - return 0; -} - -/* - * power to serial port - * onoff == 1 means on - * onoff == 0 means off - */ -static int -nsx20serialpower(int onoff) -{ - return pmuwrbit(1, 1^onoff, 6); -} - -/* - * power to modem - * onoff == 1 means on - * onoff == 0 means off - */ -static int -nsx20modempower(int onoff) -{ - if(pmuwrbit(1, 1^onoff, 0)<0) /* modem speaker */ - return -1; - return pmuwrbit(1, onoff, 5); /* modem power */ -} - -/* - * set cpu speed - * 0 == low speed - * 1 == high speed - */ -static int -nsx20cpuspeed(int speed) -{ - return pmuwrbit(0, speed, 0); -} - -/* - * f == frequency in Hz - * d == duration in ms - */ -static void -nsx20buzz(int f, int d) -{ - static QLock bl; - static Rendez br; - - USED(f); - qlock(&bl); - pmuwrbit(0, 0, 6); - tsleep(&br, return0, 0, d); - pmuwrbit(0, 1, 6); - qunlock(&bl); -} - -/* - * 1 == owl eye - * 2 == mail icon - */ -static void -nsx20lights(int val) -{ - pmuwrbit(0, (val&1), 4); /* owl */ - pmuwrbit(0, ((val>>1)&1), 1); /* mail */ -} - -/* - * headland system controller (ht21) - */ -enum -{ - /* - * system control port - */ - Head= 0x92, /* control port */ - Reset= (1<<0), /* reset the 386 */ - A20ena= (1<<1), /* enable address line 20 */ -}; - -/* - * reset machine - */ -static void -headreset(void) -{ - outb(Head, Reset); -} - -PCArch nsx20 = -{ - "AT&TNSX", - headreset, - nsx20cpuspeed, - nsx20buzz, - nsx20lights, - nsx20serialpower, - nsx20modempower, - 0, -}; diff --git a/pc/audio.h b/pc/audio.h index cc38eb89bad3c68eb33221824e80d4c68d1270c4..553979ad8cc545e15555e622e4cdaefb0560fdc8 100644 --- a/pc/audio.h +++ b/pc/audio.h @@ -9,3 +9,6 @@ enum #define seteisadma(a, b) ; #define CACHELINESZ 8 #define UNCACHED(type, v) (type*)((ulong)(v)) + +#define Int0vec VectorPIC +#define setvec(v, f, a) intrenable(v, f, a, BUSUNKNOWN) diff --git a/pc/cga.c b/pc/cga.c index ebf17e6d29cbcc84bfbe7ce2fcd7cb14a96058fb..bc4fd682430fee5fc8a84b99f93c4d079ea9a23a 100644 --- a/pc/cga.c +++ b/pc/cga.c @@ -1,202 +1,122 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +enum { + Width = 160, + Height = 25, + + Attr = 7, /* white on black */ +}; -#define WIDTH 160 -#define HEIGHT 24 -#define SCREEN ((char *)(0xB8000|KZERO)) -int pos; +#define CGASCREENBASE ((uchar*)KADDR(0xB8000)) -void -screeninit(void) +static int pos; +static int screeninitdone; +QLock screenlock; +void (*vgascreenputc)(char*); + +static uchar +cgaregr(int index) { - void vgadump(void); + outb(0x3D4, index); + return inb(0x3D4+1) & 0xFF; +} - memset(SCREEN+pos, 0, WIDTH*HEIGHT-pos); - vgadump(); +static void +cgaregw(int index, int data) +{ + outb(0x3D4, index); + outb(0x3D4+1, data); } -void -screenputc(int c) +static void +movecursor(void) +{ + cgaregw(0x0E, (pos/2>>8) & 0xFF); + cgaregw(0x0F, pos/2 & 0xFF); + CGASCREENBASE[pos+1] = Attr; +} + +static void +cgascreenputc(int c) { int i; - static int color; if(c == '\n'){ - pos = pos/WIDTH; - pos = (pos+1)*WIDTH; - } else if(c == '\t'){ + pos = pos/Width; + pos = (pos+1)*Width; + } + else if(c == '\t'){ i = 8 - ((pos/2)&7); while(i-->0) - screenputc(' '); - } else if(c == '\b'){ + cgascreenputc(' '); + } + else if(c == '\b'){ if(pos >= 2) pos -= 2; - screenputc(' '); + cgascreenputc(' '); pos -= 2; - } else { - SCREEN[pos++] = c; - SCREEN[pos++] = 0x1d; } - if(pos >= WIDTH*HEIGHT){ - memmove(SCREEN, &SCREEN[WIDTH], WIDTH*(HEIGHT-1)); - memset(&SCREEN[WIDTH*(HEIGHT-1)], 0, WIDTH); - pos = WIDTH*(HEIGHT-1); + else{ + CGASCREENBASE[pos++] = c; + CGASCREENBASE[pos++] = Attr; + } + if(pos >= Width*Height){ + memmove(CGASCREENBASE, &CGASCREENBASE[Width], Width*(Height-1)); + memset(&CGASCREENBASE[Width*(Height-1)], 0, Width); + pos = Width*(Height-1); } + movecursor(); } void -screenputs(char *s, int n) -{ - while(n-- > 0) - screenputc(*s++); -} - -int -screenbits(void) -{ - return 4; -} - - -#include -#include -#include "screen.h" - -/* - * screen dimensions - */ -#define MAXX 640 -#define MAXY 480 - -#define SCREENMEM (0xA0000 | KZERO) -GBitmap gscreen = -{ - (ulong*)SCREENMEM, - 0, - 640/32, - 0, - 0, 0, MAXX, MAXY, - 0 -}; - -typedef struct VGAmode VGAmode; -struct VGAmode -{ - uchar general[4]; - uchar sequencer[5]; - uchar crt[0x19]; - uchar graphics[9]; - uchar attribute[0x15]; -}; - -enum -{ - EMISCR= 0x3CC, /* control sync polarity */ - EMISCW= 0x3C2, - EFCW= 0x3DA, /* feature control */ - EFCR= 0x3CA, - GRX= 0x3CE, /* index to graphics registers */ - GR= 0x3CF, /* graphics registers */ - Grms= 0x04, /* read map select register */ - SRX= 0x3C4, /* index to sequence registers */ - SR= 0x3C5, /* sequence registers */ - Smmask= 0x02, /* map mask */ - CRX= 0x3D4, /* index to crt registers */ - CR= 0x3D5, /* crt registers */ - Cvre= 0x11, /* vertical retrace end */ - ARX= 0x3C0, /* index to attribute registers */ - AR= 0x3C1, /* attribute registers */ -}; - -uchar -genin(int reg) -{ - if(reg == 0) - return inb(EMISCR); - else if (reg == 1) - return inb(EFCR); -} -uchar -srin(int reg) -{ - outb(SRX, reg); - return inb(SR); -} -uchar -grin(int reg) -{ - outb(GRX, reg); - return inb(GR); -} -uchar -arin(int reg) -{ - inb(0x3DA); - outb(ARX, reg | 0x20); - return inb(AR); -} -uchar -crin(int reg) +screeninit(void) { - outb(CRX, reg); - return inb(CR); + pos = cgaregr(0x0E)<<8; + pos |= cgaregr(0x0F); + pos *= 2; + screeninitdone = 1; } void -vgadump(void) +screenputs(char* s, int n) { int i; - VGAmode *v; - - print("GEN "); - for(i = 0; i < sizeof(v->general); i++) - print("%d-%ux ", i, genin(i)); - print("\nSR "); - for(i = 0; i < sizeof(v->sequencer); i++) - print("%d-%ux ", i, srin(i)); - print("\nCR "); - for(i = 0; i < sizeof(v->crt); i++) - print("%d-%ux ", i, crin(i)); - print("\nGR "); - for(i = 0; i < sizeof(v->graphics); i++) - print("%d-%ux ", i, grin(i)); - print("\nAR "); - for(i = 0; i < sizeof(v->attribute); i++) - print("%d-%ux ", i, arin(i)); - print("\n "); -} + Rune r; + char buf[4]; -void -bigcursor(void) -{} - -void -getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb) -{ - ulong ans; - - /* - * The safari monochrome says 0 is black (zero intensity) - */ - if(p == 0) - ans = 0; + if(!islo()){ + if(!canqlock(&screenlock)) + return; + } else - ans = ~0; - *pr = *pg = *pb = ans; -} + qlock(&screenlock); + if(vgascreenputc == nil){ + while(n-- > 0) + cgascreenputc(*s++); + qunlock(&screenlock); + return; + } -int -setcolor(ulong p, ulong r, ulong g, ulong b) -{ - return 0; /* can't change mono screen colormap */ -} + while(n > 0) { + i = chartorune(&r, s); + if(i == 0){ + s++; + --n; + continue; + } + memmove(buf, s, i); + buf[i] = 0; + n -= i; + s += i; + vgascreenputc(buf); + } -void -mouseclock(void) -{ - mouseupdate(1); + qunlock(&screenlock); } diff --git a/pc/clock.c b/pc/clock.c index f538b30987d2b48eedc652a1ea11226721859715..6782f49ae5e91543a3d6858c50c2dffa091cbf8f 100644 --- a/pc/clock.c +++ b/pc/clock.c @@ -1,233 +1,90 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "ureg.h" +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" -/* - * 8253 timer - */ -enum -{ - T0cntr= 0x40, /* counter ports */ - T1cntr= 0x41, /* ... */ - T2cntr= 0x42, /* ... */ - Tmode= 0x43, /* mode port */ +void (*kproftimer)(ulong); - /* commands */ - Latch0= 0x00, /* latch counter 0's value */ - Load0= 0x30, /* load counter 0 with 2 bytes */ +typedef struct Clock0link Clock0link; +typedef struct Clock0link { + void (*clock)(void); + Clock0link* link; +} Clock0link; - /* modes */ - Square= 0x36, /* periodic square wave */ - Trigger= 0x30, /* interrupt on terminal count */ +static Clock0link *clock0link; +static Lock clock0lock; - Freq= 1193182, /* Real clock frequency */ -}; +void +addclock0link(void (*clock)(void)) +{ + Clock0link *lp; -static int cpufreq = 66000000; -static int cpumhz = 66; -static int loopconst = 100; -static int cpuidax, cpuiddx; + if((lp = malloc(sizeof(Clock0link))) == 0){ + print("addclock0link: too many links\n"); + return; + } + ilock(&clock0lock); + lp->clock = clock; + lp->link = clock0link; + clock0link = lp; + iunlock(&clock0lock); +} -static void -clock(Ureg *ur, void *arg) +void +clockintr(Ureg* ureg, void*) { - USED(arg); + Clock0link *lp; m->ticks++; + if(m->proc) + m->proc->pc = ureg->pc; + accounttime(); + if(kproftimer != nil) + kproftimer(ureg->pc); + if((active.machs & (1<machno)) == 0) + return; if(active.exiting && (active.machs & (1<machno))) exit(0); - accounttime(); checkalarms(); - hardclock(); - uartclock(); - mouseclock(); - randomclock(); - - if(up && up->state == Running){ - if(anyready()) - sched(); - - /* user profiling clock */ - if((ur->cs&0xffff) == UESEL) { - (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1); - segclock(ur->pc); - } + if(m->machno == 0){ + lock(&clock0lock); + for(lp = clock0link; lp; lp = lp->link) + lp->clock(); + unlock(&clock0lock); } -} -#define STEPPING(x) ((x)&0xf) -#define MODEL(x) (((x)>>4)&0xf) -#define FAMILY(x) (((x)>>8)&0xf) + if(up == 0 || up->state != Running) + return; -enum -{ - /* flags */ - CpuidFPU = 0x001, /* on-chip floating point unit */ - CpuidMCE = 0x080, /* machine check exception */ - CpuidCX8 = 0x100, /* CMPXCHG8B instruction */ -}; - -typedef struct -{ - int family; - int model; - int aalcycles; - char *name; -} X86type; - -X86type x86type[] = -{ - /* from the cpuid instruction */ - { 4, 0, 22, "Intel486DX", }, - { 4, 1, 22, "Intel486DX", }, - { 4, 2, 22, "Intel486SX", }, - { 4, 3, 22, "Intel486DX2", }, - { 4, 4, 22, "Intel486DX2", }, - { 4, 5, 22, "Intel486SL", }, - { 4, 8, 22, "IntelDX4", }, - { 5, 1, 23, "Pentium510", }, - { 5, 2, 23, "Pentium735", }, - { 6, 1, 16, "PentiumPro", },/* determined by trial and error */ - - /* family defaults */ - { 3, -1, 32, "Intel386", }, - { 4, -1, 22, "Intel486", }, - { 5, -1, 23, "Pentium", }, - { 6, -1, 16, "PentiumPro", }, - - /* total default */ - { -1, -1, 23, "unknown", }, -}; - -static X86type *cputype; - -/* - * delay for l milliseconds more or less. delayloop is set by - * clockinit() to match the actual CPU speed. - */ -void -delay(int l) -{ - l *= loopconst; - if(l <= 0) - l = 1; - aamloop(l); -} - -/* - * microsecond delay - */ -void -microdelay(int l) -{ - l *= loopconst; - l /= 1000; - if(l <= 0) - l = 1; - aamloop(l); + if(anyready()) + sched(); + + if((ureg->cs & 0xFFFF) == UESEL) { + (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1); + segclock(ureg->pc); + } } void -printcpufreq(void) +delay(int millisecs) { - print("CPU is a %d MHz %s (cpuid: ax %lux dx %lux)\n", - cpumhz, cputype->name, cpuidax, cpuiddx); + millisecs *= m->loopconst; + if(millisecs <= 0) + millisecs = 1; + aamloop(millisecs); } void -clockinit(void) +microdelay(int microsecs) { - int x, y; /* change in counter */ - int family, model, loops, incr; - X86type *t; - - /* - * set vector for clock interrupts - */ - setvec(Clockvec, clock, 0); - - /* - * figure out what we are - */ - x86cpuid(&cpuidax, &cpuiddx); - family = FAMILY(cpuidax); - model = MODEL(cpuidax); - for(t = x86type; t->name; t++) - if((t->family == family && t->model == model) - || (t->family == family && t->model == -1) - || (t->family == -1)) - break; - cputype = t; - - switch(cputype->family){ - case 3: - conf.copymode = 1; /* copy on reference */ - break; - default: - conf.copymode = 0; /* copy on write */ - break; - } - - /* - * set clock for 1/HZ seconds - */ - outb(Tmode, Load0|Square); - outb(T0cntr, (Freq/HZ)); /* low byte */ - outb(T0cntr, (Freq/HZ)>>8); /* high byte */ - - /* find biggest loop that doesn't wrap */ - incr = 16000000/(t->aalcycles*HZ*2); - x = 2000; - for(loops = incr; loops < 64*1024; loops += incr) { - - /* - * measure time for the loop - * - * MOVL loops,CX - * aaml1: AAM - * LOOP aaml1 - * - * the time for the loop should be independent of external - * cache and memory system since it fits in the execution - * prefetch buffer. - * - */ - outb(Tmode, Latch0); - x = inb(T0cntr); - x |= inb(T0cntr)<<8; - aamloop(loops); - outb(Tmode, Latch0); - y = inb(T0cntr); - y |= inb(T0cntr)<<8; - x -= y; - - if(x < 0) - x += Freq/HZ; - - if(x > Freq/(3*HZ)) - break; - } - - /* - * counter goes at twice the frequency, once per transition, - * i.e., twice per square wave - */ - x >>= 1; - - /* - * figure out clock frequency and a loop multiplier for delay(). - */ - cpufreq = loops*((t->aalcycles*Freq)/x); - loopconst = (cpufreq/1000)/t->aalcycles; /* AAM+LOOP's for 1 ms */ - - /* - * add in possible .2% error and convert to MHz - */ - cpumhz = (cpufreq + cpufreq/500)/1000000; + microsecs *= m->loopconst; + microsecs /= 1000; + if(microsecs <= 0) + microsecs = 1; + aamloop(microsecs); } diff --git a/pc/dat.h b/pc/dat.h index 9d978318a6cf857cebd489e6b743b1f40ca756bc..fad2a42453cfeb0284ff457abcd4831eb375fb5b 100644 --- a/pc/dat.h +++ b/pc/dat.h @@ -1,5 +1,7 @@ typedef struct Conf Conf; typedef struct FPsave FPsave; +typedef struct Irq Irq; +typedef struct Irqctl Irqctl; typedef struct ISAConf ISAConf; typedef struct Label Label; typedef struct Lock Lock; @@ -7,18 +9,13 @@ typedef struct MMU MMU; typedef struct Mach Mach; typedef struct Notsave Notsave; typedef struct PCArch PCArch; -typedef struct PCIcfg PCIcfg; +typedef struct Pcidev Pcidev; typedef struct PCMmap PCMmap; typedef struct Page Page; typedef struct PMMU PMMU; typedef struct Segdesc Segdesc; typedef struct Ureg Ureg; -#define MACHP(n) (n==0? &mach0 : *(Mach**)0) - -extern Mach mach0; -extern void (*kprofp)(ulong); - /* * parameters for sysproc.c */ @@ -73,7 +70,6 @@ struct Conf ulong monitor; /* has monitor? */ ulong npage0; /* total physical pages of memory */ ulong npage1; /* total physical pages of memory */ - ulong topofmem; /* highest physical address + 1 */ ulong npage; /* total physical pages of memory */ ulong upages; /* user page pool */ ulong nimage; /* number of page cache image headers */ @@ -81,11 +77,6 @@ struct Conf ulong base0; /* base of bank 0 */ ulong base1; /* base of bank 1 */ ulong copymode; /* 0 is copy on write, 1 is copy on reference */ - ulong nfloppy; /* number of floppy drives */ - ulong nhard; /* number of hard drives */ - ulong ldepth; /* screen depth */ - ulong maxx; /* screen width */ - ulong maxy; /* screen length */ ulong ialloc; /* max interrupt time allocation in bytes */ ulong pipeqsize; /* size in bytes of pipe queues */ }; @@ -93,14 +84,12 @@ struct Conf /* * MMU stuff in proc */ -#define MAXMMU 4 -#define MAXSMMU 1 #define NCOLOR 1 struct PMMU { - Page *mmutop; /* 1st level table */ - Page *mmufree; /* unused page table pages */ - Page *mmuused; /* used page table pages */ + Page* mmupdb; /* page directory base */ + Page* mmufree; /* unused page table pages */ + Page* mmuused; /* used page table pages */ }; /* @@ -115,21 +104,60 @@ struct Notsave #include "../port/portdat.h" -/* - * machine dependent definitions not used by ../port/dat.h - */ +typedef struct { + ulong link; /* link (old TSS selector) */ + ulong esp0; /* privilege level 0 stack pointer */ + ulong ss0; /* privilege level 0 stack selector */ + ulong esp1; /* privilege level 1 stack pointer */ + ulong ss1; /* privilege level 1 stack selector */ + ulong esp2; /* privilege level 2 stack pointer */ + ulong ss2; /* privilege level 2 stack selector */ + ulong cr3; /* page directory base register */ + ulong eip; /* instruction pointer */ + ulong eflags; /* flags register */ + ulong eax; /* general registers */ + ulong ecx; + ulong edx; + ulong ebx; + ulong esp; + ulong ebp; + ulong esi; + ulong edi; + ulong es; /* segment selectors */ + ulong cs; + ulong ss; + ulong ds; + ulong fs; + ulong gs; + ulong ldt; /* selector for task's LDT */ + ulong iomap; /* I/O map base address + T-bit */ +} Tss; + +struct Segdesc +{ + ulong d0; + ulong d1; +}; struct Mach { int machno; /* physical id of processor */ ulong splpc; /* pc of last caller to splhi */ - int mmask; /* 1<machno */ + + void* pdb; /* page directory base for this processor (va) */ + Tss* tss; /* tss for this processor */ + Segdesc gdt[6]; /* gdt for this processor */ + + Proc* proc; /* current process on this processor */ + Proc* externup; /* extern register Proc *up */ + + Page* pdbpool; + int pdbcnt; + ulong ticks; /* of the clock since boot time */ - Proc *proc; /* current process on this processor */ Label sched; /* scheduler wakeup */ Lock alarmlock; /* access to alarm list */ - void *alarm; /* alarms bound to this clock */ - int nrdy; + void* alarm; /* alarms bound to this clock */ int tlbfault; int tlbpurge; @@ -139,6 +167,14 @@ struct Mach int load; int intr; + int loopconst; + + int cpumhz; + int cpuidax; + int cpuiddx; + char cpuidid[16]; + char* cpuidtype; + int stack[1]; }; @@ -150,20 +186,12 @@ typedef void KMap; #define kmap(p) (KMap*)((p)->pa|KZERO) #define kunmap(k) -/* - * segment descriptor/gate - */ -struct Segdesc -{ - ulong d0; - ulong d1; -}; - struct { Lock; - short machs; - short exiting; + int machs; /* bitmap of active CPUs */ + int exiting; /* shutdown */ + int ispanic; /* shutdown in response to a panic */ }active; /* @@ -171,14 +199,16 @@ struct */ struct PCArch { - char *id; + char* id; + int (*ident)(void); /* this should be in the model */ void (*reset)(void); /* this should be in the model */ - int (*cpuspeed)(int); /* 0 = low, 1 = high */ - void (*buzz)(int, int); /* make a noise */ - void (*lights)(int); /* turn lights or icons on/off */ int (*serialpower)(int); /* 1 == on, 0 == off */ int (*modempower)(int); /* 1 == on, 0 == off */ - int (*extvga)(int); /* 1 == external, 0 == internal */ + + void (*intrinit)(void); + int (*intrenable)(int, int, Irqctl*); + + void (*clockenable)(void); }; /* @@ -191,29 +221,29 @@ struct ISAConf { char type[NAMELEN]; ulong port; ulong irq; - int dma; + ulong dma; ulong mem; ulong size; ulong freq; - uchar ea[6]; int nopt; char opt[NISAOPT][ISAOPTLEN]; }; +extern PCArch *arch; /* PC architecture */ + /* - * maps between ISA memory space and PCMCIA card memory space + * Each processor sees its own Mach structure at address MACHADDR. + * However, the Mach structures must also be available via the per-processor + * MMU information array machp, mainly for disambiguation and access to + * the clock which is only maintained by the bootstrap processor (0). */ -struct PCMmap -{ - ulong ca; /* card address */ - ulong cea; /* card end address */ - ulong isa; /* ISA address */ - int len; /* length of the ISA area */ - int attr; /* attribute memory */ - int ref; -}; +Mach* machp[MAXMACH]; + +#define MACHP(n) (machp[n]) +extern Mach *m; +#define up (((Mach*)MACHADDR)->externup) /* * SCSI bus @@ -234,12 +264,17 @@ struct Target { }; typedef int (*Scsiio)(Target*, int, uchar*, int, void*, int*); -#define MAXPCMCIA 8 /* maximum number of PCMCIA cards */ -#define BOOTLINE ((char *)0x80000100) /* bootline passed by boot program */ +typedef struct Irq { + void (*f)(Ureg*, void*); /* handler to call */ + void* a; /* argument to call it with */ -extern PCArch *arch; /* PC architecture */ -extern int cpuflag; /* true if this is a CPU */ + Irq* next; /* link to next handler */ +} Irq; -extern Mach *m; -extern Proc *up; -extern char filaddr[]; +typedef struct Irqctl { + int (*isr)(int); /* get isr bit for this irq */ + int (*eoi)(int); /* eoi */ + int isintr; + + Irq* irq; /* handlers on this IRQ */ +} Irqctl; diff --git a/pc/devastar.c b/pc/devastar.c index 14a328b48fe20639dc4aece9e6b8642c773ed896..495ceeff6b1f4f8595510de0369d95e1e402a38e 100644 --- a/pc/devastar.c +++ b/pc/devastar.c @@ -315,7 +315,7 @@ setpage(Astar *a, ulong offset) /* * generate the astar directory entries */ -int +static int astargen(Chan *c, Dirtab *tab, int ntab, int i, Dir *db) { int dev, sofar, ch, t; @@ -386,7 +386,7 @@ astargen(Chan *c, Dirtab *tab, int ntab, int i, Dir *db) return 1; } -void +static void astarreset(void) { int i; @@ -416,7 +416,7 @@ astarreset(void) a->irq = 15; a->id = i; - a->mem = getisa(a->mem, Pagesize, Pagesize); + a->mem = umbmalloc(a->mem, Pagesize, Pagesize); if(a->mem == 0) panic("astarreset: %lux", a->mem); a->mem &= ~KZERO; @@ -436,7 +436,7 @@ astarreset(void) } /* isa ports an ax00i can appear at */ -int isaport[] = { 0x200, 0x208, 0x300, 0x308, 0x600, 0x608, 0x700, 0x708, 0 }; +static int isaport[] = { 0x200, 0x208, 0x300, 0x308, 0x600, 0x608, 0x700, 0x708, 0 }; static int astarprobe(int port) @@ -499,36 +499,25 @@ astarsetup(Astar *a) return 0; } -void -astarinit(void) -{ -} - -Chan* +static Chan* astarattach(char *spec) { return devattach('G', spec); } -Chan* -astarclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int astarwalk(Chan *c, char *name) { return devwalk(c, name, 0, 0, astargen); } -void +static void astarstat(Chan *c, char *dp) { devstat(c, dp, 0, 0, astargen); } -Chan* +static Chan* astaropen(Chan *c, int omode) { Astar *a; @@ -565,7 +554,7 @@ astaropen(Chan *c, int omode) return c; } -void +static void astarclose(Chan *c) { Astar *a; @@ -687,7 +676,7 @@ statread(Astarchan *ac, void *buf, long n, ulong offset) return readstr(offset, buf, n, s); } -long +static long astarread(Chan *c, void *buf, long n, ulong offset) { Astar *a; @@ -713,12 +702,6 @@ astarread(Chan *c, void *buf, long n, ulong offset) return 0; } -Block* -astarbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - /* * write ISA mapped memory */ @@ -890,7 +873,7 @@ startcp(Astar *a) c |= ISAien|isairqcode[a->irq]; outb(a->port+ISActl1, c); - setvec(Int0vec + a->irq, astarintr, a); + intrenable(VectorPIC + a->irq, astarintr, a, BUSUNKNOWN); /* enable control program interrupt generation */ LOCKPAGE(a, 0); @@ -1095,8 +1078,8 @@ astarctl(Astarchan *ac, char *cmd) break; case 'H': case 'h': - qhangup(ac->iq); - qhangup(ac->oq); + qhangup(ac->iq, nil); + qhangup(ac->oq, nil); break; case 'L': case 'l': @@ -1189,7 +1172,7 @@ astarctl(Astarchan *ac, char *cmd) chancmd(ac, command); } -long +static long astarwrite(Chan *c, void *buf, long n, ulong offset) { Astar *a; @@ -1233,26 +1216,7 @@ astarwrite(Chan *c, void *buf, long n, ulong offset) return 0; } -long -astarbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -astarcreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void -astarremove(Chan *c) -{ - USED(c); - error(Eperm); -} - -void +static void astarwstat(Chan *c, char *dp) { Dir d; @@ -1271,6 +1235,24 @@ astarwstat(Chan *c, char *dp) ac->perm = d.mode; } +Dev astardevtab = { + astarreset, + devinit, + astarattach, + devclone, + astarwalk, + astarstat, + astaropen, + devcreate, + astarclose, + astarread, + devbread, + astarwrite, + devbwrite, + devremove, + astarwstat, +}; + /* * get output going */ @@ -1314,6 +1296,7 @@ astaroutput(Astarchan *ac) ccb->outwp = LEUS(wp - a->addr); } } + static void astarkick(Astarchan *ac) { diff --git a/pc/devata.c b/pc/devata.c index 3daa201d96c45fc8ff58e03e5bc8c97c3954564c..cbdec314112b19e14fad0de86d58417324f6dcce 100644 --- a/pc/devata.c +++ b/pc/devata.c @@ -155,6 +155,7 @@ struct Controller int pbase; /* base port */ uchar ctlrno; + int tbdf; uchar resetok; /* @@ -180,7 +181,7 @@ static Controller *atactlr[NCtlr]; static QLock atactlrlock[NCtlr]; static Drive *atadrive[NDrive]; static int spindownmask; -static int have640b = -1; +static int have640b; static int pbase[NCtlr] = { Pbase0, Pbase1, Pbase2, Pbase3, }; @@ -196,6 +197,7 @@ static void ataparams(Drive*); static void atapart(Drive*); static int ataprobe(Drive*, int, int, int); static void atasleep(Controller*, int); +static void ataclock(void); static int isatapi(Drive*); static long atapirwio(Chan*, char*, ulong, ulong); @@ -203,7 +205,7 @@ static void atapipart(Drive*); static void atapiintr(Controller*); static int -atagen(Chan *c, Dirtab*, int, int s, Dir *dirp) +atagen(Chan* c, Dirtab*, int, int s, Dir* dirp) { Qid qid; int drive; @@ -237,10 +239,8 @@ atagen(Chan *c, Dirtab*, int, int s, Dir *dirp) static void cmd640b(void) { - PCIcfg* pcicfg; - uchar r50[12]; - int devno; - extern void pcicfgw8(int, int, int, int, void*, int); + Pcidev *p; + int r; /* * Look for CMD640B dual PCI controllers. Amongst other @@ -249,12 +249,9 @@ cmd640b(void) * controllers this is, so if one is found then all controller * pairs are synchronised. */ - pcicfg = malloc(sizeof(PCIcfg)); - pcicfg->vid = 0x1095; - pcicfg->did = 0x0640; - devno = 0; - while((devno = pcimatch(0, devno, pcicfg)) != -1){ - have640b = devno-1; + p = 0; + while(p = pcimatch(p, 0x1095, 0x0640)){ + have640b++; /* * If one is found, make sure read-ahead is disabled on all * drives and that the 2nd controller is enabled: @@ -263,41 +260,34 @@ cmd640b(void) * bit 3 - 2nd controller enable * reg 0x57: bit 3 - drive 1 read ahead disable * bit 2 - drive 0 read ahead disable - * Doing byte-writes to PCI configuration space is not in the - * spec... */ - pcicfgr(0, have640b, 0, 0x50, r50, sizeof(r50)); - r50[0x01] |= 0xC8; - pcicfgw8(0, have640b, 0, 0x51, &r50[0x01], sizeof(r50[0x01])); - r50[0x07] |= 0x0C; - pcicfgw8(0, have640b, 0, 0x57, &r50[0x07], sizeof(r50[0x07])); + r = pcicfgr8(p, 0x51); + r |= 0xC8; + pcicfgw8(p, 0x51, r); + r = pcicfgr8(p, 0x57); + r |= 0x0C; + pcicfgw8(p, 0x57, r); } - free(pcicfg); } static void rz1000(void) { - PCIcfg* pcicfg; - ulong r40; - int devno; + Pcidev *p; + ulong r; /* * Look for PC-Tech RZ1000 controllers and turn off prefetch. * This is overkill, but cheap. */ - pcicfg = malloc(sizeof(PCIcfg)); - pcicfg->vid = 0x1042; - pcicfg->did = 0; - devno = 0; - while((devno = pcimatch(0, devno, pcicfg)) != -1){ - if(pcicfg->did != 0x1000 && pcicfg->did != 0x1001) + p = 0; + while(p = pcimatch(p, 0x1042, 0)){ + if(p->did != 0x1000 && p->did != 0x1001) continue; - pcicfgr(0, devno-1, 0, 0x40, &r40, sizeof(r40)); - r40 &= ~0x2000; - pcicfgw(0, devno-1, 0, 0x40, &r40, sizeof(r40)); + r = pcicfgr32(p, 0x40); + r &= ~0x2000; + pcicfgw32(p, 0x40, r); } - free(pcicfg); } static int @@ -378,6 +368,7 @@ atactlrprobe(int ctlrno, int irq) return -1; ctlr->pbase = port; ctlr->ctlrno = ctlrno; + ctlr->tbdf = BUSUNKNOWN; ctlr->lastcmd = 0xFF; @@ -414,7 +405,7 @@ atactlrprobe(int ctlrno, int irq) inb(port+Pcylmsb), inb(port+Pcyllsb)); if(status == 0 && inb(port+Pcylmsb) == 0xEB && inb(port+Pcyllsb) == 0x14){ DPRINT("ata%d: ATAPI ok\n", ctlrno); - setvec(irq, ataintr, ctlr); + intrenable(irq, ataintr, ctlr, ctlr->tbdf); atapi |= 0x01; mask |= 0x01; goto skipedd; @@ -425,7 +416,7 @@ atactlrprobe(int ctlrno, int irq) xfree(ctlr); return -1; } - setvec(irq, ataintr, ctlr); + intrenable(irq, ataintr, ctlr, ctlr->tbdf); ctlr->cmd = Cedd; outb(port+Pcmd, Cedd); atasleep(ctlr, Hardtimeout); @@ -480,7 +471,7 @@ skipedd: } atactlr[ctlrno] = ctlr; - if(have640b >= 0 && (ctlrno & 0x01)) + if(have640b && (ctlrno & 0x01)) ctlr->ctlrlock = &atactlrlock[ctlrno-1]; else ctlr->ctlrlock = &atactlrlock[ctlrno]; @@ -493,7 +484,7 @@ skipedd: return 0; } -void +static void atactlrreset(void) { int ctlrno, driveno, i, slave, spindown; @@ -509,7 +500,7 @@ atactlrreset(void) if(isa.irq == 0 && (isa.irq = defirq[ctlrno]) == 0) continue; - if(atactlrprobe(ctlrno, Int0vec+isa.irq)) + if(atactlrprobe(ctlrno, VectorPIC+isa.irq)) continue; for(i = 0; i < isa.nopt; i++){ @@ -539,24 +530,17 @@ atactlrreset(void) atactlr[ctlrno]->resetok = 1; } } -} - -void -atareset(void) -{ -} -void -atainit(void) -{ + if(spindownmask) + addclock0link(ataclock); } /* * Get the characteristics of each drive. Mark unresponsive ones * off line. */ -Chan* -ataattach(char *spec) +static Chan* +ataattach(char* spec) { int driveno; Drive *dp; @@ -600,38 +584,26 @@ ataattach(char *spec) return devattach('H', spec); } -Chan* -ataclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int -atawalk(Chan *c, char *name) +static int +atawalk(Chan* c, char* name) { return devwalk(c, name, 0, 0, atagen); } -void -atastat(Chan *c, char *dp) +static void +atastat(Chan* c, char* dp) { devstat(c, dp, 0, 0, atagen); } -Chan* -ataopen(Chan *c, int omode) +static Chan* +ataopen(Chan* c, int omode) { return devopen(c, omode, 0, 0, atagen); } void -atacreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void -ataclose(Chan *c) +ataclose(Chan* c) { Drive *dp; Partition *p; @@ -657,20 +629,8 @@ ataclose(Chan *c) poperror(); } -void -ataremove(Chan*) -{ - error(Eperm); -} - -void -atawstat(Chan*, char*) -{ - error(Eperm); -} - -long -ataread(Chan *c, void *a, long n, ulong offset) +static long +ataread(Chan* c, void* a, long n, ulong offset) { Drive *dp; long rv, i; @@ -723,13 +683,7 @@ ataread(Chan *c, void *a, long n, ulong offset) return rv; } -Block* -atabread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long +static long atawrite(Chan *c, void *a, long n, ulong offset) { Drive *dp; @@ -802,12 +756,6 @@ atawrite(Chan *c, void *a, long n, ulong offset) return rv; } -long -atabwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - /* * did an interrupt happen? */ @@ -1601,8 +1549,8 @@ ataintr(Ureg*, void* arg) IUNLOCK(&cp->reglock); } -void -hardclock(void) +static void +ataclock(void) { int driveno, mask; Drive *dp; @@ -1962,3 +1910,21 @@ atapiintr(Controller *cp) break; } } + +Dev atadevtab = { + devreset, + devinit, + ataattach, + devclone, + atawalk, + atastat, + ataopen, + devcreate, + ataclose, + ataread, + devbread, + atawrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/pc/devether.c b/pc/devether.c index 553f4f15d220c85d73597e6d9ee038964627dead..ffcd25fa897440769e1a6731c058795a84de9ed9 100644 --- a/pc/devether.c +++ b/pc/devether.c @@ -10,19 +10,14 @@ #include "etherif.h" -static Ether *ether[MaxEther]; - -void -etherinit(void) -{ -} +static Ether *etherxx[MaxEther]; Chan* -etherattach(char *spec) +etherattach(char* spec) { ulong ctlrno; char *p; - Chan *c; + Chan *chan; ctlrno = 0; if(spec && *spec){ @@ -30,184 +25,249 @@ etherattach(char *spec) if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther)) error(Ebadarg); } - if(ether[ctlrno] == 0) + if(etherxx[ctlrno] == 0) error(Enodev); - c = devattach('l', spec); - c->dev = ctlrno; - if(ether[ctlrno]->attach) - (*ether[ctlrno]->attach)(ether[ctlrno]); - return c; -} - -Chan* -etherclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); + chan = devattach('l', spec); + chan->dev = ctlrno; + if(etherxx[ctlrno]->attach) + etherxx[ctlrno]->attach(etherxx[ctlrno]); + return chan; } -int -etherwalk(Chan *c, char *name) +static int +etherwalk(Chan* chan, char* name) { - return netifwalk(ether[c->dev], c, name); + return netifwalk(etherxx[chan->dev], chan, name); } -void -etherstat(Chan *c, char *dp) +static void +etherstat(Chan* chan, char* dp) { - netifstat(ether[c->dev], c, dp); + netifstat(etherxx[chan->dev], chan, dp); } -Chan* -etheropen(Chan *c, int omode) +static Chan* +etheropen(Chan* chan, int omode) { - return netifopen(ether[c->dev], c, omode); + return netifopen(etherxx[chan->dev], chan, omode); } -void +static void ethercreate(Chan*, char*, int, ulong) { } -void -etherclose(Chan *c) +static void +etherclose(Chan* chan) { - netifclose(ether[c->dev], c); + netifclose(etherxx[chan->dev], chan); } -long -etherread(Chan *c, void *buf, long n, ulong offset) +static long +etherread(Chan* chan, void* buf, long n, ulong offset) { - Ether *ctlr; + Ether *ether; - ctlr = ether[c->dev]; - if((c->qid.path & CHDIR) == 0 && ctlr->ifstat){ + ether = etherxx[chan->dev]; + if((chan->qid.path & CHDIR) == 0 && ether->ifstat){ /* * With some controllers it is necessary to reach * into the chip to extract statistics. */ - if(NETTYPE(c->qid.path) == Nifstatqid) - return (*ctlr->ifstat)(ctlr, buf, n, offset); - else if(NETTYPE(c->qid.path) == Nstatqid) - (*ctlr->ifstat)(ctlr, buf, 0, offset); + if(NETTYPE(chan->qid.path) == Nifstatqid) + return ether->ifstat(ether, buf, n, offset); + else if(NETTYPE(chan->qid.path) == Nstatqid) + ether->ifstat(ether, buf, 0, offset); } - return netifread(ctlr, c, buf, n, offset); + return netifread(ether, chan, buf, n, offset); } -Block* -etherbread(Chan *c, long n, ulong offset) +static Block* +etherbread(Chan* chan, long n, ulong offset) { - return devbread(c, n, offset); + return netifbread(etherxx[chan->dev], chan, n, offset); } -void +static void etherremove(Chan*) { } -void -etherwstat(Chan *c, char *dp) +static void +etherwstat(Chan* chan, char* dp) { - netifwstat(ether[c->dev], c, dp); + netifwstat(etherxx[chan->dev], chan, dp); } -void -etherrloop(Ether *ctlr, Etherpkt *pkt, long len) +static void +etherrtrace(Netfile* f, Etherpkt* pkt, int len) { + int i, n; Block *bp; + + if(qwindow(f->in) <= 0) + return; + if(len > 64) + n = 64; + else + n = len; + bp = iallocb(n); + if(bp == 0) + return; + memmove(bp->wp, pkt->d, n); + i = TK2MS(m->ticks); + bp->wp[58] = len>>8; + bp->wp[59] = len; + bp->wp[60] = i>>24; + bp->wp[61] = i>>16; + bp->wp[62] = i>>8; + bp->wp[63] = i; + bp->wp += 64; + qpass(f->in, bp); +} + +Block* +etheriq(Ether* ether, Block* bp, int freebp) +{ + Etherpkt *pkt; ushort type; - int i, n; - Netfile *f, **fp, **ep; + int len; + Netfile **ep, *f, **fp, *fx; + Block *xbp; + + ether->inpackets++; + pkt = (Etherpkt*)bp->rp; + len = BLEN(bp); type = (pkt->type[0]<<8)|pkt->type[1]; - ep = &ctlr->f[Ntypes]; - for(fp = ctlr->f; fp < ep; fp++){ + fx = 0; + ep = ðer->f[Ntypes]; + + /* + * Multiplex the packet to all the connections which want it. + * If the packet is not to be used subsequently (freebp != 0), + * attempt to simply pass it into one of the connections, thereby + * saving a copy of the data (usual case hopefully). + */ + for(fp = ether->f; fp < ep; fp++){ if((f = *fp) && (f->type == type || f->type < 0)){ if(f->type > -2){ - if(qproduce(f->in, pkt->d, len) < 0) - ctlr->soverflows++; - } else { - if(qwindow(f->in) <= 0) - continue; - if(len > 64) - n = 64; + if(freebp && fx == 0) + fx = f; + else if(xbp = iallocb(len)){ + memmove(xbp->wp, pkt, len); + xbp->wp += len; + qpass(f->in, xbp); + } else - n = len; - bp = iallocb(n); - if(bp == 0) - continue; - memmove(bp->wp, pkt->d, n); - i = TK2MS(m->ticks); - bp->wp[58] = len>>8; - bp->wp[59] = len; - bp->wp[60] = i>>24; - bp->wp[61] = i>>16; - bp->wp[62] = i>>8; - bp->wp[63] = i; - bp->wp += 64; - qpass(f->in, bp); + ether->soverflows++; } + else + etherrtrace(f, pkt, len); } } + + if(fx){ + qpass(fx->in, bp); + return 0; + } + if(freebp){ + freeb(bp); + return 0; + } + + return bp; } static int -etherwloop(Ether *ctlr, Etherpkt *pkt, long len) +etheroq(Ether* ether, Block* bp) { - int s, different; - - different = memcmp(pkt->d, ctlr->ea, sizeof(pkt->d)); - if(different && memcmp(pkt->d, ctlr->bcast, sizeof(pkt->d)) && ctlr->prom == 0) - return 0; + int len, loopback, s; + Etherpkt *pkt; + + ether->outpackets++; + + /* + * Check if the packet has to be placed back onto the input queue, + * i.e. if it's a loopback or broadcast packet or the interface is + * in promiscuous mode. + * If it's a loopback packet indicate to etheriq that the data isn't + * needed and return, etheriq will pass-on or free the block. + */ + pkt = (Etherpkt*)bp->rp; + len = BLEN(bp); + loopback = !memcmp(pkt->d, ether->ea, sizeof(pkt->d)); + if(loopback || !memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) || ether->prom){ + s = splhi(); + etheriq(ether, bp, loopback); + splx(s); + } - s = splhi(); - etherrloop(ctlr, pkt, len); - splx(s); + if(!loopback){ + qbwrite(ether->oq, bp); + ether->transmit(ether); + } - return different == 0; + return len; } -long -etherwrite(Chan *c, void *buf, long n, ulong) +static long +etherwrite(Chan* chan, void* buf, long n, ulong) { - Ether *ctlr; + Ether *ether; + Block *bp; if(n > ETHERMAXTU) error(Ebadarg); - ctlr = ether[c->dev]; - - if(NETTYPE(c->qid.path) != Ndataqid) - return netifwrite(ctlr, c, buf, n); - if(etherwloop(ctlr, buf, n)) - return n; + ether = etherxx[chan->dev]; + if(NETTYPE(chan->qid.path) != Ndataqid) + return netifwrite(ether, chan, buf, n); - qlock(&ctlr->tlock); + bp = allocb(n); if(waserror()){ - qunlock(&ctlr->tlock); + freeb(bp); nexterror(); } - n = (*ctlr->write)(ctlr, buf, n); - qunlock(&ctlr->tlock); + memmove(bp->rp, buf, n); + memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen); poperror(); + bp->wp += n; - return n; + return etheroq(ether, bp); } -long -etherbwrite(Chan *c, Block *bp, ulong offset) +static long +etherbwrite(Chan* chan, Block* bp, ulong) { - return devbwrite(c, bp, offset); + Ether *ether; + long n; + + n = BLEN(bp); + if(n > ETHERMAXTU){ + freeb(bp); + error(Ebadarg); + } + + ether = etherxx[chan->dev]; + if(NETTYPE(chan->qid.path) != Ndataqid){ + n = netifwrite(ether, chan, bp->rp, n); + freeb(bp); + return n; + } + + return etheroq(ether, bp); } static struct { - char *type; + char* type; int (*reset)(Ether*); } cards[MaxEther+1]; void -addethercard(char *t, int (*r)(Ether*)) +addethercard(char* t, int (*r)(Ether*)) { static int ncard; @@ -218,24 +278,55 @@ addethercard(char *t, int (*r)(Ether*)) ncard++; } -void +int +parseether(uchar *to, char *from) +{ + char nip[4]; + char *p; + int i; + + p = from; + for(i = 0; i < 6; i++){ + if(*p == 0) + return -1; + nip[0] = *p++; + if(*p == 0) + return -1; + nip[1] = *p++; + nip[2] = 0; + to[i] = strtoul(nip, 0, 16); + if(*p == ':') + p++; + } + return 0; +} + +static void etherreset(void) { - Ether *ctlr; + Ether *ether; int i, n, ctlrno; - - for(ctlr = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ - if(ctlr == 0) - ctlr = malloc(sizeof(Ether)); - memset(ctlr, 0, sizeof(Ether)); - ctlr->ctlrno = ctlrno; - ctlr->mbps = 10; - if(isaconfig("ether", ctlrno, ctlr) == 0) + char name[NAMELEN], buf[128]; + + for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ + if(ether == 0) + ether = malloc(sizeof(Ether)); + memset(ether, 0, sizeof(Ether)); + ether->ctlrno = ctlrno; + ether->tbdf = BUSUNKNOWN; + ether->mbps = 10; + if(isaconfig("ether", ctlrno, ether) == 0) continue; for(n = 0; cards[n].type; n++){ - if(strcmp(cards[n].type, ctlr->type)) + if(cistrcmp(cards[n].type, ether->type)) continue; - if((*cards[n].reset)(ctlr)) + for(i = 0; i < ether->nopt; i++){ + if(strncmp(ether->opt[i], "ea=", 3)) + continue; + if(parseether(ether->ea, ðer->opt[i][3]) == -1) + memset(ether->ea, 0, Eaddrlen); + } + if(cards[n].reset(ether)) break; /* @@ -243,34 +334,60 @@ etherreset(void) * controllers together. A device set to IRQ2 will appear on * the second interrupt controller as IRQ9. */ - if(ctlr->irq == 2) - ctlr->irq = 9; - setvec(Int0vec+ctlr->irq, ctlr->interrupt, ctlr); - - print("ether#%d: %s: %dMbps port 0x%luX irq %d", - ctlrno, ctlr->type, ctlr->mbps, ctlr->port, ctlr->irq); - if(ctlr->mem) - print(" addr 0x%luX", ctlr->mem & ~KZERO); - if(ctlr->size) - print(" size 0x%luX", ctlr->size); - print(": "); - for(i = 0; i < sizeof(ctlr->ea); i++) - print("%2.2uX", ctlr->ea[i]); - print("\n"); - - if(ctlr->mbps == 100) - netifinit(ctlr, "ether", Ntypes, 128*1024); - else - netifinit(ctlr, "ether", Ntypes, 32*1024); - ctlr->alen = Eaddrlen; - memmove(ctlr->addr, ctlr->ea, sizeof(ctlr->ea)); - memmove(ctlr->bcast, etherbcast, sizeof(etherbcast)); + if(ether->irq == 2) + ether->irq = 9; + intrenable(VectorPIC+ether->irq, ether->interrupt, ether, ether->tbdf); + + i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d", + ctlrno, ether->type, ether->mbps, ether->port, ether->irq); + if(ether->mem) + i += sprint(buf+i, " addr 0x%luX", ether->mem & ~KZERO); + if(ether->size) + i += sprint(buf+i, " size 0x%luX", ether->size); + i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX", + ether->ea[0], ether->ea[1], ether->ea[2], + ether->ea[3], ether->ea[4], ether->ea[5]); + sprint(buf+i, "\n"); + print(buf); + + snprint(name, sizeof(name), "ether%d", ctlrno); + if(ether->mbps == 100){ + netifinit(ether, name, Ntypes, 256*1024); + if(ether->oq == 0) + ether->oq = qopen(256*1024, 1, 0, 0); + } + else{ + netifinit(ether, name, Ntypes, 32*1024); + if(ether->oq == 0) + ether->oq = qopen(64*1024, 1, 0, 0); + } + ether->alen = Eaddrlen; + memmove(ether->addr, ether->ea, Eaddrlen); + memset(ether->bcast, 0xFF, Eaddrlen); - ether[ctlrno] = ctlr; - ctlr = 0; + etherxx[ctlrno] = ether; + ether = 0; break; } } - if(ctlr) - free(ctlr); + if(ether) + free(ether); } + +Dev etherdevtab = { + etherreset, + devinit, + etherattach, + devclone, + etherwalk, + etherstat, + etheropen, + ethercreate, + etherclose, + etherread, + etherbread, + etherwrite, + etherbwrite, + etherremove, + etherwstat, +}; diff --git a/pc/devfloppy.c b/pc/devfloppy.c index 78b16c70fb4d2e579845ab32e68d5d4889c6163f..73d04dca7b85a93f80e79aa7cc3565347ee4ca22 100644 --- a/pc/devfloppy.c +++ b/pc/devfloppy.c @@ -6,62 +6,30 @@ #include "io.h" #include "../port/error.h" -/* Intel 82077A (8272A compatible) floppy controller */ - -typedef struct Drive Drive; -typedef struct Controller Controller; -typedef struct Type Type; +#include "floppy.h" -#define DPRINT if(floppydebug)print -int floppydebug; +/* Intel 82077A (8272A compatible) floppy controller */ -/* bits in the registers */ -enum -{ - /* status registers a & b */ - Psra= 0x3f0, - Psrb= 0x3f1, - - /* digital output register */ - Pdor= 0x3f2, - Fintena= 0x8, /* enable floppy interrupt */ - Fena= 0x4, /* 0 == reset controller */ - - /* main status register */ - Pmsr= 0x3f4, - Fready= 0x80, /* ready to be touched */ - Ffrom= 0x40, /* data from controller */ - Fbusy= 0x10, /* operation not over */ - - /* data register */ - Pdata= 0x3f5, - Frecal= 0x07, /* recalibrate cmd */ - Fseek= 0x0f, /* seek cmd */ - Fsense= 0x08, /* sense cmd */ - Fread= 0x66, /* read cmd */ - Freadid= 0x4a, /* read track id */ - Fspec= 0x03, /* set hold times */ - Fwrite= 0x45, /* write cmd */ - Fformat= 0x4d, /* format cmd */ - Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */ - Fdumpreg= 0x0e, /* dump internal registers */ - - /* digital input register */ - Pdir= 0x3F7, /* disk changed port (read only) */ - Pdsr= 0x3F7, /* data rate select port (write only) */ - Fchange= 0x80, /* disk has changed */ - - /* status 0 byte */ - Drivemask= 3<<0, - Seekend= 1<<5, - Codemask= (3<<6)|(3<<3), - Cmdexec= 1<<6, - - /* status 1 byte */ - Overrun= 0x10, +/* This module expects the following functions to be defined + * elsewhere: + * + * inb() + * outb() + * floppyexec() + * floppyeject() + * floppysetup0() + * floppysetup1() + * dmasetup() + * dmaend() + * + * On DMA systems, floppyexec() should be an empty function; + * on non-DMA systems, dmaend() should be an empty function; + * dmasetup() may enforce maximum transfer sizes. + */ +enum { /* file types */ - Qdir= 0, + Qdir= 0, Qdata= (1<<2), Qctl= (2<<2), Qmask= (3<<2), @@ -69,6 +37,9 @@ enum DMAchan= 2, /* floppy dma channel */ }; +#define DPRINT if(floppydebug)iprint +int floppydebug; + /* * types of drive (from PC equipment byte) */ @@ -81,31 +52,7 @@ enum T1440kb= 4, }; -/* - * floppy types (all MFM encoding) - */ -struct Type -{ - char *name; - int dt; /* compatible drive type */ - int bytes; /* bytes/sector */ - int sectors; /* sectors/track */ - int heads; /* number of heads */ - int steps; /* steps per cylinder */ - int tracks; /* tracks/disk */ - int gpl; /* intersector gap length for read/write */ - int fgpl; /* intersector gap length for format */ - int rate; /* rate code */ - - /* - * these depend on previous entries and are set filled in - * by floppyinit - */ - int bcode; /* coded version of bytes for the controller */ - long cap; /* drive capacity in bytes */ - long tsize; /* track size in bytes */ -}; -Type floppytype[] = +FType floppytype[] = { { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, }, { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, }, @@ -115,7 +62,6 @@ Type floppytype[] = { "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, }, { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, }, }; -#define NTYPES (sizeof(floppytype)/sizeof(Type)) /* * bytes per sector encoding for the controller. @@ -137,86 +83,34 @@ static int c2b[] = 1024, }; -/* - * a floppy drive - */ -struct Drive -{ - Type *t; /* floppy type */ - int dt; /* drive type */ - int dev; - - ulong lasttouched; /* time last touched */ - int cyl; /* current arm position */ - int confused; /* needs to be recalibrated */ - int vers; - - int tcyl; /* target cylinder */ - int thead; /* target head */ - int tsec; /* target sector */ - long len; /* size of xfer */ - - uchar *cache; /* track cache */ - int ccyl; - int chead; - - Rendez r; /* waiting here for motor to spin up */ -}; - -/* - * controller for 4 floppys - */ -struct Controller -{ - QLock; /* exclusive access to the contoller */ - - Drive *d; /* the floppy drives */ - Drive *selected; - int rate; /* current rate selected */ - uchar cmd[14]; /* command */ - int ncmd; /* # command bytes */ - uchar stat[14]; /* command status */ - int nstat; /* # status bytes */ - int confused; /* controler needs to be reset */ - Rendez r; /* wait here for command termination */ - int motor; /* bit mask of spinning disks */ - Rendez kr; /* for motor watcher */ -}; - -Controller fl; +FController fl; #define MOTORBIT(i) (1<<((i)+4)) /* * predeclared */ -static int floppycmd(void); -static void floppyeject(Drive*); -static void floppyintr(Ureg*, void*); +static int cmddone(void*); +static void floppyformat(FDrive*, char*); static void floppykproc(void*); -static void floppyon(Drive*); -static void floppyoff(Drive*); -static void floppypos(Drive*,long); -static int floppyrecal(Drive*); +static void floppypos(FDrive*,long); +static int floppyrecal(FDrive*); static int floppyresult(void); static void floppyrevive(void); -static long floppyseek(Drive*, long); +static long floppyseek(FDrive*, long); static int floppysense(void); static void floppywait(void); -static long floppyxfer(Drive*, int, void*, long, long); -static void floppyformat(Drive*, char*); -static int cmddone(void*); -void Xdelay(int); +static long floppyxfer(FDrive*, int, void*, long, long); Dirtab floppydir[]={ - "fd0disk", {Qdata + 0}, 0, 0660, - "fd0ctl", {Qctl + 0}, 0, 0660, - "fd1disk", {Qdata + 1}, 0, 0660, - "fd1ctl", {Qctl + 1}, 0, 0660, - "fd2disk", {Qdata + 2}, 0, 0660, - "fd2ctl", {Qctl + 2}, 0, 0660, - "fd3disk", {Qdata + 3}, 0, 0660, - "fd3ctl", {Qctl + 3}, 0, 0660, + "fd0disk", {Qdata + 0}, 0, 0666, + "fd0ctl", {Qctl + 0}, 0, 0666, + "fd1disk", {Qdata + 1}, 0, 0666, + "fd1ctl", {Qctl + 1}, 0, 0666, + "fd2disk", {Qdata + 2}, 0, 0666, + "fd2ctl", {Qctl + 2}, 0, 0666, + "fd3disk", {Qdata + 3}, 0, 0666, + "fd3ctl", {Qctl + 3}, 0, 0666, }; #define NFDIR 2 /* directory entries/drive */ @@ -231,32 +125,32 @@ fldump(void) * set floppy drive to its default type */ static void -setdef(Drive *dp) +floppysetdef(FDrive *dp) { - Type *t; + FType *t; - for(t = floppytype; t < &floppytype[NTYPES]; t++){ + for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++) if(dp->dt == t->dt){ dp->t = t; floppydir[NFDIR*dp->dev].length = dp->t->cap; - return; + break; } - } } -void +static void floppyreset(void) { - Drive *dp; - Type *t; - uchar equip; + FDrive *dp; + FType *t; ulong maxtsize; + + floppysetup0(&fl); /* * init dependent parameters */ maxtsize = 0; - for(t = floppytype; t < &floppytype[NTYPES]; t++){ + for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){ t->cap = t->bytes * t->heads * t->sectors * t->tracks; t->bcode = b2c[t->bytes/128]; t->tsize = t->bytes * t->sectors; @@ -267,7 +161,7 @@ floppyreset(void) /* * allocate the drive storage */ - fl.d = xalloc(conf.nfloppy*sizeof(Drive)); + fl.d = xalloc(fl.ndrive*sizeof(FDrive)); fl.selected = fl.d; /* @@ -281,42 +175,25 @@ floppyreset(void) /* * init drives */ - for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){ + for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){ dp->dev = dp - fl.d; dp->dt = T1440kb; - setdef(dp); + floppysetdef(dp); dp->cyl = -1; /* because we don't know */ dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024); dp->ccyl = -1; dp->vers = 1; } - /* - * read nvram for types of floppies 0 & 1 - */ - equip = nvramread(0x10); - if(conf.nfloppy > 0){ - fl.d[0].dt = (equip >> 4) & 0xf; - setdef(&fl.d[0]); - } - if(conf.nfloppy > 1){ - fl.d[1].dt = equip & 0xf; - setdef(&fl.d[1]); - } - /* * first operation will recalibrate */ fl.confused = 1; - setvec(Floppyvec, floppyintr, 0); -} -void -floppyinit(void) -{ + floppysetup1(&fl); } -Chan* +static Chan* floppyattach(char *spec) { static int kstarted; @@ -331,68 +208,32 @@ floppyattach(char *spec) return devattach('f', spec); } -Chan* -floppyclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int floppywalk(Chan *c, char *name) { - return devwalk(c, name, floppydir, conf.nfloppy*NFDIR, devgen); + return devwalk(c, name, floppydir, fl.ndrive*NFDIR, devgen); } -void +static void floppystat(Chan *c, char *dp) { - devstat(c, dp, floppydir, conf.nfloppy*NFDIR, devgen); + devstat(c, dp, floppydir, fl.ndrive*NFDIR, devgen); } -Chan* +static Chan* floppyopen(Chan *c, int omode) { - return devopen(c, omode, floppydir, conf.nfloppy*NFDIR, devgen); + return devopen(c, omode, floppydir, fl.ndrive*NFDIR, devgen); } -void -floppycreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void +static void floppyclose(Chan *c) { USED(c); } -void -floppyremove(Chan *c) -{ - USED(c); - error(Eperm); -} - -void -floppywstat(Chan *c, char *dp) -{ - Dirtab *dt; - Dir d; - - if(!iseve()) - error(Eperm); - if(CHDIR & c->qid.path) - error(Eperm); - - convM2D(dp, &d); - d.mode &= 0x666; - dt = &floppydir[2 * (c->qid.path & ~Qmask)]; - dt[0].perm = dt[1].perm = d.mode; -} - static void -islegal(ulong offset, long n, Drive *dp) +islegal(ulong offset, long n, FDrive *dp) { if(offset % dp->t->bytes) error(Ebadarg); @@ -412,10 +253,10 @@ islegal(ulong offset, long n, Drive *dp) * possibilities for this drive. */ static void -changed(Chan *c, Drive *dp) +changed(Chan *c, FDrive *dp) { ulong old; - Type *start; + FType *start; /* * if floppy has changed or first time through @@ -424,14 +265,14 @@ changed(Chan *c, Drive *dp) DPRINT("changed\n"); fldump(); dp->vers++; - setdef(dp); + floppysetdef(dp); start = dp->t; dp->confused = 1; /* make floppyon recal */ floppyon(dp); floppyseek(dp, dp->t->heads*dp->t->tsize); while(waserror()){ while(++dp->t){ - if(dp->t == &floppytype[NTYPES]) + if(dp->t == &floppytype[nelem(floppytype)]) dp->t = floppytype; if(dp->dt == dp->t->dt) break; @@ -454,7 +295,7 @@ changed(Chan *c, Drive *dp) } static int -readtrack(Drive *dp, int cyl, int head) +readtrack(FDrive *dp, int cyl, int head) { int i, nn, sofar; ulong pos; @@ -474,17 +315,17 @@ readtrack(Drive *dp, int cyl, int head) return nn; } -long +static long floppyread(Chan *c, void *a, long n, ulong offset) { - Drive *dp; + FDrive *dp; long rv; int sec, head, cyl; long len; uchar *aa; if(c->qid.path == CHDIR) - return devdirread(c, a, n, floppydir, conf.nfloppy*NFDIR, devgen); + return devdirread(c, a, n, floppydir, fl.ndrive*NFDIR, devgen); rv = 0; dp = &fl.d[c->qid.path & ~Qmask]; @@ -527,17 +368,11 @@ floppyread(Chan *c, void *a, long n, ulong offset) return rv; } -Block* -floppybread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - #define SNCMP(a, b) strncmp(a, b, sizeof(b)-1) -long +static long floppywrite(Chan *c, void *a, long n, ulong offset) { - Drive *dp; + FDrive *dp; long rv, i; char *aa = a; char ctlmsg[64]; @@ -587,7 +422,8 @@ floppywrite(Chan *c, void *a, long n, ulong offset) floppyformat(dp, ctlmsg); } else if(SNCMP(ctlmsg, "debug") == 0){ floppydebug = 1; - } + } else + error(Ebadctl); poperror(); qunlock(&fl); break; @@ -598,22 +434,16 @@ floppywrite(Chan *c, void *a, long n, ulong offset) return rv; } -long -floppybwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - static void floppykproc(void *a) { - Drive *dp; + FDrive *dp; USED(a); while(waserror()) ; for(;;){ - for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){ + for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){ if((fl.motor&MOTORBIT(dp->dev)) && TK2SEC(m->ticks - dp->lasttouched) > 5 && canqlock(&fl)){ @@ -630,7 +460,7 @@ floppykproc(void *a) * start a floppy drive's motor. */ static void -floppyon(Drive *dp) +floppyon(FDrive *dp) { int alreadyon; int tries; @@ -669,22 +499,10 @@ floppyon(Drive *dp) * stop the floppy if it hasn't been used in 5 seconds */ static void -floppyoff(Drive *dp) +floppyoff(FDrive *dp) { fl.motor &= ~MOTORBIT(dp->dev); outb(Pdor, fl.motor | Fintena | Fena | dp->dev); - fl.selected = dp; -} - -/* - * eject disk ( unknown on safari ) - */ -static void -floppyeject(Drive *dp) -{ - floppyon(dp); - dp->vers++; - floppyoff(dp); } /* @@ -699,6 +517,8 @@ floppycmd(void) fl.nstat = 0; for(i = 0; i < fl.ncmd; i++){ for(tries = 0; ; tries++){ + if((inb(Pmsr)&(Ffrom|Fready)) == Fready) + break; if(tries > 1000){ DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i); fldump(); @@ -707,10 +527,9 @@ floppycmd(void) floppyresult(); return -1; } - if((inb(Pmsr)&(Ffrom|Fready)) == Fready) - break; + microdelay(8); /* for machine independence */ } - outb(Pdata, fl.cmd[i]); + outb(Pfdata, fl.cmd[i]); } return 0; } @@ -732,12 +551,6 @@ floppyresult(void) for(i = 0; i < sizeof(fl.stat); i++){ /* wait for status byte */ for(tries = 0; ; tries++){ - if(tries > 1000){ - DPRINT("floppyresult: %d stats\n", i); - fldump(); - fl.confused = 1; - return -1; - } s = inb(Pmsr)&(Ffrom|Fready); if(s == Fready){ fl.nstat = i; @@ -745,8 +558,15 @@ floppyresult(void) } if(s == (Ffrom|Fready)) break; + if(tries > 1000){ + DPRINT("floppyresult: %d stats\n", i); + fldump(); + fl.confused = 1; + return -1; + } + microdelay(8); /* for machine independence */ } - fl.stat[i] = inb(Pdata); + fl.stat[i] = inb(Pfdata); } fl.nstat = sizeof(fl.stat); return fl.nstat; @@ -758,7 +578,7 @@ floppyresult(void) * truncate dp->length if it crosses a track boundary */ static void -floppypos(Drive *dp, long off) +floppypos(FDrive *dp, long off) { int lsec; int ltrack; @@ -816,7 +636,7 @@ floppywait(void) { tsleep(&fl.r, cmddone, 0, 5000); if(!cmddone(0)){ - floppyintr(0, 0); + floppyintr(0); fl.confused = 1; } } @@ -825,7 +645,7 @@ floppywait(void) * we've lost the floppy position, go to cylinder 0. */ static int -floppyrecal(Drive *dp) +floppyrecal(FDrive *dp) { dp->ccyl = -1; dp->cyl = -1; @@ -865,7 +685,7 @@ floppyrecal(Drive *dp) static void floppyrevive(void) { - Drive *dp; + FDrive *dp; /* * reset the controller if it's confused @@ -888,7 +708,7 @@ floppyrevive(void) floppywait(); /* mark all drives in an unknown state */ - for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++) + for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++) dp->confused = 1; /* set rate to a known value */ @@ -906,7 +726,7 @@ floppyrevive(void) * interrupt, no results */ static long -floppyseek(Drive *dp, long off) +floppyseek(FDrive *dp, long off) { floppypos(dp, off); if(dp->cyl == dp->tcyl) @@ -939,7 +759,7 @@ floppyseek(Drive *dp, long off) * read or write to floppy. try up to three times. */ static long -floppyxfer(Drive *dp, int cmd, void *a, long off, long n) +floppyxfer(FDrive *dp, int cmd, void *a, long off, long n) { long offset; int tries; @@ -949,12 +769,13 @@ floppyxfer(Drive *dp, int cmd, void *a, long off, long n) if(off + n > dp->t->cap) n = dp->t->cap - off; - /* retry on error */ + /* retry on error (until it gets ridiculous) */ tries = 0; while(waserror()){ - DPRINT("floppyxfer: retrying\n"); if(tries++ > 20) nexterror(); + DPRINT("floppyxfer: retrying\n"); + /*floppyon(dp);*/ } dp->len = n; @@ -976,7 +797,6 @@ floppyxfer(Drive *dp, int cmd, void *a, long off, long n) /* * start operation */ - cmd = cmd; fl.ncmd = 0; fl.cmd[fl.ncmd++] = cmd | (dp->t->heads > 1 ? Fmulti : 0); fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; @@ -990,6 +810,9 @@ floppyxfer(Drive *dp, int cmd, void *a, long off, long n) if(floppycmd() < 0) error(Eio); + /* Poll ready bits and transfer data */ + floppyexec((char*)a, dp->len, cmd==Fread); + /* * give bus to DMA, floppyintr() will read result */ @@ -1009,9 +832,9 @@ floppyxfer(Drive *dp, int cmd, void *a, long off, long n) DPRINT("xfer: failed %lux %lux %lux\n", fl.stat[0], fl.stat[1], fl.stat[2]); DPRINT("offset %lud len %d\n", off, dp->len); - if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun) + if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){ DPRINT("DMA overrun: retry\n"); - else + } else dp->confused = 1; error(Eio); } @@ -1037,29 +860,29 @@ floppyxfer(Drive *dp, int cmd, void *a, long off, long n) * format a track */ static void -floppyformat(Drive *dp, char *params) +floppyformat(FDrive *dp, char *params) { int cyl, h, sec; ulong track; uchar *buf, *bp; - Type *t; + FType *t; char *f[3]; /* * set the type */ if(parsefields(params, f, 3, " ") > 1){ - for(t = floppytype; t < &floppytype[NTYPES]; t++){ + for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){ if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){ dp->t = t; floppydir[NFDIR*dp->dev].length = dp->t->cap; break; } } - if(t >= &floppytype[NTYPES]) + if(t >= &floppytype[nelem(floppytype)]) error(Ebadarg); } else { - setdef(dp); + floppysetdef(dp); t = dp->t; } @@ -1122,6 +945,9 @@ floppyformat(Drive *dp, char *params) if(floppycmd() < 0) error(Eio); + /* Poll ready bits and transfer data */ + floppyexec((char *)buf, bp-buf, 0); + /* * give bus to DMA, floppyintr() will read result */ @@ -1150,13 +976,14 @@ floppyformat(Drive *dp, char *params) } static void -floppyintr(Ureg *ur, void *arg) +floppyintr(Ureg *ur) { - USED(ur, arg); + USED(ur); switch(fl.cmd[0]&~Fmulti){ case Fread: case Fwrite: case Fformat: + case Fdumpreg: floppyresult(); break; case Fseek: @@ -1168,3 +995,21 @@ floppyintr(Ureg *ur, void *arg) fl.ncmd = 0; wakeup(&fl.r); } + +Dev floppydevtab = { + floppyreset, + devinit, + floppyattach, + devclone, + floppywalk, + floppystat, + floppyopen, + devcreate, + floppyclose, + floppyread, + devbread, + floppywrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/pc/devi82365.c b/pc/devi82365.c index 22937c8cfed0e45a75de1b97fd3a9667602d5f3e..d1df0737618a96307b806e1d28820a5864c037fe 100644 --- a/pc/devi82365.c +++ b/pc/devi82365.c @@ -185,11 +185,11 @@ static nslot; static void cisread(Slot*); static void i82365intr(Ureg*, void*); +static void i82365reset(void); static int pcmio(int, ISAConf*); static long pcmread(int, int, void*, long, ulong); static long pcmwrite(int, int, void*, long, ulong); -void i82365reset(void); static void i82365dump(Slot*); /* @@ -353,10 +353,10 @@ pcmmap(int slotno, ulong offset, int len, int attr) /* if isa space isn't big enough, free it and get more */ if(m->len < len){ if(m->isa){ - putisa(m->isa, m->len); + umbfree(m->isa, m->len); m->len = 0; } - m->isa = getisa(0, len, Mgran)&~KZERO; + m->isa = umbmalloc(0, len, Mgran)&~KZERO; if(m->isa == 0){ print("pcmmap: out of isa space\n"); unlock(&pp->mlock); @@ -399,7 +399,6 @@ pcmunmap(int slotno, PCMmap* m) unlock(&pp->mlock); } - static void increfp(Slot *pp) { @@ -598,7 +597,7 @@ i82365dump(Slot *pp) /* * set up for slot cards */ -void +static void i82365reset(void) { static int already; @@ -632,45 +631,34 @@ i82365reset(void) slotdis(pp); /* interrupt on status change */ - wrreg(pp, Rcscic, ((PCMCIAvec-Int0vec)<<4) | Fchangeena); + wrreg(pp, Rcscic, ((VectorPCMCIA-VectorPIC)<<4) | Fchangeena); rdreg(pp, Rcsc); } } /* for card management interrupts */ - setvec(PCMCIAvec, i82365intr, 0); -} - -void -i82365init(void) -{ + intrenable(VectorPCMCIA, i82365intr, 0, BUSUNKNOWN); } -Chan * +static Chan* i82365attach(char *spec) { return devattach('y', spec); } -Chan * -i82365clone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int i82365walk(Chan *c, char *name) { return devwalk(c, name, 0, 0, pcmgen); } -void +static void i82365stat(Chan *c, char *db) { devstat(c, db, 0, 0, pcmgen); } -Chan * +static Chan* i82365open(Chan *c, int omode) { if(c->qid.path == CHDIR){ @@ -684,25 +672,7 @@ i82365open(Chan *c, int omode) return c; } -void -i82365create(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void -i82365remove(Chan*) -{ - error(Eperm); -} - -void -i82365wstat(Chan*, char*) -{ - error(Eperm); -} - -void +static void i82365close(Chan *c) { if(c->flag & COPEN) @@ -778,13 +748,7 @@ pcmread(int slotno, int attr, void *a, long n, ulong offset) return n; } -Block* -i82365bread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long +static long i82365read(Chan *c, void *a, long n, ulong offset) { char *cp, buf[2048]; @@ -833,12 +797,6 @@ i82365read(Chan *c, void *a, long n, ulong offset) return n; } -long -i82365bwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - static long pcmwrite(int dev, int attr, void *a, long n, ulong offset) { @@ -881,7 +839,7 @@ pcmwrite(int dev, int attr, void *a, long n, ulong offset) return n; } -long +static long i82365write(Chan *c, void *a, long n, ulong offset) { ulong p; @@ -918,6 +876,24 @@ i82365write(Chan *c, void *a, long n, ulong offset) return n; } +Dev i82365devtab = { + i82365reset, + devinit, + i82365attach, + devclone, + i82365walk, + i82365stat, + i82365open, + devcreate, + i82365close, + i82365read, + devbread, + i82365write, + devbwrite, + devremove, + devwstat, +}; + /* * configure the Slot for IO. We assume very heavily that we can read * configuration info from the CIS. If not, we won't set up correctly. @@ -1252,7 +1228,7 @@ timing(Slot *pp, Conftab *ct) ct->otherwait = ttiming(pp, i); /* reserved wait */ } -void +static void iospaces(Slot *pp, Conftab *ct) { uchar c; diff --git a/pc/devlpt.c b/pc/devlpt.c index c0d9d3100f3d4a8ae6a68b50bc34d03a73ffe14f..6a2c1e934064988d071b7b575cc8f8f9407f5216 100644 --- a/pc/devlpt.c +++ b/pc/devlpt.c @@ -51,7 +51,6 @@ Dirtab lptdir[]={ "pcr", {Qpcr}, 0, 0222, "data", {Qdata}, 0, 0222, }; -#define NLPT (sizeof lptdir/sizeof lptdir[0]) static int lptgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) @@ -71,16 +70,7 @@ lptgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) return 1; } -void -lptreset(void) -{ -} - -void -lptinit(void) -{} - -Chan* +static Chan* lptattach(char *spec) { Chan *c; @@ -90,7 +80,7 @@ lptattach(char *spec) if(!set){ outb(lptbase[i-1]+Qpcr, 0); /* turn off interrupts */ set = 1; - setvec(Parallelvec, lptintr, 0); + intrenable(VectorLPT, lptintr, 0, BUSUNKNOWN); } if(i < 1 || i > NDEV) error(Ebadarg); @@ -99,63 +89,37 @@ lptattach(char *spec) return c; } -Chan* -lptclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int lptwalk(Chan *c, char *name) { - return devwalk(c, name, lptdir, NLPT, lptgen); + return devwalk(c, name, lptdir, nelem(lptdir), lptgen); } -void +static void lptstat(Chan *c, char *dp) { - devstat(c, dp, lptdir, NLPT, lptgen); + devstat(c, dp, lptdir, nelem(lptdir), lptgen); } -Chan* +static Chan* lptopen(Chan *c, int omode) { - return devopen(c, omode, lptdir, NLPT, lptgen); + return devopen(c, omode, lptdir, nelem(lptdir), lptgen); } -void -lptcreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void +static void lptclose(Chan *c) { USED(c); } -void -lptremove(Chan *c) -{ - USED(c); - error(Eperm); -} - -void -lptwstat(Chan *c, char *dp) -{ - USED(c, dp); - error(Eperm); -} - -long -lptread(Chan *c, void *a, long n) +static long +lptread(Chan *c, void *a, long n, ulong) { char str[16]; int size; if(c->qid.path == CHDIR) - return devdirread(c, a, n, lptdir, NLPT, lptgen); + return devdirread(c, a, n, lptdir, nelem(lptdir), lptgen); size = sprint(str, "0x%2.2ux\n", inb(c->qid.path)); if(c->offset >= size) return 0; @@ -165,14 +129,8 @@ lptread(Chan *c, void *a, long n) return n; } -Block* -lptbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long -lptwrite(Chan *c, void *a, long n) +static long +lptwrite(Chan *c, void *a, long n, ulong) { char str[16], *p; long base, k; @@ -200,12 +158,6 @@ lptwrite(Chan *c, void *a, long n) return n; } -long -lptbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - static void outch(int base, int c) { @@ -239,3 +191,21 @@ lptintr(Ureg *ur, void *arg) USED(ur, arg); wakeup(&lptrendez); } + +Dev lptdevtab = { + devreset, + devinit, + lptattach, + devclone, + lptwalk, + lptstat, + lptopen, + devcreate, + lptclose, + lptread, + devbread, + lptwrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/pc/devrtc.c b/pc/devrtc.c index f00b7bd8b60020310c6db0c99e3a1e5b1509ed2d..6c83773483ca245f83a5f85e840e7a8f2809ac56 100644 --- a/pc/devrtc.c +++ b/pc/devrtc.c @@ -45,52 +45,34 @@ enum{ Qnvram, }; -#define NRTC 2 Dirtab rtcdir[]={ "nvram", {Qnvram, 0}, Nvsize, 0664, "rtc", {Qrtc, 0}, 0, 0664, }; -ulong rtc2sec(Rtc*); -void sec2rtc(ulong, Rtc*); -int *yrsize(int); +static ulong rtc2sec(Rtc*); +static void sec2rtc(ulong, Rtc*); -void -rtcreset(void) -{ -} - -void -rtcinit(void) -{ -} - -Chan* -rtcattach(char *spec) +static Chan* +rtcattach(char* spec) { return devattach('r', spec); } -Chan* -rtcclone(Chan *c, Chan *nc) +static int +rtcwalk(Chan* c, char* name) { - return devclone(c, nc); + return devwalk(c, name, rtcdir, nelem(rtcdir), devgen); } -int -rtcwalk(Chan *c, char *name) +static void +rtcstat(Chan* c, char* dp) { - return devwalk(c, name, rtcdir, NRTC, devgen); + devstat(c, dp, rtcdir, nelem(rtcdir), devgen); } -void -rtcstat(Chan *c, char *dp) -{ - devstat(c, dp, rtcdir, NRTC, devgen); -} - -Chan* -rtcopen(Chan *c, int omode) +static Chan* +rtcopen(Chan* c, int omode) { omode = openmode(omode); switch(c->qid.path){ @@ -102,16 +84,10 @@ rtcopen(Chan *c, int omode) if(strcmp(up->user, eve)!=0) error(Eperm); } - return devopen(c, omode, rtcdir, NRTC, devgen); + return devopen(c, omode, rtcdir, nelem(rtcdir), devgen); } -void -rtccreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void +static void rtcclose(Chan*) { } @@ -164,7 +140,7 @@ _rtctime(void) return rtc2sec(&rtc); } -Lock rtlock; +static Lock rtlock; long rtctime(void) @@ -189,14 +165,14 @@ rtctime(void) return t; } -long -rtcread(Chan *c, void *buf, long n, ulong offset) +static long +rtcread(Chan* c, void* buf, long n, ulong offset) { ulong t; char *a; if(c->qid.path & CHDIR) - return devdirread(c, buf, n, rtcdir, NRTC, devgen); + return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen); switch(c->qid.path){ case Qrtc: @@ -226,16 +202,10 @@ rtcread(Chan *c, void *buf, long n, ulong offset) return 0; } -Block* -rtcbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4) -long -rtcwrite(Chan *c, void *buf, long n, ulong offset) +static long +rtcwrite(Chan* c, void* buf, long n, ulong offset) { int t; char *a; @@ -306,23 +276,23 @@ rtcwrite(Chan *c, void *buf, long n, ulong offset) return 0; } -long -rtcbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -rtcremove(Chan*) -{ - error(Eperm); -} - -void -rtcwstat(Chan*, char*) -{ - error(Eperm); -} +Dev rtcdevtab = { + devreset, + devinit, + rtcattach, + devclone, + rtcwalk, + rtcstat, + rtcopen, + devcreate, + rtcclose, + rtcread, + devbread, + rtcwrite, + devbwrite, + devremove, + devwstat, +}; #define SEC2MIN 60L #define SEC2HOUR (60L*SEC2MIN) @@ -343,7 +313,7 @@ static int ldmsize[] = /* * return the days/month for the given year */ -int * +static int* yrsize(int yr) { if((yr % 4) == 0) @@ -355,7 +325,7 @@ yrsize(int yr) /* * compute seconds since Jan 1 1970 */ -ulong +static ulong rtc2sec(Rtc *rtc) { ulong secs; @@ -390,7 +360,7 @@ rtc2sec(Rtc *rtc) /* * compute rtc from seconds since Jan 1 1970 */ -void +static void sec2rtc(ulong secs, Rtc *rtc) { int d; @@ -439,9 +409,26 @@ sec2rtc(ulong secs, Rtc *rtc) return; } +static Lock nvramlock; + uchar -nvramread(int offset) +nvramread(int addr) +{ + uchar data; + + lock(&nvramlock); + outb(Paddr, addr); + data = inb(Pdata); + unlock(&nvramlock); + + return data; +} + +void +nvramwrite(int addr, uchar data) { - outb(Paddr, offset); - return inb(Pdata); + lock(&nvramlock); + outb(Paddr, addr); + outb(Pdata, data); + unlock(&nvramlock); } diff --git a/pc/devvga.c b/pc/devvga.c index 8574a825d0ea7f2d4fcb486f7ad451005d0db39c..5ee904a10ddca4174e8f32504f89c3d7c5805b49 100644 --- a/pc/devvga.c +++ b/pc/devvga.c @@ -15,16 +15,11 @@ enum /* default footprint is 64k */ Footshift= 16, Footprint= 1<base; + for(i = defont0.bits->width*Dy(defont0.bits->r); i > 0; i--, l++) + *l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24); } -Chan* -vgaclone(Chan *c, Chan *nc) +static Chan* +vgaattach(char *spec) { - return devclone(c, nc); + if(*spec && strcmp(spec, "0")) + error(Eio); + return devattach('v', spec); } int vgawalk(Chan *c, char *name) { - return devwalk(c, name, vgadir, Nvga, devgen); + return devwalk(c, name, vgadir, nelem(vgadir), devgen); } -void +static void vgastat(Chan *c, char *dp) { - devstat(c, dp, vgadir, Nvga, devgen); + devstat(c, dp, vgadir, nelem(vgadir), devgen); } -Chan* +static Chan* vgaopen(Chan *c, int omode) { - return devopen(c, omode, vgadir, Nvga, devgen); -} - -void -vgacreate(Chan*, char*, int, ulong) -{ - error(Eperm); + return devopen(c, omode, vgadir, nelem(vgadir), devgen); } -void +static void vgaclose(Chan*) { } @@ -172,7 +162,7 @@ checkvgaport(int port, int len) return -1; } -long +static long vgaread(Chan *c, void *buf, long n, ulong offset) { int port; @@ -184,9 +174,9 @@ vgaread(Chan *c, void *buf, long n, ulong offset) switch(c->qid.path&~CHDIR){ case Qdir: - return devdirread(c, buf, n, vgadir, Nvga, devgen); + return devdirread(c, buf, n, vgadir, nelem(vgadir), devgen); case Qvgactl: - if(cga) + if(vgascreenputc == nil) return readstr(offset, buf, n, "type: cga\n"); vgacp = vgac; port = sprint(cbuf, "type: %s\n", vgacp->name); @@ -226,12 +216,6 @@ vgaread(Chan *c, void *buf, long n, ulong offset) return 0; } -Block* -vgabread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - static void vgactl(char *arg) { @@ -257,7 +241,7 @@ vgactl(char *arg) error(Ebadarg); if(strcmp(field[1], "off") == 0){ if(hwgc){ - (*hwgc->disable)(); + hwgc->disable(); hwgc = 0; cursoron(1); } @@ -267,11 +251,11 @@ vgactl(char *arg) for(hwgcp = hwgctlr; hwgcp; hwgcp = hwgcp->link){ if(strcmp(field[1], hwgcp->name) == 0){ if(hwgc) - (*hwgc->disable)(); + hwgc->disable(); else cursoroff(1); hwgc = hwgcp; - (*hwgc->enable)(); + hwgc->enable(); setcursor(&curs); cursoron(1); return; @@ -361,9 +345,9 @@ vgactl(char *arg) mem = 0; if(vgac->linear) - (*vgac->linear)(&mem, &size, &align); + vgac->linear(&mem, &size, &align); else - mem = getspace(size, align); + mem = upamalloc(0, size, align); if(mem == 0) error("not enough free address space"); screenmem = mem; @@ -379,7 +363,7 @@ vgactl(char *arg) error(Ebadarg); } -long +static long vgawrite(Chan *c, void *buf, long n, ulong offset) { int port; @@ -419,33 +403,28 @@ vgawrite(Chan *c, void *buf, long n, ulong offset) for (lp = buf, port=offset; portbase; - for(i = defont0.bits->width*Dy(defont0.bits->r); i > 0; i--, l++) - *l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24); - - /* - * start in CGA mode - */ - cga = 1; - memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT); -} - static ulong xnto32(uchar x, int n) { @@ -579,10 +534,11 @@ setscreen(int maxx, int maxy, int ldepth) Rectangle r; if(waserror()){ - unlock(&screenlock); + qunlock(&screenlock); nexterror(); } - lock(&screenlock); + + qlock(&screenlock); /* setup a bitmap for the new size */ gscreen.ldepth = ldepth; @@ -623,7 +579,11 @@ setscreen(int maxx, int maxy, int ldepth) screenload(r, (uchar*)scrollwork.base, tl, l, 1); } - unlock(&screenlock); + /* switch software to graphics mode */ + if(vgascreenputc == nil) + vgascreenputc = screenputc; + + qunlock(&screenlock); poperror(); /* default color map (has to be outside the lock) */ @@ -640,9 +600,6 @@ setscreen(int maxx, int maxy, int ldepth) } break; } - - /* switch software to graphics mode */ - cga = 0; } /* @@ -727,13 +684,13 @@ screenload(Rectangle r, uchar *data, int tl, int l, int dolock) ulong off; uchar *q, *e; - if(screendisabled || cga || !rectclip(&r, gscreen.r) || tl<=0) + if(screendisabled || vgascreenputc == nil || !rectclip(&r, gscreen.r) || tl<=0) return; if(dolock && hwgc == 0) cursorlock(r); - lock(&palettelock); + lock(&myscreenlock); q = byteaddr(&gscreen, r.min); mx = 7>>gscreen.ldepth; lpart = (r.min.x & mx) << gscreen.ldepth; @@ -812,7 +769,7 @@ screenload(Rectangle r, uchar *data, int tl, int l, int dolock) data += l; } - unlock(&palettelock); + unlock(&myscreenlock); if(dolock && hwgc == 0) cursorunlock(); } @@ -884,13 +841,13 @@ screenunload(Rectangle r, uchar *data, int tl, int l, int dolock) ulong off; uchar *q, *e; - if(screendisabled || cga || !rectclip(&r, gscreen.r) || tl<=0) + if(screendisabled || vgascreenputc == nil || !rectclip(&r, gscreen.r) || tl<=0) return; if(dolock && hwgc == 0) cursorlock(r); - lock(&palettelock); + lock(&myscreenlock); q = byteaddr(&gscreen, r.min); mx = 7>>gscreen.ldepth; lpart = (r.min.x & mx) << gscreen.ldepth; @@ -969,109 +926,16 @@ screenunload(Rectangle r, uchar *data, int tl, int l, int dolock) data += l; } - unlock(&palettelock); + unlock(&myscreenlock); if(dolock && hwgc == 0) cursorunlock(); } -/* - * write a string to the screen - */ -void -screenputs(char *s, int n) -{ - int i; - Rune r; - char buf[4]; - - if(cga) { - cgascreenputs(s, n); - return; - } - - if((getstatus() & IFLAG) == 0) { - /* don't deadlock trying to print in interrupt */ - if(!canlock(&screenlock)) - return; - } else - lock(&screenlock); - - while(n > 0) { - i = chartorune(&r, s); - if(i == 0){ - s++; - --n; - continue; - } - memmove(buf, s, i); - buf[i] = 0; - n -= i; - s += i; - screenputc(buf); - } - - unlock(&screenlock); -} - static void nopage(int) { } -static int pos; - -static void -cgaregw(uchar index, uchar data) -{ - outb(0x03D4, index); - outb(0x03D4+1, data); -} - -static void -movecursor(void) -{ - cgaregw(0x0E, (pos/2>>8) & 0xFF); - cgaregw(0x0F, pos/2 & 0xFF); - CGASCREEN[pos+1] = 2; -} - -static void -cgascreenputc(int c) -{ - int i; - static int color; - - if(c == '\n'){ - pos = pos/CGAWIDTH; - pos = (pos+1)*CGAWIDTH; - } else if(c == '\t'){ - i = 8 - ((pos/2)&7); - while(i-->0) - cgascreenputc(' '); - } else if(c == '\b'){ - if(pos >= 2) - pos -= 2; - cgascreenputc(' '); - pos -= 2; - } else { - CGASCREEN[pos++] = c; - CGASCREEN[pos++] = 2; /* green on black */ - } - if(pos >= CGAWIDTH*CGAHEIGHT){ - memmove(CGASCREEN, &CGASCREEN[CGAWIDTH], CGAWIDTH*(CGAHEIGHT-1)); - memset(&CGASCREEN[CGAWIDTH*(CGAHEIGHT-1)], 0, CGAWIDTH); - pos = CGAWIDTH*(CGAHEIGHT-1); - } - movecursor(); -} - -static void -cgascreenputs(char *s, int n) -{ - while(n-- > 0) - cgascreenputc(*s++); -} - /* * graphics mode console */ @@ -1149,7 +1013,7 @@ screenputc(char *buf) subfstring(&chwork, Pt(off, 0), &defont0, buf, S); /* move work area to screen */ - screenload(r, (uchar*)chwork.base, tl, l, 0); + screenload(r, (uchar*)chwork.base, tl, l, 1); curpos.x += w; } @@ -1248,7 +1112,7 @@ Bitmap set = 1, }; -void +static void cursorinit(void) { static int already; @@ -1273,7 +1137,7 @@ setcursor(Cursor *curs) int i; if(hwgc) - (*hwgc->load)(curs); + hwgc->load(curs); else for(i=0; i<16; i++){ p = (uchar*)&set.base[i]; *p = curs->set[2*i]; @@ -1303,12 +1167,12 @@ cursoron(int dolock) if(dolock){ s = 0; /* to avoid compiler warning */ lock(&cursor); - } else + } /*else s = spllo(); /* to avoid freezing out the eia ports */ ret = 0; if(hwgc) - ret = (*hwgc->move)(mousexy()); + ret = hwgc->move(mousexy()); else if(cursor.visible++ == 0){ cursor.r.min = mousexy(); cursor.r.max = add(cursor.r.min, Pt(16, 16)); @@ -1357,8 +1221,8 @@ cursoron(int dolock) if(dolock) unlock(&cursor); - else - splx(s); + /*else + splx(s);*/ return ret; } diff --git a/pc/dma.c b/pc/dma.c index dde7baa4cd0ac0ed33365ac5c7bd4ac475d53603..a62b2872385622deedd3fdbe9af6a2c3d588e077 100644 --- a/pc/dma.c +++ b/pc/dma.c @@ -205,3 +205,16 @@ dmaend(int chan) memmove(xp->va, xp->bva, xp->len); xp->len = 0; } + +int +dmacount(int chan) +{ + int retval; + DMA *dp; + + dp = &dma[(chan>>2)&1]; + outb(dp->cbp, 0); + retval = inb(dp->count[chan]); + retval |= inb(dp->count[chan]) << 8; + return((retval<shift)+1); +} diff --git a/pc/ether2000.c b/pc/ether2000.c index fffbace470f3fc14006cd9bd228130f84405ea65..22f97227cf365cfedbc08027dd7838d3f75a28c7 100644 --- a/pc/ether2000.c +++ b/pc/ether2000.c @@ -8,6 +8,7 @@ #include "../port/netif.h" #include "etherif.h" +#include "ether8390.h" /* * Driver written for the 'Notebook Computer Ethernet LAN Adapter', @@ -26,12 +27,13 @@ enum { }; static int -reset(Ether *ether) +reset(Ether* ether) { ushort buf[16]; ulong port; - Dp8390 *dp8390; + Dp8390 *ctlr; int i; + uchar ea[Eaddrlen]; /* * Set up the software configuration. @@ -49,16 +51,24 @@ reset(Ether *ether) port = ether->port; ether->ctlr = malloc(sizeof(Dp8390)); - dp8390 = ether->ctlr; - dp8390->bit16 = 1; - dp8390->ram = 0; + ctlr = ether->ctlr; + ctlr->width = 2; + ctlr->ram = 0; - dp8390->dp8390 = port; - dp8390->data = port+Data; + ctlr->port = port; + ctlr->data = port+Data; - dp8390->tstart = HOWMANY(ether->mem, Dp8390BufSz); - dp8390->pstart = dp8390->tstart + HOWMANY(sizeof(Etherpkt), Dp8390BufSz); - dp8390->pstop = dp8390->tstart + HOWMANY(ether->size, Dp8390BufSz); + ctlr->tstart = HOWMANY(ether->mem, Dp8390BufSz); + ctlr->pstart = ctlr->tstart + HOWMANY(sizeof(Etherpkt), Dp8390BufSz); + ctlr->pstop = ctlr->tstart + HOWMANY(ether->size, Dp8390BufSz); + + ctlr->dummyrr = 1; + for(i = 0; i < ether->nopt; i++){ + if(strcmp(ether->opt[i], "nodummyrr")) + continue; + ctlr->dummyrr = 0; + break; + } /* * Reset the board. This is done by doing a read @@ -73,29 +83,29 @@ reset(Ether *ether) * Init the (possible) chip, then use the (possible) * chip to read the (possible) PROM for ethernet address * and a marker byte. - * We could just look at the DP8390 command register after + * Could just look at the DP8390 command register after * initialisation has been tried, but that wouldn't be * enough, there are other ethernet boards which could * match. */ dp8390reset(ether); memset(buf, 0, sizeof(buf)); - dp8390read(dp8390, buf, 0, sizeof(buf)); + dp8390read(ctlr, buf, 0, sizeof(buf)); if((buf[0x0E] & 0xFF) != 0x57 || (buf[0x0F] & 0xFF) != 0x57){ free(ether->ctlr); return -1; } /* - * Stupid machine. We asked for shorts, we got shorts, - * although the PROM is a byte array. - * Now we can set the ethernet address. + * Stupid machine. Shorts were asked for, + * shorts were delivered, although the PROM is a byte array. + * Set the ethernet address. */ - if((ether->ea[0]|ether->ea[1]|ether->ea[2]|ether->ea[3]|ether->ea[4]|ether->ea[5]) == 0){ + memset(ea, 0, Eaddrlen); + if(memcmp(ea, ether->ea, Eaddrlen) == 0){ for(i = 0; i < sizeof(ether->ea); i++) ether->ea[i] = buf[i]; } - dp8390setea(ether); return 0; diff --git a/pc/ether4100.c b/pc/ether4100.c deleted file mode 100644 index 9583cff06c9f20b85bf5de5b50dc4bd6c7fc5c98..0000000000000000000000000000000000000000 --- a/pc/ether4100.c +++ /dev/null @@ -1,100 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "../port/error.h" -#include "../port/netif.h" - -#include "etherif.h" - -/* - * Driver written for the 'national pcmcia ether adapter', - * The manual says NE2000 compatible. - * The interface appears to be pretty well described in the National - * Semiconductor Local Area Network Databook (1992) as one of the - * AT evaluation cards. - * - * The NE2000 is really just a DP8390[12] plus a data port - * and a reset port. - */ -enum { - Data = 0x10, /* offset from I/O base of data port */ - Misc = 0x18, /* offset from I/O base of miscellaneous port */ - Reset = 0x1f, /* offset from I/O base of reset port */ -}; - - -static int -reset(Ether *ether) -{ - Dp8390 *dp8390; - ulong port; - int i, slot; - uchar x, *p; - PCMmap *m; - - /* - * Set up the software configuration. - * Use defaults for port, irq, mem and size - * if not specified. - */ - if(ether->port == 0) - ether->port = 0x320; - if(ether->irq == 0) - ether->irq = 10; - if(ether->irq == 2) - ether->irq = 9; - if(ether->mem == 0) - ether->mem = 0x4000; - if(ether->size == 0) - ether->size = 16*1024; - port = ether->port; - - ether->ctlr = malloc(sizeof(Dp8390)); - dp8390 = ether->ctlr; - dp8390->bit16 = 1; - dp8390->ram = 0; - - dp8390->dp8390 = port; - dp8390->data = port+Data; - - dp8390->tstart = HOWMANY(ether->mem, Dp8390BufSz); - dp8390->pstart = dp8390->tstart + HOWMANY(sizeof(Etherpkt), Dp8390BufSz); - dp8390->pstop = dp8390->tstart + HOWMANY(ether->size, Dp8390BufSz); - - /* see if there's a pcmcia card that looks right */ - slot = pcmspecial("PC-NIC", ether); - if(slot < 0) - return -1; - - /* reset ST-NIC */ - x = inb(ether->port+Reset); - delay(2); - outb(ether->port+Reset, x); - - /* enable interrupts */ - outb(ether->port + Misc, 1<<6); - - /* Init the (possible) chip. */ - dp8390reset(ether); - - /* set the ether address */ - m = pcmmap(slot, 0, 0x1000, 1); - if(m == 0) - return -1; - p = (uchar*)(KZERO|m->isa); - for(i = 0; i < sizeof(ether->ea); i++) - ether->ea[i] = p[0xff0+2*i]; - pcmunmap(slot, m); - dp8390setea(ether); - - return 0; -} - -void -ether4100link(void) -{ - addethercard("NE4100", reset); -} diff --git a/pc/ether79c970.c b/pc/ether79c970.c index b50b9f51ff196b5afe6cd8aaa7618323ff51e9b4..b47b35a02ec4abe7f068f793cea014b9d83d1c8d 100644 --- a/pc/ether79c970.c +++ b/pc/ether79c970.c @@ -2,11 +2,7 @@ * AM79C970 * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus * To do: - * bag the tsleep in write, buffer them up; - * loop in interrupt routine until all done; - * only issue transmit interrupt if necessary? - * dynamically increase rings as necessary? - * use Block's as receive buffers? + * finish this rewrite */ #include "u.h" #include "../port/lib.h" @@ -20,66 +16,60 @@ #include "etherif.h" enum { - Lognrdre = 7, - Nrdre = (1<port+(r))) +#define csr32w(c, r, l) (outl((c)->port+(r), (ulong)(l))) + static void attach(Ether* ether) { - int port; + Ctlr *ctlr; - port = ether->port; - outl(port+Rdp, Iena|Strt); + ctlr = ether->ctlr; + + ilock(ctlr); + if(ctlr->init){ + iunlock(ctlr); + return; + } + csr32w(ctlr, Rdp, Iena|Strt); + iunlock(ctlr); +} + +static long +ifstat(Ether* ether, void* a, long n, ulong offset) +{ + Ctlr *ctlr; + char buf[512]; + int len; + + ctlr = ether->ctlr; + + ether->crcs = ctlr->crc; + ether->frames = ctlr->fram; + ether->buffs = ctlr->rxbuff+ctlr->txbuff; + ether->overflows = ctlr->oflo; + + if(n == 0) + return 0; + + len = sprint(buf, "Rxbuff: %ld\n", ctlr->rxbuff); + len += sprint(buf+len, "Crc: %ld\n", ctlr->crc); + len += sprint(buf+len, "Oflo: %ld\n", ctlr->oflo); + len += sprint(buf+len, "Fram: %ld\n", ctlr->fram); + len += sprint(buf+len, "Rtry: %ld\n", ctlr->rtry); + len += sprint(buf+len, "Lcar: %ld\n", ctlr->lcar); + len += sprint(buf+len, "Lcol: %ld\n", ctlr->lcol); + len += sprint(buf+len, "Uflo: %ld\n", ctlr->uflo); + sprint(buf+len, "Txbuff: %ld\n", ctlr->txbuff); + + return readstr(offset, a, n, buf); } static void ringinit(Ctlr* ctlr) { - int i, x; + Dre *dre; /* - * Initialise the receive and transmit buffer rings. The ring - * entries must be aligned on 16-byte boundaries. + * Initialise the receive and transmit buffer rings. + * The ring entries must be aligned on 16-byte boundaries. + * + * This routine is protected by ctlr->init. */ - if(ctlr->rdr == 0) - ctlr->rdr = xspanalloc(Nrdre*sizeof(Rdre), 0x10, 0); - if(ctlr->rrb == 0) - ctlr->rrb = xalloc(Nrdre*Rbsize); - x = PADDR(ctlr->rrb); - for(i = 0; i < Nrdre; i++){ - ctlr->rdr[i].rbadr = x; - x += Rbsize; - ctlr->rdr[i].rmd1 = Own|(-Rbsize & 0xFFFF); + if(ctlr->rdr == 0){ + ctlr->rdr = xspanalloc(Nrdre*sizeof(Dre), 0x10, 0); + for(dre = ctlr->rdr; dre < &ctlr->rdr[Nrdre]; dre++){ + dre->bp = iallocb(Rbsize); + dre->addr = PADDR(dre->bp->rp); + dre->md2 = 0; + dre->md1 = Own|(-Rbsize & 0xFFFF); + } } ctlr->rdrx = 0; if(ctlr->tdr == 0) - ctlr->tdr = xspanalloc(Ntdre*sizeof(Tdre), 0x10, 0); - if(ctlr->trb == 0) - ctlr->trb = xalloc(Ntdre*Rbsize); - x = PADDR(ctlr->trb); - for(i = 0; i < Ntdre; i++){ - ctlr->tdr[i].tbadr = x; - x += Rbsize; - } - ctlr->tdrx = 0; + ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0); + memset(ctlr->tdr, 0, Ntdre*sizeof(Dre)); + ctlr->tdrh = ctlr->tdri = 0; } static void promiscuous(void* arg, int on) { Ether *ether; - int port, x; + int x; Ctlr *ctlr; ether = arg; - port = ether->port; ctlr = ether->ctlr; /* @@ -192,94 +229,103 @@ promiscuous(void* arg, int on) * base addresses when Strt is set (unlike the older Lance chip), * so the rings must be re-initialised. */ - qlock(ðer->tlock); + ilock(ctlr); + if(ctlr->init){ + iunlock(ctlr); + return; + } + ctlr->init = 1; + iunlock(ctlr); + + while(ctlr->ntq) + ; - ilock(&ctlr->raplock); - outl(port+Rdp, Stop); + csr32w(ctlr, Rdp, Stop); - outl(port+Rap, 15); - x = inl(port+Rdp) & ~Prom; + csr32w(ctlr, Rap, 15); + x = csr32r(ctlr, Rdp) & ~Prom; if(on) x |= Prom; - outl(port+Rdp, x); - outl(port+Rap, 0); + csr32w(ctlr, Rdp, x); + csr32w(ctlr, Rap, 0); ringinit(ctlr); - outl(port+Rdp, Iena|Strt); - iunlock(&ctlr->raplock); - - qunlock(ðer->tlock); -} -static int -owntdre(void* arg) -{ - return (((Tdre*)arg)->tmd1 & Own) == 0; + ilock(ctlr); + ctlr->init = 0; + csr32w(ctlr, Rdp, Iena|Strt); + iunlock(ctlr); } -static long -write(Ether* ether, void* buf, long n) +static void +txstart(Ether* ether) { - int port; Ctlr *ctlr; - Tdre *tdre; - Etherpkt *pkt; + Block *bp; + Dre *dre; - port = ether->port; ctlr = ether->ctlr; - /* - * Wait for a transmit ring descriptor (and hence a buffer) to become - * free. If none become free after a reasonable period, give up. - */ - tdre = &ctlr->tdr[ctlr->tdrx]; - tsleep(&ctlr->trendez, owntdre, tdre, 100); - if(owntdre(tdre) == 0) - return 0; + if(ctlr->init) + return; - /* - * Copy the packet to the transmit buffer and fill in the - * source ethernet address. There's no need to pad to ETHERMINTU - * here as ApadXmit is set in CSR4. - */ - pkt = KADDR(tdre->tbadr); - memmove(pkt->d, buf, n); - memmove(pkt->s, ether->ea, sizeof(pkt->s)); + while(ctlr->ntq < (Ntdre-1)){ + bp = qget(ether->oq); + if(bp == nil) + break; - /* - * Give ownership of the descriptor to the chip, increment the - * software ring descriptor pointer and tell the chip to poll. - */ - tdre->tmd2 = 0; - tdre->tmd1 = Own|Stp|Enp|(-n & 0xFFFF); - ctlr->tdrx = NEXT(ctlr->tdrx, Ntdre); - outl(port+Rdp, Iena|Tdmd); + /* + * Give ownership of the descriptor to the chip, + * increment the software ring descriptor pointer + * and tell the chip to poll. + * There's no need to pad to ETHERMINTU + * here as ApadXmit is set in CSR4. + */ + dre = &ctlr->tdr[ctlr->tdrh]; + dre->bp = bp; + dre->addr = PADDR(bp->rp); + dre->md2 = 0; + dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF); + ctlr->ntq++; + csr32w(ctlr, Rdp, Iena|Tdmd); + ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre); + } +} + +static void +transmit(Ether* ether) +{ + Ctlr *ctlr; - ether->outpackets++; - return n; + ctlr = ether->ctlr; + ilock(ctlr); + txstart(ether); + iunlock(ctlr); } static void interrupt(Ureg*, void* arg) { - Ether *ether; - int port, csr0, status; Ctlr *ctlr; - Rdre *rdre; - Etherpkt *pkt; + Ether *ether; + int csr0, len; + Dre *dre; + Block *bp; ether = arg; - port = ether->port; ctlr = ether->ctlr; /* * Acknowledge all interrupts and whine about those that shouldn't * happen. */ - csr0 = inl(port+Rdp); - outl(port+Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena); +intrloop: + csr0 = csr32r(ctlr, Rdp) & 0xFFFF; + csr32w(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena); if(csr0 & (Babl|Miss|Merr)) - print("AMD70C970#%d: csr0 = 0x%uX\n", ether->ctlrno, csr0); + print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0); + if(!(csr0 & (Rint|Tint))) + return; /* * Receiver interrupt: run round the descriptor ring logging @@ -287,75 +333,112 @@ interrupt(Ureg*, void* arg) * until a descriptor is encountered still owned by the chip. */ if(csr0 & Rint){ - rdre = &ctlr->rdr[ctlr->rdrx]; - while(((status = rdre->rmd1) & Own) == 0){ - if(status & RxErr){ - if(status & RxBuff) - ether->buffs++; - if(status & RxCrc) - ether->crcs++; - if(status & RxOflo) - ether->overflows++; + dre = &ctlr->rdr[ctlr->rdrx]; + while(!(dre->md1 & Own)){ + if(dre->md1 & RxErr){ + if(dre->md1 & RxBuff) + ctlr->rxbuff++; + if(dre->md1 & Crc) + ctlr->crc++; + if(dre->md1 & Oflo) + ctlr->oflo++; + if(dre->md1 & Fram) + ctlr->fram++; } - else{ - ether->inpackets++; - pkt = KADDR(rdre->rbadr); - etherrloop(ether, pkt, (rdre->rmd2 & 0x0FFF)-4); + else if(bp = iallocb(Rbsize)){ + len = (dre->md2 & 0x0FFF)-4; + dre->bp->wp = dre->bp->rp+len; + etheriq(ether, dre->bp, 1); + dre->bp = bp; + dre->addr = PADDR(bp->rp); } /* * Finished with this descriptor, reinitialise it, * give it back to the chip, then on to the next... */ - rdre->rmd2 = 0; - rdre->rmd1 = Own|(-Rbsize & 0xFFFF); + dre->md2 = 0; + dre->md1 = Own|(-Rbsize & 0xFFFF); ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre); - rdre = &ctlr->rdr[ctlr->rdrx]; + dre = &ctlr->rdr[ctlr->rdrx]; } } /* * Transmitter interrupt: wakeup anyone waiting for a free descriptor. */ - if(csr0 & Tint) - wakeup(&ctlr->trendez); + if(csr0 & Tint){ + lock(ctlr); + while(ctlr->ntq){ + dre = &ctlr->tdr[ctlr->tdri]; + if(dre->md1 & Own) + break; + + if(dre->md1 & TxErr){ + if(dre->md2 & Rtry) + ctlr->rtry++; + if(dre->md2 & Lcar) + ctlr->lcar++; + if(dre->md2 & Lcol) + ctlr->lcol++; + if(dre->md2 & Uflo) + ctlr->uflo++; + if(dre->md2 & TxBuff) + ctlr->txbuff++; + ether->oerrs++; + } + + freeb(dre->bp); + + ctlr->ntq--; + ctlr->tdri = NEXT(ctlr->tdri, Ntdre); + } + txstart(ether); + unlock(ctlr); + } + goto intrloop; } -typedef struct Adapter Adapter; -struct Adapter { - Adapter* next; - int port; - int irq; -}; -static Adapter *adapter; +typedef struct Adapter { + int port; + int irq; + int tbdf; +} Adapter; +static Block* adapter; + +static void +amd79c970adapter(Block** bpp, int port, int irq, int tbdf) +{ + Block *bp; + Adapter *ap; + + bp = allocb(sizeof(Adapter)); + ap = (Adapter*)bp->rp; + ap->port = port; + ap->irq = irq; + ap->tbdf = tbdf; + + bp->next = *bpp; + *bpp = bp; +} static int amd79c90(Ether* ether) { - PCIcfg pcicfg; - static int devno = 0; + static Pcidev *p; int irq, port; - Adapter *ap; - - for(;;){ - pcicfg.vid = 0x1022; - pcicfg.did = 0x2000; - if((devno = pcimatch(0, devno, &pcicfg)) == -1) - break; - port = pcicfg.baseaddr[0] & ~0x01; - irq = pcicfg.irq; + while(p = pcimatch(p, 0x1022, 0x2000)){ + port = p->bar[0] & ~0x01; + irq = p->intl; if(ether->port == 0 || ether->port == port){ ether->irq = irq; + ether->tbdf = p->tbdf; return port; } - ap = malloc(sizeof(Adapter)); - ap->port = port; - ap->irq = irq; - ap->next = adapter; - adapter = ap; + amd79c970adapter(&adapter, port, irq, p->tbdf); } return 0; @@ -365,31 +448,44 @@ static int reset(Ether* ether) { int port, x; - Adapter *ap, **app; + Block *bp, **bpp; + Adapter *ap; uchar ea[Eaddrlen]; Ctlr *ctlr; /* * Any adapter matches if no ether->port is supplied, otherwise the * ports must match. First see if an adapter that fits the bill has - * already been found. If not then scan for another. + * already been found. If not, scan for another. */ port = 0; - for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){ + bpp = &adapter; + for(bp = *bpp; bp; bp = bp->next){ + ap = (Adapter*)bp->rp; if(ether->port == 0 || ether->port == ap->port){ port = ap->port; ether->irq = ap->irq; - *app = ap->next; - free(ap); + ether->tbdf = ap->tbdf; + *bpp = bp->next; + freeb(bp); break; } } if(port == 0 && (port = amd79c90(ether)) == 0) return -1; + /* + * Allocate a controller structure and start to initialise it. + */ + ether->ctlr = malloc(sizeof(Ctlr)); + ctlr = ether->ctlr; + ilock(ctlr); + ctlr->init = 1; + ctlr->port = port; + /* * How to tell what mode the chip is in at this point - if it's in WORD - * mode then the only 32-bit access allowedis a write to the RDP, which + * mode then the only 32-bit access allowed is a write to the RDP, which * forces the chip to DWORD mode; if it's in DWORD mode then only DWORD * accesses are allowed? * Assuming a DWORD write is done to the RDP, what will be overwritten as @@ -401,18 +497,18 @@ reset(Ether* ether) * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access. * Set the auto pad transmit in CSR4. */ - outl(port+Rdp, 0x00); - inl(port+Sreset); - outl(port+Rdp, Stop); + csr32w(ctlr, Rdp, 0x00); + csr32r(ctlr, Sreset); + csr32w(ctlr, Rdp, Stop); - outl(port+Rap, 20); - outl(port+Bdp, 0x0002); + csr32w(ctlr, Rap, 20); + csr32w(ctlr, Bdp, 0x0002); - outl(port+Rap, 4); - x = inl(port+Rdp) & 0xFFFF; - outl(port+Rdp, ApadXmt|x); + csr32w(ctlr, Rap, 4); + x = csr32r(ctlr, Rdp) & 0xFFFF; + csr32w(ctlr, Rdp, ApadXmt|x); - outl(port+Rap, 0); + csr32w(ctlr, Rap, 0); /* * Check if the adapter's station address is to be over-ridden. @@ -420,24 +516,21 @@ reset(Ether* ether) * station address in the initialisation block. */ memset(ea, 0, Eaddrlen); - if(memcmp(ea, ether->ea, Eaddrlen) == 0){ - x = inl(port+Aprom); - ether->ea[0] = x & 0xFF; - ether->ea[1] = (x>>8) & 0xFF; - ether->ea[2] = (x>>16) & 0xFF; - ether->ea[3] = (x>>24) & 0xFF; - x = inl(port+Aprom+4); - ether->ea[4] = x & 0xFF; - ether->ea[5] = (x>>8) & 0xFF; + if(!memcmp(ea, ether->ea, Eaddrlen)){ + x = csr32r(ctlr, Aprom); + ether->ea[0] = x; + ether->ea[1] = x>>8; + ether->ea[2] = x>>16; + ether->ea[3] = x>>24; + x = csr32r(ctlr, Aprom+4); + ether->ea[4] = x; + ether->ea[5] = x>>8; } /* - * Allocate a controller structure and start to fill in the - * initialisation block (must be DWORD aligned). + * Start to fill in the initialisation block + * (must be DWORD aligned). */ - ether->ctlr = malloc(sizeof(Ctlr)); - ctlr = ether->ctlr; - ctlr->iblock.rlen = Lognrdre<<4; ctlr->iblock.tlen = Logntdre<<4; memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr)); @@ -452,26 +545,32 @@ reset(Ether* ether) * enables will be set later when attaching to the network. */ x = PADDR(&ctlr->iblock); - outl(port+Rap, 1); - outl(port+Rdp, x & 0xFFFF); - outl(port+Rap, 2); - outl(port+Rdp, (x>>16) & 0xFFFF); - outl(port+Rap, 3); - outl(port+Rdp, Idonm); - outl(port+Rap, 0); - outl(port+Rdp, Init); - - while((inl(port+Rdp) & Idon) == 0) + csr32w(ctlr, Rap, 1); + csr32w(ctlr, Rdp, x & 0xFFFF); + csr32w(ctlr, Rap, 2); + csr32w(ctlr, Rdp, (x>>16) & 0xFFFF); + csr32w(ctlr, Rap, 3); + csr32w(ctlr, Rdp, Idon); + csr32w(ctlr, Rap, 0); + csr32w(ctlr, Rdp, Init); + + while(!(csr32r(ctlr, Rdp) & Idon)) ; - outl(port+Rdp, Idon|Stop); - + csr32w(ctlr, Rdp, Idon|Stop); + ctlr->init = 0; + iunlock(ctlr); + + /* + * Linkage to the generic ethernet driver. + */ ether->port = port; ether->attach = attach; - ether->write = write; + ether->transmit = transmit; ether->interrupt = interrupt; + ether->ifstat = ifstat; - ether->promiscuous = promiscuous; ether->arg = ether; + ether->promiscuous = promiscuous; return 0; } diff --git a/pc/ether8003.c b/pc/ether8003.c index 11b8b11e89800af3cb95c5ff48ce6fcf9894849f..25218e94da7d1d2ce9de83766821458df67c2911 100644 --- a/pc/ether8003.c +++ b/pc/ether8003.c @@ -8,11 +8,12 @@ #include "../port/netif.h" #include "etherif.h" +#include "ether8390.h" /* * Western Digital/Standard Microsystems Corporation cards (WD80[01]3). * Also handles 8216 cards (Elite Ultra). - * Configuration code based on that provided by SMC. + * Configuration code based on that provided by SMC a long time ago. */ enum { /* 83C584 Bus Interface Controller */ Msr = 0x00, /* Memory Select Register */ @@ -68,21 +69,21 @@ static int irq8216[8] = { }; static void -reset8003(Ether *ether, uchar ea[Eaddrlen], uchar ic[8]) +reset8003(Ether* ether, uchar ea[Eaddrlen], uchar ic[8]) { - Dp8390 *dp8390; + Dp8390 *ctlr; ulong port; - dp8390 = ether->ctlr; + ctlr = ether->ctlr; port = ether->port; /* * Check for old, dumb 8003E, which doesn't have an interface - * chip. Only the msr exists out of the 1st eight registers, reads + * chip. Only Msr exists out of the 1st eight registers, reads * of the others just alias the 2nd eight registers, the LAN - * address ROM. We can check icr, irr and laar against the ethernet + * address ROM. Can check Icr, Irr and Laar against the ethernet * address read above and if they match it's an 8003E (or an - * 8003EBT, 8003S, 8003SH or 8003WT, we don't care), in which + * 8003EBT, 8003S, 8003SH or 8003WT, doesn't matter), in which * case the default irq gets used. */ if(memcmp(&ea[1], &ic[1], 5) == 0){ @@ -92,8 +93,8 @@ reset8003(Ether *ether, uchar ea[Eaddrlen], uchar ic[8]) else{ /* * As a final sanity check for the 8013EBT, which doesn't have - * the 83C584 interface chip, but has 2 real registers, write Gp2 and if - * it reads back the same, it's not an 8013EBT. + * the 83C584 interface chip, but has 2 real registers, write Gp2 + * and if it reads back the same, it's not an 8013EBT. */ outb(port+Gp2, 0xAA); inb(port+Msr); /* wiggle bus */ @@ -106,51 +107,52 @@ reset8003(Ether *ether, uchar ea[Eaddrlen], uchar ic[8]) /* * Check if 16-bit card. - * If Bit16 is read/write, then we have an 8-bit card. - * If Bit16 is set, we're in a 16-bit slot. + * If Bit16 is read/write, then it's an 8-bit card. + * If Bit16 is set, it's in a 16-bit slot. */ outb(port+Icr, ic[Icr]^Bit16); inb(port+Msr); /* wiggle bus */ if((inb(port+Icr) & Bit16) == (ic[Icr] & Bit16)){ - dp8390->bit16 = 1; + ctlr->width = 2; ic[Icr] &= ~Bit16; } outb(port+Icr, ic[Icr]); - if(dp8390->bit16 && (inb(port+Icr) & Bit16) == 0) - dp8390->bit16 = 0; + if(ctlr->width == 2 && (inb(port+Icr) & Bit16) == 0) + ctlr->width = 1; } ether->mem = KZERO|((ic[Msr] & 0x3F)<<13); - if(dp8390->bit16) + if(ctlr->width == 2) ether->mem |= (ic[Laar] & 0x1F)<<19; else ether->mem |= 0x80000; if(ic[Icr] & (1<<3)) ether->size = 32*1024; - if(dp8390->bit16) + if(ctlr->width == 2) ether->size <<= 1; /* * Enable interface RAM, set interface width. */ outb(port+Msr, ic[Msr]|Menb); - if(dp8390->bit16) + if(ctlr->width == 2) outb(port+Laar, ic[Laar]|L16en|M16en|ZeroWS16); } static void -reset8216(Ether *ether, uchar[8]) +reset8216(Ether* ether, uchar[8]) { uchar hcr, irq, x; ulong addr, port; - Dp8390 *dp8390; + Dp8390 *ctlr; - dp8390 = ether->ctlr; - dp8390->bit16 = 1; + ctlr = ether->ctlr; port = ether->port; + ctlr->width = 2; + /* * Switch to the alternate register set and retrieve the memory * and irq information. @@ -166,8 +168,7 @@ reset8216(Ether *ether, uchar[8]) ether->irq = irq8216[((irq>>4) & 0x04)|((irq>>2) & 0x03)]; /* - * Enable interface RAM, set interface width, - * and enable interrupts. + * Enable interface RAM, set interface width, and enable interrupts. */ x = inb(port+Msr) & ~Rst; outb(port+Msr, Menb|x); @@ -178,16 +179,15 @@ reset8216(Ether *ether, uchar[8]) /* * Get configuration parameters, enable memory. - * There are opportunities here for buckets of code. - * We'll try to resist. + * There are opportunities here for buckets of code, try to resist. */ static int -reset(Ether *ether) +reset(Ether* ether) { int i; - uchar ea[Eaddrlen], ic[8], id, sum; + uchar ea[Eaddrlen], ic[8], id, nullea[Eaddrlen], sum; ulong port; - Dp8390 *dp8390; + Dp8390 *ctlr; /* * Set up the software configuration. @@ -225,8 +225,8 @@ reset(Ether *ether) return -1; ether->ctlr = malloc(sizeof(Dp8390)); - dp8390 = ether->ctlr; - dp8390->ram = 1; + ctlr = ether->ctlr; + ctlr->ram = 1; if((id & 0xFE) == 0x2A) reset8216(ether, ic); @@ -236,23 +236,24 @@ reset(Ether *ether) /* * Set the DP8390 ring addresses. */ - dp8390->dp8390 = port+0x10; - dp8390->tstart = 0; - dp8390->pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz); - dp8390->pstop = HOWMANY(ether->size, Dp8390BufSz); + ctlr->port = port+0x10; + ctlr->tstart = 0; + ctlr->pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz); + ctlr->pstop = HOWMANY(ether->size, Dp8390BufSz); /* - * Finally, init the 8390 and set the - * ethernet address. + * Finally, init the 8390,set the ethernet address + * and claim the memory used. */ dp8390reset(ether); - if((ether->ea[0]|ether->ea[1]|ether->ea[2]|ether->ea[3]|ether->ea[4]|ether->ea[5]) == 0){ + memset(nullea, 0, Eaddrlen); + if(memcmp(nullea, ether->ea, Eaddrlen) == 0){ for(i = 0; i < sizeof(ether->ea); i++) ether->ea[i] = ea[i]; } dp8390setea(ether); - if(getisa(ether->mem, ether->size, 0) == 0) + if(umbmalloc(ether->mem, ether->size, 0) == 0) panic("ether8003: 0x%lux reused", ether->mem); return 0; diff --git a/pc/ether82557.c b/pc/ether82557.c index 53f4dcd4636b63172d89811173f9e445ce63b5ff..6c52ab29e1ed9f6c006b176bf610f8fcac898849 100644 --- a/pc/ether82557.c +++ b/pc/ether82557.c @@ -4,8 +4,6 @@ * of smarts, unfortunately none of them are in the right place. * To do: * the PCI scanning code could be made common to other adapters; - * PCI code needs rewritten to handle byte, word, dword accesses - * and using the devno as a bus+dev+function triplet; * auto-negotiation; * optionally use memory-mapped registers. */ @@ -108,7 +106,7 @@ typedef struct Rfd { ushort count; ushort size; - Etherpkt; + uchar data[sizeof(Etherpkt)]; } Rfd; enum { /* field */ @@ -137,20 +135,27 @@ enum { /* count */ RfdEOF = 0x00008000, }; +typedef struct Cb Cb; typedef struct Cb { - int command; - ulong link; - uchar data[24]; /* CbIAS + CbConfigure */ -} Cb; + Cb* next; + Block* bp; -typedef struct TxCB { int command; ulong link; - ulong tbd; - ushort count; - uchar threshold; - uchar number; -} TxCB; + union { + uchar data[24]; /* CbIAS + CbConfigure */ + struct { + ulong tbd; + ushort count; + uchar threshold; + uchar number; + + ulong tba; + ushort tbasz; + ushort pad; + }; + }; +} Cb; enum { /* action command */ CbOK = 0x00002000, /* DMA completed OK */ @@ -165,7 +170,7 @@ enum { /* action command */ CbDiagnose = 0x00070000, CbCommand = 0x00070000, /* mask */ - CbSF = 0x00080000, /* CbTransmit */ + CbSF = 0x00080000, /* Flexible-mode CbTransmit */ CbI = 0x20000000, /* Interrupt after completion */ CbS = 0x40000000, /* Suspend after completion */ @@ -178,35 +183,37 @@ enum { /* CbTransmit count */ typedef struct Ctlr { int port; - - int ctlrno; - char* type; - uchar configdata[24]; - Lock lock; + Lock rlock; /* registers */ - Block* rfd[Nrfd]; /* receive side */ - int rfdl; - int rfdx; + Lock rfdlock; /* receive side */ + Block* rfdhead; + Block* rfdtail; + int nrfd; - Block* cbqhead; /* transmit side */ - Block* cbqtail; + Lock cbqlock; /* transmit side */ + Cb* cbqhead; + Cb* cbqtail; int cbqbusy; + Lock cbplock; /* pool of free Cb's */ + Cb* cbpool; + + Lock dlock; /* dump statistical counters */ ulong dump[17]; } Ctlr; static uchar configdata[24] = { 0x16, /* byte count */ - 0x44, /* Rx/Tx FIFO limit */ + 0x08, /* Rx/Tx FIFO limit */ 0x00, /* adaptive IFS */ 0x00, - 0x04, /* Rx DMA maximum byte count */ - 0x84, /* Tx DMA maximum byte count */ - 0x33, /* late SCB, CNA interrupts */ - 0x01, /* discard short Rx frames */ + 0x00, /* Rx DMA maximum byte count */ + 0x80, /* Tx DMA maximum byte count */ + 0x32, /* !late SCB, CNA interrupts */ + 0x03, /* discard short Rx frames */ 0x00, /* 503/MII */ 0x00, @@ -218,7 +225,7 @@ static uchar configdata[24] = { 0xC8, /* promiscuous mode off */ 0x00, 0x40, - 0xF2, /* transmit padding enable */ + 0xF3, /* transmit padding enable */ 0x80, /* full duplex pin enable */ 0x3F, /* no Multi IA */ 0x05, /* no Multi Cast ALL */ @@ -231,6 +238,56 @@ static uchar configdata[24] = { #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w))) #define csr32w(c, r, l) (outl((c)->port+(r), (ulong)(l))) +static Block* +rfdalloc(ulong link) +{ + Block *bp; + Rfd *rfd; + + if(bp = iallocb(sizeof(Rfd))){ + rfd = (Rfd*)bp->rp; + rfd->field = 0; + rfd->link = link; + rfd->rbd = NullPointer; + rfd->count = 0; + rfd->size = sizeof(Etherpkt); + } + + return bp; +} + +static Cb* +cballoc(Ctlr* ctlr, int command) +{ + Cb *cb; + + ilock(&ctlr->cbplock); + if(cb = ctlr->cbpool){ + ctlr->cbpool = cb->next; + iunlock(&ctlr->cbplock); + cb->next = 0; + cb->bp = 0; + } + else{ + iunlock(&ctlr->cbplock); + cb = smalloc(sizeof(Cb)); + } + + cb->command = command; + cb->link = NullPointer; + + return cb; +} + +static void +cbfree(Ctlr* ctlr, Cb* cb) +{ + ilock(&ctlr->cbplock); + cb->next = ctlr->cbpool; + ctlr->cbpool = cb; + iunlock(&ctlr->cbplock); +} + static void custart(Ctlr* ctlr) { @@ -240,32 +297,35 @@ custart(Ctlr* ctlr) } ctlr->cbqbusy = 1; + ilock(&ctlr->rlock); while(csr8r(ctlr, Command)) ; - csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp)); + csr32w(ctlr, General, PADDR(&ctlr->cbqhead->command)); csr8w(ctlr, Command, CUstart); + iunlock(&ctlr->rlock); } static void -action(Ctlr* ctlr, Block* bp) +action(Ctlr* ctlr, Cb* cb) { - Cb *cb; + Cb* tail; - cb = (Cb*)bp->rp; cb->command |= CbEL; + ilock(&ctlr->cbqlock); if(ctlr->cbqhead){ - ctlr->cbqtail->next = bp; - cb = (Cb*)ctlr->cbqtail->rp; - cb->link = PADDR(bp->rp); - cb->command &= ~CbEL; + tail = ctlr->cbqtail; + tail->next = cb; + tail->link = PADDR(&cb->command); + tail->command &= ~CbEL; } else - ctlr->cbqhead = bp; - ctlr->cbqtail = bp; + ctlr->cbqhead = cb; + ctlr->cbqtail = cb; - if(ctlr->cbqbusy == 0) + if(!ctlr->cbqbusy) custart(ctlr); + iunlock(&ctlr->cbqlock); } static void @@ -275,48 +335,33 @@ attach(Ether* ether) Ctlr *ctlr; ctlr = ether->ctlr; - ilock(&ctlr->lock); + ilock(&ctlr->rlock); status = csr16r(ctlr, Status); if((status & RUstatus) == RUidle){ while(csr8r(ctlr, Command)) ; - csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); + csr32w(ctlr, General, PADDR(ctlr->rfdhead->rp)); csr8w(ctlr, Command, RUstart); } - iunlock(&ctlr->lock); + iunlock(&ctlr->rlock); } -static Block* +static void configure(Ctlr* ctlr, int promiscuous) { - Block *bp; Cb *cb; - bp = allocb(sizeof(Cb)); - cb = (Cb*)bp->rp; - bp->wp += sizeof(Cb); - - cb->command = CbConfigure; - cb->link = NullPointer; + cb = cballoc(ctlr, CbConfigure); memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); if(promiscuous) cb->data[15] |= 0x01; - - return bp; + action(ctlr, cb); } static void promiscuous(void* arg, int on) { - Ctlr *ctlr; - Block *bp; - - ctlr = ((Ether*)arg)->ctlr; - bp = configure(ctlr, on); - - ilock(&ctlr->lock); - action(ctlr, bp); - iunlock(&ctlr->lock); + configure(((Ether*)arg)->ctlr, on); } static long @@ -330,11 +375,11 @@ ifstat(Ether* ether, void* a, long n, ulong offset) lock(&ctlr->dlock); ctlr->dump[16] = 0; - ilock(&ctlr->lock); + ilock(&ctlr->rlock); while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, DumpSC); - iunlock(&ctlr->lock); + iunlock(&ctlr->rlock); /* * Wait for completion status, should be 0xA005. @@ -375,43 +420,37 @@ ifstat(Ether* ether, void* a, long n, ulong offset) return readstr(offset, a, n, buf); } -static long -write(Ether* ether, void* buf, long n) +static void +transmit(Ether* ether) { Ctlr *ctlr; Block *bp; - TxCB *txcb; - - bp = allocb(n+sizeof(TxCB)); - txcb = (TxCB*)bp->wp; - bp->wp += sizeof(TxCB); - - txcb->command = CbTransmit; - txcb->link = NullPointer; - txcb->tbd = NullPointer; - txcb->count = CbEOF|n; - txcb->threshold = 2; - txcb->number = 0; + Cb *cb; - memmove(bp->wp, buf, n); - memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); - bp->wp += n; + bp = qget(ether->oq); + if(bp == nil) + return; ctlr = ether->ctlr; - ilock(&ctlr->lock); - action(ctlr, bp); - iunlock(&ctlr->lock); - ether->outpackets++; + cb = cballoc(ctlr, CbSF|CbTransmit); + cb->bp = bp; + cb->tbd = PADDR(&cb->tba); + cb->count = 0; + cb->threshold = 2; + cb->number = 1; + cb->tba = PADDR(bp->rp); + cb->tbasz = BLEN(bp); - return n; + action(ctlr, cb); } static void interrupt(Ureg*, void* arg) { Rfd *rfd; - Block *bp; + Cb* cb; + Block *bp, *xbp; Ctlr *ctlr; Ether *ether; int status; @@ -419,70 +458,103 @@ interrupt(Ureg*, void* arg) ether = arg; ctlr = ether->ctlr; - ilock(&ctlr->lock); for(;;){ + lock(&ctlr->rlock); status = csr16r(ctlr, Status); csr8w(ctlr, Ack, (status>>8) & 0xFF); + unlock(&ctlr->rlock); - if((status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) == 0) + if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))) break; if(status & StatFR){ - bp = ctlr->rfd[ctlr->rfdx]; + bp = ctlr->rfdhead; rfd = (Rfd*)bp->rp; while(rfd->field & RfdC){ - if(rfd->field & RfdOK){ - etherrloop(ether, rfd, rfd->count & 0x3FFF); - ether->inpackets++; + /* + * If it's an OK receive frame and a replacement buffer + * can be allocated then + * adjust the received buffer pointers for the + * actual data received; + * initialise the replacement buffer to point to + * the next in the ring; + * pass the received buffer on for disposal; + * initialise bp to point to the replacement. + * If not, just adjust the necessary fields for reuse. + */ + if((rfd->field & RfdOK) && (xbp = rfdalloc(rfd->link))){ + bp->rp += sizeof(Rfd)-sizeof(Etherpkt); + bp->wp = bp->rp + (rfd->count & 0x3FFF); + + xbp->next = bp->next; + bp->next = 0; + + etheriq(ether, bp, 1); + bp = xbp; + } + else{ + rfd->field = 0; + rfd->count = 0; } /* - * Reinitialise the frame for reception and bump - * the receive frame processing index; - * bump the sentinel index, mark the new sentinel - * and clear the old sentinel suspend bit; - * set bp and rfd for the next receive frame to - * process. + * The ring tail pointer follows the head with with one + * unused buffer in between to defeat hardware prefetch; + * once the tail pointer has been bumped on to the next + * and the new tail has the Suspend bit set, it can be + * removed from the old tail buffer. + * As a replacement for the current head buffer may have + * been allocated above, ensure that the new tail points + * to it (next and link). */ - rfd->field = 0; - rfd->count = 0; - ctlr->rfdx = NEXT(ctlr->rfdx, Nrfd); - - rfd = (Rfd*)ctlr->rfd[ctlr->rfdl]->rp; - ctlr->rfdl = NEXT(ctlr->rfdl, Nrfd); - ((Rfd*)ctlr->rfd[ctlr->rfdl]->rp)->field |= RfdS; + rfd = (Rfd*)ctlr->rfdtail->rp; + ctlr->rfdtail = ctlr->rfdtail->next; + ctlr->rfdtail->next = bp; + ((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); + ((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; rfd->field &= ~RfdS; - bp = ctlr->rfd[ctlr->rfdx]; + /* + * Finally done with the current (possibly replaced) + * head, move on to the next and maintain the sentinel + * between tail and head. + */ + ctlr->rfdhead = bp->next; + bp = ctlr->rfdhead; rfd = (Rfd*)bp->rp; } status &= ~StatFR; } if(status & StatRNR){ + lock(&ctlr->rlock); while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, RUresume); + unlock(&ctlr->rlock); status &= ~StatRNR; } if(status & StatCNA){ - while(bp = ctlr->cbqhead){ - if((((Cb*)bp->rp)->command & CbC) == 0) + lock(&ctlr->cbqlock); + while(cb = ctlr->cbqhead){ + if(!(cb->command & CbC)) break; - ctlr->cbqhead = bp->next; - freeb(bp); + ctlr->cbqhead = cb->next; + if(cb->bp) + freeb(cb->bp); + cbfree(ctlr, cb); } custart(ctlr); + unlock(&ctlr->cbqlock); status &= ~StatCNA; } if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) - panic("%s#%d: status %uX\n", ctlr->type, ctlr->ctlrno, status); + panic("#l%d: status %uX\n", ether->ctlrno, status); } - iunlock(&ctlr->lock); } static void @@ -493,28 +565,28 @@ ctlrinit(Ctlr* ctlr) Rfd *rfd; ulong link; + /* + * Create the Receive Frame Area (RFA) as a ring of allocated + * buffers. + * A sentinel buffer is maintained between the last buffer in + * the ring (marked with RfdS) and the head buffer to defeat the + * hardware prefetch of the next RFD and allow dynamic buffer + * allocation. + */ link = NullPointer; - for(i = Nrfd-1; i >= 0; i--){ - if(ctlr->rfd[i] == 0){ - bp = allocb(sizeof(Rfd)); - ctlr->rfd[i] = bp; - } - else - bp = ctlr->rfd[i]; - rfd = (Rfd*)bp->rp; - - rfd->field = 0; - rfd->link = link; - link = PADDR(rfd); - rfd->rbd = NullPointer; - rfd->count = 0; - rfd->size = sizeof(Etherpkt); + for(i = 0; i < Nrfd; i++){ + bp = rfdalloc(link); + if(ctlr->rfdhead == nil) + ctlr->rfdtail = bp; + bp->next = ctlr->rfdhead; + ctlr->rfdhead = bp; + link = PADDR(bp->rp); } - ((Rfd*)ctlr->rfd[Nrfd-1]->rp)->link = PADDR(ctlr->rfd[0]->rp); - - ctlr->rfdl = 0; - ((Rfd*)ctlr->rfd[0]->rp)->field |= RfdS; - ctlr->rfdx = 2; + ctlr->rfdtail->next = ctlr->rfdhead; + rfd = (Rfd*)ctlr->rfdtail->rp; + rfd->link = PADDR(ctlr->rfdhead->rp); + rfd->field |= RfdS; + ctlr->rfdhead = ctlr->rfdhead->next; memmove(ctlr->configdata, configdata, sizeof(configdata)); } @@ -572,7 +644,7 @@ hy93c46r(Ctlr* ctlr, int r) delay(1); csr16w(ctlr, Ecr, data); delay(1); - if((csr16r(ctlr, Ecr) & EEdo) == 0) + if(!(csr16r(ctlr, Ecr) & EEdo)) break; } @@ -591,51 +663,50 @@ hy93c46r(Ctlr* ctlr, int r) return data; } -typedef struct Adapter Adapter; -struct Adapter { - Adapter* next; - int port; - int irq; - int pcidevno; -}; -static Adapter *adapter; +typedef struct Adapter { + int port; + int irq; + int tbdf; +} Adapter; +static Block* adapter; -static int -i82557pci(Ether* ether, int* pcidevno) +static void +i82557adapter(Block** bpp, int port, int irq, int tbdf) { - PCIcfg pcicfg; - static int devno = 0; - int i, irq, port; + Block *bp; Adapter *ap; - for(;;){ - pcicfg.vid = 0x8086; - pcicfg.did = 0x1229; - if((devno = pcimatch(0, devno, &pcicfg)) == -1) - break; + bp = allocb(sizeof(Adapter)); + ap = (Adapter*)bp->rp; + ap->port = port; + ap->irq = irq; + ap->tbdf = tbdf; - port = 0; - irq = 0; - for(i = 0; i < 6; i++){ - if((pcicfg.baseaddr[i] & 0x03) != 0x01) - continue; - port = pcicfg.baseaddr[i] & ~0x01; - irq = pcicfg.irq; - if(ether->port == 0 || ether->port == port){ - ether->irq = irq; - *pcidevno = devno-1; - return port; - } + bp->next = *bpp; + *bpp = bp; +} + +static int +i82557pci(Ether* ether) +{ + static Pcidev *p; + int irq, port; + + while(p = pcimatch(p, 0x8086, 0x1229)){ + /* + * bar[0] is the memory-mapped register address (4KB), + * bar[1] is the I/O port register address (32 bytes) and + * bar[2] is for the flash ROM (1MB). + */ + port = p->bar[1] & ~0x01; + irq = p->intl; + if(ether->port == 0 || ether->port == port){ + ether->irq = irq; + ether->tbdf = p->tbdf; + return port; } - if(port == 0) - continue; - ap = malloc(sizeof(Adapter)); - ap->port = port; - ap->irq = irq; - ap->pcidevno = devno-1; - ap->next = adapter; - adapter = ap; + i82557adapter(&adapter, port, irq, p->tbdf); } return 0; @@ -644,11 +715,11 @@ i82557pci(Ether* ether, int* pcidevno) static int reset(Ether* ether) { - int i, pcidevno, port, x; - Adapter *ap, **app; + int i, port, x; + Block *bp, **bpp; + Adapter *ap; uchar ea[Eaddrlen]; Ctlr *ctlr; - Block *bp; Cb *cb; /* @@ -657,17 +728,19 @@ reset(Ether* ether) * already been found. If not, scan for another. */ port = 0; - pcidevno = -1; - for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){ + bpp = &adapter; + for(bp = *bpp; bp; bp = bp->next){ + ap = (Adapter*)bp->rp; if(ether->port == 0 || ether->port == ap->port){ + port = ap->port; ether->irq = ap->irq; - pcidevno = ap->pcidevno; - *app = ap->next; - free(ap); + ether->tbdf = ap->tbdf; + *bpp = bp->next; + freeb(bp); break; } } - if(port == 0 && (port = i82557pci(ether, &pcidevno)) == 0) + if(port == 0 && (port = i82557pci(ether)) == 0) return -1; /* @@ -680,12 +753,9 @@ reset(Ether* ether) */ ether->ctlr = malloc(sizeof(Ctlr)); ctlr = ether->ctlr; - ctlr->ctlrno = ether->ctlrno; - ctlr->type = ether->type; ctlr->port = port; - ilock(&ctlr->lock); - + ilock(&ctlr->rlock); csr32w(ctlr, Port, 0); delay(1); @@ -702,7 +772,7 @@ reset(Ether* ether) ; csr32w(ctlr, General, PADDR(ctlr->dump)); csr8w(ctlr, Command, LoadDCA); - + iunlock(&ctlr->rlock); /* * Initialise the receive frame and configuration areas. @@ -727,14 +797,14 @@ reset(Ether* ether) continue; x = dp83840r(ctlr, i, 0x19); - if((x & 0x0040) == 0){ + if(!(x & 0x0040)){ ether->mbps = 100; ctlr->configdata[8] = 1; ctlr->configdata[15] &= ~0x80; } else{ x = dp83840r(ctlr, i, 0x1B); - if((x & 0x0200) == 0){ + if(!(x & 0x0200)){ ctlr->configdata[8] = 1; ctlr->configdata[15] &= ~0x80; } @@ -745,8 +815,7 @@ reset(Ether* ether) /* * Load the chip configuration */ - bp = configure(ctlr, 0); - action(ctlr, bp); + configure(ctlr, 0); /* * Check if the adapter's station address is to be overridden. @@ -754,31 +823,25 @@ reset(Ether* ether) * the station address with the Individual Address Setup command. */ memset(ea, 0, Eaddrlen); - if(memcmp(ea, ether->ea, Eaddrlen) == 0){ + if(!memcmp(ea, ether->ea, Eaddrlen)){ for(i = 0; i < Eaddrlen/2; i++){ x = hy93c46r(ctlr, i); - ether->ea[2*i] = x & 0xFF; - ether->ea[2*i+1] = (x>>8) & 0xFF; + ether->ea[2*i] = x; + ether->ea[2*i+1] = x>>8; } } - bp = allocb(sizeof(Cb)); - cb = (Cb*)bp->rp; - bp->wp += sizeof(Cb); - - cb->command = CbIAS; - cb->link = NullPointer; + cb = cballoc(ctlr, CbIAS); memmove(cb->data, ether->ea, Eaddrlen); - action(ctlr, bp); + action(ctlr, cb); - iunlock(&ctlr->lock); /* * Linkage to the generic ethernet driver. */ ether->port = port; ether->attach = attach; - ether->write = write; + ether->transmit = transmit; ether->interrupt = interrupt; ether->ifstat = ifstat; diff --git a/pc/ether8390.c b/pc/ether8390.c index fe9878a01882168726e8c3c0f074c02d561705e9..ac88802c71e9b62b36f2fcb1b0fe547101d15265 100644 --- a/pc/ether8390.c +++ b/pc/ether8390.c @@ -1,6 +1,5 @@ /* - * National Semiconductor DP8390 - * and SMC 83C90 + * National Semiconductor DP8390 and clone * Network Interface Controller. */ #include "u.h" @@ -13,28 +12,12 @@ #include "../port/netif.h" #include "etherif.h" +#include "ether8390.h" -extern int slowinb(ulong); -extern void slowoutb(ulong, uchar); - -enum { +enum { /* NIC core registers */ Cr = 0x00, /* command register, all pages */ - Stp = 0x01, /* stop */ - Sta = 0x02, /* start */ - Txp = 0x04, /* transmit packet */ - RDMAread = (1<<3), /* remote DMA read */ - RDMAwrite = (2<<3), /* remote DMA write */ - RDMAsend = (3<<3), /* remote DMA send packet */ - RDMAabort = (4<<3), /* abort/complete remote DMA */ - Ps0 = 0x40, /* page select */ - Ps1 = 0x80, /* page select */ - Page0 = 0x00, - Page1 = Ps0, - Page2 = Ps1, -}; - -enum { /* Page 0, read */ + /* Page 0, read */ Clda0 = 0x01, /* current local DMA address 0 */ Clda1 = 0x02, /* current local DMA address 1 */ Bnry = 0x03, /* boundary pointer (R/W) */ @@ -48,9 +31,8 @@ enum { /* Page 0, read */ Cntr0 = 0x0D, /* frame alignment errors */ Cntr1 = 0x0E, /* CRC errors */ Cntr2 = 0x0F, /* missed packet errors */ -}; -enum { /* Page 0, write */ + /* Page 0, write */ Pstart = 0x01, /* page start register */ Pstop = 0x02, /* page stop register */ Tpsr = 0x04, /* transmit page start address */ @@ -64,15 +46,32 @@ enum { /* Page 0, write */ Tcr = 0x0D, /* transmit configuration register */ Dcr = 0x0E, /* data configuration register */ Imr = 0x0F, /* interrupt mask */ -}; -enum { /* Page 1, read/write */ + /* Page 1, read/write */ Par0 = 0x01, /* physical address register 0 */ Curr = 0x07, /* current page register */ Mar0 = 0x08, /* multicast address register 0 */ }; -enum { /* Interrupt Status Register */ +enum { /* Cr */ + Stp = 0x01, /* stop */ + Sta = 0x02, /* start */ + Txp = 0x04, /* transmit packet */ + Rd0 = 0x08, /* remote DMA command */ + Rd1 = 0x10, + Rd2 = 0x20, + RdREAD = Rd0, /* remote read */ + RdWRITE = Rd1, /* remote write */ + RdSEND = Rd1|Rd0, /* send packet */ + RdABORT = Rd2, /* abort/complete remote DMA */ + Ps0 = 0x40, /* page select */ + Ps1 = 0x80, + Page0 = 0x00, + Page1 = Ps0, + Page2 = Ps1, +}; + +enum { /* Isr/Imr */ Prx = 0x01, /* packet received */ Ptx = 0x02, /* packet transmitted */ Rxe = 0x04, /* receive error */ @@ -83,36 +82,33 @@ enum { /* Interrupt Status Register */ Rst = 0x80, /* reset status */ }; -enum { /* Interrupt Mask Register */ - Prxe = 0x01, /* packet received interrupt enable */ - Ptxe = 0x02, /* packet transmitted interrupt enable */ - Rxee = 0x04, /* receive error interrupt enable */ - Txee = 0x08, /* transmit error interrupt enable */ - Ovwe = 0x10, /* overwrite warning interrupt enable */ - Cnte = 0x20, /* counter overflow interrupt enable */ - Rdce = 0x40, /* DMA complete interrupt enable */ -}; - -enum { /* Data Configuration register */ +enum { /* Dcr */ Wts = 0x01, /* word transfer select */ Bos = 0x02, /* byte order select */ Las = 0x04, /* long address select */ Ls = 0x08, /* loopback select */ Arm = 0x10, /* auto-initialise remote */ - Ft1 = (0x00<<5), /* FIFO threshhold select 1 byte/word */ - Ft2 = (0x01<<5), /* FIFO threshhold select 2 bytes/words */ - Ft4 = (0x02<<5), /* FIFO threshhold select 4 bytes/words */ - Ft6 = (0x03<<5), /* FIFO threshhold select 6 bytes/words */ + Ft0 = 0x20, /* FIFO threshold select */ + Ft1 = 0x40, + Ft1WORD = 0x00, + Ft2WORD = Ft0, + Ft4WORD = Ft1, + Ft6WORD = Ft1|Ft0, }; -enum { /* Transmit Configuration Register */ +enum { /* Tcr */ Crc = 0x01, /* inhibit CRC */ - Lb = 0x02, /* internal loopback */ + Lb0 = 0x02, /* encoded loopback control */ + Lb1 = 0x04, + LpbkNORMAL = 0x00, /* normal operation */ + LpbkNIC = Lb0, /* internal NIC module loopback */ + LpbkENDEC = Lb1, /* internal ENDEC module loopback */ + LpbkEXTERNAL = Lb1|Lb0, /* external loopback */ Atd = 0x08, /* auto transmit disable */ Ofst = 0x10, /* collision offset enable */ }; -enum { /* Transmit Status Register */ +enum { /* Tsr */ Ptxok = 0x01, /* packet transmitted */ Col = 0x04, /* transmit collided */ Abt = 0x08, /* tranmit aborted */ @@ -122,7 +118,7 @@ enum { /* Transmit Status Register */ Owc = 0x80, /* out of window collision */ }; -enum { /* Receive Configuration Register */ +enum { /* Rcr */ Sep = 0x01, /* save errored packets */ Ar = 0x02, /* accept runt packets */ Ab = 0x04, /* accept broadcast */ @@ -131,7 +127,7 @@ enum { /* Receive Configuration Register */ Mon = 0x20, /* monitor mode */ }; -enum { /* Receive Status Register */ +enum { /* Rsr */ Prxok = 0x01, /* packet received intact */ Crce = 0x02, /* CRC error */ Fae = 0x04, /* frame alignment error */ @@ -149,68 +145,57 @@ typedef struct { uchar len1; } Hdr; -static void -dp8390disable(Dp8390 *dp8390) +void +dp8390getea(Ether* ether, uchar* ea) { - ulong port = dp8390->dp8390; - int timo; + Dp8390 *ctlr; + uchar cr; + int i; + + ctlr = ether->ctlr; /* - * Stop the chip. Set the Stp bit and wait for the chip - * to finish whatever was on its tiny mind before it sets - * the Rst bit. - * We need the timeout because there may not be a real - * chip there if this is called when probing for a device - * at boot. + * Get the ethernet address from the chip. + * Take care to restore the command register + * afterwards. */ - slowoutb(port+Cr, Page0|RDMAabort|Stp); - slowoutb(port+Rbcr0, 0); - slowoutb(port+Rbcr1, 0); - for(timo = 10000; (slowinb(port+Isr) & Rst) == 0 && timo; timo--) - ; -} - -static void -dp8390ring(Dp8390 *dp8390) -{ - ulong port = dp8390->dp8390; - - slowoutb(port+Pstart, dp8390->pstart); - slowoutb(port+Pstop, dp8390->pstop); - slowoutb(port+Bnry, dp8390->pstop-1); - - slowoutb(port+Cr, Page1|RDMAabort|Stp); - slowoutb(port+Curr, dp8390->pstart); - slowoutb(port+Cr, Page0|RDMAabort|Stp); - - dp8390->nxtpkt = dp8390->pstart; + ilock(ctlr); + cr = regr(ctlr, Cr) & ~Txp; + regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr)); + for(i = 0; i < Eaddrlen; i++) + ea[i] = regr(ctlr, Par0+i); + regw(ctlr, Cr, cr); + iunlock(ctlr); } void -dp8390setea(Ether *ether) +dp8390setea(Ether* ether) { - ulong port = ((Dp8390*)ether->ctlr)->dp8390; - uchar cr; int i; + uchar cr; + Dp8390 *ctlr; + + ctlr = ether->ctlr; /* * Set the ethernet address into the chip. * Take care to restore the command register - * afterwards. We don't care about multicast - * addresses as we never set the multicast - * enable. + * afterwards. Don't care about multicast + * addresses as multicast is never enabled + * (currently). */ - cr = slowinb(port+Cr) & ~Txp; - slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr)); - for(i = 0; i < sizeof(ether->ea); i++) - slowoutb(port+Par0+i, ether->ea[i]); - slowoutb(port+Cr, cr); + ilock(ctlr); + cr = regr(ctlr, Cr) & ~Txp; + regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr)); + for(i = 0; i < Eaddrlen; i++) + regw(ctlr, Par0+i, ether->ea[i]); + regw(ctlr, Cr, cr); + iunlock(ctlr); } -void* -dp8390read(Dp8390 *dp8390, void *to, ulong from, ulong len) +static void* +_dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len) { - ulong port = dp8390->dp8390; uchar cr; int timo; @@ -219,359 +204,373 @@ dp8390read(Dp8390 *dp8390, void *to, ulong from, ulong len) * using the DP8390 remote DMA facility, and place it at * 'to' in main memory, via the I/O data port. */ - cr = slowinb(port+Cr) & ~Txp; - slowoutb(port+Cr, Page0|RDMAabort|Sta); - slowoutb(port+Isr, Rdc); + cr = regr(ctlr, Cr) & ~Txp; + regw(ctlr, Cr, Page0|RdABORT|Sta); + regw(ctlr, Isr, Rdc); /* * Set up the remote DMA address and count. */ - if(dp8390->bit16) - len = ROUNDUP(len, 2); - slowoutb(port+Rbcr0, len & 0xFF); - slowoutb(port+Rbcr1, (len>>8) & 0xFF); - slowoutb(port+Rsar0, from & 0xFF); - slowoutb(port+Rsar1, (from>>8) & 0xFF); + len = ROUNDUP(len, ctlr->width); + regw(ctlr, Rbcr0, len & 0xFF); + regw(ctlr, Rbcr1, (len>>8) & 0xFF); + regw(ctlr, Rsar0, from & 0xFF); + regw(ctlr, Rsar1, (from>>8) & 0xFF); /* * Start the remote DMA read and suck the data * out of the I/O port. */ - slowoutb(port+Cr, Page0|RDMAread|Sta); - if(dp8390->bit16) - inss(dp8390->data, to, len/2); - else - insb(dp8390->data, to, len); + regw(ctlr, Cr, Page0|RdREAD|Sta); + rdread(ctlr, to, len); /* * Wait for the remote DMA to complete. The timeout - * is necessary because we may call this routine on + * is necessary because this routine may be called on * a non-existent chip during initialisation and, due - * to the miracles of the bus, we could get this far - * and still be talking to a slot full of nothing. + * to the miracles of the bus, it's possible to get this + * far and still be talking to a slot full of nothing. */ - for(timo = 10000; (slowinb(port+Isr) & Rdc) == 0 && timo; timo--) + for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--) ; - slowoutb(port+Isr, Rdc); - slowoutb(port+Cr, cr); + regw(ctlr, Isr, Rdc); + regw(ctlr, Cr, cr); + return to; } void* -dp8390write(Dp8390 *dp8390, ulong to, void *from, ulong len) +dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len) +{ + void *v; + + ilock(ctlr); + v = dp8390read(ctlr, to, from, len); + iunlock(ctlr); + + return v; +} + +static void* +dp8390write(Dp8390* ctlr, ulong to, void* from, ulong len) { - ulong port = dp8390->dp8390; ulong crda; uchar cr; - int s, tries; - - /* - * Keep out interrupts since reading and writing - * use the same DMA engine. - */ - s = splhi(); + int timo, width; /* * Write some data to offset 'to' in the card's memory * using the DP8390 remote DMA facility, reading it at * 'from' in main memory, via the I/O data port. */ - cr = slowinb(port+Cr) & ~Txp; - slowoutb(port+Cr, Page0|RDMAabort|Sta); - slowoutb(port+Isr, Rdc); + cr = regr(ctlr, Cr) & ~Txp; + regw(ctlr, Cr, Page0|RdABORT|Sta); + regw(ctlr, Isr, Rdc); - if(dp8390->bit16) - len = ROUNDUP(len, 2); + len = ROUNDUP(len, ctlr->width); /* * Set up the remote DMA address and count. - * This is straight from the DP8390[12D] datasheet, hence - * the initial set up for read. + * This is straight from the DP8390[12D] datasheet, + * hence the initial set up for read. + * Assumption here that the A7000 EtherV card will + * never need a dummyrr. */ - crda = to-1-dp8390->bit16; - slowoutb(port+Rbcr0, (len+1+dp8390->bit16) & 0xFF); - slowoutb(port+Rbcr1, ((len+1+dp8390->bit16)>>8) & 0xFF); - slowoutb(port+Rsar0, crda & 0xFF); - slowoutb(port+Rsar1, (crda>>8) & 0xFF); - slowoutb(port+Cr, Page0|RDMAread|Sta); - - for(;;){ - crda = slowinb(port+Crda0); - crda |= slowinb(port+Crda1)<<8; - if(crda == to){ - /* - * Start the remote DMA write and make sure - * the registers are correct. - */ - slowoutb(port+Cr, Page0|RDMAwrite|Sta); - - crda = slowinb(port+Crda0); - crda |= slowinb(port+Crda1)<<8; - if(crda != to) - panic("crda write %d to %d\n", crda, to); - - break; + if(ctlr->dummyrr && (ctlr->width == 1 || ctlr->width == 2)){ + if(ctlr->width == 2) + width = 1; + else + width = 0; + crda = to-1-width; + regw(ctlr, Rbcr0, (len+1+width) & 0xFF); + regw(ctlr, Rbcr1, ((len+1+width)>>8) & 0xFF); + regw(ctlr, Rsar0, crda & 0xFF); + regw(ctlr, Rsar1, (crda>>8) & 0xFF); + regw(ctlr, Cr, Page0|RdREAD|Sta); + + for(;;){ + crda = regr(ctlr, Crda0); + crda |= regr(ctlr, Crda1)<<8; + if(crda == to){ + /* + * Start the remote DMA write and make sure + * the registers are correct. + */ + regw(ctlr, Cr, Page0|RdWRITE|Sta); + + crda = regr(ctlr, Crda0); + crda |= regr(ctlr, Crda1)<<8; + if(crda != to) + panic("crda write %d to %d\n", crda, to); + + break; + } } } + else{ + regw(ctlr, Rsar0, to & 0xFF); + regw(ctlr, Rsar1, (to>>8) & 0xFF); + regw(ctlr, Rbcr0, len & 0xFF); + regw(ctlr, Rbcr1, (len>>8) & 0xFF); + regw(ctlr, Cr, Page0|RdWRITE|Sta); + } /* - * Pump the data into the I/O port. - */ - if(dp8390->bit16) - outss(dp8390->data, from, len/2); - else - outsb(dp8390->data, from, len); - - /* - * Wait for the remote DMA to finish. It should - * be almost immediate. + * Pump the data into the I/O port + * then wait for the remote DMA to finish. */ - tries = 0; - while((slowinb(port+Isr) & Rdc) == 0){ - if(tries++ >= 100000){ - print("dp8390write dma timed out\n"); - break; - } - } + rdwrite(ctlr, from, len); + for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--) + ; - slowoutb(port+Isr, Rdc); - slowoutb(port+Cr, cr); - splx(s); + regw(ctlr, Isr, Rdc); + regw(ctlr, Cr, cr); return (void*)to; } +static void +ringinit(Dp8390* ctlr) +{ + regw(ctlr, Pstart, ctlr->pstart); + regw(ctlr, Pstop, ctlr->pstop); + regw(ctlr, Bnry, ctlr->pstop-1); + + regw(ctlr, Cr, Page1|RdABORT|Stp); + regw(ctlr, Curr, ctlr->pstart); + regw(ctlr, Cr, Page0|RdABORT|Stp); + + ctlr->nxtpkt = ctlr->pstart; +} + static uchar -getcurr(Dp8390 *dp8390) +getcurr(Dp8390* ctlr) { - ulong port = dp8390->dp8390; uchar cr, curr; - cr = slowinb(port+Cr) & ~Txp; - slowoutb(port+Cr, Page1|(~(Ps1|Ps0) & cr)); - curr = slowinb(port+Curr); - slowoutb(port+Cr, cr); + cr = regr(ctlr, Cr) & ~Txp; + regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr)); + curr = regr(ctlr, Curr); + regw(ctlr, Cr, cr); + return curr; } static void -receive(Ether *ether) +receive(Ether* ether) { - Dp8390 *dp8390; - uchar curr, *pkt; + Dp8390 *ctlr; + uchar curr, *p; Hdr hdr; - ulong port, data, len, len1; - - dp8390 = ether->ctlr; - port = dp8390->dp8390; - for(curr = getcurr(dp8390); dp8390->nxtpkt != curr; curr = getcurr(dp8390)){ - ether->inpackets++; + ulong count, data, len; + Block *bp; - data = dp8390->nxtpkt*Dp8390BufSz; - if(dp8390->ram) + ctlr = ether->ctlr; + for(curr = getcurr(ctlr); ctlr->nxtpkt != curr; curr = getcurr(ctlr)){ + data = ctlr->nxtpkt*Dp8390BufSz; + if(ctlr->ram) memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr)); else - dp8390read(dp8390, &hdr, data, sizeof(Hdr)); + _dp8390read(ctlr, &hdr, data, sizeof(Hdr)); /* * Don't believe the upper byte count, work it * out from the software next-page pointer and * the current next-page pointer. */ - if(hdr.next > dp8390->nxtpkt) - len1 = hdr.next - dp8390->nxtpkt - 1; + if(hdr.next > ctlr->nxtpkt) + len = hdr.next - ctlr->nxtpkt - 1; else - len1 = (dp8390->pstop-dp8390->nxtpkt) + (hdr.next-dp8390->pstart) - 1; + len = (ctlr->pstop-ctlr->nxtpkt) + (hdr.next-ctlr->pstart) - 1; if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr))) - len1--; + len--; - len = ((len1<<8)|hdr.len0)-4; + len = ((len<<8)|hdr.len0)-4; /* * Chip is badly scrogged, reinitialise the ring. */ - if(hdr.next < dp8390->pstart || hdr.next >= dp8390->pstop + if(hdr.next < ctlr->pstart || hdr.next >= ctlr->pstop || len < 60 || len > sizeof(Etherpkt)){ print("dp8390: H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d\n", hdr.status, hdr.next, hdr.len0, hdr.len1, len); - slowoutb(port+Cr, Page0|RDMAabort|Stp); - dp8390ring(dp8390); - slowoutb(port+Cr, Page0|RDMAabort|Sta); + regw(ctlr, Cr, Page0|RdABORT|Stp); + ringinit(ctlr); + regw(ctlr, Cr, Page0|RdABORT|Sta); + return; } /* * If it's a good packet read it in to the software buffer. - * If the packet wraps round the hardware ring, read it in two pieces. - * - * We could conceivably remove the copy into rpkt here by wrapping - * this up with the etherrloop code. + * If the packet wraps round the hardware ring, read it in + * two pieces. */ - if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok){ - pkt = (uchar*)ðer->rpkt; + if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && (bp = iallocb(len))){ + p = bp->rp; + bp->wp = p+len; data += sizeof(Hdr); - len1 = len; - if((data+len1) >= dp8390->pstop*Dp8390BufSz){ - ulong count = dp8390->pstop*Dp8390BufSz - data; - - if(dp8390->ram) - memmove(pkt, (void*)(ether->mem+data), count); + if((data+len) >= ctlr->pstop*Dp8390BufSz){ + count = ctlr->pstop*Dp8390BufSz - data; + if(ctlr->ram) + memmove(p, (void*)(ether->mem+data), count); else - dp8390read(dp8390, pkt, data, count); - pkt += count; - data = dp8390->pstart*Dp8390BufSz; - len1 -= count; + _dp8390read(ctlr, p, data, count); + p += count; + data = ctlr->pstart*Dp8390BufSz; + len -= count; } - if(len1){ - if(dp8390->ram) - memmove(pkt, (void*)(ether->mem+data), len1); + if(len){ + if(ctlr->ram) + memmove(p, (void*)(ether->mem+data), len); else - dp8390read(dp8390, pkt, data, len1); + _dp8390read(ctlr, p, data, len); } /* * Copy the packet to whoever wants it. */ - etherrloop(ether, ðer->rpkt, len); + etheriq(ether, bp, 1); } /* * Finished with this packet, update the * hardware and software ring pointers. */ - dp8390->nxtpkt = hdr.next; + ctlr->nxtpkt = hdr.next; hdr.next--; - if(hdr.next < dp8390->pstart) - hdr.next = dp8390->pstop-1; - slowoutb(port+Bnry, hdr.next); + if(hdr.next < ctlr->pstart) + hdr.next = ctlr->pstop-1; + regw(ctlr, Bnry, hdr.next); } } -static int -istxavail(void *arg) -{ - return ((Ether*)arg)->tlen == 0; -} - -static long -write(Ether *ether, void *buf, long len) +static void +txstart(Ether* ether) { - Dp8390 *dp8390; - ulong port; - Etherpkt *pkt; - - dp8390 = ether->ctlr; - port = dp8390->dp8390; + int len; + Dp8390 *ctlr; + Block *bp; + uchar minpkt[ETHERMINTU], *rp; - tsleep(ðer->tr, istxavail, ether, 10000); - if(ether->tlen){ - print("dp8390: transmitter jammed\n"); - return 0; - } - ether->tlen = len; + ctlr = ether->ctlr; /* - * If it's a shared-memory interface, copy the packet - * directly to the shared-memory area. Otherwise, copy - * it to a staging buffer so the I/O-port write can be - * done in one. + * This routine is called both from the top level and from interrupt + * level and expects to be called with ctlr already locked. */ - if(dp8390->ram) - pkt = (Etherpkt*)(ether->mem+dp8390->tstart*Dp8390BufSz); - else - pkt = ðer->tpkt; - memmove(pkt, buf, len); + if(ctlr->txbusy) + return; + bp = qget(ether->oq); + if(bp == nil) + return; /* - * Give the packet a source address and make sure it - * is of minimum length. + * Make sure the packet is of minimum length; + * copy it to the card's memory by the appropriate means; + * start the transmission. */ - memmove(pkt->s, ether->ea, sizeof(ether->ea)); + len = BLEN(bp); + rp = bp->rp; if(len < ETHERMINTU){ - memset(pkt->d+len, 0, ETHERMINTU-len); + rp = minpkt; + memmove(rp, bp->rp, len); + memset(rp+len, 0, ETHERMINTU-len); len = ETHERMINTU; } - if(dp8390->ram == 0) - dp8390write(dp8390, dp8390->tstart*Dp8390BufSz, pkt, len); + if(ctlr->ram) + memmove((void*)(ether->mem+ctlr->tstart*Dp8390BufSz), rp, len); + else + dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len); + freeb(bp); + + regw(ctlr, Tbcr0, len & 0xFF); + regw(ctlr, Tbcr1, (len>>8) & 0xFF); + regw(ctlr, Cr, Page0|RdABORT|Txp|Sta); + + ether->outpackets++; + ctlr->txbusy = 1; +} + +static void +transmit(Ether* ether) +{ + Dp8390 *ctlr; - slowoutb(port+Tbcr0, len & 0xFF); - slowoutb(port+Tbcr1, (len>>8) & 0xFF); - slowoutb(port+Cr, Page0|RDMAabort|Txp|Sta); + ctlr = ether->ctlr; - return len; + ilock(ctlr); + txstart(ether); + iunlock(ctlr); } static void overflow(Ether *ether) { - Dp8390 *dp8390; - ulong port; + Dp8390 *ctlr; uchar txp; int resend; - dp8390 = ether->ctlr; - port = dp8390->dp8390; + ctlr = ether->ctlr; /* * The following procedure is taken from the DP8390[12D] datasheet, * it seems pretty adamant that this is what has to be done. */ - txp = slowinb(port+Cr) & Txp; - slowoutb(port+Cr, Page0|RDMAabort|Stp); + txp = regr(ctlr, Cr) & Txp; + regw(ctlr, Cr, Page0|RdABORT|Stp); delay(2); - slowoutb(port+Rbcr0, 0); - slowoutb(port+Rbcr1, 0); + regw(ctlr, Rbcr0, 0); + regw(ctlr, Rbcr1, 0); resend = 0; - if(txp && (slowinb(port+Isr) & (Txe|Ptx)) == 0) + if(txp && (regr(ctlr, Isr) & (Txe|Ptx)) == 0) resend = 1; - slowoutb(port+Tcr, Lb); - slowoutb(port+Cr, Page0|RDMAabort|Sta); + regw(ctlr, Tcr, LpbkNIC); + regw(ctlr, Cr, Page0|RdABORT|Sta); receive(ether); - slowoutb(port+Isr, Ovw); - slowoutb(port+Tcr, 0); + regw(ctlr, Isr, Ovw); + regw(ctlr, Tcr, 0); if(resend) - slowoutb(port+Cr, Page0|RDMAabort|Txp|Sta); + regw(ctlr, Cr, Page0|RdABORT|Txp|Sta); } static void -interrupt(Ureg*, void *arg) +interrupt(Ureg*, void* arg) { Ether *ether; - Dp8390 *dp8390; - ulong port; + Dp8390 *ctlr; uchar isr, r; ether = arg; - dp8390 = ether->ctlr; - port = dp8390->dp8390; + ctlr = ether->ctlr; /* * While there is something of interest, * clear all the interrupts and process. */ - slowoutb(port+Imr, 0x00); - while(isr = (slowinb(port+Isr) & (Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe))){ - + lock(ctlr); + regw(ctlr, Imr, 0x00); + while(isr = (regr(ctlr, Isr) & (Cnt|Ovw|Txe|Rxe|Ptx|Prx))){ if(isr & Ovw){ overflow(ether); - slowoutb(port+Isr, Ovw); + regw(ctlr, Isr, Ovw); ether->overflows++; } /* - * We have received packets. - * Take a spin round the ring. and + * Packets have been received. + * Take a spin round the ring. */ if(isr & (Rxe|Prx)){ receive(ether); - slowoutb(port+Isr, Rxe|Prx); + regw(ctlr, Isr, Rxe|Prx); } /* @@ -580,50 +579,59 @@ interrupt(Ureg*, void *arg) * and wake the output routine. */ if(isr & (Txe|Ptx)){ - r = slowinb(port+Tsr); - if(isr & Txe){ - if((r & (Cdh|Fu|Crs|Abt))) - print("dp8390: Tsr#%2.2ux\n", r); + r = regr(ctlr, Tsr); + if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){ + print("dp8390: Tsr#%2.2ux|", r); ether->oerrs++; } - slowoutb(port+Isr, Txe|Ptx); + regw(ctlr, Isr, Txe|Ptx); if(isr & Ptx) ether->outpackets++; - ether->tlen = 0; - wakeup(ðer->tr); + ctlr->txbusy = 0; + txstart(ether); } if(isr & Cnt){ - ether->frames += slowinb(port+Cntr0); - ether->crcs += slowinb(port+Cntr1); - ether->buffs += slowinb(port+Cntr2); - slowoutb(port+Isr, Cnt); + ether->frames += regr(ctlr, Cntr0); + ether->crcs += regr(ctlr, Cntr1); + ether->buffs += regr(ctlr, Cntr2); + regw(ctlr, Isr, Cnt); } } - slowoutb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); + regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx); + unlock(ctlr); } static void promiscuous(void *arg, int on) { - Dp8390 *dp8390 = ((Ether*)arg)->ctlr; + Ether *ether; + Dp8390 *ctlr; + uchar r; + + ether = arg; + ctlr = ether->ctlr; /* * Set/reset promiscuous mode. */ + r = Ab; if(on) - slowoutb(dp8390->dp8390+Rcr, Pro|Ab); - else - slowoutb(dp8390->dp8390+Rcr, Ab); + r |= Pro; + ilock(ctlr); + regw(ctlr, Rcr, r); + iunlock(ctlr); } static void -attach(Ether *ether) +attach(Ether* ether) { - Dp8390 *dp8390 = ether->ctlr; - int x; + Dp8390 *ctlr; + uchar r; + + ctlr = ether->ctlr; /* * Enable the chip for transmit/receive. @@ -631,62 +639,84 @@ attach(Ether *ether) * mode. Clear the missed-packet counter, it * increments while in monitor mode. */ - x = Ab; + r = Ab; if(ether->prom) - x |= Pro; - slowoutb(dp8390->dp8390+Rcr, x); - slowinb(dp8390->dp8390+Cntr2); + r |= Pro; + ilock(ctlr); + regw(ctlr, Rcr, r); + r = regr(ctlr, Cntr2); + iunlock(ctlr); + USED(r); +} + +static void +disable(Dp8390* ctlr) +{ + int timo; + + /* + * Stop the chip. Set the Stp bit and wait for the chip + * to finish whatever was on its tiny mind before it sets + * the Rst bit. + * The timeout is needed because there may not be a real + * chip there if this is called when probing for a device + * at boot. + */ + regw(ctlr, Cr, Page0|RdABORT|Stp); + regw(ctlr, Rbcr0, 0); + regw(ctlr, Rbcr1, 0); + for(timo = 10000; (regr(ctlr, Isr) & Rst) == 0 && timo; timo--) + ; } int -dp8390reset(Ether *ether) +dp8390reset(Ether* ether) { - Dp8390 *dp8390; - ulong port; + Dp8390 *ctlr; - dp8390 = ether->ctlr; - port = dp8390->dp8390; + ctlr = ether->ctlr; /* * This is the initialisation procedure described * as 'mandatory' in the datasheet, with references - * to the 3Com503 technical reference manual. + * to the 3C503 technical reference manual. */ - dp8390disable(dp8390); - if(dp8390->bit16) - slowoutb(port+Dcr, Ft4|Ls|Wts); + disable(ctlr); + if(ctlr->width != 1) + regw(ctlr, Dcr, Ft4WORD|Ls|Wts); else - slowoutb(port+Dcr, Ft4|Ls); + regw(ctlr, Dcr, Ft4WORD|Ls); - slowoutb(port+Rbcr0, 0); - slowoutb(port+Rbcr1, 0); + regw(ctlr, Rbcr0, 0); + regw(ctlr, Rbcr1, 0); - slowoutb(port+Tcr, 0); - slowoutb(port+Rcr, Mon); + regw(ctlr, Tcr, 0); + regw(ctlr, Rcr, Mon); /* * Init the ring hardware and software ring pointers. - * Can't initialise ethernet address as we may not know - * it yet. + * Can't initialise ethernet address as it may not be + * known yet. */ - dp8390ring(dp8390); - slowoutb(port+Tpsr, dp8390->tstart); + ringinit(ctlr); + regw(ctlr, Tpsr, ctlr->tstart); - slowoutb(port+Isr, 0xFF); - slowoutb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); + regw(ctlr, Isr, 0xFF); + regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx); /* * Leave the chip initialised, * but in monitor mode. */ - slowoutb(port+Cr, Page0|RDMAabort|Sta); + regw(ctlr, Cr, Page0|RdABORT|Sta); /* * Set up the software configuration. */ ether->attach = attach; - ether->write = write; + ether->transmit = transmit; ether->interrupt = interrupt; + ether->ifstat = 0; ether->promiscuous = promiscuous; ether->arg = ether; diff --git a/pc/ether8390.h b/pc/ether8390.h new file mode 100644 index 0000000000000000000000000000000000000000..1c464110988693b0ffb7c8142373b1ae1c105361 --- /dev/null +++ b/pc/ether8390.h @@ -0,0 +1,71 @@ +/* + * Ctlr for the boards using the National Semiconductor DP8390 + * and SMC 83C90 Network Interface Controller. + * Common code is in ether8390.c. + */ +typedef struct { + Lock; + + ulong port; /* I/O address of 8390 */ + ulong data; /* I/O data port if no shared memory */ + + uchar width; /* data transfer width in bytes */ + uchar ram; /* true if card has shared memory */ + uchar dummyrr; /* do dummy remote read */ + + uchar nxtpkt; /* receive: software bndry */ + uchar pstart; + uchar pstop; + + int txbusy; /* transmit */ + uchar tstart; /* 8390 ring addresses */ +} Dp8390; + +#define Dp8390BufSz 256 + +extern int dp8390reset(Ether*); +extern void *dp8390read(Dp8390*, void*, ulong, ulong); +extern void dp8390getea(Ether*, uchar*); +extern void dp8390setea(Ether*); + +/* + * x86-specific code. + */ +#define regr(c, r) inb((c)->port+(r)) +#define regw(c, r, v) outb((c)->port+(r), (v)) + +static void +rdread(Dp8390* ctlr, void* to, int len) +{ + switch(ctlr->width){ + default: + panic("dp8390 rdread: width %d\n", ctlr->width); + break; + + case 2: + inss(ctlr->data, to, len/2); + break; + + case 1: + insb(ctlr->data, to, len); + break; + } +} + +static void +rdwrite(Dp8390* ctlr, void* from, int len) +{ + switch(ctlr->width){ + default: + panic("dp8390 rdwrite: width %d\n", ctlr->width); + break; + + case 2: + outss(ctlr->data, from, len/2); + break; + + case 1: + outsb(ctlr->data, from, len); + break; + } +} diff --git a/pc/etherelnk3.c b/pc/etherelnk3.c index 05077a94bc0e4722f5b58bcdfe0df1bd7b592e66..d91cf4b1330d6f117632da0c0fc2a146f091a25e 100644 --- a/pc/etherelnk3.c +++ b/pc/etherelnk3.c @@ -1,11 +1,12 @@ /* * Etherlink III and Fast EtherLink adapters. * To do: - * check robustness in the face of errors; + * check robustness in the face of errors (e.g. busmaster & rxUnderrun); * RxEarly and busmaster; * autoSelect; * PCI latency timer and master enable; - * errata list. + * errata list; + * 3C90x. * * Product ID: * 9150 ISA 3C509[B] @@ -47,8 +48,8 @@ enum { }; enum { /* all windows */ - Command = 0x000E, - IntStatus = 0x000E, + CommandR = 0x000E, + IntStatusR = 0x000E, }; enum { /* Commands */ @@ -122,8 +123,8 @@ enum { /* IntStatus bits */ interruptMask = 0x01FE, }; -#define COMMAND(port, cmd, a) outs((port)+Command, ((cmd)<<11)|(a)) -#define STATUS(port) ins((port)+IntStatus) +#define COMMAND(port, cmd, a) outs((port)+CommandR, ((cmd)<<11)|(a)) +#define STATUS(port) ins((port)+IntStatusR) enum { /* Window 0 - setup */ Wsetup = 0x0000, @@ -200,6 +201,10 @@ enum { /* Window 3 - FIFO management */ ResetOptions = 0x0008, /* 3C59[0257] */ RxFree = 0x000A, /* InternalConfig bits */ + ramPartition5to3 = 0x00000000, + ramPartition3to1 = 0x00010000, + ramPartition1to1 = 0x00020000, + ramPartitionMask = 0x00030000, xcvr10BaseT = 0x00000000, xcvrAui = 0x00100000, /* 10BASE5 */ xcvr10Base2 = 0x00300000, @@ -256,7 +261,7 @@ enum { /* Window 5 - internal state */ Wstate = 0x0005, /* registers */ TxStartThresh = 0x0000, - TxAvalableThresh = 0x0002, + TxAvailableThresh = 0x0002, RxEarlyThresh = 0x0006, RxFilter = 0x0008, InterruptEnable = 0x000A, @@ -303,11 +308,9 @@ typedef struct { int attached; int busmaster; - Block* rbp[2]; /* receive buffers */ - int rbpix; + Block* rbp; /* receive buffer */ - Block* txqhead; /* transmit queue */ - Block* txqtail; + Block* txbp; /* */ int txthreshold; int txbusy; @@ -329,11 +332,12 @@ typedef struct { int xcvr; /* transceiver type */ int rxstatus9; /* old-style RxStatus register */ + int rxearly; /* RxEarlyThreshold */ int ts; /* threshold shift */ } Ctlr; static Block* -allocrbp(void) +allocrbp(Block* (*f)(int)) { Block *bp; ulong addr; @@ -342,10 +346,11 @@ allocrbp(void) * The receive buffers must be on a 32-byte * boundary for EISA busmastering. */ - bp = allocb(ROUNDUP(sizeof(Etherpkt), 4) + 31); - addr = (ulong)bp->base; - addr = ROUNDUP(addr, 32); - bp->rp = (uchar*)addr; + if(bp = f(ROUNDUP(sizeof(Etherpkt), 4) + 31)){ + addr = (ulong)bp->base; + addr = ROUNDUP(addr, 32); + bp->rp = (uchar*)addr; + } return bp; } @@ -364,7 +369,7 @@ startdma(Ether* ether, ulong address) wp = KADDR(inl(port+MasterAddress)); status = ins(port+MasterStatus); if(status & (masterInProgress|targetAbort|masterAbort)) - print("elnk3#%d: BM status 0x%uX\n", ether->ctlrno, status); + print("#l%d: BM status 0x%uX\n", ether->ctlrno, status); outs(port+MasterStatus, masterMask); outl(port+MasterAddress, address); outs(port+MasterLen, sizeof(Etherpkt)); @@ -409,7 +414,7 @@ attach(Ether* ether) */ promiscuous(ether, ether->prom); - x = interruptMask|interruptLatch; + x = interruptMask; if(ctlr->busmaster) x &= ~(rxEarly|rxComplete); COMMAND(port, SetIndicationEnable, x); @@ -422,9 +427,8 @@ attach(Ether* ether) * Prime the busmaster channel for receiving directly into a * receive packet buffer if necessary. */ - ctlr->rbpix = 0; if(ctlr->busmaster) - startdma(ether, PADDR(ctlr->rbp[ctlr->rbpix]->rp)); + startdma(ether, PADDR(ctlr->rbp->rp)); ctlr->attached = 1; iunlock(&ctlr->wlock); @@ -472,7 +476,7 @@ statistics(Ether* ether) } static void -transmit(Ether* ether) +txstart(Ether* ether) { int port, len; Ctlr *ctlr; @@ -490,60 +494,52 @@ transmit(Ether* ether) * level and expects to be called with ctlr->wlock already locked * and the correct register window (Wop) in place. */ - while(bp = ctlr->txqhead){ + for(;;){ + if(ctlr->txbp){ + bp = ctlr->txbp; + ctlr->txbp = 0; + } + else{ + bp = qget(ether->oq); + if(bp == nil) + break; + } + len = ROUNDUP(BLEN(bp), 4); if(len+4 <= ins(port+TxFree)){ outl(port+Fifo, BLEN(bp)); outsl(port+Fifo, bp->rp, len/4); - ctlr->txqhead = bp->next; freeb(bp); ether->outpackets++; } - else if(ctlr->txbusy == 0){ - ctlr->txbusy = 1; - COMMAND(port, SetTxAvailableThresh, len>>ctlr->ts); - return; + else{ + ctlr->txbp = bp; + if(ctlr->txbusy == 0){ + ctlr->txbusy = 1; + COMMAND(port, SetTxAvailableThresh, len>>ctlr->ts); + } + break; } } } -static long -write(Ether* ether, void* buf, long n) +static void +transmit(Ether* ether) { Ctlr *ctlr; - Block *bp; int port, w; port = ether->port; ctlr = ether->ctlr; - /* - * Pack the write request up in a buffer, give it a source address - * and place it on the end of the transmit queue. The data written to the - * FIFO must be padded to a dword boundary, hence the ROUNDUP allocation. - * Call transmit() to stuff it into the TxFIFO if possible. - */ - bp = allocb(ROUNDUP(n, 4)); - memmove(bp->wp, buf, n); - memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); - bp->wp += n; - ilock(&ctlr->wlock); w = (STATUS(port)>>13) & 0x07; COMMAND(port, SelectRegisterWindow, Wop); - if(ctlr->txqhead == 0) - ctlr->txqhead = bp; - else - ctlr->txqtail->next = bp; - ctlr->txqtail = bp; - if(ctlr->txbusy == 0) - transmit(ether); + txstart(ether); COMMAND(port, SelectRegisterWindow, w); iunlock(&ctlr->wlock); - - return n; } static void @@ -599,35 +595,47 @@ receive(Ether* ether) if(rxerror & crcError) ether->crcs++; } + } + /* + * If there was an error or a new receive buffer can't be + * allocated, discard the packet and go on to the next. + */ + if((rxstatus & rxError) || (bp = allocrbp(iallocb)) == 0){ COMMAND(port, RxDiscard, 0); while(STATUS(port) & commandInProgress) ; if(ctlr->busmaster) - startdma(ether, PADDR(ctlr->rbp[ctlr->rbpix]->rp)); + startdma(ether, PADDR(ctlr->rbp->rp)); + + continue; } - else{ - ether->inpackets++; - bp = ctlr->rbp[ctlr->rbpix]; - if(ctlr->busmaster == 0){ - len = (rxstatus & rxBytes9); - bp->wp = bp->rp + len; - insl(port+Fifo, bp->rp, HOWMANY(len, 4)); - } + /* + * A valid receive packet awaits: + * if using PIO, read it into the buffer; + * discard the packet from the FIFO; + * if using busmastering, start a new transfer for + * the next packet and as a side-effect get the + * end-pointer of the one just received; + * pass the packet on to whoever wants it. + */ + if(ctlr->busmaster == 0){ + len = (rxstatus & rxBytes9); + ctlr->rbp->wp = ctlr->rbp->rp + len; + insl(port+Fifo, ctlr->rbp->rp, HOWMANY(len, 4)); + } - COMMAND(port, RxDiscard, 0); - while(STATUS(port) & commandInProgress) - ; + COMMAND(port, RxDiscard, 0); + while(STATUS(port) & commandInProgress) + ; - if(ctlr->busmaster){ - ctlr->rbpix ^= 1; - bp->wp = startdma(ether, PADDR(ctlr->rbp[ctlr->rbpix]->rp)); - } + if(ctlr->busmaster) + ctlr->rbp->wp = startdma(ether, PADDR(bp->rp)); - etherrloop(ether, (Etherpkt*)bp->rp, BLEN(bp)); - } + etheriq(ether, ctlr->rbp, 1); + ctlr->rbp = bp; } } @@ -635,7 +643,7 @@ static void interrupt(Ureg*, void* arg) { Ether *ether; - int port, status, txstatus, w, x; + int port, status, s, w, x; Ctlr *ctlr; ether = arg; @@ -648,19 +656,7 @@ interrupt(Ureg*, void* arg) ctlr->interrupts++; ctlr->timer += inb(port+Timer) & 0xFF; - for(;;){ - /* - * Clear the interrupt latch. - * It's possible to receive a packet and for another - * to become complete before exiting the interrupt - * handler so this must be done first to ensure another - * interrupt will occur. - */ - COMMAND(port, AcknowledgeInterrupt, interruptLatch); - status = STATUS(port); - if((status & interruptMask) == 0) - break; - + for(status = STATUS(port); status & interruptMask; status = STATUS(port)){ if(status & hostError){ /* * Adapter failure, try to find out why, reset if @@ -670,7 +666,7 @@ interrupt(Ureg*, void* arg) COMMAND(port, SelectRegisterWindow, Wdiagnostic); x = ins(port+FifoDiagnostic); COMMAND(port, SelectRegisterWindow, Wop); - print("elnk3#%d: status 0x%uX, diag 0x%uX\n", + print("#l%d: status 0x%uX, diag 0x%uX\n", ether->ctlrno, status, x); if(x & txOverrun){ @@ -679,17 +675,23 @@ interrupt(Ureg*, void* arg) else COMMAND(port, TxReset, dmaReset); COMMAND(port, TxEnable, 0); - wakeup(ðer->tr); } if(x & rxUnderrun){ /* * This shouldn't happen... + * Reset the receiver and restore the filter and RxEarly + * threshold before re-enabling. * Need to restart any busmastering? */ + COMMAND(port, SelectRegisterWindow, Wstate); + s = (port+RxFilter) & 0x000F; + COMMAND(port, SelectRegisterWindow, Wop); COMMAND(port, RxReset, 0); while(STATUS(port) & commandInProgress) ; + COMMAND(port, SetRxFilter, s); + COMMAND(port, SetRxEarlyThresh, ctlr->rxearly>>ctlr->ts); COMMAND(port, RxEnable, 0); } @@ -710,14 +712,14 @@ interrupt(Ureg*, void* arg) * as a busmaster receive may be in progress. * For all conditions enable the transmitter. */ - txstatus = 0; + s = 0; do{ if(x = inb(port+TxStatus)) outb(port+TxStatus, 0); - txstatus |= x; + s |= x; }while(STATUS(port) & txComplete); - if(txstatus & txUnderrun){ + if(s & txUnderrun){ COMMAND(port, SelectRegisterWindow, Wdiagnostic); while(ins(port+MediaStatus) & txInProg) ; @@ -726,7 +728,7 @@ interrupt(Ureg*, void* arg) ctlr->txthreshold += ETHERMINTU; } - if(txstatus & (txJabber|txUnderrun)){ + if(s & (txJabber|txUnderrun)){ if(ctlr->busmaster == 0) COMMAND(port, TxReset, 0); else @@ -744,7 +746,7 @@ interrupt(Ureg*, void* arg) if(status & txAvailable){ COMMAND(port, AcknowledgeInterrupt, txAvailable); ctlr->txbusy = 0; - transmit(ether); + txstart(ether); status &= ~txAvailable; } @@ -765,8 +767,9 @@ interrupt(Ureg*, void* arg) * Panic if there are any interrupts not dealt with. */ if(status & interruptMask) - panic("elnk3#%d: interrupt mask 0x%uX\n", ether->ctlrno, status); + panic("#l%d: interrupt mask 0x%uX\n", ether->ctlrno, status); } + COMMAND(port, AcknowledgeInterrupt, interruptLatch); COMMAND(port, SelectRegisterWindow, w); unlock(&ctlr->wlock); @@ -806,13 +809,28 @@ ifstat(Ether* ether, void* a, long n, ulong offset) return readstr(offset, a, n, buf); } -typedef struct Adapter Adapter; -struct Adapter { - Adapter* next; - int port; - int irq; -}; -static Adapter *adapter; +typedef struct Adapter { + int port; + int irq; + int tbdf; +} Adapter; +static Block* adapter; + +static void +tcmadapter(int port, int irq, int tbdf) +{ + Block *bp; + Adapter *ap; + + bp = allocb(sizeof(Adapter)); + ap = (Adapter*)bp->rp; + ap->port = port; + ap->irq = irq; + ap->tbdf = tbdf; + + bp->next = adapter; + adapter = bp; +} /* * Write two 0 bytes to identify the IDport and then reset the @@ -914,7 +932,6 @@ static ulong tcm509isa(Ether* ether) { int irq, port; - Adapter *ap; /* * Attempt to activate adapters until one matches the @@ -958,11 +975,7 @@ tcm509isa(Ether* ether) return port; } - ap = malloc(sizeof(Adapter)); - ap->port = port; - ap->irq = irq; - ap->next = adapter; - adapter = ap; + tcmadapter(port, irq, BUSUNKNOWN); } return 0; @@ -974,7 +987,6 @@ tcm5XXeisa(Ether* ether) static int slot = 1; ushort x; int irq, port; - Adapter *ap; /* * First time through, check if this is an EISA machine. @@ -1010,11 +1022,7 @@ tcm5XXeisa(Ether* ether) return port; } - ap = malloc(sizeof(Adapter)); - ap->port = port; - ap->irq = irq; - ap->next = adapter; - adapter = ap; + tcmadapter(port, irq, BUSUNKNOWN); } return 0; @@ -1023,31 +1031,19 @@ tcm5XXeisa(Ether* ether) static int tcm59Xpci(Ether* ether) { - PCIcfg pcicfg; - static int devno = 0; + static Pcidev *p; int irq, port; - Adapter *ap; - for(;;){ - pcicfg.vid = 0x10B7; - pcicfg.did = 0; - if((devno = pcimatch(0, devno, &pcicfg)) == -1) - break; - port = pcicfg.baseaddr[0] & ~0x01; - COMMAND(port, GlobalReset, 0); - while(STATUS(port) & commandInProgress) - ; - irq = pcicfg.irq; + while(p = pcimatch(p, 0x10B7, 0)){ + port = p->bar[0] & ~0x01; + irq = p->intl; if(ether->port == 0 || ether->port == port){ ether->irq = irq; + ether->tbdf = p->tbdf; return port; } - ap = malloc(sizeof(Adapter)); - ap->port = port; - ap->irq = irq; - ap->next = adapter; - adapter = ap; + tcmadapter(port, irq, p->tbdf); } return 0; @@ -1147,7 +1143,8 @@ int etherelnk3reset(Ether* ether) { int busmaster, i, port, rxearly, rxstatus9, x, xcvr; - Adapter *ap, **app; + Block *bp, **bpp; + Adapter *ap; uchar ea[Eaddrlen]; Ctlr *ctlr; @@ -1163,20 +1160,27 @@ etherelnk3reset(Ether* ether) rxearly = 2044; rxstatus9 = 0; xcvr = 0; - for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){ + bpp = &adapter; + for(bp = *bpp; bp; bp = bp->next){ + ap = (Adapter*)bp->rp; if(ether->port == 0 || ether->port == ap->port){ port = ap->port; ether->irq = ap->irq; - *app = ap->next; - free(ap); + ether->tbdf = ap->tbdf; + *bpp = bp->next; + freeb(bp); break; } + bpp = &bp->next; } if(port == 0 && (port = tcm5XXpcmcia(ether))){ xcvr = ((ins(port+AddressConfig) & xcvrMask9)>>14)<<20; rxstatus9 = 1; } else if(port == 0 && (port = tcm59Xpci(ether))){ + COMMAND(port, GlobalReset, 0); + while(STATUS(port) & commandInProgress) + ; COMMAND(port, SelectRegisterWindow, Wfifo); rxearly = 8188; xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask); @@ -1241,8 +1245,11 @@ etherelnk3reset(Ether* ether) COMMAND(port, SelectRegisterWindow, Wdiagnostic); x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable); outs(port+MediaStatus, x); - if(x & dataRate100) + if(x & dataRate100){ busmaster = 1; + x = inl(port+InternalConfig) & ~ramPartitionMask; + outl(port+InternalConfig, x|ramPartition1to1); + } else busmaster = 0; switch(xcvr){ @@ -1298,25 +1305,23 @@ etherelnk3reset(Ether* ether) ctlr->busmaster = busmaster; ctlr->xcvr = xcvr; ctlr->rxstatus9 = rxstatus9; + ctlr->rxearly = rxearly; if(rxearly >= 2048) ctlr->ts = 2; COMMAND(port, StatisticsEnable, 0); /* - * Allocate the receive buffers. + * Allocate the receive buffer. */ - ctlr->rbpix = 0; - ctlr->rbp[0] = allocrbp(); - if(ctlr->busmaster) - ctlr->rbp[1] = allocrbp(); + ctlr->rbp = allocrbp(allocb); /* * Set a base TxStartThresh which will be incremented * if any txUnderrun errors occur and ensure no RxEarly * interrupts happen. */ - ctlr->txthreshold = ETHERMINTU*2; + ctlr->txthreshold = ETHERMAXTU/2; COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); COMMAND(port, SetRxEarlyThresh, rxearly>>ctlr->ts); @@ -1327,7 +1332,7 @@ etherelnk3reset(Ether* ether) */ ether->port = port; ether->attach = attach; - ether->write = write; + ether->transmit = transmit; ether->interrupt = interrupt; ether->ifstat = ifstat; diff --git a/pc/etherif.h b/pc/etherif.h index b369578ec9a435fa1482daa46fc63c080b235631..97f65bdfa7cb8fd57eba411f834b075ce94b4652 100644 --- a/pc/etherif.h +++ b/pc/etherif.h @@ -7,52 +7,24 @@ typedef struct Ether Ether; struct Ether { ISAConf; /* hardware info */ int ctlrno; + int tbdf; /* type+busno+devno+funcno */ int mbps; /* Mbps */ + uchar ea[Eaddrlen]; void (*attach)(Ether*); /* filled in by reset routine */ - long (*write)(Ether*, void*, long); + void (*transmit)(Ether*); void (*interrupt)(Ureg*, void*); long (*ifstat)(Ether*, void*, long, ulong); void *ctlr; - Etherpkt tpkt; /* transmit buffer */ - Etherpkt rpkt; /* receive buffer */ - - QLock tlock; /* lock for grabbing transmitter queue */ - Rendez tr; /* wait here for free xmit buffer */ - long tlen; /* length of data in tpkt */ + Queue* oq; Netif; }; -extern void etherrloop(Ether*, Etherpkt*, long); +extern Block* etheriq(Ether*, Block*, int); extern void addethercard(char*, int(*)(Ether*)); -/* - * Stuff for the boards using the National Semiconductor DP8390 - * and SMC 83C90 Network Interface Controller. - * Common code is in ether8390.c. - */ -typedef struct { - uchar bit16; /* true if a 16 bit interface */ - uchar ram; /* true if card has shared memory */ - - ulong dp8390; /* I/O address of 8390 */ - ulong data; /* I/O data port if no shared memory */ - - uchar nxtpkt; /* receive: software bndry */ - uchar tstart; /* 8390 ring addresses */ - uchar pstart; - uchar pstop; -} Dp8390; - -#define Dp8390BufSz 256 - -extern int dp8390reset(Ether*); -extern void *dp8390read(Dp8390*, void*, ulong, ulong); -extern void *dp8390write(Dp8390*, ulong, void*, ulong); -extern void dp8390setea(Ether*); - #define NEXT(x, l) (((x)+1)%(l)) #define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1) #define HOWMANY(x, y) (((x)+((y)-1))/(y)) diff --git a/pc/fault386.c b/pc/fault386.c deleted file mode 100644 index 5fbd8e376aabd120bda3e69ee60686748e03ec50..0000000000000000000000000000000000000000 --- a/pc/fault386.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "ureg.h" -#include "io.h" - -static void -fault386(Ureg *ur, void *arg) -{ - ulong addr; - int read; - int user; - int n; - int insyscall; - char buf[ERRLEN]; - - USED(arg); - - insyscall = up->insyscall; - up->insyscall = 1; - addr = getcr2(); - read = !(ur->ecode & 2); - user = (ur->cs&0xffff) == UESEL; - spllo(); - n = fault(addr, read); - if(n < 0){ - if(user){ - sprint(buf, "sys: trap: fault %s addr=0x%lux", - read? "read" : "write", addr); - postnote(up, 1, buf, NDebug); - return; - } - dumpregs(ur); - panic("fault: 0x%lux\n", addr); - } - up->insyscall = insyscall; -} - -void -faultinit(void) -{ - setvec(Faultvec, fault386, 0); -} diff --git a/pc/floppy.h b/pc/floppy.h new file mode 100644 index 0000000000000000000000000000000000000000..f39ab30f25d4d67b3ecf1d4eb7e144f8849c5231 --- /dev/null +++ b/pc/floppy.h @@ -0,0 +1,179 @@ +typedef struct FController FController; +typedef struct FDrive FDrive; +typedef struct FType FType; + +static void floppyintr(Ureg*); +static void floppyon(FDrive*); +static void floppyoff(FDrive*); +static void floppysetdef(FDrive*); + +/* + * a floppy drive + */ +struct FDrive +{ + FType *t; /* floppy type */ + int dt; /* drive type */ + int dev; + + ulong lasttouched; /* time last touched */ + int cyl; /* current arm position */ + int confused; /* needs to be recalibrated */ + int vers; + + int tcyl; /* target cylinder */ + int thead; /* target head */ + int tsec; /* target sector */ + long len; /* size of xfer */ + + uchar *cache; /* track cache */ + int ccyl; + int chead; + + Rendez r; /* waiting here for motor to spin up */ +}; + +/* + * controller for 4 floppys + */ +struct FController +{ + QLock; /* exclusive access to the contoller */ + + int ndrive; + FDrive *d; /* the floppy drives */ + FDrive *selected; + int rate; /* current rate selected */ + uchar cmd[14]; /* command */ + int ncmd; /* # command bytes */ + uchar stat[14]; /* command status */ + int nstat; /* # status bytes */ + int confused; /* controler needs to be reset */ + Rendez r; /* wait here for command termination */ + int motor; /* bit mask of spinning disks */ + Rendez kr; /* for motor watcher */ +}; + +/* + * floppy types (all MFM encoding) + */ +struct FType +{ + char *name; + int dt; /* compatible drive type */ + int bytes; /* bytes/sector */ + int sectors; /* sectors/track */ + int heads; /* number of heads */ + int steps; /* steps per cylinder */ + int tracks; /* tracks/disk */ + int gpl; /* intersector gap length for read/write */ + int fgpl; /* intersector gap length for format */ + int rate; /* rate code */ + + /* + * these depend on previous entries and are set filled in + * by floppyinit + */ + int bcode; /* coded version of bytes for the controller */ + long cap; /* drive capacity in bytes */ + long tsize; /* track size in bytes */ +}; +/* bits in the registers */ +enum +{ + /* status registers a & b */ + Psra= 0x3f0, + Psrb= 0x3f1, + + /* digital output register */ + Pdor= 0x3f2, + Fintena= 0x8, /* enable floppy interrupt */ + Fena= 0x4, /* 0 == reset controller */ + + /* main status register */ + Pmsr= 0x3f4, + Fready= 0x80, /* ready to be touched */ + Ffrom= 0x40, /* data from controller */ + Ffloppybusy= 0x10, /* operation not over */ + + /* data register */ + Pfdata= 0x3f5, + Frecal= 0x07, /* recalibrate cmd */ + Fseek= 0x0f, /* seek cmd */ + Fsense= 0x08, /* sense cmd */ + Fread= 0x66, /* read cmd */ + Freadid= 0x4a, /* read track id */ + Fspec= 0x03, /* set hold times */ + Fwrite= 0x45, /* write cmd */ + Fformat= 0x4d, /* format cmd */ + Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */ + Fdumpreg= 0x0e, /* dump internal registers */ + + /* digital input register */ + Pdir= 0x3F7, /* disk changed port (read only) */ + Pdsr= 0x3F7, /* data rate select port (write only) */ + Fchange= 0x80, /* disk has changed */ + + /* status 0 byte */ + Drivemask= 3<<0, + Seekend= 1<<5, + Codemask= (3<<6)|(3<<3), + Cmdexec= 1<<6, + + /* status 1 byte */ + Overrun= 0x10, +}; + + +static void +pcfloppyintr(Ureg *ur, void *a) +{ + USED(a); + + floppyintr(ur); +} + +void +floppysetup0(FController *fl) +{ + fl->ndrive = 2; +} + +void +floppysetup1(FController *fl) +{ + uchar equip; + + /* + * read nvram for types of floppies 0 & 1 + */ + equip = nvramread(0x10); + if(fl->ndrive > 0){ + fl->d[0].dt = (equip >> 4) & 0xf; + floppysetdef(&fl->d[0]); + } + if(fl->ndrive > 1){ + fl->d[1].dt = equip & 0xf; + floppysetdef(&fl->d[1]); + } + + intrenable(VectorFLOPPY, pcfloppyintr, fl, BUSUNKNOWN); +} + +/* + * eject disk ( unknown on safari ) + */ +void +floppyeject(FDrive *dp) +{ + floppyon(dp); + dp->vers++; + floppyoff(dp); +} + +int +floppyexec(char *a, long b, int c) +{ + USED(a, b, c); + return b; +} diff --git a/pc/fns.h b/pc/fns.h index fff67dd96eca7426c946c436ab830b60bbdc827e..79a52274c41801a0b54b4a8cf6f8a16103fe9b4d 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -1,25 +1,26 @@ #include "../port/portfns.h" void aamloop(int); +void addclock0link(void (*)(void)); void addconf(char*, char*); void addscsilink(char*, Scsiio (*)(int, ISAConf*)); -void bbinit(void); -void bigcursor(void); +void archinit(void); void bootargs(ulong); int cistrcmp(char*, char*); -#define clearmmucache() /* 386 doesn't have one */ -void clockinit(void); -void config(int); -int cpuspeed(int); +int cistrncmp(char*, char*, int); +#define clearmmucache() /* x86 doesn't have one */ +void clockintr(Ureg*, void*); +void (*coherence)(void); +void cpuid(char*, int*, int*); +int cpuidentify(void); +void cpuidprint(void); void delay(int); +int dmacount(int); int dmadone(int); void dmaend(int); void dmainit(void); long dmasetup(int, void*, long, int); -#define evenaddr(x) /* 386 doesn't care */ -void faultinit(void); -void fclock(Ureg*); -void fclockinit(void); +#define evenaddr(x) /* x86 doesn't care */ void fpenv(FPsave*); void fpinit(void); void fpoff(void); @@ -29,12 +30,15 @@ ulong fpstatus(void); ulong getcr0(void); ulong getcr2(void); ulong getcr3(void); +ulong getcr4(void); char* getconf(char*); -ulong getstatus(void); -void hardclock(void); -void i8042a20(void); +int i8042auxcmd(int); +void i8042auxenable(void (*)(int, int)); void i8042reset(void); -void ident(void); +void i8253init(int); +void i8253enable(void); +void i8259init(void); +int i8259enable(int, int, Irqctl*); void idle(void); int inb(int); void insb(int, void*, int); @@ -42,60 +46,64 @@ ushort ins(int); void inss(int, void*, int); ulong inl(int); void insl(int, void*, int); +void intrenable(int, void (*)(Ureg*, void*), void*, int); int iprint(char*, ...); int isaconfig(char*, int, ISAConf*); ulong getisa(ulong, int, int); void putisa(ulong, int); -ulong getspace(int, int); void kbdinit(void); -long* mapaddr(ulong); +void lgdt(ushort[3]); +void lidt(ushort[3]); +void ltr(ulong); void mathinit(void); +#define mmuflushtlb(pdb) putcr3(pdb) void meminit(void); +void memscan(void); void mmuinit(void); #define mmunewpage(x) -int modem(int); -void mousectl(char*); +ulong* mmuwalk(ulong*, ulong, int); +void ns16552install(void); +void ns16552special(int, int, Queue**, Queue**, int (*)(Queue*, int)); uchar nvramread(int); +void nvramwrite(int, uchar); void outb(int, int); void outsb(int, void*, int); void outs(int, ushort); void outss(int, void*, int); void outl(int, ulong); void outsl(int, void*, int); -void pcicfgr(int, int, int, int, void*, int); -void pcicfgw(int, int, int, int, void*, int); -int pcimatch(int, int, PCIcfg*); +int pcicfgr8(Pcidev*, int); +int pcicfgr16(Pcidev*, int); +int pcicfgr32(Pcidev*, int); +void pcicfgw8(Pcidev*, int, int); +void pcicfgw16(Pcidev*, int, int); +void pcicfgw32(Pcidev*, int, int); +Pcidev* pcimatch(Pcidev*, int, int); +void pcireset(void); PCMmap* pcmmap(int, ulong, int, int); int pcmspecial(char*, ISAConf*); void pcmspecialclose(int); void pcmunmap(int, PCMmap*); -void prflush(void); -void prhex(ulong); void printcpufreq(void); -void procrestore(Proc*); +#define procrestore(p) void procsave(Proc*); void procsetup(Proc*); -void ps2poll(void); -void putgdt(Segdesc*, int); -void putidt(Segdesc*, int); void putcr3(ulong); -void puttr(ulong); +void putcr4(ulong); +void rdmsr(int, ulong*, ulong*); void screeninit(void); +int screenprint(char*, ...); /* debugging */ void screenputs(char*, int); -int serial(int); -void setvec(int, void (*)(Ureg*, void*), void*); -void syscall(Ureg*, void*); -void systrap(void); -void toscreen(void*); void touser(void*); void trapinit(void); int tas(void*); -void uartclock(void); -void uartpoll(void); -void vgainit(void); -void vgasavecrash(uchar*, int); -void vgarestorecrash(uchar*, int); -int x86cpuid(int*, int*); +ulong umbmalloc(ulong, int, int); +void umbfree(ulong, int); +ulong upamalloc(ulong, int, int); +void upafree(ulong, int); +void vectortable(void); +void wrmsr(int, ulong, ulong); +void wbflush(void); int xchgw(ushort*, int); #define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1])) @@ -104,29 +112,4 @@ int xchgw(ushort*, int); #define KADDR(a) ((void*)((ulong)(a)|KZERO)) #define PADDR(a) ((ulong)(a)&~KZERO) -void ns16552install(void); -void ns16552special(int, int, Queue**, Queue**, int (*)(Queue*, int)); - -void hnputl(void*, ulong v); -void hnputs(void*, ushort v); -ulong nhgetl(void*); -ushort nhgets(void*); - -void ifwrite(void*, Block*, int); -void* ifinit(int); -ulong ifaddr(void*); -void filiput(Block*); -void fiberint(Ureg*, void*); -ulong fwblock(ulong, void*, ulong); -ulong frblock(ulong, void*, ulong); -void freset(void*); -void ifree(void*); -void ifflush(void*); -Block* iallocb(int); -void* ifroute(ulong); -int ifgetsr(void); -ulong ifunroute(ulong); -void parseip(char*, char*); - #define dcflush(a, b) -#define coherence() diff --git a/pc/i8253.c b/pc/i8253.c new file mode 100644 index 0000000000000000000000000000000000000000..0326a6551d002f90f8676db6d91a05b09ab826e7 --- /dev/null +++ b/pc/i8253.c @@ -0,0 +1,100 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +/* + * 8253 timer + */ +enum +{ + T0cntr= 0x40, /* counter ports */ + T1cntr= 0x41, /* ... */ + T2cntr= 0x42, /* ... */ + Tmode= 0x43, /* mode port */ + + /* commands */ + Latch0= 0x00, /* latch counter 0's value */ + Load0= 0x30, /* load counter 0 with 2 bytes */ + + /* modes */ + Square= 0x36, /* periodic square wave */ + Trigger= 0x30, /* interrupt on terminal count */ + + Freq= 1193182, /* Real clock frequency */ +}; + +void +i8253init(int aalcycles) +{ + int cpufreq, loops, incr, x, y; + static int initialised; + + if(initialised == 0){ + initialised = 1; + /* + * set clock for 1/HZ seconds + */ + outb(Tmode, Load0|Square); + outb(T0cntr, (Freq/HZ)); /* low byte */ + outb(T0cntr, (Freq/HZ)>>8); /* high byte */ + } + + /* find biggest loop that doesn't wrap */ + incr = 16000000/(aalcycles*HZ*2); + x = 2000; + for(loops = incr; loops < 64*1024; loops += incr) { + + /* + * measure time for the loop + * + * MOVL loops,CX + * aaml1: AAM + * LOOP aaml1 + * + * the time for the loop should be independent of external + * cache and memory system since it fits in the execution + * prefetch buffer. + * + */ + outb(Tmode, Latch0); + x = inb(T0cntr); + x |= inb(T0cntr)<<8; + aamloop(loops); + outb(Tmode, Latch0); + y = inb(T0cntr); + y |= inb(T0cntr)<<8; + x -= y; + + if(x < 0) + x += Freq/HZ; + + if(x > Freq/(3*HZ)) + break; + } + + /* + * counter goes at twice the frequency, once per transition, + * i.e., twice per square wave + */ + x >>= 1; + + /* + * figure out clock frequency and a loop multiplier for delay(). + */ + cpufreq = loops*((aalcycles*Freq)/x); + m->loopconst = (cpufreq/1000)/aalcycles; /* AAM+LOOP's for 1 ms */ + + /* + * add in possible 0.5% error and convert to MHz + */ + m->cpumhz = (cpufreq + cpufreq/200)/1000000; +} + +void +i8253enable(void) +{ + intrenable(VectorCLOCK, clockintr, 0, BUSUNKNOWN); +} diff --git a/pc/i8259.c b/pc/i8259.c new file mode 100644 index 0000000000000000000000000000000000000000..509451ca81bbbc7f5e60c123ff5b1721fd42d7c9 --- /dev/null +++ b/pc/i8259.c @@ -0,0 +1,149 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +/* + * 8259 interrupt controllers + */ +enum +{ + Int0ctl= 0x20, /* control port (ICW1, OCW2, OCW3) */ + Int0aux= 0x21, /* everything else (ICW2, ICW3, ICW4, OCW1) */ + Int1ctl= 0xA0, /* control port */ + Int1aux= 0xA1, /* everything else (ICW2, ICW3, ICW4, OCW1) */ + + Icw1= 0x10, /* select bit in ctl register */ + Ocw2= 0x00, + Ocw3= 0x08, + + EOI= 0x20, /* non-specific end of interrupt */ + + Elcr1= 0x4D0, /* Edge/Level Triggered Register */ + Elcr2= 0x4D1, +}; + +static int int0mask; /* interrupts enabled for first 8259 */ +static int int1mask; /* interrupts enabled for second 8259 */ + +int elcr; /* mask of level-triggered interrupts */ + +void +i8259init(void) +{ + int elcr1; + + int0mask = 0xFF; + int1mask = 0xFF; + + /* + * Set up the first 8259 interrupt processor. + * Make 8259 interrupts start at CPU vector Int0vec. + * Set the 8259 as master with edge triggered + * input with fully nested interrupts. + */ + outb(Int0ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered, + ICW4 will be sent */ + outb(Int0aux, VectorPIC); /* ICW2 - interrupt vector offset */ + outb(Int0aux, 0x04); /* ICW3 - have slave on level 2 */ + outb(Int0aux, 0x01); /* ICW4 - 8086 mode, not buffered */ + + /* + * Set up the second 8259 interrupt processor. + * Make 8259 interrupts start at CPU vector VectorPIC+8. + * Set the 8259 as slave with edge triggered + * input with fully nested interrupts. + */ + outb(Int1ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered, + ICW4 will be sent */ + outb(Int1aux, VectorPIC+8); /* ICW2 - interrupt vector offset */ + outb(Int1aux, 0x02); /* ICW3 - I am a slave on level 2 */ + outb(Int1aux, 0x01); /* ICW4 - 8086 mode, not buffered */ + + /* + * pass #2 8259 interrupts to #1 + */ + int0mask &= ~0x04; + outb(Int0aux, int0mask); + + /* + * Set Ocw3 to return the ISR when ctl read. + * After initialisation status read is set to IRR. + * Read IRR first to possibly deassert an outstanding + * interrupt. + */ + inb(Int0ctl); + outb(Int0ctl, Ocw3|0x03); + inb(Int1ctl); + outb(Int1ctl, Ocw3|0x03); + + /* + * Check for Edge/Level register. + * This check may not work for all chipsets. + */ + elcr1 = inb(Elcr1); + outb(Elcr1, 0); + if(inb(Elcr1) == 0){ + outb(Elcr1, 0x20); + if(inb(Elcr1) == 0x20) + elcr = (inb(Elcr2)<<8)|elcr1; + } + outb(Elcr1, elcr1); + /* + if(elcr) + print("ELCR: %4.4uX\n", elcr); + */ +} + +int +i8259isr(int v) +{ + int isr; + + /* + * tell the 8259 that we're done with the + * highest level interrupt (interrupts are still + * off at this point) + */ + isr = 0; + if(v >= VectorPIC && v <= MaxVectorPIC){ + isr = inb(Int0ctl); + outb(Int0ctl, EOI); + if(v >= VectorPIC+8){ + isr |= inb(Int1ctl)<<8; + outb(Int1ctl, EOI); + } + } + + return isr & (1<<(v-VectorPIC)); +} + +int +i8259enable(int v, int, Irqctl* irqctl) +{ + if(v < VectorPIC || v > MaxVectorPIC) + return 0; + v -= VectorPIC; + + /* + * enable corresponding interrupt in 8259 + */ + if(v < 8){ + int0mask &= ~(1<eoi = i8259isr; + else + irqctl->isr = i8259isr; + irqctl->isintr = 1; + + return v; +} diff --git a/pc/io.h b/pc/io.h index 8931c7faed55ef1685ac3c992abdc63e06c109cf..9b5312b255e6e232eba9aa95cff3943bbe9a6da6 100644 --- a/pc/io.h +++ b/pc/io.h @@ -1,74 +1,153 @@ -/* - * programmable interrupt vectors (for the 8259's) - */ -enum -{ - Bptvec= 3, /* breakpoints */ - Mathemuvec= 7, /* math coprocessor emulation interrupt */ - Mathovervec= 9, /* math coprocessor overrun interrupt */ - Matherr1vec= 16, /* math coprocessor error interrupt */ - Faultvec= 14, /* page fault */ +#define X86STEPPING(x) ((x) & 0x0F) +#define X86MODEL(x) (((x)>>4) & 0x0F) +#define X86FAMILY(x) (((x)>>8) & 0x0F) + +enum { + VectorBPT = 3, /* breakpoint */ + VectorCNA = 7, /* coprocessor not available */ + VectorCSO = 9, /* coprocessor segment overrun */ + VectorPF = 14, /* page fault */ + VectorCERR = 16, /* coprocessor error */ + + VectorLAPIC = 32, /* local APIC interrupts */ + VectorLINT0 = VectorLAPIC+0,/* LINT[01] must be offsets 0 and 1 */ + VectorLINT1 = VectorLAPIC+1, + VectorTIMER = VectorLAPIC+2, + VectorERROR = VectorLAPIC+3, + VectorPCINT = VectorLAPIC+4, + VectorSPURIOUS = VectorLAPIC+15,/* must have bits [3-0] == 0x0F */ + MaxVectorLAPIC = VectorLAPIC+15, - Int0vec= 24, /* first 8259 */ - Clockvec= Int0vec+0, /* clock interrupts */ - Kbdvec= Int0vec+1, /* keyboard interrupts */ - Uart1vec= Int0vec+3, /* modem line */ - Uart0vec= Int0vec+4, /* serial line */ - PCMCIAvec= Int0vec+5, /* PCMCIA card change */ - Floppyvec= Int0vec+6, /* floppy interrupts */ - Parallelvec= Int0vec+7, /* parallel port interrupts */ - Int1vec= Int0vec+8, - Vector9= Int0vec+9, /* unassigned */ - Vector10= Int0vec+10, /* unassigned, usually ethernet */ - Vector11= Int0vec+11, /* unassigned, usually scsi */ - Mousevec= Int0vec+12, /* mouse interrupt */ - Matherr2vec= Int0vec+13, /* math coprocessor */ - ATAvec0= Int0vec+14, /* ATA controller #1 */ - ATAvec1= Int0vec+15, /* ATA controller #2 */ + VectorSYSCALL = 64, - Syscallvec= 64, + VectorPIC = 128, /* external [A]PIC interrupts */ + VectorCLOCK = VectorPIC+0, + VectorKBD = VectorPIC+1, + VectorUART1 = VectorPIC+3, + VectorUART0 = VectorPIC+4, + VectorPCMCIA = VectorPIC+5, + VectorFLOPPY = VectorPIC+6, + VectorLPT = VectorPIC+7, + VectorIRQ7 = VectorPIC+7, + VectorAUX = VectorPIC+12, /* PS/2 port */ + VectorIRQ13 = VectorPIC+13, /* coprocessor on x386 */ + VectorATA0 = VectorPIC+14, + MaxVectorPIC = VectorPIC+15, }; +enum { + BusCBUS = 0, /* Corollary CBUS */ + BusCBUSII, /* Corollary CBUS II */ + BusEISA, /* Extended ISA */ + BusFUTURE, /* IEEE Futurebus */ + BusINTERN, /* Internal bus */ + BusISA, /* Industry Standard Architecture */ + BusMBI, /* Multibus I */ + BusMBII, /* Multibus II */ + BusMCA, /* Micro Channel Architecture */ + BusMPI, /* MPI */ + BusMPSA, /* MPSA */ + BusNUBUS, /* Apple Macintosh NuBus */ + BusPCI, /* Peripheral Component Interconnect */ + BusPCMCIA, /* PC Memory Card International Association */ + BusTC, /* DEC TurboChannel */ + BusVL, /* VESA Local bus */ + BusVME, /* VMEbus */ + BusXPRESS, /* Express System Bus */ +}; + +#define MKBUS(t,b,d,f) (((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8)) +#define BUSFNO(tbdf) (((tbdf)>>8)&0x07) +#define BUSDNO(tbdf) (((tbdf)>>11)&0x1F) +#define BUSBNO(tbdf) (((tbdf)>>16)&0xFF) +#define BUSTYPE(tbdf) ((tbdf)>>24) +#define BUSBDF(tbdf) ((tbdf)&0x00FFFF00) +#define BUSUNKNOWN (-1) + enum { MaxEISA = 16, EISAconfig = 0xC80, }; /* - * PCI Local Bus support. - * Quick hack until we figure out how to - * deal with EISA, PCI, PCMCIA, PnP, etc. + * PCI support code. */ -enum { /* configuration mechanism #1 */ - PCIaddr = 0xCF8, /* CONFIG_ADDRESS */ - PCIdata = 0xCFC, /* CONFIG_DATA */ +enum { /* type 0 and type 1 pre-defined header */ + PciVID = 0x00, /* vendor ID */ + PciDID = 0x02, /* device ID */ + PciPCR = 0x04, /* command */ + PciPSR = 0x06, /* status */ + PciRID = 0x08, /* revision ID */ + PciCCRp = 0x09, /* programming interface class code */ + PciCCRu = 0x0A, /* sub-class code */ + PciCCRb = 0x0B, /* base class code */ + PciCLS = 0x0C, /* cache line size */ + PciLTR = 0x0D, /* latency timer */ + PciHDT = 0x0E, /* header type */ + PciBST = 0x0F, /* BIST */ - /* configuration mechanism #2 */ - PCIcse = 0xCF8, /* configuration space enable */ - PCIforward = 0xCFA, /* which bus */ - - MaxPCI = 32, /* 16 for mechanism #2 */ + PciBAR0 = 0x10, /* base address */ + PciBAR1 = 0x14, + + PciINTL = 0x3C, /* interrupt line */ + PciINTP = 0x3D, /* interrupt pin */ }; -typedef struct PCIcfg { +enum { /* type 0 pre-defined header */ + PciBAR2 = 0x18, + PciBAR3 = 0x1C, + PciBAR4 = 0x20, + PciBAR5 = 0x24, + PciCIS = 0x28, /* cardbus CIS pointer */ + PciSVID = 0x2C, /* subsystem vendor ID */ + PciSID = 0x2E, /* cardbus CIS pointer */ + PciEBAR0 = 0x30, /* expansion ROM base address */ + PciMGNT = 0x3E, /* burst period length */ + PciMLT = 0x3F, /* maximum latency between bursts */ +}; + +enum { /* type 1 pre-defined header */ + PciPBN = 0x18, /* primary bus number */ + PciSBN = 0x19, /* secondary bus number */ + PciUBN = 0x1A, /* subordinate bus number */ + PciSLTR = 0x1B, /* secondary latency timer */ + PciIBR = 0x1C, /* I/O base */ + PciILR = 0x1D, /* I/O limit */ + PciSPSR = 0x1E, /* secondary status */ + PciMBR = 0x20, /* memory base */ + PciMLR = 0x22, /* memory limit */ + PciPMBR = 0x24, /* prefetchable memory base */ + PciPMLR = 0x26, /* prefetchable memory limit */ + PciPUBR = 0x28, /* prefetchable base upper 32 bits */ + PciPULR = 0x2C, /* prefetchable limit upper 32 bits */ + PciIUBR = 0x30, /* I/O base upper 16 bits */ + PciIULR = 0x32, /* I/O limit upper 16 bits */ + PciEBAR1 = 0x28, /* expansion ROM base address */ + PciBCR = 0x3E, /* bridge control register */ +}; + +typedef struct Pcidev Pcidev; +typedef struct Pcidev { + int tbdf; /* type+bus+device+function */ ushort vid; /* vendor ID */ ushort did; /* device ID */ - ushort command; - ushort status; - uchar rid; /* revision ID */ - uchar loclass; /* specific register-level programming interface */ - uchar subclass; - uchar baseclass; - uchar clsize; /* cache line size */ - uchar latency; /* latency timer */ - uchar header; /* header type */ - uchar bist; /* built-in self-test */ - ulong baseaddr[6]; /* memory or I/O base address registers */ - ulong reserved28[2]; - ulong romaddr; /* expansion ROM base address */ - ulong reserved34[2]; - uchar irq; /* interrupt line */ - uchar irp; /* interrupt pin */ - uchar mingnt; /* burst period length */ - uchar maxlat; /* maximum latency between bursts */ -} PCIcfg; + ulong bar[2]; /* base address */ + uchar intl; /* interrupt line */ + + Pcidev* next; /* next device on this bno */ +} Pcidev; + +/* + * PCMCIA support code. + */ +/* + * Map between ISA memory space and PCMCIA card memory space. + */ +struct PCMmap { + ulong ca; /* card address */ + ulong cea; /* card end address */ + ulong isa; /* ISA address */ + int len; /* length of the ISA area */ + int attr; /* attribute memory */ + int ref; +}; diff --git a/pc/kbd.c b/pc/kbd.c index 2d95fc1647607c5aa5caafeaf3d069d1653cfb74..4405d7db3b75cbae20e9380083736f9a31614a2e 100644 --- a/pc/kbd.c +++ b/pc/kbd.c @@ -6,63 +6,46 @@ #include "io.h" #include "../port/error.h" -#include - enum { - Data= 0x60, /* data port */ - - Status= 0x64, /* status port */ - Inready= 0x01, /* input character ready */ - Outbusy= 0x02, /* output busy */ - Sysflag= 0x04, /* system flag */ - Cmddata= 0x08, /* cmd==0, data==1 */ - Inhibit= 0x10, /* keyboard/mouse inhibited */ - Minready= 0x20, /* mouse character ready */ - Rtimeout= 0x40, /* general timeout */ + Data= 0x60, /* data port */ + + Status= 0x64, /* status port */ + Inready= 0x01, /* input character ready */ + Outbusy= 0x02, /* output busy */ + Sysflag= 0x04, /* system flag */ + Cmddata= 0x08, /* cmd==0, data==1 */ + Inhibit= 0x10, /* keyboard/mouse inhibited */ + Minready= 0x20, /* mouse character ready */ + Rtimeout= 0x40, /* general timeout */ Parity= 0x80, - Cmd= 0x64, /* command port (write only) */ - - CTdata= 0x0, /* chips & Technologies ps2 data port */ - CTstatus= 0x1, /* chips & Technologies ps2 status port */ - Enable= 1<<7, - Clear= 1<<6, - Error= 1<<5, - Intenable= 1<<4, - Reset= 1<<3, - Tready= 1<<2, - Rready= 1<<1, - Idle= 1<<0, - - Spec= 0x80, - - PF= Spec|0x20, /* num pad function key */ - View= Spec|0x00, /* view (shift window up) */ - KF= Spec|0x40, /* function key */ - Shift= Spec|0x60, - Break= Spec|0x61, - Ctrl= Spec|0x62, - Latin= Spec|0x63, - Caps= Spec|0x64, - Num= Spec|0x65, - Middle= Spec|0x66, - No= 0x00, /* peter */ - - Home= KF|13, - Up= KF|14, - Pgup= KF|15, - Print= KF|16, - Left= View, - Right= View, - End= '\r', - Down= View, - Pgdown= View, - Ins= KF|20, - Del= 0x7F, - - Rbutton=4, - Mbutton=2, - Lbutton=1, + Cmd= 0x64, /* command port (write only) */ + + Spec= 0x80, + + PF= Spec|0x20, /* num pad function key */ + View= Spec|0x00, /* view (shift window up) */ + KF= Spec|0x40, /* function key */ + Shift= Spec|0x60, + Break= Spec|0x61, + Ctrl= Spec|0x62, + Latin= Spec|0x63, + Caps= Spec|0x64, + Num= Spec|0x65, + Middle= Spec|0x66, + No= 0x00, /* peter */ + + Home= KF|13, + Up= KF|14, + Pgup= KF|15, + Print= KF|16, + Left= View, + Right= View, + End= '\r', + Down= View, + Pgdown= View, + Ins= KF|20, + Del= 0x7F, }; uchar kbtab[] = @@ -113,22 +96,21 @@ uchar kbtabesc1[] = [0x58] No, No, No, No, No, No, No, No, }; -static int keybuttons; -static uchar ccc; -static int shift; -ulong ctport; - enum { /* controller command byte */ Cscs1= (1<<6), /* scan code set 1 */ - Cmousedis= (1<<5), /* mouse disable */ + Cauxdis= (1<<5), /* mouse disable */ Ckbddis= (1<<4), /* kbd disable */ Csf= (1<<2), /* system flag */ - Cmouseint= (1<<1), /* mouse interrupt enable */ + Cauxint= (1<<1), /* mouse interrupt enable */ Ckbdint= (1<<0), /* kbd interrupt enable */ }; +static Lock i8042lock; +static uchar ccc; +static void (*auxputc)(int, int); + /* * wait for output no longer busy */ @@ -161,52 +143,6 @@ inready(void) return 0; } -/* - * send a command to the mouse - */ -static int -mousecmd(int cmd) -{ - unsigned int c; - int tries; - - c = 0; - tries = 0; - do{ - if(tries++ > 2) - break; - if(outready() < 0) - break; - outb(Cmd, 0xD4); - if(outready() < 0) - break; - outb(Data, cmd); - if(outready() < 0) - break; - if(inready() < 0) - break; - c = inb(Data); - } while(c == 0xFE || c == 0); - if(c != 0xFA){ - print("mouse returns %2.2ux to the %2.2ux command\n", c, cmd); - return -1; - } - return 0; -} - -/* - * ask 8042 to enable the use of address bit 20 - */ -void -i8042a20(void) -{ - outready(); - outb(Cmd, 0xD1); - outready(); - outb(Data, 0xDF); - outready(); -} - /* * ask 8042 to reset the machine */ @@ -219,10 +155,10 @@ i8042reset(void) *s = 0x1234; /* BIOS warm-boot flag */ /* - * this works for dhog + * newer reset the machine command */ outready(); - outb(Cmd, 0xFE); /* pulse reset line (means resend on AT&T machines) */ + outb(Cmd, 0xFE); outready(); /* @@ -239,127 +175,37 @@ i8042reset(void) } } -/* - * setup a serial mouse - */ -static void -serialmouse(int port, char *type, int setspeed) +int +i8042auxcmd(int cmd) { - if(mousetype == Mouseserial) - error(Emouseset); - - if(port >= 3 || port < 0) - error(Ebadarg); - - /* set up /dev/eia0 as the mouse */ - if(setspeed) - setspeed = 1200; - if(type && *type == 'M') - ns16552special(port, setspeed, &mouseq, 0, m3mouseputc); - else - ns16552special(port, setspeed, &mouseq, 0, mouseputc); - mousetype = Mouseserial; -} - -/* - * ps/2 mouse message is three bytes - * - * byte 0 - 0 0 SDY SDX 1 M R L - * byte 1 - DX - * byte 2 - DY - * - * shift & left button is the same as middle button - */ -static int -ps2mouseputc(int c) -{ - static short msg[3]; - static int nb; - static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 }; - int buttons, dx, dy; - - /* - * check byte 0 for consistency - */ - if(nb==0 && (c&0xc8)!=0x08) - return 0; - - msg[nb] = c; - if(++nb == 3){ - nb = 0; - if(msg[0] & 0x10) - msg[1] |= 0xFF00; - if(msg[0] & 0x20) - msg[2] |= 0xFF00; - - buttons = b[(msg[0]&7) | (shift ? 8 : 0)] | keybuttons; - dx = msg[1]; - dy = -msg[2]; - mousetrack(buttons, dx, dy); - } - return 0; -} - -static void -ctps2intr(Ureg *ur, void *arg) -{ - uchar c; - - USED(ur, arg); - c = inb(ctport + CTstatus); - if(c & Error) - return; - if((c & Rready) == 0) - return; - c = inb(ctport + CTdata); - ps2mouseputc(c); -} - -static void nop(void){}; - -/* - * look for a chips & technologies 82c710 ps2 mouse on a TI travelmate - */ -static int -ct82c710(void) -{ - int c; - - /* on non-C&T 2fa and 3fa are input only ports */ - /* get chips attention */ - outb(0x2fa, 0x55); nop(); nop(); - outb(0x3fa, ~0x55); nop(); nop(); - outb(0x3fa, 0x36); nop(); nop(); + unsigned int c; + int tries; - /* tell it where its config register should be */ - outb(0x3fa, 0x390>>2); nop(); nop(); - outb(0x2fa, ~(0x390>>2)); nop(); nop(); + c = 0; + tries = 0; - /* see if this is really a 710 */ - outb(0x390, 0xf); nop(); nop(); - if(inb(0x391) != (0x390>>2)) - return -1; + ilock(&i8042lock); + do{ + if(tries++ > 2) + break; + if(outready() < 0) + break; + outb(Cmd, 0xD4); + if(outready() < 0) + break; + outb(Data, cmd); + if(outready() < 0) + break; + if(inready() < 0) + break; + c = inb(Data); + } while(c == 0xFE || c == 0); + iunlock(&i8042lock); - /* get data port address */ - outb(0x390, 0xd); nop(); nop(); - c = inb(0x391); - if(c == 0 || c == 0xff) + if(c != 0xFA){ + print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd); return -1; - ctport = c<<2; - - /* turn off config mode */ - outb(0x390, 0xf); nop(); nop(); - outb(0x391, 0xf); - - setvec(Mousevec, ctps2intr, 0); - - /* enable for interrupts */ - c = inb(ctport + CTstatus); - c &= ~(Clear|Reset); - c |= Enable|Intenable; - outb(ctport + CTstatus, c); - - mousetype = MousePS2; + } return 0; } @@ -367,38 +213,37 @@ ct82c710(void) * keyboard interrupt */ static void -kbdintr(Ureg *ur, void *arg) +i8042intr(Ureg*, void*) { int s, c, i; static int esc1, esc2; - static int caps; - static int ctl; - static int num; + static int alt, caps, ctl, num, shift; static int collecting, nk; - static int alt; static uchar kc[5]; int keyup; - USED(ur, arg); - /* * get status */ + lock(&i8042lock); s = inb(Status); - if(!(s&Inready)) + if(!(s&Inready)){ + unlock(&i8042lock); return; + } /* * get the character */ c = inb(Data); + unlock(&i8042lock); /* - * if it's the mouse... + * if it's the aux port... */ if(s & Minready){ - if(mousetype == MousePS2) - ps2mouseputc(c); + if(auxputc != nil) + auxputc(c, shift); return; } @@ -443,7 +288,7 @@ kbdintr(Ureg *ur, void *arg) alt = 0; break; case Shift: - mouseshifted = shift = 0; + shift = 0; break; case Ctrl: ctl = 0; @@ -486,7 +331,7 @@ kbdintr(Ureg *ur, void *arg) num ^= 1; return; case Shift: - mouseshifted = shift = 1; + shift = 1; return; case Latin: alt = 1; @@ -501,111 +346,32 @@ kbdintr(Ureg *ur, void *arg) kbdputc(kbdq, c); } -/* - * set up a ps2 mouse - */ -static void -ps2mouse(void) +void +i8042auxenable(void (*putc)(int, int)) { - int x; + char *err = "i8042: aux init failed\n"; - if(mousetype == MousePS2) - return; + /* enable kbd/aux xfers and interrupts */ + ccc &= ~Cauxdis; + ccc |= Cauxint; - if(ct82c710() == 0) - return; - - /* enable kbd/mouse xfers and interrupts */ - x = splhi(); - ccc &= ~Cmousedis; - ccc |= Cmouseint; + ilock(&i8042lock); if(outready() < 0) - print("mouse init failed\n"); - outb(Cmd, 0x60); + print(err); + outb(Cmd, 0x60); /* write control register */ if(outready() < 0) - print("mouse init failed\n"); + print(err); outb(Data, ccc); if(outready() < 0) - print("mouse init failed\n"); - outb(Cmd, 0xA8); + print(err); + outb(Cmd, 0xA8); /* auxilliary device enable */ if(outready() < 0){ - splx(x); + iunlock(&i8042lock); return; } - - /* make mouse streaming, enabled */ - setvec(Mousevec, kbdintr, 0); - mousecmd(0xEA); - mousecmd(0xF4); - splx(x); - - mousetype = MousePS2; -} - -/* - * set/change mouse configuration - */ -void -mousectl(char *arg) -{ - int n, x; - char *field[3]; - - n = parsefields(arg, field, 3, " "); - if(strncmp(field[0], "serial", 6) == 0){ - switch(n){ - case 1: - serialmouse(atoi(field[0]+6), 0, 1); - break; - case 2: - serialmouse(atoi(field[1]), 0, 0); - break; - case 3: - default: - serialmouse(atoi(field[1]), field[2], 0); - break; - } - } else if(strcmp(field[0], "ps2") == 0){ - ps2mouse(); - } else if(strcmp(field[0], "accelerated") == 0){ - switch(mousetype){ - case MousePS2: - x = splhi(); - mousecmd(0xE7); - splx(x); - break; - default: - mouseaccelerate(field[1]); - break; - } - } else if(strcmp(field[0], "linear") == 0){ - switch(mousetype){ - case MousePS2: - x = splhi(); - mousecmd(0xE6); - splx(x); - break; - default: - mouseaccelerate("0"); - break; - } - } else if(strcmp(field[0], "res") == 0){ - if(n < 2) - n = 1; - else - n = atoi(field[1]); - switch(mousetype){ - case MousePS2: - x = splhi(); - mousecmd(0xE8); - mousecmd(n); - splx(x); - break; - } - } else if(strcmp(field[0], "swap") == 0) - mouseswap ^= 1; - else - error(Ebadctl); + auxputc = putc; + intrenable(VectorAUX, i8042intr, 0, BUSUNKNOWN); + iunlock(&i8042lock); } void @@ -616,7 +382,7 @@ kbdinit(void) kbdq = qopen(4*1024, 0, 0, 0); qnoblock(kbdq, 1); - setvec(Kbdvec, kbdintr, 0); + intrenable(VectorKBD, i8042intr, 0, BUSUNKNOWN); /* wait for a quiescent controller */ while((c = inb(Status)) & (Outbusy | Inready)) @@ -634,7 +400,7 @@ kbdinit(void) /* enable kbd xfers and interrupts */ /* disable mouse */ ccc &= ~Ckbddis; - ccc |= Csf | Ckbdint | Cscs1 | Cmousedis; + ccc |= Csf | Ckbdint | Cscs1; if(outready() < 0) print("kbd init failed\n"); outb(Cmd, 0x60); diff --git a/pc/l.s b/pc/l.s index 9442c0ab9fe4245c26b83a552666d48daccdf72c..1384fa1cdc6993a968d783459bcf173e7d1ee1b2 100644 --- a/pc/l.s +++ b/pc/l.s @@ -1,824 +1,809 @@ #include "mem.h" -#define OP16 BYTE $0x66 -#define NOP XCHGL AX,AX +#define PADDR(a) ((a) & ~KZERO) +#define KADDR(a) (KZERO|(a)) /* - * We assume that b.com got us into 32 bit mode already. We are now - * running with a PC == origin & ~KZERO. + * Some machine instructions not handled by 8[al]. */ -TEXT origin(SB),$0 +#define OP16 BYTE $0x66 +#define DELAY BYTE $0xEB; BYTE $0x00 /* JMP .+2 */ +#define CPUID BYTE $0x0F; BYTE $0xA2 /* CPUID, argument in AX */ +#define WRMSR BYTE $0x0F; BYTE $0x30 /* WRMSR, argument in AX/DX (lo/hi) */ +#define RDMSR BYTE $0x0F; BYTE $0x32 /* RDMSR, result in AX/DX (lo/hi) */ +#define WBINVD BYTE $0x0F; BYTE $0x09 - CLI +/* + * Macros for calculating offsets within the page directory base + * and page tables. Note that these are assembler-specific hence + * the '<<2'. + */ +#define PDO(a) (((((a))>>22) & 0x03FF)<<2) +#define PTO(a) (((((a))>>12) & 0x03FF)<<2) - /* - * Clear BSS - */ - LEAL edata-KZERO(SB),SI - MOVL SI,DI - ADDL $4,DI - MOVL $0,AX - MOVL AX,(SI) - LEAL end-KZERO(SB),CX - SUBL DI,CX - SHRL $2,CX - CLD; REP; MOVSL - - /* - * make a bottom level page table page that maps the first - * 16 meg of physical memory - */ - LEAL tpt-KZERO(SB),AX /* get phys addr of temporary page table */ - ADDL $(BY2PG-1),AX /* must be page alligned */ - ANDL $(~(BY2PG-1)),AX /* ... */ - MOVL $(1024),CX /* pte's per page */ - MOVL $((((1024)-1)<>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX) - - /* - * point processor to top level page & turn on paging - */ - MOVL AX,CR3 - MOVL CR0,AX - ORL $0X80010000,AX /* PG=1, WP=1 */ - ANDL $~(0x40000000|0x20000000|0x8|0x2),AX /* CD=0, NW=0, TS=0, MP=0 */ - MOVL AX,CR0 - - /* - * use a jump to an absolute location to get the PC into - * KZERO. - */ - LEAL tokzero(SB),AX +/* + * Entered here from the bootstrap programme possibly via a jump to 0x00100020, so + * need to make another jump to set the correct virtual address. + * In protected mode with paging turned on, the first 4MB of physical memory mapped + * to KZERO and up. + */ +TEXT _start0x00100020(SB),$0 + CLI + MOVL $_start0x80100020(SB), AX JMP* AX -TEXT tokzero(SB),$0 - - /* - * stack and mach - */ - MOVL $mach0(SB),SP - MOVL SP,m(SB) - MOVL $0,0(SP) - ADDL $(MACHSIZE-4),SP /* start stack under machine struct */ - MOVL $0, up(SB) - - /* - * clear flags - */ - MOVL $0,AX - PUSHL AX - POPFL - - CALL main(SB) - -loop: - JMP loop - -GLOBL mach0+0(SB), $MACHSIZE -GLOBL up(SB), $4 -GLOBL m(SB), $4 -GLOBL tpt(SB), $(BY2PG*3) - /* - * gdt to get us to 32-bit/segmented/unpaged mode + * First check if the bootstrap programme left the first 4MB nicely mapped, otherwise + * make the basic page tables for processor 0. Four pages are needed for the basic set: + * a page directory, a page table for mapping the first 4MB of physical memory, a page + * table for mapping the Mach page, and a page for the Mach structure itself. + * The remaining PTEs will be allocated later when memory is sized. */ -TEXT tgdt(SB),$0 - - /* null descriptor */ - LONG $0 - LONG $0 +TEXT _start0x80100020(SB), $0 + MOVL CR3, AX /* check the page directory base */ + CMPL AX, $PADDR(CPU0PDB) + JEQ _clearbss - /* data segment descriptor for 4 gigabytes (PL 0) */ - LONG $(0xFFFF) - LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW) + MOVL $CPU0PDB, DI /* clear 4 pages for the tables etc. */ + XORL AX, AX + MOVL $(4*BY2PG), CX + SHRL $2, CX - /* exec segment descriptor for 4 gigabytes (PL 0) */ - LONG $(0xFFFF) - LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) + CLD + REP; STOSL + + MOVL $CPU0PDB, AX + ADDL $PDO(KZERO), AX /* page directory offset for KZERO */ + MOVL $PADDR(CPU0PTE), (AX) /* PTE's for 0x80000000 */ + MOVL $(PTEWRITE|PTEVALID), BX /* page permissions */ + ORL BX, (AX) + + MOVL $CPU0PTE, AX /* first page of page table */ + MOVL $1024, CX /* 1024 pages in 4MB */ +_setpte: + MOVL BX, (AX) + ADDL $(1<machno */ - MOVL p+0(FP),DX - MOVL a+4(FP),DI - MOVL c+8(FP),CX - CLD; REP; INSB - RET + ADDL $(MACHSIZE-4), SP /* initialise stack */ /* - * output a byte + * Need to do one final thing to ensure a clean machine enviroment, + * clear the EFLAGS register, which can only be done once there is a stack. */ -TEXT outb(SB),$0 + MOVL $0, AX + PUSHL AX + POPFL - MOVL p+0(FP),DX - MOVL b+4(FP),AX - OUTB - RET + CALL main(SB) /* - * output a string of bytes to a port + * Park a processor. Should never fall through a return from main to here, + * should only be called by application processors when shutting down. */ -TEXT outsb(SB),$0 - - MOVL p+0(FP),DX - MOVL a+4(FP),SI - MOVL c+8(FP),CX - CLD; REP; OUTSB - RET +TEXT idle(SB), $0 +_idle: + HLT + JMP _idle /* - * input a short from a port + * Port I/O. + * in[bsl] input a byte|short|long + * ins[bsl] input a string of bytes|shorts|longs + * out[bsl] output a byte|short|long + * outs[bsl] output a string of bytes|shorts|longs */ -TEXT ins(SB), $0 - - MOVL p+0(FP), DX +TEXT inb(SB), $0 + MOVL port+0(FP), DX XORL AX, AX - OP16; INL + INB RET -/* - * input a string of shorts from a port - */ -TEXT inss(SB),$0 +TEXT insb(SB), $0 + MOVL port+0(FP), DX + MOVL address+4(FP), DI + MOVL count+8(FP), CX + CLD + REP; INSB + RET - MOVL p+0(FP),DX - MOVL a+4(FP),DI - MOVL c+8(FP),CX - CLD; REP; OP16; INSL +TEXT ins(SB), $0 + MOVL port+0(FP), DX + XORL AX, AX + OP16; INL RET -/* - * input a long from a port - */ -TEXT inl(SB), $0 +TEXT inss(SB), $0 + MOVL port+0(FP), DX + MOVL address+4(FP), DI + MOVL count+8(FP), CX + CLD + REP; OP16; INSL + RET - MOVL p+0(FP), DX +TEXT inl(SB), $0 + MOVL port+0(FP), DX INL RET -/* - * input a string of longs from a port - */ -TEXT insl(SB),$0 - - MOVL p+0(FP),DX - MOVL a+4(FP),DI - MOVL c+8(FP),CX - CLD; REP; INSL +TEXT insl(SB), $0 + MOVL port+0(FP), DX + MOVL address+4(FP), DI + MOVL count+8(FP), CX + CLD + REP; INSL RET -/* - * output a short to a port - */ -TEXT outs(SB), $0 +TEXT outb(SB), $0 + MOVL port+0(FP), DX + MOVL byte+4(FP), AX + OUTB + RET - MOVL p+0(FP), DX - MOVL s+4(FP), AX - OP16; OUTL +TEXT outsb(SB),$0 + MOVL port+0(FP), DX + MOVL address+4(FP), SI + MOVL count+8(FP), CX + CLD + REP; OUTSB RET -/* - * output a string of shorts to a port - */ -TEXT outss(SB),$0 +TEXT outs(SB), $0 + MOVL port+0(FP), DX + MOVL short+4(FP), AX + OP16; OUTL + RET - MOVL p+0(FP),DX - MOVL a+4(FP),SI - MOVL c+8(FP),CX - CLD; REP; OP16; OUTSL +TEXT outss(SB), $0 + MOVL port+0(FP), DX + MOVL address+4(FP), SI + MOVL count+8(FP), CX + CLD + REP; OP16; OUTSL RET -/* - * output a long to a port - */ -TEXT outl(SB), $0 - MOVL p+0(FP), DX - MOVL s+4(FP), AX +TEXT outl(SB), $0 + MOVL port+0(FP), DX + MOVL long+4(FP), AX OUTL RET +TEXT outsl(SB), $0 + MOVL port+0(FP), DX + MOVL address+4(FP), SI + MOVL count+8(FP), CX + CLD + REP; OUTSL + RET + /* - * output a string of longs to a port + * Read/write various system registers. + * CR4 and the 'model specific registers' should only be read/written + * after it has been determined the processor supports them */ -TEXT outsl(SB),$0 +TEXT lgdt(SB), $0 /* GDTR - global descriptor table */ + MOVL gdtptr+0(FP), AX + MOVL (AX), GDTR + RET - MOVL p+0(FP),DX - MOVL a+4(FP),SI - MOVL c+8(FP),CX - CLD; REP; OUTSL +TEXT lidt(SB), $0 /* IDTR - interrupt descriptor table */ + MOVL idtptr+0(FP), AX + MOVL (AX), IDTR RET -/* - * test and set - */ -TEXT tas(SB),$0 - MOVL $0xdeadead,AX - MOVL l+0(FP),BX - XCHGL AX,(BX) +TEXT ltr(SB), $0 /* TR - task register */ + MOVL tptr+0(FP), AX + MOVW AX, TASK RET -/* - * xchgw(v, *p) short for the avanstar stargate driver - */ -TEXT xchgw(SB),$0 - MOVL v+4(FP),AX - MOVL p+0(FP),BX - XCHGW AX,(BX) +TEXT getcr0(SB), $0 /* CR0 - processor control */ + MOVL CR0, AX RET -/* - * routines to load/read various system registers - */ -GLOBL idtptr(SB),$6 -TEXT putidt(SB),$0 /* interrupt descriptor table */ - MOVL t+0(FP),AX - MOVL AX,idtptr+2(SB) - MOVL l+4(FP),AX - MOVW AX,idtptr(SB) - MOVL idtptr(SB),IDTR +TEXT getcr2(SB), $0 /* CR2 - page fault linear address */ + MOVL CR2, AX RET -GLOBL gdtptr(SB),$6 -TEXT putgdt(SB),$0 /* global descriptor table */ - MOVL t+0(FP),AX - MOVL AX,gdtptr+2(SB) - MOVL l+4(FP),AX - MOVW AX,gdtptr(SB) - MOVL gdtptr(SB),GDTR +TEXT getcr3(SB), $0 /* CR3 - page directory base */ + MOVL CR3, AX RET -TEXT putcr3(SB),$0 /* top level page table pointer */ - MOVL t+0(FP),AX - MOVL AX,CR3 +TEXT putcr3(SB), $0 + MOVL cr3+0(FP), AX + MOVL AX, CR3 RET -TEXT puttr(SB),$0 /* task register */ - MOVL t+0(FP),AX - MOVW AX,TASK +TEXT getcr4(SB), $0 /* CR4 - extensions */ + MOVL CR4, AX RET -TEXT getcr0(SB),$0 /* coprocessor bits */ - MOVL CR0,AX +TEXT putcr4(SB), $0 + MOVL cr4+0(FP), AX + MOVL AX, CR4 RET -TEXT getcr2(SB),$0 /* fault address */ - MOVL CR2,AX +TEXT rdmsr(SB), $0 /* model-specific register */ + MOVL index+0(FP), CX + RDMSR + MOVL hi+4(FP), CX + MOVL DX, (CX) + MOVL lo+8(FP), CX + MOVL AX, (CX) + RET + +TEXT wrmsr(SB), $0 + MOVL index+0(FP), CX + MOVL hi+4(FP), DX + MOVL lo+8(FP), AX + WRMSR RET -TEXT getcr3(SB),$0 /* page directory base */ - MOVL CR3,AX +TEXT wbinvd(SB), $0 + WBINVD + RET + +/* + * Try to determine the CPU type which requires fiddling with EFLAGS. + * If the Id bit can be toggled then the CPUID instruciton can be used + * to determine CPU identity and features. First have to check if it's + * a 386 (Ac bit can't be set). If it's not a 386 and the Id bit can't be + * toggled then it's an older 486 of some kind. + * + * cpuid(id[], &ax, &dx); + */ +TEXT cpuid(SB), $0 + MOVL $0x240000, AX + PUSHL AX + POPFL /* set Id|Ac */ + + PUSHFL + POPL BX /* retrieve value */ + + MOVL $0, AX + PUSHL AX + POPFL /* clear Id|Ac, EFLAGS initialised */ + + PUSHFL + POPL AX /* retrieve value */ + XORL BX, AX + TESTL $0x040000, AX /* Ac */ + JZ _cpu386 /* can't set this bit on 386 */ + TESTL $0x200000, AX /* Id */ + JZ _cpu486 /* can't toggle this bit on some 486 */ + + MOVL $0, AX + CPUID + MOVL id+0(FP), BP + MOVL BX, 0(BP) /* "Genu" "Auth" "Cyri" */ + MOVL DX, 4(BP) /* "ineI" "enti" "xIns" */ + MOVL CX, 8(BP) /* "ntel" "cAMD" "tead" */ + + MOVL $1, AX + CPUID + JMP _cpuid + +_cpu486: + MOVL $0x400, AX + MOVL $0, DX + JMP _cpuid + +_cpu386: + MOVL $0x300, AX + MOVL $0, DX + +_cpuid: + MOVL ax+4(FP), BP + MOVL AX, 0(BP) + MOVL dx+8(FP), BP + MOVL DX, 0(BP) + RET + +/* + * Basic timing loop to determine CPU frequency. + */ +TEXT aamloop(SB), $0 + MOVL count+0(FP), CX +_aamloop: + AAM + LOOP _aamloop RET -#define FPOFF\ - WAIT;\ - MOVL CR0,AX;\ - ORL $0x24,AX /* EM=1, NE=1 */;\ - MOVL AX,CR0 +/* + * Floating point. + */ +#define FPOFF ;\ + WAIT ;\ + MOVL CR0, AX ;\ + ORL $0x24, AX /* EM=1, NE=1 */ ;\ + MOVL AX, CR0 -#define FPON\ - MOVL CR0,AX;\ - ANDL $~0x4,AX /* EM=0 */;\ - MOVL AX,CR0 +#define FPON ;\ + MOVL CR0, AX ;\ + ANDL $~0x4, AX /* EM=0 */ ;\ + MOVL AX, CR0 -TEXT fpoff(SB),$0 /* turn off floating point */ +TEXT fpoff(SB), $0 /* disable */ FPOFF RET -TEXT fpinit(SB),$0 /* turn on & init the floating point */ +TEXT fpinit(SB), $0 /* enable and init */ FPON FINIT WAIT PUSHW $0x033E - FLDCW 0(SP) /* ignore underflow/precision, signal others */ + FLDCW 0(SP) /* ignore underflow/precision, signal others */ POPW AX WAIT RET -TEXT fpsave(SB),$0 /* save floating point state and turn off */ - MOVL p+0(FP),AX +TEXT fpsave(SB), $0 /* save state and disable */ + MOVL p+0(FP), AX WAIT FSAVE 0(AX) FPOFF RET -TEXT fprestore(SB),$0 /* turn on floating point and restore regs */ +TEXT fprestore(SB), $0 /* enable and restore state */ FPON - MOVL p+0(FP),AX + MOVL p+0(FP), AX FRSTOR 0(AX) WAIT RET -TEXT fpstatus(SB),$0 /* get floating point status */ +TEXT fpstatus(SB), $0 /* get floating point status */ FSTSW AX RET -TEXT fpenv(SB),$0 /* save floating point environment without waiting */ - MOVL p+0(FP),AX +TEXT fpenv(SB), $0 /* save state without waiting */ + MOVL p+0(FP), AX FSTENV 0(AX) RET /* - * special traps - */ -TEXT intr0(SB),$0 - PUSHL $0 - PUSHL $0 - JMP intrcommon -TEXT intr1(SB),$0 - PUSHL $0 - PUSHL $1 - JMP intrcommon -TEXT intr2(SB),$0 - PUSHL $0 - PUSHL $2 - JMP intrcommon -TEXT intr3(SB),$0 - PUSHL $0 - PUSHL $3 - JMP intrcommon -TEXT intr4(SB),$0 - PUSHL $0 - PUSHL $4 - JMP intrcommon -TEXT intr5(SB),$0 - PUSHL $0 - PUSHL $5 - JMP intrcommon -TEXT intr6(SB),$0 - PUSHL $0 - PUSHL $6 - JMP intrcommon -TEXT intr7(SB),$0 - PUSHL $0 - PUSHL $7 - JMP intrcommon -TEXT intr8(SB),$0 - PUSHL $8 - JMP intrscommon -TEXT intr9(SB),$0 - PUSHL $0 - PUSHL $9 - JMP intrcommon -TEXT intr10(SB),$0 - PUSHL $10 - JMP intrscommon -TEXT intr11(SB),$0 - PUSHL $11 - JMP intrscommon -TEXT intr12(SB),$0 - PUSHL $12 - JMP intrscommon -TEXT intr13(SB),$0 - PUSHL $13 - JMP intrscommon -TEXT intr14(SB),$0 - PUSHL $14 - JMP intrscommon -TEXT intr15(SB),$0 - PUSHL $0 - PUSHL $15 - JMP intrcommon -TEXT intr16(SB),$0 - PUSHL $0 - PUSHL $16 - JMP intrcommon -TEXT intr17(SB),$0 - PUSHL $17 - JMP intrscommon -TEXT intr18(SB),$0 - PUSHL $16 - JMP intrscommon -TEXT intr24(SB),$0 - PUSHL $0 - PUSHL $24 - JMP intrcommon -TEXT intr25(SB),$0 - PUSHL $0 - PUSHL $25 - JMP intrcommon -TEXT intr26(SB),$0 - PUSHL $0 - PUSHL $26 - JMP intrcommon -TEXT intr27(SB),$0 - PUSHL $0 - PUSHL $27 - JMP intrcommon -TEXT intr28(SB),$0 - PUSHL $0 - PUSHL $28 - JMP intrcommon -TEXT intr29(SB),$0 - PUSHL $0 - PUSHL $29 - JMP intrcommon -TEXT intr30(SB),$0 - PUSHL $0 - PUSHL $30 - JMP intrcommon -TEXT intr31(SB),$0 - PUSHL $0 - PUSHL $31 - JMP intrcommon -TEXT intr32(SB),$0 - PUSHL $0 - PUSHL $32 - JMP intrcommon -TEXT intr33(SB),$0 - PUSHL $0 - PUSHL $33 - JMP intrcommon -TEXT intr34(SB),$0 - PUSHL $0 - PUSHL $34 - JMP intrcommon -TEXT intr35(SB),$0 - PUSHL $0 - PUSHL $35 - JMP intrcommon -TEXT intr36(SB),$0 - PUSHL $0 - PUSHL $36 - JMP intrcommon -TEXT intr37(SB),$0 - PUSHL $0 - PUSHL $37 - JMP intrcommon -TEXT intr38(SB),$0 - PUSHL $0 - PUSHL $38 - JMP intrcommon -TEXT intr39(SB),$0 - PUSHL $0 - PUSHL $39 - JMP intrcommon -TEXT intr64(SB),$0 - PUSHL $0 - PUSHL $64 - JMP intrcommon -TEXT intrbad(SB),$0 - PUSHL $0 - PUSHL $0x1ff - JMP intrcommon - -intrcommon: - PUSHL DS - PUSHL ES - PUSHL FS - PUSHL GS - PUSHAL - MOVL $(KDSEL),AX - MOVW AX,DS - MOVW AX,ES - LEAL 0(SP),AX - PUSHL AX - CALL trap(SB) - POPL AX - POPAL - NOP - POPL GS - POPL FS - POPL ES - POPL DS - NOP - ADDL $8,SP /* error code and trap type */ - IRETL - -TEXT forkret(SB), $0 - POPL AX - POPAL - NOP - POPL GS - POPL FS - POPL ES - POPL DS - NOP - ADDL $8,SP /* error code and trap type */ - IRETL - -intrscommon: - PUSHL DS - PUSHL ES - PUSHL FS - PUSHL GS - PUSHAL - MOVL $(KDSEL),AX - MOVW AX,DS - MOVW AX,ES - LEAL 0(SP),AX - PUSHL AX - CALL trap(SB) - POPL AX - POPAL - NOP - POPL GS - POPL FS - POPL ES - POPL DS - NOP - ADDL $8,SP /* error code and trap type */ - IRETL - -/* - * interrupt level is interrupts on or off */ -TEXT splhi(SB),$0 - MOVL m(SB), AX /* save PC in m->splpc */ +TEXT splhi(SB), $0 + MOVL $(MACHADDR+0x04), AX /* save PC in m->splpc */ MOVL (SP), BX - MOVL BX, 4(AX) + MOVL BX, (AX) PUSHFL POPL AX CLI RET -TEXT splx(SB),$0 - MOVL m(SB), AX /* save PC in m->splpc */ +TEXT splx(SB), $0 + MOVL $(MACHADDR+0x04), AX /* save PC in m->splpc */ MOVL (SP), BX - MOVL BX, 4(AX) + MOVL BX, (AX) - MOVL s+0(FP),AX + MOVL s+0(FP), AX PUSHL AX POPFL RET -TEXT spllo(SB),$0 +TEXT spllo(SB), $0 PUSHFL POPL AX STI -TEXT spldone(SB), $0 RET -TEXT getstatus(SB),$0 - PUSHFL - POPL AX +TEXT spldone(SB), $0 RET -/* - * return cpu type (586 == pentium or better) - */ -TEXT x86cpuid(SB),$0 - - PUSHFL - MOVL 0(SP),AX - XORL $0x240000,AX - PUSHL AX - POPFL +TEXT islo(SB), $0 PUSHFL - MOVL 0(SP),AX - XORL 4(SP),AX - MOVL AX, BX - ANDL $0x40000,BX /* on 386 we can't change this bit */ - JZ is386 - ANDL $0x200000,AX /* if we can't change this, there's no CPUID */ - JZ is486 - MOVL $1,AX - /* CPUID */ - BYTE $0x0F - BYTE $0xA2 - JMP done -is486: - MOVL $(4<<8),AX - MOVL $0,DX - JMP done -is386: - MOVL $(3<<8),AX - MOVL $0,DX -done: - MOVL a+0(FP),CX - MOVL AX,0(CX) - MOVL d+4(FP),CX - MOVL DX,0(CX) - POPFL - POPL BX + POPL AX + ANDL $0x200, AX /* interrupt enable flag */ RET /* - * basic timing loop to determine CPU frequency + * Test-And-Set */ -TEXT aamloop(SB),$0 - - MOVL c+0(FP),CX -aaml1: - AAM - LOOP aaml1 +TEXT tas(SB), $0 + MOVL $0xDEADDEAD, AX + MOVL lock+0(FP), BX + XCHGL AX, (BX) /* lock->key */ RET -/* - * label consists of a stack pointer and a PC - */ -TEXT gotolabel(SB),$0 - MOVL l+0(FP),AX - MOVL 0(AX),SP /* restore sp */ - MOVL 4(AX),AX /* put return pc on the stack */ - MOVL AX,0(SP) - MOVL $1,AX /* return 1 */ +TEXT wbflush(SB), $0 + CPUID RET -TEXT setlabel(SB),$0 - MOVL l+0(FP),AX - MOVL SP,0(AX) /* store sp */ - MOVL 0(SP),BX /* store return pc */ - MOVL BX,4(AX) - MOVL $0,AX /* return 0 */ +TEXT xchgw(SB), $0 + MOVL v+4(FP), AX + MOVL p+0(FP), BX + XCHGW AX, (BX) RET /* - * Used to get to the first process. - * Set up an interrupt return frame and IRET to user level. - */ -TEXT touser(SB),$0 - PUSHL $(UDSEL) /* old ss */ - MOVL sp+0(FP),AX /* old sp */ - PUSHL AX - PUSHFL /* old flags */ - PUSHL $(UESEL) /* old cs */ - PUSHL $(UTZERO+32) /* old pc */ - MOVL $(UDSEL),AX - MOVW AX,DS - MOVW AX,ES - MOVW AX,GS - MOVW AX,FS - IRETL - -/* - * set configuration register - */ -TEXT config(SB),$0 - MOVL l+0(FP),AX - MOVL $0x3F3,DX - OUTB - OUTB +TEXT xchgl(SB), $0 + MOVL v+4(FP), AX + MOVL p+0(FP), BX + XCHGL AX, (BX) RET - -#define SRX 0x3C4 /* index to sequence registers */ -#define SR 0x3C5 /* sequence registers */ -#define Smmask 0x02 /* map mask */ + */ /* - * The DP8390 ethernet chip needs some time between - * successive chip selects, so we force a jump into - * the instruction stream to break the pipeline. + * label consists of a stack pointer and a PC */ -TEXT slowinb(SB), $0 - MOVL p+0(FP),DX - XORL AX,AX /* CF = 0 */ - INB - - JCC _slowinb0 /* always true */ - MOVL AX,AX - -_slowinb0: +TEXT gotolabel(SB), $0 + MOVL label+0(FP), AX + MOVL 0(AX), SP /* restore sp */ + MOVL 4(AX), AX /* put return pc on the stack */ + MOVL AX, 0(SP) + MOVL $1, AX /* return 1 */ RET -TEXT slowoutb(SB), $0 - MOVL p+0(FP),DX - MOVL b+4(FP),AX - OUTB - - CLC /* CF = 0 */ - JCC _slowoutb0 /* always true */ - MOVL AX,AX - -_slowoutb0: +TEXT setlabel(SB), $0 + MOVL label+0(FP), AX + MOVL SP, 0(AX) /* store sp */ + MOVL 0(SP), BX /* store return pc */ + MOVL BX, 4(AX) + MOVL $0, AX /* return 0 */ RET /* - * dsp outb string called from devdsp.c + * Interrupt/exception handling. + * Each entry in the vector table calls either strayintr or strayintrx depending + * on whether an error code has beemn automatically pushed onto the stack + * (strayintrx) or not, in which case a dummy entry must be pushed before retrieving + * the trap type from the vector table entry and placing it on the stack as part + * of the Ureg structure. + * The size of each entry in the vector table (6 bytes) is known in trapinit(). */ - TEXT dspoutb+0(SB), $0 - - MOVL a+4(FP), BX - MOVL n+8(FP), CX - - MOVL base+0(FP), DX - ADDL $2, DX /* Pcontrol */ - - MOVL c2+12(FP), DI - MOVL c3+16(FP), SI - -dsploop: - MOVL DI, AX /* normal */ - OUTB - - SUBL $1, CX - CMPL CX, $0 - JLT dspout - - SUBL $2, DX /* Pdata */ - MOVB (BX), AX - ADDL $1, BX - OUTB - - ADDL $2, DX /* Pcontrol */ - MOVL SI, AX /* strobe */ - OUTB - - JMP dsploop - -dspout: - RET +TEXT strayintr(SB), $0 + PUSHL AX /* save AX */ + MOVL 4(SP), AX /* return PC from vectortable(SB) */ + MOVBLZX (AX), AX /* trap type */ + XCHGL AX, (SP) /* restore AX and put the type on the stack */ + JMP intrcommon +TEXT strayintrx(SB), $0 + XCHGL AX, (SP) /* exchange AX with pointer to trap type */ + MOVBLZX (AX), AX /* trap type -> AX */ + XCHGL AX, (SP) /* exchange trap type with AX */ - TEXT damove(SB), $0 +intrcommon: + PUSHL DS + PUSHL ES + PUSHL FS + PUSHL GS + PUSHAL + MOVL $(KDSEL),AX + MOVW AX, DS + MOVW AX, ES + PUSHL SP + CALL trap(SB) - MOVL p1+0(FP), DI - MOVL p2+4(FP), SI - MOVL n+8(FP), BX - CLD -/* - * less than a word, just copy bytes - */ - CMPL BX, $4 - JLS bybyte -/* - * copy bytes till dest is word alligned - */ - MOVL DI, DX - ANDL $3, DX - JEQ byword - MOVL $4, CX - SUBL DX, CX - SUBL CX, BX - REP; MOVSB -/* - * copy whole longs - */ -byword: - MOVL BX, CX - SHRL $2, CX - REP; MOVSL -/* - * copy the rest, by bytes - */ - ANDL $3, BX -bybyte: - MOVL BX, CX - REP; MOVSB - RET +TEXT forkret(SB), $0 + POPL AX + POPAL + POPL GS + POPL FS + POPL ES + POPL DS + ADDL $8, SP /* pop error code and trap type */ + IRETL -/* - * Fiber block copy routines - */ -TEXT fwblock(SB),$0 - MOVL p+0(FP),DX - MOVL a+4(FP),SI - MOVL $128,CX - CLD; REP; OUTSL - - MOVL a+4(FP),DX - MOVL $128,CX - MOVL csum+8(FP), AX -wcsum: - XORL 0(DX), AX - ADDL $4,DX - LOOP wcsum - RET - -TEXT frblock(SB),$0 - MOVL p+0(FP),DX - MOVL a+4(FP),DI - MOVL $128,CX - CLD; REP; INSL - - MOVL a+4(FP),DX - MOVL $128,CX - MOVL csum+8(FP), AX -rcsum: - XORL 0(DX), AX - ADDL $4,DX - LOOP rcsum - RET +TEXT vectortable(SB), $0 + CALL strayintr(SB); BYTE $0x00 /* divide error */ + CALL strayintr(SB); BYTE $0x01 /* debug exception */ + CALL strayintr(SB); BYTE $0x02 /* NMI interrupt */ + CALL strayintr(SB); BYTE $0x03 /* breakpoint */ + CALL strayintr(SB); BYTE $0x04 /* overflow */ + CALL strayintr(SB); BYTE $0x05 /* bound */ + CALL strayintr(SB); BYTE $0x06 /* invalid opcode */ + CALL strayintr(SB); BYTE $0x07 /* no coprocessor available */ + CALL strayintrx(SB); BYTE $0x08 /* double fault */ + CALL strayintr(SB); BYTE $0x09 /* coprocessor segment overflow */ + CALL strayintrx(SB); BYTE $0x0A /* invalid TSS */ + CALL strayintrx(SB); BYTE $0x0B /* segment not available */ + CALL strayintrx(SB); BYTE $0x0C /* stack exception */ + CALL strayintrx(SB); BYTE $0x0D /* general protection error */ + CALL strayintrx(SB); BYTE $0x0E /* page fault */ + CALL strayintr(SB); BYTE $0x0F /* */ + CALL strayintr(SB); BYTE $0x10 /* coprocessor error */ + CALL strayintrx(SB); BYTE $0x11 /* alignment check */ + CALL strayintr(SB); BYTE $0x12 /* machine check */ + CALL strayintr(SB); BYTE $0x13 + CALL strayintr(SB); BYTE $0x14 + CALL strayintr(SB); BYTE $0x15 + CALL strayintr(SB); BYTE $0x16 + CALL strayintr(SB); BYTE $0x17 + CALL strayintr(SB); BYTE $0x18 + CALL strayintr(SB); BYTE $0x19 + CALL strayintr(SB); BYTE $0x1A + CALL strayintr(SB); BYTE $0x1B + CALL strayintr(SB); BYTE $0x1C + CALL strayintr(SB); BYTE $0x1D + CALL strayintr(SB); BYTE $0x1E + CALL strayintr(SB); BYTE $0x1F + CALL strayintr(SB); BYTE $0x20 /* VectorLAPIC */ + CALL strayintr(SB); BYTE $0x21 + CALL strayintr(SB); BYTE $0x22 + CALL strayintr(SB); BYTE $0x23 + CALL strayintr(SB); BYTE $0x24 + CALL strayintr(SB); BYTE $0x25 + CALL strayintr(SB); BYTE $0x26 + CALL strayintr(SB); BYTE $0x27 + CALL strayintr(SB); BYTE $0x28 + CALL strayintr(SB); BYTE $0x29 + CALL strayintr(SB); BYTE $0x2A + CALL strayintr(SB); BYTE $0x2B + CALL strayintr(SB); BYTE $0x2C + CALL strayintr(SB); BYTE $0x2D + CALL strayintr(SB); BYTE $0x2E + CALL strayintr(SB); BYTE $0x2F + CALL strayintr(SB); BYTE $0x30 + CALL strayintr(SB); BYTE $0x31 + CALL strayintr(SB); BYTE $0x32 + CALL strayintr(SB); BYTE $0x33 + CALL strayintr(SB); BYTE $0x34 + CALL strayintr(SB); BYTE $0x35 + CALL strayintr(SB); BYTE $0x36 + CALL strayintr(SB); BYTE $0x37 + CALL strayintr(SB); BYTE $0x38 + CALL strayintr(SB); BYTE $0x39 + CALL strayintr(SB); BYTE $0x3A + CALL strayintr(SB); BYTE $0x3B + CALL strayintr(SB); BYTE $0x3C + CALL strayintr(SB); BYTE $0x3D + CALL strayintr(SB); BYTE $0x3E + CALL strayintr(SB); BYTE $0x3F + CALL strayintr(SB); BYTE $0x40 /* VectorSYSCALL */ + CALL strayintr(SB); BYTE $0x41 + CALL strayintr(SB); BYTE $0x42 + CALL strayintr(SB); BYTE $0x43 + CALL strayintr(SB); BYTE $0x44 + CALL strayintr(SB); BYTE $0x45 + CALL strayintr(SB); BYTE $0x46 + CALL strayintr(SB); BYTE $0x47 + CALL strayintr(SB); BYTE $0x48 + CALL strayintr(SB); BYTE $0x49 + CALL strayintr(SB); BYTE $0x4A + CALL strayintr(SB); BYTE $0x4B + CALL strayintr(SB); BYTE $0x4C + CALL strayintr(SB); BYTE $0x4D + CALL strayintr(SB); BYTE $0x4E + CALL strayintr(SB); BYTE $0x4F + CALL strayintr(SB); BYTE $0x50 + CALL strayintr(SB); BYTE $0x51 + CALL strayintr(SB); BYTE $0x52 + CALL strayintr(SB); BYTE $0x53 + CALL strayintr(SB); BYTE $0x54 + CALL strayintr(SB); BYTE $0x55 + CALL strayintr(SB); BYTE $0x56 + CALL strayintr(SB); BYTE $0x57 + CALL strayintr(SB); BYTE $0x58 + CALL strayintr(SB); BYTE $0x59 + CALL strayintr(SB); BYTE $0x5A + CALL strayintr(SB); BYTE $0x5B + CALL strayintr(SB); BYTE $0x5C + CALL strayintr(SB); BYTE $0x5D + CALL strayintr(SB); BYTE $0x5E + CALL strayintr(SB); BYTE $0x5F + CALL strayintr(SB); BYTE $0x60 + CALL strayintr(SB); BYTE $0x61 + CALL strayintr(SB); BYTE $0x62 + CALL strayintr(SB); BYTE $0x63 + CALL strayintr(SB); BYTE $0x64 + CALL strayintr(SB); BYTE $0x65 + CALL strayintr(SB); BYTE $0x66 + CALL strayintr(SB); BYTE $0x67 + CALL strayintr(SB); BYTE $0x68 + CALL strayintr(SB); BYTE $0x69 + CALL strayintr(SB); BYTE $0x6A + CALL strayintr(SB); BYTE $0x6B + CALL strayintr(SB); BYTE $0x6C + CALL strayintr(SB); BYTE $0x6D + CALL strayintr(SB); BYTE $0x6E + CALL strayintr(SB); BYTE $0x6F + CALL strayintr(SB); BYTE $0x70 + CALL strayintr(SB); BYTE $0x71 + CALL strayintr(SB); BYTE $0x72 + CALL strayintr(SB); BYTE $0x73 + CALL strayintr(SB); BYTE $0x74 + CALL strayintr(SB); BYTE $0x75 + CALL strayintr(SB); BYTE $0x76 + CALL strayintr(SB); BYTE $0x77 + CALL strayintr(SB); BYTE $0x78 + CALL strayintr(SB); BYTE $0x79 + CALL strayintr(SB); BYTE $0x7A + CALL strayintr(SB); BYTE $0x7B + CALL strayintr(SB); BYTE $0x7C + CALL strayintr(SB); BYTE $0x7D + CALL strayintr(SB); BYTE $0x7E + CALL strayintr(SB); BYTE $0x7F + CALL strayintr(SB); BYTE $0x80 /* Vector[A]PIC */ + CALL strayintr(SB); BYTE $0x81 + CALL strayintr(SB); BYTE $0x82 + CALL strayintr(SB); BYTE $0x83 + CALL strayintr(SB); BYTE $0x84 + CALL strayintr(SB); BYTE $0x85 + CALL strayintr(SB); BYTE $0x86 + CALL strayintr(SB); BYTE $0x87 + CALL strayintr(SB); BYTE $0x88 + CALL strayintr(SB); BYTE $0x89 + CALL strayintr(SB); BYTE $0x8A + CALL strayintr(SB); BYTE $0x8B + CALL strayintr(SB); BYTE $0x8C + CALL strayintr(SB); BYTE $0x8D + CALL strayintr(SB); BYTE $0x8E + CALL strayintr(SB); BYTE $0x8F + CALL strayintr(SB); BYTE $0x90 + CALL strayintr(SB); BYTE $0x91 + CALL strayintr(SB); BYTE $0x92 + CALL strayintr(SB); BYTE $0x93 + CALL strayintr(SB); BYTE $0x94 + CALL strayintr(SB); BYTE $0x95 + CALL strayintr(SB); BYTE $0x96 + CALL strayintr(SB); BYTE $0x97 + CALL strayintr(SB); BYTE $0x98 + CALL strayintr(SB); BYTE $0x99 + CALL strayintr(SB); BYTE $0x9A + CALL strayintr(SB); BYTE $0x9B + CALL strayintr(SB); BYTE $0x9C + CALL strayintr(SB); BYTE $0x9D + CALL strayintr(SB); BYTE $0x9E + CALL strayintr(SB); BYTE $0x9F + CALL strayintr(SB); BYTE $0xA0 + CALL strayintr(SB); BYTE $0xA1 + CALL strayintr(SB); BYTE $0xA2 + CALL strayintr(SB); BYTE $0xA3 + CALL strayintr(SB); BYTE $0xA4 + CALL strayintr(SB); BYTE $0xA5 + CALL strayintr(SB); BYTE $0xA6 + CALL strayintr(SB); BYTE $0xA7 + CALL strayintr(SB); BYTE $0xA8 + CALL strayintr(SB); BYTE $0xA9 + CALL strayintr(SB); BYTE $0xAA + CALL strayintr(SB); BYTE $0xAB + CALL strayintr(SB); BYTE $0xAC + CALL strayintr(SB); BYTE $0xAD + CALL strayintr(SB); BYTE $0xAE + CALL strayintr(SB); BYTE $0xAF + CALL strayintr(SB); BYTE $0xB0 + CALL strayintr(SB); BYTE $0xB1 + CALL strayintr(SB); BYTE $0xB2 + CALL strayintr(SB); BYTE $0xB3 + CALL strayintr(SB); BYTE $0xB4 + CALL strayintr(SB); BYTE $0xB5 + CALL strayintr(SB); BYTE $0xB6 + CALL strayintr(SB); BYTE $0xB7 + CALL strayintr(SB); BYTE $0xB8 + CALL strayintr(SB); BYTE $0xB9 + CALL strayintr(SB); BYTE $0xBA + CALL strayintr(SB); BYTE $0xBB + CALL strayintr(SB); BYTE $0xBC + CALL strayintr(SB); BYTE $0xBD + CALL strayintr(SB); BYTE $0xBE + CALL strayintr(SB); BYTE $0xBF + CALL strayintr(SB); BYTE $0xC0 + CALL strayintr(SB); BYTE $0xC1 + CALL strayintr(SB); BYTE $0xC2 + CALL strayintr(SB); BYTE $0xC3 + CALL strayintr(SB); BYTE $0xC4 + CALL strayintr(SB); BYTE $0xC5 + CALL strayintr(SB); BYTE $0xC6 + CALL strayintr(SB); BYTE $0xC7 + CALL strayintr(SB); BYTE $0xC8 + CALL strayintr(SB); BYTE $0xC9 + CALL strayintr(SB); BYTE $0xCA + CALL strayintr(SB); BYTE $0xCB + CALL strayintr(SB); BYTE $0xCC + CALL strayintr(SB); BYTE $0xCD + CALL strayintr(SB); BYTE $0xCE + CALL strayintr(SB); BYTE $0xCF + CALL strayintr(SB); BYTE $0xD0 + CALL strayintr(SB); BYTE $0xD1 + CALL strayintr(SB); BYTE $0xD2 + CALL strayintr(SB); BYTE $0xD3 + CALL strayintr(SB); BYTE $0xD4 + CALL strayintr(SB); BYTE $0xD5 + CALL strayintr(SB); BYTE $0xD6 + CALL strayintr(SB); BYTE $0xD7 + CALL strayintr(SB); BYTE $0xD8 + CALL strayintr(SB); BYTE $0xD9 + CALL strayintr(SB); BYTE $0xDA + CALL strayintr(SB); BYTE $0xDB + CALL strayintr(SB); BYTE $0xDC + CALL strayintr(SB); BYTE $0xDD + CALL strayintr(SB); BYTE $0xDE + CALL strayintr(SB); BYTE $0xDF + CALL strayintr(SB); BYTE $0xE0 + CALL strayintr(SB); BYTE $0xE1 + CALL strayintr(SB); BYTE $0xE2 + CALL strayintr(SB); BYTE $0xE3 + CALL strayintr(SB); BYTE $0xE4 + CALL strayintr(SB); BYTE $0xE5 + CALL strayintr(SB); BYTE $0xE6 + CALL strayintr(SB); BYTE $0xE7 + CALL strayintr(SB); BYTE $0xE8 + CALL strayintr(SB); BYTE $0xE9 + CALL strayintr(SB); BYTE $0xEA + CALL strayintr(SB); BYTE $0xEB + CALL strayintr(SB); BYTE $0xEC + CALL strayintr(SB); BYTE $0xED + CALL strayintr(SB); BYTE $0xEE + CALL strayintr(SB); BYTE $0xEF + CALL strayintr(SB); BYTE $0xF0 + CALL strayintr(SB); BYTE $0xF1 + CALL strayintr(SB); BYTE $0xF2 + CALL strayintr(SB); BYTE $0xF3 + CALL strayintr(SB); BYTE $0xF4 + CALL strayintr(SB); BYTE $0xF5 + CALL strayintr(SB); BYTE $0xF6 + CALL strayintr(SB); BYTE $0xF7 + CALL strayintr(SB); BYTE $0xF8 + CALL strayintr(SB); BYTE $0xF9 + CALL strayintr(SB); BYTE $0xFA + CALL strayintr(SB); BYTE $0xFB + CALL strayintr(SB); BYTE $0xFC + CALL strayintr(SB); BYTE $0xFD + CALL strayintr(SB); BYTE $0xFE + CALL strayintr(SB); BYTE $0xFF diff --git a/pc/main.c b/pc/main.c index ddee13cd353e022ab41a37ab827f325204d28441..ed1514263d3211f6fe88eb82ae3c93e6a8e4eec5 100644 --- a/pc/main.c +++ b/pc/main.c @@ -6,60 +6,98 @@ #include "io.h" #include "ureg.h" #include "init.h" -#include +Mach *m; -uchar *sp; /* stack pointer for /boot */ +static uchar *sp; /* stack pointer for /boot */ -extern PCArch nsx20, generic, ncr3170; - -PCArch *arch; -PCArch *knownarch[] = -{ - &nsx20, - &ncr3170, - &generic, -}; - -/* where b.com leaves configuration info */ -#define BOOTARGS ((char*)(KZERO|1024)) -#define BOOTARGSLEN 1024 +/* + * Where configuration info is left for the loaded programme. + * This will turn into a structure as more is done by the boot loader + * (e.g. why parse the .ini file twice?). + * There are 1024 bytes available at CONFADDR. + */ +#define BOOTLINE ((char *)CONFADDR) +#define BOOTLINELEN 64 +#define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN)) +#define BOOTARGSLEN (1024-BOOTLINELEN) #define MAXCONF 32 char bootdisk[NAMELEN]; -char filaddr[NAMELEN]; char *confname[MAXCONF]; char *confval[MAXCONF]; int nconf; -/* memory map */ -#define MAXMEG 128 -char mmap[MAXMEG+2]; +extern void ns16552install(void); /* botch: config */ + +static int isoldbcom; + +static void +bcompatibility(void) +{ + uchar *bda; + + if(strncmp(BOOTARGS, "ZORT 0\r\n", 8) == 0) + return; + isoldbcom = 1; + + memmove(BOOTARGS, KADDR(1024), BOOTARGSLEN); + memmove(BOOTLINE, KADDR(0x100), BOOTLINELEN); + + bda = KADDR(0x400); + bda[0x13] = 639; + bda[0x14] = 639>>8; +} void main(void) { - ident(); - i8042a20(); /* enable address lines 20 and up */ + outb(0x3F2, 0x00); /* botch: turn off the floppy motor */ + + /* + * There is a little leeway here in the ordering but care must be + * taken with dependencies: + * function depends on + * ======== ========== + * machinit m->machno, m->pdb + * cpuidentify m + * memscan cpuidentify (needs to know processor + * type for caching, etc.) + * archinit memscan (MP config table may be at the + * top of system physical memory); + * conf.nmach (not critical, mpinit will check); + * confinit meminit + * arch->intrinit trapinit + */ + conf.nmach = 1; + MACHP(0) = (Mach*)CPU0MACH; + m->pdb = (void*)CPU0PDB; machinit(); - active.exiting = 0; active.machs = 1; + active.exiting = 0; + cpuidentify(); + bcompatibility(); + memscan(); + archinit(); confinit(); xinit(); - dmainit(); + trapinit(); screeninit(); printinit(); - mmuinit(); - trapinit(); - ns16552install(); + if(isoldbcom) + print(" ****OLD B.COM - UPGRADE****\n"); pageinit(); + mmuinit(); + if(arch->intrinit) + arch->intrinit(); + ns16552install(); /* botch: config */ mathinit(); - clockinit(); - faultinit(); kbdinit(); + if(arch->clockenable) + arch->clockenable(); procinit0(); initseg(); - printcpufreq(); + cpuidprint(); links(); chandevreset(); swapinit(); @@ -67,32 +105,17 @@ main(void) schedinit(); } -/* - * This tries to capture architecture dependencies since things - * like power management/reseting/mouse are outside the hardware - * model. - */ -void -ident(void) -{ - char *id = (char*)(ROMBIOS + 0xFF40); - PCArch **p; - - for(p = knownarch; *p != &generic; p++) - if(strncmp((*p)->id, id, strlen((*p)->id)) == 0) - break; - arch = *p; -} - void machinit(void) { - int n; + int machno; + void *pdb; - n = m->machno; + machno = m->machno; + pdb = m->pdb; memset(m, 0, sizeof(Mach)); - m->machno = n; - m->mmask = 1<machno; + m->machno = machno; + m->pdb = pdb; } void @@ -119,7 +142,7 @@ init0(void) * Then early kproc's will have a root and dot. */ up->slash = namec("#/", Atodir, 0, 0); - up->dot = clone(up->slash, 0); + up->dot = cclone(up->slash, 0); chandevinit(); @@ -128,10 +151,6 @@ init0(void) strcat(tstr, " %s"); ksetterm(tstr); ksetenv("cputype", "386"); - if(cpuserver) - ksetenv("service", "cpu"); - else - ksetenv("service", "terminal"); for(i = 0; i < nconf; i++) if(confname[i]) ksetenv(confname[i], confval[i]); @@ -223,7 +242,7 @@ bootargs(ulong base) ac = 0; av[ac++] = pusharg("/386/9dos"); - cp[64] = 0; + cp[BOOTLINELEN-1] = 0; buf[0] = 0; if(strncmp(cp, "fd!", 3) == 0){ sprint(buf, "local!#f/fd%ddisk", atoi(cp+3)); @@ -285,106 +304,36 @@ getconf(char *name) return 0; } -/* - * zero memory to set ECC. - * do a quick memory test also. - * - * if any part of a meg is missing/broken, return -1. - */ -int -memclrtest(int meg, int len, long seed) -{ - int j, n; - long y; - long *lp; - - for(j = 0; j < len; j += BY2PG){ - lp = mapaddr(KZERO|(meg*MB+j)); - for(n = 0; n < BY2PG/BY2WD; n++) - lp[n] = seed + n; - } - for(j = 0; j < len; j += BY2PG){ - lp = mapaddr(KZERO|(meg*MB+j)); - for(n = 0; n < BY2PG/(2*BY2WD); n++){ - y = lp[n]; - lp[n] = ~lp[n^((BY2PG/BY2WD)-1)]; - lp[n^((BY2PG/BY2WD)-1)] = ~y; - } - } - for(j = 0; j < len; j += BY2PG){ - lp = mapaddr(KZERO|(meg*MB+j)); - for(n = 0; n < BY2PG/BY2WD; n++) - if(lp[n] != ~(seed + (n^((BY2PG/BY2WD)-1)))) - return -1; -/* memset(lp, '!', BY2PG);/**/ - } - return 0; -} - -/* - * look for unused address space in 0xC8000 to 1 meg - */ -void -romscan(void) -{ - uchar *p; - - p = (uchar*)(KZERO+0xC8000); - while(p < (uchar*)(KZERO+0xE0000)){ - p[0] = 0x55; - p[1] = 0xAA; - p[2] = 4; - if(p[0] == 0x55 && p[1] == 0xAA){ - p += p[2]*512; - continue; - } - p[0] = 0xCC; - p[2048-1] = 0xCC; - if(p[0] != 0xCC && p[2048-1] != 0xCC) - putisa(PADDR(p), 2048); - p += 2048; - } - - p = (uchar*)(KZERO+0xE0000); - if(p[0] != 0x55 || p[1] != 0xAA){ - p[0] = 0xCC; - p[64*1024-1] = 0xff; - if(p[0] != 0xCC && p[64*1024-1] != 0xCC) - putisa(PADDR(p), 64*1024); - } -} - static int -getcfields(char *lp, char **fields, int n, char sep) +getcfields(char* lp, char** fields, int n, char* sep) { int i; - for(i=0; lp && *lp && i=128) defmaxmsg = i; } - if(strcmp(confname[nconf], "filaddr") == 0) - strcpy(filaddr, confval[nconf]); nconf++; } - /* - * size memory above 1 meg. Kernel sits at 1 meg. We - * only recognize MB size chunks. - */ - memset(mmap, ' ', sizeof(mmap)); - x = 0x12345678; - for(i = 1; i <= MAXMEG; i++){ - /* - * write the first & last word in a megabyte of memory - */ - *mapaddr(KZERO|(i*MB)) = x; - *mapaddr(KZERO|((i+1)*MB-BY2WD)) = x; - - /* - * write the first and last word in all previous megs to - * handle address wrap around - */ - for(j = 1; j < i; j++){ - *mapaddr(KZERO|(j*MB)) = ~x; - *mapaddr(KZERO|((j+1)*MB-BY2WD)) = ~x; - } - - /* - * check for correct value - */ - if(*mapaddr(KZERO|(i*MB)) == x) - if(*mapaddr(KZERO|((i+1)*MB-BY2WD)) == x) - mmap[i] = 'x'; - x += 0x3141526; - } - - /* - * zero and clear all except first 2 meg. - */ - x = 0x12345678; - for(i = MAXMEG; i > 1; i--){ - if(mmap[i] != 'x') - continue; -/* - if(memclrtest(i, MB, x) < 0) - mmap[i] = ' '; - */ - x += 0x3141526; - } - - /* - * bank0 usually goes from the end of kernel bss to the end of memory - */ - ktop = PGROUND((ulong)end); - ktop = PADDR(ktop); - conf.base0 = ktop; - for(i = 1; mmap[i] == 'x'; i++) - ; - conf.npage0 = (i*MB - ktop)/BY2PG; - conf.topofmem = i*MB; - - /* - * bank1 usually goes from the end of BOOTARGS to 640k - */ - conf.base1 = (ulong)(BOOTARGS + BOOTARGSLEN); - conf.base1 = PGROUND(conf.base1); - conf.base1 = PADDR(conf.base1); - conf.npage1 = (640*1024 - conf.base1)/BY2PG; - - /* - * if there is a hole in memory (e.g. due to a shadow BIOS) make the - * memory after the hole be bank 1. The memory from 0 to 640k - * is lost. - */ - for(; i <= MAXMEG; i++) - if(mmap[i] == 'x'){ - conf.base1 = i*MB; - for(j = i+1; mmap[j] == 'x'; j++) - ; - conf.npage1 = (j - i)*MB/BY2PG; - conf.topofmem = j*MB; - break; - } - - /* - * add address space holes holes under 16 meg to available - * isa space. - */ - romscan(); - if(conf.topofmem < 16*MB) - putisa(conf.topofmem, 16*MB - conf.topofmem); + meminit(); conf.npage = conf.npage0 + conf.npage1; - conf.ldepth = 0; if(pcnt < 10) pcnt = 70; conf.upages = (conf.npage*pcnt)/100; @@ -525,12 +387,10 @@ confinit(void) conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5; if(cpuserver) conf.nproc *= 3; - conf.monitor = 1; + if(conf.nproc > 2000) + conf.nproc = 2000; conf.nswap = conf.nproc*80; - conf.nimage = 50; - conf.nfloppy = 2; - conf.nhard = 2; - conf.nmach = 1; + conf.nimage = 200; } char *mathmsg[] = @@ -549,15 +409,13 @@ char *mathmsg[] = * math coprocessor error */ void -matherror(Ureg *ur, void *arg) +matherror(Ureg *ur, void*) { ulong status; int i; char *msg; char note[ERRLEN]; - USED(arg); - /* * a write cycle to port 0xF0 clears the interrupt latch attached * to the error# line from the 387 @@ -591,9 +449,8 @@ matherror(Ureg *ur, void *arg) * math coprocessor emulation fault */ void -mathemu(Ureg *ur, void *arg) +mathemu(Ureg*, void*) { - USED(ur, arg); switch(up->fpstate){ case FPinit: fpinit(); @@ -613,20 +470,19 @@ mathemu(Ureg *ur, void *arg) * math coprocessor segment overrun */ void -mathover(Ureg *ur, void *arg) +mathover(Ureg*, void*) { - USED(ur, arg); -print("sys: fp: math overrun pc 0x%lux pid %d\n", ur->pc, up->pid); pexit("math overrun", 0); } void mathinit(void) { - setvec(Matherr1vec, matherror, 0); - setvec(Matherr2vec, matherror, 0); - setvec(Mathemuvec, mathemu, 0); - setvec(Mathovervec, mathover, 0); + intrenable(VectorCERR, matherror, 0, BUSUNKNOWN); + if(X86FAMILY(m->cpuidax) == 3) + intrenable(VectorIRQ13, matherror, 0, BUSUNKNOWN); + intrenable(VectorCNA, mathemu, 0, BUSUNKNOWN); + intrenable(VectorCSO, mathover, 0, BUSUNKNOWN); } /* @@ -654,122 +510,40 @@ procsave(Proc *p) } } -/* - * Restore what procsave() saves - */ void -procrestore(Proc *p) +exit(int ispanic) { - USED(p); -} + int ms, once; -/* - * the following functions all are slightly different from - * PC to PC. - */ + lock(&active); + if(ispanic) + active.ispanic = ispanic; + else if(m->machno == 0 && (active.machs & (1<machno)) == 0) + active.ispanic = 0; + once = active.machs & (1<machno); + active.machs &= ~(1<machno); + active.exiting = 1; + unlock(&active); -void -exit(int ispanic) -{ - up = 0; - active.machs = 0; - print("exiting\n"); + if(once) + print("cpu%d: exiting\n", m->machno); spllo(); - if(ispanic){ + for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ + delay(TK2MS(2)); + if(active.machs == 0 && consactive() == 0) + break; + } + + if(active.ispanic && m->machno == 0){ if(cpuserver) delay(10000); else for(;;); - } else - delay(1000); - - (*arch->reset)(); -} - -/* - * set cpu speed - * 0 == low speed - * 1 == high speed - */ -int -cpuspeed(int speed) -{ - if(arch->cpuspeed) - return (*arch->cpuspeed)(speed); - else - return 0; -} - -/* - * f == frequency (Hz) - * d == duration (ms) - */ -void -buzz(int f, int d) -{ - if(arch->buzz) - (*arch->buzz)(f, d); -} - -/* - * each bit in val stands for a light - */ -void -lights(int val) -{ - if(arch->lights) - (*arch->lights)(val); -} - -/* - * power to serial port - * onoff == 1 means on - * onoff == 0 means off - */ -int -serial(int onoff) -{ - if(arch->serialpower) - return (*arch->serialpower)(onoff); - else - return 0; -} - -/* - * power to modem - * onoff == 1 means on - * onoff == 0 means off - */ -int -modem(int onoff) -{ - if(arch->modempower) - return (*arch->modempower)(onoff); + } else - return 0; -} - -static int -parseether(uchar *to, char *from) -{ - char nip[4]; - char *p; - int i; + delay(1000); - p = from; - for(i = 0; i < 6; i++){ - if(*p == 0) - return -1; - nip[0] = *p++; - if(*p == 0) - return -1; - nip[1] = *p++; - nip[2] = 0; - to[i] = strtoul(nip, 0, 16); - if(*p == ':') - p++; - } - return 0; + arch->reset(); } int @@ -780,7 +554,7 @@ isaconfig(char *class, int ctlrno, ISAConf *isa) sprint(cc, "%s%d", class, ctlrno); for(n = 0; n < nconf; n++){ - if(strncmp(confname[n], cc, NAMELEN)) + if(cistrncmp(confname[n], cc, NAMELEN)) continue; isa->nopt = 0; p = confval[n]; @@ -789,7 +563,7 @@ isaconfig(char *class, int ctlrno, ISAConf *isa) p++; if(*p == '\0') break; - if(strncmp(p, "type=", 5) == 0){ + if(cistrncmp(p, "type=", 5) == 0){ p += 5; for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){ if(*p == '\0' || *p == ' ' || *p == '\t') @@ -798,22 +572,18 @@ isaconfig(char *class, int ctlrno, ISAConf *isa) } *q = '\0'; } - else if(strncmp(p, "port=", 5) == 0) + else if(cistrncmp(p, "port=", 5) == 0) isa->port = strtoul(p+5, &p, 0); - else if(strncmp(p, "irq=", 4) == 0) + else if(cistrncmp(p, "irq=", 4) == 0) isa->irq = strtoul(p+4, &p, 0); - else if(strncmp(p, "dma=", 4) == 0) + else if(cistrncmp(p, "dma=", 4) == 0) isa->dma = strtoul(p+4, &p, 0); - else if(strncmp(p, "mem=", 4) == 0) + else if(cistrncmp(p, "mem=", 4) == 0) isa->mem = strtoul(p+4, &p, 0); - else if(strncmp(p, "size=", 5) == 0) + else if(cistrncmp(p, "size=", 5) == 0) isa->size = strtoul(p+5, &p, 0); - else if(strncmp(p, "freq=", 5) == 0) + else if(cistrncmp(p, "freq=", 5) == 0) isa->freq = strtoul(p+5, &p, 0); - else if(strncmp(p, "ea=", 3) == 0){ - if(parseether(isa->ea, p+3) == -1) - memset(isa->ea, 0, 6); - } else if(isa->nopt < NISAOPT){ r = isa->opt[isa->nopt]; while(*p && *p != ' ' && *p != '\t'){ @@ -869,3 +639,28 @@ cistrcmp(char *a, char *b) } return 0; } + +int +cistrncmp(char *a, char *b, int n) +{ + unsigned ac, bc; + + while(n > 0){ + ac = *a++; + bc = *b++; + n--; + + if(ac >= 'A' && ac <= 'Z') + ac = 'a' + (ac - 'A'); + if(bc >= 'A' && bc <= 'Z') + bc = 'a' + (bc - 'A'); + + ac -= bc; + if(ac) + return ac; + if(bc == 0) + break; + } + + return 0; +} diff --git a/pc/mem.h b/pc/mem.h index 9cbeaf27e6c105cd6eaccbb542f081215f96c0d6..a7dc3e85e77cb28ab9061f0349b4edef4bd99594 100644 --- a/pc/mem.h +++ b/pc/mem.h @@ -15,7 +15,7 @@ #define ROUND(s, sz) (((s)+(sz-1))&~(sz-1)) #define PGROUND(s) ROUND(s, BY2PG) -#define MAXMACH 1 /* max # cpus system can run */ +#define MAXMACH 8 /* max # cpus system can run */ /* * Time @@ -29,6 +29,16 @@ /* * Fundamental addresses */ +#define IDTADDR 0x80000800 /* idt */ +#define APBOOTSTRAP 0x80001000 /* AP bootstrap code */ +#define CONFADDR 0x80001200 /* info passed from boot loader */ +#define CPU0PDB 0x80002000 /* bootstrap processor PDB */ +#define CPU0PTE 0x80003000 /* bootstrap processor PTE's for 0-2MB */ +#define CPU0MACHPTE 0x80004000 /* bootstrap processor PTE for MACHADDR */ +#define CPU0MACH 0x80005000 /* Mach for bootstrap processor */ + +#define MACHADDR 0xFEF00000 /* as seen by current processor */ +#define MACHSIZE 4096 /* * Address spaces @@ -53,8 +63,6 @@ #define ISAMEMSIZE (4*MB) /* mem space reserved for ISA */ #define globalmem(x) ((((ulong)x)&0xF0000000)==KZERO) /* addresses valid in all contexts */ -#define MACHSIZE 4096 - /* * known 80386 segments (in GDT) and their selectors */ @@ -101,8 +109,8 @@ * virtual MMU */ #define PTEMAPMEM (1024*1024) -#define SEGMAPSIZE 16 #define PTEPERTAB (PTEMAPMEM/BY2PG) +#define SEGMAPSIZE 512 #define PPN(x) ((x)&~(BY2PG-1)) /* @@ -115,11 +123,6 @@ #define PTERONLY (0<<1) #define PTEKERNEL (0<<2) #define PTEUSER (1<<2) - -/* - * flag register bits that we care about - */ -#define IFLAG 0x200 -#define IE 0x200 +#define PTESIZE (1<<7) #define getpgcolor(a) 0 diff --git a/pc/memory.c b/pc/memory.c new file mode 100644 index 0000000000000000000000000000000000000000..11e6cad017f3e0928b07aa91e5f74ccc92e99f31 --- /dev/null +++ b/pc/memory.c @@ -0,0 +1,480 @@ +/* + * Size memory and create the kernel page-tables on the fly while doing so. + * Called from main(), this code should only be run by the bootstrap processor. + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#define PDX(va) ((((ulong)(va))>>22) & 0x03FF) +#define PTX(va) ((((ulong)(va))>>12) & 0x03FF) + +enum { + MemUPA = 0, /* unbacked physical address */ + MemRAM = 1, /* physical memory */ + MemUMB = 2, /* upper memory block (<16MB) */ + NMemType = 3, + + KB = 1024, + + MemMinMB = 4, /* minimum physical memory (<=4MB) */ + MemMaxMB = 192, /* maximum physical memory to check */ + + NMemBase = 10, +}; + +typedef struct { + int size; + ulong addr; +} Map; + +typedef struct { + char* name; + Map* map; + Map* mapend; + + Lock; +} RMap; + +static Map mapupa[8]; +static RMap rmapupa = { + "unallocated unbacked physical memory", + mapupa, + &mapupa[7], +}; + +static Map xmapupa[8]; +static RMap xrmapupa = { + "unbacked physical memory", + xmapupa, + &xmapupa[7], +}; + +static Map mapram[8]; +static RMap rmapram = { + "physical memory", + mapram, + &mapram[7], +}; + +static Map mapumb[64]; +static RMap rmapumb = { + "upper memory block", + mapumb, + &mapumb[63], +}; + +void +mapfree(RMap* rmap, ulong addr, int size) +{ + Map *mp; + ulong t; + + if(size <= 0) + return; + + lock(rmap); + for(mp = rmap->map; mp->addr <= addr && mp->size; mp++) + ; + + if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){ + (mp-1)->size += size; + if(addr+size == mp->addr){ + (mp-1)->size += mp->size; + while(mp->size){ + mp++; + (mp-1)->addr = mp->addr; + (mp-1)->size = mp->size; + } + } + } + else{ + if(addr+size == mp->addr && mp->size){ + mp->addr -= size; + mp->size += size; + } + else do{ + if(mp >= rmap->mapend){ + print("mapfree: losing %d, %d\n", addr, size); + break; + } + t = mp->addr; + mp->addr = addr; + addr = t; + t = mp->size; + mp->size = size; + mp++; + }while(size = t); + } + unlock(rmap); +} + +ulong +mapalloc(RMap* rmap, ulong addr, int size, int align) +{ + Map *mp; + ulong maddr, oaddr; + + lock(rmap); + for(mp = rmap->map; mp->size; mp++){ + maddr = mp->addr; + + if(addr){ + if(maddr > addr) + continue; + if(addr+size > maddr+mp->size) + break; + maddr = addr; + } + + if(align > 0) + maddr = ((maddr+align-1)/align)*align; + if(mp->addr+mp->size-maddr < size) + continue; + + oaddr = mp->addr; + mp->addr = maddr+size; + mp->size -= maddr-oaddr+size; + if(mp->size == 0){ + do{ + mp++; + (mp-1)->addr = mp->addr; + }while((mp-1)->size = mp->size); + } + + unlock(rmap); + if(oaddr != maddr) + mapfree(rmap, oaddr, maddr-oaddr); + + return maddr; + } + unlock(rmap); + + return 0; +} + +static void +umbscan(void) +{ + uchar *p; + + /* + * Scan the Upper Memory Blocks (0xA0000->0xF0000) for pieces + * which aren't used; they can be used later for devices which + * want to allocate some virtual address space. + * Check for two things: + * 1) device BIOS ROM. This should start with a two-byte header + * of 0x55 0xAA, followed by a byte giving the size of the ROM + * in 512-byte chunks. These ROM's must start on a 2KB boundary. + * 2) device memory. This is read-write. + * There are some assumptions: there's VGA memory at 0xA0000 and + * the VGA BIOS ROM is at 0xC0000. Also, if there's no ROM signature + * at 0xE0000 then the whole 64KB up to 0xF0000 is theoretically up + * for grabs; check anyway. + */ + p = KADDR(0xC8000); + while(p < (uchar*)KADDR(0xE0000)){ + p[0] = 0x55; + p[1] = 0xAA; + p[2] = 4; + if(p[0] == 0x55 && p[1] == 0xAA){ + p += p[2]*512; + continue; + } + p[0] = 0xCC; + p[2*KB-1] = 0xCC; + if(p[0] != 0xCC && p[2*KB-1] != 0xCC) + mapfree(&rmapumb, PADDR(p), 2*KB); + p += 2*KB; + } + + p = KADDR(0xE0000); + if(p[0] != 0x55 || p[1] != 0xAA){ + p[0] = 0xCC; + p[64*KB-1] = 0xCC; + if(p[0] != 0xCC && p[64*KB-1] != 0xCC) + mapfree(&rmapumb, PADDR(p), 64*KB); + } +} + +static void +ramscan(void) +{ + ulong *k0, kzero, map, maxpa, pa, *pte, *table, *va, x; + int nvalid[NMemType]; + uchar *bda; + + /* + * The bootstrap code has has created a prototype page + * table which maps the first MemMinMB of physical memory to KZERO. + * The page directory is at m->pdb and the first page of + * free memory is after the per-processor MMU information. + */ + /* + * Initialise the memory bank information for conventional memory + * (i.e. less than 640KB). The base is the first location after the + * bootstrap processor MMU information and the limit is obtained from + * the BIOS data area. + */ + x = PADDR(CPU0MACH+BY2PG); + + bda = (uchar*)(KZERO|0x400); + mapfree(&rmapram, x, ((bda[0x14]<<8)|bda[0x13])*KB-x); + + /* + * Check if the extended memory size can be obtained from the CMOS. + * If it's 0 then it's either not known or >= 64MB. Always check + * at least 24MB in case there's a memory gap (up to 8MB) below 16MB; + * in this case the memory from the gap is remapped to the top of + * memory. + * The value in CMOS is supposed to be the number of KB minus one. + */ + maxpa = (nvramread(0x18)<<8)|nvramread(0x17); + maxpa = MB+(maxpa+1)*KB; + if(maxpa == 0 || maxpa >= 64*MB) + maxpa = MemMaxMB*MB; + if(maxpa < 24*MB) + maxpa = 24*MB; + + /* + * March up memory from the end of the loaded kernel to maxpa + * a page at a time, mapping the page and checking the page can + * be written and read correctly. The page tables are created here + * on the fly, allocating from low memory as necessary. + * Nvalid must be initialised to include some UMB's to prevent the + * first 4MB being mapped with a 4MB page extension, it's already + * partly mapped. + */ + k0 = (ulong*)KZERO; + kzero = *k0; + map = 0; + x = 0x12345678; + memset(nvalid, 0, sizeof(nvalid)); + nvalid[MemUMB] = (0x100000-0xC8000)/BY2PG; + nvalid[MemRAM] = PADDR(PGROUND((ulong)end))/BY2PG - nvalid[MemUMB]; + for(pa = PADDR(PGROUND((ulong)end)); pa < maxpa; pa += BY2PG){ + /* + * Map the page. Use mapalloc(&rmapram, ...) to make + * the page table if necessary, it will be returned to the + * pool later if it isn't needed. + */ + va = KADDR(pa); + table = &((ulong*)m->pdb)[PDX(va)]; + if(*table == 0){ + if(map == 0 && (map = mapalloc(&rmapram, 0, BY2PG, BY2PG)) == 0) + break; + memset(KADDR(map), 0, BY2PG); + *table = map|PTEWRITE|PTEVALID; + memset(nvalid, 0, sizeof(nvalid)); + } + table = KADDR(PPN(*table)); + pte = &table[PTX(va)]; + + *pte = pa|PTEWRITE|PTEUNCACHED|PTEVALID; + mmuflushtlb(PADDR(m->pdb)); + + /* + * Write a pattern to the page and write a different + * pattern to a possible mirror at KZER0. If the data + * reads back correctly the page is some type of RAM (possibly + * a linearly-mapped VGA framebuffer, for instance...) and + * can be cleared and added to the memory pool. If not, the + * page is marked invalid and added to the UMB or NOT pool + * depending on whether it is <16MB or not. + */ + *va = x; + *k0 = ~x; + if(*va == x){ + *pte &= ~PTEUNCACHED; + nvalid[MemRAM]++; + mapfree(&rmapram, pa, BY2PG); + memset(va, 0, BY2PG); + } + else{ + if(pa < 16*MB){ + nvalid[MemUMB]++; + mapfree(&rmapumb, pa, BY2PG); + } + else{ + *pte = 0; + nvalid[MemUPA]++; + mapfree(&rmapupa, pa, BY2PG); + } + } + + /* + * Done with this 4MB chunk, review the options: + * 1) not physical memory and >=16MB - invalidate the PDB entry; + * 2) physical memory - use the 4MB page extension if possible; + * 3) not physical memory and <16MB - use the 4MB page extension + * if possible; + * 4) mixed or no 4MB page extension - commit the already + * initialised space for the page table. + */ + if(((pa+BY2PG) % (4*MB)) == 0){ + table = &((ulong*)m->pdb)[PDX(va)]; + if(nvalid[MemUPA] == 1024) + *table = 0; + else if(nvalid[MemRAM] == 1024 && (m->cpuiddx & 0x08)) + *table = (pa & ~(4*MB-1))|PTESIZE|PTEWRITE|PTEVALID; + else if(nvalid[MemUMB] == 1024 && (m->cpuiddx & 0x08)) + *table = (pa & ~(4*MB-1))|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID; + else + map = 0; + } + + mmuflushtlb(PADDR(m->pdb)); + x += 0x3141526; + } + if(map) + mapfree(&rmapram, map, BY2PG); + if(pa < MemMaxMB*MB) + mapfree(&rmapupa, pa, MemMaxMB*MB-pa); + *k0 = kzero; +} + +static void +upainit(void) +{ + ulong addr, pa, pae, *table, *va, x; + + /* + * Allocate an 8MB chunk aligned to 16MB. Later can + * make the region selectable via conf if necessary. + */ + if((addr = mapalloc(&rmapupa, 0, 8*MB, 16*MB)) == 0) + return; + + pa = addr; + pae = pa+(16*MB); + while(pa < pae){ + va = KADDR(pa); + table = &((ulong*)m->pdb)[PDX(va)]; + if((pa % (4*MB)) == 0 && (m->cpuiddx & 0x08)){ + *table = pa|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID; + pa += (4*MB); + } + else{ + if(*table == 0){ + if((x = mapalloc(&rmapram, 0, BY2PG, BY2PG)) == 0) + break; + memset(KADDR(x), 0, BY2PG); + *table = x|PTEWRITE|PTEVALID; + } + table = (ulong*)(KZERO|PPN(*table)); + table[PTX(va)] = pa|PTEWRITE|PTEUNCACHED|PTEVALID; + pa += BY2PG; + } + } + + mapfree(&xrmapupa, addr, pa-addr); +} + +void +memscan(void) +{ + ulong pa, *pte; + + /* + * Set special attributes for memory between 640KB and 1MB: + * VGA memory is writethrough; + * BIOS ROM's/UMB's are uncached; + * then scan for useful memory. + */ + for(pa = 0xA0000; pa < 0xC0000; pa += BY2PG){ + pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 0); + *pte |= PTEWT; + } + for(pa = 0xC0000; pa < 0x100000; pa += BY2PG){ + pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 0); + *pte |= PTEUNCACHED; + } + mmuflushtlb(PADDR(m->pdb)); + + umbscan(); + ramscan(); + upainit(); +} + +#ifdef notdef +void +dumpmembank(void) +{ + Map *mp; + ulong maxpa, maxpa1; + + maxpa = (nvramread(0x18)<<8)|nvramread(0x17); + maxpa1 = (nvramread(0x31)<<8)|nvramread(0x30); + print("maxpa = %uX -> %uX, maxpa1 = %uX\n", maxpa, MB+(maxpa+1)*KB, maxpa1); + + for(mp = rmapram.map; mp->size; mp++) + print("%8.8uX %8.8uX %8.8uX\n", mp->addr, mp->size, mp->addr+mp->size); + for(mp = rmapumb.map; mp->size; mp++) + print("%8.8uX %8.8uX %8.8uX\n", mp->addr, mp->size, mp->addr+mp->size); + for(mp = rmapupa.map; mp->size; mp++) + print("%8.8uX %8.8uX %8.8uX\n", mp->addr, mp->size, mp->addr+mp->size); +} +#endif /* notdef */ + +void +meminit(void) +{ + Map *mp, *xmp; + + /* + * Set the conf entries describing two banks of allocatable memory. + * Grab the first and largest entries in rmapram as left by ramscan(). + * + * It would be nice to have more than 2 memory banks describable in conf. + */ + mp = rmapram.map; + conf.base0 = mp->addr; + conf.npage0 = mp->size/BY2PG; + mp++; + for(xmp = 0; mp->size; mp++){ + if(xmp == 0 || mp->size > xmp->size) + xmp = mp; + } + + if(xmp){ + conf.base1 = xmp->addr; + conf.npage1 = xmp->size/BY2PG; + } +} + +ulong +umbmalloc(ulong addr, int size, int align) +{ + ulong a; + + if(a = mapalloc(&rmapumb, addr, size, align)) + return KZERO|a; + + return 0; +} + +void +umbfree(ulong addr, int size) +{ + mapfree(&rmapumb, addr & ~KZERO, size); +} + +ulong +upamalloc(ulong addr, int size, int align) +{ + ulong a; + + if(a = mapalloc(&xrmapupa, addr, size, align)) + return KZERO|a; + + return 0; +} + +void +upafree(ulong addr, int size) +{ + mapfree(&xrmapupa, addr & ~KZERO, size); +} diff --git a/pc/mmu.c b/pc/mmu.c index b0de9f50be8b27340b721845b8c67727431a037d..2e9f79a2f93d426add9031958b60a141a2727be3 100644 --- a/pc/mmu.c +++ b/pc/mmu.c @@ -5,60 +5,12 @@ #include "fns.h" #include "io.h" -/* - * task state segment. Plan 9 ignores all the task switching goo and just - * uses the tss for esp0 and ss0 on gate's into the kernel, interrupts, - * and exceptions. The rest is completely ignored. - * - * This means that we only need one tss in the whole system. - */ -typedef struct Tss Tss; -struct Tss -{ - ulong backlink; /* unused */ - ulong sp0; /* pl0 stack pointer */ - ulong ss0; /* pl0 stack selector */ - ulong sp1; /* pl1 stack pointer */ - ulong ss1; /* pl1 stack selector */ - ulong sp2; /* pl2 stack pointer */ - ulong ss2; /* pl2 stack selector */ - ulong cr3; /* page table descriptor */ - ulong eip; /* instruction pointer */ - ulong eflags; /* processor flags */ - ulong eax; /* general (hah?) registers */ - ulong ecx; - ulong edx; - ulong ebx; - ulong esp; - ulong ebp; - ulong esi; - ulong edi; - ulong es; /* segment selectors */ - ulong cs; - ulong ss; - ulong ds; - ulong fs; - ulong gs; - ulong ldt; /* local descriptor table */ - ulong iomap; /* io map base */ -}; -Tss tss; - -/* - * segment descriptor initializers - */ #define DATASEGM(p) { 0xFFFF, SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW } #define EXECSEGM(p) { 0xFFFF, SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR } -#define CALLGATE(s,o,p) { ((o)&0xFFFF)|((s)<<16), (o)&0xFFFF0000|SEGP|SEGPL(p)|SEGCG } -#define D16SEGM(p) { 0xFFFF, (0x0<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW } -#define E16SEGM(p) { 0xFFFF, (0x0<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR } #define TSSSEGM(b,p) { ((b)<<16)|sizeof(Tss),\ ((b)&0xFF000000)|(((b)>>16)&0xFF)|SEGTSS|SEGPL(p)|SEGP } -/* - * global descriptor table describing all segments - */ -Segdesc gdt[] = +Segdesc gdt[6] = { [NULLSEG] { 0, 0}, /* null descriptor */ [KDSEG] DATASEGM(0), /* kernel data/stack */ @@ -68,137 +20,74 @@ Segdesc gdt[] = [TSSSEG] TSSSEGM(0,0), /* tss segment */ }; -static Page ktoppg; /* prototype top level page table - * containing kernel mappings */ -static ulong *kpt; /* 2nd level page tables for kernel mem */ - -#define ROUNDUP(s,v) (((s)+(v-1))&~(v-1)) -/* - * offset of virtual address into - * top level page table - */ -#define TOPOFF(v) (((ulong)(v))>>(2*PGSHIFT-2)) - -/* - * offset of virtual address into - * bottom level page table - */ -#define BTMOFF(v) ((((ulong)(v))>>(PGSHIFT))&(WD2PG-1)) - -#define MAXUMEG 64 /* maximum memory per user process in megabytes */ -#define ONEMEG (1024*1024) - -/* unallocated ISA space */ -enum { - Nisa= 256, -}; -struct -{ - Lock; - ulong s[Nisa]; - ulong e[Nisa]; -} isaalloc; +#define PDX(va) ((((ulong)(va))>>22) & 0x03FF) +#define PTX(va) ((((ulong)(va))>>12) & 0x03FF) + +static int ptebits = 0; -/* unallocated space */ -struct -{ - Lock; - ulong s; - ulong e; -} msalloc; - -/* - * Change current page table and the stack to use for exceptions - * (traps & interrupts). The exception stack comes from the tss. - * Since we use only one tss, (we hope) there's no need for a - * puttr(). - */ static void taskswitch(ulong pagetbl, ulong stack) { - tss.ss0 = KDSEL; - tss.sp0 = stack; -tss.ss1 = KDSEL; -tss.sp1 = stack; -tss.ss2 = KDSEL; -tss.sp2 = stack; - tss.cr3 = pagetbl; + Tss *tss; + + tss = m->tss; + tss->ss0 = KDSEL; + tss->esp0 = stack; + tss->ss1 = KDSEL; + tss->esp1 = stack; + tss->ss2 = KDSEL; + tss->esp2 = stack; + tss->cr3 = pagetbl; putcr3(pagetbl); } -/* - * Create a prototype page map that maps all of memory into - * kernel (KZERO) space. This is the default map. It is used - * whenever the processor is not running a process or whenever running - * a process which does not yet have its own map. - */ void mmuinit(void) { - int i, nkpt, npage, nbytes; ulong x; - ulong y; - ulong *top; - - /* - * set up the global descriptor table. we make the tss entry here - * since it requires arithmetic on an address and hence cannot - * be a compile or link time constant. - */ - x = (ulong)&tss; - gdt[TSSSEG].d0 = (x<<16)|sizeof(Tss); - gdt[TSSSEG].d1 = (x&0xFF000000)|((x>>16)&0xFF)|SEGTSS|SEGPL(0)|SEGP; - putgdt(gdt, sizeof gdt); - - /* - * set up system page tables. - * map all of physical memory to start at KZERO. - * leave a map entry for a user area. - */ - - /* allocate top level table */ - top = xspanalloc(BY2PG, BY2PG, 0); - ktoppg.va = (ulong)top; - ktoppg.pa = ktoppg.va & ~KZERO; - - /* map all memory to KZERO */ - npage = 128*MB/BY2PG; - nbytes = PGROUND(npage*BY2WD); /* words of page map */ - nkpt = nbytes/BY2PG; /* pages of page map */ - kpt = xspanalloc(nbytes, BY2PG, 0); - for(i = 0; i < npage; i++) - kpt[i] = (0+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE; - for(i = 0xa0000/BY2PG; i < 0xC0000/BY2PG; i++) - kpt[i] = (0+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE | PTEWT; - for(i = 0xC0000/BY2PG; i < MB/BY2PG; i++) - kpt[i] = (0+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE | PTEUNCACHED; - for(i = conf.topofmem/BY2PG; i < 128*MB/BY2PG; i++) - kpt[i] = (0+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE | PTEUNCACHED; - x = TOPOFF(KZERO); - y = ((ulong)kpt)&~KZERO; - for(i = 0; i < nkpt; i++) - top[x+i] = (y+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE; - - /* - * set up the task segment - */ - memset(&tss, 0, sizeof(tss)); - taskswitch(ktoppg.pa, BY2PG + (ulong)m); - puttr(TSSSEL);/**/ + ushort ptr[3]; + + m->tss = malloc(sizeof(Tss)); + memset(m->tss, 0, sizeof(Tss)); + + memmove(m->gdt, gdt, sizeof(m->gdt)); + x = (ulong)m->tss; + m->gdt[TSSSEG].d0 = (x<<16)|sizeof(Tss); + m->gdt[TSSSEG].d1 = (x&0xFF000000)|((x>>16)&0xFF)|SEGTSS|SEGPL(0)|SEGP; + + ptr[0] = sizeof(m->gdt); + x = (ulong)m->gdt; + ptr[1] = x & 0xFFFF; + ptr[2] = (x>>16) & 0xFFFF; + lgdt(ptr); + + ptr[0] = sizeof(Segdesc)*256; + x = IDTADDR; + ptr[1] = x & 0xFFFF; + ptr[2] = (x>>16) & 0xFFFF; + lidt(ptr); + + taskswitch(PADDR(m->pdb), (ulong)m + BY2PG); + ltr(TSSSEL); +} - /* - * allocatable, non ISA memory - */ - if(conf.topofmem > 16*1024*1024) - msalloc.s = conf.topofmem; - else - msalloc.s = 16*1024*1024; - msalloc.e = 128*1024*1024; +ulong* +mmuwalk(ulong *pdb, ulong va, int create) +{ + ulong *table, x; + + table = &pdb[PDX(va)]; + if(*table == 0){ + if(create == 0) + return 0; + x = PADDR((ulong)xspanalloc(BY2PG, BY2PG, 0)); + *table = x|ptebits|PTEWRITE|PTEVALID; + } + table = (ulong*)(KZERO|PPN(*table)); + va = PTX(va); + return &table[va]; } -/* - * Mark the mmu and tlb as inconsistent and call mmuswitch to fix it up. - */ void flushmmu(void) { @@ -210,280 +99,155 @@ flushmmu(void) splx(s); } -/* - * Switch to a process's memory map. If the process doesn't - * have a map yet, just use the prototype one that contains - * mappings for only the kernel. - */ +static void +mmuptefree(Proc *p) +{ + ulong *pdb; + Page **lpg, *pg; + + if(p->mmupdb && p->mmuused){ + pdb = (ulong*)p->mmupdb->va; + lpg = &p->mmuused; + for(pg = *lpg; pg; pg = pg->next){ + pdb[pg->daddr] = 0; + lpg = &pg->next; + } + *lpg = p->mmufree; + p->mmufree = p->mmuused; + p->mmuused = 0; + } +} + void mmuswitch(Proc *p) { - Page *pg; ulong *top; if(p->newtlb){ - /* - * newtlb set means that they are inconsistent - * with the segment.c data structures. - * - * bin the current second level page tables and - * the pointers to them in the top level page. - * pg->daddr is used by putmmu to save the offset into - * the top level page. - */ - if(p->mmutop && p->mmuused){ - top = (ulong*)p->mmutop->va; - for(pg = p->mmuused; pg->next; pg = pg->next) - top[pg->daddr] = 0; - top[pg->daddr] = 0; - pg->next = p->mmufree; - p->mmufree = p->mmuused; - p->mmuused = 0; - } + mmuptefree(p); p->newtlb = 0; } - /* tell processor about new page table (flushes cached entries) */ - if(p->mmutop) - taskswitch(p->mmutop->pa, (ulong)(p->kstack+KSTACK)); + if(p->mmupdb){ + top = (ulong*)p->mmupdb->va; + top[PDX(MACHADDR)] = ((ulong*)m->pdb)[PDX(MACHADDR)]; + taskswitch(p->mmupdb->pa, (ulong)(p->kstack+KSTACK)); + } else - taskswitch(ktoppg.pa, (ulong)(p->kstack+KSTACK)); + taskswitch(PADDR(m->pdb), (ulong)(p->kstack+KSTACK)); } -static void -simpleputpage(Page *pg) +void +mmurelease(Proc *p) { - if(pg->ref != 1) - panic("simpleputpage"); + Page *pg, *next; - pg->ref = 0; - if(palloc.head){ - pg->next = palloc.head; - palloc.head->prev = pg; - } - else { - palloc.tail = pg; - pg->next = 0; + /* + * Release any pages allocated for a page directory base or page-tables + * for this process: + * switch to the prototype pdb for this processor (m->pdb); + * call mmuptefree() to place all pages used for page-tables (p->mmuused) + * onto the process' free list (p->mmufree). This has the side-effect of + * cleaning any user entries in the pdb (p->mmupdb); + * if there's a pdb put it in the cache of pre-initialised pdb's + * for this processor (m->pdbpool) or on the process' free list; + * finally, place any pages freed back into the free pool (palloc). + * This routine is only called from sched() with palloc locked. + */ + taskswitch(PADDR(m->pdb), (ulong)m + BY2PG); + mmuptefree(p); + + if(p->mmupdb){ + if(m->pdbcnt > 10){ + p->mmupdb->next = p->mmufree; + p->mmufree = p->mmupdb; + } + else{ + p->mmupdb->next = m->pdbpool; + m->pdbpool = p->mmupdb; + m->pdbcnt++; + } + p->mmupdb = 0; } - palloc.head = pg; - pg->prev = 0; - palloc.freecount++; - if(palloc.r.p != 0) + for(pg = p->mmufree; pg; pg = next){ + next = pg->next; + if(--pg->ref) + panic("mmurelease: pg->ref %d\n", pg->ref); + pg->ref = 0; + if(palloc.head){ + pg->next = palloc.head; + palloc.head->prev = pg; + } + else{ + palloc.tail = pg; + pg->next = 0; + } + palloc.head = pg; + pg->prev = 0; + + palloc.freecount++; + } + if(p->mmufree && palloc.r.p) wakeup(&palloc.r); + p->mmufree = 0; } -/* - * give all page table pages back to the free pool. This is called in sched() - * with palloc locked. - */ -void -mmurelease(Proc *p) +static Page* +mmupdballoc(void) { + int s; Page *pg; - Page *next; - /* point 386 to protoype page map and m->stack */ - taskswitch(ktoppg.pa, BY2PG + (ulong)m); - - /* give away page table pages */ - for(pg = p->mmufree; pg; pg = next){ - next = pg->next; - simpleputpage(pg); + s = splhi(); + if(m->pdbpool == 0){ + spllo(); + pg = newpage(0, 0, 0); + pg->va = VA(kmap(pg)); + memmove((void*)pg->va, m->pdb, BY2PG); } - p->mmufree = 0; - for(pg = p->mmuused; pg; pg = next){ - next = pg->next; - simpleputpage(pg); + else{ + pg = m->pdbpool; + m->pdbpool = pg->next; + m->pdbcnt--; } - p->mmuused = 0; - if(p->mmutop) - simpleputpage(p->mmutop); - p->mmutop = 0; + splx(s); + return pg; } -/* - * Add an entry into the mmu. - */ void putmmu(ulong va, ulong pa, Page *pg) { - int topoff; - ulong *top; - ulong *pt; + int pdbx; + ulong *pdb, *pt; int s; - /* - * create a top level page if we don't already have one. - * copy the kernel top level page into it for kernel mappings. - */ - if(up->mmutop == 0){ - pg = newpage(0, 0, 0); - pg->va = VA(kmap(pg)); - memmove((void*)pg->va, (void*)ktoppg.va, BY2PG); - up->mmutop = pg; - } - top = (ulong*)up->mmutop->va; - topoff = TOPOFF(va); + if(up->mmupdb == 0) + up->mmupdb = mmupdballoc(); + pdb = (ulong*)up->mmupdb->va; + pdbx = PDX(va); - /* - * if bottom level page table missing, allocate one - * and point the top level page at it. - */ - s = splhi(); - if(PPN(top[topoff]) == 0){ + if(PPN(pdb[pdbx]) == 0){ if(up->mmufree == 0){ - spllo(); pg = newpage(1, 0, 0); pg->va = VA(kmap(pg)); - splhi(); - } else { + } + else { pg = up->mmufree; up->mmufree = pg->next; memset((void*)pg->va, 0, BY2PG); } - top[topoff] = PPN(pg->pa) | PTEVALID | PTEUSER | PTEWRITE; - pg->daddr = topoff; + pdb[pdbx] = PPN(pg->pa)|ptebits|PTEUSER|PTEWRITE|PTEVALID; + pg->daddr = pdbx; pg->next = up->mmuused; up->mmuused = pg; } - /* - * put in new mmu entry - */ - pt = (ulong*)(PPN(top[topoff])|KZERO); - pt[BTMOFF(va)] = pa | PTEUSER; + pt = (ulong*)(PPN(pdb[pdbx])|KZERO); + pt[PTX(va)] = pa|ptebits|PTEUSER; - /* flush cached mmu entries */ - /*taskswitch(up->mmutop->pa, (ulong)(up->kstack+KSTACK));/**/ - putcr3(up->mmutop->pa);/**/ + s = splhi(); + pdb[PDX(MACHADDR)] = ((ulong*)m->pdb)[PDX(MACHADDR)]; + putcr3(up->mmupdb->pa); splx(s); } - -/* - * make isa address space available - */ -void -putisa(ulong addr, int len) -{ - ulong e; - int i, hole; - - addr &= ~KZERO; - - e = addr + len; - lock(&isaalloc); - hole = -1; - for(i = 0; i < Nisa; i++){ - if(isaalloc.s[i] == e){ - isaalloc.s[i] = addr; - break; - } - if(isaalloc.e[i] == addr){ - isaalloc.e[i] = e; - break; - } - if(isaalloc.s[i] == 0) - hole = i; - } - if(i >= Nisa && hole >= 0){ - isaalloc.s[hole] = addr; - isaalloc.e[hole] = e; - } - unlock(&isaalloc); -} - -/* - * allocate some address space (already mapped into the kernel) - * for ISA bus memory. - */ -ulong -getisa(ulong addr, int len, int align) -{ - int i; - long os, s, e; - - lock(&isaalloc); - os = s = e = 0; - for(i = 0; i < Nisa; i++){ - s = os = isaalloc.s[i]; - if(s == 0) - continue; - e = isaalloc.e[i]; - if(addr && addr >= s && addr < e) - break; - if(align > 0) - s = ((s + align - 1)/align)*align; - if(e - s >= len) - break; - } - if(i >= Nisa){ - unlock(&isaalloc); - return 0; - } - - /* remove */ - isaalloc.s[i] = 0; - unlock(&isaalloc); - - /* give back edges */ - if(s != os) - putisa(os, s - os); - os = s + len; - if(os != e) - putisa(os, e - os); - - return KZERO|s; -} - -/* - * used to map a page into 16 meg - BY2PG for confinit(). tpt is the temporary - * page table set up by l.s. - */ -long* -mapaddr(ulong addr) -{ - ulong base; - ulong off; - static ulong *pte, top; - extern ulong tpt[]; - - if(pte == 0){ - top = (((ulong)tpt)+(BY2PG-1))&~(BY2PG-1); - pte = (ulong*)top; - top &= ~KZERO; - top += BY2PG; - pte += (4*1024*1024-BY2PG)>>PGSHIFT; - } - - base = off = addr; - base &= ~(KZERO|(BY2PG-1)); - off &= BY2PG-1; - - *pte = base|PTEVALID|PTEKERNEL|PTEWRITE; /**/ - putcr3((ulong)top); - - return (long*)(KZERO | 4*1024*1024-BY2PG | off); -} - -/* - * get non-ISA memory space - */ -ulong -getspace(int len, int span) -{ - ulong x; - - lock(&msalloc); - x = msalloc.s; - if(span) - x = ROUND(x, span); - if(len > msalloc.e - x){ - unlock(&msalloc); - return 0; - } - msalloc.s = x + len; - unlock(&msalloc); - - return x | KZERO; -} diff --git a/pc/mouse.c b/pc/mouse.c new file mode 100644 index 0000000000000000000000000000000000000000..faef3a4becf5abac1cd5e0d87ddc328d02627ca4 --- /dev/null +++ b/pc/mouse.c @@ -0,0 +1,145 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "io.h" + +#include +#include "screen.h" + +/* + * setup a serial mouse + */ +static void +serialmouse(int port, char *type, int setspeed) +{ + if(mousetype == Mouseserial) + error(Emouseset); + + if(port >= 3 || port < 0) + error(Ebadarg); + + /* set up /dev/eia? as the mouse */ + if(setspeed) + setspeed = 1200; + if(type && *type == 'M') + ns16552special(port, setspeed, 0, 0, m3mouseputc); + else + ns16552special(port, setspeed, 0, 0, mouseputc); + mousetype = Mouseserial; +} + +/* + * ps/2 mouse message is three bytes + * + * byte 0 - 0 0 SDY SDX 1 M R L + * byte 1 - DX + * byte 2 - DY + * + * shift & left button is the same as middle button + */ +static void +ps2mouseputc(int c, int shift) +{ + static short msg[3]; + static int nb; + static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 }; + int buttons, dx, dy; + + /* + * check byte 0 for consistency + */ + if(nb==0 && (c&0xc8)!=0x08) + return; + + msg[nb] = c; + if(++nb == 3){ + nb = 0; + if(msg[0] & 0x10) + msg[1] |= 0xFF00; + if(msg[0] & 0x20) + msg[2] |= 0xFF00; + + buttons = b[(msg[0]&7) | (shift ? 8 : 0)]; + dx = msg[1]; + dy = -msg[2]; + mousetrack(buttons, dx, dy); + } + return; +} + +/* + * set up a ps2 mouse + */ +static void +ps2mouse(void) +{ + if(mousetype == MousePS2) + return; + + i8042auxenable(ps2mouseputc); + /* make mouse streaming, enabled */ + i8042auxcmd(0xEA); + i8042auxcmd(0xF4); + + mousetype = MousePS2; +} + +void +mousectl(char* arg) +{ + int n; + char *field[3]; + + n = parsefields(arg, field, 3, " "); + if(strncmp(field[0], "serial", 6) == 0){ + switch(n){ + case 1: + serialmouse(atoi(field[0]+6), 0, 1); + break; + case 2: + serialmouse(atoi(field[1]), 0, 0); + break; + case 3: + default: + serialmouse(atoi(field[1]), field[2], 0); + break; + } + } else if(strcmp(field[0], "ps2") == 0){ + ps2mouse(); + } else if(strcmp(field[0], "accelerated") == 0){ + switch(mousetype){ + case MousePS2: + i8042auxcmd(0xE7); + break; + default: + mouseaccelerate(field[1]); + break; + } + } else if(strcmp(field[0], "linear") == 0){ + switch(mousetype){ + case MousePS2: + i8042auxcmd(0xE6); + break; + default: + mouseaccelerate("0"); + break; + } + } else if(strcmp(field[0], "res") == 0){ + if(n < 2) + n = 1; + else + n = atoi(field[1]); + switch(mousetype){ + case MousePS2: + i8042auxcmd(0xE8); + i8042auxcmd(n); + break; + } + } else if(strcmp(field[0], "swap") == 0) + mouseswap ^= 1; + else + error(Ebadctl); +} diff --git a/pc/mp.c b/pc/mp.c new file mode 100644 index 0000000000000000000000000000000000000000..b04df776b1eebce3dd3556ed770ed432e808048f --- /dev/null +++ b/pc/mp.c @@ -0,0 +1,620 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "mp.h" +#include "apbootstrap.h" + +extern int elcr; + +static Bus* mpbus; +static Bus* mpbuslast; +static Apic mpapic[MaxAPICNO+1]; +static int machno2apicno[MaxAPICNO+1]; /* inverse map: machno -> APIC ID */ +static Lock mprdthilock; +static int mprdthi; + +static char* buses[] = { + "CBUSI ", + "CBUSII", + "EISA ", + "FUTURE", + "INTERN", + "ISA ", + "MBI ", + "MBII ", + "MCA ", + "MPI ", + "MPSA ", + "NUBUS ", + "PCI ", + "PCMCIA", + "TC ", + "VL ", + "VME ", + "XPRESS", + 0, +}; + +static Apic* +mkprocessor(PCMPprocessor* p) +{ + Apic *apic; + + if(!(p->flags & PcmpEN) || p->apicno > MaxAPICNO) + return 0; + + apic = &mpapic[p->apicno]; + apic->type = PcmpPROCESSOR; + apic->apicno = p->apicno; + apic->flags = p->flags; + apic->vecbase = VectorLAPIC; + apic->lintr[0] = ApicIMASK; + apic->lintr[1] = ApicIMASK; + + if(p->flags & PcmpBP){ + machno2apicno[0] = p->apicno; + apic->machno = 0; + } + else{ + machno2apicno[conf.nmach] = p->apicno; + apic->machno = conf.nmach; + conf.nmach++; + } + + return apic; +} + +static Bus* +mkbus(PCMPbus* p) +{ + Bus *bus; + int i; + + for(i = 0; buses[i]; i++){ + if(strncmp(buses[i], p->string, sizeof(p->string)) == 0) + break; + } + if(buses[i] == 0) + return 0; + + bus = xalloc(sizeof(Bus)); + if(mpbus) + mpbuslast->next = bus; + else + mpbus = bus; + mpbuslast = bus; + + bus->type = i; + bus->busno = p->busno; + if(bus->type == BusEISA){ + bus->po = PcmpLOW; + bus->el = PcmpLEVEL; + } + else if(bus->type == BusPCI){ + bus->po = PcmpLOW; + bus->el = PcmpLEVEL; + } + else{ + bus->po = PcmpHIGH; + bus->el = PcmpEDGE; + } + + return bus; +} + +static Bus* +mpgetbus(int busno) +{ + Bus *bus; + + for(bus = mpbus; bus; bus = bus->next){ + if(bus->busno == busno) + return bus; + } + print("mpgetbus: can't find bus %d\n", busno); + + return 0; +} + +static Apic* +mkioapic(PCMPioapic* p) +{ + Apic *apic; + ulong addr, *pte; + + if(!(p->flags & PcmpEN) || p->apicno > MaxAPICNO) + return 0; + + /* + * Map the I/O APIC. This should be in the same 4MB segment + * as MACHADDR so no new 2nd level table will be allocated. + */ + addr = p->addr; + if((pte = mmuwalk(m->pdb, addr, 1)) == 0) + return 0; + if(!(*pte & PTEVALID)){ + *pte = addr|PTEWRITE|PTEUNCACHED|PTEVALID; + mmuflushtlb(PADDR(m->pdb)); + } + + apic = &mpapic[p->apicno]; + apic->type = PcmpIOAPIC; + apic->apicno = p->apicno; + apic->addr = KADDR(addr); + apic->flags = p->flags; + + return apic; +} + +static Aintr* +mkiointr(PCMPintr* p) +{ + Bus *bus; + Aintr *aintr; + + /* + * According to the MultiProcessor Specification, a destination + * I/O APIC of 0xFF means the signal is routed to all I/O APICs. + * It's unclear how that can possibly be correct so treat it as + * an error for now. + */ + if(p->apicno == 0xFF) + return 0; + if((bus = mpgetbus(p->busno)) == 0) + return 0; + + aintr = xalloc(sizeof(Aintr)); + aintr->intr = p; + aintr->apic = &mpapic[p->apicno]; + aintr->next = bus->aintr; + bus->aintr = aintr; + + return aintr; +} + +static int +mpintrinit(Bus* bus, PCMPintr* intr, int vector) +{ + int el, po, v; + + /* + * Parse an I/O or Local APIC interrupt table entry and + * return the encoded vector. + */ + v = vector; + + switch(intr->intr){ + + default: /* PcmpINT */ + v |= ApicLOWEST; + break; + + case PcmpNMI: + v |= ApicNMI; + break; + + case PcmpSMI: + v |= ApicSMI; + break; + + case PcmpExtINT: + v |= ApicExtINT; + break; + } + + po = intr->flags & PcmpPOMASK; + el = intr->flags & PcmpELMASK; + + /* + */ + if(bus->type == BusEISA && !po && !el /*&& !(elcr & (1<<(v-VectorPIC)))*/){ + po = PcmpHIGH; + el = PcmpEDGE; + } + if(!po) + po = bus->po; + if(po == PcmpLOW) + v |= ApicLOW; + else if(po != PcmpHIGH){ + print("mpintrinit: bad polarity 0x%uX\n", po); + return ApicIMASK; + } + + if(!el) + el = bus->el; + if(el == PcmpLEVEL) + v |= ApicLEVEL; + else if(el != PcmpEDGE){ + print("mpintrinit: bad trigger 0x%uX\n", el); + return ApicIMASK; + } + + return v; +} + +static int +mklintr(PCMPintr* p) +{ + Apic *apic; + Bus *bus; + int intin, v; + + /* + * The offsets of vectors for LINT[01] are known to be + * 0 and 1 from the local APIC vector space at VectorLAPIC. + * Can't use apic->vecbase here as this vector may be applied + * to all local APICs (apicno == 0xFF). + */ + if((bus = mpgetbus(p->busno)) == 0) + return 0; + intin = p->intin; + v = mpintrinit(bus, p, VectorLAPIC+intin); + + if(p->apicno == 0xFF){ + for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ + if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR) + apic->lintr[intin] = v; + } + } + else{ + apic = &mpapic[p->apicno]; + if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR) + apic->lintr[intin] = v; + } + + return v; +} + +#define PDX(va) ((((ulong)(va))>>22) & 0x03FF) +#define PTX(va) ((((ulong)(va))>>12) & 0x03FF) + +static void +squidboy(Apic* apic) +{ + int clkin; + + /*iprint("Hello Squidboy\n");*/ + + machinit(); + mmuinit(); + + cpuidentify(); + cpuidprint(); + + lock(&mprdthilock); + mprdthi |= (1<apicno)<<24; + unlock(&mprdthilock); + + /* + * Restrain your octopus! Don't let it go out on the sea! + */ + while(MACHP(0)->ticks == 0) + ; + + clkin = lapicinit(apic); + lapiconline(clkin); + + lock(&active); + active.machs |= 1<machno; + unlock(&active); + + schedinit(); +} + +static void +mpstartap(Apic* apic) +{ + ulong *apbootp, *pdb, *pte; + Mach *mach; + int i, machno; + uchar *p; + + /* + * Initialise the AP page-tables and Mach structure. These are + * the same as for the bootstrap processor with the exception of + * the PTE for the Mach structure. + * Xspanalloc will panic if an allocation can't be made. + */ + pdb = xspanalloc(3*BY2PG, BY2PG, 0); + memmove(pdb, (void*)CPU0PDB, BY2PG); + + pte = (ulong*)(((uchar*)pdb)+BY2PG); + memmove(pte, (void*)CPU0MACHPTE, BY2PG); + pdb[PDX(MACHADDR)] = PADDR(pte)|PTEWRITE|PTEVALID; + + mach = (Mach*)(((uchar*)pdb)+2*BY2PG); + if((pte = mmuwalk(pdb, MACHADDR, 0)) == 0) + return; + *pte = PADDR(mach)|PTEWRITE|PTEVALID; + + machno = apic->machno; + MACHP(machno) = mach; + mach->machno = machno; + mach->pdb = pdb; + + /* + * Tell the AP where its kernel vector and pdb are. + * The offsets are known in the AP bootstrap code. + */ + apbootp = (ulong*)(APBOOTSTRAP+0x08); + *apbootp++ = (ulong)squidboy; + *apbootp++ = PADDR(pdb); + *apbootp = (ulong)apic; + + /* + * Universal Startup Algorithm. + */ + p = KADDR(0x467); + *p++ = PADDR(APBOOTSTRAP); + *p++ = PADDR(APBOOTSTRAP)>>8; + i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16; + *p++ = i; + *p = i>>8; + + nvramwrite(0x0F, 0x0A); + lapicstartap(apic, PADDR(APBOOTSTRAP)); + for(i = 0; i < 100000 && (active.machs & (1<physaddr); + clkin = 0; + + /* + * Map the local APIC. This should be in the same 4MB segment + * as MACHADDR so no new 2nd level table will be allocated. + */ + if((pte = mmuwalk(m->pdb, pcmp->lapicbase, 1)) == 0) + return; + if(!(*pte & PTEVALID)){ + *pte = pcmp->lapicbase|PTEWRITE|PTEUNCACHED|PTEVALID; + mmuflushtlb(PADDR(m->pdb)); + } + + /* + * Run through the table saving information needed for starting application + * processors and initialising any I/O APICs. The table is guaranteed to be in + * order such that only one pass is necessary. + */ + p = ((uchar*)pcmp)+sizeof(PCMP); + e = ((uchar*)pcmp)+pcmp->length; + while(p < e) switch(*p){ + + case PcmpPROCESSOR: + if(apic = mkprocessor((PCMPprocessor*)p)){ + /* + * Must initialise the bootstrap processor APIC + * now as it will be needed in order to start the + * application processors later and there's no + * guarantee that the bootstrap processor appears + * first in the table before the others. + */ + apic->addr = KADDR(pcmp->lapicbase); + if(apic->flags & PcmpBP) + clkin = lapicinit(apic); + } + p += sizeof(PCMPprocessor); + continue; + + case PcmpBUS: + mkbus((PCMPbus*)p); + p += sizeof(PCMPbus); + continue; + + case PcmpIOAPIC: + if(apic = mkioapic((PCMPioapic*)p)) + ioapicinit(apic, ((PCMPioapic*)p)->apicno); + p += sizeof(PCMPioapic); + continue; + + case PcmpIOINTR: + mkiointr((PCMPintr*)p); + p += sizeof(PCMPintr); + continue; + + case PcmpLINTR: + mklintr((PCMPintr*)p); + p += sizeof(PCMPintr); + continue; + } + + /* + * Initialise all the processors. + */ + memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap)); + for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ + if(!(apic->flags & PcmpEN) || apic->type != PcmpPROCESSOR) + continue; + + if(apic->flags & PcmpBP){ + lock(&mprdthilock); + mprdthi |= (1<apicno)<<24; + unlock(&mprdthilock); + + /* + * These interrupts are local to the processor + * and do not appear in the I/O APIC so it is OK + * to set them now. + */ + intrenable(VectorTIMER, clockintr, 0, BUSUNKNOWN); + intrenable(VectorERROR, lapicerror, 0, BUSUNKNOWN); + intrenable(VectorSPURIOUS, lapicspurious, 0, BUSUNKNOWN); + lapiconline(clkin); + continue; + } + + mpstartap(apic); + } + + /* + * Remember to set conf.copymode here if nmach > 1. + * Look for an ExtINT line and enable it. + */ + if(conf.nmach > 1) + conf.copymode = 1; +} + +static int +mpintrenablex(int v, int tbdf, Irqctl* irqctl) +{ + Bus *bus; + Aintr *aintr; + Apic *apic; + int bno, dno, lo, n, type; + + if(v >= VectorLAPIC && v <= MaxVectorLAPIC){ + if(v != VectorSPURIOUS) + irqctl->isr = lapiceoi; + irqctl->isintr = 1; + return v; + } + + if(v < VectorPIC || v > MaxVectorPIC) + return 0; + + /* + * Find the bus, default is ISA. + * There cannot be multiple ISA or EISA buses. + */ + if(tbdf == BUSUNKNOWN){ + type = BusISA; + bno = 0; + dno = -1; + } + else{ + type = BUSTYPE(tbdf); + bno = BUSBNO(tbdf); + dno = BUSDNO(tbdf); + } + n = 0; + for(bus = mpbus; bus; bus = bus->next){ + if(bus->type != type) + continue; + if(n == bno) + break; + n++; + } + if(bus == 0){ + /* + * The MP configuration table on some older systems + * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus + * but none for ISA. It also has the interrupt type and + * polarity set to 'default for this bus' which wouldn't + * be compatible with ISA. + */ + for(bus = mpbus; bus; bus = bus->next){ + if(bus->type == BusEISA) + break; + } + if(bus == 0){ + print("ioapicirq: can't find bus type %d\n", type); + return -1; + } + } + + /* + * Find the interrupt info. + */ + for(aintr = bus->aintr; aintr; aintr = aintr->next){ + if(bus->type == BusPCI){ + n = (aintr->intr->irq>>2) & 0x1F; + if(n != dno) + continue; + } + else{ + n = aintr->intr->irq; + if(n != (v-VectorPIC)) + continue; + } + + lo = mpintrinit(bus, aintr->intr, v); + if(lo & ApicIMASK) + return -1; + lo |= ApicLOGICAL; + + apic = aintr->apic; + if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC){ + lock(&mprdthilock); + ioapicrdtw(apic, aintr->intr->intin, mprdthi, lo); + unlock(&mprdthilock); + } + + irqctl->isr = lapicisr; + irqctl->eoi = lapiceoi; + irqctl->isintr = 1; + + return lo & 0xFF; + } + + return -1; +} + +int +mpintrenable(int v, int tbdf, Irqctl* irqctl) +{ + int r; + + r = mpintrenablex(v, tbdf, irqctl); + if(r == -1 && tbdf != BUSUNKNOWN && _mp_->specrev == 1) + return mpintrenablex(v, BUSUNKNOWN, irqctl); + return r; +} + +void +mpshutdown(void) +{ + /* + * To be done... + */ + if(m->machno){ + /* + * If this processor received the CTRL-ALT-DEL from + * the keyboard, acknowledge it. Send an INIT to self. + */ + if(lapicisr(VectorKBD)) + lapiceoi(VectorKBD); + lapicicrw(0, 0x00040000|ApicINIT); + idle(); + } + + print("apshutdown: active = 0x%2.2uX\n", active.machs); + delay(1000); + splhi(); + + /* + * INIT all excluding self. + */ + lapicicrw(0, 0x000C0000|ApicINIT); + +#ifdef notdef + /* + * Often the BIOS hangs during restart if a conventional 8042 + * warm-boot sequence is tried. The following is Intel specific and + * seems to perform a cold-boot, but at least it comes back. + */ + *(ushort*)(KZERO|0x472) = 0x1234; /* BIOS warm-boot flag */ + outb(0xCF9, 0x02); + outb(0xCF9, 0x06); +#else + pcireset(); + i8042reset(); +#endif /* notdef */ +} diff --git a/pc/mp.h b/pc/mp.h new file mode 100644 index 0000000000000000000000000000000000000000..15b75a0bf10fcb6ab4653d1f2c6046542620dcf0 --- /dev/null +++ b/pc/mp.h @@ -0,0 +1,226 @@ +/* + * MultiProcessor Specification Version 1.[14]. + */ +typedef struct { /* floating pointer */ + uchar signature[4]; /* "_MP_" */ + long physaddr; /* physical address of MP configuration table */ + uchar length; /* 1 */ + uchar specrev; /* [14] */ + uchar checksum; /* all bytes must add up to 0 */ + uchar type; /* MP system configuration type */ + uchar imcrp; + uchar reserved[3]; +} _MP_; + +typedef struct { /* configuration table header */ + uchar signature[4]; /* "PCMP" */ + ushort length; /* total table length */ + uchar version; /* [14] */ + uchar checksum; /* all bytes must add up to 0 */ + uchar product[20]; /* product id */ + ulong oemtable; /* OEM table pointer */ + ushort oemlength; /* OEM table length */ + ushort entry; /* entry count */ + ulong lapicbase; /* address of local APIC */ + ushort xlength; /* extended table length */ + uchar xchecksum; /* extended table checksum */ + uchar reserved; +} PCMP; + +typedef struct { /* processor table entry */ + uchar type; /* entry type (0) */ + uchar apicno; /* local APIC id */ + uchar version; /* local APIC verison */ + uchar flags; /* CPU flags */ + uchar signature[4]; /* CPU signature */ + ulong feature; /* feature flags from CPUID instruction */ + uchar reserved[8]; +} PCMPprocessor; + +typedef struct { /* bus table entry */ + uchar type; /* entry type (1) */ + uchar busno; /* bus id */ + char string[6]; /* bus type string */ +} PCMPbus; + +typedef struct { /* I/O APIC table entry */ + uchar type; /* entry type (2) */ + uchar apicno; /* I/O APIC id */ + uchar version; /* I/O APIC version */ + uchar flags; /* I/O APIC flags */ + ulong addr; /* I/O APIC address */ +} PCMPioapic; + +typedef struct { /* interrupt table entry */ + uchar type; /* entry type ([34]) */ + uchar intr; /* interrupt type */ + ushort flags; /* interrupt flag */ + uchar busno; /* source bus id */ + uchar irq; /* source bus irq */ + uchar apicno; /* destination APIC id */ + uchar intin; /* destination APIC [L]INTIN# */ +} PCMPintr; + +typedef struct { /* system address space mapping entry */ + uchar type; /* entry type (128) */ + uchar length; /* of this entry (20) */ + uchar busno; /* bus id */ + uchar addrtype; + ulong addrbase[2]; + ulong addrlength[2]; +} PCMPsasm; + +typedef struct { /* bus hierarchy descriptor entry */ + uchar type; /* entry type (129) */ + uchar length; /* of this entry (8) */ + uchar busno; /* bus id */ + uchar info; /* bus info */ + uchar parent; /* parent bus */ + uchar reserved[3]; +} PCMPhierarchy; + +typedef struct { /* compatibility bus address space modifier entry */ + uchar type; /* entry type (130) */ + uchar length; /* of this entry (8) */ + uchar busno; /* bus id */ + uchar modifier; /* address modifier */ + ulong range; /* predefined range list */ +} PCMPcbasm; + +enum { /* table entry types */ + PcmpPROCESSOR = 0x00, /* one entry per processor */ + PcmpBUS = 0x01, /* one entry per bus */ + PcmpIOAPIC = 0x02, /* one entry per I/O APIC */ + PcmpIOINTR = 0x03, /* one entry per bus interrupt source */ + PcmpLINTR = 0x04, /* one entry per system interrupt source */ + + PcmpSASM = 0x80, + PcmpHIERARCHY = 0x81, + PcmpCBASM = 0x82, + + /* PCMPprocessor and PCMPioapic flags */ + PcmpEN = 0x01, /* enabled */ + PcmpBP = 0x02, /* bootstrap processor */ + + /* PCMPiointr and PCMPlintr flags */ + PcmpPOMASK = 0x03, /* polarity conforms to specifications of bus */ + PcmpHIGH = 0x01, /* active high */ + PcmpLOW = 0x03, /* active low */ + PcmpELMASK = 0x0C, /* trigger mode of APIC input signals */ + PcmpEDGE = 0x04, /* edge-triggered */ + PcmpLEVEL = 0x0C, /* level-triggered */ + + /* PCMPiointr and PCMPlintr interrupt type */ + PcmpINT = 0x00, /* vectored interrupt from APIC Rdt */ + PcmpNMI = 0x01, /* non-maskable interrupt */ + PcmpSMI = 0x02, /* system management interrupt */ + PcmpExtINT = 0x03, /* vectored interrupt from external PIC */ + + /* PCMPsasm addrtype */ + PcmpIOADDR = 0x00, /* I/O address */ + PcmpMADDR = 0x01, /* memory address */ + PcmpPADDR = 0x02, /* prefetch address */ + + /* PCMPhierarchy info */ + PcmpSD = 0x01, /* subtractive decode bus */ + + /* PCMPcbasm modifier */ + PcmpPR = 0x01, /* predefined range list */ +}; + +/* + * Condensed form of the MP Configuration Table. + * This is created during a single pass through the MP Configuration + * table. + */ +typedef struct Aintr Aintr; +typedef struct Bus Bus; +typedef struct Apic Apic; + +typedef struct Bus { + uchar type; + uchar busno; + uchar po; + uchar el; + + Aintr* aintr; /* interrupts tied to this bus */ + Bus* next; +} Bus; + +typedef struct Aintr { + PCMPintr* intr; + Apic* apic; + Aintr* next; +}; + +typedef struct Apic { + int type; + int apicno; + ulong* addr; /* register base address */ + int flags; /* PcmpBP|PcmpEN */ + int vecbase; /* starting vector offset */ + + Lock; /* I/O APIC: register access */ + int mre; /* I/O APIC: maximum redirection entry */ + + int lintr[2]; /* Local APIC */ + int machno; +} Apic; + +enum { + MaxAPICNO = 7, +}; + +enum { /* I/O APIC registers */ + IoapicID = 0x00, /* ID */ + IoapicVER = 0x01, /* version */ + IoapicARB = 0x02, /* arbitration ID */ + IoapicRDT = 0x10, /* redirection table */ +}; + +/* + * Common bits for + * I/O APIC Redirection Table Entry; + * Local APIC Local Interrupt Vector Table; + * Local APIC Inter-Processor Interrupt; + * Local APIC Timer Vector Table. + */ +enum { + ApicFIXED = 0x00000000, /* [10:8] Delivery Mode */ + ApicLOWEST = 0x00000100, /* Lowest priority */ + ApicSMI = 0x00000200, /* System Management Interrupt */ + ApicRR = 0x00000300, /* Remote Read */ + ApicNMI = 0x00000400, + ApicINIT = 0x00000500, /* INIT/RESET */ + ApicSTARTUP = 0x00000600, /* Startup IPI */ + ApicExtINT = 0x00000700, + + ApicPHYSICAL = 0x00000000, /* [11] Destination Mode (RW) */ + ApicLOGICAL = 0x00000800, + + ApicDELIVS = 0x00001000, /* [12] Delivery Status (RO) */ + ApicHIGH = 0x00000000, /* [13] Interrupt Input Pin Polarity (RW) */ + ApicLOW = 0x00002000, + ApicRemoteIRR = 0x00004000, /* [14] Remote IRR (RO) */ + ApicEDGE = 0x00000000, /* [15] Trigger Mode (RW) */ + ApicLEVEL = 0x00008000, + ApicIMASK = 0x00010000, /* [16] Interrupt Mask */ +}; + +extern void ioapicrdtr(Apic*, int, int*, int*); +extern void ioapicrdtw(Apic*, int, int, int); +extern void ioapicinit(Apic*, int); +extern void lapiconline(int); +extern int lapicinit(Apic*); +extern void lapicstartap(Apic*, int); +extern void lapicerror(Ureg*, void*); +extern void lapicspurious(Ureg*, void*); +extern int lapicisr(int); +extern int lapiceoi(int); +extern void lapicicrw(int, int); + +extern void mpinit(void); +extern void mpshutdown(void); +extern int mpintrenable(int, int, Irqctl*); + +extern _MP_ *_mp_; diff --git a/pc/ns16552.h b/pc/ns16552.h index 2dd1c4c7bb7df5d84ace6e65f7fd07a0c0a3bfd6..5b1c0901d8463aea995c2a5f64b2e81a47e47a2e 100644 --- a/pc/ns16552.h +++ b/pc/ns16552.h @@ -15,7 +15,8 @@ enum #define uartrdreg(u,r) inb((u)->port + r) void ns16552setup(ulong, ulong, char*); - +void ns16552special(int, int, Queue**, Queue**, int (*)(Queue*, int)); +void uartclock(void); /* * definition of an optional serial card */ @@ -32,11 +33,11 @@ uartpower(int dev, int onoff) { switch(dev){ case Modem: - if(modem(onoff) < 0) + if((*arch->modempower)(onoff) < 0) print("can't turn %s modem speaker\n", onoff?"on":"off"); break; case Serial: - if(serial(onoff) < 0) + if((*arch->serialpower)(onoff) < 0) print("can't turn %s serial port power\n", onoff?"on":"off"); break; } @@ -46,10 +47,8 @@ uartpower(int dev, int onoff) * handle an interrupt to a single uart */ static void -ns16552intrx(Ureg *ur, void *arg) +ns16552intrx(Ureg*, void* arg) { - USED(ur); - ns16552intr((ulong)arg); } @@ -58,13 +57,12 @@ ns16552intrx(Ureg *ur, void *arg) * tells which of 8 devices interrupted. */ static void -mp008intr(Ureg *ur, void *arg) +mp008intr(Ureg* ureg, void* arg) { int i, loops; uchar n; Scard *mp; - USED(ur); mp = arg; for(loops = 0; loops < 1024; loops++){ n = ~inb(mp->mem); @@ -72,7 +70,7 @@ mp008intr(Ureg *ur, void *arg) return; for(i = 0; n; i++){ if(n & 1) - ns16552intrx(ur, (void*)(mp->first+i)); + ns16552intrx(ureg, (void*)(mp->first+i)); n >>= 1; } } @@ -85,7 +83,7 @@ void ns16552install(void) { int i, j, port, nscard; - char *p; + char *p, *q; Scard *sc; char name[NAMELEN]; static int already; @@ -96,14 +94,17 @@ ns16552install(void) /* first two ports are always there and always the normal frequency */ ns16552setup(0x3F8, UartFREQ, "eia0"); - setvec(Uart0vec, ns16552intrx, (void*)0); + intrenable(VectorUART0, ns16552intrx, (void*)0, BUSUNKNOWN); ns16552setup(0x2F8, UartFREQ, "eia1"); - setvec(Uart1vec, ns16552intrx, (void*)1); + intrenable(VectorUART1, ns16552intrx, (void*)1, BUSUNKNOWN); + addclock0link(uartclock); /* set up a serial console */ - p = getconf("console"); - if(p) - ns16552special(atoi(p), 9600, &kbdq, &printq, kbdcr2nl); + if(p = getconf("console")){ + port = strtol(p, &q, 0); + if(p != q && (port == 0 || port == 1)) + ns16552special(port, 9600, &kbdq, &printq, kbdcr2nl); + } /* the rest come out of plan9.ini */ nscard = 0; @@ -128,7 +129,7 @@ ns16552install(void) if(sc->freq == 0) sc->freq = UartFREQ; sc->first = nuart; - setvec(Int0vec+sc->irq, mp008intr, sc); + intrenable(VectorPIC+sc->irq, mp008intr, sc, BUSUNKNOWN); port = sc->port; for(j=0; j < sc->size; j++){ sprint(name, "eia%d%2.2d", nscard, j); @@ -145,7 +146,7 @@ ns16552install(void) sc->freq = UartFREQ; sprint(name, "eia%d00", nscard); ns16552setup(sc->port, sc->freq, name); - setvec(Int0vec+sc->irq, ns16552intrx, (void*)(nuart-1)); + intrenable(VectorPIC+sc->irq, ns16552intrx, (void*)(nuart-1), BUSUNKNOWN); } nscard++; } diff --git a/pc/pci.c b/pc/pci.c index 07e76348cd3259e3382e2364239e777c36e94f90..f5aa72bb03102cd8898ea2b5c9e571d498016de0 100644 --- a/pc/pci.c +++ b/pc/pci.c @@ -1,6 +1,7 @@ /* - * Trivial PCI configuration code. - * Only deals with bus 0, amongst other glaring omissions. + * PCI support code. + * To do: + * initialise bridge mappings if the PCI BIOS didn't. */ #include "u.h" #include "../port/lib.h" @@ -10,204 +11,412 @@ #include "io.h" #include "../port/error.h" -static Lock pcicfglock; +enum { /* configuration mechanism #1 */ + PciADDR = 0xCF8, /* CONFIG_ADDRESS */ + PciDATA = 0xCFC, /* CONFIG_DATA */ + + /* configuration mechanism #2 */ + PciCSE = 0xCF8, /* configuration space enable */ + PciFORWARD = 0xCFA, /* which bus */ + MaxFNO = 7, + MaxUBN = 255, +}; + +static Lock pcicfglock; +static Lock pcicfginitlock; static int pcicfgmode = -1; +static int pcimaxdno; +static Pcidev* pciroot; -static void -pcicfginit(int) +static int pcicfgrw8(int, int, int, int); +static int pcicfgrw16(int, int, int, int); +static int pcicfgrw32(int, int, int, int); + +static int +pciscan(int bno, Pcidev** list) { + Pcidev *p, *head, *tail; + int dno, fno, l, maxfno, maxubn, sbn, tbdf, ubn; + + maxubn = bno; + head = tail = 0; + for(dno = 0; dno < pcimaxdno; dno++){ + maxfno = 0; + for(fno = 0; fno <= maxfno; fno++){ + /* + * For this possible device, form the bus+device+function + * triplet needed to address it and try to read the vendor + * and device ID. If successful, allocate a device struct + * and start to fill it in with some useful information from + * the device's configuration space. + */ + tbdf = MKBUS(BusPCI, bno, dno, fno); + l = pcicfgrw32(tbdf, PciVID, 0, 1); + if(l == 0xFFFFFFFF || l == 0) + continue; + p = malloc(sizeof(*p)); + p->tbdf = tbdf; + p->vid = l; + p->did = l>>16; + p->bar[0] = pcicfgrw32(tbdf, PciBAR0, 0, 1); + p->bar[1] = pcicfgrw32(tbdf, PciBAR1, 0, 1); + p->intl = pcicfgrw8(tbdf, PciINTL, 0, 1); + + /* + * Read the base and sub- class and if the device is + * a bridge put it on a list of buses to be descended + * later. + * If it's not a bridge just add it to the tail of the + * device list. + */ + l = pcicfgrw16(tbdf, PciCCRu, 0, 1); + if(l == ((0x06<<8)|0x04)){ + if(head) + tail->next = p; + else + head = p; + tail = p; + } + else{ + *list = p; + list = &p->next; + } + + /* + * If the device is a multi-function device adjust the + * loop count so all possible functions are checked. + */ + l = pcicfgrw8(tbdf, PciHDT, 0, 1); + if(l & 0x80) + maxfno = MaxFNO; + } + } + /* - * Try to determine which PCI configuration mode is implemented. - * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses - * a DWORD at 0xCF8 and another at 0xCFC and will pass through - * any non-DWORD accesses as normal I/O cycles. There shouldn't be - * a device behind theses addresses so if Mode2 accesses fail try - * for Mode1 (which is preferred, Mode2 is deprecated). + * If any bridges were found, recursively descend the tree. + * The end result will be a single list of all devices in ascending + * bus number order. */ - outb(PCIcse, 0); - if(inb(PCIcse) == 0){ - pcicfgmode = 2; - return; - } + for(p = head; p; p = head){ + /* + * Take the primary bridge device off the bridge list + * and link to the end of the final device list. + */ + head = p->next; + p->next = 0; + *list = p; + list = &p->next; - outl(PCIaddr, 0); - if(inl(PCIaddr) == 0){ - pcicfgmode = 1; - return; + /* + * If the secondary or subordinate bus number is not initialised + * try to do what the PCI BIOS should have done and fill in the + * numbers as the tree is descended. On the way down the subordinate + * bus number is set to the maximum as it's not known how many + * buses are behind this one; the final value is set on the way + * back up. + */ + tbdf = p->tbdf; + sbn = pcicfgrw8(tbdf, PciSBN, 0, 1); + ubn = pcicfgrw8(tbdf, PciUBN, 0, 1); + if(sbn == 0 || ubn == 0){ + sbn = maxubn+1; + /* + * Make sure memory, I/O and master enables are off, + * set the primary, secondary and subordinate bus numbers + * and clear the secondary status before attempting to + * scan the secondary bus. + * + * Initialisation of the bridge should be done here. + */ + pcicfgrw32(tbdf, PciPCR, 0xFFFF0000, 0); + l = (MaxUBN<<16)|(sbn<<8)|bno; + pcicfgrw32(tbdf, PciPBN, l, 0); + pcicfgrw16(tbdf, PciSPSR, 0xFFFF, 0); + maxubn = pciscan(sbn, list); + l = (maxubn<<16)|(sbn<<8)|bno; + pcicfgrw32(tbdf, PciPBN, l, 0); + } + else{ + maxubn = ubn; + pciscan(sbn, list); + } } - pcicfgmode = -1; + return maxubn; } -/* - * Read a chunk of PCI configuration space. - * Assumes arguments are within limits and regno and - * nbytes are DWORD aligned. - */ -void -pcicfgr(int busno, int devno, int funcno, int regno, void* data, int nbytes) +static void +pcicfginit(void) +{ + lock(&pcicfginitlock); + if(pcicfgmode == -1){ + /* + * Try to determine which PCI configuration mode is implemented. + * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses + * a DWORD at 0xCF8 and another at 0xCFC and will pass through + * any non-DWORD accesses as normal I/O cycles. There shouldn't be + * a device behind theses addresses so if Mode2 accesses fail try + * for Mode1 (which is preferred, Mode2 is deprecated). + */ + outb(PciCSE, 0); + if(inb(PciCSE) == 0){ + pcicfgmode = 2; + pcimaxdno = 31; + } + else{ + outl(PciADDR, 0); + if(inl(PciADDR) == 0){ + pcicfgmode = 1; + pcimaxdno = 15; + } + } + + if(pcicfgmode > 0) + pciscan(0, &pciroot); + } + unlock(&pcicfginitlock); +} + +static int +pcicfgrw8(int tbdf, int rno, int data, int read) { - ulong addr, *p; - int base, len; + int o, type, x; - lock(&pcicfglock); if(pcicfgmode == -1) - pcicfginit(busno); + pcicfginit(); + + if(BUSBNO(tbdf)) + type = 0x01; + else + type = 0x00; + x = -1; + if(BUSDNO(tbdf) >= pcimaxdno) + return x; + lock(&pcicfglock); switch(pcicfgmode){ case 1: - addr = 0x80000000|((busno & 0xFF)<<16)|((devno & 0x1F)<<11)|((funcno & 0x03)<<8); - p = data; - for(len = nbytes/sizeof(ulong); len > 0; len--){ - outl(PCIaddr, addr|(regno & 0xFF)); - *p = inl(PCIdata); - p++; - regno += sizeof(ulong); - } - - outl(PCIaddr, 0); + o = rno & 0x03; + rno &= ~0x03; + outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); + if(read) + x = inb(PciDATA+o); + else + outb(PciDATA+o, data); + outl(PciADDR, 0); break; case 2: - if(devno >= 16) - break; - outb(PCIcse, 0x80|((funcno & 0x07)<<1)); - outb(PCIforward, busno); - - base = (0xC000|(devno<<8)) + regno; - p = data; - for(len = nbytes/sizeof(ulong); len > 0; len--){ - *p = inl(base); - p++; - base += sizeof(*p); - } - - outb(PCIcse, 0); + outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); + outb(PciFORWARD, BUSBNO(tbdf)); + if(read) + x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno); + else + outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); + outb(PciCSE, 0); break; } - unlock(&pcicfglock); + + return x; +} + +int +pcicfgr8(Pcidev* pcidev, int rno) +{ + return pcicfgrw8(pcidev->tbdf, rno, 0, 1); } void -pcicfgw(int busno, int devno, int funcno, int regno, void* data, int nbytes) +pcicfgw8(Pcidev* pcidev, int rno, int data) +{ + pcicfgrw8(pcidev->tbdf, rno, data, 0); +} + +static int +pcicfgrw16(int tbdf, int rno, int data, int read) { - ulong addr, *p; - int base, len; + int o, type, x; - lock(&pcicfglock); if(pcicfgmode == -1) - pcicfginit(busno); + pcicfginit(); + + if(BUSBNO(tbdf)) + type = 0x01; + else + type = 0x00; + x = -1; + if(BUSDNO(tbdf) >= pcimaxdno) + return x; + lock(&pcicfglock); switch(pcicfgmode){ case 1: - addr = 0x80000000|((busno & 0xFF)<<16)|((devno & 0x1F)<<11)|((funcno & 0x03)<<8); - p = data; - for(len = nbytes/sizeof(*p); len > 0; len--){ - outl(PCIaddr, addr|(regno & 0xFF)); - outl(PCIdata, *p); - p++; - regno += sizeof(*p); - } - - outl(PCIaddr, 0); + o = rno & 0x02; + rno &= ~0x03; + outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); + if(read) + x = ins(PciDATA+o); + else + outs(PciDATA+o, data); + outl(PciADDR, 0); break; case 2: - if(devno >= 16) - break; - outb(PCIcse, 0x80|((funcno & 0x07)<<1)); - outb(PCIforward, busno); - - base = (0xC000|(devno<<8)) + regno; - p = data; - for(len = nbytes/sizeof(*p); len > 0; len--){ - outl(base, *p); - p++; - base += sizeof(*p); - } - - outb(PCIcse, 0); + outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); + outb(PciFORWARD, BUSBNO(tbdf)); + if(read) + x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno); + else + outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); + outb(PciCSE, 0); + break; } - unlock(&pcicfglock); + + return x; +} + +int +pcicfgr16(Pcidev* pcidev, int rno) +{ + return pcicfgrw16(pcidev->tbdf, rno, 0, 1); } -/* - * This is not in the spec, but at least the CMD640B requires it. - */ void -pcicfgw8(int busno, int devno, int funcno, int regno, void* data, int nbytes) +pcicfgw16(Pcidev* pcidev, int rno, int data) +{ + pcicfgrw16(pcidev->tbdf, rno, data, 0); +} + +static int +pcicfgrw32(int tbdf, int rno, int data, int read) { - ulong addr; - uchar *p; - int base, len; + int type, x; - lock(&pcicfglock); if(pcicfgmode == -1) - pcicfginit(busno); + pcicfginit(); + + if(BUSBNO(tbdf)) + type = 0x01; + else + type = 0x00; + x = -1; + if(BUSDNO(tbdf) >= pcimaxdno) + return x; + lock(&pcicfglock); switch(pcicfgmode){ - default: - addr = 0x80000000|((busno & 0xFF)<<16)|((devno & 0x1F)<<11)|((funcno & 0x03)<<8); - p = data; - for(len = nbytes/sizeof(*p); len > 0; len--){ - outl(PCIaddr, addr|(regno & 0xFF)); - outb(PCIdata, *p); - p++; - regno += sizeof(*p); - } - - outl(PCIaddr, 0); - break; + case 1: + rno &= ~0x03; + outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); + if(read) + x = inl(PciDATA); + else + outl(PciDATA, data); + outl(PciADDR, 0); break; case 2: - if(devno >= 16) - break; - outb(PCIcse, 0x80|((funcno & 0x07)<<1)); - outb(PCIforward, busno); - - base = (0xC000|(devno<<8)) + regno; - p = data; - for(len = nbytes/sizeof(*p); len > 0; len--){ - outb(base, *p); - p++; - base += sizeof(*p); - } - - outb(PCIcse, 0); + outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); + outb(PciFORWARD, BUSBNO(tbdf)); + if(read) + x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno); + else + outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); + outb(PciCSE, 0); + break; } - unlock(&pcicfglock); + + return x; } int -pcimatch(int busno, int devno, PCIcfg* pcicfg) +pcicfgr32(Pcidev* pcidev, int rno) { - ulong l; + return pcicfgrw32(pcidev->tbdf, rno, 0, 1); +} + +void +pcicfgw32(Pcidev* pcidev, int rno, int data) +{ + pcicfgrw32(pcidev->tbdf, rno, data, 0); +} + +Pcidev* +pcimatch(Pcidev* previous, int vid, int did) +{ + Pcidev *p; - lock(&pcicfglock); if(pcicfgmode == -1) - pcicfginit(busno); - unlock(&pcicfglock); + pcicfginit(); - while(devno < MaxPCI){ - if(pcicfgmode == 2 && devno >= 16) - break; - l = 0; - pcicfgr(busno, devno, 0, 0, &l, sizeof(ulong)); - devno++; - if((l & 0xFFFF) != pcicfg->vid) - continue; - if(pcicfg->did && ((l>>16) & 0xFFFF) != pcicfg->did) + if(previous == 0) + previous = pciroot; + else + previous = previous->next; + + for(p = previous; p; p = p->next){ + if(p->vid != vid) continue; - pcicfgr(busno, devno-1, 0, 0, pcicfg, sizeof(PCIcfg)); - return devno; + if(did == 0 || p->did == did) + break; + } + + return p; +} + +void +pcireset(void) +{ + Pcidev *p; + int pcr; + + if(pcicfgmode == -1) + pcicfginit(); + + for(p = pciroot; p; p = p->next){ + pcr = pcicfgr16(p, PciPSR); + pcicfgw16(p, PciPSR, pcr & ~0x04); + } +} + +/* + * Hack for now to get SYMBIOS controller on-line. + */ +void* +pcimemmap(int tbdf, int rno, ulong *paddr) +{ + long size; + ulong p, v; + + if(pcicfgmode == -1) + pcicfginit(); + + v = pcicfgrw32(tbdf, rno, 0, 1); + if(v & 1){ + print("pcimemmap: not a memory base register\n"); + return 0; + } + if(v & 6){ + print("pcimemmap: only 32 bit relocs supported\n"); + return 0; } - return -1; + v = 0xFFFFFFFF; + pcicfgrw32(tbdf, rno, v, 0); + v = pcicfgrw32(tbdf, rno, 0, 1); + /* clear out bottom bits and negate to find size */ + size = -(v & ~0x0F); + v = umbmalloc(0, size, size); +print("rno %uX, size %uX, v %uX\n", rno, size, v); + p = PADDR(v); + if(paddr) + *paddr = p; + pcicfgrw32(tbdf, rno, p, 0); + return (void*)v; } diff --git a/pc/screen.h b/pc/screen.h index ac28818ff1b263dad2b2a75ce37568c1b0e1a93e..6b7600460ca983fcdf3a42cc48afc9385dea72c6 100644 --- a/pc/screen.h +++ b/pc/screen.h @@ -14,8 +14,27 @@ struct Cursorinfo }; Cursorinfo cursor; +Cursor curs; extern int cursoron(int); extern void cursoroff(int); -extern Point mousexy(void); -extern void cursorinit(void); extern void setcursor(Cursor*); + +/* + * mouse types + */ +enum +{ + Mouseother= 0, + Mouseserial= 1, + MousePS2= 2, +}; +extern int mousetype; + +extern void mousectl(char*); +extern void mousetrack(int, int, int); +extern Point mousexy(void); + +extern void mouseaccelerate(char*); +extern int m3mouseputc(void*, int); +extern int mouseputc(void*, int); +extern int mouseswap; diff --git a/pc/scsi.c b/pc/scsi.c index a801ccd8a01a43ba98cb7218334a3237462d1f72..7ebe7f7f817c39ea7966efd5e7a7175ab9a7cb6a 100644 --- a/pc/scsi.c +++ b/pc/scsi.c @@ -75,7 +75,7 @@ scsireset(void) for(lp = link; lp; lp = lp->link){ if(strcmp(lp->type, ctlr->type)) continue; - if((ctlr->io = (*lp->reset)(ctlrno, ctlr)) == 0) + if((ctlr->io = lp->reset(ctlrno, ctlr)) == 0) break; print("scsi#%d: %s: port 0x%luX irq %d", @@ -116,7 +116,7 @@ scsiexec(Target *t, int rw, uchar *cmd, int cbytes, void *data, int *dbytes) * There should be no calls to 'error()' below this * which percolate back up. */ - switch(s = (*scsi[t->ctlrno]->io)(t, rw, cmd, cbytes, data, dbytes)){ + switch(s = scsi[t->ctlrno]->io(t, rw, cmd, cbytes, data, dbytes)){ case STcheck: memmove(lastcmd, cmd, cbytes); @@ -245,7 +245,6 @@ scsiinv(int devno, int *type, Target **rt, uchar **inq, char *id) return -1; } - int scsitest(Target *t, char lun) { @@ -540,8 +539,8 @@ scsireadcdda(Target *t, char lun, int, void *b, long n, long bsize, long bno) cmd[3] = bno>>16; cmd[4] = bno>>8; cmd[5] = bno; - cmd[8] = n>>8; - cmd[9] = n; + cmd[6] = n>>8; + cmd[7] = n; nbytes = n*bsize; s = scsiexec(t, SCSIread, cmd, sizeof(cmd), b, &nbytes); diff --git a/pc/trap.c b/pc/trap.c index 699f76c997100e8d53c1e66113df14824addf77a..a195dde2a7b6a0d2fc5089f9f40b2be122a2b5cf 100644 --- a/pc/trap.c +++ b/pc/trap.c @@ -9,229 +9,76 @@ void noted(Ureg*, ulong); -void intr0(void), intr1(void), intr2(void), intr3(void); -void intr4(void), intr5(void), intr6(void), intr7(void); -void intr8(void), intr9(void), intr10(void), intr11(void); -void intr12(void), intr13(void), intr14(void), intr15(void); -void intr16(void), intr17(void), intr18(void); -void intr24(void), intr25(void), intr26(void), intr27(void); -void intr28(void), intr29(void), intr30(void), intr31(void); -void intr32(void), intr33(void), intr34(void), intr35(void); -void intr36(void), intr37(void), intr38(void), intr39(void); -void intr64(void); -void intrbad(void); +static void debugbpt(Ureg*, void*); +static void fault386(Ureg*, void*); +static void syscall(Ureg*, void*); -/* - * 8259 interrupt controllers - */ -enum -{ - Int0ctl= 0x20, /* control port (ICW1, OCW2, OCW3) */ - Int0aux= 0x21, /* everything else (ICW2, ICW3, ICW4, OCW1) */ - Int1ctl= 0xA0, /* control port */ - Int1aux= 0xA1, /* everything else (ICW2, ICW3, ICW4, OCW1) */ - - Icw1= 0x10, /* select bit in ctl register */ - Ocw2= 0x00, - Ocw3= 0x08, - - EOI= 0x20, /* non-specific end of interrupt */ - - Maxhandler= 128, /* max number of interrupt handlers */ -}; - -int int0mask = 0xff; /* interrupts enabled for first 8259 */ -int int1mask = 0xff; /* interrupts enabled for second 8259 */ - -/* - * trap/interrupt gates - */ -Segdesc ilt[256]; -int badintr[16]; - -typedef struct Handler Handler; -struct Handler -{ - void (*r)(Ureg*, void*); - void *arg; - Handler *next; -}; - -struct -{ - Lock; - Handler *ivec[256]; - Handler h[Maxhandler]; - int free; -} halloc; - -void -sethvec(int v, void (*r)(void), int type, int pri) -{ - ilt[v].d0 = ((ulong)r)&0xFFFF|(KESEL<<16); - ilt[v].d1 = ((ulong)r)&0xFFFF0000|SEGP|SEGPL(pri)|type; -} +static Lock irqctllock; +static Irqctl *irqctl[256]; void -setvec(int v, void (*r)(Ureg*, void*), void *arg) +intrenable(int v, void (*f)(Ureg*, void*), void* a, int tbdf) { - Handler *h; - - lock(&halloc); - if(halloc.free >= Maxhandler) - panic("out of interrupt handlers"); - h = &halloc.h[halloc.free++]; - h->next = halloc.ivec[v]; - h->r = r; - h->arg = arg; - halloc.ivec[v] = h; - unlock(&halloc); - - /* - * enable corresponding interrupt in 8259 - */ - if((v&~0x7) == Int0vec){ - int0mask &= ~(1<<(v&7)); - outb(Int0aux, int0mask); - } else if((v&~0x7) == Int1vec){ - int1mask &= ~(1<<(v&7)); - outb(Int1aux, int1mask); + Irq * irq; + Irqctl *ctl; + + lock(&irqctllock); + if(irqctl[v] == 0){ + ctl = xalloc(sizeof(Irqctl)); + if(arch->intrenable(v, tbdf, ctl) == -1){ + unlock(&irqctllock); + /* + print("intrenable: didn't find v %d, tbdf 0x%uX\n", v, tbdf); + */ + xfree(ctl); + return; + } + irqctl[v] = ctl; } + ctl = irqctl[v]; + irq = xalloc(sizeof(Irq)); + irq->f = f; + irq->a = a; + irq->next = ctl->irq; + ctl->irq = irq; + unlock(&irqctllock); } -void -debugbpt(Ureg *ur, void *arg) -{ - char buf[ERRLEN]; - - USED(arg); - - if(up == 0) - panic("kernel bpt"); - /* restore pc to instruction that caused the trap */ - ur->pc--; - sprint(buf, "sys: breakpoint"); - postnote(up, 1, buf, NDebug); -} - -/* - * set up the interrupt/trap gates - */ void trapinit(void) { - int i; - - /* - * set all interrupts to panics - */ - for(i = 0; i < 256; i++) - sethvec(i, intrbad, SEGIG, 0); - - /* - * 80386 processor (and coprocessor) traps - */ - sethvec(0, intr0, SEGIG, 0); - sethvec(1, intr1, SEGIG, 0); - sethvec(2, intr2, SEGIG, 0); - sethvec(4, intr4, SEGIG, 0); - sethvec(5, intr5, SEGIG, 0); - sethvec(6, intr6, SEGIG, 0); - sethvec(7, intr7, SEGIG, 0); - sethvec(8, intr8, SEGIG, 0); - sethvec(9, intr9, SEGIG, 0); - sethvec(10, intr10, SEGIG, 0); - sethvec(11, intr11, SEGIG, 0); - sethvec(12, intr12, SEGIG, 0); - sethvec(13, intr13, SEGIG, 0); - sethvec(14, intr14, SEGIG, 0); /* page fault */ - sethvec(15, intr15, SEGIG, 0); - sethvec(16, intr16, SEGIG, 0); /* math coprocessor */ - sethvec(17, intr17, SEGIG, 0); - sethvec(18, intr18, SEGIG, 0); - - /* - * device interrupts - */ - sethvec(24, intr24, SEGIG, 0); - sethvec(25, intr25, SEGIG, 0); - sethvec(26, intr26, SEGIG, 0); - sethvec(27, intr27, SEGIG, 0); - sethvec(28, intr28, SEGIG, 0); - sethvec(29, intr29, SEGIG, 0); - sethvec(30, intr30, SEGIG, 0); - sethvec(31, intr31, SEGIG, 0); - sethvec(32, intr32, SEGIG, 0); - sethvec(33, intr33, SEGIG, 0); - sethvec(34, intr34, SEGIG, 0); - sethvec(35, intr35, SEGIG, 0); - sethvec(36, intr36, SEGIG, 0); - sethvec(37, intr37, SEGIG, 0); - sethvec(38, intr38, SEGIG, 0); - sethvec(39, intr39, SEGIG, 0); - - /* - * system calls and break points - */ - sethvec(Syscallvec, intr64, SEGIG, 3); - setvec(Syscallvec, syscall, 0); - sethvec(Bptvec, intr3, SEGIG, 3); - setvec(Bptvec, debugbpt, 0); - - - /* - * tell the hardware where the table is (and how long) - */ - putidt(ilt, sizeof(ilt)); - - /* - * Set up the first 8259 interrupt processor. - * Make 8259 interrupts start at CPU vector Int0vec. - * Set the 8259 as master with edge triggered - * input with fully nested interrupts. - */ - outb(Int0ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, edge triggered, - ICW4 will be sent */ - outb(Int0aux, Int0vec); /* ICW2 - interrupt vector offset */ - outb(Int0aux, 0x04); /* ICW3 - have slave on level 2 */ - outb(Int0aux, 0x01); /* ICW4 - 8086 mode, not buffered */ - - /* - * Set up the second 8259 interrupt processor. - * Make 8259 interrupts start at CPU vector Int1vec. - * Set the 8259 as master with level triggered - * input with fully nested interrupts. - */ - outb(Int1ctl, (1<<4)|(0<<3)|(1<<0)); /* ICW1 - master, level triggered, - ICW4 will be sent */ - outb(Int1aux, Int1vec); /* ICW2 - interrupt vector offset */ - outb(Int1aux, 0x02); /* ICW3 - I am a slave on level 2 */ - outb(Int1aux, 0x01); /* ICW4 - 8086 mode, not buffered */ - - /* - * pass #2 8259 interrupts to #1 - */ - int0mask &= ~0x04; - outb(Int0aux, int0mask); + int v, pri; + ulong vaddr; + Segdesc *idt; + + idt = (Segdesc*)IDTADDR; + vaddr = (ulong)vectortable; + for(v = 0; v < 256; v++){ + if(v == VectorBPT || v == VectorSYSCALL) + pri = 3; + else + pri = 0; + idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16); + idt[v].d1 = (vaddr & 0xFFFF0000)|SEGP|SEGPL(pri)|SEGIG; + vaddr += 6; + } - /* - * Set Ocw3 to return the ISR when ctl read. - */ - outb(Int0ctl, Ocw3|0x03); - outb(Int1ctl, Ocw3|0x03); + intrenable(VectorBPT, debugbpt, 0, BUSUNKNOWN); + intrenable(VectorPF, fault386, 0, BUSUNKNOWN); + intrenable(VectorSYSCALL, syscall, 0, BUSUNKNOWN); } char *excname[] = { [0] "divide error", [1] "debug exception", - [2] " nonmaskable interrupt", + [2] "nonmaskable interrupt", [3] "breakpoint", [4] "overflow", [5] "bounds check", [6] "invalid opcode", [7] "coprocessor not available", [8] "double fault", - [9] "9 (reserved)", + [9] "coprocessor segment overrun", [10] "invalid TSS", [11] "segment not present", [12] "stack exception", @@ -240,11 +87,10 @@ char *excname[] = { [15] "15 (reserved)", [16] "coprocessor error", [17] "alignment check", - [18] "something bad happened", + [18] "machine check", }; -Ureg lastur; -Ureg scndlastur; +static int nspuriousintr; /* * All traps come here. It is slower to have all traps call trap() rather than @@ -252,149 +98,124 @@ Ureg scndlastur; * and possible bugs. trap is called splhi(). */ void -trap(Ureg *ur) +trap(Ureg* ureg) { int v, user; - int c; char buf[ERRLEN]; - Handler *h; - static int iret_traps; - ushort isr; - - v = ur->trap; + Irqctl *ctl; + Irq *irq; - user = (ur->cs&0xffff) == UESEL; + user = (ureg->cs & 0xFFFF) == UESEL; if(user) - up->dbgreg = ur; - else if(ur->pc <= (ulong)end && *(uchar*)ur->pc == 0xCF) { - if(iret_traps++ > 10) - panic("iret trap"); - goto saveout; - } - iret_traps = 0; + up->dbgreg = ureg; - /* - * tell the 8259 that we're done with the - * highest level interrupt (interrupts are still - * off at this point) - */ - c = v&~0x7; - isr = 0; - if(c==Int0vec || c==Int1vec){ - isr = inb(Int0ctl); - outb(Int0ctl, EOI); - if(c == Int1vec){ - isr |= inb(Int1ctl)<<8; - outb(Int1ctl, EOI); - } - } + v = ureg->trap; + if(ctl = irqctl[v]){ + if(ctl->isintr) + m->intr++; + if(ctl->isr) + ctl->isr(v); - if(v>=256 || (h = halloc.ivec[v]) == 0){ - - /* a processor or coprocessor error */ - if(v <= 16){ - if(user){ - spllo(); - sprint(buf, "sys: trap: %s", excname[v]); - postnote(up, 1, buf, NDebug); - goto out; - } else { - dumpregs(ur); - panic("%s pc=0x%lux", excname[v], ur->pc); - } - } + for(irq = ctl->irq; irq; irq = irq->next) + irq->f(ureg, irq->a); - if(v >= Int0vec && v < Int0vec+16){ - /* an unknown interrupt */ - v -= Int0vec; - /* - * Check for a default IRQ7. This can happen when - * the IRQ input goes away before the acknowledge. - * In this case, a 'default IRQ7' is generated, but - * the corresponding bit in the ISR isn't set. - * In fact, just ignore all such interrupts. - */ - if((isr & (1<pc, badintr[v]); - print("isr = 0x%4.4ux\n", isr); - } - } else { - /* unimplemented traps */ - print("illegal trap %d pc=0x%lux\n", v, ur->pc); - } - goto saveout; + if(ctl->eoi) + ctl->eoi(v); + } + else if(v <= 16 && user){ + spllo(); + sprint(buf, "sys: trap: %s", excname[v]); + postnote(up, 1, buf, NDebug); + } + else if(v >= VectorPIC && v <= MaxVectorPIC){ + /* + * An unknown interrupt. + * Check for a default IRQ7. This can happen when + * the IRQ input goes away before the acknowledge. + * In this case, a 'default IRQ7' is generated, but + * the corresponding bit in the ISR isn't set. + * In fact, just ignore all such interrupts. + */ + if(nspuriousintr < 2) + print("spurious interrupt %d\n", v-VectorPIC); + nspuriousintr++; + return; + } + else{ + dumpregs(ureg); + if(v < nelem(excname)) + panic("%s", excname[v]); + panic("unknown trap/intr: %d\n", v); } - - /* there may be multiple handlers on one interrupt level */ - do { - (*h->r)(ur, h->arg); - h = h->next; - } while(h); /* * check user since syscall does its own notifying */ -out: splhi(); - if(v != Syscallvec && user && (up->procctl || up->nnote)) - notify(ur); -saveout: - scndlastur = lastur; - lastur = *ur; + if(v != VectorSYSCALL && user && (up->procctl || up->nnote)) + notify(ureg); } /* * dump registers */ void -dumpregs2(Ureg *ur) +dumpregs2(Ureg* ureg) { - ur->cs &= 0xffff; - ur->ds &= 0xffff; - ur->es &= 0xffff; - ur->fs &= 0xffff; - ur->gs &= 0xffff; + ureg->cs &= 0xFFFF; + ureg->ds &= 0xFFFF; + ureg->es &= 0xFFFF; + ureg->fs &= 0xFFFF; + ureg->gs &= 0xFFFF; if(up) - print("registers for %s %d\n", up->text, up->pid); + print("cpu%d: registers for %s %d\n", m->machno, up->text, up->pid); else - print("registers for kernel\n"); - print("FLAGS=%lux TRAP=%lux ECODE=%lux CS=%4.4lux PC=%lux", ur->flags, ur->trap, - ur->ecode, ur->cs, ur->pc); - print(" SS=%4.4lux USP=%lux\n", ur->ss&0xffff, ur->usp); - print(" AX %8.8lux BX %8.8lux CX %8.8lux DX %8.8lux\n", - ur->ax, ur->bx, ur->cx, ur->dx); - print(" SI %8.8lux DI %8.8lux BP %8.8lux\n", - ur->si, ur->di, ur->bp); - print(" DS %4.4lux ES %4.4lux FS %4.4lux GS %4.4lux\n", - ur->ds, ur->es, ur->fs, ur->gs); + print("cpu%d: registers for kernel\n", m->machno); + print("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX", ureg->flags, ureg->trap, + ureg->ecode, ureg->pc); + print(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp); + print(" AX %8.8luX BX %8.8luX CX %8.8luX DX %8.8luX\n", + ureg->ax, ureg->bx, ureg->cx, ureg->dx); + print(" SI %8.8luX DI %8.8luX BP %8.8luX\n", + ureg->si, ureg->di, ureg->bp); + print(" CS %4.4uX DS %4.4uX ES %4.4uX FS %4.4uX GS %4.4uX\n", + ureg->cs, ureg->ds, ureg->es, ureg->fs, ureg->gs); } void -dumpregs(Ureg *ur) +dumpregs(Ureg* ureg) { extern ulong etext; - ulong *x; + ulong mca[2], mct[2]; + dumpregs2(ureg); - x = (ulong*)(ur+1); -/* - dumpregs2(&scndlastur); - dumpregs2(&lastur); -*/ - dumpregs2(ur); - print(" CR0 %8.8lux CR2 %8.8lux\n", getcr0(), getcr2()); - print(" magic %lux %lux %lux\n", x[0], x[1], x[2]); - print(" ur %lux up %lux\n", ur, up); + /* + * Processor control registers. + * If machine check exception, time stamp counter, page size extensions or + * enhanced virtual 8086 mode extensions are supported, there is a CR4. + * If there is a CR4 and machine check extensions, read the machine check + * address and machine check type registers if RDMSR supported. + */ + print(" CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux", getcr0(), getcr2(), getcr3()); + if(m->cpuiddx & 0x9A){ + print(" CR4 %8.8luX", getcr4()); + if((m->cpuiddx & 0xA0) == 0xA0){ + rdmsr(0x00, &mca[1], &mca[0]); + rdmsr(0x01, &mct[1], &mct[0]); + print("\n MCA %8.8luX:%8.8luX MCT %8.8luX", + mca[1], mca[0], mct[0]); + } + } + print("\n ur %luX up %luX\n", ureg, up); } void dumpstack(void) { ulong l, v, i; + uchar *p; extern ulong etext; if(up == 0) @@ -404,8 +225,11 @@ dumpstack(void) for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){ v = *(ulong*)l; if(KTZERO < v && v < (ulong)&etext){ - print("%lux ", v); - i++; + p = (uchar*)v; + if(*(p-5) == 0xE8){ + print("%lux ", p-5); + i++; + } } if(i == 8){ i = 0; @@ -414,6 +238,46 @@ dumpstack(void) } } +static void +debugbpt(Ureg* ureg, void*) +{ + char buf[ERRLEN]; + + if(up == 0) + panic("kernel bpt"); + /* restore pc to instruction that caused the trap */ + ureg->pc--; + sprint(buf, "sys: breakpoint"); + postnote(up, 1, buf, NDebug); +} + +static void +fault386(Ureg* ureg, void*) +{ + ulong addr; + int read, user, n, insyscall; + char buf[ERRLEN]; + + insyscall = up->insyscall; + up->insyscall = 1; + addr = getcr2(); + read = !(ureg->ecode & 2); + user = (ureg->cs&0xffff) == UESEL; + spllo(); + n = fault(addr, read); + if(n < 0){ + if(user){ + sprint(buf, "sys: trap: fault %s addr=0x%lux", + read? "read" : "write", addr); + postnote(up, 1, buf, NDebug); + return; + } + dumpregs(ureg); + panic("fault: 0x%lux\n", addr); + } + up->insyscall = insyscall; +} + /* * system calls */ @@ -422,24 +286,22 @@ dumpstack(void) /* * syscall is called splhi() */ -void -syscall(Ureg *ur, void *arg) +static void +syscall(Ureg* ureg, void*) { ulong sp; long ret; int i; - USED(arg); - - + m->syscall++; up->insyscall = 1; - up->pc = ur->pc; - up->dbgreg = ur; + up->pc = ureg->pc; + up->dbgreg = ureg; - if((ur->cs)&0xffff == KESEL) + if((ureg->cs)&0xffff == KESEL) panic("recursive system call"); - up->scallnr = ur->ax; + up->scallnr = ureg->ax; if(up->scallnr == RFORK && up->fpstate == FPactive){ /* * so that the child starts out with the @@ -454,12 +316,12 @@ syscall(Ureg *ur, void *arg) } spllo(); - sp = ur->usp; + sp = ureg->usp; up->nerrlab = 0; ret = -1; if(!waserror()){ if(up->scallnr >= nsyscall){ - pprint("bad sys call number %d pc %lux\n", up->scallnr, ur->pc); + pprint("bad sys call number %d pc %lux\n", up->scallnr, ureg->pc); postnote(up, 1, "sys: bad sys call", NDebug); error(Ebadarg); } @@ -470,7 +332,7 @@ syscall(Ureg *ur, void *arg) up->s = *((Sargs*)(sp+1*BY2WD)); up->psstate = sysctab[up->scallnr]; - ret = (*systab[up->scallnr])(up->s.args); + ret = systab[up->scallnr](up->s.args); poperror(); } if(up->nerrlab){ @@ -489,14 +351,14 @@ syscall(Ureg *ur, void *arg) * ignored. On other machines the return value is put into * the results register by caller of syscall. */ - ur->ax = ret; + ureg->ax = ret; if(up->scallnr == NOTED) - noted(ur, *(ulong*)(sp+BY2WD)); + noted(ureg, *(ulong*)(sp+BY2WD)); splhi(); if(up->scallnr!=RFORK && (up->procctl || up->nnote)) - notify(ur); + notify(ureg); } @@ -505,7 +367,7 @@ syscall(Ureg *ur, void *arg) * Pass user the Ureg struct and the note on his stack. */ int -notify(Ureg *ur) +notify(Ureg* ureg) { int l; ulong s, sp; @@ -524,7 +386,7 @@ notify(Ureg *ur) l = strlen(n->msg); if(l > ERRLEN-15) /* " pc=0x12345678\0" */ l = ERRLEN-15; - sprint(n->msg+l, " pc=0x%.8lux", ur->pc); + sprint(n->msg+l, " pc=0x%.8lux", ureg->pc); } if(n->flag!=NUser && (up->notified || up->notify==0)){ @@ -544,7 +406,7 @@ notify(Ureg *ur) qunlock(&up->debug); pexit(n->msg, n->flag!=NDebug); } - sp = ur->usp; + sp = ureg->usp; sp -= sizeof(Ureg); if(!okaddr((ulong)up->notify, 1, 0) @@ -555,7 +417,7 @@ notify(Ureg *ur) } up->ureg = (void*)sp; - memmove((Ureg*)sp, ur, sizeof(Ureg)); + memmove((Ureg*)sp, ureg, sizeof(Ureg)); *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */ up->ureg = (void*)sp; sp -= BY2WD+ERRLEN; @@ -564,8 +426,8 @@ notify(Ureg *ur) *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg; /* arg 1 is ureg* */ *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ - ur->usp = sp; - ur->pc = (ulong)up->notify; + ureg->usp = sp; + ureg->pc = (ulong)up->notify; up->notified = 1; up->nnote--; memmove(&up->lastnote, &up->note[0], sizeof(Note)); @@ -580,9 +442,9 @@ notify(Ureg *ur) * Return user to state before notify() */ void -noted(Ureg *ur, ulong arg0) +noted(Ureg* ureg, ulong arg0) { - Ureg *nur; + Ureg *nureg; ulong oureg, sp; qlock(&up->debug); @@ -593,10 +455,10 @@ noted(Ureg *ur, ulong arg0) } up->notified = 0; - nur = up->ureg; /* pointer to user returned Ureg struct */ + nureg = up->ureg; /* pointer to user returned Ureg struct */ /* sanity clause */ - oureg = (ulong)nur; + oureg = (ulong)nureg; if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){ pprint("bad ureg in noted or call to noted() when not notified\n"); qunlock(&up->debug); @@ -604,18 +466,18 @@ noted(Ureg *ur, ulong arg0) } /* don't let user change text or stack segments */ - nur->cs = ur->cs; - nur->ss = ur->ss; + nureg->cs = ureg->cs; + nureg->ss = ureg->ss; /* don't let user change system flags */ - nur->flags = (ur->flags & ~0xCD5) | (nur->flags & 0xCD5); + nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5); - memmove(ur, nur, sizeof(Ureg)); + memmove(ureg, nureg, sizeof(Ureg)); switch(arg0){ case NCONT: case NRSTR: - if(!okaddr(nur->pc, 1, 0) || !okaddr(nur->usp, BY2WD, 0)){ + if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){ pprint("suicide: trap in noted\n"); qunlock(&up->debug); pexit("Suicide", 0); @@ -625,7 +487,7 @@ noted(Ureg *ur, ulong arg0) break; case NSAVE: - if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){ + if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->usp, BY2WD, 0)){ pprint("suicide: trap in noted\n"); qunlock(&up->debug); pexit("Suicide", 0); @@ -633,7 +495,7 @@ noted(Ureg *ur, ulong arg0) qunlock(&up->debug); sp = oureg-4*BY2WD-ERRLEN; splhi(); - ur->sp = sp; + ureg->sp = sp; ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */ ((ulong*)sp)[0] = 0; /* arg 0 is pc */ break; @@ -655,54 +517,54 @@ long execregs(ulong entry, ulong ssize, ulong nargs) { ulong *sp; - Ureg *ur; + Ureg *ureg; sp = (ulong*)(USTKTOP - ssize); *--sp = nargs; - ur = up->dbgreg; - ur->usp = (ulong)sp; - ur->pc = entry; + ureg = up->dbgreg; + ureg->usp = (ulong)sp; + ureg->pc = entry; return USTKTOP-BY2WD; /* address of user-level clock */ } ulong userpc(void) { - Ureg *ur; + Ureg *ureg; - ur = (Ureg*)up->dbgreg; - return ur->pc; + ureg = (Ureg*)up->dbgreg; + return ureg->pc; } /* This routine must save the values of registers the user is not permitted to write - * from devproc and the restore the saved values before returning + * from devproc and then restore the saved values before returning */ void -setregisters(Ureg *xp, char *pureg, char *uva, int n) +setregisters(Ureg* ureg, char* pureg, char* uva, int n) { ulong flags; ulong cs; ulong ss; - flags = xp->flags; - cs = xp->cs; - ss = xp->ss; + flags = ureg->flags; + cs = ureg->cs; + ss = ureg->ss; memmove(pureg, uva, n); - xp->flags = (xp->flags & 0xff) | (flags & 0xff00); - xp->cs = cs; - xp->ss = ss; + ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00); + ureg->cs = cs; + ureg->ss = ss; } static void linkproc(void) { spllo(); - (*up->kpfun)(up->kparg); + up->kpfun(up->kparg); } void -kprocchild(Proc *p, void (*func)(void*), void *arg) +kprocchild(Proc* p, void (*func)(void*), void* arg) { p->sched.pc = (ulong)linkproc; p->sched.sp = (ulong)p->kstack+KSTACK; @@ -712,23 +574,23 @@ kprocchild(Proc *p, void (*func)(void*), void *arg) } void -forkchild(Proc *p, Ureg *ur) +forkchild(Proc *p, Ureg *ureg) { - Ureg *cur; + Ureg *cureg; /* - * We add 2*BY2Wd to the stack because we have to account for + * Add 2*BY2WD to the stack to account for * - the return PC * - trap's argument (ur) */ p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD); p->sched.pc = (ulong)forkret; - cur = (Ureg*)(p->sched.sp+2*BY2WD); - memmove(cur, ur, sizeof(Ureg)); - cur->ax = 0; /* return value of syscall in child */ + cureg = (Ureg*)(p->sched.sp+2*BY2WD); + memmove(cureg, ureg, sizeof(Ureg)); + cureg->ax = 0; /* return value of syscall in child */ - /* Things from bottom of syscall we never got to execute */ + /* Things from bottom of syscall which were never executed */ p->psstate = 0; p->insyscall = 0; } @@ -737,20 +599,20 @@ forkchild(Proc *p, Ureg *ur) * a sleeping process */ void -setkernur(Ureg *xp, Proc *p) +setkernur(Ureg* ureg, Proc* p) { - xp->pc = p->sched.pc; - xp->sp = p->sched.sp+4; + ureg->pc = p->sched.pc; + ureg->sp = p->sched.sp+4; } ulong dbgpc(Proc *p) { - Ureg *ur; + Ureg *ureg; - ur = p->dbgreg; - if(ur == 0) + ureg = p->dbgreg; + if(ureg == 0) return 0; - return ur->pc; + return ureg->pc; } diff --git a/pc/u.h b/pc/u.h index cc6fc082ffe947a284614e360d1430fdeb2019eb..6942b9797239e8d179f07d57aeb9655564795dea 100644 --- a/pc/u.h +++ b/pc/u.h @@ -1,10 +1,10 @@ #define nil ((void*)0) typedef unsigned short ushort; typedef unsigned char uchar; +typedef signed char schar; typedef unsigned int uint; typedef unsigned long ulong; -typedef signed char schar; -typedef long vlong; +typedef long long vlong; typedef union Length Length; typedef ushort Rune; diff --git a/pc/vgaark2000pv.c b/pc/vgaark2000pv.c index 402dcc2bc68ddb7ab5bbbc81643dc08dbec85013..a20ffb3c7b494f43fd6be5cba4d76c8c22ca73aa 100644 --- a/pc/vgaark2000pv.c +++ b/pc/vgaark2000pv.c @@ -28,8 +28,12 @@ disable(void) { uchar seq20; + lock(&ark2000pvlock); + seq20 = vgaxi(Seqx, 0x20) & ~0x08; vgaxo(Seqx, 0x20, seq20); + + unlock(&ark2000pvlock); } static void @@ -37,6 +41,8 @@ enable(void) { uchar seq20; + lock(&ark2000pvlock); + /* * Disable the cursor then configure for X-Windows style, * 32x32 and 4/8-bit colour depth. @@ -66,6 +72,8 @@ enable(void) * Enable the cursor. */ vgaxo(Seqx, 0x20, seq20); + + unlock(&ark2000pvlock); } static void @@ -185,17 +193,9 @@ static Hwgc ark2000pvhwgc = { static void ark2000pvpage(int page) { - /* - * Shouldn't need to lock if linear addressing - * is enabled. - */ - if((vgaxi(Seqx, 0x10) & 0x10) == 0 && hwgc == &ark2000pvhwgc){ - lock(&ark2000pvlock); - setark2000pvpage(page); - unlock(&ark2000pvlock); - } - else - setark2000pvpage(page); + lock(&ark2000pvlock); + setark2000pvpage(page); + unlock(&ark2000pvlock); } static Vgac ark2000pv = { diff --git a/pc/vgaclgd542x.c b/pc/vgaclgd542x.c index 7c9f61fd792eda1302de3cf7b85630483aeebc04..f1e7693f70a16eb404b8e2bcaf62f715e90a2c7c 100644 --- a/pc/vgaclgd542x.c +++ b/pc/vgaclgd542x.c @@ -9,10 +9,14 @@ #include "screen.h" #include "vga.h" +static Lock clgd542xlock; + static void clgd542xpage(int page) { + lock(&clgd542xlock); vgaxo(Grx, 0x09, page<<4); + unlock(&clgd542xlock); } static Vgac clgd542x = { diff --git a/pc/vgaet4000.c b/pc/vgaet4000.c index c149ce19fccc6e54aeb7c4d13c1a9a7e15c4c616..31b93cb6f7b188b0af71fc428087c3a48636b783 100644 --- a/pc/vgaet4000.c +++ b/pc/vgaet4000.c @@ -12,7 +12,7 @@ extern Bitmap gscreen; extern Cursor curcursor; -static Lock et4000pagelock; +static Lock et4000lock; static ulong storage; static Point hotpoint; @@ -35,9 +35,11 @@ disable(void) { uchar imaF7; + lock(&et4000lock); outb(0x217A, 0xF7); imaF7 = inb(0x217B) & ~0x80; outb(0x217B, imaF7); + unlock(&et4000lock); } static void @@ -45,7 +47,14 @@ enable(void) { uchar imaF7; - disable(); + lock(&et4000lock); + + /* + * disable(); + */ + outb(0x217A, 0xF7); + imaF7 = inb(0x217B) & ~0x80; + outb(0x217B, imaF7); /* * Configure CRTCB for Sprite, 64x64, @@ -110,12 +119,14 @@ enable(void) outb(0x217A, 0xF7); imaF7 = inb(0x217B); outb(0x217B, 0x80|imaF7); + + unlock(&et4000lock); } static void load(Cursor *c) { - uchar p0, p1, *mem; + uchar imaF7, p0, p1, *mem; int i, x, y; ushort p; @@ -123,12 +134,12 @@ load(Cursor *c) * Lock the display memory so we can update the * cursor bitmap if necessary. */ - lock(&et4000pagelock); + lock(&et4000lock); if(memcmp(c, &curcursor, sizeof(Cursor)) == 0){ outb(0x217A, 0xF7); p0 = inb(0x217B); outb(0x217B, 0x80|p0); - unlock(&et4000pagelock); + unlock(&et4000lock); return; } memmove(&curcursor, c, sizeof(Cursor)); @@ -140,7 +151,9 @@ load(Cursor *c) * pointer to the two planes. What if this crosses * into a new page? */ - disable(); + outb(0x217A, 0xF7); + imaF7 = inb(0x217B) & ~0x80; + outb(0x217B, imaF7); setet4000page(storage>>16); mem = ((uchar*)gscreen.base) + (storage & 0xFFFF); @@ -190,7 +203,7 @@ load(Cursor *c) p = inb(0x217B)|0x80; outb(0x217B, p); - unlock(&et4000pagelock); + unlock(&et4000lock); } static int @@ -198,7 +211,7 @@ move(Point p) { int x, xo, y, yo; - if(canlock(&et4000pagelock) == 0) + if(canlock(&et4000lock) == 0) return 1; /* @@ -244,7 +257,7 @@ move(Point p) outb(0x217A, 0xE4); outb(0x217B, y & 0xFF); - unlock(&et4000pagelock); + unlock(&et4000lock); return 0; } @@ -261,13 +274,9 @@ Hwgc et4000hwgc = { static void et4000page(int page) { - if(hwgc == &et4000hwgc){ - lock(&et4000pagelock); - setet4000page(page); - unlock(&et4000pagelock); - } - else - setet4000page(page); + lock(&et4000lock); + setet4000page(page); + unlock(&et4000lock); } static Vgac et4000 = { diff --git a/pc/vgamach32.c b/pc/vgamach32.c index 64aca73fdd01bd5db8cb5f684df2c42682eea0d1..f5f2ae21d6b7d316977317dbcdb90208420a3ad1 100644 --- a/pc/vgamach32.c +++ b/pc/vgamach32.c @@ -9,11 +9,14 @@ #include "screen.h" #include "vga.h" +static Lock mach32lock; + static void mach32page(int page) { uchar ae, p; + lock(&mach32lock); p = (page & 0x0F)<<1; p |= (page & 0x07)<<5; @@ -26,6 +29,8 @@ mach32page(int page) p |= p<<2; p |= ae & 0xF0; outs(0x1CE, (p<<8)|0xAE); + + unlock(&mach32lock); } static Vgac mach32 = { diff --git a/pc/vgas3.c b/pc/vgas3.c index 5ab0880bc1b335a1212fcde5c589f3da00347bcd..6ebe91369f031bddbce01026c9c89b85841850da 100644 --- a/pc/vgas3.c +++ b/pc/vgas3.c @@ -14,7 +14,7 @@ * generic S3 chipset. * Assume we're in enhanced mode. */ -static Lock s3pagelock; +static Lock s3lock; static ulong storage; static Point hotpoint; @@ -57,7 +57,7 @@ vsyncactive(void) } static void -disable(void) +_disable(void) { uchar crt45; @@ -69,12 +69,22 @@ disable(void) vgaxo(Crtx, 0x45, crt45); } +static void +disable(void) +{ + lock(&s3lock); + _disable(); + unlock(&s3lock); +} + static void enable(void) { int i; - disable(); + lock(&s3lock); + + _disable(); /* * Cursor colours. Set both the CR0[EF] and the colour @@ -105,6 +115,8 @@ enable(void) vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55)|0x10); vsyncactive(); vgaxo(Crtx, 0x45, 0x01); + + unlock(&s3lock); } static void @@ -119,11 +131,11 @@ load(Cursor *c) * If it's the same as the last cursor we loaded, * just make sure it's enabled. */ - lock(&s3pagelock); + lock(&s3lock); if(memcmp(c, &curcursor, sizeof(Cursor)) == 0){ vsyncactive(); vgaxo(Crtx, 0x45, 0x01); - unlock(&s3pagelock); + unlock(&s3lock); return; } memmove(&curcursor, c, sizeof(Cursor)); @@ -135,7 +147,7 @@ load(Cursor *c) * pointer to the two planes. What if this crosses * into a new page? */ - disable(); + _disable(); sets3page(storage>>16); p = ((uchar*)gscreen.base) + (storage & 0xFFFF); @@ -177,7 +189,7 @@ load(Cursor *c) vsyncactive(); vgaxo(Crtx, 0x45, 0x01); - unlock(&s3pagelock); + unlock(&s3lock); } static int @@ -185,7 +197,7 @@ move(Point p) { int x, xo, y, yo; - if(canlock(&s3pagelock) == 0) + if(canlock(&s3lock) == 0) return 1; /* @@ -217,7 +229,7 @@ move(Point p) vgaxo(Crtx, 0x4F, yo); vgaxo(Crtx, 0x48, (y>>8) & 0x07); - unlock(&s3pagelock); + unlock(&s3lock); return 0; } @@ -234,13 +246,9 @@ Hwgc s3hwgc = { static void s3page(int page) { - if(hwgc == &s3hwgc){ - lock(&s3pagelock); - sets3page(page); - unlock(&s3pagelock); - } - else - sets3page(page); + lock(&s3lock); + sets3page(page); + unlock(&s3lock); } static Vgac s3 = { diff --git a/port/alarm.c b/port/alarm.c index 9f8efdca1b903abdd3e27feed5b058af34790ac5..a854c3f8f2c5fd2df89c2f4ca980e7501048f3c8 100644 --- a/port/alarm.c +++ b/port/alarm.c @@ -52,7 +52,7 @@ checkalarms(void) if(p && p->alarm <= now) wakeup(&alarmr); - if(talarm.list == 0 || canlock(&talarm) == 0) + if(talarm.list == 0 || !canlock(&talarm)) return; for(;;) { diff --git a/port/auth.c b/port/auth.c index c10c8b2909bd726069cf468ecc275347e42bebee..dbbb9b2f197edf7dfee2a53735d1a804af992950 100644 --- a/port/auth.c +++ b/port/auth.c @@ -106,7 +106,7 @@ sysfsession(ulong *arg) validaddr(arg[1], TICKREQLEN, 1); c = fdtochan(arg[0], OWRITE, 0, 1); if(waserror()){ - close(c); + cclose(c); nexterror(); } @@ -142,11 +142,11 @@ sysfsession(ulong *arg) f.type = Tsession; memmove(f.chal, s->cchal, CHALLEN); n = convS2M(&f, buf); - if((*devtab[c->type].write)(c, buf, n, 0) != n) + if(devtab[c->type]->write(c, buf, n, 0) != n) error(Emountrpc); - n = (*devtab[c->type].read)(c, buf, sizeof buf, 0); + n = devtab[c->type]->read(c, buf, sizeof buf, 0); if(n == 2 && buf[0] == 'O' && buf[1] == 'K') - n = (*devtab[c->type].read)(c, buf, sizeof buf, 0); + n = devtab[c->type]->read(c, buf, sizeof buf, 0); poperror(); if(convM2S(buf, &f, n) == 0){ unlock(&s->send); @@ -195,7 +195,7 @@ sysfsession(ulong *arg) memmove(tr.hostid, eve, NAMELEN); convTR2M(&tr, (char*)arg[1]); - close(c); + cclose(c); poperror(); return 0; } diff --git a/port/cache.c b/port/cache.c index 1a057520e4ced5e93037bc5c30ec2f052f894785..3938eae0d28f6dd311497e23de3ef87faf189069 100644 --- a/port/cache.c +++ b/port/cache.c @@ -202,6 +202,7 @@ copen(Chan *c) *l = m; ctail(m); + qlock(m); c->mcp = m; e = m->list; m->list = 0; @@ -212,6 +213,7 @@ copen(Chan *c) free(e); e = next; } + qunlock(m); } static int diff --git a/port/chan.c b/port/chan.c index f4e4252027fc25b8f12fd069792219b37f688850..86f16168275185f70dd1fecd66062c5081fc666a 100644 --- a/port/chan.c +++ b/port/chan.c @@ -56,7 +56,7 @@ chandevreset(void) int i; for(i=0; devchar[i]; i++) - (*devtab[i].reset)(); + devtab[i]->reset(); } void @@ -65,7 +65,7 @@ chandevinit(void) int i; for(i=0; devchar[i]; i++) - (*devtab[i].init)(); + devtab[i]->init(); } Chan* @@ -128,16 +128,15 @@ chanfree(Chan *c) } void -close(Chan *c) +cclose(Chan *c) { if(c->flag&CFREE) - panic("close"); - + panic("cclose %lux", getcallerpc(c)); if(decref(c)) return; if(!waserror()) { - (*devtab[c->type].close)(c); + devtab[c->type]->close(c); poperror(); } @@ -165,7 +164,7 @@ eqchan(Chan *a, Chan *b, int pathonly) } int -mount(Chan *new, Chan *old, int flag, char *spec) +cmount(Chan *new, Chan *old, int flag, char *spec) { Pgrp *pg; int order, flg; @@ -255,7 +254,7 @@ mount(Chan *new, Chan *old, int flag, char *spec) } void -unmount(Chan *mnt, Chan *mounted) +cunmount(Chan *mnt, Chan *mounted) { Pgrp *pg; Mhead *m, **l; @@ -280,7 +279,7 @@ unmount(Chan *mnt, Chan *mounted) *l = m->hash; wunlock(&pg->ns); mountfree(m->mount); - close(m->from); + cclose(m->from); free(m); return; } @@ -296,7 +295,7 @@ unmount(Chan *mnt, Chan *mounted) if(m->mount == 0) { *l = m->hash; wunlock(&pg->ns); - close(m->from); + cclose(m->from); free(m); return; } @@ -310,9 +309,9 @@ unmount(Chan *mnt, Chan *mounted) } Chan* -clone(Chan *c, Chan *nc) +cclone(Chan *c, Chan *nc) { - return (*devtab[c->type].clone)(c, nc); + return devtab[c->type]->clone(c, nc); } Chan* @@ -332,11 +331,11 @@ domount(Chan *c) for(m = MOUNTH(pg, c); m; m = m->hash) if(eqchan(m->from, c, 1)) { - nc = clone(m->mount->to, 0); + nc = cclone(m->mount->to, 0); nc->mnt = m->mount; nc->xmnt = nc->mnt; nc->mountid = m->mount->mountid; - close(c); + cclose(c); c = nc; break; } @@ -365,8 +364,8 @@ undomount(Chan *c) for(f = *h; f; f = f->hash) { for(t = f->mount; t; t = t->next) { if(eqchan(c, t->to, 1)) { - close(c); - c = clone(t->head->from, 0); + cclose(c); + c = cclone(t->head->from, 0); break; } } @@ -394,7 +393,7 @@ walk(Chan *ac, char *name, int domnt) dotdot = 1; } - if((*devtab[ac->type].walk)(ac, name) != 0) { + if(devtab[ac->type]->walk(ac, name) != 0) { if(dotdot) ac = undomount(ac); if(domnt) @@ -412,14 +411,14 @@ walk(Chan *ac, char *name, int domnt) if(waserror()) { runlock(&pg->ns); if(c) - close(c); + cclose(c); nexterror(); } for(f = ac->mnt; f; f = f->next) { - c = clone(f->to, 0); - if((*devtab[c->type].walk)(c, name) != 0) + c = cclone(f->to, 0); + if(devtab[c->type]->walk(c, name) != 0) break; - close(c); + cclose(c); c = 0; } poperror(); @@ -434,13 +433,13 @@ walk(Chan *ac, char *name, int domnt) c->mnt = 0; if(domnt) { if(waserror()) { - close(c); + cclose(c); nexterror(); } c = domount(c); poperror(); } - close(ac); + cclose(ac); return c; } @@ -462,16 +461,16 @@ createdir(Chan *c) } for(f = c->mnt; f; f = f->next) { if(f->to->flag&CCREATE) { - nc = clone(f->to, 0); + nc = cclone(f->to, 0); nc->mnt = f; runlock(&pg->ns); poperror(); - close(c); + cclose(c); return nc; } } error(Enocreate); - return 0; /* not reached */ + return 0; } Chan* @@ -505,7 +504,7 @@ mchan(char *id, int walkname) incref(c); } else - c = clone(c, 0); + c = cclone(c, 0); runlock(&pg->ns); poperror(); return c; @@ -554,7 +553,7 @@ namec(char *name, int amode, int omode, ulong perm) isdot = 0; switch(name[0]) { case '/': - c = clone(up->slash, 0); + c = cclone(up->slash, 0); name = skipslash(name); break; case '#': @@ -583,18 +582,18 @@ namec(char *name, int amode, int omode, ulong perm) if(t == -1) error(Ebadsharp); - c = (*devtab[t].attach)(elem+n); + c = devtab[t]->attach(elem+n); name = skipslash(name); break; default: - c = clone(up->dot, 0); + c = cclone(up->dot, 0); name = skipslash(name); if(*name == 0) isdot = 1; } if(waserror()){ - close(c); + cclose(c); nexterror(); } @@ -656,7 +655,7 @@ namec(char *name, int amode, int omode, ulong perm) if(omode == OEXEC) c->flag &= ~CCACHE; - c = (*devtab[c->type].open)(c, omode); + c = devtab[c->type]->open(c, omode); if(omode & OCEXEC) c->flag |= CCEXEC; @@ -686,21 +685,21 @@ namec(char *name, int amode, int omode, ulong perm) * first, just in case someone is trying to * use clwalk outside the kernel. */ - cc = clone(c, 0); + cc = cclone(c, 0); if(waserror()){ - close(cc); + cclose(cc); nexterror(); } nameok(elem); nc = walk(cc, elem, 1); if(nc != 0) { poperror(); - close(c); + cclose(c); c = nc; omode |= OTRUNC; goto Open; } - close(cc); + cclose(cc); poperror(); /* @@ -722,7 +721,7 @@ namec(char *name, int amode, int omode, ulong perm) omode |= OTRUNC; goto Open; } - (*devtab[c->type].create)(c, elem, omode, perm); + devtab[c->type]->create(c, elem, omode, perm); if(omode & OCEXEC) c->flag |= CCEXEC; if(omode & ORCLOSE) diff --git a/port/dev.c b/port/dev.c index 36504390c31e834b8d4f7bc8352b1a797c373a74..e112b1fc42ea62daa7d88067bbb52b82a166405f 100644 --- a/port/dev.c +++ b/port/dev.c @@ -59,7 +59,17 @@ devgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) return 1; } -Chan * +void +devreset(void) +{ +} + +void +devinit(void) +{ +} + +Chan* devattach(int tc, char *spec) { Chan *c; @@ -75,7 +85,7 @@ devattach(int tc, char *spec) return c; } -Chan * +Chan* devclone(Chan *c, Chan *nc) { if(c->flag & COPEN) @@ -129,7 +139,7 @@ devwalk(Chan *c, char *name, Dirtab *tab, int ntab, Devgen *gen) continue; } } - return 0; /* not reached */ + return 0; } void @@ -146,8 +156,10 @@ devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen) convD2M(&dir, db); return; } - print("%s %s: devstat %C %lux\n", up->text, up->user, - devchar[c->type], c->qid.path); + print("%s %s: devstat %C %lux\n", + up->text, up->user, + devchar[c->type], c->qid.path); + error(Enonexist); case 0: break; @@ -189,7 +201,7 @@ devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) return m; } -Chan * +Chan* devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) { int i; @@ -230,6 +242,12 @@ Return: return c; } +void +devcreate(Chan*, char*, int, ulong) +{ + error(Eperm); +} + Block* devbread(Chan *c, long n, ulong offset) { @@ -242,7 +260,7 @@ devbread(Chan *c, long n, ulong offset) freeb(bp); nexterror(); } - bp->wp += devtab[c->type].read(c, bp->wp, n, offset); + bp->wp += devtab[c->type]->read(c, bp->wp, n, offset); poperror(); return bp; } @@ -252,9 +270,20 @@ devbwrite(Chan *c, Block *bp, ulong offset) { long n; - n = devtab[c->type].write(c, bp->rp, BLEN(bp), offset); + n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset); freeb(bp); return n; } +void +devremove(Chan*) +{ + error(Eperm); +} + +void +devwstat(Chan*, char*) +{ + error(Eperm); +} diff --git a/port/devXXX.c b/port/devXXX.c index 672d5477dc87c5b305d1769e4137c84341358d31..1bf8852bcd6aa6d61bdd8ab053ede41fbf107f61 100644 --- a/port/devXXX.c +++ b/port/devXXX.c @@ -17,80 +17,82 @@ enum{ Dirtab XXXtab[]={ "data", {Qdata, 0}, 0, 0600, }; -#define NXXXtab (sizeof(XXXtab)/sizeof(Dirtab)) -void -XXXreset(void) +static void +XXXreset(void) /* default in dev.c */ { } -void -XXXinit(void) +static void +XXXinit(void) /* default in dev.c */ { } -Chan * -XXXattach(char *spec) +static Chan* +XXXattach(char* spec) { return devattach('X', spec); } -Chan * -XXXclone(Chan *c, Chan *nc) +static Chan* +XXXclone(Chan* c, Chan* nc) /* default in dev.c */ { return devclone(c, nc); } -int -XXXwalk(Chan *c, char *name) +static int +XXXwalk(Chan* c, char* name) { - return devwalk(c, name, XXXtab, NXXXtab, devgen); + return devwalk(c, name, XXXtab, nelem(XXXtab), devgen); } -void -XXXstat(Chan *c, char *db) +static void +XXXstat(Chan* c, char* db) { - devstat(c, db, XXXtab, NXXXtab, devgen); + devstat(c, db, XXXtab, nelem(XXXtab), devgen); } -Chan * -XXXopen(Chan *c, int omode) +static Chan* +XXXopen(Chan* c, int omode) { - return devopen(c, omode, XXXtab, NXXXtab, devgen); + return devopen(c, omode, XXXtab, nelem(XXXtab), devgen); } -void -XXXcreate(Chan *c, char *name, int omode, ulong perm) +static void +XXXcreate(Chan* c, char* name, int omode, ulong perm) /* default in dev.c */ { USED(c, name, omode, perm); error(Eperm); } -void -XXXremove(Chan *c) +static void +XXXremove(Chan* c) /* default in dev.c */ { USED(c); error(Eperm); } -void -XXXwstat(Chan *c, char *dp) +static void +XXXwstat(Chan* c, char* dp) /* default in dev.c */ { USED(c, dp); error(Eperm); } -void -XXXclose(Chan *c) +static void +XXXclose(Chan* c) { + USED(c); } -long -XXXread(Chan *c, void *a, long n, ulong offset) +static long +XXXread(Chan* c, void* a, long n, ulong offset) { + USED(offset); + switch(c->qid.path & ~CHDIR){ case Qdir: - return devdirread(c, a, n, XXXtab, NXXXtab, devgen); + return devdirread(c, a, n, XXXtab, nelem(XXXtab), devgen); case Qdata: break; default: @@ -100,15 +102,17 @@ XXXread(Chan *c, void *a, long n, ulong offset) return n; } -Block* -XXXbread(Chan *c, long n, ulong offset) +static Block* +XXXbread(Chan* c, long n, ulong offset) /* default in dev.c */ { return devbread(c, n, offset); } -long -XXXwrite(Chan *c, char *a, long n, ulong offset) +static long +XXXwrite(Chan* c, char* a, long n, ulong offset) { + USED(a, offset); + switch(c->qid.path & ~CHDIR){ case Qdata: break; @@ -118,8 +122,26 @@ XXXwrite(Chan *c, char *a, long n, ulong offset) return n; } -long -XXXbwrite(Chan *c, Block *bp, ulong offset) +static long +XXXbwrite(Chan* c, Block* bp, ulong offset) /* default in dev.c */ { return devbwrite(c, bp, offset); } + +Dev XXXdevtab = { /* defaults in dev.c */ + XXXreset, /* devreset */ + XXXinit, /* devinit */ + XXXattach, + XXXclone, /* devclone */ + XXXwalk, + XXXstat, + XXXopen, + XXXcreate, /* devcreate */ + XXXclose, + XXXread, + XXXbread, /* devbread */ + XXXwrite, + XXXbwrite, /* devbwrite */ + XXXremove, /* devremove */ + XXXwstat, /* devwstat */ +}; diff --git a/port/devaudio.c b/port/devaudio.c index eb7c82d8ea3014b22fd43af50aa95c3675153b78..45eaffb245d453f5b19501461cc72ac43408f0ad 100644 --- a/port/devaudio.c +++ b/port/devaudio.c @@ -10,8 +10,6 @@ #include "io.h" #include "audio.h" -#define NPORT (sizeof audiodir/sizeof(Dirtab)) - typedef struct AQueue AQueue; typedef struct Buf Buf; @@ -94,18 +92,18 @@ static struct int irval; } volumes[] = { -[Vaudio] "audio", Fout, 50, 50, -[Vsynth] "synth", Fin|Fout, 0, 0, -[Vcd] "cd", Fin|Fout, 0, 0, -[Vline] "line", Fin|Fout, 0, 0, +[Vaudio] "audio", Fout, 50, 50, +[Vsynth] "synth", Fin|Fout, 0, 0, +[Vcd] "cd", Fin|Fout, 0, 0, +[Vline] "line", Fin|Fout, 0, 0, [Vmic] "mic", Fin|Fout|Fmono, 0, 0, [Vspeaker] "speaker", Fout|Fmono, 0, 0, [Vtreb] "treb", Fout, 50, 50, [Vbass] "bass", Fout, 50, 50, -[Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed, - 0 +[Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed, + 0 }; static struct @@ -142,7 +140,7 @@ sbcmd(int val) return 0; } } -/* print("SB16 sbcmd (#%.2x) timeout\n", val); /**/ +/* print("#A: sbcmd (#%.2x) timeout\n", val); /**/ return 1; } @@ -157,7 +155,7 @@ sbread(void) return inb(blaster.read); } } -/* print("SB16 sbread did not respond\n"); /**/ +/* print("#A: sbread did not respond\n"); /**/ return 0xbb; } @@ -422,14 +420,14 @@ audiosbintr(void) void pcaudiosbintr(Ureg*, void*) { -/* print("sb16 audio interrupt\n"); /**/ +/* print("#A: audio interrupt\n"); /**/ audiosbintr(); } void audiodmaintr(void) { -/* print("sb16 dma interrupt\n"); /**/ +/* print("#A: dma interrupt\n"); /**/ } static int @@ -450,7 +448,7 @@ waitaudio(void) pokeaudio(); tsleep(&audio.vous, anybuf, 0, 10*1000); if(audio.intr == 0) { -/* print("audio timeout\n"); /**/ +/* print("#A: audio timeout\n"); /**/ audio.active = 0; pokeaudio(); } @@ -487,11 +485,6 @@ setempty(void) iunlock(&blaster); } -void -audioreset(void) -{ -} - static void resetlevel(void) { @@ -505,7 +498,7 @@ resetlevel(void) } } -void +static void audioinit(void) { ISAConf sbconf; @@ -525,7 +518,7 @@ audioinit(void) case 0x280: break; default: - print("devaudio: bad sb16 port 0x%x\n", sbconf.port); + print("#A: bad port 0x%x\n", sbconf.port); return; } switch(sbconf.irq){ @@ -535,12 +528,10 @@ audioinit(void) case 10: break; default: - print("devaudio: bad sb16 irq %d\n", sbconf.irq); + print("#A: bad irq %d\n", sbconf.irq); return; } - blaster.dma = sbconf.dma; - blaster.reset = sbconf.port + 0x6; blaster.read = sbconf.port + 0xa; blaster.write = sbconf.port + 0xc; @@ -551,6 +542,7 @@ audioinit(void) blaster.clri8 = sbconf.port + 0xe; blaster.clri16 = sbconf.port + 0xf; blaster.clri401 = sbconf.port + 0x100; + blaster.dma = sbconf.dma; seteisadma(blaster.dma, audiodmaintr); setvec(Int0vec+sbconf.irq, pcaudiosbintr, 0); @@ -565,7 +557,7 @@ audioinit(void) i = sbread(); if(i != 0xaa) { - print("sound blaster didnt respond #%.2x\n", i); + print("#A: no response #%.2x\n", i); return; } @@ -574,7 +566,7 @@ audioinit(void) audio.minor = sbread(); if(audio.major != 4) { - print("bad soundblaster model #%.2x #%.2x; not SB 16\n", audio.major, audio.minor); + print("#A: model #%.2x #%.2x; not SB 16\n", audio.major, audio.minor); return; } /* @@ -595,31 +587,25 @@ audioinit(void) mxcmd(0x81, 1<mode = openmode(omode); c->flag |= COPEN; c->offset = 0; @@ -664,13 +650,7 @@ audioopen(Chan *c, int omode) return c; } -void -audiocreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void +static void audioclose(Chan *c) { @@ -701,7 +681,7 @@ audioclose(Chan *c) } } -long +static long audioread(Chan *c, char *a, long n, ulong offset) { int liv, riv, lov, rov; @@ -717,7 +697,7 @@ audioread(Chan *c, char *a, long n, ulong offset) break; case Qdir: - return devdirread(c, a, n, audiodir, NPORT, devgen); + return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); case Qaudio: if(audio.amode != Aread) @@ -795,13 +775,7 @@ audioread(Chan *c, char *a, long n, ulong offset) return n0-n; } -Block* -audiobread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long +static long audiowrite(Chan *c, char *a, long n, ulong) { long m, n0; @@ -928,24 +902,6 @@ audiowrite(Chan *c, char *a, long n, ulong) return n0 - n; } -long -audiobwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -audioremove(Chan*) -{ - error(Eperm); -} - -void -audiowstat(Chan*, char*) -{ - error(Eperm); -} - static void swab(uchar *a) { @@ -963,3 +919,21 @@ swab(uchar *a) *p++ = b; } } + +Dev audiodevtab = { + devreset, + audioinit, + audioattach, + devclone, + audiowalk, + audiostat, + audioopen, + devcreate, + audioclose, + audioread, + devbread, + audiowrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/port/devboot.c b/port/devboot.c deleted file mode 100644 index 28545986acbdd49b97ae54057fa2a8b4409e0acb..0000000000000000000000000000000000000000 --- a/port/devboot.c +++ /dev/null @@ -1,142 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "../port/error.h" - -enum{ - Qdir, - Qboot, - Qmem, -}; - -Dirtab bootdir[]={ - "boot", {Qboot}, 0, 0666, - "mem", {Qmem}, 0, 0666, -}; - -#define NBOOT (sizeof bootdir/sizeof(Dirtab)) - -void -bootreset(void) -{ -} - -void -bootinit(void) -{ -} - -Chan* -bootattach(char *spec) -{ - return devattach('B', spec); -} - -Chan* -bootclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int -bootwalk(Chan *c, char *name) -{ - return devwalk(c, name, bootdir, NBOOT, devgen); -} - -void -bootstat(Chan *c, char *dp) -{ - devstat(c, dp, bootdir, NBOOT, devgen); -} - -Chan* -bootopen(Chan *c, int omode) -{ - return devopen(c, omode, bootdir, NBOOT, devgen); -} - -void -bootcreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void -bootclose(Chan*) -{ -} - -long -bootread(Chan *c, void *buf, long n, ulong offset) -{ - switch(c->qid.path & ~CHDIR){ - - case Qdir: - return devdirread(c, buf, n, bootdir, NBOOT, devgen); - - case Qmem: - /* kernel memory */ - if(offset>=KZERO && offset KZERO+conf.npage*BY2PG) - n = KZERO+conf.npage*BY2PG - offset; - memmove(buf, (char*)offset, n); - return n; - } - error(Ebadarg); - } - - error(Egreg); - return 0; /* not reached */ -} - -Block* -bootbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long -bootwrite(Chan *c, void *buf, long n, ulong offset) -{ - ulong pc; - - switch(c->qid.path & ~CHDIR){ - case Qmem: - /* kernel memory */ - if(offset>=KZERO && offset KZERO+conf.npage*BY2PG) - n = KZERO+conf.npage*BY2PG - offset; - memmove((char*)offset, buf, n); - return n; - } - error(Ebadarg); - - case Qboot: - pc = *(ulong*)buf; - splhi(); - gotopc(pc); - } - error(Ebadarg); - return 0; /* not reached */ -} - -long -bootbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -bootremove(Chan*) -{ - error(Eperm); -} - -void -bootwstat(Chan*, char*) -{ - error(Eperm); -} diff --git a/port/devcons.c b/port/devcons.c index a60a9e99d272061a28870eb4e1075170c5a538e9..2bc18217586e202e872f9f210c1d16100fe84eef 100644 --- a/port/devcons.c +++ b/port/devcons.c @@ -5,11 +5,11 @@ #include "fns.h" #include "../port/error.h" +void (*consdebug)(void); -Queue *mouseq; -Queue *kbdq; /* unprocessed console input */ -Queue *lineq; /* processed console input */ -Queue *printq; /* console output */ +Queue* kbdq; /* unprocessed console input */ +Queue* lineq; /* processed console input */ +Queue* printq; /* console output */ static struct { @@ -28,7 +28,7 @@ static struct char sysname[NAMELEN]; -static ulong randomread(uchar*, ulong); +static ulong randomread(void*, ulong); static void randominit(void); static void seednrand(void); @@ -39,6 +39,21 @@ printinit(void) qnoblock(lineq, 1); } +int +consactive(void) +{ + if(printq) + return qlen(printq) > 0; + return 0; +} + +void +prflush(void) +{ + while(consactive()) + ; +} + /* * Print a string on the console. Convert \n to \r\n for serial * line consoles. Locking of the queues is left up to the screen @@ -110,8 +125,8 @@ snprint(char *s, int n, char *fmt, ...) int sprint(char *s, char *fmt, ...) { - va_list arg; int n; + va_list arg; va_start(arg, fmt); n = doprint(s, s+PRINTSIZE, fmt, arg) - s; @@ -122,9 +137,9 @@ sprint(char *s, char *fmt, ...) int print(char *fmt, ...) { - char buf[PRINTSIZE]; - va_list arg; int n; + va_list arg; + char buf[PRINTSIZE]; va_start(arg, fmt); n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; @@ -135,11 +150,11 @@ print(char *fmt, ...) } int -fprint(int, char *fmt, ...) +fprint(int, char *fmt, ...) /* needed so we can use user-level libg */ { - char buf[PRINTSIZE]; - va_list arg; int n; + va_list arg; + char buf[PRINTSIZE]; va_start(arg, fmt); n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; @@ -152,9 +167,9 @@ fprint(int, char *fmt, ...) void panic(char *fmt, ...) { - char buf[PRINTSIZE]; - va_list arg; int n; + va_list arg; + char buf[PRINTSIZE]; strcpy(buf, "panic: "); va_start(arg, fmt); @@ -172,10 +187,10 @@ panic(char *fmt, ...) int pprint(char *fmt, ...) { - char buf[2*PRINTSIZE]; + int n; Chan *c; va_list arg; - int n; + char buf[2*PRINTSIZE]; if(up->fgrp == 0) return 0; @@ -190,7 +205,7 @@ pprint(char *fmt, ...) if(waserror()) return 0; - (*devtab[c->type].write)(c, buf, n, c->offset); + devtab[c->type]->write(c, buf, n, c->offset); poperror(); lock(c); @@ -200,13 +215,6 @@ pprint(char *fmt, ...) return n; } -void -prflush(void) -{ - while(consactive()) - ; -} - void echo(Rune r, char *buf, int n) { @@ -238,7 +246,8 @@ echo(Rune r, char *buf, int n) ixsummary(); break; case 'd': - consdebug(); + if(consdebug != nil) + consdebug(); return; case 'p': procdump(); @@ -333,14 +342,6 @@ kbdclock(void) kbdputc(kbdq, kbd.c); } -int -consactive(void) -{ - if(printq) - return qlen(printq) > 0; - return 0; -} - enum{ Qdir, Qauth, @@ -354,9 +355,7 @@ enum{ Qkey, Qhostdomain, Qhostowner, - Qlights, Qmsec, - Qnoise, Qnull, Qpgrpid, Qpid, @@ -382,9 +381,7 @@ Dirtab consdir[]={ "hostowner", {Qhostowner}, NAMELEN, 0664, "hz", {Qhz}, NUMSIZE, 0666, "key", {Qkey}, DESKEYLEN, 0622, - "lights", {Qlights}, 0, 0220, "msec", {Qmsec}, NUMSIZE, 0444, - "noise", {Qnoise}, 0, 0220, "null", {Qnull}, 0, 0666, "pgrpid", {Qpgrpid}, NUMSIZE, 0444, "pid", {Qpid}, NUMSIZE, 0444, @@ -398,8 +395,6 @@ Dirtab consdir[]={ "user", {Quser}, NAMELEN, 0666, }; -#define NCONS (sizeof consdir/sizeof(Dirtab)) - ulong boottime; /* seconds since epoch at boot */ long @@ -437,18 +432,13 @@ readstr(ulong off, char *buf, ulong n, char *str) return n; } -void -consreset(void) -{ -} - -void +static void consinit(void) { randominit(); } -Chan* +static Chan* consattach(char *spec) { static int seeded; @@ -460,25 +450,19 @@ consattach(char *spec) return devattach('c', spec); } -Chan* -consclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int conswalk(Chan *c, char *name) { - return devwalk(c, name, consdir, NCONS, devgen); + return devwalk(c, name, consdir, nelem(consdir), devgen); } -void +static void consstat(Chan *c, char *dp) { - devstat(c, dp, consdir, NCONS, devgen); + devstat(c, dp, consdir, nelem(consdir), devgen); } -Chan* +static Chan* consopen(Chan *c, int omode) { c->aux = 0; @@ -491,16 +475,10 @@ consopen(Chan *c, int omode) qunlock(&kbd); break; } - return devopen(c, omode, consdir, NCONS, devgen); -} - -void -conscreate(Chan*, char*, int, ulong) -{ - error(Eperm); + return devopen(c, omode, consdir, nelem(consdir), devgen); } -void +static void consclose(Chan *c) { /* last close of control file turns off raw */ @@ -520,7 +498,7 @@ consclose(Chan *c) } } -long +static long consread(Chan *c, void *buf, long n, ulong offset) { ulong l; @@ -534,15 +512,15 @@ consread(Chan *c, void *buf, long n, ulong offset) return n; switch(c->qid.path & ~CHDIR){ case Qdir: - return devdirread(c, buf, n, consdir, NCONS, devgen); + return devdirread(c, buf, n, consdir, nelem(consdir), devgen); case Qcons: qlock(&kbd); - if(waserror()){ + if(waserror()) { qunlock(&kbd); nexterror(); } - while(!qcanread(lineq)){ + while(!qcanread(lineq)) { qread(kbdq, &kbd.line[kbd.x], 1); ch = kbd.line[kbd.x]; if(kbd.raw){ @@ -693,54 +671,7 @@ consread(Chan *c, void *buf, long n, ulong offset) return -1; /* never reached */ } -Block* -consbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -void -conslights(char *a, int n) -{ - char line[128]; - char *lp; - int c; - - lp = line; - while(n--){ - *lp++ = c = *a++; - if(c=='\n' || n==0 || lp==&line[sizeof(line)-1]) - break; - } - *lp = 0; - lights(strtoul(line, 0, 0)); -} - -void -consnoise(char *a, int n) -{ - int freq; - int duration; - char line[128]; - char *lp; - int c; - - lp = line; - while(n--){ - *lp++ = c = *a++; - if(c=='\n' || n==0 || lp==&line[sizeof(line)-1]){ - *lp = 0; - freq = strtoul(line, &lp, 0); - while(*lp==' ' || *lp=='\t') - lp++; - duration = strtoul(lp, &lp, 0); - buzz(freq, duration); - lp = line; - } - } -} - -long +static long conswrite(Chan *c, void *va, long n, ulong offset) { char cbuf[64]; @@ -829,14 +760,6 @@ conswrite(Chan *c, void *va, long n, ulong offset) case Qnull: break; - case Qnoise: - consnoise(a, n); - break; - - case Qlights: - conslights(a, n); - break; - case Qreboot: if(!iseve()) error(Eperm); @@ -895,24 +818,6 @@ conswrite(Chan *c, void *va, long n, ulong offset) return n; } -long -consbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -consremove(Chan*) -{ - error(Eperm); -} - -void -conswstat(Chan*, char*) -{ - error(Eperm); -} - void setterm(char *f) { @@ -922,12 +827,30 @@ setterm(char *f) ksetenv("terminal", buf); } +Dev consdevtab = { + devreset, + consinit, + consattach, + devclone, + conswalk, + consstat, + consopen, + devcreate, + consclose, + consread, + devbread, + conswrite, + devbwrite, + devremove, + devwstat, +}; + static struct { QLock; - ulong randomcount; Rendez producer; Rendez consumer; + ulong randomcount; uchar buf[4096]; uchar *ep; uchar *rp; @@ -941,7 +864,7 @@ static struct static void seednrand(void) { - randomread((uchar*)&rb.randn, sizeof(rb.randn)); + randomread((void*)&rb.randn, sizeof(rb.randn)); } int @@ -960,6 +883,12 @@ rbnotfull(void*) return i != 1 && i != (1 - sizeof(rb.buf)); } +static int +rbnotempty(void*) +{ + return rb.wp != rb.rp; +} + void genrandom(void*) { @@ -978,6 +907,7 @@ genrandom(void*) static void randominit(void) { + addclock0link(randomclock); rb.ep = rb.buf + sizeof(rb.buf); rb.rp = rb.wp = rb.buf; kproc("genrandom", genrandom, 0); @@ -1010,19 +940,15 @@ randomclock(void) wakeup(&rb.consumer); } -static int -rbnotempty(void*) -{ - return rb.wp != rb.rp; -} - /* * consume random bytes from a circular buffer */ static ulong -randomread(uchar *p, ulong n) +randomread(void *xp, ulong n) { - uchar *e; + uchar *e, *p; + + p = xp; if(waserror()){ qunlock(&rb); diff --git a/port/devdup.c b/port/devdup.c index 40886120e7052d45c22afe0a326f342799bbf354..951c44482b0a841ab90d57b60237907c6291dfe4 100644 --- a/port/devdup.c +++ b/port/devdup.c @@ -5,9 +5,7 @@ #include "fns.h" #include "../port/error.h" - - -int +static int dupgen(Chan *c, Dirtab*, int, int s, Dir *dp) { char buf[8]; @@ -24,41 +22,25 @@ dupgen(Chan *c, Dirtab*, int, int s, Dir *dp) return 1; } -void -dupinit(void) -{ -} - -void -dupreset(void) -{ -} - -Chan * +static Chan* dupattach(char *spec) { return devattach('d', spec); } -Chan * -dupclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int dupwalk(Chan *c, char *name) { return devwalk(c, name, (Dirtab *)0, 0, dupgen); } -void +static void dupstat(Chan *c, char *db) { devstat(c, db, (Dirtab *)0, 0L, dupgen); } -Chan * +static Chan* dupopen(Chan *c, int omode) { Chan *f; @@ -73,37 +55,19 @@ dupopen(Chan *c, int omode) } fdtochan(c->qid.path, openmode(omode), 0, 0); /* error check only */ f = up->fgrp->fd[c->qid.path]; - close(c); + cclose(c); incref(f); if(omode & OCEXEC) f->flag |= CCEXEC; return f; } -void -dupcreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void -dupremove(Chan*) -{ - error(Eperm); -} - -void -dupwstat(Chan*, char*) -{ - error(Egreg); -} - -void +static void dupclose(Chan*) { } -long +static long dupread(Chan *c, void *va, long n, ulong) { char *a = va; @@ -113,21 +77,27 @@ dupread(Chan *c, void *va, long n, ulong) return devdirread(c, a, n, (Dirtab *)0, 0L, dupgen); } -Block* -dupbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long +static long dupwrite(Chan*, void*, long, ulong) { panic("dupwrite"); return 0; /* not reached */ } -long -dupbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} +Dev dupdevtab = { + devreset, + devinit, + dupattach, + devclone, + dupwalk, + dupstat, + dupopen, + devcreate, + dupclose, + dupread, + devbread, + dupwrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/port/devenv.c b/port/devenv.c index 95ffe503ea33feda64bcc21f4e3e14815f2ba517..f4fa7f830388c6f11d996d2b12c135b4a40c2c9e 100644 --- a/port/devenv.c +++ b/port/devenv.c @@ -11,17 +11,7 @@ enum Maxenvsize = 16300, }; -void -envreset(void) -{ -} - -void -envinit(void) -{ -} - -int +static int envgen(Chan *c, Dirtab*, int, int s, Dir *dp) { Egrp *eg; @@ -43,31 +33,25 @@ envgen(Chan *c, Dirtab*, int, int s, Dir *dp) return 1; } -Chan* +static Chan* envattach(char *spec) { return devattach('e', spec); } -Chan* -envclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int envwalk(Chan *c, char *name) { return devwalk(c, name, 0, 0, envgen); } -void +static void envstat(Chan *c, char *db) { devstat(c, db, 0, 0, envgen); } -Chan * +static Chan* envopen(Chan *c, int omode) { Egrp *eg; @@ -101,7 +85,7 @@ envopen(Chan *c, int omode) return c; } -void +static void envcreate(Chan *c, char *name, int omode, ulong) { Egrp *eg; @@ -140,7 +124,7 @@ envcreate(Chan *c, char *name, int omode, ulong) c->flag |= COPEN; } -void +static void envremove(Chan *c) { Egrp *eg; @@ -172,18 +156,12 @@ envremove(Chan *c) free(e); } -void -envwstat(Chan*, char*) -{ - error(Eperm); -} - -void +static void envclose(Chan*) { } -long +static long envread(Chan *c, void *a, long n, ulong offset) { Egrp *eg; @@ -213,13 +191,7 @@ envread(Chan *c, void *a, long n, ulong offset) return n; } -Block* -envbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long +static long envwrite(Chan *c, void *a, long n, ulong offset) { char *s; @@ -258,11 +230,23 @@ envwrite(Chan *c, void *a, long n, ulong offset) return n; } -long -envbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} +Dev envdevtab = { + devreset, + devinit, + envattach, + devclone, + envwalk, + envstat, + envopen, + envcreate, + envclose, + envread, + devbread, + envwrite, + devbwrite, + envremove, + devwstat, +}; void envcpy(Egrp *to, Egrp *from) @@ -315,6 +299,6 @@ ksetenv(char *ename, char *eval) sprint(buf, "#e/%s", ename); c = namec(buf, Acreate, OWRITE, 0600); - (*devtab[c->type].write)(c, eval, strlen(eval), 0); - close(c); + devtab[c->type]->write(c, eval, strlen(eval), 0); + cclose(c); } diff --git a/port/devkprof.c b/port/devkprof.c index 974e5774b709a67458567a714ea9d14598ffdd12..098bbf39a80e0ef97d31746958523e7e406420cf 100644 --- a/port/devkprof.c +++ b/port/devkprof.c @@ -22,29 +22,44 @@ enum{ Kprofdirqid, Kprofdataqid, Kprofctlqid, - Nkproftab=Kprofctlqid, - Kprofmaxqid, }; -Dirtab kproftab[Nkproftab]={ +Dirtab kproftab[]={ "kpdata", {Kprofdataqid}, 0, 0600, "kpctl", {Kprofctlqid}, 0, 0600, }; -void kproftimer(ulong); - -void -kprofreset(void) +static void +_kproftimer(ulong pc) { + extern void spldone(void); + + if(kprof.time == 0) + return; + /* + * if the pc is coming out of spllo or splx, + * use the pc saved when we went splhi. + */ + if(pc>=(ulong)spllo && pc<=(ulong)spldone) + pc = m->splpc; + + kprof.buf[0] += TK2MS(1); + if(kprof.minpc<=pc && pc>= LRES; + kprof.buf[pc] += TK2MS(1); + }else + kprof.buf[1] += TK2MS(1); } -void +static void kprofinit(void) { if(SZ != sizeof kprof.buf[0]) panic("kprof size"); + kproftimer = _kproftimer; } -Chan * +static Chan* kprofattach(char *spec) { ulong n; @@ -62,25 +77,20 @@ kprofattach(char *spec) kproftab[0].length = n; return devattach('T', spec); } -Chan * -kprofclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} -int +static int kprofwalk(Chan *c, char *name) { - return devwalk(c, name, kproftab, (long)Nkproftab, devgen); + return devwalk(c, name, kproftab, nelem(kproftab), devgen); } -void +static void kprofstat(Chan *c, char *db) { - devstat(c, db, kproftab, (long)Nkproftab, devgen); + devstat(c, db, kproftab, nelem(kproftab), devgen); } -Chan * +static Chan* kprofopen(Chan *c, int omode) { if(c->qid.path == CHDIR){ @@ -93,30 +103,12 @@ kprofopen(Chan *c, int omode) return c; } -void -kprofcreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void -kprofremove(Chan*) -{ - error(Eperm); -} - -void -kprofwstat(Chan*, char*) -{ - error(Eperm); -} - -void +static void kprofclose(Chan*) { } -long +static long kprofread(Chan *c, void *va, long n, ulong offset) { ulong end; @@ -125,7 +117,7 @@ kprofread(Chan *c, void *va, long n, ulong offset) switch(c->qid.path & ~CHDIR){ case Kprofdirqid: - return devdirread(c, va, n, kproftab, Nkproftab, devgen); + return devdirread(c, va, n, kproftab, nelem(kproftab), devgen); case Kprofdataqid: end = kprof.nbuf*SZ; @@ -157,13 +149,7 @@ kprofread(Chan *c, void *va, long n, ulong offset) return n; } -Block* -kprofbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long +static long kprofwrite(Chan *c, char *a, long n, ulong) { switch((int)(c->qid.path&~CHDIR)){ @@ -182,31 +168,20 @@ kprofwrite(Chan *c, char *a, long n, ulong) return n; } -long -kprofbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -kproftimer(ulong pc) -{ - extern void spldone(void); - - if(kprof.time == 0) - return; - /* - * if the pc is coming out of spllo or splx, - * use the pc saved when we went splhi. - */ - if(pc>=(ulong)spllo && pc<=(ulong)spldone) - pc = m->splpc; - - kprof.buf[0] += TK2MS(1); - if(kprof.minpc<=pc && pc>= LRES; - kprof.buf[pc] += TK2MS(1); - }else - kprof.buf[1] += TK2MS(1); -} +Dev kprofdevtab = { + devreset, + kprofinit, + kprofattach, + devclone, + kprofwalk, + kprofstat, + kprofopen, + devcreate, + kprofclose, + kprofread, + devbread, + kprofwrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/port/devlance.c b/port/devlance.c index 04254982c7ca94f3aeb12113ccc7ceba1c74c10b..1693b0fac46d65761164c95e7d5db277b1d41e51 100644 --- a/port/devlance.c +++ b/port/devlance.c @@ -134,7 +134,7 @@ struct Softlance static void promiscuous(void*, int); -void +static void lancereset(void) { static int inited; @@ -144,10 +144,10 @@ lancereset(void) lancesetup(&l); /* general network interface structure */ - netifinit(&l, "ether", Ntypes, 32*1024); + netifinit(&l, "ether0", Ntypes, 32*1024); l.alen = 6; - memmove(l.addr, l.ea, 6); - memmove(l.bcast, etherbcast, 6); + memmove(l.addr, l.ea, Eaddrlen); + memset(l.bcast, 0xFF, Eaddrlen); l.promiscuous = promiscuous; l.arg = &l; @@ -374,7 +374,7 @@ promiscuous(void*, int on) lancestart(0);; } -void +static void lanceinit(void) { lancestart(0); @@ -382,53 +382,47 @@ lanceinit(void) l.ea[0], l.ea[1], l.ea[2], l.ea[3], l.ea[4], l.ea[5]); } -Chan* +static Chan* lanceattach(char *spec) { - return devattach('l', spec); -} + char *s; -Chan* -lanceclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); + s = spec; + if(s && *s && (*s != '0' || *(s+1))) + error(Enodev); + + return devattach('l', spec); } -int +static int lancewalk(Chan *c, char *name) { return netifwalk(&l, c, name); } -Chan* +static Chan* lanceopen(Chan *c, int omode) { return netifopen(&l, c, omode); } -void +static void lancecreate(Chan*, char*, int, ulong) { } -void +static void lanceclose(Chan *c) { netifclose(&l, c); } -long +static long lanceread(Chan *c, void *buf, long n, ulong offset) { return netifread(&l, c, buf, n, offset); } -Block* -lancebread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - static int isoutbuf(void *x) { @@ -462,7 +456,7 @@ etherloop(Etherpkt *p, long n) return !different; } -long +static long lancewrite(Chan *c, void *buf, long n, ulong) { Msg *m; @@ -511,25 +505,60 @@ lancewrite(Chan *c, void *buf, long n, ulong) return n; } -long -lancebwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void +static void lanceremove(Chan*) { } -void +static void lancestat(Chan *c, char *dp) { netifstat(&l, c, dp); } -void +static void lancewstat(Chan *c, char *dp) { netifwstat(&l, c, dp); } + +int +parseether(uchar *to, char *from) +{ + char nip[4]; + char *p; + int i; + + p = from; + for(i = 0; i < 6; i++){ + if(*p == 0) + return -1; + nip[0] = *p++; + if(*p == 0) + return -1; + nip[1] = *p++; + nip[2] = 0; + to[i] = strtoul(nip, 0, 16); + if(*p == ':') + p++; + } + return 0; +} + +Dev lancedevtab = { + lancereset, + lanceinit, + lanceattach, + devclone, + lancewalk, + lancestat, + lanceopen, + lancecreate, + lanceclose, + lanceread, + devbread, + lancewrite, + devbwrite, + lanceremove, + lancewstat, +}; diff --git a/port/devmnt.c b/port/devmnt.c index efc2e479d2b13d72ec1d0c0e0ecf577cbe3271c2..4e8926e2779cc123e91ced6d0162c7063664d573 100644 --- a/port/devmnt.c +++ b/port/devmnt.c @@ -34,7 +34,7 @@ struct Mntalloc #define limit(n, max) (n > max ? max : n) void mattach(Mnt*, Chan*, char*); -void mntauth(Mnt *, Mntrpc *, char *, ushort); +void mntauth(Mnt*, Mntrpc*, char*, ushort); Mnt* mntchk(Chan*); void mntdirfix(uchar*, Chan*); int mntflush(Mnt*, Mntrpc*); @@ -43,8 +43,8 @@ void mntgate(Mnt*); void mntpntfree(Mnt*); void mntqrm(Mnt*, Mntrpc*); Mntrpc* mntralloc(Chan*); -long mntrdwr(int , Chan*, void*,long , ulong); -long mnt9prdwr(int , Chan*, void*,long , ulong); +long mntrdwr(int, Chan*, void*, long, ulong); +long mnt9prdwr(int, Chan*, void*, long, ulong); void mntrpcread(Mnt*, Mntrpc*); void mountio(Mnt*, Mntrpc*); void mountmux(Mnt*, Mntrpc*); @@ -63,7 +63,7 @@ enum Tagend = 0xfffe, }; -void +static void mntreset(void) { mntalloc.id = 1; @@ -72,12 +72,7 @@ mntreset(void) cinit(); } -void -mntinit(void) -{ -} - -Chan* +static Chan* mntattach(char *muxattach) { Mnt *m; @@ -149,14 +144,6 @@ mntattach(char *muxattach) m->blocksize = defmaxmsg; m->flags = bogus.flags & ~MCACHE; - switch(devchar[m->c->type]) { - default: - m->mux = 0; - break; - case 'C': /* Cyclone */ - m->mux = 1; - break; - } incref(m->c); sprint(buf, "#M%d", m->id); @@ -247,7 +234,7 @@ mattach(Mnt *m, Chan *c, char *spec) mntfree(r); } -Chan* +static Chan* mntclone(Chan *c, Chan *nc) { Mnt *m; @@ -263,7 +250,7 @@ mntclone(Chan *c, Chan *nc) if(waserror()) { mntfree(r); if(alloc) - close(nc); + cclose(nc); nexterror(); } @@ -282,7 +269,7 @@ mntclone(Chan *c, Chan *nc) return nc; } -int +static int mntwalk(Chan *c, char *name) { Mnt *m; @@ -311,7 +298,7 @@ mntwalk(Chan *c, char *name) return 1; } -void +static void mntstat(Chan *c, char *dp) { Mnt *m; @@ -333,7 +320,7 @@ mntstat(Chan *c, char *dp) mntfree(r); } -Chan* +static Chan* mntopen(Chan *c, int omode) { Mnt *m; @@ -363,7 +350,7 @@ mntopen(Chan *c, int omode) return c; } -void +static void mntcreate(Chan *c, char *name, int omode, ulong perm) { Mnt *m; @@ -392,7 +379,7 @@ mntcreate(Chan *c, char *name, int omode, ulong perm) copen(c); } -void +static void mntclunk(Chan *c, int t) { Mnt *m; @@ -431,7 +418,7 @@ mclose(Mnt *m, Chan *c) mntfree(q); } m->id = 0; - close(m->c); + cclose(m->c); mntpntfree(m); } @@ -455,19 +442,19 @@ mntpntfree(Mnt *m) unlock(&mntalloc); } -void +static void mntclose(Chan *c) { mntclunk(c, Tclunk); } -void +static void mntremove(Chan *c) { mntclunk(c, Tremove); } -void +static void mntwstat(Chan *c, char *dp) { Mnt *m; @@ -493,7 +480,7 @@ mntread9p(Chan *c, void *buf, long n, ulong offset) return mnt9prdwr(Tread, c, buf, n, offset); } -long +static long mntread(Chan *c, void *buf, long n, ulong offset) { uchar *p, *e; @@ -530,30 +517,18 @@ mntread(Chan *c, void *buf, long n, ulong offset) return n; } -Block* -mntbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - long mntwrite9p(Chan *c, void *buf, long n, ulong offset) { return mnt9prdwr(Twrite, c, buf, n, offset); } -long +static long mntwrite(Chan *c, void *buf, long n, ulong offset) { return mntrdwr(Twrite, c, buf, n, offset); } -long -mntbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - long mnt9prdwr(int type, Chan *c, void *buf, long n, ulong offset) { @@ -685,6 +660,8 @@ mountio(Mnt *m, Mntrpc *r) /* Transmit a file system rpc */ n = convS2M(&r->request, r->rpc); + if(n < 0) + panic("bad message type in mountio"); if(waserror()) { if(mntflush(m, r) == 0) nexterror(); @@ -694,16 +671,11 @@ mountio(Mnt *m, Mntrpc *r) if(mnt9prdwr(Twrite, m->c, r->rpc, n, 0) != n) error(Emountrpc); }else{ - if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n) + if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n) error(Emountrpc); } poperror(); } - if(m->mux) { - mntqrm(m, r); - mntrpcread(m, r); - return; - } /* Gate readers onto the mount point one at a time */ for(;;) { @@ -738,8 +710,7 @@ mntrpcread(Mnt *m, Mntrpc *r) for(;;) { if(waserror()) { if(mntflush(m, r) == 0) { - if(m->mux == 0) - mntgate(m); + mntgate(m); nexterror(); } continue; @@ -749,7 +720,7 @@ mntrpcread(Mnt *m, Mntrpc *r) if(devchar[m->c->type] == L'M') n = mnt9prdwr(Tread, m->c, r->rpc, MAXRPC, 0); else - n = devtab[m->c->type].read(m->c, r->rpc, MAXRPC, 0); + n = devtab[m->c->type]->read(m->c, r->rpc, MAXRPC, 0); poperror(); if(n == 0) continue; @@ -763,7 +734,6 @@ void mntgate(Mnt *m) { Mntrpc *q; - int x; lock(m); m->rip = 0; @@ -821,6 +791,8 @@ mntflush(Mnt *m, Mntrpc *r) flush.tag = r->flushtag; flush.oldtag = r->request.tag; n = convS2M(&flush, r->flush); + if(n < 0) + panic("bad message type in mntflush"); if(waserror()) { if(strcmp(up->error, Eintr) == 0) @@ -828,14 +800,14 @@ mntflush(Mnt *m, Mntrpc *r) mntqrm(m, r); return 0; } - l = (*devtab[m->c->type].write)(m->c, r->flush, n, 0); + l = devtab[m->c->type]->write(m->c, r->flush, n, 0); if(l != n) error(Ehungup); poperror(); return 1; } -Mntrpc * +Mntrpc* mntralloc(Chan *c) { Mntrpc *new; @@ -857,6 +829,7 @@ mntralloc(Chan *c) new->c = c; new->done = 0; new->flushed = 0; + new->flushtag = 0; return new; } @@ -941,7 +914,7 @@ recoverchan(Mnt *m, Chan *c) mntopen(c, c->mode); } -Mnt * +Mnt* mntchk(Chan *c) { Mnt *m; @@ -1069,7 +1042,7 @@ mntrepl(char *buf) srvrecover(m->c, c1); lock(m); - close(m->c); + cclose(m->c); m->c = c1; m->recprog = 0; @@ -1079,3 +1052,21 @@ mntrepl(char *buf) unlock(m); } + +Dev mntdevtab = { + mntreset, + devinit, + mntattach, + mntclone, + mntwalk, + mntstat, + mntopen, + mntcreate, + mntclose, + mntread, + devbread, + mntwrite, + devbwrite, + mntremove, + mntwstat, +}; diff --git a/port/devmouse.c b/port/devmouse.c index 35c5bcd8f120d4ab5f8c507757658ae7d28ce9b0..158e65d1ba6f878a65e762bea86647340c8943bb 100644 --- a/port/devmouse.c +++ b/port/devmouse.c @@ -1,11 +1,11 @@ #include "u.h" #include "../port/lib.h" -#include #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" +#include #include "screen.h" typedef struct Mouseinfo Mouseinfo; @@ -53,6 +53,7 @@ Cursor arrow = { void Cursortocursor(Cursor*); int mousechanged(void*); +static void mouseclock(void); enum{ Qdir, @@ -67,11 +68,9 @@ Dirtab mousedir[]={ "mousectl", {Qmousectl}, 0, 0220, }; -#define NMOUSE (sizeof(mousedir)/sizeof(Dirtab)) - extern Bitmap gscreen; -void +static void mousereset(void) { if(!conf.monitor) @@ -79,9 +78,10 @@ mousereset(void) curs = arrow; Cursortocursor(&arrow); + addclock0link(mouseclock); } -void +static void mouseinit(void) { if(!conf.monitor) @@ -90,7 +90,7 @@ mouseinit(void) cursoron(1); } -Chan* +static Chan* mouseattach(char *spec) { if(!conf.monitor) @@ -98,7 +98,7 @@ mouseattach(char *spec) return devattach('m', spec); } -Chan* +static Chan* mouseclone(Chan *c, Chan *nc) { nc = devclone(c, nc); @@ -107,19 +107,19 @@ mouseclone(Chan *c, Chan *nc) return nc; } -int +static int mousewalk(Chan *c, char *name) { - return devwalk(c, name, mousedir, NMOUSE, devgen); + return devwalk(c, name, mousedir, nelem(mousedir), devgen); } -void +static void mousestat(Chan *c, char *db) { - devstat(c, db, mousedir, NMOUSE, devgen); + devstat(c, db, mousedir, nelem(mousedir), devgen); } -Chan* +static Chan* mouseopen(Chan *c, int omode) { switch(c->qid.path){ @@ -146,7 +146,7 @@ mouseopen(Chan *c, int omode) return c; } -void +static void mousecreate(Chan*, char*, int, ulong) { if(!conf.monitor) @@ -154,19 +154,7 @@ mousecreate(Chan*, char*, int, ulong) error(Eperm); } -void -mouseremove(Chan*) -{ - error(Eperm); -} - -void -mousewstat(Chan*, char*) -{ - error(Eperm); -} - -void +static void mouseclose(Chan *c) { if(c->qid.path!=CHDIR && (c->flag&COPEN)){ @@ -184,7 +172,7 @@ mouseclose(Chan *c) } -long +static long mouseread(Chan *c, void *va, long n, ulong offset) { char buf[4*12+1]; @@ -194,7 +182,7 @@ mouseread(Chan *c, void *va, long n, ulong offset) p = va; switch(c->qid.path){ case CHDIR: - return devdirread(c, va, n, mousedir, NMOUSE, devgen); + return devdirread(c, va, n, mousedir, nelem(mousedir), devgen); case Qcursor: if(offset != 0) @@ -231,13 +219,7 @@ mouseread(Chan *c, void *va, long n, ulong offset) return 0; } -Block* -mousebread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long +static long mousewrite(Chan *c, void *va, long n, ulong) { char *p; @@ -305,11 +287,23 @@ mousewrite(Chan *c, void *va, long n, ulong) return -1; } -long -mousebwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} +Dev mousedevtab = { + mousereset, + mouseinit, + mouseattach, + mouseclone, + mousewalk, + mousestat, + mouseopen, + mousecreate, + mouseclose, + mouseread, + devbread, + mousewrite, + devbwrite, + devremove, + devwstat, +}; void Cursortocursor(Cursor *c) @@ -324,7 +318,7 @@ Cursortocursor(Cursor *c) /* * called by the clock routine to redraw the cursor */ -void +static void mouseclock(void) { if(mouse.track){ diff --git a/port/devns16552.c b/port/devns16552.c index 8d0a23f97d1546526c1087fefada74c8122badb3..f2a14905b0c3f29595148ce976887acf4a77e61d 100644 --- a/port/devns16552.c +++ b/port/devns16552.c @@ -283,7 +283,6 @@ ns16552mflow(Uart *p, int n) uartwrreg(p, Iena, 0); p->modem = 0; p->cts = 1; - iunlock(&p->tlock); } iunlock(&p->tlock); @@ -377,9 +376,8 @@ ns16552disable(Uart *p) ns16552rts(p, 0); ns16552mflow(p, 0); ilock(&p->tlock); - p->blocked = 0; + p->xonoff = p->blocked = 0; iunlock(&p->tlock); - p->xonoff = 0; uartpower(p->dev, 0); @@ -559,7 +557,7 @@ ns16552intr(int dev) } unlock(&p->tlock); if(p->putc) - (*p->putc)(p->iq, ch); + p->putc(p->iq, ch); else { lock(&p->rlock); if(p->ip < p->ie) @@ -661,7 +659,7 @@ setlength(int i) /* * all uarts must be ns16552setup() by this point or inside of ns16552install() */ -void +static void ns16552reset(void) { int i; @@ -689,30 +687,19 @@ ns16552reset(void) } } -void -ns16552init(void) -{ -} - -Chan* +static Chan* ns16552attach(char *spec) { return devattach('t', spec); } -Chan* -ns16552clone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int ns16552walk(Chan *c, char *name) { return devwalk(c, name, ns16552dir, ndir, devgen); } -void +static void ns16552stat(Chan *c, char *dp) { if(NETTYPE(c->qid.path) == Ndataqid) @@ -720,7 +707,7 @@ ns16552stat(Chan *c, char *dp) devstat(c, dp, ns16552dir, ndir, devgen); } -Chan* +static Chan* ns16552open(Chan *c, int omode) { Uart *p; @@ -744,13 +731,7 @@ ns16552open(Chan *c, int omode) return c; } -void -ns16552create(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void +static void ns16552close(Chan *c) { Uart *p; @@ -775,7 +756,7 @@ ns16552close(Chan *c) } } -long +static long uartstatus(Chan*, Uart *p, void *buf, long n, long offset) { uchar mstat; @@ -809,7 +790,7 @@ for(j = 0; j < 8; j++) i+=sprint(str+i, " %ux", uartrdreg(p, j)); return readstr(offset, buf, n, str); } -long +static long ns16552read(Chan *c, void *buf, long n, ulong offset) { Uart *p; @@ -832,13 +813,7 @@ ns16552read(Chan *c, void *buf, long n, ulong offset) return 0; } -Block* -ns16552bread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -void +static void ns16552ctl(Uart *p, char *cmd) { int i, n; @@ -869,8 +844,8 @@ ns16552ctl(Uart *p, char *cmd) break; case 'H': case 'h': - qhangup(p->iq); - qhangup(p->oq); + qhangup(p->iq, 0); + qhangup(p->oq, 0); break; case 'L': case 'l': @@ -907,12 +882,14 @@ ns16552ctl(Uart *p, char *cmd) break; case 'X': case 'x': + ilock(&p->tlock); p->xonoff = n; + iunlock(&p->tlock); break; } } -long +static long ns16552write(Chan *c, void *buf, long n, ulong) { Uart *p; @@ -945,19 +922,7 @@ ns16552write(Chan *c, void *buf, long n, ulong) } } -long -ns16552bwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -ns16552remove(Chan*) -{ - error(Eperm); -} - -void +static void ns16552wstat(Chan *c, char *dp) { Dir d; @@ -975,3 +940,21 @@ ns16552wstat(Chan *c, char *dp) d.mode &= 0666; dt[0].perm = dt[1].perm = d.mode; } + +Dev ns16552devtab = { + ns16552reset, + devinit, + ns16552attach, + devclone, + ns16552walk, + ns16552stat, + ns16552open, + devcreate, + ns16552close, + ns16552read, + devbread, + ns16552write, + devbwrite, + devremove, + ns16552wstat, +}; diff --git a/port/devpipe.c b/port/devpipe.c index 9c06563af554965af2708a71494fa86a7986f1c6..781963c7b9444da36d3a44b58bbf2c38edee2d15 100644 --- a/port/devpipe.c +++ b/port/devpipe.c @@ -38,7 +38,7 @@ Dirtab pipedir[] = }; #define NPIPEDIR 2 -void +static void pipeinit(void) { if(conf.pipeqsize == 0){ @@ -49,15 +49,10 @@ pipeinit(void) } } -void -pipereset(void) -{ -} - /* * create a pipe, no streams are created until an open */ -Chan* +static Chan* pipeattach(char *spec) { Pipe *p; @@ -91,7 +86,7 @@ pipeattach(char *spec) return c; } -Chan* +static Chan* pipeclone(Chan *c, Chan *nc) { Pipe *p; @@ -114,7 +109,7 @@ pipeclone(Chan *c, Chan *nc) return nc; } -int +static int pipegen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) { int id; @@ -130,13 +125,13 @@ pipegen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) } -int +static int pipewalk(Chan *c, char *name) { return devwalk(c, name, pipedir, NPIPEDIR, pipegen); } -void +static void pipestat(Chan *c, char *db) { Pipe *p; @@ -163,7 +158,7 @@ pipestat(Chan *c, char *db) /* * if the stream doesn't exist, create it */ -Chan * +static Chan* pipeopen(Chan *c, int omode) { Pipe *p; @@ -195,25 +190,7 @@ pipeopen(Chan *c, int omode) return c; } -void -pipecreate(Chan*, char*, int, ulong) -{ - error(Egreg); -} - -void -piperemove(Chan*) -{ - error(Egreg); -} - -void -pipewstat(Chan*, char*) -{ - error(Eperm); -} - -void +static void pipeclose(Chan *c) { Pipe *p; @@ -229,14 +206,14 @@ pipeclose(Chan *c) case Qdata0: p->qref[0]--; if(p->qref[0] == 0){ - qhangup(p->q[1]); + qhangup(p->q[1], 0); qclose(p->q[0]); } break; case Qdata1: p->qref[1]--; if(p->qref[1] == 0){ - qhangup(p->q[0]); + qhangup(p->q[0], 0); qclose(p->q[1]); } break; @@ -265,7 +242,7 @@ pipeclose(Chan *c) qunlock(p); } -long +static long piperead(Chan *c, void *va, long n, ulong) { Pipe *p; @@ -285,7 +262,7 @@ piperead(Chan *c, void *va, long n, ulong) return -1; /* not reached */ } -Block* +static Block* pipebread(Chan *c, long n, ulong offset) { Pipe *p; @@ -306,12 +283,12 @@ pipebread(Chan *c, long n, ulong offset) * a write to a closed pipe causes a note to be sent to * the process. */ -long +static long pipewrite(Chan *c, void *va, long n, ulong) { Pipe *p; - if((getstatus()&IE) == 0) + if(!islo()) print("pipewrite hi %lux\n", getcallerpc(c)); if(waserror()) { /* avoid notes when pipe is a mounted queue */ @@ -339,7 +316,7 @@ pipewrite(Chan *c, void *va, long n, ulong) return n; } -long +static long pipebwrite(Chan *c, Block *bp, ulong) { long n; @@ -370,3 +347,21 @@ pipebwrite(Chan *c, Block *bp, ulong) poperror(); return n; } + +Dev pipedevtab = { + devreset, + pipeinit, + pipeattach, + pipeclone, + pipewalk, + pipestat, + pipeopen, + devcreate, + pipeclose, + piperead, + pipebread, + pipewrite, + pipebwrite, + devremove, + devwstat, +}; diff --git a/port/devproc.c b/port/devproc.c index 0bc440171a7448a2bf3016d209a17e27d59a7e2e..b7da7fb4c1107d530e28f65ae59ab19f0247c0bd 100644 --- a/port/devproc.c +++ b/port/devproc.c @@ -57,7 +57,6 @@ char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", "Shdata" }; * 32 bits of pid, for consistency checking * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid. */ -#define NPROC (sizeof procdir/sizeof(Dirtab)) #define QSHIFT 4 /* location in qid of proc slot # */ #define QID(q) (((q).path&0x0000000F)>>0) @@ -72,7 +71,7 @@ Segment* txt2data(Proc*, Segment*); int procstopped(void*); void mntscan(Mntwalk*); -int +static int procgen(Chan *c, Dirtab *tab, int, int s, Dir *dp) { Qid qid; @@ -93,7 +92,7 @@ procgen(Chan *c, Dirtab *tab, int, int s, Dir *dp) devdir(c, qid, buf, 0, p->user, CHDIR|0555, dp); return 1; } - if(s >= NPROC) + if(s >= nelem(procdir)) return -1; if(tab) panic("procgen"); @@ -125,31 +124,20 @@ procgen(Chan *c, Dirtab *tab, int, int s, Dir *dp) return 1; } -void +static void procinit(void) { if(conf.nproc >= (1<<(16-QSHIFT))-1) print("warning: too many procs for devproc\n"); } -void -procreset(void) -{ -} - -Chan* +static Chan* procattach(char *spec) { return devattach('p', spec); } -Chan* -procclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int procwalk(Chan *c, char *name) { if(strcmp(name, "..") == 0) { @@ -160,13 +148,13 @@ procwalk(Chan *c, char *name) return devwalk(c, name, 0, 0, procgen); } -void +static void procstat(Chan *c, char *db) { devstat(c, db, 0, 0, procgen); } -Chan * +static Chan* procopen(Chan *c, int omode) { Proc *p; @@ -234,19 +222,7 @@ procopen(Chan *c, int omode) return devopen(c, omode, 0, 0, procgen); } -void -proccreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void -procremove(Chan*) -{ - error(Eperm); -} - -void +static void procwstat(Chan *c, char *db) { Proc *p; @@ -266,14 +242,14 @@ procwstat(Chan *c, char *db) p->procmode = d.mode&0777; } -void +static void procclose(Chan * c) { if(QID(c->qid) == Qns && c->aux != 0) free(c->aux); } -long +static long procread(Chan *c, void *va, long n, ulong offset) { long l; @@ -510,12 +486,6 @@ procread(Chan *c, void *va, long n, ulong offset) return 0; /* not reached */ } -Block* -procbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - void mntscan(Mntwalk *mw) { @@ -554,7 +524,7 @@ mntscan(Mntwalk *mw) runlock(&pg->ns); } -long +static long procwrite(Chan *c, void *va, long n, ulong offset) { int id; @@ -648,13 +618,25 @@ procwrite(Chan *c, void *va, long n, ulong offset) return n; } -long -procbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} +Dev procdevtab = { + devreset, + procinit, + procattach, + devclone, + procwalk, + procstat, + procopen, + devcreate, + procclose, + procread, + devbread, + procwrite, + devbwrite, + devremove, + procwstat, +}; -Chan * +Chan* proctext(Chan *c, Proc *p) { Chan *tc; @@ -686,7 +668,7 @@ proctext(Chan *c, Proc *p) error(Eprocdied); if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) { - close(tc); + cclose(tc); error(Eprocdied); } @@ -740,7 +722,7 @@ procctlfgrp(Fgrp *f) if(c != 0) { f->fd[i] = 0; unlock(f); - close(c); + cclose(c); lock(f); } } diff --git a/port/devroot.c b/port/devroot.c index 8a37800dda0fbf9f202a08707ef8ac7d9b2ac440..0b289ee0a69bb77c4877f65416483cdff0c5d4c2 100644 --- a/port/devroot.c +++ b/port/devroot.c @@ -72,30 +72,19 @@ addrootfile(char *name, uchar *contents, ulong len) nroot++; } -void +static void rootreset(void) { addrootfile("boot", bootcode, bootlen); /* always have a boot file */ } -void -rootinit(void) -{ -} - -Chan* +static Chan* rootattach(char *spec) { return devattach('/', spec); } -Chan* -rootclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int rootwalk(Chan *c, char *name) { if(strcmp(name, "..") == 0) { @@ -107,13 +96,13 @@ rootwalk(Chan *c, char *name) return devwalk(c, name, rootdir, nroot, devgen); } -void +static void rootstat(Chan *c, char *dp) { devstat(c, dp, rootdir, nroot, devgen); } -Chan* +static Chan* rootopen(Chan *c, int omode) { switch(c->qid.path & ~CHDIR) { @@ -131,16 +120,10 @@ rootopen(Chan *c, int omode) return devopen(c, omode, rootdir, nroot, devgen); } -void -rootcreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - /* * sysremove() knows this is a nop */ -void +static void rootclose(Chan *c) { switch(c->qid.path) { @@ -153,13 +136,13 @@ rootclose(Chan *c) } } -int +static int rdrdy(void*) { return reclist.q != 0; } -long +static long rootread(Chan *c, void *buf, long n, ulong offset) { ulong t; @@ -209,13 +192,7 @@ rootread(Chan *c, void *buf, long n, ulong offset) return n; } -Block* -rootbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long +static long rootwrite(Chan *c, void *buf, long n, ulong) { char tmp[256]; @@ -235,23 +212,23 @@ rootwrite(Chan *c, void *buf, long n, ulong) return 0; } -long -rootbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -rootremove(Chan*) -{ - error(Eperm); -} - -void -rootwstat(Chan*, char*) -{ - error(Eperm); -} +Dev rootdevtab = { + rootreset, + devinit, + rootattach, + devclone, + rootwalk, + rootstat, + rootopen, + devcreate, + rootclose, + rootread, + devbread, + rootwrite, + devbwrite, + devremove, + devwstat, +}; void rootrecover(Path *p, char *mntname) diff --git a/port/devsd.c b/port/devsd.c index 0bbd4adf743e4cc0aa5a165856f1fce9f7c5b718..bf484ea1df7bd829f038f8af75c65e0ca9a8a3ad 100644 --- a/port/devsd.c +++ b/port/devsd.c @@ -94,12 +94,7 @@ sdgen(Chan *c, Dirtab*, int, int s, Dir *dirp) return 1; } -void -sdreset(void) -{ -} - -void +static void sdinit(void) { Disk *d; @@ -142,7 +137,7 @@ sdinit(void) * the get capacity until the drive is attached. */ if(scsicap(d->t, d->lun, &d->size, &d->bsize) != STok) { - nbytes = sizeof(scratch); + nbytes = 0xFF; memset(scratch, 0, nbytes); scsireqsense(d->t, 0, scratch, &nbytes, 1); if((scratch[2] & 0x0F) != 0x02 && (scratch[2] & 0x0F) != 0) @@ -183,7 +178,7 @@ sdinit(void) scsifree(scratch); } -Chan* +static Chan* sdattach(char *spec) { int i; @@ -198,49 +193,25 @@ sdattach(char *spec) return devattach('w', spec); } -Chan * -sdclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int sdwalk(Chan *c, char *name) { return devwalk(c, name, 0, 0, sdgen); } -void +static void sdstat(Chan *c, char *db) { devstat(c, db, 0, 0, sdgen); } -Chan * +static Chan* sdopen(Chan *c, int omode) { return devopen(c, omode, 0, 0, sdgen); } -void -sdcreate(Chan*, char*, int, ulong) -{ - error(Eperm); -} - -void -sdremove(Chan*) -{ - error(Eperm); -} - -void -sdwstat(Chan*, char*) -{ - error(Eperm); -} - -void +static void sdclose(Chan *c) { Disk *d; @@ -259,7 +230,7 @@ sdclose(Chan *c) } } -long +static long sdread(Chan *c, void *a, long n, ulong offset) { if(c->qid.path & CHDIR) @@ -268,13 +239,7 @@ sdread(Chan *c, void *a, long n, ulong offset) return sdio(c, 0, a, n, offset); } -Block* -sdbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long +static long sdwrite(Chan *c, char *a, long n, ulong offset) { Disk *d; @@ -286,11 +251,23 @@ sdwrite(Chan *c, char *a, long n, ulong offset) return sdio(c, 1, a, n, offset); } -long -sdbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} +Dev sddevtab = { + devreset, + sdinit, + sdattach, + devclone, + sdwalk, + sdstat, + sdopen, + devcreate, + sdclose, + sdread, + devbread, + sdwrite, + devbwrite, + devremove, + devwstat, +}; static int sdrdpart(Disk *d) @@ -343,10 +320,10 @@ sdrdpart(Disk *d) /* * parse partition table. */ - n = parsefields(b, line, Npart+2, "\n"); + n = parsefields(b, line, nelem(line), "\n"); if(n > 0 && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0) { for(i = 1; i < n; i++) { - if(parsefields(line[i], field, 3, " ") != 3) + if(parsefields(line[i], field, nelem(field), " ") != 3) break; if(p >= &d->table[Npart]) break; diff --git a/port/devsrv.c b/port/devsrv.c index d3d4bb9581910162a42664b7cdc1c8df684c1dd4..c2c8230799a109f46fe524eb42faf6d507ef2f87 100644 --- a/port/devsrv.c +++ b/port/devsrv.c @@ -21,7 +21,7 @@ static QLock srvlk; static Srv *srv; static int qidpath; -int +static int srvgen(Chan *c, Dirtab*, int, int s, Dir *dp) { Srv *sp; @@ -39,42 +39,31 @@ srvgen(Chan *c, Dirtab*, int, int s, Dir *dp) return 1; } -void +static void srvinit(void) { qidpath = 1; } -void -srvreset(void) -{ -} - -Chan* +static Chan* srvattach(char *spec) { return devattach('s', spec); } -Chan* -srvclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int srvwalk(Chan *c, char *name) { return devwalk(c, name, 0, 0, srvgen); } -void +static void srvstat(Chan *c, char *db) { devstat(c, db, 0, 0, srvgen); } -Chan* +static Chan* srvopen(Chan *c, int omode) { Srv *sp; @@ -105,14 +94,14 @@ srvopen(Chan *c, int omode) if(omode!=sp->chan->mode && sp->chan->mode!=ORDWR) error(Eperm); - close(c); + cclose(c); incref(sp->chan); qunlock(&srvlk); poperror(); return sp->chan; } -void +static void srvcreate(Chan *c, char *name, int omode, ulong perm) { Srv *sp; @@ -144,7 +133,7 @@ srvcreate(Chan *c, char *name, int omode, ulong perm) c->mode = OWRITE; } -void +static void srvremove(Chan *c) { Srv *sp, **l; @@ -175,11 +164,11 @@ srvremove(Chan *c) poperror(); if(sp->chan) - close(sp->chan); + cclose(sp->chan); free(sp); } -void +static void srvwstat(Chan *c, char *dp) { Dir d; @@ -209,25 +198,19 @@ srvwstat(Chan *c, char *dp) poperror(); } -void +static void srvclose(Chan*) { } -long +static long srvread(Chan *c, void *va, long n, ulong) { isdir(c); return devdirread(c, va, n, 0, 0, srvgen); } -Block* -srvbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long +static long srvwrite(Chan *c, void *va, long n, ulong) { Srv *sp; @@ -246,7 +229,7 @@ srvwrite(Chan *c, void *va, long n, ulong) qlock(&srvlk); if(waserror()) { qunlock(&srvlk); - close(c1); + cclose(c1); nexterror(); } for(sp = srv; sp; sp = sp->link) @@ -265,11 +248,23 @@ srvwrite(Chan *c, void *va, long n, ulong) return n; } -long -srvbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} +Dev srvdevtab = { + devreset, + srvinit, + srvattach, + devclone, + srvwalk, + srvstat, + srvopen, + srvcreate, + srvclose, + srvread, + devbread, + srvwrite, + devbwrite, + srvremove, + srvwstat, +}; void srvrecover(Chan *old, Chan *new) @@ -282,7 +277,7 @@ srvrecover(Chan *old, Chan *new) sp->chan = new; incref(new); qunlock(&srvlk); - close(old); + cclose(old); return; } } diff --git a/port/devssl.c b/port/devssl.c index 1d36c697fe951b7432b7aa9ae647274712143e44..f670861b562f8c67481762e9f41b612e9bfbd56f 100644 --- a/port/devssl.c +++ b/port/devssl.c @@ -108,12 +108,7 @@ static void sslhangup(Dstate*); static Dstate* dsclone(Chan *c); static void dsnew(Chan *c, Dstate **); -void -sslreset(void) -{ -} - -int +static int sslgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp) { Qid q; @@ -173,14 +168,14 @@ sslgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp) return -1; } -void +static void sslinit(void) { if((dstate = malloc(sizeof(Dstate*) * maxdstate)) == 0) panic("sslinit"); } -Chan * +static Chan* sslattach(void *spec) { Chan *c; @@ -191,25 +186,19 @@ sslattach(void *spec) return c; } -Chan * -sslclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int +static int sslwalk(Chan *c, char *name) { return devwalk(c, name, 0, 0, sslgen); } -void +static void sslstat(Chan *c, char *db) { devstat(c, db, 0, 0, sslgen); } -Chan * +static Chan* sslopen(Chan *c, int omode) { Dstate *s, **pp; @@ -273,24 +262,7 @@ sslopen(Chan *c, int omode) return c; } -void -sslcreate(Chan *c, char *name, int omode, ulong perm) -{ - USED(c); - USED(name); - USED(omode); - USED(perm); - error(Eperm); -} - -void -sslremove(Chan *c) -{ - USED(c); - error(Eperm); -} - -void +static void sslwstat(Chan *c, char *dp) { Dir d; @@ -308,7 +280,7 @@ sslwstat(Chan *c, char *dp) s->perm = d.mode; } -void +static void sslclose(Chan *c) { Dstate *s; @@ -335,7 +307,7 @@ sslclose(Chan *c) sslhangup(s); if(s->c) - close(s->c); + cclose(s->c); if(s->in.secret) free(s->in.secret); if(s->out.secret) @@ -349,16 +321,6 @@ sslclose(Chan *c) } } -static int -blen(Block *bp) -{ - int i = 0; - - for(; bp; bp = bp->next) - i += BLEN(bp); - return i; -} - /* * make sure we have at least 'n' bytes in list 'l' */ @@ -377,7 +339,7 @@ ensure(Dstate *s, Block **l, int n) } while(sofar < n){ - bl = (*devtab[s->c->type].bread)(s->c, Maxdmsg, 0); + bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0); if(bl == 0) error(Ehungup); *l = bl; @@ -419,20 +381,6 @@ consume(Block **l, uchar *p, int n) } } -/* - * free a list of blocks - */ -void -freeblist(Block *b) -{ - Block *next; - - for(; b != 0; b = next){ - next = b->next; - freeb(b); - } -} - /* * remove at most n bytes from the queue, if discard is set * dump the remainder @@ -481,7 +429,7 @@ qremove(Block **l, int n, int discard) return first; } -Block* +static Block* sslbread(Chan *c, long n, ulong offset) { volatile struct { Dstate *s; } s; @@ -560,7 +508,7 @@ sslbread(Chan *c, long n, ulong offset) return b; } -long +static long sslread(Chan *c, void *a, long n, ulong offset) { volatile struct { Block *b; } b; @@ -627,7 +575,7 @@ randfill(uchar *buf, int len) /* * use SSL record format, add in count and digest or encrypt */ -long +static long sslbwrite(Chan *c, Block *b, ulong offset) { volatile struct { Dstate *s; } s; @@ -718,7 +666,7 @@ sslbwrite(Chan *c, Block *b, ulong offset) } m = BLEN(nb); - (*devtab[s.s->c->type].bwrite)(s.s->c, nb, s.s->c->offset); + devtab[s.s->c->type]->bwrite(s.s->c, nb, s.s->c->offset); s.s->c->offset += m; } qunlock(&s.s->out.q); @@ -776,7 +724,7 @@ initRC4key(OneWay *w) setupRC4state(w->state, w->secret, w->slen); } -long +static long sslwrite(Chan *c, void *a, long n, ulong offset) { volatile struct { Dstate *s; } s; @@ -930,6 +878,23 @@ out: return n; } +Dev ssldevtab = { + devreset, + sslinit, + sslattach, + devclone, + sslwalk, + sslstat, + sslopen, + devcreate, + sslclose, + sslread, + sslbread, + sslwrite, + sslbwrite, + devremove, + sslwstat, +}; static Block* encryptb(Dstate *s, Block *b, int offset) @@ -1039,8 +1004,8 @@ digestb(Dstate *s, Block *b, int offset) n = BLEN(b) - h; /* hash secret + message */ - (*s->hf)(w->secret, w->slen, 0, &ss); - (*s->hf)(b->rp + h, n, 0, &ss); + s->hf(w->secret, w->slen, 0, &ss); + s->hf(b->rp + h, n, 0, &ss); /* hash message id */ p = msgid; @@ -1049,7 +1014,7 @@ digestb(Dstate *s, Block *b, int offset) *p++ = n>>16; *p++ = n>>8; *p = n; - (*s->hf)(msgid, 4, b->rp + offset, &ss); + s->hf(msgid, 4, b->rp + offset, &ss); return b; } @@ -1070,7 +1035,7 @@ checkdigestb(Dstate *s, Block *inb) memset(&ss, 0, sizeof(ss)); /* hash secret */ - (*s->hf)(w->secret, w->slen, 0, &ss); + s->hf(w->secret, w->slen, 0, &ss); /* hash message */ h = s->diglen; @@ -1078,7 +1043,7 @@ checkdigestb(Dstate *s, Block *inb) n = BLEN(b) - h; if(n < 0) panic("checkdigestb"); - (*s->hf)(b->rp + h, n, 0, &ss); + s->hf(b->rp + h, n, 0, &ss); h = 0; } @@ -1089,7 +1054,7 @@ checkdigestb(Dstate *s, Block *inb) *p++ = n>>16; *p++ = n>>8; *p = n; - (*s->hf)(msgid, 4, digest, &ss); + s->hf(msgid, 4, digest, &ss); if(memcmp(digest, inb->rp, s->diglen) != 0) error("bad digest"); diff --git a/port/devtinyfs.c b/port/devtinyfs.c index 97d6e030de243390291d3fbfda68ad0fd99a1f23..c8d568347dee978f549548ef2e9b6e7800a30bec 100644 --- a/port/devtinyfs.c +++ b/port/devtinyfs.c @@ -190,7 +190,7 @@ readdata(Tfs *fs, ulong bno, uchar *buf, int *lenp) { if(bno >= fs->nblocks) return 0; - if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno) != Blen) + if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen) error(Eio); return validdata(fs, buf, lenp); } @@ -217,7 +217,7 @@ writedata(Tfs *fs, ulong bno, ulong next, uchar *buf, int len, int last) memmove(md.data, buf, len); md.sum = 0 - checksum((uchar*)&md); - if(devtab[fs->c->type].write(fs->c, &md, Blen, Blen*bno) != Blen) + if(devtab[fs->c->type]->write(fs->c, &md, Blen, Blen*bno) != Blen) error(Eio); } @@ -238,7 +238,7 @@ writedir(Tfs *fs, Tfile *f) PUTS(md->pin, f->pin); md->sum = 0 - checksum(buf); - if(devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno) != Blen) + if(devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno) != Blen) error(Eio); } @@ -253,7 +253,7 @@ freeblocks(Tfs *fs, ulong bno, ulong bend) while(bno != bend && bno != Notabno){ mapclr(fs, bno); - if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno) != Blen) + if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno) != Blen) break; md = validdata(fs, buf, 0); if(md == 0) @@ -276,10 +276,10 @@ freefile(Tfs *fs, Tfile *f, ulong bend) /* change file type to free on medium */ if(f->bno != Notabno){ - if(devtab[fs->c->type].read(fs->c, buf, Blen, Blen*f->bno) != Blen) + if(devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*f->bno) != Blen) return; buf[0] = Tagfree; - devtab[fs->c->type].write(fs->c, buf, Blen, Blen*f->bno); + devtab[fs->c->type]->write(fs->c, buf, Blen, Blen*f->bno); mapclr(fs, f->bno); } @@ -364,7 +364,7 @@ fsinit(Tfs *fs) Mdir *mdir; Mdata *mdata; - devtab[fs->c->type].stat(fs->c, dbuf); + devtab[fs->c->type]->stat(fs->c, dbuf); convM2D(dbuf, &d); fs->nblocks = d.length/Blen; if(fs->nblocks < 3) @@ -379,7 +379,7 @@ fsinit(Tfs *fs) /* find files */ for(bno = 0; bno < fs->nblocks; bno++){ - n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); + n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno); if(n != Blen) break; @@ -408,7 +408,7 @@ fsinit(Tfs *fs) freefile(fs, f, bno); break; } - n = devtab[fs->c->type].read(fs->c, buf, Blen, Blen*bno); + n = devtab[fs->c->type]->read(fs->c, buf, Blen, Blen*bno); if(n != Blen){ freefile(fs, f, bno); break; @@ -459,19 +459,14 @@ tinyfsgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) return 1; } -void +static void tinyfsreset(void) { if(Nlen > NAMELEN) panic("tinyfsreset"); } -void -tinyfsinit(void) -{ -} - -Chan * +static Chan* tinyfsattach(char *spec) { Tfs *fs; @@ -493,7 +488,7 @@ tinyfsattach(char *spec) cc = namec(p, Aopen, ORDWR, 0); if(waserror()){ - close(cc); + cclose(cc); nexterror(); } @@ -508,7 +503,7 @@ tinyfsattach(char *spec) if(i < Maxfs){ fs->r++; qunlock(&fs->ql); - close(cc); + cclose(cc); } else { for(fs = tinyfs.fs; fs < &tinyfs.fs[Maxfs]; fs++){ qlock(&fs->ql); @@ -536,7 +531,7 @@ tinyfsattach(char *spec) return c; } -Chan * +static Chan* tinyfsclone(Chan *c, Chan *nc) { Tfs *fs; @@ -550,7 +545,7 @@ tinyfsclone(Chan *c, Chan *nc) return devclone(c, nc); } -int +static int tinyfswalk(Chan *c, char *name) { int n; @@ -568,13 +563,13 @@ tinyfswalk(Chan *c, char *name) return n; } -void +static void tinyfsstat(Chan *c, char *db) { devstat(c, db, 0, 0, tinyfsgen); } -Chan * +static Chan* tinyfsopen(Chan *c, int omode) { Tfs *fs; @@ -610,7 +605,7 @@ tinyfsopen(Chan *c, int omode) return devopen(c, omode, 0, 0, tinyfsgen); } -void +static void tinyfscreate(Chan *c, char *name, int omode, ulong perm) { Tfs *fs; @@ -634,7 +629,7 @@ tinyfscreate(Chan *c, char *name, int omode, ulong perm) c->mode = openmode(omode); } -void +static void tinyfsremove(Chan *c) { Tfs *fs; @@ -649,14 +644,7 @@ tinyfsremove(Chan *c) qunlock(&fs->ql); } -void -tinyfswstat(Chan *c, char *dp) -{ - USED(c, dp); - error(Eperm); -} - -void +static void tinyfsclose(Chan *c) { Tfs *fs; @@ -706,13 +694,13 @@ tinyfsclose(Chan *c) if(fs->map) free(fs->map); fs->map = 0; - close(fs->c); + cclose(fs->c); fs->c = 0; } qunlock(&fs->ql); } -long +static long tinyfsread(Chan *c, void *a, long n, ulong offset) { Tfs *fs; @@ -780,17 +768,11 @@ tinyfsread(Chan *c, void *a, long n, ulong offset) return sofar; } -Block* -tinyfsbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - /* * if we get a write error in this routine, blocks will * be lost. They should be recovered next fsinit. */ -long +static long tinyfswrite(Chan *c, void *a, long n, ulong offset) { Tfs *fs; @@ -889,8 +871,20 @@ tinyfswrite(Chan *c, void *a, long n, ulong offset) return n; } -long -tinyfsbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} +Dev tinyfsdevtab = { + tinyfsreset, + devinit, + tinyfsattach, + tinyfsclone, + tinyfswalk, + tinyfsstat, + tinyfsopen, + tinyfscreate, + tinyfsclose, + tinyfsread, + devbread, + tinyfswrite, + devbwrite, + tinyfsremove, + devwstat, +}; diff --git a/port/fault.c b/port/fault.c index 8adc26683c3744c17ab132f9a7a55d1975160e93..f91f6383e43926cee2d7f3a0b761c9bc84ff2f95 100644 --- a/port/fault.c +++ b/port/fault.c @@ -5,8 +5,6 @@ #include "fns.h" #include "../port/error.h" -void faulterror(char*); - int fault(ulong addr, int read) { @@ -39,6 +37,16 @@ fault(ulong addr, int read) return 0; } +static void +faulterror(char *s) +{ + if(up->nerrlab) { + postnote(up, 1, s, NDebug); + error(s); + } + pexit(s, 0); +} + int fixfault(Segment *s, ulong addr, int read, int doputmmu) { @@ -211,7 +219,7 @@ pio(Segment *s, ulong addr, ulong soff, Page **p) if(ask > BY2PG) ask = BY2PG; - n = (*devtab[c->type].read)(c, kaddr, ask, daddr); + n = devtab[c->type]->read(c, kaddr, ask, daddr); if(n != ask) error(Eioload); if(ask < BY2PG) @@ -239,7 +247,7 @@ pio(Segment *s, ulong addr, ulong soff, Page **p) faulterror("sys: page in I/O error"); } - n = (*devtab[c->type].read)(c, kaddr, BY2PG, daddr); + n = devtab[c->type]->read(c, kaddr, BY2PG, daddr); if(n != BY2PG) error(Eioload); @@ -261,16 +269,6 @@ pio(Segment *s, ulong addr, ulong soff, Page **p) memset((*p)->cachectl, PG_TXTFLUSH, sizeof((*p)->cachectl)); } -void -faulterror(char *s) -{ - if(up->nerrlab) { - postnote(up, 1, s, NDebug); - error(s); - } - pexit(s, 0); -} - /* * Called only in a system call */ diff --git a/port/netif.c b/port/netif.c index 3609126bbd2c32b19726dbb9d271beea65baa71c..22fb1292fed431706404353aaa03b7e88640dc92 100644 --- a/port/netif.c +++ b/port/netif.c @@ -6,8 +6,6 @@ #include "../port/error.h" #include "../port/netif.h" -uchar etherbcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - static int netown(Netfile*, char*, int); static int openfile(Netif*, int); static char* matchtoken(char*, char*); @@ -18,7 +16,8 @@ static char* matchtoken(char*, char*); void netifinit(Netif *nif, char *name, int nfile, ulong limit) { - nif->name = name; + strncpy(nif->name, name, NAMELEN-1); + nif->name[NAMELEN-1] = 0; nif->nfile = nfile; nif->f = xalloc(nfile*sizeof(Netfile*)); memset(nif->f, 0, nfile*sizeof(Netfile*)); @@ -197,6 +196,15 @@ netifread(Netif *nif, Chan *c, void *a, long n, ulong offset) return -1; /* not reached */ } +Block* +netifbread(Netif *nif, Chan *c, long n, ulong offset) +{ + if((c->qid.path & CHDIR) || NETTYPE(c->qid.path) != Ndataqid) + return devbread(c, n, offset); + + return qbread(nif->f[NETID(c->qid.path)]->in, n); +} + /* * the devxxx.c that calls us handles writing data, it knows best */ @@ -224,8 +232,8 @@ netifwrite(Netif *nif, Chan *c, void *a, long n) } else if(matchtoken(buf, "promiscuous")){ f->prom = 1; nif->prom++; - if(nif->prom == 1) - (*nif->promiscuous)(nif->arg, 1); + if(nif->prom == 1 && nif->promiscuous != nil) + nif->promiscuous(nif->arg, 1); } qunlock(nif); return n; @@ -273,8 +281,8 @@ netifclose(Netif *nif, Chan *c) if(--(f->inuse) == 0){ if(f->prom){ qlock(nif); - if(--(nif->prom) == 0) - (*nif->promiscuous)(nif->arg, 0); + if(--(nif->prom) == 0 && nif->promiscuous != nil) + nif->promiscuous(nif->arg, 0); qunlock(nif); f->prom = 0; } @@ -423,6 +431,7 @@ ulong nhgetl(void *p) { uchar *a; + a = p; return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0); } @@ -431,6 +440,7 @@ ushort nhgets(void *p) { uchar *a; + a = p; return (a[0]<<8)|(a[1]<<0); } diff --git a/port/netif.h b/port/netif.h index 637b167b94b910df087bb31cae9319e3c07c9341..4344cc934a764a37285556c267be4099e61cfd66 100644 --- a/port/netif.h +++ b/port/netif.h @@ -34,10 +34,10 @@ struct Netfile ulong mode; char owner[NAMELEN]; - int type; /* multiplexor type */ - int prom; /* promiscuous mode */ + int type; /* multiplexor type */ + int prom; /* promiscuous mode */ - Queue *in; /* input buffer */ + Queue *in; /* input buffer */ }; /* @@ -48,7 +48,7 @@ struct Netif QLock; /* multiplexing */ - char *name; /* for top level directory */ + char name[NAMELEN]; /* for top level directory */ int nfile; /* max number of Netfiles */ Netfile **f; @@ -81,6 +81,7 @@ int netifwalk(Netif*, Chan*, char*); Chan* netifopen(Netif*, Chan*, int); void netifclose(Netif*, Chan*); long netifread(Netif*, Chan*, void*, long, ulong); +Block* netifbread(Netif*, Chan*, long, ulong); long netifwrite(Netif*, Chan*, void*, long); void netifwstat(Netif*, Chan*, char*); void netifstat(Netif*, Chan*, char*); @@ -103,5 +104,3 @@ struct Etherpkt uchar type[2]; uchar data[1500]; }; - -extern uchar etherbcast[6]; diff --git a/port/pgrp.c b/port/pgrp.c index dddb2bb38585c9aecad890b09106a6667f260d66..1ef04ea817d5ab6dbc8cfaea88a1c6f11a997ca2 100644 --- a/port/pgrp.c +++ b/port/pgrp.c @@ -79,7 +79,7 @@ closepgrp(Pgrp *p) e = &p->mnthash[MNTHASH]; for(h = p->mnthash; h < e; h++) { for(f = *h; f; f = next) { - close(f->from); + cclose(f->from); mountfree(f->mount); next = f->hash; free(f); @@ -190,7 +190,7 @@ closefgrp(Fgrp *f) if(decref(f) == 0) { for(i = 0; i <= f->maxfd; i++) if(c = f->fd[i]) - close(c); + cclose(c); free(f); } @@ -220,7 +220,7 @@ mountfree(Mount *m) while(m) { f = m->next; - close(m->to); + cclose(m->to); m->mountid = 0; free(m); m = f; diff --git a/port/portdat.h b/port/portdat.h index 7c1eb0c3ddec98c593094234c310b801beb64925..94d4dbacfceeb30667d05ae48c488109fcc17311 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -241,7 +241,6 @@ struct Mnt Mntrpc *recwait; /* List of rpc's with recovery pending */ ulong id; /* Multiplexor id for channel check */ Mnt *list; /* Free list */ - char mux; /* Set if the device does the multiplexing */ int flags; /* recover/cache */ char recprog; /* Recovery in progress */ int blocksize; /* read/write block size */ @@ -621,16 +620,13 @@ enum extern Conf conf; extern char* conffile; extern int cpuserver; -extern int cpuserver; extern Rune* devchar; -extern Dev devtab[]; +extern Dev* devtab[]; extern char eve[]; extern char hostdomain[]; -extern int hwcurs; extern uchar initcode[]; extern FPsave initfp; -extern Queue *kbdq; -extern Queue *mouseq; +extern Queue* kbdq; extern Ref noteidalloc; extern int nrdy; extern Palloc palloc; @@ -690,19 +686,6 @@ enum SCSImaxxfer = 2048*1024, }; -/* - * mouse types - */ -enum -{ - Mouseother= 0, - Mouseserial= 1, - MousePS2= 2, -}; -extern int mouseshifted; -extern int mousetype; -extern int mouseswap; - enum { LRESPROF = 3, @@ -710,6 +693,3 @@ enum extern int nsyscall; extern Physseg physseg[]; -extern ulong crasharea; -extern ulong crashend; -extern ulong randomcount; diff --git a/port/portfns.h b/port/portfns.h index 1f0cdea78da3de35deff6500e59e4120305a04e3..9ecdd727025a6dfaad12ffba1c70765da934eea5 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -14,7 +14,7 @@ void authreply(Session*, ulong, Fcall*); ulong authrequest(Session*, Fcall*); long authwrite(Chan*, char*, int); Page* auxpage(void); -void buzz(int, int); +int blocklen(Block*); void cachedel(Image*, ulong); void cachepage(Page*, Image*); int cangetc(void*); @@ -28,38 +28,47 @@ void chanfree(Chan*); void chanrec(Mnt*); void checkalarms(void); void cinit(void); -Chan* clone(Chan*, Chan*); -void close(Chan*); +Chan* cclone(Chan*, Chan*); +void cclose(Chan*); void closeegrp(Egrp*); void closefgrp(Fgrp*); void closemount(Mount*); void closepgrp(Pgrp*); void closergrp(Rgrp*); long clrfpintr(void); +int cmount(Chan*, Chan*, int, char*); void confinit(void); void confinit1(int); int consactive(void); -void consdebug(void); +void (*consdebug)(void); void copen(Chan*); +Block* concatblock(Block*); +Block* copyblock(Block*, int); void copypage(Page*, Page*); int cread(Chan*, uchar*, int, ulong); +void cunmount(Chan*, Chan*); void cupdate(Chan*, uchar*, int, ulong); void cwrite(Chan*, uchar*, int, ulong); ulong dbgpc(Proc*); int decref(Ref*); int decrypt(void*, void*, int); void delay(int); +void devreset(void); +void devinit(void); Chan* devattach(int, char*); Block* devbread(Chan*, long, ulong); long devbwrite(Chan*, Block*, ulong); Chan* devclone(Chan*, Chan*); +void devcreate(Chan*, char*, int, ulong); void devdir(Chan*, Qid, char*, long, char*, long, Dir*); long devdirread(Chan*, char*, long, Dirtab*, int, Devgen*); Devgen devgen; int devno(int, int); Chan* devopen(Chan*, int, Dirtab*, int, Devgen*); +void devremove(Chan*); void devstat(Chan*, char*, Dirtab*, int, Devgen*); int devwalk(Chan*, char*, Dirtab*, int, Devgen*); +void devwstat(Chan*, char*); Chan* domount(Chan*); void dumpaproc(Proc*); void dumpqueues(void); @@ -85,6 +94,7 @@ void forkchild(Proc*, Ureg*); void forkret(void); void free(void*); void freeb(Block*); +void freeblist(Block*); int freebroken(void); void freechan(Chan*); void freepte(Segment*, Pte*); @@ -107,6 +117,7 @@ void initscsi(void); void initseg(void); void isdir(Chan*); int iseve(void); +int islo(void); int ispages(void*); void ixsummary(void); void kbdclock(void); @@ -120,15 +131,13 @@ void killbig(void); int kprint(char*, ...); void kproc(char*, void(*)(void*), void*); void kprocchild(Proc*, void (*)(void*), void*); -void kproftimer(ulong); +void (*kproftimer)(ulong); void ksetenv(char*, char*); long latin1(uchar*, int); -void lights(int); void links(void); void lock(Lock*); void lockinit(void); Page* lookpage(Image*, ulong); -int m3mouseputc(void*, int); void machinit(void); void* mallocz(ulong, int); void* malloc(ulong); @@ -140,17 +149,11 @@ void mntdump(void); long mntread9p(Chan*, void*, long, ulong); void mntrepl(char*); long mntwrite9p(Chan*, void*, long, ulong); -int mount(Chan*, Chan*, int, char*); void mountfree(Mount*); -void mouseaccelerate(char*); -void mousebuttons(int); -void mouseclock(void); -void mousectl(char*); -int mouseputc(void*, int); -void mousetrack(int, int, int); int msize(void*); Chan* namec(char*, int, int, ulong); void nameok(char*); +#define nelem(x) (sizeof(x)/sizeof(x[0])) Chan* newchan(void); Mount* newmount(Mhead*, Chan*, int, char*); Page* newpage(int, Segment **, ulong); @@ -166,13 +169,13 @@ int openmode(ulong); Block* padblock(Block*, int); void pageinit(void); void panic(char*, ...); +int parseether(uchar*, char*); int parsefields(char*, char**, int, char*); void pexit(char*, int); void pgrpcpy(Pgrp*, Pgrp*); void pgrpnote(ulong, char*, long, int); Pgrp* pgrptab(int); void pio(Segment *, ulong, ulong, Page **); -void pixreverse(uchar*, int, int); #define poperror() up->nerrlab-- int postnote(Proc*, int, char*, int); int pprint(char*, ...); @@ -190,6 +193,7 @@ Pte* ptealloc(void); Pte* ptecpy(Pte*); Path* ptenter(Pthash*, Path*, char*); int ptpath(Path*, char*, int); +int pullblock(Block**, int); Block* pullupblock(Block*, int); void putimage(Image*); void putmmu(ulong, ulong, Page*); @@ -205,9 +209,14 @@ long qbwrite(Queue*, Block*); int qcanread(Queue*); void qclose(Queue*); int qconsume(Queue*, void*, int); +Block* qcopy(Queue*, int, ulong); +void qdiscard(Queue*, int); void qflush(Queue*); -void qhangup(Queue*); +int qfull(Queue*); +Block* qget(Queue*); +void qhangup(Queue*, char*); void qinit(void); +int qiwrite(Queue*, void*, int); int qlen(Queue*); void qlock(QLock*); Queue* qopen(int, int, void (*)(void*), void*); @@ -217,8 +226,7 @@ long qread(Queue*, void*, int); void qreopen(Queue*); void qunlock(QLock*); int qwindow(Queue*); -long qiwrite(Queue*, void*, int); -long qwrite(Queue*, void*, int); +int qwrite(Queue*, void*, int); void qsetlimit(Queue*, int); void qnoblock(Queue*, int); void randomclock(void); @@ -234,6 +242,7 @@ int return0(void*); void rlock(RWlock*); void rootrecover(Path*, char*); void rootreq(Chan*, Mnt*); +long rtctime(void); void runlock(RWlock*); Proc* runproc(void); void savefpregs(FPsave*); @@ -273,12 +282,12 @@ int spllo(void); void splx(int); void srvrecover(Chan*, Chan*); void swapinit(void); +Block* trimblock(Block*, int, int); void tsleep(Rendez*, int (*)(void*), void*, int); void unbreak(Proc*); void uncachepage(Page*); long unionread(Chan*, void*, long); void unlock(Lock*); -void unmount(Chan*, Chan*); Chan* undomount(Chan*); void userinit(void); ulong userpc(void); @@ -297,10 +306,6 @@ void xhole(ulong, ulong); void xinit(void); void* xspanalloc(ulong, int, ulong); void xsummary(void); -void z8530config(int, int, int, int, int); -void z8530setup(uchar*, uchar*, uchar*, uchar*, ulong, int); -void z8530special(int, int, Queue**, Queue**, int (*)(Queue*, int)); -void z8530intr(int); Segment* data2txt(Segment*); Segment* dupseg(Segment**, int, int); Segment* newseg(int, ulong, ulong); @@ -309,4 +314,3 @@ void hnputl(void*, ulong); void hnputs(void*, ushort); ulong nhgetl(void*); ushort nhgets(void*); -void filsetalloc(void* (*)(int), void* (*)(int)); diff --git a/port/proc.c b/port/proc.c index 3acc99cf703af1d69e8de303205435230ec776b4..8e7f78b42ba654d63d4dfdb767c4a4a03aa7715f 100644 --- a/port/proc.c +++ b/port/proc.c @@ -11,21 +11,21 @@ Ref noteidalloc; struct { Lock; - Proc *arena; - Proc *free; + Proc* arena; + Proc* free; }procalloc; struct { Lock; - Waitq *free; + Waitq* free; }waitqalloc; typedef struct { Lock; - Proc *head; - Proc *tail; + Proc* head; + Proc* tail; int n; } Schedq; @@ -365,6 +365,8 @@ procinit0(void) /* bad planning - clashes with devproc.c */ int i; procalloc.free = xalloc(conf.nproc*sizeof(Proc)); + if(procalloc.free == nil) + panic("cannot allocate %d procs\n", conf.nproc); procalloc.arena = procalloc.free; p = procalloc.free; @@ -435,7 +437,7 @@ sleep(Rendez *r, int (*f)(void*), void *arg) int tfn(void *arg) { - return MACHP(0)->ticks >= up->twhen || (*up->tfn)(arg); + return MACHP(0)->ticks >= up->twhen || up->tfn(arg); } void @@ -649,7 +651,7 @@ pexit(char *exitstr, int freemem) if(up->rgrp) closergrp(up->rgrp); - close(up->dot); + cclose(up->dot); closepgrp(up->pgrp); /* @@ -985,6 +987,7 @@ exhausted(char *resource) char buf[ERRLEN]; sprint(buf, "no free %s", resource); + iprint("%s\n", buf); error(buf); } diff --git a/port/qio.c b/port/qio.c index b9560d9fccf755e9c466ea6d9787717be0034531..a54992f3918bc3a2cc4eecccf9f23375f849c066 100644 --- a/port/qio.c +++ b/port/qio.c @@ -11,9 +11,17 @@ struct ulong bytes; } ialloc; +static ulong padblockcnt; +static ulong concatblockcnt; +static ulong pullupblockcnt; +static ulong copyblockcnt; +static ulong consumecnt; +static ulong producecnt; +static ulong qcopycnt; + static int debuging; -#define QDEBUG if(0) +#define QDEBUG if(0) /* * IO queues @@ -41,11 +49,13 @@ struct Queue Rendez rr; /* process waiting to read */ QLock wlock; /* mutex for writing processes */ Rendez wr; /* process waiting to write */ + + char err[ERRLEN]; }; enum { - /* Queue.state */ + /* Queue.state */ Qstarve = (1<<0), /* consumer starved */ Qmsg = (1<<1), /* message stream */ Qclosed = (1<<2), @@ -55,6 +65,11 @@ enum void checkb(Block *b, char *msg) { + void *dead = (void*)0xDEADBABE; + + if(b == dead) + panic("checkb b %s %lux", msg, b); + if(b->base > b->lim) panic("checkb 0 %s %lux %lux", msg, b->base, b->lim); if(b->rp < b->base) @@ -65,6 +80,14 @@ checkb(Block *b, char *msg) panic("checkb 3 %s %lux %lux", msg, b->rp, b->lim); if(b->wp > b->lim) panic("checkb 4 %s %lux %lux", msg, b->wp, b->lim); + + if(b->base == dead || b->lim == dead || b->next == dead + || b->rp == dead || b->wp == dead){ + print("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n", + b->base, b->lim, b->next); + print("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp); + panic("checkb dead: %s\n", msg); + } } /* @@ -107,7 +130,7 @@ void freeb(Block *b) { /* - * drivers which perform non cache coherent DMA manage their own buffer + * drivers which perform non cache coherent DMA manage their own buffer * pool of uncached buffers and provide their own free routine. */ if(b->free) { @@ -130,11 +153,264 @@ freeb(Block *b) free(b); } +/* + * free a list of blocks + */ +void +freeblist(Block *b) +{ + Block *next; + + for(; b != 0; b = next){ + next = b->next; + b->next = 0; + freeb(b); + } +} + +/* + * pad a block to the front (or the back if size is negative) + */ +Block* +padblock(Block *bp, int size) +{ + int n; + Block *nbp; + + if(size >= 0){ + if(bp->rp - bp->base >= size){ + bp->rp -= size; + return bp; + } + + n = BLEN(bp); + padblockcnt += n; + nbp = allocb(size+n); + nbp->rp += size; + nbp->wp = nbp->rp; + memmove(nbp->wp, bp->rp, n); + nbp->wp += n; + freeb(bp); + nbp->rp -= size; + } else { + size = -size; + + if(bp->lim - bp->wp >= size) + return bp; + + n = BLEN(bp); + padblockcnt += n; + nbp = allocb(size+n); + memmove(nbp->wp, bp->rp, n); + nbp->wp += n; + freeb(bp); + } + return nbp; +} + +/* + * return count of bytes in a string of blocks + */ +int +blocklen(Block *bp) +{ + int len; + + len = 0; + while(bp) { + len += BLEN(bp); + bp = bp->next; + } + return len; +} + +/* + * copy the string of blocks into + * a single block and free the string + */ +Block* +concatblock(Block *bp) +{ + int len; + Block *nb, *f; + + if(bp->next == 0) + return bp; + + nb = allocb(blocklen(bp)); + for(f = bp; f; f = f->next) { + len = BLEN(f); + memmove(nb->wp, f->rp, len); + nb->wp += len; + } + concatblockcnt += BLEN(nb); + freeblist(bp); + return nb; +} + +/* + * make sure the first block has at least n bytes + */ +Block* +pullupblock(Block *bp, int n) +{ + int i; + Block *nbp; + + /* + * this should almost always be true, it's + * just to avoid every caller checking. + */ + if(BLEN(bp) >= n) + return bp; + + /* + * if not enough room in the first block, + * add another to the front of the list. + */ + if(bp->lim - bp->rp < n){ + nbp = allocb(n); + nbp->next = bp; + bp = nbp; + } + + /* + * copy bytes from the trailing blocks into the first + */ + n -= BLEN(bp); + while(nbp = bp->next){ + i = BLEN(nbp); + if(i > n) { + memmove(bp->wp, nbp->rp, n); + pullupblockcnt += n; + bp->wp += n; + nbp->rp += n; + return bp; + } + else { + memmove(bp->wp, nbp->rp, i); + pullupblockcnt += i; + bp->wp += i; + bp->next = nbp->next; + nbp->next = 0; + freeb(nbp); + n -= i; + if(n == 0) + return bp; + } + } + freeb(bp); + return 0; +} + +/* + * trim to len bytes starting at offset + */ +Block * +trimblock(Block *bp, int offset, int len) +{ + ulong l; + Block *nb, *startb; + + if(blocklen(bp) < offset+len) { + freeblist(bp); + return nil; + } + + while((l = BLEN(bp)) < offset) { + offset -= l; + nb = bp->next; + bp->next = nil; + freeb(bp); + bp = nb; + } + + startb = bp; + bp->rp += offset; + + while((l = BLEN(bp)) < len) { + len -= l; + bp = bp->next; + } + + bp->wp -= (BLEN(bp) - len); + + if(bp->next) { + freeblist(bp->next); + bp->next = nil; + } + + return startb; +} + +/* + * copy 'count' bytes into a new block + */ +Block* +copyblock(Block *bp, int count) +{ + int l; + Block *nbp; + + nbp = allocb(count); + for(; count > 0 && bp != 0; bp = bp->next){ + l = BLEN(bp); + if(l > count) + l = count; + memmove(nbp->wp, bp->rp, l); + nbp->wp += l; + count -= l; + } + if(count > 0){ + memset(nbp->wp, 0, count); + nbp->wp += count; + } + copyblockcnt += count; + + return nbp; +} + +/* + * throw away up to count bytes from a + * list of blocks. Return count of bytes + * thrown away. + */ +int +pullblock(Block **bph, int count) +{ + Block *bp; + int n, bytes; + + bytes = 0; + if(bph == nil) + return 0; + + while(*bph != nil && count != 0) { + bp = *bph; + n = BLEN(bp); + if(count < n) + n = count; + bytes += n; + count -= n; + bp->rp += n; + if(BLEN(bp) == 0) { + *bph = bp->next; + bp->next = nil; + freeb(bp); + } + } + return bytes; +} + void ixsummary(void) { debuging ^= 1; print("ialloc %d/%d %d\n", ialloc.bytes, conf.ialloc, debuging); + print("pad %lud, concat %lud, pullup %lud, copy %lud\n", + padblockcnt, concatblockcnt, pullupblockcnt, copyblockcnt); + print("consume %lud, produce %lud, qcopy %lud\n", + consumecnt, producecnt, qcopycnt); } /* @@ -167,46 +443,80 @@ allocb(int size) return b; } -ulong padblockoverhead; - /* - * pad a block to the front (or the back if size is negative) + * get next block from a queue, return null if nothing there */ Block* -padblock(Block *bp, int size) +qget(Queue *q) { - int n; - Block *nbp; + int dowakeup; + Block *b; - if(size >= 0){ - if(bp->rp - bp->base >= size){ - bp->rp -= size; - return bp; - } + /* sync with qwrite */ + ilock(q); - n = bp->wp - bp->rp; - padblockoverhead += n; - nbp = allocb(size+n); - nbp->rp += size; - nbp->wp = nbp->rp; - memmove(nbp->wp, bp->rp, n); - nbp->wp += n; - freeb(bp); - nbp->rp -= size; - } else { - size = -size; + b = q->bfirst; + if(b == 0){ + q->state |= Qstarve; + iunlock(q); + return 0; + } + q->bfirst = b->next; + b->next = 0; + q->len -= BLEN(b); - if(bp->lim - bp->wp >= size) - return bp; + /* if writer flow controlled, restart */ + if((q->state & Qflow) && q->len < q->limit/2){ + q->state &= ~Qflow; + dowakeup = 1; + } else + dowakeup = 0; - n = bp->wp - bp->rp; - padblockoverhead += n; - nbp = allocb(size+n); - memmove(nbp->wp, bp->rp, n); - nbp->wp += n; - freeb(bp); + iunlock(q); + + if(dowakeup) + wakeup(&q->wr); + + return b; +} + +/* + * throw away the next 'len' bytes in the queue + */ +void +qdiscard(Queue *q, int len) +{ + Block *b; + int dowakeup, n, sofar; + + lock(q); + for(sofar = 0; sofar < len; sofar += n){ + b = q->bfirst; + if(b == nil) + break; + n = BLEN(b); + if(n <= len - sofar){ + q->bfirst = b->next; + b->next = 0; + freeb(b); + } else { + n = len - sofar; + b->rp += n; + } + q->len -= n; } - return nbp; + + /* if writer flow controlled, restart */ + if((q->state & Qflow) && q->len < q->limit/2){ + q->state &= ~Qflow; + dowakeup = 1; + } else + dowakeup = 0; + + unlock(q); + + if(dowakeup) + wakeup(&q->wr); } /* @@ -241,6 +551,7 @@ qconsume(Queue *q, void *vp, int len) if(n < len) len = n; memmove(p, b->rp, len); + consumecnt += n; if((q->state & Qmsg) || len == n) q->bfirst = b->next; b->rp += len; @@ -260,8 +571,10 @@ qconsume(Queue *q, void *vp, int len) QDEBUG checkb(b, "qconsume 2"); /* discard the block if we're done with it */ - if((q->state & Qmsg) || len == n) + if((q->state & Qmsg) || len == n){ + b->next = 0; freeb(b); + } return len; } @@ -270,19 +583,24 @@ qpass(Queue *q, Block *b) { int len, dowakeup; - len = BLEN(b); /* sync with qread */ dowakeup = 0; ilock(q); - /* save in buffer */ + /* add buffer to queue */ if(q->bfirst) q->blast->next = b; else q->bfirst = b; + len = BLEN(b); + QDEBUG checkb(b, "qpass"); + while(b->next){ + b = b->next; + QDEBUG checkb(b, "qpass"); + len += BLEN(b); + } q->blast = b; q->len += len; - QDEBUG checkb(b, "qpass"); if(q->len >= q->limit/2) q->state |= Qflow; @@ -324,12 +642,14 @@ qproduce(Queue *q, void *vp, int len) return 0; } memmove(b->wp, p, len); + producecnt += len; b->wp += len; if(q->bfirst) q->blast->next = b; else q->bfirst = b; q->blast = b; + /* b->next = 0; done by iallocb() */ q->len += len; QDEBUG checkb(b, "qproduce"); @@ -345,6 +665,56 @@ qproduce(Queue *q, void *vp, int len) return len; } +/* + * copy from offset in the queue + */ +Block* +qcopy(Queue *q, int len, ulong offset) +{ + int sofar; + int n; + Block *b, *nb; + uchar *p; + + nb = allocb(len); + + lock(q); + + /* go to offset */ + b = q->bfirst; + for(sofar = 0; ; sofar += n){ + if(b == nil){ + unlock(q); + return nb; + } + n = BLEN(b); + if(sofar + n > offset){ + p = b->rp + offset - sofar; + n -= offset - sofar; + break; + } + b = b->next; + } + + /* copy bytes from there */ + for(sofar = 0; sofar < len;){ + if(n > len - sofar) + n = len - sofar; + memmove(nb->wp, p, n); + qcopycnt += n; + sofar += n; + nb->wp += n; + b = b->next; + if(b == nil) + break; + n = BLEN(b); + p = b->rp; + } + unlock(q); + + return nb; +} + /* * called by non-interrupt code */ @@ -396,15 +766,17 @@ qbread(Queue *q, int len) ilock(q); b = q->bfirst; - if(b) + if(b){ + QDEBUG checkb(b, "qbread 0"); break; + } if(q->state & Qclosed){ iunlock(q); poperror(); qunlock(&q->rlock); if(++q->eof > 3) - error(Ehungup); + error(q->err); return 0; } @@ -415,8 +787,10 @@ qbread(Queue *q, int len) /* remove a buffered block */ q->bfirst = b->next; + b->next = 0; n = BLEN(b); q->len -= n; + QDEBUG checkb(b, "qbread 1"); /* if writer flow controlled, restart */ if((q->state & Qflow) && q->len < q->limit/2){ @@ -451,7 +825,7 @@ qbread(Queue *q, int len) /* wakeup flow controlled writers */ if(dowakeup){ if(q->kick) - (*q->kick)(q->arg); + q->kick(q->arg); wakeup(&q->wr); } @@ -521,7 +895,7 @@ qbwrite(Queue *q, Block *b) if(q->state & Qclosed){ iunlock(q); freeb(b); - error(Ehungup); + error(q->err); } if(q->bfirst) @@ -529,6 +903,7 @@ qbwrite(Queue *q, Block *b) else q->bfirst = b; q->blast = b; + b->next = 0; q->len += n; if(q->state & Qstarve){ @@ -540,7 +915,7 @@ qbwrite(Queue *q, Block *b) if(dowakeup){ if(q->kick) - (*q->kick)(q->arg); + q->kick(q->arg); wakeup(&q->rr); } @@ -552,14 +927,14 @@ qbwrite(Queue *q, Block *b) /* * write to a queue. only 128k at a time is atomic. */ -long +int qwrite(Queue *q, void *vp, int len) { int n, sofar; Block *b; uchar *p = vp; - QDEBUG if((getstatus()&IE) == 0) + QDEBUG if(islo() == 0) print("qwrite hi %lux\n", getcallerpc(q)); sofar = 0; @@ -589,7 +964,7 @@ qwrite(Queue *q, void *vp, int len) * used by print() to write to a queue. Since we may be splhi or not in * a process, don't qlock. */ -long +int qiwrite(Queue *q, void *vp, int len) { int n, sofar, dowakeup; @@ -627,7 +1002,7 @@ qiwrite(Queue *q, void *vp, int len) if(dowakeup){ if(q->kick) - (*q->kick)(q->arg); + q->kick(q->arg); wakeup(&q->rr); } @@ -637,6 +1012,17 @@ qiwrite(Queue *q, void *vp, int len) return len; } +/* + * be extremely careful when calling this, + * as there is no reference accounting + */ +void +qfree(Queue *q) +{ + qclose(q); + free(q); +} + /* * Mark a queue as closed. No further IO is permitted. * All blocks are released. @@ -644,11 +1030,15 @@ qiwrite(Queue *q, void *vp, int len) void qclose(Queue *q) { - Block *b, *bfirst; + Block *bfirst; + + if(q == nil) + return; /* mark it */ ilock(q); q->state |= Qclosed; + strcpy(q->err, Ehungup); bfirst = q->bfirst; q->bfirst = 0; q->len = 0; @@ -656,11 +1046,7 @@ qclose(Queue *q) iunlock(q); /* free queued blocks */ - while(bfirst){ - b = bfirst->next; - freeb(bfirst); - bfirst = b; - } + freeblist(bfirst); /* wake up readers/writers */ wakeup(&q->rr); @@ -672,11 +1058,15 @@ qclose(Queue *q) * blocks. */ void -qhangup(Queue *q) +qhangup(Queue *q, char *msg) { /* mark it */ ilock(q); q->state |= Qclosed; + if(msg == 0 || *msg == 0) + strcpy(q->err, Ehungup); + else + strncpy(q->err, msg, ERRLEN-1); iunlock(q); /* wake up readers/writers */ @@ -752,7 +1142,7 @@ qnoblock(Queue *q, int onoff) void qflush(Queue *q) { - Block *b, *bfirst; + Block *bfirst; /* mark it */ ilock(q); @@ -762,71 +1152,20 @@ qflush(Queue *q) iunlock(q); /* free queued blocks */ - while(bfirst){ - b = bfirst->next; - freeb(bfirst); - bfirst = b; - } + freeblist(bfirst); /* wake up readers/writers */ wakeup(&q->wr); } int -qstate(Queue *q) +qfull(Queue *q) { - return q->state; + return q->state & Qflow; } -/* - * make sure the first block has at least n bytes - */ -Block* -pullupblock(Block *bp, int n) +int +qstate(Queue *q) { - int i; - Block *nbp; - - /* - * this should almost always be true, the rest it - * just to avoid every caller checking. - */ - if(BLEN(bp) >= n) - return bp; - - /* - * if not enough room in the first block, - * add another to the front of the list. - */ - if(bp->lim - bp->rp < n){ - nbp = allocb(n); - nbp->next = bp; - bp = nbp; - } - - /* - * copy bytes from the trailing blocks into the first - */ - n -= BLEN(bp); - while(nbp = bp->next){ - i = BLEN(nbp); - if(i > n) { - memmove(bp->wp, nbp->rp, n); - bp->wp += n; - nbp->rp += n; - return bp; - } - else { - memmove(bp->wp, nbp->rp, i); - bp->wp += i; - bp->next = nbp->next; - nbp->next = 0; - freeb(nbp); - n -= i; - if(n == 0) - return bp; - } - } - freeb(bp); - return 0; + return q->state; } diff --git a/port/segment.c b/port/segment.c index a1a6ee0a923e1cf391e366ce980a56f5f3f67df2..073232fe1cf24a51a94cfcc98996de51418dad0a 100644 --- a/port/segment.c +++ b/port/segment.c @@ -316,7 +316,7 @@ imagechanreclaim(void) imagealloc.nfreechan--; c = imagealloc.freechan[imagealloc.nfreechan]; unlock(&imagealloc); - close(c); + cclose(c); } qunlock(&imagealloc.fcreclaim); diff --git a/port/swap.c b/port/swap.c index 3708278a63304280759194d59bc1c1b9f0f2eb6e..807b9dd7d9ea0babdb6737f9ea1bc3cd03469fa9 100644 --- a/port/swap.c +++ b/port/swap.c @@ -303,7 +303,7 @@ executeio(void) if(waserror()) panic("executeio: page out I/O error"); - n = (*devtab[c->type].write)(c, kaddr, BY2PG, out->daddr); + n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr); if(n != BY2PG) nexterror(); @@ -331,7 +331,7 @@ setswapchan(Chan *c) if(swapimage.c) { if(swapalloc.free != conf.nswap) error(Einuse); - close(swapimage.c); + cclose(swapimage.c); } incref(c); swapimage.c = c; diff --git a/port/sysfile.c b/port/sysfile.c index 2e8bf5ddafdae329b07a7448793c0e6a669ccfa7..0ffdffeaa9f59dcda1bd94715cc0c8a2fd4944ac 100644 --- a/port/sysfile.c +++ b/port/sysfile.c @@ -12,8 +12,8 @@ int newfd(Chan *c) { - Fgrp *f = up->fgrp; int i; + Fgrp *f = up->fgrp; lock(f); for(i=0; iflag&CMSG)) { if(iref) - close(c); + cclose(c); error(Ebadusefd); } @@ -58,13 +58,13 @@ fdtochan(int fd, int mode, int chkmnt, int iref) if((mode&OTRUNC) && c->mode==OREAD) { if(iref) - close(c); + cclose(c); error(Ebadusefd); } if((mode&~OTRUNC) != c->mode) { if(iref) - close(c); + cclose(c); error(Ebadusefd); } @@ -114,26 +114,26 @@ syspipe(ulong *arg) validaddr(arg[0], 2*BY2WD, 1); evenaddr(arg[0]); - d = &devtab[devno('|', 0)]; + d = devtab[devno('|', 0)]; c[0] = namec("#|", Atodir, 0, 0); c[1] = 0; fd[0] = -1; fd[1] = -1; if(waserror()){ - close(c[0]); + cclose(c[0]); if(c[1]) - close(c[1]); + cclose(c[1]); if(fd[0] >= 0) f->fd[fd[0]]=0; if(fd[1] >= 0) f->fd[fd[1]]=0; nexterror(); } - c[1] = clone(c[0], 0); + c[1] = cclone(c[0], 0); walk(c[0], "data", 1); walk(c[1], "data1", 1); - c[0] = (*d->open)(c[0], ORDWR); - c[1] = (*d->open)(c[1], ORDWR); + c[0] = d->open(c[0], ORDWR); + c[1] = d->open(c[1], ORDWR); fd[0] = newfd(c[0]); fd[1] = newfd(c[1]); ((long*)arg[0])[0] = fd[0]; @@ -156,7 +156,7 @@ sysdup(ulong *arg) fd = arg[1]; if(fd != -1){ if(fd<0 || NFD<=fd) { - close(c); + cclose(c); error(Ebadfd); } lock(f); @@ -167,10 +167,10 @@ sysdup(ulong *arg) f->fd[fd] = c; unlock(f); if(oc) - close(oc); + cclose(oc); }else{ if(waserror()) { - close(c); + cclose(c); nexterror(); } fd = newfd(c); @@ -189,7 +189,7 @@ sysopen(ulong *arg) openmode(arg[1]); /* error check only */ if(waserror()){ if(c) - close(c); + cclose(c); nexterror(); } validaddr(arg[0], 1, 0); @@ -225,7 +225,7 @@ fdclose(int fd, int flag) f->maxfd = i; unlock(f); - close(c); + cclose(c); } long @@ -252,30 +252,30 @@ unionread(Chan *c, void *va, long n) runlock(&pg->ns); nexterror(); } - nc = clone(c->mnt->to, 0); + nc = cclone(c->mnt->to, 0); poperror(); if(c->mountid != c->mnt->mountid) { pprint("unionread: changed underfoot?\n"); runlock(&pg->ns); - close(nc); + cclose(nc); return 0; } /* Error causes component of union to be skipped */ if(waserror()) { - close(nc); + cclose(nc); goto next; } - nc = (*devtab[nc->type].open)(nc, OREAD); + nc = devtab[nc->type]->open(nc, OREAD); nc->offset = c->offset; - nr = (*devtab[nc->type].read)(nc, va, n, nc->offset); + nr = devtab[nc->type]->read(nc, va, n, nc->offset); /* devdirread e.g. changes it */ c->offset = nc->offset; poperror(); - close(nc); + cclose(nc); if(nr > 0) { runlock(&pg->ns); return nr; @@ -302,7 +302,7 @@ sysread9p(ulong *arg) validaddr(arg[1], arg[2], 1); c = fdtochan(arg[0], OREAD, 1, 1); if(waserror()) { - close(c); + cclose(c); nexterror(); } @@ -318,7 +318,7 @@ sysread9p(ulong *arg) if(dir && c->mnt) n = unionread(c, (void*)arg[1], n); else if(devchar[c->type] != L'M') - n = (*devtab[c->type].read)(c, (void*)arg[1], n, c->offset); + n = devtab[c->type]->read(c, (void*)arg[1], n, c->offset); else n = mntread9p(c, (void*)arg[1], n, c->offset); @@ -327,7 +327,7 @@ sysread9p(ulong *arg) unlock(c); poperror(); - close(c); + cclose(c); return n; } @@ -342,7 +342,7 @@ sysread(ulong *arg) validaddr(arg[1], arg[2], 1); c = fdtochan(arg[0], OREAD, 1, 1); if(waserror()) { - close(c); + cclose(c); nexterror(); } @@ -358,14 +358,14 @@ sysread(ulong *arg) if(dir && c->mnt) n = unionread(c, (void*)arg[1], n); else - n = (*devtab[c->type].read)(c, (void*)arg[1], n, c->offset); + n = devtab[c->type]->read(c, (void*)arg[1], n, c->offset); lock(c); c->offset += n; unlock(c); poperror(); - close(c); + cclose(c); return n; } @@ -379,7 +379,7 @@ syswrite9p(ulong *arg) validaddr(arg[1], arg[2], 0); c = fdtochan(arg[0], OWRITE, 1, 1); if(waserror()) { - close(c); + cclose(c); nexterror(); } @@ -387,7 +387,7 @@ syswrite9p(ulong *arg) error(Eisdir); if(devchar[c->type] != L'M') - n = (*devtab[c->type].write)(c, (void*)arg[1], arg[2], c->offset); + n = devtab[c->type]->write(c, (void*)arg[1], arg[2], c->offset); else n = mntwrite9p(c, (void*)arg[1], arg[2], c->offset); lock(c); @@ -395,7 +395,7 @@ syswrite9p(ulong *arg) unlock(c); poperror(); - close(c); + cclose(c); return n; } @@ -409,21 +409,21 @@ syswrite(ulong *arg) validaddr(arg[1], arg[2], 0); c = fdtochan(arg[0], OWRITE, 1, 1); if(waserror()) { - close(c); + cclose(c); nexterror(); } if(c->qid.path & CHDIR) error(Eisdir); - n = (*devtab[c->type].write)(c, (void*)arg[1], arg[2], c->offset); + n = devtab[c->type]->write(c, (void*)arg[1], arg[2], c->offset); lock(c); c->offset += n; unlock(c); poperror(); - close(c); + cclose(c); return n; } @@ -457,7 +457,7 @@ sysseek(ulong *arg) break; case 2: - (*devtab[c->type].stat)(c, buf); + devtab[c->type]->stat(c, buf); convM2D(buf, &dir); c->offset = dir.length + (long)arg[1]; off = c->offset; @@ -475,12 +475,12 @@ sysfstat(ulong *arg) evenaddr(arg[1]); c = fdtochan(arg[0], -1, 0, 1); if(waserror()) { - close(c); + cclose(c); nexterror(); } - (*devtab[c->type].stat)(c, (char*)arg[1]); + devtab[c->type]->stat(c, (char*)arg[1]); poperror(); - close(c); + cclose(c); return 0; } @@ -494,12 +494,12 @@ sysstat(ulong *arg) validaddr(arg[0], 1, 0); c = namec((char*)arg[0], Aaccess, 0, 0); if(waserror()){ - close(c); + cclose(c); nexterror(); } - (*devtab[c->type].stat)(c, (char*)arg[1]); + devtab[c->type]->stat(c, (char*)arg[1]); poperror(); - close(c); + cclose(c); return 0; } @@ -511,7 +511,7 @@ syschdir(ulong *arg) validaddr(arg[0], 1, 0); c = namec((char*)arg[0], Atodir, 0, 0); - close(up->dot); + cclose(up->dot); up->dot = c; return 0; } @@ -538,7 +538,7 @@ bindmount(ulong *arg, int ismount) if(ismount){ bc = fdtochan(fd, ORDWR, 0, 1); if(waserror()) { - close(bc); + cclose(bc); nexterror(); } bogus.chan = bc; @@ -552,10 +552,10 @@ bindmount(ulong *arg, int ismount) error(Ebadspec); ret = devno('M', 0); - c0 = (*devtab[ret].attach)((char*)&bogus); + c0 = devtab[ret]->attach((char*)&bogus); poperror(); - close(bc); + cclose(bc); } else { bogus.spec = 0; @@ -564,23 +564,23 @@ bindmount(ulong *arg, int ismount) } if(waserror()){ - close(c0); + cclose(c0); nexterror(); } validaddr(arg[1], 1, 0); c1 = namec((char*)arg[1], Amount, 0, 0); if(waserror()){ - close(c1); + cclose(c1); nexterror(); } - ret = mount(c0, c1, flag, bogus.spec); + ret = cmount(c0, c1, flag, bogus.spec); poperror(); - close(c1); + cclose(c1); poperror(); - close(c0); + cclose(c0); if(ismount) fdclose(fd, 0); return ret; @@ -610,7 +610,7 @@ sysunmount(ulong *arg) if(arg[0]) { if(waserror()) { - close(cmount); + cclose(cmount); nexterror(); } validaddr(arg[0], 1, 0); @@ -619,15 +619,16 @@ sysunmount(ulong *arg) } if(waserror()) { - close(cmount); + cclose(cmount); if(cmounted) - close(cmounted); + cclose(cmounted); nexterror(); } - unmount(cmount, cmounted); - close(cmount); + + cunmount(cmount, cmounted); + cclose(cmount); if(cmounted) - close(cmounted); + cclose(cmounted); poperror(); return 0; } @@ -641,7 +642,7 @@ syscreate(ulong *arg) openmode(arg[1]); /* error check only */ if(waserror()) { if(c) - close(c); + cclose(c); nexterror(); } validaddr(arg[0], 1, 0); @@ -660,17 +661,17 @@ sysremove(ulong *arg) c = namec((char*)arg[0], Aaccess, 0, 0); if(waserror()){ c->type = 0; /* see below */ - close(c); + cclose(c); nexterror(); } - (*devtab[c->type].remove)(c); + devtab[c->type]->remove(c); /* * Remove clunks the fid, but we need to recover the Chan * so fake it up. rootclose() is known to be a nop. */ c->type = 0; poperror(); - close(c); + cclose(c); return 0; } @@ -684,12 +685,12 @@ syswstat(ulong *arg) validaddr(arg[0], 1, 0); c = namec((char*)arg[0], Aaccess, 0, 0); if(waserror()){ - close(c); + cclose(c); nexterror(); } - (*devtab[c->type].wstat)(c, (char*)arg[1]); + devtab[c->type]->wstat(c, (char*)arg[1]); poperror(); - close(c); + cclose(c); return 0; } @@ -702,11 +703,11 @@ sysfwstat(ulong *arg) nameok((char*)arg[1]); c = fdtochan(arg[0], -1, 1, 1); if(waserror()) { - close(c); + cclose(c); nexterror(); } - (*devtab[c->type].wstat)(c, (char*)arg[1]); + devtab[c->type]->wstat(c, (char*)arg[1]); poperror(); - close(c); + cclose(c); return 0; } diff --git a/port/sysproc.c b/port/sysproc.c index d409ea54a3de0fb786019f909e8acc3f69752e27..811554a3db5aecc9817761c781c4b0932d483f3f 100644 --- a/port/sysproc.c +++ b/port/sysproc.c @@ -219,13 +219,13 @@ sysexec(ulong *arg) for(;;){ tc = namec(file, Aopen, OEXEC, 0); if(waserror()){ - close(tc); + cclose(tc); nexterror(); } if(!indir) strcpy(elem, up->elem); - n = (*devtab[tc->type].read)(tc, &exec, sizeof(Exec), 0); + n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0); if(n < 2) error(Ebadexec); magic = l2be(exec.magic); @@ -259,7 +259,7 @@ sysexec(ulong *arg) file = progarg[0]; progarg[0] = elem; poperror(); - close(tc); + cclose(tc); } data = l2be(exec.data); @@ -401,7 +401,7 @@ sysexec(ulong *arg) up->basepri = PriRoot; up->priority = up->basepri; poperror(); - close(tc); + cclose(tc); /* * At this point, the mmu contains info about the old address diff --git a/port/taslock.c b/port/taslock.c index 3277c2ffd9bc61afcab54ac36daedde205bd050b..31051540ded092f3aaa4ff22f2c5a5aacaffaec6 100644 --- a/port/taslock.c +++ b/port/taslock.c @@ -13,7 +13,7 @@ lockloop(Lock *l, ulong pc) dumpaproc(up); /* lower priority till we get the lock */ - if(up && up->state == Running && (getstatus()&IE)){ + if(up && up->state == Running && islo()){ up->lockpri = 1; sched(); } @@ -94,8 +94,8 @@ canlock(Lock *l) void unlock(Lock *l) { - l->key = 0; l->pc = 0; + l->key = 0; coherence(); } @@ -105,8 +105,8 @@ iunlock(Lock *l) ulong sr; sr = l->sr; - l->key = 0; l->pc = 0; + l->key = 0; splx(sr); coherence(); } diff --git a/power/clock.c b/power/clock.c deleted file mode 100644 index 4c865ca970782c07b1a0525d1f9c443db082d348..0000000000000000000000000000000000000000 --- a/power/clock.c +++ /dev/null @@ -1,112 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" - -#include "ureg.h" - -void -delay(int ms) -{ - int i; - - ms *= 7000; /* experimentally determined */ - for(i=0; ictl = CTR(2)|SET16|MODE2; - t->cnt2 = TIME2&0xFF; - t->cnt2 = (TIME2>>8)&0xFF; - t->ctl = CTR(1)|SET16|MODE2; - t->cnt1 = TIME1&0xFF; - t->cnt1 = (TIME1>>8)&0xFF; - t->ctl = CTR(0)|SET16|MODE2; - t->cnt0 = TIME0; - t->cnt0 = (TIME0>>8)&0xFF; - i = *CLRTIM0; - USED(i); - i = *CLRTIM1; - USED(i); - m->ticks = 0; -} - -void -clock(Ureg *ur) -{ - int i; - - if((ur->cause&INTR2) == 0) { - if(ur->cause & INTR4) { - i = *CLRTIM1; - USED(i); - } - return; - } - i = *CLRTIM0; - USED(i); - - m->ticks++; - if(m->proc) - m->proc->pc = ur->pc; - - accounttime(); - duartslave(); - if((active.machs&(1<machno)) == 0) - return; - - if(active.exiting && active.machs&(1<machno)) { - print("someone's exiting\n"); - exit(0); - } - - checkalarms(); - kproftimer(ur->pc); - - if(up == 0 || (ur->status&IEP) == 0 || up->state != Running) - return; - - if(anyready()) - sched(); - - /* user profiling clock */ - if(ur->status & KUP) - (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1); -} diff --git a/power/dat.h b/power/dat.h deleted file mode 100644 index 1f00ead903a08150e38a5d8012e9b49a58708cc5..0000000000000000000000000000000000000000 --- a/power/dat.h +++ /dev/null @@ -1,191 +0,0 @@ -typedef struct Conf Conf; -typedef struct Lancepkt Lancepkt; -typedef struct FPsave FPsave; -typedef struct Lance Lance; -typedef struct Lancemem Lancemem; -typedef struct Label Label; -typedef struct Lock Lock; -typedef struct Mach Mach; -typedef struct MMU MMU; -typedef struct Notsave Notsave; -typedef struct PMMU PMMU; -typedef struct Softtlb Softtlb; -typedef struct Ureg Ureg; -/* - * parameters for sysproc.c - */ -#define EXEC_MAGIC(magic) (magic==V_MAGIC) - -/* - * machine dependent definitions used by ../port/dat.h - */ - -struct Lock -{ - int val; - ulong pc; - ulong sr; - ulong pid; -}; - -struct Label -{ - ulong sp; - ulong pc; -}; - -struct Conf -{ - ulong nmach; /* processors */ - ulong nproc; /* processes */ - ulong npage0; /* total physical pages of memory */ - ulong npage1; /* total physical pages of memory */ - ulong npage; /* total physical pages of memory */ - ulong upages; /* user page pool */ - ulong nimage; /* number of page cache image headers */ - ulong nswap; /* number of swap pages */ - ulong base0; /* base of bank 0 */ - ulong base1; /* base of bank 1 */ - ulong copymode; /* 0 is copy on write, 1 is copy on reference */ - ulong ipif; /* Ip protocol interfaces */ - ulong ip; /* Ip conversations per interface */ - ulong arp; /* Arp table size */ - ulong frag; /* Ip fragment assemble queue size */ - ulong debugger; /* use processor 1 as a kernel debugger */ - ulong ialloc; /* bytes available for interrupt time allocation */ - ulong pipeqsize; /* size in bytes of pipe queues */ -}; - -/* - * floating point registers - */ -enum -{ - FPinit, - FPactive, - FPinactive, -}; - -struct FPsave -{ - long fpreg[32]; - long fpstatus; -}; - -/* - * mmu goo in the Proc structure - */ -struct PMMU -{ - int pidonmach[MAXMACH]; -}; - -/* - * things saved in the Proc structure during a notify - */ -struct Notsave -{ - int UNUSED; -}; - -#include "../port/portdat.h" - -/* First FOUR members offsets known by l.s */ -struct Mach -{ - int machno; /* physical id of processor */ - Softtlb *stb; /* Software tlb simulation */ - Proc *proc; /* current process on this processor */ - ulong splpc; /* pc that called splhi() */ - int tlbfault; /* this offset known in l.s/utlbmiss() */ - - /* Ok to change from here */ - ulong ticks; /* of the clock since boot time */ - Label sched; /* scheduler wakeup */ - Lock alarmlock; /* access to alarm list */ - void *alarm; /* alarms bound to this clock */ - int lastpid; /* last pid allocated on this machine */ - Proc *pidproc[NTLBPID]; /* process that owns this tlbpid on this mach */ - - int tlbpurge; - int pfault; - int cs; - int syscall; - int load; - int intr; - int ledval; /* value last written to LED */ - int otlbfault; - int nrdy; - - int stack[1]; -}; - -/* - * machine dependent definitions not used by ../port/dat.h - */ -struct Softtlb -{ - ulong virt; - ulong phys; -}; - -/* - * Fake kmap - */ -typedef void KMap; -#define VA(k) ((ulong)(k)) -#define kmap(p) (KMap*)((p)->pa|KZERO) -#define kunmap(k) -#define PPN(x) x -#define AOUT_MAGIC V_MAGIC || magic==M_MAGIC -/* - * LANCE CSR3 (bus control bits) - */ -#define BSWP 0x4 -#define ACON 0x2 -#define BCON 0x1 - -struct Lancepkt -{ - uchar d[6]; - uchar s[6]; - uchar type[2]; - uchar data[1500]; - uchar crc[4]; -}; - -/* - * system dependent lance stuff - * filled by lancesetup() - */ -struct Lance -{ - ushort lognrrb; /* log2 number of receive ring buffers */ - ushort logntrb; /* log2 number of xmit ring buffers */ - ushort nrrb; /* number of receive ring buffers */ - ushort ntrb; /* number of xmit ring buffers */ - ushort *rap; /* lance address register */ - ushort *rdp; /* lance data register */ - ushort busctl; /* bus control bits */ - uchar ea[6]; /* our ether addr */ - int sep; /* separation between shorts in lance ram - as seen by host */ - ushort *lanceram; /* start of lance ram as seen by host */ - Lancemem *lm; /* start of lance ram as seen by lance */ - Lancepkt *rp; /* receive buffers (host address) */ - Lancepkt *tp; /* transmit buffers (host address) */ - Lancepkt *lrp; /* receive buffers (lance address) */ - Lancepkt *ltp; /* transmit buffers (lance address) */ -}; - -struct -{ - Lock; - short machs; - short exiting; -}active; - -#define MACHP(n) ((Mach *)(MACHADDR+n*BY2PG)) - -extern register Mach *m; -extern register Proc *up; diff --git a/power/devduart.c b/power/devduart.c deleted file mode 100644 index bbd06133d651dda2156d239d9f8af4a2b8e01193..0000000000000000000000000000000000000000 --- a/power/devduart.c +++ /dev/null @@ -1,715 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "../port/error.h" - -#include "../port/netif.h" - -/* - * Register set for half the duart. - * There are really two sets in adjacent memory locations. - */ -struct Duartreg -{ - uchar mr12; /* Mode Register Channels 1 & 2 */ - uchar pad0[15]; - uchar srcsr; /* Status Register/Clock Select Register */ - uchar pad1[15]; - uchar cmnd; /* Command Register */ - uchar pad2[15]; - uchar data; /* RX Holding / TX Holding Register */ - uchar pad3[15]; - uchar ipcacr; /* Input Uart Change/Aux. Control Register */ - uchar pad4[15]; - uchar isimr; /* Interrupt Status/Interrupt Mask Register */ - uchar pad5[15]; - uchar ctur; /* Counter/Timer Upper Register */ - uchar pad6[15]; - uchar ctlr; /* Counter/Timer Lower Register */ - uchar pad7[15]; -}; -#define ppcr isimr /* in the second register set */ - -enum -{ - DBD75 = 0, - DBD110 = 1, - DBD38400 = 2, - DBD150 = 3, - DBD300 = 4, - DBD600 = 5, - DBD1200 = 6, - DBD2000 = 7, - DBD2400 = 8, - DBD4800 = 9, - DBD1800 = 10, - DBD9600 = 11, - DBD19200 = 12, - CHARERR = 0x00, /* MR1x - Mode Register 1 */ - EVENPAR = 0x00, - ODDPAR = 0x04, - NOPAR = 0x10, - CBITS8 = 0x03, - CBITS7 = 0x02, - CBITS6 = 0x01, - CBITS5 = 0x00, - NORMOP = 0x00, /* MR2x - Mode Register 2 */ - TWOSTOPB = 0x0F, - ONESTOPB = 0x07, - ENBRX = 0x01, /* CRx - Command Register */ - DISRX = 0x02, - ENBTX = 0x04, - DISTX = 0x08, - RESETMR = 0x10, - RESETRCV = 0x20, - RESETTRANS = 0x30, - RESETERR = 0x40, - RESETBCH = 0x50, - STRTBRK = 0x60, - STOPBRK = 0x70, - RCVRDY = 0x01, /* SRx - Channel Status Register */ - FIFOFULL = 0x02, - XMTRDY = 0x04, - XMTEMT = 0x08, - OVRERR = 0x10, - PARERR = 0x20, - FRMERR = 0x40, - RCVDBRK = 0x80, - IMIPC = 0x80, /* IMRx/ISRx - Int Mask/Interrupt Status */ - IMDBB = 0x40, - IMRRDYB = 0x20, - IMXRDYB = 0x10, - IMCRDY = 0x08, - IMDBA = 0x04, - IMRRDYA = 0x02, - IMXRDYA = 0x01, - BD38400 = 0xCC|0x0000, - BD19200 = 0xCC|0x0100, - BD9600 = 0xBB|0x0000, - BD4800 = 0x99|0x0000, - BD2400 = 0x88|0x0000, - BD1200 = 0x66|0x0000, - BD300 = 0x44|0x0000, - - Maxduart = 8, -}; - -/* - * requests to perform on a duart - */ -enum -{ - Dnone= 0, - Dbaud, - Dbreak, - Ddtr, - Dprint, - Dena, - Dstate, -}; - -/* - * a duart - */ -typedef struct Duart Duart; -struct Duart -{ - QLock; - Duartreg *reg; /* duart registers */ - uchar imr; /* sticky interrupt mask reg bits */ - uchar acr; /* sticky auxiliary reg bits */ - int inited; -}; -Duart duart[Maxduart]; - -/* - * values specific to a single duart port - */ -typedef struct Uart Uart; -struct Uart -{ - QLock; - Duart *d; /* device */ - Duartreg *reg; /* duart registers (for this port) */ - int c; /* character to restart output */ - int op; /* operation requested */ - int val; /* value of operation */ - Rendez opr; /* waiot here for op to complete */ - - int printing; /* need kick */ - int opens; - Rendez r; - - /* buffers */ - int (*putc)(Queue*, int); - Queue *iq; - Queue *oq; -}; -Uart uart[2*Maxduart]; - -void duartkick(Uart*); - -/* - * configure a duart port, default is 9600 baud, 8 bits/char, 1 stop bit, - * no parity - */ -void -duartsetup(Uart *p, Duart *d, int devno) -{ - Duartreg *reg; - - p->d = d; - reg = &d->reg[devno]; - p->reg = reg; - - reg->cmnd = RESETRCV|DISTX|DISRX; - reg->cmnd = RESETTRANS; - reg->cmnd = RESETERR; - reg->cmnd = STOPBRK; - - reg->cmnd = RESETMR; - reg->mr12 = NOPAR|CBITS8; - reg->mr12 = ONESTOPB; - reg->srcsr = (DBD9600<<4)|DBD9600; - reg->cmnd = ENBTX|ENBRX; - - p->iq = qopen(4*1024, 0, 0, 0); - p->oq = qopen(4*1024, 0, duartkick, p); -} - -/* - * init the duart on the current processor - */ -void -duartinit(void) -{ - Uart *p; - Duart *d; - - d = &duart[m->machno]; - if(d->inited) - return; - - d->reg = DUARTREG; - d->imr = IMRRDYA|IMXRDYA|IMRRDYB|IMXRDYB; - d->reg->isimr = d->imr; - d->acr = 0x80; /* baud rate set 2 */ - d->reg->ipcacr = d->acr; - - p = &uart[2*m->machno]; - - duartsetup(p, d, 0); - p++; - duartsetup(p, d, 1); - d->inited = 1; -} - -/* - * enable a duart port - */ -void -duartenable(Uart *p) -{ - p->reg->cmnd = ENBTX|ENBRX; -} - -void -duartenable0(void) -{ - DUARTREG->cmnd = ENBTX|ENBRX; -} - -void -duartbaud(Uart *p, int b) -{ - int x; - - switch(b){ - case 38400: - x = BD38400; - break; - case 19200: - x = BD19200; - break; - case 9600: - x = BD9600; - break; - case 4800: - x = BD4800; - break; - case 2400: - x = BD2400; - break; - case 1200: - x = BD1200; - break; - case 300: - x = BD300; - break; - default: - return; - } - if(x & 0x0100) - p->d->acr |= 0x80; - else - p->d->acr &= ~0x80; - p->d->reg->ipcacr = p->d->acr; - p->reg->srcsr = x; -} - -void -duartdtr(Uart *p, int val) -{ - if (val) - p->reg->ctlr = 0x01; - else - p->reg->ctur = 0x01; -} - -void -duartbreak(Uart *p, int val) -{ - Duartreg *reg; - - reg = p->reg; - if (val){ - p->d->imr &= ~IMXRDYB; - p->d->reg->isimr = p->d->imr; - reg->cmnd = STRTBRK|ENBTX; - } else { - reg->cmnd = STOPBRK|ENBTX; - p->d->imr |= IMXRDYB; - p->d->reg->isimr = p->d->imr; - } -} - -/* - * do anything requested for this CPU's duarts - */ -void -duartslave0(Uart *p) -{ - switch(p->op){ - case Ddtr: - duartdtr(p, p->val); - break; - case Dbaud: - duartbaud(p, p->val); - break; - case Dbreak: - duartbreak(p, p->val); - break; - case Dprint: - p->reg->cmnd = ENBTX; - p->reg->data = p->val; - break; - case Dena: - duartenable(p); - break; - case Dstate: - p->val = p->reg->ppcr; - break; - } - p->op = Dnone; - wakeup(&p->opr); -} -void -duartslave(void) -{ - Uart *p; - - p = &uart[2*m->machno]; - if(p->op != Dnone) - duartslave0(p); - p++; - if(p->op != Dnone) - duartslave0(p); -} - -void -duartrintr(Uart *p) -{ - char ch; - int status; - Duartreg *reg; - - reg = p->reg; - status = reg->srcsr; - ch = reg->data; - if(status & (FRMERR|OVRERR|PARERR)) - reg->cmnd = RESETERR; - - if(p->putc) - (*p->putc)(p->iq, ch); - else - qproduce(p->iq, &ch, 1); -} - -/* - * (re)start output - */ -void -duartkick(Uart *p) -{ - char ch; - int n, x; - - x = splhi(); - if(p->printing) { - splx(x); - return; - } - - n = qconsume(p->oq, &ch, 1); - if(n <= 0){ - splx(x); - return; - } - - p->printing = 1; - p->val = ch; - p->op = Dprint; - splx(x); -} - -void -duartxintr(Uart *p) -{ - char ch; - Duartreg *reg; - - reg = p->reg; - if(qconsume(p->oq, &ch, 1) <= 0) { - p->printing = 0; - reg->cmnd = DISTX; - } - else - reg->data = ch; -} - -void -duartintr(void) -{ - int cause; - Duartreg *reg; - Uart *p; - - p = &uart[2*m->machno]; - reg = p->reg; - cause = reg->isimr; - - if(cause & IMRRDYA) - duartrintr(p); - - if(cause & IMXRDYA) - duartxintr(p); - - if(cause & IMRRDYB) - duartrintr(p+1); - - if(cause & IMXRDYB) - duartxintr(p+1); -} - -/* - * processor 0 only - */ -int -duartrawputc(int c) -{ - int i; - Duartreg *reg; - - reg = DUARTREG; - if(c == '\n') { - duartrawputc('\r'); - delay(100); - } - reg->cmnd = ENBTX; - i = 0; - while((reg->srcsr&XMTRDY) == 0 && i++ < 100000) - ; - reg->data = c; - return c; -} - -int -iprint(char *fmt, ...) -{ - int n, i; - char buf[512]; - va_list arg; - - va_start(arg, fmt); - n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; - va_end(arg); - - for(i = 0; i < n; i++) - duartrawputc(buf[i]); - return n; -} - -void -duartspecial(int port, int s, Queue **in, Queue **out, int (*putc)(Queue*, int)) -{ - Uart *p; - - p = &uart[port]; - - duartenable(p); - if(s) - duartbaud(p, s); - - p->putc = putc; - if(in != 0) - *in = p->iq; - if(out != 0) - *out = p->oq; - - p->opens++; -} - -static int -opdone(void *x) -{ - Uart *p = x; - - return p->op == Dnone; -} - -Dirtab *duartdir; -int nuart; - -void -duartreset(void) -{ - int i; - Dirtab *dp; - - nuart = 2*conf.nmach; - duartdir = xalloc(2 * nuart * sizeof(Dirtab)); - dp = duartdir; - for(i = 0; i < nuart; i++){ - /* 2 directory entries per port */ - print(dp->name, "eia%d", i); - dp->qid.path = NETQID(i, Ndataqid); - dp->perm = 0666; - dp++; - - print(dp->name, "eia%dctl", i); - dp->qid.path = NETQID(i, Nctlqid); - dp->perm = 0666; - dp++; - } -} - -Chan* -duartattach(char *spec) -{ - return devattach('t', spec); -} - -Chan* -duartclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int -duartwalk(Chan *c, char *name) -{ - return devwalk(c, name, duartdir, 2*nuart, devgen); -} - -void -duartstat(Chan *c, char *dp) -{ - int i; - Uart *p; - Dir dir; - - i = NETID(c->qid.path); - switch(NETTYPE(c->qid.path)){ - case Ndataqid: - p = &uart[i]; - devdir(c, c->qid, duartdir[2*i].name, qlen(p->iq), eve, 0660, &dir); - convD2M(&dir, dp); - break; - default: - devstat(c, dp, duartdir, 2*nuart, devgen); - break; - } -} - -Chan* -duartopen(Chan *c, int omode) -{ - Uart *p; - - if(c->qid.path & CHDIR){ - if(omode != OREAD) - error(Ebadarg); - } - else { - p = &uart[NETID(c->qid.path)]; - qlock(p); - p->opens++; - if(p->opens == 1) { - /* enable the port */ - p->op = Dena; - sleep(&p->opr, opdone, p); - - qreopen(p->iq); - qreopen(p->oq); - } - qunlock(p); - } - - c->mode = omode&~OTRUNC; - c->flag |= COPEN; - c->offset = 0; - return c; -} - -void -duartcreate(Chan *c, char *name, int omode, ulong perm) -{ - USED(c, name, omode, perm); - error(Eperm); -} - -void -duartclose(Chan *c) -{ - Uart *p; - - if(c->qid.path & CHDIR) - return; - - p = &uart[NETID(c->qid.path)]; - qlock(p); - p->opens++; - if(p->opens == 0){ - qclose(p->iq); - qclose(p->oq); - } - qunlock(p); -} - -long -duartread(Chan *c, void *buf, long n, ulong offset) -{ - Uart *p; - - if(c->qid.path & CHDIR) - return devdirread(c, buf, n, duartdir, 2*nuart, devgen); - - p = &uart[NETID(c->qid.path)]; - switch(NETTYPE(c->qid.path)){ - case Ndataqid: - return qread(p->iq, buf, n); - case Nctlqid: - return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE); - } - - return 0; -} - -Block* -duartbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -static void -duartctl(Uart *p, char *cmd) -{ - int n, i; - - /* let output drain for a while */ - for(i = 0; i < 16 && qlen(p->oq); i++) - tsleep(&p->r, qlen, p->oq, 125); - - n = atoi(cmd+1); - switch(cmd[0]){ - case 'B': - case 'b': - if(strncmp(cmd+1, "reak", 4) == 0) - break; - p->val = n; - p->op = Dbaud; - sleep(&p->opr, opdone, p); - break; - case 'D': - case 'd': - p->val = n; - p->op = Ddtr; - sleep(&p->opr, opdone, p); - break; - case 'K': - case 'k': - p->val = 1; - p->op = Dbreak; - if(!waserror()){ - sleep(&p->opr, opdone, p); - tsleep(&p->opr, return0, 0, n); - poperror(); - } - p->val = 0; - p->op = Dbreak; - sleep(&p->opr, opdone, p); - break; - case 'R': - case 'r': - /* can't control? */ - break; - } -} - -long -duartwrite(Chan *c, void *va, long n, ulong offset) -{ - Uart *p; - char cmd[32]; - - USED(offset); - - if(c->qid.path & CHDIR) - error(Eperm); - - p = &uart[NETID(c->qid.path)]; - switch(NETTYPE(c->qid.path)){ - case Ndataqid: - return qwrite(p->oq, va, n); - case Nctlqid: - if(n >= sizeof(cmd)) - n = sizeof(cmd)-1; - memmove(cmd, va, n); - cmd[n] = 0; - duartctl(p, cmd); - return n; - } -} - -long -duartbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -duartremove(Chan *c) -{ - USED(c); - error(Eperm); -} - -void -duartwstat(Chan *c, char *p) -{ - USED(c, p); - error(Eperm); -} diff --git a/power/devrtc.c b/power/devrtc.c deleted file mode 100644 index a2da2f506110d4327a9fdad37d2a1d8402571fc5..0000000000000000000000000000000000000000 --- a/power/devrtc.c +++ /dev/null @@ -1,501 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "../port/error.h" - -#include "io.h" - -typedef struct Rtc Rtc; -typedef struct Nvram Nvram; - -/* - * length of nvram is 2048 - * the last addresses are reserved by convention for - * a checksum and setting the real time clock - */ -enum{ - NVLEN = 2046, - NVCKSUM = 2046, - NVRTC = 2047, - Nbcd = 8, /* number of bcd bytes in the clock */ - Qrtc = 1, - Qnvram, -}; - -struct Nvram{ - uchar val; - uchar pad[7]; -}; - -struct Rtc -{ - int sec; - int min; - int hour; - int mday; - int mon; - int year; -}; - -QLock rtclock; /* mutex on nvram operations */ - -static Dirtab rtcdir[]={ - "rtc", {Qrtc, 0}, 0, 0644, - "nvram", {Qnvram, 0}, 0, 0600, -}; -#define NRTC (sizeof(rtcdir)/sizeof(rtcdir[0])) - -static uchar pattern[] = -{ - 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c -}; - -ulong rtc2sec(Rtc*); -void sec2rtc(ulong, Rtc*); -int *yrsize(int); -void setrtc(Rtc*); -long rtctime(void); -void nvcksum(void); - -void -rtcreset(void) -{ -} - -void -rtcinit(void) -{ -} - -Chan* -rtcattach(char *spec) -{ - return devattach('r', spec); -} - -Chan* -rtcclone(Chan *c, Chan *nc) -{ - return devclone(c, nc); -} - -int -rtcwalk(Chan *c, char *name) -{ - return devwalk(c, name, rtcdir, NRTC, devgen); -} - -void -rtcstat(Chan *c, char *dp) -{ - devstat(c, dp, rtcdir, NRTC, devgen); -} - -Chan* -rtcopen(Chan *c, int omode) -{ - omode = openmode(omode); - switch(c->qid.path){ - case Qrtc: - if(strcmp(up->user, eve)!=0 && omode!=OREAD) - error(Eperm); - break; - case Qnvram: - if(strcmp(up->user, eve)!=0 || !cpuserver) - error(Eperm); - } - return devopen(c, omode, rtcdir, NRTC, devgen); -} - -void -rtccreate(Chan *c, char *name, int omode, ulong perm) -{ - USED(c); - USED(name); - USED(omode); - USED(perm); - error(Eperm); -} - -void -rtcclose(Chan *c) -{ - USED(c); -} - -long -rtcread(Chan *c, void *buf, long n, ulong offset) -{ - Nvram *nv; - char *p; - ulong t, ot; - int i; - - if(c->qid.path & CHDIR) - return devdirread(c, buf, n, rtcdir, NRTC, devgen); - - switch(c->qid.path){ - case Qrtc: - qlock(&rtclock); - t = rtctime(); - do{ - ot = t; - t = rtctime(); /* make sure there's no skew */ - }while(t != ot); - qunlock(&rtclock); - n = readnum(offset, buf, n, t, 12); - return n; - case Qnvram: - if(offset > NVLEN) - return 0; - if(n > NVLEN - offset) - n = NVLEN - offset; - nv = (Nvram *)NVRAM; - p = buf; - qlock(&rtclock); - for(i = 0; i < n; i++) - p[i] = nv[i+offset].val; - qunlock(&rtclock); - return n; - } - error(Egreg); - return -1; /* never reached */ -} - -Block* -rtcbread(Chan *c, long n, ulong offset) -{ - return devbread(c, n, offset); -} - -long -rtcwrite(Chan *c, void *buf, long n, ulong offset) -{ - Nvram *nv; - Rtc rtc; - ulong secs; - char *cp, *ep; - int i; - - switch(c->qid.path){ - case Qrtc: - if(offset!=0) - error(Ebadarg); - /* - * read the time - */ - cp = ep = buf; - ep += n; - while(cp < ep){ - if(*cp>='0' && *cp<='9') - break; - cp++; - } - secs = strtoul(cp, 0, 0); - /* - * convert to bcd - */ - sec2rtc(secs, &rtc); - /* - * write it - */ - qlock(&rtclock); - setrtc(&rtc); - qunlock(&rtclock); - return n; - case Qnvram: - if(offset > NVLEN) - return 0; - if(n > NVLEN - offset) - n = NVLEN - offset; - nv = (Nvram *)NVRAM; - qlock(&rtclock); - for(i = 0; i < n; i++) - nv[i+offset].val = ((char*)buf)[i]; - nvcksum(); - qunlock(&rtclock); - return n; - } - error(Egreg); - return -1; /* never reached */ -} - -long -rtcbwrite(Chan *c, Block *bp, ulong offset) -{ - return devbwrite(c, bp, offset); -} - -void -rtcremove(Chan *c) -{ - USED(c); - error(Eperm); -} - -void -rtcwstat(Chan *c, char *dp) -{ - USED(c); - USED(dp); - error(Eperm); -} - -void -nvcksum(void) -{ - Nvram *nv; - uchar cksum; - int i; - - /* - * Seed the checksum so all-zeroes (all-ones) nvram doesn't have a zero - * (all-ones) checksum. - */ - cksum = 0xa5; - nv = (Nvram *)NVRAM; - for(i = 0; i < NVLEN; i++){ - cksum ^= nv[i].val; - cksum = (cksum << 1) | ((cksum >> 7) & 1); - } - nv[NVCKSUM].val = cksum; -} - -/* - * issue pattern recognition bits to nv ram to address the - * real time clock - */ -void -rtcpattern(void) -{ - uchar *nv; - uchar ch; - int i, j; - - nv = &((Nvram*)NVRAM)[NVRTC].val; - - /* - * read the pattern sequence pointer to reset it - */ - ch = *nv; - USED(ch); - - /* - * stuff the pattern recognition codes one bit at - * a time into *nv. - */ - for(i = 0; i < Nbcd; i++){ - ch = pattern[i]; - for (j = 0; j < 8; j++){ - *nv = ch & 0x1; - ch >>= 1; - } - } -} - -#define GETBCD(o) ((bcdclock[o]&0xf) + 10*(bcdclock[o]>>4)) - -long -rtctime(void) -{ - int i,j; - uchar ch; - uchar *nv; - uchar bcdclock[Nbcd]; - Rtc rtc; - - nv = &((Nvram*)NVRAM)[NVRTC].val; - - /* - * set up the pattern for the clock - */ - rtcpattern(); - - /* - * read out the clock one bit at a time - */ - for(i = 0; i < Nbcd; i++){ - ch = 0; - for (j = 0; j < 8; j++) - ch |= ((*nv & 0x1) << j); - bcdclock[i] = ch; - } - - /* - * see if the clock oscillator is on - */ - if(bcdclock[4] & 0x20) - return 0; /* nope, time is bogus */ - - /* - * convert from BCD - */ - rtc.sec = GETBCD(1); - rtc.min = GETBCD(2); - rtc.hour = GETBCD(3); - rtc.mday = GETBCD(5); - rtc.mon = GETBCD(6); - rtc.year = GETBCD(7); - - /* - * the world starts jan 1 1970 - */ - if(rtc.year < 70) - rtc.year += 2000; - else - rtc.year += 1900; - return rtc2sec(&rtc); -} - -#define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4) - -void -setrtc(Rtc *rtc) -{ - int i, j; - uchar ch; - uchar bcdclock[Nbcd]; - uchar *nv; - - bcdclock[0] = bcdclock[4] = 0; - PUTBCD(rtc->sec, 1); - PUTBCD(rtc->min, 2); - PUTBCD(rtc->hour, 3); - PUTBCD(rtc->mday, 5); - PUTBCD(rtc->mon, 6); - PUTBCD(rtc->year, 7); - - /* - * set up the pattern for the clock - */ - rtcpattern(); - - /* - * write the clock one bit at a time - */ - nv = &((Nvram*)NVRAM)[NVRTC].val; - for(i = 0; i < Nbcd; i++){ - ch = bcdclock[i]; - for (j = 0; j < 8; j++){ - *nv = ch & 1; - ch >>= 1; - } - } -} - -#define SEC2MIN 60L -#define SEC2HOUR (60L*SEC2MIN) -#define SEC2DAY (24L*SEC2HOUR) - -/* - * days per month plus days/year - */ -static int dmsize[] = -{ - 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; -static int ldmsize[] = -{ - 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -/* - * return the days/month for the given year - */ -int * -yrsize(int yr) -{ - if((yr % 4) == 0) - return ldmsize; - else - return dmsize; -} - -/* - * compute seconds since Jan 1 1970 - */ -ulong -rtc2sec(Rtc *rtc) -{ - ulong secs; - int i; - int *d2m; - - secs = 0; - - /* - * seconds per year - */ - for(i = 1970; i < rtc->year; i++){ - d2m = yrsize(i); - secs += d2m[0] * SEC2DAY; - } - - /* - * seconds per month - */ - d2m = yrsize(rtc->year); - for(i = 1; i < rtc->mon; i++) - secs += d2m[i] * SEC2DAY; - - secs += (rtc->mday-1) * SEC2DAY; - secs += rtc->hour * SEC2HOUR; - secs += rtc->min * SEC2MIN; - secs += rtc->sec; - - return secs; -} - -/* - * compute rtc from seconds since Jan 1 1970 - */ -void -sec2rtc(ulong secs, Rtc *rtc) -{ - int d; - long hms, day; - int *d2m; - - /* - * break initial number into days - */ - hms = secs % SEC2DAY; - day = secs / SEC2DAY; - if(hms < 0) { - hms += SEC2DAY; - day -= 1; - } - - /* - * generate hours:minutes:seconds - */ - rtc->sec = hms % 60; - d = hms / 60; - rtc->min = d % 60; - d /= 60; - rtc->hour = d; - - /* - * year number - */ - if(day >= 0) - for(d = 1970; day >= *yrsize(d); d++) - day -= *yrsize(d); - else - for (d = 1970; day < 0; d--) - day += *yrsize(d-1); - rtc->year = d; - - /* - * generate month - */ - d2m = yrsize(rtc->year); - for(d = 1; day >= d2m[d]; d++) - day -= d2m[d]; - rtc->mday = day + 1; - rtc->mon = d; - - return; -} diff --git a/power/faultmips.c b/power/faultmips.c deleted file mode 100644 index 6b1d0f9225e431c7864807f426ed4afd682d09b1..0000000000000000000000000000000000000000 --- a/power/faultmips.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "ureg.h" -#include "../port/error.h" -#include "io.h" - -/* - * find out fault address and type of access. - * Call common fault handler. - */ -void -faultmips(Ureg *ur, int user, int code) -{ - int read; - ulong addr; - extern char *excname[]; - char *p, buf[ERRLEN]; - - addr = ur->badvaddr; - addr &= ~(BY2PG-1); - read = !(code==CTLBM || code==CTLBS); - - if(fault(addr, read) == 0) - return; - - if(user) { - p = "store"; - if(read) - p = "load"; - sprint(buf, "sys: trap: fault %s addr=0x%lux", p, ur->badvaddr); - postnote(up, 1, buf, NDebug); - return; - } - print("kernel %s vaddr=0x%lux\n", excname[code], ur->badvaddr); - print("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->status, ur->pc, ur->sp); - dumpregs(ur); - panic("fault"); -} - -/* - * called in sysfile.c - */ -void -evenaddr(ulong addr) -{ - if(addr & 3){ - postnote(up, 1, "sys: odd address", NDebug); - error(Ebadarg); - } -} diff --git a/power/fns.h b/power/fns.h deleted file mode 100644 index d8ff6abdfe7a7cf4827e3e09702ed6c3a5892ce7..0000000000000000000000000000000000000000 --- a/power/fns.h +++ /dev/null @@ -1,87 +0,0 @@ -#include "../port/portfns.h" - -void arginit(void); -void clearmmucache(void); -void clock(Ureg*); -void clockinit(void); -ulong confeval(char*); -void confread(void); -void confprint(void); -void confset(char*); -int conschar(void); -void dcflush(void*, ulong); -int duartactive(void); -void duartenable0(void); -void duartinit(void); -void duartintr(void); -void duartreset(void); -void duartslave(void); -void duartspecial(int, int, Queue**, Queue**, int (*)(Queue*, int)); -void duartxmit(int); -void evenaddr(ulong); -void faultmips(Ureg*, int, int); -ulong fcr31(void); -void firmware(int); -void flushmmu(void); -#define flushpage(s) icflush((void*)(s), BY2PG) -void fptrap(Ureg*); -ulong getstatus(void); -void gettlb(int, ulong*); -ulong gettlbvirt(int); -void gotopc(ulong); -ulong getcallerpc(void*); -void icflush(void *, ulong); -void ioboardinit(void); -void intr(Ureg*); -int iprint(char*, ...); -void kbdchar(int); -void kproftimer(ulong); -void lanceintr(void); -void lanceparity(void); -void lancesetup(Lance*); -void launchinit(void); -void launch(int); -int muxlock(int*, int*); -void newstart(void); -int newtlbpid(Proc*); -void novme(int); -void online(void); -Block* prepend(Block*, int); -void prflush(void); -void printslave(void); -#define procsetup(p) ((p)->fpstate = FPinit) -#define procsave(p) -#define procrestore(p) -void purgetlb(int); -void putcontext(int); -void putstlb(ulong, ulong); -void putstrn(char*, long); -void puttlb(ulong, ulong); -void puttlbx(int, ulong, ulong); -int readlog(ulong, char*, ulong); -void restfpregs(FPsave*, ulong); -#define screenputs(a, b) -void scsiintr(int); -void setvmevec(int, void (*)(int)); -void sinit(void); -uchar* smap(int, uchar*); -void sunmap(int, uchar*); -long syscall(Ureg*); -void sysloginit(void); -void syslog(char*, int); -void tlbinit(void); -Block* tolance(Block*, int); -void touser(void*); -void vecinit(void); -void vector0(void); -void vector80(void); -void vmereset(void); -void wbflush(void); -#define waserror() setlabel(&up->errlab[up->nerrlab++]) -#define kmapperm(x) kmap(x) -#define KADDR(a) ((void*)((ulong)(a)|KZERO)) -#define PADDR(a) ((ulong)(a)&~KZERO) -Page* lkpage(Segment*, ulong); -void lkpgfree(Page*); -#define vcacheinval(s) -#define coherence() diff --git a/power/fptrap.c b/power/fptrap.c deleted file mode 100644 index bdf9ea7daff2e5270b5f3a4ddaa9a50ce8a2db18..0000000000000000000000000000000000000000 --- a/power/fptrap.c +++ /dev/null @@ -1,283 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "ureg.h" -#include "io.h" -#include "../port/error.h" - -enum /* op */ -{ - ABS = 5, - ADD = 0, - CVTD = 33, - CVTS = 32, - CVTW = 36, - DIV = 3, - MOV = 6, - MUL = 2, - NEG = 7, - SUB = 1, -}; - -static int fpunimp(ulong); -static ulong branch(Ureg*, ulong); - -void -fptrap(Ureg *ur) -{ - ulong iw, npc; - - if((up->fpsave.fpstatus&(1<<17)) == 0) - return; - -print("fpt: %d %s %lux\n", up->pid, up->text, up->fpsave.fpstatus); - - if(ur->cause & (1<<31)) - iw = *(ulong*)(ur->pc+4); - else - iw = *(ulong*)ur->pc; - - if(fpunimp(iw) == 0) - return; - - if(ur->cause & (1<<31)){ - npc = branch(ur, up->fpsave.fpstatus); - if(npc == 0) - return; - ur->pc = npc; - } - else - ur->pc += 4; - - up->fpsave.fpstatus = up->fpsave.fpstatus & ~(1<<17); -} - -static void -unpack(FPsave *f, int fmt, int reg, int *sign, int *exp) -{ - *sign = 1; - if(f->fpreg[reg] & 0x80000000) - *sign = -1; - - switch(fmt){ - case 0: - *exp = ((f->fpreg[reg]>>23)&0xFF) - ((1<<7)-2); - break; - case 1: - if(reg & 1) /* shouldn't happen */ - reg &= ~1; - *exp = ((f->fpreg[reg]>>20)&0x7FF) - ((1<<10)-2); - break; - } -} - -static void -zeroreg(FPsave *f, int fmt, int reg, int sign) -{ - int size; - - size = 0; - switch(fmt){ - case 0: - size = 4; - break; - case 1: - if(reg & 1) - reg &= ~1; - size = 8; - break; - } - memset(&f->fpreg[reg], 0, size); - if(sign < 0) - f->fpreg[reg] |= 0x80000000; -} - -static int -fpunimp(ulong iw) -{ - int ss, st, sd; - int es, et, ed; - int maxe, maxm; - ulong op, fmt, ft, fs, fd; - - if((iw>>25) != 0x23) - return 0; - op = iw & ((1<<6)-1); - fmt = (iw>>21) & ((1<<4)-1); - ft = (iw>>16) & ((1<<5)-1); - fs = (iw>>11) & ((1<<5)-1); - fd = (iw>>6) & ((1<<5)-1); - unpack(&up->fpsave, fmt, fs, &ss, &es); - unpack(&up->fpsave, fmt, ft, &st, &et); - ed = 0; - maxe = 0; - maxm = 0; - switch(fmt){ - case 0: - maxe = 1<<7; - maxm = 24; - break; - case 1: - maxe = 1<<10; - maxm = 53; - break; - } - switch(op){ - case ABS: - up->fpsave.fpreg[fd] &= ~0x80000000; - return 1; - - case NEG: - up->fpsave.fpreg[fd] ^= 0x80000000; - return 1; - - case SUB: - st = -st; - case ADD: - if(es<-(maxe-maxm) && et<-(maxe-maxm)) - ed = -maxe; - if(es > et) - sd = es; - else - sd = et; - break; - - case DIV: - et = -et; - case MUL: - sd = 1; - if(ss != st) - sd = -1; - ed = es + et; - break; - - case CVTS: - if(fmt != 1) - return 0; - fmt = 0; /* convert FROM double TO single */ - maxe = 1<<7; - ed = es; - sd = ss; - break; - - default: /* probably a compare */ - return 0; - } - if(ed <= -(maxe-4)){ /* guess: underflow */ - zeroreg(&up->fpsave, fmt, fd, sd); - /* Set underflow exception and sticky */ - up->fpsave.fpstatus |= (1<<3)|(1<<13); - return 1; - } - return 0; -} - -static ulong* -reg(Ureg *ur, int regno) -{ - /* regs go from R31 down in ureg, R29 is missing */ - if(regno == 31) - return &ur->r31; - if(regno == 30) - return &ur->r30; - if(regno == 29) - return &ur->sp; - return (&ur->r28) + (28-regno); -} - -static ulong -branch(Ureg *ur, ulong fcr31) -{ - ulong iw, npc, rs, rt, rd, offset; - - iw = *(ulong*)ur->pc; - rs = (iw>>21) & 0x1F; - if(rs) - rs = *reg(ur, rs); - rt = (iw>>16) & 0x1F; - if(rt) - rt = *reg(ur, rt); - offset = iw & ((1<<16)-1); - if(offset & (1<<15)) /* sign extend */ - offset |= ~((1<<16)-1); - offset <<= 2; - /* - * Integer unit jumps first - */ - switch(iw>>26){ - case 0: /* SPECIAL: JR or JALR */ - switch(iw&0x3F){ - case 0x09: /* JALR */ - rd = (iw>>11) & 0x1F; - if(rd) - *reg(ur, rd) = ur->pc+8; - /* fall through */ - case 0x08: /* JR */ - return rs; - default: - return 0; - } - case 1: /* BCOND */ - switch((iw>>16) & 0x1F){ - case 0x10: /* BLTZAL */ - ur->r31 = ur->pc + 8; - /* fall through */ - case 0x00: /* BLTZ */ - if((long)rs < 0) - return ur->pc+4 + offset; - return ur->pc + 8; - case 0x11: /* BGEZAL */ - ur->r31 = ur->pc + 8; - /* fall through */ - case 0x01: /* BGEZ */ - if((long)rs >= 0) - return ur->pc+4 + offset; - return ur->pc + 8; - default: - return 0; - } - case 3: /* JAL */ - ur->r31 = ur->pc+8; - /* fall through */ - case 2: /* JMP */ - npc = iw & ((1<<26)-1); - npc <<= 2; - return npc | (ur->pc&0xF0000000); - case 4: /* BEQ */ - if(rs == rt) - return ur->pc+4 + offset; - return ur->pc + 8; - case 5: /* BNE */ - if(rs != rt) - return ur->pc+4 + offset; - return ur->pc + 8; - case 6: /* BLEZ */ - if((long)rs <= 0) - return ur->pc+4 + offset; - return ur->pc + 8; - case 7: /* BGTZ */ - if((long)rs > 0) - return ur->pc+4 + offset; - return ur->pc + 8; - } - /* - * Floating point unit jumps - */ - if((iw>>26) == 0x11) /* COP1 */ - switch((iw>>16) & 0x3C1){ - case 0x101: /* BCT */ - case 0x181: /* BCT */ - if(fcr31 & (1<<23)) - return ur->pc+4 + offset; - return ur->pc + 8; - case 0x100: /* BCF */ - case 0x180: /* BCF */ - if(!(fcr31 & (1<<23))) - return ur->pc+4 + offset; - return ur->pc + 8; - } - /* shouldn't get here */ - return 0; -} diff --git a/power/io.h b/power/io.h deleted file mode 100644 index c49c4b93d1b912915fce542a6993ddc310e98f40..0000000000000000000000000000000000000000 --- a/power/io.h +++ /dev/null @@ -1,148 +0,0 @@ -#define UNCACHED 0xA0000000 -#define IO2(t,x) ((t *)(UNCACHED|0x17000000|(x))) -#define VMEA24SUP(t, x) ((t *)(UNCACHED|0x13000000|(x))) -#define VMEA32SUP(t, x) ((t *)(UNCACHED|0x30000000|(x))) -#define SYNCBUS(t,x) ((t *)(UNCACHED|0x1E000000|(x))) -#define SBSEM SYNCBUS(ulong, 0) -#define SBSEMTOP SYNCBUS(ulong, 0x400000) - -#define LED ((char*)0xBF200001) -enum -{ - LEDtrapmask= 0xf<<0, - LEDkfault= 1<<4, - LEDclock= 1<<5, - LEDfault= 1<<6, - LEDpulse= 1<<7, -}; -/* -#define LEDON(x) (m->ledval &= ~(x), *LED = m->ledval) -#define LEDOFF(x) (m->ledval |= (x), *LED = m->ledval) -*/ -#define LEDON(x) -#define LEDOFF(x) - -typedef struct SBCC SBCC; -typedef struct Timer Timer; -typedef struct Duartreg Duartreg; - -struct SBCC -{ - ulong level[14]; /* cpu interrupt level for cpu->cpu ints */ - ulong junk0[2]; - ulong status[14]; /* status from other cpu */ - ulong junk1[2]; - ulong elevel; /* cpu interrupt level for vme->cpu ints */ - ulong junk2[7]; - ulong flevel; /* cpu interrupt level for vme->cpu ints */ - ulong junk3[3]; - ulong overrun; - ulong junk4[3]; - ulong id; /* id of this cpu */ - ulong eintenable; - ulong eintpending; - ulong fintenable; - ulong fintpending; - ulong idintenable; - ulong idintpending; - ulong junk5[8]; - ulong intxmit; -}; - -#define SBCCREG SYNCBUS(SBCC, 0x400000) - -#define TIMERREG SYNCBUS(Timer, 0x1600000) -#define CLRTIM0 SYNCBUS(uchar, 0x1100000) -#define CLRTIM1 SYNCBUS(uchar, 0x1180000) - -#define DUARTREG SYNCBUS(Duartreg, 0x1A00000) - -#define LANCERAM IO2(ushort, 0xE00000) -#define LANCEEND IO2(ushort, 0xF00000) -#define LANCE3RAM IO2(ushort, 0xFF4000) -#define LANCE3END IO2(ushort, 0xFF8000) -#define LANCERDP IO2(ushort, 0xFC0002) -#define LANCERAP IO2(ushort, 0xFC000a) -#define LANCEID IO2(ushort, 0xFF0002) -#define WRITEMAP IO2(ulong, 0xFA0000) -#define LANCEINDEX 0x1E00 /* index of lancemap */ - -#define SCSI0ADDR IO2(uchar, 0xF08007) -#define SCSI0DATA IO2(uchar, 0xF08107) -#define SCSI1ADDR IO2(uchar, 0xF0C007) -#define SCSI1DATA IO2(uchar, 0xF0C107) -#define SCSI0CNT IO2(ulong, 0xF54000) -#define SCSI1CNT IO2(ulong, 0xF58000) -#define SCSI0FLS IO2(uchar, 0xF30001) -#define SCSI1FLS IO2(uchar, 0xF34001) - -#define IOID IO2(uchar, 0xFFFFF0) -#define IO2R1 1 /* IO2 revision level 1 */ -#define IO2R2 2 /* IO2 revision level 2 */ -#define IO3R1 3 /* IO3 revision level 1 */ -extern int ioid; /* io board type */ - -typedef struct MODE MODE; -typedef struct INTVEC INTVEC; - -struct MODE { - uchar masterslave; /* master/slave addresses for the IO2 */ - uchar resetforce; - uchar checkbits; - uchar promenet; -}; - -#define MODEREG IO2(MODE, 0xF40000) - -/* - * VME addressing. - * MP2VME takes a physical MP bus address and returns an address - * usable by a VME device through A32 space. VME2MP is its inverse - */ -#define MASTER 0x1 /* 0x10000000 - Map for cyclone A32 addressing */ -#define SLAVE 0x4 -#define MP2VME(addr) (((ulong)(addr) & 0x0fffffff) | (SLAVE<<28)) -#define VME2MP(addr) (((ulong)(addr) & 0x0fffffff) | KZERO) - - -struct INTVEC { - struct { - ulong vec; - ulong fill2; - } i[8]; -}; - -#define INTVECREG IO2(INTVEC, 0xF60000) -#define NVRAM IO2(uchar, 0xF10000) -#define INTPENDREG IO2(uchar, 0xF20000) /* same as LED */ -#define INTPENDREG3 IO2(uchar, 0xFF0000) /* same as ENET ID */ -#define IO2CLRMASK IO2(ulong, 0xFE0000) -#define IO2SETMASK IO2(ulong, 0xFE8000) -#define MPBERR0 IO2(ulong, 0xF48000) -#define MPBERR1 IO2(ulong, 0xF4C000) -#define RTC (NVRAM+0x3ff8) - -#define SBEADDR ((ulong *)(UNCACHED|0x1F080000)) - -#define PROM_RESET 0 /* run diags, check bootmode, reinit */ -#define PROM_EXEC 1 /* load new program image */ -#define PROM_RESTART 2 /* re-enter monitor command loop */ -#define PROM_REINIT 3 /* re-init monitor, then cmd loop */ -#define PROM_REBOOT 4 /* check bootmode, no config */ -#define PROM_AUTOBOOT 5 /* autoboot the system */ - -/* - * hs datakit board - */ -typedef struct HSdev HSdev; -struct HSdev { - ushort version; - ushort pad0x02; - ushort vector; - ushort pad0x06; - ushort csr; - ushort pad0x0A; - ushort data; -}; -#define HSDEV VMEA24SUP(HSdev, 0xF90000) - diff --git a/power/l.s b/power/l.s deleted file mode 100644 index 65e525a3007970a9e0a4d7446462d974028959dd..0000000000000000000000000000000000000000 --- a/power/l.s +++ /dev/null @@ -1,792 +0,0 @@ -#include "mem.h" - -#define SP R29 - -#define PROM (KSEG1+0x1FC00000) -#define NOOP NOR R0,R0 -#define WAIT NOOP; NOOP - -/* - * Boot first processor - */ -TEXT start(SB), $-4 - - MOVW $setR30(SB), R30 - MOVW $(CU1|INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1 - MOVW R1, M(STATUS) - WAIT - - MOVW $(0x1C<<7), R1 - MOVW R1, FCR31 /* permit only inexact and underflow */ - NOOP - MOVD $0.5, F26 - SUBD F26, F26, F24 - ADDD F26, F26, F28 - ADDD F28, F28, F30 - - MOVD F24, F0 - MOVD F24, F2 - MOVD F24, F4 - MOVD F24, F6 - MOVD F24, F8 - MOVD F24, F10 - MOVD F24, F12 - MOVD F24, F14 - MOVD F24, F16 - MOVD F24, F18 - MOVD F24, F20 - MOVD F24, F22 - - MOVW $MACHADDR, R(MACH) - ADDU $(BY2PG-4), R(MACH), SP - MOVW $0, R(USER) - MOVW R0, 0(R(MACH)) - - MOVW $edata(SB), R1 - MOVW $end(SB), R2 - -clrbss: - MOVB $0, (R1) - ADDU $1, R1 - BNE R1, R2, clrbss - - MOVW R4, _argc(SB) - MOVW R5, _argv(SB) - MOVW R6, _env(SB) - JAL main(SB) - JMP (R0) - -/* - * Take first processor into user mode - * - argument is stack pointer to user - */ - -TEXT touser(SB), $-4 - - MOVW R1, SP /* user stack pointer */ - MOVW M(STATUS), R1 - OR $(KUP|IEP), R1 - MOVW R1, M(STATUS) - NOOP - MOVW $(UTZERO+32), R26 /* header appears in text */ - RFE (R26) - -/* - * Bring subsequent processors on line - */ -TEXT newstart(SB), $0 - - MOVW $setR30(SB), R30 - MOVW $(INTR5|INTR4|INTR3|INTR2|INTR1|SW1|SW0), R1 - MOVW R1, M(STATUS) - NOOP - MOVW $MACHADDR, R(MACH) - MOVB (MPID+3), R1 - AND $7, R1 - SLL $PGSHIFT, R1, R2 - ADDU R2, R(MACH) - ADDU $(BY2PG-4), R(MACH), SP - MOVW $0, R(USER) - MOVW R1, 0(R(MACH)) - JAL online(SB) - JMP (R0) - -TEXT firmware(SB), $0 - - SLL $3, R1 - ADD $PROM, R1 - JMP (R1) - -TEXT splhi(SB), $0 - - MOVW R31, 0xC(R(MACH)) /* save PC in m->splpc */ - MOVW M(STATUS), R1 - AND $~IE, R1, R2 - MOVW R2, M(STATUS) - NOOP - RET - -TEXT splx(SB), $0 - - MOVW R31, 0xC(R(MACH)) /* save PC in m->splpc */ - MOVW M(STATUS), R2 - AND $IE, R1 - AND $~IE, R2 - OR R2, R1 - MOVW R1, M(STATUS) - NOOP - RET - -TEXT spllo(SB), $0 - - MOVW M(STATUS), R1 - OR $IE, R1, R2 - MOVW R2, M(STATUS) - NOOP - RET - -TEXT muxlock(SB),$0 - - MOVW R1, R2 /* sbsem */ - MOVW 4(FP), R3 /* lk->val */ - - MOVW M(STATUS), R5 /* splhi */ - AND $~IE, R5, R4 - MOVW R4, M(STATUS) - - MOVW 0(R2),R4 /* grab sbsem */ - AND $1, R4 - BNE R4, f1 - MOVW 0(R3),R4 - BNE R4, f0 - - MOVW $1, R1 - MOVW R1, 0(R3) /* lk->val = 1 */ - MOVW R0, 0(R2) /* *sbsem = 0 */ - MOVW R5, M(STATUS) /* splx */ - RET - -f0: MOVW R0, 0(R2) /* *sbsem = 0 */ -f1: MOVW R5, M(STATUS) /* splx */ - MOVW R0, R1 /* return 0 */ - RET - -TEXT spldone(SB), $0 - - RET - -TEXT wbflush(SB), $-4 - - MOVW $WBFLUSH, R1 - MOVW 0(R1), R1 - RET - -TEXT setlabel(SB), $-4 - - MOVW R29, 0(R1) - MOVW R31, 4(R1) - MOVW $0, R1 - RET - -TEXT gotolabel(SB), $-4 - - MOVW 0(R1), R29 - MOVW 4(R1), R31 - MOVW $1, R1 - RET - -TEXT getcallerpc(SB), $0 - - MOVW 0(SP), R1 - RET - -TEXT gotopc(SB), $8 - - MOVW R1, 0(FP) /* save arguments for later */ - MOVW $(64*1024), R7 - MOVW R7, 8(SP) - JAL icflush(SB) - MOVW 0(FP), R7 - MOVW _argc(SB), R4 - MOVW _argv(SB), R5 - MOVW _env(SB), R6 - MOVW R0, 4(SP) - JMP (R7) - -TEXT putcontext(SB), $4 - - SLL $6, R1 - MOVW R1, M(TLBVIRT) - RET - -TEXT puttlb(SB), $4 - - MOVW 4(FP), R2 - MOVW R1, M(TLBVIRT) - MOVW R2, M(TLBPHYS) - NOOP - TLBP - NOOP - MOVW M(INDEX), R3 - BGEZ R3, index - TLBWR - NOOP - RET - -index: - TLBWI - NOOP - RET - -TEXT puttlbx(SB), $0 - - MOVW 4(FP), R2 - MOVW 8(FP), R3 - SLL $8, R1 - MOVW R2, M(TLBVIRT) - MOVW R3, M(TLBPHYS) - MOVW R1, M(INDEX) - NOOP - TLBWI - NOOP - RET - -TEXT tlbp(SB), $0 - TLBP - NOOP - MOVW M(INDEX), R1 - RET - -TEXT tlbvirt(SB), $0 - MOVW M(TLBVIRT), R1 - RET - - -TEXT gettlb(SB), $0 - MOVW 4(FP), R4 - SLL $8, R1 - MOVW R1, M(INDEX) - NOOP - TLBR - NOOP - MOVW M(TLBVIRT), R1 - MOVW M(TLBPHYS), R2 - NOOP - MOVW R1, 0(R4) - MOVW R2, 4(R4) - RET - -TEXT gettlbvirt(SB), $0 - SLL $8, R1 - MOVW R1, M(INDEX) - NOOP - TLBR - NOOP - MOVW M(TLBVIRT), R1 - NOOP - RET - -TEXT getcause(SB), $0 - MOVW M(CAUSE), R1 - RET - -TEXT vector80(SB), $-4 - MOVW $exception(SB), R26 - JMP (R26) - -TEXT vector0(SB), $-4 -/* - get m->tlbfault BUG - MOVW $((MACHADDR+368) & 0xffff0000), R26 - OR $((MACHADDR+368) & 0xffff), R26 - MOVW (R26), R27 - ADD $1, R27 - MOVW R27, (R26) -*/ - MOVW $utlbmiss(SB), R26 - MOVW M(TLBVIRT), R27 - JMP (R26) - -TEXT utlbmiss(SB), $-4 - - MOVW R27, R26 - SLL $1, R26 - SRL $12, R27 - XOR R26, R27 - AND $(STLBSIZE-1), R27 - SLL $8, R27 - /* R27 = (((tlbvirt<<1)^(tlbvirt>>12)) & (STLBSIZE-1)) << 8 (8 to clear zero in TLBPHYS) */ - MOVW R27, M(TLBPHYS) /* scratch register, store */ - - MOVW $((MACHADDR+4) & 0xffff0000), R26 /* get &mach[0].stb BUG */ - OR $((MACHADDR+4) & 0xffff), R26 - MOVW $MPID, R27 /* add BY2PG*machno */ - MOVB 3(R27), R27 - AND $7, R27 - SLL $PGSHIFT, R27 - ADDU R27, R26 - - MOVW M(TLBPHYS), R27 /* scratch register, load */ - MOVW (R26), R26 - SRL $5, R27 /* R27 is now index * 8 */ - ADDU R26, R27 - MOVW 4(R27), R26 - MOVW R26, M(TLBPHYS) - - MOVW M(TLBVIRT), R26 - MOVW (R27), R27 - BNE R26, R27, stlbm - - TLBWR - MOVW M(EPC), R27 - RFE (R27) - -stlbm: - MOVW $exception(SB), R26 - JMP (R26) - - -TEXT exception(SB), $-4 - MOVW M(STATUS), R26 - AND $KUP, R26 - BEQ R26, waskernel - -wasuser: - MOVW $(MACHADDR&0xffff0000), R27 - OR $(MACHADDR&0xffff), R27 - MOVW $MPID, R26 - MOVB 3(R26), R26 - AND $7, R26 - SLL $PGSHIFT, R26 - ADDU R26,R27 /* R27->current mach */ - MOVW 8(R27), R26 /* R27 = mach->proc */ - MOVW 8(R26), R27 /* mach->proc->kstack */ - MOVW SP, R26 /* save user sp */ - ADDU $(KSTACK-UREGSIZE-2*BY2WD), R27, SP - - MOVW R26, 0x10(SP) /* user SP */ - MOVW R31, 0x28(SP) - MOVW R30, 0x2C(SP) - MOVW M(CAUSE), R26 - MOVW R(MACH), 0x3C(SP) - MOVW R(USER), 0x40(SP) - AND $(0xF<<2), R26 - SUB $(CSYS<<2), R26 - - JAL saveregs(SB) - - MOVW $setR30(SB), R30 - MOVW $MPID, R1 - MOVB 3(R1), R1 - MOVW $MACHADDR, R(MACH) /* locn of &mach[0] */ - AND $7, R1 - SLL $PGSHIFT, R1 - ADDU R1, R(MACH) /* add offset for mach # */ - MOVW 8(R(MACH)), R(USER) /* set up to mach->p */ - MOVW 4(SP), R1 /* first arg for syscall/trap */ - BNE R26, notsys - - JAL syscall(SB) - -sysrestore: - MOVW 0x28(SP), R31 - MOVW 0x08(SP), R26 - MOVW 0x2C(SP), R30 - MOVW R26, M(STATUS) - NOOP - MOVW 0x0C(SP), R26 /* old pc */ - MOVW 0x10(SP), SP - RFE (R26) - -notsys: - JAL trap(SB) - -restore: - JAL restregs(SB) - MOVW 0x28(SP), R31 - MOVW 0x2C(SP), R30 - MOVW 0x3C(SP), R(MACH) - MOVW 0x40(SP), R(USER) - MOVW 0x10(SP), SP - RFE (R26) - -waskernel: - MOVW $1, R26 /* not syscall */ - MOVW SP, -0x90(SP) /* drop this if possible */ - SUB $0xA0, SP - MOVW R31, 0x28(SP) - JAL saveregs(SB) - MOVW 4(SP), R1 /* first arg for trap */ - JAL trap(SB) - JAL restregs(SB) - MOVW 0x28(SP), R31 - ADD $0xA0, SP - RFE (R26) - -TEXT forkret(SB), $0 - MOVW R0, R1 /* Fake out system call return */ - JMP sysrestore - -TEXT saveregs(SB), $-4 - MOVW R1, 0x9C(SP) - MOVW R2, 0x98(SP) - ADDU $8, SP, R1 - MOVW R1, 0x04(SP) /* arg to base of regs */ - MOVW M(STATUS), R1 - MOVW M(EPC), R2 - MOVW R1, 0x08(SP) - MOVW R2, 0x0C(SP) - - BEQ R26, return /* syscall, don't save */ - - MOVW M(CAUSE), R1 - MOVW M(BADVADDR), R2 - MOVW R1, 0x14(SP) - MOVW M(TLBVIRT), R1 - MOVW R2, 0x18(SP) - MOVW R1, 0x1C(SP) - MOVW HI, R1 - MOVW LO, R2 - MOVW R1, 0x20(SP) - MOVW R2, 0x24(SP) - /* LINK,SB,SP missing */ - MOVW R28, 0x30(SP) - /* R27, R26 not saved */ - /* R25, R24 missing */ - MOVW R23, 0x44(SP) - MOVW R22, 0x48(SP) - MOVW R21, 0x4C(SP) - MOVW R20, 0x50(SP) - MOVW R19, 0x54(SP) - MOVW R18, 0x58(SP) - MOVW R17, 0x5C(SP) - MOVW R16, 0x60(SP) - MOVW R15, 0x64(SP) - MOVW R14, 0x68(SP) - MOVW R13, 0x6C(SP) - MOVW R12, 0x70(SP) - MOVW R11, 0x74(SP) - MOVW R10, 0x78(SP) - MOVW R9, 0x7C(SP) - MOVW R8, 0x80(SP) - MOVW R7, 0x84(SP) - MOVW R6, 0x88(SP) - MOVW R5, 0x8C(SP) - MOVW R4, 0x90(SP) - MOVW R3, 0x94(SP) -return: - RET - -TEXT restregs(SB), $-4 - /* LINK,SB,SP missing */ - MOVW 0x30(SP), R28 - /* R27, R26 not saved */ - /* R25, R24 missing */ - MOVW 0x44(SP), R23 - MOVW 0x48(SP), R22 - MOVW 0x4C(SP), R21 - MOVW 0x50(SP), R20 - MOVW 0x54(SP), R19 - MOVW 0x58(SP), R18 - MOVW 0x5C(SP), R17 - MOVW 0x60(SP), R16 - MOVW 0x64(SP), R15 - MOVW 0x68(SP), R14 - MOVW 0x6C(SP), R13 - MOVW 0x70(SP), R12 - MOVW 0x74(SP), R11 - MOVW 0x78(SP), R10 - MOVW 0x7C(SP), R9 - MOVW 0x80(SP), R8 - MOVW 0x84(SP), R7 - MOVW 0x88(SP), R6 - MOVW 0x8C(SP), R5 - MOVW 0x90(SP), R4 - MOVW 0x94(SP), R3 - MOVW 0x24(SP), R2 - MOVW 0x20(SP), R1 - MOVW R2, LO - MOVW R1, HI - MOVW 0x08(SP), R1 - MOVW 0x98(SP), R2 - MOVW R1, M(STATUS) - NOOP - MOVW 0x9C(SP), R1 - MOVW 0x0C(SP), R26 /* old pc */ - RET - -TEXT rfnote(SB), $0 - MOVW R1, R26 /* 1st arg is &uregpointer */ - SUBU $(BY2WD), R26, SP /* pc hole */ - JMP restore - -TEXT clrfpintr(SB), $0 - - MOVW M(STATUS), R3 - OR $CU1, R3 - MOVW R3, M(STATUS) - WAIT - MOVW FCR31, R1 /* Read it to stall the fpu */ - WAIT - MOVW R0, FCR31 - WAIT - AND $~CU1, R3 - MOVW R3, M(STATUS) - RET - -TEXT savefpregs(SB), $0 - MOVW M(STATUS), R3 - MOVW FCR31, R2 /* Read stalls the fpu until inst. complete. */ - WAIT - - MOVD F0, 0x00(R1) - MOVD F2, 0x08(R1) - MOVD F4, 0x10(R1) - MOVD F6, 0x18(R1) - MOVD F8, 0x20(R1) - MOVD F10, 0x28(R1) - MOVD F12, 0x30(R1) - MOVD F14, 0x38(R1) - MOVD F16, 0x40(R1) - MOVD F18, 0x48(R1) - MOVD F20, 0x50(R1) - MOVD F22, 0x58(R1) - MOVD F24, 0x60(R1) - MOVD F26, 0x68(R1) - MOVD F28, 0x70(R1) - MOVD F30, 0x78(R1) - WAIT - - MOVW R2, 0x80(R1) - AND $~CU1, R3 - MOVW R3, M(STATUS) - RET - -TEXT restfpregs(SB), $0 - - MOVW M(STATUS), R3 - OR $CU1, R3 - MOVW R3, M(STATUS) - MOVW fpstat+4(FP), R2 - NOOP - - MOVD 0x00(R1), F0 - MOVD 0x08(R1), F2 - MOVD 0x10(R1), F4 - MOVD 0x18(R1), F6 - MOVD 0x20(R1), F8 - MOVD 0x28(R1), F10 - MOVD 0x30(R1), F12 - MOVD 0x38(R1), F14 - MOVD 0x40(R1), F16 - MOVD 0x48(R1), F18 - MOVD 0x50(R1), F20 - MOVD 0x58(R1), F22 - MOVD 0x60(R1), F24 - MOVD 0x68(R1), F26 - MOVD 0x70(R1), F28 - MOVD 0x78(R1), F30 - - MOVW R2, FCR31 - AND $~CU1, R3 - MOVW R3, M(STATUS) - RET - -TEXT fcr31(SB), $0 - - MOVW FCR31, R1 - RET - -#define NOP WORD $0x0 - -TEXT icflush(SB), $-4 - MOVW R1, R4 - MOVW 4(FP), R5 - MOVW $icflush0(SB), R2 /* Jump to uncache space */ - MOVW $0xA0000000, R1 - OR R1, R2 - JMP (R2) - NOP - -TEXT icflush0(SB), $-4 - - MOVW $833, R12 /* cache_pass magic */ - MOVW $0x10000, R9 /* icache size */ - - MOVW $0, R13 - MOVW M(STATUS), R11 - - BEQ R9, R0, _icflush3 - MOVW $0x30000, R2 /* swap and isolate */ - - NOP - NOP - NOP - NOP - NOP - MOVW R2, M(STATUS) - NOP - NOP - NOP - NOP - NOP - - MOVW R4, R8 - MOVW R5, R9 - AND $0xFFFC, R8 - MOVW $0x9F200000, R1 - OR R1, R8 - - MOVW $icflush1(SB), R2 - JMP (R2) - NOP - -TEXT icflush1(SB), $-4 -_icflush1: - SGT R12, R13, R1 - BNE R1, _icflush2 - - MOVW $0, R13 - MOVW R11, M(STATUS) - MOVW $0x30000, R2 /* swap and isolate */ - - NOP - NOP - NOP - NOP - NOP - MOVW R2, M(STATUS) - NOP - NOP - NOP - NOP - NOP - -_icflush2: - MOVW R0, 0(R8) - MOVW R0, 4(R8) - MOVW R0, 8(R8) - MOVW R0, 12(R8) - MOVW R0, 16(R8) - MOVW R0, 20(R8) - MOVW R0, 24(R8) - MOVW R0, 28(R8) - ADDU $-32, R9 - ADDU $1, R13 - ADDU $32, R8 - BGTZ R9, _icflush1 - - MOVW $icflush3(SB), R2 /* Jump to uncache space */ - MOVW $0xA0000000, R1 - OR R1, R2 - JMP (R2) - NOP - -TEXT icflush3(SB), $-4 -_icflush3: - NOP - NOP - NOP - NOP - NOP - MOVW R11, M(STATUS) - NOP - NOP - NOP - NOP - NOP - - MOVW $icflush4(SB), R2 - JMP (R2) - NOP - -TEXT icflush4(SB), $-4 - RET - -TEXT dcflush(SB), $-4 - MOVW R1, R4 - MOVW 4(FP), R5 - MOVW $dcflush0(SB), R2 /* Jump to uncache space */ - MOVW $0xA0000000, R1 - OR R1, R2 - JMP (R2) - NOP - -TEXT dcflush0(SB), $-4 - - MOVW $833, R12 /* cache_pass magdc */ - MOVW $0x10000, R9 /* dcache size */ - - MOVW $0, R13 - MOVW M(STATUS), R11 - - BEQ R9, R0, _dcflush3 - MOVW $0x10000, R2 /* isolate data cache */ - - NOP - NOP - NOP - NOP - NOP - MOVW R2, M(STATUS) - NOP - NOP - NOP - NOP - NOP - - MOVW R4, R8 - MOVW R5, R9 - AND $0xFFFC, R8 - MOVW $0x9F200000, R1 - OR R1, R8 - - MOVW $dcflush1(SB), R2 - JMP (R2) - NOP - -TEXT dcflush1(SB), $-4 -_dcflush1: - SGT R12, R13, R1 - BNE R1, _dcflush2 - - MOVW $0, R13 - MOVW R11, M(STATUS) - MOVW $0x10000, R2 /* isolate data cache */ - - NOP - NOP - NOP - NOP - NOP - MOVW R2, M(STATUS) - NOP - NOP - NOP - NOP - NOP - -_dcflush2: - MOVW R0, 0(R8) - MOVW R0, 4(R8) - MOVW R0, 8(R8) - MOVW R0, 12(R8) - MOVW R0, 16(R8) - MOVW R0, 20(R8) - MOVW R0, 24(R8) - MOVW R0, 28(R8) - ADDU $-32, R9 - ADDU $1, R13 - ADDU $32, R8 - BGTZ R9, _dcflush1 - - MOVW $dcflush3(SB), R2 /* Jump to uncache space */ - MOVW $0xA0000000, R1 - OR R1, R2 - JMP (R2) - NOP - -TEXT dcflush3(SB), $-4 -_dcflush3: - NOP - NOP - NOP - NOP - NOP - MOVW R11, M(STATUS) - NOP - NOP - NOP - NOP - NOP - - MOVW $dcflush4(SB), R2 - JMP (R2) - NOP - -TEXT dcflush4(SB), $-4 - RET - -TEXT getstatus(SB), $0 - MOVW M(STATUS), R1 - RET diff --git a/power/lock.c b/power/lock.c deleted file mode 100644 index dc304a032c135c2f2827caa94cc6855e6bb6efcd..0000000000000000000000000000000000000000 --- a/power/lock.c +++ /dev/null @@ -1,165 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "../port/error.h" - -/* - * The hardware semaphores are strange. Only 64 per page can be used, - * 1024 pages of them. Only the low bit is meaningful. - * Reading an unset semaphore sets the semaphore and returns the old value. - * Writing a semaphore sets the value, so writing 0 resets (clears) the semaphore. - */ - -enum -{ - SEMPERPG = 64, /* hardware semaphores per page */ - NSEMPG = 1024, - ULOCKPG = 512, -}; - -struct -{ - Lock lock; /* lock to allocate */ - uchar bmap[NSEMPG]; /* allocation map */ - int ulockpg; /* count of user lock available */ -}semalloc; - -Page lkpgheader[NSEMPG]; -#define lhash(laddr) ((int)laddr>>2)&(((NSEMPG-ULOCKPG)*(BY2PG>>2))-1)&~0x3c0 - -void -lockinit(void) -{ - int *sbsem, h, i; - - /* - * Initialise the system semaphore hardware - */ - for(i = 0; i < (NSEMPG-ULOCKPG)*BY2PG; i += 4) { - h = lhash(i); - sbsem = (int*)SBSEM+h; - *sbsem = 0; - } - semalloc.ulockpg = ULOCKPG; -} - -/* equivalent of newpage for pages of hardware locks */ -Page* -lkpage(Segment *s, ulong va) -{ - int i; - Page *pg; - uchar *p, *top; - ulong pa; - - USED(s); - lock(&semalloc.lock); - if(--semalloc.ulockpg < 0) { - semalloc.ulockpg++; - unlock(&semalloc.lock); - return 0; - } - top = &semalloc.bmap[NSEMPG]; - for(p = semalloc.bmap; p < top && *p; p++) - ; - if(p >= top) - panic("lkpage"); - - *p = 1; - i = p-semalloc.bmap; - pg = &lkpgheader[i]; - pa = (ulong)(SBSEM+(i*WD2PG)); - memset((void*)pa, 0, BY2PG); - pg->pa = pa & ~UNCACHED; - pg->va = va; - pg->ref = 1; - - unlock(&semalloc.lock); - return pg; -} - -void -lkpgfree(Page *pg) -{ - uchar *p; - - lock(&semalloc.lock); - p = &semalloc.bmap[((pg->pa|UNCACHED)-(ulong)SBSEM)/BY2PG]; - if(!*p) - panic("lkpgfree"); - *p = 0; - - semalloc.ulockpg++; - unlock(&semalloc.lock); -} - -void -lock(Lock *lk) -{ - int *hwsem, hash; - - hash = lhash(lk); - hwsem = (int*)SBSEM+hash; - - for(;;) { - if(muxlock(hwsem, &lk->val)) - return; - while(lk->val) - ; - } - print("lock loop %lux pc %lux held by pc %lux\n", lk, getcallerpc(lk), lk->pc); - dumpstack(); -} - -void -ilock(Lock *lk) -{ - int *hwsem, hash; - ulong x; - - x = splhi(); - hash = lhash(lk); - hwsem = (int*)SBSEM+hash; - - for(;;) { - if(muxlock(hwsem, &lk->val)){ - lk->sr = x; - return; - } - while(lk->val) - ; - } - splx(x); - print("lock loop %lux pc %lux held by pc %lux\n", lk, getcallerpc(lk), lk->pc); - dumpstack(); -} - -int -canlock(Lock *lk) -{ - int hash; - - hash = lhash(lk); - return muxlock((int*)SBSEM+hash, &lk->val); -} - -void -unlock(Lock *l) -{ - l->pc = 0; - l->val = 0; -} - -void -iunlock(Lock *l) -{ - ulong sr; - - sr = l->sr; - l->pc = 0; - l->val = 0; - splx(sr); -} diff --git a/power/main.c b/power/main.c deleted file mode 100644 index df439c79c874dbb1e5b88f2eb9a885576ed074d2..0000000000000000000000000000000000000000 --- a/power/main.c +++ /dev/null @@ -1,730 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "init.h" - -Softtlb stlb[MAXMACH][STLBSIZE]; /* software tlb simulation */ -int _argc; /* args passed by boot process */ -char **_argv; -char **_env; -char argbuf[128]; /* arguments passed to initcode */ -int argsize; -char consname[NAMELEN]; /* environment vars from NVRAM */ -char diskless[NAMELEN]; -char confbuf[4*1024]; /* config file read by boot program */ -int ioid; /* IO board type */ - -void -main(void) -{ - machinit(); - active.exiting = 0; - active.machs = 1; - arginit(); - confinit(); - lockinit(); - xinit(); - duartinit(); - printinit(); - duartspecial(0, 9600, &kbdq, &printq, kbdcr2nl); - print("\n\nBrazil\n"); - pageinit(); - tlbinit(); - procinit0(); - vecinit(); - initseg(); - clockinit(); - ioboardinit(); - links(); - chandevreset(); - swapinit(); - userinit(); - launchinit(); - schedinit(); -} - -void -machinit(void) -{ - int n; - - icflush(0, 64*1024); - dcflush(0, 64*1024); - n = m->machno; - memset(m, 0, sizeof(Mach)); - m->machno = n; - m->stb = &stlb[n][0]; - - m->ledval = 0xff; -} - -void -tlbinit(void) -{ - int i; - - for(i=0; i= IO3R1) - noforce = 1; - else - noforce = 0; - MODEREG->resetforce = (1<<1) | noforce; - delay(140); - MODEREG->resetforce = noforce; -} - -/* - * We have to program both the IO2 board to generate interrupts - * and the SBCC on CPU 0 to accept them. - */ -void -ioboardinit(void) -{ - long i; - int maxlevel; - - ioid = *IOID; - if(ioid >= IO3R1) - maxlevel = 8; - else - maxlevel = 8; - - vmereset(); - MODEREG->masterslave = (SLAVE<<4) | MASTER; - - /* - * all VME interrupts to the error routine - */ - for(i=0; i<256; i++) - setvmevec(i, novme); - - /* - * tell IO2 to sent all interrupts to CPU 0's SBCC - */ - for(i=0; ii[i].vec = 0<<8; - - /* - * Tell CPU 0's SBCC to map all interrupts from the IO2 to MIPS level 5 - * - * 0x01 level 0 - * 0x02 level 1 - * 0x04 level 2 - * 0x08 level 4 - * 0x10 level 5 - */ - SBCCREG->flevel = 0x10; - - /* - * Tell CPU 0's SBCC to enable all interrupts from the IO2. - * - * The SBCC 16 bit registers are read/written as ulong, but only - * bits 23-16 and 7-0 are meaningful. - */ - SBCCREG->fintenable |= 0xff; /* allow all interrupts on the IO2 */ - SBCCREG->idintenable |= 0x800000; /* allow interrupts from the IO2 */ - - /* - * Enable all interrupts on the IO2. If IO3, run in compatibility mode. - */ - *IO2SETMASK = 0xff000000; - -} - -void -launchinit(void) -{ - int i; - - for(i=1; islash = namec("#/", Atodir, 0, 0); - up->dot = clone(up->slash, 0); - - chandevinit(); - - if(!waserror()){ - ksetenv("cputype", "mips"); - sprint(buf, "sgi %s 4D", conffile); - ksetenv("terminal", buf); - ksetenv("sysname", sysname); - poperror(); - } - - kproc("alarm", alarmkproc, 0); - touser((uchar*)(USTKTOP-sizeof(argbuf))); -} - -FPsave initfp; - -void -userinit(void) -{ - Proc *p; - KMap *k; - Page *pg; - char **av; - Segment *s; - - p = newproc(); - p->pgrp = newpgrp(); - p->egrp = smalloc(sizeof(Egrp)); - p->egrp->ref = 1; - p->fgrp = smalloc(sizeof(Fgrp)); - p->fgrp->ref = 1; - p->procmode = 0640; - - strcpy(p->text, "*init*"); - strcpy(p->user, eve); - - savefpregs(&initfp); - p->fpstate = FPinit; - p->fpsave.fpstatus = initfp.fpstatus; - - /* - * Kernel Stack - */ - p->sched.pc = (ulong)init0; - p->sched.sp = (ulong)p->kstack+KSTACK-(1+MAXSYSARG)*BY2WD; - /* - * User Stack, pass input arguments to boot process - */ - s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); - p->seg[SSEG] = s; - pg = newpage(1, 0, USTKTOP-BY2PG); - segpage(s, pg); - k = kmap(pg); - for(av = (char**)argbuf; *av; av++) - *av += (USTKTOP - sizeof(argbuf)) - (ulong)argbuf; - - memmove((uchar*)VA(k) + BY2PG - sizeof(argbuf), argbuf, sizeof argbuf); - kunmap(k); - - /* Text */ - s = newseg(SG_TEXT, UTZERO, 1); - p->seg[TSEG] = s; - segpage(s, newpage(1, 0, UTZERO)); - k = kmap(s->map[0]->pages[0]); - memmove((ulong*)VA(k), initcode, sizeof initcode); - kunmap(k); - - ready(p); -} - -void -lights(int v) -{ - - *LED = ~v; -} - -typedef struct Beef Beef; -struct Beef -{ - long deadbeef; - long sum; - long cpuid; - long virid; - long erno; - void (*launch)(void); - void (*rend)(void); - long junk1[4]; - long isize; - long dsize; - long nonbss; - long junk2[18]; -}; - -void -launch(int n) -{ - Beef *p; - long i, s; - ulong *ptr; - - p = (Beef*) 0xb0000500 + n; - p->launch = newstart; - p->sum = 0; - s = 0; - ptr = (ulong*)p; - for (i = 0; i < sizeof(Beef)/sizeof(ulong); i++) - s += *ptr++; - p->sum = -(s+1); - - for(i=0; i<3000000; i++) - if(p->launch == 0) - break; -} - -void -online(void) -{ - machinit(); - lock(&active); - active.machs |= 1<machno; - unlock(&active); - tlbinit(); - duartinit(); - clockinit(); - schedinit(); -} - -void -exit(int ispanic) -{ - int i; - - USED(ispanic); - lock(&active); - active.machs &= ~(1<machno); - active.exiting = 1; - unlock(&active); - spllo(); - print("cpu %d exiting\n", m->machno); - while(active.machs || consactive()) - for(i=0; i<1000; i++) - ; - splhi(); - for(i=0; i<2000000; i++) - ; - duartenable0(); - firmware(PROM_REINIT); - firmware(cpuserver ? PROM_AUTOBOOT : PROM_REINIT); -} - -typedef struct Conftab { - char *sym; - ulong *x; -} Conftab; - -#include "conf.h" - -Conf conf; - -ulong -confeval(char *exp) -{ - char *op; - Conftab *ct; - - /* crunch leading white */ - while(*exp==' ' || *exp=='\t') - exp++; - - op = strchr(exp, '+'); - if(op != 0){ - *op++ = 0; - return confeval(exp) + confeval(op); - } - - op = strchr(exp, '*'); - if(op != 0){ - *op++ = 0; - return confeval(exp) * confeval(op); - } - - if(*exp >= '0' && *exp <= '9') - return strtoul(exp, 0, 0); - - /* crunch trailing white */ - op = strchr(exp, ' '); - if(op) - *op = 0; - op = strchr(exp, '\t'); - if(op) - *op = 0; - - /* lookup in symbol table */ - for(ct = conftab; ct->sym; ct++) - if(strcmp(exp, ct->sym) == 0) - return *(ct->x); - - return 0; -} - -/* - * each line of the configuration is of the form `param = expression'. - */ -void -confset(char *sym) -{ - char *val, *p; - Conftab *ct; - - /* - * parse line - */ - - /* comment */ - if(p = strchr(sym, '#')) - *p = 0; - - /* skip white */ - for(p = sym; *p==' ' || *p=='\t'; p++) - ; - sym = p; - - /* skip sym */ - for(; *p && *p!=' ' && *p!='\t' && *p!='='; p++) - ; - if(*p) - *p++ = 0; - - /* skip white */ - for(; *p==' ' || *p=='\t' || *p=='='; p++) - ; - val = p; - - /* - * lookup value - */ - for(ct = conftab; ct->sym; ct++) - if(strcmp(sym, ct->sym) == 0){ - *(ct->x) = confeval(val); - return; - } - - if(strcmp(sym, "sysname")==0){ - p = strchr(val, ' '); - if(p) - *p = 0; - strcpy(sysname, val); - } else if(strcmp(sym, "eve")==0){ - p = strchr(val, ' '); - if(p) - *p = 0; - strcpy(eve, val); - } -} - -/* - * read the ascii configuration left by the boot kernel - */ -void -confread(void) -{ - char *line; - char *end; - - /* - * process configuration file - */ - line = confbuf; - while(end = strchr(line, '\n')){ - *end = 0; - confset(line); - line = end+1; - } -} - -void -confprint(void) -{ - Conftab *ct; - - /* - * lookup value - */ - for(ct = conftab; ct->sym; ct++) - print("%s == %d\n", ct->sym, *ct->x); -} - -void -confinit(void) -{ - long x, i, *l; - ulong ktop; - - /* - * copy configuration down from high memory - */ - strcpy(confbuf, (char *)(0x80000000 + (4*MB) - BY2PG)); - - /* - * size memory - */ - x = 0x12345678; - for(i=4; i<128; i+=4){ - l = (long*)(KSEG1|(i*MB)); - *l = x; - wbflush(); - *(ulong*)KSEG1 = *(ulong*)KSEG1; /* clear latches */ - if(*l != x) - break; - x += 0x3141526; - } - conf.npage0 = i*1024/4; - conf.base0 = 0; - conf.npage = conf.npage0; - conf.npage1 = 0; - conf.base1 = 0; - - ktop = PGROUND((ulong)end); - ktop = PADDR(ktop); - conf.npage0 -= ktop/BY2PG; - conf.base0 += ktop; - - conf.upages = (conf.npage*70)/100; - i = conf.npage-conf.upages; - if(i > (12*MB)/BY2PG) - conf.upages += i - ((12*MB)/BY2PG); - conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG; - /* - * clear MP bus error caused by sizing memory - */ - i = *SBEADDR; - USED(i); - - /* - * set minimal default values - */ - conf.nmach = 2; - conf.nproc = 100; - conf.nswap = 262144; - conf.nimage = 200; - conf.ipif = 8; - conf.ip = 64; - conf.arp = 32; - conf.frag = 32; - - confread(); - - if(conf.nmach > MAXMACH) - panic("confinit"); - - conf.copymode = 1; /* copy on reference */ -} - -/* - * copy arguments passed by the boot kernel (or ROM) into a temporary buffer. - * we do this because the arguments are in memory that may be allocated - * to processes or kernel buffers. - * - * also grab any environment variables that might be useful - */ -struct -{ - char *name; - char *val; -}bootenv[] = { - {"netaddr=", sysname}, - {"console=", consname}, - {"diskless=", diskless}, -}; -char *sp; - -char * -pusharg(char *p) -{ - int n; - - n = strlen(p)+1; - sp -= n; - memmove(sp, p, n); - return sp; -} - -void -arginit(void) -{ - int i, n; - char **av; - - /* - * get boot env variables - */ - if(*sysname == 0) - for(av = _env; *av; av++) - for(i=0; i < sizeof bootenv/sizeof bootenv[0]; i++){ - n = strlen(bootenv[i].name); - if(strncmp(*av, bootenv[i].name, n) == 0){ - strncpy(bootenv[i].val, (*av)+n, NAMELEN); - bootenv[i].val[NAMELEN-1] = '\0'; - break; - } - } - - /* - * pack args into buffer - */ - av = (char**)argbuf; - sp = argbuf + sizeof(argbuf); - for(i = 0; i < _argc; i++){ - if(i && *(_argv[i]) != '-') - diskless[0] = 0; - av[i] = pusharg(_argv[i]); - } - - /* - * if no boot method is specified, look for - * a default in the diskless environment variable - */ - if(diskless[0] > '1') - av[i++] = pusharg(diskless); - av[i] = 0; -} - -/* - * setup the IO2 lance, io buffers are in lance memory - */ -void -lanceIO2setup(Lance *lp) -{ - ushort *sp; - - /* - * reset lance and set parity on its memory - */ - MODEREG->promenet &= ~1; - MODEREG->promenet |= 1; - for(sp = LANCERAM; sp < LANCEEND; sp += 1) - *sp = 0; - - lp->sep = 1; - lp->lanceram = LANCERAM; - lp->lm = (Lancemem*)0; - - /* - * Allocate space in lance memory for the io buffers. - * Start at 4k to avoid the initialization block and - * descriptor rings. - */ - lp->lrp = (Lancepkt*)(4*1024); - lp->ltp = lp->lrp + lp->nrrb; - lp->rp = (Lancepkt*)(((ulong)LANCERAM) + (ulong)lp->lrp); - lp->tp = lp->rp + lp->nrrb; -} - -/* - * setup the IO3 lance, io buffers are in host memory mapped to - * lance address space - */ -void -lanceIO3setup(Lance *lp) -{ - ulong x, y; - int index; - ushort *sp; - int len; - - /* - * reset lance and set parity on its memory - */ - MODEREG->promenet |= 1; - MODEREG->promenet &= ~1; - for(sp = LANCE3RAM; sp < LANCE3END; sp += 2) - *sp = 0; - - lp->sep = 4; - lp->lanceram = LANCE3RAM; - lp->lm = (Lancemem*)0x800000; - - /* - * allocate some host memory for buffers and map it into lance - * space - */ - len = (lp->nrrb + lp->ntrb)*sizeof(Lancepkt); - lp->rp = (Lancepkt*)xspanalloc(len , BY2PG, 0); - lp->tp = lp->rp + lp->nrrb; - x = (ulong)lp->rp; - lp->lrp = (Lancepkt*)(x & 0xFFF); - lp->ltp = lp->lrp + lp->nrrb; - index = LANCEINDEX; - for(y = x+len; x < y; x += 0x1000){ - *WRITEMAP = (index<<16) | (x>>12)&0xFFFF; - index++; - } -} - -/* - * set up the lance - */ -void -lancesetup(Lance *lp) -{ - lp->rap = LANCERAP; - lp->rdp = LANCERDP; - lp->ea[0] = LANCEID[20]>>8; - lp->ea[1] = LANCEID[16]>>8; - lp->ea[2] = LANCEID[12]>>8; - lp->ea[3] = LANCEID[8]>>8; - lp->ea[4] = LANCEID[4]>>8; - lp->ea[5] = LANCEID[0]>>8; - lp->lognrrb = 7; - lp->logntrb = 7; - lp->nrrb = 1<lognrrb; - lp->ntrb = 1<logntrb; - lp->busctl = BSWP; - if(ioid >= IO3R1) - lanceIO3setup(lp); - else - lanceIO2setup(lp); -} - -void -lanceparity(void) -{ - print("lance DRAM parity error\n"); - MODEREG->promenet &= ~4; - MODEREG->promenet |= 4; -} - -/* - * for the sake of a single devcons.c - */ -void -buzz(int f, int d) -{ - USED(f); - USED(d); -} diff --git a/power/mem.h b/power/mem.h deleted file mode 100644 index 88795af90ea8ab89330ebf19adc0ebf0d3138060..0000000000000000000000000000000000000000 --- a/power/mem.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Memory and machine-specific definitions. Used in C and assembler. - */ - -/* - * Sizes - */ - -#define BI2BY 8 /* bits per byte */ -#define BI2WD 32 /* bits per word */ -#define BY2WD 4 /* bytes per word */ -#define BY2V 8 /* bytes per very long word */ -#define BY2PG 4096 /* bytes per page */ -#define WD2PG (BY2PG/BY2WD) /* words per page */ -#define PGSHIFT 12 /* log(BY2PG) */ -#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1)) -#define PGROUND(s) ROUND(s, BY2PG) -#define ICACHESIZE (64*1024) /* Power series */ - -#define MAXMACH 4 /* max # cpus system can run */ - -/* - * Time - */ -#define HZ 20 -#define MS2HZ 50 /* millisec per clock tick */ -#define TK2SEC(t) ((t)/20) /* ticks to seconds */ -#define TK2MS(t) ((t)*MS2HZ) /* ticks to milliseconds */ -#define MS2TK(t) ((t)/MS2HZ) /* milliseconds to ticks */ - -/* - * CP0 registers - */ - -#define INDEX 0 -#define RANDOM 1 -#define TLBPHYS 2 -#define CONTEXT 4 -#define BADVADDR 8 -#define TLBVIRT 10 -#define STATUS 12 -#define CAUSE 13 -#define EPC 14 -#define PRID 15 - -/* - * M(STATUS) bits - */ -#define IE 0x00000001 -#define KUC 0x00000002 -#define IEP 0x00000004 -#define KUP 0x00000008 -#define IEO 0x00000010 -#define KUO 0x00000020 -#define INTMASK 0x0000ff00 -#define SW0 0x00000100 -#define SW1 0x00000200 -#define INTR0 0x00000400 -#define INTR1 0x00000800 -#define INTR2 0x00001000 -#define INTR3 0x00002000 -#define INTR4 0x00004000 -#define INTR5 0x00008000 -#define ISC 0x00010000 -#define SWC 0x00020000 -#define CM 0x00080000 -#define PE 0x00100000 -#define CU1 0x20000000 - -/* - * Traps - */ - -#define UTLBMISS (KSEG0+0x00) -#define EXCEPTION (KSEG0+0x80) - -/* - * Magic registers - */ - -#define MACH 25 /* R25 is m-> */ -#define USER 24 /* R24 is up-> */ -#define MPID 0xBF000000 /* long; low 3 bits mp bus slot */ -#define WBFLUSH 0xBC000000 /* D-CACHE data; write buffer flush */ - -#define UREGSIZE 0xA0 /* Sizeof(Ureg)+space for retpc & ur */ -/* - * Fundamental addresses - */ - -#define MACHADDR 0x80014000 -/* - * MMU - */ - -#define KUSEG 0x00000000 -#define KSEG0 0x80000000 -#define KSEG1 0xA0000000 -#define KSEG2 0xC0000000 -#define KSEGM 0xE0000000 /* mask to check which seg */ - -#define KSTACK 4096 /* Size of kernel stack */ - -#define PTEGLOBL (1<<8) -#define PTEVALID (1<<9) -#define PTEWRITE (1<<10) -#define PTEUNCACHED (1<<11) -#define PTERONLY 0 -#define PTEPID(n) ((n)<<6) -#define TLBPID(n) (((n)>>6)&0x3F) -#define PTEMAPMEM (2*1024*1024) -#define PTEPERTAB (PTEMAPMEM/BY2PG) -#define STLBLOG 13 -#define STLBSIZE (1<newtlb) { - memset(p->pidonmach, 0, sizeof p->pidonmach); - p->newtlb = 0; - } - tp = p->pidonmach[m->machno]; - if(tp == 0) - tp = newtlbpid(p); - - putcontext(tp); -} - -void -mmurelease(Proc *p) -{ - memset(p->pidonmach, 0, sizeof p->pidonmach); -} - -/* - * Process must be non-interruptible - */ -int -newtlbpid(Proc *p) -{ - int i, s; - Proc **h; - - i = m->lastpid; - h = m->pidproc; - for(s = 0; s < NTLBPID; s++) { - i++; - if(i >= NTLBPID) - i = 1; - if(h[i] == 0) - break; - } - - if(h[i]) - purgetlb(i); - if(h[i] != 0) - panic("newtlb"); - - m->pidproc[i] = p; - p->pidonmach[m->machno] = i; - m->lastpid = i; - - return i; -} - -void -putmmu(ulong tlbvirt, ulong tlbphys, Page *pg) -{ - short tp; - char *ctl; - - splhi(); - - ctl = &pg->cachectl[m->machno]; - if(*ctl == PG_TXTFLUSH) { - dcflush((void*)pg->pa, BY2PG); - icflush((void*)pg->pa, BY2PG); - *ctl = PG_NOFLUSH; - } - - tp = up->pidonmach[m->machno]; - if(tp == 0) - tp = newtlbpid(up); - - tlbvirt |= PTEPID(tp); - putstlb(tlbvirt, tlbphys); - puttlb(tlbvirt, tlbphys); - spllo(); -} - -void -purgetlb(int tlbpid) -{ - int i, mno; - Proc *sp, **pidproc; - Softtlb *entry, *etab; - - m->tlbpurge++; - - /* - * find all pid entries that are no longer used by processes - */ - mno = m->machno; - pidproc = m->pidproc; - for(i=1; ipidonmach[mno] != i) - pidproc[i] = 0; - } - - /* - * shoot down the one we want - */ - sp = pidproc[tlbpid]; - if(sp != 0) - sp->pidonmach[mno] = 0; - pidproc[tlbpid] = 0; - - /* - * clean out all dead tlbpids from the stlb; - */ - entry = m->stb; - for(etab = &entry[STLBSIZE]; entry < etab; entry++) - if(pidproc[TLBPID(entry->virt)] == 0) - entry->virt = 0; - - /* - * clean up the hardware - */ - for(i=TLBROFF; inewtlb = 1; - mmuswitch(up); - spllo(); -} - -void -clearmmucache(void) -{ -} - -void -putstlb(ulong tlbvirt, ulong tlbphys) -{ - Softtlb *entry; - - /* This hash function is also coded into utlbmiss in l.s */ - entry = &m->stb[((tlbvirt<<1) ^ (tlbvirt>>12)) & (STLBSIZE-1)]; - entry->phys = tlbphys; - entry->virt = tlbvirt; - if(tlbphys == 0) - entry->virt = 0; -} diff --git a/power/segment.h b/power/segment.h deleted file mode 100644 index ecb7b8b120a8047599bd61600d4f3721346e4e10..0000000000000000000000000000000000000000 --- a/power/segment.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Attach segment types - */ - -#define VME16IO3 0x17C00000 -#define VME32TDFB (0x30000000+128*MB) - -Physseg physseg[] = -{ - { SG_PHYSICAL, "lock", 0, 1024*BY2PG, lkpage, lkpgfree }, - { SG_SHARED, "shared", 0, SEGMAXSIZE, 0, 0 }, - { SG_BSS, "memory", 0, SEGMAXSIZE, 0, 0 }, - { SG_PHYSICAL, "vme16", VME16IO3, 64*1024, 0, 0 }, - { SG_PHYSICAL, "tdsfb", VME32TDFB, 4*MB, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, -}; diff --git a/power/trap.c b/power/trap.c deleted file mode 100644 index 15cc47e47d469ff08a4936658b58e02ffc754a64..0000000000000000000000000000000000000000 --- a/power/trap.c +++ /dev/null @@ -1,715 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "ureg.h" -#include "io.h" -#include "../port/error.h" - -void (*vmevec[256])(int); -void noted(Ureg*, Ureg**, ulong); -void rfnote(Ureg**); - -char *excname[] = -{ - "trap: external interrupt", - "trap: TLB modification", - "trap: TLB miss (load or fetch)", - "trap: TLB miss (store)", - "trap: address error (load or fetch)", - "trap: address error (store)", - "trap: bus error (fetch)", - "trap: bus error (data load or store)", - "trap: system call", - "breakpoint", - "trap: reserved instruction", - "trap: coprocessor unusable", - "trap: arithmetic overflow", - "trap: undefined 13", - "trap: undefined 14", - "trap: undefined 15", /* used as sys call for debugger */ -}; - -char *fpcause[] = -{ - "inexact operation", - "underflow", - "overflow", - "division by zero", - "invalid operation", -}; -char *fpexcname(Ureg*, ulong, char*); -#define FPEXPMASK (0x3f<<12) /* Floating exception bits in fcr31 */ - -char* -regname[]= -{ - "STATUS", "PC", "SP", "CAUSE", - "BADADDR", "TLBVIRT", "HI", "LO", - "R31", "R30", "R28", "R27", - "R26", "R25", "R24", "R23", - "R22", "R21", "R20", "R19", - "R18", "R17", "R16", "R15", - "R14", "R13", "R12", "R11", - "R10", "R9", "R8", "R7", - "R6", "R5", "R4", "R3", - "R2", "R1" -}; - -void -trap(Ureg *ur) -{ - ulong fcr31; - int user, cop, x, fpchk, ecode; - char buf[2*ERRLEN], buf1[ERRLEN], *fpexcep; - - user = ur->status&KUP; - ecode = (ur->cause>>2)&0xf; - - fpchk = 0; - if(user) { - up->dbgreg = ur; - if(up->fpstate == FPactive) { - if((ur->status&CU1) == 0) /* Paranoid */ - panic("FPactive but no CU1"); - up->fpstate = FPinactive; - ur->status &= ~CU1; - savefpregs(&up->fpsave); - fptrap(ur); - fpchk = 1; - } - } - - switch(ecode){ - case CINT: - if(ur->cause&INTR3) { /* FP trap */ - clrfpintr(); - ur->cause &= ~INTR3; - } - intr(ur); - break; - - case CTLBM: - case CTLBL: - case CTLBS: - if(up == 0) - panic("kfault pc %lux addr %lux", ur->pc, ur->badvaddr); - - x = up->insyscall; - up->insyscall = 1; - - spllo(); - faultmips(ur, user, ecode); - up->insyscall = x; - break; - - case CCPU: - cop = (ur->cause>>28)&3; - if(user && cop == 1) { - if(up->fpstate == FPinit) { - up->fpstate = FPinactive; - fcr31 = up->fpsave.fpstatus; - up->fpsave = initfp; - up->fpsave.fpstatus = fcr31; - break; - } - if(up->fpstate == FPinactive) - break; - } - /* Fallthrough */ - - default: - if(user) { - spllo(); - sprint(buf, "sys: %s", excname[ecode]); - postnote(up, 1, buf, NDebug); - break; - } - print("kernel %s pc=%lux\n", excname[ecode], ur->pc); - dumpregs(ur); - dumpstack(); - if(m->machno == 0) - spllo(); - exit(1); - } - - if(fpchk) { - fcr31 = up->fpsave.fpstatus; - if((fcr31>>12) & ((fcr31>>7)|0x20) & 0x3f) { - spllo(); - fpexcep = fpexcname(ur, fcr31, buf1); - sprint(buf, "sys: fp: %s", fpexcep); - postnote(up, 1, buf, NDebug); - } - } - - splhi(); - if(!user) - return; - - notify(ur); - if(up->fpstate == FPinactive) { - restfpregs(&up->fpsave, up->fpsave.fpstatus); - up->fpstate = FPactive; - ur->status |= CU1; - } -} - -void -intr(Ureg *ur) -{ - long v; - int i, any; - ulong cause; - static int bogies; - uchar pend, xxx; - - m->intr++; - cause = ur->cause&(INTR5|INTR4|INTR3|INTR2|INTR1); - - if(cause & INTR1){ - duartintr(); - cause &= ~INTR1; - } - - while(cause & INTR5) { - any = 0; - if(!(*MPBERR1 & (1<<8))){ - print("MP bus error %lux %lux\n", *MPBERR0, *MPBERR1); - print("PC %lux R31 %lux\n", ur->pc, ur->r31); - *MPBERR0 = 0; - i = *SBEADDR; - USED(i); - any = 1; - } - - /* - * directions from IO2 manual - * 1. clear all IO2 masks - */ - *IO2CLRMASK = 0xff000000; - - /* - * 2. wait for interrupt in progress - */ - while(!(*INTPENDREG & (1<<5))) - ; - - /* - * 3. read pending interrupts - */ - pend = SBCCREG->fintpending; - - /* - * 4. clear pending register - */ - i = SBCCREG->flevel; - USED(i); - - /* - * 4a. attempt to fix problem - */ - if(!(*INTPENDREG & (1<<5))) - print("pause again\n"); - while(!(*INTPENDREG & (1<<5))) - ; - xxx = SBCCREG->fintpending; - if(xxx){ - print("new pend %ux\n", xxx); - i = SBCCREG->flevel; - USED(i); - } - - /* - * 5a. process lance, scsi - */ - if(pend & 1) { - v = INTVECREG->i[0].vec; - if(!(v & (1<<12))){ - print("ioberr %lux %lux\n", *MPBERR0, *MPBERR1); - print("PC %lux R31 %lux\n", ur->pc, ur->r31); - *MPBERR0 = 0; - any = 1; - } - if(ioid < IO3R1){ - if(!(v & 7)) - any = 1; - if(!(v & (1<<2))) - lanceintr(); - if(!(v & (1<<1))) - lanceparity(); - if(!(v & (1<<0))) - print("SCSI interrupt\n"); - }else{ - if(v & 7) - any = 1; - if(v & (1<<2)) - lanceintr(); -/* - if(v & (1<<1)) - scsiintr(1); - if(v & (1<<0)) - scsiintr(0); -*/ - } - } - /* - * 5b. process vme - * i can guess your level - */ - for(i=1; pend>>=1; i++){ - if(pend & 1) { - v = INTVECREG->i[i].vec; - if(!(v & (1<<12))){ - print("io2 mp bus error %d %lux %lux\n", - i, *MPBERR0, *MPBERR1); - *MPBERR0 = 0; - } - v &= 0xff; - (*vmevec[v])(v); - any = 1; - } - } - /* - * 6. re-enable interrupts - */ - *IO2SETMASK = 0xff000000; - if(any == 0) - cause &= ~INTR5; - } - - if(cause & (INTR2|INTR4)) { - LEDON(LEDclock); - clock(ur); - LEDOFF(LEDclock); - cause &= ~(INTR2|INTR4); - } - - if(cause) - panic("cause %lux %lux\n", up, cause); -} - -char* -fpexcname(Ureg *ur, ulong fcr31, char *buf) -{ - int i; - char *s; - ulong fppc; - - fppc = ur->pc; - if(ur->cause & (1<<31)) /* branch delay */ - fppc += 4; - s = 0; - if(fcr31 & (1<<17)) - s = "unimplemented operation"; - else{ - fcr31 >>= 7; /* trap enable bits */ - fcr31 &= (fcr31>>5); /* anded with exceptions */ - for(i=0; i<5; i++) - if(fcr31 & (1<kstack + KSTACK; - for(l=(ulong)&l; l < top; l += BY2WD) { - v = *(ulong*)l; - if(KTZERO < v && v < (ulong)&etext) { - print("%lux=%lux\n", l, v); - delay(100); - } - } -} - -void -dumpregs(Ureg *ur) -{ - int i; - ulong *l; - - if(up) - print("registers for %s %d\n", up->text, up->pid); - else - print("registers for kernel\n"); - - l = &ur->status; - for(i=0; iprocctl) - procctl(up); - if(up->nnote == 0) - return 0; - - spllo(); - qlock(&up->debug); - up->notepending = 0; - n = &up->note[0]; - if(strncmp(n->msg, "sys:", 4) == 0) { - l = strlen(n->msg); - if(l > ERRLEN-15) /* " pc=0x12345678\0" */ - l = ERRLEN-15; - - sprint(n->msg+l, " pc=0x%lux", ur->pc); - } - - if(n->flag != NUser && (up->notified || up->notify==0)) { - if(n->flag == NDebug) - pprint("suicide: %s\n", n->msg); - - qunlock(&up->debug); - pexit(n->msg, n->flag!=NDebug); - } - - if(up->notified) { - qunlock(&up->debug); - splhi(); - return 0; - } - - if(!up->notify) { - qunlock(&up->debug); - pexit(n->msg, n->flag!=NDebug); - } - sp = ur->usp - sizeof(Ureg); - - if(sp&(BY2WD-1) || !okaddr((ulong)up->notify, BY2WD, 0) - || !okaddr(sp-ERRLEN-4*BY2WD, sizeof(Ureg)+ERRLEN+4*BY2WD, 1)) { - pprint("suicide: bad address or sp in notify\n"); - qunlock(&up->debug); - pexit("Suicide", 0); - } - - memmove((Ureg*)sp, ur, sizeof(Ureg)); - *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */ - up->ureg = (void*)sp; - sp -= BY2WD+ERRLEN; - memmove((char*)sp, up->note[0].msg, ERRLEN); - sp -= 3*BY2WD; - *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */ - ur->r1 = (ulong)up->ureg; /* arg 1 is ureg* */ - *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;/* arg 1 0(FP) is ureg* (for Alef) */ - *(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */ - ur->usp = sp; - ur->pc = (ulong)up->notify; - up->notified = 1; - up->nnote--; - memmove(&up->lastnote, &up->note[0], sizeof(Note)); - memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); - - qunlock(&up->debug); - splhi(); - return 1; -} - -/* - * Check that status is OK to return from note. - */ -int -validstatus(ulong kstatus, ulong ustatus) -{ - if((kstatus & INTMASK) != (ustatus & INTMASK)) - return 0; - if((ustatus&(KUO|IEO|KUP|IEP|KUC|IE)) != (KUP|IEP)) - return 0; - if(ustatus & (0xFFFF0000&~(CU1|CM|PE))) /* no CU3, CU2, CU0, BEV, TS, PZ, SWC, ISC */ - return 0; - return 1; -} - -/* - * Return user to state before notify() - */ -void -noted(Ureg *kur, Ureg **urp, ulong arg0) -{ - Ureg *nur; - ulong oureg, sp; - - qlock(&up->debug); - if(arg0!=NRSTR && !up->notified) { - qunlock(&up->debug); - pprint("call to noted() when not notified\n"); - pexit("Suicide", 0); - } - up->notified = 0; - - nur = up->ureg; - - oureg = (ulong)nur; - if((oureg & (BY2WD-1)) - || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){ - pprint("bad ureg in noted or call to noted() when not notified\n"); - qunlock(&up->debug); - pexit("Suicide", 0); - } - - if(!validstatus(kur->status, nur->status)) { - qunlock(&up->debug); - pprint("bad noted ureg status %lux\n", nur->status); - pexit("Suicide", 0); - } - - memmove(*urp, up->ureg, sizeof(Ureg)); - switch(arg0) { - case NCONT: - case NRSTR: - if(!okaddr(nur->pc, 1, 0) || !okaddr(nur->usp, BY2WD, 0)){ - pprint("suicide: trap in noted\n"); - qunlock(&up->debug); - pexit("Suicide", 0); - } - splhi(); - qunlock(&up->debug); - rfnote(urp); - break; - - case NSAVE: - if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){ - pprint("suicide: trap in noted\n"); - qunlock(&up->debug); - pexit("Suicide", 0); - } - qunlock(&up->debug); - sp = oureg-4*BY2WD-ERRLEN; - splhi(); - (*urp)->sp = sp; - ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */ - ((ulong*)sp)[0] = 0; /* arg 0 is pc */ - (*urp)->r1 = oureg; /* arg 1 is ureg* */ - rfnote(urp); - break; - - default: - pprint("unknown noted arg 0x%lux\n", arg0); - up->lastnote.flag = NDebug; - /* fall through */ - - case NDFLT: - if(up->lastnote.flag == NDebug) - pprint("suicide: %s\n", up->lastnote.msg); - qunlock(&up->debug); - pexit(up->lastnote.msg, up->lastnote.flag != NDebug); - } -} - - -#include "../port/systab.h" - -long -syscall(Ureg *aur) -{ - long ret; - ulong sp; - Ureg *ur; - - m->syscall++; - up->insyscall = 1; - ur = aur; - up->pc = ur->pc; - up->dbgreg = aur; - ur->cause = 15<<2; /* for debugging: system call is undef 15; */ - - if(up->fpstate == FPactive) { - if((ur->status&CU1) == 0) - panic("syscall: FPactive but no CU1"); - up->fpsave.fpstatus = fcr31(); - up->fpstate = FPinit; - ur->status &= ~CU1; - } - - spllo(); - - if(up->procctl) - procctl(up); - - up->scallnr = ur->r1; - up->nerrlab = 0; - sp = ur->sp; - ret = -1; - if(!waserror()){ - if(up->scallnr >= nsyscall) { - pprint("bad sys call number %d pc %lux\n", - up->scallnr, ur->pc); - postnote(up, 1, "sys: bad sys call", NDebug); - error(Ebadarg); - } - - if(sp & (BY2WD-1)){ - pprint("odd sp in sys call pc %lux sp %lux\n", ur->pc, ur->sp); - postnote(up, 1, "sys: odd stack", NDebug); - error(Ebadarg); - } - - if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs))) - validaddr(sp, sizeof(Sargs), 0); - - up->s = *((Sargs*)(sp+BY2WD)); - up->psstate = sysctab[up->scallnr]; - - ret = (*systab[up->scallnr])(up->s.args); - poperror(); - } - ur->pc += 4; - up->nerrlab = 0; - up->psstate = 0; - up->insyscall = 0; - if(up->scallnr == NOTED) /* ugly hack */ - noted(ur, &aur, *(ulong*)(sp+BY2WD)); /* doesn't return */ - - splhi(); - if(up->scallnr!=RFORK && (up->procctl || up->nnote)){ - ur->r1 = ret; /* load up for noted() */ - if(notify(ur)) - return ur->r1; - } - - return ret; -} - -void -forkchild(Proc *p, Ureg *ur) -{ - Ureg *cur; - - p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD); - p->sched.pc = (ulong)forkret; - - cur = (Ureg*)(p->sched.sp+2*BY2WD); - memmove(cur, ur, sizeof(Ureg)); - - cur->pc += 4; - - /* Things from bottom of syscall we never got to execute */ - p->psstate = 0; - p->insyscall = 0; -} - -static -void -linkproc(void) -{ - spllo(); - (*up->kpfun)(up->kparg); -} - -void -kprocchild(Proc *p, void (*func)(void*), void *arg) -{ - p->sched.pc = (ulong)linkproc; - p->sched.sp = (ulong)p->kstack+KSTACK; - - p->kpfun = func; - p->kparg = arg; -} - -long -execregs(ulong entry, ulong ssize, ulong nargs) -{ - Ureg *ur; - ulong *sp; - - sp = (ulong*)(USTKTOP - ssize); - *--sp = nargs; - - ur = (Ureg*)up->dbgreg; - ur->usp = (ulong)sp; - ur->pc = entry - 4; /* syscall advances it */ - up->fpsave.fpstatus = initfp.fpstatus; - return USTKTOP-BY2WD; /* address of user-level clock */ -} - -ulong -userpc(void) -{ - Ureg *ur; - - ur = (Ureg*)up->dbgreg; - return ur->pc; -} - -void -novme(int v) -{ - static count = 0; - - print("vme intr 0x%.2x\n", v); - count++; - if(count >= 10) - panic("too many vme intr"); -} - -void -setvmevec(int v, void (*f)(int)) -{ - void (*g)(int); - - v &= 0xff; - g = vmevec[v]; - if(g && g != novme && g != f) - print("second setvmevec to 0x%.2x\n", v); - vmevec[v] = f; -} - -/* This routine must save the values of registers the user is not permitted to - * write from devproc and then restore the saved values before returning - */ -void -setregisters(Ureg *xp, char *pureg, char *uva, int n) -{ - ulong status; - - status = xp->status; - memmove(pureg, uva, n); - xp->status = status; -} - -/* Give enough context in the ureg to produce a kernel stack for - * a sleeping process - */ -void -setkernur(Ureg *xp, Proc *p) -{ - xp->pc = p->sched.pc; - xp->sp = p->sched.sp; - xp->r31 = (ulong)sched; -} - -ulong -dbgpc(Proc *p) -{ - Ureg *ur; - - ur = p->dbgreg; - if(ur == 0) - return 0; - - return ur->pc; -} diff --git a/power/u.h b/power/u.h deleted file mode 100644 index c0a5e940ad543777333dbcfdd4bdab65796fff60..0000000000000000000000000000000000000000 --- a/power/u.h +++ /dev/null @@ -1,25 +0,0 @@ -#define nil ((void*)0) -typedef unsigned short ushort; -typedef unsigned char uchar; -typedef signed char schar; -typedef unsigned long ulong; -typedef long vlong; -typedef union Length Length; -typedef ushort Rune; - -union Length -{ - char clength[8]; - vlong vlength; - struct{ - long hlength; - long length; - }; -}; - -typedef char *va_list; - -#define va_start(list, start) list = (char *)(&(start)+1) -#define va_end(list) -#define va_arg(list, mode) (sizeof(mode)==1 ? ((mode *) (list += 4))[-4] : \ -sizeof(mode)==2 ? ((mode *) (list += 4))[-2] : ((mode *) (list += sizeof(mode)))[-1])