1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
#include <u.h>
#include <libc.h>
#include <tos.h>
/*
* This code is a mixture of cpuid(1) and the nanosec() found in vmx,
* in order to force the use of nsec(2) in case we are running in a
* virtualized environment where the clock is mis-bhyve-ing.
*/
typedef struct Res {
ulong ax, bx, cx, dx;
} Res;
static uchar _cpuid[] = {
0x5E, /* POP SI (PC) */
0x5D, /* POP BP (Res&) */
0x58, /* POP AX */
0x59, /* POP CX */
0x51, /* PUSH CX */
0x50, /* PUSH AX */
0x55, /* PUSH BP */
0x56, /* PUSH SI */
0x31, 0xDB, /* XOR BX, BX */
0x31, 0xD2, /* XOR DX, DX */
0x0F, 0xA2, /* CPUID */
0x89, 0x45, 0x00, /* MOV AX, 0(BP) */
0x89, 0x5d, 0x04, /* MOV BX, 4(BP) */
0x89, 0x4d, 0x08, /* MOV CX, 8(BP) */
0x89, 0x55, 0x0C, /* MOV DX, 12(BP) */
0xC3, /* RET */
};
static Res (*cpuid)(ulong ax, ulong cx) = (Res(*)(ulong, ulong)) _cpuid;
/*
* nsec() is wallclock and can be adjusted by timesync
* so need to use cycles() instead, but fall back to
* nsec() in case we can't
*/
uvlong
nanosec(void)
{
static uvlong fasthz, xstart;
char buf[13], path[128];
ulong w;
uvlong x, div;
int fd;
Res r;
if(fasthz == ~0ULL)
return nsec() - xstart;
if(fasthz == 0){
/* first long in a.out header */
snprint(path, sizeof path, "/proc/%d/text", getpid());
fd = open(path, OREAD);
if(fd < 0)
goto Wallclock;
if(read(fd, buf, 4) != 4){
close(fd);
goto Wallclock;
}
close(fd);
w = ((ulong *) buf)[0];
switch(w){
default:
goto Wallclock;
case 0x978a0000: /* amd64 */
/* patch out POP BP -> POP AX */
_cpuid[1] = 0x58;
case 0xeb010000: /* 386 */
break;
}
segflush(_cpuid, sizeof(_cpuid));
r = cpuid(0x40000000, 0);
((ulong *) buf)[0] = r.bx;
((ulong *) buf)[1] = r.cx;
((ulong *) buf)[2] = r.dx;
buf[12] = 0;
if(strstr(buf, "bhyve") != nil)
goto Wallclock;
if(_tos->cyclefreq){
fasthz = _tos->cyclefreq;
cycles(&xstart);
} else {
Wallclock:
fasthz = ~0ULL;
xstart = nsec();
}
return 0;
}
cycles(&x);
x -= xstart;
/* this is ugly */
for(div = 1000000000ULL; x < 0x1999999999999999ULL && div > 1 ; div /= 10ULL, x *= 10ULL);
return x / (fasthz / div);
}
|