4

So I am programming in assembly ARMv8, I would like to know if there is any instruction, like in x86, to recover information about CPU. This is the information I need:

(CPUID) Signature: 660f01

(CPUID) Features: MMX, AMD64, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AES, AVX, CLMUL, FMA, FMA4, XOP, PSE, PSE-36, NX, SVM

(CPUID) Cache L1: 4 x 32 KB Data, 4 x 96 KB Instruction (CPUID) Cache L2: 4 x 1 MB Unified (CPUID) Cache L3: None

Or something equivalent in arm. For example, I know ARMS does not support MMX, but it supports NEON. How can I check if that processor supports it?

MustSee
  • 121
  • 2
  • 7
  • 1
    There is such a thing. Check the architecture reference manual. Unfortunately I am unaware of the details. – fuz Nov 16 '20 at 19:44
  • just look for CPUID in the architectural reference manual. – old_timer Nov 16 '20 at 20:48
  • 1
    @old_timer: I did this, but the only hits seem to refer to AArch32 and are pretty difficult to understand without more background. – Nate Eldredge Nov 16 '20 at 20:58
  • okay, it is a series of registers that give you lots of cpu information, what kinds of instructions or at times specific instructions available, etc. – old_timer Nov 16 '20 at 21:02
  • 2
    Yeah, but it's pretty hard to digest what can be found where, and I'm not seeing anything that looks like a direct equivalent to Intel's CPUID. This does seem like a question where a summary from an expert could save a person an awful lot of legwork and blind alleys – Nate Eldredge Nov 16 '20 at 21:03
  • The closest thing I found seems to be `mrs x0, VPIDR_EL2` but it's a privileged instruction and crashes if executed from userspace. Oh wait, here we go: `mrs x0, MIDR_EL1`. – Nate Eldredge Nov 16 '20 at 21:44
  • [Related](https://stackoverflow.com/q/49051641/1219280): (cpuid im arm writes into MIDR register) – Veverke Apr 27 '21 at 08:04

3 Answers3

11

(This answer is for AArch64.)

Based on some reading and experimentation, there are some system registers that you can read for information about the CPU and its features, using the mrs instruction. The reference for this is the Armv8 Architecture Reference Manual; there's a list of ID registers at section K14.3.3 (in my revision which is possibly not the very latest).

A couple that might be of particular interest:

  • MIDR_EL1 has general information about the CPU: Implementer (e.g. Arm, Broadcom, NVidia), variant, architecture, part number, revision.

  • REVIDR_EL1 has implementation revision information. (It's zero on my Raspberry Pi 4.)

  • IID_AA64_ISAR{0,1}_EL1 have information about which instructions are implemented on the device: CRC. SHA, Atomic, random numbers, etc.

There doesn't seem to be anything directly comparable to the human-readable brand strings produced by x86's CPUID.

Here's some code I used for testing with gcc under Linux. Some registers may not be readable in userspace and result in an exception, so the program handles the resulting signal so as to be able to continue in this case.

I don't yet understand the exception level system well enough to be sure whether these really read the hardware register directly, or if they trap so that the kernel and/or hypervisor could emulate and/or censor the results.

#include <stdio.h>
#include <stdint.h>
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>

sigjmp_buf go_here;

void sigill_handler(int signum) {
    (void)signum;
    siglongjmp(go_here, 1);
}

#define PRINT_REG(s)                                            \
    do {                                                        \
        if (sigsetjmp(go_here, 1)) {                            \
            printf("%s:\tSIGILL\n", s);                         \
        } else {                                                \
            unsigned long ret;                                  \
            asm("mrs %0, " s : "=r" (ret));                     \
            printf("%s:\t%#lx\n", s, ret);                      \
        }                                                       \
    } while (0)

int main(void) {
    struct sigaction sa;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = sigill_handler;
    if (sigaction(SIGILL, &sa, NULL) < 0) {
        perror("sigaction");
        exit(2);
    }
    
    PRINT_REG("MIDR_EL1");
    PRINT_REG("VPIDR_EL2");
    PRINT_REG("REVIDR_EL1");
    PRINT_REG("ID_AA64ISAR0_EL1");
    PRINT_REG("ID_AA64ISAR1_EL1");
    PRINT_REG("MVFR0_EL1");
    PRINT_REG("MVFR1_EL1");
    PRINT_REG("MVFR2_EL1");
    return 0;
}
Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • Is there anything that gives me something like that? (CPUID) Signature: 660f01 (CPUID) Features: MMX, AMD64, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AES, AVX, CLMUL, FMA, FMA4, XOP, PSE, PSE-36, NX, SVM (CPUID) Cache L1: 4 x 32 KB Data, 4 x 96 KB Instruction (CPUID) Cache L2: 4 x 1 MB Unified (CPUID) Cache L3: None – MustSee Nov 18 '20 at 12:44
  • mrs is for the arm64 status register, for arm it's vmrs. – rurban Nov 18 '20 at 16:06
  • @MarlonPedersoli The register given in Nate's answer give information like this. You just have to check the individual feature bits, like on x86. Turning this into a textual representation is something you have to program yourself. – fuz Nov 18 '20 at 20:11
  • but isn't mrs an instruction? I understand it returns just some bits and I have to turn it into text myself – MustSee Nov 19 '20 at 11:48
  • @MarlonPedersoli Exactly, that's correct. The ARMv8 ARM explains what bits have what meaning. Please read it for yourself. – fuz Nov 19 '20 at 19:41
1

There isn't any instruction in arm that provide CPU implemented features. But there are system registers which indicate what features are supported by CPU. These typically start as ID_* for example, ID_AA64PFR0_EL1 is architecture processor feature register. You can refer ARM Architecture Reference Manual to get the system register list and details regarding the features supported. These are not accessible from user application and are accessible only from higher exception level using MRS instruction. Also note that architecture provides means to trap the accesses as well.

Shivakumar
  • 427
  • 2
  • 15
0

You usually just need to check for NEON not all individual capabilities. aarch64 includes NEON. For arm32 on linux you usually read from /proc/self/auxv See eg https://github.com/steinwurf/cpuid/blob/master/src/cpuid/detail/init_linux_gcc_arm.hpp

On windows msvc you usually only need to check ifdef PLATFORM_WINDOWS_PHONE. This guarantees NEON. Similar on clang check only __ARM_NEON__ and various capabilities via static defines.

There is a status register, you can read from. I do also some arm specific asm intrinsics, but they are too fragile. The https://github.com/simd-everywhere/simde library can help much better.

rurban
  • 4,025
  • 24
  • 27
  • 1
    There are actually more relevant instruction set extensions than just NEON on ARMv8. – fuz Nov 16 '20 at 19:47
  • How does Linux figure out what the CPU can do, so it can populate `/proc/self/auxv` or `/proc/cpuinfo`? – Peter Cordes Nov 16 '20 at 21:45
  • 1
    @PeterCordes On ARMv7 and earlier, Linux needs to have this compiled in because there is apparently no mechanism to find out at runtime (there could be a mechanism available to privileged code only, but I am unaware of the details) – fuz Nov 18 '20 at 20:09
  • @fuz: Perhaps catch invalid-instruction exceptions, and try executing things? You can do that in userspace with a signal handler for SIGILL. But only for features you can detect via an exception or lack thereof, not stuff like atomicity guarantees. (If there are any for a 2-register `ldm` on any CPUs...) – Peter Cordes Nov 18 '20 at 20:12
  • 1
    @PeterCordes A lot of undefined instructions are “constrained undefined” on ARMv7, so it can be rather difficult to spot whether an extension is present or not. Additionally, the processor may have one of multiple incompatible coprocessors present at the same space in the instruction set. – fuz Nov 18 '20 at 20:14