diff options
author | Tom <tomut@yahoo.com> | 2020-06-27 17:06:33 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-01 12:07:01 +0200 |
commit | d98edb31715a528056c956b842b9d5ea959d4304 (patch) | |
tree | f90f29ab3dfce48f687d3ed812e172b6d324a65d /Kernel | |
parent | fb41d89384cb5bbdf602ae41ae7e038fb48a34ce (diff) | |
download | serenity-d98edb31715a528056c956b842b9d5ea959d4304.zip |
Kernel: List all CPUs in /proc/cpuinfo
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Arch/i386/CPU.cpp | 25 | ||||
-rw-r--r-- | Kernel/Arch/i386/CPU.h | 25 | ||||
-rw-r--r-- | Kernel/Arch/i386/ProcessorInfo.cpp | 95 | ||||
-rw-r--r-- | Kernel/Arch/i386/ProcessorInfo.h | 56 | ||||
-rw-r--r-- | Kernel/Assertions.h | 3 | ||||
-rw-r--r-- | Kernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Kernel/Devices/Device.h | 1 | ||||
-rw-r--r-- | Kernel/Devices/FullDevice.cpp | 1 | ||||
-rw-r--r-- | Kernel/FileSystem/ProcFS.cpp | 78 | ||||
-rw-r--r-- | Kernel/VM/MemoryManager.cpp | 6 | ||||
-rw-r--r-- | Kernel/VM/PhysicalPage.h | 1 | ||||
-rw-r--r-- | Kernel/VM/Region.h | 1 |
12 files changed, 229 insertions, 64 deletions
diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp index a29b4ef4af..63cdb482cb 100644 --- a/Kernel/Arch/i386/CPU.cpp +++ b/Kernel/Arch/i386/CPU.cpp @@ -28,6 +28,7 @@ #include <AK/String.h> #include <AK/Types.h> #include <Kernel/Arch/i386/CPU.h> +#include <Kernel/Arch/i386/ProcessorInfo.h> #include <Kernel/Arch/i386/ISRStubs.h> #include <Kernel/Interrupts/APIC.h> #include <Kernel/Interrupts/GenericInterruptHandler.h> @@ -795,6 +796,22 @@ u32 read_dr6() FPUState Processor::s_clean_fpu_state; +static Vector<Processor*>* s_processors; + +Vector<Processor*>& Processor::processors() +{ + ASSERT(s_processors); + return *s_processors; +} + +Processor& Processor::by_id(u32 cpu) +{ + auto& procs = processors(); + ASSERT(procs[cpu] != nullptr); + ASSERT(procs.size() > cpu); + return *procs[cpu]; +} + void Processor::initialize(u32 cpu) { m_self = this; @@ -817,6 +834,14 @@ void Processor::initialize(u32 cpu) : "=m"(s_clean_fpu_state)); } + m_info = new ProcessorInfo(*this); + + if (!s_processors) + s_processors = new Vector<Processor*>(); + if (cpu >= s_processors->size()) + s_processors->resize(cpu + 1); + (*s_processors)[cpu] = this; + klog() << "CPU #" << cpu << " using Processor at " << VirtualAddress(FlatPtr(this)); } diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h index cc6eebcdb2..a19285f396 100644 --- a/Kernel/Arch/i386/CPU.h +++ b/Kernel/Arch/i386/CPU.h @@ -28,6 +28,7 @@ #include <AK/Badge.h> #include <AK/Noncopyable.h> +#include <AK/Vector.h> #include <Kernel/PhysicalAddress.h> #include <Kernel/VirtualAddress.h> @@ -609,6 +610,8 @@ struct TrapFrame; #define GDT_SELECTOR_PROC 0x30 #define GDT_SELECTOR_TSS 0x38 +class ProcessorInfo; + class Processor { Processor* m_self; // must be first field (%fs offset 0x0) @@ -622,11 +625,14 @@ class Processor { TSS32 m_tss; static FPUState s_clean_fpu_state; + ProcessorInfo* m_info; + bool m_invoke_scheduler_async; void gdt_init(); void write_raw_gdt_entry(u16 selector, u32 low, u32 high); void write_gdt_entry(u16 selector, Descriptor& descriptor); + static Vector<Processor*>& processors(); public: void initialize(u32 cpu); @@ -634,15 +640,30 @@ public: Descriptor& get_gdt_entry(u16 selector); void flush_gdt(); const DescriptorTablePointer& get_gdtr(); + + static Processor& by_id(u32 cpu); + + template <typename Callback> + static inline IterationDecision for_each(Callback callback) + { + auto& procs = processors(); + for (auto it = procs.begin(); it != procs.end(); ++it) { + if (callback(**it) == IterationDecision::Break) + return IterationDecision::Break; + } + return IterationDecision::Continue; + } + + ALWAYS_INLINE ProcessorInfo& info() { return *m_info; } ALWAYS_INLINE static Processor& current() { return *(Processor*)read_fs_u32(0); } - ALWAYS_INLINE static u32 id() + ALWAYS_INLINE u32 id() { - return current().m_cpu; + return m_cpu; } ALWAYS_INLINE u32& in_irq() diff --git a/Kernel/Arch/i386/ProcessorInfo.cpp b/Kernel/Arch/i386/ProcessorInfo.cpp new file mode 100644 index 0000000000..21bb32549e --- /dev/null +++ b/Kernel/Arch/i386/ProcessorInfo.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <AK/Assertions.h> +#include <AK/HashMap.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> + +namespace Kernel { + +ProcessorInfo::ProcessorInfo(Processor& processor): + m_processor(processor) +{ + { + CPUID cpuid(0); + StringBuilder builder; + auto emit_u32 = [&](u32 value) { + builder.appendf("%c%c%c%c", + value & 0xff, + (value >> 8) & 0xff, + (value >> 16) & 0xff, + (value >> 24) & 0xff); + }; + emit_u32(cpuid.ebx()); + emit_u32(cpuid.edx()); + emit_u32(cpuid.ecx()); + m_cpuid = builder.build(); + } + { + CPUID cpuid(1); + m_stepping = cpuid.eax() & 0xf; + u32 model = (cpuid.eax() >> 4) & 0xf; + u32 family = (cpuid.eax() >> 8) & 0xf; + m_type = (cpuid.eax() >> 12) & 0x3; + u32 extended_model = (cpuid.eax() >> 16) & 0xf; + u32 extended_family = (cpuid.eax() >> 20) & 0xff; + if (family == 15) { + m_display_family = family + extended_family; + m_display_model = model + (extended_model << 4); + } else if (family == 6) { + m_display_family = family; + m_display_model = model + (extended_model << 4); + } else { + m_display_family = family; + m_display_model = model; + } + } + { + // FIXME: Check first that this is supported by calling CPUID with eax=0x80000000 + // and verifying that the returned eax>=0x80000004. + alignas(u32) char buffer[48]; + u32* bufptr = reinterpret_cast<u32*>(buffer); + auto copy_brand_string_part_to_buffer = [&](u32 i) { + CPUID cpuid(0x80000002 + i); + *bufptr++ = cpuid.eax(); + *bufptr++ = cpuid.ebx(); + *bufptr++ = cpuid.ecx(); + *bufptr++ = cpuid.edx(); + }; + copy_brand_string_part_to_buffer(0); + copy_brand_string_part_to_buffer(1); + copy_brand_string_part_to_buffer(2); + m_brandstr = buffer; + } +} + +} + +#include <AK/String.h> diff --git a/Kernel/Arch/i386/ProcessorInfo.h b/Kernel/Arch/i386/ProcessorInfo.h new file mode 100644 index 0000000000..5e71e8c26d --- /dev/null +++ b/Kernel/Arch/i386/ProcessorInfo.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <AK/String.h> + +namespace Kernel { + +class Processor; + +class ProcessorInfo +{ + Processor& m_processor; + String m_cpuid; + String m_brandstr; + u32 m_display_model; + u32 m_display_family; + u32 m_stepping; + u32 m_type; + +public: + ProcessorInfo(Processor& processor); + + const String& cpuid() const { return m_cpuid; } + const String& brandstr() const { return m_brandstr; } + u32 display_model() const { return m_display_model; } + u32 display_family() const { return m_display_family; } + u32 stepping() const { return m_stepping; } + u32 type() const { return m_type; } +}; + +} diff --git a/Kernel/Assertions.h b/Kernel/Assertions.h index 54b57fad3c..5a82abd29c 100644 --- a/Kernel/Assertions.h +++ b/Kernel/Assertions.h @@ -26,8 +26,6 @@ #pragma once -#include <Kernel/Arch/i386/CPU.h> - #define __STRINGIFY_HELPER(x) #x #define __STRINGIFY(x) __STRINGIFY_HELPER(x) @@ -48,6 +46,7 @@ if (!(x)) \ CRASH(); \ } while (0) + #define ASSERT_INTERRUPTS_DISABLED() ASSERT(!(cpu_flags() & 0x200)) #define ASSERT_INTERRUPTS_ENABLED() ASSERT(cpu_flags() & 0x200) #define TODO ASSERT_NOT_REACHED diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 4c25ce009f..330654c0ed 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -4,6 +4,7 @@ set(KERNEL_SOURCES ACPI/MultiProcessorParser.cpp ACPI/Parser.cpp Arch/i386/CPU.cpp + Arch/i386/ProcessorInfo.cpp Arch/PC/BIOS.cpp CMOS.cpp CommandLine.cpp diff --git a/Kernel/Devices/Device.h b/Kernel/Devices/Device.h index 669a855893..8fa97a02ab 100644 --- a/Kernel/Devices/Device.h +++ b/Kernel/Devices/Device.h @@ -36,6 +36,7 @@ // - CharacterDevice (sequential) #include <AK/Function.h> #include <AK/HashMap.h> +#include <Kernel/Arch/i386/CPU.h> #include <Kernel/FileSystem/File.h> #include <Kernel/UnixTypes.h> diff --git a/Kernel/Devices/FullDevice.cpp b/Kernel/Devices/FullDevice.cpp index 895c34fc01..97c7c5e70b 100644 --- a/Kernel/Devices/FullDevice.cpp +++ b/Kernel/Devices/FullDevice.cpp @@ -27,6 +27,7 @@ #include "FullDevice.h" #include <AK/Memory.h> #include <AK/StdLibExtras.h> +#include <Kernel/Arch/i386/CPU.h> #include <LibC/errno_numbers.h> namespace Kernel { diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index c06795aab5..1b46072390 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -29,6 +29,7 @@ #include <AK/JsonObjectSerializer.h> #include <AK/JsonValue.h> #include <Kernel/Arch/i386/CPU.h> +#include <Kernel/Arch/i386/ProcessorInfo.h> #include <Kernel/CommandLine.h> #include <Kernel/Console.h> #include <Kernel/Devices/BlockDevice.h> @@ -758,63 +759,26 @@ Optional<KBuffer> procfs$df(InodeIdentifier) Optional<KBuffer> procfs$cpuinfo(InodeIdentifier) { KBufferBuilder builder; - { - CPUID cpuid(0); - builder.appendf("cpuid: "); - auto emit_u32 = [&](u32 value) { - builder.appendf("%c%c%c%c", - value & 0xff, - (value >> 8) & 0xff, - (value >> 16) & 0xff, - (value >> 24) & 0xff); - }; - emit_u32(cpuid.ebx()); - emit_u32(cpuid.edx()); - emit_u32(cpuid.ecx()); - builder.appendf("\n"); - } - { - CPUID cpuid(1); - u32 stepping = cpuid.eax() & 0xf; - u32 model = (cpuid.eax() >> 4) & 0xf; - u32 family = (cpuid.eax() >> 8) & 0xf; - u32 type = (cpuid.eax() >> 12) & 0x3; - u32 extended_model = (cpuid.eax() >> 16) & 0xf; - u32 extended_family = (cpuid.eax() >> 20) & 0xff; - u32 display_model; - u32 display_family; - if (family == 15) { - display_family = family + extended_family; - display_model = model + (extended_model << 4); - } else if (family == 6) { - display_family = family; - display_model = model + (extended_model << 4); - } else { - display_family = family; - display_model = model; - } - builder.appendf("family: %u\n", display_family); - builder.appendf("model: %u\n", display_model); - builder.appendf("stepping: %u\n", stepping); - builder.appendf("type: %u\n", type); - } - { - // FIXME: Check first that this is supported by calling CPUID with eax=0x80000000 - // and verifying that the returned eax>=0x80000004. - alignas(u32) char buffer[48]; - u32* bufptr = reinterpret_cast<u32*>(buffer); - auto copy_brand_string_part_to_buffer = [&](u32 i) { - CPUID cpuid(0x80000002 + i); - *bufptr++ = cpuid.eax(); - *bufptr++ = cpuid.ebx(); - *bufptr++ = cpuid.ecx(); - *bufptr++ = cpuid.edx(); - }; - copy_brand_string_part_to_buffer(0); - copy_brand_string_part_to_buffer(1); - copy_brand_string_part_to_buffer(2); - builder.appendf("brandstr: \"%s\"\n", buffer); - } + bool first = true; + + Processor::for_each( + [&](Processor& proc) -> IterationDecision + { + if (first) + first = false; + else + builder.append('\n'); + + auto& info = proc.info(); + 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("model: %u\n", info.display_model()); + builder.appendf("stepping: %u\n", info.stepping()); + builder.appendf("type: %u\n", info.type()); + builder.appendf("brandstr: \"%s\"\n", info.brandstr().characters()); + return IterationDecision::Continue; + }); return builder.build(); } diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index 5934ce1985..a185e15000 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -270,16 +270,16 @@ PageFaultResponse MemoryManager::handle_page_fault(const PageFault& fault) ASSERT(Thread::current); ScopedSpinLock lock(s_lock); if (Processor::current().in_irq()) { - dbg() << "CPU[" << Processor::id() << "] BUG! Page fault while handling IRQ! code=" << fault.code() << ", vaddr=" << fault.vaddr() << ", irq level: " << Processor::current().in_irq(); + dbg() << "CPU[" << Processor::current().id() << "] BUG! Page fault while handling IRQ! code=" << fault.code() << ", vaddr=" << fault.vaddr() << ", irq level: " << Processor::current().in_irq(); dump_kernel_regions(); return PageFaultResponse::ShouldCrash; } #ifdef PAGE_FAULT_DEBUG - dbg() << "MM: CPU[" << Processor::id() << "] handle_page_fault(" << String::format("%w", fault.code()) << ") at " << fault.vaddr(); + dbg() << "MM: CPU[" << Processor::current().id() << "] handle_page_fault(" << String::format("%w", fault.code()) << ") at " << fault.vaddr(); #endif auto* region = region_from_vaddr(fault.vaddr()); if (!region) { - klog() << "CPU[" << Processor::id() << "] NP(error) fault at invalid address " << fault.vaddr(); + klog() << "CPU[" << Processor::current().id() << "] NP(error) fault at invalid address " << fault.vaddr(); return PageFaultResponse::ShouldCrash; } diff --git a/Kernel/VM/PhysicalPage.h b/Kernel/VM/PhysicalPage.h index 1e9b573947..498ce7dd03 100644 --- a/Kernel/VM/PhysicalPage.h +++ b/Kernel/VM/PhysicalPage.h @@ -27,6 +27,7 @@ #pragma once #include <AK/NonnullRefPtr.h> +#include <Kernel/Arch/i386/CPU.h> #include <Kernel/Assertions.h> #include <Kernel/Heap/SlabAllocator.h> #include <Kernel/PhysicalAddress.h> diff --git a/Kernel/VM/Region.h b/Kernel/VM/Region.h index 445f0a2825..d2dc634f5c 100644 --- a/Kernel/VM/Region.h +++ b/Kernel/VM/Region.h @@ -29,6 +29,7 @@ #include <AK/InlineLinkedList.h> #include <AK/String.h> #include <AK/Weakable.h> +#include <Kernel/Arch/i386/CPU.h> #include <Kernel/Heap/SlabAllocator.h> #include <Kernel/VM/RangeAllocator.h> #include <Kernel/VM/VMObject.h> |