Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Cache information interface and implementation for AMD and Intel on Linux
[palacios.git] / linux_module / iface-cache_info.c
1 /*
2  * Palacios cache information interface
3  *
4  *
5  * (c) Peter Dinda, 2015
6  */
7
8 #include <linux/fs.h>
9 #include <linux/file.h>
10 #include <linux/uaccess.h>
11 #include <linux/namei.h>
12 #include <linux/poll.h>
13 #include <linux/anon_inodes.h>
14
15 #include "palacios.h"
16 #include "util-hashtable.h"
17 #include "linux-exts.h"
18 #include "vm.h"
19
20 #define sint64_t int64_t
21
22 #include <linux/spinlock.h>
23 #include <asm/uaccess.h>
24 #include <linux/inet.h>
25 #include <linux/kthread.h>
26 #include <linux/netdevice.h>
27 #include <linux/ip.h>
28 #include <linux/in.h>
29 #include <linux/string.h>
30 #include <linux/preempt.h>
31 #include <linux/sched.h>
32 #include <linux/list.h>
33 #include <linux/syscalls.h>
34
35 #include <linux/module.h>
36 #include <linux/kernel.h>
37 #include <linux/socket.h>
38 #include <linux/net.h>
39 #include <linux/slab.h>
40
41 #include <palacios/vmm.h>
42 #include <interfaces/vmm_cache_info.h>
43
44
45 /*
46   This is a simple implementation of the Palacios cache info 
47   
48 */
49
50
51 static inline void cpuid_string(u32 id, u32 dest[4]) {
52   asm volatile("cpuid"
53                :"=a"(*dest),"=b"(*(dest+1)),"=c"(*(dest+2)),"=d"(*(dest+3))
54                :"a"(id));
55 }
56
57
58 static int get_cpu_vendor(char name[13])
59 {
60   u32 dest[4];
61   u32 maxid;
62
63   cpuid_string(0,dest);
64   maxid=dest[0];
65   ((u32*)name)[0]=dest[1];
66   ((u32*)name)[1]=dest[3];
67   ((u32*)name)[2]=dest[2];
68   name[12]=0;
69    
70   return maxid;
71 }
72
73 static int is_intel(void)
74 {
75   char name[13];
76   get_cpu_vendor(name);
77   return !strcmp(name,"GenuineIntel");
78 }
79
80 static int is_amd(void)
81 {
82   char name[13];
83   get_cpu_vendor(name);
84   return !strcmp(name,"AuthenticAMD");
85 }
86
87 static uint32_t decode_amd_l2l3_assoc(uint32_t val)
88 {
89     switch (val) {
90         case 0:
91         case 1:
92         case 2:
93         case 4:
94             return val;
95         case 6:
96             return 8;
97         case 8:
98             return 16;
99         case 0xa:
100             return 32;
101         case 0xb:
102             return 48;
103         case 0xc:
104             return 64;
105         case 0xd:
106             return 96;
107         case 0xe:
108             return 128;
109         case 0xf:
110             return (uint32_t)-1;
111         default:
112             ERROR("Unknown associativity encoding %x\n",val);
113             return 0;
114     }
115 }
116
117 static int get_cache_level_amd_legacy(v3_cache_type_t type, uint32_t level, struct v3_cache_info *c)
118 {
119     uint32_t eax, ebx, ecx, edx;
120     uint32_t l1_dtlb_24_assoc;
121     uint32_t l1_dtlb_24_entries;
122     uint32_t l1_itlb_24_assoc;
123     uint32_t l1_itlb_24_entries;
124     uint32_t l1_dtlb_4k_assoc;
125     uint32_t l1_dtlb_4k_entries;
126     uint32_t l1_itlb_4k_assoc;
127     uint32_t l1_itlb_4k_entries;
128     uint32_t l1_dcache_size;
129     uint32_t l1_dcache_assoc;
130     uint32_t l1_dcache_linespertag;
131     uint32_t l1_dcache_linesize;
132     uint32_t l1_icache_size;
133     uint32_t l1_icache_assoc;
134     uint32_t l1_icache_linespertag;
135     uint32_t l1_icache_linesize;
136     uint32_t l2_dtlb_24_assoc;
137     uint32_t l2_dtlb_24_entries;
138     uint32_t l2_itlb_24_assoc;
139     uint32_t l2_itlb_24_entries;
140     uint32_t l2_dtlb_4k_assoc;
141     uint32_t l2_dtlb_4k_entries;
142     uint32_t l2_itlb_4k_assoc;
143     uint32_t l2_itlb_4k_entries;
144     uint32_t l2_cache_size;
145     uint32_t l2_cache_assoc;
146     uint32_t l2_cache_linespertag;
147     uint32_t l2_cache_linesize;
148     uint32_t l3_cache_size;
149     uint32_t l3_cache_assoc;
150     uint32_t l3_cache_linespertag;
151     uint32_t l3_cache_linesize;
152
153     // L1 caches and tlbs
154     cpuid(0x80000005,&eax,&ebx,&ecx,&edx);
155
156     l1_dtlb_24_assoc = (eax >> 24) & 0xff;
157     l1_dtlb_24_entries = (eax >> 16) & 0xff;
158     l1_itlb_24_assoc = (eax >> 8) & 0xff;
159     l1_itlb_24_entries = (eax) & 0xff;
160     l1_dtlb_4k_assoc = (ebx >> 24) & 0xff;
161     l1_dtlb_4k_entries = (ebx >> 16) & 0xff;
162     l1_itlb_4k_assoc = (ebx >> 8) & 0xff;
163     l1_itlb_4k_entries = (ebx) & 0xff;
164     l1_dcache_size = ((ecx >> 24) & 0xff) * 1024;
165     l1_dcache_assoc = (ecx >> 16) & 0xff;
166     l1_dcache_linespertag = (ecx >> 8) & 0xff;
167     l1_dcache_linesize = ((ecx) & 0xff) * l1_dcache_linespertag;
168     l1_icache_size = ((edx >> 24) & 0xff) * 1024;
169     l1_icache_assoc = (edx >> 16) & 0xff;
170     l1_icache_linespertag = (edx >> 8) & 0xff;
171     l1_icache_linesize = ((edx) & 0xff) * l1_icache_linespertag;
172
173
174     // L2 caches and tlbs plus L3 cache
175     cpuid(0x80000006,&eax,&ebx,&ecx,&edx);
176
177     l2_dtlb_24_assoc = decode_amd_l2l3_assoc((eax >> 28) & 0xf);
178     l2_dtlb_24_entries = (eax >> 16) & 0xfff;
179     l2_itlb_24_assoc = decode_amd_l2l3_assoc((eax >> 12) & 0xf);
180     l2_itlb_24_entries = (eax) & 0xfff;
181     l2_dtlb_4k_assoc = decode_amd_l2l3_assoc((ebx >> 28) & 0xf);
182     l2_dtlb_4k_entries = (ebx >> 16) & 0xfff;
183     l2_itlb_4k_assoc = decode_amd_l2l3_assoc((ebx >> 12) & 0xf);
184     l2_itlb_4k_entries = (ebx) & 0xfff;
185     l2_cache_size = ((ecx >> 16) & 0xffff) * 1024;
186     l2_cache_assoc = decode_amd_l2l3_assoc((ecx >> 12) & 0xf);
187     l2_cache_linespertag = (ecx >> 8) & 0xf;
188     l2_cache_linesize = ((ecx) & 0xff) * l1_dcache_linespertag;
189     l3_cache_size = ((edx >> 18) & 0x3fff) * 1024 * 512;
190     l3_cache_assoc = decode_amd_l2l3_assoc((edx >> 12) & 0xf);
191     l3_cache_linespertag = (edx >> 8) & 0xf;
192     l3_cache_linesize = ((edx) & 0xff) * l3_cache_linespertag;
193     
194     
195     INFO("L1 ITLB: 2/4MB: %u assoc, %u entries; 4KB: %u assoc %u entries\n",
196          l1_itlb_24_assoc,l1_itlb_24_entries,l1_itlb_4k_assoc,l1_itlb_4k_entries);
197     INFO("L2 ITLB: 2/4MB: %u assoc, %u entries; 4KB: %u assoc %u entries\n",
198          l2_itlb_24_assoc,l2_itlb_24_entries,l2_itlb_4k_assoc,l2_itlb_4k_entries);
199     
200     INFO("L1 DTLB: 2/4MB: %u assoc, %u entries; 4KB: %u assoc %u entries\n",
201          l1_dtlb_24_assoc,l1_dtlb_24_entries,l1_dtlb_4k_assoc,l1_dtlb_4k_entries);
202     INFO("L2 DTLB: 2/4MB: %u assoc, %u entries; 4KB: %u assoc %u entries\n",
203          l2_dtlb_24_assoc,l2_dtlb_24_entries,l2_dtlb_4k_assoc,l2_dtlb_4k_entries);
204     
205     INFO("L1 ICACHE: %u size, %u assoc, %u linesize %u linespertag\n",
206          l1_icache_size,l1_icache_assoc,l1_icache_linesize,l1_icache_linespertag);
207     
208     INFO("L1 DCACHE: %u size, %u assoc, %u linesize %u linespertag\n",
209          l1_dcache_size,l1_dcache_assoc,l1_dcache_linesize,l1_dcache_linespertag);
210     
211     INFO("L2 CACHE: %u size, %u assoc, %u linesize %u linespertag\n",
212          l2_cache_size,l2_cache_assoc,l2_cache_linesize,l2_cache_linespertag);
213     
214     INFO("L3 CACHE: %u size, %u assoc, %u linesize %u linespertag\n",
215          l3_cache_size,l3_cache_assoc,l3_cache_linesize,l3_cache_linespertag);
216     
217     if (!c) { 
218         // debug
219         return 0;
220     }
221
222     c->type=type;
223     c->level=level;
224     c->blocksize=0;
225     c->associativity=0; // does not exist unless we say otherwise
226     
227     switch (type) {
228
229         case V3_CACHE_CODE: 
230             if (level==1) { 
231                 c->size = l1_icache_size;
232                 c->blocksize = l1_icache_linesize;
233                 c->associativity = l1_icache_assoc == 0xff ? -1 : l1_icache_assoc;
234             }           
235             break;
236
237         case V3_CACHE_DATA: 
238             if (level==1) { 
239                 c->size = l1_dcache_size;
240                 c->blocksize = l1_dcache_linesize;
241                 c->associativity = l1_dcache_assoc == 0xff ? -1 : l1_dcache_assoc;
242             } 
243             break;
244             
245         case V3_CACHE_COMBINED: 
246             if (level==2) { 
247                 c->size = l2_cache_size;
248                 c->blocksize = l2_cache_linesize;
249                 c->associativity = l2_cache_assoc;
250             } else if (level==3) { 
251                 c->size = l3_cache_size;
252                 c->blocksize = l3_cache_linesize;
253                 c->associativity = l3_cache_assoc;
254             } else if (level==-1) { 
255                 // find highest level combined cache that is enabled
256                 if (l3_cache_assoc) { 
257                     c->size = l3_cache_size;
258                     c->blocksize = l3_cache_linesize;
259                     c->associativity = l3_cache_assoc;
260                 } else {
261                     c->size = l2_cache_size;
262                     c->blocksize = l2_cache_linesize;
263                     c->associativity = l2_cache_assoc;
264                 }
265             }
266             break;
267
268         case V3_TLB_CODE: 
269             if (level==1) { 
270                 c->size = l1_itlb_4k_entries;
271                 c->associativity = l1_itlb_4k_assoc == 0xff ? -1 : l1_itlb_4k_assoc;
272             } else if (level==2) { 
273                 c->size = l2_itlb_4k_entries;
274                 c->associativity = l2_itlb_4k_assoc;
275             }
276             break;
277             
278         case V3_TLB_DATA: 
279             if (level==1) { 
280                 c->size = l1_dtlb_4k_entries;
281                 c->associativity = l1_dtlb_4k_assoc == 0xff ? -1 : l1_dtlb_4k_assoc;
282             } else if (level==2) { 
283                 c->size = l2_dtlb_4k_entries;
284                 c->associativity = l2_dtlb_4k_assoc;
285             }
286             break;
287         
288         case V3_TLB_COMBINED: 
289             // no combined TLB exposed on this machine;
290             break;
291             
292         default:
293             ERROR("Don't know how to handle cache info request type %x\n",type);
294             return -1;
295     }
296
297     return 0;
298 }
299
300
301 static int get_cache_level_amd(v3_cache_type_t type, uint32_t level, struct v3_cache_info *c)
302 {
303     uint32_t eax, ebx, ecx, edx;
304
305     cpuid(0x80000000,&eax,&ebx,&ecx,&edx);
306
307     if (eax < 0x80000006) { 
308         ERROR("AMD processor does not support even legacy cache info\n");
309         return -1;
310     }
311
312     cpuid(0x80000001,&eax,&ebx,&ecx,&edx);
313
314     if ((ecx >> 22) & 0x1) {
315         INFO("AMD Processor has Cache Topology Support - Legacy results may be inaccurate\n");
316     }
317
318     return get_cache_level_amd_legacy(type,level,c);
319 }
320
321 #define INTEL_MAX_CACHE 256
322
323 static int get_cache_level_intel_det(v3_cache_type_t type, uint32_t level, struct v3_cache_info *c)
324 {
325     uint32_t i;
326     uint32_t eax, ebx, ecx, edx;
327     uint32_t ctype, clevel, cassoc, cparts, csets, clinesize, csize;
328
329     if (type==V3_TLB_CODE || type==V3_TLB_DATA || type==V3_TLB_COMBINED) { 
330         ERROR("TLB query unsupported on Intel\n");
331         return -1;
332     }
333
334     if (c) { 
335         c->type = type;
336         c->level = 0;  // max level found so far
337     }
338     
339     for (i=0;i<INTEL_MAX_CACHE;i++) {
340
341         cpuid_count(4,i,&eax,&ebx,&ecx,&edx);
342
343         ctype = eax & 0x1f;
344
345         if (!ctype) { 
346             // no more caches
347             break;
348         }
349
350         clevel = (eax >> 5) & 0x7;
351         cassoc = eax & 0x200 ? -1 : ((ebx>>22) & 0x3ff) + 1 ;
352         cparts = ((ebx >> 12) & 0x3ff) + 1;
353         clinesize = (ebx & 0xfff) + 1;
354         csets = ecx + 1;
355         csize = cassoc * cparts * clinesize * csets;
356
357         INFO("Cache: index %u type %u level %u assoc %u parts %u linesize %u sets %u size %u\n",
358              i,ctype,clevel,cassoc,cparts,clinesize,csets,csize);
359
360         if (c &&
361             (((ctype==1 && type==V3_CACHE_DATA) ||
362               (ctype==2 && type==V3_CACHE_CODE) ||
363               (ctype==3 && type==V3_CACHE_COMBINED)) &&
364              ((clevel==level) || 
365               (level==-1 && clevel>c->level)))) { 
366             
367             c->level = clevel;
368             c->size = csize;
369             c->blocksize = clinesize;
370             c->associativity = cassoc;
371         } 
372     }
373
374     if (i==INTEL_MAX_CACHE) { 
375         return -1;
376     } else {
377         return 0;
378     }
379 }
380
381
382 static int get_cache_level_intel(v3_cache_type_t type, uint32_t level, struct v3_cache_info *c)
383 {
384     uint32_t eax, ebx, ecx, edx;
385
386     cpuid(0,&eax,&ebx,&ecx,&edx);
387     
388     if (eax < 4) { 
389         ERROR("Intel Processor does not support deterministic cache parameters function\n");
390         return -1;
391     }
392
393     return get_cache_level_intel_det(type,level,c);
394 }
395
396 static int get_cache_level(v3_cache_type_t type, uint32_t level, struct v3_cache_info *c)
397 {
398     if (is_amd()) { 
399         return get_cache_level_amd(type,level,c);
400     } else if (is_intel()) { 
401         return get_cache_level_intel(type,level,c);
402     } else {
403         ERROR("Cannot get cache information for unknown architecture\n");
404         return -1;
405     }
406         
407         
408 }
409
410
411 /***************************************************************************************************
412   Hooks to palacios and inititialization
413 *************************************************************************************************/
414
415     
416 static struct v3_cache_info_iface hooks = {
417     .get_cache_level = get_cache_level,
418 };
419
420
421 static int init_cache_info(void)
422 {
423
424     // just to see what's there - this should enumerate all
425     // and fail immediately otherwise
426     if (get_cache_level(-1,0,0)) { 
427         ERROR("Cannot intialized cache information\n");
428         return -1;
429     }
430
431     V3_Init_Cache_Info(&hooks);
432
433     INFO("cache_info inited\n");
434
435     return 0;
436
437 }
438
439 static int deinit_cache_info(void)
440 {
441     INFO("cache_info deinited\n");
442
443     return 0;
444 }
445
446
447
448
449
450 static struct linux_ext cache_info_ext = {
451     .name = "CACHE_INFO_INTERFACE",
452     .init = init_cache_info,
453     .deinit = deinit_cache_info,
454 };
455
456
457 register_extension(&cache_info_ext);