ProcessorInfo.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/StringBuilder.h>
  8. #include <AK/Types.h>
  9. #include <Kernel/Arch/Processor.h>
  10. #include <Kernel/Arch/x86/CPUID.h>
  11. #include <Kernel/Arch/x86/ProcessorInfo.h>
  12. namespace Kernel {
  13. ProcessorInfo::ProcessorInfo(Processor const& processor)
  14. : m_vendor_id_string(build_vendor_id_string())
  15. , m_hypervisor_vendor_id_string(build_hypervisor_vendor_id_string(processor))
  16. , m_brand_string(build_brand_string())
  17. , m_features_string(build_features_string(processor))
  18. {
  19. CPUID cpuid(1);
  20. m_stepping = cpuid.eax() & 0xf;
  21. u32 model = (cpuid.eax() >> 4) & 0xf;
  22. u32 family = (cpuid.eax() >> 8) & 0xf;
  23. m_type = (cpuid.eax() >> 12) & 0x3;
  24. u32 extended_model = (cpuid.eax() >> 16) & 0xf;
  25. u32 extended_family = (cpuid.eax() >> 20) & 0xff;
  26. if (family == 15) {
  27. m_display_family = family + extended_family;
  28. m_display_model = model + (extended_model << 4);
  29. } else if (family == 6) {
  30. m_display_family = family;
  31. m_display_model = model + (extended_model << 4);
  32. } else {
  33. m_display_family = family;
  34. m_display_model = model;
  35. }
  36. populate_cache_sizes();
  37. }
  38. static void emit_u32(StringBuilder& builder, u32 value)
  39. {
  40. builder.appendff("{:c}{:c}{:c}{:c}",
  41. value & 0xff,
  42. (value >> 8) & 0xff,
  43. (value >> 16) & 0xff,
  44. (value >> 24) & 0xff);
  45. }
  46. NonnullOwnPtr<KString> ProcessorInfo::build_vendor_id_string()
  47. {
  48. CPUID cpuid(0);
  49. StringBuilder builder;
  50. emit_u32(builder, cpuid.ebx());
  51. emit_u32(builder, cpuid.edx());
  52. emit_u32(builder, cpuid.ecx());
  53. // NOTE: This isn't necessarily fixed length and might have null terminators at the end.
  54. return KString::must_create(builder.string_view().trim("\0"sv, TrimMode::Right));
  55. }
  56. NonnullOwnPtr<KString> ProcessorInfo::build_hypervisor_vendor_id_string(Processor const& processor)
  57. {
  58. if (!processor.has_feature(CPUFeature::HYPERVISOR))
  59. return KString::must_create({});
  60. CPUID cpuid(0x40000000);
  61. StringBuilder builder;
  62. emit_u32(builder, cpuid.ebx());
  63. emit_u32(builder, cpuid.ecx());
  64. emit_u32(builder, cpuid.edx());
  65. // NOTE: This isn't necessarily fixed length and might have null terminators at the end.
  66. return KString::must_create(builder.string_view().trim("\0"sv, TrimMode::Right));
  67. }
  68. NonnullOwnPtr<KString> ProcessorInfo::build_brand_string()
  69. {
  70. u32 max_extended_leaf = CPUID(0x80000000).eax();
  71. if (max_extended_leaf < 0x80000004)
  72. return KString::must_create({});
  73. StringBuilder builder;
  74. auto append_brand_string_part_to_builder = [&](u32 i) {
  75. CPUID cpuid(0x80000002 + i);
  76. emit_u32(builder, cpuid.eax());
  77. emit_u32(builder, cpuid.ebx());
  78. emit_u32(builder, cpuid.ecx());
  79. emit_u32(builder, cpuid.edx());
  80. };
  81. append_brand_string_part_to_builder(0);
  82. append_brand_string_part_to_builder(1);
  83. append_brand_string_part_to_builder(2);
  84. // NOTE: This isn't necessarily fixed length and might have null terminators at the end.
  85. return KString::must_create(builder.string_view().trim("\0"sv, TrimMode::Right));
  86. }
  87. NonnullOwnPtr<KString> ProcessorInfo::build_features_string(Processor const& processor)
  88. {
  89. StringBuilder builder;
  90. bool first = true;
  91. for (auto feature = CPUFeature::Type(1u); feature != CPUFeature::__End; feature <<= 1u) {
  92. if (processor.has_feature(feature)) {
  93. if (first)
  94. first = false;
  95. else
  96. MUST(builder.try_append(' '));
  97. MUST(builder.try_append(cpu_feature_to_string_view(feature)));
  98. }
  99. }
  100. return KString::must_create(builder.string_view());
  101. }
  102. void ProcessorInfo::populate_cache_sizes()
  103. {
  104. u32 max_extended_leaf = CPUID(0x80000000).eax();
  105. if (max_extended_leaf < 0x80000005)
  106. return;
  107. auto l1_cache_info = CPUID(0x80000005);
  108. // NOTE: Except for L2, these are not available on Intel CPUs in this form and return 0 for each register in that case.
  109. if (l1_cache_info.ecx() != 0) {
  110. m_l1_data_cache = Cache {
  111. .size = ((l1_cache_info.ecx() >> 24) & 0xff) * KiB,
  112. .line_size = l1_cache_info.ecx() & 0xff,
  113. };
  114. }
  115. if (l1_cache_info.edx() != 0) {
  116. m_l1_instruction_cache = Cache {
  117. .size = ((l1_cache_info.edx() >> 24) & 0xff) * KiB,
  118. .line_size = l1_cache_info.edx() & 0xff,
  119. };
  120. }
  121. if (max_extended_leaf < 0x80000006)
  122. return;
  123. auto l2_l3_cache_info = CPUID(0x80000006);
  124. if (l2_l3_cache_info.ecx() != 0) {
  125. m_l2_cache = Cache {
  126. .size = ((l2_l3_cache_info.ecx() >> 16) & 0xffff) * KiB,
  127. .line_size = l2_l3_cache_info.ecx() & 0xff,
  128. };
  129. }
  130. if (l2_l3_cache_info.edx() != 0) {
  131. m_l3_cache = Cache {
  132. .size = (static_cast<u64>((l2_l3_cache_info.edx() >> 18)) & 0x3fff) * 512 * KiB,
  133. .line_size = l2_l3_cache_info.edx() & 0xff,
  134. };
  135. }
  136. }
  137. }