-
Notifications
You must be signed in to change notification settings - Fork 0
/
CTC.cpp
344 lines (282 loc) · 6.72 KB
/
CTC.cpp
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
#include "CTC.h"
//
// Functionality macros
//
#define CTC_PrefetchLine( n, l ) _mm_prefetch( ( CHAR* )( g_CTC_CommunicationLines + ( n * g_CTC_CacheLineSize ) ), l );
#define CTC_FlushLine( n ) _mm_clflushopt( g_CTC_CommunicationLines + ( n * g_CTC_CacheLineSize ) );
//
// Base virtual address for the communication channel cache lines
//
UINT8* g_CTC_CommunicationLines = NULL;
//
// The size of a cache line on the current executing machine
//
UINT64 g_CTC_CacheLineSize = NULL;
VOID
CTC_Initialze(
IN LPVOID CommunicationLines OPTIONAL
)
{
UINT32 CPUInfo[ 4 ]{ };
//
// Obtain the feature bits and processor information for the executing machine(EAX=1)
//
__cpuidex( ( INT32* )&CPUInfo, 1, NULL );
//
// Obtain the cache line size(bits 15:8)*8
//
g_CTC_CacheLineSize = ( ( CPUInfo[ 1 ] >> 8 ) & 0xFF ) * 8;
if ( CommunicationLines == NULL ) {
g_CTC_CommunicationLines = ( UINT8* )GetModuleHandleA( "kernelbase.dll" );
}
else {
g_CTC_CommunicationLines = ( UINT8* )( ( UINT64 )CommunicationLines & ~( g_CTC_CacheLineSize - 1ull ) );
}
}
#pragma optimize( "", off )
DECLSPEC_NOINLINE
UINT64
CTC_MeasureLine_Internal(
IN UINT32 Line
)
{
UINT32 Junk;
//
// Obtain initial timestamp counter
//
UINT64 InitTSC = __rdtscp( &Junk );
//
// Perform a read operation at the specified address
//
Junk = *( g_CTC_CommunicationLines + ( Line * g_CTC_CacheLineSize ) );
//
// Return read delta
//
return __rdtscp( &Junk ) - InitTSC;
}
DECLSPEC_NOINLINE
UINT64
CTC_MeasureLine(
IN UINT32 LineNumber
)
{
UINT64 Average = NULL;
//
// Fetch the communication line into all cache levels
//
CTC_PrefetchLine( LineNumber, _MM_HINT_T0 );
for ( UINT32 i = NULL; i < 10; i++ ) {
//
// Perform timing measurement
//
Average += CTC_MeasureLine_Internal( LineNumber );
}
//
// Return the average time of 10 measurements
//
return Average / 10;
}
DECLSPEC_NOINLINE
BOOL
CTC_IsLinePositive(
IN UINT32 LineNumber
)
{
UINT16 NumMeasurements = NULL;
UINT16 Likelihood = NULL;
while ( NumMeasurements < 16 ) {
//
// If the current measurement is above the threshold, increase likelihood
//
if ( CTC_MeasureLine( LineNumber ) > CTC_MEASUREMENT_POSITIVE_THRESHOLD ) {
Likelihood++;
}
NumMeasurements++;
}
return ( Likelihood > ( NumMeasurements / 2 ) );
}
DECLSPEC_NOINLINE
VOID
CTC_SetLinesToUINT64(
IN UINT64 Value
)
{
for ( UINT32 n = CTC_TRANSMIT_FLUSH_COUNT; n--; )
{
for ( UINT64 i = NULL; i < 64; i++ )
{
//
// Flush the line that corresponds to the current bit if set
//
if ( Value & ( 1ull << i ) ) {
CTC_FlushLine( i );
}
}
}
}
#pragma optimize( "", on )
DECLSPEC_NOINLINE
UINT64
CTC_MostFrequentUINT64(
IN UINT64* Values,
IN UINT16 Count
)
{
UINT64 Result = NULL;
UINT16 OccuranceBar = NULL;
for ( UINT16 i = NULL; i < Count; i++ )
{
UINT16 CurrentOccurances = NULL;
for ( UINT16 j = NULL; j < Count; j++ )
{
if ( &Values[ j ] == &Values[ i ] ) {
continue;
}
if ( Values[ j ] == Values[ i ] ) {
CurrentOccurances++;
}
if ( CurrentOccurances > ( Count >> 1 ) ) {
Result = Values[ i ];
return Result;
}
}
if ( CurrentOccurances > OccuranceBar )
{
OccuranceBar = CurrentOccurances;
Result = Values[ i ];
}
}
return Result;
}
VOID
CTC_GenerateChecksum(
IN PCTC_TRANSMIT_BLOCK TransmitBlock,
OUT UINT16* Checksum
)
{
#define CTC_CHECKSUM_CRC_SEED 0x5596A0B1
UINT32 CRC = _mm_crc32_u16( CTC_CHECKSUM_CRC_SEED,
TransmitBlock->s.ArrayEntry ^ ( ( TransmitBlock->s.Value & 0xFFFF ) + ( ( TransmitBlock->s.Value >> 16 ) & 0xFFFF ) ) );
*Checksum = ( ( CRC >> 16 ) & 0xFFFF ) ^ ( CRC & 0xFFFF );
}
DECLSPEC_NOINLINE
UINT64
CTC_ConvertLinesToUINT64(
VOID
)
{
UINT64 ValueSamples[ 16 ]{ };
UINT16 SampleCount = NULL;
while ( SampleCount < ARRAYSIZE( ValueSamples ) )
{
for ( UINT64 i = NULL; i < 64; i++ ) {
ValueSamples[ SampleCount ] |= ( ( UINT64 )CTC_IsLinePositive( i ) << i );
}
SampleCount++;
}
return CTC_MostFrequentUINT64( ValueSamples, SampleCount );
}
DECLSPEC_NOINLINE
VOID
CTC_TransmitData_Internal(
IN UINT32* Array,
IN UINT32 ArraySize
)
{
CTC_SetLinesToUINT64( CTC_TRANSMIT_START_MAGIC );
for ( UINT32 i = NULL; i < ArraySize; i++ )
{
CTC_TRANSMIT_BLOCK CurrentBlock;
CurrentBlock.s.Value = Array[ i ];
CurrentBlock.s.ArrayEntry = i;
CTC_GenerateChecksum( &CurrentBlock, &CurrentBlock.s.Checksum );
CTC_SetLinesToUINT64( CurrentBlock.AsUint64 );
}
CTC_SetLinesToUINT64( CTC_TRANSMIT_END_MAGIC );
}
#include <cstdio>
DECLSPEC_NOINLINE
VOID
CTC_ReceiveData_Internal(
OUT UINT32* Array,
IN UINT32 ArraySize
)
{
//
// Await the start of the transmission
//
while ( CTC_ConvertLinesToUINT64( ) != CTC_TRANSMIT_START_MAGIC ) {
}
while ( true )
{
UINT64 Value = CTC_ConvertLinesToUINT64( );
UINT16 Checksum = NULL;
if ( Value == CTC_TRANSMIT_END_MAGIC ) {
break;
}
PCTC_TRANSMIT_BLOCK TransmitBlock = ( PCTC_TRANSMIT_BLOCK )&Value;
if ( TransmitBlock->s.ArrayEntry >= ArraySize ) {
continue;
}
CTC_GenerateChecksum( TransmitBlock, &Checksum );
if ( Checksum == TransmitBlock->s.Checksum ) {
Array[ TransmitBlock->s.ArrayEntry ] = TransmitBlock->s.Value;
}
}
}
BOOL
CTC_ReceiveData(
OUT UINT8* Data,
IN UINT32 Length
)
{
//
// Align the length of the array to the size of a UINT32
//
UINT32 AlignedLength = ( Length + 3 ) & ~( 3 );
//
// Allocate a temporary buffer
//
UINT32* RecvBuffer = ( UINT32* )HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, AlignedLength );
if ( RecvBuffer == NULL ) {
return FALSE;
}
//
// Receive the data
//
CTC_ReceiveData_Internal( RecvBuffer, AlignedLength >> 2 );
RtlCopyMemory( Data, RecvBuffer, Length );
//
// Free the temporary buffer
//
HeapFree( GetProcessHeap( ), NULL, RecvBuffer );
return TRUE;
}
BOOL
CTC_TransmitData(
IN UINT8* Data,
IN UINT32 Length
)
{
//
// Align the length of the array to the size of a UINT32
//
UINT32 AlignedLength = ( Length + 3 ) & ~( 3 );
//
// Allocate a temporary buffer
//
UINT32* SendBuffer = ( UINT32* )HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, AlignedLength );
if ( SendBuffer == NULL ) {
return FALSE;
}
RtlCopyMemory( SendBuffer, Data, Length );
//
// Transmit the data
//
CTC_TransmitData_Internal( SendBuffer, AlignedLength >> 2 );
//
// Free the temporary buffer
//
HeapFree( GetProcessHeap( ), NULL, SendBuffer );
return TRUE;
}