Saturday, January 17, 2009

How to determine if your CPU is HVM-capable

Some time ago I installed Solaris Express Community Edition because I wanted to try Sun xVM to run a couple of Windows 2003 Server domains. I knew that the CPU of my Sun Ultra 20 M2, an AMD Opteron 1214, was HVM-capable but strangely virt-install was reporting it as not. Documentation stated that invoking virt-install without arguments in an HVM-capable machine should ask if the domain that's going to be created is for a fully virtualized guest.

Googling around for an explanation, I hit the following blog: Detecting Hardware Virtualization support for xVM. The blogger posts a small C program to check for HVM support. I paste the blogger's program which should be run when the system is not running the hypervisor.

/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/

/*
* Test to see if Intel VT-x or AMD-v is supported according to cpuid.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>


static const char devname[] = "/dev/cpu/self/cpuid";

#define EAX 0
#define EBX 1
#define ECX 2
#define EDX 3

int
main(int argc, char **argv)
{
int device;
uint32_t func;
uint32_t regs[4];
uint32_t v;
int r;
int bit;
int nbits;

/*
* open cpuid device
*/
device = open(devname, O_RDONLY);
if (device == -1)
goto fail;

func = 0x0;
if (pread(device, regs, sizeof (regs), func) != sizeof (regs))
goto fail;

if (regs[EBX] == 0x68747541 &&
regs[ECX] == 0x444d4163 &&
regs[EDX] == 0x69746e65) { /* AuthenticAMD */

func = 0x80000001;
r = ECX;
bit = 2;
nbits = 1;

} else if (regs[EBX] == 0x756e6547 &&
regs[ECX] == 0x6c65746e &&
regs[EDX] == 0x49656e69) { /* GenuineIntel */

func = 1;
r = ECX;
bit = 5;
nbits = 1;

} else {
goto fail;
}

if (pread(device, regs, sizeof (regs), func) != sizeof (regs))
goto fail;

v = regs[r] >> bit;
if (nbits < 32 && nbits > 0)
v &= (1 << nbits) - 1;

if (v)
printf("yes\n");
else
printf("no\n");

(void) close(device);
exit(0);

fail:
printf("no\n");
(void) close(device);
exit(1);
}

2 comments:

William said...

It looks like the include statements were processed as HTML tags.

Grey said...

Thanks William. The source code was completely messed up.

Bye,
Grey