Subversion Repositories Kolibri OS

Rev

Rev 4304 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1.  
  2. #include <stdint.h>
  3. #include <stdio.h>
  4.  
  5.  
  6. static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
  7.                 unsigned int *ecx, unsigned int *edx)
  8. {
  9.     /* ecx is often an input as well as an output. */
  10.     asm volatile("cpuid"
  11.         : "=a" (*eax),
  12.           "=b" (*ebx),
  13.           "=c" (*ecx),
  14.           "=d" (*edx)
  15.         : "0" (*eax), "2" (*ecx)
  16.         : "memory");
  17. }
  18.  
  19. /* Some CPUID calls want 'count' to be placed in ecx */
  20. static inline void cpuid_count(unsigned int op, int count,
  21.                                unsigned int *eax, unsigned int *ebx,
  22.                                unsigned int *ecx, unsigned int *edx)
  23. {
  24.     *eax = op;
  25.     *ecx = count;
  26.     native_cpuid(eax, ebx, ecx, edx);
  27. }
  28.  
  29.  
  30. enum _cache_type {
  31.         CACHE_TYPE_NULL = 0,
  32.         CACHE_TYPE_DATA = 1,
  33.         CACHE_TYPE_INST = 2,
  34.         CACHE_TYPE_UNIFIED = 3
  35. };
  36.  
  37.  
  38. union _cpuid4_leaf_eax {
  39.         struct {
  40.                 enum _cache_type        type:5;
  41.                 unsigned int            level:3;
  42.                 unsigned int            is_self_initializing:1;
  43.                 unsigned int            is_fully_associative:1;
  44.                 unsigned int            reserved:4;
  45.                 unsigned int            num_threads_sharing:12;
  46.                 unsigned int            num_cores_on_die:6;
  47.         } split;
  48.         uint32_t full;
  49. };
  50.  
  51. union _cpuid4_leaf_ebx {
  52.         struct {
  53.                 unsigned int            coherency_line_size:12;
  54.                 unsigned int            physical_line_partition:10;
  55.                 unsigned int            ways_of_associativity:10;
  56.         } split;
  57.         uint32_t full;
  58. };
  59.  
  60. union _cpuid4_leaf_ecx {
  61.         struct {
  62.                 unsigned int            number_of_sets:32;
  63.         } split;
  64.         uint32_t full;
  65. };
  66.  
  67. struct _cpuid4_info_regs {
  68.         union _cpuid4_leaf_eax eax;
  69.         union _cpuid4_leaf_ebx ebx;
  70.         union _cpuid4_leaf_ecx ecx;
  71.         unsigned long size;
  72. };
  73.  
  74. static int
  75. cpuid4_cache_lookup_regs(int index,
  76.                    struct _cpuid4_info_regs *this_leaf)
  77. {
  78.     union _cpuid4_leaf_eax  eax;
  79.     union _cpuid4_leaf_ebx  ebx;
  80.     union _cpuid4_leaf_ecx  ecx;
  81.     unsigned                edx;
  82.  
  83.     cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
  84.  
  85.     if (eax.split.type == CACHE_TYPE_NULL)
  86.         return -1; /* better error ? */
  87.  
  88.     this_leaf->eax = eax;
  89.     this_leaf->ebx = ebx;
  90.     this_leaf->ecx = ecx;
  91.     this_leaf->size = (ecx.split.number_of_sets  + 1) *
  92.               (ebx.split.coherency_line_size     + 1) *
  93.               (ebx.split.physical_line_partition + 1) *
  94.               (ebx.split.ways_of_associativity   + 1);
  95.     return 0;
  96. }
  97.  
  98. static int find_num_cache_leaves()
  99. {
  100.     unsigned int        eax, ebx, ecx, edx, op;
  101.     union _cpuid4_leaf_eax  cache_eax;
  102.     int             i = -1;
  103.  
  104.     do {
  105.         ++i;
  106.         /* Do cpuid(op) loop to find out num_cache_leaves */
  107.         cpuid_count(4, i, &eax, &ebx, &ecx, &edx);
  108.         cache_eax.full = eax;
  109.     } while (cache_eax.split.type != CACHE_TYPE_NULL);
  110.     return i;
  111. };
  112.  
  113. unsigned int cpu_cache_size()
  114. {
  115.     unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4)  */
  116.     unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
  117.     unsigned int num_cache_leaves;
  118.  
  119.     num_cache_leaves = find_num_cache_leaves();
  120.  
  121.     for (i = 0; i < num_cache_leaves; i++)
  122.     {
  123.         struct _cpuid4_info_regs this_leaf;
  124.         int retval;
  125.  
  126.         retval = cpuid4_cache_lookup_regs(i, &this_leaf);
  127.         if (retval >= 0) {
  128.             switch (this_leaf.eax.split.level)
  129.             {
  130.                 case 1:
  131.                     if (this_leaf.eax.split.type == CACHE_TYPE_DATA)
  132.                         new_l1d = this_leaf.size;
  133.                     else if (this_leaf.eax.split.type == CACHE_TYPE_INST)
  134.                         new_l1i = this_leaf.size;
  135.                     break;
  136.                 case 2:
  137.                     new_l2 = this_leaf.size;
  138.                     break;
  139.                 case 3:
  140.                     new_l3 = this_leaf.size;
  141.                     break;
  142.                 default:
  143.                     break;
  144.             }
  145.         }
  146.     }
  147.     printf("l2 cache %d l3 cache %d\n", new_l2, new_l3);
  148.  
  149.     return new_l3 != 0 ? new_l3 : new_l2;
  150. };
  151.