[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH] tools/ocaml/libs/xc: add OCaml stubs to query CPU policy
Introduces following functions in Xenctrl and associated types: get_system_cpu_policy cpu_policy_to_featureset, string_of_xen_cpu_policy_index These are wrappers around the existing C functions in xenctrl.h, that will be used by xenopsd initially. -Wno-declaration-after-statement is disabled to allow mixing declarations and code to simplify writing the stubs by using variable length arrays on the stack instead of allocating/freeing memory (which would require additional error-handling logic). Signed-off-by: Edwin Török <edvin.torok@xxxxxxxxxx> --- tools/ocaml/libs/xc/Makefile | 2 +- tools/ocaml/libs/xc/xenctrl.ml | 37 ++++++ tools/ocaml/libs/xc/xenctrl.mli | 71 ++++++++++ tools/ocaml/libs/xc/xenctrl_stubs.c | 195 ++++++++++++++++++++++++++++ 4 files changed, 304 insertions(+), 1 deletion(-) diff --git a/tools/ocaml/libs/xc/Makefile b/tools/ocaml/libs/xc/Makefile index b6da4fdbaf..64dca99613 100644 --- a/tools/ocaml/libs/xc/Makefile +++ b/tools/ocaml/libs/xc/Makefile @@ -3,7 +3,7 @@ XEN_ROOT=$(TOPLEVEL)/../.. include $(TOPLEVEL)/common.make CFLAGS += -I../mmap $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) -CFLAGS += $(APPEND_CFLAGS) +CFLAGS += $(APPEND_CFLAGS) -Wno-declaration-after-statement OCAMLINCLUDE += -I ../mmap OBJS = xenctrl diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml index a5588c643f..fa2cea5091 100644 --- a/tools/ocaml/libs/xc/xenctrl.ml +++ b/tools/ocaml/libs/xc/xenctrl.ml @@ -286,6 +286,43 @@ external version_capabilities: handle -> string = type featureset_index = Featureset_raw | Featureset_host | Featureset_pv | Featureset_hvm external get_cpu_featureset : handle -> featureset_index -> int64 array = "stub_xc_get_cpu_featureset" +(* order must match the order in Val_cpuid_leaf *) +type xen_cpuid_leaf = { + leaf: int64; + subleaf: int64; + a: int64; + b: int64; + c: int64; + d: int64; +} + +(* order must match the order in Val_msr_entry *) +type xen_msr_entry = { + idx: int64; + flags: int64; + value: int64; (* val is a keyword, using 'value' *) +} + +type xen_cpu_policy = { + leaves: xen_cpuid_leaf array; + msrs: xen_msr_entry array; +} + +(* must match XEN_SYSCTL_cpu_policy* order in xen/include/public/sysctl.h *) +type xen_cpu_policy_index = Cpu_policy_raw | Cpu_policy_host | Cpu_policy_pv_max | Cpu_policy_hvm_max | Cpu_policy_pv_default | Cpu_policy_hvm_default + +let string_of_xen_cpu_policy_index = function + | Cpu_policy_raw -> "Raw" + | Cpu_policy_host -> "Host" + | Cpu_policy_pv_max -> "PV Max" + | Cpu_policy_hvm_max -> "HVM Max" + | Cpu_policy_pv_default -> "PV default" + | Cpu_policy_hvm_default -> "HVM default" + +external get_system_cpu_policy: handle -> xen_cpu_policy_index -> xen_cpu_policy = "stub_xc_get_system_cpu_policy" + +external cpu_policy_to_featureset: handle -> xen_cpu_policy -> int64 array = "stub_xc_policy_to_featureset" + external watchdog : handle -> int -> int32 -> int = "stub_xc_watchdog" diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli index 6e94940a8a..605adeeec9 100644 --- a/tools/ocaml/libs/xc/xenctrl.mli +++ b/tools/ocaml/libs/xc/xenctrl.mli @@ -223,6 +223,77 @@ external version_capabilities : handle -> string type featureset_index = Featureset_raw | Featureset_host | Featureset_pv | Featureset_hvm external get_cpu_featureset : handle -> featureset_index -> int64 array = "stub_xc_get_cpu_featureset" +(** CPUID takes a leaf (EAX) and optional subleaf (ECX) as input and + returns feature information bitset in 4 registers (EAX, EBX, ECX, EDX). + This record captures one such invocation of CPUID. + + CPU manuals contain tables explaining the available leaves/subleaves and feature bits: + + https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html + Intel® 64 and IA-32 architectures software developer's manual volume 2A: Instruction set reference + Chapter 3.2, Table 3-8 + + https://developer.amd.com/resources/developer-guides-manuals/ + AMD64 Architecture Programmer’s Manual Volume 3: General Purpose and System Instructions + Appendix D Instruction Subsets and CPUID Feature Flags + *) +type xen_cpuid_leaf = { + leaf: int64; (** initial EAX value *) + subleaf: int64; (** initial ECX value *) + a: int64; (** EAX result *) + b: int64; (** EBX result *) + c: int64; (** ECX result *) + d: int64; (** EDX result *) +} + +(** CPU Model Specific Registers control various aspects of CPU behaviour. + + RDMSR takes ECX as input and returns its result in EDX:EAX. + This record captures one invocation of RDMSR. + + CPU manuals document the available MSRs and feature bits + + https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html + Intel® 64 and IA-32 architectures software developer's manual volume 4: Model-specific registers + Chapter 2, "Model-Specific Registers (MSRs)" + + https://developer.amd.com/resources/developer-guides-manuals/ + AMD64 Architecture Programmer’s Manual Volume 2: System Programming + Appendix A "MSR Cross-Reference" + *) +type xen_msr_entry = { + idx: int64; (** MSR register - ECX input *) + flags: int64; (** reserved, must be zero *) + value: int64; (** EDX:EAX output *) +} + +(** Xen CPU policy contains the CPUID features and MSRs visible in a domain. + The order of leaves and MSRs is not important, but entries cannot be duplicated. + *) +type xen_cpu_policy = { + leaves: xen_cpuid_leaf array; (** Array of CPUID leaves/ *) + msrs: xen_msr_entry array; (** Array of MSRs *) +} + +(** Xen CPU policy to query or set *) +type xen_cpu_policy_index = + | Cpu_policy_raw (** as seen on boot *) + | Cpu_policy_host (** features implemented by the host *) + | Cpu_policy_pv_max (** maximum PV features that we can accept in a migration: either implemented natively or emulated *) + | Cpu_policy_hvm_max (** maximum HVM features that we can accept in a migration: either implemented natively or emulated *) + | Cpu_policy_pv_default (** default PV features for newly booted VMs *) + | Cpu_policy_hvm_default (** default HVM features for newly booted VMs *) + +(** [string_of_xen_cpu_policy_index policy_index] is the name of the [policy_index] policy *) +val string_of_xen_cpu_policy_index : xen_cpu_policy_index -> string + +(** [get_system_cpu_policy xenctrlhandle policy_index] retrieves the [policy_index] policy from the running hypervisor *) +external get_system_cpu_policy: handle -> xen_cpu_policy_index -> xen_cpu_policy = "stub_xc_get_system_cpu_policy" + +(** [cpu_policy_to_featureset xenctrlhandle policy] converts [policy] to a featureset for backwards compatibility + (e.g. accepting incoming migrations in xenopsd from a non-policy-aware xenopsd) *) +external cpu_policy_to_featureset: handle -> xen_cpu_policy -> int64 array = "stub_xc_policy_to_featureset" + external pages_to_kib : int64 -> int64 = "stub_pages_to_kib" val pages_to_mib : int64 -> int64 external watchdog : handle -> int -> int32 -> int diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c index d05d7bb30e..4a230de8b7 100644 --- a/tools/ocaml/libs/xc/xenctrl_stubs.c +++ b/tools/ocaml/libs/xc/xenctrl_stubs.c @@ -34,6 +34,9 @@ #include <xenctrl.h> #include <xen-tools/libs.h> +#include <xen/lib/x86/cpuid.h> +#include <xen/lib/x86/msr.h> + #include "mmap_stubs.h" #define PAGE_SHIFT 12 @@ -1216,6 +1219,198 @@ CAMLprim value stub_xc_watchdog(value xch, value domid, value timeout) CAMLreturn(Val_int(ret)); } +static CAMLprim value Val_cpuid_leaf(const xen_cpuid_leaf_t *leaf) +{ + CAMLparam0(); + CAMLlocal1(result); + result = caml_alloc_tuple(6); + Store_field(result, 0, caml_copy_int64(leaf->leaf)); + Store_field(result, 1, caml_copy_int64(leaf->subleaf)); + Store_field(result, 2, caml_copy_int64(leaf->a)); + Store_field(result, 3, caml_copy_int64(leaf->b)); + Store_field(result, 4, caml_copy_int64(leaf->c)); + Store_field(result, 5, caml_copy_int64(leaf->d)); + + CAMLreturn(result); +} + +static CAMLprim void cpuid_leaf_of_val(xen_cpuid_leaf_t *leaf, value v) +{ + CAMLparam1(v); + leaf->leaf = Int64_val(Field(v, 0)); + leaf->subleaf = Int64_val(Field(v, 1)); + leaf->a = Int64_val(Field(v, 2)); + leaf->b = Int64_val(Field(v, 3)); + leaf->c = Int64_val(Field(v, 4)); + leaf->d = Int64_val(Field(v, 5)); + + CAMLreturn0; +} + +static CAMLprim value Val_msr_entry(const xen_msr_entry_t *msr) +{ + CAMLparam0(); + CAMLlocal1(result); + result = caml_alloc_tuple(3); + Store_field(result, 0, caml_copy_int64(msr->idx)); + Store_field(result, 1, caml_copy_int64(msr->flags)); + Store_field(result, 2, caml_copy_int64(msr->val)); + CAMLreturn(result); +} + +#if 0 +static CAMLprim void msr_entry_of_val(xen_msr_entry_t *msr, value v) +{ + CAMLparam1(v); + msr->idx = Int64_val(Field(v, 0)); + msr->flags = Int64_val(Field(v, 1)); + msr->val = Int64_val(Field(v, 2)); + CAMLreturn0; +} +#endif + +static CAMLprim value Val_leaves(const xen_cpuid_leaf_t *leaves, uint32_t nr_leaves) +{ + CAMLparam0(); + CAMLlocal1(result); + uint32_t i; + + result = caml_alloc(nr_leaves, 0); + for (i=0;i<nr_leaves;i++) + Store_field(result, i, Val_cpuid_leaf(&leaves[i])); + + CAMLreturn(result); +} + +static CAMLprim value Val_msrs(const xen_msr_entry_t *msrs, uint32_t nr_msrs) +{ + CAMLparam0(); + CAMLlocal1(result); + + result = caml_alloc(nr_msrs, 0); + for (unsigned i=0;i<nr_msrs;i++) + Store_field(result, i, Val_msr_entry(&msrs[i])); + CAMLreturn(result); +} + +static CAMLprim value Val_policy(const xen_cpuid_leaf_t *leaves, uint32_t nr_leaves, const xen_msr_entry_t *msrs, uint32_t nr_msrs) +{ + CAMLparam0(); + CAMLlocal1(result); + + result = caml_alloc_tuple(2); + Store_field(result, 0, Val_leaves(leaves, nr_leaves)); + Store_field(result, 1, Val_msrs(msrs, nr_msrs)); + CAMLreturn(result); +} + +static void cpuid_policy_of_val(struct cpuid_policy *p, value policy) +{ + CAMLparam1(policy); + CAMLlocal1(cpu_policy); + uint32_t i; + + cpu_policy = Field(policy, 0); + + uint32_t nr_leaves = caml_array_length(cpu_policy); + xen_cpuid_leaf_t leaves[nr_leaves]; + for (i=0;i<nr_leaves;i++) + cpuid_leaf_of_val(&leaves[i], Field(cpu_policy, i)); + + + uint32_t err_leaf=0, err_subleaf=0; + int rc = x86_cpuid_copy_from_buffer(p, leaves, nr_leaves, &err_leaf, &err_subleaf); + if (rc) + caml_failwith("Failed to deserialize CPU policy"); /* TODO: err_leaf/err_subleaf */ + + CAMLreturn0; +} + +#if 0 +static void msr_policy_of_val(struct msr_policy *p, value policy) +{ + CAMLparam1(policy); + CAMLlocal1(msr_policy); + uint32_t i; + + msr_policy = Field(policy, 1); + + uint32_t nr_msrs = caml_array_length(msr_policy); + xen_msr_entry_t msrs[nr_msrs]; + for (i=0;i<nr_msrs;i++) + msr_entry_of_val(&msrs[i], Field(msr_policy, i)); + + uint32_t err_msr = 0; + int rc = x86_msr_copy_from_buffer(p, msrs, nr_msrs, &err_msr); + if (rc) + caml_failwith("Failed to deserialize CPU policy"); /* TODO: err_msr */ + + CAMLreturn0; +} +#endif + +CAMLprim value stub_xc_get_system_cpu_policy(value xch, value policy_kind) +{ + CAMLparam2(xch, policy_kind); + CAMLlocal1(result); + + uint32_t max_leaves = 0, max_msrs = 0; + + if (xc_cpu_policy_get_size(_H(xch), &max_leaves, &max_msrs)) + failwith_xc(_H(xch)); + + xen_cpuid_leaf_t leaves[max_leaves]; + xen_msr_entry_t msrs[max_msrs]; + memset(leaves, 0, sizeof(leaves)); + memset(msrs, 0, sizeof(msrs)); + + /* It'd be simpler if we could avoid this allocation here, + but the type is private */ + xc_cpu_policy_t *policy = xc_cpu_policy_init(); + if (!policy) + caml_raise_out_of_memory(); + + int rc; + rc = xc_cpu_policy_get_system(_H(xch), Int_val(policy_kind), policy) || + xc_cpu_policy_serialise(_H(xch), policy, leaves, &max_leaves, msrs, &max_msrs); + xc_cpu_policy_destroy(policy); + if (rc) + failwith_xc(_H(xch)); + + result = Val_policy(leaves, max_leaves, msrs, max_msrs); + CAMLreturn(result); +} + +CAMLprim value stub_xc_policy_to_featureset(value xch, value policy) +{ + CAMLparam2(xch, policy); + CAMLlocal1(result); + struct cpuid_policy p; + + memset(&p, 0, sizeof(p)); + cpuid_policy_of_val(&p, policy); + + uint32_t fs_len; + int rc = xc_get_cpu_featureset(_H(xch), 0, &fs_len, NULL); + if (rc) + failwith_xc(_H(xch)); + /* xenctrl stub is statically linked, xenctrl is dynamically loaded, + * the 2 featureset lengths could be different, but fs_len should be the greater one. + * */ + if (fs_len < FEATURESET_NR_ENTRIES) + caml_invalid_argument("cpuid_policy_to_featureset"); + + uint32_t featureset[fs_len]; + memset(featureset, 0, sizeof(featureset)); + cpuid_policy_to_featureset(&p, featureset); + + result = caml_alloc(fs_len, 0); + for(unsigned i=0; i<fs_len; i++) + Store_field(result, i, caml_copy_int64(featureset[i])); + + CAMLreturn(result); +} + /* * Local variables: * indent-tabs-mode: t -- 2.27.0
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |