WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-api

[Xen-API] [PATCH] CP-1635: Cpuid module to obtain CPU information

To: xen-api <xen-api@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-API] [PATCH] CP-1635: Cpuid module to obtain CPU information
From: Rob Hoes <rob.hoes@xxxxxxxxxx>
Date: Tue, 16 Feb 2010 23:09:12 +0000
Delivery-date: Tue, 16 Feb 2010 15:09:58 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-api-request@lists.xensource.com?subject=help>
List-id: Discussion of API issues surrounding Xen <xen-api.lists.xensource.com>
List-post: <mailto:xen-api@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-api>, <mailto:xen-api-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-api>, <mailto:xen-api-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-api-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Rob Hoes <rob.hoes@xxxxxxxxxx>
CP-1635: Cpuid module to obtain CPU information

This module obtains the vendor/model/family/stepping as well as feature 
information from the CPU, and determines whether CPU feature masks can be 
applied.

Signed-off-by: Rob Hoes <rob.hoes@xxxxxxxxxx>

diff -r b48ef328a270 .hgignore
--- a/.hgignore Tue Feb 16 22:47:58 2010 +0000
+++ b/.hgignore Tue Feb 16 22:59:09 2010 +0000
@@ -14,3 +14,4 @@
 ^config\.log$
 ^config\.status$
 ^configure$
+doc/*
diff -r b48ef328a270 Makefile.in
--- a/Makefile.in       Tue Feb 16 22:47:58 2010 +0000
+++ b/Makefile.in       Tue Feb 16 22:59:09 2010 +0000
@@ -31,6 +31,7 @@
 endif
        $(MAKE) -C forking_executioner
        $(MAKE) -C mlvm
+       $(MAKE) -C cpuid
 
 .PHONY: allxen
 allxen:
@@ -67,6 +68,7 @@
 endif
        $(MAKE) -C forking_executioner install
        $(MAKE) -C mlvm install
+       $(MAKE) -C cpuid install
 
 installxen:
 ifeq ($(HAVE_XEN),1)
@@ -102,6 +104,7 @@
 endif
        $(MAKE) -C forking_executioner uninstall
        $(MAKE) -C mlvm uninstall
+       $(MAKE) -C cpuid uninstall
 
 uninstallxen:
 ifeq ($(HAVE_XEN),1)
@@ -160,6 +163,7 @@
        $(MAKE) -C mmap doc
        $(MAKE) -C forking_executioner doc
        $(MAKE) -C mlvm doc
+       $(MAKE) -C cpuid doc
 
 .PHONY: clean
 clean:
@@ -179,6 +183,7 @@
        make -C doc clean
        make -C forking_executioner clean
        make -C mlvm clean
+       make -C cpuid clean
 
 cleanxen:
        $(MAKE) -C mmap clean
diff -r b48ef328a270 cpuid/META.in
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/cpuid/META.in     Tue Feb 16 22:59:09 2010 +0000
@@ -0,0 +1,5 @@
+version = "@VERSION@"
+description = "Cpuid extension"
+requires = ""
+archive(byte) = "cpuid.cma"
+archive(native) = "cpuid.cmxa"
diff -r b48ef328a270 cpuid/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/cpuid/Makefile    Tue Feb 16 22:59:09 2010 +0000
@@ -0,0 +1,72 @@
+CC = gcc
+CFLAGS = -Wall -fPIC -O2 -I/opt/xensource/lib/ocaml -I$(XEN_ROOT)/usr/include
+OCAMLC = ocamlc -g
+OCAMLOPT = ocamlopt
+INCLUDES = -I ../stdext
+
+LDFLAGS = -cclib -L./
+
+VERSION := $(shell hg parents --template "{rev}" 2>/dev/null || echo 0.0)
+OCAMLOPTFLAGS = -g -dtypes
+
+OCAMLABI := $(shell ocamlc -version)
+OCAMLLIBDIR := $(shell ocamlc -where)
+OCAMLDESTDIR ?= $(OCAMLLIBDIR)
+
+OBJS = cpuid
+INTF = $(foreach obj, $(OBJS),$(obj).cmi)
+LIBS = cpuid.cma cpuid.cmxa
+
+DOCDIR = /myrepos/xen-api-libs.hg/doc
+
+all: $(INTF) $(LIBS) $(PROGRAMS)
+
+bins: $(PROGRAMS)
+
+libs: $(LIBS)
+
+cpuid.cmxa: cpuid_stubs.a $(foreach obj,$(OBJS),$(obj).cmx)
+       $(OCAMLOPT) $(OCAMLOPTFLAGS) $(INCLUDES) -a -o $@ -cclib -lcpuid_stubs 
$(foreach obj,$(OBJS),$(obj).cmx)
+
+cpuid.cma: $(foreach obj,$(OBJS),$(obj).cmo)
+       $(OCAMLC) -a -dllib dllcpuid_stubs.so -cclib -lcpuid_stubs $(INCLUDES) 
-o $@ $(foreach obj,$(OBJS),$(obj).cmo)
+
+cpuid_stubs.a: cpuid_stubs.o
+       ocamlmklib -o cpuid_stubs $+
+
+libcpuid_stubs.a: cpuid_stubs.o
+       ar rcs $@ $+
+       ocamlmklib -o cpuid_stubs $+
+
+%.cmo: %.ml
+       $(OCAMLC) $(INCLUDES) -c -o $@ $<
+
+%.cmi: %.mli
+       $(OCAMLC) $(INCLUDES) -c -o $@ $<
+
+%.cmx: %.ml
+       $(OCAMLOPT) $(OCAMLOPTFLAGS) $(INCLUDES) -c -o $@ $<
+
+%.o: %.c
+       $(CC) $(CFLAGS) -c -o $@ $<
+
+META: META.in
+       sed 's/@VERSION@/$(VERSION)/g' < $< > $@
+
+.PHONY: install
+install: path = $(DESTDIR)$(shell ocamlfind printconf destdir)
+install: $(LIBS) META
+       mkdir -p $(path)
+       ocamlfind install -destdir $(path) -ldconf ignore cpuid META $(INTF) 
$(LIBS) *.a *.so *.cmx
+
+.PHONY: uninstall
+uninstall:
+       ocamlfind remove cpuid
+
+.PHONY: doc
+doc: $(INTF)
+       python ../doc/doc.py $(DOCDIR) "cpuid" "package" "$(OBJS)" "." "stdext" 
""
+       
+clean:
+       rm -f *.o *.so *.a *.cmo *.cmi *.cma *.cmx *.cmxa *.annot $(LIBS) 
$(PROGRAMS)
+
diff -r b48ef328a270 cpuid/cpuid.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/cpuid/cpuid.ml    Tue Feb 16 22:59:09 2010 +0000
@@ -0,0 +1,198 @@
+(*
+ * Copyright (C) 2006-2010 Citrix Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+open Int32
+open Printf
+open Stringext
+
+exception InvalidFeatureString of string
+exception MaskingNotSupported of string
+exception ManufacturersDiffer
+
+(* === Types and conversion === *)
+
+type manufacturer = AMD | Intel | Unknown
+and features =
+       {
+               base_ecx: int32;
+               base_edx: int32;
+               ext_ecx: int32;
+               ext_edx: int32;
+       }
+and cpu_info =
+       {
+               manufacturer: manufacturer;
+               family: int32;
+               model: int32;
+               stepping: int32;
+               features: features;
+               physical_features: features;
+               maskable: bool;
+       }
+
+let features_to_string f =
+       sprintf "%8.8lx-%8.8lx-%8.8lx-%8.8lx"
+               f.base_ecx f.base_edx f.ext_ecx f.ext_edx
+               
+let string_to_features s =
+       let digits = String.explode "0123456789abcdef" in
+       let len = String.length s in
+       let buf = Buffer.create len in
+       for i = 0 to len - 1 do
+               match Char.lowercase s.[i] with
+               | ' ' | '-' -> ()
+               | c when List.mem c digits -> Buffer.add_char buf c
+               | _ -> raise (InvalidFeatureString "String contains illegal 
character")
+       done;
+       let s = Buffer.contents buf in
+       if String.length s <> 32 then raise (InvalidFeatureString "String is 
not of the right length");
+       {
+               base_ecx = Int32.of_string ("0x" ^ (String.sub s 0 8));
+               base_edx = Int32.of_string ("0x" ^ (String.sub s 8 8));
+               ext_ecx = Int32.of_string ("0x" ^ (String.sub s 16 8));
+               ext_edx = Int32.of_string ("0x" ^ (String.sub s 24 8))
+       }
+       
+(* === Read CPUID information from the hardware === *)
+       
+(* CPUID wrapper: Arguments are leaf and count, *)
+(* return values are %eax, %ebx, %ecx and %edx  *)
+external cpuid: int32 -> int32 -> (int32 * int32 * int32 * int32) = "do_cpuid"
+
+let read_manufacturer () = 
+       match cpuid 0l 0l with
+       | (_, 0x68747541l, 0x444D4163l, 0x69746E65l) -> AMD
+       | (_, 0x756e6547l, 0x6c65746el, 0x49656e69l) -> Intel 
+       | _ -> Unknown
+
+(* Unfold the family/model/stepping numbers from leaf 1 *)
+let read_family () = 
+       match cpuid 1l 0l with (eax, _, _, _) ->
+               let family = (shift_right (logand eax 0x00000f00l) 8) in
+               match family with
+               | 0xfl -> add family (shift_right (logand eax 0x0ff00000l) 20)
+               | _ -> family
+
+let read_model () = 
+       match cpuid 1l 0l with (eax, _, _, _) -> 
+               logor (shift_right (logand eax 0x000000f0l) 4) 
+                       (shift_right (logand eax 0x000f0000l) 12)
+
+let read_stepping () = 
+       match cpuid 1l 0l with (eax, _, _, _) -> 
+               logand eax 0xfl         
+
+(* Read the feature flags and extended feature flags *)
+let read_features () = 
+       let base = cpuid 1l 0l in
+       let ext = cpuid 0x80000001l 0l in
+       match (base, ext) with 
+       | ((_, _, base_ecx, base_edx), (_, _, ext_ecx, ext_edx)) -> 
+               {
+                       base_ecx = base_ecx;
+                       base_edx = base_edx;
+                       ext_ecx = ext_ecx;
+                       ext_edx = ext_edx
+               } 
+               
+(* Does this Intel CPU support "FlexMigration"? 
+ * It's not sensibly documented, so check by model *)
+let has_flexmigration family model stepping = 
+       family > 0x6l || (model > 0x17l || (model = 0x17l && stepping >= 4l))
+
+(* Does this AMD CPU have Extended Migration Technology? 
+ * Known good on Barcelona and better; did exist on some older CPUs 
+ * but not really documented which ones *)
+let has_emt family = 
+       family >= 0x10l
+       
+let is_maskable manufacturer family model stepping =
+       match manufacturer with 
+       | Unknown -> false
+       | Intel ->
+               if has_flexmigration family model stepping then true
+               else false
+       | AMD ->
+               if has_emt family then true
+               else false
+
+let get_physical_features features =
+       let features_file = "/var/xapi/features" in
+       try
+               let data = Unixext.read_whole_file_to_string features_file in
+               string_to_features data
+       with _ ->
+               let data = features_to_string features in
+               Unixext.write_string_to_file features_file data;
+               features
+
+let read_cpu_info () =
+       let manufacturer = read_manufacturer () in
+       let family = read_family () in
+       let model = read_model () in
+       let features = read_features () in
+       let stepping = read_stepping () in
+       {
+               manufacturer = manufacturer;
+               family = family;
+               model = model;
+               stepping = stepping;
+               features = features;
+               physical_features = get_physical_features features;
+               maskable = is_maskable manufacturer family model stepping;
+       }
+       
+(* === Masking checks === *)
+
+let assert_maskability cpu manufacturer features = 
+       (* Manufacturers need to be the same *)
+       if manufacturer != cpu.manufacturer then 
+               raise ManufacturersDiffer;
+       (* Check whether masking is supported on the CPU *)
+       if not cpu.maskable then 
+               begin match cpu.manufacturer with 
+               | Unknown -> raise (MaskingNotSupported "Unknown CPU 
manufacturer")
+               | Intel -> raise (MaskingNotSupported "CPU does not have 
FlexMigration")
+               | AMD -> raise (MaskingNotSupported "CPU does not have Extended 
Migration Technology")
+               end;
+       (* Check whether the features can be obtained by masking the physical 
features *)
+       let possible = (logand cpu.physical_features.base_ecx 
features.base_ecx) = features.base_ecx 
+               && (logand cpu.physical_features.base_edx features.base_edx) = 
features.base_edx
+               && begin match manufacturer with 
+               | Intel ->
+                       (* Intel can't mask extented features but doesn't (yet) 
need to *)
+                       cpu.physical_features.ext_ecx = features.ext_ecx
+                               && cpu.physical_features.ext_edx = 
features.ext_edx
+               | AMD ->
+                       (logand cpu.physical_features.ext_ecx features.ext_ecx) 
= features.ext_ecx 
+                               && (logand cpu.physical_features.ext_edx 
features.ext_edx) = features.ext_edx
+               | _ -> false
+               end
+       in
+       if not possible then
+               raise (InvalidFeatureString "CPU features cannot be masked to 
obtain given features")
+
+let xen_masking_string cpu features = 
+       let rec stringify reglist = 
+               match reglist with 
+               | (reg, host, pool) :: rest ->
+                       if (host = pool) then stringify rest
+                       else ("cpuid_mask_" ^ reg, sprintf "0x%8.8lx" pool) :: 
stringify rest
+               | [] -> [] 
+       in
+       stringify [("ecx", cpu.physical_features.base_ecx, features.base_ecx);
+               ("edx", cpu.physical_features.base_edx, features.base_edx);
+               ("ext_ecx", cpu.physical_features.ext_ecx, features.ext_ecx); 
+               ("ext_edx", cpu.physical_features.ext_edx, features.ext_edx)]
+
diff -r b48ef328a270 cpuid/cpuid.mli
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/cpuid/cpuid.mli   Tue Feb 16 22:59:09 2010 +0000
@@ -0,0 +1,75 @@
+(*
+ * Copyright (C) 2006-2010 Citrix Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+(** Module to read CPUID information and do feature masking checks. *)
+
+(** {2 Types and Conversion} *)
+
+(** Manufacturer of the CPU. *)
+type manufacturer =
+| AMD          (** AMD *)
+| Intel                (** Intel *)
+| Unknown      (** Other manufacturer *)
+
+(** CPU feature bit vector. *)
+and features
+
+(** CPUID information. *)
+and cpu_info =
+       {
+               manufacturer: manufacturer;             (** Manufacturer of the 
CPU *)
+               family: int32;                                  (** Family 
number of the CPU *)
+               model: int32;                                   (** Model 
number of the CPU *)
+               stepping: int32;                                (** Stepping 
number of the CPU *)
+               features: features;                             (** Feature bit 
vector of the CPU *)
+               physical_features: features;    (** Physical Feature bit vector 
of the CPU *)
+               maskable: bool;                                 (** Boolean 
indicating whether the CPU supports
+                                                                               
Intel FlexMigration or AMD Extended Migration,
+                                                                               
or cannot be masked *)
+       }
+       
+(** Convert {!features} into a string of 4 groups of 8 hexadecimal digits, 
separated by dashes. *)
+val features_to_string : features -> string
+
+(** Convert a feature string into a {!features} value. The string must contain
+ *  32 hexadecimal digits and may have spaces and dashes. *)
+val string_to_features : string -> features
+
+
+(** {2 Reading CPUID Information} *)
+
+(** Read the CPUID information from the hardware. *)
+val read_cpu_info : unit -> cpu_info
+
+
+(** {2 Masking Checks} *)
+
+(** Check that this CPU can be masked to fit the pool. Raises {!CannotMaskCpu} 
+ *  including a reason string if this is not possible. *)
+val assert_maskability : cpu_info -> manufacturer -> features -> unit
+
+(** Return the CPU masking string to add to the Xen command-line, 
+ *  or raise an exception saying why it can't be done. *)
+val xen_masking_string : cpu_info -> features -> (string * string) list
+
+(** Raised by {!string_to_features} if the given string is malformed,
+ *  or by {!assert_maskability} if the CPU features cannot be masked to 
+ *  obtain given features. *)
+exception InvalidFeatureString of string
+
+(** Raised by {!assert_maskability} if the CPU does not support feature 
masking. *)
+exception MaskingNotSupported of string
+
+(** Raised by {!assert_maskability} if manufacturers are not equal. *)
+exception ManufacturersDiffer
+
diff -r b48ef328a270 cpuid/cpuid_stubs.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/cpuid/cpuid_stubs.c       Tue Feb 16 22:59:09 2010 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006-2010 Citrix Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include <stdint.h>
+#include <caml/mlvalues.h>
+#include <caml/alloc.h>
+#include <caml/memory.h>
+
+CAMLprim value do_cpuid(value leaf, value word)
+{
+    int32_t eax, ebx, ecx, edx, tmp;
+
+    CAMLparam2(leaf, word);
+    CAMLlocal1(rv);
+
+    eax = Int32_val(leaf);
+    ecx = Int32_val(word);
+
+    /* Execute CPUID; the MOVs are because ocamlc uses -fPIC and
+     * 32-bit gcc won't let you just use "=b" to get at %ebx in PIC */
+    asm("mov %%ebx, %4 ; cpuid ; mov %%ebx, %1 ; mov %4, %%ebx " 
+        : "+a" (eax), "=r" (ebx), "+c" (ecx), "=d" (edx), "=r" (tmp));
+    
+    /* Wrap the return value up as an OCaml tuple */
+    rv = caml_alloc_tuple(4);
+    Store_field(rv, 0, caml_copy_int32(eax));
+    Store_field(rv, 1, caml_copy_int32(ebx));
+    Store_field(rv, 2, caml_copy_int32(ecx));
+    Store_field(rv, 3, caml_copy_int32(edx));
+
+    CAMLreturn(rv);
+}

Attachment: cpuid
Description: Text document

_______________________________________________
xen-api mailing list
xen-api@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/mailman/listinfo/xen-api
<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-API] [PATCH] CP-1635: Cpuid module to obtain CPU information, Rob Hoes <=