理想未来ってなんやねん

娘可愛い。お父さん頑張る。

使用しているマシンの仮想化機能対応状況の確認方法(AMD編)

先日のhbstudy #17で、仮想化するなら新しいハードウェア(NPT/EPTに対応したCPU)を使用した方が良いという話を聞いたので、対応しているか調べてみようと思いました。


AMD編としているのは、今社内で使っているサーバーで古めのものはAMD Opteronを搭載しているが殆どだったので、取り敢えずNPTに対応しているかどうかが分かれば最低限用事は足りるためです。
時間があればIntelについても調べてみたいと思います。

KVMに対応しているか調べる方法

EPT/NPTは取り敢えず置いておいて、KVMに対応しているかどうかは簡単な方法だと、

$ egrep '(vmx|svm)' --color=always /proc/cpuinfo

で確認できます。

しかし、NPTに対応しているかなど、CentOS 5.xでは細かい状況まではわかりません。


IOMMUに対応していればNPTにも対応しているだろうということで、dmesgが吐き出すメッセージで確認する方法もあります。

# dmesg | grep -e DMAR -e IOMMU 

しかし、カーネルが古いと確認できません。
CentOSの場合、利用出来るのは5.4か5.5以降のようです。

NPTに対応しているかどうかを調べる方法

/proc/cpuinfoでmodel nameが分かるので、そこから調べていくという方法もありますが、別の方法を模索してみました。

kvm-kmodのソースを調べてみところ、インラインアセンブラでcpuid命令を実行して取得しているようでしたので、適当にコードを抜粋してチェックするプログラムを書いてみました。

#include <stdio.h>

#define __cpuid                 native_cpuid

#define SVM_CPUID_FUNC          (0x8000000a)

#define SVM_FEATURE_NPT            (1 <<  0)
#define SVM_FEATURE_LBRV           (1 <<  1)
#define SVM_FEATURE_SVML           (1 <<  2)
#define SVM_FEATURE_NRIP           (1 <<  3)
#define SVM_FEATURE_PAUSE_FILTER   (1 << 10)

static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
                                unsigned int *ecx, unsigned int *edx)
{
        /* ecx is often an input as well as an output. */
        asm volatile("cpuid"
            : "=a" (*eax),
              "=b" (*ebx),
              "=c" (*ecx),
              "=d" (*edx)
            : "0" (*eax), "2" (*ecx));
}

static inline void cpuid(unsigned int op,
                         unsigned int *eax, unsigned int *ebx,
                         unsigned int *ecx, unsigned int *edx)
{
        *eax = op;
        *ecx = 0;
        __cpuid(eax, ebx, ecx, edx);
}

static inline unsigned int cpuid_edx(unsigned int op)
{
        unsigned int eax, ebx, ecx, edx;

        cpuid(op, &eax, &ebx, &ecx, &edx);

        return edx;
}

int main(int argc, const char **argv)
{
    unsigned int svm_features = cpuid_edx(SVM_CPUID_FUNC);
    printf("NPT  supported         : %s\n", svm_features & SVM_FEATURE_NPT          ? "YES" : "NO");
    printf("LBRV supported         : %s\n", svm_features & SVM_FEATURE_LBRV         ? "YES" : "NO");
    printf("SVML supported         : %s\n", svm_features & SVM_FEATURE_SVML         ? "YES" : "NO");
    printf("NRIP supported         : %s\n", svm_features & SVM_FEATURE_NRIP         ? "YES" : "NO");
    printf("PAUSE_FILTER supported : %s\n", svm_features & SVM_FEATURE_PAUSE_FILTER ? "YES" : "NO");
}

上記ソースをcpuid_check.cとか名前を付けて保存し、gccコンパイルして実行。

$ gcc cpuid_check.c -o cpuid_check
$ ./cpuid_check
NPT supported          : YES
LBRV supported         : YES
SVML supported         : YES
NRIP supported         : NO
PAUSE_FILTER supported : NO

上手く動きました。
とりあえずNPTには対応しているようです。


以上、力技で調べてみましたが、もっと良い方法をご存知あればご教示頂けると幸いです。