Skip to content

Commit dc2d84c

Browse files
robhoesandyhhp
authored andcommitted
Offload VM CPU Policy checks to Xen
In order to support MSR_ARCH_CAPS, combining policies becomes more complicated than a simple intersection. More generally, it is more convenient to have all levelling/compatibility logic in a single codebase to avoid needing linked changes in Xapi. Where possible, offload the decisions into Xen. Signed-off-by: Rob Hoes <rob.hoes@citrix.com> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
1 parent e19cfd9 commit dc2d84c

File tree

4 files changed

+136
-9
lines changed

4 files changed

+136
-9
lines changed

ocaml/xenopsd/c_stubs/xenctrlext_stubs.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,96 @@ CAMLprim value stub_xenctrlext_cputopoinfo(value xch_val)
452452
CAMLreturn(result);
453453
}
454454

455+
/*
456+
* Convert an Ocaml int64 array to a C uint32_t array, zero extending as
457+
* necessary.
458+
*/
459+
static void ocaml_int64_array_to_c_array(value o, uint32_t *c, mlsize_t c_len)
460+
{
461+
mlsize_t i, o_len = caml_array_length(o);
462+
463+
for (i = 0; i < o_len; ++i)
464+
c[i] = Int64_val(Field(o, i));
465+
for (; i < c_len; ++i)
466+
c[i] = 0;
467+
}
468+
469+
#ifndef MAX
470+
#define MAX(a, b) ((a) > (b) ? (a) : (b))
471+
#endif
472+
473+
__attribute__((weak))
474+
void xc_combine_cpu_featuresets(
475+
const uint32_t *p1, const uint32_t *p2, uint32_t *out, size_t len);
476+
477+
/* int64 array (p1) -> int64 array (p2) -> int64 array (new) */
478+
CAMLprim value stub_xenctrlext_combine_cpu_featuresets(value p1, value p2)
479+
{
480+
CAMLparam2(p1, p2);
481+
CAMLlocal1(result);
482+
483+
mlsize_t p1_len = caml_array_length(p1);
484+
mlsize_t p2_len = caml_array_length(p2);
485+
mlsize_t len = MAX(p1_len, p2_len);
486+
mlsize_t i;
487+
488+
uint32_t c_p1[len], c_p2[len], c_out[len];
489+
490+
if (!xc_combine_cpu_featuresets)
491+
raise_unix_errno_msg(ENOSYS, "xc_combine_cpu_featuresets");
492+
493+
if (len == 0)
494+
CAMLreturn(Atom(0));
495+
496+
ocaml_int64_array_to_c_array(p1, c_p1, len);
497+
ocaml_int64_array_to_c_array(p2, c_p2, len);
498+
499+
xc_combine_cpu_featuresets(c_p1, c_p2, c_out, len);
500+
501+
/* Turn c_out back into an Ocaml int64 array. */
502+
result = caml_alloc(len, 0);
503+
for ( i = 0; i < len; ++i )
504+
Store_field(result, i, caml_copy_int64(c_out[i]));
505+
506+
CAMLreturn(result);
507+
}
508+
509+
__attribute__((weak))
510+
const char *xc_cpu_featuresets_are_compatible(
511+
const uint32_t *vm, const uint32_t *host, size_t len, char err[128]);
512+
513+
/* int64 array (vm) -> int64 array (host) -> string option (None on success, string on failure) */
514+
CAMLprim value stub_xenctrlext_featuresets_are_compatible(value vm, value host)
515+
{
516+
CAMLparam2(vm, host);
517+
CAMLlocal1(result);
518+
519+
mlsize_t vm_len = caml_array_length(vm);
520+
mlsize_t host_len = caml_array_length(host);
521+
mlsize_t len = MAX(vm_len, host_len);
522+
523+
uint32_t c_vm[len], c_host[len];
524+
char msg[128];
525+
const char *err;
526+
527+
if (!xc_cpu_featuresets_are_compatible)
528+
raise_unix_errno_msg(ENOSYS, "xc_cpu_featuresets_are_compatible");
529+
530+
ocaml_int64_array_to_c_array(vm, c_vm, len);
531+
ocaml_int64_array_to_c_array(host, c_host, len);
532+
533+
err = xc_cpu_featuresets_are_compatible(c_vm, c_host, len, msg);
534+
535+
if (!err)
536+
result = Val_none;
537+
else {
538+
result = caml_alloc_small(1, Tag_some);
539+
Store_field(result, 0, caml_copy_string(err));
540+
}
541+
542+
CAMLreturn(result);
543+
}
544+
455545
CAMLprim value stub_xenforeignmemory_open(value unit)
456546
{
457547
CAMLparam1(unit);

ocaml/xenopsd/xc/xenctrlext.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ external numainfo : handle -> numainfo = "stub_xenctrlext_numainfo"
103103

104104
external cputopoinfo : handle -> cputopo array = "stub_xenctrlext_cputopoinfo"
105105

106+
external combine_cpu_policies : int64 array -> int64 array -> int64 array
107+
= "stub_xenctrlext_combine_cpu_featuresets"
108+
109+
external policy_is_compatible : int64 array -> int64 array -> string option
110+
= "stub_xenctrlext_featuresets_are_compatible"
111+
106112
module Xenforeignmemory = struct
107113
type handle
108114

ocaml/xenopsd/xc/xenctrlext.mli

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ external numainfo : handle -> numainfo = "stub_xenctrlext_numainfo"
8585

8686
external cputopoinfo : handle -> cputopo array = "stub_xenctrlext_cputopoinfo"
8787

88+
external combine_cpu_policies : int64 array -> int64 array -> int64 array
89+
= "stub_xenctrlext_combine_cpu_featuresets"
90+
91+
external policy_is_compatible : int64 array -> int64 array -> string option
92+
= "stub_xenctrlext_featuresets_are_compatible"
93+
8894
module Xenforeignmemory : sig
8995
type handle
9096

ocaml/xenopsd/xc/xenops_server_xen.ml

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,24 +1127,49 @@ module HOST = struct
11271127

11281128
let combine_cpu_policies policy1 policy2 =
11291129
let open Cpuid in
1130-
intersect
1130+
let combine p1 p2 =
1131+
try Xenctrlext.combine_cpu_policies p1 p2
1132+
with Xenctrlext.Unix_error (Unix.ENOSYS, _) ->
1133+
debug
1134+
"xc_combine_cpu_policies: ENOSYS; fallback to OCaml implementation" ;
1135+
intersect p1 p2
1136+
in
1137+
combine
11311138
(policy1 |> CPU_policy.to_string |> features_of_string)
11321139
(policy2 |> CPU_policy.to_string |> features_of_string)
11331140
|> string_of_features
11341141
|> CPU_policy.of_string `host
11351142

11361143
let is_compatible vm_policy host_policy =
11371144
let open Cpuid in
1145+
let is_compatible' vm host =
1146+
let vm' = zero_extend vm (Array.length host) in
1147+
let compatible = is_subset vm' host in
1148+
if not compatible then
1149+
info
1150+
"The VM's CPU policy is not compatible with the target host's. The \
1151+
host is missing: %s"
1152+
(diff vm' host |> string_of_features) ;
1153+
compatible
1154+
in
1155+
let check v h =
1156+
try
1157+
match Xenctrlext.policy_is_compatible v h with
1158+
| None ->
1159+
true
1160+
| Some s ->
1161+
info
1162+
"The VM's CPU policy is not compatible with the target host's. \
1163+
The host is missing: %s"
1164+
s ;
1165+
false
1166+
with Xenctrlext.Unix_error (Unix.ENOSYS, _) ->
1167+
debug "policy_is_compatible: ENOSYS; fallback to OCaml implementation" ;
1168+
is_compatible' v h
1169+
in
11381170
let vm = vm_policy |> CPU_policy.to_string |> features_of_string in
11391171
let host = host_policy |> CPU_policy.to_string |> features_of_string in
1140-
let vm' = zero_extend vm (Array.length host) in
1141-
let compatible = is_subset vm' host in
1142-
if not compatible then
1143-
info
1144-
"The VM's CPU policy is not compatible with the target host's. The \
1145-
host is missing: %s"
1146-
(diff vm' host |> string_of_features) ;
1147-
compatible
1172+
check vm host
11481173
end
11491174

11501175
let dB_m = Mutex.create ()

0 commit comments

Comments
 (0)