1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/x86/cpu/cpu.hpp"
4
5#include "mos/assert.hpp"
6#include "mos/platform/platform.hpp"
7#include "mos/platform/platform_defs.hpp"
8#include "mos/syslog/printk.hpp"
9#include "mos/x86/cpu/cpuid.hpp"
10#include "mos/x86/tasks/fpu_context.hpp"
11
12#include <mos_string.hpp>
13
14// clang-format off
15#define do_static_assert(feat) MOS_STATIC_ASSERT(X86_CPUID_LEAF_ENUM(feat) >= 0);
16#define test_ensure_all_leaves_are_supported(feature) do_static_assert(CPU_FEATURE_##feature)
17FOR_ALL_CPU_FEATURES(test_ensure_all_leaves_are_supported)
18#undef test_ensure_all_leaves_are_supported
19#undef do_static_assert
20// clang-format on
21
22void x86_cpu_initialise_caps(void)
23{
24 platform_cpuinfo_t *cpuinfo = &per_cpu(platform_info->cpu)->cpuinfo;
25 memzero(s: cpuinfo, n: sizeof(platform_cpuinfo_t));
26
27#define impl_fill_leaf(_l, _sl, _r) cpuinfo->cpuid[X86_CPUID_LEAF_ENUM(_l, _sl, _r, _)] = x86_cpuid(_r, _l, _sl);
28 FOR_ALL_SUPPORTED_CPUID_LEAF(impl_fill_leaf);
29#undef impl_fill_leaf
30
31 MOS_ASSERT_X(cpu_has_feature(CPU_FEATURE_FSGSBASE), "FSGSBASE is required");
32 MOS_ASSERT_X(cpu_has_feature(CPU_FEATURE_FXSR), "FXSR is required");
33 MOS_ASSERT_X(cpu_has_feature(CPU_FEATURE_SSE), "SSE is required");
34 MOS_ASSERT_X(cpu_has_feature(CPU_FEATURE_XSAVE), "XSAVE is required");
35
36 x86_cpu_set_cr4(x86_cpu_get_cr4() | BIT(7) | BIT(11) | BIT(16)); // set CR4.PGE, CR4.FSGSBASE, CR4.UMIP
37}
38
39void x86_cpu_setup_xsave_area(void)
40{
41 pr_dinfo2(x86_startup, "setting up xsave area...");
42
43 reg_t cr0 = x86_cpu_get_cr0();
44 cr0 &= ~BIT(2); // clear coprocessor emulation CR0.EM
45 cr0 |= BIT(1);
46 x86_cpu_set_cr0(cr0);
47
48 reg_t cr4 = x86_cpu_get_cr4();
49 cr4 |= BIT(9) | BIT(10) | BIT(18); // set CR4.OSFXSR, CR4.OSXMMEXCPT and CR4.OSXSAVE
50 x86_cpu_set_cr4(cr4);
51
52 reg_t xcr0 = XCR0_X87 | XCR0_SSE; // bit 0, 1
53 size_t xsave_size = 512; // X87 + SSE
54
55 // SSE
56 xcr0 |= XCR0_SSE; // bit 1
57 xsave_size += 64; // XSAVE header
58
59 // AVX
60 if (cpu_has_feature(CPU_FEATURE_AVX))
61 xcr0 |= XCR0_AVX;
62
63 static const char *const xcr0_names[] = {
64 /*0*/ "x87", //
65 /*1*/ "SSE", //
66 /*2*/ "AVX", //
67 /*3*/ "MPX BNDREGS", //
68 /*4*/ "MPX BNDCSR", //
69 /*5*/ "AVX-512 OPMASK", //
70 /*6*/ "AVX-512 ZMM0-15", //
71 /*7*/ "AVX-512 ZMM16-31", //
72 /*8*/ "PT", //
73 /*9*/ "PKRU", //
74 };
75
76 for (size_t state_component = 2; state_component < 64; state_component++)
77 {
78 reg32_t size, offset, ecx, edx;
79 __cpuid_count(0xd, state_component, size, offset, ecx, edx);
80 if (size && offset && ((ecx & BIT(0)) == 0))
81 {
82 const char *const name = state_component < MOS_ARRAY_SIZE(xcr0_names) ? xcr0_names[state_component] : "<unknown>";
83 pr_dinfo2(x86_startup, "XSAVE state component '%s': size=%d, offset=%d", name, size, offset);
84
85 if (xcr0 & BIT(state_component))
86 {
87 pr_dcont(x86_startup, " (enabled)");
88 xsave_size += size;
89 }
90 }
91 }
92
93 pr_dinfo2(x86_startup, "XSAVE area size: %zu", xsave_size);
94
95 __asm__ volatile("xsetbv" : : "c"(0), "a"(xcr0), "d"(xcr0 >> 32));
96 xsave_area_slab.ent_size = xsave_size;
97}
98