5

In Windows X86, the CPU brand can be queried with cpuid intrinsic function. Here is a sample of the code:

#include <stdio.h>
#include <intrin.h>

int main(void)
{
    int cpubrand[4 * 3];

    __cpuid(&cpubrand[0], 0x80000002);
    __cpuid(&cpubrand[4], 0x80000003);
    __cpuid(&cpubrand[8], 0x80000004);

    char str[48];
    memset(str, 0, sizeof str);
    memcpy(str, cpubrand, sizeof cpubrand);
    printf("%s\n", str);
}

What is the alternative of this in Windows ARM64?

Biswapriyo
  • 3,491
  • 3
  • 22
  • 42

4 Answers4

6

The direct way to get this information would be to read the Main ID Register MIDR_EL1. This could be done via the mrs instruction in (inline) assembly or via the _ReadStatusReg instrinct.

Unfortunately this register cannot be accessed from user mode (i.e. EL0) and every attempt throws an exception. At Linux the behavior is then emulated so that MIDR_EL1 can still be accessed. However, I do not know or have the opportunity to test whether Windows also offers this feature.


References:

fcdt
  • 2,371
  • 5
  • 14
  • 26
4

Although probably not the answer you're looking for (i.e. directly interrogating the CPU), you can fetch the "ProcessorNameString" value from the Windows Registry using code like the following:

#define BUFSIZ 64 // For easy adjustment of limits, if required

char answer[BUFSIZ] = "Error Reading CPU Name from Registry!", inBuffer[BUFSIZ] = "";
const char *csName = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
HKEY hKey;  DWORD gotType, gotSize = BUFSIZ;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, csName, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
    if (!RegQueryValueExA(hKey, "ProcessorNameString", nullptr, &gotType, (PBYTE)(inBuffer), &gotSize)) {
        if ((gotType == REG_SZ) && strlen(inBuffer)) strcpy(answer, inBuffer);
    }
    RegCloseKey(hKey);
}

This will (or should) give you the processor's 'name' that the Windows system sees! I don't have access to an ARM64 system, so I can't properly test it but, on my x64 system, I get the following (correct) string: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz (which is exactly that returned by using __cpuid() calls to get the "Brand String").

However, like you, I would be very interested to know of a way to do this directly - i.e., how would the Windows O/S get this info on an ARM64 system?

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • the name in CPUID instruction is a 48-byte null-terminated string, so you don't actually need such a huge buffer – phuclv Mar 08 '20 at 16:55
  • @phuclv A very good point (see edit - also made code a bit cleaner). I transferred the code from part of a project that was using a similar registry entry, but which had potentially much longer strings. (I've used 64 chars, because I'm not sure the ARM64 system - if there even is one - conforms to the Intel standard.) – Adrian Mole Mar 08 '20 at 17:05
  • 1
    Just for the information, standard Task Manager on Win10 uses this method to get CPU name. – ge0rdi Jun 20 '20 at 19:34
  • @ge0rdi But the question still remains: How does Windows *initially* determine that info, so that it can be written to the registry? I suspect it's probably reading stuff from the BIOS (during installation). – Adrian Mole Jun 20 '20 at 19:37
  • 1
    "is a 48-byte null-terminated string, so you don't actually need such a huge buffer " ... famous last words. – Kaz Jul 08 '20 at 15:27
2

Not a way to get name directly from the CPU either, but you can get processor name from the WMI Win32_Processor class

It can be obtained by running wmic cpu get name in cmd or (Get-WmiObject Win32_Processor).Name in PowerShell. Getting it from C# is also easy, something like

ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT Name FROM Win32_Processor")
foreach (ManagementObject mo in mos.Get())
{
    Console.WriteLine(mo["Name"]);
}

However doing that from C is a lot trickier. Luckily there's already a similar example in this answer. The main part should be like this

BSTR query    = SysAllocString(L"SELECT Name FROM Win32_Processor");
hr = services->lpVtbl->ExecQuery(services, language, query, WBEM_FLAG_BIDIRECTIONAL, NULL, &results);
...
hr = result->lpVtbl->Get(result, L"Name", 0, &name, 0, 0);
SysFreeString(query);
phuclv
  • 37,963
  • 15
  • 156
  • 475
  • Using System.Management failed for me on a Surface Pro X. It threw an unexpected PlatformNotSupported exception citing the arm architecture. – Daniel Henry Feb 16 '21 at 21:50
  • @DanielHenry can you try [`CIM_Processor`](https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/cim-processor)? WMI has been deprecated and moved to CIM which is more platform independent – phuclv Feb 17 '21 at 00:17
1

Another solution is to use cpuinfo which is a cross-platform CPU information library and also supports ARM64

cpuinfo_initialize();
printf("Running on %s CPU\n", cpuinfo_get_package(0)->name);

It seems it also gets the CPU name from the registry key HARDWARE\DESCRIPTION\System\CentralProcessor\0 like Windows Task Manager

phuclv
  • 37,963
  • 15
  • 156
  • 475