コンテンツにスキップ

ARM64アセンブリ言語/ARM64 CPU情報表示ツール

出典: フリー教科書『ウィキブックス(Wikibooks)』

このコードは、ARM64アーキテクチャのCPUに関する詳細な情報(CPU ID、キャッシュ構成、ハードウェア機能、マルチプロセッサ情報など)をシステムレジスタや/proc/cpuinfoから取得して表示するツールです。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/auxv.h>

// ARM64固有のシステムレジスタを読み取る関数
static inline unsigned long read_midr_el1(void) {
    unsigned long val;
    __asm__ volatile("mrs %0, midr_el1" : "=r" (val));
    return val;
}

static inline unsigned long read_mpidr_el1(void) {
    unsigned long val;
    __asm__ volatile("mrs %0, mpidr_el1" : "=r" (val));
    return val;
}

static inline unsigned long read_ctr_el0(void) {
    unsigned long val;
    __asm__ volatile("mrs %0, ctr_el0" : "=r" (val));
    return val;
}

// MIDR_EL1レジスタのデコード
void decode_midr(unsigned long midr) {
    unsigned int implementer = (midr >> 24) & 0xFF;
    unsigned int variant = (midr >> 20) & 0xF;
    unsigned int architecture = (midr >> 16) & 0xF;
    unsigned int partnum = (midr >> 4) & 0xFFF;
    unsigned int revision = midr & 0xF;
    
    printf("=== CPU ID Register (MIDR_EL1) ===\n");
    printf("Raw value: 0x%lx\n", midr);
    printf("Implementer: 0x%02x ", implementer);
    
    switch(implementer) {
        case 0x41: printf("(ARM Limited)\n"); break;
        case 0x42: printf("(Broadcom)\n"); break;
        case 0x43: printf("(Cavium)\n"); break;
        case 0x46: printf("(Fujitsu)\n"); break;
        case 0x48: printf("(HiSilicon)\n"); break;
        case 0x4E: printf("(NVIDIA)\n"); break;
        case 0x50: printf("(Applied Micro)\n"); break;
        case 0x51: printf("(Qualcomm)\n"); break;
        case 0x56: printf("(Marvell)\n"); break;
        default: printf("(Unknown)\n"); break;
    }
    
    printf("Variant: 0x%x\n", variant);
    printf("Architecture: 0x%x\n", architecture);
    printf("Part Number: 0x%03x ", partnum);
    
    // ARM Cortex-Aシリーズの判定
    if (implementer == 0x41) {  // ARM Limited
        switch(partnum) {
            case 0xD03: printf("(Cortex-A53)\n"); break;
            case 0xD04: printf("(Cortex-A35)\n"); break;
            case 0xD05: printf("(Cortex-A55)\n"); break;
            case 0xD07: printf("(Cortex-A57)\n"); break;
            case 0xD08: printf("(Cortex-A72)\n"); break;
            case 0xD09: printf("(Cortex-A73)\n"); break;
            case 0xD0A: printf("(Cortex-A75)\n"); break;
            case 0xD0B: printf("(Cortex-A76)\n"); break;
            case 0xD0C: printf("(Neoverse-N1)\n"); break;
            case 0xD0D: printf("(Cortex-A77)\n"); break;
            case 0xD40: printf("(Neoverse-V1)\n"); break;
            case 0xD41: printf("(Cortex-A78)\n"); break;
            case 0xD44: printf("(Cortex-X1)\n"); break;
            case 0xD46: printf("(Cortex-A510)\n"); break;
            case 0xD47: printf("(Cortex-A710)\n"); break;
            case 0xD48: printf("(Cortex-X2)\n"); break;
            case 0xD49: printf("(Neoverse-N2)\n"); break;
            case 0xD4A: printf("(Neoverse-E1)\n"); break;
            case 0xD4B: printf("(Cortex-A78C)\n"); break;
            case 0xD4C: printf("(Cortex-X1C)\n"); break;
            case 0xD4D: printf("(Cortex-A715)\n"); break;
            case 0xD4E: printf("(Cortex-X3)\n"); break;
            default: printf("(Unknown ARM core)\n"); break;
        }
    } else {
        printf("(Non-ARM core)\n");
    }
    
    printf("Revision: 0x%x\n", revision);
    printf("\n");
}

// キャッシュ情報のデコード
void decode_cache_info(unsigned long ctr) {
    printf("=== Cache Type Register (CTR_EL0) ===\n");
    printf("Raw value: 0x%lx\n", ctr);
    
    unsigned int cwg = (ctr >> 24) & 0xF;
    unsigned int erg = (ctr >> 20) & 0xF;
    unsigned int dminline = (ctr >> 16) & 0xF;
    unsigned int l1ip = (ctr >> 14) & 0x3;
    unsigned int iminline = ctr & 0xF;
    
    printf("Cache Writeback Granule: %u bytes\n", cwg ? (4 << cwg) : 0);
    printf("Exclusives Reservation Granule: %u bytes\n", erg ? (4 << erg) : 0);
    printf("D-cache min line size: %u bytes\n", 4 << dminline);
    printf("I-cache min line size: %u bytes\n", 4 << iminline);
    
    printf("L1 I-cache policy: ");
    switch(l1ip) {
        case 0: printf("RESERVED\n"); break;
        case 1: printf("AIVIVT (Virtual Index, Virtual Tag)\n"); break;
        case 2: printf("VIPT (Virtual Index, Physical Tag)\n"); break;
        case 3: printf("PIPT (Physical Index, Physical Tag)\n"); break;
    }
    printf("\n");
}

// /proc/cpuinfoから情報を読み取る
void read_proc_cpuinfo() {
    FILE *fp = fopen("/proc/cpuinfo", "r");
    if (!fp) {
        perror("Failed to open /proc/cpuinfo");
        return;
    }
    
    printf("=== /proc/cpuinfo Information ===\n");
    char line[256];
    int cpu_count = 0;
    
    while (fgets(line, sizeof(line), fp)) {
        if (strncmp(line, "processor", 9) == 0) {
            cpu_count++;
        } else if (strncmp(line, "model name", 10) == 0 ||
                   strncmp(line, "CPU implementer", 15) == 0 ||
                   strncmp(line, "CPU architecture", 16) == 0 ||
                   strncmp(line, "CPU variant", 11) == 0 ||
                   strncmp(line, "CPU part", 8) == 0 ||
                   strncmp(line, "CPU revision", 12) == 0 ||
                   strncmp(line, "Features", 8) == 0) {
            printf("%s", line);
        }
    }
    
    printf("Total CPU cores: %d\n\n", cpu_count);
    fclose(fp);
}

// ハードウェア機能の確認
void check_hwcaps() {
    printf("=== Hardware Capabilities (via getauxval) ===\n");
    
    unsigned long hwcap = getauxval(AT_HWCAP);
    unsigned long hwcap2 = getauxval(AT_HWCAP2);
    
    printf("HWCAP: 0x%lx\n", hwcap);
    printf("HWCAP2: 0x%lx\n", hwcap2);
    
    // 主要な機能フラグをチェック
    printf("Supported features:\n");
    if (hwcap & (1 << 0)) printf("  - FP (Floating Point)\n");
    if (hwcap & (1 << 1)) printf("  - ASIMD (Advanced SIMD)\n");
    if (hwcap & (1 << 2)) printf("  - EVTSTRM (Generic timer events)\n");
    if (hwcap & (1 << 3)) printf("  - AES (AES instructions)\n");
    if (hwcap & (1 << 4)) printf("  - PMULL (Polynomial multiply)\n");
    if (hwcap & (1 << 5)) printf("  - SHA1 (SHA-1 instructions)\n");
    if (hwcap & (1 << 6)) printf("  - SHA2 (SHA-2 instructions)\n");
    if (hwcap & (1 << 7)) printf("  - CRC32 (CRC32 instructions)\n");
    if (hwcap & (1 << 8)) printf("  - ATOMICS (Atomic instructions)\n");
    if (hwcap & (1 << 9)) printf("  - FPHP (Half-precision floating point)\n");
    if (hwcap & (1 << 10)) printf("  - ASIMDHP (Advanced SIMD half-precision)\n");
    if (hwcap & (1 << 11)) printf("  - CPUID (ID registers available)\n");
    if (hwcap & (1 << 12)) printf("  - ASIMDRDM (Rounding double multiply)\n");
    if (hwcap & (1 << 13)) printf("  - JSCVT (JavaScript conversion)\n");
    if (hwcap & (1 << 14)) printf("  - FCMA (Floating point complex)\n");
    if (hwcap & (1 << 15)) printf("  - LRCPC (Load-acquire RCpc)\n");
    if (hwcap & (1 << 16)) printf("  - DCPOP (Data cache clean)\n");
    if (hwcap & (1 << 17)) printf("  - SHA3 (SHA-3 instructions)\n");
    if (hwcap & (1 << 18)) printf("  - SM3 (SM3 hash)\n");
    if (hwcap & (1 << 19)) printf("  - SM4 (SM4 cipher)\n");
    if (hwcap & (1 << 20)) printf("  - ASIMDDP (Dot product)\n");
    if (hwcap & (1 << 21)) printf("  - SHA512 (SHA-512 instructions)\n");
    if (hwcap & (1 << 22)) printf("  - SVE (Scalable Vector Extension)\n");
    
    printf("\n");
}

int main() {
    printf("ARM64 CPU Information Display\n");
    printf("=============================\n\n");
    
    // システムレジスタから情報を取得
    unsigned long midr = read_midr_el1();
    unsigned long mpidr = read_mpidr_el1();
    unsigned long ctr = read_ctr_el0();
    
    // CPU ID情報の表示
    decode_midr(midr);
    
    // キャッシュ情報の表示
    decode_cache_info(ctr);
    
    // MPIDR_EL1 (Multiprocessor Affinity Register)
    printf("=== Multiprocessor Affinity Register (MPIDR_EL1) ===\n");
    printf("Raw value: 0x%lx\n", mpidr);
    printf("Affinity Level 0: %lu\n", mpidr & 0xFF);
    printf("Affinity Level 1: %lu\n", (mpidr >> 8) & 0xFF);
    printf("Affinity Level 2: %lu\n", (mpidr >> 16) & 0xFF);
    printf("Affinity Level 3: %lu\n", (mpidr >> 32) & 0xFF);
    printf("Multiprocessor system: %s\n\n", (mpidr & (1UL << 30)) ? "No" : "Yes");
    
    // /proc/cpuinfoから情報を読み取り
    read_proc_cpuinfo();
    
    // ハードウェア機能の確認
    check_hwcaps();
    
    // 基本的なシステム情報
    printf("=== System Information ===\n");
    printf("Page size: %ld bytes\n", sysconf(_SC_PAGESIZE));
    printf("Number of processors: %ld\n", sysconf(_SC_NPROCESSORS_ONLN));
    printf("Number of processors configured: %ld\n", sysconf(_SC_NPROCESSORS_CONF));
    
    return 0;
}
実行例
ARM64 CPU Information Display
=============================

=== CPU ID Register (MIDR_EL1) ===
Raw value: 0x411fd401
Implementer: 0x41 (ARM Limited)
Variant: 0x1
Architecture: 0xf
Part Number: 0xd40 (Neoverse-V1)
Revision: 0x1

=== Cache Type Register (CTR_EL0) ===
Raw value: 0xb444c004
Cache Writeback Granule: 64 bytes
Exclusives Reservation Granule: 64 bytes
D-cache min line size: 64 bytes
I-cache min line size: 64 bytes
L1 I-cache policy: PIPT (Physical Index, Physical Tag)

=== Multiprocessor Affinity Register (MPIDR_EL1) ===
Raw value: 0x80000000
Affinity Level 0: 0
Affinity Level 1: 0
Affinity Level 2: 0
Affinity Level 3: 0
Multiprocessor system: Yes

=== /proc/cpuinfo Information ===
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm ssbs paca pacg dcpodp svei8mm svebf16 i8mm bf16 dgh rng
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x1
CPU part	: 0xd40
CPU revision	: 1
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm ssbs paca pacg dcpodp svei8mm svebf16 i8mm bf16 dgh rng
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x1
CPU part	: 0xd40
CPU revision	: 1
Total CPU cores: 2

=== Hardware Capabilities (via getauxval) ===
HWCAP: 0xdfffffff
HWCAP2: 0x1f201
Supported features:
  - FP (Floating Point)
  - ASIMD (Advanced SIMD)
  - EVTSTRM (Generic timer events)
  - AES (AES instructions)
  - PMULL (Polynomial multiply)
  - SHA1 (SHA-1 instructions)
  - SHA2 (SHA-2 instructions)
  - CRC32 (CRC32 instructions)
  - ATOMICS (Atomic instructions)
  - FPHP (Half-precision floating point)
  - ASIMDHP (Advanced SIMD half-precision)
  - CPUID (ID registers available)
  - ASIMDRDM (Rounding double multiply)
  - JSCVT (JavaScript conversion)
  - FCMA (Floating point complex)
  - LRCPC (Load-acquire RCpc)
  - DCPOP (Data cache clean)
  - SHA3 (SHA-3 instructions)
  - SM3 (SM3 hash)
  - SM4 (SM4 cipher)
  - ASIMDDP (Dot product)
  - SHA512 (SHA-512 instructions)
  - SVE (Scalable Vector Extension)

