diff --git a/tools/ocaml/libs/xc/META.in b/tools/ocaml/libs/xc/META.in new file mode 100644 index 0000000..e46d7dd --- /dev/null +++ b/tools/ocaml/libs/xc/META.in @@ -0,0 +1,4 @@ +version = "@VERSION@" +description = "Xen Control Interface" +archive(byte) = "xc.cma" +archive(native) = "xc.cmxa" diff --git a/tools/ocaml/libs/xc/Makefile b/tools/ocaml/libs/xc/Makefile new file mode 100644 index 0000000..9e361b5 --- /dev/null +++ b/tools/ocaml/libs/xc/Makefile @@ -0,0 +1,28 @@ +TOPLEVEL=../.. +include $(TOPLEVEL)/common.make + +CFLAGS += -I../mmap -I./ +OCAMLINCLUDE += -I ../mmap -I ../uuid + +OBJS = xc +INTF = xc.cmi +LIBS = xc.cma xc.cmxa + +xc_OBJS = $(OBJS) +xc_C_OBJS = xc_lib xc_stubs + +OCAML_LIBRARY = xc + +all: $(INTF) $(LIBS) + +libs: $(LIBS) + +.PHONY: install +install: $(LIBS) META + ocamlfind install -destdir $(DESTDIR)$(shell ocamlfind printconf destdir) -ldconf ignore xc META $(INTF) $(LIBS) *.a *.so *.cmx + +.PHONY: uninstall +uninstall: + ocamlfind remove xc + +include $(TOPLEVEL)/Makefile.rules diff --git a/tools/ocaml/libs/xc/xc.h b/tools/ocaml/libs/xc/xc.h new file mode 100644 index 0000000..8ef7009 --- /dev/null +++ b/tools/ocaml/libs/xc/xc.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2006-2007 XenSource Ltd. + * Copyright (C) 2008 Citrix Ltd. + * Author Vincent Hanquez + * + * 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. + */ + +#define __XEN_TOOLS__ + +#include +#include +#include +#include +#include +#include +#if XEN_SYSCTL_INTERFACE_VERSION < 4 +#include +#else +#include +#endif +#include +#include +#include +#include +#include "xc_e820.h" + +typedef xen_domctl_getdomaininfo_t xc_domaininfo_t; +typedef xen_domctl_getvcpuinfo_t xc_vcpuinfo_t; +typedef xen_sysctl_physinfo_t xc_physinfo_t; + +struct xc_core_header { + unsigned int xch_magic; + unsigned int xch_nr_vcpus; + unsigned int xch_nr_pages; + unsigned int xch_ctxt_offset; + unsigned int xch_index_offset; + unsigned int xch_pages_offset; +}; + +typedef union { +#if defined(__i386__) || defined(__x86_64__) + vcpu_guest_context_x86_64_t x64; + vcpu_guest_context_x86_32_t x32; +#endif + vcpu_guest_context_t c; +} vcpu_guest_context_any_t; + +char * xc_error_get(void); +void xc_error_clear(void); + +int xc_using_injection(void); + +int xc_interface_open(void); +int xc_interface_close(int handle); + +int xc_domain_create(int handle, unsigned int ssidref, + xen_domain_handle_t dhandle, + unsigned int flags, unsigned int *pdomid); +int xc_domain_pause(int handle, unsigned int domid); +int xc_domain_unpause(int handle, unsigned int domid); +int xc_domain_resume_fast(int handle, unsigned int domid); +int xc_domain_destroy(int handle, unsigned int domid); +int xc_domain_shutdown(int handle, int domid, int reason); + +int xc_vcpu_setaffinity(int handle, unsigned int domid, int vcpu, + uint64_t cpumap); +int xc_vcpu_getaffinity(int handle, unsigned int domid, int vcpu, + uint64_t *cpumap); + +int xc_domain_getinfolist(int handle, unsigned int first_domain, + unsigned int max_domains, xc_domaininfo_t *info); +int xc_domain_getinfo(int handle, unsigned int first_domain, + xc_domaininfo_t *info); + +int xc_domain_setmaxmem(int handle, unsigned int domid, unsigned int max_memkb); +int xc_domain_set_memmap_limit(int handle, unsigned int domid, + unsigned long map_limitkb); + +int xc_domain_set_time_offset(int handle, unsigned int domid, int time_offset); + +int xc_domain_memory_increase_reservation(int handle, unsigned int domid, + unsigned long nr_extents, + unsigned int extent_order, + unsigned int address_bits, + xen_pfn_t *extent_start); +int xc_domain_memory_decrease_reservation(int handle, unsigned int domid, + unsigned long nr_extents, + unsigned int extent_order, + unsigned int address_bits, + xen_pfn_t *extent_start); +int xc_domain_memory_populate_physmap(int handle, unsigned int domid, + unsigned long nr_extents, + unsigned int extent_order, + unsigned int address_bits, + xen_pfn_t *extent_start); +int xc_domain_setvmxassist(int handle, unsigned int domid, int use_vmxassist); +int xc_domain_max_vcpus(int handle, unsigned int domid, unsigned int max); +int xc_domain_sethandle(int handle, unsigned int domid, + xen_domain_handle_t dhandle); +int xc_vcpu_getinfo(int handle, unsigned int domid, unsigned int vcpu, + xc_vcpuinfo_t *info); +int xc_domain_ioport_permission(int handle, unsigned int domid, + unsigned int first_port, unsigned int nr_ports, + unsigned int allow_access); +int xc_vcpu_setcontext(int handle, unsigned int domid, + unsigned int vcpu, vcpu_guest_context_any_t *ctxt); +int xc_vcpu_getcontext(int handle, unsigned int domid, + unsigned int vcpu, vcpu_guest_context_any_t *ctxt); +int xc_domain_irq_permission(int handle, unsigned int domid, + unsigned char pirq, unsigned char allow_access); +int xc_domain_iomem_permission(int handle, unsigned int domid, + unsigned long first_mfn, unsigned long nr_mfns, + unsigned char allow_access); +long long xc_domain_get_cpu_usage(int handle, unsigned int domid, + unsigned int vcpu); +void *xc_map_foreign_range(int handle, unsigned int domid, + int size, int prot, unsigned long mfn); +int xc_map_foreign_ranges(int handle, unsigned int domid, + privcmd_mmap_entry_t *entries, int nr); +int xc_readconsolering(int handle, char **pbuffer, + unsigned int *pnr_chars, int clear); +int xc_send_debug_keys(int handle, char *keys); +int xc_physinfo(int handle, xc_physinfo_t *put_info); +int xc_pcpu_info(int handle, int max_cpus, uint64_t *info, int *nr_cpus); +int xc_sched_id(int handle, int *sched_id); +int xc_version(int handle, int cmd, void *arg); +int xc_evtchn_alloc_unbound(int handle, unsigned int domid, + unsigned int remote_domid); +int xc_evtchn_reset(int handle, unsigned int domid); + +int xc_sched_credit_domain_set(int handle, unsigned int domid, + struct xen_domctl_sched_credit *sdom); +int xc_sched_credit_domain_get(int handle, unsigned int domid, + struct xen_domctl_sched_credit *sdom); +int xc_shadow_allocation_get(int handle, unsigned int domid, + uint32_t *mb); +int xc_shadow_allocation_set(int handle, unsigned int domid, + uint32_t mb); +int xc_domain_get_pfn_list(int handle, unsigned int domid, + xen_pfn_t *pfn_array, unsigned long max_pfns); +int xc_hvm_check_pvdriver(int handle, unsigned int domid); + +int xc_domain_assign_device(int handle, unsigned int domid, + int domain, int bus, int slot, int func); +int xc_domain_deassign_device(int handle, unsigned int domid, + int domain, int bus, int slot, int func); +int xc_domain_test_assign_device(int handle, unsigned int domid, + int domain, int bus, int slot, int func); +int xc_domain_watchdog(int handle, int id, uint32_t timeout); +int xc_domain_set_machine_address_size(int xc, uint32_t domid, unsigned int width); +int xc_domain_get_machine_address_size(int xc, uint32_t domid); + +int xc_domain_cpuid_set(int xc, unsigned int domid, int hvm, + uint32_t input, uint32_t oinput, + char *config[4], char *config_out[4]); +int xc_domain_cpuid_apply(int xc, unsigned int domid, int hvm); +int xc_cpuid_check(uint32_t input, uint32_t optsubinput, + char *config[4], char *config_out[4]); + +int xc_domain_send_s3resume(int handle, unsigned int domid); +int xc_domain_set_vpt_align(int handle, unsigned int domid, int vpt_align); +int xc_domain_set_hpet(int handle, unsigned int domid, int hpet); +int xc_domain_set_timer_mode(int handle, unsigned int domid, int mode); +int xc_domain_get_acpi_s_state(int handle, unsigned int domid); + +#if XEN_SYSCTL_INTERFACE_VERSION >= 6 +#define SAFEDIV(a, b) (((b) > 0) ? (a) / (b) : (a)) +#define COMPAT_FIELD_physinfo_get_nr_cpus(p) (p).nr_cpus +#define COMPAT_FIELD_physinfo_get_sockets_per_node(p) \ + SAFEDIV((p).nr_cpus, ((p).threads_per_core * (p).cores_per_socket * (p).nr_nodes)) +#else +#define COMPAT_FIELD_physinfo_get_nr_cpus(p) \ + ((p).threads_per_core * (p).sockets_per_node * \ + (p).cores_per_socket * (p).threads_per_core) +#define COMPAT_FIELD_physinfo_get_sockets_per_node(p) (p).sockets_per_node +#endif + +#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030209 +#define COMPAT_FIELD_ADDRESS_BITS mem_flags +#else +#define COMPAT_FIELD_ADDRESS_BITS address_bits +#endif diff --git a/tools/ocaml/libs/xc/xc.ml b/tools/ocaml/libs/xc/xc.ml new file mode 100644 index 0000000..b9dd284 --- /dev/null +++ b/tools/ocaml/libs/xc/xc.ml @@ -0,0 +1,340 @@ +(* + * Copyright (C) 2006-2007 XenSource Ltd. + * Copyright (C) 2008 Citrix Ltd. + * Author Vincent Hanquez + * + * 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. + *) + +(** *) +type domid = int + +(* ** xenctrl.h ** *) + +type vcpuinfo = +{ + online: bool; + blocked: bool; + running: bool; + cputime: int64; + cpumap: int32; +} + +type domaininfo = +{ + domid : domid; + dying : bool; + shutdown : bool; + paused : bool; + blocked : bool; + running : bool; + hvm_guest : bool; + shutdown_code : int; + total_memory_pages: nativeint; + max_memory_pages : nativeint; + shared_info_frame : int64; + cpu_time : int64; + nr_online_vcpus : int; + max_vcpu_id : int; + ssidref : int32; + handle : int array; +} + +type sched_control = +{ + weight : int; + cap : int; +} + +type physinfo_cap_flag = + | CAP_HVM + | CAP_DirectIO + +type physinfo = +{ + threads_per_core : int; + cores_per_socket : int; + nr_cpus : int; + max_node_id : int; + cpu_khz : int; + total_pages : nativeint; + free_pages : nativeint; + scrub_pages : nativeint; + (* XXX hw_cap *) + capabilities : physinfo_cap_flag list; +} + +type version = +{ + major : int; + minor : int; + extra : string; +} + + +type compile_info = +{ + compiler : string; + compile_by : string; + compile_domain : string; + compile_date : string; +} + +type shutdown_reason = Poweroff | Reboot | Suspend | Crash | Halt + +type domain_create_flag = CDF_HVM | CDF_HAP + +exception Error of string + +type handle + +(* this is only use by coredumping *) +external sizeof_core_header: unit -> int + = "stub_sizeof_core_header" +external sizeof_vcpu_guest_context: unit -> int + = "stub_sizeof_vcpu_guest_context" +external sizeof_xen_pfn: unit -> int = "stub_sizeof_xen_pfn" +(* end of use *) + +external interface_open: unit -> handle = "stub_xc_interface_open" +external interface_close: handle -> unit = "stub_xc_interface_close" + +external using_injection: unit -> bool = "stub_xc_using_injection" + +let with_intf f = + let xc = interface_open () in + let r = try f xc with exn -> interface_close xc; raise exn in + interface_close xc; + r + +external _domain_create: handle -> int32 -> domain_create_flag list -> int array -> domid + = "stub_xc_domain_create" + +let domain_create handle n flags uuid = + _domain_create handle n flags (Uuid.int_array_of_uuid uuid) + +external _domain_sethandle: handle -> domid -> int array -> unit + = "stub_xc_domain_sethandle" + +let domain_sethandle handle n uuid = + _domain_sethandle handle n (Uuid.int_array_of_uuid uuid) + +external domain_setvmxassist: handle -> domid -> bool -> unit + = "stub_xc_domain_setvmxassist" + +external domain_max_vcpus: handle -> domid -> int -> unit + = "stub_xc_domain_max_vcpus" + +external domain_pause: handle -> domid -> unit = "stub_xc_domain_pause" +external domain_unpause: handle -> domid -> unit = "stub_xc_domain_unpause" +external domain_resume_fast: handle -> domid -> unit = "stub_xc_domain_resume_fast" +external domain_destroy: handle -> domid -> unit = "stub_xc_domain_destroy" + +external domain_shutdown: handle -> domid -> shutdown_reason -> unit + = "stub_xc_domain_shutdown" + +external _domain_getinfolist: handle -> domid -> int -> domaininfo list + = "stub_xc_domain_getinfolist" + +let domain_getinfolist handle first_domain = + let nb = 2 in + let last_domid l = (List.hd l).domid + 1 in + let rec __getlist from = + let l = _domain_getinfolist handle from nb in + (if List.length l = nb then __getlist (last_domid l) else []) @ l + in + List.rev (__getlist first_domain) + +external domain_getinfo: handle -> domid -> domaininfo= "stub_xc_domain_getinfo" + +external domain_get_vcpuinfo: handle -> int -> int -> vcpuinfo + = "stub_xc_vcpu_getinfo" + +external domain_ioport_permission: handle -> domid -> int -> int -> bool -> unit + = "stub_xc_domain_ioport_permission" +external domain_iomem_permission: handle -> domid -> nativeint -> nativeint -> bool -> unit + = "stub_xc_domain_iomem_permission" +external domain_irq_permission: handle -> domid -> int -> bool -> unit + = "stub_xc_domain_irq_permission" + +external vcpu_affinity_set: handle -> domid -> int -> int64 -> unit + = "stub_xc_vcpu_setaffinity" +external vcpu_affinity_get: handle -> domid -> int -> int64 + = "stub_xc_vcpu_getaffinity" + +external vcpu_context_get: handle -> domid -> int -> string + = "stub_xc_vcpu_context_get" + +external sched_id: handle -> int = "stub_xc_sched_id" + +external sched_credit_domain_set: handle -> domid -> sched_control -> unit + = "stub_sched_credit_domain_set" +external sched_credit_domain_get: handle -> domid -> sched_control + = "stub_sched_credit_domain_get" + +external shadow_allocation_set: handle -> domid -> int -> unit + = "stub_shadow_allocation_set" +external shadow_allocation_get: handle -> domid -> int + = "stub_shadow_allocation_get" + +external evtchn_alloc_unbound: handle -> domid -> domid -> int + = "stub_xc_evtchn_alloc_unbound" +external evtchn_reset: handle -> domid -> unit = "stub_xc_evtchn_reset" + +external readconsolering: handle -> string = "stub_xc_readconsolering" + +external send_debug_keys: handle -> string -> unit = "stub_xc_send_debug_keys" +external physinfo: handle -> physinfo = "stub_xc_physinfo" +external pcpu_info: handle -> int -> int64 array = "stub_xc_pcpu_info" + +external domain_setmaxmem: handle -> domid -> int64 -> unit + = "stub_xc_domain_setmaxmem" +external domain_set_memmap_limit: handle -> domid -> int64 -> unit + = "stub_xc_domain_set_memmap_limit" +external domain_memory_increase_reservation: handle -> domid -> int64 -> unit + = "stub_xc_domain_memory_increase_reservation" + +external domain_set_machine_address_size: handle -> domid -> int -> unit + = "stub_xc_domain_set_machine_address_size" +external domain_get_machine_address_size: handle -> domid -> int + = "stub_xc_domain_get_machine_address_size" + +external domain_cpuid_set: handle -> domid -> bool -> (int64 * (int64 option)) + -> string option array + -> string option array + = "stub_xc_domain_cpuid_set" +external domain_cpuid_apply: handle -> domid -> bool -> unit + = "stub_xc_domain_cpuid_apply" +external cpuid_check: (int64 * (int64 option)) -> string option array -> (bool * string option array) + = "stub_xc_cpuid_check" + +external map_foreign_range: handle -> domid -> int + -> nativeint -> Mmap.mmap_interface + = "stub_map_foreign_range" + +external domain_get_pfn_list: handle -> domid -> nativeint -> nativeint array + = "stub_xc_domain_get_pfn_list" + +external domain_assign_device: handle -> domid -> (int * int * int * int) -> unit + = "stub_xc_domain_assign_device" +external domain_deassign_device: handle -> domid -> (int * int * int * int) -> unit + = "stub_xc_domain_deassign_device" +external domain_test_assign_device: handle -> domid -> (int * int * int * int) -> bool + = "stub_xc_domain_test_assign_device" + +external domain_set_timer_mode: handle -> domid -> int -> unit = "stub_xc_domain_set_timer_mode" +external domain_set_hpet: handle -> domid -> int -> unit = "stub_xc_domain_set_hpet" +external domain_set_vpt_align: handle -> domid -> int -> unit = "stub_xc_domain_set_vpt_align" + +external domain_send_s3resume: handle -> domid -> unit = "stub_xc_domain_send_s3resume" +external domain_get_acpi_s_state: handle -> domid -> int = "stub_xc_domain_get_acpi_s_state" + +(** check if some hvm domain got pv driver or not *) +external hvm_check_pvdriver: handle -> domid -> bool + = "stub_xc_hvm_check_pvdriver" + +external version: handle -> version = "stub_xc_version_version" +external version_compile_info: handle -> compile_info + = "stub_xc_version_compile_info" +external version_changeset: handle -> string = "stub_xc_version_changeset" +external version_capabilities: handle -> string = + "stub_xc_version_capabilities" + +external watchdog : handle -> int -> int32 -> int + = "stub_xc_watchdog" + +(* core dump structure *) +type core_magic = Magic_hvm | Magic_pv + +type core_header = { + xch_magic: core_magic; + xch_nr_vcpus: int; + xch_nr_pages: nativeint; + xch_index_offset: int64; + xch_ctxt_offset: int64; + xch_pages_offset: int64; +} + +external marshall_core_header: core_header -> string = "stub_marshall_core_header" + +(* coredump *) +let coredump xch domid fd = + let dump s = + let wd = Unix.write fd s 0 (String.length s) in + if wd <> String.length s then + failwith "error while writing"; + in + + let info = domain_getinfo xch domid in + + let nrpages = info.total_memory_pages in + let ctxt = Array.make info.max_vcpu_id None in + let nr_vcpus = ref 0 in + for i = 0 to info.max_vcpu_id - 1 + do + ctxt.(i) <- try + let v = vcpu_context_get xch domid i in + incr nr_vcpus; + Some v + with _ -> None + done; + + (* FIXME page offset if not rounded to sup *) + let page_offset = + Int64.add + (Int64.of_int (sizeof_core_header () + + (sizeof_vcpu_guest_context () * !nr_vcpus))) + (Int64.of_nativeint ( + Nativeint.mul + (Nativeint.of_int (sizeof_xen_pfn ())) + nrpages) + ) + in + + let header = { + xch_magic = if info.hvm_guest then Magic_hvm else Magic_pv; + xch_nr_vcpus = !nr_vcpus; + xch_nr_pages = nrpages; + xch_ctxt_offset = Int64.of_int (sizeof_core_header ()); + xch_index_offset = Int64.of_int (sizeof_core_header () + + sizeof_vcpu_guest_context ()); + xch_pages_offset = page_offset; + } in + + dump (marshall_core_header header); + for i = 0 to info.max_vcpu_id - 1 + do + match ctxt.(i) with + | None -> () + | Some ctxt_i -> dump ctxt_i + done; + let pfns = domain_get_pfn_list xch domid nrpages in + if Array.length pfns <> Nativeint.to_int nrpages then + failwith "could not get the page frame list"; + + let page_size = Mmap.getpagesize () in + for i = 0 to Nativeint.to_int nrpages - 1 + do + let page = map_foreign_range xch domid page_size pfns.(i) in + let data = Mmap.read page 0 page_size in + Mmap.unmap page; + dump data + done + +(* ** Misc ** *) + +(** + Convert the given number of pages to an amount in KiB, rounded up. + *) +external pages_to_kib : int64 -> int64 = "stub_pages_to_kib" +let pages_to_mib pages = Int64.div (pages_to_kib pages) 1024L + +let _ = Callback.register_exception "xc.error" (Error "register_callback") diff --git a/tools/ocaml/libs/xc/xc.mli b/tools/ocaml/libs/xc/xc.mli new file mode 100644 index 0000000..dc55b67 --- /dev/null +++ b/tools/ocaml/libs/xc/xc.mli @@ -0,0 +1,196 @@ +(* + * Copyright (C) 2006-2007 XenSource Ltd. + * Copyright (C) 2008 Citrix Ltd. + * Author Vincent Hanquez + * + * 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. + *) + +type domid = int +type vcpuinfo = { + online : bool; + blocked : bool; + running : bool; + cputime : int64; + cpumap : int32; +} +type domaininfo = { + domid : domid; + dying : bool; + shutdown : bool; + paused : bool; + blocked : bool; + running : bool; + hvm_guest : bool; + shutdown_code : int; + total_memory_pages : nativeint; + max_memory_pages : nativeint; + shared_info_frame : int64; + cpu_time : int64; + nr_online_vcpus : int; + max_vcpu_id : int; + ssidref : int32; + handle : int array; +} +type sched_control = { weight : int; cap : int; } +type physinfo_cap_flag = CAP_HVM | CAP_DirectIO +type physinfo = { + threads_per_core : int; + cores_per_socket : int; + nr_cpus : int; + max_node_id : int; + cpu_khz : int; + total_pages : nativeint; + free_pages : nativeint; + scrub_pages : nativeint; + capabilities : physinfo_cap_flag list; +} +type version = { major : int; minor : int; extra : string; } +type compile_info = { + compiler : string; + compile_by : string; + compile_domain : string; + compile_date : string; +} +type shutdown_reason = Poweroff | Reboot | Suspend | Crash | Halt + +type domain_create_flag = CDF_HVM | CDF_HAP + +exception Error of string +type handle +external sizeof_core_header : unit -> int = "stub_sizeof_core_header" +external sizeof_vcpu_guest_context : unit -> int + = "stub_sizeof_vcpu_guest_context" +external sizeof_xen_pfn : unit -> int = "stub_sizeof_xen_pfn" +external interface_open : unit -> handle = "stub_xc_interface_open" +external using_injection : unit -> bool = "stub_xc_using_injection" +external interface_close : handle -> unit = "stub_xc_interface_close" +val with_intf : (handle -> 'a) -> 'a +external _domain_create : handle -> int32 -> domain_create_flag list -> int array -> domid + = "stub_xc_domain_create" +val domain_create : handle -> int32 -> domain_create_flag list -> 'a Uuid.t -> domid +external _domain_sethandle : handle -> domid -> int array -> unit + = "stub_xc_domain_sethandle" +val domain_sethandle : handle -> domid -> 'a Uuid.t -> unit +external domain_setvmxassist: handle -> domid -> bool -> unit + = "stub_xc_domain_setvmxassist" +external domain_max_vcpus : handle -> domid -> int -> unit + = "stub_xc_domain_max_vcpus" +external domain_pause : handle -> domid -> unit = "stub_xc_domain_pause" +external domain_unpause : handle -> domid -> unit = "stub_xc_domain_unpause" +external domain_resume_fast : handle -> domid -> unit + = "stub_xc_domain_resume_fast" +external domain_destroy : handle -> domid -> unit = "stub_xc_domain_destroy" +external domain_shutdown : handle -> domid -> shutdown_reason -> unit + = "stub_xc_domain_shutdown" +external _domain_getinfolist : handle -> domid -> int -> domaininfo list + = "stub_xc_domain_getinfolist" +val domain_getinfolist : handle -> domid -> domaininfo list +external domain_getinfo : handle -> domid -> domaininfo + = "stub_xc_domain_getinfo" +external domain_get_vcpuinfo : handle -> int -> int -> vcpuinfo + = "stub_xc_vcpu_getinfo" +external domain_ioport_permission: handle -> domid -> int -> int -> bool -> unit + = "stub_xc_domain_ioport_permission" +external domain_iomem_permission: handle -> domid -> nativeint -> nativeint -> bool -> unit + = "stub_xc_domain_iomem_permission" +external domain_irq_permission: handle -> domid -> int -> bool -> unit + = "stub_xc_domain_irq_permission" +external vcpu_affinity_set : handle -> domid -> int -> int64 -> unit + = "stub_xc_vcpu_setaffinity" +external vcpu_affinity_get : handle -> domid -> int -> int64 + = "stub_xc_vcpu_getaffinity" +external vcpu_context_get : handle -> domid -> int -> string + = "stub_xc_vcpu_context_get" +external sched_id : handle -> int = "stub_xc_sched_id" +external sched_credit_domain_set : handle -> domid -> sched_control -> unit + = "stub_sched_credit_domain_set" +external sched_credit_domain_get : handle -> domid -> sched_control + = "stub_sched_credit_domain_get" +external shadow_allocation_set : handle -> domid -> int -> unit + = "stub_shadow_allocation_set" +external shadow_allocation_get : handle -> domid -> int + = "stub_shadow_allocation_get" +external evtchn_alloc_unbound : handle -> domid -> domid -> int + = "stub_xc_evtchn_alloc_unbound" +external evtchn_reset : handle -> domid -> unit = "stub_xc_evtchn_reset" +external readconsolering : handle -> string = "stub_xc_readconsolering" +external send_debug_keys : handle -> string -> unit = "stub_xc_send_debug_keys" +external physinfo : handle -> physinfo = "stub_xc_physinfo" +external pcpu_info: handle -> int -> int64 array = "stub_xc_pcpu_info" +external domain_setmaxmem : handle -> domid -> int64 -> unit + = "stub_xc_domain_setmaxmem" +external domain_set_memmap_limit : handle -> domid -> int64 -> unit + = "stub_xc_domain_set_memmap_limit" +external domain_memory_increase_reservation : + handle -> domid -> int64 -> unit + = "stub_xc_domain_memory_increase_reservation" +external map_foreign_range : + handle -> domid -> int -> nativeint -> Mmap.mmap_interface + = "stub_map_foreign_range" +external domain_get_pfn_list : + handle -> domid -> nativeint -> nativeint array + = "stub_xc_domain_get_pfn_list" + +external domain_assign_device: handle -> domid -> (int * int * int * int) -> unit + = "stub_xc_domain_assign_device" +external domain_deassign_device: handle -> domid -> (int * int * int * int) -> unit + = "stub_xc_domain_deassign_device" +external domain_test_assign_device: handle -> domid -> (int * int * int * int) -> bool + = "stub_xc_domain_test_assign_device" + +external domain_set_timer_mode: handle -> domid -> int -> unit = "stub_xc_domain_set_timer_mode" +external domain_set_hpet: handle -> domid -> int -> unit = "stub_xc_domain_set_hpet" +external domain_set_vpt_align: handle -> domid -> int -> unit = "stub_xc_domain_set_vpt_align" + +external domain_send_s3resume: handle -> domid -> unit + = "stub_xc_domain_send_s3resume" +external domain_get_acpi_s_state: handle -> domid -> int = "stub_xc_domain_get_acpi_s_state" + +external hvm_check_pvdriver : handle -> domid -> bool + = "stub_xc_hvm_check_pvdriver" +external version : handle -> version = "stub_xc_version_version" +external version_compile_info : handle -> compile_info + = "stub_xc_version_compile_info" +external version_changeset : handle -> string = "stub_xc_version_changeset" +external version_capabilities : handle -> string + = "stub_xc_version_capabilities" +type core_magic = Magic_hvm | Magic_pv +type core_header = { + xch_magic : core_magic; + xch_nr_vcpus : int; + xch_nr_pages : nativeint; + xch_index_offset : int64; + xch_ctxt_offset : int64; + xch_pages_offset : int64; +} +external marshall_core_header : core_header -> string + = "stub_marshall_core_header" +val coredump : handle -> domid -> Unix.file_descr -> unit +external pages_to_kib : int64 -> int64 = "stub_pages_to_kib" +val pages_to_mib : int64 -> int64 +external watchdog : handle -> int -> int32 -> int + = "stub_xc_watchdog" + +external domain_set_machine_address_size: handle -> domid -> int -> unit + = "stub_xc_domain_set_machine_address_size" +external domain_get_machine_address_size: handle -> domid -> int + = "stub_xc_domain_get_machine_address_size" + +external domain_cpuid_set: handle -> domid -> bool -> (int64 * (int64 option)) + -> string option array + -> string option array + = "stub_xc_domain_cpuid_set" +external domain_cpuid_apply: handle -> domid -> bool -> unit + = "stub_xc_domain_cpuid_apply" +external cpuid_check: (int64 * (int64 option)) -> string option array -> (bool * string option array) + = "stub_xc_cpuid_check" + diff --git a/tools/ocaml/libs/xc/xc_cpufeature.h b/tools/ocaml/libs/xc/xc_cpufeature.h new file mode 100644 index 0000000..047a6c9 --- /dev/null +++ b/tools/ocaml/libs/xc/xc_cpufeature.h @@ -0,0 +1,116 @@ +#ifndef __LIBXC_CPUFEATURE_H +#define __LIBXC_CPUFEATURE_H + +/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */ +#define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */ +#define X86_FEATURE_VME (0*32+ 1) /* Virtual Mode Extensions */ +#define X86_FEATURE_DE (0*32+ 2) /* Debugging Extensions */ +#define X86_FEATURE_PSE (0*32+ 3) /* Page Size Extensions */ +#define X86_FEATURE_TSC (0*32+ 4) /* Time Stamp Counter */ +#define X86_FEATURE_MSR (0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */ +#define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extensions */ +#define X86_FEATURE_MCE (0*32+ 7) /* Machine Check Architecture */ +#define X86_FEATURE_CX8 (0*32+ 8) /* CMPXCHG8 instruction */ +#define X86_FEATURE_APIC (0*32+ 9) /* Onboard APIC */ +#define X86_FEATURE_SEP (0*32+11) /* SYSENTER/SYSEXIT */ +#define X86_FEATURE_MTRR (0*32+12) /* Memory Type Range Registers */ +#define X86_FEATURE_PGE (0*32+13) /* Page Global Enable */ +#define X86_FEATURE_MCA (0*32+14) /* Machine Check Architecture */ +#define X86_FEATURE_CMOV (0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */ +#define X86_FEATURE_PAT (0*32+16) /* Page Attribute Table */ +#define X86_FEATURE_PSE36 (0*32+17) /* 36-bit PSEs */ +#define X86_FEATURE_PN (0*32+18) /* Processor serial number */ +#define X86_FEATURE_CLFLSH (0*32+19) /* Supports the CLFLUSH instruction */ +#define X86_FEATURE_DS (0*32+21) /* Debug Store */ +#define X86_FEATURE_ACPI (0*32+22) /* ACPI via MSR */ +#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */ +#define X86_FEATURE_FXSR (0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */ + /* of FPU context), and CR4.OSFXSR available */ +#define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */ +#define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */ +#define X86_FEATURE_SELFSNOOP (0*32+27) /* CPU self snoop */ +#define X86_FEATURE_HT (0*32+28) /* Hyper-Threading */ +#define X86_FEATURE_ACC (0*32+29) /* Automatic clock control */ +#define X86_FEATURE_IA64 (0*32+30) /* IA-64 processor */ +#define X86_FEATURE_PBE (0*32+31) /* Pending Break Enable */ + +/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */ +/* Don't duplicate feature flags which are redundant with Intel! */ +#define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */ +#define X86_FEATURE_MP (1*32+19) /* MP Capable. */ +#define X86_FEATURE_NX (1*32+20) /* Execute Disable */ +#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */ +#define X86_FEATURE_FFXSR (1*32+25) /* FFXSR instruction optimizations */ +#define X86_FEATURE_PAGE1GB (1*32+26) /* 1Gb large page support */ +#define X86_FEATURE_RDTSCP (1*32+27) /* RDTSCP */ +#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */ +#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */ +#define X86_FEATURE_3DNOW (1*32+31) /* 3DNow! */ + +/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */ +#define X86_FEATURE_RECOVERY (2*32+ 0) /* CPU in recovery mode */ +#define X86_FEATURE_LONGRUN (2*32+ 1) /* Longrun power control */ +#define X86_FEATURE_LRTI (2*32+ 3) /* LongRun table interface */ + +/* Other features, Linux-defined mapping, word 3 */ +/* This range is used for feature bits which conflict or are synthesized */ +#define X86_FEATURE_CXMMX (3*32+ 0) /* Cyrix MMX extensions */ +#define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */ +#define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */ +#define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */ +/* cpu types for specific tunings: */ +#define X86_FEATURE_K8 (3*32+ 4) /* Opteron, Athlon64 */ +#define X86_FEATURE_K7 (3*32+ 5) /* Athlon */ +#define X86_FEATURE_P3 (3*32+ 6) /* P3 */ +#define X86_FEATURE_P4 (3*32+ 7) /* P4 */ +#define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */ + +/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ +#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ +#define X86_FEATURE_DTES64 (4*32+ 2) /* 64-bit Debug Store */ +#define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor/Mwait support */ +#define X86_FEATURE_DSCPL (4*32+ 4) /* CPL Qualified Debug Store */ +#define X86_FEATURE_VMXE (4*32+ 5) /* Virtual Machine Extensions */ +#define X86_FEATURE_SMXE (4*32+ 6) /* Safer Mode Extensions */ +#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */ +#define X86_FEATURE_TM2 (4*32+ 8) /* Thermal Monitor 2 */ +#define X86_FEATURE_SSSE3 (4*32+ 9) /* Supplemental Streaming SIMD Extensions-3 */ +#define X86_FEATURE_CID (4*32+10) /* Context ID */ +#define X86_FEATURE_CX16 (4*32+13) /* CMPXCHG16B */ +#define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */ +#define X86_FEATURE_PDCM (4*32+15) /* Perf/Debug Capability MSR */ +#define X86_FEATURE_DCA (4*32+18) /* Direct Cache Access */ +#define X86_FEATURE_SSE4_1 (4*32+19) /* Streaming SIMD Extensions 4.1 */ +#define X86_FEATURE_SSE4_2 (4*32+20) /* Streaming SIMD Extensions 4.2 */ +#define X86_FEATURE_POPCNT (4*32+23) /* POPCNT instruction */ +#define X86_FEATURE_HYPERVISOR (4*32+31) /* Running under some hypervisor */ + +/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ +#define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */ +#define X86_FEATURE_XSTORE_EN (5*32+ 3) /* on-CPU RNG enabled */ +#define X86_FEATURE_XCRYPT (5*32+ 6) /* on-CPU crypto (xcrypt insn) */ +#define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* on-CPU crypto enabled */ +#define X86_FEATURE_ACE2 (5*32+ 8) /* Advanced Cryptography Engine v2 */ +#define X86_FEATURE_ACE2_EN (5*32+ 9) /* ACE v2 enabled */ +#define X86_FEATURE_PHE (5*32+ 10) /* PadLock Hash Engine */ +#define X86_FEATURE_PHE_EN (5*32+ 11) /* PHE enabled */ +#define X86_FEATURE_PMM (5*32+ 12) /* PadLock Montgomery Multiplier */ +#define X86_FEATURE_PMM_EN (5*32+ 13) /* PMM enabled */ + +/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */ +#define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */ +#define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */ +#define X86_FEATURE_SVME (6*32+ 2) /* Secure Virtual Machine */ +#define X86_FEATURE_EXTAPICSPACE (6*32+ 3) /* Extended APIC space */ +#define X86_FEATURE_ALTMOVCR (6*32+ 4) /* LOCK MOV CR accesses CR+8 */ +#define X86_FEATURE_ABM (6*32+ 5) /* Advanced Bit Manipulation */ +#define X86_FEATURE_SSE4A (6*32+ 6) /* AMD Streaming SIMD Extensions-4a */ +#define X86_FEATURE_MISALIGNSSE (6*32+ 7) /* Misaligned SSE Access */ +#define X86_FEATURE_3DNOWPF (6*32+ 8) /* 3DNow! Prefetch */ +#define X86_FEATURE_OSVW (6*32+ 9) /* OS Visible Workaround */ +#define X86_FEATURE_IBS (6*32+ 10) /* Instruction Based Sampling */ +#define X86_FEATURE_SSE5 (6*32+ 11) /* AMD Streaming SIMD Extensions-5 */ +#define X86_FEATURE_SKINIT (6*32+ 12) /* SKINIT, STGI/CLGI, DEV */ +#define X86_FEATURE_WDT (6*32+ 13) /* Watchdog Timer */ + +#endif /* __LIBXC_CPUFEATURE_H */ diff --git a/tools/ocaml/libs/xc/xc_cpuid.h b/tools/ocaml/libs/xc/xc_cpuid.h new file mode 100644 index 0000000..43743ef --- /dev/null +++ b/tools/ocaml/libs/xc/xc_cpuid.h @@ -0,0 +1,285 @@ +#ifndef XC_CPUID_H +#define XC_CPUID_H + +#ifdef XEN_DOMCTL_set_cpuid + +#include "xc_cpufeature.h" + +#define bitmaskof(idx) (1u << ((idx) & 31)) +#define clear_bit(idx, dst) ((dst) &= ~(1u << ((idx) & 31))) +#define set_bit(idx, dst) ((dst) |= (1u << ((idx) & 31))) + +#define DEF_MAX_BASE 0x00000004u +#define DEF_MAX_EXT 0x80000008u + +static void xc_cpuid(uint32_t eax, uint32_t ecx, uint32_t regs[4]) +{ + unsigned int realecx = (ecx == XEN_CPUID_INPUT_UNUSED) ? 0 : ecx; + asm ( +#ifdef __i386__ + "push %%ebx; cpuid; mov %%ebx,%1; pop %%ebx" +#else + "push %%rbx; cpuid; mov %%ebx,%1; pop %%rbx" +#endif + : "=a" (regs[0]), "=r" (regs[1]), "=c" (regs[2]), "=d" (regs[3]) + : "0" (eax), "2" (realecx)); +} + +enum { CPU_BRAND_INTEL, CPU_BRAND_AMD, CPU_BRAND_UNKNOWN }; + +static int xc_cpuid_brand_get(void) +{ + uint32_t regs[4]; + char str[13]; + uint32_t *istr = (uint32_t *) str; + + xc_cpuid(0, 0, regs); + istr[0] = regs[1]; + istr[1] = regs[3]; + istr[2] = regs[2]; + str[12] = '\0'; + if (strcmp(str, "AuthenticAMD") == 0) { + return CPU_BRAND_AMD; + } else if (strcmp(str, "GenuineIntel") == 0) { + return CPU_BRAND_INTEL; + } else + return CPU_BRAND_UNKNOWN; +} + +static int hypervisor_is_64bit(int xc) +{ + xen_capabilities_info_t xen_caps; + return ((xc_version(xc, XENVER_capabilities, &xen_caps) == 0) && + (strstr(xen_caps, "x86_64") != NULL)); +} + +static void do_hvm_cpuid_policy(int xc, int domid, uint32_t input, uint32_t regs[4]) +{ + unsigned long is_pae; + int brand; + + /* pae ? */ + xc_get_hvm_param(xc, domid, HVM_PARAM_PAE_ENABLED, &is_pae); + is_pae = !!is_pae; + + switch (input) { + case 0x00000000: + if (regs[0] > DEF_MAX_BASE) + regs[0] = DEF_MAX_BASE; + break; + case 0x00000001: + regs[2] &= (bitmaskof(X86_FEATURE_XMM3) | + bitmaskof(X86_FEATURE_SSSE3) | + bitmaskof(X86_FEATURE_CX16) | + bitmaskof(X86_FEATURE_SSE4_1) | + bitmaskof(X86_FEATURE_SSE4_2) | + bitmaskof(X86_FEATURE_POPCNT)); + + regs[2] |= bitmaskof(X86_FEATURE_HYPERVISOR); + + regs[3] &= (bitmaskof(X86_FEATURE_FPU) | + bitmaskof(X86_FEATURE_VME) | + bitmaskof(X86_FEATURE_DE) | + bitmaskof(X86_FEATURE_PSE) | + bitmaskof(X86_FEATURE_TSC) | + bitmaskof(X86_FEATURE_MSR) | + bitmaskof(X86_FEATURE_PAE) | + bitmaskof(X86_FEATURE_MCE) | + bitmaskof(X86_FEATURE_CX8) | + bitmaskof(X86_FEATURE_APIC) | + bitmaskof(X86_FEATURE_SEP) | + bitmaskof(X86_FEATURE_MTRR) | + bitmaskof(X86_FEATURE_PGE) | + bitmaskof(X86_FEATURE_MCA) | + bitmaskof(X86_FEATURE_CMOV) | + bitmaskof(X86_FEATURE_PAT) | + bitmaskof(X86_FEATURE_CLFLSH) | + bitmaskof(X86_FEATURE_MMX) | + bitmaskof(X86_FEATURE_FXSR) | + bitmaskof(X86_FEATURE_XMM) | + bitmaskof(X86_FEATURE_XMM2)); + /* We always support MTRR MSRs. */ + regs[3] |= bitmaskof(X86_FEATURE_MTRR); + + if (!is_pae) + clear_bit(X86_FEATURE_PAE, regs[3]); + break; + case 0x80000000: + if (regs[0] > DEF_MAX_EXT) + regs[0] = DEF_MAX_EXT; + break; + case 0x80000001: + if (!is_pae) + clear_bit(X86_FEATURE_NX, regs[3]); + break; + case 0x80000008: + regs[0] &= 0x0000ffffu; + regs[1] = regs[2] = regs[3] = 0; + break; + case 0x00000002: /* Intel cache info (dumped by AMD policy) */ + case 0x00000004: /* Intel cache info (dumped by AMD policy) */ + case 0x80000002: /* Processor name string */ + case 0x80000003: /* ... continued */ + case 0x80000004: /* ... continued */ + case 0x80000005: /* AMD L1 cache/TLB info (dumped by Intel policy) */ + case 0x80000006: /* AMD L2/3 cache/TLB info ; Intel L2 cache features */ + break; + default: + regs[0] = regs[1] = regs[2] = regs[3] = 0; + break; + } + + brand = xc_cpuid_brand_get(); + if (brand == CPU_BRAND_AMD) { + switch (input) { + case 0x00000001: + /* Mask Intel-only features. */ + regs[2] &= ~(bitmaskof(X86_FEATURE_SSSE3) | + bitmaskof(X86_FEATURE_SSE4_1) | + bitmaskof(X86_FEATURE_SSE4_2)); + break; + + case 0x00000002: + case 0x00000004: + regs[0] = regs[1] = regs[2] = 0; + break; + + case 0x80000001: { + int is_64bit = hypervisor_is_64bit(xc) && is_pae; + + if (!is_pae) + clear_bit(X86_FEATURE_PAE, regs[3]); + clear_bit(X86_FEATURE_PSE36, regs[3]); + + /* Filter all other features according to a whitelist. */ + regs[2] &= ((is_64bit ? bitmaskof(X86_FEATURE_LAHF_LM) : 0) | + bitmaskof(X86_FEATURE_ALTMOVCR) | + bitmaskof(X86_FEATURE_ABM) | + bitmaskof(X86_FEATURE_SSE4A) | + bitmaskof(X86_FEATURE_MISALIGNSSE) | + bitmaskof(X86_FEATURE_3DNOWPF)); + regs[3] &= (0x0183f3ff | /* features shared with 0x00000001:EDX */ + (is_pae ? bitmaskof(X86_FEATURE_NX) : 0) | + (is_64bit ? bitmaskof(X86_FEATURE_LM) : 0) | + bitmaskof(X86_FEATURE_SYSCALL) | + bitmaskof(X86_FEATURE_MP) | + bitmaskof(X86_FEATURE_MMXEXT) | + bitmaskof(X86_FEATURE_FFXSR) | + bitmaskof(X86_FEATURE_3DNOW) | + bitmaskof(X86_FEATURE_3DNOWEXT)); + break; + } + } + } else if (brand == CPU_BRAND_INTEL) { + switch (input) { + case 0x00000001: + /* Mask AMD-only features. */ + regs[2] &= ~(bitmaskof(X86_FEATURE_POPCNT)); + break; + + case 0x00000004: + regs[0] &= 0x3FF; + regs[3] &= 0x3FF; + break; + + case 0x80000001: + { + int is_64bit = hypervisor_is_64bit(xc) && is_pae; + + /* Only a few features are advertised in Intel's 0x80000001. */ + regs[2] &= (is_64bit ? bitmaskof(X86_FEATURE_LAHF_LM) : 0); + regs[3] &= ((is_pae ? bitmaskof(X86_FEATURE_NX) : 0) | + (is_64bit ? bitmaskof(X86_FEATURE_LM) : 0) | + (is_64bit ? bitmaskof(X86_FEATURE_SYSCALL) : 0)); + break; + } + case 0x80000005: + { + regs[0] = regs[1] = regs[2] = 0; + break; + } + } + } +} + +static void do_pv_cpuid_policy(int xc, int domid, uint32_t input, uint32_t regs[4]) +{ + int brand; + int guest_64_bits, xen_64_bits; + int ret; + + ret = xc_domain_get_machine_address_size(xc, domid); + if (ret < 0) + return; + guest_64_bits = (ret == 64); + xen_64_bits = hypervisor_is_64bit(xc); + brand = xc_cpuid_brand_get(); + + if ((input & 0x7fffffff) == 1) { + clear_bit(X86_FEATURE_VME, regs[3]); + clear_bit(X86_FEATURE_PSE, regs[3]); + clear_bit(X86_FEATURE_PGE, regs[3]); + clear_bit(X86_FEATURE_MCE, regs[3]); + clear_bit(X86_FEATURE_MCA, regs[3]); + clear_bit(X86_FEATURE_MTRR, regs[3]); + clear_bit(X86_FEATURE_PSE36, regs[3]); + } + + switch (input) { + case 1: + if (!xen_64_bits || brand == CPU_BRAND_AMD) + clear_bit(X86_FEATURE_SEP, regs[3]); + clear_bit(X86_FEATURE_DS, regs[3]); + clear_bit(X86_FEATURE_ACC, regs[3]); + clear_bit(X86_FEATURE_PBE, regs[3]); + + clear_bit(X86_FEATURE_DTES64, regs[2]); + clear_bit(X86_FEATURE_MWAIT, regs[2]); + clear_bit(X86_FEATURE_DSCPL, regs[2]); + clear_bit(X86_FEATURE_VMXE, regs[2]); + clear_bit(X86_FEATURE_SMXE, regs[2]); + clear_bit(X86_FEATURE_EST, regs[2]); + clear_bit(X86_FEATURE_TM2, regs[2]); + if (!guest_64_bits) + clear_bit(X86_FEATURE_CX16, regs[2]); + clear_bit(X86_FEATURE_XTPR, regs[2]); + clear_bit(X86_FEATURE_PDCM, regs[2]); + clear_bit(X86_FEATURE_DCA, regs[2]); + break; + case 0x80000001: + if (!guest_64_bits) { + clear_bit(X86_FEATURE_LM, regs[3]); + clear_bit(X86_FEATURE_LAHF_LM, regs[2]); + if (brand != CPU_BRAND_AMD) + clear_bit(X86_FEATURE_SYSCALL, regs[3]); + } else + set_bit(X86_FEATURE_SYSCALL, regs[3]); + clear_bit(X86_FEATURE_PAGE1GB, regs[3]); + clear_bit(X86_FEATURE_RDTSCP, regs[3]); + + clear_bit(X86_FEATURE_SVME, regs[2]); + clear_bit(X86_FEATURE_OSVW, regs[2]); + clear_bit(X86_FEATURE_IBS, regs[2]); + clear_bit(X86_FEATURE_SKINIT, regs[2]); + clear_bit(X86_FEATURE_WDT, regs[2]); + break; + case 5: /* MONITOR/MWAIT */ + case 0xa: /* Architectural Performance Monitor Features */ + case 0x8000000a: /* SVM revision and features */ + case 0x8000001b: /* Instruction Based Sampling */ + regs[0] = regs[1] = regs[2] = regs[3] = 0; + break; + } +} + +static void do_cpuid_policy(int xc, int domid, int hvm, uint32_t input, uint32_t regs[4]) +{ + if (hvm) + do_hvm_cpuid_policy(xc, domid, input, regs); + else + do_pv_cpuid_policy(xc, domid, input, regs); +} + +#endif + +#endif diff --git a/tools/ocaml/libs/xc/xc_e820.h b/tools/ocaml/libs/xc/xc_e820.h new file mode 100644 index 0000000..52bbb0f --- /dev/null +++ b/tools/ocaml/libs/xc/xc_e820.h @@ -0,0 +1,20 @@ +#ifndef __XC_E820_H__ +#define __XC_E820_H__ + +#include + +/* + * PC BIOS standard E820 types and structure. + */ +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 +#define E820_NVS 4 + +struct e820entry { + uint64_t addr; + uint64_t size; + uint32_t type; +} __attribute__((packed)); + +#endif /* __XC_E820_H__ */ diff --git a/tools/ocaml/libs/xc/xc_lib.c b/tools/ocaml/libs/xc/xc_lib.c new file mode 100644 index 0000000..7fffc43 --- /dev/null +++ b/tools/ocaml/libs/xc/xc_lib.c @@ -0,0 +1,1502 @@ +/* + * Copyright (C) 2006-2007 XenSource Ltd. + * Copyright (C) 2008 Citrix Ltd. + * Author Vincent Hanquez + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xc.h" + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#define DECLARE_DOMCTL(_cmd, _domain) \ + struct xen_domctl domctl = { \ + .cmd = _cmd, \ + .domain = _domain, \ + .interface_version = XEN_DOMCTL_INTERFACE_VERSION, \ + } + +#define DECLARE_SYSCTL(_cmd) \ + struct xen_sysctl sysctl = { \ + .cmd = _cmd, \ + .interface_version = XEN_SYSCTL_INTERFACE_VERSION, \ + } + +#define DECLARE_HYPERCALL2(_cmd, _arg0, _arg1) \ + privcmd_hypercall_t hypercall = { \ + .op = _cmd, \ + .arg[0] = (unsigned long) _arg0,\ + .arg[1] = (unsigned long) _arg1,\ + } +#define DECLARE_HYPERCALL0(_cmd) DECLARE_HYPERCALL2(_cmd, 0, 0); +#define DECLARE_HYPERCALL1(_cmd, _arg0) DECLARE_HYPERCALL2(_cmd, _arg0, 0); + +/*---- Errors handlings ----*/ +#ifndef WITHOUT_GOOD_ERROR +#define ERROR_STRLEN 256 + +static char __error_str[ERROR_STRLEN]; + +char * xc_error_get(void) +{ + return __error_str; +} + +static void xc_error_set(const char *fmt, ...) +{ + va_list ap; + char __errordup[ERROR_STRLEN]; + + va_start(ap, fmt); + vsnprintf(__errordup, ERROR_STRLEN, fmt, ap); + va_end(ap); + memcpy(__error_str, __errordup, ERROR_STRLEN); +} + +static void xc_error_dom_set(unsigned int domid, const char *fmt, ...) +{ + va_list ap; + char __errordup[ERROR_STRLEN]; + int i; + + i = snprintf(__errordup, ERROR_STRLEN, "domain %u - ", domid); + va_start(ap, fmt); + i += vsnprintf(__errordup + i, ERROR_STRLEN - i, fmt, ap); + va_end(ap); + snprintf(__errordup + i, ERROR_STRLEN - i, + " failed: %s", xc_error_get()); + memcpy(__error_str, __errordup, ERROR_STRLEN); +} + +void xc_error_clear(void) +{ + memset(__error_str, '\0', ERROR_STRLEN); +} +#else +char * xc_error_get(void) +{ + return ""; +} +#define xc_error_set(fmt, ...) do {} while (0) +#define xc_error_dom_set(id, fmt, ...) do {} while (0) +#define xc_error_clear() do {} while (0) +#endif + +#define xc_error_hypercall(_h, _r) \ + xc_error_set("hypercall %lld fail: %d: %s (ret %d)", _h.op, errno, errno ? strerror(errno) : strerror(-_r), _r) + +int xc_using_injection(void) +{ + return 0; +} + +/*---- Trivia ----*/ +int xc_interface_open(void) +{ + int fd, ret; + + fd = open("/proc/xen/privcmd", O_RDWR); + if (fd == -1) { + xc_error_set("open /proc/xen/privcmd failed: %s", + strerror(errno)); + return -1; + } + + ret = fcntl(fd, F_GETFD); + if (ret < 0) { + xc_error_set("cannot get handle flags: %s", + strerror(errno)); + goto out; + } + + ret = fcntl(fd, F_SETFD, ret | FD_CLOEXEC); + if (ret < 0) { + xc_error_set("cannot set handle flags: %s", + strerror(errno)); + goto out; + } + + return fd; +out: + close(fd); + return -1; +} + +int xc_interface_close(int handle) +{ + int ret; + + ret = close(handle); + if (ret != 0) + xc_error_set("close xc failed: %s", strerror(errno)); + return ret; +} + +/*---- Low private operations ----*/ +static int do_xen_hypercall(int handle, privcmd_hypercall_t *hypercall) +{ + return ioctl(handle, IOCTL_PRIVCMD_HYPERCALL, (unsigned long) hypercall); +} + +static int do_domctl(int handle, struct xen_domctl *domctl) +{ + int ret; + DECLARE_HYPERCALL1(__HYPERVISOR_domctl, domctl); + + if (mlock(domctl, sizeof(*domctl)) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -1; + } + + ret = do_xen_hypercall(handle, &hypercall); + if (ret < 0) + xc_error_hypercall(hypercall, ret); + + munlock(domctl, sizeof(*domctl)); + return ret; +} + +static int do_sysctl(int handle, struct xen_sysctl *sysctl) +{ + int ret; + DECLARE_HYPERCALL1(__HYPERVISOR_sysctl, sysctl); + + if (mlock(sysctl, sizeof(*sysctl)) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -1; + } + + ret = do_xen_hypercall(handle, &hypercall); + if (ret < 0) + xc_error_hypercall(hypercall, ret); + + munlock(sysctl, sizeof(*sysctl)); + return ret; +} + +static int do_evtchnctl(int handle, int cmd, void *arg, size_t arg_size) +{ + DECLARE_HYPERCALL2(__HYPERVISOR_event_channel_op, cmd, arg); + int ret; + + if (mlock(arg, arg_size) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -1; + } + + ret = do_xen_hypercall(handle, &hypercall); + if (ret < 0) + xc_error_hypercall(hypercall, ret); + munlock(arg, arg_size); + return ret; +} + +static int do_memctl_reservation(int handle, int cmd, + struct xen_memory_reservation *reservation) +{ + int ret; + DECLARE_HYPERCALL2(__HYPERVISOR_memory_op, cmd, reservation); + xen_pfn_t *extent_start; + + if (cmd != XENMEM_increase_reservation && + cmd != XENMEM_decrease_reservation && + cmd != XENMEM_populate_physmap) { + xc_error_set("do_memctl_reservation: unknown cmd %d", cmd); + return -EINVAL; + } + + if (mlock(reservation, sizeof(*reservation)) == -1) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -ENOMEM; + } + get_xen_guest_handle(extent_start, reservation->extent_start); + if (extent_start && mlock(extent_start, reservation->nr_extents + * sizeof(xen_pfn_t)) == -1) { + xc_error_set("mlock failed: %s", strerror(errno)); + munlock(reservation, sizeof(*reservation)); + return -3; + } + + ret = do_xen_hypercall(handle, &hypercall); + if (ret) + xc_error_hypercall(hypercall, ret); + munlock(extent_start, reservation->nr_extents * sizeof(xen_pfn_t)); + get_xen_guest_handle(extent_start, reservation->extent_start); + munlock(reservation, sizeof(*reservation)); + return ret; +} + +static int do_ioctl(int handle, int cmd, void *arg) +{ + return ioctl(handle, cmd, arg); +} + +static void * do_mmap(void *start, size_t length, int prot, int flags, + int fd, off_t offset) +{ + return mmap(start, length, prot, flags, fd, offset); +} + +int xc_get_hvm_param(int handle, unsigned int domid, + int param, unsigned long *value) +{ + struct xen_hvm_param arg = { + .domid = domid, + .index = param, + }; + DECLARE_HYPERCALL2(__HYPERVISOR_hvm_op, HVMOP_get_param, + (unsigned long) &arg); + int ret; + + if (mlock(&arg, sizeof(arg)) == -1) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -1; + } + + ret = do_xen_hypercall(handle, &hypercall); + if (ret) + xc_error_hypercall(hypercall, ret); + *value = arg.value; + munlock(&arg, sizeof(arg)); + return ret; +} + +static int xc_set_hvm_param(int handle, unsigned int domid, + int param, unsigned long value) +{ + struct xen_hvm_param arg = { + .domid = domid, + .index = param, + .value = value, + }; + DECLARE_HYPERCALL2(__HYPERVISOR_hvm_op, HVMOP_set_param, (unsigned long) &arg); + int ret; + + if (mlock(&arg, sizeof(arg)) == -1) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -1; + } + + ret = do_xen_hypercall(handle, &hypercall); + if (ret) + xc_error_hypercall(hypercall, ret); + munlock(&arg, sizeof(arg)); + return ret; +} + + +/*---- XC API ----*/ +int xc_domain_create(int handle, unsigned int ssidref, + xen_domain_handle_t dhandle, + unsigned int flags, unsigned int *pdomid) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_createdomain, *pdomid); + domctl.u.createdomain.ssidref = ssidref; + domctl.u.createdomain.flags = flags; + memcpy(domctl.u.createdomain.handle, dhandle, sizeof(xen_domain_handle_t)); + + ret = do_domctl(handle, &domctl); + if (ret != 0) { + xc_error_set("creating domain failed: %s", xc_error_get()); + return ret; + } + *pdomid = domctl.domain; + return 0; +} + +int xc_domain_pause(int handle, unsigned int domid) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_pausedomain, domid); + + ret = do_domctl(handle, &domctl); + if (ret != 0) + xc_error_dom_set(domid, "pause"); + return ret; +} + +int xc_domain_unpause(int handle, unsigned int domid) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_unpausedomain, domid); + + ret = do_domctl(handle, &domctl); + if (ret != 0) + xc_error_dom_set(domid, "unpause"); + return ret; +} + +/* return 1 if hvm domain got pv driver, 0 if not. -1 is error occurs */ +int xc_hvm_check_pvdriver(int handle, unsigned int domid) +{ + int ret; + unsigned long irq = 0; + xc_domaininfo_t info; + + ret = xc_domain_getinfolist(handle, domid, 1, &info); + if (ret != 1) { + xc_error_set("domain getinfo failed: %s", strerror(errno)); + xc_error_dom_set(domid, "hvm_check_pvdriver"); + return -1; + } + + if (!(info.flags & XEN_DOMINF_hvm_guest)) { + xc_error_set("domain is not hvm"); + xc_error_dom_set(domid, "hvm_check_pvdriver"); + return -1; + } + xc_get_hvm_param(handle, domid, HVM_PARAM_CALLBACK_IRQ, &irq); + return irq; +} + +static int modify_returncode_register(int handle, unsigned int domid) +{ + int ret; + xc_domaininfo_t info; + xen_capabilities_info_t caps; + vcpu_guest_context_any_t context; + + ret = xc_domain_getinfolist(handle, domid, 1, &info); + if (ret != 1) { + xc_error_set("domain getinfo failed: %s", strerror(errno)); + return -1; + } + + /* HVM guests without PV drivers do not have a return code to modify */ + if (info.flags & XEN_DOMINF_hvm_guest) { + unsigned long irq = 0; + xc_get_hvm_param(handle, domid, HVM_PARAM_CALLBACK_IRQ, &irq); + if (!irq) + return 0; + } + + ret = xc_version(handle, XENVER_capabilities, &caps); + if (ret) { + xc_error_set("could not get Xen capabilities"); + return ret; + } + + ret = xc_vcpu_getcontext(handle, domid, 0, &context); + if (ret) { + xc_error_set("could not get vcpu 0 context"); + return ret; + } + + if (!(info.flags & XEN_DOMINF_hvm_guest)) + context.c.user_regs.eax = 1; + else if (strstr(caps, "x86_64")) + context.x64.user_regs.eax = 1; + else + context.x32.user_regs.eax = 1; + + ret = xc_vcpu_setcontext(handle, domid, 0, &context); + if (ret) { + xc_error_set("could not set vcpu 0 context"); + return ret; + } + return 0; +} + +int xc_domain_resume_fast(int handle, unsigned int domid) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_resumedomain, domid); + + ret = modify_returncode_register(handle, domid); + if (ret != 0) { + xc_error_dom_set(domid, "resume_fast"); + return ret; + } + + ret = do_domctl(handle, &domctl); + if (ret != 0) + xc_error_dom_set(domid, "resume_fast"); + return ret; +} + +int xc_domain_destroy(int handle, unsigned int domid) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_destroydomain, domid); + + do { + ret = do_domctl(handle, &domctl); + } while (ret && (errno == EAGAIN)); + if (ret != 0) + xc_error_dom_set(domid, "destroy"); + return ret; +} + +int xc_domain_shutdown(int handle, int domid, int reason) +{ + sched_remote_shutdown_t arg = { + .domain_id = domid, + .reason = reason, + }; + DECLARE_HYPERCALL2(__HYPERVISOR_sched_op, SCHEDOP_remote_shutdown, &arg); + int ret; + + if (mlock(&arg, sizeof(arg)) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + xc_error_dom_set(domid, "shutdown %d", reason); + return -1; + } + + ret = do_xen_hypercall(handle, &hypercall); + if (ret < 0) { + xc_error_hypercall(hypercall, ret); + xc_error_dom_set(domid, "shutdown %d", reason); + } + munlock(&arg, sizeof(arg)); + return ret; +} + +int xc_vcpu_setaffinity(int handle, unsigned int domid, int vcpu, + uint64_t cpumap) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_setvcpuaffinity, domid); + domctl.u.vcpuaffinity.vcpu = vcpu; + domctl.u.vcpuaffinity.cpumap.nr_cpus = sizeof(cpumap) * 8; + + set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap.bitmap, (uint8_t *) &cpumap); + + if (mlock(&cpumap, sizeof(cpumap)) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + xc_error_dom_set(domid, "vcpu %d set affinity", vcpu); + return -1; + } + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "vcpu %d set affinity", vcpu); + munlock(&cpumap, sizeof(cpumap)); + return ret; +} + +int xc_vcpu_getaffinity(int handle, unsigned int domid, int vcpu, + uint64_t *cpumap) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_getvcpuaffinity, domid); + domctl.u.vcpuaffinity.vcpu = vcpu; + domctl.u.vcpuaffinity.cpumap.nr_cpus = sizeof(*cpumap) * 8; + + set_xen_guest_handle(domctl.u.vcpuaffinity.cpumap.bitmap, cpumap); + + if (mlock(cpumap, sizeof(*cpumap)) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + xc_error_dom_set(domid, "vcpu %d get affinity", vcpu); + return -1; + } + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "vcpu %d get affinity", vcpu); + munlock(cpumap, sizeof(*cpumap)); + return ret; +} + +int xc_vcpu_context_get(int handle, unsigned int domid, unsigned short vcpu, + struct vcpu_guest_context *ctxt) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_getvcpucontext, domid); + domctl.u.vcpucontext.vcpu = vcpu; + + set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt); + + if (mlock(ctxt, sizeof(struct vcpu_guest_context)) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + xc_error_dom_set(domid, "vcpu %d get context", vcpu); + return -1; + } + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "vcpu %d get context", vcpu); + munlock(ctxt, sizeof(struct vcpu_guest_context)); + + return ret; +} + +int xc_domain_getinfolist(int handle, unsigned int first_domain, + unsigned int max_domains, xc_domaininfo_t *info) +{ + int ret; + DECLARE_SYSCTL(XEN_SYSCTL_getdomaininfolist); + sysctl.u.getdomaininfolist.first_domain = first_domain; + sysctl.u.getdomaininfolist.max_domains = max_domains; + set_xen_guest_handle(sysctl.u.getdomaininfolist.buffer, info); + + if (mlock(info, max_domains * sizeof(xc_domaininfo_t)) != 0) { + xc_error_set("getinfolist(%d, %u, %u, %x (%d)) failed: mlock failed: %s", + handle, first_domain, max_domains, info, sizeof(xc_domaininfo_t), + strerror(errno)); + return -1; + } + + ret = do_sysctl(handle, &sysctl); + if (ret < 0) + xc_error_set("getinfolist(%d, %u, %u, %x (%d)) failed: %s", + handle, first_domain, max_domains, info, sizeof(xc_domaininfo_t), + xc_error_get()); + else + ret = sysctl.u.getdomaininfolist.num_domains; + + munlock(info, max_domains * sizeof(xc_domaininfo_t)); + return ret; +} + +int xc_domain_getinfo(int handle, unsigned int domid, xc_domaininfo_t *info) +{ + int ret; + ret = xc_domain_getinfolist(handle, domid, 1, info); + if (ret != 1) { + xc_error_set("getinfo failed: domain %d: %s", domid, xc_error_get()); + return -1; + } + + /* If the requested domain didn't exist but there exists one with a + higher domain ID, this will be returned. We consider this an error since + we only wanted info about a specific domain. */ + if (info->domain != domid) { + xc_error_set("getinfo failed: domain %d nolonger exists", domid); + return -1; + } + + return 0; +} + +int xc_domain_setmaxmem(int handle, unsigned int domid, unsigned int max_memkb) +{ + DECLARE_DOMCTL(XEN_DOMCTL_max_mem, domid); + domctl.u.max_mem.max_memkb = max_memkb; + int ret; + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "set max memory to %u", max_memkb); + return ret; +} + +int xc_domain_set_memmap_limit(int handle, unsigned int domid, + unsigned long map_limitkb) +{ + int ret; + struct xen_foreign_memory_map fmap = { + .domid = domid, + .map = { .nr_entries = 1 } + }; + struct e820entry e820 = { + .addr = 0, + .size = (uint64_t)map_limitkb << 10, + .type = E820_RAM + }; + DECLARE_HYPERCALL2(__HYPERVISOR_memory_op, XENMEM_set_memory_map, &fmap); + + set_xen_guest_handle(fmap.map.buffer, &e820); + + if (mlock(&fmap, sizeof(fmap)) != 0) { + xc_error_set("set_memmap_limit failed: mlock failed: %s", + strerror(errno)); + return -1; + } + + if (mlock(&e820, sizeof(e820)) != 0) { + xc_error_set("set_memmap_limit failed: mlock failed: %s", + strerror(errno)); + munlock(&fmap, sizeof(fmap)); + return -1; + } + + ret = do_xen_hypercall(handle, &hypercall); + if (ret) + xc_error_hypercall(hypercall, ret); + + munlock(&e820, sizeof(e820)); + munlock(&fmap, sizeof(fmap)); + return ret; +} + +int xc_domain_set_time_offset(int handle, unsigned int domid, int time_offset) +{ + DECLARE_DOMCTL(XEN_DOMCTL_settimeoffset, domid); + domctl.u.settimeoffset.time_offset_seconds = time_offset; + int ret; + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "set time offset %d", time_offset); + return ret; +} + +int xc_domain_memory_increase_reservation(int handle, unsigned int domid, + unsigned long nr_extents, + unsigned int extent_order, + unsigned int address_bits, + xen_pfn_t *extent_start) +{ + int ret; + struct xen_memory_reservation reservation = { + .nr_extents = nr_extents, + .extent_order = extent_order, + .COMPAT_FIELD_ADDRESS_BITS = address_bits, + .domid = domid + }; + + set_xen_guest_handle(reservation.extent_start, extent_start); + + ret = do_memctl_reservation(handle, XENMEM_increase_reservation, + &reservation); + if (ret != nr_extents) { + xc_error_dom_set(domid, "increase reservation to %lu", + nr_extents); + return (ret >= 0) ? -1 : ret; + } + return 0; +} + +int xc_domain_memory_decrease_reservation(int handle, unsigned int domid, + unsigned long nr_extents, + unsigned int extent_order, + unsigned int address_bits, + xen_pfn_t *extent_start) +{ + int ret; + struct xen_memory_reservation reservation = { + .nr_extents = nr_extents, + .extent_order = extent_order, + .COMPAT_FIELD_ADDRESS_BITS = 0, + .domid = domid + }; + + set_xen_guest_handle(reservation.extent_start, extent_start); + if (!extent_start) { + xc_error_set("decrease reservation: extent start is NULL"); + return -EINVAL; + } + + ret = do_memctl_reservation(handle, XENMEM_decrease_reservation, + &reservation); + if (ret < nr_extents) { + xc_error_dom_set(domid, "decrease reservation to %lu", + nr_extents); + return (ret >= 0) ? -1 : ret; + } + return 0; +} + +int xc_domain_memory_populate_physmap(int handle, unsigned int domid, + unsigned long nr_extents, + unsigned int extent_order, + unsigned int address_bits, + xen_pfn_t *extent_start) +{ + int ret; + struct xen_memory_reservation reservation = { + .nr_extents = nr_extents, + .extent_order = extent_order, + .COMPAT_FIELD_ADDRESS_BITS = address_bits, + .domid = domid + }; + + set_xen_guest_handle(reservation.extent_start, extent_start); + ret = do_memctl_reservation(handle, XENMEM_populate_physmap, + &reservation); + if (ret < nr_extents) { + xc_error_dom_set(domid, "populate physmap"); + return (ret >= 0) ? -1 : ret; + } + return 0; +} + +int xc_domain_setvmxassist(int handle, unsigned int domid, int use_vmxassist) +{ + int ret = 0; +#ifdef XEN_DOMCTL_setvmxassist + DECLARE_DOMCTL(XEN_DOMCTL_setvmxassist, domid); + domctl.u.setvmxassist.use_vmxassist = use_vmxassist; + + ret = do_domctl(handle, &domctl); + if (ret) + xc_error_dom_set(domid, "setting vmxassist to %d", + use_vmxassist); +#endif + return ret; +} + +int xc_domain_max_vcpus(int handle, unsigned int domid, unsigned int max) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_max_vcpus, domid); + domctl.u.max_vcpus.max = max; + + ret = do_domctl(handle, &domctl); + if (ret) + xc_error_dom_set(domid, "setting max vcpus to %d", max); + return ret; +} + +int xc_domain_sethandle(int handle, unsigned int domid, + xen_domain_handle_t dhandle) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_setdomainhandle, domid); + memcpy(domctl.u.setdomainhandle.handle, dhandle, sizeof(xen_domain_handle_t)); + + ret = do_domctl(handle, &domctl); + if (ret) + xc_error_dom_set(domid, "set handle"); + return ret; +} + +int xc_vcpu_getinfo(int handle, unsigned int domid, unsigned int vcpu, + xc_vcpuinfo_t *info) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_getvcpuinfo, domid); + domctl.u.getvcpuinfo.vcpu = vcpu; + + ret = do_domctl(handle, &domctl); + if (ret < 0) { + xc_error_dom_set(domid, "vcpu %u getinfo", vcpu); + return ret; + } + memcpy(info, &domctl.u.getvcpuinfo, sizeof(*info)); + return ret; +} + +int xc_domain_ioport_permission(int handle, unsigned int domid, + unsigned int first_port, unsigned int nr_ports, + unsigned int allow_access) +{ + DECLARE_DOMCTL(XEN_DOMCTL_ioport_permission, domid); + domctl.u.ioport_permission.first_port = first_port; + domctl.u.ioport_permission.nr_ports = nr_ports; + domctl.u.ioport_permission.allow_access = allow_access; + + return do_domctl(handle, &domctl); +} + +int xc_vcpu_getcontext(int handle, unsigned int domid, + unsigned int vcpu, vcpu_guest_context_any_t *ctxt) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_getvcpucontext, domid); + domctl.u.vcpucontext.vcpu = vcpu; + set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt); + + if (mlock(ctxt, sizeof(*ctxt)) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -1; + } + + ret = do_domctl(handle, &domctl); + if (ret) + xc_error_dom_set(domid, "vcpu %u getcontext", vcpu); + munlock(ctxt, sizeof(*ctxt)); + return ret; +} + +int xc_vcpu_setcontext(int handle, unsigned int domid, + unsigned int vcpu, vcpu_guest_context_any_t *ctxt) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_setvcpucontext, domid); + domctl.u.vcpucontext.vcpu = vcpu; + set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt); + + if (mlock(ctxt, sizeof(*ctxt)) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -1; + } + + ret = do_domctl(handle, &domctl); + if (ret) + xc_error_dom_set(domid, "vcpu %u setcontext", vcpu); + + munlock(ctxt, sizeof(*ctxt)); + return ret; +} + +int xc_domain_irq_permission(int handle, unsigned int domid, + unsigned char pirq, unsigned char allow_access) +{ + DECLARE_DOMCTL(XEN_DOMCTL_irq_permission, domid); + domctl.u.irq_permission.pirq = pirq; + domctl.u.irq_permission.allow_access = allow_access; + int ret; + + ret = do_domctl(handle, &domctl); + if (ret) + xc_error_dom_set(domid, "irq permission %u to %u", + pirq, allow_access); + return ret; +} + +int xc_domain_iomem_permission(int handle, unsigned int domid, + unsigned long first_mfn, unsigned long nr_mfns, + unsigned char allow_access) +{ + DECLARE_DOMCTL(XEN_DOMCTL_iomem_permission, domid); + domctl.u.iomem_permission.first_mfn = first_mfn; + domctl.u.iomem_permission.nr_mfns = nr_mfns; + domctl.u.iomem_permission.allow_access = allow_access; + int ret; + + ret = do_domctl(handle, &domctl); + if (ret) + xc_error_dom_set(domid, "iomem permission [%lu, %lu] to %u", + first_mfn, first_mfn + nr_mfns, allow_access); + return ret; +} + +long long xc_domain_get_cpu_usage(int handle, unsigned int domid, + unsigned int vcpu) +{ + DECLARE_DOMCTL(XEN_DOMCTL_getvcpuinfo, domid); + domctl.u.getvcpuinfo.vcpu = vcpu; + + if (do_domctl(handle, &domctl) < 0) { + xc_error_dom_set(domid, "get cpu %d usage", vcpu); + return -1; + } + return domctl.u.getvcpuinfo.cpu_time; +} + +void *xc_map_foreign_range(int handle, unsigned int domid, + int size, int prot, unsigned long mfn) +{ + privcmd_mmap_entry_t entry = { + .mfn = mfn, + .npages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT, + }; + privcmd_mmap_t ioctlx = { + .num = 1, + .dom = domid, + .entry = &entry, + }; + void *addr; + + addr = do_mmap(NULL, size, prot, MAP_SHARED, handle, 0); + if (addr == MAP_FAILED) { + xc_error_set("mmap failed: %s", strerror(errno)); + xc_error_dom_set(domid, "map foreign range [%lx,%lx] prot %u", + mfn, mfn + size, prot); + return NULL; + } + entry.va = (unsigned long) addr; + if (do_ioctl(handle, IOCTL_PRIVCMD_MMAP, &ioctlx) < 0) { + xc_error_set("ioctl failed: %s", strerror(errno)); + xc_error_dom_set(domid, "map foreign range [%lx,%lx] prot %u", + mfn, mfn + size, prot); + munmap(addr, size); + return NULL; + } + return addr; +} + +int xc_map_foreign_ranges(int handle, unsigned int domid, + privcmd_mmap_entry_t *entries, int nr) +{ + privcmd_mmap_t ioctlx = { + .num = nr, + .dom = domid, + .entry = entries, + }; + int ret; + + ret = do_ioctl(handle, IOCTL_PRIVCMD_MMAP, &ioctlx); + if (ret < 0) { + xc_error_set("ioctl failed: %s", strerror(errno)); + xc_error_dom_set(domid, "map foreign ranges"); + return -1; + } + return ret; +} + +int xc_readconsolering(int handle, char **pbuffer, + unsigned int *pnr_chars, int clear) +{ + int ret; + DECLARE_SYSCTL(XEN_SYSCTL_readconsole); + char *buffer = *pbuffer; + unsigned int nr_chars = *pnr_chars; + + set_xen_guest_handle(sysctl.u.readconsole.buffer, buffer); + sysctl.u.readconsole.count = nr_chars; + sysctl.u.readconsole.clear = clear; + + if (mlock(buffer, nr_chars) != 0) { + xc_error_set("read console ring: mlock failed: %s", + strerror(errno)); + return -1; + } + + ret = do_sysctl(handle, &sysctl); + if (ret != 0) + xc_error_set("read console ring failed: %s", xc_error_get()); + else + *pnr_chars = sysctl.u.readconsole.count; + + munlock(buffer, nr_chars); + return ret; +} + +int xc_send_debug_keys(int handle, char *keys) +{ + int ret; + DECLARE_SYSCTL(XEN_SYSCTL_debug_keys); + + set_xen_guest_handle(sysctl.u.debug_keys.keys, keys); + sysctl.u.debug_keys.nr_keys = strlen(keys); + + if (mlock(keys, sysctl.u.debug_keys.nr_keys) != 0) { + xc_error_set("send debug keys: mlock failed: %s", + strerror(errno)); + return -1; + } + + ret = do_sysctl(handle, &sysctl); + if (ret != 0) + xc_error_set("send debug keys: %s", xc_error_get()); + + munlock(keys, sysctl.u.debug_keys.nr_keys); + return ret; +} + +int xc_physinfo(int handle, xc_physinfo_t *put_info) +{ + DECLARE_SYSCTL(XEN_SYSCTL_physinfo); + int ret; + + ret = do_sysctl(handle, &sysctl); + if (ret) { + xc_error_set("physinfo failed: %s", xc_error_get()); + return ret; + } + memcpy(put_info, &sysctl.u.physinfo, sizeof(*put_info)); + return 0; +} + +int xc_pcpu_info(int handle, int max_cpus, uint64_t *info, int *nr_cpus) +{ + DECLARE_SYSCTL(XEN_SYSCTL_getcpuinfo); + int ret; + + sysctl.u.getcpuinfo.max_cpus = max_cpus; + set_xen_guest_handle(sysctl.u.getcpuinfo.info, info); + + if (mlock(info, sizeof(*info) * max_cpus) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -1; + } + + ret = do_sysctl(handle, &sysctl); + if (ret) + xc_error_set("pcpu info failed: %s", xc_error_get()); + else if (ret == 0 && nr_cpus) + *nr_cpus = sysctl.u.getcpuinfo.nr_cpus; + munlock(info, sizeof(*info) * max_cpus); + return ret; +} + +int xc_sched_id(int handle, int *sched_id) +{ + DECLARE_SYSCTL(XEN_SYSCTL_sched_id); + int ret; + + ret = do_sysctl(handle, &sysctl); + if (ret) { + xc_error_set("sched id failed: %s", xc_error_get()); + return ret; + } + *sched_id = sysctl.u.sched_id.sched_id; + return 0; +} + +int xc_version(int handle, int cmd, void *arg) +{ + int argsize; + int ret; + DECLARE_HYPERCALL2(__HYPERVISOR_xen_version, cmd, arg); + + switch (cmd) { + case XENVER_extraversion: + argsize = sizeof(xen_extraversion_t); break; + case XENVER_compile_info: + argsize = sizeof(xen_compile_info_t); break; + case XENVER_capabilities: + argsize = sizeof(xen_capabilities_info_t); break; + case XENVER_changeset: + argsize = sizeof(xen_changeset_info_t); break; + case XENVER_platform_parameters: + argsize = sizeof(xen_platform_parameters_t); break; + case XENVER_version: + argsize = 0; break; + default: + xc_error_set("version: unknown command"); + return -1; + } + if (argsize && mlock(arg, argsize) == -1) { + xc_error_set("version: mlock failed: %s", strerror(errno)); + return -ENOMEM; + } + + ret = do_xen_hypercall(handle, &hypercall); + if (ret) + xc_error_hypercall(hypercall, ret); + + if (argsize) + munlock(arg, argsize); + return ret; +} + +int xc_evtchn_alloc_unbound(int handle, unsigned int domid, + unsigned int remote_domid) +{ + struct evtchn_alloc_unbound arg = { + .dom = domid, + .remote_dom = remote_domid, + }; + int ret; + + ret = do_evtchnctl(handle, EVTCHNOP_alloc_unbound, &arg, sizeof(arg)); + if (ret) { + xc_error_dom_set(domid, "alloc unbound evtchn to %d", + remote_domid); + return ret; + } + return arg.port; +} + +int xc_evtchn_reset(int handle, unsigned int domid) +{ + struct evtchn_reset arg = { + .dom = domid, + }; + int ret; + + ret = do_evtchnctl(handle, EVTCHNOP_reset, &arg, sizeof(arg)); + if (ret) + xc_error_dom_set(domid, "reset evtchn of %d", domid); + return ret; +} + +int xc_sched_credit_domain_set(int handle, unsigned int domid, + struct xen_domctl_sched_credit *sdom) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_scheduler_op, domid); + domctl.u.scheduler_op.sched_id = XEN_SCHEDULER_CREDIT; + domctl.u.scheduler_op.cmd = XEN_DOMCTL_SCHEDOP_putinfo; + domctl.u.scheduler_op.u.credit = *sdom; + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "credit scheduler domain set"); + return ret; +} + +int xc_sched_credit_domain_get(int handle, unsigned int domid, + struct xen_domctl_sched_credit *sdom) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_scheduler_op, domid); + + domctl.u.scheduler_op.sched_id = XEN_SCHEDULER_CREDIT; + domctl.u.scheduler_op.cmd = XEN_DOMCTL_SCHEDOP_getinfo; + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "credit scheduler domain get"); + else + *sdom = domctl.u.scheduler_op.u.credit; + return ret; +} + +int xc_shadow_allocation_get(int handle, unsigned int domid, uint32_t *mb) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_shadow_op, domid); + + domctl.u.shadow_op.op = XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION; + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "shadow allocation get"); + else + *mb = domctl.u.shadow_op.mb; + return ret; +} + +int xc_shadow_allocation_set(int handle, unsigned int domid, uint32_t mb) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_shadow_op, domid); + + domctl.u.shadow_op.op = XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION; + domctl.u.shadow_op.mb = mb; + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "shadow allocation set"); + return ret; +} + +int xc_domain_get_pfn_list(int handle, unsigned int domid, + xen_pfn_t *pfn_array, unsigned long max_pfns) +{ + int ret; + DECLARE_DOMCTL(XEN_DOMCTL_getmemlist, domid); + + domctl.u.getmemlist.max_pfns = max_pfns; + set_xen_guest_handle(domctl.u.getmemlist.buffer, pfn_array); + + if (mlock(pfn_array, max_pfns * sizeof(xen_pfn_t)) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -1; + } + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "get pfn list"); + + munlock(pfn_array, max_pfns * sizeof(xen_pfn_t)); + return (ret < 0) ? ret : domctl.u.getmemlist.num_pfns; +} + +#define MARSHALL_BDF(d,b,s,f) \ + (((b) & 0xff) << 16 | ((s) & 0x1f) << 11 | ((f) & 0x7) << 8) + +int xc_domain_assign_device(int handle, unsigned int domid, + int domain, int bus, int slot, int func) +{ + int ret = -EBADF; +#ifdef XEN_DOMCTL_assign_device + DECLARE_DOMCTL(XEN_DOMCTL_assign_device, domid); + + domctl.u.assign_device.machine_bdf = MARSHALL_BDF(domain, bus, slot, func); + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "assign device"); +#endif + return ret; +} + +int xc_domain_deassign_device(int handle, unsigned int domid, + int domain, int bus, int slot, int func) +{ + int ret = -EBADF; +#ifdef XEN_DOMCTL_deassign_device + DECLARE_DOMCTL(XEN_DOMCTL_deassign_device, domid); + + domctl.u.assign_device.machine_bdf = MARSHALL_BDF(domain, bus, slot, func); + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "deassign device"); +#endif + return ret; +} + +int xc_domain_test_assign_device(int handle, unsigned int domid, + int domain, int bus, int slot, int func) +{ + int ret = -EBADF; +#ifdef XEN_DOMCTL_test_assign_device + DECLARE_DOMCTL(XEN_DOMCTL_test_assign_device, domid); + domctl.u.assign_device.machine_bdf = MARSHALL_BDF(domain, bus, slot, func); + + ret = do_domctl(handle, &domctl); + if (ret < 0) + xc_error_dom_set(domid, "test assign device"); +#endif + return ret; +} + +int xc_domain_watchdog(int handle, int id, uint32_t timeout) +{ + int ret = -EBADF; +#ifdef SCHEDOP_watchdog + sched_watchdog_t arg = { + .id = (uint32_t) id, + .timeout = timeout, + }; + DECLARE_HYPERCALL2(__HYPERVISOR_sched_op, SCHEDOP_watchdog, &arg); + + if (mlock(&arg, sizeof(arg)) != 0) { + xc_error_set("mlock failed: %s", strerror(errno)); + return -1; + } + + ret = do_xen_hypercall(handle, &hypercall); + if (ret < 0) { + xc_error_hypercall(hypercall, ret); + } + munlock(&arg, sizeof(arg)); +#endif + return ret; +} + +int xc_domain_set_machine_address_size(int xc, uint32_t domid, unsigned int width) +{ + DECLARE_DOMCTL(XEN_DOMCTL_set_machine_address_size, domid); + int rc; + + domctl.u.address_size.size = width; + rc = do_domctl(xc, &domctl); + if (rc != 0) + xc_error_dom_set(domid, "set machine address size"); + + return rc; +} + +int xc_domain_get_machine_address_size(int xc, uint32_t domid) +{ + DECLARE_DOMCTL(XEN_DOMCTL_get_machine_address_size, domid); + int rc; + + rc = do_domctl(xc, &domctl); + if (rc != 0) + xc_error_dom_set(domid, "get machine address size"); + return rc == 0 ? domctl.u.address_size.size : rc; +} + +#include "xc_cpuid.h" +int xc_domain_cpuid_set(int xc, unsigned int domid, int hvm, + uint32_t input, uint32_t oinput, + char *config[4], char *config_out[4]) +{ + int ret = -EBADF; +#ifdef XEN_DOMCTL_set_cpuid + DECLARE_DOMCTL(XEN_DOMCTL_set_cpuid, domid); + uint32_t regs[4], polregs[4]; + int i, j; + + xc_cpuid(input, oinput, regs); + memcpy(polregs, regs, sizeof(regs)); + do_cpuid_policy(xc, domid, hvm, input, polregs); + + for (i = 0; i < 4; i++) { + if (!config[i]) { + regs[i] = polregs[i]; + continue; + } + + for (j = 0; j < 32; j++) { + unsigned char val, polval; + + val = !!((regs[i] & (1U << (31 - j)))); + polval = !!((regs[i] & (1U << (31 - j)))); + + switch (config[i][j]) { + case '1': val = 1; break; /* force to true */ + case '0': val = 0; break; /* force to false */ + case 'x': val = polval; break; + case 'k': case 's': break; + default: + xc_error_dom_set(domid, "domain cpuid set: invalid config"); + ret = -EINVAL; + goto out; + } + + if (val) + set_bit(31 - j, regs[i]); + else + clear_bit(31 - j, regs[i]); + + if (config_out && config_out[i]) { + config_out[i][j] = (config[i][j] == 's') + ? '0' + val + : config[i][j]; + } + } + } + + domctl.u.cpuid.input[0] = input; + domctl.u.cpuid.input[1] = oinput; + domctl.u.cpuid.eax = regs[0]; + domctl.u.cpuid.ebx = regs[1]; + domctl.u.cpuid.ecx = regs[2]; + domctl.u.cpuid.edx = regs[3]; + ret = do_domctl(xc, &domctl); + if (ret) { + xc_error_dom_set(domid, "cpuid set"); + goto out; + } +out: +#endif + return ret; +} + +int xc_domain_cpuid_apply(int xc, unsigned int domid, int hvm) +{ + int ret = -EBADF; +#ifdef XEN_DOMCTL_set_cpuid + uint32_t regs[4], base_max, ext_max, eax, ecx; + + /* determinate cpuid range */ + xc_cpuid(0, 0, regs); + base_max = MIN(regs[0], DEF_MAX_BASE); + xc_cpuid(0x80000000, 0, regs); + ext_max = MIN(regs[0], DEF_MAX_EXT); + + eax = ecx = 0; + while (!(eax & 0x80000000) || (eax <= ext_max)) { + xc_cpuid(eax, ecx, regs); + + do_cpuid_policy(xc, domid, hvm, eax, regs); + + if (regs[0] || regs[1] || regs[2] || regs[3]) { + DECLARE_DOMCTL(XEN_DOMCTL_set_cpuid, domid); + + domctl.u.cpuid.input[0] = eax; + domctl.u.cpuid.input[1] = (eax == 4) ? ecx : XEN_CPUID_INPUT_UNUSED; + domctl.u.cpuid.eax = regs[0]; + domctl.u.cpuid.ebx = regs[1]; + domctl.u.cpuid.ecx = regs[2]; + domctl.u.cpuid.edx = regs[3]; + + ret = do_domctl(xc, &domctl); + if (ret) { + xc_error_dom_set(domid, "cpuid apply"); + goto out; + } + + /* we repeat when doing node 4 (cache descriptor leaves) increasing ecx + * until the cpuid eax value masked is 0 */ + if (eax == 4) { + ecx++; + if ((regs[0] & 0x1f) != 0) + continue; + ecx = 0; + } + } + + eax++; + if (!(eax & 0x80000000) && (eax > base_max)) + eax = 0x80000000; + } + ret = 0; +out: +#endif + return ret; +} + +/* + * return 1 on checking success + * 0 on checking failure + * -EINVAL if the config contains unknown character + */ +int xc_cpuid_check(uint32_t input, uint32_t optsubinput, + char *config[4], char *config_out[4]) +{ + int ret = -EBADF; +#ifdef XEN_DOMCTL_set_cpuid + uint32_t regs[4]; + int i, j; + + xc_cpuid(input, optsubinput, regs); + + ret = 1; + for (i = 0; i < 4; i++) { + if (!config[i]) + continue; + for (j = 0; j < 32; j++) { + unsigned char val; + + val = !!((regs[i] & (1U << (31 - j)))); + + switch (config[i][j]) { + case '1': if (!val) { ret = 0; goto out; }; break; + case '0': if (val) { ret = 0; goto out; }; break; + case 'x': case 's': break; + default: + xc_error_set("cpuid check: invalid config"); + ret = -EINVAL; + goto out; + } + + if (config_out && config_out[i]) { + config_out[i][j] = (config[i][j] == 's') + ? '0' + val + : config[i][j]; + } + } + } +out: +#endif + return ret; +} + +#ifndef HVM_PARAM_HPET_ENABLED +#define HVM_PARAM_HPET_ENABLED 11 +#endif + +#ifndef HVM_PARAM_ACPI_S_STATE +#define HVM_PARAM_ACPI_S_STATE 14 +#endif + +#ifndef HVM_PARAM_VPT_ALIGN +#define HVM_PARAM_VPT_ALIGN 16 +#endif + +int xc_domain_send_s3resume(int handle, unsigned int domid) +{ + return xc_set_hvm_param(handle, domid, HVM_PARAM_ACPI_S_STATE, 0); +} + +int xc_domain_set_timer_mode(int handle, unsigned int domid, int mode) +{ + return xc_set_hvm_param(handle, domid, + HVM_PARAM_TIMER_MODE, (unsigned long) mode); +} + +int xc_domain_set_hpet(int handle, unsigned int domid, int hpet) +{ + return xc_set_hvm_param(handle, domid, HVM_PARAM_HPET_ENABLED, (unsigned long) hpet); +} + +int xc_domain_set_vpt_align(int handle, unsigned int domid, int vpt_align) +{ + return xc_set_hvm_param(handle, domid, HVM_PARAM_HPET_ENABLED, (unsigned long) vpt_align); +} + +int xc_domain_get_acpi_s_state(int handle, unsigned int domid) +{ + int ret; + unsigned long value; + + ret = xc_get_hvm_param(handle, domid, HVM_PARAM_ACPI_S_STATE, &value); + if (ret != 0) + xc_error_dom_set(domid, "get acpi s-state"); + return value; +} diff --git a/tools/ocaml/libs/xc/xc_stubs.c b/tools/ocaml/libs/xc/xc_stubs.c new file mode 100644 index 0000000..b43a750 --- /dev/null +++ b/tools/ocaml/libs/xc/xc_stubs.c @@ -0,0 +1,1170 @@ +/* + * Copyright (C) 2006-2007 XenSource Ltd. + * Copyright (C) 2008 Citrix Ltd. + * Author Vincent Hanquez + * + * 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. + */ + +#define _XOPEN_SOURCE 600 +#include + +#define CAML_NAME_SPACE +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "xc.h" + +#include "mmap_stubs.h" + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#define _H(__h) (Int_val(__h)) +#define _D(__d) ((uint32_t)Int_val(__d)) + +#define Val_none (Val_int(0)) + +#define string_of_option_array(array, index) \ + ((Field(array, index) == Val_none) ? NULL : String_val(Field(Field(array, index), 0))) + +/* maybe here we should check the range of the input instead of blindly + * casting it to uint32 */ +#define cpuid_input_of_val(i1, i2, input) \ + i1 = (uint32_t) Int64_val(Field(input, 0)); \ + i2 = ((Field(input, 1) == Val_none) ? 0xffffffff : (uint32_t) Int64_val(Field(Field(input, 1), 0))); + +/** + * Convert the given number of pages to an amount in MiB, rounded up. + */ +void failwith_xc(void) +{ + caml_raise_with_string(*caml_named_value("xc.error"), xc_error_get()); +} + +CAMLprim value stub_sizeof_core_header(value unit) +{ + CAMLparam1(unit); + CAMLreturn(Val_int(sizeof(struct xc_core_header))); +} + +CAMLprim value stub_sizeof_vcpu_guest_context(value unit) +{ + CAMLparam1(unit); + CAMLreturn(Val_int(sizeof(struct vcpu_guest_context))); +} + +CAMLprim value stub_sizeof_xen_pfn(value unit) +{ + CAMLparam1(unit); + CAMLreturn(Val_int(sizeof(xen_pfn_t))); +} + +#define XC_CORE_MAGIC 0xF00FEBED +#define XC_CORE_MAGIC_HVM 0xF00FEBEE + +CAMLprim value stub_marshall_core_header(value header) +{ + CAMLparam1(header); + CAMLlocal1(s); + struct xc_core_header c_header; + + c_header.xch_magic = (Field(header, 0)) + ? XC_CORE_MAGIC + : XC_CORE_MAGIC_HVM; + c_header.xch_nr_vcpus = Int_val(Field(header, 1)); + c_header.xch_nr_pages = Nativeint_val(Field(header, 2)); + c_header.xch_ctxt_offset = Int64_val(Field(header, 3)); + c_header.xch_index_offset = Int64_val(Field(header, 4)); + c_header.xch_pages_offset = Int64_val(Field(header, 5)); + + s = caml_alloc_string(sizeof(c_header)); + memcpy(String_val(s), (char *) &c_header, sizeof(c_header)); + CAMLreturn(s); +} + +CAMLprim value stub_xc_interface_open() +{ + int handle; + handle = xc_interface_open(); + if (handle == -1) + failwith_xc(); + return Val_int(handle); +} + + +CAMLprim value stub_xc_interface_open_fake() +{ + return Val_int(-1); +} + +CAMLprim value stub_xc_using_injection() +{ + if (xc_using_injection ()){ + return Val_int(1); + } else { + return Val_int(0); + } +} + +CAMLprim value stub_xc_interface_close(value xc_handle) +{ + CAMLparam1(xc_handle); + + int handle = _H(xc_handle); + // caml_enter_blocking_section(); + xc_interface_close(handle); + // caml_leave_blocking_section(); + + CAMLreturn(Val_unit); +} + +static int domain_create_flag_table[] = { + XEN_DOMCTL_CDF_hvm_guest, + XEN_DOMCTL_CDF_hap, +}; + +CAMLprim value stub_xc_domain_create(value xc_handle, value ssidref, + value flags, value handle) +{ + CAMLparam4(xc_handle, ssidref, flags, handle); + + uint32_t domid = 0; + xen_domain_handle_t h = { 0 }; + int result; + int i; + int c_xc_handle = _H(xc_handle); + uint32_t c_ssidref = Int32_val(ssidref); + unsigned int c_flags = 0; + value l; + + if (Wosize_val(handle) != 16) + caml_invalid_argument("Handle not a 16-integer array"); + + for (i = 0; i < sizeof(h); i++) { + h[i] = Int_val(Field(handle, i)) & 0xff; + } + + for (l = flags; l != Val_none; l = Field(l, 1)) { + int v = Int_val(Field(l, 0)); + c_flags |= domain_create_flag_table[v]; + } + + // caml_enter_blocking_section(); + result = xc_domain_create(c_xc_handle, c_ssidref, h, c_flags, &domid); + // caml_leave_blocking_section(); + + if (result < 0) + failwith_xc(); + + CAMLreturn(Val_int(domid)); +} + +CAMLprim value stub_xc_domain_setvmxassist(value xc_handle, value domid, + value use_vmxassist) +{ + CAMLparam3(xc_handle, domid, use_vmxassist); + int r; + + r = xc_domain_setvmxassist(_H(xc_handle), _D(domid), + Bool_val(use_vmxassist)); + if (r) + failwith_xc(); + + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_max_vcpus(value xc_handle, value domid, + value max_vcpus) +{ + CAMLparam3(xc_handle, domid, max_vcpus); + int r; + + r = xc_domain_max_vcpus(_H(xc_handle), _D(domid), Int_val(max_vcpus)); + if (r) + failwith_xc(); + + CAMLreturn(Val_unit); +} + + +value stub_xc_domain_sethandle(value xc_handle, value domid, value handle) +{ + CAMLparam3(xc_handle, domid, handle); + xen_domain_handle_t h = { 0 }; + int i; + + if (Wosize_val(handle) != 16) + caml_invalid_argument("Handle not a 16-integer array"); + + for (i = 0; i < sizeof(h); i++) { + h[i] = Int_val(Field(handle, i)) & 0xff; + } + + i = xc_domain_sethandle(_H(xc_handle), _D(domid), h); + if (i) + failwith_xc(); + + CAMLreturn(Val_unit); +} + +static value dom_op(value xc_handle, value domid, int (*fn)(int, uint32_t)) +{ + CAMLparam2(xc_handle, domid); + + int c_xc_handle = _H(xc_handle); + uint32_t c_domid = _D(domid); + + // caml_enter_blocking_section(); + int result = fn(c_xc_handle, c_domid); + // caml_leave_blocking_section(); + if (result) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_pause(value xc_handle, value domid) +{ + return dom_op(xc_handle, domid, xc_domain_pause); +} + + +CAMLprim value stub_xc_domain_unpause(value xc_handle, value domid) +{ + return dom_op(xc_handle, domid, xc_domain_unpause); +} + +CAMLprim value stub_xc_domain_destroy(value xc_handle, value domid) +{ + return dom_op(xc_handle, domid, xc_domain_destroy); +} + +CAMLprim value stub_xc_domain_resume_fast(value xc_handle, value domid) +{ + return dom_op(xc_handle, domid, xc_domain_resume_fast); +} + +CAMLprim value stub_xc_domain_shutdown(value handle, value domid, value reason) +{ + CAMLparam3(handle, domid, reason); + int ret; + + ret = xc_domain_shutdown(_H(handle), _D(domid), Int_val(reason)); + if (ret < 0) + failwith_xc(); + + CAMLreturn(Val_unit); +} + +static value alloc_domaininfo(xc_domaininfo_t * info) +{ + CAMLparam0(); + CAMLlocal2(result, tmp); + int i; + + result = caml_alloc_tuple(16); + + Store_field(result, 0, Val_int(info->domain)); + Store_field(result, 1, Val_bool(info->flags & XEN_DOMINF_dying)); + Store_field(result, 2, Val_bool(info->flags & XEN_DOMINF_shutdown)); + Store_field(result, 3, Val_bool(info->flags & XEN_DOMINF_paused)); + Store_field(result, 4, Val_bool(info->flags & XEN_DOMINF_blocked)); + Store_field(result, 5, Val_bool(info->flags & XEN_DOMINF_running)); + Store_field(result, 6, Val_bool(info->flags & XEN_DOMINF_hvm_guest)); + Store_field(result, 7, Val_int((info->flags >> XEN_DOMINF_shutdownshift) + & XEN_DOMINF_shutdownmask)); + Store_field(result, 8, caml_copy_nativeint(info->tot_pages)); + Store_field(result, 9, caml_copy_nativeint(info->max_pages)); + Store_field(result, 10, caml_copy_int64(info->shared_info_frame)); + Store_field(result, 11, caml_copy_int64(info->cpu_time)); + Store_field(result, 12, Val_int(info->nr_online_vcpus)); + Store_field(result, 13, Val_int(info->max_vcpu_id)); + Store_field(result, 14, caml_copy_int32(info->ssidref)); + + tmp = caml_alloc_small(16, 0); + for (i = 0; i < 16; i++) { + Field(tmp, i) = Val_int(info->handle[i]); + } + + Store_field(result, 15, tmp); + + CAMLreturn(result); +} + +CAMLprim value stub_xc_domain_getinfolist(value xc_handle, value first_domain, value nb) +{ + CAMLparam3(xc_handle, first_domain, nb); + CAMLlocal2(result, temp); + xc_domaininfo_t * info; + int i, ret, toalloc; + + /* get the minimum number of allocate byte we need and bump it up to page boundary */ + toalloc = (sizeof(xc_domaininfo_t) * Int_val(nb)) | 0xfff; + ret = posix_memalign((void **) ((void *) &info), 4096, toalloc); + if (ret) + caml_raise_out_of_memory(); + + result = temp = Val_emptylist; + + int c_xc_handle = _H(xc_handle); + uint32_t c_first_domain = _D(first_domain); + unsigned int c_max_domains = Int_val(nb); + // caml_enter_blocking_section(); + int retval = xc_domain_getinfolist(c_xc_handle, c_first_domain, + c_max_domains, info); + // caml_leave_blocking_section(); + + if (retval < 0) { + free(info); + failwith_xc(); + } + for (i = 0; i < retval; i++) { + result = caml_alloc_small(2, Tag_cons); + Field(result, 0) = Val_int(0); + Field(result, 1) = temp; + temp = result; + + Store_field(result, 0, alloc_domaininfo(info + i)); + } + + free(info); + CAMLreturn(result); +} + +CAMLprim value stub_xc_domain_getinfo(value xc_handle, value domid) +{ + CAMLparam2(xc_handle, domid); + CAMLlocal1(result); + xc_domaininfo_t info; + int ret; + + ret = xc_domain_getinfo(_H(xc_handle), _D(domid), &info); + if (ret != 0) + failwith_xc(); + + result = alloc_domaininfo(&info); + CAMLreturn(result); +} + +CAMLprim value stub_xc_vcpu_getinfo(value xc_handle, value domid, value vcpu) +{ + CAMLparam3(xc_handle, domid, vcpu); + CAMLlocal1(result); + xc_vcpuinfo_t info; + int retval; + + int c_xc_handle = _H(xc_handle); + uint32_t c_domid = _D(domid); + uint32_t c_vcpu = Int_val(vcpu); + // caml_enter_blocking_section(); + retval = xc_vcpu_getinfo(c_xc_handle, c_domid, + c_vcpu, &info); + // caml_leave_blocking_section(); + if (retval < 0) + failwith_xc(); + + result = caml_alloc_tuple(5); + Store_field(result, 0, Val_bool(info.online)); + Store_field(result, 1, Val_bool(info.blocked)); + Store_field(result, 2, Val_bool(info.running)); + Store_field(result, 3, caml_copy_int64(info.cpu_time)); + Store_field(result, 4, caml_copy_int32(info.cpu)); + + CAMLreturn(result); +} + +CAMLprim value stub_xc_vcpu_context_get(value xc_handle, value domid, + value cpu) +{ + CAMLparam3(xc_handle, domid, cpu); + CAMLlocal1(context); + int ret; + struct vcpu_guest_context ctxt; + + ret = xc_vcpu_getcontext(_H(xc_handle), _D(domid), Int_val(cpu), &ctxt); + + context = caml_alloc_string(sizeof(ctxt)); + memcpy(String_val(context), (char *) &ctxt, sizeof(ctxt)); + + CAMLreturn(context); +} + +CAMLprim value stub_xc_vcpu_setaffinity(value xc_handle, value domid, + value vcpu, value cpumap) +{ + CAMLparam4(xc_handle, domid, vcpu, cpumap); + uint64_t c_cpumap; + int retval; + + c_cpumap = Int64_val(cpumap); + retval = xc_vcpu_setaffinity(_H(xc_handle), _D(domid), + Int_val(vcpu), c_cpumap); + if (retval < 0) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_vcpu_getaffinity(value xc_handle, value domid, + value vcpu) +{ + CAMLparam3(xc_handle, domid, vcpu); + CAMLlocal1(ret); + uint64_t cpumap; + int retval; + + retval = xc_vcpu_getaffinity(_H(xc_handle), _D(domid), + Int_val(vcpu), &cpumap); + if (retval < 0) + failwith_xc(); + ret = caml_copy_int64(cpumap); + CAMLreturn(ret); +} + +CAMLprim value stub_xc_sched_id(value xc_handle) +{ + CAMLparam1(xc_handle); + int sched_id; + + if (xc_sched_id(_H(xc_handle), &sched_id)) + failwith_xc(); + CAMLreturn(Val_int(sched_id)); +} + +CAMLprim value stub_xc_evtchn_alloc_unbound(value xc_handle, + value local_domid, + value remote_domid) +{ + CAMLparam3(xc_handle, local_domid, remote_domid); + + int c_xc_handle = _H(xc_handle); + uint32_t c_local_domid = _D(local_domid); + uint32_t c_remote_domid = _D(remote_domid); + + // caml_enter_blocking_section(); + int result = xc_evtchn_alloc_unbound(c_xc_handle, c_local_domid, + c_remote_domid); + // caml_leave_blocking_section(); + + if (result < 0) + failwith_xc(); + CAMLreturn(Val_int(result)); +} + +CAMLprim value stub_xc_evtchn_reset(value handle, value domid) +{ + CAMLparam2(handle, domid); + int r; + + r = xc_evtchn_reset(_H(handle), _D(domid)); + if (r < 0) + failwith_xc(); + CAMLreturn(Val_unit); +} + + +#define RING_SIZE 32768 +static char ring[RING_SIZE]; + +CAMLprim value stub_xc_readconsolering(value xc_handle) +{ + unsigned int size = RING_SIZE; + char *ring_ptr = ring; + + CAMLparam1(xc_handle); + int c_xc_handle = _H(xc_handle); + + // caml_enter_blocking_section(); + int retval = xc_readconsolering(c_xc_handle, &ring_ptr, &size, 0); + // caml_leave_blocking_section(); + + if (retval) + failwith_xc(); + ring[size] = '\0'; + CAMLreturn(caml_copy_string(ring)); +} + +CAMLprim value stub_xc_send_debug_keys(value xc_handle, value keys) +{ + CAMLparam2(xc_handle, keys); + int r; + + r = xc_send_debug_keys(_H(xc_handle), String_val(keys)); + if (r) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_physinfo(value xc_handle) +{ + CAMLparam1(xc_handle); + CAMLlocal3(physinfo, cap_list, tmp); + xc_physinfo_t c_physinfo; + int r; + + // caml_enter_blocking_section(); + r = xc_physinfo(_H(xc_handle), &c_physinfo); + // caml_leave_blocking_section(); + + if (r) + failwith_xc(); + + tmp = cap_list = Val_emptylist; + for (r = 0; r < 2; r++) { + if ((c_physinfo.capabilities >> r) & 1) { + tmp = caml_alloc_small(2, Tag_cons); + Field(tmp, 0) = Val_int(r); + Field(tmp, 1) = cap_list; + cap_list = tmp; + } + } + + physinfo = caml_alloc_tuple(9); + Store_field(physinfo, 0, Val_int(c_physinfo.threads_per_core)); + Store_field(physinfo, 1, Val_int(c_physinfo.cores_per_socket)); + Store_field(physinfo, 2, Val_int(c_physinfo.nr_cpus)); + Store_field(physinfo, 3, Val_int(c_physinfo.max_node_id)); + Store_field(physinfo, 4, Val_int(c_physinfo.cpu_khz)); + Store_field(physinfo, 5, caml_copy_nativeint(c_physinfo.total_pages)); + Store_field(physinfo, 6, caml_copy_nativeint(c_physinfo.free_pages)); + Store_field(physinfo, 7, caml_copy_nativeint(c_physinfo.scrub_pages)); + Store_field(physinfo, 8, cap_list); + + CAMLreturn(physinfo); +} + +CAMLprim value stub_xc_pcpu_info(value xc_handle, value nr_cpus) +{ + CAMLparam2(xc_handle, nr_cpus); + CAMLlocal2(pcpus, v); + uint64_t *info; + int r, size; + + if (Int_val(nr_cpus) < 1) + caml_invalid_argument("nr_cpus"); + + info = calloc(Int_val(nr_cpus) + 1, sizeof(uint64_t)); + if (!info) + caml_raise_out_of_memory(); + + // caml_enter_blocking_section(); + r = xc_pcpu_info(_H(xc_handle), Int_val(nr_cpus), info, &size); + // caml_leave_blocking_section(); + + if (r) { + free(info); + failwith_xc(); + } + + if (size > 0) { + int i; + pcpus = caml_alloc(size, 0); + for (i = 0; i < size; i++) { + v = caml_copy_int64(info[i]); + caml_modify(&Field(pcpus, i), v); + } + } else + pcpus = Atom(0); + free(info); + CAMLreturn(pcpus); +} + +CAMLprim value stub_xc_domain_setmaxmem(value xc_handle, value domid, + value max_memkb) +{ + CAMLparam3(xc_handle, domid, max_memkb); + + int c_xc_handle = _H(xc_handle); + uint32_t c_domid = _D(domid); + unsigned int c_max_memkb = Int64_val(max_memkb); + // caml_enter_blocking_section(); + int retval = xc_domain_setmaxmem(c_xc_handle, c_domid, + c_max_memkb); + // caml_leave_blocking_section(); + if (retval) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_set_memmap_limit(value xc_handle, value domid, + value map_limitkb) +{ + CAMLparam3(xc_handle, domid, map_limitkb); + unsigned long v; + int retval; + + v = Int64_val(map_limitkb); + retval = xc_domain_set_memmap_limit(_H(xc_handle), _D(domid), v); + if (retval) + failwith_xc(); + + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_memory_increase_reservation(value xc_handle, + value domid, + value mem_kb) +{ + CAMLparam3(xc_handle, domid, mem_kb); + + unsigned long nr_extents = ((unsigned long)(Int64_val(mem_kb))) >> (PAGE_SHIFT - 10); + + int c_xc_handle = _H(xc_handle); + uint32_t c_domid = _D(domid); + // caml_enter_blocking_section(); + int retval = xc_domain_memory_increase_reservation(c_xc_handle, c_domid, + nr_extents, 0, 0, NULL); + // caml_leave_blocking_section(); + + if (retval) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_set_machine_address_size(value xc_handle, + value domid, + value width) +{ + CAMLparam3(xc_handle, domid, width); + int c_xc_handle = _H(xc_handle); + uint32_t c_domid = _D(domid); + int c_width = Int_val(width); + + int retval = xc_domain_set_machine_address_size(c_xc_handle, c_domid, c_width); + if (retval) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_get_machine_address_size(value xc_handle, + value domid) +{ + CAMLparam2(xc_handle, domid); + int retval; + + retval = xc_domain_get_machine_address_size(_H(xc_handle), _D(domid)); + if (retval < 0) + failwith_xc(); + CAMLreturn(Val_int(retval)); +} + +CAMLprim value stub_xc_domain_cpuid_set(value xc_handle, value domid, + value is_hvm, value input, + value config) +{ + CAMLparam5(xc_handle, domid, is_hvm, input, config); + CAMLlocal2(array, tmp); + int r; + char *c_config[4], *out_config[4]; + uint32_t c_input, c_oinput; + + c_config[0] = string_of_option_array(config, 0); + c_config[1] = string_of_option_array(config, 1); + c_config[2] = string_of_option_array(config, 2); + c_config[3] = string_of_option_array(config, 3); + + cpuid_input_of_val(c_input, c_oinput, input); + + array = caml_alloc(4, 0); + for (r = 0; r < 4; r++) { + tmp = Val_none; + if (c_config[r]) { + tmp = caml_alloc_small(1, 0); + Field(tmp, 0) = caml_alloc_string(32); + } + Store_field(array, r, tmp); + } + + for (r = 0; r < 4; r++) + out_config[r] = (c_config[r]) ? String_val(Field(Field(array, r), 0)) : NULL; + + r = xc_domain_cpuid_set(_H(xc_handle), _D(domid), Bool_val(is_hvm), + c_input, c_oinput, c_config, out_config); + if (r < 0) + failwith_xc(); + CAMLreturn(array); +} + +CAMLprim value stub_xc_domain_cpuid_apply(value xc_handle, value domid, value is_hvm) +{ + CAMLparam3(xc_handle, domid, is_hvm); + int r; + r = xc_domain_cpuid_apply(_H(xc_handle), _D(domid), Bool_val(is_hvm)); + if (r < 0) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_cpuid_check(value input, value config) +{ + CAMLparam2(input, config); + CAMLlocal3(ret, array, tmp); + int r; + uint32_t c_input, c_oinput; + char *c_config[4], *out_config[4]; + + c_config[0] = string_of_option_array(config, 0); + c_config[1] = string_of_option_array(config, 1); + c_config[2] = string_of_option_array(config, 2); + c_config[3] = string_of_option_array(config, 3); + + cpuid_input_of_val(c_input, c_oinput, input); + + array = caml_alloc(4, 0); + for (r = 0; r < 4; r++) { + tmp = Val_none; + if (c_config[r]) { + tmp = caml_alloc_small(1, 0); + Field(tmp, 0) = caml_alloc_string(32); + } + Store_field(array, r, tmp); + } + + for (r = 0; r < 4; r++) + out_config[r] = (c_config[r]) ? String_val(Field(Field(array, r), 0)) : NULL; + + r = xc_cpuid_check(c_input, c_oinput, c_config, out_config); + if (r < 0) + failwith_xc(); + + ret = caml_alloc_tuple(2); + Store_field(ret, 0, Val_bool(r)); + Store_field(ret, 1, array); + + CAMLreturn(ret); +} + +CAMLprim value stub_xc_version_version(value xc_handle) +{ + CAMLparam1(xc_handle); + CAMLlocal1(result); + xen_extraversion_t extra; + long packed; + int retval; + + int c_xc_handle = _H(xc_handle); + // caml_enter_blocking_section(); + packed = xc_version(c_xc_handle, XENVER_version, NULL); + retval = xc_version(c_xc_handle, XENVER_extraversion, &extra); + // caml_leave_blocking_section(); + + if (retval) + failwith_xc(); + + result = caml_alloc_tuple(3); + + Store_field(result, 0, Val_int(packed >> 16)); + Store_field(result, 1, Val_int(packed & 0xffff)); + Store_field(result, 2, caml_copy_string(extra)); + + CAMLreturn(result); +} + + +CAMLprim value stub_xc_version_compile_info(value xc_handle) +{ + CAMLparam1(xc_handle); + CAMLlocal1(result); + xen_compile_info_t ci; + int retval; + + int c_xc_handle = _H(xc_handle); + // caml_enter_blocking_section(); + retval = xc_version(c_xc_handle, XENVER_compile_info, &ci); + // caml_leave_blocking_section(); + + if (retval) + failwith_xc(); + + result = caml_alloc_tuple(4); + + Store_field(result, 0, caml_copy_string(ci.compiler)); + Store_field(result, 1, caml_copy_string(ci.compile_by)); + Store_field(result, 2, caml_copy_string(ci.compile_domain)); + Store_field(result, 3, caml_copy_string(ci.compile_date)); + + CAMLreturn(result); +} + + +static value xc_version_single_string(value xc_handle, int code, void *info) +{ + CAMLparam1(xc_handle); + int retval; + + int c_xc_handle = _H(xc_handle); + // caml_enter_blocking_section(); + retval = xc_version(c_xc_handle, code, info); + // caml_leave_blocking_section(); + + if (retval) + failwith_xc(); + + CAMLreturn(caml_copy_string((char *)info)); +} + + +CAMLprim value stub_xc_version_changeset(value xc_handle) +{ + xen_changeset_info_t ci; + + return xc_version_single_string(xc_handle, XENVER_changeset, &ci); +} + + +CAMLprim value stub_xc_version_capabilities(value xc_handle) +{ + xen_capabilities_info_t ci; + + return xc_version_single_string(xc_handle, XENVER_capabilities, &ci); +} + + +CAMLprim value stub_pages_to_kib(value pages) +{ + CAMLparam1(pages); + + CAMLreturn(caml_copy_int64(Int64_val(pages) << (PAGE_SHIFT - 10))); +} + + +CAMLprim value stub_map_foreign_range(value xc_handle, value dom, + value size, value mfn) +{ + CAMLparam4(xc_handle, dom, size, mfn); + CAMLlocal1(result); + struct mmap_interface *intf; + + result = caml_alloc(sizeof(struct mmap_interface), Abstract_tag); + intf = (struct mmap_interface *) result; + + intf->len = Int_val(size); + + int c_xc_handle = _H(xc_handle); + uint32_t c_dom = _D(dom); + unsigned long c_mfn = Nativeint_val(mfn); + // caml_enter_blocking_section(); + intf->addr = xc_map_foreign_range(c_xc_handle, c_dom, + intf->len, PROT_READ|PROT_WRITE, + c_mfn); + // caml_leave_blocking_section(); + if (!intf->addr) + caml_failwith("xc_map_foreign_range error"); + CAMLreturn(result); +} + +CAMLprim value stub_sched_credit_domain_get(value xc_handle, value domid) +{ + CAMLparam2(xc_handle, domid); + CAMLlocal1(sdom); + struct xen_domctl_sched_credit c_sdom; + int ret; + + // caml_enter_blocking_section(); + ret = xc_sched_credit_domain_get(_H(xc_handle), _D(domid), &c_sdom); + // caml_leave_blocking_section(); + if (ret != 0) + failwith_xc(); + + sdom = caml_alloc_tuple(2); + Store_field(sdom, 0, Val_int(c_sdom.weight)); + Store_field(sdom, 1, Val_int(c_sdom.cap)); + + CAMLreturn(sdom); +} + +CAMLprim value stub_sched_credit_domain_set(value xc_handle, value domid, + value sdom) +{ + CAMLparam3(xc_handle, domid, sdom); + struct xen_domctl_sched_credit c_sdom; + int ret; + + c_sdom.weight = Int_val(Field(sdom, 0)); + c_sdom.cap = Int_val(Field(sdom, 1)); + // caml_enter_blocking_section(); + ret = xc_sched_credit_domain_set(_H(xc_handle), _D(domid), &c_sdom); + // caml_leave_blocking_section(); + if (ret != 0) + failwith_xc(); + + CAMLreturn(Val_unit); +} + +CAMLprim value stub_shadow_allocation_get(value xc_handle, value domid) +{ + CAMLparam2(xc_handle, domid); + CAMLlocal1(mb); + uint32_t c_mb; + int ret; + + // caml_enter_blocking_section(); + ret = xc_shadow_allocation_get(_H(xc_handle), _D(domid), &c_mb); + // caml_leave_blocking_section(); + if (ret != 0) + failwith_xc(); + + mb = Val_int(c_mb); + CAMLreturn(mb); +} + +CAMLprim value stub_shadow_allocation_set(value xc_handle, value domid, + value mb) +{ + CAMLparam3(xc_handle, domid, mb); + uint32_t c_mb; + int ret; + + c_mb = Int_val(mb); + // caml_enter_blocking_section(); + ret = xc_shadow_allocation_set(_H(xc_handle), _D(domid), c_mb); + // caml_leave_blocking_section(); + if (ret != 0) + failwith_xc(); + + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_get_pfn_list(value xc_handle, value domid, + value nr_pfns) +{ + CAMLparam3(xc_handle, domid, nr_pfns); + CAMLlocal2(array, v); + unsigned long c_nr_pfns; + long ret, i; + xen_pfn_t *c_array; + + c_nr_pfns = Nativeint_val(nr_pfns); + + c_array = malloc(sizeof(xen_pfn_t) * c_nr_pfns); + if (!c_array) + caml_raise_out_of_memory(); + + ret = xc_domain_get_pfn_list(_H(xc_handle), _D(domid), + c_array, c_nr_pfns); + if (ret < 0) { + free(c_array); + failwith_xc(); + } + + array = caml_alloc(ret, 0); + for (i = 0; i < ret; i++) { + v = caml_copy_nativeint(c_array[i]); + Store_field(array, i, v); + } + free(c_array); + + CAMLreturn(array); +} + +CAMLprim value stub_xc_domain_ioport_permission(value xc_handle, value domid, + value start_port, value nr_ports, + value allow) +{ + CAMLparam5(xc_handle, domid, start_port, nr_ports, allow); + uint32_t c_start_port, c_nr_ports; + uint8_t c_allow; + int ret; + + c_start_port = Int_val(start_port); + c_nr_ports = Int_val(nr_ports); + c_allow = Bool_val(allow); + + ret = xc_domain_ioport_permission(_H(xc_handle), _D(domid), + c_start_port, c_nr_ports, c_allow); + if (ret < 0) + failwith_xc(); + + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_iomem_permission(value xc_handle, value domid, + value start_pfn, value nr_pfns, + value allow) +{ + CAMLparam5(xc_handle, domid, start_pfn, nr_pfns, allow); + unsigned long c_start_pfn, c_nr_pfns; + uint8_t c_allow; + int ret; + + c_start_pfn = Nativeint_val(start_pfn); + c_nr_pfns = Nativeint_val(nr_pfns); + c_allow = Bool_val(allow); + + ret = xc_domain_iomem_permission(_H(xc_handle), _D(domid), + c_start_pfn, c_nr_pfns, c_allow); + if (ret < 0) + failwith_xc(); + + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_irq_permission(value xc_handle, value domid, + value pirq, value allow) +{ + CAMLparam4(xc_handle, domid, pirq, allow); + uint8_t c_pirq; + uint8_t c_allow; + int ret; + + c_pirq = Int_val(pirq); + c_allow = Bool_val(allow); + + ret = xc_domain_irq_permission(_H(xc_handle), _D(domid), + c_pirq, c_allow); + if (ret < 0) + failwith_xc(); + + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_hvm_check_pvdriver(value xc_handle, value domid) +{ + CAMLparam2(xc_handle, domid); + int ret; + + ret = xc_hvm_check_pvdriver(_H(xc_handle), _D(domid)); + if (ret < 0) + failwith_xc(); + CAMLreturn(Val_bool(ret)); +} + +CAMLprim value stub_xc_domain_test_assign_device(value xc_handle, value domid, value desc) +{ + CAMLparam3(xc_handle, domid, desc); + int ret; + int domain, bus, slot, func; + + domain = Int_val(Field(desc, 0)); + bus = Int_val(Field(desc, 1)); + slot = Int_val(Field(desc, 2)); + func = Int_val(Field(desc, 3)); + + ret = xc_domain_test_assign_device(_H(xc_handle), _D(domid), + domain, bus, slot, func); + CAMLreturn(Val_bool(ret == 0)); +} + +CAMLprim value stub_xc_domain_assign_device(value xc_handle, value domid, value desc) +{ + CAMLparam3(xc_handle, domid, desc); + int ret; + int domain, bus, slot, func; + + domain = Int_val(Field(desc, 0)); + bus = Int_val(Field(desc, 1)); + slot = Int_val(Field(desc, 2)); + func = Int_val(Field(desc, 3)); + + ret = xc_domain_assign_device(_H(xc_handle), _D(domid), + domain, bus, slot, func); + if (ret < 0) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_deassign_device(value xc_handle, value domid, value desc) +{ + CAMLparam3(xc_handle, domid, desc); + int ret; + int domain, bus, slot, func; + + domain = Int_val(Field(desc, 0)); + bus = Int_val(Field(desc, 1)); + slot = Int_val(Field(desc, 2)); + func = Int_val(Field(desc, 3)); + + ret = xc_domain_deassign_device(_H(xc_handle), _D(domid), + domain, bus, slot, func); + if (ret < 0) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_set_timer_mode(value handle, value id, value mode) +{ + CAMLparam3(handle, id, mode); + int ret; + + ret = xc_domain_set_timer_mode(_H(handle), _D(id), Int_val(mode)); + if (ret < 0) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_set_hpet(value handle, value id, value mode) +{ + CAMLparam3(handle, id, mode); + int ret; + + ret = xc_domain_set_hpet(_H(handle), _D(id), Int_val(mode)); + if (ret < 0) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_set_vpt_align(value handle, value id, value mode) +{ + CAMLparam3(handle, id, mode); + int ret; + + ret = xc_domain_set_vpt_align(_H(handle), _D(id), Int_val(mode)); + if (ret < 0) + failwith_xc(); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_watchdog(value handle, value domid, value timeout) +{ + CAMLparam3(handle, domid, timeout); + int ret; + unsigned int c_timeout = Int32_val(timeout); + + ret = xc_domain_watchdog(_H(handle), _D(domid), c_timeout); + if (ret < 0) + failwith_xc(); + + CAMLreturn(Val_int(ret)); +} + +CAMLprim value stub_xc_domain_send_s3resume(value handle, value domid) +{ + CAMLparam2(handle, domid); + xc_domain_send_s3resume(_H(handle), _D(domid)); + CAMLreturn(Val_unit); +} + +CAMLprim value stub_xc_domain_get_acpi_s_state(value handle, value domid) +{ + CAMLparam2(handle, domid); + int ret; + + ret = xc_domain_get_acpi_s_state(_H(handle), _D(domid)); + if (ret < 0) + failwith_xc(); + + CAMLreturn(Val_int(ret)); +} + +/* + * Local variables: + * indent-tabs-mode: t + * c-basic-offset: 8 + * tab-width: 8 + * End: + */