mirror of
https://github.com/RGBCube/serenity
synced 2025-05-20 17:55:08 +00:00
Kernel: Consolidate features into CPUFeature enum
This allows us to consolidate printing out all the CPU features into one log statement. Also expose them in /proc/cpuinfo
This commit is contained in:
parent
e373e5f007
commit
9b4e6f6a23
9 changed files with 197 additions and 145 deletions
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Arch/i386/CPU.h>
|
||||
#include <Kernel/Arch/i386/ProcessorInfo.h>
|
||||
|
@ -633,7 +634,7 @@ void exit_trap(TrapFrame* trap)
|
|||
return Processor::current().exit_trap(*trap);
|
||||
}
|
||||
|
||||
void sse_init()
|
||||
static void sse_init()
|
||||
{
|
||||
asm volatile(
|
||||
"mov %cr0, %eax\n"
|
||||
|
@ -645,122 +646,6 @@ void sse_init()
|
|||
"mov %eax, %cr4\n");
|
||||
}
|
||||
|
||||
bool g_cpu_supports_nx;
|
||||
bool g_cpu_supports_pae;
|
||||
bool g_cpu_supports_pge;
|
||||
bool g_cpu_supports_rdrand;
|
||||
bool g_cpu_supports_rdseed;
|
||||
bool g_cpu_supports_smap;
|
||||
bool g_cpu_supports_smep;
|
||||
bool g_cpu_supports_sse;
|
||||
bool g_cpu_supports_tsc;
|
||||
bool g_cpu_supports_umip;
|
||||
|
||||
void cpu_detect()
|
||||
{
|
||||
CPUID processor_info(0x1);
|
||||
g_cpu_supports_pae = (processor_info.edx() & (1 << 6));
|
||||
g_cpu_supports_pge = (processor_info.edx() & (1 << 13));
|
||||
g_cpu_supports_sse = (processor_info.edx() & (1 << 25));
|
||||
g_cpu_supports_tsc = (processor_info.edx() & (1 << 4));
|
||||
g_cpu_supports_rdrand = (processor_info.ecx() & (1 << 30));
|
||||
|
||||
CPUID extended_processor_info(0x80000001);
|
||||
g_cpu_supports_nx = (extended_processor_info.edx() & (1 << 20));
|
||||
|
||||
CPUID extended_features(0x7);
|
||||
g_cpu_supports_smap = (extended_features.ebx() & (1 << 20));
|
||||
g_cpu_supports_smep = (extended_features.ebx() & (1 << 7));
|
||||
g_cpu_supports_umip = (extended_features.ecx() & (1 << 2));
|
||||
g_cpu_supports_rdseed = (extended_features.ebx() & (1 << 18));
|
||||
}
|
||||
|
||||
void cpu_setup(u32 cpu)
|
||||
{
|
||||
if (cpu == 0)
|
||||
cpu_detect();
|
||||
|
||||
if (g_cpu_supports_sse) {
|
||||
sse_init();
|
||||
klog() << "x86: SSE support enabled";
|
||||
}
|
||||
|
||||
asm volatile(
|
||||
"movl %%cr0, %%eax\n"
|
||||
"orl $0x00010000, %%eax\n"
|
||||
"movl %%eax, %%cr0\n" ::
|
||||
: "%eax", "memory");
|
||||
klog() << "x86: WP support enabled";
|
||||
|
||||
if (g_cpu_supports_pge) {
|
||||
// Turn on CR4.PGE so the CPU will respect the G bit in page tables.
|
||||
asm volatile(
|
||||
"mov %cr4, %eax\n"
|
||||
"orl $0x80, %eax\n"
|
||||
"mov %eax, %cr4\n");
|
||||
klog() << "x86: PGE support enabled";
|
||||
} else {
|
||||
klog() << "x86: PGE support not detected";
|
||||
}
|
||||
|
||||
if (g_cpu_supports_nx) {
|
||||
// Turn on IA32_EFER.NXE
|
||||
asm volatile(
|
||||
"movl $0xc0000080, %ecx\n"
|
||||
"rdmsr\n"
|
||||
"orl $0x800, %eax\n"
|
||||
"wrmsr\n");
|
||||
klog() << "x86: NX support enabled";
|
||||
} else {
|
||||
klog() << "x86: NX support not detected";
|
||||
}
|
||||
|
||||
if (g_cpu_supports_smep) {
|
||||
// Turn on CR4.SMEP
|
||||
asm volatile(
|
||||
"mov %cr4, %eax\n"
|
||||
"orl $0x100000, %eax\n"
|
||||
"mov %eax, %cr4\n");
|
||||
klog() << "x86: SMEP support enabled";
|
||||
} else {
|
||||
klog() << "x86: SMEP support not detected";
|
||||
}
|
||||
|
||||
if (g_cpu_supports_smap) {
|
||||
// Turn on CR4.SMAP
|
||||
klog() << "x86: Enabling SMAP";
|
||||
asm volatile(
|
||||
"mov %cr4, %eax\n"
|
||||
"orl $0x200000, %eax\n"
|
||||
"mov %eax, %cr4\n");
|
||||
klog() << "x86: SMAP support enabled";
|
||||
} else {
|
||||
klog() << "x86: SMAP support not detected";
|
||||
}
|
||||
|
||||
if (g_cpu_supports_umip) {
|
||||
asm volatile(
|
||||
"mov %cr4, %eax\n"
|
||||
"orl $0x800, %eax\n"
|
||||
"mov %eax, %cr4\n");
|
||||
klog() << "x86: UMIP support enabled";
|
||||
}
|
||||
|
||||
if (g_cpu_supports_tsc) {
|
||||
asm volatile(
|
||||
"mov %cr4, %eax\n"
|
||||
"orl $0x4, %eax\n"
|
||||
"mov %eax, %cr4\n");
|
||||
klog() << "x86: RDTSC support restricted";
|
||||
}
|
||||
|
||||
if (g_cpu_supports_rdrand) {
|
||||
klog() << "x86: Using RDRAND for good randomness";
|
||||
} else {
|
||||
klog() << "x86: No RDRAND support detected, randomness will be poor";
|
||||
}
|
||||
}
|
||||
|
||||
u32 read_cr0()
|
||||
{
|
||||
u32 cr0;
|
||||
|
@ -822,6 +707,156 @@ Processor& Processor::by_id(u32 cpu)
|
|||
return *procs[cpu];
|
||||
}
|
||||
|
||||
|
||||
void Processor::cpu_detect()
|
||||
{
|
||||
// NOTE: This is called during Processor::early_initialize, we cannot
|
||||
// safely log at this point because we don't have kmalloc
|
||||
// initialized yet!
|
||||
auto set_feature =
|
||||
[&](CPUFeature f) {
|
||||
m_features = static_cast<CPUFeature>(static_cast<u32>(m_features) | static_cast<u32>(f));
|
||||
};
|
||||
m_features = static_cast<CPUFeature>(0);
|
||||
|
||||
CPUID processor_info(0x1);
|
||||
if (processor_info.edx() & (1 << 6))
|
||||
set_feature(CPUFeature::PAE);
|
||||
if (processor_info.edx() & (1 << 13))
|
||||
set_feature(CPUFeature::PGE);
|
||||
if (processor_info.edx() & (1 << 25))
|
||||
set_feature(CPUFeature::SSE);
|
||||
if (processor_info.edx() & (1 << 4))
|
||||
set_feature(CPUFeature::TSC);
|
||||
if (processor_info.ecx() & (1 << 30))
|
||||
set_feature(CPUFeature::RDRAND);
|
||||
|
||||
CPUID extended_processor_info(0x80000001);
|
||||
if (extended_processor_info.edx() & (1 << 20))
|
||||
set_feature(CPUFeature::NX);
|
||||
|
||||
CPUID extended_features(0x7);
|
||||
if (extended_features.ebx() & (1 << 20))
|
||||
set_feature(CPUFeature::SMAP);
|
||||
if (extended_features.ebx() & (1 << 7))
|
||||
set_feature(CPUFeature::SMEP);
|
||||
if (extended_features.ecx() & (1 << 2))
|
||||
set_feature(CPUFeature::UMIP);
|
||||
if (extended_features.ebx() & (1 << 18))
|
||||
set_feature(CPUFeature::RDSEED);
|
||||
}
|
||||
|
||||
void Processor::cpu_setup()
|
||||
{
|
||||
// NOTE: This is called during Processor::early_initialize, we cannot
|
||||
// safely log at this point because we don't have kmalloc
|
||||
// initialized yet!
|
||||
cpu_detect();
|
||||
|
||||
if (has_feature(CPUFeature::SSE))
|
||||
sse_init();
|
||||
|
||||
asm volatile(
|
||||
"movl %%cr0, %%eax\n"
|
||||
"orl $0x00010000, %%eax\n"
|
||||
"movl %%eax, %%cr0\n" ::
|
||||
: "%eax", "memory");
|
||||
|
||||
if (has_feature(CPUFeature::PGE)) {
|
||||
// Turn on CR4.PGE so the CPU will respect the G bit in page tables.
|
||||
asm volatile(
|
||||
"mov %cr4, %eax\n"
|
||||
"orl $0x80, %eax\n"
|
||||
"mov %eax, %cr4\n");
|
||||
}
|
||||
|
||||
if (has_feature(CPUFeature::NX)) {
|
||||
// Turn on IA32_EFER.NXE
|
||||
asm volatile(
|
||||
"movl $0xc0000080, %ecx\n"
|
||||
"rdmsr\n"
|
||||
"orl $0x800, %eax\n"
|
||||
"wrmsr\n");
|
||||
}
|
||||
|
||||
if (has_feature(CPUFeature::SMEP)) {
|
||||
// Turn on CR4.SMEP
|
||||
asm volatile(
|
||||
"mov %cr4, %eax\n"
|
||||
"orl $0x100000, %eax\n"
|
||||
"mov %eax, %cr4\n");
|
||||
}
|
||||
|
||||
if (has_feature(CPUFeature::SMAP)) {
|
||||
// Turn on CR4.SMAP
|
||||
asm volatile(
|
||||
"mov %cr4, %eax\n"
|
||||
"orl $0x200000, %eax\n"
|
||||
"mov %eax, %cr4\n");
|
||||
}
|
||||
|
||||
if (has_feature(CPUFeature::UMIP)) {
|
||||
asm volatile(
|
||||
"mov %cr4, %eax\n"
|
||||
"orl $0x800, %eax\n"
|
||||
"mov %eax, %cr4\n");
|
||||
}
|
||||
|
||||
if (has_feature(CPUFeature::TSC)) {
|
||||
asm volatile(
|
||||
"mov %cr4, %eax\n"
|
||||
"orl $0x4, %eax\n"
|
||||
"mov %eax, %cr4\n");
|
||||
}
|
||||
}
|
||||
|
||||
String Processor::features_string() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
auto feature_to_str =
|
||||
[](CPUFeature f) -> const char*
|
||||
{
|
||||
switch (f) {
|
||||
case CPUFeature::NX:
|
||||
return "nx";
|
||||
case CPUFeature::PAE:
|
||||
return "pae";
|
||||
case CPUFeature::PGE:
|
||||
return "pge";
|
||||
case CPUFeature::RDRAND:
|
||||
return "rdrand";
|
||||
case CPUFeature::RDSEED:
|
||||
return "rdseed";
|
||||
case CPUFeature::SMAP:
|
||||
return "smap";
|
||||
case CPUFeature::SMEP:
|
||||
return "smep";
|
||||
case CPUFeature::SSE:
|
||||
return "sse";
|
||||
case CPUFeature::TSC:
|
||||
return "tsc";
|
||||
case CPUFeature::UMIP:
|
||||
return "umip";
|
||||
// no default statement here intentionally so that we get
|
||||
// a warning if a new feature is forgotten to be added here
|
||||
}
|
||||
// Shouldn't ever happen
|
||||
return "???";
|
||||
};
|
||||
bool first = true;
|
||||
for (u32 flag = 1; flag < sizeof(m_features) * 8; flag <<= 1) {
|
||||
if ((static_cast<u32>(m_features) & flag) != 0) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
builder.append(' ');
|
||||
auto str = feature_to_str(static_cast<CPUFeature>(flag));
|
||||
builder.append(str, strlen(str));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
void Processor::early_initialize(u32 cpu)
|
||||
{
|
||||
m_self = this;
|
||||
|
@ -838,6 +873,8 @@ void Processor::early_initialize(u32 cpu)
|
|||
m_mm_data = nullptr;
|
||||
m_info = nullptr;
|
||||
|
||||
cpu_setup();
|
||||
|
||||
gdt_init();
|
||||
ASSERT(¤t() == this); // sanity check
|
||||
}
|
||||
|
@ -847,12 +884,9 @@ void Processor::initialize(u32 cpu)
|
|||
ASSERT(m_self == this);
|
||||
ASSERT(¤t() == this); // sanity check
|
||||
|
||||
m_cpu = cpu;
|
||||
m_in_irq = 0;
|
||||
|
||||
m_idle_thread = nullptr;
|
||||
m_current_thread = nullptr;
|
||||
m_mm_data = nullptr;
|
||||
klog() << "CPU[" << id() << "]: Supported features: " << features_string();
|
||||
if (!has_feature(CPUFeature::RDRAND))
|
||||
klog() << "CPU[" << id() << "]: No RDRAND support detected, randomness will be poor";
|
||||
|
||||
if (cpu == 0)
|
||||
idt_init();
|
||||
|
|
|
@ -265,7 +265,6 @@ struct RegisterState;
|
|||
|
||||
const DescriptorTablePointer& get_gdtr();
|
||||
const DescriptorTablePointer& get_idtr();
|
||||
void sse_init();
|
||||
void register_interrupt_handler(u8 number, void (*f)());
|
||||
void register_user_callable_interrupt_handler(u8 number, void (*f)());
|
||||
GenericInterruptHandler& get_interrupt_handler(u8 interrupt_number);
|
||||
|
@ -599,6 +598,19 @@ private:
|
|||
SplitQword m_start;
|
||||
};
|
||||
|
||||
enum class CPUFeature : u32 {
|
||||
NX = (1 << 0),
|
||||
PAE = (1 << 1),
|
||||
PGE = (1 << 2),
|
||||
RDRAND = (1 << 3),
|
||||
RDSEED = (1 << 4),
|
||||
SMAP = (1 << 5),
|
||||
SMEP = (1 << 6),
|
||||
SSE = (1 << 7),
|
||||
TSC = (1 << 8),
|
||||
UMIP = (1 << 9)
|
||||
};
|
||||
|
||||
class Thread;
|
||||
struct TrapFrame;
|
||||
|
||||
|
@ -614,6 +626,8 @@ class ProcessorInfo;
|
|||
struct MemoryManagerData;
|
||||
|
||||
class Processor {
|
||||
friend class ProcessorInfo;
|
||||
|
||||
Processor* m_self; // must be first field (%fs offset 0x0)
|
||||
|
||||
DescriptorTablePointer m_gdtr;
|
||||
|
@ -626,6 +640,7 @@ class Processor {
|
|||
|
||||
TSS32 m_tss;
|
||||
static FPUState s_clean_fpu_state;
|
||||
CPUFeature m_features;
|
||||
|
||||
ProcessorInfo* m_info;
|
||||
MemoryManagerData* m_mm_data;
|
||||
|
@ -640,6 +655,11 @@ class Processor {
|
|||
void write_gdt_entry(u16 selector, Descriptor& descriptor);
|
||||
static Vector<Processor*>& processors();
|
||||
|
||||
void cpu_detect();
|
||||
void cpu_setup();
|
||||
|
||||
String features_string() const;
|
||||
|
||||
public:
|
||||
void early_initialize(u32 cpu);
|
||||
void initialize(u32 cpu);
|
||||
|
@ -740,6 +760,11 @@ public:
|
|||
return s_clean_fpu_state;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool has_feature(CPUFeature f) const
|
||||
{
|
||||
return (static_cast<u32>(m_features) & static_cast<u32>(f)) != 0;
|
||||
}
|
||||
|
||||
void check_invoke_scheduler();
|
||||
void invoke_scheduler_async() { m_invoke_scheduler_async = true; }
|
||||
|
||||
|
@ -846,22 +871,9 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void cpu_setup(u32 cpu);
|
||||
|
||||
extern bool g_cpu_supports_nx;
|
||||
extern bool g_cpu_supports_pae;
|
||||
extern bool g_cpu_supports_pge;
|
||||
extern bool g_cpu_supports_rdrand;
|
||||
extern bool g_cpu_supports_rdseed;
|
||||
extern bool g_cpu_supports_smap;
|
||||
extern bool g_cpu_supports_smep;
|
||||
extern bool g_cpu_supports_sse;
|
||||
extern bool g_cpu_supports_tsc;
|
||||
extern bool g_cpu_supports_umip;
|
||||
|
||||
ALWAYS_INLINE void stac()
|
||||
{
|
||||
if (!g_cpu_supports_smap)
|
||||
if (!Processor::current().has_feature(CPUFeature::SMAP))
|
||||
return;
|
||||
asm volatile("stac" ::
|
||||
: "cc");
|
||||
|
@ -869,7 +881,7 @@ ALWAYS_INLINE void stac()
|
|||
|
||||
ALWAYS_INLINE void clac()
|
||||
{
|
||||
if (!g_cpu_supports_smap)
|
||||
if (!Processor::current().has_feature(CPUFeature::SMAP))
|
||||
return;
|
||||
asm volatile("clac" ::
|
||||
: "cc");
|
||||
|
|
|
@ -88,6 +88,9 @@ ProcessorInfo::ProcessorInfo(Processor& processor):
|
|||
copy_brand_string_part_to_buffer(2);
|
||||
m_brandstr = buffer;
|
||||
}
|
||||
|
||||
// Cache the CPU feature string
|
||||
m_features = m_processor.features_string();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ class ProcessorInfo
|
|||
Processor& m_processor;
|
||||
String m_cpuid;
|
||||
String m_brandstr;
|
||||
String m_features;
|
||||
u32 m_display_model;
|
||||
u32 m_display_family;
|
||||
u32 m_stepping;
|
||||
|
@ -47,6 +48,7 @@ public:
|
|||
|
||||
const String& cpuid() const { return m_cpuid; }
|
||||
const String& brandstr() const { return m_brandstr; }
|
||||
const String& features() const { return m_features; }
|
||||
u32 display_model() const { return m_display_model; }
|
||||
u32 display_family() const { return m_display_family; }
|
||||
u32 stepping() const { return m_stepping; }
|
||||
|
|
|
@ -773,6 +773,7 @@ Optional<KBuffer> procfs$cpuinfo(InodeIdentifier)
|
|||
builder.appendf("processor: %u\n", proc.id());
|
||||
builder.appendf("cpuid: %s\n", info.cpuid().characters());
|
||||
builder.appendf("family: %u\n", info.display_family());
|
||||
builder.appendf("features: %s\n", info.features().characters());
|
||||
builder.appendf("model: %u\n", info.display_model());
|
||||
builder.appendf("stepping: %u\n", info.stepping());
|
||||
builder.appendf("type: %u\n", info.type());
|
||||
|
|
|
@ -44,10 +44,12 @@ KernelRng& KernelRng::the()
|
|||
|
||||
KernelRng::KernelRng()
|
||||
{
|
||||
if (g_cpu_supports_rdseed || g_cpu_supports_rdrand) {
|
||||
bool supports_rdseed = Processor::current().has_feature(CPUFeature::RDSEED);
|
||||
bool supports_rdrand = Processor::current().has_feature(CPUFeature::RDRAND);
|
||||
if (supports_rdseed || supports_rdrand) {
|
||||
for (size_t i = 0; i < resource().pool_count * resource().reseed_threshold; ++i) {
|
||||
u32 value = 0;
|
||||
if (g_cpu_supports_rdseed) {
|
||||
if (supports_rdseed) {
|
||||
asm volatile(
|
||||
"1:\n"
|
||||
"rdseed %0\n"
|
||||
|
|
|
@ -80,7 +80,7 @@ void MemoryManager::protect_kernel_image()
|
|||
pte.set_writable(false);
|
||||
}
|
||||
|
||||
if (g_cpu_supports_nx) {
|
||||
if (Processor::current().has_feature(CPUFeature::NX)) {
|
||||
// Disable execution of the kernel data and bss segments.
|
||||
for (size_t i = (FlatPtr)&start_of_kernel_data; i < (FlatPtr)&end_of_kernel_bss; i += PAGE_SIZE) {
|
||||
auto& pte = ensure_pte(kernel_page_directory(), VirtualAddress(i));
|
||||
|
|
|
@ -237,7 +237,7 @@ void Region::map_individual_page_impl(size_t page_index)
|
|||
pte.set_writable(false);
|
||||
else
|
||||
pte.set_writable(is_writable());
|
||||
if (g_cpu_supports_nx)
|
||||
if (Processor::current().has_feature(CPUFeature::NX))
|
||||
pte.set_execute_disabled(!is_executable());
|
||||
pte.set_user_allowed(is_user_accessible());
|
||||
#ifdef MM_DEBUG
|
||||
|
|
|
@ -106,7 +106,6 @@ extern "C" [[noreturn]] void init()
|
|||
setup_serial_debug();
|
||||
|
||||
s_bsp_processor.early_initialize(0);
|
||||
cpu_setup(0);
|
||||
|
||||
kmalloc_init();
|
||||
slab_alloc_init();
|
||||
|
@ -169,7 +168,6 @@ extern "C" [[noreturn]] void init_ap(u32 cpu, Processor* processor_info)
|
|||
|
||||
klog() << "CPU #" << cpu << " processor_info at " << VirtualAddress(FlatPtr(processor_info));
|
||||
|
||||
cpu_setup(cpu);
|
||||
processor_info->initialize(cpu);
|
||||
MemoryManager::initialize(cpu);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue