M ip/devip.c => ip/devip.c +1 -1
@@ 520,7 520,7 @@ ipread(Chan *ch, void *a, long n, vlong off)
Conv *c;
Proto *x;
char *buf, *p;
- long m, rv;
+ long rv;
Fs *f;
ulong offset = off;
M pc/archgeneric.c => pc/archgeneric.c +38 -0
@@ 17,6 17,8 @@ nop(void)
}
void (*coherence)(void) = nop;
+void cycletimerinit(void);
+uvlong cycletimer(uvlong*);
PCArch* arch;
extern PCArch* knownarch[];
@@ 32,6 34,8 @@ PCArch archgeneric = {
i8259enable, /* intrenable */
i8253enable, /* clockenable */
+
+ i8253read, /* read the standard timer */
};
typedef struct {
@@ 185,6 189,12 @@ archinit(void)
arch->intrenable = archgeneric.intrenable;
}
+ /* pick the better timer */
+ if(X86FAMILY(m->cpuidax) >= 5){
+ cycletimerinit();
+ arch->fastclock = cycletimer;
+ }
+
/*
* Decide whether to use copy-on-reference (386 and mp).
*/
@@ 194,3 204,31 @@ archinit(void)
if(X86FAMILY(m->cpuidax) == 6 /*&& conf.nmach > 1*/)
coherence = wbflush;
}
+
+static uvlong fasthz;
+
+void
+cycletimerinit(void)
+{
+ fasthz = 1000000LL*m->cpumhz;
+}
+
+/*
+ * return the most precice clock we have
+ */
+uvlong
+cycletimer(uvlong *hz)
+{
+ uvlong tsc;
+
+ rdmsr(0x10, (vlong*)&tsc);
+ if(hz != nil)
+ *hz = fasthz;
+ return tsc;
+}
+
+uvlong
+fastticks(uvlong *hz)
+{
+ return (*arch->fastclock)(hz);
+}
M pc/clock.c => pc/clock.c +1 -0
@@ 88,3 88,4 @@ microdelay(int microsecs)
microsecs = 1;
aamloop(microsecs);
}
+
M pc/dat.h => pc/dat.h +1 -0
@@ 221,6 221,7 @@ struct PCArch
int (*intrenable)(int, int, Irqctl*);
void (*clockenable)(void);
+ uvlong (*fastclock)(uvlong*);
};
/*
M pc/fns.h => pc/fns.h +1 -0
@@ 36,6 36,7 @@ void i8042auxenable(void (*)(int, int));
void i8042reset(void);
void i8253init(int);
void i8253enable(void);
+uvlong i8253read(uvlong*);
void i8259init(void);
int i8259enable(int, int, Irqctl*);
void idle(void);
M pc/i8253.c => pc/i8253.c +14 -0
@@ 98,3 98,17 @@ i8253enable(void)
{
intrenable(VectorCLOCK, clockintr, 0, BUSUNKNOWN);
}
+
+Lock i8253lock;
+
+/*
+ * return time elapsed since clock start in
+ * 10ths of nanoseconds
+ */
+uvlong
+i8253read(uvlong *hz)
+{
+ if(hz)
+ *hz = HZ;
+ return m->ticks;
+}
M port/devcons.c => port/devcons.c +31 -0
@@ 345,6 345,7 @@ enum{
Qconsctl,
Qcputime,
Qdrivers,
+ Qfastclock,
Qhz,
Qkey,
Qhostdomain,
@@ 373,6 374,7 @@ static Dirtab consdir[]={
"consctl", {Qconsctl}, 0, 0220,
"cputime", {Qcputime}, 6*NUMSIZE, 0444,
"drivers", {Qdrivers}, 0, 0644,
+ "fastclock", {Qfastclock}, 4*NUMSIZE, 0444,
"hostdomain", {Qhostdomain}, DOMLEN, 0664,
"hostowner", {Qhostowner}, NAMELEN, 0664,
"hz", {Qhz}, NUMSIZE, 0666,
@@ 401,6 403,21 @@ seconds(void)
}
int
+readvlnum(ulong off, char *buf, ulong n, uvlong val, int size)
+{
+ char tmp[64];
+
+ snprint(tmp, sizeof(tmp), "%*.0ulld", size-1, val);
+ tmp[size-1] = ' ';
+ if(off >= size)
+ return 0;
+ if(off+n > size)
+ n = size-off;
+ memmove(buf, tmp+off, n);
+ return n;
+}
+
+int
readnum(ulong off, char *buf, ulong n, ulong val, int size)
{
char tmp[64];
@@ 515,6 532,7 @@ consread(Chan *c, void *buf, long n, vlong off)
char *cbuf = buf;
int ch, i, k, id, eol;
vlong offset = off;
+ uvlong ticks, fasthz;
if(n <= 0)
return n;
@@ 623,6 641,19 @@ consread(Chan *c, void *buf, long n, vlong off)
memmove(buf, tmp+k, n);
return n;
+ case Qfastclock:
+ ticks = fastticks(&fasthz);
+
+ k = offset;
+ if(k >= 4*NUMSIZE)
+ return 0;
+ if(k+n > 4*NUMSIZE)
+ n = 4*NUMSIZE - k;
+ readvlnum(0, tmp, 2*NUMSIZE, ticks, 2*NUMSIZE);
+ readvlnum(0, tmp+2*NUMSIZE, 2*NUMSIZE, fasthz, 2*NUMSIZE);
+ memmove(buf, tmp+k, n);
+ return n;
+
case Qkey:
return keyread(buf, n, offset);
M port/portfns.h => port/portfns.h +1 -0
@@ 91,6 91,7 @@ void error(char*);
long execregs(ulong, ulong, ulong);
void exhausted(char*);
void exit(int);
+uvlong fastticks(uvlong*);
int fault(ulong, int);
void fdclose(int, int);
Chan* fdtochan(int, int, int, int);