=== System Information ===
Page size: 4096 bytes
Number of processors: 2
Number of processors configured: 2

このARM64 CPU情報表示ツールのコードを詳しく解説します。

概要

[編集]

このプログラムは、ARM64(AArch64)アーキテクチャのCPUに関する詳細な情報を取得・表示するツールです。システムレジスタから直接情報を読み取り、CPUの種類や機能を詳細に分析します。

主要な構成要素

[編集]

1. システムレジスタ読み取り関数

[編集]
static inline unsigned long read_midr_el1(void)
static inline unsigned long read_mpidr_el1(void) 
static inline unsigned long read_ctr_el0(void)

これらの関数は、ARM64の特権レベルレジスタからCPU情報を直接読み取ります:

  • MIDR_EL1: CPU識別レジスタ(製造元、アーキテクチャ、型番など)
  • MPIDR_EL1: マルチプロセッサ親和性レジスタ(コア番号、クラスタ情報)
  • CTR_EL0: キャッシュタイプレジスタ(キャッシュライン情報)

2. CPU ID情報のデコード (decode_midr)

[編集]

MIDR_EL1レジスタの32ビット値を以下のようにビットフィールドに分解:

[31:24] Implementer    - CPU製造元
[23:20] Variant        - バリアント番号  
[19:16] Architecture   - アーキテクチャ識別子
[15:4]  PartNum        - 部品番号
[3:0]   Revision       - リビジョン番号

製造元コードから実際のメーカー名を判定し、ARM製のCPUの場合は部品番号からCortex-A53、Cortex-A78などの具体的なコア名も識別します。

3. キャッシュ情報の解析 (decode_cache_info)

[編集]

CTR_EL0レジスタから以下の情報を抽出:

  • CWG: キャッシュライトバックの単位サイズ
  • ERG: 排他的予約の単位サイズ
  • DMinLine: データキャッシュの最小ライン長
  • IMinLine: 命令キャッシュの最小ライン長
  • L1IP: L1命令キャッシュのポリシー(VIVT/VIPT/PIPTなど)

4. /proc/cpuinfo の解析 (read_proc_cpuinfo)

[編集]

Linuxカーネルが提供するCPU情報ファイルから:

  • プロセッサ数のカウント
  • CPU実装者、アーキテクチャ、部品番号などの情報
  • サポートしている機能フラグ

5. ハードウェア機能の確認 (check_hwcaps)

[編集]

getauxval()システムコールを使用してカーネルが認識しているハードウェア機能を取得:

  • HWCAP: 基本的なハードウェア機能フラグ
  • HWCAP2: 拡張ハードウェア機能フラグ

具体的にチェックする機能:

  • 浮動小数点演算(FP)
  • SIMD命令(ASIMD)
  • 暗号化命令(AES、SHA1/2/3)
  • 原子操作命令(ATOMICS)
  • ベクトル拡張(SVE)など

6. メイン処理の流れ

[編集]
  1. 各システムレジスタから生データを取得
  2. CPU ID情報を詳細に解析・表示
  3. キャッシュ構成情報を解析・表示
  4. マルチプロセッサ情報を表示
  5. /proc/cpuinfoの内容を解析
  6. ハードウェア機能一覧を表示
  7. 基本的なシステム情報(ページサイズ、プロセッサ数)を表示

技術的なポイント

[編集]

インラインアセンブリの使用

[編集]
__asm__ volatile("mrs %0, midr_el1" : "=r" (val));

mrs命令を使用してシステムレジスタから直接値を読み取っています。これにより、カーネルやライブラリを介さずに生のハードウェア情報にアクセスできます。

ビット演算による情報抽出

[編集]

レジスタの値から特定のビットフィールドを抽出するため、シフト演算とマスク演算を多用しています:

unsigned int implementer = (midr >> 24) & 0xFF;

このツールは、ARM64システムの詳細なハードウェア情報を取得したい開発者やシステム管理者にとって非常に有用で、CPUの性能特性や対応機能を詳細に把握できます。