From f9d03d2c24597487794512a96aabe3c77c2ad539 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 8 May 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-05-08 --- mpc/devether.c | 5 +- mpc/etherscc.c | 162 ++++++++++++++++++++++++++++------------------- mpc/main.c | 76 +++++++++++++++++++++- mpc/trap.c | 168 +++++++++++++++++++++++++++++++++++++++++++++---- port/cache.c | 70 ++++++++++++++++++--- port/tod.c | 132 ++++++++------------------------------ 6 files changed, 420 insertions(+), 193 deletions(-) diff --git a/mpc/devether.c b/mpc/devether.c index 843ad35e14b9aa326daa5336ecc862c079d17ad0..09e5bd649e1b7bcc720e18560c4cd41d29260451 100644 --- a/mpc/devether.c +++ b/mpc/devether.c @@ -304,7 +304,7 @@ void addethercard(char* t, int (*r)(Ether*)) { static int ncard; - +print("addethercard\n"); if(ncard == MaxEther) panic("too many ether cards"); cards[ncard].type = t; @@ -342,6 +342,7 @@ etherreset(void) int i, n, ctlrno; char name[NAMELEN], buf[128]; +print("etherreset\n"); //ethermediumlink(); for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ if(ether == 0) @@ -352,7 +353,9 @@ etherreset(void) ether->mbps = 10; if(isaconfig("ether", ctlrno, ether) == 0) continue; +print("after isaconfig %d\n", n); for(n = 0; cards[n].type; n++){ +print("card %d\n", n); if(cistrcmp(cards[n].type, ether->type)) continue; for(i = 0; i < ether->nopt; i++){ diff --git a/mpc/etherscc.c b/mpc/etherscc.c index 7343c38e619bdc7907ea5378c3d500083740050b..860e16baae7c6d6a559a8843a9530523a0766357 100644 --- a/mpc/etherscc.c +++ b/mpc/etherscc.c @@ -132,7 +132,6 @@ attach(Ether *ether) ctlr->active = 1; ctlr->scc->gsmrl |= ENR|ENT; eieio(); -// m->bcsr[1] &= ~DisableEther; } static void @@ -395,95 +394,132 @@ sccsetup(Ctlr *ctlr, SCC *scc, uchar *ea) Etherparam *p; IMM *io; - io = ioplock(); - if(ctlr->port == 2){ - io->papar |= SIBIT(12)|SIBIT(13); /* enable TXD2 and RXD2 pins */ - io->padir &= ~(SIBIT(12)|SIBIT(13)); - io->paodr &= ~SIBIT(12); - - io->pcpar &= ~(SIBIT(9)|SIBIT(8)); /* enable CLSN (CTS2) and RENA (CD2) */ - io->pcdir &= ~(SIBIT(9)|SIBIT(8)); - io->pcso |= SIBIT(9)|SIBIT(8); +print("sccsetup\n"); - io->papar |= SIBIT(6)|SIBIT(5); /* enable CLK2 and CLK3 */ - io->padir &= ~(SIBIT(6)|SIBIT(5)); - eieio(); + io = ioplock(); + p = (Etherparam*)KADDR(SCC1P); + + if(ctlr->port != 1) + panic("only do SCC1 at the momment"); + + // step 1: enable TXD RXD ports + io->papar |= SIBIT(14)|SIBIT(15); + io->padir &= ~(SIBIT(14)|SIBIT(15)); + io->paodr &= ~SIBIT(14); + + // step 2: enable CLSN and RENA ports + io->pcpar &= ~(SIBIT(11)|SIBIT(10)); + io->pcdir &= ~(SIBIT(11)|SIBIT(10)); + io->pcso |= SIBIT(11)|SIBIT(10); + eieio(); - rcs = CLK2; - tcs = CLK3; - }else{ - io->papar |= SIBIT(14)|SIBIT(15); /* enable TXD1 and RXD1 pins */ - io->padir &= ~(SIBIT(14)|SIBIT(15)); - io->paodr &= ~SIBIT(14); + // setp 3 + io->pcpar &= ~SIBIT(15); /* disble TENA pin */ - io->pcpar &= ~(SIBIT(10)|SIBIT(11)); /* enable CLSN (CTS1) and RENA (CD1) */ - io->pcdir &= ~(SIBIT(10)|SIBIT(11)); - io->pcso |= SIBIT(10)|SIBIT(11); - eieio(); + // step 4: enable clocks + io->papar |= SIBIT(6)|SIBIT(4); /* enable CLK2 and CLK4 */ + io->padir &= ~(SIBIT(6)|SIBIT(4)); + eieio(); - io->papar |= SIBIT(6)|SIBIT(7); /* enable CLK2 and CLK1 */ - io->padir &= ~(SIBIT(6)|SIBIT(7)); - eieio(); + // step 5/6: route clocks + io->sicr = (7<<3) | (5); + eieio(); - io->pcpar &= ~(SIBIT(4)|SIBIT(5)|SIBIT(6)); /* ETHLOOP, TPFULDL~, TPSQEL~ */ - io->pcdir |= SIBIT(4)|SIBIT(5)|SIBIT(6); - io->pcdat &= ~SIBIT(4); - io->pcdat |= SIBIT(5)|SIBIT(6); - eieio(); + // step 7: set dma priority + io->sdcr = 1; - rcs = CLK2; - tcs = CLK1; - } iopunlock(); - sccnmsi(ctlr->port, rcs, tcs); /* connect the clocks */ +// sccnmsi(ctlr->port, rcs, tcs); /* connect the clocks */ - p = (Etherparam*)KADDR(ctlr->sccid==SCC1ID? SCC1P: SCC2P); - memset(p, 0, sizeof(*p)); - p->rfcr = 0x18; - p->tfcr = 0x18; - p->mrblr = Bufsize; + // step 8: p->rbase = PADDR(ctlr->rdr); p->tbase = PADDR(ctlr->tdr); - cpmop(InitRxTx, ctlr->sccid, 0); + // step 9: + cpmop(InitRxTx, SCC1ID, 0); + + // step 10 + p->rfcr = 0x18; // manuals say 0x10 + p->tfcr = 0x18; + + // step 11 + p->mrblr = Bufsize; + // step 12: p->c_pres = ~0; + + // step 13: p->c_mask = 0xDEBB20E3; + + // step 14: p->crcec = 0; p->alec = 0; p->disfc = 0; + + // step 15: p->pads = 0x8888; + + // step 16: p->ret_lim = 0xF; + + // step 17: p->mflr = Rbsize; + + // step 18: p->minflr = ETHERMINTU+4; - p->maxd1 = Bufsize; - p->maxd2 = Bufsize; - p->p_per = 0; /* only moderate aggression */ + // step 19: + p->maxd1 = Bufsize; /* was 0x5F0 */ + p->maxd2 = Bufsize; /* was 0x5F0 */ + + // step 20: + memset(p->gaddr, 0, sizeof(p->gaddr)); + + // step 21: for(i=0; ipaddr[2-i/2] = (ea[i+1]<<8)|ea[i]; /* it's not the obvious byte order */ + p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i]; - scc->psmr = (2<<10)|(5<<1); /* 32-bit CRC, ignore 22 bits before SFD */ - scc->dsr = 0xd555; - scc->gsmrh = 0; /* normal operation */ - scc->gsmrl = (1<<28)|(4<<21)|(1<<19)|0xC; /* transmit clock invert, 48 bit preamble, repetitive 10 preamble, ethernet */ - eieio(); + // step 22 + p->p_per = 0; /* only moderate aggression */ + + // step 23: + memset(p->iaddr, 0, sizeof(p->iaddr)); + + // step 24: + memset(p->taddr, 0, sizeof(p->taddr)); + + // step 25: + + // step 26: + + // step 27: scc->scce = ~0; /* clear all events */ - eieio(); + + // step 28: scc->sccm = TXE | RXF | TXB; /* enable interrupts */ - eieio(); + p->p_per = 0; /* only moderate aggression */ - if(ctlr->sccid == SCC2ID){ - io->pbpar |= IBIT(18); /* enable TENA pin (RTS2) */ - io->pbdir |= IBIT(18); - }else{ - io->pbpar |= IBIT(19); /* enable TENA pin (RTS1) */ - io->pbdir |= IBIT(19); - } - eieio(); + // step 29: + // set by setvec + + // step 30: + scc->gsmrh = 0; /* normal operation */ + + // step 31: + scc->gsmrl = 0x1088000c; + + // step 32: + scc->dsr = 0xd555; + + // step 33: + scc->psmr = 0x080A; /* 32-bit CRC, non-promiscuous */ + + // step 34 + io->pcpar |= SIBIT(15); /* enable TENA pin (RTS2) */ + io->pcdir &= ~SIBIT(15); - /* enable is deferred until attach */ + // step 35: done at attach time } static int @@ -499,7 +535,7 @@ reset(Ether* ether) } if(!(ether->port >= 1 && ether->port <= 4)){ - print("%s ether: no SCC port %d\n", ether->type, ether->port); + print("%s ether: no SCC port %ld\n", ether->type, ether->port); return -1; } @@ -548,5 +584,5 @@ void etherscclink(void) { addethercard("SCC", reset); - addethercard("SCC2", reset); +// addethercard("SCC2", reset); } diff --git a/mpc/main.c b/mpc/main.c index 1e4cdb5a998e4e50212751c54d152ed6345c0331..2229c5476f79474d0898fc137ee7633c96568839 100644 --- a/mpc/main.c +++ b/mpc/main.c @@ -7,7 +7,7 @@ #include "init.h" #include "pool.h" -#define MAXCONF 1000 +#define MAXCONF 32 char *confname[MAXCONF]; char *confval[MAXCONF]; @@ -17,6 +17,8 @@ int predawn = 1; Conf conf; +static void options(void); + void main(void) { @@ -40,9 +42,11 @@ if(0) { pageinit(); procinit0(); initseg(); + options(); links(); chandevreset(); swapinit(); +print("usrinit\n"); userinit(); predawn = 0; schedinit(); @@ -71,7 +75,7 @@ machinit(void) void bootargs(ulong base) { -print("bootargs = %ux\n", base); +print("bootargs = %ulx\n", base); USED(base); } @@ -269,6 +273,74 @@ confinit(void) conf.copymode = 0; /* copy on write */ } +static int +getcfields(char* lp, char** fields, int n, char* sep) +{ + int i; + + for(i = 0; lp && *lp && i < n; i++){ + while(*lp && strchr(sep, *lp) != 0) + *lp++ = 0; + if(*lp == 0) + break; + fields[i] = lp; + while(*lp && strchr(sep, *lp) == 0){ + if(*lp == '\\' && *(lp+1) == '\n') + *lp++ = ' '; + lp++; + } + } + + return i; +} + +static char BOOTARGS[] = + "ether0=type=SCC port=1 ea=08003e27df94\r\n" + "vgasize=640x480x8\r\n" + "kernelpercent=40\r\n" + "console=0 lcd\r\nbaud=9600\r\n"; + +static void +options(void) +{ + long i, n; + char *cp, *p, *q; + char *line[MAXCONF]; + + /* + * parse configuration args from dos file plan9.ini + */ + cp = BOOTARGS; /* where b.com leaves its config */ + + /* + * Strip out '\r', change '\t' -> ' '. + */ + p = cp; + for(q = cp; *q; q++){ + if(*q == '\r') + continue; + if(*q == '\t') + *q = ' '; + *p++ = *q; + } + *p = 0; + + n = getcfields(cp, line, MAXCONF, "\n"); + for(i = 0; i < n; i++){ + if(*line[i] == '#') + continue; + cp = strchr(line[i], '='); + if(cp == 0) + continue; + *cp++ = 0; + if(cp - line[i] >= NAMELEN+1) + *(line[i]+NAMELEN-1) = 0; + confname[nconf] = line[i]; + confval[nconf] = cp; + nconf++; + } +} + int isaconfig(char *class, int ctlrno, ISAConf *isa) { diff --git a/mpc/trap.c b/mpc/trap.c index 8b1c26073c143b8ebb097f40f3ada90a633439c2..7d2838922283b0a50d961a67b17a68e4337e4967 100644 --- a/mpc/trap.c +++ b/mpc/trap.c @@ -34,6 +34,7 @@ struct void faultpower(Ureg *ur, ulong addr, int read); void kernfault(Ureg*, int); void syscall(Ureg* ureg); +void noted(Ureg*, ulong); char *excname[] = { @@ -373,7 +374,7 @@ intrstats(char *buf, int bsize) n = 0; for(i=0; inintr) - n += snprint(buf+n, bsize-n, "%3d %lud %lud %lud\n", i, h->nintr, h->ticks, h->maxtick); + n += snprint(buf+n, bsize-n, "%3d %ud %uld %ud\n", i, h->nintr, h->ticks, h->maxtick); return n; } @@ -442,7 +443,7 @@ dumpregs(Ureg *ur) int i; ulong *l; if(up) { - print("registers for %s %d\n", up->text, up->pid); + print("registers for %s %ld\n", up->text, up->pid); if(ur->srr1 & MSR_PR == 0) if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK) print("invalid stack ptr\n"); @@ -459,7 +460,7 @@ dumpregs(Ureg *ur) static void linkproc(void) { -print("linkproc %ux\n", up); +print("linkproc %ulx\n", up); spllo(); (*up->kpfun)(up->kparg); pexit("", 0); @@ -653,12 +654,157 @@ syscall(Ureg* ureg) * the results register by caller of syscall. */ ureg->r3 = ret; -//print("ret = %d\n", ret); -// if(scallnr == NOTED) -// noted(ureg, *(ulong*)(sp+BY2WD)); - -// if(scallnr!=RFORK && (up->procctl || up->nnote)){ -// splhi(); -// notify(ureg); -// } + + if(scallnr == NOTED) + noted(ureg, *(ulong*)(sp+BY2WD)); + + if(scallnr!=RFORK && (up->procctl || up->nnote)){ + splhi(); + notify(ureg); + } +} +/* + * Call user, if necessary, with note. + * Pass user the Ureg struct and the note on his stack. + */ +int +notify(Ureg* ur) +{ + int l; + ulong s, sp; + Note *n; + + if(up->procctl) + procctl(up); + if(up->nnote == 0) + return 0; + + s = 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%.8lux", 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 & ~(BY2V-1); + sp -= sizeof(Ureg); + + if(!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 = (long)up->ureg; /* arg 1 is ureg* */ + ((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */ + ((ulong*)sp)[0] = 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); + splx(s); + return 1; +} + + +/* + * Return user to state before notify() + */ +void +noted(Ureg* ureg, ulong arg0) +{ + Ureg *nureg; + 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; + + nureg = up->ureg; /* pointer to user returned Ureg struct */ + + /* sanity clause */ + 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); + pexit("Suicide", 0); + } + + memmove(ureg, nureg, sizeof(Ureg)); + + switch(arg0){ + case NCONT: + case NRSTR: + if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){ + pprint("suicide: trap in noted\n"); + qunlock(&up->debug); + pexit("Suicide", 0); + } + up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD)); + qunlock(&up->debug); + break; + + case NSAVE: + if(!okaddr(nureg->pc, BY2WD, 0) + || !okaddr(nureg->usp, BY2WD, 0)){ + pprint("suicide: trap in noted\n"); + qunlock(&up->debug); + pexit("Suicide", 0); + } + qunlock(&up->debug); + sp = oureg-4*BY2WD-ERRLEN; + splhi(); + ureg->sp = sp; + ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */ + ((ulong*)sp)[0] = 0; /* arg 0 is pc */ + 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); + } } diff --git a/port/cache.c b/port/cache.c index 3cd0894689135dac915137c0a0144a3c31dd92a1..8084a3b8c9ab1861ff6cca775a6c0bc0431615f4 100644 --- a/port/cache.c +++ b/port/cache.c @@ -5,13 +5,12 @@ #include "fns.h" #include "../port/error.h" -Image fscache; - enum { NHASH = 128, MAXCACHE = 1024*1024, NFILE = 4096, + NEXTENT = 200, /* extent allocation size */ }; typedef struct Extent Extent; @@ -46,7 +45,60 @@ struct Cache Mntcache *tail; Mntcache *hash[NHASH]; }; -Cache cache; + +typedef struct Ecache Ecache; +struct Ecache +{ + Lock; + int total; + int free; + Extent* head; +}; + +static Image fscache; +static Cache cache; +static Ecache ecache; + +static void +extentfree(Extent* e) +{ + lock(&ecache); + e->next = ecache.head; + ecache.head = e; + ecache.free++; + unlock(&ecache); +} + +static Extent* +extentalloc(void) +{ + Extent *e; + int i; + + lock(&ecache); + if(ecache.head == nil){ + e = xalloc(NEXTENT*sizeof(Extent)); + if(e == nil){ + unlock(&ecache); + return nil; + } + for(i = 0; i < NEXTENT; i++){ + e->next = ecache.head; + ecache.head = e; + e++; + } + ecache.free += NEXTENT; + ecache.total += NEXTENT; + } + + e = ecache.head; + ecache.head = e->next; + memset(e, 0, sizeof(Extent)); + ecache.free--; + unlock(&ecache); + + return e; +} void cinit(void) @@ -120,7 +172,7 @@ cnodata(Mntcache *m) */ for(e = m->list; e; e = n) { n = e->next; - free(e); + extentfree(e); } m->list = 0; } @@ -210,7 +262,7 @@ copen(Chan *c) while(e) { next = e->next; - free(e); + extentfree(e); e = next; } qunlock(m); @@ -271,7 +323,7 @@ cread(Chan *c, uchar *buf, int len, vlong off) p = cpage(e); if(p == 0) { *t = e->next; - free(e); + extentfree(e); qunlock(m); return total; } @@ -322,13 +374,13 @@ cchain(uchar *buf, ulong offset, int len, Extent **tail) *tail = 0; t = &start; while(len) { - e = malloc(sizeof(Extent)); + e = extentalloc(); if(e == 0) break; p = auxpage(); if(p == 0) { - free(e); + extentfree(e); break; } l = len; @@ -583,7 +635,7 @@ cwrite(Chan* c, uchar *buf, int len, vlong off) /* free the overlap - its a rare case */ while(f && f->start < eblock) { e = f->next; - free(f); + extentfree(f); f = e; } diff --git a/port/tod.c b/port/tod.c index 70cff3c500c5c356977778b3e5e9ec6f87c6f3f4..2690e4e60253cd53736e38b57ae8e0d7572dc613 100644 --- a/port/tod.c +++ b/port/tod.c @@ -9,89 +9,24 @@ // on the system. converting the time to nanoseconds requires // the following formula // -// t = (((1000000000<>s2))>>(s1-s2) +// t = (((1000000000<<31)/f)*ticks)>>31 // // where // // 'f' is the clock frequency // 'ticks' are clock ticks -// 's1' and 's2' are shift ammounts to avoid 64 bit -// overflows in the calculations // // to avoid too much calculation in gettod(), we calculate // -// mult = (1000000000<>s2)) <= 63 -// or log2(mult) + 6 + log2(f) - s2 <= 63 -// or log2(mult) + log2(f) - 57 <= s2 -// -// by definition -// -// 3) log2(mult) = log2(1000000000) + s1 - log2(f) -// or log2(mult) = 30 + s1 - log2(f) -// -// To balance the accuracy of the multiplier and the sampled -// ticks we set -// -// 4) log2(mult) = log2(f>>s2) -// or log2(mult) = log2(f) - s2 -// -// Combining 2) and 4) we get -// -// 5) log2(f) - s2 + log2(f) - 57 <= s2 -// or 2*log2(f) - 57 <= 2*s2 -// or log2(f) - 28 <= s2 -// -// Combining 3) and 4) -// -// 6) 30 + s1 - log2(f) = log2(f) - s2 -// or s1 = 2*log2(f) - s2 - 30 -// -// Since shifting ticks left doesn't increase accuracy, and -// shifting 1000000000 right loses accuracy -// -// 7) s2 >= 0 -// 8) s1 >= 0 -// -// As an example, that gives us the following -// -// for f = 100, log2(f) = 7 -// -// s2 = 0 -// s1 = 0 -// -// for f = 267000000, log2(f) = 28 -// -// s2 = 0 -// s1 = 26 -// -// for f = 2000000000, log2(f) = 31 -// -// s2 = 3 -// s1 = 29 -// -// for f = 8000000000, log2(f) = 33 -// -// s2 = 5 -// s1 = 31 + // frequency of the tod clock #define TODFREQ 1000000000LL -static vlong logtab[40]; - struct { Lock; int s1; // time = ((ticks>>s2)*multiplier)>>(s1-s2) @@ -106,56 +41,38 @@ struct { ulong send; // ... } tod; -int -log2(vlong x) -{ - int i; - - for(i = 0; i < nelem(logtab); i++){ - if(x < logtab[i]) - break; - } - return i+8; -} - void todinit(void) { - vlong v; - int i; - - v = 1LL<<8; - for(i = 0; i < nelem(logtab); i++){ - logtab[i] = v; - v <<= 1; - } fastticks((uvlong*)&tod.hz); todsetfreq(tod.hz); addclock0link(todfix); } // -// This routine makes sure that the multiplier has -// at least Log2mult bits to guarantee that precision. +// calculate multiplier // void todsetfreq(vlong f) { int lf; - // this ensures that the multiplier has 22 bits + // the shift is an attempt to maintain precision + // during the caculations. the number of bits in + // the multiplier should be log(TODFREQ) + 31 - log(f). + // + // Freq bits + // 167 MHZ 34 + // 267 MHZ 33 + // 500 MHZ 32 + // + // in all cases, we need to call todget() at least once + // a second to keep the subsequent calculations from + // overflowing. + ilock(&tod); tod.hz = f; - lf = log2(f); - tod.s2 = lf - 28; - if(tod.s2 < 0) - tod.s2 = 0; - tod.s1 = 2*lf - tod.s2 - 30; - if(tod.s1 < 0) - tod.s1 = 0; - if(tod.s1 > 32) - tod.s1 = 32; - tod.multiplier = (TODFREQ<>tod.s2)*tod.multiplier)>>(tod.s1-tod.s2); + // convert to epoch, make sure calculation is unsigned + x = (((uvlong)diff) * ((uvlong)tod.multiplier)) >> 31; x += tod.off; // protect against overflows (gettod is called at least once a second) tod.last = ticks; tod.off = x; - /* time can't go backwards */ + // time can't go backwards if(x < tod.lasttime) x = tod.lasttime; tod.lasttime = x; @@ -236,8 +154,8 @@ todget(void) void todfix(void) { - // once a minute, make sure we don't overflow - if((MACHP(0)->ticks % (60*HZ)) == 0) + // once a second, make sure we don't overflow + if((MACHP(0)->ticks % HZ) == 0) todget(); }