diff --git a/bin/system-info.c b/bin/system-info.c index 2f58661c87e00cab51cee1637460e7b2d249ac3f..7bd36df9bef41f0c8e60dbeb86f35fea51226054 100644 --- a/bin/system-info.c +++ b/bin/system-info.c @@ -251,6 +251,49 @@ jsonify_flags (JsonBuilder *builder, g_type_class_unref (class); } +static void +jsonify_flags_string_bool_map (JsonBuilder *builder, + GType flags_type, + unsigned int values) +{ + GFlagsClass *class; + GFlagsValue *flags_value; + + g_return_if_fail (G_TYPE_IS_FLAGS (flags_type)); + + class = g_type_class_ref (flags_type); + + for (flags_value = class->values; flags_value->value_name; flags_value++) + { + /* Skip the numerically zero flag (usually "none") */ + if (flags_value->value == 0) + continue; + + json_builder_set_member_name (builder, flags_value->value_nick); + if ((flags_value->value & values) == flags_value->value) + { + json_builder_add_boolean_value (builder, TRUE); + values &= ~flags_value->value; + } + else + { + json_builder_add_boolean_value (builder, FALSE); + } + } + + if (values) + { + gchar *rest = g_strdup_printf ("0x%x", values); + + json_builder_set_member_name (builder, rest); + json_builder_add_boolean_value (builder, TRUE); + + g_free (rest); + } + + g_type_class_unref (class); +} + static void jsonify_library_issues (JsonBuilder *builder, SrtLibraryIssues issues) @@ -306,6 +349,13 @@ jsonify_locale_issues (JsonBuilder *builder, jsonify_flags (builder, SRT_TYPE_LOCALE_ISSUES, issues); } +static void +jsonify_x86_features (JsonBuilder *builder, + SrtX86FeatureFlags features) +{ + jsonify_flags_string_bool_map (builder, SRT_TYPE_X86_FEATURE_FLAGS, features); +} + static void print_libraries_details (JsonBuilder *builder, GList *libraries, @@ -743,6 +793,7 @@ main (int argc, SrtSteamIssues steam_issues = SRT_STEAM_ISSUES_NONE; SrtRuntimeIssues runtime_issues = SRT_RUNTIME_ISSUES_NONE; SrtLocaleIssues locale_issues = SRT_LOCALE_ISSUES_NONE; + SrtX86FeatureFlags x86_features = SRT_X86_FEATURE_NONE; char *expectations = NULL; gboolean verbose = FALSE; JsonBuilder *builder; @@ -1213,6 +1264,14 @@ main (int argc, } json_builder_end_array (builder); + json_builder_set_member_name (builder, "cpu-features"); + json_builder_begin_object (builder); + { + x86_features = srt_system_info_get_x86_features (info); + jsonify_x86_features (builder, x86_features); + } + json_builder_end_object (builder); + json_builder_end_object (builder); // End global object JsonNode *root = json_builder_get_root (builder); diff --git a/bin/system-info.md b/bin/system-info.md index 498e5fec96089473ebb310b79aabd4d70ef50f48..12a745421276ccba1695eb73ac0fb95615f11362 100644 --- a/bin/system-info.md +++ b/bin/system-info.md @@ -652,6 +652,23 @@ keys: **steam_uri_handler** : A boolean value indicating whether this entry can open `steam:` URIs. +**cpu-features** +: An object decribing some of the features that the CPU in use supports. + Currently it has the following string keys, each with a boolean + value indicating whether the CPU feature is present or absent: + + **x86-64** + : Whether the CPU supports the "Long mode", i.e. x86-64 architecture + (listed as `lm` in `/proc/cpuinfo`). + + **sse3** + : Whether the CPU supports the SSE3 extension (Streaming SIMD Extensions + 3, listed as `pni` (Prescott New Instructions) in `/proc/cpuinfo`). + + **cmpxchg16b** + : Whether the CPU supports the CMPXCHG16B instruction + (listed as `cx16` in `/proc/cpuinfo`). + # EXIT STATUS 0 diff --git a/steam-runtime-tools/cpu-feature-internal.h b/steam-runtime-tools/cpu-feature-internal.h new file mode 100644 index 0000000000000000000000000000000000000000..76f1ecc5fd9c1ec673e83bd2187484e955f4e567 --- /dev/null +++ b/steam-runtime-tools/cpu-feature-internal.h @@ -0,0 +1,35 @@ +/*<private_header>*/ +/* + * Copyright © 2020 Collabora Ltd. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include "steam-runtime-tools/cpu-feature.h" + +#include <glib.h> +#include <glib-object.h> + +G_GNUC_INTERNAL +SrtX86FeatureFlags _srt_feature_get_x86_flags (void); diff --git a/steam-runtime-tools/cpu-feature.c b/steam-runtime-tools/cpu-feature.c new file mode 100644 index 0000000000000000000000000000000000000000..79579b38a6b6822b68b2c031223ce816a0167b72 --- /dev/null +++ b/steam-runtime-tools/cpu-feature.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2020 Collabora Ltd. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "steam-runtime-tools/cpu-feature.h" +#include "steam-runtime-tools/cpu-feature-internal.h" + +#include <sys/stat.h> +#include <sys/types.h> +#include <cpuid.h> + +#include "steam-runtime-tools/glib-compat.h" +#include "steam-runtime-tools/utils.h" + +/** +* SECTION:cpu-feature +* @title: CPU features +* @short_description: Information about supported CPU features +* @include: steam-runtime-tools/steam-runtime-tools.h +* +* #SrtX86FeatureFlags represents the features that the CPU supports. +*/ + +SrtX86FeatureFlags +_srt_feature_get_x86_flags (void) +{ + guint eax = 0; + guint ebx = 0; + guint ecx = 0; + guint edx = 0; + int result; + SrtX86FeatureFlags features = SRT_X86_FEATURE_NONE; + + /* Get the list of basic features (leaf 1) */ + result = __get_cpuid (1, &eax, &ebx, &ecx, &edx); + if (result != 1) + { + g_debug ("Something went wrong trying to list supported x86 features"); + return features; + } + + if (ecx & bit_CMPXCHG16B) + features |= SRT_X86_FEATURE_CMPXCHG16B; + + if (ecx & bit_SSE3) + features |= SRT_X86_FEATURE_SSE3; + + result = __get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx); + if (result != 1) + { + g_debug ("Something went wrong trying to list extended supported x86 features"); + return features; + } + + /* Long mode, 64-bit capable */ + if (edx & bit_LM) + features |= SRT_X86_FEATURE_X86_64; + + return features; +} \ No newline at end of file diff --git a/steam-runtime-tools/cpu-feature.h b/steam-runtime-tools/cpu-feature.h new file mode 100644 index 0000000000000000000000000000000000000000..111c19287c249ffb605f7b3e2ff7a590b5524b10 --- /dev/null +++ b/steam-runtime-tools/cpu-feature.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2020 Collabora Ltd. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#if !defined(_SRT_IN_SINGLE_HEADER) && !defined(_SRT_COMPILATION) +#error "Do not include directly, use <steam-runtime-tools/steam-runtime-tools.h>" +#endif + +/** + * SrtX86FeatureFlags: + * @SRT_X86_FEATURE_NONE: None of the features listed here are supported + * @SRT_X86_FEATURE_X86_64: The CPU supports the "Long mode", where an OS can + * access 64-bit instructions and registers (i.e. x86-64 architecture), + * indicated by `lm` in Linux `/proc/cpuinfo` + * @SRT_X86_FEATURE_SSE3: The CPU supports the SSE3 extension (Streaming SIMD + * Extensions 3, also known as Prescott New Instructions), indicated by + * `pni` in Linux `/proc/cpuinfo` + * @SRT_X86_FEATURE_CMPXCHG16B: The CPU supports the CMPXCHG16B instruction, + * indicated by `cx16` in Linux `/proc/cpuinfo` + * + * A bitfield with flags representing the features that the CPU supports, or + * %SRT_X86_FEATURE_NONE (which is numerically zero) if none of the features + * we checked are supported. + * + * In general, more bits set means more instructions are supported. + * + * At the time of writing, the Steam client requires %SRT_X86_FEATURE_X86_64, + * %SRT_X86_FEATURE_SSE3 and %SRT_X86_FEATURE_CMPXCHG16B. + */ +typedef enum +{ + SRT_X86_FEATURE_X86_64 = (1 << 0), + SRT_X86_FEATURE_SSE3 = (1 << 1), + SRT_X86_FEATURE_CMPXCHG16B = (1 << 2), + SRT_X86_FEATURE_NONE = 0 +} SrtX86FeatureFlags; diff --git a/steam-runtime-tools/meson.build b/steam-runtime-tools/meson.build index 4a3b4f3383175ed10350fd5b8e385c74277036cc..665ce5b9b45187f748cec8281d63b5bbb1735522 100644 --- a/steam-runtime-tools/meson.build +++ b/steam-runtime-tools/meson.build @@ -24,6 +24,8 @@ libsteamrt_sources = [ 'architecture-internal.h', 'architecture.c', + 'cpu-feature-internal.h', + 'cpu-feature.c', 'desktop-entry-internal.h', 'desktop-entry.c', 'graphics-internal.h', @@ -45,6 +47,7 @@ libsteamrt_sources = [ libsteamrt_public_headers = [ 'architecture.h', + 'cpu-feature.h', 'desktop-entry.h', 'graphics.h', 'library.h', diff --git a/steam-runtime-tools/steam-runtime-tools.h b/steam-runtime-tools/steam-runtime-tools.h index a2afe659f3f52ca47ccb88a785282bddad28c043..ee1e2812037d4b67d912ed05189f6c0aebd039b6 100644 --- a/steam-runtime-tools/steam-runtime-tools.h +++ b/steam-runtime-tools/steam-runtime-tools.h @@ -28,6 +28,7 @@ #define _SRT_IN_SINGLE_HEADER #include <steam-runtime-tools/architecture.h> +#include <steam-runtime-tools/cpu-feature.h> #include <steam-runtime-tools/desktop-entry.h> #include <steam-runtime-tools/enums.h> #include <steam-runtime-tools/graphics.h> diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c index c0061848a8db9869435c71cad48250997e932669..19c5208e7f5949a183e44a3be1970510f3009a6b 100644 --- a/steam-runtime-tools/system-info.c +++ b/steam-runtime-tools/system-info.c @@ -27,6 +27,7 @@ #include "steam-runtime-tools/architecture.h" #include "steam-runtime-tools/architecture-internal.h" +#include "steam-runtime-tools/cpu-feature-internal.h" #include "steam-runtime-tools/desktop-entry-internal.h" #include "steam-runtime-tools/glib-compat.h" #include "steam-runtime-tools/graphics.h" @@ -154,6 +155,11 @@ struct _SrtSystemInfo GList *values; gboolean have_data; } desktop_entry; + struct + { + SrtX86FeatureFlags x86_features; + gboolean have_x86; + } cpu_features; SrtOsRelease os_release; SrtTestFlags test_flags; Tristate can_write_uinput; @@ -3052,3 +3058,32 @@ srt_system_info_list_desktop_entries (SrtSystemInfo *self) return g_list_reverse (ret); } + +static void +ensure_x86_features_cached (SrtSystemInfo *self) +{ + if (self->cpu_features.have_x86) + return; + + self->cpu_features.x86_features = _srt_feature_get_x86_flags (); + self->cpu_features.have_x86 = TRUE; +} + +/** + * srt_system_info_get_x86_features: + * @self: The #SrtSystemInfo object + * + * Detect and return a list of x86 features that the CPU supports. + * + * Returns: x86 CPU supported features, or %SRT_X86_FEATURE_NONE + * if none of the checked features are supported. + */ +SrtX86FeatureFlags +srt_system_info_get_x86_features (SrtSystemInfo *self) +{ + g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), SRT_X86_FEATURE_NONE); + + ensure_x86_features_cached (self); + + return self->cpu_features.x86_features; +} diff --git a/steam-runtime-tools/system-info.h b/steam-runtime-tools/system-info.h index 266ef0584ca3cceea7609af2cf006db3f8ac9b1c..08ecca115be109d3272339415ca364b986d8bd26 100644 --- a/steam-runtime-tools/system-info.h +++ b/steam-runtime-tools/system-info.h @@ -32,6 +32,7 @@ #include <glib.h> #include <glib-object.h> +#include <steam-runtime-tools/cpu-feature.h> #include <steam-runtime-tools/graphics.h> #include <steam-runtime-tools/library.h> #include <steam-runtime-tools/locale.h> @@ -197,6 +198,8 @@ gchar **srt_system_info_list_driver_environment (SrtSystemInfo *self); GList *srt_system_info_list_desktop_entries (SrtSystemInfo *self); +SrtX86FeatureFlags srt_system_info_get_x86_features (SrtSystemInfo *self); + #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC G_DEFINE_AUTOPTR_CLEANUP_FUNC (SrtSystemInfo, g_object_unref) #endif diff --git a/tests/system-info-cli.c b/tests/system-info-cli.c index 050220b88c4b3dd94b13a205e494c9b0ead1e7bf..9744747842e8d49d305bf25c3706eb0e0936e3f5 100644 --- a/tests/system-info-cli.c +++ b/tests/system-info-cli.c @@ -132,6 +132,8 @@ libraries_presence (Fixture *f, g_assert_true (json_object_has_member (json, "driver_environment")); + g_assert_true (json_object_has_member (json, "cpu-features")); + g_assert_true (json_object_has_member (json, "architectures")); json = json_object_get_object_member (json, "architectures");