You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cpuid.c 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*
  2. * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. #include <string.h>
  21. #include <ipxe/cpuid.h>
  22. /** @file
  23. *
  24. * x86 CPU feature detection
  25. *
  26. */
  27. /**
  28. * Check whether or not CPUID instruction is supported
  29. *
  30. * @ret is_supported CPUID instruction is supported
  31. */
  32. static int cpuid_is_supported ( void ) {
  33. unsigned long original;
  34. unsigned long inverted;
  35. __asm__ ( "pushf\n\t"
  36. "pushf\n\t"
  37. "pop %0\n\t"
  38. "mov %0,%1\n\t"
  39. "xor %2,%1\n\t"
  40. "push %1\n\t"
  41. "popf\n\t"
  42. "pushf\n\t"
  43. "pop %1\n\t"
  44. "popf\n\t"
  45. : "=&r" ( original ), "=&r" ( inverted )
  46. : "ir" ( CPUID_FLAG ) );
  47. return ( ( original ^ inverted ) & CPUID_FLAG );
  48. }
  49. /**
  50. * Issue CPUID instruction
  51. *
  52. * @v operation CPUID operation
  53. * @v eax Output via %eax
  54. * @v ebx Output via %ebx
  55. * @v ecx Output via %ecx
  56. * @v edx Output via %edx
  57. */
  58. static inline __attribute__ (( always_inline )) void
  59. cpuid ( uint32_t operation, uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
  60. uint32_t *edx ) {
  61. __asm__ ( "cpuid"
  62. : "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
  63. : "0" ( operation ) );
  64. }
  65. /**
  66. * Get Intel-defined x86 CPU features
  67. *
  68. * @v features x86 CPU features to fill in
  69. */
  70. static void x86_intel_features ( struct x86_features *features ) {
  71. uint32_t max_level;
  72. uint32_t discard_a;
  73. uint32_t discard_b;
  74. uint32_t discard_c;
  75. uint32_t discard_d;
  76. /* Check that features are available via CPUID */
  77. cpuid ( CPUID_VENDOR_ID, &max_level, &discard_b, &discard_c,
  78. &discard_d );
  79. if ( max_level < CPUID_FEATURES ) {
  80. DBGC ( features, "CPUID has no Intel-defined features (max "
  81. "level %08x)\n", max_level );
  82. return;
  83. }
  84. /* Get features */
  85. cpuid ( CPUID_FEATURES, &discard_a, &discard_b,
  86. &features->intel.ecx, &features->intel.edx );
  87. DBGC ( features, "CPUID Intel features: %%ecx=%08x, %%edx=%08x\n",
  88. features->intel.ecx, features->intel.edx );
  89. }
  90. /**
  91. * Get AMD-defined x86 CPU features
  92. *
  93. * @v features x86 CPU features to fill in
  94. */
  95. static void x86_amd_features ( struct x86_features *features ) {
  96. uint32_t max_level;
  97. uint32_t discard_a;
  98. uint32_t discard_b;
  99. uint32_t discard_c;
  100. uint32_t discard_d;
  101. /* Check that features are available via CPUID */
  102. cpuid ( CPUID_AMD_MAX_FN, &max_level, &discard_b, &discard_c,
  103. &discard_d );
  104. if ( ( max_level & CPUID_AMD_CHECK_MASK ) != CPUID_AMD_CHECK ) {
  105. DBGC ( features, "CPUID has no extended functions\n" );
  106. return;
  107. }
  108. if ( max_level < CPUID_AMD_FEATURES ) {
  109. DBGC ( features, "CPUID has no AMD-defined features (max "
  110. "level %08x)\n", max_level );
  111. return;
  112. }
  113. /* Get features */
  114. cpuid ( CPUID_AMD_FEATURES, &discard_a, &discard_b,
  115. &features->amd.ecx, &features->amd.edx );
  116. DBGC ( features, "CPUID AMD features: %%ecx=%08x, %%edx=%08x\n",
  117. features->amd.ecx, features->amd.edx );
  118. }
  119. /**
  120. * Get x86 CPU features
  121. *
  122. * @v features x86 CPU features to fill in
  123. */
  124. void x86_features ( struct x86_features *features ) {
  125. /* Clear all features */
  126. memset ( features, 0, sizeof ( *features ) );
  127. /* Check that CPUID instruction is available */
  128. if ( ! cpuid_is_supported() ) {
  129. DBGC ( features, "CPUID instruction is not supported\n" );
  130. return;
  131. }
  132. /* Get Intel-defined features */
  133. x86_intel_features ( features );
  134. /* Get AMD-defined features */
  135. x86_amd_features ( features );
  136. }