From 3983e7f35d5e2a839ebd6423843366f2d19cead8 Mon Sep 17 00:00:00 2001 From: Intel A80486DX2-66 Date: Fri, 8 Mar 2024 14:56:35 +0300 Subject: [PATCH] C: add cpuid_vendor_id.mod.c --- c-programming/.gitignore | 1 + c-programming/sys/cpuid_vendor_id.mod.c | 82 +++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 c-programming/sys/cpuid_vendor_id.mod.c diff --git a/c-programming/.gitignore b/c-programming/.gitignore index f3dbb58..522dab0 100644 --- a/c-programming/.gitignore +++ b/c-programming/.gitignore @@ -53,3 +53,4 @@ # Custom **/*.tmp +!**/*.mod.c diff --git a/c-programming/sys/cpuid_vendor_id.mod.c b/c-programming/sys/cpuid_vendor_id.mod.c new file mode 100644 index 0000000..9f9851d --- /dev/null +++ b/c-programming/sys/cpuid_vendor_id.mod.c @@ -0,0 +1,82 @@ +/* + * cpuid_vendor_id.mod.c + * + * The file is a modified version of a gist "cpuid_vendor_id.c" by leiless: + * https://gist.github.com/leiless/8b8603ae31c00fe38d2e97d94462a5a5 + * (revision 73830d4b10090dcf6748cc60a0aacee252cd9e9d2dd54549aa7b995321380091) + * + * The following license information applies for the modifications: + * Author: Intel A80486DX2-66 + * License: Creative Commons Zero 1.0 Universal + */ + +#if !(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || \ + defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(__i386) || defined(__i386__) || defined(__IA32__) || \ + defined(_M_I86) || defined(_M_IX86) || defined(__X86__) || defined(_X86_)) +# error "This code isn't supposed to work on non-x86 CPUs." +#endif + +#include + +#ifdef _WIN32 +#include // __cpuid() +#endif + +typedef unsigned int cpuid_t[4]; + +#define EAX 0 +#define EBX 1 +#define ECX 2 +#define EDX 3 + +// https://elixir.bootlin.com/linux/latest/source/arch/x86/include/asm/ +// processor.h#L216 +// +// https://stackoverflow.com/questions/6491566/getting-the-machine-serial +// -number-and-cpu-id-using-c-c-in-linux +// +// https://stackoverflow.com/questions/1666093/cpuid-implementations-in-c +static inline void native_cpuid(unsigned int function_id, cpuid_t r) { +#ifdef _WIN32 + __cpuid((int *) r, (int) function_id); +#else + r[EAX] = function_id; + r[ECX] = 0; + + // NOTE:XXX: Register ECX is often an input as well as an output + asm volatile("cpuid" + : "=a" (r[EAX]), + "=b" (r[EBX]), + "=c" (r[ECX]), + "=d" (r[EDX]) + : "0" (r[EAX]), "2" (r[ECX]) + : "memory"); +#endif +} + +#define VENDOR_ID_LEN 13 + +/* + * FIXME: you have to make sure the vendor argument is at least lengthed + * VENDOR_ID_LEN + */ +static inline void cpuid_vendor_id(char vendor[VENDOR_ID_LEN]) { + // Always initialize the result in case of buggy CPU (like ES/QS CPUs) + cpuid_t v; + native_cpuid(0, v); + + // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex + // ?view=msvc-170#example + ((unsigned int *) vendor)[0] = v[EBX]; + ((unsigned int *) vendor)[1] = v[EDX]; + ((unsigned int *) vendor)[2] = v[ECX]; + vendor[VENDOR_ID_LEN - 1] = '\0'; +} + +int main(void) { + char vendor_string[VENDOR_ID_LEN]; + cpuid_vendor_id(vendor_string); + printf("CPU Vendor ID: '%s'\n", vendor_string); + return 0; +}