diff --git a/Config.mk b/Config.mk index 6f9f970fe6..0181cc3ad1 100644 --- a/Config.mk +++ b/Config.mk @@ -36,6 +36,12 @@ endif cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \ /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;) +# cc-ver +# Usage: ifeq ($(call cc-ver,$(CC),0x030400),y) +cc-ver = $(shell if [ $$((`$(1) -dumpversion | awk -F. \ + '{ printf "0x%02x%02x%02x", $$1, $$2, $$3}'`)) -ge $$(($(2))) ]; \ + then echo y; else echo n; fi ;) + ifneq ($(debug),y) CFLAGS += -DNDEBUG else diff --git a/buildconfigs/conf.linux-native/00_xen_to_native b/buildconfigs/conf.linux-native/00_xen_to_native index 6f155024fc..024bc9bbca 100644 --- a/buildconfigs/conf.linux-native/00_xen_to_native +++ b/buildconfigs/conf.linux-native/00_xen_to_native @@ -74,8 +74,10 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_XEN_DISABLE_SERIAL is not set # CONFIG_XEN_SYSFS is not set # CONFIG_XEN_COMPAT_030002_AND_LATER is not set +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set # CONFIG_XEN_COMPAT_LATEST_ONLY is not set # CONFIG_XEN_COMPAT_030002 is not set +# CONFIG_XEN_COMPAT_030004 is not set # CONFIG_HAVE_ARCH_ALLOC_SKB is not set # CONFIG_HAVE_ARCH_DEV_ALLOC_SKB is not set # CONFIG_NO_IDLE_HZ is not set diff --git a/buildconfigs/linux-defconfig_xen0_ia64 b/buildconfigs/linux-defconfig_xen0_ia64 index 9869aab066..ae4281e94c 100644 --- a/buildconfigs/linux-defconfig_xen0_ia64 +++ b/buildconfigs/linux-defconfig_xen0_ia64 @@ -1619,7 +1619,7 @@ CONFIG_CRYPTO_DES=y CONFIG_XEN_BALLOON=y CONFIG_XEN_REBOOT=y # CONFIG_XEN_SMPBOOT is not set -CONFIG_XEN_INTERFACE_VERSION=0x00030203 +CONFIG_XEN_INTERFACE_VERSION=0x00030205 # # XEN @@ -1647,8 +1647,10 @@ CONFIG_XEN_NETDEV_FRONTEND=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y CONFIG_XEN_COMPAT_030002_AND_LATER=y +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set # CONFIG_XEN_COMPAT_LATEST_ONLY is not set CONFIG_XEN_COMPAT_030002=y +CONFIG_XEN_COMPAT_030004=y CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y CONFIG_XEN_DEVMEM=y diff --git a/buildconfigs/linux-defconfig_xen0_x86_32 b/buildconfigs/linux-defconfig_xen0_x86_32 index ad24086d00..0ade353004 100644 --- a/buildconfigs/linux-defconfig_xen0_x86_32 +++ b/buildconfigs/linux-defconfig_xen0_x86_32 @@ -1384,7 +1384,7 @@ CONFIG_CRYPTO_CRC32C=m # # CONFIG_CRYPTO_DEV_PADLOCK is not set CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030203 +CONFIG_XEN_INTERFACE_VERSION=0x00030205 # # XEN @@ -1411,8 +1411,10 @@ CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y CONFIG_XEN_COMPAT_030002_AND_LATER=y +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set # CONFIG_XEN_COMPAT_LATEST_ONLY is not set CONFIG_XEN_COMPAT_030002=y +CONFIG_XEN_COMPAT_030004=y CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y CONFIG_XEN_UTIL=y diff --git a/buildconfigs/linux-defconfig_xen0_x86_64 b/buildconfigs/linux-defconfig_xen0_x86_64 index ea1ec55f79..5d37ba6a0f 100644 --- a/buildconfigs/linux-defconfig_xen0_x86_64 +++ b/buildconfigs/linux-defconfig_xen0_x86_64 @@ -1334,7 +1334,7 @@ CONFIG_CRYPTO_CRC32C=m # Hardware crypto devices # CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030203 +CONFIG_XEN_INTERFACE_VERSION=0x00030205 # # XEN @@ -1361,8 +1361,10 @@ CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y CONFIG_XEN_COMPAT_030002_AND_LATER=y +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set # CONFIG_XEN_COMPAT_LATEST_ONLY is not set CONFIG_XEN_COMPAT_030002=y +CONFIG_XEN_COMPAT_030004=y CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y CONFIG_XEN_UTIL=y diff --git a/buildconfigs/linux-defconfig_xenU_ia64 b/buildconfigs/linux-defconfig_xenU_ia64 index ed518155e7..7ef2d7ac84 100644 --- a/buildconfigs/linux-defconfig_xenU_ia64 +++ b/buildconfigs/linux-defconfig_xenU_ia64 @@ -1471,7 +1471,7 @@ CONFIG_CRYPTO_DES=y CONFIG_XEN_BALLOON=y CONFIG_XEN_REBOOT=y # CONFIG_XEN_SMPBOOT is not set -CONFIG_XEN_INTERFACE_VERSION=0x00030203 +CONFIG_XEN_INTERFACE_VERSION=0x00030205 # # XEN @@ -1489,8 +1489,10 @@ CONFIG_XEN_KEYBOARD=y # CONFIG_XEN_DISABLE_SERIAL is not set CONFIG_XEN_SYSFS=y CONFIG_XEN_COMPAT_030002_AND_LATER=y +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set # CONFIG_XEN_COMPAT_LATEST_ONLY is not set CONFIG_XEN_COMPAT_030002=y +CONFIG_XEN_COMPAT_030004=y CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y CONFIG_XEN_DEVMEM=y diff --git a/buildconfigs/linux-defconfig_xenU_x86_32 b/buildconfigs/linux-defconfig_xenU_x86_32 index 441f128a92..f2bbb868ef 100644 --- a/buildconfigs/linux-defconfig_xenU_x86_32 +++ b/buildconfigs/linux-defconfig_xenU_x86_32 @@ -904,7 +904,7 @@ CONFIG_CRYPTO_CRC32C=m # # CONFIG_CRYPTO_DEV_PADLOCK is not set CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030203 +CONFIG_XEN_INTERFACE_VERSION=0x00030205 # # XEN @@ -920,8 +920,10 @@ CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y CONFIG_XEN_COMPAT_030002_AND_LATER=y +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set # CONFIG_XEN_COMPAT_LATEST_ONLY is not set CONFIG_XEN_COMPAT_030002=y +CONFIG_XEN_COMPAT_030004=y CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y CONFIG_XEN_UTIL=y diff --git a/buildconfigs/linux-defconfig_xenU_x86_64 b/buildconfigs/linux-defconfig_xenU_x86_64 index 1d7a46dba7..69fedf944f 100644 --- a/buildconfigs/linux-defconfig_xenU_x86_64 +++ b/buildconfigs/linux-defconfig_xenU_x86_64 @@ -1200,7 +1200,7 @@ CONFIG_CRYPTO_CRC32C=m # Hardware crypto devices # CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030203 +CONFIG_XEN_INTERFACE_VERSION=0x00030205 # # XEN @@ -1216,8 +1216,10 @@ CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y CONFIG_XEN_COMPAT_030002_AND_LATER=y +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set # CONFIG_XEN_COMPAT_LATEST_ONLY is not set CONFIG_XEN_COMPAT_030002=y +CONFIG_XEN_COMPAT_030004=y CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y CONFIG_XEN_UTIL=y diff --git a/buildconfigs/linux-defconfig_xen_ia64 b/buildconfigs/linux-defconfig_xen_ia64 index 25253bc891..58d97492ef 100644 --- a/buildconfigs/linux-defconfig_xen_ia64 +++ b/buildconfigs/linux-defconfig_xen_ia64 @@ -1619,7 +1619,7 @@ CONFIG_CRYPTO_DES=y CONFIG_XEN_BALLOON=y CONFIG_XEN_REBOOT=y # CONFIG_XEN_SMPBOOT is not set -CONFIG_XEN_INTERFACE_VERSION=0x00030203 +CONFIG_XEN_INTERFACE_VERSION=0x00030205 # # XEN @@ -1648,8 +1648,10 @@ CONFIG_XEN_KEYBOARD=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y CONFIG_XEN_COMPAT_030002_AND_LATER=y +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set # CONFIG_XEN_COMPAT_LATEST_ONLY is not set CONFIG_XEN_COMPAT_030002=y +CONFIG_XEN_COMPAT_030004=y CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y CONFIG_XEN_DEVMEM=y diff --git a/buildconfigs/linux-defconfig_xen_x86_32 b/buildconfigs/linux-defconfig_xen_x86_32 index 8a793de380..1c949151cc 100644 --- a/buildconfigs/linux-defconfig_xen_x86_32 +++ b/buildconfigs/linux-defconfig_xen_x86_32 @@ -3242,7 +3242,7 @@ CONFIG_CRYPTO_TEST=m # # CONFIG_CRYPTO_DEV_PADLOCK is not set CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030203 +CONFIG_XEN_INTERFACE_VERSION=0x00030205 # # XEN @@ -3271,8 +3271,10 @@ CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y CONFIG_XEN_COMPAT_030002_AND_LATER=y +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set # CONFIG_XEN_COMPAT_LATEST_ONLY is not set CONFIG_XEN_COMPAT_030002=y +CONFIG_XEN_COMPAT_030004=y CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y CONFIG_XEN_UTIL=y diff --git a/buildconfigs/linux-defconfig_xen_x86_64 b/buildconfigs/linux-defconfig_xen_x86_64 index a7269fbf88..8ac68363f0 100644 --- a/buildconfigs/linux-defconfig_xen_x86_64 +++ b/buildconfigs/linux-defconfig_xen_x86_64 @@ -3072,7 +3072,7 @@ CONFIG_CRYPTO_TEST=m # Hardware crypto devices # CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030203 +CONFIG_XEN_INTERFACE_VERSION=0x00030205 # # XEN @@ -3101,8 +3101,10 @@ CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y CONFIG_XEN_COMPAT_030002_AND_LATER=y +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set # CONFIG_XEN_COMPAT_LATEST_ONLY is not set CONFIG_XEN_COMPAT_030002=y +CONFIG_XEN_COMPAT_030004=y CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y CONFIG_XEN_UTIL=y diff --git a/docs/man/xm.pod.1 b/docs/man/xm.pod.1 index 3cd8b80ac6..90dab93d9a 100644 --- a/docs/man/xm.pod.1 +++ b/docs/man/xm.pod.1 @@ -619,7 +619,7 @@ devices, or by device id, such as 0x1400 (/dev/hdc device id in hex). =item I The access mode for the device from the guest domain. Supported modes -are I (read/write) or I (read-only). +are I (read/write) or I (read-only). =item I diff --git a/docs/misc/dump-core-format.txt b/docs/misc/dump-core-format.txt index 99384ca94a..545740b6bd 100644 --- a/docs/misc/dump-core-format.txt +++ b/docs/misc/dump-core-format.txt @@ -80,8 +80,7 @@ Currently the following sections are defined. Some sections are optional. gmfn: machine physical frame number The size of arrays is stored in xch_nr_pages member of header note descriptor in .note.Xen note section. - There is no rule about the order. Analysis tools must no rely - on its order. + The entryies are stored in pfn-ascending order. This section must exist when the domain is non auto translated physmap mode. Currently x86 paravirtualized domain. @@ -94,8 +93,7 @@ Currently the following sections are defined. Some sections are optional. in .xen_pages section. The size of arrays is stored in xch_nr_pages member of header note descriptor in .note.Xen note section. - There is no rule about the order. Analysis tools must no rely - on its order. + The entries are stored in ascending order. This section must exist when the domain is auto translated physmap mode. Currently x86 full virtualized domain and ia64 domain. @@ -226,6 +224,8 @@ Currently only (major, minor) = (0, 1) is used. [When the format is changed, it would be described here.] (0, 1) update +- .xen_p2m, .xen_pfn section + Arrays must be in pfn ascending order for efficient looking up. - EI_CLASS member of elf header was changed to ELFCLASS64 independent of architecture. This is mainly for x86_32pae. The format version isn't bumped because analysis tools can distinguish it. diff --git a/docs/src/user.tex b/docs/src/user.tex index f71231d44c..6706a31acb 100644 --- a/docs/src/user.tex +++ b/docs/src/user.tex @@ -3179,6 +3179,11 @@ editing \path{grub.conf}. one of 80x25, 80x28, 80x30, 80x34, 80x43, 80x50, 80x60. \item[ keep ] Keep the VGA console even after domain 0 boots. \end{description} +\item [ console\_to\_ring ] Place guest console output into the + hypervisor console ring buffer. This is disabled by default. + When enabled, both hypervisor output and guest console output + is available from the ring buffer. This can be useful for logging + and/or remote presentation of console data. \item [ sync\_console ] Force synchronous console output. This is useful if you system fails unexpectedly before it has sent all available output to the console. In most cases Xen will diff --git a/docs/xen-api/coversheet.tex b/docs/xen-api/coversheet.tex index cd0ad615d6..f7e4425ce6 100644 --- a/docs/xen-api/coversheet.tex +++ b/docs/xen-api/coversheet.tex @@ -47,4 +47,4 @@ Date: \datestring{} \legalnotice{} \newpage -\pagestyle{plain} \ No newline at end of file +\pagestyle{fancy} \ No newline at end of file diff --git a/docs/xen-api/presentation.tex b/docs/xen-api/presentation.tex index ba7ebdbde7..abc18bafe9 100644 --- a/docs/xen-api/presentation.tex +++ b/docs/xen-api/presentation.tex @@ -57,14 +57,14 @@ type $t_1$ to values of type $t_2$. \end{itemize} Note that there are a number of cases where {\em Ref}s are {\em doubly -linked\/}---e.g.\ a VM has a field called {\tt groups} of type -$(\mathit{VMGroup}~\mathit{Ref})~\mathit{Set}$; this field lists -the VMGroups that a particular VM is part of. Similarly, the VMGroups -class has a field called {\tt VMs} of type $(\mathit{VM}~{\mathit -Ref})~\mathit{Set}$ that contains the VMs that are part of a particular -VMGroup. These two fields are {\em bound together\/}, in the sense that -adding a new VMGroup to a VM causes the VMs field of the corresponding -VMGroup object to be updated automatically. +linked\/}---e.g.\ a VM has a field called {\tt VIFs} of type +$(\mathit{VIF}~\mathit{Ref})~\mathit{Set}$; this field lists +the network interfaces attached to a particular VM. Similarly, the VIF +class has a field called {\tt VM} of type $(\mathit{VM}~{\mathit +Ref})$ which references the VM to which the interface is connected. +These two fields are {\em bound together\/}, in the sense that +creating a new VIF causes the {\tt VIFs} field of the corresponding +VM object to be updated automatically. The API reference explicitly lists the fields that are bound together in this way. It also contains a diagram that shows diff --git a/docs/xen-api/todo.tex b/docs/xen-api/todo.tex index 6f679ca01e..b66dec0aba 100644 --- a/docs/xen-api/todo.tex +++ b/docs/xen-api/todo.tex @@ -91,17 +91,10 @@ same subnet. \end{itemize} -\item TPM +\item ACM \begin{itemize} -\item Would it not be better to have a class TPM and a member TPMs ((TPM ref) -Set) containing an array of zero or one references to TPMs? I assume that -an empty array would make it clear that no TPM is associated with the VM -instead of encoding its existence into TPM/instance or TPM/backend -somehow. The current members instance and backend could then be moved into -the TPM class. - -\item Also a Xen system can be running an access control policy where each +\item A Xen system can be running an access control policy where each VM's run-time access to resources is restricted by the label it has been given compared to those of the resources. Currently a VM's configuration file may contain a line like access\_control[policy='$<$name of the system's diff --git a/docs/xen-api/vm-lifecycle.tex b/docs/xen-api/vm-lifecycle.tex index 23ddb9e9ae..cf790cbcba 100644 --- a/docs/xen-api/vm-lifecycle.tex +++ b/docs/xen-api/vm-lifecycle.tex @@ -22,3 +22,19 @@ Figure~\ref{fig-vm-lifecycle} shows the states that a VM can be in and the API calls that can be used to move the VM between these states. + +\section{VM boot parameters} + +The VM class contains a number of fields that control the way in which the VM is booted. +With reference to the fields defined in the VM class (see later in this document), +this section outlines the boot options available and the mechanisms provided for controlling them. + +VM booting is controlled by setting one of the two mutually exclusive groups: ``PV'', and ``HVM''. If HVM.boot\_policy is the empty string, then paravirtual domain building and booting will be used; otherwise the VM will be loaded as an HVM domain, and booted using an emulated BIOS. + +When paravirtual booting is in use, the PV/bootloader field indicates the bootloader to use. It may be ``pygrub'', in which case the platform's default installation of pygrub will be used, or a full path within the control domain to some other bootloader. The other fields, PV/kernel, PV/ramdisk, PV/args and PV/bootloader\_args will be passed to the bootloader unmodified, and interpretation of those fields is then specific to the bootloader itself, including the possibility that the bootloader will ignore some or all of those given values. Finally the paths of all bootable disks are added to the bootloader commandline (a disk is bootable if its VBD has the bootable flag set). There may be zero, one or many bootable disks; the bootloader decides which disk (if any) to boot from. + +If the bootloader is pygrub, then the menu.lst is parsed if present in the guest's filesystem, otherwise the specified kernel and ramdisk are used, or an autodetected kernel is used if nothing is specified and autodetection is possible. PV/args is appended to the kernel command line, no matter which mechanism is used for finding the kernel. + +If PV/bootloader is empty but PV/kernel is specified, then the kernel and ramdisk values will be treated as paths within the control domain. If both PV/bootloader and PV/kernel are empty, then the behaviour is as if PV/bootloader was specified as ``pygrub''. + +When using HVM booting, HVM/boot\_policy and HVM/boot\_params specify the boot handling. Only one policy is currently defined: ``BIOS order''. In this case, HVM/boot\_params should contain one key-value pair ``order'' = ``N'' where N is the string that will be passed to QEMU. \ No newline at end of file diff --git a/docs/xen-api/wire-protocol.tex b/docs/xen-api/wire-protocol.tex index 1548f41c9e..2d11f739c9 100644 --- a/docs/xen-api/wire-protocol.tex +++ b/docs/xen-api/wire-protocol.tex @@ -30,8 +30,13 @@ These types are mapped onto XML-RPC types in a straight-forward manner: \item Floats, Bools, DateTimes and Strings map directly to the XML-RPC {\tt double}, {\tt boolean}, {\tt dateTime.iso8601}, and {\tt string} elements. - \item all our ``{\tt ref\_}'' types (e.g.\ {\tt ref\_vm} in the above - example) map to XML-RPC's {\tt String} type. The string itself is the OSF + \item all ``{\tt ref\_}'' types are opaque references, encoded as the + XML-RPC's {\tt String} type. Users of the API should not make assumptions + about the concrete form of these strings and should not expect them to + remain valid after the client's session with the server has terminated. + + \item fields named ``{\tt uuid}'' of type ``{\tt String}'' are mapped to + the XML-RPC {\tt String} type. The string itself is the OSF DCE UUID presentation format (as output by {\tt uuidgen}, etc). \item ints are all assumed to be 64-bit in our API and are encoded as a @@ -84,6 +89,32 @@ These types are mapped onto XML-RPC types in a straight-forward manner: \end{itemize} +\subsection{Note on References vs UUIDs} + +References are opaque types --- encoded as XML-RPC strings on the wire --- understood +only by the particular server which generated them. Servers are free to choose +any concrete representation they find convenient; clients should not make any +assumptions or attempt to parse the string contents. References are not guaranteed +to be permanent identifiers for objects; clients should not assume that references +generated during one session are valid for any future session. References do not +allow objects to be compared for equality. Two references to the same object are +not guaranteed to be textually identical. + +UUIDs are intended to be permanent names for objects. They are +guaranteed to be in the OSF DCE UUID presentation format (as output by {\tt uuidgen}. +Clients may store UUIDs on disk and use them to lookup objects in subsequent sessions +with the server. Clients may also test equality on objects by comparing UUID strings. + +The API provides mechanisms +for translating between UUIDs and opaque references. Each class that contains a UUID +field provides: +\begin{itemize} +\item A ``{\tt get\_by\_uuid}'' method that takes a UUID, $u$, and returns an opaque reference +to the server-side object that has UUID=$u$; +\item A {\tt get\_uuid} function (a regular ``field getter'' RPC) that takes an opaque reference, +$r$, and returns the UUID of the server-side object that is referenced by $r$. +\end{itemize} + \subsection{Return Values/Status Codes} \label{synchronous-result} @@ -138,7 +169,7 @@ may look like this: \subsection{Transport Layer} -We ought to support at least +The following transport layers are currently supported: \begin{itemize} \item HTTP/S for remote administration \item HTTP over Unix domain sockets for local administration @@ -247,13 +278,12 @@ call takes the session token as the only parameter) \begin{verbatim} >>> all_vms = host.get_resident_VMs(session)['Value'] >>> all_vms -['b7b92d9e-d442-4710-92a5-ab039fd7d89b', '23e1e837-abbf-4675-b077-d4007989b0cc', - '2045dbc0-0734-4eea-9cb2-b8218c6b5bf2', '3202ae18-a046-4c32-9fda-e32e9631866e'] +['OpaqueRef:1', 'OpaqueRef:2', 'OpaqueRef:3', 'OpaqueRef:4' ] \end{verbatim} -The VM references here are UUIDs, though they may not be that simple in the -future, and you should treat them as opaque strings. Once a reference to a VM -has been acquired a lifecycle operation may be invoked: +The VM references here have the form {\tt OpaqueRef:X}, though they may not be +that simple in the future, and you should treat them as opaque strings. +Once a reference to a VM has been acquired a lifecycle operation may be invoked: \begin{verbatim} >>> xen.VM.start(session, all_vms[3], False) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index cce4ae5cc7..4a11ef0d9b 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -231,7 +231,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt this\_user} & user ref & Currently connected $\mathit{RO}_\mathit{run}$ & {\tt last\_active} & int & Timestamp for last time session was active \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: session} +\subsection{RPCs associated with class: session} \subsubsection{RPC name:~login\_with\_password} {\bf Overview:} @@ -505,7 +505,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt error\_info} & string Set & if the task has f $\mathit{RO}_\mathit{run}$ & {\tt allowed\_operations} & (task\_allowed\_operations) Set & Operations allowed on this task \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: task} +\subsection{RPCs associated with class: task} \subsubsection{RPC name:~cancel} {\bf Overview:} @@ -1022,40 +1022,7 @@ references to objects with match names \hline \multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf VM} \\ \multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A -virtual machine (or 'guest'). - -VM booting is controlled by setting one of the two mutually exclusive -groups: "PV", and "HVM". If HVM.boot\_policy is the empty string, then -paravirtual domain building and booting will be used; otherwise the VM will -be loaded as an HVM domain, and booted using an emulated BIOS. - -When paravirtual booting is in use, the PV/bootloader field indicates the -bootloader to use. It may be "pygrub", in which case the platform's -default installation of pygrub will be used, or a full path within the -control domain to some other bootloader. The other fields, PV/kernel, -PV/ramdisk, PV/args and PV/bootloader\_args will be passed to the -bootloader unmodified, and interpretation of those fields is then specific -to the bootloader itself, including the possibility that the bootloader -will ignore some or all of those given values. Finally the paths of all -bootable disks are added to the bootloader commandline (a disk is bootable -if its VBD has the bootable flag set). There may be zero, one or many -bootable disks; the bootloader decides which disk (if any) to boot from. - -If the bootloader is pygrub, then the menu.lst is parsed if present in the -guest's filesystem, otherwise the specified kernel and ramdisk are used, or -an autodetected kernel is used if nothing is specified and autodetection is -possible. PV/args is appended to the kernel command line, no matter which -mechanism is used for finding the kernel. - -If PV/bootloader is empty but PV/kernel is specified, then the kernel and -ramdisk values will be treated as paths within the control domain. If both -PV/bootloader and PV/kernel are empty, then the behaviour is as if -PV/bootloader was specified as "pygrub". - -When using HVM booting, HVM/boot\_policy and HVM/boot\_params specify the -boot handling. Only one policy is currently defined: "BIOS order". In -this case, HVM/boot\_params should contain one key-value pair "order" = "N" -where N is the string that will be passed to QEMU.}} \\ +virtual machine (or 'guest').}} \\ \hline Quals & Field & Type & Description \\ \hline @@ -1072,7 +1039,6 @@ $\mathit{RW}$ & {\tt memory/static\_max} & int & Statically-set (i.e. absolute) $\mathit{RW}$ & {\tt memory/dynamic\_max} & int & Dynamic maximum (bytes) \\ $\mathit{RW}$ & {\tt memory/dynamic\_min} & int & Dynamic minimum (bytes) \\ $\mathit{RW}$ & {\tt memory/static\_min} & int & Statically-set (i.e. absolute) mininum (bytes) \\ -$\mathit{RW}$ & {\tt VCPUs/policy} & string & the name of the VCPU scheduling policy to be applied \\ $\mathit{RW}$ & {\tt VCPUs/params} & (string $\rightarrow$ string) Map & configuration parameters for the selected VCPU policy \\ $\mathit{RW}$ & {\tt VCPUs/max} & int & Max number of VCPUs \\ $\mathit{RW}$ & {\tt VCPUs/at\_startup} & int & Boot number of VCPUs \\ @@ -1091,12 +1057,8 @@ $\mathit{RW}$ & {\tt PV/args} & string & kernel command-line arguments \\ $\mathit{RW}$ & {\tt PV/bootloader\_args} & string & miscellaneous arguments for the bootloader \\ $\mathit{RW}$ & {\tt HVM/boot\_policy} & string & HVM boot policy \\ $\mathit{RW}$ & {\tt HVM/boot\_params} & (string $\rightarrow$ string) Map & HVM boot params \\ -$\mathit{RW}$ & {\tt platform/std\_VGA} & bool & emulate standard VGA instead of cirrus logic \\ -$\mathit{RW}$ & {\tt platform/serial} & string & redirect serial port to pty \\ -$\mathit{RW}$ & {\tt platform/localtime} & bool & set RTC to local time \\ -$\mathit{RW}$ & {\tt platform/clock\_offset} & bool & timeshift applied to guest's clock \\ -$\mathit{RW}$ & {\tt platform/enable\_audio} & bool & emulate audio \\ -$\mathit{RO}_\mathit{ins}$ & {\tt PCI\_bus} & string & PCI bus path for pass-through devices \\ +$\mathit{RW}$ & {\tt platform} & (string $\rightarrow$ string) Map & platform-specific configuration \\ +$\mathit{RW}$ & {\tt PCI\_bus} & string & PCI bus path for pass-through devices \\ $\mathit{RW}$ & {\tt other\_config} & (string $\rightarrow$ string) Map & additional configuration \\ $\mathit{RO}_\mathit{run}$ & {\tt domid} & int & domain ID (if available, -1 otherwise) \\ $\mathit{RO}_\mathit{run}$ & {\tt is\_control\_domain} & bool & true if this is a control domain (domain 0 or a driver domain) \\ @@ -1104,7 +1066,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt metrics} & VM\_metrics ref & metrics associat $\mathit{RO}_\mathit{run}$ & {\tt guest\_metrics} & VM\_guest\_metrics ref & metrics associated with the running guest \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: VM} +\subsection{RPCs associated with class: VM} \subsubsection{RPC name:~clone} {\bf Overview:} @@ -1178,7 +1140,8 @@ void \vspace{0.3cm} -\noindent{\bf Possible Error Codes:} {\tt VM\_BAD\_POWER\_STATE} +\noindent{\bf Possible Error Codes:} {\tt VM\_BAD\_POWER\_STATE}, {\tt +VM\_HVM\_REQUIRED} \vspace{0.6cm} \subsubsection{RPC name:~pause} @@ -1362,8 +1325,10 @@ void \vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} + +\noindent{\bf Possible Error Codes:} {\tt VM\_BAD\_POWER\_STATE} + +\vspace{0.6cm} \subsubsection{RPC name:~hard\_reboot} {\bf Overview:} @@ -2209,72 +2174,6 @@ void -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~get\_VCPUs\_policy} - -{\bf Overview:} -Get the VCPUs/policy field of the given VM. - - \noindent {\bf Signature:} -\begin{verbatim} string get_VCPUs_policy (session_id s, VM ref self)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & reference to the object \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -string -} - - -value of the field -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~set\_VCPUs\_policy} - -{\bf Overview:} -Set the VCPUs/policy field of the given VM. - - \noindent {\bf Signature:} -\begin{verbatim} void set_VCPUs_policy (session_id s, VM ref self, string value)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & reference to the object \\ \hline - -{\tt string } & value & New value to set \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -void -} - - - \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -3438,13 +3337,13 @@ void \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} -\subsubsection{RPC name:~get\_platform\_std\_VGA} +\subsubsection{RPC name:~get\_platform} {\bf Overview:} -Get the platform/std\_VGA field of the given VM. +Get the platform field of the given VM. \noindent {\bf Signature:} -\begin{verbatim} bool get_platform_std_VGA (session_id s, VM ref self)\end{verbatim} +\begin{verbatim} ((string -> string) Map) get_platform (session_id s, VM ref self)\end{verbatim} \noindent{\bf Arguments:} @@ -3462,7 +3361,7 @@ Get the platform/std\_VGA field of the given VM. \noindent {\bf Return Type:} {\tt -bool +(string $\rightarrow$ string) Map } @@ -3470,13 +3369,13 @@ value of the field \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} -\subsubsection{RPC name:~set\_platform\_std\_VGA} +\subsubsection{RPC name:~set\_platform} {\bf Overview:} -Set the platform/std\_VGA field of the given VM. +Set the platform field of the given VM. \noindent {\bf Signature:} -\begin{verbatim} void set_platform_std_VGA (session_id s, VM ref self, bool value)\end{verbatim} +\begin{verbatim} void set_platform (session_id s, VM ref self, (string -> string) Map value)\end{verbatim} \noindent{\bf Arguments:} @@ -3488,7 +3387,7 @@ Set the platform/std\_VGA field of the given VM. {\bf type} & {\bf name} & {\bf description} \\ \hline {\tt VM ref } & self & reference to the object \\ \hline -{\tt bool } & value & New value to set \\ \hline +{\tt (string $\rightarrow$ string) Map } & value & New value to set \\ \hline \end{tabular} @@ -3504,13 +3403,13 @@ void \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} -\subsubsection{RPC name:~get\_platform\_serial} +\subsubsection{RPC name:~add\_to\_platform} {\bf Overview:} -Get the platform/serial field of the given VM. +Add the given key-value pair to the platform field of the given VM. \noindent {\bf Signature:} -\begin{verbatim} string get_platform_serial (session_id s, VM ref self)\end{verbatim} +\begin{verbatim} void add_to_platform (session_id s, VM ref self, string key, string value)\end{verbatim} \noindent{\bf Arguments:} @@ -3522,39 +3421,9 @@ Get the platform/serial field of the given VM. {\bf type} & {\bf name} & {\bf description} \\ \hline {\tt VM ref } & self & reference to the object \\ \hline -\end{tabular} +{\tt string } & key & Key to add \\ \hline -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -string -} - - -value of the field -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~set\_platform\_serial} - -{\bf Overview:} -Set the platform/serial field of the given VM. - - \noindent {\bf Signature:} -\begin{verbatim} void set_platform_serial (session_id s, VM ref self, string value)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & reference to the object \\ \hline - -{\tt string } & value & New value to set \\ \hline +{\tt string } & value & Value to add \\ \hline \end{tabular} @@ -3570,13 +3439,14 @@ void \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} -\subsubsection{RPC name:~get\_platform\_localtime} +\subsubsection{RPC name:~remove\_from\_platform} {\bf Overview:} -Get the platform/localtime field of the given VM. +Remove the given key and its corresponding value from the platform field of +the given VM. If the key is not in that Map, then do nothing. \noindent {\bf Signature:} -\begin{verbatim} bool get_platform_localtime (session_id s, VM ref self)\end{verbatim} +\begin{verbatim} void remove_from_platform (session_id s, VM ref self, string key)\end{verbatim} \noindent{\bf Arguments:} @@ -3588,171 +3458,7 @@ Get the platform/localtime field of the given VM. {\bf type} & {\bf name} & {\bf description} \\ \hline {\tt VM ref } & self & reference to the object \\ \hline -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -bool -} - - -value of the field -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~set\_platform\_localtime} - -{\bf Overview:} -Set the platform/localtime field of the given VM. - - \noindent {\bf Signature:} -\begin{verbatim} void set_platform_localtime (session_id s, VM ref self, bool value)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & reference to the object \\ \hline - -{\tt bool } & value & New value to set \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -void -} - - - -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~get\_platform\_clock\_offset} - -{\bf Overview:} -Get the platform/clock\_offset field of the given VM. - - \noindent {\bf Signature:} -\begin{verbatim} bool get_platform_clock_offset (session_id s, VM ref self)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & reference to the object \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -bool -} - - -value of the field -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~set\_platform\_clock\_offset} - -{\bf Overview:} -Set the platform/clock\_offset field of the given VM. - - \noindent {\bf Signature:} -\begin{verbatim} void set_platform_clock_offset (session_id s, VM ref self, bool value)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & reference to the object \\ \hline - -{\tt bool } & value & New value to set \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -void -} - - - -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~get\_platform\_enable\_audio} - -{\bf Overview:} -Get the platform/enable\_audio field of the given VM. - - \noindent {\bf Signature:} -\begin{verbatim} bool get_platform_enable_audio (session_id s, VM ref self)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & reference to the object \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -bool -} - - -value of the field -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~set\_platform\_enable\_audio} - -{\bf Overview:} -Set the platform/enable\_audio field of the given VM. - - \noindent {\bf Signature:} -\begin{verbatim} void set_platform_enable_audio (session_id s, VM ref self, bool value)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & reference to the object \\ \hline - -{\tt bool } & value & New value to set \\ \hline +{\tt string } & key & Key to remove \\ \hline \end{tabular} @@ -3797,6 +3503,40 @@ string value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~set\_PCI\_bus} + +{\bf Overview:} +Set the PCI\_bus field of the given VM. + + \noindent {\bf Signature:} +\begin{verbatim} void set_PCI_bus (session_id s, VM ref self, string value)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline + +{\tt string } & value & New value to set \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -4245,7 +3985,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt VCPUs/number} & int & Current number of VCPUs $\mathit{RO}_\mathit{run}$ & {\tt VCPUs/utilisation} & (int $\rightarrow$ float) Map & Utilisation for all of guest's current VCPUs \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: VM\_metrics} +\subsection{RPCs associated with class: VM\_metrics} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -4481,7 +4221,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt networks} & (string $\rightarrow$ string) Map $\mathit{RO}_\mathit{run}$ & {\tt other} & (string $\rightarrow$ string) Map & anything else \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: VM\_guest\_metrics} +\subsection{RPCs associated with class: VM\_guest\_metrics} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -4825,7 +4565,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt host\_CPUs} & (host\_cpu ref) Set & The physi $\mathit{RO}_\mathit{ins}$ & {\tt metrics} & host\_metrics ref & metrics associated with this host. \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: host} +\subsection{RPCs associated with class: host} \subsubsection{RPC name:~disable} {\bf Overview:} @@ -6078,7 +5818,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt memory/total} & int & Host's total memory (by $\mathit{RO}_\mathit{run}$ & {\tt memory/free} & int & Host's free memory (bytes) \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: host\_metrics} +\subsection{RPCs associated with class: host\_metrics} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -6283,7 +6023,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt flags} & string & the flags of the physical C $\mathit{RO}_\mathit{run}$ & {\tt utilisation} & float & the current CPU utilisation \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: host\_cpu} +\subsection{RPCs associated with class: host\_cpu} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -6677,7 +6417,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt VIFs} & (VIF ref) Set & list of connected vif $\mathit{RO}_\mathit{run}$ & {\tt PIFs} & (PIF ref) Set & list of connected pifs \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: network} +\subsection{RPCs associated with class: network} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -7115,7 +6855,72 @@ $\mathit{RO}_\mathit{run}$ & {\tt qos/supported\_algorithms} & string Set & sup $\mathit{RO}_\mathit{run}$ & {\tt metrics} & VIF\_metrics ref & metrics associated with this VIF. \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: VIF} +\subsection{RPCs associated with class: VIF} +\subsubsection{RPC name:~plug} + +{\bf Overview:} +Hotplug the specified VIF, dynamically attaching it to the running VM. + + \noindent {\bf Signature:} +\begin{verbatim} void plug (session_id s, VIF ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VIF ref } & self & The VIF to hotplug \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~unplug} + +{\bf Overview:} +Hot-unplug the specified VIF, dynamically unattaching it from the running +VM. + + \noindent {\bf Signature:} +\begin{verbatim} void unplug (session_id s, VIF ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VIF ref } & self & The VIF to hot-unplug \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -7942,7 +7747,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt io/read\_kbs} & float & Read bandwidth (KiB/s $\mathit{RO}_\mathit{run}$ & {\tt io/write\_kbs} & float & Write bandwidth (KiB/s) \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: VIF\_metrics} +\subsection{RPCs associated with class: VIF\_metrics} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -8148,7 +7953,7 @@ $\mathit{RW}$ & {\tt VLAN} & int & VLAN tag for all traffic passing through thi $\mathit{RO}_\mathit{ins}$ & {\tt metrics} & PIF\_metrics ref & metrics associated with this PIF. \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: PIF} +\subsection{RPCs associated with class: PIF} \subsubsection{RPC name:~create\_VLAN} {\bf Overview:} @@ -8719,7 +8524,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt io/read\_kbs} & float & Read bandwidth (KiB/s $\mathit{RO}_\mathit{run}$ & {\tt io/write\_kbs} & float & Write bandwidth (KiB/s) \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: PIF\_metrics} +\subsection{RPCs associated with class: PIF\_metrics} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -8926,7 +8731,7 @@ $\mathit{RO}_\mathit{ins}$ & {\tt type} & string & type of the storage reposito $\mathit{RO}_\mathit{ins}$ & {\tt location} & string & a string that uniquely determines the location of the storage repository; the format of this string depends on the repository's type \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: SR} +\subsection{RPCs associated with class: SR} \subsubsection{RPC name:~clone} {\bf Overview:} @@ -9549,18 +9354,18 @@ Quals & Field & Type & Description \\ $\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\ $\mathit{RW}$ & {\tt name/label} & string & a human-readable name \\ $\mathit{RW}$ & {\tt name/description} & string & a notes field containg human-readable description \\ -$\mathit{RW}$ & {\tt SR} & SR ref & storage repository in which the VDI resides \\ +$\mathit{RO}_\mathit{ins}$ & {\tt SR} & SR ref & storage repository in which the VDI resides \\ $\mathit{RO}_\mathit{run}$ & {\tt VBDs} & (VBD ref) Set & list of vbds that refer to this disk \\ $\mathit{RO}_\mathit{run}$ & {\tt crash\_dumps} & (crashdump ref) Set & list of crash dumps that refer to this disk \\ $\mathit{RW}$ & {\tt virtual\_size} & int & size of disk as presented to the guest (in bytes). Note that, depending on storage backend type, requested size may not be respected exactly \\ $\mathit{RO}_\mathit{run}$ & {\tt physical\_utilisation} & int & amount of physical space that the disk image is currently taking up on the storage repository (in bytes) \\ -$\mathit{RO}_\mathit{ins}$ & {\tt sector\_size} & int & sector size of VDI (in bytes) \\ $\mathit{RO}_\mathit{ins}$ & {\tt type} & vdi\_type & type of the VDI \\ $\mathit{RW}$ & {\tt sharable} & bool & true if this disk may be shared \\ $\mathit{RW}$ & {\tt read\_only} & bool & true if this disk may ONLY be mounted read-only \\ +$\mathit{RW}$ & {\tt other\_config} & (string $\rightarrow$ string) Map & additional configuration \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: VDI} +\subsection{RPCs associated with class: VDI} \subsubsection{RPC name:~snapshot} {\bf Overview:} @@ -9842,40 +9647,6 @@ SR ref value of the field -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~set\_SR} - -{\bf Overview:} -Set the SR field of the given VDI. - - \noindent {\bf Signature:} -\begin{verbatim} void set_SR (session_id s, VDI ref self, SR ref value)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & reference to the object \\ \hline - -{\tt SR ref } & value & New value to set \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -void -} - - - \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -10037,38 +9808,6 @@ int } -value of the field -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~get\_sector\_size} - -{\bf Overview:} -Get the sector\_size field of the given VDI. - - \noindent {\bf Signature:} -\begin{verbatim} int get_sector_size (session_id s, VDI ref self)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & reference to the object \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -int -} - - value of the field \vspace{0.3cm} \vspace{0.3cm} @@ -10234,6 +9973,143 @@ void +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_other\_config} + +{\bf Overview:} +Get the other\_config field of the given VDI. + + \noindent {\bf Signature:} +\begin{verbatim} ((string -> string) Map) get_other_config (session_id s, VDI ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +(string $\rightarrow$ string) Map +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~set\_other\_config} + +{\bf Overview:} +Set the other\_config field of the given VDI. + + \noindent {\bf Signature:} +\begin{verbatim} void set_other_config (session_id s, VDI ref self, (string -> string) Map value)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline + +{\tt (string $\rightarrow$ string) Map } & value & New value to set \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~add\_to\_other\_config} + +{\bf Overview:} +Add the given key-value pair to the other\_config field of the given VDI. + + \noindent {\bf Signature:} +\begin{verbatim} void add_to_other_config (session_id s, VDI ref self, string key, string value)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline + +{\tt string } & key & Key to add \\ \hline + +{\tt string } & value & Value to add \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~remove\_from\_other\_config} + +{\bf Overview:} +Remove the given key and its corresponding value from the other\_config +field of the given VDI. If the key is not in that Map, then do nothing. + + \noindent {\bf Signature:} +\begin{verbatim} void remove_from_other_config (session_id s, VDI ref self, string key)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline + +{\tt string } & key & Key to remove \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -10426,7 +10302,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt qos/supported\_algorithms} & string Set & sup $\mathit{RO}_\mathit{run}$ & {\tt metrics} & VBD\_metrics ref & metrics associated with this VBD \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: VBD} +\subsection{RPCs associated with class: VBD} \subsubsection{RPC name:~media\_change} {\bf Overview:} @@ -10459,6 +10335,71 @@ void +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~plug} + +{\bf Overview:} +Hotplug the specified VBD, dynamically attaching it to the running VM. + + \noindent {\bf Signature:} +\begin{verbatim} void plug (session_id s, VBD ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VBD ref } & self & The VBD to hotplug \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~unplug} + +{\bf Overview:} +Hot-unplug the specified VBD, dynamically unattaching it from the running +VM. + + \noindent {\bf Signature:} +\begin{verbatim} void unplug (session_id s, VBD ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VBD ref } & self & The VBD to hot-unplug \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -11354,7 +11295,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt io/read\_kbs} & float & Read bandwidth (KiB/s $\mathit{RO}_\mathit{run}$ & {\tt io/write\_kbs} & float & Write bandwidth (KiB/s) \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: VBD\_metrics} +\subsection{RPCs associated with class: VBD\_metrics} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -11556,7 +11497,7 @@ $\mathit{RO}_\mathit{ins}$ & {\tt device\_config} & (string $\rightarrow$ strin $\mathit{RO}_\mathit{run}$ & {\tt currently\_attached} & bool & is the SR currently attached on this host? \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: PBD} +\subsection{RPCs associated with class: PBD} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -11884,7 +11825,39 @@ $\mathit{RO}_\mathit{ins}$ & {\tt VM} & VM ref & the virtual machine \\ $\mathit{RO}_\mathit{ins}$ & {\tt VDI} & VDI ref & the virtual disk \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: crashdump} +\subsection{RPCs associated with class: crashdump} +\subsubsection{RPC name:~destroy} + +{\bf Overview:} +Destroy the specified crashdump. + + \noindent {\bf Signature:} +\begin{verbatim} void destroy (session_id s, crashdump ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt crashdump ref } & self & The crashdump to destroy \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -11999,70 +11972,6 @@ VDI ref value of the field -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~create} - -{\bf Overview:} -Create a new crashdump instance, and return its handle. - - \noindent {\bf Signature:} -\begin{verbatim} (crashdump ref) create (session_id s, crashdump record args)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt crashdump record } & args & All constructor arguments \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -crashdump ref -} - - -reference to the newly created object -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~destroy} - -{\bf Overview:} -Destroy the specified crashdump instance. - - \noindent {\bf Signature:} -\begin{verbatim} void destroy (session_id s, crashdump ref self)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt crashdump ref } & self & reference to the object \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -void -} - - - \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -12148,7 +12057,7 @@ $\mathit{RO}_\mathit{ins}$ & {\tt VM} & VM ref & the virtual machine \\ $\mathit{RO}_\mathit{ins}$ & {\tt backend} & VM ref & the domain where the backend is located \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: VTPM} +\subsection{RPCs associated with class: VTPM} \subsubsection{RPC name:~get\_uuid} {\bf Overview:} @@ -12393,7 +12302,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt VM} & VM ref & VM to which this console is at $\mathit{RW}$ & {\tt other\_config} & (string $\rightarrow$ string) Map & additional configuration \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: console} +\subsection{RPCs associated with class: console} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -12828,7 +12737,7 @@ $\mathit{RO}_\mathit{ins}$ & {\tt short\_name} & string & short name (e.g. user $\mathit{RW}$ & {\tt fullname} & string & full name \\ \hline \end{longtable} -\subsection{Additional RPCs associated with class: user} +\subsection{RPCs associated with class: user} \subsubsection{RPC name:~get\_uuid} {\bf Overview:} @@ -13093,7 +13002,7 @@ all fields from the object \section{Class: debug} \subsection{Fields for class: debug} {\bf Class debug has no fields.} -\subsection{Additional RPCs associated with class: debug} +\subsection{RPCs associated with class: debug} \subsubsection{RPC name:~get\_all} {\bf Overview:} @@ -13467,6 +13376,15 @@ expected and actual VM state at the time of the call. \begin{verbatim}VM_BAD_POWER_STATE(vm, expected, actual)\end{verbatim} \begin{center}\rule{10em}{0.1pt}\end{center} +\subsubsection{VM\_HVM\_REQUIRED} + +HVM is required for this operation + +\vspace{0.3cm} +{\bf Signature:} +\begin{verbatim}VM_HVM_REQUIRED(vm)\end{verbatim} +\begin{center}\rule{10em}{0.1pt}\end{center} + \newpage diff --git a/docs/xen-api/xenapi.tex b/docs/xen-api/xenapi.tex index ff8cfa9fcc..e671d84156 100644 --- a/docs/xen-api/xenapi.tex +++ b/docs/xen-api/xenapi.tex @@ -16,6 +16,7 @@ \usepackage{a4wide} \usepackage{graphics} \usepackage{longtable} +\usepackage{fancyhdr} \setlength\topskip{0cm} \setlength\topmargin{0cm} @@ -35,7 +36,7 @@ \chapter{Introduction} -This document contains a proposal for a Xen Management API---an interface for +This document contains a description of the Xen Management API---an interface for remotely configuring and controlling virtualised guests running on a Xen-enabled host. diff --git a/extras/mini-os/arch/x86/mm.c b/extras/mini-os/arch/x86/mm.c index d1508f8263..15ed4877a8 100644 --- a/extras/mini-os/arch/x86/mm.c +++ b/extras/mini-os/arch/x86/mm.c @@ -49,7 +49,7 @@ #endif unsigned long *phys_to_machine_mapping; -extern char *stack; +extern char stack[]; extern void page_walk(unsigned long virt_addr); void new_pt_frame(unsigned long *pt_pfn, unsigned long prev_l_mfn, @@ -453,7 +453,7 @@ void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p) printk(" _text: %p\n", &_text); printk(" _etext: %p\n", &_etext); printk(" _edata: %p\n", &_edata); - printk(" stack start: %p\n", &stack); + printk(" stack start: %p\n", stack); printk(" _end: %p\n", &_end); /* First page follows page table pages and 3 more pages (store page etc) */ diff --git a/extras/mini-os/gnttab.c b/extras/mini-os/gnttab.c index 4d75897a98..b22f51ceae 100644 --- a/extras/mini-os/gnttab.c +++ b/extras/mini-os/gnttab.c @@ -135,7 +135,7 @@ gnttab_alloc_and_grant(void **map) return gref; } -static const char *gnttabop_error_msgs[] = GNTTABOP_error_msgs; +static const char * const gnttabop_error_msgs[] = GNTTABOP_error_msgs; const char * gnttabop_error(int16_t status) diff --git a/extras/mini-os/hypervisor.c b/extras/mini-os/hypervisor.c index 2c2efa7e46..ed87845195 100644 --- a/extras/mini-os/hypervisor.c +++ b/extras/mini-os/hypervisor.c @@ -35,8 +35,8 @@ void do_hypervisor_callback(struct pt_regs *regs) { - u32 l1, l2; - unsigned int l1i, l2i, port; + unsigned long l1, l2, l1i, l2i; + unsigned int port; int cpu = 0; shared_info_t *s = HYPERVISOR_shared_info; vcpu_info_t *vcpu_info = &s->vcpu_info[cpu]; diff --git a/extras/mini-os/include/wait.h b/extras/mini-os/include/wait.h index f581db9109..d8338fbd8e 100644 --- a/extras/mini-os/include/wait.h +++ b/extras/mini-os/include/wait.h @@ -74,6 +74,13 @@ static inline void wake_up(struct wait_queue_head *head) local_irq_restore(flags); \ } while (0) +#define remove_waiter(w) do { \ + unsigned long flags; \ + local_irq_save(flags); \ + remove_wait_queue(&w); \ + local_irq_restore(flags); \ +} while (0) + #define wait_event(wq, condition) do{ \ unsigned long flags; \ if(condition) \ diff --git a/extras/mini-os/include/xenbus.h b/extras/mini-os/include/xenbus.h index 3866a8bbce..cd4e85d122 100644 --- a/extras/mini-os/include/xenbus.h +++ b/extras/mini-os/include/xenbus.h @@ -13,6 +13,7 @@ void init_xenbus(void); char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value); char *xenbus_watch_path(xenbus_transaction_t xbt, const char *path); +void wait_for_watch(void); char* xenbus_wait_for_value(const char*,const char*); /* Associates a value with a path. Returns a malloc'd error string on diff --git a/extras/mini-os/xenbus/xenbus.c b/extras/mini-os/xenbus/xenbus.c index f483211947..9433b22b02 100644 --- a/extras/mini-os/xenbus/xenbus.c +++ b/extras/mini-os/xenbus/xenbus.c @@ -72,11 +72,12 @@ static void memcpy_from_ring(const void *Ring, memcpy(dest + c1, ring, c2); } -static inline void wait_for_watch(void) +void wait_for_watch(void) { DEFINE_WAIT(w); add_waiter(w,watch_queue); schedule(); + remove_waiter(w); wake(current); } diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/cpu/mtrr/main-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/cpu/mtrr/main-xen.c index 380e20ec5b..6b0b18bbbf 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/cpu/mtrr/main-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/cpu/mtrr/main-xen.c @@ -14,11 +14,11 @@ static DEFINE_MUTEX(mtrr_mutex); void generic_get_mtrr(unsigned int reg, unsigned long *base, unsigned int *size, mtrr_type * type) { - dom0_op_t op; + struct xen_platform_op op; - op.cmd = DOM0_READ_MEMTYPE; + op.cmd = XENPF_read_memtype; op.u.read_memtype.reg = reg; - (void)HYPERVISOR_dom0_op(&op); + (void)HYPERVISOR_platform_op(&op); *size = op.u.read_memtype.nr_mfns; *base = op.u.read_memtype.mfn; @@ -36,12 +36,12 @@ unsigned int *usage_table; static void __init set_num_var_ranges(void) { - dom0_op_t op; + struct xen_platform_op op; for (num_var_ranges = 0; ; num_var_ranges++) { - op.cmd = DOM0_READ_MEMTYPE; + op.cmd = XENPF_read_memtype; op.u.read_memtype.reg = num_var_ranges; - if (HYPERVISOR_dom0_op(&op) != 0) + if (HYPERVISOR_platform_op(&op) != 0) break; } } @@ -64,15 +64,15 @@ int mtrr_add_page(unsigned long base, unsigned long size, unsigned int type, char increment) { int error; - dom0_op_t op; + struct xen_platform_op op; mutex_lock(&mtrr_mutex); - op.cmd = DOM0_ADD_MEMTYPE; + op.cmd = XENPF_add_memtype; op.u.add_memtype.mfn = base; op.u.add_memtype.nr_mfns = size; op.u.add_memtype.type = type; - error = HYPERVISOR_dom0_op(&op); + error = HYPERVISOR_platform_op(&op); if (error) { mutex_unlock(&mtrr_mutex); BUG_ON(error > 0); @@ -117,7 +117,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) unsigned long lbase; unsigned int lsize; int error = -EINVAL; - dom0_op_t op; + struct xen_platform_op op; mutex_lock(&mtrr_mutex); @@ -141,10 +141,10 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) goto out; } if (--usage_table[reg] < 1) { - op.cmd = DOM0_DEL_MEMTYPE; + op.cmd = XENPF_del_memtype; op.u.del_memtype.handle = 0; op.u.del_memtype.reg = reg; - error = HYPERVISOR_dom0_op(&op); + error = HYPERVISOR_platform_op(&op); if (error) { BUG_ON(error > 0); goto out; diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/io_apic-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/io_apic-xen.c index 023ec42582..8d50b28ddd 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/io_apic-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/io_apic-xen.c @@ -2510,10 +2510,10 @@ static int __init io_apic_bug_finalize(void) if(sis_apic_bug == -1) sis_apic_bug = 0; if (is_initial_xendomain()) { - dom0_op_t op = { .cmd = DOM0_PLATFORM_QUIRK }; + struct xen_platform_op op = { .cmd = XENPF_platform_quirk }; op.u.platform_quirk.quirk_id = sis_apic_bug ? QUIRK_IOAPIC_BAD_REGSEL : QUIRK_IOAPIC_GOOD_REGSEL; - HYPERVISOR_dom0_op(&op); + HYPERVISOR_platform_op(&op); } return 0; } diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/ioport-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/ioport-xen.c index 60ada981fb..1f704215e1 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/ioport-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/ioport-xen.c @@ -81,7 +81,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) t->io_bitmap_ptr = bitmap; set_thread_flag(TIF_IO_BITMAP); - set_iobitmap.bitmap = (char *)bitmap; + set_xen_guest_handle(set_iobitmap.bitmap, (char *)bitmap); set_iobitmap.nr_ports = IO_BITMAP_BITS; HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap); } diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/microcode-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/microcode-xen.c index 55a416c885..15e30d1efb 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/microcode-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/microcode-xen.c @@ -71,12 +71,12 @@ static int do_microcode_update (const void __user *ubuf, size_t len) return -ENOMEM; if (copy_from_user(kbuf, ubuf, len) == 0) { - dom0_op_t op; + struct xen_platform_op op; - op.cmd = DOM0_MICROCODE; + op.cmd = XENPF_microcode_update; set_xen_guest_handle(op.u.microcode.data, kbuf); op.u.microcode.length = len; - err = HYPERVISOR_dom0_op(&op); + err = HYPERVISOR_platform_op(&op); } else err = -EFAULT; diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/process-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/process-xen.c index 2225fcc962..6c19ecc417 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/process-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/process-xen.c @@ -307,7 +307,8 @@ void exit_thread(void) if (unlikely(test_thread_flag(TIF_IO_BITMAP))) { struct task_struct *tsk = current; struct thread_struct *t = &tsk->thread; - struct physdev_set_iobitmap set_iobitmap = { 0 }; + struct physdev_set_iobitmap set_iobitmap; + memset(&set_iobitmap, 0, sizeof(set_iobitmap)); HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap); kfree(t->io_bitmap_ptr); t->io_bitmap_ptr = NULL; @@ -606,7 +607,8 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas } if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) { - iobmp_op.bitmap = (char *)next->io_bitmap_ptr; + set_xen_guest_handle(iobmp_op.bitmap, + (char *)next->io_bitmap_ptr); iobmp_op.nr_ports = next->io_bitmap_ptr ? IO_BITMAP_BITS : 0; mcl->op = __HYPERVISOR_physdev_op; mcl->args[0] = PHYSDEVOP_set_iobitmap; diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/quirks-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/quirks-xen.c index 26b35341bd..85385ae6e1 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/quirks-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/quirks-xen.c @@ -30,11 +30,11 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word); if (!(word & (1 << 13))) { - dom0_op_t op; + struct xen_platform_op op; printk(KERN_INFO "Disabling irq balancing and affinity\n"); - op.cmd = DOM0_PLATFORM_QUIRK; + op.cmd = XENPF_platform_quirk; op.u.platform_quirk.quirk_id = QUIRK_NOIRQBALANCING; - (void)HYPERVISOR_dom0_op(&op); + (void)HYPERVISOR_platform_op(&op); } /* put back the original value for config space*/ diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c index b57ab9bdfe..597deb733d 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c @@ -435,7 +435,7 @@ int do_settimeofday(struct timespec *tv) s64 nsec; unsigned int cpu; struct shadow_time_info *shadow; - dom0_op_t op; + struct xen_platform_op op; if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) return -EINVAL; @@ -460,11 +460,11 @@ int do_settimeofday(struct timespec *tv) __normalize_time(&sec, &nsec); if (is_initial_xendomain() && !independent_wallclock) { - op.cmd = DOM0_SETTIME; + op.cmd = XENPF_settime; op.u.settime.secs = sec; op.u.settime.nsecs = nsec; op.u.settime.system_time = shadow->system_timestamp; - HYPERVISOR_dom0_op(&op); + HYPERVISOR_platform_op(&op); update_wallclock(); } else if (independent_wallclock) { nsec -= shadow->system_timestamp; @@ -488,7 +488,7 @@ static void sync_xen_wallclock(unsigned long dummy) { time_t sec; s64 nsec; - dom0_op_t op; + struct xen_platform_op op; if (!ntp_synced() || independent_wallclock || !is_initial_xendomain()) return; @@ -499,11 +499,11 @@ static void sync_xen_wallclock(unsigned long dummy) nsec = xtime.tv_nsec + ((jiffies - wall_jiffies) * (u64)NS_PER_TICK); __normalize_time(&sec, &nsec); - op.cmd = DOM0_SETTIME; + op.cmd = XENPF_settime; op.u.settime.secs = sec; op.u.settime.nsecs = nsec; op.u.settime.system_time = processed_system_time; - HYPERVISOR_dom0_op(&op); + HYPERVISOR_platform_op(&op); update_wallclock(); @@ -907,6 +907,10 @@ static void setup_cpu0_timer_irq(void) BUG_ON(per_cpu(timer_irq, 0) < 0); } +static struct vcpu_set_periodic_timer xen_set_periodic_tick = { + .period_ns = NS_PER_TICK +}; + void __init time_init(void) { #ifdef CONFIG_HPET_TIMER @@ -919,6 +923,10 @@ void __init time_init(void) return; } #endif + + HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, 0, + &xen_set_periodic_tick); + get_time_values_from_xen(0); processed_system_time = per_cpu(shadow_time, 0).system_timestamp; @@ -976,8 +984,10 @@ EXPORT_SYMBOL(jiffies_to_st); */ static void stop_hz_timer(void) { + struct vcpu_set_singleshot_timer singleshot; unsigned int cpu = smp_processor_id(); unsigned long j; + int rc; cpu_set(cpu, nohz_cpu_mask); @@ -997,8 +1007,16 @@ static void stop_hz_timer(void) j = jiffies + 1; } - if (HYPERVISOR_set_timer_op(jiffies_to_st(j)) != 0) - BUG(); + singleshot.timeout_abs_ns = jiffies_to_st(j); + singleshot.flags = 0; + rc = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &singleshot); +#ifdef CONFIG_XEN_COMPAT_030004 + if (rc) { + BUG_ON(rc != -ENOSYS); + rc = HYPERVISOR_set_timer_op(singleshot.timeout_abs_ns); + } +#endif + BUG_ON(rc); } static void start_hz_timer(void) @@ -1030,6 +1048,8 @@ void time_resume(void) init_cpu_khz(); for_each_online_cpu(cpu) { + HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu, + &xen_set_periodic_tick); get_time_values_from_xen(cpu); per_cpu(processed_system_time, cpu) = per_cpu(shadow_time, 0).system_timestamp; @@ -1050,6 +1070,9 @@ int local_setup_timer(unsigned int cpu) BUG_ON(cpu == 0); + HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu, + &xen_set_periodic_tick); + do { seq = read_seqbegin(&xtime_lock); /* Use cpu0 timestamp: cpu's shadow is not initialised yet. */ diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/vsyscall-note-xen.S b/linux-2.6-xen-sparse/arch/i386/kernel/vsyscall-note-xen.S index c2d6dbf159..019d9afb83 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/vsyscall-note-xen.S +++ b/linux-2.6-xen-sparse/arch/i386/kernel/vsyscall-note-xen.S @@ -28,5 +28,5 @@ #define NOTE_KERNELCAP_END ASM_ELF_NOTE_END NOTE_KERNELCAP_BEGIN(1, 1) -NOTE_KERNELCAP(1, "nosegneg") /* Change 1 back to 0 when glibc is fixed! */ +NOTE_KERNELCAP(0, "nosegneg") NOTE_KERNELCAP_END diff --git a/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c b/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c index 7c9a60aace..1042f9c260 100644 --- a/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c +++ b/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c @@ -146,7 +146,7 @@ void xen_tlb_flush_mask(cpumask_t *mask) if ( cpus_empty(*mask) ) return; op.cmd = MMUEXT_TLB_FLUSH_MULTI; - op.arg2.vcpumask = mask->bits; + set_xen_guest_handle(op.arg2.vcpumask, mask->bits); BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); } @@ -165,7 +165,7 @@ void xen_invlpg_mask(cpumask_t *mask, unsigned long ptr) return; op.cmd = MMUEXT_INVLPG_MULTI; op.arg1.linear_addr = ptr & PAGE_MASK; - op.arg2.vcpumask = mask->bits; + set_xen_guest_handle(op.arg2.vcpumask, mask->bits); BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); } diff --git a/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c b/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c index 4f72489800..df20e591c1 100644 --- a/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c @@ -256,8 +256,9 @@ void pte_free(struct page *pte) unsigned long va = (unsigned long)__va(pfn << PAGE_SHIFT); if (!pte_write(*virt_to_ptep(va))) - BUG_ON(HYPERVISOR_update_va_mapping( - va, pfn_pte(pfn, PAGE_KERNEL), 0)); + if (HYPERVISOR_update_va_mapping( + va, pfn_pte(pfn, PAGE_KERNEL), 0)) + BUG(); } else clear_bit(PG_pinned, &pte->flags); @@ -600,7 +601,7 @@ static void pgd_walk(pgd_t *pgd_base, pgprot_t flags) int g, u, m, rc; if (xen_feature(XENFEAT_auto_translated_physmap)) - return 0; + return; for (g = 0; g < USER_PTRS_PER_PGD; g++, pgd++) { if (pgd_none(*pgd)) @@ -672,14 +673,23 @@ void mm_unpin(struct mm_struct *mm) void mm_pin_all(void) { struct page *page; + unsigned long flags; if (xen_feature(XENFEAT_writable_page_tables)) return; + /* + * Allow uninterrupted access to the pgd_list. Also protects + * __pgd_pin() by disabling preemption. + * All other CPUs must be at a safe point (e.g., in stop_machine + * or offlined entirely). + */ + spin_lock_irqsave(&pgd_lock, flags); for (page = pgd_list; page; page = (struct page *)page->index) { if (!test_bit(PG_pinned, &page->flags)) __pgd_pin((pgd_t *)page_address(page)); } + spin_unlock_irqrestore(&pgd_lock, flags); } void _arch_dup_mmap(struct mm_struct *mm) diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c index 49f9ea6708..95588e7304 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c index d4cafe06ba..c78f15355d 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c index e1e312d204..dc1012a0f6 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #define __XEN__ #include #include @@ -40,25 +40,25 @@ #define ROUND_DIV(v,s) (((v) + (s) - 1) / (s)) static int -xencomm_privcmd_dom0_op(privcmd_hypercall_t *hypercall) +xencomm_privcmd_platform_op(privcmd_hypercall_t *hypercall) { - dom0_op_t kern_op; - dom0_op_t __user *user_op = (dom0_op_t __user *)hypercall->arg[0]; + struct xen_platform_op kern_op; + struct xen_platform_op __user *user_op = (struct xen_platform_op __user *)hypercall->arg[0]; struct xencomm_handle *op_desc; struct xencomm_handle *desc = NULL; int ret = 0; - if (copy_from_user(&kern_op, user_op, sizeof(dom0_op_t))) + if (copy_from_user(&kern_op, user_op, sizeof(struct xen_platform_op))) return -EFAULT; - if (kern_op.interface_version != DOM0_INTERFACE_VERSION) + if (kern_op.interface_version != XENPF_INTERFACE_VERSION) return -EACCES; op_desc = xencomm_create_inline(&kern_op); switch (kern_op.cmd) { default: - printk("%s: unknown dom0 cmd %d\n", __func__, kern_op.cmd); + printk("%s: unknown platform cmd %d\n", __func__, kern_op.cmd); return -ENOSYS; } @@ -67,10 +67,10 @@ xencomm_privcmd_dom0_op(privcmd_hypercall_t *hypercall) return ret; } - ret = xencomm_arch_hypercall_dom0_op(op_desc); + ret = xencomm_arch_hypercall_platform_op(op_desc); /* FIXME: should we restore the handle? */ - if (copy_to_user(user_op, &kern_op, sizeof(dom0_op_t))) + if (copy_to_user(user_op, &kern_op, sizeof(struct xen_platform_op))) ret = -EFAULT; if (desc) @@ -638,8 +638,8 @@ int privcmd_hypercall(privcmd_hypercall_t *hypercall) { switch (hypercall->op) { - case __HYPERVISOR_dom0_op: - return xencomm_privcmd_dom0_op(hypercall); + case __HYPERVISOR_platform_op: + return xencomm_privcmd_platform_op(hypercall); case __HYPERVISOR_domctl: return xencomm_privcmd_domctl(hypercall); case __HYPERVISOR_sysctl: diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/ioport-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/ioport-xen.c index 1fcbb20839..a57442c698 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/ioport-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/ioport-xen.c @@ -59,7 +59,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) memset(bitmap, 0xff, IO_BITMAP_BYTES); t->io_bitmap_ptr = bitmap; - set_iobitmap.bitmap = (char *)bitmap; + set_xen_guest_handle(set_iobitmap.bitmap, (char *)bitmap); set_iobitmap.nr_ports = IO_BITMAP_BITS; HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap); } diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/process-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/process-xen.c index 6a7bf2ed37..41aa70ce63 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/process-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/process-xen.c @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include #include @@ -304,7 +304,8 @@ void exit_thread(void) struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); #endif #ifdef CONFIG_XEN - struct physdev_set_iobitmap iobmp_op = { 0 }; + struct physdev_set_iobitmap iobmp_op; + memset(&iobmp_op, 0, sizeof(iobmp_op)); #endif kfree(t->io_bitmap_ptr); @@ -540,7 +541,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) } if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) { - iobmp_op.bitmap = (char *)next->io_bitmap_ptr; + set_xen_guest_handle(iobmp_op.bitmap, + (char *)next->io_bitmap_ptr); iobmp_op.nr_ports = next->io_bitmap_ptr ? IO_BITMAP_BITS : 0; mcl->op = __HYPERVISOR_physdev_op; mcl->args[0] = PHYSDEVOP_set_iobitmap; diff --git a/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c b/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c index de7c80dfb8..40bd5d235e 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c @@ -597,8 +597,10 @@ void __init xen_init_pt(void) early_make_page_readonly(level2_kernel_pgt, XENFEAT_writable_page_tables); - xen_pgd_pin(__pa_symbol(init_level4_pgt)); - xen_pgd_pin(__pa_symbol(init_level4_user_pgt)); + if (!xen_feature(XENFEAT_writable_page_tables)) { + xen_pgd_pin(__pa_symbol(init_level4_pgt)); + xen_pgd_pin(__pa_symbol(init_level4_user_pgt)); + } set_pgd((pgd_t *)(init_level4_user_pgt + 511), mk_kernel_pgd(__pa_symbol(level3_user_pgt))); diff --git a/linux-2.6-xen-sparse/arch/x86_64/mm/pageattr-xen.c b/linux-2.6-xen-sparse/arch/x86_64/mm/pageattr-xen.c index ae434e6be4..3b5fc26e84 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/mm/pageattr-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/mm/pageattr-xen.c @@ -79,14 +79,17 @@ void mm_pin(struct mm_struct *mm) spin_lock(&mm->page_table_lock); mm_walk(mm, PAGE_KERNEL_RO); - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)mm->pgd, - pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL_RO), - UVMF_TLB_FLUSH)); - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)__user_pgd(mm->pgd), - pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, PAGE_KERNEL_RO), - UVMF_TLB_FLUSH)); + if (HYPERVISOR_update_va_mapping( + (unsigned long)mm->pgd, + pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL_RO), + UVMF_TLB_FLUSH)) + BUG(); + if (HYPERVISOR_update_va_mapping( + (unsigned long)__user_pgd(mm->pgd), + pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, + PAGE_KERNEL_RO), + UVMF_TLB_FLUSH)) + BUG(); xen_pgd_pin(__pa(mm->pgd)); /* kernel */ xen_pgd_pin(__pa(__user_pgd(mm->pgd))); /* user */ mm->context.pinned = 1; @@ -106,12 +109,15 @@ void mm_unpin(struct mm_struct *mm) xen_pgd_unpin(__pa(mm->pgd)); xen_pgd_unpin(__pa(__user_pgd(mm->pgd))); - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)mm->pgd, - pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL), 0)); - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)__user_pgd(mm->pgd), - pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, PAGE_KERNEL), 0)); + if (HYPERVISOR_update_va_mapping( + (unsigned long)mm->pgd, + pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL), 0)) + BUG(); + if (HYPERVISOR_update_va_mapping( + (unsigned long)__user_pgd(mm->pgd), + pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, + PAGE_KERNEL), 0)) + BUG(); mm_walk(mm, PAGE_KERNEL); xen_tlb_flush(); mm->context.pinned = 0; @@ -127,43 +133,50 @@ void mm_pin_all(void) if (xen_feature(XENFEAT_writable_page_tables)) return; + /* + * Allow uninterrupted access to the mm_unpinned list. We don't + * actually take the mm_unpinned_lock as it is taken inside mm_pin(). + * All other CPUs must be at a safe point (e.g., in stop_machine + * or offlined entirely). + */ + preempt_disable(); while (!list_empty(&mm_unpinned)) mm_pin(list_entry(mm_unpinned.next, struct mm_struct, context.unpinned)); + preempt_enable(); } void _arch_dup_mmap(struct mm_struct *mm) { - if (!mm->context.pinned) - mm_pin(mm); + if (!mm->context.pinned) + mm_pin(mm); } void _arch_exit_mmap(struct mm_struct *mm) { - struct task_struct *tsk = current; + struct task_struct *tsk = current; - task_lock(tsk); + task_lock(tsk); - /* - * We aggressively remove defunct pgd from cr3. We execute unmap_vmas() - * *much* faster this way, as no tlb flushes means bigger wrpt batches. - */ - if ( tsk->active_mm == mm ) - { - tsk->active_mm = &init_mm; - atomic_inc(&init_mm.mm_count); + /* + * We aggressively remove defunct pgd from cr3. We execute unmap_vmas() + * *much* faster this way, as no tlb flushes means bigger wrpt batches. + */ + if (tsk->active_mm == mm) { + tsk->active_mm = &init_mm; + atomic_inc(&init_mm.mm_count); - switch_mm(mm, &init_mm, tsk); + switch_mm(mm, &init_mm, tsk); - atomic_dec(&mm->mm_count); - BUG_ON(atomic_read(&mm->mm_count) == 0); - } + atomic_dec(&mm->mm_count); + BUG_ON(atomic_read(&mm->mm_count) == 0); + } - task_unlock(tsk); + task_unlock(tsk); - if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) && - !mm->context.has_foreign_mappings ) - mm_unpin(mm); + if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) && + !mm->context.has_foreign_mappings ) + mm_unpin(mm); } struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) @@ -183,8 +196,9 @@ void pte_free(struct page *pte) unsigned long va = (unsigned long)__va(page_to_pfn(pte)<tpmvd = tvd; vtpms->tpm_private = tp; chip = tpm_register_hardware(dev, &tpm_vtpm); diff --git a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_vtpm.h b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_vtpm.h index 27dba1a51d..77aa342baa 100644 --- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_vtpm.h +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_vtpm.h @@ -4,16 +4,6 @@ struct tpm_chip; struct tpm_private; -struct tpm_virtual_device { - /* - * This field indicates the maximum size the driver can - * transfer in one chunk. It is filled in by the front-end - * driver and should be propagated to the generic tpm driver - * for allocation of buffers. - */ - unsigned int max_tx_size; -}; - struct vtpm_state { struct transmission *current_request; spinlock_t req_list_lock; @@ -30,8 +20,6 @@ struct vtpm_state { unsigned long disconnect_time; - struct tpm_virtual_device *tpmvd; - /* * The following is a private structure of the underlying * driver. It is passed as parameter in the send function. @@ -51,7 +39,6 @@ int vtpm_vd_send(struct tpm_private * tp, /* these functions are offered by tpm_vtpm.c */ struct tpm_chip *init_vtpm(struct device *, - struct tpm_virtual_device *, struct tpm_private *); void cleanup_vtpm(struct device *); int vtpm_vd_recv(const struct tpm_chip* chip, diff --git a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c index 8b62b07724..5488217463 100644 --- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c @@ -369,10 +369,6 @@ static void backend_changed(struct xenbus_device *dev, } } -struct tpm_virtual_device tvd = { - .max_tx_size = PAGE_SIZE * TPMIF_TX_RING_SIZE, -}; - static int tpmfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { @@ -383,7 +379,7 @@ static int tpmfront_probe(struct xenbus_device *dev, if (!tp) return -ENOMEM; - tp->chip = init_vtpm(&dev->dev, &tvd, tp); + tp->chip = init_vtpm(&dev->dev, tp); if (IS_ERR(tp->chip)) return PTR_ERR(tp->chip); @@ -500,11 +496,6 @@ static void __init init_tpm_xenbus(void) xenbus_register_frontend(&tpmfront); } -static void __exit exit_tpm_xenbus(void) -{ - xenbus_unregister_driver(&tpmfront); -} - static int tpmif_allocate_tx_buffers(struct tpm_private *tp) { unsigned int i; @@ -530,13 +521,11 @@ static void tpmif_free_tx_buffers(struct tpm_private *tp) static void tpmif_rx_action(unsigned long priv) { struct tpm_private *tp = (struct tpm_private *)priv; - int i = 0; unsigned int received; unsigned int offset = 0; u8 *buffer; - tpmif_tx_request_t *tx; - tx = &tp->tx->ring[i].req; + tpmif_tx_request_t *tx = &tp->tx->ring[i].req; atomic_set(&tp->tx_busy, 0); wake_up_interruptible(&tp->wait_q); @@ -545,7 +534,7 @@ static void tpmif_rx_action(unsigned long priv) buffer = kmalloc(received, GFP_ATOMIC); if (!buffer) - goto exit; + return; for (i = 0; i < TPMIF_TX_RING_SIZE && offset < received; i++) { struct tx_buffer *txb = tp->tx_buffers[i]; @@ -566,10 +555,6 @@ static void tpmif_rx_action(unsigned long priv) vtpm_vd_recv(tp->chip, buffer, received, tp->tx_remember); kfree(buffer); - -exit: - - return; } @@ -730,13 +715,6 @@ static int __init tpmif_init(void) } -void __exit tpmif_exit(void) -{ - exit_tpm_xenbus(); - tpm_private_put(); - gnttab_free_grant_references(gref_head); -} - module_init(tpmif_init); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/linux-2.6-xen-sparse/drivers/xen/Kconfig b/linux-2.6-xen-sparse/drivers/xen/Kconfig index 019256771c..71ba9f264d 100644 --- a/linux-2.6-xen-sparse/drivers/xen/Kconfig +++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig @@ -13,7 +13,7 @@ config XEN if XEN config XEN_INTERFACE_VERSION hex - default 0x00030203 + default 0x00030205 menu "XEN" @@ -227,6 +227,9 @@ choice config XEN_COMPAT_030002_AND_LATER bool "3.0.2 and later" + config XEN_COMPAT_030004_AND_LATER + bool "3.0.4 and later" + config XEN_COMPAT_LATEST_ONLY bool "no compatibility code" @@ -236,6 +239,10 @@ config XEN_COMPAT_030002 bool default XEN_COMPAT_030002_AND_LATER +config XEN_COMPAT_030004 + bool + default XEN_COMPAT_030002_AND_LATER || XEN_COMPAT_030004_AND_LATER + endmenu config HAVE_IRQ_IGNORE_UNHANDLED diff --git a/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c index 1b4bda2184..5fa4c31a9b 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c @@ -299,7 +299,9 @@ static void tap_backend_changed(struct xenbus_watch *watch, * and disk info to xenstore */ err = xenbus_gather(XBT_NIL, dev->nodename, "info", "%lu", &info, - NULL); + NULL); + if (XENBUS_EXIST_ERR(err)) + return; if (err) { xenbus_dev_error(dev, err, "getting info"); return; diff --git a/linux-2.6-xen-sparse/drivers/xen/char/mem.c b/linux-2.6-xen-sparse/drivers/xen/char/mem.c index 4fba735afa..7e857b222e 100644 --- a/linux-2.6-xen-sparse/drivers/xen/char/mem.c +++ b/linux-2.6-xen-sparse/drivers/xen/char/mem.c @@ -27,7 +27,7 @@ #include #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE -static inline int valid_phys_addr_range(unsigned long addr, size_t *count) +static inline int valid_phys_addr_range(unsigned long addr, size_t count) { return 1; } @@ -44,7 +44,7 @@ static ssize_t read_mem(struct file * file, char __user * buf, ssize_t read = 0, sz; void __iomem *v; - if (!valid_phys_addr_range(p, &count)) + if (!valid_phys_addr_range(p, count)) return -EFAULT; while (count > 0) { @@ -95,7 +95,7 @@ static ssize_t write_mem(struct file * file, const char __user * buf, ssize_t written = 0, sz; void __iomem *v; - if (!valid_phys_addr_range(p, &count)) + if (!valid_phys_addr_range(p, count)) return -EFAULT; while (count > 0) { diff --git a/linux-2.6-xen-sparse/drivers/xen/console/console.c b/linux-2.6-xen-sparse/drivers/xen/console/console.c index 78fbc79940..1053ef8ff1 100644 --- a/linux-2.6-xen-sparse/drivers/xen/console/console.c +++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c @@ -348,8 +348,11 @@ void xencons_rx(char *buf, unsigned len, struct pt_regs *regs) #ifdef CONFIG_MAGIC_SYSRQ if (sysrq_enabled) { if (buf[i] == '\x0f') { /* ^O */ - sysrq_requested = jiffies; - continue; /* don't print the sysrq key */ + if (!sysrq_requested) { + sysrq_requested = jiffies; + continue; /* don't print sysrq key */ + } + sysrq_requested = 0; } else if (sysrq_requested) { unsigned long sysrq_timeout = sysrq_requested + HZ*2; diff --git a/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c b/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c index 72efdce56f..6f6ac97195 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c +++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -85,7 +84,7 @@ static void post_suspend(int suspend_cancelled) pfn_to_mfn(xen_start_info->console.domU.mfn); } else { #ifdef CONFIG_SMP - cpu_initialized_map = cpumask_of_cpu(0); + cpu_initialized_map = cpu_online_map; #endif } @@ -181,20 +180,6 @@ static int take_machine_down(void *p_fast_suspend) time_resume(); local_irq_enable(); - if (fast_suspend && !suspend_cancelled) { - /* - * In fast-suspend mode the APs may not be brought back online - * when we resume. In that case we do it here. - */ - for_each_online_cpu(cpu) { - if (cpu == 0) - continue; - cpu_set_initialized(cpu); - err = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL); - BUG_ON(err); - } - } - return suspend_cancelled; } diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index b05e3000e3..98072726cb 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -110,6 +110,7 @@ static unsigned int alloc_index = 0; static inline unsigned long alloc_mfn(void) { + BUG_ON(alloc_index == 0); return mfn_list[--alloc_index]; } @@ -552,6 +553,7 @@ static void net_rx_action(unsigned long unused) *(int *)skb->cb = nr_frags; if (!xen_feature(XENFEAT_auto_translated_physmap) && + !((netif_t *)netdev_priv(skb->dev))->copying_receiver && check_mfn(nr_frags + 1)) { /* Memory squeeze? Back off for an arbitrary while. */ if ( net_ratelimit() ) @@ -1265,7 +1267,7 @@ static void net_tx_action(unsigned long unused) /* Check the remap error code. */ if (unlikely(netbk_tx_check_mop(skb, &mop))) { - printk(KERN_ALERT "#### netback grant fails\n"); + DPRINTK("netback grant failed.\n"); skb_shinfo(skb)->nr_frags = 0; kfree_skb(skb); continue; diff --git a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c index 9eee88cd07..4c99534bb3 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space.c @@ -349,17 +349,13 @@ void pciback_config_free_dev(struct pci_dev *dev) int pciback_config_add_field_offset(struct pci_dev *dev, struct config_field *field, - unsigned int offset) + unsigned int base_offset) { int err = 0; struct pciback_dev_data *dev_data = pci_get_drvdata(dev); struct config_field_entry *cfg_entry; void *tmp; - /* silently ignore duplicate fields */ - if (pciback_field_is_dup(dev, field->offset)) - goto out; - cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL); if (!cfg_entry) { err = -ENOMEM; @@ -368,7 +364,12 @@ int pciback_config_add_field_offset(struct pci_dev *dev, cfg_entry->data = NULL; cfg_entry->field = field; - cfg_entry->base_offset = offset; + cfg_entry->base_offset = base_offset; + + /* silently ignore duplicate fields */ + err = pciback_field_is_dup(dev,OFFSET(cfg_entry)); + if (err) + goto out; if (field->init) { tmp = field->init(dev, OFFSET(cfg_entry)); diff --git a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.c b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.c index 4ec0c78b89..525ec95c65 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.c +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.c @@ -32,16 +32,14 @@ static inline void register_quirk(struct pciback_config_quirk *quirk) list_add_tail(&quirk->quirks_list, &pciback_quirks); } -int pciback_field_is_dup(struct pci_dev *dev, int reg) +int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg) { int ret = 0; struct pciback_dev_data *dev_data = pci_get_drvdata(dev); - struct config_field *field; struct config_field_entry *cfg_entry; list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { - field = cfg_entry->field; - if (field->offset == reg) { + if ( OFFSET(cfg_entry) == reg) { ret = 1; break; } diff --git a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.h b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.h index 5c47e1269b..acd0e1ae8f 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.h +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/conf_space_quirks.h @@ -30,6 +30,6 @@ void pciback_config_field_free(struct config_field *field); int pciback_config_quirk_release(struct pci_dev *dev); -int pciback_field_is_dup(struct pci_dev *dev, int reg); +int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg); #endif diff --git a/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c index b33855932d..7d2118226b 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c @@ -589,10 +589,6 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg, } dev = psdev->dev; - /* check for duplicate field */ - if (pciback_field_is_dup(dev, reg)) - goto out; - field = kzalloc(sizeof(*field), GFP_ATOMIC); if (!field) { err = -ENOMEM; @@ -728,10 +724,10 @@ static ssize_t pcistub_quirk_show(struct device_driver *drv, char *buf) if (count >= PAGE_SIZE) goto out; - count += scnprintf(buf + count, PAGE_SIZE - - count, "\t\t%08x:%01x:%08x\n", - field->offset, field->size, - field->mask); + count += scnprintf(buf + count, PAGE_SIZE - count, + "\t\t%08x:%01x:%08x\n", + cfg_entry->base_offset + field->offset, + field->size, field->mask); } } diff --git a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c index 46414068c1..0defc39d69 100644 --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @@ -28,7 +28,6 @@ #include #include #include -#include #include static struct proc_dir_entry *privcmd_intf; diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c index c00aaf7f6f..2521b8203d 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c @@ -110,7 +110,6 @@ int xb_write(const void *data, unsigned len) /* Read indexes, then verify. */ cons = intf->req_cons; prod = intf->req_prod; - mb(); if (!check_indexes(cons, prod)) { intf->req_cons = intf->req_prod = 0; return -EIO; @@ -122,15 +121,18 @@ int xb_write(const void *data, unsigned len) if (avail > len) avail = len; + /* Must write data /after/ reading the consumer index. */ + mb(); + memcpy(dst, data, avail); data += avail; len -= avail; - /* Other side must not see new header until data is there. */ + /* Other side must not see new producer until data is there. */ wmb(); intf->req_prod += avail; - /* This implies mb() before other side sees interrupt. */ + /* Implies mb(): other side will see the updated producer. */ notify_remote_via_evtchn(xen_store_evtchn); } @@ -165,7 +167,6 @@ int xb_read(void *data, unsigned len) /* Read indexes, then verify. */ cons = intf->rsp_cons; prod = intf->rsp_prod; - mb(); if (!check_indexes(cons, prod)) { intf->rsp_cons = intf->rsp_prod = 0; return -EIO; @@ -177,7 +178,7 @@ int xb_read(void *data, unsigned len) if (avail > len) avail = len; - /* We must read header before we read data. */ + /* Must read data /after/ reading the producer index. */ rmb(); memcpy(data, src, avail); @@ -190,7 +191,7 @@ int xb_read(void *data, unsigned len) pr_debug("Finished read of %i bytes (%i to go)\n", avail, len); - /* Implies mb(): they will see new header. */ + /* Implies mb(): other side will see the updated consumer. */ notify_remote_via_evtchn(xen_store_evtchn); } diff --git a/linux-2.6-xen-sparse/include/asm-i386/kexec.h b/linux-2.6-xen-sparse/include/asm-i386/kexec.h index 4610897c78..abddf7b4d2 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/kexec.h +++ b/linux-2.6-xen-sparse/include/asm-i386/kexec.h @@ -47,6 +47,9 @@ /* The native architecture */ #define KEXEC_ARCH KEXEC_ARCH_386 +/* We can also handle crash dumps from 64 bit kernel. */ +#define vmcore_elf_check_arch_cross(x) ((x)->e_machine == EM_X86_64) + #define MAX_NOTE_BYTES 1024 /* CPU does not save ss and esp on stack if execution is already diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h index c3ed3584b6..e50fd5a9a2 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h @@ -201,11 +201,11 @@ HYPERVISOR_set_timer_op( } static inline int -HYPERVISOR_dom0_op( - dom0_op_t *dom0_op) +HYPERVISOR_platform_op( + struct xen_platform_op *platform_op) { - dom0_op->interface_version = DOM0_INTERFACE_VERSION; - return _hypercall1(int, dom0_op, dom0_op); + platform_op->interface_version = XENPF_INTERFACE_VERSION; + return _hypercall1(int, platform_op, platform_op); } static inline int diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h index 5797dcc696..9bc4554b96 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h index 584f65e178..14c1d27629 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pci.h @@ -143,11 +143,4 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev, /* generic pci stuff */ #include -/* On Xen we have to scan all functions since Xen hides bridges from - * us. If a bridge is at fn=0 and that slot has a multifunction - * device, we won't find the additional devices without scanning all - * functions. */ -#undef pcibios_scan_all_fns -#define pcibios_scan_all_fns(a, b) 1 - #endif /* __i386_PCI_H */ diff --git a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h index 9ae66fe781..ee4d0ce604 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h @@ -120,9 +120,9 @@ HYPERVISOR_set_timer_op(u64 timeout) } static inline int -xencomm_arch_hypercall_dom0_op(struct xencomm_handle *op) +xencomm_arch_hypercall_platform_op(struct xencomm_handle *op) { - return _hypercall1(int, dom0_op, op); + return _hypercall1(int, platform_op, op); } static inline int diff --git a/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h b/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h index 4cfea9a769..712778213d 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h @@ -51,7 +51,7 @@ extern int running_on_xen; #include #include #include -#include +#include #include #include #include diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h index 5c6c8deff6..9279217762 100644 --- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h @@ -204,11 +204,11 @@ HYPERVISOR_set_timer_op( } static inline int -HYPERVISOR_dom0_op( - dom0_op_t *dom0_op) +HYPERVISOR_platform_op( + struct xen_platform_op *platform_op) { - dom0_op->interface_version = DOM0_INTERFACE_VERSION; - return _hypercall1(int, dom0_op, dom0_op); + platform_op->interface_version = XENPF_INTERFACE_VERSION; + return _hypercall1(int, platform_op, platform_op); } static inline int diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pci.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pci.h index 8ec15d931e..764270fa4f 100644 --- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pci.h +++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pci.h @@ -163,11 +163,4 @@ static inline void pcibios_add_platform_entries(struct pci_dev *dev) #include #endif -/* On Xen we have to scan all functions since Xen hides bridges from - * us. If a bridge is at fn=0 and that slot has a multifunction - * device, we won't find the additional devices without scanning all - * functions. */ -#undef pcibios_scan_all_fns -#define pcibios_scan_all_fns(a, b) 1 - #endif /* __x8664_PCI_H */ diff --git a/linux-2.6-xen-sparse/kernel/kexec.c b/linux-2.6-xen-sparse/kernel/kexec.c index c46558f7da..a6e2120138 100644 --- a/linux-2.6-xen-sparse/kernel/kexec.c +++ b/linux-2.6-xen-sparse/kernel/kexec.c @@ -330,13 +330,27 @@ static int kimage_is_destination_range(struct kimage *image, return 0; } -static struct page *kimage_alloc_pages(gfp_t gfp_mask, unsigned int order) +static struct page *kimage_alloc_pages(gfp_t gfp_mask, unsigned int order, unsigned long limit) { struct page *pages; pages = alloc_pages(gfp_mask, order); if (pages) { unsigned int count, i; +#ifdef CONFIG_XEN + int address_bits; + + if (limit == ~0UL) + address_bits = BITS_PER_LONG; + else + address_bits = long_log2(limit); + + if (xen_create_contiguous_region((unsigned long)page_address(pages), + order, address_bits) < 0) { + __free_pages(pages, order); + return NULL; + } +#endif pages->mapping = NULL; set_page_private(pages, order); count = 1 << order; @@ -355,6 +369,9 @@ static void kimage_free_pages(struct page *page) count = 1 << order; for (i = 0; i < count; i++) ClearPageReserved(page + i); +#ifdef CONFIG_XEN + xen_destroy_contiguous_region((unsigned long)page_address(page), order); +#endif __free_pages(page, order); } @@ -400,7 +417,7 @@ static struct page *kimage_alloc_normal_control_pages(struct kimage *image, do { unsigned long pfn, epfn, addr, eaddr; - pages = kimage_alloc_pages(GFP_KERNEL, order); + pages = kimage_alloc_pages(GFP_KERNEL, order, KEXEC_CONTROL_MEMORY_LIMIT); if (!pages) break; pfn = kexec_page_to_pfn(pages); @@ -709,7 +726,7 @@ static struct page *kimage_alloc_page(struct kimage *image, kimage_entry_t *old; /* Allocate a page, if we run out of memory give up */ - page = kimage_alloc_pages(gfp_mask, 0); + page = kimage_alloc_pages(gfp_mask, 0, KEXEC_SOURCE_MEMORY_LIMIT); if (!page) return NULL; /* If the page cannot be used file it away */ diff --git a/linux-2.6-xen-sparse/mm/Kconfig b/linux-2.6-xen-sparse/mm/Kconfig new file mode 100644 index 0000000000..14492aaa5b --- /dev/null +++ b/linux-2.6-xen-sparse/mm/Kconfig @@ -0,0 +1,157 @@ +config SELECT_MEMORY_MODEL + def_bool y + depends on EXPERIMENTAL || ARCH_SELECT_MEMORY_MODEL + +choice + prompt "Memory model" + depends on SELECT_MEMORY_MODEL + default DISCONTIGMEM_MANUAL if ARCH_DISCONTIGMEM_DEFAULT + default SPARSEMEM_MANUAL if ARCH_SPARSEMEM_DEFAULT + default FLATMEM_MANUAL + +config FLATMEM_MANUAL + bool "Flat Memory" + depends on !(ARCH_DISCONTIGMEM_ENABLE || ARCH_SPARSEMEM_ENABLE) || ARCH_FLATMEM_ENABLE + help + This option allows you to change some of the ways that + Linux manages its memory internally. Most users will + only have one option here: FLATMEM. This is normal + and a correct option. + + Some users of more advanced features like NUMA and + memory hotplug may have different options here. + DISCONTIGMEM is an more mature, better tested system, + but is incompatible with memory hotplug and may suffer + decreased performance over SPARSEMEM. If unsure between + "Sparse Memory" and "Discontiguous Memory", choose + "Discontiguous Memory". + + If unsure, choose this option (Flat Memory) over any other. + +config DISCONTIGMEM_MANUAL + bool "Discontiguous Memory" + depends on ARCH_DISCONTIGMEM_ENABLE + help + This option provides enhanced support for discontiguous + memory systems, over FLATMEM. These systems have holes + in their physical address spaces, and this option provides + more efficient handling of these holes. However, the vast + majority of hardware has quite flat address spaces, and + can have degraded performance from extra overhead that + this option imposes. + + Many NUMA configurations will have this as the only option. + + If unsure, choose "Flat Memory" over this option. + +config SPARSEMEM_MANUAL + bool "Sparse Memory" + depends on ARCH_SPARSEMEM_ENABLE + help + This will be the only option for some systems, including + memory hotplug systems. This is normal. + + For many other systems, this will be an alternative to + "Discontiguous Memory". This option provides some potential + performance benefits, along with decreased code complexity, + but it is newer, and more experimental. + + If unsure, choose "Discontiguous Memory" or "Flat Memory" + over this option. + +endchoice + +config DISCONTIGMEM + def_bool y + depends on (!SELECT_MEMORY_MODEL && ARCH_DISCONTIGMEM_ENABLE) || DISCONTIGMEM_MANUAL + +config SPARSEMEM + def_bool y + depends on SPARSEMEM_MANUAL + +config FLATMEM + def_bool y + depends on (!DISCONTIGMEM && !SPARSEMEM) || FLATMEM_MANUAL + +config FLAT_NODE_MEM_MAP + def_bool y + depends on !SPARSEMEM + +# +# Both the NUMA code and DISCONTIGMEM use arrays of pg_data_t's +# to represent different areas of memory. This variable allows +# those dependencies to exist individually. +# +config NEED_MULTIPLE_NODES + def_bool y + depends on DISCONTIGMEM || NUMA + +config HAVE_MEMORY_PRESENT + def_bool y + depends on ARCH_HAVE_MEMORY_PRESENT || SPARSEMEM + +# +# SPARSEMEM_EXTREME (which is the default) does some bootmem +# allocations when memory_present() is called. If this can not +# be done on your architecture, select this option. However, +# statically allocating the mem_section[] array can potentially +# consume vast quantities of .bss, so be careful. +# +# This option will also potentially produce smaller runtime code +# with gcc 3.4 and later. +# +config SPARSEMEM_STATIC + def_bool n + +# +# Architectecture platforms which require a two level mem_section in SPARSEMEM +# must select this option. This is usually for architecture platforms with +# an extremely sparse physical address space. +# +config SPARSEMEM_EXTREME + def_bool y + depends on SPARSEMEM && !SPARSEMEM_STATIC + +# eventually, we can have this option just 'select SPARSEMEM' +config MEMORY_HOTPLUG + bool "Allow for memory hot-add" + depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG + depends on (IA64 || X86 || PPC64) + +comment "Memory hotplug is currently incompatible with Software Suspend" + depends on SPARSEMEM && HOTPLUG && SOFTWARE_SUSPEND + +# Heavily threaded applications may benefit from splitting the mm-wide +# page_table_lock, so that faults on different parts of the user address +# space can be handled with less contention: split it at this NR_CPUS. +# Default to 4 for wider testing, though 8 might be more appropriate. +# ARM's adjust_pte (unused if VIPT) depends on mm-wide page_table_lock. +# PA-RISC 7xxx's spinlock_t would enlarge struct page from 32 to 44 bytes. +# XEN on x86 architecture uses the mapping field on pagetable pages to store a +# pointer to the destructor. This conflicts with pte_lock_deinit(). +# +config SPLIT_PTLOCK_CPUS + int + default "4096" if ARM && !CPU_CACHE_VIPT + default "4096" if PARISC && !PA20 + default "4096" if X86_XEN || X86_64_XEN + default "4" + +# +# support for page migration +# +config MIGRATION + bool "Page migration" + def_bool y + depends on NUMA + help + Allows the migration of the physical location of pages of processes + while the virtual addresses are not changed. This is useful for + example on NUMA systems to put pages nearer to the processors accessing + the page. + +config RESOURCES_64BIT + bool "64 bit Memory and IO resources (EXPERIMENTAL)" if (!64BIT && EXPERIMENTAL) + default 64BIT + help + This option allows memory and IO resources to be 64 bit. diff --git a/patches/linux-2.6.18/allow-i386-crash-kernels-to-handle-x86_64-dumps-fix.patch b/patches/linux-2.6.18/allow-i386-crash-kernels-to-handle-x86_64-dumps-fix.patch new file mode 100644 index 0000000000..2d60059ca7 --- /dev/null +++ b/patches/linux-2.6.18/allow-i386-crash-kernels-to-handle-x86_64-dumps-fix.patch @@ -0,0 +1,30 @@ +From: Andrew Morton + +In file included from arch/i386/kernel/setup.c:46: +include/linux/crash_dump.h:19:36: warning: extra tokens at end of #ifndef directive + +Cc: "Eric W. Biederman" +Cc: Andi Kleen +Cc: Horms +Cc: Ian Campbell +Cc: Magnus Damm +Cc: Vivek Goyal +Signed-off-by: Andrew Morton +--- + + include/linux/crash_dump.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff -puN include/linux/crash_dump.h~allow-i386-crash-kernels-to-handle-x86_64-dumps-fix include/linux/crash_dump.h +--- a/include/linux/crash_dump.h~allow-i386-crash-kernels-to-handle-x86_64-dumps-fix ++++ a/include/linux/crash_dump.h +@@ -16,7 +16,7 @@ extern struct proc_dir_entry *proc_vmcor + + /* Architecture code defines this if there are other possible ELF + * machine types, e.g. on bi-arch capable hardware. */ +-#ifndef vmcore_elf_check_arch_cross(x) ++#ifndef vmcore_elf_check_arch_cross + #define vmcore_elf_check_arch_cross(x) 0 + #endif + +_ diff --git a/patches/linux-2.6.18/allow-i386-crash-kernels-to-handle-x86_64-dumps.patch b/patches/linux-2.6.18/allow-i386-crash-kernels-to-handle-x86_64-dumps.patch new file mode 100644 index 0000000000..ad9eb93b3b --- /dev/null +++ b/patches/linux-2.6.18/allow-i386-crash-kernels-to-handle-x86_64-dumps.patch @@ -0,0 +1,66 @@ +From: Ian Campbell + +The specific case I am encountering is kdump under Xen with a 64 bit +hypervisor and 32 bit kernel/userspace. The dump created is 64 bit due to +the hypervisor but the dump kernel is 32 bit for maximum compatibility. + +It's possibly less likely to be useful in a purely native scenario but I +see no reason to disallow it. + +Signed-off-by: Ian Campbell +Acked-by: Vivek Goyal +Cc: Horms +Cc: Magnus Damm +Cc: "Eric W. Biederman" +Cc: Andi Kleen +Signed-off-by: Andrew Morton +--- + + fs/proc/vmcore.c | 2 +- + include/asm-i386/kexec.h | 3 +++ + include/linux/crash_dump.h | 8 ++++++++ + 3 files changed, 12 insertions(+), 1 deletion(-) + +diff -puN fs/proc/vmcore.c~allow-i386-crash-kernels-to-handle-x86_64-dumps fs/proc/vmcore.c +--- a/fs/proc/vmcore.c~allow-i386-crash-kernels-to-handle-x86_64-dumps ++++ a/fs/proc/vmcore.c +@@ -514,7 +514,7 @@ static int __init parse_crash_elf64_head + /* Do some basic Verification. */ + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || + (ehdr.e_type != ET_CORE) || +- !elf_check_arch(&ehdr) || ++ !vmcore_elf_check_arch(&ehdr) || + ehdr.e_ident[EI_CLASS] != ELFCLASS64 || + ehdr.e_ident[EI_VERSION] != EV_CURRENT || + ehdr.e_version != EV_CURRENT || +diff -puN include/asm-i386/kexec.h~allow-i386-crash-kernels-to-handle-x86_64-dumps include/asm-i386/kexec.h +--- a/include/asm-i386/kexec.h~allow-i386-crash-kernels-to-handle-x86_64-dumps ++++ a/include/asm-i386/kexec.h +@@ -47,6 +47,9 @@ + /* The native architecture */ + #define KEXEC_ARCH KEXEC_ARCH_386 + ++/* We can also handle crash dumps from 64 bit kernel. */ ++#define vmcore_elf_check_arch_cross(x) ((x)->e_machine == EM_X86_64) ++ + #define MAX_NOTE_BYTES 1024 + + /* CPU does not save ss and esp on stack if execution is already +diff -puN include/linux/crash_dump.h~allow-i386-crash-kernels-to-handle-x86_64-dumps include/linux/crash_dump.h +--- a/include/linux/crash_dump.h~allow-i386-crash-kernels-to-handle-x86_64-dumps ++++ a/include/linux/crash_dump.h +@@ -14,5 +14,13 @@ extern ssize_t copy_oldmem_page(unsigned + extern const struct file_operations proc_vmcore_operations; + extern struct proc_dir_entry *proc_vmcore; + ++/* Architecture code defines this if there are other possible ELF ++ * machine types, e.g. on bi-arch capable hardware. */ ++#ifndef vmcore_elf_check_arch_cross(x) ++#define vmcore_elf_check_arch_cross(x) 0 ++#endif ++ ++#define vmcore_elf_check_arch(x) (elf_check_arch(x) || vmcore_elf_check_arch_cross(x)) ++ + #endif /* CONFIG_CRASH_DUMP */ + #endif /* LINUX_CRASHDUMP_H */ +_ diff --git a/patches/linux-2.6.18/series b/patches/linux-2.6.18/series index 85bbae63e4..a3597cd5a0 100644 --- a/patches/linux-2.6.18/series +++ b/patches/linux-2.6.18/series @@ -19,3 +19,5 @@ x86-elfnote-as-preprocessor-macro.patch fixaddr-top.patch git-c06cb8b1c4d25e5b4d7a2d7c2462619de1e0dbc4.patch softlockup-no-idle-hz.patch +allow-i386-crash-kernels-to-handle-x86_64-dumps.patch +allow-i386-crash-kernels-to-handle-x86_64-dumps-fix.patch diff --git a/patches/linux-2.6.18/softlockup-no-idle-hz.patch b/patches/linux-2.6.18/softlockup-no-idle-hz.patch index 6799bfc4bf..d98edac8f2 100644 --- a/patches/linux-2.6.18/softlockup-no-idle-hz.patch +++ b/patches/linux-2.6.18/softlockup-no-idle-hz.patch @@ -34,7 +34,7 @@ diff -pruN ../orig-linux-2.6.18/kernel/softlockup.c ./kernel/softlockup.c + !per_cpu(watchdog_task, this_cpu)) + return MAX_JIFFY_OFFSET; + -+ return min_t(long, 0, touch_timestamp + HZ - jiffies); ++ return max_t(long, 0, touch_timestamp + HZ - jiffies); +} + /* diff --git a/tools/Rules.mk b/tools/Rules.mk index df3b231a1a..3e13eceb55 100644 --- a/tools/Rules.mk +++ b/tools/Rules.mk @@ -23,6 +23,11 @@ LDFLAGS += $(shell getconf LFS_LDFLAGS) CFLAGS-$(CONFIG_X86_32) += $(call cc-option,$(CC),-mno-tls-direct-seg-refs) CFLAGS += $(CFLAGS-y) +# Require GCC v3.4+ (to avoid issues with alignment constraints in Xen headers) +ifeq ($(CONFIG_X86)$(call cc-ver,$(CC),0x030400),yn) +$(error Xen tools require at least gcc-3.4) +endif + %.opic: %.c $(CC) $(CPPFLAGS) -DPIC $(CFLAGS) -fPIC -c -o $@ $< diff --git a/tools/blktap/drivers/block-qcow.c b/tools/blktap/drivers/block-qcow.c index 36f77e6f05..b0822f729d 100644 --- a/tools/blktap/drivers/block-qcow.c +++ b/tools/blktap/drivers/block-qcow.c @@ -1057,6 +1057,7 @@ int tdqcow_queue_write(struct disk_driver *dd, uint64_t sector, index_in_cluster+n); if (!cluster_offset) { DPRINTF("Ooops, no write cluster offset!\n"); + aio_unlock(s, sector); return cb(dd, -EIO, sector, nb_sectors, id, private); } diff --git a/tools/firmware/Makefile b/tools/firmware/Makefile index 8091da46d3..38338471fd 100644 --- a/tools/firmware/Makefile +++ b/tools/firmware/Makefile @@ -14,10 +14,10 @@ SUBDIRS += hvmloader .PHONY: all all: - @set -e; if ! `which bcc 1>/dev/null 2>/dev/null`; then \ + @set -e; if [ $$((`( bcc -v 2>&1 | grep version || echo 0.0.0 ) | cut -d' ' -f 3 | awk -F. '{ printf "0x%02x%02x%02x", $$1, $$2, $$3}'`)) -lt $$((0x00100e)) ] ; then \ echo "***********************************************************"; \ - echo "WARNING: Install dev86 package to build firmware!"; \ - echo " (http://www.cix.co.uk/~mayday)"; \ + echo "Require dev86 package version >= 0.16.14 to build firmware!"; \ + echo "(visit http://www.cix.co.uk/~mayday for more information)"; \ echo "***********************************************************"; \ else \ for subdir in $(SUBDIRS); do \ diff --git a/tools/firmware/hvmloader/32bitbios_support.c b/tools/firmware/hvmloader/32bitbios_support.c index f9274090cc..7cb32a299d 100644 --- a/tools/firmware/hvmloader/32bitbios_support.c +++ b/tools/firmware/hvmloader/32bitbios_support.c @@ -17,158 +17,129 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. */ + #include #include #ifdef __sun__ #include #endif -#include #include "util.h" #include "config.h" #include "../rombios/32bit/32bitbios_flat.h" #include "../rombios/32bit/jumptable.h" - -/* - * relocate ELF file of type ET_REL - */ -static int relocate_elf(unsigned char *elfarray) { +/* Relocate ELF file of type ET_REL */ +static void relocate_elf(char *elfarray) +{ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray; Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff]; - int i; + Elf32_Sym *syms, *sym; + Elf32_Rel *rels; + char *code; + uint32_t *loc, fix; + int i, j; - if (ehdr->e_type != ET_REL) { - printf("Not a relocatable BIOS object file. Has type %d, need %d\n", - ehdr->e_type, ET_REL); - return -1; - } - - for (i = 0; i < ehdr->e_shnum; i++) { - if (!(shdr[i]).sh_flags & SHF_ALLOC) { - shdr[i].sh_addr = 0; - continue; - } + for ( i = 0; i < ehdr->e_shnum; i++ ) shdr[i].sh_addr = (Elf32_Addr)&elfarray[shdr[i].sh_offset]; - } - for (i = 0; i < ehdr->e_shnum; i++) { - if (shdr[i].sh_type == SHT_REL && shdr[i].sh_addr != 0) { - Elf32_Shdr *targetsec = (Elf32_Shdr *)&(shdr[shdr[i].sh_info]); - Elf32_Shdr *symtabsec = (Elf32_Shdr *)&(shdr[shdr[i].sh_link]); - Elf32_Sym *syms = (Elf32_Sym *)symtabsec->sh_addr; - Elf32_Rel *rels = (Elf32_Rel *)shdr[i].sh_addr; - unsigned char *code = (unsigned char *)targetsec->sh_addr; - int j; + for ( i = 0; i < ehdr->e_shnum; i++ ) + { + if ( shdr[i].sh_type == SHT_RELA ) + printf("Unsupported section type SHT_RELA\n"); - for (j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++) { - int idx = ELF32_R_SYM(rels[j].r_info); - Elf32_Sym *symbol = &syms[idx]; - uint32_t *loc = (uint32_t *)&code[rels[j].r_offset]; - uint32_t fix = shdr[symbol->st_shndx].sh_addr + - symbol->st_value; + if ( shdr[i].sh_type != SHT_REL ) + continue; - switch (ELF32_R_TYPE(rels[j].r_info)) { - case R_386_PC32: - *loc += (fix - (uint32_t)loc); - break; + syms = (Elf32_Sym *)shdr[shdr[i].sh_link].sh_addr; + rels = (Elf32_Rel *)shdr[i].sh_addr; + code = (char *)shdr[shdr[i].sh_info].sh_addr; - case R_386_32: - *loc += fix; - break; - } + for ( j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++ ) + { + sym = &syms[ELF32_R_SYM(rels[j].r_info)]; + loc = (uint32_t *)&code[rels[j].r_offset]; + fix = shdr[sym->st_shndx].sh_addr + sym->st_value; + + switch ( ELF32_R_TYPE(rels[j].r_info) ) + { + case R_386_PC32: + *loc += fix - (uint32_t)loc; + break; + + case R_386_32: + *loc += fix; + break; } - } else if (shdr[i].sh_type == SHT_RELA) { - return -2; } } - return 0; } -/* scan the rombios for the destination of the jumptable */ -static char* get_jump_table_start(void) +/* Scan the rombios for the destination of the jump table. */ +static char *get_jump_table_start(void) { char *bios_mem; for ( bios_mem = (char *)ROMBIOS_BEGIN; bios_mem != (char *)ROMBIOS_END; - bios_mem++ ) { - if (strncmp(bios_mem, "___JMPT", 7) == 0) + bios_mem++ ) + if ( !strncmp(bios_mem, "___JMPT", 7) ) return bios_mem; - } return NULL; } -/* copy relocated jumptable into the rombios */ -static int copy_jumptable(unsigned char *elfarray) +/* Copy relocated jumptable into the rombios. */ +static void copy_jumptable(char *elfarray) { - int rc = 0; Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray; Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff]; - Elf32_Shdr *shdr_strings = (Elf32_Shdr *)&shdr[ehdr->e_shstrndx]; - char *secstrings = (char *)&elfarray[shdr_strings->sh_offset]; - uint32_t *rombiosjumptable = (uint32_t *)get_jump_table_start(); - uint32_t *biosjumptable = NULL; + char *secstrings = &elfarray[shdr[ehdr->e_shstrndx].sh_offset]; + char *jump_table = get_jump_table_start(); int i; - if (rombiosjumptable == NULL) { - return -3; - } - - /* find the section with the jump table and copy to lower BIOS memory */ - for (i = 0; i < ehdr->e_shnum; i++) { - if (!strcmp(JUMPTABLE_SECTION_NAME, secstrings + shdr[i].sh_name)) { - uint32_t biosjumptableentries; - biosjumptable = (uint32_t *)shdr[i].sh_addr; - biosjumptableentries = shdr[i].sh_size / 4; - for (int j = 0; j < biosjumptableentries; j++) { - rombiosjumptable[j] = biosjumptable[j]; - if (biosjumptable[j] == 0 && - j < (biosjumptableentries - 1)) { - printf("WARNING: jumptable entry %d is NULL!\n",j); - } - } + /* Find the section with the jump table and copy to lower BIOS memory. */ + for ( i = 0; i < ehdr->e_shnum; i++ ) + if ( !strcmp(JUMPTABLE_SECTION_NAME, secstrings + shdr[i].sh_name) ) break; - } - } - if (biosjumptable == NULL) { + if ( i == ehdr->e_shnum ) + { printf("Could not find " JUMPTABLE_SECTION_NAME " section in file.\n"); - rc = -4; + return; } - return 0; + if ( jump_table == NULL ) + { + printf("Could not find jump table in file.\n"); + return; + } + + memcpy(jump_table, (char *)shdr[i].sh_addr, shdr[i].sh_size); } -static int relocate_32bitbios(unsigned char *elfarray, uint32_t elfarraysize) +static void relocate_32bitbios(char *elfarray, uint32_t elfarraysize) { - int rc = 0; uint32_t mask = (64 * 1024) - 1; - uint32_t to_malloc = (elfarraysize + mask) & ~mask; /* round to 64kb */ - unsigned char *highbiosarea; + char *highbiosarea; - highbiosarea = (unsigned char *)(long) - e820_malloc((uint64_t)to_malloc, - E820_RESERVED, - (uint64_t)0xffffffff); - - if (highbiosarea != 0) { - memcpy(highbiosarea, elfarray, elfarraysize); - rc = relocate_elf(highbiosarea); - if (rc == 0) { - rc = copy_jumptable(highbiosarea); - } - } else { - rc = -5; + highbiosarea = (char *)(long) + e820_malloc((elfarraysize + mask) & ~mask, /* round to 64kb */ + E820_RESERVED, + (uint64_t)0xffffffff); + if ( highbiosarea == NULL ) + { + printf("No available memory for BIOS high memory area\n"); + return; } - return rc; + memcpy(highbiosarea, elfarray, elfarraysize); + relocate_elf(highbiosarea); + copy_jumptable(highbiosarea); } -int highbios_setup(void) +void highbios_setup(void) { - return relocate_32bitbios((unsigned char *)highbios_array, - sizeof(highbios_array)); + relocate_32bitbios((char *)highbios_array, sizeof(highbios_array)); } diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h index 04824f5642..3e8424e138 100644 --- a/tools/firmware/hvmloader/acpi/acpi2_0.h +++ b/tools/firmware/hvmloader/acpi/acpi2_0.h @@ -49,8 +49,8 @@ struct acpi_header { uint32_t length; uint8_t revision; uint8_t checksum; - uint8_t oem_id[6]; - uint8_t oem_table_id[8]; + char oem_id[6]; + char oem_table_id[8]; uint32_t oem_revision; uint32_t creator_id; uint32_t creator_revision; @@ -90,7 +90,7 @@ struct acpi_20_generic_address { struct acpi_10_rsdp { uint64_t signature; uint8_t checksum; - uint8_t oem_id[6]; + char oem_id[6]; uint8_t reserved; uint32_t rsdt_address; }; @@ -101,7 +101,7 @@ struct acpi_10_rsdp { struct acpi_20_rsdp { uint64_t signature; uint8_t checksum; - uint8_t oem_id[6]; + char oem_id[6]; uint8_t revision; uint32_t rsdt_address; uint32_t length; @@ -142,6 +142,51 @@ struct acpi_20_tcpa { }; #define ACPI_2_0_TCPA_LAML_SIZE (64*1024) +/* + * Fixed ACPI Description Table Structure (FADT) in ACPI 1.0. + */ +struct acpi_10_fadt { + struct acpi_header header; + uint32_t firmware_ctrl; + uint32_t dsdt; + uint8_t reserved0; + uint8_t preferred_pm_profile; + uint16_t sci_int; + uint32_t smi_cmd; + uint8_t acpi_enable; + uint8_t acpi_disable; + uint8_t s4bios_req; + uint8_t pstate_cnt; + uint32_t pm1a_evt_blk; + uint32_t pm1b_evt_blk; + uint32_t pm1a_cnt_blk; + uint32_t pm1b_cnt_blk; + uint32_t pm2_cnt_blk; + uint32_t pm_tmr_blk; + uint32_t gpe0_blk; + uint32_t gpe1_blk; + uint8_t pm1_evt_len; + uint8_t pm1_cnt_len; + uint8_t pm2_cnt_len; + uint8_t pm_tmr_len; + uint8_t gpe0_blk_len; + uint8_t gpe1_blk_len; + uint8_t gpe1_base; + uint8_t cst_cnt; + uint16_t p_lvl2_lat; + uint16_t p_lvl3_lat; + uint16_t flush_size; + uint16_t flush_stride; + uint8_t duty_offset; + uint8_t duty_width; + uint8_t day_alrm; + uint8_t mon_alrm; + uint8_t century; + uint16_t iapc_boot_arch; + uint8_t reserved1; + uint32_t flags; +}; + /* * Fixed ACPI Description Table Structure (FADT). */ @@ -345,6 +390,7 @@ struct acpi_20_madt_intsrcovr { #define ACPI_2_0_XSDT_REVISION 0x01 #define ACPI_2_0_TCPA_REVISION 0x02 #define ACPI_2_0_HPET_REVISION 0x01 +#define ACPI_1_0_FADT_REVISION 0x01 #pragma pack () diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c index ff99160612..7be1ea4a71 100644 --- a/tools/firmware/hvmloader/acpi/build.c +++ b/tools/firmware/hvmloader/acpi/build.c @@ -20,9 +20,9 @@ #include "ssdt_tpm.h" #include "../config.h" #include "../util.h" -#include -#define align16(sz) (((sz) + 15) & ~15) +#define align16(sz) (((sz) + 15) & ~15) +#define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d)) extern struct acpi_20_rsdp Rsdp; extern struct acpi_20_rsdt Rsdt; @@ -57,8 +57,8 @@ int construct_madt(struct acpi_20_madt *madt) memset(madt, 0, sizeof(*madt)); madt->header.signature = ACPI_2_0_MADT_SIGNATURE; madt->header.revision = ACPI_2_0_MADT_REVISION; - strncpy(madt->header.oem_id, ACPI_OEM_ID, 6); - strncpy(madt->header.oem_table_id, ACPI_OEM_TABLE_ID, 8); + fixed_strcpy(madt->header.oem_id, ACPI_OEM_ID); + fixed_strcpy(madt->header.oem_table_id, ACPI_OEM_TABLE_ID); madt->header.oem_revision = ACPI_OEM_REVISION; madt->header.creator_id = ACPI_CREATOR_ID; madt->header.creator_revision = ACPI_CREATOR_REVISION; @@ -131,8 +131,8 @@ int construct_hpet(struct acpi_20_hpet *hpet) memset(hpet, 0, sizeof(*hpet)); hpet->header.signature = ACPI_2_0_HPET_SIGNATURE; hpet->header.revision = ACPI_2_0_HPET_REVISION; - strncpy(hpet->header.oem_id, ACPI_OEM_ID, 6); - strncpy(hpet->header.oem_table_id, ACPI_OEM_TABLE_ID, 8); + fixed_strcpy(hpet->header.oem_id, ACPI_OEM_ID); + fixed_strcpy(hpet->header.oem_table_id, ACPI_OEM_TABLE_ID); hpet->header.oem_revision = ACPI_OEM_REVISION; hpet->header.creator_id = ACPI_CREATOR_ID; hpet->header.creator_revision = ACPI_CREATOR_REVISION; @@ -150,6 +150,7 @@ int construct_processor_objects(uint8_t *buf) { static const char pdat[13] = { 0x5b, 0x83, 0x0b, 0x50, 0x52 }; static const char hex[] = "0123456789ABCDEF"; + static const char pr_scope[] = "\\_PR_"; unsigned int i, length, nr_cpus = get_vcpu_nr(); struct acpi_header *hdr; uint8_t *p = buf; @@ -161,8 +162,8 @@ int construct_processor_objects(uint8_t *buf) hdr = (struct acpi_header *)p; hdr->signature = ASCII32('S','S','D','T'); hdr->revision = 2; - strncpy(hdr->oem_id, ACPI_OEM_ID, 6); - strncpy(hdr->oem_table_id, ACPI_OEM_TABLE_ID, 8); + fixed_strcpy(hdr->oem_id, ACPI_OEM_ID); + fixed_strcpy(hdr->oem_table_id, ACPI_OEM_TABLE_ID); hdr->oem_revision = ACPI_OEM_REVISION; hdr->creator_id = ACPI_CREATOR_ID; hdr->creator_revision = ACPI_CREATOR_REVISION; @@ -176,7 +177,7 @@ int construct_processor_objects(uint8_t *buf) *p++ = 0x10; /* PkgLength (includes length bytes!). */ - length = 1 + 5 + (nr_cpus * sizeof(pdat)); + length = 1 + strlen(pr_scope) + (nr_cpus * sizeof(pdat)); if ( length <= 0x3f ) { *p++ = length; @@ -195,8 +196,8 @@ int construct_processor_objects(uint8_t *buf) } /* NameString */ - strncpy(p, "\\_PR_", 5); - p += 5; + strncpy(p, pr_scope, strlen(pr_scope)); + p += strlen(pr_scope); /* * 3. Processor Objects. @@ -263,8 +264,8 @@ int construct_secondary_tables(uint8_t *buf, unsigned long *table_ptrs) tcpa->header.signature = ACPI_2_0_TCPA_SIGNATURE; tcpa->header.length = sizeof(*tcpa); tcpa->header.revision = ACPI_2_0_TCPA_REVISION; - strncpy(tcpa->header.oem_id, ACPI_OEM_ID, 6); - strncpy(tcpa->header.oem_table_id, ACPI_OEM_TABLE_ID, 8); + fixed_strcpy(tcpa->header.oem_id, ACPI_OEM_ID); + fixed_strcpy(tcpa->header.oem_table_id, ACPI_OEM_TABLE_ID); tcpa->header.oem_revision = ACPI_OEM_REVISION; tcpa->header.creator_id = ACPI_CREATOR_ID; tcpa->header.creator_revision = ACPI_CREATOR_REVISION; @@ -291,6 +292,7 @@ int acpi_build_tables(uint8_t *buf) struct acpi_20_rsdt *rsdt; struct acpi_20_xsdt *xsdt; struct acpi_20_fadt *fadt; + struct acpi_10_fadt *fadt_10; struct acpi_20_facs *facs; unsigned char *dsdt; unsigned long secondary_tables[16]; @@ -304,6 +306,25 @@ int acpi_build_tables(uint8_t *buf) memcpy(dsdt, &AmlCode, DsdtLen); offset += align16(DsdtLen); + /* + * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2 + * or above properly, notably Windows 2000, which tries to copy FADT + * into a 116 bytes buffer thus causing an overflow. The solution is to + * link the higher revision FADT with the XSDT only and introduce a + * compatible revision 1 FADT that is linked with the RSDT. Refer to: + * http://www.acpi.info/presentations/S01USMOBS169_OS%20new.ppt + */ + fadt_10 = (struct acpi_10_fadt *)&buf[offset]; + memcpy(fadt_10, &Fadt, sizeof(struct acpi_10_fadt)); + offset += align16(sizeof(struct acpi_10_fadt)); + fadt_10->header.length = sizeof(struct acpi_10_fadt); + fadt_10->header.revision = ACPI_1_0_FADT_REVISION; + fadt_10->dsdt = (unsigned long)dsdt; + fadt_10->firmware_ctrl = (unsigned long)facs; + set_checksum(fadt_10, + offsetof(struct acpi_header, checksum), + sizeof(struct acpi_10_fadt)); + fadt = (struct acpi_20_fadt *)&buf[offset]; memcpy(fadt, &Fadt, sizeof(struct acpi_20_fadt)); offset += align16(sizeof(struct acpi_20_fadt)); @@ -330,7 +351,7 @@ int acpi_build_tables(uint8_t *buf) rsdt = (struct acpi_20_rsdt *)&buf[offset]; memcpy(rsdt, &Rsdt, sizeof(struct acpi_header)); - rsdt->entry[0] = (unsigned long)fadt; + rsdt->entry[0] = (unsigned long)fadt_10; for ( i = 0; secondary_tables[i]; i++ ) rsdt->entry[i+1] = secondary_tables[i]; rsdt->header.length = sizeof(struct acpi_header) + (i+1)*sizeof(uint32_t); diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c index bed26597ca..beabd06248 100644 --- a/tools/firmware/hvmloader/hvmloader.c +++ b/tools/firmware/hvmloader/hvmloader.c @@ -29,7 +29,6 @@ #include "pci_regs.h" #include #include -#include /* memory map */ #define HYPERCALL_PHYSICAL_ADDRESS 0x00080000 @@ -38,23 +37,53 @@ #define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000 #define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000 -/* invoke SVM's paged realmode support */ -#define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001 - -/* - * C runtime start off - */ asm( " .text \n" " .globl _start \n" "_start: \n" + /* C runtime kickoff. */ " cld \n" " cli \n" - " lgdt gdt_desr \n" - " movl $stack_top, %esp \n" - " movl %esp, %ebp \n" + " movl $stack_top,%esp \n" + " movl %esp,%ebp \n" " call main \n" - " ud2 \n" + /* Relocate real-mode trampoline to 0x0. */ + " mov $trampoline_start,%esi \n" + " xor %edi,%edi \n" + " mov $trampoline_end,%ecx \n" + " sub %esi,%ecx \n" + " rep movsb \n" + /* Load real-mode compatible segment state (base 0x0000, limit 0xffff). */ + " lgdt gdt_desr \n" + " mov $0x0010,%ax \n" + " mov %ax,%ds \n" + " mov %ax,%es \n" + " mov %ax,%fs \n" + " mov %ax,%gs \n" + " mov %ax,%ss \n" + /* Initialise all 32-bit GPRs to zero. */ + " xor %eax,%eax \n" + " xor %ebx,%ebx \n" + " xor %ecx,%ecx \n" + " xor %edx,%edx \n" + " xor %esp,%esp \n" + " xor %ebp,%ebp \n" + " xor %esi,%esi \n" + " xor %edi,%edi \n" + /* Enter real mode, reload all segment registers and IDT. */ + " ljmp $0x8,$0x0 \n" + "trampoline_start: .code16 \n" + " mov %eax,%cr0 \n" + " ljmp $0,$1f-trampoline_start\n" + "1: mov %ax,%ds \n" + " mov %ax,%es \n" + " mov %ax,%fs \n" + " mov %ax,%gs \n" + " mov %ax,%ss \n" + " lidt 1f-trampoline_start \n" + " ljmp $0xf000,$0xfff0 \n" + "1: .word 0x3ff,0,0 \n" + "trampoline_end: .code32 \n" " \n" "gdt_desr: \n" " .word gdt_end - gdt - 1 \n" @@ -63,8 +92,8 @@ asm( " .align 8 \n" "gdt: \n" " .quad 0x0000000000000000 \n" - " .quad 0x00CF92000000FFFF \n" - " .quad 0x00CF9A000000FFFF \n" + " .quad 0x00009a000000ffff \n" /* Ring 0 code, base 0 limit 0xffff */ + " .quad 0x000092000000ffff \n" /* Ring 0 data, base 0 limit 0xffff */ "gdt_end: \n" " \n" " .bss \n" @@ -83,19 +112,6 @@ cirrus_check(void) return inb(0x3C5) == 0x12; } -static int -vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx) -{ - int eax; - - __asm__ __volatile__ ( - ".byte 0x0F,0x01,0xD9" - : "=a" (eax) - : "a"(function), - "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi) ); - return eax; -} - static int check_amd(void) { @@ -280,25 +296,57 @@ static void pci_setup(void) } } -static -int must_load_nic(void) +/* + * If the network card is in the boot order, load the Etherboot option ROM. + * Read the boot order bytes from CMOS and check if any of them are 0x4. + */ +static int must_load_nic(void) { - /* If the network card is in the boot order, load the Etherboot - * option ROM. Read the boot order bytes from CMOS and check - * if any of them are 0x4. */ uint8_t boot_order; - /* Read CMOS register 0x3d (boot choices 0 and 1) */ - outb(0x70, 0x3d); - boot_order = inb(0x71); - if ( (boot_order & 0xf) == 0x4 || (boot_order & 0xf0) == 0x40 ) + /* Read CMOS register 0x3d (boot choices 0 and 1). */ + boot_order = cmos_inb(0x3d); + if ( ((boot_order & 0xf) == 0x4) || ((boot_order & 0xf0) == 0x40) ) return 1; - /* Read CMOS register 0x38 (boot choice 2 and FDD test flag) */ - outb(0x70, 0x38); - boot_order = inb(0x71); - if ( (boot_order & 0xf0) == 0x40 ) - return 1; - return 0; + + /* Read CMOS register 0x38 (boot choice 2 and FDD test flag). */ + boot_order = cmos_inb(0x38); + return ((boot_order & 0xf0) == 0x40); +} + +/* Replace possibly erroneous memory-size CMOS fields with correct values. */ +static void cmos_write_memory_size(void) +{ + struct e820entry *map = E820_MAP; + int i, nr = *E820_MAP_NR; + uint32_t base_mem = 640, ext_mem = 0, alt_mem = 0; + + for ( i = 0; i < nr; i++ ) + if ( (map[i].addr >= 0x100000) && (map[i].type == E820_RAM) ) + break; + + if ( i != nr ) + { + alt_mem = ext_mem = map[i].addr + map[i].size; + ext_mem = (ext_mem > 0x0100000) ? (ext_mem - 0x0100000) >> 10 : 0; + if ( ext_mem > 0xffff ) + ext_mem = 0xffff; + alt_mem = (alt_mem > 0x1000000) ? (alt_mem - 0x1000000) >> 16 : 0; + } + + /* All BIOSes: conventional memory (640kB). */ + cmos_outb(0x15, (uint8_t)(base_mem >> 0)); + cmos_outb(0x16, (uint8_t)(base_mem >> 8)); + + /* All BIOSes: extended memory (1kB chunks above 1MB). */ + cmos_outb(0x17, (uint8_t)( ext_mem >> 0)); + cmos_outb(0x18, (uint8_t)( ext_mem >> 8)); + cmos_outb(0x30, (uint8_t)( ext_mem >> 0)); + cmos_outb(0x31, (uint8_t)( ext_mem >> 8)); + + /* Some BIOSes: alternative extended memory (64kB chunks above 16MB). */ + cmos_outb(0x34, (uint8_t)( alt_mem >> 0)); + cmos_outb(0x35, (uint8_t)( alt_mem >> 8)); } int main(void) @@ -349,13 +397,9 @@ int main(void) ASSERT((ACPI_PHYSICAL_ADDRESS + acpi_sz) <= 0xF0000); } - if ( check_amd() ) - { - /* AMD implies this is SVM */ - printf("SVM go ...\n"); - vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0); - } - else + cmos_write_memory_size(); + + if ( !check_amd() ) { printf("Loading VMXAssist ...\n"); memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS, @@ -368,7 +412,7 @@ int main(void) ); } - printf("Failed to invoke ROMBIOS\n"); + printf("Invoking ROMBIOS ...\n"); return 0; } diff --git a/tools/firmware/hvmloader/smbios.c b/tools/firmware/hvmloader/smbios.c index df25999c3a..c9a4992e4c 100644 --- a/tools/firmware/hvmloader/smbios.c +++ b/tools/firmware/hvmloader/smbios.c @@ -22,7 +22,6 @@ #include #include -#include #include "smbios.h" #include "smbios_types.h" #include "util.h" @@ -129,47 +128,32 @@ write_smbios_tables(void *start, return (size_t)((char *)p - (char *)start); } -/* This tries to figure out how much pseudo-physical memory (in MB) - is allocated to the current domU. - - It iterates through the e820 table, adding up the 'usable' and - 'reserved' entries and rounding up to the nearest MB. - - The e820map is not at e820 in hvmloader, so this uses the - E820_MAP_* constants from e820.h to pick it up where libxenguest - left it. - */ +/* Calculate how much pseudo-physical memory (in MB) is allocated to us. */ static uint64_t get_memsize(void) { - struct e820entry *map = NULL; - uint8_t num_entries = 0; + struct e820entry *map = E820_MAP; + uint8_t num_entries = *E820_MAP_NR; uint64_t memsize = 0; - uint8_t i; - - map = (struct e820entry *) (E820_MAP_PAGE + E820_MAP_OFFSET); - num_entries = *((uint8_t *) (E820_MAP_PAGE + E820_MAP_NR_OFFSET)); - - /* walk through e820map, ignoring any entries that aren't marked - as usable or reserved. */ + int i; + /* + * Walk through e820map, ignoring any entries that aren't marked + * as usable or reserved. + */ for ( i = 0; i < num_entries; i++ ) { - if (map->type == E820_RAM || map->type == E820_RESERVED) + if ( (map->type == E820_RAM) || (map->type == E820_RESERVED) ) memsize += map->size; map++; } - /* Round up to the nearest MB. The user specifies domU - pseudo-physical memory in megabytes, so not doing this - could easily lead to reporting one less MB than the user - specified. */ - if ( memsize & ((1<<20)-1) ) - memsize = (memsize >> 20) + 1; - else - memsize = (memsize >> 20); - - return memsize; + /* + * Round up to the nearest MB. The user specifies domU pseudo-physical + * memory in megabytes, so not doing this could easily lead to reporting + * one less MB than the user specified. + */ + return (memsize + (1 << 20) - 1) >> 20; } void diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c index ce32a9001e..2f5f23d1e5 100644 --- a/tools/firmware/hvmloader/util.c +++ b/tools/firmware/hvmloader/util.c @@ -27,17 +27,17 @@ void outb(uint16_t addr, uint8_t val) { - __asm__ __volatile__ ( "outb %%al, %%dx" :: "d"(addr), "a"(val) ); + __asm__ __volatile__ ( "outb %%al, %%dx" : : "d" (addr), "a" (val) ); } void outw(uint16_t addr, uint16_t val) { - __asm__ __volatile__ ( "outw %%ax, %%dx" :: "d"(addr), "a"(val) ); + __asm__ __volatile__ ( "outw %%ax, %%dx" : : "d" (addr), "a" (val) ); } void outl(uint16_t addr, uint32_t val) { - __asm__ __volatile__ ( "outl %%eax, %%dx" :: "d"(addr), "a"(val) ); + __asm__ __volatile__ ( "outl %%eax, %%dx" : : "d" (addr), "a" (val) ); } uint8_t inb(uint16_t addr) @@ -61,6 +61,18 @@ uint32_t inl(uint16_t addr) return val; } +uint8_t cmos_inb(uint8_t idx) +{ + outb(0x70, idx); + return inb(0x71); +} + +void cmos_outb(uint8_t idx, uint8_t val) +{ + outb(0x70, idx); + outb(0x71, val); +} + char *itoa(char *a, unsigned int i) { unsigned int _i = i, x = 0; @@ -280,9 +292,6 @@ uuid_to_string(char *dest, uint8_t *uuid) *p = '\0'; } -#include -#define E820_MAP_NR ((unsigned char *)E820_MAP_PAGE + E820_MAP_NR_OFFSET) -#define E820_MAP ((struct e820entry *)(E820_MAP_PAGE + E820_MAP_OFFSET)) uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask) { uint64_t addr = 0; diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h index 368f93ddda..cc1f42dba9 100644 --- a/tools/firmware/hvmloader/util.h +++ b/tools/firmware/hvmloader/util.h @@ -26,6 +26,10 @@ uint8_t inb(uint16_t addr); uint16_t inw(uint16_t addr); uint32_t inl(uint16_t addr); +/* CMOS access */ +uint8_t cmos_inb(uint8_t idx); +void cmos_outb(uint8_t idx, uint8_t val); + /* APIC access */ uint32_t ioapic_read(uint32_t reg); void ioapic_write(uint32_t reg, uint32_t val); @@ -78,9 +82,13 @@ int vprintf(const char *fmt, va_list ap); /* Allocate region of specified type in the e820 table. */ uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask); -/* Prepare the 32bit BIOS */ -int highbios_setup(void); +/* General e820 access. */ +#include +#define E820_MAP_NR ((unsigned char *)E820_MAP_PAGE + E820_MAP_NR_OFFSET) +#define E820_MAP ((struct e820entry *)(E820_MAP_PAGE + E820_MAP_OFFSET)) +/* Prepare the 32bit BIOS */ +void highbios_setup(void); #define isdigit(c) ((c) >= '0' && (c) <= '9') diff --git a/tools/firmware/rombios/32bit/tcgbios/tcgbios.c b/tools/firmware/rombios/32bit/tcgbios/tcgbios.c index dc1a9e0d51..e4483982c4 100644 --- a/tools/firmware/rombios/32bit/tcgbios/tcgbios.c +++ b/tools/firmware/rombios/32bit/tcgbios/tcgbios.c @@ -95,13 +95,15 @@ struct ptti_cust *TCG_CommandList[] = { }; /* local function prototypes */ -static void sha1(const unsigned char *data, uint32_t length, unsigned char *hash); +static void sha1(const unsigned char *data, uint32_t length, + unsigned char *hash); static uint32_t TCG_ShutdownPreBootInterface(uint32_t ebx); static uint32_t HashAll32(struct hai *hai, unsigned char *hash, uint32_t magic, uint32_t ecx, uint32_t edx); static uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s, struct hleeo *hleeo, - uint32_t magic, uint32_t ecx, uint32_t edx); + uint32_t magic, uint32_t ecx, + uint32_t edx); static uint32_t HashLogEvent32(struct hlei *hlei, struct hleo *hleo, uint32_t ebx, uint32_t ecx, uint32_t edx); static uint32_t PassThroughToTPM32(struct pttti *pttti, struct pttto *pttto, @@ -181,8 +183,7 @@ uint32_t MA_InitTPM(uint16_t startupcode) } static -uint32_t MA_Transmit(unsigned char *cmdbuffer, - unsigned char *respbuffer, +uint32_t MA_Transmit(unsigned char *cmdbuffer, unsigned char *respbuffer, uint32_t respbufferlen) { uint32_t rc = 0; @@ -289,15 +290,14 @@ void tcpa_acpi_init(void) uint32_t ctr = 0; /* get RSDT from RSDP */ rsdt = (struct acpi_20_rsdt *)rsdp->rsdt_address; - /* rsdt may be anywhere in 32bit space */ length = rsdt->header.length; off = 36; while ((off + 3) < length) { /* try all pointers to structures */ tcpa = (struct acpi_20_tcpa *)rsdt->entry[ctr]; /* valid TCPA ACPI table ? */ - if (ACPI_2_0_TCPA_SIGNATURE == tcpa->header.signature && - acpi_validate_entry(&tcpa->header) == 0) { + if (ACPI_2_0_TCPA_SIGNATURE == tcpa->header.signature + && acpi_validate_entry(&tcpa->header) == 0) { found = 1; break; } @@ -311,7 +311,6 @@ void tcpa_acpi_init(void) tcpa = 0; } - /* initialize the TCPA part of the EBDA with our data */ tcpa_acpi.tcpa_ptr = tcpa; tcpa_acpi.lasa_last_ptr = 0; tcpa_acpi.entry_count = 0; @@ -748,9 +747,7 @@ void tcpa_measure_post(Bit32u from, Bit32u to) } static -uint32_t SendCommand32(uint32_t idx, - struct pttto *pttto, - uint32_t size_ptto) +uint32_t SendCommand32(uint32_t idx, struct pttto *pttto, uint32_t size_ptto) { uint32_t rc = 0; struct pttti *pttti = (struct pttti *)TCG_CommandList[idx]; @@ -796,7 +793,8 @@ uint32_t tcpa_initialize_tpm(uint32_t physpres) uint32_t pttto_size = sizeof(_pttto); if (rc == 0) { - rc = SendCommand32(IDX_CMD_TPM_Startup_0x01, pttto, pttto_size); + rc = SendCommand32(IDX_CMD_TPM_Startup_0x01, pttto, + pttto_size); } if (rc == 0 && physpres != 0) { @@ -884,11 +882,8 @@ uint32_t _TCG_TPM_Extend(unsigned char *hash, uint32_t pcrindex) static -uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s, - struct hleeo *hleeo, - uint32_t magic, - uint32_t ecx, - uint32_t edx) +uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s, struct hleeo *hleeo, + uint32_t magic, uint32_t ecx, uint32_t edx) { uint32_t rc = 0; uint16_t size; @@ -978,11 +973,8 @@ uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s, static -uint32_t PassThroughToTPM32(struct pttti *pttti, - struct pttto *pttto, - uint32_t magic, - uint32_t ecx, - uint32_t edx) +uint32_t PassThroughToTPM32(struct pttti *pttti, struct pttto *pttto, + uint32_t magic, uint32_t ecx, uint32_t edx) { uint32_t rc = 0; uint8_t *cmd32; @@ -1047,9 +1039,7 @@ uint32_t TCG_ShutdownPreBootInterface(uint32_t ebx) static uint32_t HashLogEvent32(struct hlei *hlei, struct hleo *hleo, - uint32_t ebx, - uint32_t ecx, - uint32_t edx) + uint32_t ebx, uint32_t ecx, uint32_t edx) { uint32_t rc = 0; uint16_t size; @@ -1144,9 +1134,7 @@ uint32_t HashLogEvent32(struct hlei *hlei, struct hleo *hleo, static uint32_t HashAll32(struct hai *hai, unsigned char *hash, - uint32_t magic, - uint32_t ecx, - uint32_t edx) + uint32_t magic, uint32_t ecx, uint32_t edx) { uint32_t rc = 0; @@ -1187,9 +1175,7 @@ uint32_t HashAll32(struct hai *hai, unsigned char *hash, static uint32_t TSS32(struct ti *ti, struct to *to, - uint32_t ebx, - uint32_t ecx, - uint32_t edx) + uint32_t ebx, uint32_t ecx, uint32_t edx) { uint32_t rc = 0; if (TCG_IsShutdownPreBootInterface() == 0) { @@ -1209,11 +1195,11 @@ uint32_t TSS32(struct ti *ti, struct to *to, static uint32_t CompactHashLogExtendEvent32(unsigned char *buffer, - uint32_t info, - uint32_t magic, - uint32_t length, - uint32_t pcrindex, - uint32_t *edx_ptr) + uint32_t info, + uint32_t magic, + uint32_t length, + uint32_t pcrindex, + uint32_t *edx_ptr) { uint32_t rc = 0; struct hleeo hleeo; @@ -1356,9 +1342,7 @@ void sha1_do(sha1_ctx *ctx, const unsigned char *data32, uint32_t length) /* treat data in 64-byte chunks */ for (offset = 0; length - offset >= 64; offset += 64) { - /* copy into the 'w' array */ memcpy(w, data32 + offset, 64); - /* hash the block in the 'w' array */ sha1_block((uint32_t *)w, ctx); bits += (64 * 8); } @@ -1408,7 +1392,8 @@ void sha1(const unsigned char *data, uint32_t length, unsigned char *hash) } -uint32_t TCGInterruptHandler(pushad_regs_t *regs, uint32_t esds, uint32_t flags_ptr) +uint32_t TCGInterruptHandler(pushad_regs_t *regs, uint32_t esds, + uint32_t flags_ptr) { uint16_t DS = esds >> 16; uint16_t ES = esds & 0xffff; @@ -1435,7 +1420,6 @@ uint32_t TCGInterruptHandler(pushad_regs_t *regs, uint32_t esds, uint32_t flags_ } } break; - case 0x01: regs->u.r32.eax = HashLogExtendEvent32((struct hleei_short*) diff --git a/tools/firmware/rombios/32bitgateway.c b/tools/firmware/rombios/32bitgateway.c index 98f61be6e4..4da5a39c45 100644 --- a/tools/firmware/rombios/32bitgateway.c +++ b/tools/firmware/rombios/32bitgateway.c @@ -153,26 +153,17 @@ realmode_gdtdesc: ;to be used in real mode switch_to_realmode: ; Implementation of switching from protected mode to real mode - ; restores all registers and prepares cs, es, ds, ss to be used - ; in real mode + ; prepares cs, es, ds, ss to be used in real mode + ; spills eax START_PM_CODE ; need to fix up the stack to return in 16 bit mode ; currently the 32 bit return address is on the stack - push bp ;pop@A1 - mov bp, sp - push eax ;pop@X + pop eax + push ax - mov eax, [bp] ; return address low 16bits - ; and 'bp' are being moved - mov 2[bp], eax - - pop eax ;@X - add sp, #2 ; adjust stack for 'lost' bytes - - push eax ;pop@1 - push bx ;pop@2 - push si ;pop@3 + push bx ;pop@1 + push si ;pop@2 call _ebda_ss_offset32 ; get the offset of the ss mov bx, ax ; entry within the ebda. @@ -229,10 +220,8 @@ switch_to_realmode_goon_2: sti ; allow interrupts - pop si ;@3 - pop bx ;@2 - pop eax ;@1 - pop bp ;@A1 + pop si ;@2 + pop bx ;@1 ret diff --git a/tools/firmware/rombios/rombios.c b/tools/firmware/rombios/rombios.c index 7b6ef8062d..eb288a80fa 100644 --- a/tools/firmware/rombios/rombios.c +++ b/tools/firmware/rombios/rombios.c @@ -4196,178 +4196,86 @@ ASM_END case 0xe8: switch(regs.u.r8.al) { - case 0x20: // coded by osmaker aka K.J. - if(regs.u.r32.edx == 0x534D4150) /* SMAP */ - { -#ifdef HVMASSIST - if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) { - Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14; + case 0x20: { + Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14; - if (regs.u.r16.bx + 0x14 <= e820_table_size) { - memcpyb(ES, regs.u.r16.di, - 0xe000, 0x10 + regs.u.r16.bx, 0x14); - } - regs.u.r32.ebx += 0x14; - if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size) - regs.u.r32.ebx = 0; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; - CLEAR_CF(); - return; - } else if (regs.u.r16.bx == 1) { - extended_memory_size = inb_cmos(0x35); - extended_memory_size <<= 8; - extended_memory_size |= inb_cmos(0x34); - extended_memory_size *= 64; - if (extended_memory_size > 0x3bc000) // greater than EFF00000??? - { - extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 - } - extended_memory_size *= 1024; - extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off + if (regs.u.r32.edx != 0x534D4150) /* SMAP */ + goto int15_unimplemented; - if (extended_memory_size <= 15728640) - { - extended_memory_size = inb_cmos(0x31); - extended_memory_size <<= 8; - extended_memory_size |= inb_cmos(0x30); - extended_memory_size *= 1024; - } - - write_word(ES, regs.u.r16.di, 0x0000); - write_word(ES, regs.u.r16.di+2, 0x0010); - write_word(ES, regs.u.r16.di+4, 0x0000); - write_word(ES, regs.u.r16.di+6, 0x0000); - - write_word(ES, regs.u.r16.di+8, extended_memory_size); - extended_memory_size >>= 16; - write_word(ES, regs.u.r16.di+10, extended_memory_size); - extended_memory_size >>= 16; - write_word(ES, regs.u.r16.di+12, extended_memory_size); - extended_memory_size >>= 16; - write_word(ES, regs.u.r16.di+14, extended_memory_size); - - write_word(ES, regs.u.r16.di+16, 0x1); - write_word(ES, regs.u.r16.di+18, 0x0); - - regs.u.r32.ebx = 0; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; - CLEAR_CF(); - return; - } else { /* AX=E820, DX=534D4150, BX unrecognized */ - goto int15_unimplemented; - } -#else - switch(regs.u.r16.bx) - { - case 0: - write_word(ES, regs.u.r16.di, 0x00); - write_word(ES, regs.u.r16.di+2, 0x00); - write_word(ES, regs.u.r16.di+4, 0x00); - write_word(ES, regs.u.r16.di+6, 0x00); - - write_word(ES, regs.u.r16.di+8, 0xFC00); - write_word(ES, regs.u.r16.di+10, 0x0009); - write_word(ES, regs.u.r16.di+12, 0x0000); - write_word(ES, regs.u.r16.di+14, 0x0000); - - write_word(ES, regs.u.r16.di+16, 0x1); - write_word(ES, regs.u.r16.di+18, 0x0); - - regs.u.r32.ebx = 1; - - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; - CLEAR_CF(); - return; - break; - case 1: - extended_memory_size = inb_cmos(0x35); - extended_memory_size <<= 8; - extended_memory_size |= inb_cmos(0x34); - extended_memory_size *= 64; - if(extended_memory_size > 0x3bc000) // greater than EFF00000??? - { - extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 - } - extended_memory_size *= 1024; - extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off - - if(extended_memory_size <= 15728640) - { - extended_memory_size = inb_cmos(0x31); - extended_memory_size <<= 8; - extended_memory_size |= inb_cmos(0x30); - extended_memory_size *= 1024; - } - - write_word(ES, regs.u.r16.di, 0x0000); - write_word(ES, regs.u.r16.di+2, 0x0010); - write_word(ES, regs.u.r16.di+4, 0x0000); - write_word(ES, regs.u.r16.di+6, 0x0000); - - write_word(ES, regs.u.r16.di+8, extended_memory_size); - extended_memory_size >>= 16; - write_word(ES, regs.u.r16.di+10, extended_memory_size); - extended_memory_size >>= 16; - write_word(ES, regs.u.r16.di+12, extended_memory_size); - extended_memory_size >>= 16; - write_word(ES, regs.u.r16.di+14, extended_memory_size); - - write_word(ES, regs.u.r16.di+16, 0x1); - write_word(ES, regs.u.r16.di+18, 0x0); - - regs.u.r32.ebx = 0; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; - CLEAR_CF(); - return; - break; - default: /* AX=E820, DX=534D4150, BX unrecognized */ - goto int15_unimplemented; + if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) { + if (regs.u.r16.bx + 0x14 <= e820_table_size) + memcpyb(ES, regs.u.r16.di, + 0xe000, 0x10 + regs.u.r16.bx, 0x14); + regs.u.r32.ebx += 0x14; + if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size) + regs.u.r32.ebx = 0; + } else if (regs.u.r16.bx == 1) { + Bit32u base, type; + Bit16u off; + for (off = 0; off < e820_table_size; off += 0x14) { + base = read_dword(0xe000, 0x10 + off); + type = read_dword(0xe000, 0x20 + off); + if ((base >= 0x100000) && (type == 1)) break; } -#endif - } else { - // if DX != 0x534D4150) - goto int15_unimplemented; - } + if (off == e820_table_size) { + SET_CF(); + break; + } + memcpyb(ES, regs.u.r16.di, 0xe000, 0x10 + off, 0x14); + regs.u.r32.ebx = 0; + } else { /* AX=E820, DX=534D4150, BX unrecognized */ + goto int15_unimplemented; + } + + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); break; + } - case 0x01: - // do we have any reason to fail here ? - CLEAR_CF(); + case 0x01: { + Bit16u off, e820_table_size = read_word(0xe000, 0x8) * 0x14; + Bit32u base, type, size; - // my real system sets ax and bx to 0 - // this is confirmed by Ralph Brown list - // but syslinux v1.48 is known to behave - // strangely if ax is set to 0 - // regs.u.r16.ax = 0; - // regs.u.r16.bx = 0; + // do we have any reason to fail here ? + CLEAR_CF(); - // Get the amount of extended memory (above 1M) - regs.u.r8.cl = inb_cmos(0x30); - regs.u.r8.ch = inb_cmos(0x31); + // Get the amount of extended memory (above 1M) + regs.u.r8.cl = inb_cmos(0x30); + regs.u.r8.ch = inb_cmos(0x31); - // limit to 15M - if(regs.u.r16.cx > 0x3c00) - { - regs.u.r16.cx = 0x3c00; - } + // limit to 15M + if (regs.u.r16.cx > (15*1024)) + regs.u.r16.cx = 15*1024; - // Get the amount of extended memory above 16M in 64k blocs - regs.u.r8.dl = inb_cmos(0x34); - regs.u.r8.dh = inb_cmos(0x35); + // Find first RAM E820 entry >= 1MB. + for (off = 0; off < e820_table_size; off += 0x14) { + base = read_dword(0xe000, 0x10 + off); + type = read_dword(0xe000, 0x20 + off); + if ((base >= 0x100000) && (type == 1)) + break; + } - // Set configured memory equal to extended memory - regs.u.r16.ax = regs.u.r16.cx; - regs.u.r16.bx = regs.u.r16.dx; - break; + // If there is RAM above 16MB, return amount in 64kB chunks. + regs.u.r16.dx = 0; + if (off != e820_table_size) { + size = base + read_dword(0xe000, 0x18 + off); + if (size > 0x1000000) { + size -= 0x1000000; + regs.u.r16.dx = (Bit16u)(size >> 16); + } + } + + // Set configured memory equal to extended memory + regs.u.r16.ax = regs.u.r16.cx; + regs.u.r16.bx = regs.u.r16.dx; + break; + } default: /* AH=0xE8?? but not implemented */ - goto int15_unimplemented; - } - break; + goto int15_unimplemented; + } + break; int15_unimplemented: // fall into the default default: @@ -7792,10 +7700,11 @@ ASM_END bootdrv = (Bit8u)(status>>8); bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment); - /* Canonicalize bootseg:bootip */ #if BX_TCGBIOS tcpa_add_bootdevice((Bit32u)1L, (Bit32u)0L); #endif + + /* Canonicalize bootseg:bootip */ bootip = (bootseg & 0x0fff) << 4; bootseg &= 0xf000; break; @@ -7812,8 +7721,6 @@ ASM_END #if BX_TCGBIOS tcpa_ipl((Bit32u)bootseg); /* specs: 8.2.3 steps 4 and 5 */ #endif - /* Debugging info */ - printf("Booting from %x:%x\n", bootseg, bootip); /* Jump to the boot vector */ ASM_START diff --git a/tools/firmware/rombios/tcgbios.c b/tools/firmware/rombios/tcgbios.c index c8f5af2853..de2066fd1d 100644 --- a/tools/firmware/rombios/tcgbios.c +++ b/tools/firmware/rombios/tcgbios.c @@ -228,6 +228,8 @@ int1a_function32(regs, ES, DS, FLAGS) { Bit16u rc; + BX_DEBUG_INT1A("int1a_32: AX=%04x\n", regs.u.r16.ax); + switch (regs.u.r8.ah) { case 0xbb: /* @@ -256,8 +258,10 @@ int1a_function32(regs, ES, DS, FLAGS) default: SET_CF(); } + break; default: SET_CF(); break; } + BX_DEBUG_INT1A("int1a_32: FLAGS=%04x\n", FLAGS); } diff --git a/tools/ioemu/hw/ide.c b/tools/ioemu/hw/ide.c index c4db9fe738..274dd8f850 100644 --- a/tools/ioemu/hw/ide.c +++ b/tools/ioemu/hw/ide.c @@ -396,17 +396,41 @@ typedef struct PCIIDEState { #ifdef DMA_MULTI_THREAD +static pthread_t ide_dma_thread; static int file_pipes[2]; static void ide_dma_loop(BMDMAState *bm); static void dma_thread_loop(BMDMAState *bm); +extern int suspend_requested; static void *dma_thread_func(void* opaque) { BMDMAState* req; + fd_set fds; + int rv, nfds = file_pipes[0] + 1; + struct timeval tm; - while (read(file_pipes[0], &req, sizeof(req))) { - dma_thread_loop(req); + while (1) { + + /* Wait at most a second for the pipe to become readable */ + FD_ZERO(&fds); + FD_SET(file_pipes[0], &fds); + tm.tv_sec = 1; + tm.tv_usec = 0; + rv = select(nfds, &fds, NULL, NULL, &tm); + + if (rv != 0) { + if (read(file_pipes[0], &req, sizeof(req)) == 0) + return NULL; + dma_thread_loop(req); + } else { + if (suspend_requested) { + /* Need to tidy up the DMA thread so that we don't end up + * finishing operations after the domain's ioreqs are + * drained and its state saved */ + return NULL; + } + } } return NULL; @@ -414,24 +438,41 @@ static void *dma_thread_func(void* opaque) static void dma_create_thread(void) { - pthread_t tid; int rt; + pthread_attr_t a; if (pipe(file_pipes) != 0) { fprintf(stderr, "create pipe failed\n"); exit(1); } - if ((rt = pthread_create(&tid, NULL, dma_thread_func, NULL))) { + if ((rt = pthread_attr_init(&a)) + || (rt = pthread_attr_setdetachstate(&a, PTHREAD_CREATE_JOINABLE))) { + fprintf(stderr, "Oops, dma thread attr setup failed, errno=%d\n", rt); + exit(1); + } + + if ((rt = pthread_create(&ide_dma_thread, &a, dma_thread_func, NULL))) { fprintf(stderr, "Oops, dma thread creation failed, errno=%d\n", rt); exit(1); } +} - if ((rt = pthread_detach(tid))) { - fprintf(stderr, "Oops, dma thread detachment failed, errno=%d\n", rt); - exit(1); +void ide_stop_dma_thread(void) +{ + int rc; + /* Make sure the IDE DMA thread is stopped */ + if ( (rc = pthread_join(ide_dma_thread, NULL)) != 0 ) + { + fprintf(stderr, "Oops, error collecting IDE DMA thread (%s)\n", + strerror(rc)); } } + +#else +void ide_stop_dma_thread(void) +{ +} #endif /* DMA_MULTI_THREAD */ #if defined(__ia64__) diff --git a/tools/ioemu/hw/usb-hid.c b/tools/ioemu/hw/usb-hid.c index 60849a4ed0..c7af3d65ab 100644 --- a/tools/ioemu/hw/usb-hid.c +++ b/tools/ioemu/hw/usb-hid.c @@ -517,6 +517,49 @@ static void usb_mouse_handle_destroy(USBDevice *dev) qemu_free(s); } +void usb_mouse_save(QEMUFile *f, void *opaque) +{ + USBMouseState *s = (USBMouseState*)opaque; + + qemu_put_be32s(f, &s->dx); + qemu_put_be32s(f, &s->dy); + qemu_put_be32s(f, &s->dz); + qemu_put_be32s(f, &s->buttons_state); + qemu_put_be32s(f, &s->x); + qemu_put_be32s(f, &s->y); + qemu_put_be32s(f, &s->kind); + qemu_put_be32s(f, &s->mouse_grabbed); + qemu_put_be32s(f, &s->status_changed); + +} + +int usb_mouse_load(QEMUFile *f, void *opaque, int version_id) +{ + USBMouseState *s = (USBMouseState*)opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->dx); + qemu_get_be32s(f, &s->dy); + qemu_get_be32s(f, &s->dz); + qemu_get_be32s(f, &s->buttons_state); + qemu_get_be32s(f, &s->x); + qemu_get_be32s(f, &s->y); + qemu_get_be32s(f, &s->kind); + qemu_get_be32s(f, &s->mouse_grabbed); + qemu_get_be32s(f, &s->status_changed); + + if ( s->kind == USB_TABLET) { + fprintf(logfile, "usb_mouse_load:add usb_tablet_event.\n"); + qemu_add_mouse_event_handler(usb_tablet_event, s, 1); + } else if ( s->kind == USB_MOUSE) { + fprintf(logfile, "usb_mouse_load:add usb_mouse_event.\n"); + qemu_add_mouse_event_handler(usb_mouse_event, s, 0); + } +} + + USBDevice *usb_tablet_init(void) { USBMouseState *s; @@ -536,6 +579,8 @@ USBDevice *usb_tablet_init(void) pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); + register_savevm("USB tablet dev", 0, 1, usb_mouse_save, usb_mouse_load, s); + return (USBDevice *)s; } @@ -558,5 +603,7 @@ USBDevice *usb_mouse_init(void) pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); + register_savevm("USB mouse dev", 0, 1, usb_mouse_save, usb_mouse_load, s); + return (USBDevice *)s; } diff --git a/tools/ioemu/hw/usb-ohci.c b/tools/ioemu/hw/usb-ohci.c index e87d9da70a..a563262676 100644 --- a/tools/ioemu/hw/usb-ohci.c +++ b/tools/ioemu/hw/usb-ohci.c @@ -1186,5 +1186,7 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); } + register_savevm("OHCI USB", 0, 1, generic_pci_save, generic_pci_load, ohci); + ohci_reset(ohci); } diff --git a/tools/ioemu/hw/usb-uhci.c b/tools/ioemu/hw/usb-uhci.c index 7212c5e82d..46cff274cf 100644 --- a/tools/ioemu/hw/usb-uhci.c +++ b/tools/ioemu/hw/usb-uhci.c @@ -658,6 +658,50 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); } +void uhci_usb_save(QEMUFile *f, void *opaque) +{ + int i; + UHCIState *s = (UHCIState*)opaque; + + qemu_put_be16s(f, &s->cmd); + qemu_put_be16s(f, &s->status); + qemu_put_be16s(f, &s->intr); + qemu_put_be16s(f, &s->frnum); + qemu_put_be32s(f, &s->fl_base_addr); + qemu_put_8s(f, &s->sof_timing); + qemu_put_8s(f, &s->status2); + + for(i = 0; i < NB_PORTS; i++) { + qemu_put_be16s(f, &s->ports[i].ctrl); + } + + qemu_put_timer(f, s->frame_timer); +} + +int uhci_usb_load(QEMUFile *f, void *opaque, int version_id) +{ + int i; + UHCIState *s = (UHCIState*)opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be16s(f, &s->cmd); + qemu_get_be16s(f, &s->status); + qemu_get_be16s(f, &s->intr); + qemu_get_be16s(f, &s->frnum); + qemu_get_be32s(f, &s->fl_base_addr); + qemu_get_8s(f, &s->sof_timing); + qemu_get_8s(f, &s->status2); + + for(i = 0; i < NB_PORTS; i++) { + qemu_get_be16s(f, &s->ports[i].ctrl); + } + + qemu_get_timer(f, s->frame_timer); + +} + void usb_uhci_init(PCIBus *bus, int devfn) { UHCIState *s; @@ -693,4 +737,8 @@ void usb_uhci_init(PCIBus *bus, int devfn) to rely on this. */ pci_register_io_region(&s->dev, 4, 0x20, PCI_ADDRESS_SPACE_IO, uhci_map); + + register_savevm("UHCI_usb_pci", 0, 1, generic_pci_save, generic_pci_load, s); + + register_savevm("UHCI usb controller", 0, 1, uhci_usb_save, uhci_usb_load, s); } diff --git a/tools/ioemu/hw/usb.c b/tools/ioemu/hw/usb.c index 34aac5fa9b..e4166518b0 100644 --- a/tools/ioemu/hw/usb.c +++ b/tools/ioemu/hw/usb.c @@ -191,3 +191,43 @@ int set_usb_string(uint8_t *buf, const char *str) } return q - buf; } + +void generic_usb_save(QEMUFile* f, void *opaque) +{ + USBDevice *s = (USBDevice*)opaque; + + qemu_put_be32s(f, &s->speed); + qemu_put_8s(f, &s->addr); + qemu_put_be32s(f, &s->state); + + qemu_put_buffer(f, s->setup_buf, 8); + qemu_put_buffer(f, s->data_buf, 1024); + + qemu_put_be32s(f, &s->remote_wakeup); + qemu_put_be32s(f, &s->setup_state); + qemu_put_be32s(f, &s->setup_len); + qemu_put_be32s(f, &s->setup_index); + +} + +int generic_usb_load(QEMUFile* f, void *opaque, int version_id) +{ + USBDevice *s = (USBDevice*)opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->speed); + qemu_get_8s(f, &s->addr); + qemu_get_be32s(f, &s->state); + + qemu_get_buffer(f, s->setup_buf, 8); + qemu_get_buffer(f, s->data_buf, 1024); + + qemu_get_be32s(f, &s->remote_wakeup); + qemu_get_be32s(f, &s->setup_state); + qemu_get_be32s(f, &s->setup_len); + qemu_get_be32s(f, &s->setup_index); + + return 0; +} diff --git a/tools/ioemu/hw/usb.h b/tools/ioemu/hw/usb.h index 98fde06569..9df69f8dc8 100644 --- a/tools/ioemu/hw/usb.h +++ b/tools/ioemu/hw/usb.h @@ -176,3 +176,9 @@ USBDevice *usb_tablet_init(void); /* usb-msd.c */ USBDevice *usb_msd_init(const char *filename); + +/* usb.c */ +void generic_usb_save(QEMUFile* f, void *opaque); +int generic_usb_load(QEMUFile* f, void *opaque, int version_id); + + diff --git a/tools/ioemu/target-i386-dm/exec-dm.c b/tools/ioemu/target-i386-dm/exec-dm.c index 35891ed064..225f8b6f3a 100644 --- a/tools/ioemu/target-i386-dm/exec-dm.c +++ b/tools/ioemu/target-i386-dm/exec-dm.c @@ -450,6 +450,9 @@ static inline int paddr_is_ram(target_phys_addr_t addr) #define phys_ram_addr(x) (phys_ram_base + (x)) #endif +extern unsigned long *logdirty_bitmap; +extern unsigned long logdirty_bitmap_size; + void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write) { @@ -485,9 +488,20 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, l = 1; } } else if (paddr_is_ram(addr)) { - /* Reading from RAM */ + /* Writing to RAM */ ptr = phys_ram_addr(addr); memcpy(ptr, buf, l); + if (logdirty_bitmap != NULL) { + /* Record that we have dirtied this frame */ + unsigned long pfn = addr >> TARGET_PAGE_BITS; + if (pfn / 8 >= logdirty_bitmap_size) { + fprintf(logfile, "dirtying pfn %x >= bitmap size %x\n", + pfn, logdirty_bitmap_size * 8); + } else { + logdirty_bitmap[pfn / HOST_LONG_BITS] + |= 1UL << pfn % HOST_LONG_BITS; + } + } #ifdef __ia64__ sync_icache(ptr, l); #endif diff --git a/tools/ioemu/target-i386-dm/helper2.c b/tools/ioemu/target-i386-dm/helper2.c index dc3394d5b7..17261e632d 100644 --- a/tools/ioemu/target-i386-dm/helper2.c +++ b/tools/ioemu/target-i386-dm/helper2.c @@ -439,6 +439,18 @@ void cpu_ioreq_xor(CPUState *env, ioreq_t *req) req->data = tmp1; } +void cpu_ioreq_xchg(CPUState *env, ioreq_t *req) +{ + unsigned long tmp1; + + if (req->data_is_ptr != 0) + hw_error("expected scalar value"); + + read_physical(req->addr, req->size, &tmp1); + write_physical(req->addr, req->size, &req->data); + req->data = tmp1; +} + void __handle_ioreq(CPUState *env, ioreq_t *req) { if (!req->data_is_ptr && req->dir == IOREQ_WRITE && req->size != 4) @@ -463,6 +475,9 @@ void __handle_ioreq(CPUState *env, ioreq_t *req) case IOREQ_TYPE_XOR: cpu_ioreq_xor(env, req); break; + case IOREQ_TYPE_XCHG: + cpu_ioreq_xchg(env, req); + break; default: hw_error("Invalid ioreq type 0x%x\n", req->type); } @@ -577,7 +592,28 @@ int main_loop(void) destroy_hvm_domain(); else { char qemu_file[20]; + ioreq_t *req; + int rc; + sprintf(qemu_file, "/tmp/xen.qemu-dm.%d", domid); + xc_domain_pause(xc_handle, domid); + + /* Pull all outstanding ioreqs through the system */ + handle_buffered_io(env); + main_loop_wait(1); /* For the select() on events */ + + /* Stop the IDE thread */ + ide_stop_dma_thread(); + + /* Make sure that all outstanding IO responses are handled too */ + if ( xc_hvm_drain_io(xc_handle, domid) != 0 ) + { + fprintf(stderr, "error clearing ioreq rings (%s)\n", + strerror(errno)); + return -1; + } + + /* Save the device state */ if (qemu_savevm(qemu_file) < 0) fprintf(stderr, "qemu save fail.\n"); } diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index 0b78fa8650..6f9219fa40 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -841,10 +841,22 @@ void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) #ifdef CONFIG_DM static void timer_save(QEMUFile *f, void *opaque) { + /* need timer for save/restoe qemu_timer in usb_uhci */ + if (cpu_ticks_enabled) { + hw_error("cannot save state if virtual timers are running"); + } + qemu_put_be64s(f, &cpu_clock_offset); } static int timer_load(QEMUFile *f, void *opaque, int version_id) { + if (version_id != 1) + return -EINVAL; + if (cpu_ticks_enabled) { + return -EINVAL; + } + + qemu_get_be64s(f, &cpu_clock_offset); return 0; } #else /* !CONFIG_DM */ @@ -3900,6 +3912,7 @@ static int usb_device_add(const char *devname) const char *p; USBDevice *dev; USBPort *port; + char usb_name[256] = "USB "; if (!free_usb_ports) return -1; @@ -3936,6 +3949,12 @@ static int usb_device_add(const char *devname) free_usb_ports = port->next; port->next = used_usb_ports; used_usb_ports = port; + + pstrcpy(usb_name + strlen(usb_name), + sizeof(usb_name) - strlen(usb_name), + devname); + register_savevm(usb_name, 0, 1, generic_usb_save, generic_usb_load, dev); + usb_attach(port, dev); return 0; } diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index 8535ba689c..a6b53aa312 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -843,6 +843,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn); int pmac_ide_init (BlockDriverState **hd_table, SetIRQFunc *set_irq, void *irq_opaque, int irq); +void ide_stop_dma_thread(void); /* cdrom.c */ int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); diff --git a/tools/ioemu/xenstore.c b/tools/ioemu/xenstore.c index edaf741c3d..26063f5a93 100644 --- a/tools/ioemu/xenstore.c +++ b/tools/ioemu/xenstore.c @@ -11,9 +11,14 @@ #include "vl.h" #include "block_int.h" #include +#include +#include +#include +#include +#include static struct xs_handle *xsh = NULL; -static char *hd_filename[MAX_DISKS]; +static char *media_filename[MAX_DISKS]; static QEMUTimer *insert_timer = NULL; #define UWAIT_MAX (30*1000000) /* thirty seconds */ @@ -40,10 +45,10 @@ static void insert_media(void *opaque) int i; for (i = 0; i < MAX_DISKS; i++) { - if (hd_filename[i]) { - do_change(bs_table[i]->device_name, hd_filename[i]); - free(hd_filename[i]); - hd_filename[i] = NULL; + if (media_filename[i] && bs_table[i]) { + do_change(bs_table[i]->device_name, media_filename[i]); + free(media_filename[i]); + media_filename[i] = NULL; } } } @@ -82,7 +87,7 @@ void xenstore_parse_domain_config(int domid) unsigned int len, num, hd_index; for(i = 0; i < MAX_DISKS; i++) - hd_filename[i] = NULL; + media_filename[i] = NULL; xsh = xs_daemon_open(); if (xsh == NULL) { @@ -128,19 +133,12 @@ void xenstore_parse_domain_config(int domid) continue; free(type); type = xs_read(xsh, XBT_NULL, buf, &len); - /* read params to get the patch of the image -- read it last - * so that we have its path in buf when setting up the - * watch */ if (pasprintf(&buf, "%s/params", bpath) == -1) continue; free(params); params = xs_read(xsh, XBT_NULL, buf, &len); if (params == NULL) continue; - if (params[0]) { - hd_filename[hd_index] = params; /* strdup() */ - params = NULL; /* don't free params on re-use */ - } /* * check if device has a phantom vbd; the phantom is hooked * to the frontend device (for ease of cleanup), so lookup @@ -151,38 +149,42 @@ void xenstore_parse_domain_config(int domid) continue; free(fpath); fpath = xs_read(xsh, XBT_NULL, buf, &len); - if (fpath != NULL) { + if (fpath) { if (pasprintf(&buf, "%s/dev", fpath) == -1) continue; + free(params); params = xs_read(xsh, XBT_NULL, buf , &len); - if (params != NULL) { - free(hd_filename[hd_index]); - hd_filename[hd_index] = params; - params = NULL; /* don't free params on re-use */ + if (params) { /* * wait for device, on timeout silently fail because we will * fail to open below */ - waitForDevice(hd_filename[hd_index]); + waitForDevice(params); } } + bs_table[hd_index] = bdrv_new(dev); - /* re-establish buf */ - if (pasprintf(&buf, "%s/params", bpath) == -1) - continue; /* check if it is a cdrom */ if (type && !strcmp(type, "cdrom")) { bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM); - xs_watch(xsh, buf, dev); + if (pasprintf(&buf, "%s/params", bpath) != -1) + xs_watch(xsh, buf, dev); } - if (hd_filename[hd_index]) { - if (bdrv_open(bs_table[hd_index], hd_filename[hd_index], - 0 /* snapshot */) < 0) + /* open device now if media present */ + if (params[0]) { + if (bdrv_open(bs_table[hd_index], params, 0 /* snapshot */) < 0) fprintf(stderr, "qemu: could not open hard disk image '%s'\n", - hd_filename[hd_index]); + params); } } + /* Set a watch for log-dirty requests from the migration tools */ + if (pasprintf(&buf, "%s/logdirty/next-active", path) != -1) { + xs_watch(xsh, buf, "logdirty"); + fprintf(logfile, "Watching %s\n", buf); + } + + out: free(type); free(params); @@ -201,6 +203,116 @@ int xenstore_fd(void) return -1; } +unsigned long *logdirty_bitmap = NULL; +unsigned long logdirty_bitmap_size; +extern int vga_ram_size, bios_size; + +void xenstore_process_logdirty_event(void) +{ + char *act; + static char *active_path = NULL; + static char *next_active_path = NULL; + static char *seg = NULL; + unsigned int len; + int i; + + fprintf(logfile, "Triggered log-dirty buffer switch\n"); + + if (!seg) { + char *path, *p, *key_ascii, key_terminated[17] = {0,}; + key_t key; + int shmid; + + /* Find and map the shared memory segment for log-dirty bitmaps */ + if (!(path = xs_get_domain_path(xsh, domid))) { + fprintf(logfile, "Log-dirty: can't get domain path in store\n"); + exit(1); + } + if (!(path = realloc(path, strlen(path) + + strlen("/logdirty/next-active") + 1))) { + fprintf(logfile, "Log-dirty: out of memory\n"); + exit(1); + } + strcat(path, "/logdirty/"); + p = path + strlen(path); + strcpy(p, "key"); + + key_ascii = xs_read(xsh, XBT_NULL, path, &len); + if (!key_ascii) { + /* No key yet: wait for the next watch */ + free(path); + return; + } + strncpy(key_terminated, key_ascii, 16); + free(key_ascii); + key = (key_t) strtoull(key_terminated, NULL, 16); + + /* Figure out how bit the log-dirty bitmaps are */ + logdirty_bitmap_size = ((phys_ram_size + 0x20 + - (vga_ram_size + bios_size)) + >> (TARGET_PAGE_BITS)); /* nr of bits in map*/ + if (logdirty_bitmap_size > HVM_BELOW_4G_MMIO_START >> TARGET_PAGE_BITS) + logdirty_bitmap_size += + HVM_BELOW_4G_MMIO_LENGTH >> TARGET_PAGE_BITS; /* still bits */ + logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1) + / HOST_LONG_BITS); /* longs */ + logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */ + + /* Map the shared-memory segment */ + if ((shmid = shmget(key, + 2 * logdirty_bitmap_size, + S_IRUSR|S_IWUSR)) == -1 + || (seg = shmat(shmid, NULL, 0)) == (void *)-1) { + fprintf(logfile, "Log-dirty: can't map segment %16.16llx (%s)\n", + (unsigned long long) key, strerror(errno)); + exit(1); + } + + fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg); + + /* Double-check that the bitmaps are the size we expect */ + if (logdirty_bitmap_size != *(uint32_t *)seg) { + fprintf(logfile, "Log-dirty: got %lu, calc %lu\n", + *(uint32_t *)seg, logdirty_bitmap_size); + return; + } + + /* Remember the paths for the next-active and active entries */ + strcpy(p, "active"); + if (!(active_path = strdup(path))) { + fprintf(logfile, "Log-dirty: out of memory\n"); + exit(1); + } + strcpy(p, "next-active"); + if (!(next_active_path = strdup(path))) { + fprintf(logfile, "Log-dirty: out of memory\n"); + exit(1); + } + free(path); + } + + /* Read the required active buffer from the store */ + act = xs_read(xsh, XBT_NULL, next_active_path, &len); + if (!act) { + fprintf(logfile, "Log-dirty: can't read next-active\n"); + exit(1); + } + + /* Switch buffers */ + i = act[0] - '0'; + if (i != 0 && i != 1) { + fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act); + exit(1); + } + logdirty_bitmap = seg + i * logdirty_bitmap_size; + + /* Ack that we've switched */ + xs_write(xsh, XBT_NULL, active_path, act, len); + free(act); +} + + + void xenstore_process_event(void *opaque) { char **vec, *image = NULL; @@ -210,6 +322,11 @@ void xenstore_process_event(void *opaque) if (!vec) return; + if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) { + xenstore_process_logdirty_event(); + goto out; + } + if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) || strlen(vec[XS_WATCH_TOKEN]) != 3) goto out; @@ -220,13 +337,13 @@ void xenstore_process_event(void *opaque) do_eject(0, vec[XS_WATCH_TOKEN]); bs_table[hd_index]->filename[0] = 0; - if (hd_filename[hd_index]) { - free(hd_filename[hd_index]); - hd_filename[hd_index] = NULL; + if (media_filename[hd_index]) { + free(media_filename[hd_index]); + media_filename[hd_index] = NULL; } if (image[0]) { - hd_filename[hd_index] = strdup(image); + media_filename[hd_index] = strdup(image); xenstore_check_new_media_present(5000); } diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index ff034ea260..c924ea509a 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -58,7 +58,7 @@ GUEST_SRCS-$(CONFIG_POWERPC) += xc_dom_powerpc.c CFLAGS += -Werror -Wmissing-prototypes CFLAGS += -fno-strict-aliasing -CFLAGS += $(INCLUDES) -I. +CFLAGS += $(INCLUDES) -I. -I../xenstore # Needed for posix_fadvise64() in xc_linux.c CFLAGS-$(CONFIG_Linux) += -D_GNU_SOURCE diff --git a/tools/libxc/xc_core.c b/tools/libxc/xc_core.c index 3dcf51e131..3c1ff185a6 100644 --- a/tools/libxc/xc_core.c +++ b/tools/libxc/xc_core.c @@ -349,11 +349,7 @@ xc_domain_dumpcore_via_callback(int xc_handle, /* Map the shared info frame */ live_shinfo = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ, info.shared_info_frame); - if ( !live_shinfo -#ifdef __ia64__ - && !info.hvm -#endif - ) + if ( !live_shinfo && !info.hvm ) { PERROR("Couldn't map live_shinfo"); goto out; diff --git a/tools/libxc/xc_core_ia64.c b/tools/libxc/xc_core_ia64.c index 455d532ee2..dff561b3d4 100644 --- a/tools/libxc/xc_core_ia64.c +++ b/tools/libxc/xc_core_ia64.c @@ -22,6 +22,28 @@ #include "xc_core.h" #include "xc_efi.h" #include "xc_dom.h" +#include + +static int +xc_memory_map_cmp(const void *lhs__, const void *rhs__) +{ + const struct xc_core_memory_map *lhs = + (const struct xc_core_memory_map *)lhs__; + const struct xc_core_memory_map *rhs = + (const struct xc_core_memory_map *)rhs__; + + if (lhs->addr < rhs->addr) + return -1; + if (lhs->addr > rhs->addr) + return 1; + + /* memory map overlap isn't allowed. complain */ + DPRINTF("duplicated addresses are detected " + "(0x%" PRIx64 ", 0x%" PRIx64 "), " + "(0x%" PRIx64 ", 0x%" PRIx64 ")\n", + lhs->addr, lhs->size, rhs->addr, rhs->size); + return 0; +} int xc_core_arch_auto_translated_physmap(const xc_dominfo_t *info) @@ -111,6 +133,7 @@ memory_map_get_old_hvm(int xc_handle, xc_dominfo_t *info, } *mapp = map; *nr_entries = i; + qsort(map, *nr_entries, sizeof(map[0]), &xc_memory_map_cmp); return 0; out: @@ -196,6 +219,7 @@ xc_core_arch_memory_map_get(int xc_handle, xc_dominfo_t *info, ret = 0; out: munmap(memmap_info, PAGE_SIZE); + qsort(map, *nr_entries, sizeof(map[0]), &xc_memory_map_cmp); return ret; old: diff --git a/tools/libxc/xc_core_x86.c b/tools/libxc/xc_core_x86.c index 6ea775aef6..bd82110713 100644 --- a/tools/libxc/xc_core_x86.c +++ b/tools/libxc/xc_core_x86.c @@ -21,12 +21,15 @@ #include "xg_private.h" #include "xc_core.h" +static int max_gpfn(int xc_handle, domid_t domid) +{ + return xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &domid); +} + int xc_core_arch_auto_translated_physmap(const xc_dominfo_t *info) { - if ( info->hvm ) - return 1; - return 0; + return info->hvm; } int @@ -35,14 +38,14 @@ xc_core_arch_memory_map_get(int xc_handle, xc_dominfo_t *info, xc_core_memory_map_t **mapp, unsigned int *nr_entries) { - unsigned long max_pfn = live_shinfo->arch.max_pfn; - xc_core_memory_map_t *map = NULL; + unsigned long max_pfn = max_gpfn(xc_handle, info->domid); + xc_core_memory_map_t *map; map = malloc(sizeof(*map)); - if ( !map ) + if ( map == NULL ) { PERROR("Could not allocate memory"); - goto out; + return -1; } map->addr = 0; @@ -51,11 +54,6 @@ xc_core_arch_memory_map_get(int xc_handle, xc_dominfo_t *info, *mapp = map; *nr_entries = 1; return 0; - -out: - if ( map ) - free(map); - return -1; } int @@ -67,7 +65,7 @@ xc_core_arch_map_p2m(int xc_handle, xc_dominfo_t *info, xen_pfn_t *live_p2m_frame_list_list = NULL; xen_pfn_t *live_p2m_frame_list = NULL; uint32_t dom = info->domid; - unsigned long max_pfn = live_shinfo->arch.max_pfn; + unsigned long max_pfn = max_gpfn(xc_handle, info->domid); int ret = -1; int err; diff --git a/tools/libxc/xc_dom_x86.c b/tools/libxc/xc_dom_x86.c index 0641078f9c..6a71cec811 100644 --- a/tools/libxc/xc_dom_x86.c +++ b/tools/libxc/xc_dom_x86.c @@ -434,24 +434,12 @@ static int vcpu_x86_32(struct xc_dom_image *dom, void *ptr) { vcpu_guest_context_x86_32_t *ctxt = ptr; xen_pfn_t cr3_pfn; - int i; xc_dom_printf("%s: called\n", __FUNCTION__); /* clear everything */ memset(ctxt, 0, sizeof(*ctxt)); - /* Virtual IDT is empty at start-of-day. */ - for ( i = 0; i < 256; i++ ) - { - ctxt->trap_ctxt[i].vector = i; - ctxt->trap_ctxt[i].cs = FLAT_KERNEL_CS_X86_32; - } - - /* No callback handlers. */ - ctxt->event_callback_cs = FLAT_KERNEL_CS_X86_32; - ctxt->failsafe_callback_cs = FLAT_KERNEL_CS_X86_32; - ctxt->user_regs.ds = FLAT_KERNEL_DS_X86_32; ctxt->user_regs.es = FLAT_KERNEL_DS_X86_32; ctxt->user_regs.fs = FLAT_KERNEL_DS_X86_32; @@ -465,11 +453,10 @@ static int vcpu_x86_32(struct xc_dom_image *dom, void *ptr) dom->parms.virt_base + (dom->start_info_pfn) * PAGE_SIZE_X86; ctxt->user_regs.eflags = 1 << 9; /* Interrupt Enable */ - ctxt->kernel_ss = FLAT_KERNEL_SS_X86_32; - ctxt->kernel_sp = - dom->parms.virt_base + (dom->bootstack_pfn + 1) * PAGE_SIZE_X86; + ctxt->kernel_ss = ctxt->user_regs.ss; + ctxt->kernel_sp = ctxt->user_regs.esp; - ctxt->flags = VGCF_in_kernel_X86_32; + ctxt->flags = VGCF_in_kernel_X86_32 | VGCF_online_X86_32; if ( dom->parms.pae == 2 /* extended_cr3 */ || dom->parms.pae == 3 /* bimodal */ ) ctxt->vm_assist |= (1UL << VMASST_TYPE_pae_extended_cr3); @@ -486,20 +473,12 @@ static int vcpu_x86_64(struct xc_dom_image *dom, void *ptr) { vcpu_guest_context_x86_64_t *ctxt = ptr; xen_pfn_t cr3_pfn; - int i; xc_dom_printf("%s: called\n", __FUNCTION__); /* clear everything */ memset(ctxt, 0, sizeof(*ctxt)); - /* Virtual IDT is empty at start-of-day. */ - for ( i = 0; i < 256; i++ ) - { - ctxt->trap_ctxt[i].vector = i; - ctxt->trap_ctxt[i].cs = FLAT_KERNEL_CS_X86_64; - } - ctxt->user_regs.ds = FLAT_KERNEL_DS_X86_64; ctxt->user_regs.es = FLAT_KERNEL_DS_X86_64; ctxt->user_regs.fs = FLAT_KERNEL_DS_X86_64; @@ -513,11 +492,10 @@ static int vcpu_x86_64(struct xc_dom_image *dom, void *ptr) dom->parms.virt_base + (dom->start_info_pfn) * PAGE_SIZE_X86; ctxt->user_regs.rflags = 1 << 9; /* Interrupt Enable */ - ctxt->kernel_ss = FLAT_KERNEL_SS_X86_64; - ctxt->kernel_sp = - dom->parms.virt_base + (dom->bootstack_pfn + 1) * PAGE_SIZE_X86; + ctxt->kernel_ss = ctxt->user_regs.ss; + ctxt->kernel_sp = ctxt->user_regs.esp; - ctxt->flags = VGCF_in_kernel_X86_64; + ctxt->flags = VGCF_in_kernel_X86_64 | VGCF_online_X86_64; cr3_pfn = xc_dom_p2m_guest(dom, dom->pgtables_seg.pfn); ctxt->ctrlreg[3] = xen_pfn_to_cr3_x86_64(cr3_pfn); xc_dom_printf("%s: cr3: pfn 0x%" PRIpfn " mfn 0x%" PRIpfn "\n", diff --git a/tools/libxc/xc_hvm_build.c b/tools/libxc/xc_hvm_build.c index 2238d315bc..751aa9cf7a 100644 --- a/tools/libxc/xc_hvm_build.c +++ b/tools/libxc/xc_hvm_build.c @@ -137,6 +137,12 @@ static void build_e820map(void *e820_page, unsigned long long mem_size) e820entry[nr_map].type = E820_RAM; nr_map++; + /* Explicitly reserve space for special pages (ioreq and xenstore). */ + e820entry[nr_map].addr = mem_size - PAGE_SIZE * 3; + e820entry[nr_map].size = PAGE_SIZE * 3; + e820entry[nr_map].type = E820_RESERVED; + nr_map++; + if ( extra_mem_size ) { e820entry[nr_map].addr = (1ULL << 32); @@ -280,7 +286,6 @@ static int setup_guest(int xc_handle, /* NB. evtchn_upcall_mask is unused: leave as zero. */ memset(&shared_info->evtchn_mask[0], 0xff, sizeof(shared_info->evtchn_mask)); - shared_info->arch.max_pfn = page_array[nr_pages - 1]; munmap(shared_info, PAGE_SIZE); if ( v_end > HVM_BELOW_4G_RAM_END ) @@ -302,9 +307,15 @@ static int setup_guest(int xc_handle, /* Set [er]ip in the way that's right for Xen */ if ( strstr(caps, "x86_64") ) + { ctxt->c64.user_regs.rip = elf_uval(&elf, elf.ehdr, e_entry); + ctxt->c64.flags = VGCF_online; + } else + { ctxt->c32.user_regs.eip = elf_uval(&elf, elf.ehdr, e_entry); + ctxt->c32.flags = VGCF_online; + } return 0; @@ -344,7 +355,7 @@ static int xc_hvm_build_internal(int xc_handle, memset(&launch_domctl, 0, sizeof(launch_domctl)); launch_domctl.domain = (domid_t)domid; - launch_domctl.u.vcpucontext.vcpu = 0; + launch_domctl.u.vcpucontext.vcpu = 0; set_xen_guest_handle(launch_domctl.u.vcpucontext.ctxt, &ctxt.c); launch_domctl.cmd = XEN_DOMCTL_setvcpucontext; rc = xc_domctl(xc_handle, &launch_domctl); diff --git a/tools/libxc/xc_hvm_restore.c b/tools/libxc/xc_hvm_restore.c index 001fe2a6e4..4b54b0aaf5 100644 --- a/tools/libxc/xc_hvm_restore.c +++ b/tools/libxc/xc_hvm_restore.c @@ -70,9 +70,6 @@ int xc_hvm_restore(int xc_handle, int io_fd, { DECLARE_DOMCTL; - /* The new domain's shared-info frame number. */ - unsigned long shared_info_frame; - /* A copy of the CPU context of the guest. */ vcpu_guest_context_t ctxt; @@ -86,8 +83,6 @@ int xc_hvm_restore(int xc_handle, int io_fd, uint8_t *hvm_buf = NULL; unsigned long long v_end, memsize; unsigned long shared_page_nr; - shared_info_t *shared_info = NULL; - xen_pfn_t arch_max_pfn; unsigned long pfn; unsigned int prev_pc, this_pc; @@ -96,11 +91,12 @@ int xc_hvm_restore(int xc_handle, int io_fd, /* Types of the pfns in the current region */ unsigned long region_pfn_type[MAX_BATCH_SIZE]; - struct xen_add_to_physmap xatp; - /* Number of pages of memory the guest has. *Not* the same as max_pfn. */ unsigned long nr_pages; + /* The size of an array big enough to contain all guest pfns */ + unsigned long pfn_array_size = max_pfn + 1; + /* hvm guest mem size (Mb) */ memsize = (unsigned long long)*store_mfn; v_end = memsize << 20; @@ -127,7 +123,7 @@ int xc_hvm_restore(int xc_handle, int io_fd, } - pfns = malloc(max_pfn * sizeof(xen_pfn_t)); + pfns = malloc(pfn_array_size * sizeof(xen_pfn_t)); if (pfns == NULL) { ERROR("memory alloc failed"); errno = ENOMEM; @@ -139,11 +135,10 @@ int xc_hvm_restore(int xc_handle, int io_fd, goto out; } - for ( i = 0; i < max_pfn; i++ ) + for ( i = 0; i < pfn_array_size; i++ ) pfns[i] = i; - for ( i = HVM_BELOW_4G_RAM_END >> PAGE_SHIFT; i < max_pfn; i++ ) + for ( i = HVM_BELOW_4G_RAM_END >> PAGE_SHIFT; i < pfn_array_size; i++ ) pfns[i] += HVM_BELOW_4G_MMIO_LENGTH >> PAGE_SHIFT; - arch_max_pfn = pfns[max_pfn - 1];/* used later */ /* Allocate memory for HVM guest, skipping VGA hole 0xA0000-0xC0000. */ rc = xc_domain_memory_populate_physmap( @@ -281,6 +276,14 @@ int xc_hvm_restore(int xc_handle, int io_fd, else shared_page_nr = (v_end >> PAGE_SHIFT) - 1; + /* Paranoia: clean pages. */ + if ( xc_clear_domain_page(xc_handle, dom, shared_page_nr) || + xc_clear_domain_page(xc_handle, dom, shared_page_nr-1) || + xc_clear_domain_page(xc_handle, dom, shared_page_nr-2) ) { + ERROR("error clearing comms frames!\n"); + goto out; + } + xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, shared_page_nr-1); xc_set_hvm_param(xc_handle, dom, HVM_PARAM_BUFIOREQ_PFN, shared_page_nr-2); xc_set_hvm_param(xc_handle, dom, HVM_PARAM_IOREQ_PFN, shared_page_nr); @@ -289,29 +292,6 @@ int xc_hvm_restore(int xc_handle, int io_fd, *store_mfn = (v_end >> PAGE_SHIFT) - 2; DPRINTF("hvm restore:calculate new store_mfn=0x%lx,v_end=0x%llx..\n", *store_mfn, v_end); - /* restore hvm context including pic/pit/shpage */ - if (!read_exact(io_fd, &rec_len, sizeof(uint32_t))) { - ERROR("error read hvm context size!\n"); - goto out; - } - - hvm_buf = malloc(rec_len); - if (hvm_buf == NULL) { - ERROR("memory alloc for hvm context buffer failed"); - errno = ENOMEM; - goto out; - } - - if (!read_exact(io_fd, hvm_buf, rec_len)) { - ERROR("error read hvm buffer!\n"); - goto out; - } - - if (( rc = xc_domain_hvm_setcontext(xc_handle, dom, hvm_buf, rec_len))) { - ERROR("error set hvm buffer!\n"); - goto out; - } - if (!read_exact(io_fd, &nr_vcpus, sizeof(uint32_t))) { ERROR("error read nr vcpu !\n"); goto out; @@ -339,28 +319,28 @@ int xc_hvm_restore(int xc_handle, int io_fd, } } - /* Shared-info pfn */ - if (!read_exact(io_fd, &(shared_info_frame), sizeof(uint32_t)) ) { - ERROR("reading the shared-info pfn failed!\n"); + /* restore hvm context including pic/pit/shpage */ + if (!read_exact(io_fd, &rec_len, sizeof(uint32_t))) { + ERROR("error read hvm context size!\n"); goto out; } - /* Map the shared-info frame where it was before */ - xatp.domid = dom; - xatp.space = XENMAPSPACE_shared_info; - xatp.idx = 0; - xatp.gpfn = shared_info_frame; - if ( (rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp)) != 0 ) { - ERROR("setting the shared-info pfn failed!\n"); + + hvm_buf = malloc(rec_len); + if (hvm_buf == NULL) { + ERROR("memory alloc for hvm context buffer failed"); + errno = ENOMEM; goto out; } - if ( (xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp) != 0) || - ((shared_info = xc_map_foreign_range( - xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, - shared_info_frame)) == NULL) ) + + if (!read_exact(io_fd, hvm_buf, rec_len)) { + ERROR("error read hvm buffer!\n"); goto out; - /* shared_info.arch.max_pfn is used by dump-core */ - shared_info->arch.max_pfn = arch_max_pfn; - munmap(shared_info, PAGE_SIZE); + } + + if (( rc = xc_domain_hvm_setcontext(xc_handle, dom, hvm_buf, rec_len))) { + ERROR("error set hvm buffer!\n"); + goto out; + } rc = 0; goto out; diff --git a/tools/libxc/xc_hvm_save.c b/tools/libxc/xc_hvm_save.c index d1b44bd1c6..75a017cf7c 100644 --- a/tools/libxc/xc_hvm_save.c +++ b/tools/libxc/xc_hvm_save.c @@ -27,12 +27,14 @@ #include #include #include -#include #include "xc_private.h" #include "xg_private.h" #include "xg_save_restore.h" +#include +#include + /* ** Default values for important tuning parameters. Can override by passing ** non-zero replacement values to xc_hvm_save(). @@ -49,11 +51,30 @@ static unsigned long max_mfn; /* virtual starting address of the hypervisor */ static unsigned long hvirt_start; -/* #levels of page tables used by the currrent guest */ +/* #levels of page tables used by the current guest */ static unsigned int pt_levels; -/* total number of pages used by the current guest */ -static unsigned long max_pfn; +/* Shared-memory bitmaps for getting log-dirty bits from qemu */ +static unsigned long *qemu_bitmaps[2]; +static int qemu_active; +static int qemu_non_active; + +int xc_hvm_drain_io(int handle, domid_t dom) +{ + DECLARE_HYPERCALL; + xen_hvm_drain_io_t arg; + int rc; + + hypercall.op = __HYPERVISOR_hvm_op; + hypercall.arg[0] = HVMOP_drain_io; + hypercall.arg[1] = (unsigned long)&arg; + arg.domid = dom; + if ( lock_pages(&arg, sizeof(arg)) != 0 ) + return -1; + rc = do_xen_hypercall(handle, &hypercall); + unlock_pages(&arg, sizeof(arg)); + return rc; +} /* ** During (live) save/migrate, we maintain a number of bitmaps to track @@ -61,7 +82,8 @@ static unsigned long max_pfn; */ #define BITS_PER_LONG (sizeof(unsigned long) * 8) -#define BITMAP_SIZE ((max_pfn + BITS_PER_LONG - 1) / 8) +#define BITS_TO_LONGS(bits) (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define BITMAP_SIZE (BITS_TO_LONGS(pfn_array_size) * sizeof(unsigned long)) #define BITMAP_ENTRY(_nr,_bmap) \ ((unsigned long *)(_bmap))[(_nr)/BITS_PER_LONG] @@ -108,6 +130,7 @@ static inline int permute( int i, int nr, int order_nr ) return i; } + static uint64_t tv_to_us(struct timeval *new) { return (new->tv_sec * 1000000) + new->tv_usec; @@ -183,7 +206,7 @@ static int print_stats(int xc_handle, uint32_t domid, int pages_sent, return 0; } -static int analysis_phase(int xc_handle, uint32_t domid, int max_pfn, +static int analysis_phase(int xc_handle, uint32_t domid, int pfn_array_size, unsigned long *arr, int runs) { long long start, now; @@ -196,7 +219,7 @@ static int analysis_phase(int xc_handle, uint32_t domid, int max_pfn, int i; xc_shadow_control(xc_handle, domid, XEN_DOMCTL_SHADOW_OP_CLEAN, - arr, max_pfn, NULL, 0, NULL); + arr, pfn_array_size, NULL, 0, NULL); DPRINTF("#Flush\n"); for ( i = 0; i < 40; i++ ) { usleep(50000); @@ -236,7 +259,7 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd, if (info->shutdown && info->shutdown_reason == SHUTDOWN_suspend) - return 0; // success + return 0; // success if (info->paused) { // try unpausing domain, wait, and retest @@ -261,17 +284,26 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd, } int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, - uint32_t max_factor, uint32_t flags, int (*suspend)(int)) + uint32_t max_factor, uint32_t flags, int (*suspend)(int), + void *(*init_qemu_maps)(int, unsigned), + void (*qemu_flip_buffer)(int, int)) { xc_dominfo_t info; int rc = 1, i, j, last_iter, iter = 0; int live = (flags & XCFLAGS_LIVE); int debug = (flags & XCFLAGS_DEBUG); + int stdvga = (flags & XCFLAGS_STDVGA); int sent_last_iter, skip_this_iter; - /* The new domain's shared-info frame number. */ - unsigned long shared_info_frame; + /* The highest guest-physical frame number used by the current guest */ + unsigned long max_pfn; + + /* The size of an array big enough to contain all guest pfns */ + unsigned long pfn_array_size; + + /* Other magic frames: ioreqs and xenstore comms */ + unsigned long ioreq_pfn, bufioreq_pfn, store_pfn; /* A copy of the CPU context of the guest. */ vcpu_guest_context_t ctxt; @@ -283,15 +315,12 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, uint32_t hvm_buf_size; uint8_t *hvm_buf = NULL; - /* Live mapping of shared info structure */ - shared_info_t *live_shinfo = NULL; - /* base of the region in which domain memory is mapped */ unsigned char *region_base = NULL; uint32_t rec_size, nr_vcpus; - /* power of 2 order of max_pfn */ + /* power of 2 order of pfn_array_size */ int order_nr; /* bitmap of pages: @@ -337,7 +366,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, ERROR("HVM:Could not get vcpu context"); goto out; } - shared_info_frame = info.shared_info_frame; /* cheesy sanity check */ if ((info.max_memkb >> (PAGE_SHIFT - 10)) > max_mfn) { @@ -346,10 +374,12 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, goto out; } - /* Map the shared info frame */ - if(!(live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, - PROT_READ, shared_info_frame))) { - ERROR("HVM:Couldn't map live_shinfo"); + if ( xc_get_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, &store_pfn) + || xc_get_hvm_param(xc_handle, dom, HVM_PARAM_IOREQ_PFN, &ioreq_pfn) + || xc_get_hvm_param(xc_handle, dom, + HVM_PARAM_BUFIOREQ_PFN, &bufioreq_pfn) ) + { + ERROR("HVM: Could not read magic PFN parameters"); goto out; } @@ -357,8 +387,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, "nr_pages=0x%lx\n", info.max_memkb, max_mfn, info.nr_pages); if (live) { - ERROR("hvm domain doesn't support live migration now.\n"); - goto out; if (xc_shadow_control(xc_handle, dom, XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY, @@ -368,6 +396,7 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, } last_iter = 0; + DPRINTF("hvm domain live migration debug start: logdirty enable.\n"); } else { /* This is a non-live suspend. Issue the call back to get the @@ -388,20 +417,28 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, /* Calculate the highest PFN of "normal" memory: * HVM memory is sequential except for the VGA and MMIO holes. */ - max_pfn = info.nr_pages; + max_pfn = info.nr_pages - 1; + /* If the domain has a Cirrus framebuffer and we haven't already + * suspended qemu-dm, it will have 8MB of framebuffer memory + * still allocated, which we don't want to copy: qemu will save it + * for us later */ + if ( live && !stdvga ) + max_pfn -= 0x800; /* Skip the VGA hole from 0xa0000 to 0xc0000 */ - max_pfn += 0x20; + max_pfn += 0x20; /* Skip the MMIO hole: 256MB just below 4GB */ if ( max_pfn >= (HVM_BELOW_4G_MMIO_START >> PAGE_SHIFT) ) max_pfn += (HVM_BELOW_4G_MMIO_LENGTH >> PAGE_SHIFT); - skip_this_iter = 0;/*XXX*/ - /* pretend we sent all the pages last iteration */ - sent_last_iter = max_pfn; + /* Size of any array that covers 0 ... max_pfn */ + pfn_array_size = max_pfn + 1; - /* calculate the power of 2 order of max_pfn, e.g. + /* pretend we sent all the pages last iteration */ + sent_last_iter = pfn_array_size; + + /* calculate the power of 2 order of pfn_array_size, e.g. 15->4 16->4 17->5 */ - for (i = max_pfn-1, order_nr = 0; i ; i >>= 1, order_nr++) + for (i = pfn_array_size-1, order_nr = 0; i ; i >>= 1, order_nr++) continue; /* Setup to_send / to_fix and to_skip bitmaps */ @@ -409,6 +446,15 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, to_skip = malloc(BITMAP_SIZE); + if (live) { + /* Get qemu-dm logging dirty pages too */ + void *seg = init_qemu_maps(dom, BITMAP_SIZE); + qemu_bitmaps[0] = seg; + qemu_bitmaps[1] = seg + BITMAP_SIZE; + qemu_active = 0; + qemu_non_active = 1; + } + hvm_buf_size = xc_domain_hvm_getcontext(xc_handle, dom, 0, 0); if ( hvm_buf_size == -1 ) { @@ -435,7 +481,7 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, return 1; } - analysis_phase(xc_handle, dom, max_pfn, to_skip, 0); + analysis_phase(xc_handle, dom, pfn_array_size, to_skip, 0); /* We want zeroed memory so use calloc rather than malloc. */ @@ -465,9 +511,10 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, DPRINTF("Saving HVM domain memory pages: iter %d 0%%", iter); - while( N < max_pfn ){ + while( N < pfn_array_size ){ - unsigned int this_pc = (N * 100) / max_pfn; + unsigned int this_pc = (N * 100) / pfn_array_size; + int rc; if ((this_pc - prev_pc) >= 5) { DPRINTF("\b\b\b\b%3d%%", this_pc); @@ -476,9 +523,9 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, /* slightly wasteful to peek the whole array evey time, but this is fast enough for the moment. */ - if (!last_iter && xc_shadow_control( - xc_handle, dom, XEN_DOMCTL_SHADOW_OP_PEEK, - to_skip, max_pfn, NULL, 0, NULL) != max_pfn) { + if (!last_iter && (rc = xc_shadow_control( + xc_handle, dom, XEN_DOMCTL_SHADOW_OP_PEEK, to_skip, + pfn_array_size, NULL, 0, NULL)) != pfn_array_size) { ERROR("Error peeking HVM shadow bitmap"); goto out; } @@ -486,11 +533,11 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, /* load pfn_batch[] with the mfn of all the pages we're doing in this batch. */ - for (batch = 0; batch < MAX_BATCH_SIZE && N < max_pfn ; N++) { + for (batch = 0; batch < MAX_BATCH_SIZE && N < pfn_array_size; N++){ - int n = permute(N, max_pfn, order_nr); + int n = permute(N, pfn_array_size, order_nr); - if (debug) { + if (0&&debug) { DPRINTF("%d pfn= %08lx %d \n", iter, (unsigned long)n, test_bit(n, to_send)); } @@ -505,7 +552,10 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, /* Skip PFNs that aren't really there */ if ((n >= 0xa0 && n < 0xc0) /* VGA hole */ || (n >= (HVM_BELOW_4G_MMIO_START >> PAGE_SHIFT) - && n < (1ULL << 32) >> PAGE_SHIFT)) /* 4G MMIO hole */ + && n < (1ULL << 32) >> PAGE_SHIFT) /* 4G MMIO hole */ + || n == store_pfn + || n == ioreq_pfn + || n == bufioreq_pfn) continue; /* @@ -570,7 +620,7 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, print_stats( xc_handle, dom, sent_this_iter, &stats, 1); DPRINTF("Total pages sent= %ld (%.2fx)\n", - total_sent, ((float)total_sent)/max_pfn ); + total_sent, ((float)total_sent)/pfn_array_size ); } if (last_iter && debug){ @@ -597,7 +647,7 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, ((sent_this_iter > sent_last_iter) && RATE_IS_MAX()) || (iter >= max_iters) || (sent_this_iter+skip_this_iter < 50) || - (total_sent > max_pfn*max_factor) ) { + (total_sent > pfn_array_size*max_factor) ) { DPRINTF("Start last iteration for HVM domain\n"); last_iter = 1; @@ -608,23 +658,36 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, goto out; } - DPRINTF("SUSPEND shinfo %08lx eip %08lx edx %08lx\n", - info.shared_info_frame, + DPRINTF("SUSPEND eip %08lx edx %08lx\n", (unsigned long)ctxt.user_regs.eip, (unsigned long)ctxt.user_regs.edx); } if (xc_shadow_control(xc_handle, dom, XEN_DOMCTL_SHADOW_OP_CLEAN, to_send, - max_pfn, NULL, 0, &stats) != max_pfn) { + pfn_array_size, NULL, + 0, &stats) != pfn_array_size) { ERROR("Error flushing shadow PT"); goto out; } + /* Pull in the dirty bits from qemu too */ + if (!last_iter) { + qemu_active = qemu_non_active; + qemu_non_active = qemu_active ? 0 : 1; + qemu_flip_buffer(dom, qemu_active); + for (j = 0; j < BITMAP_SIZE / sizeof(unsigned long); j++) { + to_send[j] |= qemu_bitmaps[qemu_non_active][j]; + qemu_bitmaps[qemu_non_active][j] = 0; + } + } else { + for (j = 0; j < BITMAP_SIZE / sizeof(unsigned long); j++) + to_send[j] |= qemu_bitmaps[qemu_active][j]; + } + sent_last_iter = sent_this_iter; print_stats(xc_handle, dom, sent_this_iter, &stats, 1); - } @@ -640,20 +703,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, goto out; } - if ( (rec_size = xc_domain_hvm_getcontext(xc_handle, dom, hvm_buf, - hvm_buf_size)) == -1) { - ERROR("HVM:Could not get hvm buffer"); - goto out; - } - - if (!write_exact(io_fd, &rec_size, sizeof(uint32_t))) { - ERROR("error write hvm buffer size"); - goto out; - } - - if ( !write_exact(io_fd, hvm_buf, rec_size) ) { - ERROR("write HVM info failed!\n"); - } /* save vcpu/vmcs context */ if (!write_exact(io_fd, &nr_vcpus, sizeof(uint32_t))) { @@ -682,12 +731,21 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, } } - /* Shared-info pfn */ - if (!write_exact(io_fd, &(shared_info_frame), sizeof(uint32_t)) ) { - ERROR("write shared-info pfn failed!\n"); + if ( (rec_size = xc_domain_hvm_getcontext(xc_handle, dom, hvm_buf, + hvm_buf_size)) == -1) { + ERROR("HVM:Could not get hvm buffer"); goto out; } - + + if (!write_exact(io_fd, &rec_size, sizeof(uint32_t))) { + ERROR("error write hvm buffer size"); + goto out; + } + + if ( !write_exact(io_fd, hvm_buf, rec_size) ) { + ERROR("write HVM info failed!\n"); + } + /* Success! */ rc = 0; diff --git a/tools/libxc/xc_linux_restore.c b/tools/libxc/xc_linux_restore.c index 6fa0388d3f..d3a87262a0 100644 --- a/tools/libxc/xc_linux_restore.c +++ b/tools/libxc/xc_linux_restore.c @@ -189,6 +189,7 @@ int xc_linux_restore(int xc_handle, int io_fd, uint64_t vcpumap = 1ULL; unsigned int max_vcpu_id = 0; + int new_ctxt_format = 0; max_pfn = nr_pfns; @@ -372,6 +373,7 @@ int xc_linux_restore(int xc_handle, int io_fd, } if (j == -2) { + new_ctxt_format = 1; if (!read_exact(io_fd, &max_vcpu_id, sizeof(int)) || (max_vcpu_id >= 64) || !read_exact(io_fd, &vcpumap, sizeof(uint64_t))) { @@ -797,6 +799,9 @@ int xc_linux_restore(int xc_handle, int io_fd, goto out; } + if ( !new_ctxt_format ) + ctxt.flags |= VGCF_online; + if (i == 0) { /* * Uncanonicalise the suspend-record frame number and poke diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c index b2a648528a..987eb0eb13 100644 --- a/tools/libxc/xc_misc.c +++ b/tools/libxc/xc_misc.c @@ -33,6 +33,25 @@ int xc_readconsolering(int xc_handle, return ret; } +int xc_send_debug_keys(int xc_handle, char *keys) +{ + int ret, len = strlen(keys); + DECLARE_SYSCTL; + + sysctl.cmd = XEN_SYSCTL_debug_keys; + set_xen_guest_handle(sysctl.u.debug_keys.keys, keys); + sysctl.u.debug_keys.nr_keys = len; + + if ( (ret = lock_pages(keys, len)) != 0 ) + return ret; + + ret = do_sysctl(xc_handle, &sysctl); + + unlock_pages(keys, len); + + return ret; +} + int xc_physinfo(int xc_handle, xc_physinfo_t *put_info) { diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c index 77321c458b..3e2557e581 100644 --- a/tools/libxc/xc_private.c +++ b/tools/libxc/xc_private.c @@ -23,7 +23,7 @@ void xc_default_error_handler(const xc_error const *err) fprintf(stderr, "ERROR %s: %s\n", desc, err->message); } -const xc_error const *xc_get_last_error(void) +const xc_error *xc_get_last_error(void) { return &last_error; } @@ -263,6 +263,15 @@ int xc_memory_op(int xc_handle, goto out1; } break; + case XENMEM_current_reservation: + case XENMEM_maximum_reservation: + case XENMEM_maximum_gpfn: + if ( lock_pages(arg, sizeof(domid_t)) ) + { + PERROR("Could not lock"); + goto out1; + } + break; } ret = do_xen_hypercall(xc_handle, &hypercall); @@ -287,6 +296,11 @@ int xc_memory_op(int xc_handle, case XENMEM_add_to_physmap: unlock_pages(arg, sizeof(struct xen_add_to_physmap)); break; + case XENMEM_current_reservation: + case XENMEM_maximum_reservation: + case XENMEM_maximum_gpfn: + unlock_pages(arg, sizeof(domid_t)); + break; } out1: diff --git a/tools/libxc/xc_ptrace_core.c b/tools/libxc/xc_ptrace_core.c index 82d06bb2d8..42d49cfcb7 100644 --- a/tools/libxc/xc_ptrace_core.c +++ b/tools/libxc/xc_ptrace_core.c @@ -390,7 +390,6 @@ map_gmfn_to_offset_elf(unsigned long gmfn) { /* * linear search - * There is no gurantee that those tables are sorted. */ unsigned long i; if (current_is_auto_translated_physmap) { diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 199750de73..4b346a74f0 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -467,6 +467,8 @@ int xc_readconsolering(int xc_handle, unsigned int *pnr_chars, int clear); +int xc_send_debug_keys(int xc_handle, char *keys); + typedef xen_sysctl_physinfo_t xc_physinfo_t; int xc_physinfo(int xc_handle, xc_physinfo_t *info); @@ -770,19 +772,19 @@ typedef struct { * data pointed to are only valid until the next call to * libxc. */ -const xc_error const *xc_get_last_error(void); +const xc_error *xc_get_last_error(void); /* * Clear the last error */ void xc_clear_last_error(void); -typedef void (*xc_error_handler)(const xc_error const* err); +typedef void (*xc_error_handler)(const xc_error * const err); /* * The default error handler which prints to stderr */ -void xc_default_error_handler(const xc_error const* err); +void xc_default_error_handler(const xc_error * const err); /* * Convert an error code into a text description diff --git a/tools/libxc/xenguest.h b/tools/libxc/xenguest.h index cb3c6a4d1c..76b7413f15 100644 --- a/tools/libxc/xenguest.h +++ b/tools/libxc/xenguest.h @@ -12,6 +12,7 @@ #define XCFLAGS_LIVE 1 #define XCFLAGS_DEBUG 2 #define XCFLAGS_HVM 4 +#define XCFLAGS_STDVGA 8 /** @@ -31,8 +32,10 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, * @return 0 on success, -1 on failure */ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, - uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */, - int (*suspend)(int domid)); + uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */, + int (*suspend)(int domid), + void *(*init_qemu_maps)(int, unsigned), + void (*qemu_flip_buffer)(int, int)); /** * This function will restore a saved domain running Linux. @@ -155,6 +158,8 @@ int xc_set_hvm_param( int xc_get_hvm_param( int handle, domid_t dom, int param, unsigned long *value); +int xc_hvm_drain_io(int handle, domid_t dom); + /* PowerPC specific. */ int xc_prose_build(int xc_handle, uint32_t domid, diff --git a/tools/libxc/xg_private.c b/tools/libxc/xg_private.c index 63ffea4aad..1014131004 100644 --- a/tools/libxc/xg_private.c +++ b/tools/libxc/xg_private.c @@ -201,7 +201,9 @@ __attribute__((weak)) __attribute__((weak)) int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, uint32_t max_factor, uint32_t flags, - int (*suspend)(int domid)) + int (*suspend)(int domid), + void *(*init_qemu_maps)(int, unsigned), + void (*qemu_flip_buffer)(int, int)) { errno = ENOSYS; return -1; @@ -229,6 +231,11 @@ __attribute__((weak)) int xc_set_hvm_param( return -ENOSYS; } +__attribute__((weak)) int xc_hvm_drain_io(int handle, domid_t dom) +{ + return -ENOSYS; +} + /* * Local variables: * mode: C diff --git a/tools/libxen/include/xen_crashdump.h b/tools/libxen/include/xen_crashdump.h index fff0a1a144..00869dbb4c 100644 --- a/tools/libxen/include/xen_crashdump.h +++ b/tools/libxen/include/xen_crashdump.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, XenSource Inc. + * Copyright (c) 2006-2007, XenSource Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -161,20 +161,6 @@ extern bool xen_crashdump_get_by_uuid(xen_session *session, xen_crashdump *result, char *uuid); -/** - * Create a new crashdump instance, and return its handle. - */ -extern bool -xen_crashdump_create(xen_session *session, xen_crashdump *result, xen_crashdump_record *record); - - -/** - * Destroy the specified crashdump instance. - */ -extern bool -xen_crashdump_destroy(xen_session *session, xen_crashdump crashdump); - - /** * Get the uuid field of the given crashdump. */ @@ -196,6 +182,13 @@ extern bool xen_crashdump_get_vdi(xen_session *session, xen_vdi *result, xen_crashdump crashdump); +/** + * Destroy the specified crashdump + */ +extern bool +xen_crashdump_destroy(xen_session *session, xen_crashdump self); + + /** * Return a list of all the crashdumps known to the system. */ diff --git a/tools/libxen/include/xen_vbd.h b/tools/libxen/include/xen_vbd.h index 86ad38f207..14a6685a95 100644 --- a/tools/libxen/include/xen_vbd.h +++ b/tools/libxen/include/xen_vbd.h @@ -72,7 +72,6 @@ typedef struct xen_vbd_record struct xen_vm_record_opt *vm; struct xen_vdi_record_opt *vdi; char *device; - char *image; bool bootable; enum xen_vbd_mode mode; enum xen_vbd_type type; @@ -357,6 +356,22 @@ extern bool xen_vbd_media_change(xen_session *session, xen_vbd vbd, xen_vdi vdi); +/** + * Hotplug the specified VBD, dynamically attaching it to the running + * VM + */ +extern bool +xen_vbd_plug(xen_session *session, xen_vbd self); + + +/** + * Hot-unplug the specified VBD, dynamically unattaching it from the + * running VM + */ +extern bool +xen_vbd_unplug(xen_session *session, xen_vbd self); + + /** * Return a list of all the VBDs known to the system. */ diff --git a/tools/libxen/include/xen_vdi.h b/tools/libxen/include/xen_vdi.h index 90120370d5..9ebb8fd9ee 100644 --- a/tools/libxen/include/xen_vdi.h +++ b/tools/libxen/include/xen_vdi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, XenSource Inc. + * Copyright (c) 2006-2007, XenSource Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,6 +22,7 @@ #include "xen_common.h" #include "xen_crashdump_decl.h" #include "xen_sr_decl.h" +#include "xen_string_string_map.h" #include "xen_vbd_decl.h" #include "xen_vdi_decl.h" #include "xen_vdi_type.h" @@ -73,11 +74,10 @@ typedef struct xen_vdi_record struct xen_crashdump_record_opt_set *crash_dumps; int64_t virtual_size; int64_t physical_utilisation; - int64_t sector_size; - char *location; enum xen_vdi_type type; bool sharable; bool read_only; + xen_string_string_map *other_config; } xen_vdi_record; /** @@ -250,13 +250,6 @@ extern bool xen_vdi_get_physical_utilisation(xen_session *session, int64_t *result, xen_vdi vdi); -/** - * Get the sector_size field of the given VDI. - */ -extern bool -xen_vdi_get_sector_size(xen_session *session, int64_t *result, xen_vdi vdi); - - /** * Get the type field of the given VDI. */ @@ -278,6 +271,13 @@ extern bool xen_vdi_get_read_only(xen_session *session, bool *result, xen_vdi vdi); +/** + * Get the other_config field of the given VDI. + */ +extern bool +xen_vdi_get_other_config(xen_session *session, xen_string_string_map **result, xen_vdi vdi); + + /** * Set the name/label field of the given VDI. */ @@ -292,13 +292,6 @@ extern bool xen_vdi_set_name_description(xen_session *session, xen_vdi vdi, char *description); -/** - * Set the SR field of the given VDI. - */ -extern bool -xen_vdi_set_sr(xen_session *session, xen_vdi vdi, xen_sr sr); - - /** * Set the virtual_size field of the given VDI. */ @@ -320,6 +313,30 @@ extern bool xen_vdi_set_read_only(xen_session *session, xen_vdi vdi, bool read_only); +/** + * Set the other_config field of the given VDI. + */ +extern bool +xen_vdi_set_other_config(xen_session *session, xen_vdi vdi, xen_string_string_map *other_config); + + +/** + * Add the given key-value pair to the other_config field of the given + * VDI. + */ +extern bool +xen_vdi_add_to_other_config(xen_session *session, xen_vdi vdi, char *key, char *value); + + +/** + * Remove the given key and its corresponding value from the + * other_config field of the given VDI. If the key is not in that Map, then + * do nothing. + */ +extern bool +xen_vdi_remove_from_other_config(xen_session *session, xen_vdi vdi, char *key); + + /** * Take an exact copy of the VDI; the snapshot lives in the same * Storage Repository as its parent. diff --git a/tools/libxen/include/xen_vif.h b/tools/libxen/include/xen_vif.h index 05a070aff4..8a1cffb7bd 100644 --- a/tools/libxen/include/xen_vif.h +++ b/tools/libxen/include/xen_vif.h @@ -331,6 +331,22 @@ extern bool xen_vif_remove_from_qos_algorithm_params(xen_session *session, xen_vif vif, char *key); +/** + * Hotplug the specified VIF, dynamically attaching it to the running + * VM + */ +extern bool +xen_vif_plug(xen_session *session, xen_vif self); + + +/** + * Hot-unplug the specified VIF, dynamically unattaching it from the + * running VM + */ +extern bool +xen_vif_unplug(xen_session *session, xen_vif self); + + /** * Return a list of all the VIFs known to the system. */ diff --git a/tools/libxen/include/xen_vm.h b/tools/libxen/include/xen_vm.h index 71a3f62ca4..ddce6a8d1d 100644 --- a/tools/libxen/include/xen_vm.h +++ b/tools/libxen/include/xen_vm.h @@ -40,39 +40,6 @@ * The VM class. * * A virtual machine (or 'guest'). - * - * VM booting is controlled by setting one of the two mutually exclusive - * groups: "PV", and "HVM". If HVM.boot_policy is the empty string, then - * paravirtual domain building and booting will be used; otherwise the VM will - * be loaded as an HVM domain, and booted using an emulated BIOS. - * - * When paravirtual booting is in use, the PV/bootloader field indicates the - * bootloader to use. It may be "pygrub", in which case the platform's - * default installation of pygrub will be used, or a full path within the - * control domain to some other bootloader. The other fields, PV/kernel, - * PV/ramdisk, PV/args and PV/bootloader_args will be passed to the bootloader - * unmodified, and interpretation of those fields is then specific to the - * bootloader itself, including the possibility that the bootloader will - * ignore some or all of those given values. Finally the paths of all bootable - * disks are added to the bootloader commandline (a disk is bootable if its - * VBD has the bootable flag set). There may be zero, one or many bootable - * disks; the bootloader decides which disk (if any) to boot from. - * - * If the bootloader is pygrub, then the menu.lst is parsed if present in the - * guest's filesystem, otherwise the specified kernel and ramdisk are used, or - * an autodetected kernel is used if nothing is specified and autodetection is - * possible. PV/args is appended to the kernel command line, no matter which - * mechanism is used for finding the kernel. - * - * If PV/bootloader is empty but PV/kernel is specified, then the kernel and - * ramdisk values will be treated as paths within the control domain. If both - * PV/bootloader and PV/kernel are empty, then the behaviour is as if - * PV/bootloader was specified as "pygrub". - * - * When using HVM booting, HVM/boot_policy and HVM/boot_params specify the - * boot handling. Only one policy is currently defined: "BIOS order". In - * this case, HVM/boot_params should contain one key-value pair "order" = "N" - * where N is the string that will be passed to QEMU.. */ @@ -120,7 +87,6 @@ typedef struct xen_vm_record int64_t memory_dynamic_max; int64_t memory_dynamic_min; int64_t memory_static_min; - char *vcpus_policy; xen_string_string_map *vcpus_params; int64_t vcpus_max; int64_t vcpus_at_startup; @@ -139,11 +105,7 @@ typedef struct xen_vm_record char *pv_bootloader_args; char *hvm_boot_policy; xen_string_string_map *hvm_boot_params; - bool platform_std_vga; - char *platform_serial; - bool platform_localtime; - bool platform_clock_offset; - bool platform_enable_audio; + xen_string_string_map *platform; char *pci_bus; xen_string_string_map *other_config; int64_t domid; @@ -359,13 +321,6 @@ extern bool xen_vm_get_memory_static_min(xen_session *session, int64_t *result, xen_vm vm); -/** - * Get the VCPUs/policy field of the given VM. - */ -extern bool -xen_vm_get_vcpus_policy(xen_session *session, char **result, xen_vm vm); - - /** * Get the VCPUs/params field of the given VM. */ @@ -493,38 +448,10 @@ xen_vm_get_hvm_boot_params(xen_session *session, xen_string_string_map **result, /** - * Get the platform/std_VGA field of the given VM. + * Get the platform field of the given VM. */ extern bool -xen_vm_get_platform_std_vga(xen_session *session, bool *result, xen_vm vm); - - -/** - * Get the platform/serial field of the given VM. - */ -extern bool -xen_vm_get_platform_serial(xen_session *session, char **result, xen_vm vm); - - -/** - * Get the platform/localtime field of the given VM. - */ -extern bool -xen_vm_get_platform_localtime(xen_session *session, bool *result, xen_vm vm); - - -/** - * Get the platform/clock_offset field of the given VM. - */ -extern bool -xen_vm_get_platform_clock_offset(xen_session *session, bool *result, xen_vm vm); - - -/** - * Get the platform/enable_audio field of the given VM. - */ -extern bool -xen_vm_get_platform_enable_audio(xen_session *session, bool *result, xen_vm vm); +xen_vm_get_platform(xen_session *session, xen_string_string_map **result, xen_vm vm); /** @@ -632,13 +559,6 @@ extern bool xen_vm_set_memory_static_min(xen_session *session, xen_vm vm, int64_t static_min); -/** - * Set the VCPUs/policy field of the given VM. - */ -extern bool -xen_vm_set_vcpus_policy(xen_session *session, xen_vm vm, char *policy); - - /** * Set the VCPUs/params field of the given VM. */ @@ -765,38 +685,32 @@ xen_vm_remove_from_hvm_boot_params(xen_session *session, xen_vm vm, char *key); /** - * Set the platform/std_VGA field of the given VM. + * Set the platform field of the given VM. */ extern bool -xen_vm_set_platform_std_vga(xen_session *session, xen_vm vm, bool std_vga); +xen_vm_set_platform(xen_session *session, xen_vm vm, xen_string_string_map *platform); /** - * Set the platform/serial field of the given VM. + * Add the given key-value pair to the platform field of the given VM. */ extern bool -xen_vm_set_platform_serial(xen_session *session, xen_vm vm, char *serial); +xen_vm_add_to_platform(xen_session *session, xen_vm vm, char *key, char *value); /** - * Set the platform/localtime field of the given VM. + * Remove the given key and its corresponding value from the platform + * field of the given VM. If the key is not in that Map, then do nothing. */ extern bool -xen_vm_set_platform_localtime(xen_session *session, xen_vm vm, bool localtime); +xen_vm_remove_from_platform(xen_session *session, xen_vm vm, char *key); /** - * Set the platform/clock_offset field of the given VM. + * Set the PCI_bus field of the given VM. */ extern bool -xen_vm_set_platform_clock_offset(xen_session *session, xen_vm vm, bool clock_offset); - - -/** - * Set the platform/enable_audio field of the given VM. - */ -extern bool -xen_vm_set_platform_enable_audio(xen_session *session, xen_vm vm, bool enable_audio); +xen_vm_set_pci_bus(xen_session *session, xen_vm vm, char *pci_bus); /** diff --git a/tools/libxen/src/xen_common.c b/tools/libxen/src/xen_common.c index c6e2181850..f2c9644521 100644 --- a/tools/libxen/src/xen_common.c +++ b/tools/libxen/src/xen_common.c @@ -110,7 +110,7 @@ parse_structmap_value(xen_session *, xmlNode *, const abstract_type *, static size_t size_of_member(const abstract_type *); static const char * -get_val_as_string(const struct abstract_type *, void *, char *); +get_val_as_string(const struct abstract_type *, void *, char *, size_t); void @@ -666,8 +666,7 @@ static void parse_into(xen_session *s, xmlNode *value_node, { if (!is_container_node(value_node, "value") || value_node->children->type != XML_ELEMENT_NODE || - 0 != strcmp((char *)value_node->children->name, "struct") || - value_node->children->children == NULL) + 0 != strcmp((char *)value_node->children->name, "struct")) { server_error(s, "Expected Map from the server, but didn't get it"); @@ -890,6 +889,9 @@ static size_t size_of_member(const abstract_type *type) case REF: return sizeof(arbitrary_record_opt *); + case STRUCT: + return type->struct_size; + default: assert(false); } @@ -1183,7 +1185,8 @@ add_struct_value(const struct abstract_type *type, void *value, case INT: case ENUM: { - const char *val_as_string = get_val_as_string(type, value, buf); + const char *val_as_string = + get_val_as_string(type, value, buf, sizeof(buf)); adder(node, key, "string", val_as_string); } break; @@ -1215,7 +1218,8 @@ add_struct_value(const struct abstract_type *type, void *value, for (size_t i = 0; i < set_val->size; i++) { - void *member_value = set_val->contents + (i * member_size); + void *member_value = (char *)set_val->contents + + (i * member_size); add_struct_value(member_type, member_value, add_unnamed_value, NULL, data_node); } @@ -1254,7 +1258,7 @@ add_struct_value(const struct abstract_type *type, void *value, void *r_value = contents + (i * member_size) + r_offset; const char *l_value_as_string = - get_val_as_string(l_type, l_value, buf); + get_val_as_string(l_type, l_value, buf, sizeof(buf)); add_struct_value(r_type, r_value, add_struct_member, l_value_as_string, struct_node); @@ -1270,7 +1274,8 @@ add_struct_value(const struct abstract_type *type, void *value, static const char * -get_val_as_string(const struct abstract_type *type, void *value, char *buf) +get_val_as_string(const struct abstract_type *type, void *value, char *buf, + size_t bufsize) { switch (type->typename) { @@ -1304,7 +1309,7 @@ get_val_as_string(const struct abstract_type *type, void *value, char *buf) case INT: { int64_t val = *(int64_t *)value; - snprintf(buf, sizeof(buf), "%"PRId64, val); + snprintf(buf, bufsize, "%"PRId64, val); return buf; } break; diff --git a/tools/libxen/src/xen_crashdump.c b/tools/libxen/src/xen_crashdump.c index 53504ba249..2d3840896e 100644 --- a/tools/libxen/src/xen_crashdump.c +++ b/tools/libxen/src/xen_crashdump.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, XenSource Inc. + * Copyright (c) 2006-2007, XenSource Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -114,37 +114,6 @@ xen_crashdump_get_by_uuid(xen_session *session, xen_crashdump *result, char *uui } -bool -xen_crashdump_create(xen_session *session, xen_crashdump *result, xen_crashdump_record *record) -{ - abstract_value param_values[] = - { - { .type = &xen_crashdump_record_abstract_type_, - .u.struct_val = record } - }; - - abstract_type result_type = abstract_type_string; - - *result = NULL; - XEN_CALL_("crashdump.create"); - return session->ok; -} - - -bool -xen_crashdump_destroy(xen_session *session, xen_crashdump crashdump) -{ - abstract_value param_values[] = - { - { .type = &abstract_type_string, - .u.string_val = crashdump } - }; - - xen_call_(session, "crashdump.destroy", param_values, 1, NULL, NULL); - return session->ok; -} - - bool xen_crashdump_get_vm(xen_session *session, xen_vm *result, xen_crashdump crashdump) { @@ -179,6 +148,20 @@ xen_crashdump_get_vdi(xen_session *session, xen_vdi *result, xen_crashdump crash } +bool +xen_crashdump_destroy(xen_session *session, xen_crashdump self) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = self } + }; + + xen_call_(session, "crashdump.destroy", param_values, 1, NULL, NULL); + return session->ok; +} + + bool xen_crashdump_get_all(xen_session *session, struct xen_crashdump_set **result) { diff --git a/tools/libxen/src/xen_vbd.c b/tools/libxen/src/xen_vbd.c index def7403ef9..893bf70958 100644 --- a/tools/libxen/src/xen_vbd.c +++ b/tools/libxen/src/xen_vbd.c @@ -54,9 +54,6 @@ static const struct_member xen_vbd_record_struct_members[] = { .key = "device", .type = &abstract_type_string, .offset = offsetof(xen_vbd_record, device) }, - { .key = "image", - .type = &abstract_type_string, - .offset = offsetof(xen_vbd_record, image) }, { .key = "bootable", .type = &abstract_type_bool, .offset = offsetof(xen_vbd_record, bootable) }, @@ -551,6 +548,34 @@ xen_vbd_media_change(xen_session *session, xen_vbd vbd, xen_vdi vdi) } +bool +xen_vbd_plug(xen_session *session, xen_vbd self) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = self } + }; + + xen_call_(session, "VBD.plug", param_values, 1, NULL, NULL); + return session->ok; +} + + +bool +xen_vbd_unplug(xen_session *session, xen_vbd self) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = self } + }; + + xen_call_(session, "VBD.unplug", param_values, 1, NULL, NULL); + return session->ok; +} + + bool xen_vbd_get_all(xen_session *session, struct xen_vbd_set **result) { diff --git a/tools/libxen/src/xen_vdi.c b/tools/libxen/src/xen_vdi.c index 150d341b1b..10f3fc4066 100644 --- a/tools/libxen/src/xen_vdi.c +++ b/tools/libxen/src/xen_vdi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, XenSource Inc. + * Copyright (c) 2006-2007, XenSource Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,7 @@ #include "xen_crashdump.h" #include "xen_internal.h" #include "xen_sr.h" +#include "xen_string_string_map.h" #include "xen_vbd.h" #include "xen_vdi.h" #include "xen_vdi_type_internal.h" @@ -64,12 +65,6 @@ static const struct_member xen_vdi_record_struct_members[] = { .key = "physical_utilisation", .type = &abstract_type_int, .offset = offsetof(xen_vdi_record, physical_utilisation) }, - { .key = "sector_size", - .type = &abstract_type_int, - .offset = offsetof(xen_vdi_record, sector_size) }, - { .key = "location", - .type = &abstract_type_string, - .offset = offsetof(xen_vdi_record, location) }, { .key = "type", .type = &xen_vdi_type_abstract_type_, .offset = offsetof(xen_vdi_record, type) }, @@ -78,7 +73,10 @@ static const struct_member xen_vdi_record_struct_members[] = .offset = offsetof(xen_vdi_record, sharable) }, { .key = "read_only", .type = &abstract_type_bool, - .offset = offsetof(xen_vdi_record, read_only) } + .offset = offsetof(xen_vdi_record, read_only) }, + { .key = "other_config", + .type = &abstract_type_string_string_map, + .offset = offsetof(xen_vdi_record, other_config) } }; const abstract_type xen_vdi_record_abstract_type_ = @@ -105,6 +103,7 @@ xen_vdi_record_free(xen_vdi_record *record) xen_sr_record_opt_free(record->sr); xen_vbd_record_opt_set_free(record->vbds); xen_crashdump_record_opt_set_free(record->crash_dumps); + xen_string_string_map_free(record->other_config); free(record); } @@ -314,22 +313,6 @@ xen_vdi_get_physical_utilisation(xen_session *session, int64_t *result, xen_vdi } -bool -xen_vdi_get_sector_size(xen_session *session, int64_t *result, xen_vdi vdi) -{ - abstract_value param_values[] = - { - { .type = &abstract_type_string, - .u.string_val = vdi } - }; - - abstract_type result_type = abstract_type_int; - - XEN_CALL_("VDI.get_sector_size"); - return session->ok; -} - - bool xen_vdi_get_type(xen_session *session, enum xen_vdi_type *result, xen_vdi vdi) { @@ -377,6 +360,23 @@ xen_vdi_get_read_only(xen_session *session, bool *result, xen_vdi vdi) } +bool +xen_vdi_get_other_config(xen_session *session, xen_string_string_map **result, xen_vdi vdi) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = vdi } + }; + + abstract_type result_type = abstract_type_string_string_map; + + *result = NULL; + XEN_CALL_("VDI.get_other_config"); + return session->ok; +} + + bool xen_vdi_set_name_label(xen_session *session, xen_vdi vdi, char *label) { @@ -409,22 +409,6 @@ xen_vdi_set_name_description(xen_session *session, xen_vdi vdi, char *descriptio } -bool -xen_vdi_set_sr(xen_session *session, xen_vdi vdi, xen_sr sr) -{ - abstract_value param_values[] = - { - { .type = &abstract_type_string, - .u.string_val = vdi }, - { .type = &abstract_type_string, - .u.string_val = sr } - }; - - xen_call_(session, "VDI.set_SR", param_values, 2, NULL, NULL); - return session->ok; -} - - bool xen_vdi_set_virtual_size(xen_session *session, xen_vdi vdi, int64_t virtual_size) { @@ -473,6 +457,56 @@ xen_vdi_set_read_only(xen_session *session, xen_vdi vdi, bool read_only) } +bool +xen_vdi_set_other_config(xen_session *session, xen_vdi vdi, xen_string_string_map *other_config) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = vdi }, + { .type = &abstract_type_string_string_map, + .u.set_val = (arbitrary_set *)other_config } + }; + + xen_call_(session, "VDI.set_other_config", param_values, 2, NULL, NULL); + return session->ok; +} + + +bool +xen_vdi_add_to_other_config(xen_session *session, xen_vdi vdi, char *key, char *value) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = vdi }, + { .type = &abstract_type_string, + .u.string_val = key }, + { .type = &abstract_type_string, + .u.string_val = value } + }; + + xen_call_(session, "VDI.add_to_other_config", param_values, 3, NULL, NULL); + return session->ok; +} + + +bool +xen_vdi_remove_from_other_config(xen_session *session, xen_vdi vdi, char *key) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = vdi }, + { .type = &abstract_type_string, + .u.string_val = key } + }; + + xen_call_(session, "VDI.remove_from_other_config", param_values, 2, NULL, NULL); + return session->ok; +} + + bool xen_vdi_snapshot(xen_session *session, xen_vdi *result, xen_vdi vdi) { diff --git a/tools/libxen/src/xen_vif.c b/tools/libxen/src/xen_vif.c index 11cba1dcbd..a139a83bc3 100644 --- a/tools/libxen/src/xen_vif.c +++ b/tools/libxen/src/xen_vif.c @@ -499,6 +499,34 @@ xen_vif_remove_from_qos_algorithm_params(xen_session *session, xen_vif vif, char } +bool +xen_vif_plug(xen_session *session, xen_vif self) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = self } + }; + + xen_call_(session, "VIF.plug", param_values, 1, NULL, NULL); + return session->ok; +} + + +bool +xen_vif_unplug(xen_session *session, xen_vif self) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = self } + }; + + xen_call_(session, "VIF.unplug", param_values, 1, NULL, NULL); + return session->ok; +} + + bool xen_vif_get_all(xen_session *session, struct xen_vif_set **result) { diff --git a/tools/libxen/src/xen_vm.c b/tools/libxen/src/xen_vm.c index 910c9f8b31..f80916188e 100644 --- a/tools/libxen/src/xen_vm.c +++ b/tools/libxen/src/xen_vm.c @@ -88,9 +88,6 @@ static const struct_member xen_vm_record_struct_members[] = { .key = "memory_static_min", .type = &abstract_type_int, .offset = offsetof(xen_vm_record, memory_static_min) }, - { .key = "VCPUs_policy", - .type = &abstract_type_string, - .offset = offsetof(xen_vm_record, vcpus_policy) }, { .key = "VCPUs_params", .type = &abstract_type_string_string_map, .offset = offsetof(xen_vm_record, vcpus_params) }, @@ -145,21 +142,9 @@ static const struct_member xen_vm_record_struct_members[] = { .key = "HVM_boot_params", .type = &abstract_type_string_string_map, .offset = offsetof(xen_vm_record, hvm_boot_params) }, - { .key = "platform_std_VGA", - .type = &abstract_type_bool, - .offset = offsetof(xen_vm_record, platform_std_vga) }, - { .key = "platform_serial", - .type = &abstract_type_string, - .offset = offsetof(xen_vm_record, platform_serial) }, - { .key = "platform_localtime", - .type = &abstract_type_bool, - .offset = offsetof(xen_vm_record, platform_localtime) }, - { .key = "platform_clock_offset", - .type = &abstract_type_bool, - .offset = offsetof(xen_vm_record, platform_clock_offset) }, - { .key = "platform_enable_audio", - .type = &abstract_type_bool, - .offset = offsetof(xen_vm_record, platform_enable_audio) }, + { .key = "platform", + .type = &abstract_type_string_string_map, + .offset = offsetof(xen_vm_record, platform) }, { .key = "PCI_bus", .type = &abstract_type_string, .offset = offsetof(xen_vm_record, pci_bus) }, @@ -203,7 +188,6 @@ xen_vm_record_free(xen_vm_record *record) free(record->name_description); xen_vdi_record_opt_free(record->suspend_vdi); xen_host_record_opt_free(record->resident_on); - free(record->vcpus_policy); xen_string_string_map_free(record->vcpus_params); xen_console_record_opt_set_free(record->consoles); xen_vif_record_opt_set_free(record->vifs); @@ -217,7 +201,7 @@ xen_vm_record_free(xen_vm_record *record) free(record->pv_bootloader_args); free(record->hvm_boot_policy); xen_string_string_map_free(record->hvm_boot_params); - free(record->platform_serial); + xen_string_string_map_free(record->platform); free(record->pci_bus); xen_string_string_map_free(record->other_config); xen_vm_metrics_record_opt_free(record->metrics); @@ -509,23 +493,6 @@ xen_vm_get_memory_static_min(xen_session *session, int64_t *result, xen_vm vm) } -bool -xen_vm_get_vcpus_policy(xen_session *session, char **result, xen_vm vm) -{ - abstract_value param_values[] = - { - { .type = &abstract_type_string, - .u.string_val = vm } - }; - - abstract_type result_type = abstract_type_string; - - *result = NULL; - XEN_CALL_("VM.get_VCPUs_policy"); - return session->ok; -} - - bool xen_vm_get_vcpus_params(xen_session *session, xen_string_string_map **result, xen_vm vm) { @@ -825,7 +792,7 @@ xen_vm_get_hvm_boot_params(xen_session *session, xen_string_string_map **result, bool -xen_vm_get_platform_std_vga(xen_session *session, bool *result, xen_vm vm) +xen_vm_get_platform(xen_session *session, xen_string_string_map **result, xen_vm vm) { abstract_value param_values[] = { @@ -833,74 +800,10 @@ xen_vm_get_platform_std_vga(xen_session *session, bool *result, xen_vm vm) .u.string_val = vm } }; - abstract_type result_type = abstract_type_bool; - - XEN_CALL_("VM.get_platform_std_VGA"); - return session->ok; -} - - -bool -xen_vm_get_platform_serial(xen_session *session, char **result, xen_vm vm) -{ - abstract_value param_values[] = - { - { .type = &abstract_type_string, - .u.string_val = vm } - }; - - abstract_type result_type = abstract_type_string; + abstract_type result_type = abstract_type_string_string_map; *result = NULL; - XEN_CALL_("VM.get_platform_serial"); - return session->ok; -} - - -bool -xen_vm_get_platform_localtime(xen_session *session, bool *result, xen_vm vm) -{ - abstract_value param_values[] = - { - { .type = &abstract_type_string, - .u.string_val = vm } - }; - - abstract_type result_type = abstract_type_bool; - - XEN_CALL_("VM.get_platform_localtime"); - return session->ok; -} - - -bool -xen_vm_get_platform_clock_offset(xen_session *session, bool *result, xen_vm vm) -{ - abstract_value param_values[] = - { - { .type = &abstract_type_string, - .u.string_val = vm } - }; - - abstract_type result_type = abstract_type_bool; - - XEN_CALL_("VM.get_platform_clock_offset"); - return session->ok; -} - - -bool -xen_vm_get_platform_enable_audio(xen_session *session, bool *result, xen_vm vm) -{ - abstract_value param_values[] = - { - { .type = &abstract_type_string, - .u.string_val = vm } - }; - - abstract_type result_type = abstract_type_bool; - - XEN_CALL_("VM.get_platform_enable_audio"); + XEN_CALL_("VM.get_platform"); return session->ok; } @@ -1149,22 +1052,6 @@ xen_vm_set_memory_static_min(xen_session *session, xen_vm vm, int64_t static_min } -bool -xen_vm_set_vcpus_policy(xen_session *session, xen_vm vm, char *policy) -{ - abstract_value param_values[] = - { - { .type = &abstract_type_string, - .u.string_val = vm }, - { .type = &abstract_type_string, - .u.string_val = policy } - }; - - xen_call_(session, "VM.set_VCPUs_policy", param_values, 2, NULL, NULL); - return session->ok; -} - - bool xen_vm_set_vcpus_params(xen_session *session, xen_vm vm, xen_string_string_map *params) { @@ -1442,81 +1329,67 @@ xen_vm_remove_from_hvm_boot_params(xen_session *session, xen_vm vm, char *key) bool -xen_vm_set_platform_std_vga(xen_session *session, xen_vm vm, bool std_vga) +xen_vm_set_platform(xen_session *session, xen_vm vm, xen_string_string_map *platform) { abstract_value param_values[] = { { .type = &abstract_type_string, .u.string_val = vm }, - { .type = &abstract_type_bool, - .u.bool_val = std_vga } + { .type = &abstract_type_string_string_map, + .u.set_val = (arbitrary_set *)platform } }; - xen_call_(session, "VM.set_platform_std_VGA", param_values, 2, NULL, NULL); + xen_call_(session, "VM.set_platform", param_values, 2, NULL, NULL); return session->ok; } bool -xen_vm_set_platform_serial(xen_session *session, xen_vm vm, char *serial) +xen_vm_add_to_platform(xen_session *session, xen_vm vm, char *key, char *value) { abstract_value param_values[] = { { .type = &abstract_type_string, .u.string_val = vm }, { .type = &abstract_type_string, - .u.string_val = serial } + .u.string_val = key }, + { .type = &abstract_type_string, + .u.string_val = value } }; - xen_call_(session, "VM.set_platform_serial", param_values, 2, NULL, NULL); + xen_call_(session, "VM.add_to_platform", param_values, 3, NULL, NULL); return session->ok; } bool -xen_vm_set_platform_localtime(xen_session *session, xen_vm vm, bool localtime) +xen_vm_remove_from_platform(xen_session *session, xen_vm vm, char *key) { abstract_value param_values[] = { { .type = &abstract_type_string, .u.string_val = vm }, - { .type = &abstract_type_bool, - .u.bool_val = localtime } + { .type = &abstract_type_string, + .u.string_val = key } }; - xen_call_(session, "VM.set_platform_localtime", param_values, 2, NULL, NULL); + xen_call_(session, "VM.remove_from_platform", param_values, 2, NULL, NULL); return session->ok; } bool -xen_vm_set_platform_clock_offset(xen_session *session, xen_vm vm, bool clock_offset) +xen_vm_set_pci_bus(xen_session *session, xen_vm vm, char *pci_bus) { abstract_value param_values[] = { { .type = &abstract_type_string, .u.string_val = vm }, - { .type = &abstract_type_bool, - .u.bool_val = clock_offset } - }; - - xen_call_(session, "VM.set_platform_clock_offset", param_values, 2, NULL, NULL); - return session->ok; -} - - -bool -xen_vm_set_platform_enable_audio(xen_session *session, xen_vm vm, bool enable_audio) -{ - abstract_value param_values[] = - { { .type = &abstract_type_string, - .u.string_val = vm }, - { .type = &abstract_type_bool, - .u.bool_val = enable_audio } + .u.string_val = pci_bus } }; - xen_call_(session, "VM.set_platform_enable_audio", param_values, 2, NULL, NULL); + xen_call_(session, "VM.set_PCI_bus", param_values, 2, NULL, NULL); return session->ok; } diff --git a/tools/libxen/test/test_bindings.c b/tools/libxen/test/test_bindings.c index 6a51cd3a05..92f2d9b6ca 100644 --- a/tools/libxen/test/test_bindings.c +++ b/tools/libxen/test/test_bindings.c @@ -373,8 +373,9 @@ static xen_vm create_new_vm(xen_session *session, bool hvm) .memory_dynamic_max = 256, .memory_dynamic_min = 128, .memory_static_min = 128, - .vcpus_policy = "credit", .vcpus_params = vcpus_params, + .vcpus_max = 4, + .vcpus_at_startup = 2, .actions_after_shutdown = XEN_ON_NORMAL_EXIT_DESTROY, .actions_after_reboot = XEN_ON_NORMAL_EXIT_RESTART, .actions_after_crash = XEN_ON_CRASH_BEHAVIOUR_PRESERVE, @@ -420,8 +421,7 @@ static xen_vm create_new_vm(xen_session *session, bool hvm) .name_label = "MyRootFS", .name_description = "MyRootFS description", .sr = &sr_record, - .virtual_size = (1 << 21), // 1GiB / 512 bytes/sector - .sector_size = 512, + .virtual_size = (INT64_C(1) << 30), // 1GiB .type = XEN_VDI_TYPE_SYSTEM, .sharable = false, .read_only = false diff --git a/tools/python/scripts/test_hvm_create.py b/tools/python/scripts/test_hvm_create.py index 7cae70539a..35abfe0396 100644 --- a/tools/python/scripts/test_hvm_create.py +++ b/tools/python/scripts/test_hvm_create.py @@ -39,14 +39,13 @@ vm_cfg = { local_vdi_cfg = { 'name_label': 'gentoo.hvm', 'name_description': '', - 'location': 'file:/root/gentoo.amd64.hvm.img', 'virtual_size': 0, - 'sector_size': 0, 'type': 'system', 'parent': '', 'SR_name': 'Local', 'sharable': False, 'read_only': False, + 'other_config': {'location': 'file:/root/gentoo.amd64.hvm.img'}, } local_vbd_cfg = { diff --git a/tools/python/scripts/test_vm_create.py b/tools/python/scripts/test_vm_create.py index e4d8f3023a..6575f153ea 100644 --- a/tools/python/scripts/test_vm_create.py +++ b/tools/python/scripts/test_vm_create.py @@ -39,8 +39,7 @@ vm_cfg = { vdi_cfg = { 'name_label': 'API_VDI', 'name_description': '', - 'virtual_size': 100 * 1024 * 1024, - 'sector_size': 1024, + 'virtual_size': 100 * 1024 * 1024 * 1024, 'type': 'system', 'parent': '', 'SR_name': 'QCoW', @@ -60,14 +59,13 @@ vbd_cfg = { local_vdi_cfg = { 'name_label': 'gentoo.amd64.img', 'name_description': '', - 'location': 'file:/root/gentoo.amd64.img', 'virtual_size': 0, - 'sector_size': 0, 'type': 'system', 'parent': '', 'SR_name': 'Local', 'sharable': False, 'read_only': False, + 'other_config': {'location': 'file:/root/gentoo.amd64.img'}, } local_vbd_cfg = { diff --git a/tools/python/scripts/xapi.py b/tools/python/scripts/xapi.py index 1e49f86d4c..1a07795212 100644 --- a/tools/python/scripts/xapi.py +++ b/tools/python/scripts/xapi.py @@ -40,8 +40,7 @@ VM_LIST_FORMAT = '%(name_label)-18s %(memory_actual)-5s %(VCPUs_number)-5s'\ ' %(power_state)-10s %(uuid)-36s' SR_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(physical_size)-10s' \ '%(type)-10s' -VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s '\ - '%(sector_size)-8s' +VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s' VBD_LIST_FORMAT = '%(device)-6s %(uuid)-36s %(VDI)-8s' TASK_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(status)-8s %(progress)-4s' VIF_LIST_FORMAT = '%(name)-8s %(device)-7s %(uuid)-36s %(MAC)-10s' @@ -96,12 +95,9 @@ OPTIONS = { 'vdi-create': [(('--name-label',), {'help': 'Name for VDI'}), (('--name-description',), {'help': 'Description for VDI'}), - (('--sector-size',), {'type': 'int', - 'help': 'Sector size', - 'default': 0}), (('--virtual-size',), {'type': 'int', 'default': 0, - 'help': 'Size of VDI in sectors'}), + 'help': 'Size of VDI in bytes'}), (('--type',), {'choices': ['system', 'user', 'ephemeral'], 'default': 'system', 'help': 'VDI type'}), @@ -569,8 +565,7 @@ def xapi_vdi_list(args, async = False): if not is_long: print VDI_LIST_FORMAT % {'name_label': 'VDI Label', 'uuid' : 'UUID', - 'virtual_size': 'Bytes', - 'sector_size': 'Sector Size'} + 'virtual_size': 'Bytes'} for vdi in vdis: vdi_struct = execute(server, 'VDI.get_record', (session, vdi)) diff --git a/tools/python/scripts/xapi.vdicfg.py b/tools/python/scripts/xapi.vdicfg.py index 86129bfae9..cb63653550 100644 --- a/tools/python/scripts/xapi.vdicfg.py +++ b/tools/python/scripts/xapi.vdicfg.py @@ -1,7 +1,6 @@ name_label = 'VDI 1' name_description = '' -virtual_size = 10 * 1024 * 1024 -sector_size = 1024 +virtual_size = 10 * 1024 * 1024 * 1024 type = 'system' sharable = False read_only = False diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 1e40d515cb..975b7d3a38 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -47,20 +47,24 @@ static PyObject *dom_op(XcObject *self, PyObject *args, static PyObject *pyxc_error_to_exception(void) { PyObject *pyerr; - const xc_error const *err = xc_get_last_error(); + const xc_error *err = xc_get_last_error(); const char *desc = xc_error_code_to_desc(err->code); - if (err->code == XC_ERROR_NONE) + if ( err->code == XC_ERROR_NONE ) return PyErr_SetFromErrno(xc_error_obj); - if (err->message[0] != '\0') + if ( err->message[0] != '\0' ) pyerr = Py_BuildValue("(iss)", err->code, desc, err->message); else pyerr = Py_BuildValue("(is)", err->code, desc); xc_clear_last_error(); - PyErr_SetObject(xc_error_obj, pyerr); + if ( pyerr != NULL ) + { + PyErr_SetObject(xc_error_obj, pyerr); + Py_DECREF(pyerr); + } return NULL; } @@ -70,13 +74,13 @@ static PyObject *pyxc_domain_dumpcore(XcObject *self, PyObject *args) uint32_t dom; char *corefile; - if (!PyArg_ParseTuple(args, "is", &dom, &corefile)) + if ( !PyArg_ParseTuple(args, "is", &dom, &corefile) ) return NULL; if ( (corefile == NULL) || (corefile[0] == '\0') ) return NULL; - if (xc_domain_dumpcore(self->xc_handle, dom, corefile) != 0) + if ( xc_domain_dumpcore(self->xc_handle, dom, corefile) != 0 ) return pyxc_error_to_exception(); Py_INCREF(zero); @@ -168,10 +172,10 @@ static PyObject *pyxc_domain_shutdown(XcObject *self, PyObject *args) { uint32_t dom, reason; - if (!PyArg_ParseTuple(args, "ii", &dom, &reason)) + if ( !PyArg_ParseTuple(args, "ii", &dom, &reason) ) return NULL; - if (xc_domain_shutdown(self->xc_handle, dom, reason) != 0) + if ( xc_domain_shutdown(self->xc_handle, dom, reason) != 0 ) return pyxc_error_to_exception(); Py_INCREF(zero); @@ -183,10 +187,10 @@ static PyObject *pyxc_domain_resume(XcObject *self, PyObject *args) uint32_t dom; int fast; - if (!PyArg_ParseTuple(args, "ii", &dom, &fast)) + if ( !PyArg_ParseTuple(args, "ii", &dom, &fast) ) return NULL; - if (xc_domain_resume(self->xc_handle, dom, fast) != 0) + if ( xc_domain_resume(self->xc_handle, dom, fast) != 0 ) return pyxc_error_to_exception(); Py_INCREF(zero); @@ -282,7 +286,7 @@ static PyObject *pyxc_domain_getinfo(XcObject *self, PyObject *args, PyObject *kwds) { - PyObject *list, *info_dict; + PyObject *list, *info_dict, *pyhandle; uint32_t first_dom = 0; int max_doms = 1024, nr_doms, i, j; @@ -308,26 +312,34 @@ static PyObject *pyxc_domain_getinfo(XcObject *self, list = PyList_New(nr_doms); for ( i = 0 ; i < nr_doms; i++ ) { - PyObject *pyhandle = PyList_New(sizeof(xen_domain_handle_t)); + info_dict = Py_BuildValue( + "{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" + ",s:L,s:L,s:L,s:i,s:i}", + "domid", (int)info[i].domid, + "online_vcpus", info[i].nr_online_vcpus, + "max_vcpu_id", info[i].max_vcpu_id, + "hvm", info[i].hvm, + "dying", info[i].dying, + "crashed", info[i].crashed, + "shutdown", info[i].shutdown, + "paused", info[i].paused, + "blocked", info[i].blocked, + "running", info[i].running, + "mem_kb", (long long)info[i].nr_pages*(XC_PAGE_SIZE/1024), + "cpu_time", (long long)info[i].cpu_time, + "maxmem_kb", (long long)info[i].max_memkb, + "ssidref", (int)info[i].ssidref, + "shutdown_reason", info[i].shutdown_reason); + pyhandle = PyList_New(sizeof(xen_domain_handle_t)); + if ( (pyhandle == NULL) || (info_dict == NULL) ) + { + Py_DECREF(list); + if ( pyhandle != NULL ) { Py_DECREF(pyhandle); } + if ( info_dict != NULL ) { Py_DECREF(info_dict); } + return NULL; + } for ( j = 0; j < sizeof(xen_domain_handle_t); j++ ) PyList_SetItem(pyhandle, j, PyInt_FromLong(info[i].handle[j])); - info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" - ",s:l,s:L,s:l,s:i,s:i}", - "domid", info[i].domid, - "online_vcpus", info[i].nr_online_vcpus, - "max_vcpu_id", info[i].max_vcpu_id, - "hvm", info[i].hvm, - "dying", info[i].dying, - "crashed", info[i].crashed, - "shutdown", info[i].shutdown, - "paused", info[i].paused, - "blocked", info[i].blocked, - "running", info[i].running, - "mem_kb", info[i].nr_pages*(XC_PAGE_SIZE/1024), - "cpu_time", info[i].cpu_time, - "maxmem_kb", info[i].max_memkb, - "ssidref", info[i].ssidref, - "shutdown_reason", info[i].shutdown_reason); PyDict_SetItemString(info_dict, "handle", pyhandle); Py_DECREF(pyhandle); PyList_SetItem(list, i, info_dict); @@ -1007,6 +1019,24 @@ static PyObject *pyxc_domain_send_trigger(XcObject *self, return zero; } +static PyObject *pyxc_send_debug_keys(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + char *keys; + + static char *kwd_list[] = { "keys", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "s", kwd_list, &keys) ) + return NULL; + + if ( xc_send_debug_keys(self->xc_handle, keys) != 0 ) + return pyxc_error_to_exception(); + + Py_INCREF(zero); + return zero; +} + static PyObject *dom_op(XcObject *self, PyObject *args, int (*fn)(int, uint32_t)) { @@ -1380,6 +1410,12 @@ static PyMethodDef pyxc_methods[] = { " vcpu [int]: VCPU to be sent trigger.\n" "Returns: [int] 0 on success; -1 on error.\n" }, + { "send_debug_keys", + (PyCFunction)pyxc_send_debug_keys, + METH_VARARGS | METH_KEYWORDS, "\n" + "Inject debug keys into Xen.\n" + " keys [str]: String of keys to inject.\n" }, + #ifdef __powerpc__ { "arch_alloc_real_mode_area", (PyCFunction)pyxc_alloc_real_mode_area, diff --git a/tools/python/xen/util/blkif.py b/tools/python/xen/util/blkif.py index 363bd41dd2..15d20dde8c 100644 --- a/tools/python/xen/util/blkif.py +++ b/tools/python/xen/util/blkif.py @@ -66,16 +66,23 @@ def blkdev_segment(name): 'type' : 'Disk' } return val -def blkdev_uname_to_file(uname): - """Take a blkdev uname and return the corresponding filename.""" - fn = None +def _parse_uname(uname): + fn = taptype = None if uname.find(":") != -1: (typ, fn) = uname.split(":", 1) if typ == "phy" and not fn.startswith("/"): fn = "/dev/%s" %(fn,) if typ == "tap": - (typ, fn) = fn.split(":", 1) - return fn + (taptype, fn) = fn.split(":", 1) + return (fn, taptype) + +def blkdev_uname_to_file(uname): + """Take a blkdev uname and return the corresponding filename.""" + return _parse_uname(uname)[0] + +def blkdev_uname_to_taptype(uname): + """Take a blkdev uname and return the blktap type.""" + return _parse_uname(uname)[1] def mount_mode(name): mode = None diff --git a/tools/python/xen/util/xmlrpclib2.py b/tools/python/xen/util/xmlrpclib2.py index a77b61b5ee..3bdd717de2 100644 --- a/tools/python/xen/util/xmlrpclib2.py +++ b/tools/python/xen/util/xmlrpclib2.py @@ -200,6 +200,18 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer): else: response = self._dispatch(method, params) + if self.xenapi and \ + (response is None or + not isinstance(response, dict) or + 'Status' not in response): + log.exception('Internal error handling %s: Invalid result %s', + method, response) + response = { "Status": "Failure", + "ErrorDescription": + ['INTERNAL_ERROR', + 'Invalid result %s handling %s' % + (response, method)]} + # With either Unicode or normal strings, we can only transmit # \t, \n, \r, \u0020-\ud7ff, \ue000-\ufffd, and \u10000-\u10ffff # in an XML document. xmlrpclib does not escape these values @@ -215,24 +227,30 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer): response = xmlrpclib.dumps(response, methodresponse=1, allow_none=1) - except xmlrpclib.Fault, fault: - response = xmlrpclib.dumps(fault) except Exception, exn: - if self.xenapi: - if _is_not_supported(exn): - errdesc = ['MESSAGE_METHOD_UNKNOWN', method] + try: + if self.xenapi: + if _is_not_supported(exn): + errdesc = ['MESSAGE_METHOD_UNKNOWN', method] + else: + log.exception('Internal error handling %s', method) + errdesc = ['INTERNAL_ERROR', str(exn)] + + response = xmlrpclib.dumps( + ({ "Status": "Failure", + "ErrorDescription": errdesc },), + methodresponse = 1) else: - log.exception('Internal error handling %s', method) - errdesc = ['INTERNAL_ERROR', str(exn)] - response = xmlrpclib.dumps( - ({ "Status": "Failure", - "ErrorDescription": errdesc },), - methodresponse = 1) - else: - log.exception('Internal error handling %s', method) - import xen.xend.XendClient - response = xmlrpclib.dumps( - xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn))) + import xen.xend.XendClient + if isinstance(exn, xmlrpclib.Fault): + response = xmlrpclib.dumps(exn) + else: + log.exception('Internal error handling %s', method) + response = xmlrpclib.dumps( + xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn))) + except: + log.exception('Internal error handling error') + return response @@ -241,7 +259,7 @@ def _is_not_supported(exn): try: m = notSupportedRE.search(exn[0]) return m is not None - except TypeError, e: + except: return False diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 4ab6916b53..a0f7c351b4 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -31,10 +31,14 @@ from xen.xend.XendError import * from xen.xend.XendClient import ERROR_INVALID_DOMAIN from xen.xend.XendLogging import log from xen.xend.XendTask import XendTask +from xen.xend.XendVMMetrics import XendVMMetrics from xen.xend.XendAPIConstants import * from xen.util.xmlrpclib2 import stringify +from xen.util.blkif import blkdev_name_to_number + + AUTH_NONE = 'none' AUTH_PAM = 'pam' @@ -192,6 +196,16 @@ def valid_vm(func): _check_ref(XendDomain.instance().is_valid_vm, 'VM', func, *args, **kwargs) +def valid_vm_metrics(func): + """Decorator to verify if vm_metrics_ref is valid before calling method. + + @param func: function with params: (self, session, vm_metrics_ref, ...) + @rtype: callable object + """ + return lambda *args, **kwargs: \ + _check_ref(XendVMMetrics.is_valid_vm_metrics, + 'VM_metrics', func, *args, **kwargs) + def valid_network(func): """Decorator to verify if network_ref is valid before calling method. @@ -400,6 +414,7 @@ class XendAPI(object): 'host_metrics' : valid_host_metrics, 'network' : valid_network, 'VM' : valid_vm, + 'VM_metrics' : valid_vm_metrics, 'VBD' : valid_vbd, 'VBD_metrics' : valid_vbd_metrics, 'VIF' : valid_vif, @@ -629,6 +644,7 @@ class XendAPI(object): host_attr_ro = ['software_version', 'resident_VMs', 'host_CPUs', + 'cpu_configuration', 'metrics', 'capabilities', 'supported_bootloaders', @@ -638,6 +654,7 @@ class XendAPI(object): 'API_version_vendor_implementation'] host_attr_rw = ['name_label', + 'sched_policy', 'name_description', 'other_config'] @@ -647,7 +664,9 @@ class XendAPI(object): ('shutdown', None), ('add_to_other_config', None), ('remove_from_other_config', None), - ('dmesg', 'String')] + ('dmesg', 'String'), + ('get_log', 'String'), + ('send_debug_keys', None)] host_funcs = [('get_by_name_label', 'Set(host)')] @@ -676,8 +695,9 @@ class XendAPI(object): return xen_api_success_void() def host_remove_from_other_config(self, session, host_ref, key): node = XendNode.instance() - del node.other_config[key] - node.save() + if key in node.other_config: + del node.other_config[key] + node.save() return xen_api_success_void() def host_get_API_version_major(self, _, ref): return xen_api_success(XEN_API_VERSION_MAJOR) @@ -699,7 +719,13 @@ class XendAPI(object): return xen_api_success(XendNode.instance().get_capabilities()) def host_get_supported_bootloaders(self, session, host_ref): return xen_api_success(['pygrub']) - + def host_get_sched_policy(self, _, host_ref): + return xen_api_success(XendNode.instance().get_vcpus_policy()) + def host_set_sched_policy(self, _, host_ref, policy): + return xen_api_todo() + def host_get_cpu_configuration(self, _, host_ref): + return xen_api_success(XendNode.instance().get_cpu_configuration()) + # object methods def host_disable(self, session, host_ref): XendDomain.instance().set_allow_new_domains(False) @@ -716,8 +742,21 @@ class XendAPI(object): return xen_api_error(XEND_ERROR_HOST_RUNNING) return xen_api_error(XEND_ERROR_UNSUPPORTED) - def host_dmesg(self, session, host_ref): - return xen_api_success(XendDmesg.instance().info()) + def host_dmesg(self, session, host_ref, clear): + if clear: + return xen_api_success(XendDmesg.instance().clear()) + else: + return xen_api_success(XendDmesg.instance().info()) + + def host_get_log(self, session, host_ref): + log_file = open(XendLogging.getLogFilename()) + log_buffer = log_file.read() + return xen_api_success(log_buffer) + + def host_send_debug_keys(self, _, host_ref, keys): + node = XendNode.instance() + node.send_debug_keys(keys) + return xen_api_success_void() def host_get_record(self, session, host_ref): node = XendNode.instance() @@ -734,9 +773,11 @@ class XendAPI(object): 'other_config': node.other_config, 'resident_VMs': dom.get_domain_refs(), 'host_CPUs': node.get_host_cpu_refs(), + 'cpu_configuration': node.get_cpu_configuration(), 'metrics': node.host_metrics_uuid, 'capabilities': node.get_capabilities(), - 'supported_bootloaders': 'pygrub'} + 'supported_bootloaders': 'pygrub', + 'sched_policy': node.get_vcpus_policy()} return xen_api_success(record) # class methods @@ -758,7 +799,8 @@ class XendAPI(object): 'modelname', 'stepping', 'flags', - 'utilisation'] + 'utilisation', + 'features'] # attributes def _host_cpu_get(self, ref, field): @@ -767,6 +809,8 @@ class XendAPI(object): def host_cpu_get_host(self, _, ref): return xen_api_success(XendNode.instance().uuid) + def host_cpu_get_features(self, _, ref): + return self._host_cpu_get(ref, 'features') def host_cpu_get_number(self, _, ref): return self._host_cpu_get(ref, 'number') def host_cpu_get_vendor(self, _, ref): @@ -989,19 +1033,17 @@ class XendAPI(object): VM_attr_ro = ['power_state', 'resident_on', - 'memory_actual', 'memory_static_max', 'memory_static_min', 'VCPUs_number', - 'VCPUs_utilisation', 'consoles', 'VIFs', 'VBDs', 'VTPMs', - 'PCI_bus', 'tools_version', 'domid', 'is_control_domain', + 'metrics' ] VM_attr_rw = ['name_label', @@ -1011,7 +1053,6 @@ class XendAPI(object): 'auto_power_on', 'memory_dynamic_max', 'memory_dynamic_min', - 'VCPUs_policy', 'VCPUs_params', 'actions_after_shutdown', 'actions_after_reboot', @@ -1024,12 +1065,8 @@ class XendAPI(object): 'PV_bootloader_args', 'HVM_boot_policy', 'HVM_boot_params', - 'platform_std_VGA', - 'platform_serial', - 'platform_localtime', - 'platform_clock_offset', - 'platform_enable_audio', - 'platform_keymap', + 'platform', + 'PCI_bus', 'other_config'] VM_methods = [('clone', 'VM'), @@ -1042,8 +1079,16 @@ class XendAPI(object): ('hard_reboot', None), ('suspend', None), ('resume', None), + ('send_sysrq', None), + ('add_to_HVM_boot_params', None), + ('remove_from_HVM_boot_params', None), + ('add_to_VCPUs_params', None), + ('remove_from_VCPUs_params', None), + ('add_to_platform', None), + ('remove_from_platform', None), ('add_to_other_config', None), - ('remove_from_other_config', None)] + ('remove_from_other_config', None), + ('send_trigger', None)] VM_funcs = [('create', 'VM'), ('get_by_name_label', 'Set(VM)')] @@ -1058,7 +1103,6 @@ class XendAPI(object): 'memory_dynamic_max', 'memory_dynamic_min', 'memory_static_min', - 'VCPUs_policy', 'VCPUs_params', 'actions_after_shutdown', 'actions_after_reboot', @@ -1071,13 +1115,7 @@ class XendAPI(object): 'PV_bootloader_args', 'HVM_boot_policy', 'HVM_boot_params', - 'platform_std_VGA', - 'platform_serial', - 'platform_localtime', - 'platform_clock_offset', - 'platform_enable_audio', - 'platform_keymap', - 'grub_cmdline', + 'platform', 'PCI_bus', 'other_config'] @@ -1089,7 +1127,10 @@ class XendAPI(object): xd = XendDomain.instance() dominfo = xd.get_vm_by_uuid(vm_ref) dominfo.info[name] = value - xd.managed_config_save(dominfo) + return self._VM_save(dominfo) + + def _VM_save(self, dominfo): + XendDomain.instance().managed_config_save(dominfo) return xen_api_success_void() # attributes (ro) @@ -1099,11 +1140,7 @@ class XendAPI(object): def VM_get_resident_on(self, session, vm_ref): return xen_api_success(XendNode.instance().uuid) - - def VM_get_memory_actual(self, session, vm_ref): - dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() # unsupported by xc - + def VM_get_memory_static_max(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_memory_static_max()) @@ -1116,10 +1153,6 @@ class XendAPI(object): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.getVCpuCount()) - def VM_get_VCPUs_utilisation(self, session, vm_ref): - dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success(dom.get_vcpus_util()) - def VM_get_VIFs(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_vifs()) @@ -1136,14 +1169,14 @@ class XendAPI(object): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_consoles()) - def VM_get_PCI_bus(self, session, vm_ref): - dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return dom.get_pci_bus() - def VM_get_tools_version(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return dom.get_tools_version() + def VM_get_metrics(self, _, vm_ref): + dom = XendDomain.instance().get_vm_by_uuid(vm_ref) + return xen_api_success(dom.get_metrics()) + # attributes (rw) def VM_get_name_label(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) @@ -1167,11 +1200,7 @@ class XendAPI(object): def VM_get_memory_dynamic_min(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success(dom.get_memory_dynamic_min()) - - def VM_get_VCPUs_policy(self, session, vm_ref): - dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success(dom.get_vcpus_policy()) + return xen_api_success(dom.get_memory_dynamic_min()) def VM_get_VCPUs_params(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) @@ -1214,29 +1243,16 @@ class XendAPI(object): def VM_get_HVM_boot_params(self, session, vm_ref): return self.VM_get('HVM_boot_params', session, vm_ref) - def VM_get_platform_std_VGA(self, session, vm_ref): + def VM_get_platform(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success(dom.get_platform_std_vga()) + return xen_api_success(dom.get_platform()) - def VM_get_platform_serial(self, session, vm_ref): + def VM_get_PCI_bus(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success(dom.get_platform_serial()) + return dom.get_pci_bus() - def VM_get_platform_localtime(self, session, vm_ref): - dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success(dom.get_platform_localtime()) - - def VM_get_platform_clock_offset(self, session, vm_ref): - dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success(dom.get_platform_clock_offset()) - - def VM_get_platform_enable_audio(self, session, vm_ref): - dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success(dom.get_platform_enable_audio()) - - def VM_get_platform_keymap(self, session, vm_ref): - dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success(dom.get_platform_keymap()) + def VM_set_PCI_bus(self, session, vm_ref, val): + return self.VM_set('PCI_bus', session, vm_ref, val) def VM_get_other_config(self, session, vm_ref): return self.VM_get('other_config', session, vm_ref) @@ -1253,7 +1269,7 @@ class XendAPI(object): def VM_set_name_label(self, session, vm_ref, label): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) dom.setName(label) - return xen_api_success_void() + return self._VM_save(dom) def VM_set_name_description(self, session, vm_ref, desc): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) @@ -1275,21 +1291,32 @@ class XendAPI(object): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def VM_set_VCPUs_policy(self, session, vm_ref, policy): + def VM_set_VCPUs_params(self, session, vm_ref, value): + return self.VM_set('vcpus_params', session, vm_ref, value) + + def VM_add_to_VCPUs_params(self, session, vm_ref, key, value): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() - - def VM_set_VCPUs_params(self, session, vm_ref, params): + if 'vcpus_params' not in dom.info: + dom.info['vcpus_params'] = {} + dom.info['vcpus_params'][key] = value + return self._VM_save(dom) + + def VM_remove_from_VCPUs_params(self, session, vm_ref, key): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() + if 'vcpus_params' in dom.info \ + and key in dom.info['vcpus_params']: + del dom.info['vcpus_params'][key] + return self._VM_save(dom) + else: + return xen_api_success_void() def VM_set_actions_after_shutdown(self, session, vm_ref, action): - if action not in XEN_API_ON_NORMAL_EXIST: + if action not in XEN_API_ON_NORMAL_EXIT: return xen_api_error(['VM_ON_NORMAL_EXIT_INVALID', vm_ref]) return self.VM_set('actions_after_shutdown', session, vm_ref, action) def VM_set_actions_after_reboot(self, session, vm_ref, action): - if action not in XEN_API_ON_NORMAL_EXIST: + if action not in XEN_API_ON_NORMAL_EXIT: return xen_api_error(['VM_ON_NORMAL_EXIT_INVALID', vm_ref]) return self.VM_set('actions_after_reboot', session, vm_ref, action) @@ -1319,14 +1346,16 @@ class XendAPI(object): if 'HVM_boot_params' not in dom.info: dom.info['HVM_boot_params'] = {} dom.info['HVM_boot_params'][key] = value - return xen_api_success_void() + return self._VM_save(dom) def VM_remove_from_HVM_boot_params(self, session, vm_ref, key): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) if 'HVM_boot_params' in dom.info \ and key in dom.info['HVM_boot_params']: del dom.info['HVM_boot_params'][key] - return xen_api_success_void() + return self._VM_save(dom) + else: + return xen_api_success_void() def VM_set_PV_bootloader(self, session, vm_ref, value): return self.VM_set('PV_bootloader', session, vm_ref, value) @@ -1343,40 +1372,42 @@ class XendAPI(object): def VM_set_PV_bootloader_args(self, session, vm_ref, value): return self.VM_set('PV_bootloader_args', session, vm_ref, value) - def VM_set_platform_std_VGA(self, session, vm_ref, value): - return self.VM_set('platform_std_vga', session, vm_ref, value) + def VM_set_platform(self, session, vm_ref, value): + return self.VM_set('platform', session, vm_ref, value) - def VM_set_platform_serial(self, session, vm_ref, value): - return self.VM_set('platform_serial', session, vm_ref, value) + def VM_add_to_platform(self, session, vm_ref, key, value): + dom = XendDomain.instance().get_vm_by_uuid(vm_ref) + plat = dom.get_platform() + plat[key] = value + return self.VM_set_platform(session, vm_ref, plat) + + def VM_remove_from_platform(self, session, vm_ref, key): + dom = XendDomain.instance().get_vm_by_uuid(vm_ref) + plat = dom.get_platform() + if key in plat: + del plat[key] + return self.VM_set_platform(session, vm_ref, plat) + else: + return xen_api_success_void() - def VM_set_platform_keymap(self, session, vm_ref, value): - return self.VM_set('platform_keymap', session, vm_ref, value) - - def VM_set_platform_localtime(self, session, vm_ref, value): - return self.VM_set('platform_localtime', session, vm_ref, value) - - def VM_set_platform_clock_offset(self, session, vm_ref, value): - return self.VM_set('platform_clock_offset', session, vm_ref, value) - - def VM_set_platform_enable_audio(self, session, vm_ref, value): - return self.VM_set('platform_enable_audio', session, vm_ref, value) - def VM_set_other_config(self, session, vm_ref, value): - return self.VM_set('otherconfig', session, vm_ref, value) + return self.VM_set('other_config', session, vm_ref, value) def VM_add_to_other_config(self, session, vm_ref, key, value): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - if dom and 'otherconfig' in dom.info: - dom.info['otherconfig'][key] = value - return xen_api_success_void() + if dom and 'other_config' in dom.info: + dom.info['other_config'][key] = value + return self._VM_save(dom) def VM_remove_from_other_config(self, session, vm_ref, key): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - if dom and 'otherconfig' in dom.info \ - and key in dom.info['otherconfig']: - del dom.info['otherconfig'][key] - return xen_api_success_void() - + if dom and 'other_config' in dom.info \ + and key in dom.info['other_config']: + del dom.info['other_config'][key] + return self._VM_save(dom) + else: + return xen_api_success_void() + # class methods def VM_get_all(self, session): refs = [d.get_uuid() for d in XendDomain.instance().list('all')] @@ -1417,11 +1448,8 @@ class XendAPI(object): 'memory_static_max': xeninfo.get_memory_static_max(), 'memory_dynamic_min': xeninfo.get_memory_dynamic_min(), 'memory_dynamic_max': xeninfo.get_memory_dynamic_max(), - 'memory_actual': xeninfo.get_memory_static_min(), - 'VCPUs_policy': xeninfo.get_vcpus_policy(), 'VCPUs_params': xeninfo.get_vcpus_params(), 'VCPUs_number': xeninfo.getVCpuCount(), - 'VCPUs_utilisation': xeninfo.get_vcpus_util(), 'actions_after_shutdown': xeninfo.get_on_shutdown(), 'actions_after_reboot': xeninfo.get_on_reboot(), 'actions_after_suspend': xeninfo.get_on_suspend(), @@ -1437,12 +1465,7 @@ class XendAPI(object): 'PV_bootloader_args': xeninfo.info.get('PV_bootloader_args'), 'HVM_boot_policy': xeninfo.info.get('HVM_boot_policy'), 'HVM_boot_params': xeninfo.info.get('HVM_boot_params'), - 'platform_std_VGA': xeninfo.get_platform_std_vga(), - 'platform_serial': xeninfo.get_platform_serial(), - 'platform_localtime': xeninfo.get_platform_localtime(), - 'platform_clock_offset': xeninfo.get_platform_clock_offset(), - 'platform_enable_audio': xeninfo.get_platform_enable_audio(), - 'platform_keymap': xeninfo.get_platform_keymap(), + 'platform': xeninfo.get_platform(), 'PCI_bus': xeninfo.get_pci_bus(), 'tools_version': xeninfo.get_tools_version(), 'other_config': xeninfo.info.get('other_config', {}), @@ -1486,10 +1509,13 @@ class XendAPI(object): start_paused = start_paused) def VM_start(self, session, vm_ref, start_paused): - return XendTask.log_progress(0, 100, do_vm_func, - "domain_start", vm_ref, - start_paused = start_paused) - + try: + return XendTask.log_progress(0, 100, do_vm_func, + "domain_start", vm_ref, + start_paused = start_paused) + except HVMRequired, exn: + return xen_api_error(['VM_HVM_REQUIRED', vm_ref]) + def VM_suspend(self, session, vm_ref): return XendTask.log_progress(0, 100, do_vm_func, "domain_suspend", vm_ref) @@ -1498,10 +1524,56 @@ class XendAPI(object): return XendTask.log_progress(0, 100, do_vm_func, "domain_unpause", vm_ref) + def VM_send_sysrq(self, _, vm_ref, req): + xeninfo = XendDomain.instance().get_vm_by_uuid(vm_ref) + if xeninfo.state != XEN_API_VM_POWER_STATE_RUNNING: + return xen_api_error( + ['VM_BAD_POWER_STATE', vm_ref, + XendDomain.POWER_STATE_NAMES[XEN_API_VM_POWER_STATE_RUNNING], + XendDomain.POWER_STATE_NAMES[xeninfo.state]]) + xeninfo.send_sysrq(req) + return xen_api_success_void() + + + def VM_send_trigger(self, _, vm_ref, trigger, vcpu): + xendom = XendDomain.instance() + xeninfo = xendom.get_vm_by_uuid(vm_ref) + xendom.domain_send_trigger(xeninfo.getDomid(), trigger, vcpu) + return xen_api_success_void() + + + # Xen API: Class VM_metrics + # ---------------------------------------------------------------- + + VM_metrics_attr_ro = ['memory_actual', + 'vcpus_number', + 'vcpus_utilisation'] + VM_metrics_attr_rw = [] + VM_metrics_methods = [] + + def _VM_metrics_get(self, ref): + return XendVMMetrics.get_by_uuid(ref) + + def VM_metrics_get_all(self, _): + return xen_api_success(XendVMMetrics.get_all()) + + def VM_metrics_get_record(self, _, ref): + return xen_api_success(self._VM_metrics_get(ref).get_record()) + + def VM_metrics_get_memory_actual(self, _, ref): + return xen_api_success(self._VM_metrics_get(ref).get_memory_actual()) + + def VM_metrics_get_vcpus_number(self, _, ref): + return xen_api_success(self._VM_metrics_get(ref).get_vcpus_number()) + + def VM_metrics_get_vcpus_utilisation(self, _, ref): + return xen_api_success(self._VM_metrics_get(ref).get_vcpus_utilisation()) + # Xen API: Class VBD # ---------------------------------------------------------------- - VBD_attr_ro = ['metrics'] + VBD_attr_ro = ['metrics', + 'runtime_properties'] VBD_attr_rw = ['VM', 'VDI', 'device', @@ -1542,23 +1614,28 @@ class XendAPI(object): # class methods def VBD_create(self, session, vbd_struct): xendom = XendDomain.instance() + xennode = XendNode.instance() + if not xendom.is_valid_vm(vbd_struct['VM']): return xen_api_error(['HANDLE_INVALID', 'VM', vbd_struct['VM']]) dom = xendom.get_vm_by_uuid(vbd_struct['VM']) - vbd_ref = '' + vdi = xennode.get_vdi_by_uuid(vbd_struct['VDI']) + if not vdi: + return xen_api_error(['HANDLE_INVALID', 'VDI', vdi_ref]) + + # new VBD via VDI/SR + vdi_image = vdi.get_location() + try: - # new VBD via VDI/SR - vdi_ref = vbd_struct.get('VDI') - vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref) - if not vdi: - return xen_api_error(['HANDLE_INVALID', 'VDI', vdi_ref]) - vdi_image = vdi.get_location() vbd_ref = XendTask.log_progress(0, 100, dom.create_vbd, vbd_struct, vdi_image) - except XendError: - return xen_api_todo() + except XendError, e: + log.exception("Error in VBD_create") + return xen_api_error(['INTERNAL_ERROR', str(e)]) + + vdi.addVBD(vbd_ref) xendom.managed_config_save(dom) return xen_api_success(vbd_ref) @@ -1570,7 +1647,14 @@ class XendAPI(object): if not vm: return xen_api_error(['HANDLE_INVALID', 'VBD', vbd_ref]) + vdi_ref = XendDomain.instance()\ + .get_dev_property_by_uuid('vbd', vbd_ref, "VDI") + vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref) + XendTask.log_progress(0, 100, vm.destroy_vbd, vbd_ref) + + vdi.removeVBD(vbd_ref) + return xen_api_success_void() def _VBD_get(self, vbd_ref, prop): @@ -1582,6 +1666,24 @@ class XendAPI(object): def VBD_get_metrics(self, _, vbd_ref): return xen_api_success(vbd_ref) + def VBD_get_runtime_properties(self, _, vbd_ref): + xendom = XendDomain.instance() + dominfo = xendom.get_vm_with_dev_uuid('vbd', vbd_ref) + device = dominfo.get_dev_config_by_uuid('vbd', vbd_ref) + + try: + devid = int(device['id']) + device_sxps = dominfo.getDeviceSxprs('vbd') + device_dicts = [dict(device_sxp[1][1:]) for device_sxp in device_sxps] + device_dict = [device_dict + for device_dict in device_dicts + if int(device_dict['virtual-device']) == devid][0] + + return xen_api_success(device_dict) + except Exception, exn: + log.exception(exn) + return xen_api_success({}) + # attributes (rw) def VBD_get_VM(self, session, vbd_ref): return self._VBD_get(vbd_ref, 'VM') @@ -1642,7 +1744,8 @@ class XendAPI(object): # Xen API: Class VIF # ---------------------------------------------------------------- - VIF_attr_ro = ['metrics'] + VIF_attr_ro = ['metrics', + 'runtime_properties'] VIF_attr_rw = ['device', 'network', 'VM', @@ -1679,18 +1782,17 @@ class XendAPI(object): # class methods def VIF_create(self, session, vif_struct): xendom = XendDomain.instance() - if xendom.is_valid_vm(vif_struct['VM']): - dom = xendom.get_vm_by_uuid(vif_struct['VM']) - try: - vif_ref = dom.create_vif(vif_struct) - xendom.managed_config_save(dom) - return xen_api_success(vif_ref) - except XendError: - return xen_api_error(XEND_ERROR_TODO) - else: + if not xendom.is_valid_vm(vif_struct['VM']): return xen_api_error(['HANDLE_INVALID', 'VM', vif_struct['VM']]) - + dom = xendom.get_vm_by_uuid(vif_struct['VM']) + try: + vif_ref = dom.create_vif(vif_struct) + xendom.managed_config_save(dom) + return xen_api_success(vif_ref) + except XendError: + return xen_api_error(XEND_ERROR_TODO) + def VIF_destroy(self, session, vif_ref): xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vif', vif_ref) @@ -1728,6 +1830,27 @@ class XendAPI(object): vifs = reduce(lambda x, y: x + y, vifs) return xen_api_success(vifs) + def VIF_get_runtime_properties(self, _, vif_ref): + xendom = XendDomain.instance() + dominfo = xendom.get_vm_with_dev_uuid('vif', vif_ref) + device = dominfo.get_dev_config_by_uuid('vif', vif_ref) + + try: + devid = int(device['id']) + + device_sxps = dominfo.getDeviceSxprs('vif') + device_dicts = [dict(device_sxp[1][1:]) + for device_sxp in device_sxps] + + device_dict = [device_dict + for device_dict in device_dicts + if int(device_dict['handle']) == devid][0] + + return xen_api_success(device_dict) + + except Exception, exn: + log.exception(exn) + return xen_api_success({}) # Xen API: Class VIF_metrics # ---------------------------------------------------------------- @@ -1754,16 +1877,16 @@ class XendAPI(object): # Xen API: Class VDI # ---------------------------------------------------------------- - VDI_attr_ro = ['VBDs', + VDI_attr_ro = ['SR', + 'VBDs', 'physical_utilisation', - 'sector_size', 'type'] VDI_attr_rw = ['name_label', 'name_description', - 'SR', 'virtual_size', 'sharable', - 'read_only'] + 'read_only', + 'other_config'] VDI_attr_inst = VDI_attr_ro + VDI_attr_rw VDI_methods = [('snapshot', 'VDI')] @@ -1774,14 +1897,12 @@ class XendAPI(object): return XendNode.instance().get_vdi_by_uuid(ref) def VDI_get_VBDs(self, session, vdi_ref): - return xen_api_todo() + vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref) + return xen_api_success(vdi.getVBDs()) def VDI_get_physical_utilisation(self, session, vdi_ref): return xen_api_success(self._get_VDI(vdi_ref). - get_physical_utilisation()) - - def VDI_get_sector_size(self, session, vdi_ref): - return xen_api_success(self._get_VDI(vdi_ref).sector_size) + get_physical_utilisation()) def VDI_get_type(self, session, vdi_ref): return xen_api_success(self._get_VDI(vdi_ref).type) @@ -1812,9 +1933,6 @@ class XendAPI(object): self._get_VDI(vdi_ref).name_description = value return xen_api_success_void() - def VDI_set_SR(self, session, vdi_ref, value): - return xen_api_error(XEND_ERROR_UNSUPPORTED) - def VDI_set_virtual_size(self, session, vdi_ref, value): return xen_api_error(XEND_ERROR_UNSUPPORTED) @@ -1826,6 +1944,14 @@ class XendAPI(object): self._get_VDI(vdi_ref).read_only = bool(value) return xen_api_success_void() + def VDI_get_other_config(self, session, vdi_ref): + return xen_api_success( + self._get_VDI(vdi_ref).other_config) + + def VDI_set_other_config(self, session, vdi_ref, other_config): + self._get_VDI(vdi_ref).other_config = other_config + return xen_api_success_void() + # Object Methods def VDI_snapshot(self, session, vdi_ref): return xen_api_todo() @@ -1842,13 +1968,13 @@ class XendAPI(object): 'name_label': image.name_label, 'name_description': image.name_description, 'SR': image.sr_uuid, - 'VBDs': [], # TODO + 'VBDs': image.getVBDs(), 'virtual_size': image.virtual_size, 'physical_utilisation': image.physical_utilisation, - 'sector_size': image.sector_size, 'type': image.type, 'sharable': image.sharable, 'read_only': image.read_only, + 'other_config': image.other_config }) # Class Functions @@ -1929,7 +2055,7 @@ class XendAPI(object): XendDomain.POWER_STATE_NAMES[dom.state]]) from xen.xend.server import tpmif tpmif.destroy_vtpmstate(dom.getName()) - return xen_api_success(True) + return xen_api_success_void() else: return xen_api_error(['HANDLE_INVALID', 'VM', vtpm_struct['VM']]) diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py index e94d9fbde7..3982188016 100644 --- a/tools/python/xen/xend/XendCheckpoint.py +++ b/tools/python/xen/xend/XendCheckpoint.py @@ -9,6 +9,7 @@ import os import re import string import threading +import fcntl from struct import pack, unpack, calcsize from xen.util.xpopen import xPopen3 @@ -73,10 +74,15 @@ def save(fd, dominfo, network, live, dst, checkpoint=False): write_exact(fd, config, "could not write guest state file: config") image_cfg = dominfo.info.get('image', {}) - hvm = image_cfg.has_key('hvm') + hvm = dominfo.info.is_hvm() + stdvga = 0 if hvm: log.info("save hvm domain") + if dominfo.info['platform'].has_key('stdvga'): + if dominfo.info['platform']['stdvga'] == 1: + stdvga = 1 + # xc_save takes three customization parameters: maxit, max_f, and # flags the last controls whether or not save is 'live', while the # first two further customize behaviour when 'live' save is @@ -84,7 +90,8 @@ def save(fd, dominfo, network, live, dst, checkpoint=False): # libxenguest; see the comments and/or code in xc_linux_save() for # more information. cmd = [xen.util.auxbin.pathTo(XC_SAVE), str(fd), - str(dominfo.getDomid()), "0", "0", str(int(live) | (int(hvm) << 2)) ] + str(dominfo.getDomid()), "0", "0", + str(int(live) | (int(hvm) << 2) | (int(stdvga) << 3)) ] log.debug("[xc_save]: %s", string.join(cmd)) def saveInputHandler(line, tochild): @@ -183,11 +190,11 @@ def restore(xd, fd, dominfo = None, paused = False): # if hvm, pass mem size to calculate the store_mfn image_cfg = dominfo.info.get('image', {}) - is_hvm = image_cfg.has_key('hvm') + is_hvm = dominfo.info.is_hvm() if is_hvm: hvm = dominfo.info['memory_static_min'] - apic = dominfo.info['image']['hvm'].get('apic', 0) - pae = dominfo.info['image']['hvm'].get('pae', 0) + apic = int(dominfo.info['platform'].get('apic', 0)) + pae = int(dominfo.info['platform'].get('pae', 0)) log.info("restore hvm domain %d, mem=%d, apic=%d, pae=%d", dominfo.domid, hvm, apic, pae) else: @@ -224,6 +231,15 @@ def restore(xd, fd, dominfo = None, paused = False): forkHelper(cmd, fd, handler.handler, True) + # We don't want to pass this fd to any other children -- we + # might need to recover ths disk space that backs it. + try: + flags = fcntl.fcntl(fd, fcntl.F_GETFD) + flags |= fcntl.FD_CLOEXEC + fcntl.fcntl(fd, fcntl.F_SETFD, flags) + except: + pass + if handler.store_mfn is None: raise XendError('Could not read store MFN') diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index ec8a66fb7e..d8f5c3fe66 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -12,7 +12,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ -# Copyright (C) 2006 XenSource Ltd +# Copyright (C) 2006-2007 XenSource Ltd #============================================================================ import logging @@ -28,7 +28,7 @@ from xen.xend.PrettyPrint import prettyprintstring from xen.xend.XendConstants import DOM_STATE_HALTED log = logging.getLogger("xend.XendConfig") -log.setLevel(logging.DEBUG) +log.setLevel(logging.WARN) """ @@ -105,28 +105,23 @@ XENAPI_CFG_TO_LEGACY_CFG = { 'uuid': 'uuid', 'vcpus_number': 'vcpus', 'cpus': 'cpus', - 'memory_static_min': 'memory', - 'memory_static_max': 'maxmem', 'name_label': 'name', 'actions_after_shutdown': 'on_poweroff', 'actions_after_reboot': 'on_reboot', 'actions_after_crash': 'on_crash', - 'platform_localtime': 'localtime', 'PV_bootloader': 'bootloader', 'PV_bootloader_args': 'bootloader_args', } LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG) -# Mapping from XendConfig configuration keys to the old -# legacy configuration keys that are found in the 'image' -# SXP object. -XENAPI_HVM_CFG = { - 'platform_std_vga': 'stdvga', - 'platform_serial' : 'serial', - 'platform_localtime': 'localtime', - 'platform_keymap' : 'keymap' -} +# Platform configuration keys. +XENAPI_PLATFORM_CFG = [ 'acpi', 'apic', 'boot', 'device_model', 'display', + 'fda', 'fdb', 'keymap', 'isa', 'localtime', + 'nographic', 'pae', 'serial', 'sdl', + 'soundhw','stdvga', 'usb', 'usbdevice', 'vnc', + 'vncconsole', 'vncdisplay', 'vnclisten', + 'vncpasswd', 'vncunused', 'xauthority'] # List of XendConfig configuration keys that have no direct equivalent # in the old world. @@ -139,11 +134,10 @@ XENAPI_CFG_TYPES = { 'user_version': str, 'is_a_template': bool0, 'resident_on': str, - 'memory_static_min': int, + 'memory_static_min': int, # note these are stored in bytes, not KB! 'memory_static_max': int, 'memory_dynamic_min': int, 'memory_dynamic_max': int, - 'memory_actual': int, 'cpus': list, 'vcpus_policy': str, 'vcpus_params': dict, @@ -151,7 +145,6 @@ XENAPI_CFG_TYPES = { 'actions_after_shutdown': str, 'actions_after_reboot': str, 'actions_after_crash': str, - 'tpm_backend': int, 'PV_bootloader': str, 'PV_kernel': str, 'PV_ramdisk': str, @@ -159,15 +152,10 @@ XENAPI_CFG_TYPES = { 'PV_bootloader_args': str, 'HVM_boot_policy': str, 'HVM_boot_params': dict, - 'platform_std_vga': bool0, - 'platform_serial': str, - 'platform_localtime': bool0, - 'platform_clock_offset': bool0, - 'platform_enable_audio': bool0, - 'platform_keymap': str, - 'pci_bus': str, + 'PCI_bus': str, + 'platform': dict, 'tools_version': dict, - 'otherconfig': dict, + 'other_config': dict, } # List of legacy configuration keys that have no equivalent in the @@ -237,44 +225,7 @@ LEGACY_XENSTORE_VM_PARAMS = [ 'on_xend_stop', ] -LEGACY_IMAGE_CFG = [ - ('root', str), - ('ip', str), - ('nographic', int), - ('vnc', int), - ('sdl', int), - ('vncdisplay', int), - ('vncunused', int), - ('vncpasswd', str), - ('vnclisten', str), -] - -LEGACY_IMAGE_HVM_CFG = [ - ('device_model', str), - ('display', str), - ('xauthority', str), - ('vncconsole', int), - ('pae', int), - ('apic', int), -] - -LEGACY_IMAGE_HVM_DEVICES_CFG = [ - ('acpi', int), - ('boot', str), - ('fda', str), - ('fdb', str), - ('isa', int), - ('keymap', str), - ('localtime', int), - ('serial', str), - ('stdvga', int), - ('soundhw', str), - ('usb', int), - ('usbdevice', str), - ('vcpus', int), -] - -LEGACY_DM = '/usr/lib/xen/bin/qemu-dm' +DEFAULT_DM = '/usr/lib/xen/bin/qemu-dm' ## ## Config Choices @@ -316,7 +267,6 @@ class XendConfig(dict): self._sxp_to_xapi_unsupported(sxp_obj) elif xapi: self.update_with_xenapi_config(xapi) - self._add_xapi_unsupported(xapi) elif dominfo: # output from xc.domain_getinfo self._dominfo_to_xapi(dominfo) @@ -361,9 +311,7 @@ class XendConfig(dict): 'shadow_memory': 0, 'memory_static_max': 0, 'memory_dynamic_max': 0, - 'memory_actual': 0, 'devices': {}, - 'image': {}, 'security': None, 'on_xend_start': 'ignore', 'on_xend_stop': 'ignore', @@ -377,24 +325,44 @@ class XendConfig(dict): 'vbd_refs': [], 'vtpm_refs': [], 'other_config': {}, + 'platform': {} } return defaults + # + # Here we assume these values exist in the dict. + # If they don't we have a bigger problem, lets not + # try and 'fix it up' but acutually fix the cause ;-) + # def _memory_sanity_check(self): - if self['memory_static_min'] == 0: - self['memory_static_min'] = self['memory_dynamic_min'] - - # If the static max is not set, let's set it to dynamic max. - # If the static max is smaller than static min, then fix it! - self['memory_static_max'] = max(self['memory_static_max'], - self['memory_dynamic_max'], - self['memory_static_min']) - - for mem_type in ('memory_static_min', 'memory_static_max'): - if self[mem_type] <= 0: - raise XendConfigError('Memory value too low for %s: %d' % - (mem_type, self[mem_type])) + log.debug("_memory_sanity_check memory_static_min: %s, " + "memory_static_max: %i, " + "memory_dynamic_min: %i, " + "memory_dynamic_max: %i", + self["memory_static_min"], + self["memory_static_max"], + self["memory_dynamic_min"], + self["memory_dynamic_max"]) + + if not self["memory_static_min"] <= self["memory_static_max"]: + raise XendConfigError("memory_static_min must be less " \ + "than or equal to memory_static_max") + if not self["memory_dynamic_min"] <= self["memory_dynamic_max"]: + raise XendConfigError("memory_dynamic_min must be less " \ + "than or equal to memory_dynamic_max") + if not self["memory_static_min"] <= self["memory_dynamic_min"]: + raise XendConfigError("memory_static_min must be less " \ + "than or equal to memory_dynamic_min") + if not self["memory_dynamic_max"] <= self["memory_static_max"]: + raise XendConfigError("memory_dynamic_max must be less " \ + "than or equal to memory_static_max") + if not self["memory_dynamic_max"] > 0: + raise XendConfigError("memory_dynamic_max must be greater " \ + "than zero") + if not self["memory_static_max"] > 0: + raise XendConfigError("memory_static_max must be greater " \ + "than zero") def _actions_sanity_check(self): for event in ['shutdown', 'reboot', 'crash']: @@ -417,19 +385,34 @@ class XendConfig(dict): if 'name_label' not in self: self['name_label'] = 'Domain-' + self['uuid'] + def _platform_sanity_check(self): + if self.is_hvm(): + if 'device_model' not in self['platform']: + self['platform']['device_model'] = DEFAULT_DM + + # Compatibility hack, can go away soon. + if 'soundhw' not in self['platform'] and \ + self['platform'].get('enable_audio'): + self['platform']['soundhw'] = 'sb16' + def validate(self): self._uuid_sanity_check() self._name_sanity_check() self._memory_sanity_check() self._actions_sanity_check() self._vcpus_sanity_check() + self._platform_sanity_check() def _dominfo_to_xapi(self, dominfo): self['domid'] = dominfo['domid'] self['online_vcpus'] = dominfo['online_vcpus'] self['vcpus_number'] = dominfo['max_vcpu_id'] + 1 - self['memory_dynamic_min'] = (dominfo['mem_kb'] + 1023)/1024 - self['memory_dynamic_max'] = (dominfo['maxmem_kb'] + 1023)/1024 + + self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024 + self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024 + self['memory_static_min'] = 0 + self['memory_static_max'] = dominfo['maxmem_kb'] * 1024 + self['cpu_time'] = dominfo['cpu_time']/1e9 # TODO: i don't know what the security stuff expects here if dominfo.get('ssidref'): @@ -483,6 +466,13 @@ class XendConfig(dict): log.warn('Ignoring unrecognised value for deprecated option:' 'restart = \'%s\'', restart) + # Handle memory, passed in as MiB + + if sxp.child_value(sxp_cfg, "memory") != None: + cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory")) + if sxp.child_value(sxp_cfg, "maxmem") != None: + cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem")) + # Only extract options we know about. extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values() @@ -498,6 +488,18 @@ class XendConfig(dict): log.warn("Unable to parse key %s: %s: %s" % (key, str(val), e)) + if 'platform' not in cfg: + cfg['platform'] = {} + localtime = sxp.child_value(sxp_cfg, 'localtime') + if localtime is not None: + cfg['platform']['localtime'] = localtime + + # Compatibility hack -- can go soon. + for key in XENAPI_PLATFORM_CFG: + val = sxp.child_value(sxp_cfg, "platform_" + key, None) + if val is not None: + self['platform'][key] = val + # Compatibility hack -- can go soon. boot_order = sxp.child_value(sxp_cfg, 'HVM_boot') if boot_order: @@ -640,6 +642,21 @@ class XendConfig(dict): except KeyError: pass + # Lets try and handle memory correctly + + MiB = 1024 * 1024 + + if "memory" in cfg: + self["memory_static_min"] = 0 + self["memory_static_max"] = int(cfg["memory"]) * MiB + self["memory_dynamic_min"] = int(cfg["memory"]) * MiB + self["memory_dynamic_max"] = int(cfg["memory"]) * MiB + + if "maxmem" in cfg: + self["memory_static_max"] = int(cfg["maxmem"]) * MiB + + self._memory_sanity_check() + def update_with(n, o): if not self.get(n): self[n] = cfg.get(o, '') @@ -652,17 +669,9 @@ class XendConfig(dict): self.update_with_image_sxp(image_sxp) # Convert Legacy HVM parameters to Xen API configuration - self['platform_std_vga'] = bool0(cfg.get('stdvga', 0)) - self['platform_serial'] = str(cfg.get('serial', '')) - self['platform_localtime'] = bool0(cfg.get('localtime', 0)) - self['platform_enable_audio'] = bool0(cfg.get('soundhw', 0)) - - # make sure a sane maximum is set - if self['memory_static_max'] <= 0: - self['memory_static_max'] = self['memory_static_min'] - - self['memory_dynamic_max'] = self['memory_static_max'] - self['memory_dynamic_min'] = self['memory_static_min'] + for key in XENAPI_PLATFORM_CFG: + if key in cfg: + self['platform'][key] = cfg[key] # set device references in the configuration self['devices'] = cfg.get('devices', {}) @@ -672,7 +681,7 @@ class XendConfig(dict): self['vtpm_refs'] = cfg.get('vtpm_refs', []) # coalesce hvm vnc frame buffer with vfb config - if self['image']['type'] == 'hvm' and self['image'].get('vnc', 0): + if self.is_hvm() and self['platform'].get('vnc', 0): # add vfb device if it isn't there already has_rfb = False for console_uuid in self['console_refs']: @@ -685,11 +694,11 @@ class XendConfig(dict): if not has_rfb: dev_config = ['vfb'] - # copy VNC related params from image config to vfb dev conf + # copy VNC related params from platform config to vfb dev conf for key in ['vncpasswd', 'vncunused', 'vncdisplay', 'vnclisten']: - if key in self['image']: - dev_config.append([key, self['image'][key]]) + if key in self['platform']: + dev_config.append([key, self['platform'][key]]) self.device_add('vfb', cfg_sxp = dev_config) @@ -706,39 +715,19 @@ class XendConfig(dict): # the image (as well as HVM images) image_sxp = sxp.child_value(sxp_cfg, 'image', []) if image_sxp: - image = {} - image['type'] = sxp.name(image_sxp) - for arg, conv in LEGACY_IMAGE_CFG: - val = sxp.child_value(image_sxp, arg, None) - if val != None: - image[arg] = conv(val) - - image_hvm = {} - for arg, conv in LEGACY_IMAGE_HVM_CFG: - val = sxp.child_value(image_sxp, arg, None) - if val != None: - image_hvm[arg] = conv(val) - - image_hvm_devices = {} - for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG: - val = sxp.child_value(image_sxp, arg, None) - if val != None: - image_hvm_devices[arg] = conv(val) - - if image_hvm or image_hvm_devices: - image['hvm'] = image_hvm - image['hvm']['devices'] = image_hvm_devices - + image_type = sxp.name(image_sxp) + if image_type != 'hvm' and image_type != 'linux': + self['platform']['image_type'] = image_type + + for key in XENAPI_PLATFORM_CFG: + val = sxp.child_value(image_sxp, key, None) + if val is not None: + self['platform'][key] = val + notes = sxp.children(image_sxp, 'notes') if notes: - image['notes'] = self.notes_from_sxp(notes[0]) + self['notes'] = self.notes_from_sxp(notes[0]) - self['image'] = image - - for apikey, imgkey in XENAPI_HVM_CFG.items(): - val = sxp.child_value(image_sxp, imgkey, None) - if val != None: - self[apikey] = val self._hvm_boot_params_from_sxp(image_sxp) # extract backend value @@ -774,33 +763,6 @@ class XendConfig(dict): _set_cfg_if_exists('up_time') _set_cfg_if_exists('status') # TODO, deprecated - def _add_xapi_unsupported(self, xapi_dict): - """Updates the configuration object with entries that are not - officially supported by the Xen API but is required for - the rest of Xend to function. - """ - - # populate image - if 'image' in xapi_dict: - self['image'].update(xapi_dict['image']) - else: - hvm = self['HVM_boot_policy'] != '' - self['image']['type'] = hvm and 'hvm' or 'linux' - if hvm: - self['image']['hvm'] = {'devices': {}} - for xapi, cfgapi in XENAPI_HVM_CFG.items(): - if xapi in self: - self['image']['hvm']['devices'][cfgapi] = self[xapi] - - # currently unsupported options - self['image']['hvm']['device_model'] = LEGACY_DM - self['image']['vnc'] = 0 - self['image']['hvm']['pae'] = 1 - - if self['platform_enable_audio']: - self['image']['hvm']['devices']['soundhw'] = 'sb16' - - def _get_old_state_string(self): """Returns the old xm state string. @rtype: string @@ -884,18 +846,29 @@ class XendConfig(dict): else: sxpr.append([legacy, self[xenapi]]) + MiB = 1024*1024 + + sxpr.append(["maxmem", int(self["memory_static_max"])/MiB]) + sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB]) + + if not legacy_only: + sxpr.append(['memory_dynamic_min', + int(self.get('memory_dynamic_min'))]) + sxpr.append(['memory_dynamic_max', + int(self.get('memory_dynamic_max'))]) + sxpr.append(['memory_static_max', + int(self.get('memory_static_max'))]) + sxpr.append(['memory_static_min', + int(self.get('memory_static_min'))]) + for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG: if legacy in ('domid', 'uuid'): # skip these continue if self.has_key(legacy) and self[legacy] not in (None, []): sxpr.append([legacy, self[legacy]]) - if 'image' in self and self['image']: - sxpr.append(['image', self.image_sxpr()]) - + sxpr.append(['image', self.image_sxpr()]) sxpr.append(['status', domain.state]) - sxpr.append(['memory_dynamic_min', self.get('memory_dynamic_min')]) - sxpr.append(['memory_dynamic_max', self.get('memory_dynamic_max')]) if domain.getDomid() is not None: sxpr.append(['state', self._get_old_state_string()]) @@ -1339,7 +1312,7 @@ class XendConfig(dict): def image_sxpr(self): """Returns a backwards compatible image SXP expression that is used in xenstore's /vm//image value and xm list.""" - image = [self['image'].get('type', 'linux')] + image = [self.image_type()] if self.has_key('PV_kernel'): image.append(['kernel', self['PV_kernel']]) if self.has_key('PV_ramdisk') and self['PV_ramdisk']: @@ -1347,28 +1320,12 @@ class XendConfig(dict): if self.has_key('PV_args') and self['PV_args']: image.append(['args', self['PV_args']]) - for arg, conv in LEGACY_IMAGE_CFG: - if self['image'].has_key(arg): - image.append([arg, self['image'][arg]]) + for key in XENAPI_PLATFORM_CFG: + if key in self['platform']: + image.append([key, self['platform'][key]]) - if 'hvm' in self['image']: - for arg, conv in LEGACY_IMAGE_HVM_CFG: - if self['image']['hvm'].get(arg): - image.append([arg, conv(self['image']['hvm'][arg])]) - - if 'hvm' in self['image'] and 'devices' in self['image']['hvm']: - for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG: - val = self['image']['hvm']['devices'].get(arg) - if val != None: - try: - if conv: val = conv(val) - except (ValueError, TypeError): - if type(val) == bool: val = int(val) - - image.append([arg, val]) - - if 'notes' in self['image']: - image.append(self.notes_sxp(self['image']['notes'])) + if 'notes' in self: + image.append(self.notes_sxp(self['notes'])) return image @@ -1399,57 +1356,24 @@ class XendConfig(dict): self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','') self['PV_args'] = kernel_args - # Store image SXP in python dictionary format - image = {} - image['type'] = sxp.name(image_sxp) - for arg, conv in LEGACY_IMAGE_CFG: - val = sxp.child_value(image_sxp, arg, None) - if val != None: - image[arg] = conv(val) - - image_hvm = {} - for arg, conv in LEGACY_IMAGE_HVM_CFG: - val = sxp.child_value(image_sxp, arg, None) - if val != None: - image_hvm[arg] = conv(val) - - image_hvm_devices = {} - for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG: - val = sxp.child_value(image_sxp, arg, None) - if val != None: - try: - image_hvm_devices[arg] = conv(val) - except (ValueError, TypeError): - image_hvm_devices[arg] = val - - - if image_hvm or image_hvm_devices: - image['hvm'] = image_hvm - image['hvm']['devices'] = image_hvm_devices + for key in XENAPI_PLATFORM_CFG: + val = sxp.child_value(image_sxp, key, None) + if val is not None: + self['platform'][key] = val notes = sxp.children(image_sxp, 'notes') if notes: - image['notes'] = self.notes_from_sxp(notes[0]) + self['notes'] = self.notes_from_sxp(notes[0]) - self['image'] = image - - for apikey, imgkey in XENAPI_HVM_CFG.items(): - val = sxp.child_value(image_sxp, imgkey, None) - if val != None: - type_conv = XENAPI_CFG_TYPES[apikey] - if callable(type_conv): - self[apikey] = type_conv(val) - else: - self[apikey] = val self._hvm_boot_params_from_sxp(image_sxp) def set_notes(self, notes): 'Add parsed elfnotes to image' - self['image']['notes'] = notes + self['notes'] = notes def get_notes(self): try: - return self['image']['notes'] or {} + return self['notes'] or {} except KeyError: return {} @@ -1471,11 +1395,9 @@ class XendConfig(dict): self['HVM_boot_policy'] = 'BIOS order' self['HVM_boot_params'] = { 'order' : boot } + def is_hvm(self): + return self['HVM_boot_policy'] != '' -# -# debugging -# - -if __name__ == "__main__": - pass - + def image_type(self): + stored_type = self['platform'].get('image_type') + return stored_type or (self.is_hvm() and 'hvm' or 'linux') diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 7e5f618870..18aad354b4 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -495,7 +495,7 @@ class XendDomain: self._refresh(refresh_shutdown = False) dom = self.domain_lookup_nr(domid) if not dom: - raise XendInvalidDomain("No domain named '%s'." % str(domid)) + raise XendInvalidDomain(str(domid)) return dom finally: self.domains_lock.release() @@ -674,7 +674,7 @@ class XendDomain: else: return domid - raise XendInvalidDomain("Domain does not exist") + raise XendInvalidDomain(vm_uuid) finally: self.domains_lock.release() diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index c784c95f80..bd4c595797 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -13,7 +13,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray -# Copyright (C) 2005, 2006 XenSource Ltd +# Copyright (C) 2005-2007 XenSource Ltd #============================================================================ """Representation of a single domain. @@ -34,7 +34,7 @@ from types import StringTypes import xen.lowlevel.xc from xen.util import asserts -from xen.util.blkif import blkdev_uname_to_file +from xen.util.blkif import blkdev_uname_to_file, blkdev_uname_to_taptype from xen.util import security from xen.xend import balloon, sxp, uuid, image, arch, osdep @@ -51,6 +51,8 @@ from xen.xend.xenstore.xswatch import xswatch from xen.xend.XendConstants import * from xen.xend.XendAPIConstants import * +from xen.xend.XendVMMetrics import XendVMMetrics + MIGRATE_TIMEOUT = 30.0 BOOTLOADER_LOOPBACK_DEVICE = '/dev/xvdp' @@ -176,14 +178,8 @@ def recreate(info, priv): vm._storeVmDetails() vm._storeDomDetails() - if vm.info['image']: # Only dom0 should be without an image entry when - # recreating, but we cope with missing ones - # elsewhere just in case. - vm.image = image.create(vm, - vm.info, - vm.info['image'], - vm.info['devices']) - vm.image.recreate() + vm.image = image.create(vm, vm.info) + vm.image.recreate() vm._registerWatches() vm.refreshShutdown(xeninfo) @@ -375,6 +371,8 @@ class XendDomainInfo: self._augmentInfo(priv) self._checkName(self.info['name_label']) + + self.metrics = XendVMMetrics(uuid.createString(), self) # @@ -448,9 +446,7 @@ class XendDomainInfo: self.storeDom("control/shutdown", reason) ## shutdown hypercall for hvm domain desides xenstore write - image_cfg = self.info.get('image', {}) - hvm = image_cfg.has_key('hvm') - if hvm: + if self.info.is_hvm(): for code in DOMAIN_SHUTDOWN_REASONS.keys(): if DOMAIN_SHUTDOWN_REASONS[code] == reason: break @@ -580,12 +576,14 @@ class XendDomainInfo: if target <= 0: raise XendError('Invalid memory size') - self.info['memory_static_min'] = target + MiB = 1024 * 1024 + self.info['memory_dynamic_min'] = target * MiB + self.info['memory_dynamic_max'] = target * MiB + if self.domid >= 0: self.storeVm("memory", target) self.storeDom("memory/target", target << 10) else: - self.info['memory_dynamic_min'] = target xen.xend.XendDomain.instance().managed_config_save(self) def setMemoryMaximum(self, limit): @@ -635,6 +633,10 @@ class XendDomainInfo: except RuntimeError, exn: raise XendError(str(exn)) + + def getDomInfo(self): + return dom_get(self.domid) + # # internal functions ... TODO: re-categorised # @@ -664,6 +666,10 @@ class XendDomainInfo: if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG: xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg] self.info[xapiarg] = val + elif arg == "memory": + self.info["static_memory_min"] = val + elif arg == "maxmem": + self.info["static_memory_max"] = val else: self.info[arg] = val @@ -780,7 +786,7 @@ class XendDomainInfo: 'vm': self.vmpath, 'name': self.info['name_label'], 'console/limit': str(xoptions.get_console_limit() * 1024), - 'memory/target': str(self.info['memory_static_min'] * 1024), + 'memory/target': str(self.info['memory_dynamic_max'] / 1024), } def f(n, v): @@ -864,7 +870,15 @@ class XendDomainInfo: xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg] if val != None and val != self.info[xapiarg]: self.info[xapiarg] = val - changed= True + changed = True + elif arg == "memory": + if val != None and val != self.info["static_memory_min"]: + self.info["static_memory_min"] = val + changed = True + elif arg == "maxmem": + if val != None and val != self.info["static_memory_max"]: + self.info["static_memory_max"] = val + changed = True # Check whether image definition has been updated image_sxp = self._readVm('image') @@ -969,11 +983,12 @@ class XendDomainInfo: def getMemoryTarget(self): """Get this domain's target memory size, in KB.""" - return self.info['memory_static_min'] * 1024 + return self.info['memory_dynamic_max'] / 1024 def getMemoryMaximum(self): """Get this domain's maximum memory size, in KB.""" - return self.info['memory_static_max'] * 1024 + # remember, info now stores memory in bytes + return self.info['memory_static_max'] / 1024 def getResume(self): return str(self._resume) @@ -1389,9 +1404,7 @@ class XendDomainInfo: self.shutdownStartTime = None - image_cfg = self.info.get('image', {}) - hvm = image_cfg.has_key('hvm') - + hvm = self.info.is_hvm() if hvm: info = xc.xeninfo() if 'hvm' not in info['xen_caps']: @@ -1438,14 +1451,8 @@ class XendDomainInfo: self._configureBootloader() - if not self._infoIsSet('image'): - raise VmError('Missing image in configuration') - try: - self.image = image.create(self, - self.info, - self.info['image'], - self.info['devices']) + self.image = image.create(self, self.info) localtime = self.info.get('platform_localtime', False) if localtime: @@ -1463,13 +1470,14 @@ class XendDomainInfo: # Use architecture- and image-specific calculations to determine # the various headrooms necessary, given the raw configured # values. maxmem, memory, and shadow are all in KiB. + # but memory_static_max etc are all stored in bytes now. memory = self.image.getRequiredAvailableMemory( - self.info['memory_static_min'] * 1024) + self.info['memory_dynamic_max'] / 1024) maxmem = self.image.getRequiredAvailableMemory( - self.info['memory_static_max'] * 1024) + self.info['memory_static_max'] / 1024) shadow = self.image.getRequiredShadowMemory( - self.info['shadow_memory'] * 1024, - self.info['memory_static_max'] * 1024) + self.info['shadow_memory'] / 1024, + self.info['memory_static_max'] / 1024) log.debug("_initDomain:shadow_memory=0x%x, memory_static_max=0x%x, memory_static_min=0x%x.", self.info['shadow_memory'], self.info['memory_static_max'], self.info['memory_static_min'],) # Round shadow up to a multiple of a MiB, as shadow_mem_control @@ -1505,9 +1513,15 @@ class XendDomainInfo: self.info['start_time'] = time.time() self._stateSet(DOM_STATE_RUNNING) - except (RuntimeError, VmError), exn: + except VmError, exn: log.exception("XendDomainInfo.initDomain: exception occurred") - self.image.cleanupBootloading() + if self.image: + self.image.cleanupBootloading() + raise exn + except RuntimeError, exn: + log.exception("XendDomainInfo.initDomain: exception occurred") + if self.image: + self.image.cleanupBootloading() raise VmError(str(exn)) @@ -1574,13 +1588,8 @@ class XendDomainInfo: self.console_mfn = console_mfn self._introduceDomain() - image_cfg = self.info.get('image', {}) - hvm = image_cfg.has_key('hvm') - if hvm: - self.image = image.create(self, - self.info, - self.info['image'], - self.info['devices']) + if self.info.is_hvm(): + self.image = image.create(self, self.info) if self.image: self.image.createDeviceModel(True) self.image.register_shutdown_watch() @@ -1657,7 +1666,18 @@ class XendDomainInfo: log.exception("XendDomainInfo.destroy: xc.domain_destroy failed.") from xen.xend import XendDomain - XendDomain.instance().remove_domain(self) + + if "transient" in self.info["other_config"]\ + and bool(self.info["other_config"]["transient"]): + xendDomainInstance = XendDomain.instance() + + xendDomainInstance.domains_lock.acquire() + xendDomainInstance._refresh(refresh_shutdown = False) + xendDomainInstance.domains_lock.release() + + xendDomainInstance.domain_delete(self.info["name_label"]) + else: + XendDomain.instance().remove_domain(self) self.cleanupDomain() self._cleanup_phantom_devs(paths) @@ -1742,11 +1762,7 @@ class XendDomainInfo: if boot: # HVM booting. - self.info['image']['type'] = 'hvm' - if not 'devices' in self.info['image']: - self.info['image']['devices'] = {} - self.info['image']['devices']['boot'] = \ - self.info['HVM_boot_params'].get('order', 'dc') + pass elif not blexec and kernel: # Boot from dom0. Nothing left to do -- the kernel and ramdisk # will be picked up by image.py. @@ -1770,7 +1786,8 @@ class XendDomainInfo: disk = devinfo[1]['uname'] fn = blkdev_uname_to_file(disk) - mounted = devtype == 'tap' and not os.stat(fn).st_rdev + taptype = blkdev_uname_to_taptype(disk) + mounted = devtype == 'tap' and taptype != 'aio' and taptype != 'sync' and not os.stat(fn).st_rdev if mounted: # This is a file, not a device. pygrub can cope with a # file if it's raw, but if it's QCOW or other such formats @@ -1786,7 +1803,7 @@ class XendDomainInfo: from xen.xend import XendDomain dom0 = XendDomain.instance().privilegedDomain() - dom0._waitForDeviceUUID(dom0.create_vbd(vbd, fn)) + dom0._waitForDeviceUUID(dom0.create_vbd(vbd, disk)) fn = BOOTLOADER_LOOPBACK_DEVICE try: @@ -1844,7 +1861,7 @@ class XendDomainInfo: # 1MB per vcpu plus 4Kib/Mib of RAM. This is higher than # the minimum that Xen would allocate if no value were given. overhead_kb = self.info['vcpus_number'] * 1024 + \ - self.info['memory_static_max'] * 4 + (self.info['memory_static_max'] / 1024 / 1024) * 4 overhead_kb = ((overhead_kb + 1023) / 1024) * 1024 # The domain might already have some shadow memory overhead_kb -= xc.shadow_mem_control(self.domid) * 1024 @@ -1910,10 +1927,14 @@ class XendDomainInfo: if self._infoIsSet(info_key): to_store[key] = str(self.info[info_key]) - if self.info.get('image'): - image_sxpr = self.info.image_sxpr() - if image_sxpr: - to_store['image'] = sxp.to_string(image_sxpr) + if self._infoIsSet("static_memory_min"): + to_store["memory"] = str(self.info["static_memory_min"]) + if self._infoIsSet("static_memory_max"): + to_store["maxmem"] = str(self.info["static_memory_max"]) + + image_sxpr = self.info.image_sxpr() + if image_sxpr: + to_store['image'] = sxp.to_string(image_sxpr) if self._infoIsSet('security'): secinfo = self.info['security'] @@ -2000,7 +2021,11 @@ class XendDomainInfo: info = dom_get(self.domid) if not info: return - + + if info["maxmem_kb"] < 0: + info["maxmem_kb"] = XendNode.instance() \ + .physinfo_dict()['total_memory'] * 1024 + #manually update ssidref / security fields if security.on() and info.has_key('ssidref'): if (info['ssidref'] != 0) and self.info.has_key('security'): @@ -2057,15 +2082,6 @@ class XendDomainInfo: return self.info.get('memory_dynamic_max', 0) def get_memory_dynamic_min(self): return self.info.get('memory_dynamic_min', 0) - - def get_vcpus_policy(self): - sched_id = xc.sched_id_get() - if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF: - return 'sedf' - elif sched_id == xen.lowlevel.xc.XEN_SCHEDULER_CREDIT: - return 'credit' - else: - return 'unknown' def get_vcpus_params(self): if self.getDomid() is None: return self.info['vcpus_params'] @@ -2074,22 +2090,14 @@ class XendDomainInfo: return retval def get_power_state(self): return XEN_API_VM_POWER_STATE[self.state] - def get_platform_std_vga(self): - return self.info.get('platform_std_vga', False) - def get_platform_serial(self): - return self.info.get('platform_serial', '') - def get_platform_localtime(self): - return self.info.get('platform_localtime', False) - def get_platform_clock_offset(self): - return self.info.get('platform_clock_offset', False) - def get_platform_enable_audio(self): - return self.info.get('platform_enable_audio', False) - def get_platform_keymap(self): - return self.info.get('platform_keymap', '') + def get_platform(self): + return self.info.get('platform', {}) def get_pci_bus(self): return self.info.get('pci_bus', '') def get_tools_version(self): return self.info.get('tools_version', {}) + def get_metrics(self): + return self.metrics.get_uuid(); def get_on_shutdown(self): after_shutdown = self.info.get('actions_after_shutdown') @@ -2278,8 +2286,6 @@ class XendDomainInfo: @return: uuid of the device """ xenapi_vbd['image'] = vdi_image_path - log.debug('create_vbd: %s' % xenapi_vbd) - dev_uuid = '' if vdi_image_path.startswith('tap'): dev_uuid = self.info.device_add('tap', cfg_xenapi = xenapi_vbd) else: @@ -2289,16 +2295,25 @@ class XendDomainInfo: raise XendError('Failed to create device') if self.state == XEN_API_VM_POWER_STATE_RUNNING: + _, config = self.info['devices'][dev_uuid] - dev_control = None if vdi_image_path.startswith('tap'): - dev_control = self.getDeviceController('tap') + dev_control = self.getDeviceController('tap') else: dev_control = self.getDeviceController('vbd') - - config['devid'] = dev_control.createDevice(config) + try: + devid = dev_control.createDevice(config) + dev_control.waitForDevice(devid) + self.info.device_update(dev_uuid, + cfg_xenapi = {'devid': devid}) + except Exception, exn: + log.exception(exn) + del self.info['devices'][dev_uuid] + self.info['vbd_refs'].remove(dev_uuid) + raise + return dev_uuid def create_phantom_vbd_with_vdi(self, xenapi_vbd, vdi_image_path): @@ -2332,9 +2347,21 @@ class XendDomainInfo: raise XendError('Failed to create device') if self.state == XEN_API_VM_POWER_STATE_RUNNING: - _, config = self.info['devices'][dev_uuid] - config['devid'] = self.getDeviceController('vif').createDevice(config) + _, config = self.info['devices'][dev_uuid] + dev_control = self.getDeviceController('vif') + + try: + devid = dev_control.createDevice(config) + dev_control.waitForDevice(devid) + self.info.device_update(dev_uuid, + cfg_xenapi = {'devid': devid}) + except Exception, exn: + log.exception(exn) + del self.info['devices'][dev_uuid] + self.info['vif_refs'].remove(dev_uuid) + raise + return dev_uuid def create_vtpm(self, xenapi_vtpm): @@ -2401,7 +2428,7 @@ class XendDomainInfo: def __str__(self): return '' % \ (str(self.domid), self.info['name_label'], - str(self.info['memory_static_min']), DOM_STATES[self.state]) + str(self.info['memory_dynamic_max']), DOM_STATES[self.state]) __repr__ = __str__ diff --git a/tools/python/xen/xend/XendError.py b/tools/python/xen/xend/XendError.py index f1507c43dc..bbd5f4f6dd 100644 --- a/tools/python/xen/xend/XendError.py +++ b/tools/python/xen/xend/XendError.py @@ -13,6 +13,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray +# Copyright (c) 2006, 2007 XenSource Inc. #============================================================================ from xmlrpclib import Fault @@ -55,6 +56,12 @@ class VmError(XendError): """Vm construction error.""" pass +class HVMRequired(VmError): + def __init__(self): + XendError.__init__(self, + 'HVM guest support is unavailable: is VT/AMD-V ' + 'supported by your CPU and enabled in your BIOS?') + XEND_ERROR_AUTHENTICATION_FAILED = ('ELUSER', 'Authentication Failed') XEND_ERROR_SESSION_INVALID = ('EPERMDENIED', 'Session Invalid') diff --git a/tools/python/xen/xend/XendLogging.py b/tools/python/xen/xend/XendLogging.py index 6d6140188d..3d6b678f1d 100644 --- a/tools/python/xen/xend/XendLogging.py +++ b/tools/python/xen/xend/XendLogging.py @@ -59,6 +59,18 @@ if 'TRACE' not in logging.__dict__: return filename, frame[2] logging.Logger.findCaller = findCaller + # Work around a bug in Python's inspect module: findsource is supposed to + # raise IOError if it fails, with other functions in that module coping + # with that, but some people are seeing IndexError raised from there. + if hasattr(inspect, 'findsource'): + real_findsource = getattr(inspect, 'findsource') + def findsource(*args, **kwargs): + try: + return real_findsource(*args, **kwargs) + except IndexError, exn: + raise IOError(exn) + inspect.findsource = findsource + log = logging.getLogger("xend") diff --git a/tools/python/xen/xend/XendNode.py b/tools/python/xen/xend/XendNode.py index 9d2a70dd9e..3917c8080c 100644 --- a/tools/python/xen/xend/XendNode.py +++ b/tools/python/xen/xend/XendNode.py @@ -75,6 +75,11 @@ class XendNode: self.other_config = {} self.cpus = {} self.host_metrics_uuid = uuid.createString() + + # put some arbitrary params in other_config as this + # is directly exposed via XenAPI + self.other_config["xen_pagesize"] = self.xeninfo_dict()["xen_pagesize"] + self.other_config["platform_params"] = self.xeninfo_dict()["platform_params"] # load CPU UUIDs saved_cpus = self.state_store.load_state('cpu') @@ -95,15 +100,12 @@ class XendNode: self.cpus[u] = {'uuid': u, 'number': i } for u in self.cpus.keys(): - log.error(self.cpus[u]) number = self.cpus[u]['number'] # We can run off the end of the cpuinfo list if domain0 does not # have #vcpus == #pcpus. In that case we just replicate one that's # in the hash table. if not cpuinfo.has_key(number): number = cpuinfo.keys()[0] - log.error(number) - log.error(cpuinfo) if arch.type == "x86": self.cpus[u].update( { 'host' : self.uuid, @@ -356,14 +358,37 @@ class XendNode: def xen_version(self): info = self.xc.xeninfo() + try: from xen import VERSION - return {'Xen': '%(xen_major)d.%(xen_minor)d' % info, + info = {'Xen': '%(xen_major)d.%(xen_minor)d' % info, 'Xend': VERSION} except (ImportError, AttributeError): - return {'Xen': '%(xen_major)d.%(xen_minor)d' % info, + info = {'Xen': '%(xen_major)d.%(xen_minor)d' % info, 'Xend': '3.0.3'} + # Add xend_config_format + info.update(self.xendinfo_dict()) + + # Add version info about machine + info.update(self.nodeinfo_dict()) + + # Add specific xen version info + xeninfo_dict = self.xeninfo_dict() + + info.update({ + "xen_major": xeninfo_dict["xen_major"], + "xen_minor": xeninfo_dict["xen_minor"], + "xen_extra": xeninfo_dict["xen_extra"], + "cc_compiler": xeninfo_dict["cc_compiler"], + "cc_compile_by": xeninfo_dict["cc_compile_by"], + "cc_compile_domain": xeninfo_dict["cc_compile_domain"], + "cc_compile_date": xeninfo_dict["cc_compile_date"], + "xen_changeset": xeninfo_dict["xen_changeset"] + }) + + return info + def get_name(self): return self.name @@ -418,6 +443,27 @@ class XendNode: return 0.0 + def get_vcpus_policy(self): + sched_id = self.xc.sched_id_get() + if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF: + return 'sedf' + elif sched_id == xen.lowlevel.xc.XEN_SCHEDULER_CREDIT: + return 'credit' + else: + return 'unknown' + + def get_cpu_configuration(self): + phys_info = self.physinfo_dict() + + cpu_info = { + "nr_nodes": phys_info["nr_nodes"], + "sockets_per_node": phys_info["sockets_per_node"], + "cores_per_socket": phys_info["cores_per_socket"], + "threads_per_core": phys_info["threads_per_core"] + } + + return cpu_info + # # Network Functions # @@ -453,6 +499,12 @@ class XendNode: return pif.network raise Exception('Bridge %s is not connected to a network' % bridge) + # + # Debug keys. + # + + def send_debug_keys(self, keys): + return self.xc.send_debug_keys(keys) # # Getting host information. @@ -478,7 +530,8 @@ class XendNode: info['cores_per_socket'] * info['threads_per_core']) info['cpu_mhz'] = info['cpu_khz'] / 1000 - # physinfo is in KiB + + # physinfo is in KiB, need it in MiB info['total_memory'] = info['total_memory'] / 1024 info['free_memory'] = info['free_memory'] / 1024 diff --git a/tools/python/xen/xend/XendVDI.py b/tools/python/xen/xend/XendVDI.py index f0dda203a8..140ca01226 100644 --- a/tools/python/xen/xend/XendVDI.py +++ b/tools/python/xen/xend/XendVDI.py @@ -54,7 +54,6 @@ class XendVDI(AutoSaveObject): SAVED_CFG = ['name_label', 'name_description', - 'sector_size', 'virtual_size', 'physical_utilisation', 'sharable', @@ -67,13 +66,22 @@ class XendVDI(AutoSaveObject): self.sr_uuid = sr_uuid self.name_label = "" self.name_description = "" - self.sector_size = 1024 self.virtual_size = 0 self.physical_utilisation = 0 self.sharable = False self.read_only = False self.type = "system" - self.location = '' + self.other_config = {} + self.vbds = [] + + def addVBD(self, vbd_ref): + self.vbds.append(vbd_ref) + + def removeVBD(self, vbd_ref): + self.vbds.remove(vbd_ref) + + def getVBDs(self): + return self.vbds def load_config_dict(self, cfg): """Loads configuration into the object from a dict. @@ -144,11 +152,10 @@ class XendVDI(AutoSaveObject): 'name_description': self.name_description, 'virtual_size': self.virtual_size, 'physical_utilisation': self.physical_utilisation, - 'sector_size': self.sector_size, 'sharable': False, 'readonly': False, 'SR': self.sr_uuid, - 'location': self.get_location(), + 'other_config': self.other_config, 'VBDs': []} def get_location(self): @@ -163,12 +170,11 @@ class XendQCoWVDI(XendVDI): self.cfg_path = cfg_path self.physical_utilisation = psize self.virtual_size = vsize - self.sector_size = 512 self.auto_save = True - self.location = 'tap:qcow:%s' % self.qcow_path + self.other_config['location'] = 'tap:qcow:%s' % self.qcow_path def get_location(self): - return self.location + return self.other_config['location'] class XendLocalVDI(XendVDI): def __init__(self, vdi_struct): @@ -182,11 +188,10 @@ class XendLocalVDI(XendVDI): self.name_description = vdi_struct.get('name_description', '') self.physical_utilisation = 0 self.virtual_size = 0 - self.sector_size = 0 self.type = vdi_struct.get('type', '') self.sharable = vdi_struct.get('sharable', False) self.read_only = vdi_struct.get('read_only', False) - self.location = vdi_struct.get('location', 'file:/dev/null') + self.other_config = vdi_struct.get('other_config', {}) def get_location(self): - return self.location + return self.other_config['location'] diff --git a/tools/python/xen/xend/XendVMMetrics.py b/tools/python/xen/xend/XendVMMetrics.py new file mode 100644 index 0000000000..d531411b30 --- /dev/null +++ b/tools/python/xen/xend/XendVMMetrics.py @@ -0,0 +1,70 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (c) 2006-2007 Xensource Inc. +#============================================================================ + +from xen.xend.XendLogging import log + +instances = {} + +class XendVMMetrics: + """VM Metrics.""" + + def get_by_uuid(_, uuid): + return instances[uuid] + + get_by_uuid = classmethod(get_by_uuid) + + def is_valid_vm_metrics(_, uuid): + return uuid in instances + + is_valid_vm_metrics = classmethod(is_valid_vm_metrics) + + def get_all(_): + return instances.keys() + + get_all = classmethod(get_all) + + def __init__(self, uuid, xend_domain_instance): + self.uuid = uuid + self.xend_domain_instance = xend_domain_instance + instances[uuid] = self + + def get_uuid(self): + return self.uuid + + def get_memory_actual(self): + return self.get_record()["memory_actual"] + + def get_vcpus_number(self): + return self.get_record()["vcpus_number"] + + def get_vcpus_utilisation(self): + return self.xend_domain_instance.get_vcpus_util() + + def get_record(self): + domInfo = self.xend_domain_instance.getDomInfo() + if domInfo: + return { 'uuid' : self.uuid, + 'memory_actual' : domInfo["mem_kb"] * 1024, + 'vcpus_number' : domInfo["online_vcpus"], + 'vcpus_utilisation' : self.get_vcpus_utilisation() + } + else: + return { 'uuid' : self.uuid, + 'memory_actual' : 0, + 'vcpus_number' : 0, + 'vcpus_utilisation' : {} + } diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 4f929cd92d..d9e850ccc9 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -13,7 +13,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2005 Mike Wray -# Copyright (C) 2005 XenSource Ltd +# Copyright (C) 2005-2007 XenSource Ltd #============================================================================ @@ -24,7 +24,7 @@ import signal import xen.lowlevel.xc from xen.xend.XendConstants import REVERSE_DOMAIN_SHUTDOWN_REASONS -from xen.xend.XendError import VmError, XendError +from xen.xend.XendError import VmError, XendError, HVMRequired from xen.xend.XendLogging import log from xen.xend.XendOptions import instance as xenopts from xen.xend.server.netif import randomMAC @@ -36,13 +36,12 @@ xc = xen.lowlevel.xc.xc() MAX_GUEST_CMDLINE = 1024 -def create(vm, vmConfig, imageConfig, deviceConfig): +def create(vm, vmConfig): """Create an image handler for a vm. @return ImageHandler instance """ - return findImageHandlerClass(imageConfig)(vm, vmConfig, imageConfig, - deviceConfig) + return findImageHandlerClass(vmConfig)(vm, vmConfig) class ImageHandler: @@ -65,7 +64,7 @@ class ImageHandler: ostype = None - def __init__(self, vm, vmConfig, imageConfig, deviceConfig): + def __init__(self, vm, vmConfig): self.vm = vm self.bootloader = False @@ -73,9 +72,9 @@ class ImageHandler: self.ramdisk = None self.cmdline = None - self.configure(vmConfig, imageConfig, deviceConfig) + self.configure(vmConfig) - def configure(self, vmConfig, imageConfig, _): + def configure(self, vmConfig): """Config actions common to all unix-like domains.""" if '_temp_using_bootloader' in vmConfig: self.bootloader = True @@ -233,30 +232,29 @@ class HVMImageHandler(ImageHandler): ostype = "hvm" - def __init__(self, vm, vmConfig, imageConfig, deviceConfig): - ImageHandler.__init__(self, vm, vmConfig, imageConfig, deviceConfig) + def __init__(self, vm, vmConfig): + ImageHandler.__init__(self, vm, vmConfig) self.shutdownWatch = None self.rebootFeatureWatch = None - def configure(self, vmConfig, imageConfig, deviceConfig): - ImageHandler.configure(self, vmConfig, imageConfig, deviceConfig) + def configure(self, vmConfig): + ImageHandler.configure(self, vmConfig) if not self.kernel: self.kernel = '/usr/lib/xen/boot/hvmloader' info = xc.xeninfo() if 'hvm' not in info['xen_caps']: - raise VmError("HVM guest support is unavailable: is VT/AMD-V " - "supported by your CPU and enabled in your BIOS?") + raise HVMRequired() self.dmargs = self.parseDeviceModelArgs(vmConfig) - self.device_model = imageConfig['hvm'].get('device_model') + self.device_model = vmConfig['platform'].get('device_model') if not self.device_model: raise VmError("hvm: missing device model") - self.display = imageConfig['hvm'].get('display') - self.xauthority = imageConfig['hvm'].get('xauthority') - self.vncconsole = imageConfig['hvm'].get('vncconsole') + self.display = vmConfig['platform'].get('display') + self.xauthority = vmConfig['platform'].get('xauthority') + self.vncconsole = vmConfig['platform'].get('vncconsole') self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)), ("image/device-model", self.device_model), @@ -264,9 +262,9 @@ class HVMImageHandler(ImageHandler): self.pid = None - self.pae = imageConfig['hvm'].get('pae', 0) - self.apic = imageConfig['hvm'].get('apic', 0) - self.acpi = imageConfig['hvm']['devices'].get('acpi', 0) + self.pae = int(vmConfig['platform'].get('pae', 0)) + self.apic = int(vmConfig['platform'].get('apic', 0)) + self.acpi = int(vmConfig['platform'].get('acpi', 0)) def buildDomain(self): @@ -302,11 +300,10 @@ class HVMImageHandler(ImageHandler): 'localtime', 'serial', 'stdvga', 'isa', 'acpi', 'usb', 'usbdevice', 'keymap' ] - hvmDeviceConfig = vmConfig['image']['hvm']['devices'] ret = ['-vcpus', str(self.vm.getVCpuCount())] for a in dmargs: - v = hvmDeviceConfig.get(a) + v = vmConfig['platform'].get(a) # python doesn't allow '-' in variable names if a == 'stdvga': a = 'std-vga' @@ -366,14 +363,14 @@ class HVMImageHandler(ImageHandler): # Find RFB console device, and if it exists, make QEMU enable # the VNC console. # - if vmConfig['image'].get('nographic'): + if int(vmConfig['platform'].get('nographic', 0)) != 0: # skip vnc init if nographic is set ret.append('-nographic') return ret vnc_config = {} - has_vnc = int(vmConfig['image'].get('vnc', 0)) != 0 - has_sdl = int(vmConfig['image'].get('sdl', 0)) != 0 + has_vnc = int(vmConfig['platform'].get('vnc', 0)) != 0 + has_sdl = int(vmConfig['platform'].get('sdl', 0)) != 0 for dev_uuid in vmConfig['console_refs']: dev_type, dev_info = vmConfig['devices'][dev_uuid] if dev_type == 'vfb': @@ -385,8 +382,8 @@ class HVMImageHandler(ImageHandler): if not vnc_config: for key in ('vncunused', 'vnclisten', 'vncdisplay', 'vncpasswd'): - if key in vmConfig['image']: - vnc_config[key] = vmConfig['image'][key] + if key in vmConfig['platform']: + vnc_config[key] = vmConfig['platform'][key] if not vnc_config.get('vncunused', 0) and \ vnc_config.get('vncdisplay', 0): @@ -604,9 +601,7 @@ def findImageHandlerClass(image): @param image config @return ImageHandler subclass or None """ - image_type = image['type'] - if image_type is None: - raise VmError('missing image type') + image_type = image.image_type() try: return _handlers[arch.type][image_type] except KeyError: diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 04f7a789a6..adb83b679c 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -276,9 +276,12 @@ class Daemon: if not m: return None modulename = m.group(1) - if re.search('sxp.py', modulename): - return None - if re.search('SrvServer.py', modulename): + if modulename.endswith('.pyc'): + modulename = modulename[:-1] + if modulename == 'sxp.py' or \ + modulename == 'XendLogging.py' or \ + modulename == 'XendMonitor.py' or \ + modulename == 'server/SrvServer.py': return None self.traceindent += 1 self.print_trace("> %s:%s\n" diff --git a/tools/python/xen/xend/server/XMLRPCServer.py b/tools/python/xen/xend/server/XMLRPCServer.py index 7c3a2a1a9d..ed07811ff6 100644 --- a/tools/python/xen/xend/server/XMLRPCServer.py +++ b/tools/python/xen/xend/server/XMLRPCServer.py @@ -157,7 +157,7 @@ class XMLRPCServer: self.server.register_function(fn, "xend.domain.%s" % name[7:]) # Functions in XendNode and XendDmesg - for type, lst, n in [(XendNode, ['info'], 'node'), + for type, lst, n in [(XendNode, ['info', 'send_debug_keys'], 'node'), (XendDmesg, ['info', 'clear'], 'node.dmesg')]: inst = type.instance() for name in lst: diff --git a/tools/python/xen/xend/server/vfbif.py b/tools/python/xen/xend/server/vfbif.py index fb510de25f..cbef190248 100644 --- a/tools/python/xen/xend/server/vfbif.py +++ b/tools/python/xen/xend/server/vfbif.py @@ -46,7 +46,7 @@ class VfbifController(DevController): def createDevice(self, config): DevController.createDevice(self, config) - if self.vm.info.get('HVM_boot_policy'): + if self.vm.info.is_hvm(): # is HVM, so qemu-dm will handle the vfb. return diff --git a/tools/python/xen/xm/XenAPI.py b/tools/python/xen/xm/XenAPI.py index 8d58c3f7f6..ae2448eb71 100644 --- a/tools/python/xen/xm/XenAPI.py +++ b/tools/python/xen/xm/XenAPI.py @@ -155,7 +155,7 @@ class Session(xen.util.xmlrpclib2.ServerProxy): def _parse_result(result): if type(result) != dict or 'Status' not in result: - raise xmlrpclib.Fault(500, 'Missing Status in response from server') + raise xmlrpclib.Fault(500, 'Missing Status in response from server: ' + str(result)) if result['Status'] == 'Success': if 'Value' in result: return result['Value'] diff --git a/tools/python/xen/xm/addlabel.py b/tools/python/xen/xm/addlabel.py index af176da433..2d42d6702d 100644 --- a/tools/python/xen/xm/addlabel.py +++ b/tools/python/xen/xm/addlabel.py @@ -17,7 +17,7 @@ # Author: Bryan D. Payne #============================================================================ -"""Labeling a domain configuration file or a resoruce. +"""Labeling a domain configuration file or a resource. """ import os import sys diff --git a/tools/python/xen/xm/create.dtd b/tools/python/xen/xm/create.dtd new file mode 100644 index 0000000000..b544edc5bd --- /dev/null +++ b/tools/python/xen/xm/create.dtd @@ -0,0 +1,118 @@ + +%HTMLlat1; + +%HTMLsymbol; + +%HTMLspecial; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 450e3283d1..abdfa22031 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -28,12 +28,13 @@ import time import xmlrpclib from xen.xend import sxp -from xen.xend import PrettyPrint +from xen.xend import PrettyPrint as SXPPrettyPrint from xen.xend import osdep import xen.xend.XendClient from xen.xend.XendBootloader import bootloader from xen.util import blkif from xen.util import security +from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm from xen.xm.opts import * @@ -98,6 +99,11 @@ gopts.opt('dryrun', short='n', use="Dry run - prints the resulting configuration in SXP but " "does not create the domain.") +gopts.opt('xmldryrun', short='x', + fn=set_true, default=0, + use="XML dry run - prints the resulting configuration in XML but " + "does not create the domain.") + gopts.opt('paused', short='p', fn=set_true, default=0, use='Leave the domain paused after it is created.') @@ -1241,34 +1247,59 @@ def main(argv): except IOError, exn: raise OptionError("Cannot read file %s: %s" % (config, exn[1])) + if serverType == SERVER_XEN_API: + from xen.xm.xenapi_create import sxp2xml + sxp2xml_inst = sxp2xml() + doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True) + if opts.vals.dryrun: - PrettyPrint.prettyprint(config) + SXPPrettyPrint.prettyprint(config) + + if opts.vals.xmldryrun and serverType == SERVER_XEN_API: + from xml.dom.ext import PrettyPrint as XMLPrettyPrint + XMLPrettyPrint(doc) + + if opts.vals.dryrun or opts.vals.xmldryrun: + return + + if opts.vals.console_autoconnect: + do_console(sxp.child_value(config, 'name', -1)) + + if serverType == SERVER_XEN_API: + from xen.xm.xenapi_create import xenapi_create + xenapi_create_inst = xenapi_create() + vm_refs = xenapi_create_inst.create(document = doc) + + map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs) else: if not create_security_check(config): - raise security.ACMError('Security Configuration prevents domain from starting') - else: - if opts.vals.console_autoconnect: - cpid = os.fork() - if cpid != 0: - for i in range(10): - # Catch failure of the create process - time.sleep(1) - (p, rv) = os.waitpid(cpid, os.WNOHANG) - if os.WIFEXITED(rv): - if os.WEXITSTATUS(rv) != 0: - sys.exit(os.WEXITSTATUS(rv)) - try: - # Acquire the console of the created dom - name = sxp.child_value(config, 'name', -1) - dom = server.xend.domain(name) - domid = int(sxp.child_value(dom, 'domid', '-1')) - console.execConsole(domid) - except: - pass - print("Could not start console\n"); - sys.exit(0) - dom = make_domain(opts, config) - + raise security.ACMError( + 'Security Configuration prevents domain from starting') + dom = make_domain(opts, config) + +def do_console(domain_name): + cpid = os.fork() + if cpid != 0: + for i in range(10): + # Catch failure of the create process + time.sleep(1) + (p, rv) = os.waitpid(cpid, os.WNOHANG) + if os.WIFEXITED(rv): + if os.WEXITSTATUS(rv) != 0: + sys.exit(os.WEXITSTATUS(rv)) + try: + # Acquire the console of the created dom + if serverType == SERVER_XEN_API: + domid = server.xenapi.VM.get_domid( + get_single_vm(domain_name)) + else: + dom = server.xend.domain(domain_name) + domid = int(sxp.child_value(dom, 'domid', '-1')) + console.execConsole(domid) + except: + pass + print("Could not start console\n"); + sys.exit(0) if __name__ == '__main__': main(sys.argv) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 7075e95444..66a5951f7f 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -25,6 +25,7 @@ import atexit import cmd import os import pprint +import readline import shlex import sys import re @@ -32,11 +33,11 @@ import getopt import socket import traceback import xmlrpclib -import traceback import time import datetime from select import select import xml.dom.minidom +from xen.util.blkif import blkdev_name_to_number import warnings warnings.filterwarnings('ignore', category=FutureWarning) @@ -48,18 +49,19 @@ from xen.xend.XendConstants import * from xen.xm.opts import OptionError, Opts, wrap, set_true from xen.xm import console -from xen.util import security from xen.util.xmlrpclib2 import ServerProxy import XenAPI + # getopt.gnu_getopt is better, but only exists in Python 2.3+. Use # getopt.getopt if gnu_getopt is not available. This will mean that options # may only be specified before positional arguments. if not hasattr(getopt, 'gnu_getopt'): getopt.gnu_getopt = getopt.getopt -XM_CONFIG_FILE = '/etc/xen/xm-config.xml' +XM_CONFIG_FILE_ENVVAR = 'XM_CONFIG_FILE' +XM_CONFIG_FILE_DEFAULT = '/etc/xen/xm-config.xml' # Supported types of server SERVER_LEGACY_XMLRPC = 'LegacyXMLRPC' @@ -133,11 +135,12 @@ SUBCOMMAND_HELP = { 'sched-credit': ('[-d [-w[=WEIGHT]|-c[=CAP]]]', 'Get/set credit scheduler parameters.'), 'sysrq' : (' ', 'Send a sysrq to a domain.'), + 'debug-keys' : ('', 'Send debug keys to Xen.'), 'trigger' : (' []', 'Send a trigger to a domain.'), 'vcpu-list' : ('[]', 'List the VCPUs for a domain or all domains.'), - 'vcpu-pin' : (' ', + 'vcpu-pin' : (' ', 'Set which CPUs a VCPU can use.'), 'vcpu-set' : (' ', 'Set the number of active VCPUs for allowed for the' @@ -260,7 +263,6 @@ common_commands = [ "shutdown", "start", "suspend", - "trigger", "top", "unpause", "uptime", @@ -300,6 +302,7 @@ domain_commands = [ ] host_commands = [ + "debug-keys", "dmesg", "info", "log", @@ -349,13 +352,14 @@ all_commands = (domain_commands + host_commands + scheduler_commands + # Configuration File Parsing ## +xmConfigFile = os.getenv(XM_CONFIG_FILE_ENVVAR, XM_CONFIG_FILE_DEFAULT) config = None -if os.path.isfile(XM_CONFIG_FILE): +if os.path.isfile(xmConfigFile): try: - config = xml.dom.minidom.parse(XM_CONFIG_FILE) + config = xml.dom.minidom.parse(xmConfigFile) except: print >>sys.stderr, ('Ignoring invalid configuration file %s.' % - XM_CONFIG_FILE) + xmConfigFile) def parseServer(): if config: @@ -489,6 +493,18 @@ def usage(cmd = None): # #################################################################### +def get_default_SR(): + return [sr_ref + for sr_ref in server.xenapi.SR.get_all() + if server.xenapi.SR.get_type(sr_ref) == "local"][0] + +def get_default_Network(): + return [network_ref + for network_ref in server.xenapi.network.get_all()][0] + +def map2sxp(m): + return [[k, m[k]] for k in m.keys()] + def arg_check(args, name, lo, hi = -1): n = len([i for i in args if i != '--']) @@ -555,7 +571,11 @@ class Shell(cmd.Cmd): if serverType == SERVER_XEN_API: res = server.xenapi._UNSUPPORTED_list_all_methods() for f in res: - setattr(Shell, 'do_' + f, self.default) + setattr(Shell, 'do_' + f + ' ', self.default) + + def preloop(self): + cmd.Cmd.preloop(self) + readline.set_completer_delims(' ') def default(self, line): words = shlex.split(line) @@ -576,9 +596,9 @@ class Shell(cmd.Cmd): return False def completedefault(self, text, line, begidx, endidx): - cmd = line.split(' ')[0] - clas, func = cmd.split('.') - if begidx != len(cmd) + 1 or \ + words = shlex.split(line[:begidx]) + clas, func = words[0].split('.') + if len(words) > 1 or \ func.startswith('get_by_') or \ func == 'get_all': return [] @@ -667,10 +687,41 @@ def xm_restore(args): def getDomains(domain_names, state, full = 0): - if domain_names: - return [server.xend.domain(dom, full) for dom in domain_names] + if serverType == SERVER_XEN_API: + doms_sxp = [] + doms_dict = [] + dom_refs = server.xenapi.VM.get_all() + for dom_ref in dom_refs: + dom_rec = server.xenapi.VM.get_record(dom_ref) + dom_metrics_ref = server.xenapi.VM.get_metrics(dom_ref) + dom_metrics = server.xenapi.VM_metrics.get_record(dom_metrics_ref) + dom_rec.update({'name': dom_rec['name_label'], + 'memory_actual': int(dom_metrics['memory_actual'])/1024, + 'vcpus': dom_metrics['vcpus_number'], + 'state': '-----', + 'cpu_time': dom_metrics['vcpus_utilisation']}) + + doms_sxp.append(['domain'] + map2sxp(dom_rec)) + doms_dict.append(dom_rec) + + if domain_names: + doms = [['domain'] + map2sxp(dom) for dom in doms_dict + if dom["name"] in domain_names] + + if len(doms) > 0: + return doms + else: + print "Error: no domain%s named %s" % \ + (len(domain_names) > 1 and 's' or '', + ', '.join(domain_names)) + sys.exit(-1) + else: + return doms_sxp else: - return server.xend.domains_with_state(True, state, full) + if domain_names: + return [server.xend.domain(dom, full) for dom in domain_names] + else: + return server.xend.domains_with_state(True, state, full) def xm_list(args): @@ -729,26 +780,48 @@ def parse_doms_info(info): else: up_time = time.time() - start_time - return { + parsed_info = { 'domid' : get_info('domid', str, ''), 'name' : get_info('name', str, '??'), - 'mem' : get_info('memory_dynamic_min', int, 0), 'state' : get_info('state', str, ''), - 'cpu_time' : get_info('cpu_time', float, 0.0), + # VCPUs is the number online when the VM is up, or the number # configured otherwise. 'vcpus' : get_info('online_vcpus', int, get_info('vcpus', int, 0)), - 'up_time' : up_time, - 'seclabel' : security.get_security_printlabel(info), + 'up_time' : up_time } + # We're not supporting security stuff just yet via XenAPI + + if serverType != SERVER_XEN_API: + from xen.util import security + parsed_info['seclabel'] = security.get_security_printlabel(info) + else: + parsed_info['seclabel'] = "" + + if serverType == SERVER_XEN_API: + parsed_info['mem'] = get_info('memory_actual', int, 0) / 1024 + cpu_times = get_info('cpu_time', lambda x : (x), 0.0) + if sum(cpu_times.values()) > 0: + parsed_info['cpu_time'] = sum(cpu_times.values()) / float(len(cpu_times.values())) + else: + parsed_info['cpu_time'] = 0 + else: + parsed_info['mem'] = get_info('memory', int,0) + parsed_info['cpu_time'] = get_info('cpu_time', float, 0.0) + + return parsed_info + def check_sched_type(sched): - current = 'unknown' - for x in server.xend.node.info()[1:]: - if len(x) > 1 and x[0] == 'xen_scheduler': - current = x[1] - break + if serverType == SERVER_XEN_API: + current = server.xenapi.host.get_sched_policy(server.xenapi.session.get_this_host()) + else: + current = 'unknown' + for x in server.xend.node.info()[1:]: + if len(x) > 1 and x[0] == 'xen_scheduler': + current = x[1] + break if sched != current: err("Xen is running with the %s scheduler" % current) sys.exit(1) @@ -788,17 +861,22 @@ def xm_label_list(doms): output = [] format = '%(name)-32s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \ '%(cpu_time)8.1f %(seclabel)9s' - - for dom in doms: - d = parse_doms_info(dom) - if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']: - if not d['seclabel']: - d['seclabel'] = 'ERROR' - elif security.active_policy in ['DEFAULT']: - d['seclabel'] = 'DEFAULT' - else: - d['seclabel'] = 'INACTIVE' - output.append((format % d, d['seclabel'])) + + if serverType != SERVER_XEN_API: + from xen.util import security + + for dom in doms: + d = parse_doms_info(dom) + + if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']: + if not d['seclabel']: + d['seclabel'] = 'ERROR' + elif security.active_policy in ['DEFAULT']: + d['seclabel'] = 'DEFAULT' + else: + d['seclabel'] = 'INACTIVE' + + output.append((format % d, d['seclabel'])) #sort by labels output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower())) @@ -807,7 +885,6 @@ def xm_label_list(doms): def xm_vcpu_list(args): - if args: dominfo = map(server.xend.domain.getVCPUInfo, args) else: @@ -1078,7 +1155,10 @@ def xm_vcpu_pin(args): dom = args[0] vcpu = args[1] - cpumap = cpu_make_map(args[2]) + if args[2] == 'all': + cpumap = cpu_make_map('0-63') + else: + cpumap = cpu_make_map(args[2]) server.xend.domain.pincpu(dom, vcpu, cpumap) @@ -1086,49 +1166,69 @@ def xm_mem_max(args): arg_check(args, "mem-max", 2) dom = args[0] - mem = int_unit(args[1], 'm') - server.xend.domain.maxmem_set(dom, mem) + if serverType == SERVER_XEN_API: + mem = int_unit(args[1], 'k') * 1024 + server.xenapi.VM.set_memory_static_max(get_single_vm(dom), mem) + else: + mem = int_unit(args[1], 'm') + server.xend.domain.maxmem_set(dom, mem) def xm_mem_set(args): arg_check(args, "mem-set", 2) dom = args[0] - mem_target = int_unit(args[1], 'm') - server.xend.domain.setMemoryTarget(dom, mem_target) + if serverType == SERVER_XEN_API: + mem_target = int_unit(args[1], 'm') * 1024 * 1024 + server.xenapi.VM.set_memory_dynamic_max(get_single_vm(dom), mem_target) + server.xenapi.VM.set_memory_dynamic_min(get_single_vm(dom), mem_target) + else: + mem_target = int_unit(args[1], 'm') + server.xend.domain.setMemoryTarget(dom, mem_target) def xm_vcpu_set(args): arg_check(args, "vcpu-set", 2) - - server.xend.domain.setVCpuCount(args[0], int(args[1])) + dom = args[0] + vcpus = int(args[1]) + + if serverType == SERVER_XEN_API: + server.xenapi.VM.set_vcpus_live(get_single_vm(dom), vcpus) + else: + server.xend.domain.setVCpuCount(dom, vcpus) def xm_destroy(args): arg_check(args, "destroy", 1) dom = args[0] + if serverType == SERVER_XEN_API: server.xenapi.VM.hard_shutdown(get_single_vm(dom)) else: server.xend.domain.destroy(dom) - def xm_domid(args): arg_check(args, "domid", 1) name = args[0] - dom = server.xend.domain(name) - print sxp.child_value(dom, 'domid') + if serverType == SERVER_XEN_API: + print server.xenapi.VM.get_domid(get_single_vm(name)) + else: + dom = server.xend.domain(name) + print sxp.child_value(dom, 'domid') def xm_domname(args): arg_check(args, "domname", 1) name = args[0] - - dom = server.xend.domain(name) - print sxp.child_value(dom, 'name') + + if serverType == SERVER_XEN_API: + print server.xenapi.VM.get_name_label(get_single_vm(name)) + else: + dom = server.xend.domain(name) + print sxp.child_value(dom, 'name') def xm_sched_sedf(args): def ns_to_ms(val): @@ -1276,13 +1376,59 @@ def xm_sched_credit(args): def xm_info(args): arg_check(args, "info", 0) - info = server.xend.node.info() - - for x in info[1:]: - if len(x) < 2: - print "%-23s: (none)" % x[0] - else: - print "%-23s:" % x[0], x[1] + if serverType == SERVER_XEN_API: + + # Need to fake out old style xm info as people rely on parsing it + + host_record = server.xenapi.host.get_record( + server.xenapi.session.get_this_host()) + + host_cpu_records = map(server.xenapi.host_cpu.get_record, host_record["host_CPUs"]) + + host_metrics_record = server.xenapi.host_metrics.get_record(host_record["metrics"]) + + info = { + "host": host_record["name_label"], + "release": host_record["software_version"]["release"], + "version": host_record["software_version"]["version"], + "machine": host_record["software_version"]["machine"], + "nr_cpus": len(host_record["host_CPUs"]), + "nr_nodes": host_record["cpu_configuration"]["nr_nodes"], + "sockets_per_node": host_record["cpu_configuration"]["sockets_per_node"], + "cores_per_socket": host_record["cpu_configuration"]["cores_per_socket"], + "threads_per_core": host_record["cpu_configuration"]["threads_per_core"], + "cpu_mhz": sum([int(host_cpu_record["speed"]) for host_cpu_record in host_cpu_records]) + / len(host_cpu_records), + "hw_caps": host_cpu_records[0]["features"], + "total_memory": int(host_metrics_record["memory_total"])/1024/1024, + "free_memory": int(host_metrics_record["memory_free"])/1024/1024, + "xen_major": host_record["software_version"]["xen_major"], + "xen_minor": host_record["software_version"]["xen_minor"], + "xen_extra": host_record["software_version"]["xen_extra"], + "xen_caps": " ".join(host_record["capabilities"]), + "xen_scheduler": host_record["sched_policy"], + "xen_pagesize": host_record["other_config"]["xen_pagesize"], + "platform_params": host_record["other_config"]["platform_params"], + "xen_changeset": host_record["software_version"]["xen_changeset"], + "cc_compiler": host_record["software_version"]["cc_compiler"], + "cc_compile_by": host_record["software_version"]["cc_compile_by"], + "cc_compile_domain": host_record["software_version"]["cc_compile_domain"], + "cc_compile_date": host_record["software_version"]["cc_compile_date"], + "xend_config_format":host_record["software_version"]["xend_config_format"] + } + + sorted = info.items() + sorted.sort(lambda (x1,y1), (x2,y2): -cmp(x1,x2)) + + for (k, v) in sorted: + print "%-23s:" % k, v + else: + info = server.xend.node.info() + for x in info[1:]: + if len(x) < 2: + print "%-23s: (none)" % x[0] + else: + print "%-23s:" % x[0], x[1] def xm_console(args): arg_check(args, "console", 1, 2) @@ -1308,13 +1454,17 @@ def xm_console(args): dom = params[0] try: - info = server.xend.domain(dom) + if serverType == SERVER_XEN_API: + domid = int(server.xenapi.VM.get_domid(get_single_vm(dom))) + else: + info = server.xend.domain(dom) + domid = int(sxp.child_value(info, 'domid', '-1')) except: if quiet: sys.exit(1) else: raise - domid = int(sxp.child_value(info, 'domid', '-1')) + if domid == -1: if quiet: sys.exit(1) @@ -1382,7 +1532,10 @@ def xm_sysrq(args): arg_check(args, "sysrq", 2) dom = args[0] req = args[1] - server.xend.domain.send_sysrq(dom, req) + if serverType == SERVER_XEN_API: + server.xenapi.VM.send_sysrq(get_single_vm(dom), req) + else: + server.xend.domain.send_sysrq(dom, req) def xm_trigger(args): vcpu = 0 @@ -1392,8 +1545,23 @@ def xm_trigger(args): trigger = args[1] if len(args) == 3: vcpu = int(args[2]) + + if serverType == SERVER_XEN_API: + server.xenapi.VM.send_trigger(get_single_vm(dom), trigger, vcpu) + else: + server.xend.domain.send_trigger(dom, trigger, vcpu) + +def xm_debug_keys(args): + arg_check(args, "debug-keys", 1) + + keys = str(args[0]) - server.xend.domain.send_trigger(dom, trigger, vcpu) + if serverType == SERVER_XEN_API: + server.xenapi.host.send_debug_keys( + server.xenapi.session.get_this_host(), + keys) + else: + server.xend.node.send_debug_keys(keys) def xm_top(args): arg_check(args, "top", 0) @@ -1418,17 +1586,33 @@ def xm_dmesg(args): err("No parameter required") usage('dmesg') - if not use_clear: - print server.xend.node.dmesg.info() + if serverType == SERVER_XEN_API: + if not use_clear: + print server.xenapi.host.dmesg( + server.xenapi.session.get_this_host(),0) + else: + server.xenapi.host.dmesg( + server.xenapi.session.get_this_host(),1) else: - server.xend.node.dmesg.clear() + if not use_clear: + print server.xend.node.dmesg.info() + else: + server.xend.node.dmesg.clear() def xm_log(args): arg_check(args, "log", 0) - - print server.xend.node.log() + + if serverType == SERVER_XEN_API: + print server.xenapi.host.get_log( + server.xenapi.session.get_this_host()) + else: + print server.xend.node.log() def xm_serve(args): + if serverType == SERVER_XEN_API: + print "Not supported with XenAPI" + sys.exit(-1) + arg_check(args, "serve", 0) from fcntl import fcntl, F_SETFL @@ -1503,12 +1687,21 @@ def xm_network_list(args): (use_long, params) = arg_check_for_resource_list(args, "network-list") dom = params[0] - if use_long: + + if serverType == SERVER_XEN_API: + vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom)) + vif_properties = \ + map(server.xenapi.VIF.get_runtime_properties, vif_refs) + devs = map(lambda (handle, properties): [handle, map2sxp(properties)], + zip(range(len(vif_properties)), vif_properties)) + else: devs = server.xend.domain.getDeviceSxprs(dom, 'vif') + + if use_long: map(PrettyPrint.prettyprint, devs) else: hdr = 0 - for x in server.xend.domain.getDeviceSxprs(dom, 'vif'): + for x in devs: if hdr == 0: print 'Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path' hdr = 1 @@ -1528,12 +1721,25 @@ def xm_block_list(args): (use_long, params) = arg_check_for_resource_list(args, "block-list") dom = params[0] - if use_long: + + if serverType == SERVER_XEN_API: + vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom)) + vbd_properties = \ + map(server.xenapi.VBD.get_runtime_properties, vbd_refs) + vbd_devs = \ + map(server.xenapi.VBD.get_device, vbd_refs) + vbd_devids = \ + map(blkdev_name_to_number, vbd_devs) + devs = map(lambda (devid, prop): [devid, map2sxp(prop)], + zip(vbd_devids, vbd_properties)) + else: devs = server.xend.domain.getDeviceSxprs(dom, 'vbd') + + if use_long: map(PrettyPrint.prettyprint, devs) else: hdr = 0 - for x in server.xend.domain.getDeviceSxprs(dom, 'vbd'): + for x in devs: if hdr == 0: print 'Vdev BE handle state evt-ch ring-ref BE-path' hdr = 1 @@ -1588,13 +1794,17 @@ def parse_block_configuration(args): if len(args) == 5: vbd.append(['backend', args[4]]) - # verify that policy permits attaching this resource - if security.on(): - dominfo = server.xend.domain(dom) - label = security.get_security_printlabel(dominfo) - else: - label = None - security.res_security_check(args[1], label) + if serverType != SERVER_XEN_API: + # verify that policy permits attaching this resource + from xen.util import security + + if security.on(): + dominfo = server.xend.domain(dom) + label = security.get_security_printlabel(dominfo) + else: + label = None + + security.res_security_check(args[1], label) return (dom, vbd) @@ -1602,8 +1812,45 @@ def parse_block_configuration(args): def xm_block_attach(args): arg_check(args, 'block-attach', 4, 5) - (dom, vbd) = parse_block_configuration(args) - server.xend.domain.device_create(dom, vbd) + if serverType == SERVER_XEN_API: + dom = args[0] + uname = args[1] + dev = args[2] + mode = args[3] + + # First create new VDI + vdi_record = { + "name_label": "vdi" + str(uname.__hash__()), + "name_description": "", + "SR": get_default_SR(), + "virtual_size": 0, + "sector_size": 512, + "type": "system", + "sharable": False, + "read_only": mode!="w", + "other_config": {"location": uname} + } + + vdi_ref = server.xenapi.VDI.create(vdi_record) + + # Now create new VBD + + vbd_record = { + "VM": get_single_vm(dom), + "VDI": vdi_ref, + "device": dev, + "bootable": True, + "mode": mode=="w" and "RW" or "RO", + "type": "Disk", + "qos_algorithm_type": "", + "qos_algorithm_params": {} + } + + server.xenapi.VBD.create(vbd_record) + + else: + (dom, vbd) = parse_block_configuration(args) + server.xend.domain.device_create(dom, vbd) def xm_block_configure(args): @@ -1621,15 +1868,65 @@ def xm_network_attach(args): vif_params = ['type', 'mac', 'bridge', 'ip', 'script', \ 'backend', 'vifname', 'rate', 'model'] - for a in args[1:]: - vif_param = a.split("=") - if len(vif_param) != 2 or vif_param[1] == '' or \ - vif_param[0] not in vif_params: - err("Invalid argument: %s" % a) - usage('network-attach') - vif.append(vif_param) + if serverType == SERVER_XEN_API: + vif_record = { + "device": "eth0", + "network": get_default_Network(), + "VM": get_single_vm(dom), + "MAC": "", + "MTU": "", + "qos_algorithm_type": "", + "qos_algorithm_params": {}, + "other_config": {} + } - server.xend.domain.device_create(dom, vif) + def set(keys, val): + record = vif_record + for key in keys[:-1]: + record = record[key] + record[keys[-1]] = val + + vif_conv = { + 'type': + lambda x: None, + 'mac': + lambda x: set(['MAC'], x), + 'bridge': + lambda x: set(['network'], get_net_from_bridge(x)), + 'ip': + lambda x: set(['other_config', 'ip'], x), + 'script': + lambda x: set(['other_config', 'script'], x), + 'backend': + lambda x: set(['other_config', 'backend'], x), + 'vifname': + lambda x: set(['device'], x), + 'rate': + lambda x: set(['qos_algorithm_params', 'rate'], x), + 'model': + lambda x: None + } + + for a in args[1:]: + vif_param = a.split("=") + if len(vif_param) != 2 or vif_param[1] == '' or \ + vif_param[0] not in vif_params: + err("Invalid argument: %s" % a) + usage('network-attach') + else: + vif_conv[vif_param[0]](vif_param[1]) + + print str(vif_record) + server.xenapi.VIF.create(vif_record) + else: + for a in args[1:]: + vif_param = a.split("=") + if len(vif_param) != 2 or vif_param[1] == '' or \ + vif_param[0] not in vif_params: + err("Invalid argument: %s" % a) + usage('network-attach') + vif.append(vif_param) + server.xend.domain.device_create(dom, vif) def detach(args, command, deviceClass): @@ -1649,16 +1946,49 @@ def detach(args, command, deviceClass): def xm_block_detach(args): - try: - detach(args, 'block-detach', 'vbd') - return - except: - pass - detach(args, 'block-detach', 'tap') + if serverType == SERVER_XEN_API: + arg_check(args, "xm_block_detach", 2, 3) + dom = args[0] + dev = args[1] + vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom)) + vbd_refs = [vbd_ref for vbd_ref in vbd_refs + if server.xenapi.VBD.get_device(vbd_ref) == dev] + if len(vbd_refs) > 0: + vbd_ref = vbd_refs[0] + vdi_ref = server.xenapi.VBD.get_VDI(vbd_ref) + server.xenapi.VBD.destroy(vbd_ref) + + if len(server.xenapi.VDI.get_VBDs(vdi_ref)) <= 0: + server.xenapi.VDI.destroy(vdi_ref) + else: + raise OptionError("Cannot find device '%s' in domain '%s'" + % (dev,dom)) + else: + try: + detach(args, 'block-detach', 'vbd') + return + except: + pass + detach(args, 'block-detach', 'tap') def xm_network_detach(args): - detach(args, 'network-detach', 'vif') + if serverType == SERVER_XEN_API: + arg_check(args, "xm_block_detach", 2, 3) + dom = args[0] + devid = args[1] + vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom)) + vif_refs = [vif_ref for vif_ref in vif_refs + if server.xenapi.VIF.\ + get_runtime_properties(vif_ref)["handle"] == devid] + if len(vif_refs) > 0: + vif_ref = vif_refs[0] + + server.xenapi.VIF.destroy(vif_ref) + else: + print "Cannot find device '%s' in domain '%s'" % (devid,dom) + else: + detach(args, 'network-detach', 'vif') def xm_vnet_list(args): @@ -1738,6 +2068,7 @@ commands = { "pause": xm_pause, "unpause": xm_unpause, # host commands + "debug-keys": xm_debug_keys, "dmesg": xm_dmesg, "info": xm_info, "log": xm_log, @@ -1881,7 +2212,7 @@ def _run_cmd(cmd, cmd_name, args): err("Domain '%s' does not exist." % ex.faultString) else: err(ex.faultString) - _usage(cmd_name) + _usage(cmd_name) except xmlrpclib.ProtocolError, ex: if ex.errcode == -1: print >>sys.stderr, ( @@ -1898,13 +2229,17 @@ def _run_cmd(cmd, cmd_name, args): err(str(e)) _usage(cmd_name) print e.usage - except security.ACMError, e: - err(str(e)) - except: - print "Unexpected error:", sys.exc_info()[0] - print - print "Please report to xen-devel@lists.xensource.com" - raise + except Exception, e: + if serverType != SERVER_XEN_API: + from xen.util import security + if isinstance(e, security.ACMError): + err(str(e)) + return False, 1 + else: + print "Unexpected error:", sys.exc_info()[0] + print + print "Please report to xen-devel@lists.xensource.com" + raise return False, 1 diff --git a/tools/python/xen/xm/messages/en/xen-xm.po b/tools/python/xen/xm/messages/en/xen-xm.po index 3ea171b2fa..6e289b4aa3 100644 --- a/tools/python/xen/xm/messages/en/xen-xm.po +++ b/tools/python/xen/xm/messages/en/xen-xm.po @@ -19,7 +19,7 @@ msgid "" msgstr "" "Project-Id-Version: Xen-xm 3.0\n" -"PO-Revision-Date: 2007-02-20 15:22+0000\n" +"PO-Revision-Date: 2007-03-10 23:17+0000\n" "Last-Translator: Ewan Mellor \n" "Language-Team: xen-devel \n" "MIME-Version: 1.0\n" @@ -61,3 +61,6 @@ msgstr "The VLAN tag you gave (%(1)s) is invalid -- it must be between 0 and 409 msgid "VM_BAD_POWER_STATE" msgstr "The VM must be %(2)s to perform the requested operation (it is currently %(3)s)." + +msgid "VM_HVM_REQUIRED" +msgstr "HVM guest support is unavailable: is VT/AMD-V supported by your CPU and enabled in your BIOS?" diff --git a/tools/python/xen/xm/new.py b/tools/python/xen/xm/new.py index 2c6cae84b6..742c7ff8fd 100644 --- a/tools/python/xen/xm/new.py +++ b/tools/python/xen/xm/new.py @@ -22,6 +22,9 @@ from xen.xend import PrettyPrint from xen.xend import sxp from xen.xend import XendClient +from xen.xm.main import serverType, SERVER_XEN_API +from xen.xm.xenapi_create import * + from opts import * from create import * @@ -65,7 +68,15 @@ def main(argv): if opts.vals.dryrun: PrettyPrint.prettyprint(config) - else: + return + + if serverType == SERVER_XEN_API: + sxp2xml_inst = sxp2xml() + doc = sxp2xml_inst.convert_sxp_to_xml(config) + + xenapi_create_inst = xenapi_create() + vm_refs = xenapi_create_inst.create(document = doc) + else: make_unstarted_domain(opts, config) if __name__ == '__main__': diff --git a/tools/python/xen/xm/shutdown.py b/tools/python/xen/xm/shutdown.py index 88d36dfba1..8284a73bca 100644 --- a/tools/python/xen/xm/shutdown.py +++ b/tools/python/xen/xm/shutdown.py @@ -21,7 +21,8 @@ import time from xen.xend import sxp from opts import * -from main import server +from main import server, serverType, SERVER_XEN_API, get_single_vm +from xen.xend.XendAPIConstants import * gopts = Opts(use="""[options] [DOM] @@ -49,6 +50,9 @@ gopts.opt('reboot', short='R', use='Shutdown and reboot.') def wait_reboot(opts, doms, rcs): + if serverType == SERVER_XEN_API: + opts.err("Cannot wait for reboot w/ XenAPI (yet)") + while doms: alive = server.xend.domains(0) reboot = [] @@ -68,7 +72,12 @@ def wait_reboot(opts, doms, rcs): def wait_shutdown(opts, doms): while doms: - alive = server.xend.domains(0) + if serverType == SERVER_XEN_API: + alive = [dom for dom in server.xenapi.VM.get_all() + if server.xenapi.VM.get_power_state(dom) == + XEN_API_VM_POWER_STATE[XEN_API_VM_POWER_STATE_RUNNING]] + else: + alive = server.xend.domains(0) dead = [] for d in doms: if d in alive: continue @@ -82,8 +91,16 @@ def wait_shutdown(opts, doms): def shutdown(opts, doms, mode, wait): rcs = {} for d in doms: - rcs[d] = server.xend.domain.getRestartCount(d) - server.xend.domain.shutdown(d, mode) + if serverType == SERVER_XEN_API: + if mode == 'halt': + server.xenapi.VM.clean_shutdown(d) + if mode == 'reboot': + server.xenapi.VM.clean_reboot(d) + if mode == 'poweroff': + server.xenapi.VM.clean_shutdown(d) + else: + rcs[d] = server.xend.domain.getRestartCount(d) + server.xend.domain.shutdown(d, mode) if wait: if mode == 'reboot': @@ -103,9 +120,13 @@ def shutdown_mode(opts): return 'poweroff' def main_all(opts, args): - doms = server.xend.domains(0) - dom0_name = sxp.child_value(server.xend.domain(0), 'name') - doms.remove(dom0_name) + if serverType == SERVER_XEN_API: + doms = [dom for dom in server.xenapi.VM.get_all() + if not server.xenapi.VM.get_is_control_domain(dom)] + else: + doms = server.xend.domains(0) + dom0_name = sxp.child_value(server.xend.domain(0), 'name') + doms.remove(dom0_name) mode = shutdown_mode(opts) shutdown(opts, doms, mode, opts.vals.wait) @@ -113,6 +134,8 @@ def main_dom(opts, args): if len(args) == 0: opts.err('No domain parameter given') if len(args) > 1: opts.err('No multiple domain parameters allowed') dom = args[0] + if serverType == SERVER_XEN_API: + dom = get_single_vm(dom) mode = shutdown_mode(opts) shutdown(opts, [ dom ], mode, opts.vals.wait) diff --git a/tools/python/xen/xm/xenapi_create.py b/tools/python/xen/xm/xenapi_create.py new file mode 100644 index 0000000000..52d91e101b --- /dev/null +++ b/tools/python/xen/xm/xenapi_create.py @@ -0,0 +1,636 @@ +#!/usr/bin/python +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2007 Tom Wilkie +#============================================================================ +"""Domain creation using new XenAPI +""" + +from xen.xm.main import server, get_default_SR +from xml.dom.minidom import parse, getDOMImplementation +from xml.dom.ext import PrettyPrint +from xml.parsers.xmlproc import xmlproc, xmlval, xmldtd +from xen.xend import sxp +from xen.xend.XendAPIConstants import XEN_API_ON_NORMAL_EXIT, \ + XEN_API_ON_CRASH_BEHAVIOUR + + +import sys +import os +import traceback + +def log(_, msg): + #print "> " + msg + pass + +DEBUG = 0 + +def get_name_label(node): + name_node = node.getElementsByTagName("name")[0] + label_node = name_node.getElementsByTagName("label")[0] + return " ".join([child.nodeValue for child in label_node.childNodes]) + +def get_name_description(node): + name_node = node.getElementsByTagName("name")[0] + description_node = name_node.getElementsByTagName("description")[0] + return " ".join([child.nodeValue for child in description_node.childNodes]) + +def get_text_in_child_node(node, child): + tag_node = node.getElementsByTagName(child)[0] + return tag_node.nodeValue + +def get_child_node_attribute(node, child, attribute): + tag_node = node.getElementsByTagName(child)[0] + return tag_node.attributes[attribute].value + +def get_child_nodes_as_dict(node, child_name, + key_attribute_name, + value_attribute_name): + return dict([(child.attributes[key_attribute_name].value, + child.attributes[value_attribute_name].value) + for child in node.getElementsByTagName(child_name)]) + +def try_quietly(fn, *args): + try: + return fn(*args) + except: + return None + +class xenapi_create: + + def __init__(self): + self.DEFAULT_STORAGE_REPOSITORY = get_default_SR() + + self.dtd = "/usr/lib/python/xen/xm/create.dtd" + + def create(self, filename=None, document=None): + """ + Create a domain from an XML file or DOM tree + """ + if filename is not None: + self.check_dtd(file) + document = parse(file) + elif document is not None: + self.check_dom_against_dtd(document) + + self.check_doc(document) + + vdis = document.getElementsByTagName("vdi") + vdi_refs_dict = self.create_vdis(vdis) + + try: + vms = document.getElementsByTagName("vm") + return self.create_vms(vms, vdi_refs_dict) + except Exception, exn: + try_quietly(self.cleanup_vdis(vdi_refs_dict)) + raise exn + + # Methods to check xml file + # try to use dtd to check where possible + def check_dtd(self, file): + """ + Check file against DTD. + Use this if possible as it gives nice + error messages + """ + dtd = xmldtd.load_dtd(self.dtd) + parser = xmlproc.XMLProcessor() + parser.set_application(xmlval.ValidatingApp(dtd, parser)) + parser.dtd = dtd + parser.ent = dtd + parser.parse_resource(file) + + def check_dom_against_dtd(self, dom): + """ + Check DOM again DTD. + Doesn't give as nice error messages. + (no location info) + """ + dtd = xmldtd.load_dtd(self.dtd) + app = xmlval.ValidatingApp(dtd, self) + app.set_locator(self) + self.dom2sax(dom, app) + + # Get errors back from ValidatingApp + def report_error(self, number, args=None): + self.errors = xmlproc.errors.english + try: + msg = self.errors[number] + if args != None: + msg = msg % args + except KeyError: + msg = self.errors[4002] % number # Unknown err msg :-) + print msg + sys.exit(-1) + + # Here for compatibility with ValidatingApp + def get_line(self): + return -1 + + def get_column(self): + return -1 + + def dom2sax(self, dom, app): + """ + Take a dom tree and tarverse it, + issuing SAX calls to app. + """ + for child in dom.childNodes: + if child.nodeType == child.TEXT_NODE: + data = child.nodeValue + app.handle_data(data, 0, len(data)) + else: + app.handle_start_tag( + child.nodeName, + self.attrs_to_dict(child.attributes)) + self.dom2sax(child, app) + app.handle_end_tag(child.nodeName) + + def attrs_to_dict(self, attrs): + return dict(attrs.items()) + + # + # Checks which cannot be done with dtd + # + def check_doc(self, doc): + vms = doc.getElementsByTagName("vm") + self.check_vms(vms) + + def check_vms(self, vms): + map(self.check_vm, vms) + + def check_vm(self, vm): + vifs = vm.getElementsByTagName("vif") + self.check_vifs(vifs) + + def check_vifs(self, vifs): + map(self.check_vif, vifs) + + def check_vif(self, vif): + """ + Check that the vif has + either a bridge or network + name but not both + """ + if "bridge" in vif.attributes.keys() \ + and "network" in vif.attributes.keys(): + raise "You cannot specify both a bridge and\ + a network name." + + # Cleanup methods here + def cleanup_vdis(self, vdi_refs_dict): + map(self.cleanup_vdi, vdi_refs_dict.values()) + + def cleanup_vdi(self, vdi_ref): + server.xenapi.VDI.destroy(vdi_ref) + + def cleanup_vms(self, vm_refs): + map(self.cleanup_vm, vm_refs) + + def cleanup_vm(self, vm_ref): + server.xenapi.VM.destroy(vm_ref) + + # Create methods here + def create_vdis(self, vdis): + log(DEBUG, "create_vdis") + return dict(map(self.create_vdi, vdis)) + + def create_vdi(self, vdi): + log(DEBUG, "create_vdi") + + vdi_record = { + "name_label": get_name_label(vdi), + "name_description": get_name_description(vdi), + "SR": self.DEFAULT_STORAGE_REPOSITORY, + "virtual_size": vdi.attributes["size"].value, + "type": vdi.attributes["type"].value, + "shareable": vdi.attributes["shareable"].value, + "read_only": vdi.attributes["read_only"].value, + "other_config": {"location": + vdi.attributes["src"].value} + } + + key = vdi.attributes["name"].value + value = server.xenapi.VDI.create(vdi_record) + + return (key, value) + + def create_vms(self, vms, vdis): + log(DEBUG, "create_vms") + return map(lambda vm: self.create_vm(vm, vdis), vms) + + def create_vm(self, vm, vdis): + log(DEBUG, "create_vm") + + vm_record = { + "name_label": + get_name_label(vm), + "name_description": + get_name_description(vm), + "user_version": + get_text_in_child_node(vm, "version"), + "is_a_template": + vm.attributes["is_a_template"].value, + "auto_power_on": + vm.attributes["auto_power_on"].value, + "memory_static_max": + get_child_node_attribute(vm, "memory", "static_max"), + "memory_static_min": + get_child_node_attribute(vm, "memory", "static_min"), + "memory_dynamic_max": + get_child_node_attribute(vm, "memory", "dynamic_max"), + "memory_dynamic_min": + get_child_node_attribute(vm, "memory", "dynamic_min"), + "vcpus_params": + get_child_nodes_as_dict(vm, "vcpu_param", "key", "value"), + "vcpus_max": + vm.attributes["vcpus_max"].value, + "vcpus_at_startup": + vm.attributes["vcpus_at_startup"].value, + "actions_after_shutdown": + vm.attributes["actions_after_shutdown"].value, + "actions_after_reboot": + vm.attributes["actions_after_reboot"].value, + "actions_after_crash": + vm.attributes["actions_after_crash"].value, + "platform_std_VGA": + vm.attributes["platform_std_VGA"].value, + "platform_serial": + vm.attributes["platform_serial"].value, + "platform_localtime": + vm.attributes["platform_localtime"].value, + "platform_clock_offet": + vm.attributes["platform_clock_offet"].value, + "platform_enable_audio": + vm.attributes["platform_enable_audio"].value, + "PCI_bus": + vm.attributes["platform_enable_audio"].value, + "other_config": + get_child_nodes_as_dict(vm, "other_config", "key", "value") + } + + if len(vm.getElementsByTagName("pv")) > 0: + vm_record.update({ + "PV_bootloader": + get_child_node_attribute(vm, "pv", "bootloader"), + "PV_kernel": + get_child_node_attribute(vm, "pv", "kernel"), + "PV_ramdisk": + get_child_node_attribute(vm, "pv", "ramdisk"), + "PV_args": + get_child_node_attribute(vm, "pv", "args"), + "PV_bootloader_args": + get_child_node_attribute(vm, "pv", "bootloader_args") + }) + else: + hvm = vm.getElementsByTagName("hvm")[0] + vm_record.update({ + "HVM_boot_policy": + get_child_node_attribute(vm, "hvm", "boot_policy"), + "HVM_boot_params": + get_child_nodes_as_dict(hvm, "boot_params", "key", "value") + }) + try: + vm_ref = server.xenapi.VM.create(vm_record) + except: + traceback.print_exc() + sys.exit(-1) + + # Now create vbds + + vbds = vm.getElementsByTagName("vbd") + + self.create_vbds(vm_ref, vbds, vdis) + + # Now create vifs + + vifs = vm.getElementsByTagName("vif") + + self.create_vifs(vm_ref, vifs) + + return vm_ref + + def create_vbds(self, vm_ref, vbds, vdis): + log(DEBUG, "create_vbds") + return map(lambda vbd: self.create_vbd(vm_ref, vbd, vdis), vbds) + + def create_vbd(self, vm_ref, vbd, vdis): + log(DEBUG, "create_vbd") + + vbd_record = { + "VM": + vm_ref, + "VDI": + vdis[vbd.attributes["vdi"].value], + "device": + vbd.attributes["device"].value, + "bootable": + vbd.attributes["bootable"].value, + "mode": + vbd.attributes["mode"].value, + "type": + vbd.attributes["type"].value, + "qos_algorithm_type": + vbd.attributes["qos_algorithm_type"].value, + "qos_algorithm_params": + get_child_nodes_as_dict(vbd, + "qos_algorithm_param", "key", "value") + } + + return server.xenapi.VBD.create(vbd_record) + + def create_vifs(self, vm_ref, vifs): + log(DEBUG, "create_vifs") + return map(lambda vif: self.create_vif(vm_ref, vif), vifs) + + def create_vif(self, vm_ref, vif): + log(DEBUG, "create_vif") + + if "bridge" in vif.attributes.keys(): + raise "Not allowed to add by bridge just yet" + elif "network" in vif.attributes.keys(): + network = [network_ref + for network_ref in server.xenapi.network.get_all() + if server.xenapi.network.get_name_label(network_ref) + == vif.attributes["network"].value][0] + else: + network = self._get_network_ref() + + vif_record = { + "device": + vif.attributes["device"].value, + "network": + network, + "VM": + vm_ref, + "MAC": + vif.attributes["mac"].value, + "MTU": + vif.attributes["mtu"].value, + "qos_algorithm_type": + vif.attributes["qos_algorithm_type"].value, + "qos_algorithm_params": + get_child_nodes_as_dict(vif, + "qos_algorithm_param", "key", "value") + } + + return server.xenapi.VIF.create(vif_record) + + _network_refs = [] + + def _get_network_ref(self): + try: + return self._network_refs.pop(0) + except IndexError: + self._network_refs = server.xenapi.network.get_all() + return self._network_refs.pop(0) + +def get_child_by_name(exp, childname, default = None): + try: + return [child for child in sxp.children(exp) + if child[0] == childname][0][1] + except: + return default + +# Convert old sxp into new xml + +class sxp2xml: + + def convert_sxp_to_xml(self, config, transient=False): + + devices = [child for child in sxp.children(config) + if len(child) > 0 and child[0] == "device"] + + vbds_sxp = map(lambda x: x[1], [device for device in devices + if device[1][0] == "vbd"]) + + vifs_sxp = map(lambda x: x[1], [device for device in devices + if device[1][0] == "vif"]) + # Create XML Document + + impl = getDOMImplementation() + + document = impl.createDocument(None, "xm", None) + + # Lets make the VM tag.. + + vm = document.createElement("vm") + + # Some string compatibility + + actions_after_shutdown \ + = get_child_by_name(config, "on_poweroff", "destroy") + actions_after_reboot \ + = get_child_by_name(config, "on_reboot", "restart") + actions_after_crash \ + = get_child_by_name(config, "on_crash", "restart") + + def conv_chk(val, vals): + val.replace("-", "_") + if val not in vals: + raise "Invalid value: " + val + else: + return val + + actions_after_shutdown = conv_chk(actions_after_shutdown,\ + XEN_API_ON_NORMAL_EXIT) + actions_after_reboot = conv_chk(actions_after_reboot, \ + XEN_API_ON_NORMAL_EXIT) + actions_after_crash = conv_chk(actions_after_crash, \ + XEN_API_ON_CRASH_BEHAVIOUR) + # Flesh out tag attributes + + vm.attributes["is_a_template"] = "false" + vm.attributes["auto_power_on"] = "false" + vm.attributes["actions_after_shutdown"] \ + = actions_after_shutdown + vm.attributes["actions_after_reboot"] \ + = actions_after_reboot + vm.attributes["actions_after_crash"] \ + = actions_after_crash + vm.attributes["platform_std_VGA"] = "false" + vm.attributes["platform_serial"] = "" + vm.attributes["platform_localtime"] = "" + vm.attributes["platform_clock_offet"] = "" + vm.attributes["platform_enable_audio"] = "" + vm.attributes["PCI_bus"] = "" + + vm.attributes["vcpus_max"] \ + = str(get_child_by_name(config, "vcpus", 1)) + vm.attributes["vcpus_at_startup"] \ + = str(get_child_by_name(config, "vcpus", 1)) + + # Make the name tag + + vm.appendChild(self.make_name_tag( + get_child_by_name(config, "name"), document)) + + # Make version tag + + version = document.createElement("version") + version.appendChild(document.createTextNode("1.0")) + vm.appendChild(version) + + # Make pv or hvm tag + + image = get_child_by_name(config, "image") + + if image[0] == "linux": + pv = document.createElement("pv") + pv.attributes["kernel"] \ + = get_child_by_name(image, "kernel", "") + pv.attributes["bootloader"] = "" + pv.attributes["ramdisk"] \ + = get_child_by_name(image, "ramdisk", "") + pv.attributes["args"] \ + = "root=" + get_child_by_name(image, "root", "") \ + + " " + get_child_by_name(image, "args", "") + pv.attributes["bootloader_args"] = "" + + vm.appendChild(pv) + elif image[0] == "hvm": + hvm = document.createElement("hvm") + hvm.attributes["boot_policy"] = "" + + vm.appendChild(hvm) + + # Make memory tag + + memory = document.createElement("memory") + + memory_str = str(int( + get_child_by_name(config, "memory"))*1024*1024) + + memory.attributes["static_min"] = str(0) + memory.attributes["static_max"] = memory_str + memory.attributes["dynamic_min"] = memory_str + memory.attributes["dynamic_max"] = memory_str + + if get_child_by_name(config, "maxmem"): + memory.attributes["static_max"] = \ + str(int(get_child_by_name(config, "maxmem")*1024*1024)) + + vm.appendChild(memory) + + # And now the vbds + + vbds = map(lambda vbd: self.extract_vbd(vbd, document), vbds_sxp) + + map(vm.appendChild, vbds) + + # And now the vifs + + vifs = map(lambda vif: self.extract_vif(vif, document), vifs_sxp) + + map(vm.appendChild, vifs) + + # transient? + + if transient: + other_config = document.createElement("other_config") + other_config.attributes["key"] = "transient" + other_config.attributes["value"] = "True" + vm.appendChild(other_config) + + # Add it to doc_root + + document.documentElement.appendChild(vm) + + # We want to pull out vdis + + vdis = map(lambda vdb: self.extract_vdi(vdb, document), vbds_sxp) + + map(document.documentElement.appendChild, vdis) + + return document + + def make_name_tag(self, label_text, document): + name = document.createElement("name") + + label = document.createElement("label") + label.appendChild(document.createTextNode(str(label_text))) + name.appendChild(label) + + description = document.createElement("description") + description.appendChild(document.createTextNode(" ")) + name.appendChild(description) + + return name + + def extract_vbd(self, vbd_sxp, document): + src = get_child_by_name(vbd_sxp, "uname") + name = str(src.__hash__()) + + vbd = document.createElement("vbd") + + vbd.attributes["name"] = "vdb" + name + vbd.attributes["vdi"] = "vdi" + name + vbd.attributes["mode"] \ + = get_child_by_name(vbd_sxp, "mode") != "w" \ + and "RO" or "RW" + vbd.attributes["device"] \ + = get_child_by_name(vbd_sxp, "dev") + vbd.attributes["bootable"] = "1" + vbd.attributes["type"] = "disk" + vbd.attributes["qos_algorithm_type"] = "" + + return vbd + + def extract_vdi(self, vbd_sxp, document): + src = get_child_by_name(vbd_sxp, "uname") + name = "vdi" + str(src.__hash__()) + path = src[src.find(":")+1:] + + vdi = document.createElement("vdi") + + vdi.attributes["src"] = src + vdi.attributes["read_only"] \ + = (get_child_by_name(vbd_sxp, "mode") != "w") \ + and "true" or "false" + vdi.attributes["size"] \ + = str(os.path.getsize(path)) + vdi.attributes["type"] = "system" + vdi.attributes["shareable"] = "false" + vdi.attributes["name"] = name + + vdi.appendChild(self.make_name_tag(name, document)) + + return vdi + + def extract_vif(self, vif_sxp, document): + + vif = document.createElement("vif") + + dev = get_child_by_name(vif_sxp, "vifname", "eth0") + + vif.attributes["name"] \ + = "vif" + str(dev.__hash__()) + vif.attributes["mac"] \ + = get_child_by_name(vif_sxp, "mac", "") + vif.attributes["mtu"] \ + = get_child_by_name(vif_sxp, "mtu", "") + vif.attributes["device"] = dev + vif.attributes["qos_algorithm_type"] = "" + + if get_child_by_name(vif_sxp, "bridge") is not None: + vif.attributes["bridge"] \ + = get_child_by_name(vif_sxp, "bridge") + + return vif + + + + + diff --git a/tools/xcutils/Makefile b/tools/xcutils/Makefile index 6022505577..f8ac92f7d9 100644 --- a/tools/xcutils/Makefile +++ b/tools/xcutils/Makefile @@ -13,7 +13,7 @@ include $(XEN_ROOT)/tools/Rules.mk PROGRAMS_INSTALL_DIR = /usr/$(LIBDIR)/xen/bin -INCLUDES += -I $(XEN_LIBXC) +INCLUDES += -I $(XEN_LIBXC) -I $(XEN_XENSTORE) CFLAGS += -Werror -fno-strict-aliasing CFLAGS += $(INCLUDES) @@ -22,9 +22,9 @@ CFLAGS += $(INCLUDES) CFLAGS += -Wp,-MD,.$(@F).d PROG_DEP = .*.d -PROGRAMS = xc_restore xc_save readnotes +PROGRAMS = xc_restore xc_save readnotes -LDLIBS = -L$(XEN_LIBXC) -lxenguest -lxenctrl +LDLIBS = -L$(XEN_LIBXC) -L$(XEN_XENSTORE) -lxenguest -lxenctrl -lxenstore .PHONY: all all: build diff --git a/tools/xcutils/xc_save.c b/tools/xcutils/xc_save.c index 0c9530da4d..2285af4b97 100644 --- a/tools/xcutils/xc_save.c +++ b/tools/xcutils/xc_save.c @@ -12,7 +12,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -31,6 +37,123 @@ static int suspend(int domid) !strncmp(ans, "done\n", 5)); } +/* For HVM guests, there are two sources of dirty pages: the Xen shadow + * log-dirty bitmap, which we get with a hypercall, and qemu's version. + * The protocol for getting page-dirtying data from qemu uses a + * double-buffered shared memory interface directly between xc_save and + * qemu-dm. + * + * xc_save calculates the size of the bitmaps and notifies qemu-dm + * through the store that it wants to share the bitmaps. qemu-dm then + * starts filling in the 'active' buffer. + * + * To change the buffers over, xc_save writes the other buffer number to + * the store and waits for qemu to acknowledge that it is now writing to + * the new active buffer. xc_save can then process and clear the old + * active buffer. */ + +static char *qemu_active_path; +static char *qemu_next_active_path; +static struct xs_handle *xs; + +/* Get qemu to change buffers. */ +static void qemu_flip_buffer(int domid, int next_active) +{ + char digit = '0' + next_active; + unsigned int len; + char *active_str, **watch; + struct timeval tv; + fd_set fdset; + + /* Tell qemu that we want it to start writing log-dirty bits to the + * other buffer */ + if (!xs_write(xs, XBT_NULL, qemu_next_active_path, &digit, 1)) { + errx(1, "can't write next-active to store path (%s)\n", + qemu_next_active_path); + exit(1); + } + + /* Wait a while for qemu to signal that it has switched to the new + * active buffer */ + read_again: + tv.tv_sec = 5; + tv.tv_usec = 0; + FD_ZERO(&fdset); + FD_SET(xs_fileno(xs), &fdset); + if ((select(xs_fileno(xs) + 1, &fdset, NULL, NULL, &tv)) != 1) { + errx(1, "timed out waiting for qemu to switch buffers\n"); + exit(1); + } + watch = xs_read_watch(xs, &len); + free(watch); + + active_str = xs_read(xs, XBT_NULL, qemu_active_path, &len); + if (active_str == NULL || active_str[0] - '0' != next_active) + /* Watch fired but value is not yet right */ + goto read_again; +} + +static void * init_qemu_maps(int domid, unsigned int bitmap_size) +{ + key_t key; + char key_ascii[17] = {0,}; + int shmid = -1; + void *seg; + char *path, *p; + + /* Make a shared-memory segment */ + while (shmid == -1) + { + key = rand(); /* No security, just a sequence of numbers */ + shmid = shmget(key, 2 * bitmap_size, + IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR); + if (shmid == -1 && errno != EEXIST) + errx(1, "can't get shmem to talk to qemu-dm"); + } + + /* Map it into our address space */ + seg = shmat(shmid, NULL, 0); + if (seg == (void *) -1) + errx(1, "can't map shmem to talk to qemu-dm"); + memset(seg, 0, 2 * bitmap_size); + + /* Write the size of it into the first 32 bits */ + *(uint32_t *)seg = bitmap_size; + + /* Tell qemu about it */ + if ((xs = xs_daemon_open()) == NULL) + errx(1, "Couldn't contact xenstore"); + if (!(path = xs_get_domain_path(xs, domid))) + errx(1, "can't get domain path in store"); + if (!(path = realloc(path, strlen(path) + + strlen("/logdirty/next-active") + 1))) + errx(1, "no memory for constructing xenstore path"); + strcat(path, "/logdirty/"); + p = path + strlen(path); + + strcpy(p, "key"); + snprintf(key_ascii, 17, "%16.16llx", (unsigned long long) key); + if (!xs_write(xs, XBT_NULL, path, key_ascii, 16)) + errx(1, "can't write key (%s) to store path (%s)\n", key_ascii, path); + + /* Watch for qemu's indication of the active buffer, and request it + * to start writing to buffer 0 */ + strcpy(p, "active"); + if (!xs_watch(xs, path, "qemu-active-buffer")) + errx(1, "can't set watch in store (%s)\n", path); + if (!(qemu_active_path = strdup(path))) + errx(1, "no memory for copying xenstore path"); + + strcpy(p, "next-active"); + if (!(qemu_next_active_path = strdup(path))) + errx(1, "no memory for copying xenstore path"); + + qemu_flip_buffer(domid, 0); + + free(path); + return seg; +} + int main(int argc, char **argv) @@ -52,9 +175,11 @@ main(int argc, char **argv) flags = atoi(argv[5]); if (flags & XCFLAGS_HVM) - ret = xc_hvm_save(xc_fd, io_fd, domid, maxit, max_f, flags, &suspend); + ret = xc_hvm_save(xc_fd, io_fd, domid, maxit, max_f, flags, + &suspend, &init_qemu_maps, &qemu_flip_buffer); else - ret = xc_linux_save(xc_fd, io_fd, domid, maxit, max_f, flags, &suspend); + ret = xc_linux_save(xc_fd, io_fd, domid, maxit, max_f, flags, + &suspend); xc_interface_close(xc_fd); diff --git a/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py b/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py index 3e9f0f2514..5d435e27c6 100644 --- a/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py +++ b/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py @@ -32,10 +32,10 @@ except ConsoleError, e: status, output = traceCommand("xm block-attach %s phy:NOT-EXIST xvda1 w" % domain.getName()) eyecatcher = "Error" -where = output.find(eyecatcher) +where = re.compile(eyecatcher, re.IGNORECASE).search(output) if status == 0: FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status ) -elif where == -1: +elif where is None: FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output ) try: diff --git a/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py b/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py index 802e101147..2fa482414a 100644 --- a/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py +++ b/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py @@ -31,10 +31,10 @@ except ConsoleError, e: status, output = traceCommand("xm block-attach %s file:/dev/NOT-EXIST xvda1 w" % domain.getName()) eyecatcher = "Error" -where = output.find(eyecatcher) +where = re.compile(eyecatcher, re.IGNORECASE).search(output) if status == 0: FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status ) -elif where == -1: +elif where is None: FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output ) try: diff --git a/tools/xm-test/tests/destroy/01_destroy_basic_pos.py b/tools/xm-test/tests/destroy/01_destroy_basic_pos.py index 3d007b12a4..02e31d6aa8 100644 --- a/tools/xm-test/tests/destroy/01_destroy_basic_pos.py +++ b/tools/xm-test/tests/destroy/01_destroy_basic_pos.py @@ -37,4 +37,4 @@ if not re.search("proc", run["output"]): # destroy domain - positive test status, output = traceCommand("xm destroy %s" % domain.getName()) if status != 0: - FAIL("xm destroy returned invalud %i != 0" % status) + FAIL("xm destroy returned invalid %i != 0" % status) diff --git a/tools/xm-test/tests/network-attach/network_utils.py b/tools/xm-test/tests/network-attach/network_utils.py index 084b5ebd90..93fe72a811 100644 --- a/tools/xm-test/tests/network-attach/network_utils.py +++ b/tools/xm-test/tests/network-attach/network_utils.py @@ -12,6 +12,18 @@ def count_eth(console): FAIL(str(e)) return len(run['output'].splitlines()) +def get_state(domain_name, number): + s, o = traceCommand("xm network-list %s | awk '/^%d/ {print $5}'" % + (domain_name, number)) + print o + + if s != 0: + FAIL("network-list failed") + if o == "": + return 0 + else: + return int(o) + def network_attach(domain_name, console): eths_before = count_eth(console) status, output = traceCommand("xm network-attach %s" % domain_name) @@ -30,6 +42,13 @@ def network_detach(domain_name, console, num=0): if status != 0: return -1, "xm network-detach returned invalid %i != 0" % status + for i in range(10): + if get_state(domain_name, num) == 0: + break + time.sleep(1) + else: + FAIL("network-detach failed: device did not disappear") + eths_after = count_eth(console) if eths_after != (eths_before-1): return -2, "Network device was not actually disconnected from domU" diff --git a/tools/xm-test/tests/vtpm/09_vtpm-xapi.py b/tools/xm-test/tests/vtpm/09_vtpm-xapi.py index 6a17c51045..15775801f6 100644 --- a/tools/xm-test/tests/vtpm/09_vtpm-xapi.py +++ b/tools/xm-test/tests/vtpm/09_vtpm-xapi.py @@ -91,7 +91,7 @@ if vtpm_uuid not in vm_vtpms: try: console = domain.start() except DomainError, e: - FAIL("Unable to create domain (%s)" % domName) + FAIL("Unable to create domain (%s)") try: console.sendInput("input") @@ -113,7 +113,7 @@ if not re.search("PCR-00:",run["output"]): FAIL("1. Virtual TPM is not working correctly on /dev/vtpm on backend side: \n%s" % run["output"]) try: - rc = session.xenapi.VTPM.destroy(vtpm_uuid) + session.xenapi.VTPM.destroy(vtpm_uuid) #Should never get here FAIL("Could destroy vTPM while VM is running") except: @@ -124,7 +124,7 @@ if rc: FAIL("Could not suspend VM") try: - rc = session.xenapi.VTPM.destroy(vtpm_uuid) + session.xenapi.VTPM.destroy(vtpm_uuid) #May not throw an exception in 'suspend' state except: pass @@ -150,8 +150,9 @@ if not re.search("PCR-00:",run["output"]): domain.stop() -rc = session.xenapi.VTPM.destroy(vtpm_uuid) -if not rc: +try: + session.xenapi.VTPM.destroy(vtpm_uuid) +except: FAIL("Could NOT destroy vTPM while domain is halted.") domain.destroy() diff --git a/tools/xm-test/tests/vtpm/vtpm_utils.py b/tools/xm-test/tests/vtpm/vtpm_utils.py index 0af46574c9..da65aab5fb 100644 --- a/tools/xm-test/tests/vtpm/vtpm_utils.py +++ b/tools/xm-test/tests/vtpm/vtpm_utils.py @@ -8,7 +8,8 @@ from XmTestLib import * if ENABLE_HVM_SUPPORT: SKIP("vtpm tests not supported for HVM domains") -status, output = traceCommand("ps aux | grep vtpm_manager | grep -v grep") +status, output = traceCommand("COLUMNS=200 ; " + "ps aux | grep vtpm_manager | grep -v grep") if output == "": SKIP("virtual TPM manager must be started to run this test; might " "need /dev/tpm0") diff --git a/unmodified_drivers/linux-2.6/platform-pci/evtchn.c b/unmodified_drivers/linux-2.6/platform-pci/evtchn.c index 9063e37f17..0c19cf5cda 100644 --- a/unmodified_drivers/linux-2.6/platform-pci/evtchn.c +++ b/unmodified_drivers/linux-2.6/platform-pci/evtchn.c @@ -167,7 +167,8 @@ EXPORT_SYMBOL(notify_remote_via_irq); irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned int l1i, port; - int cpu = smp_processor_id(); + /* XXX: All events are bound to vcpu0 but irq may be redirected. */ + int cpu = 0; /*smp_processor_id();*/ irqreturn_t(*handler) (int, void *, struct pt_regs *); shared_info_t *s = shared_info_area; vcpu_info_t *v = &s->vcpu_info[cpu]; diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index 631d8dfa09..2bb2ef8172 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -672,8 +672,11 @@ int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c) /* This overrides some registers. */ vcpu_init_regs(v); - /* Don't redo final setup */ - set_bit(_VCPUF_initialised, &v->vcpu_flags); + /* Don't redo final setup. Auto-online VCPU0. */ + if (!test_and_set_bit(_VCPUF_initialised, &v->vcpu_flags) && + (v->vcpu_id == 0)) + clear_bit(_VCPUF_down, &v->vcpu_flags); + return 0; } @@ -1182,6 +1185,7 @@ int construct_dom0(struct domain *d, printk("Dom0: 0x%lx\n", (u64)dom0); set_bit(_VCPUF_initialised, &v->vcpu_flags); + clear_bit(_VCPUF_down, &v->vcpu_flags); /* Build firmware. Note: Linux kernel reserve memory used by start_info, so there is diff --git a/xen/arch/ia64/xen/xensetup.c b/xen/arch/ia64/xen/xensetup.c index 4d88db400b..38a22b5e48 100644 --- a/xen/arch/ia64/xen/xensetup.c +++ b/xen/arch/ia64/xen/xensetup.c @@ -543,8 +543,6 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus); domain0_ready = 1; - schedulers_start(); - domain_unpause_by_systemcontroller(dom0); startup_cpu_idle_loop(); diff --git a/xen/arch/powerpc/domain.c b/xen/arch/powerpc/domain.c index e129adbe0f..1ecf35a666 100644 --- a/xen/arch/powerpc/domain.c +++ b/xen/arch/powerpc/domain.c @@ -142,6 +142,8 @@ void free_vcpu_struct(struct vcpu *v) int vcpu_initialise(struct vcpu *v) { + /* Guests by default have a 100Hz ticker. */ + v->periodic_period = MILLISECS(10); return 0; } @@ -166,7 +168,10 @@ int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c) d->shared_info->wc_nsec = dom0->shared_info->wc_nsec; d->shared_info->arch.boot_timebase = dom0->shared_info->arch.boot_timebase; - set_bit(_VCPUF_initialised, &v->vcpu_flags); + /* Auto-online VCPU0 when it is initialised. */ + if ( !test_and_set_bit(_VCPUF_initialised, &v->vcpu_flags) && + (v->vcpu_id == 0) ) + clear_bit(_VCPUF_down, &v->vcpu_flags); cpu_init_vcpu(v); diff --git a/xen/arch/powerpc/domain_build.c b/xen/arch/powerpc/domain_build.c index 08d53ff9dc..af7ad3db45 100644 --- a/xen/arch/powerpc/domain_build.c +++ b/xen/arch/powerpc/domain_build.c @@ -274,6 +274,7 @@ int construct_dom0(struct domain *d, ofd_dom0_fixup(d, *ofh_tree + rma, cmdline, shared_info_addr); set_bit(_VCPUF_initialised, &v->vcpu_flags); + clear_bit(_VCPUF_down, &v->vcpu_flags); rc = 0; diff --git a/xen/arch/powerpc/setup.c b/xen/arch/powerpc/setup.c index ad6408d4e9..9d19c6739a 100644 --- a/xen/arch/powerpc/setup.c +++ b/xen/arch/powerpc/setup.c @@ -366,9 +366,6 @@ static void __init __start_xen(multiboot_info_t *mbi) kick_secondary_cpus(max_cpus); } - /* Secondary processors must be online before we call this. */ - schedulers_start(); - /* This cannot be called before secondary cpus are marked online. */ percpu_free_unused_areas(); diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk index 899f28129c..86b9f33ab1 100644 --- a/xen/arch/x86/Rules.mk +++ b/xen/arch/x86/Rules.mk @@ -58,19 +58,7 @@ HDRS += $(wildcard $(BASEDIR)/include/asm-x86/hvm/*.h) HDRS += $(wildcard $(BASEDIR)/include/asm-x86/hvm/svm/*.h) HDRS += $(wildcard $(BASEDIR)/include/asm-x86/hvm/vmx/*.h) -# Test for at least GCC v3.2.x. -gcc-ver = $(shell $(CC) -dumpversion | sed -e 's/^\(.\)\.\(.\)\.\(.\)/\$(1)/') -ifeq ($(call gcc-ver,1),1) -$(error gcc-1.x.x unsupported - upgrade to at least gcc-3.2.x) -endif -ifeq ($(call gcc-ver,1),2) -$(error gcc-2.x.x unsupported - upgrade to at least gcc-3.2.x) -endif -ifeq ($(call gcc-ver,1),3) -ifeq ($(call gcc-ver,2),0) -$(error gcc-3.0.x unsupported - upgrade to at least gcc-3.2.x) -endif -ifeq ($(call gcc-ver,2),1) -$(error gcc-3.1.x unsupported - upgrade to at least gcc-3.2.x) -endif +# Require GCC v3.4+ (to avoid issues with alignment constraints in Xen headers) +ifneq ($(call cc-ver,$(CC),0x030400),y) +$(error Xen requires at least gcc-3.4) endif diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c index f6a79a7d2f..fbb8f30bab 100644 --- a/xen/arch/x86/apic.c +++ b/xen/arch/x86/apic.c @@ -1022,6 +1022,13 @@ int reprogram_timer(s_time_t timeout) s_time_t expire; u64 apic_tmict; + /* + * If we don't have local APIC then we just poll the timer list off the + * PIT interrupt. + */ + if ( !cpu_has_apic ) + return 1; + /* * We use this value because we don't trust zero (we think it may just * cause an immediate interrupt). At least this is guaranteed to hold it @@ -1044,13 +1051,6 @@ int reprogram_timer(s_time_t timeout) return 0; } - /* - * If we don't have local APIC then we just poll the timer list off the - * PIT interrupt. Cheesy but good enough to work on eg. VMware :-) - */ - if ( !cpu_has_apic ) - return 1; - /* conversion to bus units */ apic_tmict = (((u64)bus_scale) * expire)>>18; diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 57fc717915..6a543a3a1b 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -350,6 +350,9 @@ int vcpu_initialise(struct vcpu *v) } else { + /* PV guests by default have a 100Hz ticker. */ + v->periodic_period = MILLISECS(10); + /* PV guests get an emulated PIT too for video BIOSes to use. */ if ( !is_idle_domain(d) && (v->vcpu_id == 0) ) pit_init(v, cpu_khz); @@ -457,8 +460,10 @@ int arch_domain_create(struct domain *d) fail: free_xenheap_page(d->shared_info); #ifdef __x86_64__ - free_domheap_page(virt_to_page(d->arch.mm_perdomain_l2)); - free_domheap_page(virt_to_page(d->arch.mm_perdomain_l3)); + if ( d->arch.mm_perdomain_l2 ) + free_domheap_page(virt_to_page(d->arch.mm_perdomain_l2)); + if ( d->arch.mm_perdomain_l3 ) + free_domheap_page(virt_to_page(d->arch.mm_perdomain_l3)); #endif free_xenheap_pages(d->arch.mm_perdomain_pt, pdpt_order); return rc; @@ -596,7 +601,7 @@ int arch_set_info_guest( } if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) ) - return 0; + goto out; memset(v->arch.guest_context.debugreg, 0, sizeof(v->arch.guest_context.debugreg)); @@ -701,6 +706,11 @@ int arch_set_info_guest( update_cr3(v); + out: + if ( flags & VGCF_online ) + clear_bit(_VCPUF_down, &v->vcpu_flags); + else + set_bit(_VCPUF_down, &v->vcpu_flags); return 0; #undef c } @@ -1376,7 +1386,8 @@ int hypercall_xlat_continuation(unsigned int *id, unsigned int mask, ...) } #endif -static void relinquish_memory(struct domain *d, struct list_head *list) +static void relinquish_memory(struct domain *d, struct list_head *list, + unsigned long type) { struct list_head *ent; struct page_info *page; @@ -1405,23 +1416,24 @@ static void relinquish_memory(struct domain *d, struct list_head *list) put_page(page); /* - * Forcibly invalidate base page tables at this point to break circular - * 'linear page table' references. This is okay because MMU structures - * are not shared across domains and this domain is now dead. Thus base - * tables are not in use so a non-zero count means circular reference. + * Forcibly invalidate top-most, still valid page tables at this point + * to break circular 'linear page table' references. This is okay + * because MMU structures are not shared across domains and this domain + * is now dead. Thus top-most valid tables are not in use so a non-zero + * count means circular reference. */ y = page->u.inuse.type_info; for ( ; ; ) { x = y; if ( likely((x & (PGT_type_mask|PGT_validated)) != - (PGT_base_page_table|PGT_validated)) ) + (type|PGT_validated)) ) break; y = cmpxchg(&page->u.inuse.type_info, x, x & ~PGT_validated); if ( likely(y == x) ) { - free_page_type(page, PGT_base_page_table); + free_page_type(page, type); break; } } @@ -1519,8 +1531,16 @@ void domain_relinquish_resources(struct domain *d) destroy_gdt(v); /* Relinquish every page of memory. */ - relinquish_memory(d, &d->xenpage_list); - relinquish_memory(d, &d->page_list); +#if CONFIG_PAGING_LEVELS >= 4 + relinquish_memory(d, &d->xenpage_list, PGT_l4_page_table); + relinquish_memory(d, &d->page_list, PGT_l4_page_table); +#endif +#if CONFIG_PAGING_LEVELS >= 3 + relinquish_memory(d, &d->xenpage_list, PGT_l3_page_table); + relinquish_memory(d, &d->page_list, PGT_l3_page_table); +#endif + relinquish_memory(d, &d->xenpage_list, PGT_l2_page_table); + relinquish_memory(d, &d->page_list, PGT_l2_page_table); /* Free page used by xen oprofile buffer */ free_xenoprof_pages(d); diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index 5d7941ab5d..96215da601 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -902,6 +902,7 @@ int construct_dom0(struct domain *d, update_domain_wallclock_time(d); set_bit(_VCPUF_initialised, &v->vcpu_flags); + clear_bit(_VCPUF_down, &v->vcpu_flags); /* * Initial register values: diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index d8ca0b0621..503b0000c7 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -145,6 +145,12 @@ long arch_do_domctl( } arr32 = alloc_xenheap_page(); + if ( !arr32 ) + { + ret = -ENOMEM; + put_domain(d); + break; + } ret = 0; for ( n = 0; n < num; ) @@ -157,7 +163,7 @@ long arch_do_domctl( domctl->u.getpageframeinfo2.array, n, k) ) { - ret = -EINVAL; + ret = -EFAULT; break; } @@ -201,7 +207,7 @@ long arch_do_domctl( if ( copy_to_guest_offset(domctl->u.getpageframeinfo2.array, n, arr32, k) ) { - ret = -EINVAL; + ret = -EFAULT; break; } @@ -444,6 +450,8 @@ void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c) c(flags &= ~(VGCF_i387_valid|VGCF_in_kernel)); if ( test_bit(_VCPUF_fpu_initialised, &v->vcpu_flags) ) c(flags |= VGCF_i387_valid); + if ( !test_bit(_VCPUF_down, &v->vcpu_flags) ) + c(flags |= VGCF_online); if ( is_hvm_vcpu(v) ) { diff --git a/xen/arch/x86/gdbstub.c b/xen/arch/x86/gdbstub.c index 8ed5e20298..a3af473ee2 100644 --- a/xen/arch/x86/gdbstub.c +++ b/xen/arch/x86/gdbstub.c @@ -73,38 +73,16 @@ gdb_arch_read_reg(unsigned long regnum, struct cpu_user_regs *regs, /* Like copy_from_user, but safe to call with interrupts disabled. Trust me, and don't look behind the curtain. */ -unsigned +unsigned int gdb_arch_copy_from_user(void *dest, const void *src, unsigned len) { - int __d0, __d1, __d2; - ASSERT(!local_irq_is_enabled()); - __asm__ __volatile__( - "1: rep; movsb\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: addl $4, %%esp\n" - " jmp 2b\n" - ".previous\n" - ".section __pre_ex_table,\"a\"\n" - " "__FIXUP_ALIGN"\n" - " "__FIXUP_WORD" 1b,3b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " "__FIXUP_ALIGN"\n" - " "__FIXUP_WORD" 1b,2b\n" - ".previous\n" - : "=c"(__d2), "=D" (__d0), "=S" (__d1) - : "0"(len), "1"(dest), "2"(src) - : "memory"); - ASSERT(!local_irq_is_enabled()); - return __d2; + return copy_from_user(dest, src, len); } unsigned int gdb_arch_copy_to_user(void *dest, const void *src, unsigned len) { - /* XXX */ - return len; + return copy_to_user(dest, src, len); } void diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c index 419a886eba..b3fb6ffe29 100644 --- a/xen/arch/x86/hvm/hpet.c +++ b/xen/arch/x86/hvm/hpet.c @@ -29,6 +29,10 @@ #define S_TO_NS 1000000000ULL /* 1s = 10^9 ns */ #define S_TO_FS 1000000000000000ULL /* 1s = 10^15 fs */ +/* Frequency_of_TSC / frequency_of_HPET = 32 */ +#define TSC_PER_HPET_TICK 32 +#define guest_time_hpet(v) (hvm_get_guest_time(v) / TSC_PER_HPET_TICK) + #define HPET_ID 0x000 #define HPET_PERIOD 0x004 #define HPET_CFG 0x010 @@ -67,7 +71,9 @@ #define HPET_TN_INT_ROUTE_CAP_MASK (0xffffffffULL \ << HPET_TN_INT_ROUTE_CAP_SHIFT) -#define hpet_tick_to_ns(h, tick) ((s_time_t)(tick)*S_TO_NS/h->tsc_freq) +#define hpet_tick_to_ns(h, tick) ((s_time_t)(tick)* \ + (S_TO_NS*TSC_PER_HPET_TICK)/h->tsc_freq) + #define timer_config(h, n) (h->hpet.timers[n].config) #define timer_enabled(h, n) (timer_config(h, n) & HPET_TN_ENABLE) #define timer_is_periodic(h, n) (timer_config(h, n) & HPET_TN_PERIODIC) @@ -108,7 +114,7 @@ static inline int hpet_check_access_length( static inline uint64_t hpet_read_maincounter(HPETState *h) { if ( hpet_enabled(h) ) - return hvm_get_guest_time(h->vcpu) + h->mc_offset; + return guest_time_hpet(h->vcpu) + h->mc_offset; else return h->hpet.mc64; } @@ -144,7 +150,7 @@ static void hpet_stop_timer(HPETState *h, unsigned int tn) /* the number of HPET tick that stands for * 1/(2^10) second, namely, 0.9765625 milliseconds */ -#define HPET_TINY_TIME_SPAN (h->tsc_freq >> 10) +#define HPET_TINY_TIME_SPAN ((h->tsc_freq >> 10) / TSC_PER_HPET_TICK) static void hpet_set_timer(HPETState *h, unsigned int tn) { @@ -225,14 +231,14 @@ static void hpet_write( if ( !(old_val & HPET_CFG_ENABLE) && (new_val & HPET_CFG_ENABLE) ) { /* Enable main counter and interrupt generation. */ - h->mc_offset = h->hpet.mc64 - hvm_get_guest_time(h->vcpu); + h->mc_offset = h->hpet.mc64 - guest_time_hpet(h->vcpu); for ( i = 0; i < HPET_TIMER_NUM; i++ ) hpet_set_timer(h, i); } else if ( (old_val & HPET_CFG_ENABLE) && !(new_val & HPET_CFG_ENABLE) ) { /* Halt main counter and disable interrupt generation. */ - h->hpet.mc64 = h->mc_offset + hvm_get_guest_time(h->vcpu); + h->hpet.mc64 = h->mc_offset + guest_time_hpet(h->vcpu); for ( i = 0; i < HPET_TIMER_NUM; i++ ) hpet_stop_timer(h, i); } @@ -384,7 +390,7 @@ static int hpet_save(struct domain *d, hvm_domain_context_t *h) HPETState *hp = &d->arch.hvm_domain.pl_time.vhpet; /* Write the proper value into the main counter */ - hp->hpet.mc64 = hp->mc_offset + hvm_get_guest_time(hp->vcpu); + hp->hpet.mc64 = hp->mc_offset + guest_time_hpet(hp->vcpu); /* Save the HPET registers */ return hvm_save_entry(HPET, 0, h, &hp->hpet); @@ -400,7 +406,7 @@ static int hpet_load(struct domain *d, hvm_domain_context_t *h) return -EINVAL; /* Recalculate the offset between the main counter and guest time */ - hp->mc_offset = hp->hpet.mc64 - hvm_get_guest_time(hp->vcpu); + hp->mc_offset = hp->hpet.mc64 - guest_time_hpet(hp->vcpu); /* Restart the timers */ for ( i = 0; i < HPET_TIMER_NUM; i++ ) @@ -425,8 +431,8 @@ void hpet_init(struct vcpu *v) h->hpet.capability = 0x8086A201ULL; /* This is the number of femptoseconds per HPET tick. */ - /* Here we define HPET's frequency to be the same as the TSC's. */ - h->hpet.capability |= ((S_TO_FS/h->tsc_freq) << 32); + /* Here we define HPET's frequency to be 1/32 of the TSC's */ + h->hpet.capability |= ((S_TO_FS*TSC_PER_HPET_TICK/h->tsc_freq) << 32); for ( i = 0; i < HPET_TIMER_NUM; i++ ) { diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index f48bb6f49a..17d0cf25ee 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -146,6 +146,48 @@ void hvm_do_resume(struct vcpu *v) } } +/* Called from the tools when saving a domain to make sure the io + * request-response ring is entirely empty. */ +static int hvmop_drain_io( + XEN_GUEST_HANDLE(xen_hvm_drain_io_t) uop) +{ + struct xen_hvm_drain_io op; + struct domain *d; + struct vcpu *v; + ioreq_t *p; + int rc; + + if ( copy_from_guest(&op, uop, 1) ) + return -EFAULT; + + if ( !IS_PRIV(current->domain) ) + return -EPERM; + + d = rcu_lock_domain_by_id(op.domid); + if ( d == NULL ) + return -ESRCH; + + rc = -EINVAL; + /* Can't do this to yourself, or to a domain without an ioreq ring */ + if ( d == current->domain || !is_hvm_domain(d) || get_sp(d) == NULL ) + goto out; + + rc = 0; + + domain_pause(d); /* It's not safe to do this to running vcpus */ + for_each_vcpu(d, v) + { + p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq; + if ( p->state == STATE_IORESP_READY ) + hvm_io_assist(v); + } + domain_unpause(d); + + out: + rcu_unlock_domain(d); + return rc; +} + int hvm_domain_initialise(struct domain *d) { int rc; @@ -380,7 +422,7 @@ void hvm_triple_fault(void) */ static int __hvm_copy(void *buf, paddr_t addr, int size, int dir, int virt) { - unsigned long mfn; + unsigned long gfn, mfn; char *p; int count, todo; @@ -390,9 +432,11 @@ static int __hvm_copy(void *buf, paddr_t addr, int size, int dir, int virt) count = min_t(int, PAGE_SIZE - (addr & ~PAGE_MASK), todo); if ( virt ) - mfn = get_mfn_from_gpfn(paging_gva_to_gfn(current, addr)); + gfn = paging_gva_to_gfn(current, addr); else - mfn = get_mfn_from_gpfn(addr >> PAGE_SHIFT); + gfn = addr >> PAGE_SHIFT; + + mfn = get_mfn_from_gpfn(gfn); if ( mfn == INVALID_MFN ) return todo; @@ -400,14 +444,15 @@ static int __hvm_copy(void *buf, paddr_t addr, int size, int dir, int virt) p = (char *)map_domain_page(mfn) + (addr & ~PAGE_MASK); if ( dir ) + { memcpy(p, buf, count); /* dir == TRUE: *to* guest */ + mark_dirty(current->domain, mfn); + } else memcpy(buf, p, count); /* dir == FALSE: *from guest */ unmap_domain_page(p); - mark_dirty(current->domain, mfn); - addr += count; buf += count; todo -= count; @@ -913,6 +958,12 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) guest_handle_cast(arg, xen_hvm_set_pci_link_route_t)); break; + case HVMOP_drain_io: + rc = hvmop_drain_io( + guest_handle_cast(arg, xen_hvm_drain_io_t)); + break; + + default: { gdprintk(XENLOG_WARNING, "Bad HVM op %ld.\n", op); diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c index 9ba8c3e4a3..185a7c2f55 100644 --- a/xen/arch/x86/hvm/platform.c +++ b/xen/arch/x86/hvm/platform.c @@ -415,6 +415,17 @@ static int mmio_decode(int address_bytes, unsigned char *opcode, GET_OP_SIZE_FOR_NONEBYTE(*op_size); return mem_reg(*op_size, opcode, mmio_op, rex); + case 0x08: /* or r8, m8 */ + mmio_op->instr = INSTR_OR; + *op_size = BYTE; + GET_OP_SIZE_FOR_BYTE(size_reg); + return reg_mem(size_reg, opcode, mmio_op, rex); + + case 0x09: /* or r32/16, m32/16 */ + mmio_op->instr = INSTR_OR; + GET_OP_SIZE_FOR_NONEBYTE(*op_size); + return reg_mem(*op_size, opcode, mmio_op, rex); + case 0x0A: /* or m8, r8 */ mmio_op->instr = INSTR_OR; *op_size = BYTE; diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index 5cda6bbb75..036eba7bfe 100644 --- a/xen/arch/x86/hvm/rtc.c +++ b/xen/arch/x86/hvm/rtc.c @@ -174,6 +174,11 @@ static void rtc_copy_date(RTCState *s) { const struct tm *tm = &s->current_tm; + if (s->time_offset_seconds != s->pt.vcpu->domain->time_offset_seconds) { + s->current_tm = gmtime(get_localtime(s->pt.vcpu->domain)); + s->time_offset_seconds = s->pt.vcpu->domain->time_offset_seconds; + } + s->hw.cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec); s->hw.cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min); if ( s->hw.cmos_data[RTC_REG_B] & RTC_24H ) @@ -211,10 +216,16 @@ static int get_days_in_month(int month, int year) } /* update 'tm' to the next second */ -static void rtc_next_second(struct tm *tm) +static void rtc_next_second(RTCState *s) { + struct tm *tm = &s->current_tm; int days_in_month; + if (s->time_offset_seconds != s->pt.vcpu->domain->time_offset_seconds) { + s->current_tm = gmtime(get_localtime(s->pt.vcpu->domain)); + s->time_offset_seconds = s->pt.vcpu->domain->time_offset_seconds; + } + tm->tm_sec++; if ((unsigned)tm->tm_sec >= 60) { tm->tm_sec = 0; @@ -258,7 +269,7 @@ static void rtc_update_second(void *opaque) } else { - rtc_next_second(&s->current_tm); + rtc_next_second(s); if ( !(s->hw.cmos_data[RTC_REG_B] & RTC_SET) ) s->hw.cmos_data[RTC_REG_A] |= RTC_UIP; diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 61380c606a..abff76a2b8 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -107,22 +106,10 @@ static inline void svm_inject_exception(struct vcpu *v, int trap, static void stop_svm(void) { u32 eax, edx; - int cpu = smp_processor_id(); - /* We turn off the EFER_SVME bit. */ rdmsr(MSR_EFER, eax, edx); eax &= ~EFER_SVME; wrmsr(MSR_EFER, eax, edx); - - /* release the HSA */ - free_host_save_area(hsa[cpu]); - hsa[cpu] = NULL; - wrmsr(MSR_K8_VM_HSAVE_PA, 0, 0 ); - - /* free up the root vmcb */ - free_vmcb(root_vmcb[cpu]); - root_vmcb[cpu] = NULL; - root_vmcb_pa[cpu] = 0; } static void svm_store_cpu_guest_regs( @@ -462,6 +449,9 @@ int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c) vmcb->rflags = c->eflags; v->arch.hvm_svm.cpu_shadow_cr0 = c->cr0; + vmcb->cr0 = c->cr0 | X86_CR0_WP | X86_CR0_ET; + if ( !paging_mode_hap(v->domain) ) + vmcb->cr0 |= X86_CR0_PG; #ifdef HVM_DEBUG_SUSPEND printk("%s: cr3=0x%"PRIx64", cr0=0x%"PRIx64", cr4=0x%"PRIx64".\n", @@ -495,7 +485,6 @@ int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c) * first. */ HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 c->cr3 = %"PRIx64"", c->cr3); - /* current!=vcpu as not called by arch_vmx_do_launch */ mfn = gmfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT); if( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain) ) goto bad_cr3; @@ -579,7 +568,7 @@ void svm_save_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data) data->msr_star = vmcb->star; data->msr_cstar = vmcb->cstar; data->msr_syscall_mask = vmcb->sfmask; - data->msr_efer = vmcb->efer; + data->msr_efer = v->arch.hvm_svm.cpu_shadow_efer; data->tsc = hvm_get_guest_time(v); } @@ -594,7 +583,12 @@ void svm_load_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data) vmcb->star = data->msr_star; vmcb->cstar = data->msr_cstar; vmcb->sfmask = data->msr_syscall_mask; - vmcb->efer = data->msr_efer; + v->arch.hvm_svm.cpu_shadow_efer = data->msr_efer; + vmcb->efer = data->msr_efer | EFER_SVME; + /* VMCB's EFER.LME isn't set unless we're actually in long mode + * (see long_mode_do_msr_write()) */ + if ( !(vmcb->efer & EFER_LMA) ) + vmcb->efer &= ~EFER_LME; hvm_set_guest_time(v, data->tsc); } @@ -754,6 +748,14 @@ static void svm_set_tsc_offset(struct vcpu *v, u64 offset) static void svm_init_ap_context( struct vcpu_guest_context *ctxt, int vcpuid, int trampoline_vector) { + struct vcpu *v; + cpu_user_regs_t *regs; + u16 cs_sel; + + /* We know this is safe because hvm_bringup_ap() does it */ + v = current->domain->vcpu[vcpuid]; + regs = &v->arch.guest_context.user_regs; + memset(ctxt, 0, sizeof(*ctxt)); /* @@ -761,8 +763,19 @@ static void svm_init_ap_context( * passed to us is page alligned and is the physicall frame number for * the code. We will execute this code in real mode. */ + cs_sel = trampoline_vector << 8; ctxt->user_regs.eip = 0x0; - ctxt->user_regs.cs = (trampoline_vector << 8); + ctxt->user_regs.cs = cs_sel; + + /* + * This is the launch of an AP; set state so that we begin executing + * the trampoline code in real-mode. + */ + svm_do_vmmcall_reset_to_realmode(v, regs); + /* Adjust the vmcb's hidden register state. */ + v->arch.hvm_svm.vmcb->rip = 0; + v->arch.hvm_svm.vmcb->cs.sel = cs_sel; + v->arch.hvm_svm.vmcb->cs.base = (cs_sel << 4); } static void svm_init_hypercall_page(struct domain *d, void *hypercall_page) @@ -907,32 +920,6 @@ static void svm_load_cpu_guest_regs( svm_load_cpu_user_regs(v, regs); } -static void arch_svm_do_launch(struct vcpu *v) -{ - svm_do_launch(v); - - if ( paging_mode_hap(v->domain) ) { - v->arch.hvm_svm.vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table); - } - - if ( v->vcpu_id != 0 ) - { - cpu_user_regs_t *regs = ¤t->arch.guest_context.user_regs; - u16 cs_sel = regs->cs; - /* - * This is the launch of an AP; set state so that we begin executing - * the trampoline code in real-mode. - */ - svm_do_vmmcall_reset_to_realmode(v, regs); - /* Adjust the state to execute the trampoline code.*/ - v->arch.hvm_svm.vmcb->rip = 0; - v->arch.hvm_svm.vmcb->cs.sel= cs_sel; - v->arch.hvm_svm.vmcb->cs.base = (cs_sel << 4); - } - - reset_stack_and_jump(svm_asm_do_launch); -} - static void svm_ctxt_switch_from(struct vcpu *v) { svm_save_dr(v); @@ -954,16 +941,30 @@ static void svm_ctxt_switch_to(struct vcpu *v) svm_restore_dr(v); } +static void arch_svm_do_resume(struct vcpu *v) +{ + if ( v->arch.hvm_svm.launch_core != smp_processor_id() ) + { + v->arch.hvm_svm.launch_core = smp_processor_id(); + hvm_migrate_timers(v); + } + + hvm_do_resume(v); + reset_stack_and_jump(svm_asm_do_resume); +} + static int svm_vcpu_initialise(struct vcpu *v) { int rc; - v->arch.schedule_tail = arch_svm_do_launch; + v->arch.schedule_tail = arch_svm_do_resume; v->arch.ctxt_switch_from = svm_ctxt_switch_from; v->arch.ctxt_switch_to = svm_ctxt_switch_to; v->arch.hvm_svm.saved_irq_vector = -1; + v->arch.hvm_svm.launch_core = -1; + if ( (rc = svm_create_vmcb(v)) != 0 ) { dprintk(XENLOG_WARNING, @@ -1027,10 +1028,12 @@ void svm_npt_detect(void) /* check CPUID for nested paging support */ cpuid(0x8000000A, &eax, &ebx, &ecx, &edx); - if ( edx & 0x01 ) { /* nested paging */ + if ( edx & 0x01 ) /* nested paging */ + { hap_capable_system = 1; } - else if ( opt_hap_enabled ) { + else if ( opt_hap_enabled ) + { printk(" nested paging is not supported by this CPU.\n"); hap_capable_system = 0; /* no nested paging, we disable flag. */ } @@ -1058,8 +1061,9 @@ int start_svm(void) return 0; } - if (!(hsa[cpu] = alloc_host_save_area())) - return 0; + if (!hsa[cpu]) + if (!(hsa[cpu] = alloc_host_save_area())) + return 0; rdmsr(MSR_EFER, eax, edx); eax |= EFER_SVME; @@ -1074,8 +1078,9 @@ int start_svm(void) phys_hsa_hi = (u32) (phys_hsa >> 32); wrmsr(MSR_K8_VM_HSAVE_PA, phys_hsa_lo, phys_hsa_hi); - if (!(root_vmcb[cpu] = alloc_vmcb())) - return 0; + if (!root_vmcb[cpu]) + if (!(root_vmcb[cpu] = alloc_vmcb())) + return 0; root_vmcb_pa[cpu] = virt_to_maddr(root_vmcb[cpu]); if (cpu == 0) @@ -1086,24 +1091,6 @@ int start_svm(void) return 1; } -void arch_svm_do_resume(struct vcpu *v) -{ - /* pinning VCPU to a different core? */ - if ( v->arch.hvm_svm.launch_core == smp_processor_id()) { - hvm_do_resume( v ); - reset_stack_and_jump( svm_asm_do_resume ); - } - else { - if (svm_dbg_on) - printk("VCPU core pinned: %d to %d\n", - v->arch.hvm_svm.launch_core, smp_processor_id() ); - v->arch.hvm_svm.launch_core = smp_processor_id(); - hvm_migrate_timers( v ); - hvm_do_resume( v ); - reset_stack_and_jump( svm_asm_do_resume ); - } -} - static int svm_do_nested_pgfault(paddr_t gpa, struct cpu_user_regs *regs) { if (mmio_space(gpa)) { @@ -2601,65 +2588,6 @@ static int svm_do_vmmcall_reset_to_realmode(struct vcpu *v, } -/* - * svm_do_vmmcall - SVM VMMCALL handler - * - * returns 0 on success, non-zero otherwise - */ -static int svm_do_vmmcall(struct vcpu *v, struct cpu_user_regs *regs) -{ - struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; - int inst_len; - - ASSERT(vmcb); - ASSERT(regs); - - inst_len = __get_instruction_length(v, INSTR_VMCALL, NULL); - ASSERT(inst_len > 0); - - HVMTRACE_1D(VMMCALL, v, regs->eax); - - if ( regs->eax & 0x80000000 ) - { - /* VMMCALL sanity check */ - if ( vmcb->cpl > get_vmmcall_cpl(regs->edi) ) - { - printk("VMMCALL CPL check failed\n"); - return -1; - } - - /* handle the request */ - switch ( regs->eax ) - { - case VMMCALL_RESET_TO_REALMODE: - if ( svm_do_vmmcall_reset_to_realmode(v, regs) ) - { - printk("svm_do_vmmcall_reset_to_realmode() failed\n"); - return -1; - } - /* since we just reset the VMCB, return without adjusting - * the eip */ - return 0; - - case VMMCALL_DEBUG: - printk("DEBUG features not implemented yet\n"); - break; - default: - break; - } - - hvm_print_line(v, regs->eax); /* provides the current domain */ - } - else - { - hvm_do_hypercall(regs); - } - - __update_guest_eip(vmcb, inst_len); - return 0; -} - - void svm_dump_inst(unsigned long eip) { u8 opcode[256]; @@ -3162,9 +3090,14 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs) svm_handle_invlpg(1, regs); break; - case VMEXIT_VMMCALL: - svm_do_vmmcall(v, regs); + case VMEXIT_VMMCALL: { + int inst_len = __get_instruction_length(v, INSTR_VMCALL, NULL); + ASSERT(inst_len > 0); + HVMTRACE_1D(VMMCALL, v, regs->eax); + __update_guest_eip(vmcb, inst_len); + hvm_do_hypercall(regs); break; + } case VMEXIT_CR0_READ: svm_cr_access(v, 0, TYPE_MOV_FROM_CR, regs); diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c index f2a220011e..446ddbb968 100644 --- a/xen/arch/x86/hvm/svm/vmcb.c +++ b/xen/arch/x86/hvm/svm/vmcb.c @@ -79,11 +79,6 @@ struct host_save_area *alloc_host_save_area(void) return hsa; } -void free_host_save_area(struct host_save_area *hsa) -{ - free_xenheap_page(hsa); -} - static int construct_vmcb(struct vcpu *v) { struct arch_svm_struct *arch_svm = &v->arch.hvm_svm; @@ -201,11 +196,13 @@ static int construct_vmcb(struct vcpu *v) arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP; - if ( paging_mode_hap(v->domain) ) { + if ( paging_mode_hap(v->domain) ) + { vmcb->cr0 = arch_svm->cpu_shadow_cr0; vmcb->np_enable = 1; /* enable nested paging */ vmcb->g_pat = 0x0007040600070406ULL; /* guest PAT */ vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_PG; + vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table); } return 0; @@ -252,16 +249,6 @@ void svm_destroy_vmcb(struct vcpu *v) arch_svm->vmcb = NULL; } -void svm_do_launch(struct vcpu *v) -{ - hvm_stts(v); - - /* current core is the one we intend to perform the VMRUN on */ - v->arch.hvm_svm.launch_core = smp_processor_id(); - - v->arch.schedule_tail = arch_svm_do_resume; -} - static void svm_dump_sel(char *name, svm_segment_register_t *s) { printk("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n", diff --git a/xen/arch/x86/hvm/svm/x86_32/exits.S b/xen/arch/x86/hvm/svm/x86_32/exits.S index c465e3b7fa..604fa94c9e 100644 --- a/xen/arch/x86/hvm/svm/x86_32/exits.S +++ b/xen/arch/x86/hvm/svm/x86_32/exits.S @@ -80,15 +80,24 @@ popl %eax; \ addl $(NR_SKIPPED_REGS*4), %esp - ALIGN - #define VMRUN .byte 0x0F,0x01,0xD8 #define VMLOAD .byte 0x0F,0x01,0xDA #define VMSAVE .byte 0x0F,0x01,0xDB #define STGI .byte 0x0F,0x01,0xDC #define CLGI .byte 0x0F,0x01,0xDD -ENTRY(svm_asm_do_launch) +ENTRY(svm_asm_do_resume) + GET_CURRENT(%ebx) + xorl %ecx,%ecx + notl %ecx + cli # tests must not race interrupts + movl VCPU_processor(%ebx),%eax + shl $IRQSTAT_shift,%eax + test %ecx,irq_stat(%eax,1) + jnz svm_process_softirqs + call svm_intr_assist + call svm_load_cr2 + CLGI sti GET_CURRENT(%ebx) @@ -134,31 +143,8 @@ svm_stgi_label: addl $4,%esp jmp svm_asm_do_resume - ALIGN - -ENTRY(svm_asm_do_resume) -svm_test_all_events: - GET_CURRENT(%ebx) -/*test_all_events:*/ - xorl %ecx,%ecx - notl %ecx - cli # tests must not race interrupts -/*test_softirqs:*/ - movl VCPU_processor(%ebx),%eax - shl $IRQSTAT_shift,%eax - test %ecx,irq_stat(%eax,1) - jnz svm_process_softirqs -svm_restore_all_guest: - call svm_intr_assist - call svm_load_cr2 - /* - * Check if we are going back to AMD-V based VM - * By this time, all the setups in the VMCB must be complete. - */ - jmp svm_asm_do_launch - ALIGN svm_process_softirqs: sti call do_softirq - jmp svm_test_all_events + jmp svm_asm_do_resume diff --git a/xen/arch/x86/hvm/svm/x86_64/exits.S b/xen/arch/x86/hvm/svm/x86_64/exits.S index 042cd6dc8e..cbff00cb5c 100644 --- a/xen/arch/x86/hvm/svm/x86_64/exits.S +++ b/xen/arch/x86/hvm/svm/x86_64/exits.S @@ -98,7 +98,17 @@ #define STGI .byte 0x0F,0x01,0xDC #define CLGI .byte 0x0F,0x01,0xDD -ENTRY(svm_asm_do_launch) +ENTRY(svm_asm_do_resume) + GET_CURRENT(%rbx) + cli # tests must not race interrupts + movl VCPU_processor(%rbx),%eax + shl $IRQSTAT_shift, %rax + leaq irq_stat(%rip), %rdx + testl $~0, (%rdx, %rax, 1) + jnz svm_process_softirqs + call svm_intr_assist + call svm_load_cr2 + CLGI sti GET_CURRENT(%rbx) @@ -150,28 +160,8 @@ svm_stgi_label: call svm_vmexit_handler jmp svm_asm_do_resume -ENTRY(svm_asm_do_resume) -svm_test_all_events: - GET_CURRENT(%rbx) -/*test_all_events:*/ - cli # tests must not race interrupts -/*test_softirqs:*/ - movl VCPU_processor(%rbx),%eax - shl $IRQSTAT_shift, %rax - leaq irq_stat(%rip), %rdx - testl $~0, (%rdx, %rax, 1) - jnz svm_process_softirqs -svm_restore_all_guest: - call svm_intr_assist - call svm_load_cr2 - /* - * Check if we are going back to AMD-V based VM - * By this time, all the setups in the VMCB must be complete. - */ - jmp svm_asm_do_launch - ALIGN svm_process_softirqs: sti call do_softirq - jmp svm_test_all_events + jmp svm_asm_do_resume diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 2cc294ba36..af2d0bbe44 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -195,8 +195,9 @@ int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda) result = 1; break; default: - gdprintk(XENLOG_WARNING, "Bad DFR value for lapic of vcpu %d\n", - vlapic_vcpu(vlapic)->vcpu_id); + gdprintk(XENLOG_WARNING, "Bad DFR value for lapic of vcpu %d: %08x\n", + vlapic_vcpu(vlapic)->vcpu_id, + vlapic_get_reg(vlapic, APIC_DFR)); break; } diff --git a/xen/arch/x86/hvm/vpic.c b/xen/arch/x86/hvm/vpic.c index 3a5b2a16a8..5dfe1e4a6b 100644 --- a/xen/arch/x86/hvm/vpic.c +++ b/xen/arch/x86/hvm/vpic.c @@ -54,8 +54,8 @@ static int vpic_get_priority(struct hvm_hw_vpic *vpic, uint8_t mask) if ( mask == 0 ) return VPIC_PRIO_NONE; - /* prio = ffs(mask ROL vpic->priority_add); */ - asm ( "rol %%cl,%b1 ; bsf %1,%0" + /* prio = ffs(mask ROR vpic->priority_add); */ + asm ( "ror %%cl,%b1 ; bsf %1,%0" : "=r" (prio) : "r" ((uint32_t)mask), "c" (vpic->priority_add) ); return prio; } diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 81bea072c5..e0590f33a2 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -108,6 +108,7 @@ #include #include #include +#include #include #define MEM_LOG(_f, _a...) gdprintk(XENLOG_WARNING , _f "\n" , ## _a) @@ -246,6 +247,11 @@ int memory_is_conventional_ram(paddr_t p) return 0; } +unsigned long domain_get_maximum_gpfn(struct domain *d) +{ + return is_hvm_domain(d) ? d->arch.p2m.max_mapped_pfn : arch_get_max_pfn(d); +} + void share_xen_page_with_guest( struct page_info *page, struct domain *d, int readonly) { @@ -517,7 +523,6 @@ static int get_page_and_type_from_pagenr(unsigned long page_nr, return 1; } -#ifndef CONFIG_X86_PAE /* We do not support guest linear mappings on PAE. */ /* * We allow root tables to map each other (a.k.a. linear page tables). It * needs some special care with reference counts and access permissions: @@ -530,48 +535,48 @@ static int get_page_and_type_from_pagenr(unsigned long page_nr, * frame if it is mapped by a different root table. This is sufficient and * also necessary to allow validation of a root table mapping itself. */ -static int -get_linear_pagetable( - root_pgentry_t re, unsigned long re_pfn, struct domain *d) -{ - unsigned long x, y; - struct page_info *page; - unsigned long pfn; - - if ( (root_get_flags(re) & _PAGE_RW) ) - { - MEM_LOG("Attempt to create linear p.t. with write perms"); - return 0; - } - - if ( (pfn = root_get_pfn(re)) != re_pfn ) - { - /* Make sure the mapped frame belongs to the correct domain. */ - if ( unlikely(!get_page_from_pagenr(pfn, d)) ) - return 0; - - /* - * Make sure that the mapped frame is an already-validated L2 table. - * If so, atomically increment the count (checking for overflow). - */ - page = mfn_to_page(pfn); - y = page->u.inuse.type_info; - do { - x = y; - if ( unlikely((x & PGT_count_mask) == PGT_count_mask) || - unlikely((x & (PGT_type_mask|PGT_validated)) != - (PGT_root_page_table|PGT_validated)) ) - { - put_page(page); - return 0; - } - } - while ( (y = cmpxchg(&page->u.inuse.type_info, x, x + 1)) != x ); - } - - return 1; +#define define_get_linear_pagetable(level) \ +static int \ +get_##level##_linear_pagetable( \ + level##_pgentry_t pde, unsigned long pde_pfn, struct domain *d) \ +{ \ + unsigned long x, y; \ + struct page_info *page; \ + unsigned long pfn; \ + \ + if ( (level##e_get_flags(pde) & _PAGE_RW) ) \ + { \ + MEM_LOG("Attempt to create linear p.t. with write perms"); \ + return 0; \ + } \ + \ + if ( (pfn = level##e_get_pfn(pde)) != pde_pfn ) \ + { \ + /* Make sure the mapped frame belongs to the correct domain. */ \ + if ( unlikely(!get_page_from_pagenr(pfn, d)) ) \ + return 0; \ + \ + /* \ + * Ensure that the mapped frame is an already-validated page table. \ + * If so, atomically increment the count (checking for overflow). \ + */ \ + page = mfn_to_page(pfn); \ + y = page->u.inuse.type_info; \ + do { \ + x = y; \ + if ( unlikely((x & PGT_count_mask) == PGT_count_mask) || \ + unlikely((x & (PGT_type_mask|PGT_validated)) != \ + (PGT_##level##_page_table|PGT_validated)) ) \ + { \ + put_page(page); \ + return 0; \ + } \ + } \ + while ( (y = cmpxchg(&page->u.inuse.type_info, x, x + 1)) != x ); \ + } \ + \ + return 1; \ } -#endif /* !CONFIG_X86_PAE */ int get_page_from_l1e( @@ -633,7 +638,8 @@ get_page_from_l1e( /* NB. Virtual address 'l2e' maps to a machine address within frame 'pfn'. */ -static int +define_get_linear_pagetable(l2); +static int get_page_from_l2e( l2_pgentry_t l2e, unsigned long pfn, struct domain *d) { @@ -649,16 +655,16 @@ get_page_from_l2e( } rc = get_page_and_type_from_pagenr(l2e_get_pfn(l2e), PGT_l1_page_table, d); -#if CONFIG_PAGING_LEVELS == 2 if ( unlikely(!rc) ) - rc = get_linear_pagetable(l2e, pfn, d); -#endif + rc = get_l2_linear_pagetable(l2e, pfn, d); + return rc; } #if CONFIG_PAGING_LEVELS >= 3 -static int +define_get_linear_pagetable(l3); +static int get_page_from_l3e( l3_pgentry_t l3e, unsigned long pfn, struct domain *d) { @@ -674,12 +680,16 @@ get_page_from_l3e( } rc = get_page_and_type_from_pagenr(l3e_get_pfn(l3e), PGT_l2_page_table, d); + if ( unlikely(!rc) ) + rc = get_l3_linear_pagetable(l3e, pfn, d); + return rc; } #endif /* 3 level */ #if CONFIG_PAGING_LEVELS >= 4 -static int +define_get_linear_pagetable(l4); +static int get_page_from_l4e( l4_pgentry_t l4e, unsigned long pfn, struct domain *d) { @@ -695,9 +705,8 @@ get_page_from_l4e( } rc = get_page_and_type_from_pagenr(l4e_get_pfn(l4e), PGT_l3_page_table, d); - if ( unlikely(!rc) ) - rc = get_linear_pagetable(l4e, pfn, d); + rc = get_l4_linear_pagetable(l4e, pfn, d); return rc; } @@ -2765,7 +2774,9 @@ int do_update_va_mapping(unsigned long va, u64 val64, flush_tlb_one_mask(d->domain_dirty_cpumask, va); break; default: - if ( unlikely(get_user(vmask, (unsigned long *)bmap_ptr)) ) + if ( unlikely(!IS_COMPAT(d) ? + get_user(vmask, (unsigned long *)bmap_ptr) : + get_user(vmask, (unsigned int *)bmap_ptr)) ) rc = -EFAULT; pmask = vcpumask_to_pcpumask(d, vmask); flush_tlb_one_mask(pmask, va); diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index f341fe3bc8..efabba8223 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -36,7 +36,6 @@ #include #include #include -#include #include "private.h" @@ -802,7 +801,7 @@ void shadow_prealloc(struct domain *d, unsigned int order) v = current; if ( v->domain != d ) v = d->vcpu[0]; - ASSERT(v != NULL); + ASSERT(v != NULL); /* Shouldn't have enabled shadows if we've no vcpus */ /* Stage one: walk the list of pinned pages, unpinning them */ perfc_incrc(shadow_prealloc_1); @@ -861,7 +860,9 @@ static void shadow_blow_tables(struct domain *d) struct vcpu *v = d->vcpu[0]; mfn_t smfn; int i; - + + ASSERT(v != NULL); + /* Pass one: unpin all pinned pages */ list_for_each_backwards_safe(l,t, &d->arch.paging.shadow.pinned_shadows) { @@ -1129,6 +1130,7 @@ shadow_free_p2m_page(struct domain *d, struct page_info *pg) SHADOW_ERROR("Odd p2m page count c=%#x t=%"PRtype_info"\n", pg->count_info, pg->u.inuse.type_info); } + pg->count_info = 0; /* Free should not decrement domain's total allocation, since * these pages were allocated without an owner. */ page_set_owner(pg, NULL); @@ -1243,6 +1245,9 @@ static unsigned int sh_set_allocation(struct domain *d, list_del(&sp->list); d->arch.paging.shadow.free_pages -= 1<arch.paging.shadow.total_pages -= 1<arch.paging.shadow.dirty_bitmap == NULL); d->arch.paging.shadow.dirty_bitmap_size = - (arch_get_max_pfn(d) + (BITS_PER_LONG - 1)) & + (domain_get_maximum_gpfn(d) + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1); d->arch.paging.shadow.dirty_bitmap = xmalloc_array(unsigned long, @@ -2676,7 +2681,8 @@ sh_alloc_log_dirty_bitmap(struct domain *d) d->arch.paging.shadow.dirty_bitmap_size = 0; return -ENOMEM; } - memset(d->arch.paging.shadow.dirty_bitmap, 0, d->arch.paging.shadow.dirty_bitmap_size/8); + memset(d->arch.paging.shadow.dirty_bitmap, 0, + d->arch.paging.shadow.dirty_bitmap_size/8); return 0; } @@ -2807,7 +2813,11 @@ shadow_write_p2m_entry(struct vcpu *v, unsigned long gfn, l1_pgentry_t *p, This is pretty heavy handed, but this is a rare operation (it might happen a dozen times during boot and then never again), so it doesn't matter too much. */ - shadow_blow_tables(d); + if ( d->arch.paging.shadow.has_fast_mmio_entries ) + { + shadow_blow_tables(d); + d->arch.paging.shadow.has_fast_mmio_entries = 0; + } #endif shadow_unlock(d); @@ -2989,6 +2999,13 @@ int shadow_domctl(struct domain *d, return 0; } + if ( unlikely(d->vcpu[0] == NULL) ) + { + SHADOW_ERROR("Shadow op on a domain (%u) with no vcpus\n", + d->domain_id); + return -EINVAL; + } + switch ( sc->op ) { case XEN_DOMCTL_SHADOW_OP_OFF: diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index 581ab45196..108c2e692d 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -660,6 +660,8 @@ _sh_propagate(struct vcpu *v, { /* Guest l1e maps MMIO space */ *sp = sh_l1e_mmio(guest_l1e_get_gfn(*gp), gflags); + if ( !d->arch.paging.shadow.has_fast_mmio_entries ) + d->arch.paging.shadow.has_fast_mmio_entries = 1; goto done; } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 61271bbee3..446c42f3d9 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -195,13 +195,13 @@ static void __init percpu_free_unused_areas(void) /* Find first unused CPU number. */ for ( i = 0; i < NR_CPUS; i++ ) - if ( !cpu_online(i) ) + if ( !cpu_possible(i) ) break; first_unused = i; - /* Check that there are no holes in cpu_online_map. */ + /* Check that there are no holes in cpu_possible_map. */ for ( ; i < NR_CPUS; i++ ) - BUG_ON(cpu_online(i)); + BUG_ON(cpu_possible(i)); #ifndef MEMORY_GUARD init_xenheap_pages(__pa(__per_cpu_start) + (first_unused << PERCPU_SHIFT), @@ -717,8 +717,6 @@ void __init __start_xen(multiboot_info_t *mbi) do_initcalls(); - schedulers_start(); - if ( opt_watchdog ) watchdog_enable(); diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index f6054857f4..2423ad5493 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -905,6 +905,10 @@ static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs) struct vcpu *v = current; struct domain *d = v->domain; + /* No fixups in interrupt context or when interrupts are disabled. */ + if ( in_irq() || !(regs->eflags & X86_EFLAGS_IF) ) + return 0; + if ( unlikely(IN_HYPERVISOR_RANGE(addr)) ) { if ( paging_mode_external(d) && guest_mode(regs) ) @@ -915,9 +919,6 @@ static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs) return 0; } - ASSERT(!in_irq()); - ASSERT(regs->eflags & X86_EFLAGS_IF); - if ( VM_ASSIST(d, VMASST_TYPE_writable_pagetables) && guest_kernel_mode(v, regs) && /* Do not check if access-protection fault since the page may diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c index 001a781235..93a047db3a 100644 --- a/xen/arch/x86/x86_64/asm-offsets.c +++ b/xen/arch/x86/x86_64/asm-offsets.c @@ -59,6 +59,7 @@ void __dummy__(void) OFFSET(VCPU_domain, struct vcpu, domain); OFFSET(VCPU_vcpu_info, struct vcpu, vcpu_info); OFFSET(VCPU_trap_bounce, struct vcpu, arch.trap_bounce); + OFFSET(VCPU_int80_bounce, struct vcpu, arch.int80_bounce); OFFSET(VCPU_thread_flags, struct vcpu, arch.flags); OFFSET(VCPU_event_addr, struct vcpu, arch.guest_context.event_callback_eip); diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S index 3f1d1b8d07..095bd61f73 100644 --- a/xen/arch/x86/x86_64/compat/entry.S +++ b/xen/arch/x86/x86_64/compat/entry.S @@ -187,6 +187,10 @@ ENTRY(compat_post_handle_exception) call compat_create_bounce_frame jmp compat_test_all_events +ENTRY(compat_int80_direct_trap) + call compat_create_bounce_frame + jmp compat_restore_all_guest + /* CREATE A BASIC EXCEPTION FRAME ON GUEST OS (RING-1) STACK: */ /* {[ERRCODE,] EIP, CS, EFLAGS, [ESP, SS]} */ /* %rdx: trap_bounce, %rbx: struct vcpu */ diff --git a/xen/arch/x86/x86_64/compat/traps.c b/xen/arch/x86/x86_64/compat/traps.c index a7f24cecf8..0172e846c4 100644 --- a/xen/arch/x86/x86_64/compat/traps.c +++ b/xen/arch/x86/x86_64/compat/traps.c @@ -1,6 +1,7 @@ #ifdef CONFIG_COMPAT #include +#include #include #include @@ -291,6 +292,9 @@ int compat_set_trap_table(XEN_GUEST_HANDLE(trap_info_compat_t) traps) XLAT_trap_info(dst + cur.vector, &cur); + if ( cur.vector == 0x80 ) + init_int80_direct_trap(current); + guest_handle_add_offset(traps, 1); } diff --git a/xen/arch/x86/x86_64/compat_kexec.S b/xen/arch/x86/x86_64/compat_kexec.S index c06db6fc7e..cc6f3d6fce 100644 --- a/xen/arch/x86/x86_64/compat_kexec.S +++ b/xen/arch/x86/x86_64/compat_kexec.S @@ -103,13 +103,13 @@ compat_page_list: /* * These compat page tables contain an identity mapping of the - * first 1G of the physical address space. + * first 4G of the physical address space. */ compat_pg_table: .long compat_pg_table_l2 + 0*PAGE_SIZE + 0x01 - __PAGE_OFFSET, 0 - .long 0, 0 - .long 0, 0 - .long 0, 0 + .long compat_pg_table_l2 + 1*PAGE_SIZE + 0x01 - __PAGE_OFFSET, 0 + .long compat_pg_table_l2 + 2*PAGE_SIZE + 0x01 - __PAGE_OFFSET, 0 + .long compat_pg_table_l2 + 3*PAGE_SIZE + 0x01 - __PAGE_OFFSET, 0 .align 4096,0 @@ -123,4 +123,7 @@ compat_pg_table_l2: .endif .endm - identmap + identmap 0x00000000 + identmap 0x40000000 + identmap 0x80000000 + identmap 0xc0000000 diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index cffd89dced..17311c7242 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -222,6 +222,35 @@ bad_hypercall: movq $-ENOSYS,UREGS_rax(%rsp) jmp test_all_events +ENTRY(int80_direct_trap) + pushq $0 + SAVE_ALL + + GET_CURRENT(%rbx) + + /* Check that the callback is non-null. */ + leaq VCPU_int80_bounce(%rbx),%rdx + cmp $0, TRAPBOUNCE_flags(%rdx) + jz int80_slow_path + + movq VCPU_domain(%rbx),%rax + btl $_DOMF_compat,DOMAIN_domain_flags(%rax) + jc compat_int80_direct_trap + + call create_bounce_frame + jmp restore_all_guest + +int80_slow_path: + /* + * Setup entry vector and error code as if this was a GPF caused by an + * IDT entry with DPL==0. + */ + movl $((0x80 << 3) | 0x2),UREGS_error_code(%rsp) + movl $TRAP_gp_fault,UREGS_entry_vector(%rsp) + /* A GPF wouldn't have incremented the instruction pointer. */ + sub $2,UREGS_rip(%rsp) + jmp handle_exception_saved + /* CREATE A BASIC EXCEPTION FRAME ON GUEST OS STACK: */ /* { RCX, R11, [DS-GS,] [CR2,] [ERRCODE,] RIP, CS, RFLAGS, RSP, SS } */ /* %rdx: trap_bounce, %rbx: struct vcpu */ @@ -359,6 +388,7 @@ ENTRY(ret_from_intr) /* No special register assumptions. */ ENTRY(handle_exception) SAVE_ALL +handle_exception_saved: testb $X86_EFLAGS_IF>>8,UREGS_eflags+1(%rsp) jz exception_with_ints_disabled sti diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c index 0c6ee1de35..7a255c291f 100644 --- a/xen/arch/x86/x86_64/traps.c +++ b/xen/arch/x86/x86_64/traps.c @@ -247,6 +247,7 @@ unsigned long do_iret(void) asmlinkage void syscall_enter(void); asmlinkage void compat_hypercall(void); +asmlinkage void int80_direct_trap(void); void __init percpu_traps_init(void) { char *stack_bottom, *stack; @@ -262,6 +263,7 @@ void __init percpu_traps_init(void) #ifdef CONFIG_COMPAT /* The hypercall entry vector is only accessible from ring 1. */ _set_gate(idt_table+HYPERCALL_VECTOR, 15, 1, &compat_hypercall); + _set_gate(idt_table+0x80, 15, 3, &int80_direct_trap); #endif } @@ -346,6 +348,22 @@ void __init percpu_traps_init(void) wrmsr(MSR_SYSCALL_MASK, EF_VM|EF_RF|EF_NT|EF_DF|EF_IE|EF_TF, 0U); } +void init_int80_direct_trap(struct vcpu *v) +{ + struct trap_info *ti = &v->arch.guest_context.trap_ctxt[0x80]; + struct trap_bounce *tb = &v->arch.int80_bounce; + + if ( !guest_gate_selector_okay(v->domain, ti->cs) ) + return; + + tb->flags = TBF_EXCEPTION; + tb->cs = ti->cs; + tb->eip = ti->address; + + if ( null_trap_bounce(v, tb) ) + tb->flags = 0; +} + static long register_guest_callback(struct callback_register *reg) { long ret = 0; diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index ac209cb61d..aecb36cf78 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -726,7 +726,7 @@ x86_emulate( uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0; unsigned int op_bytes, def_op_bytes, ad_bytes, def_ad_bytes; unsigned int lock_prefix = 0, rep_prefix = 0; - int rc = X86EMUL_OKAY; + int override_seg = -1, rc = X86EMUL_OKAY; struct operand src, dst; /* Data operand effective address (usually computed from ModRM). */ @@ -758,22 +758,22 @@ x86_emulate( ad_bytes = def_ad_bytes ^ (mode_64bit() ? 12 : 6); break; case 0x2e: /* CS override */ - ea.mem.seg = x86_seg_cs; + override_seg = x86_seg_cs; break; case 0x3e: /* DS override */ - ea.mem.seg = x86_seg_ds; + override_seg = x86_seg_ds; break; case 0x26: /* ES override */ - ea.mem.seg = x86_seg_es; + override_seg = x86_seg_es; break; case 0x64: /* FS override */ - ea.mem.seg = x86_seg_fs; + override_seg = x86_seg_fs; break; case 0x65: /* GS override */ - ea.mem.seg = x86_seg_gs; + override_seg = x86_seg_gs; break; case 0x36: /* SS override */ - ea.mem.seg = x86_seg_ss; + override_seg = x86_seg_ss; break; case 0xf0: /* LOCK */ lock_prefix = 1; @@ -839,14 +839,35 @@ x86_emulate( /* 16-bit ModR/M decode. */ switch ( modrm_rm ) { - case 0: ea.mem.off = _regs.ebx + _regs.esi; break; - case 1: ea.mem.off = _regs.ebx + _regs.edi; break; - case 2: ea.mem.off = _regs.ebp + _regs.esi; break; - case 3: ea.mem.off = _regs.ebp + _regs.edi; break; - case 4: ea.mem.off = _regs.esi; break; - case 5: ea.mem.off = _regs.edi; break; - case 6: ea.mem.off = _regs.ebp; break; - case 7: ea.mem.off = _regs.ebx; break; + case 0: + ea.mem.off = _regs.ebx + _regs.esi; + break; + case 1: + ea.mem.off = _regs.ebx + _regs.edi; + break; + case 2: + ea.mem.seg = x86_seg_ss; + ea.mem.off = _regs.ebp + _regs.esi; + break; + case 3: + ea.mem.seg = x86_seg_ss; + ea.mem.off = _regs.ebp + _regs.edi; + break; + case 4: + ea.mem.off = _regs.esi; + break; + case 5: + ea.mem.off = _regs.edi; + break; + case 6: + if ( modrm_mod == 0 ) + break; + ea.mem.seg = x86_seg_ss; + ea.mem.off = _regs.ebp; + break; + case 7: + ea.mem.off = _regs.ebx; + break; } switch ( modrm_mod ) { @@ -876,10 +897,20 @@ x86_emulate( ea.mem.off <<= (sib >> 6) & 3; if ( (modrm_mod == 0) && ((sib_base & 7) == 5) ) ea.mem.off += insn_fetch_type(int32_t); - else if ( (sib_base == 4) && !twobyte && (b == 0x8f) ) - /* POP must have its EA calculated post increment. */ - ea.mem.off += _regs.esp + - ((mode_64bit() && (op_bytes == 4)) ? 8 : op_bytes); + else if ( sib_base == 4 ) + { + ea.mem.seg = x86_seg_ss; + ea.mem.off += _regs.esp; + if ( !twobyte && (b == 0x8f) ) + /* POP computes its EA post increment. */ + ea.mem.off += ((mode_64bit() && (op_bytes == 4)) + ? 8 : op_bytes); + } + else if ( sib_base == 5 ) + { + ea.mem.seg = x86_seg_ss; + ea.mem.off += _regs.ebp; + } else ea.mem.off += *(long*)decode_register(sib_base, &_regs, 0); } @@ -887,6 +918,8 @@ x86_emulate( { modrm_rm |= (rex_prefix & 1) << 3; ea.mem.off = *(long *)decode_register(modrm_rm, &_regs, 0); + if ( (modrm_rm == 5) && (modrm_mod != 0) ) + ea.mem.seg = x86_seg_ss; } switch ( modrm_mod ) { @@ -920,6 +953,9 @@ x86_emulate( } } + if ( override_seg != -1 ) + ea.mem.seg = override_seg; + /* Special instructions do their own operand decoding. */ if ( (d & DstMask) == ImplicitOps ) goto special_insn; diff --git a/xen/common/compat/domain.c b/xen/common/compat/domain.c index 3f54260316..12929122f6 100644 --- a/xen/common/compat/domain.c +++ b/xen/common/compat/domain.c @@ -55,6 +55,10 @@ int compat_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg) case VCPUOP_up: case VCPUOP_down: case VCPUOP_is_up: + case VCPUOP_set_periodic_timer: + case VCPUOP_stop_periodic_timer: + case VCPUOP_set_singleshot_timer: + case VCPUOP_stop_singleshot_timer: rc = do_vcpu_op(cmd, vcpuid, arg); break; diff --git a/xen/common/compat/memory.c b/xen/common/compat/memory.c index 1301e42f04..53628d7a35 100644 --- a/xen/common/compat/memory.c +++ b/xen/common/compat/memory.c @@ -170,6 +170,7 @@ int compat_memory_op(unsigned int cmd, XEN_GUEST_HANDLE(void) compat) case XENMEM_current_reservation: case XENMEM_maximum_reservation: + case XENMEM_maximum_gpfn: { #define xen_domid_t domid_t #define compat_domid_t domid_compat_t @@ -325,6 +326,7 @@ int compat_memory_op(unsigned int cmd, XEN_GUEST_HANDLE(void) compat) case XENMEM_maximum_ram_page: case XENMEM_current_reservation: case XENMEM_maximum_reservation: + case XENMEM_maximum_gpfn: break; case XENMEM_translate_gpfn_list: diff --git a/xen/common/domain.c b/xen/common/domain.c index c1a1dc2b4e..3008a4cc90 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -102,7 +102,7 @@ struct vcpu *alloc_vcpu( v->runstate.state = is_idle_vcpu(v) ? RUNSTATE_running : RUNSTATE_offline; v->runstate.state_entry_time = NOW(); - if ( (vcpu_id != 0) && !is_idle_domain(d) ) + if ( !is_idle_domain(d) ) set_bit(_VCPUF_down, &v->vcpu_flags); if ( sched_init_vcpu(v, cpu_id) != 0 ) @@ -267,6 +267,9 @@ void domain_kill(struct domain *d) domain_relinquish_resources(d); put_domain(d); + /* Kick page scrubbing after domain_relinquish_resources(). */ + page_scrub_kick(); + send_guest_global_virq(dom0, VIRQ_DOM_EXC); } @@ -543,16 +546,12 @@ long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg) { case VCPUOP_initialise: if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL ) - { - rc = -ENOMEM; - break; - } + return -ENOMEM; if ( copy_from_guest(ctxt, arg, 1) ) { xfree(ctxt); - rc = -EFAULT; - break; + return -EFAULT; } LOCK_BIGLOCK(d); @@ -566,9 +565,11 @@ long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg) case VCPUOP_up: if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) ) - rc = -EINVAL; - else if ( test_and_clear_bit(_VCPUF_down, &v->vcpu_flags) ) + return -EINVAL; + + if ( test_and_clear_bit(_VCPUF_down, &v->vcpu_flags) ) vcpu_wake(v); + break; case VCPUOP_down: @@ -589,6 +590,63 @@ long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg) break; } + case VCPUOP_set_periodic_timer: + { + struct vcpu_set_periodic_timer set; + + if ( copy_from_guest(&set, arg, 1) ) + return -EFAULT; + + if ( set.period_ns < MILLISECS(1) ) + return -EINVAL; + + v->periodic_period = set.period_ns; + vcpu_force_reschedule(v); + + break; + } + + case VCPUOP_stop_periodic_timer: + { + v->periodic_period = 0; + vcpu_force_reschedule(v); + break; + } + + case VCPUOP_set_singleshot_timer: + { + struct vcpu_set_singleshot_timer set; + + if ( v != current ) + return -EINVAL; + + if ( copy_from_guest(&set, arg, 1) ) + return -EFAULT; + + if ( (set.flags & VCPU_SSHOTTMR_future) && + (set.timeout_abs_ns < NOW()) ) + return -ETIME; + + if ( v->singleshot_timer.cpu != smp_processor_id() ) + { + stop_timer(&v->singleshot_timer); + v->singleshot_timer.cpu = smp_processor_id(); + } + + set_timer(&v->singleshot_timer, set.timeout_abs_ns); + + break; + } + + case VCPUOP_stop_singleshot_timer: + { + if ( v != current ) + return -EINVAL; + + stop_timer(&v->singleshot_timer); + break; + } + default: rc = arch_do_vcpu_op(cmd, v, arg); break; diff --git a/xen/common/domctl.c b/xen/common/domctl.c index 3a45586d65..6f2f351895 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -268,18 +268,14 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) case XEN_DOMCTL_unpausedomain: { struct domain *d = rcu_lock_domain_by_id(op->domain); + ret = -ESRCH; - if ( d != NULL ) - { - ret = -EINVAL; - if ( (d != current->domain) && (d->vcpu[0] != NULL) && - test_bit(_VCPUF_initialised, &d->vcpu[0]->vcpu_flags) ) - { - domain_unpause_by_systemcontroller(d); - ret = 0; - } - rcu_unlock_domain(d); - } + if ( d == NULL ) + break; + + domain_unpause_by_systemcontroller(d); + rcu_unlock_domain(d); + ret = 0; } break; diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index 1af842a528..2ea6ff37eb 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -1392,8 +1392,7 @@ gnttab_release_mappings( { BUG_ON(!(act->pin & GNTPIN_hstr_mask)); act->pin -= GNTPIN_hstr_inc; - /* Done implicitly when page tables are destroyed. */ - /* put_page(mfn_to_page(act->frame)); */ + gnttab_release_put_page(mfn_to_page(act->frame)); } } else @@ -1409,8 +1408,7 @@ gnttab_release_mappings( { BUG_ON(!(act->pin & GNTPIN_hstw_mask)); act->pin -= GNTPIN_hstw_inc; - /* Done implicitly when page tables are destroyed. */ - /* put_page_and_type(mfn_to_page(act->frame)); */ + gnttab_release_put_page_and_type(mfn_to_page(act->frame)); } if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 ) diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index b99d396399..471642aec6 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -47,7 +47,7 @@ void handle_keypress(unsigned char key, struct cpu_user_regs *regs) { irq_keyhandler_t *h; - if ( key_table[key].flags & KEYHANDLER_IRQ_CALLBACK ) + if ( !in_irq() || (key_table[key].flags & KEYHANDLER_IRQ_CALLBACK) ) { console_start_log_everything(); if ( (h = key_table[key].u.irq_handler) != NULL ) @@ -135,12 +135,25 @@ static void cpuset_print(char *set, int size, cpumask_t mask) *set++ = '\0'; } +static void periodic_timer_print(char *str, int size, uint64_t period) +{ + if ( period == 0 ) + { + strlcpy(str, "No periodic timer", size); + return; + } + + snprintf(str, size, + "%u Hz periodic timer (period %u ms)", + 1000000000/(int)period, (int)period/1000000); +} + static void dump_domains(unsigned char key) { struct domain *d; struct vcpu *v; s_time_t now = NOW(); - char cpuset[100]; + char tmpstr[100]; printk("'%c' pressed -> dumping domain info (now=0x%X:%08X)\n", key, (u32)(now>>32), (u32)now); @@ -150,11 +163,11 @@ static void dump_domains(unsigned char key) for_each_domain ( d ) { printk("General information for domain %u:\n", d->domain_id); - cpuset_print(cpuset, sizeof(cpuset), d->domain_dirty_cpumask); + cpuset_print(tmpstr, sizeof(tmpstr), d->domain_dirty_cpumask); printk(" flags=%lx refcnt=%d nr_pages=%d xenheap_pages=%d " "dirty_cpus=%s\n", d->domain_flags, atomic_read(&d->refcnt), - d->tot_pages, d->xenheap_pages, cpuset); + d->tot_pages, d->xenheap_pages, tmpstr); printk(" handle=%02x%02x%02x%02x-%02x%02x-%02x%02x-" "%02x%02x-%02x%02x%02x%02x%02x%02x vm_assist=%08lx\n", d->handle[ 0], d->handle[ 1], d->handle[ 2], d->handle[ 3], @@ -179,18 +192,21 @@ static void dump_domains(unsigned char key) v->vcpu_flags, vcpu_info(v, evtchn_upcall_pending), vcpu_info(v, evtchn_upcall_mask)); - cpuset_print(cpuset, sizeof(cpuset), v->vcpu_dirty_cpumask); - printk("dirty_cpus=%s ", cpuset); - cpuset_print(cpuset, sizeof(cpuset), v->cpu_affinity); - printk("cpu_affinity=%s\n", cpuset); + cpuset_print(tmpstr, sizeof(tmpstr), v->vcpu_dirty_cpumask); + printk("dirty_cpus=%s ", tmpstr); + cpuset_print(tmpstr, sizeof(tmpstr), v->cpu_affinity); + printk("cpu_affinity=%s\n", tmpstr); arch_dump_vcpu_info(v); + periodic_timer_print(tmpstr, sizeof(tmpstr), v->periodic_period); + printk(" %s\n", tmpstr); printk(" Notifying guest (virq %d, port %d, stat %d/%d/%d)\n", VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG], test_bit(v->virq_to_evtchn[VIRQ_DEBUG], shared_info_addr(d, evtchn_pending)), test_bit(v->virq_to_evtchn[VIRQ_DEBUG], shared_info_addr(d, evtchn_mask)), - test_bit(v->virq_to_evtchn[VIRQ_DEBUG]/BITS_PER_GUEST_LONG(d), + test_bit(v->virq_to_evtchn[VIRQ_DEBUG] / + BITS_PER_GUEST_LONG(d), vcpu_info_addr(v, evtchn_pending_sel))); send_guest_vcpu_virq(v, VIRQ_DEBUG); } diff --git a/xen/common/memory.c b/xen/common/memory.c index f7e5efc0a5..edd2ebe8d5 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -584,6 +584,7 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) case XENMEM_current_reservation: case XENMEM_maximum_reservation: + case XENMEM_maximum_gpfn: if ( copy_from_guest(&domid, arg, 1) ) return -EFAULT; @@ -594,7 +595,19 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) else if ( (d = rcu_lock_domain_by_id(domid)) == NULL ) return -ESRCH; - rc = (op == XENMEM_current_reservation) ? d->tot_pages : d->max_pages; + switch ( op ) + { + case XENMEM_current_reservation: + rc = d->tot_pages; + break; + case XENMEM_maximum_reservation: + rc = d->max_pages; + break; + default: + ASSERT(op == XENMEM_maximum_gpfn); + rc = domain_get_maximum_gpfn(d); + break; + } if ( unlikely(domid != DOMID_SELF) ) rcu_unlock_domain(d); diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index dad5f071d9..2c01e73af4 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -970,6 +970,8 @@ __initcall(pagealloc_keyhandler_init); * PAGE SCRUBBING */ +static DEFINE_PER_CPU(struct timer, page_scrub_timer); + static void page_scrub_softirq(void) { struct list_head *ent; @@ -978,7 +980,7 @@ static void page_scrub_softirq(void) int i; s_time_t start = NOW(); - /* Aim to do 1ms of work (ten percent of a 10ms jiffy). */ + /* Aim to do 1ms of work every 10ms. */ do { spin_lock(&page_scrub_lock); @@ -1014,6 +1016,13 @@ static void page_scrub_softirq(void) free_heap_pages(pfn_dom_zone_type(page_to_mfn(pg)), pg, 0); } } while ( (NOW() - start) < MILLISECS(1) ); + + set_timer(&this_cpu(page_scrub_timer), NOW() + MILLISECS(10)); +} + +static void page_scrub_timer_fn(void *unused) +{ + page_scrub_schedule_work(); } unsigned long avail_scrub_pages(void) @@ -1049,6 +1058,10 @@ __initcall(register_heap_trigger); static __init int page_scrub_init(void) { + int cpu; + for_each_cpu ( cpu ) + init_timer(&per_cpu(page_scrub_timer, cpu), + page_scrub_timer_fn, NULL, cpu); open_softirq(PAGE_SCRUB_SOFTIRQ, page_scrub_softirq); return 0; } diff --git a/xen/common/perfc.c b/xen/common/perfc.c index d5bcd9b2e1..bbff5d7b5c 100644 --- a/xen/common/perfc.c +++ b/xen/common/perfc.c @@ -136,8 +136,8 @@ static xen_sysctl_perfc_desc_t perfc_d[NR_PERFCTRS]; static xen_sysctl_perfc_val_t *perfc_vals; static int perfc_nbr_vals; static int perfc_init = 0; -static int perfc_copy_info(XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t) desc, - XEN_GUEST_HANDLE(xen_sysctl_perfc_val_t) val) +static int perfc_copy_info(XEN_GUEST_HANDLE_64(xen_sysctl_perfc_desc_t) desc, + XEN_GUEST_HANDLE_64(xen_sysctl_perfc_val_t) val) { unsigned int i, j; unsigned int v = 0; @@ -217,29 +217,20 @@ static int perfc_copy_info(XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t) desc, int perfc_control(xen_sysctl_perfc_op_t *pc) { static DEFINE_SPINLOCK(lock); - XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t) desc; - XEN_GUEST_HANDLE(xen_sysctl_perfc_val_t) val; int rc; - /* - * 64 bit guest handles cannot be passed as parameters to - * functions so cast to a regular guest handle. - */ - desc = guest_handle_cast(pc->desc, xen_sysctl_perfc_desc_t); - val = guest_handle_cast(pc->val, xen_sysctl_perfc_val_t); - spin_lock(&lock); switch ( pc->cmd ) { case XEN_SYSCTL_PERFCOP_reset: - perfc_copy_info(desc, val); + perfc_copy_info(pc->desc, pc->val); perfc_reset(0); rc = 0; break; case XEN_SYSCTL_PERFCOP_query: - perfc_copy_info(desc, val); + perfc_copy_info(pc->desc, pc->val); rc = 0; break; diff --git a/xen/common/sched_credit.c b/xen/common/sched_credit.c index 2ce83ace70..6bbbb7ae5b 100644 --- a/xen/common/sched_credit.c +++ b/xen/common/sched_credit.c @@ -186,6 +186,8 @@ struct csched_pcpu { struct list_head runq; uint32_t runq_sort_last; + struct timer ticker; + unsigned int tick; }; /* @@ -245,7 +247,7 @@ struct csched_private { */ static struct csched_private csched_priv; - +static void csched_tick(void *_cpu); static inline int __cycle_cpu(int cpu, const cpumask_t *mask) @@ -362,12 +364,13 @@ csched_pcpu_init(int cpu) if ( csched_priv.master >= csched_priv.ncpus ) csched_priv.master = cpu; + init_timer(&spc->ticker, csched_tick, (void *)(unsigned long)cpu, cpu); INIT_LIST_HEAD(&spc->runq); spc->runq_sort_last = csched_priv.runq_sort; per_cpu(schedule_data, cpu).sched_priv = spc; /* Start off idling... */ - BUG_ON( !is_idle_vcpu(per_cpu(schedule_data, cpu).curr) ); + BUG_ON(!is_idle_vcpu(per_cpu(schedule_data, cpu).curr)); cpu_set(cpu, csched_priv.idlers); spin_unlock_irqrestore(&csched_priv.lock, flags); @@ -1013,8 +1016,13 @@ csched_acct(void) } static void -csched_tick(unsigned int cpu) +csched_tick(void *_cpu) { + unsigned int cpu = (unsigned long)_cpu; + struct csched_pcpu *spc = CSCHED_PCPU(cpu); + + spc->tick++; + /* * Accounting for running VCPU */ @@ -1028,7 +1036,7 @@ csched_tick(unsigned int cpu) * we could distribute or at the very least cycle the duty. */ if ( (csched_priv.master == cpu) && - (per_cpu(schedule_data, cpu).tick % CSCHED_TICKS_PER_ACCT) == 0 ) + (spc->tick % CSCHED_TICKS_PER_ACCT) == 0 ) { csched_acct(); } @@ -1041,6 +1049,8 @@ csched_tick(unsigned int cpu) * once per accounting period (currently 30 milliseconds). */ csched_runq_sort(cpu); + + set_timer(&spc->ticker, NOW() + MILLISECS(CSCHED_MSECS_PER_TICK)); } static struct csched_vcpu * @@ -1248,8 +1258,7 @@ csched_dump_pcpu(int cpu) spc = CSCHED_PCPU(cpu); runq = &spc->runq; - printk(" tick=%lu, sort=%d, sibling=0x%lx, core=0x%lx\n", - per_cpu(schedule_data, cpu).tick, + printk(" sort=%d, sibling=0x%lx, core=0x%lx\n", spc->runq_sort_last, cpu_sibling_map[cpu].bits[0], cpu_core_map[cpu].bits[0]); @@ -1341,6 +1350,22 @@ csched_init(void) CSCHED_STATS_RESET(); } +/* Tickers cannot be kicked until SMP subsystem is alive. */ +static __init int csched_start_tickers(void) +{ + struct csched_pcpu *spc; + unsigned int cpu; + + for_each_online_cpu ( cpu ) + { + spc = CSCHED_PCPU(cpu); + set_timer(&spc->ticker, NOW() + MILLISECS(CSCHED_MSECS_PER_TICK)); + } + + return 0; +} +__initcall(csched_start_tickers); + struct scheduler sched_credit_def = { .name = "SMP Credit Scheduler", @@ -1359,7 +1384,6 @@ struct scheduler sched_credit_def = { .adjust = csched_dom_cntl, .pick_cpu = csched_cpu_pick, - .tick = csched_tick, .do_schedule = csched_schedule, .dump_cpu_state = csched_dump_pcpu, diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 8ba192d0ac..f78319e381 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -45,8 +45,8 @@ boolean_param("dom0_vcpus_pin", opt_dom0_vcpus_pin); /* Various timer handlers. */ static void s_timer_fn(void *unused); -static void t_timer_fn(void *unused); -static void vcpu_timer_fn(void *data); +static void vcpu_periodic_timer_fn(void *data); +static void vcpu_singleshot_timer_fn(void *data); static void poll_timer_fn(void *data); /* This is global for now so that private implementations can reach it */ @@ -66,9 +66,6 @@ static struct scheduler ops; (( ops.fn != NULL ) ? ops.fn( __VA_ARGS__ ) \ : (typeof(ops.fn(__VA_ARGS__)))0 ) -/* Per-CPU periodic timer sends an event to the currently-executing domain. */ -static DEFINE_PER_CPU(struct timer, t_timer); - static inline void vcpu_runstate_change( struct vcpu *v, int new_state, s_time_t new_entry_time) { @@ -113,9 +110,13 @@ int sched_init_vcpu(struct vcpu *v, unsigned int processor) else cpus_setall(v->cpu_affinity); - /* Initialise the per-domain timers. */ - init_timer(&v->timer, vcpu_timer_fn, v, v->processor); - init_timer(&v->poll_timer, poll_timer_fn, v, v->processor); + /* Initialise the per-vcpu timers. */ + init_timer(&v->periodic_timer, vcpu_periodic_timer_fn, + v, v->processor); + init_timer(&v->singleshot_timer, vcpu_singleshot_timer_fn, + v, v->processor); + init_timer(&v->poll_timer, poll_timer_fn, + v, v->processor); /* Idle VCPUs are scheduled immediately. */ if ( is_idle_domain(d) ) @@ -132,7 +133,8 @@ int sched_init_vcpu(struct vcpu *v, unsigned int processor) void sched_destroy_vcpu(struct vcpu *v) { - kill_timer(&v->timer); + kill_timer(&v->periodic_timer); + kill_timer(&v->singleshot_timer); kill_timer(&v->poll_timer); SCHED_OP(destroy_vcpu, v); } @@ -223,10 +225,29 @@ static void vcpu_migrate(struct vcpu *v) vcpu_wake(v); } +/* + * Force a VCPU through a deschedule/reschedule path. + * For example, using this when setting the periodic timer period means that + * most periodic-timer state need only be touched from within the scheduler + * which can thus be done without need for synchronisation. + */ +void vcpu_force_reschedule(struct vcpu *v) +{ + vcpu_schedule_lock_irq(v); + if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) + set_bit(_VCPUF_migrating, &v->vcpu_flags); + vcpu_schedule_unlock_irq(v); + + if ( test_bit(_VCPUF_migrating, &v->vcpu_flags) ) + { + vcpu_sleep_nosync(v); + vcpu_migrate(v); + } +} + int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity) { cpumask_t online_affinity; - unsigned long flags; if ( (v->domain->domain_id == 0) && opt_dom0_vcpus_pin ) return -EINVAL; @@ -235,13 +256,13 @@ int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity) if ( cpus_empty(online_affinity) ) return -EINVAL; - vcpu_schedule_lock_irqsave(v, flags); + vcpu_schedule_lock_irq(v); v->cpu_affinity = *affinity; if ( !cpu_isset(v->processor, v->cpu_affinity) ) set_bit(_VCPUF_migrating, &v->vcpu_flags); - vcpu_schedule_unlock_irqrestore(v, flags); + vcpu_schedule_unlock_irq(v); if ( test_bit(_VCPUF_migrating, &v->vcpu_flags) ) { @@ -450,7 +471,7 @@ ret_t do_sched_op(int cmd, XEN_GUEST_HANDLE(void) arg) #ifndef COMPAT -/* Per-domain one-shot-timer hypercall. */ +/* Per-vcpu oneshot-timer hypercall. */ long do_set_timer_op(s_time_t timeout) { struct vcpu *v = current; @@ -458,7 +479,7 @@ long do_set_timer_op(s_time_t timeout) if ( timeout == 0 ) { - stop_timer(&v->timer); + stop_timer(&v->singleshot_timer); } else if ( unlikely(timeout < 0) || /* overflow into 64th bit? */ unlikely((offset > 0) && ((uint32_t)(offset >> 50) != 0)) ) @@ -474,14 +495,20 @@ long do_set_timer_op(s_time_t timeout) * timeout in this case can burn a lot of CPU. We therefore go for a * reasonable middleground of triggering a timer event in 100ms. */ - gdprintk(XENLOG_INFO, "Warning: huge timeout set by domain %d (vcpu %d):" - " %"PRIx64"\n", + gdprintk(XENLOG_INFO, "Warning: huge timeout set by domain %d " + "(vcpu %d): %"PRIx64"\n", v->domain->domain_id, v->vcpu_id, (uint64_t)timeout); - set_timer(&v->timer, NOW() + MILLISECS(100)); + set_timer(&v->singleshot_timer, NOW() + MILLISECS(100)); } else { - set_timer(&v->timer, timeout); + if ( v->singleshot_timer.cpu != smp_processor_id() ) + { + stop_timer(&v->singleshot_timer); + v->singleshot_timer.cpu = smp_processor_id(); + } + + set_timer(&v->singleshot_timer, timeout); } return 0; @@ -540,6 +567,28 @@ long sched_adjust(struct domain *d, struct xen_domctl_scheduler_op *op) return 0; } +static void vcpu_periodic_timer_work(struct vcpu *v) +{ + s_time_t now = NOW(); + uint64_t periodic_next_event; + + ASSERT(!active_timer(&v->periodic_timer)); + + if ( v->periodic_period == 0 ) + return; + + periodic_next_event = v->periodic_last_event + v->periodic_period; + if ( now > periodic_next_event ) + { + send_timer_event(v); + v->periodic_last_event = now; + periodic_next_event = now + v->periodic_period; + } + + v->periodic_timer.cpu = smp_processor_id(); + set_timer(&v->periodic_timer, periodic_next_event); +} + /* * The main function * - deschedule the current domain (scheduler independent). @@ -606,14 +655,13 @@ static void schedule(void) perfc_incrc(sched_ctx); - prev->sleep_tick = sd->tick; + stop_timer(&prev->periodic_timer); /* Ensure that the domain has an up-to-date time base. */ if ( !is_idle_vcpu(next) ) { update_vcpu_system_time(next); - if ( next->sleep_tick != sd->tick ) - send_timer_event(next); + vcpu_periodic_timer_work(next); } TRACE_4D(TRC_SCHED_SWITCH, @@ -631,13 +679,6 @@ void context_saved(struct vcpu *prev) vcpu_migrate(prev); } -/**************************************************************************** - * Timers: the scheduler utilises a number of timers - * - s_timer: per CPU timer for preemption and scheduling decisions - * - t_timer: per CPU periodic timer to send timer interrupt to current dom - * - dom_timer: per domain timer to specifiy timeout values - ****************************************************************************/ - /* The scheduler timer: force a run through the scheduler */ static void s_timer_fn(void *unused) { @@ -645,28 +686,15 @@ static void s_timer_fn(void *unused) perfc_incrc(sched_irq); } -/* Periodic tick timer: send timer event to current domain */ -static void t_timer_fn(void *unused) +/* Per-VCPU periodic timer function: sends a virtual timer interrupt. */ +static void vcpu_periodic_timer_fn(void *data) { - struct vcpu *v = current; - - this_cpu(schedule_data).tick++; - - if ( !is_idle_vcpu(v) ) - { - update_vcpu_system_time(v); - send_timer_event(v); - } - - page_scrub_schedule_work(); - - SCHED_OP(tick, smp_processor_id()); - - set_timer(&this_cpu(t_timer), NOW() + MILLISECS(10)); + struct vcpu *v = data; + vcpu_periodic_timer_work(v); } -/* Per-VCPU timer function: sends a virtual timer interrupt. */ -static void vcpu_timer_fn(void *data) +/* Per-VCPU single-shot timer function: sends a virtual timer interrupt. */ +static void vcpu_singleshot_timer_fn(void *data) { struct vcpu *v = data; send_timer_event(v); @@ -691,7 +719,6 @@ void __init scheduler_init(void) { spin_lock_init(&per_cpu(schedule_data, i).schedule_lock); init_timer(&per_cpu(schedule_data, i).s_timer, s_timer_fn, NULL, i); - init_timer(&per_cpu(t_timer, i), t_timer_fn, NULL, i); } for ( i = 0; schedulers[i] != NULL; i++ ) @@ -708,16 +735,6 @@ void __init scheduler_init(void) SCHED_OP(init); } -/* - * Start a scheduler for each CPU - * This has to be done *after* the timers, e.g., APICs, have been initialised - */ -void schedulers_start(void) -{ - t_timer_fn(0); - smp_call_function((void *)t_timer_fn, NULL, 1, 1); -} - void dump_runq(unsigned char key) { s_time_t now = NOW(); diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index 789e643ff2..0cba2c1164 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -121,6 +122,20 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl) break; #endif + case XEN_SYSCTL_debug_keys: + { + char c; + uint32_t i; + + for ( i = 0; i < op->u.debug_keys.nr_keys; i++ ) + { + if ( copy_from_guest_offset(&c, op->u.debug_keys.keys, i, 1) ) + return -EFAULT; + handle_keypress(c, guest_cpu_user_regs()); + } + } + break; + default: ret = arch_do_sysctl(op, u_sysctl); break; diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index 927b47112f..ef11d735ba 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -48,6 +48,10 @@ string_param("conswitch", opt_conswitch); static int opt_sync_console; boolean_param("sync_console", opt_sync_console); +/* console_to_ring: send guest (incl. dom 0) console data to console ring. */ +static int opt_console_to_ring; +boolean_param("console_to_ring", opt_console_to_ring); + #define CONRING_SIZE 16384 #define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1)) static char conring[CONRING_SIZE]; @@ -329,7 +333,14 @@ static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count) sercon_puts(kbuf); for ( kptr = kbuf; *kptr != '\0'; kptr++ ) + { vga_putchar(*kptr); + if ( opt_console_to_ring ) + putchar_console_ring(*kptr); + } + + if ( opt_console_to_ring ) + send_guest_global_virq(dom0, VIRQ_CON_RING); guest_handle_add_offset(buffer, kcount); count -= kcount; diff --git a/xen/include/asm-ia64/grant_table.h b/xen/include/asm-ia64/grant_table.h index 45d7dac7e9..f10d92e419 100644 --- a/xen/include/asm-ia64/grant_table.h +++ b/xen/include/asm-ia64/grant_table.h @@ -64,4 +64,7 @@ static inline void gnttab_clear_flag(unsigned long nr, uint16_t *addr) clear_bit(nr, addr); } +#define gnttab_release_put_page(page) put_page((page)) +#define gnttab_release_put_page_and_type(page) put_page_and_type((page)) + #endif /* __ASM_GRANT_TABLE_H__ */ diff --git a/xen/include/asm-ia64/mm.h b/xen/include/asm-ia64/mm.h index fa0830d414..057f841c16 100644 --- a/xen/include/asm-ia64/mm.h +++ b/xen/include/asm-ia64/mm.h @@ -511,4 +511,6 @@ int steal_page( #define domain_clamp_alloc_bitsize(d, b) (b) +#define domain_get_maximum_gpfn(d) (-ENOSYS) + #endif /* __ASM_IA64_MM_H__ */ diff --git a/xen/include/asm-powerpc/grant_table.h b/xen/include/asm-powerpc/grant_table.h index 334a925cbb..e8ca87cbb4 100644 --- a/xen/include/asm-powerpc/grant_table.h +++ b/xen/include/asm-powerpc/grant_table.h @@ -69,4 +69,17 @@ static inline uint cpu_foreign_map_order(void) /* 16 GiB */ return 34 - PAGE_SHIFT; } + +#if 0 +/* + * without put_page()/put_page_and_type() page might be leaked. + * with put_page()/put_page_and_type() freed page might be accessed. + */ +#define gnttab_release_put_page(page) put_page((page)) +#define gnttab_release_put_page_and_type(page) put_page_and_type((page)) +#else +#define gnttab_release_put_page(page) do { } while (0) +#define gnttab_release_put_page_and_type(page) do { } while (0) +#endif + #endif /* __ASM_PPC_GRANT_TABLE_H__ */ diff --git a/xen/include/asm-powerpc/mm.h b/xen/include/asm-powerpc/mm.h index e258d5eb1b..ed6a10c67b 100644 --- a/xen/include/asm-powerpc/mm.h +++ b/xen/include/asm-powerpc/mm.h @@ -278,4 +278,6 @@ extern int steal_page(struct domain *d, struct page_info *page, #define domain_clamp_alloc_bitsize(d, b) (b) +#define domain_get_maximum_gpfn(d) (-ENOSYS) + #endif diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index 94791f7a80..bdc2f16f12 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -79,6 +79,9 @@ struct shadow_domain { struct shadow_page_info **hash_table; int hash_walking; /* Some function is walking the hash table */ + /* Fast MMIO path heuristic */ + int has_fast_mmio_entries; + /* Shadow log-dirty bitmap */ unsigned long *dirty_bitmap; unsigned int dirty_bitmap_size; /* in pages, bit per page */ @@ -245,6 +248,9 @@ struct arch_vcpu #ifdef CONFIG_X86_32 struct desc_struct int80_desc; #endif +#ifdef CONFIG_X86_64 + struct trap_bounce int80_bounce; +#endif /* Virtual Machine Extensions */ struct hvm_vcpu hvm_vcpu; diff --git a/xen/include/asm-x86/grant_table.h b/xen/include/asm-x86/grant_table.h index 32dc43b898..f0c49bac3b 100644 --- a/xen/include/asm-x86/grant_table.h +++ b/xen/include/asm-x86/grant_table.h @@ -38,4 +38,14 @@ static inline void gnttab_clear_flag(unsigned long nr, uint16_t *addr) clear_bit(nr, addr); } +#define gnttab_release_put_page(page) \ + do { \ + /* Done implicitly when page tables are destroyed. */ \ + } while (0) + +#define gnttab_release_put_page_and_type(page) \ + do { \ + /* Done implicitly when page tables are destroyed. */ \ + } while (0) + #endif /* __ASM_GRANT_TABLE_H__ */ diff --git a/xen/include/asm-x86/hvm/svm/svm.h b/xen/include/asm-x86/hvm/svm/svm.h index b72eff2bc9..12459c72ef 100644 --- a/xen/include/asm-x86/hvm/svm/svm.h +++ b/xen/include/asm-x86/hvm/svm/svm.h @@ -29,8 +29,6 @@ #include extern void svm_dump_vmcb(const char *from, struct vmcb_struct *vmcb); -extern void svm_do_launch(struct vcpu *v); -extern void arch_svm_do_resume(struct vcpu *v); extern u64 root_vmcb_pa[NR_CPUS]; diff --git a/xen/include/asm-x86/hvm/svm/vmcb.h b/xen/include/asm-x86/hvm/svm/vmcb.h index 8551e8a479..efedf27ae9 100644 --- a/xen/include/asm-x86/hvm/svm/vmcb.h +++ b/xen/include/asm-x86/hvm/svm/vmcb.h @@ -447,7 +447,7 @@ struct arch_svm_struct { u32 *msrpm; u64 vmexit_tsc; /* tsc read at #VMEXIT. for TSC_OFFSET */ int saved_irq_vector; - u32 launch_core; + int launch_core; unsigned long flags; /* VMCB flags */ unsigned long cpu_shadow_cr0; /* Guest value for CR0 */ @@ -460,7 +460,6 @@ struct arch_svm_struct { struct vmcb_struct *alloc_vmcb(void); struct host_save_area *alloc_host_save_area(void); void free_vmcb(struct vmcb_struct *vmcb); -void free_host_save_area(struct host_save_area *hsa); int svm_create_vmcb(struct vcpu *v); void svm_destroy_vmcb(struct vcpu *v); diff --git a/xen/include/asm-x86/hvm/svm/vmmcall.h b/xen/include/asm-x86/hvm/svm/vmmcall.h deleted file mode 100644 index 7587bab7c6..0000000000 --- a/xen/include/asm-x86/hvm/svm/vmmcall.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * vmmcall.h: VMMCALL instruction support - * - * Travis Betak, travis.betak@amd.com - * Copyright (c) 2005, AMD Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - * - */ - -#ifndef __ASM_X86_HVM_SVM_VMMCALL_H__ -#define __ASM_X86_HVM_SVM_VMMCALL_H__ - -/* VMMCALL command fields */ -#define VMMCALL_CODE_CPL_MASK 0x60000000 -#define VMMCALL_CODE_MBZ_MASK 0x1FFF0000 -#define VMMCALL_CODE_COMMAND_MASK 0x0000FFFF - -#define MAKE_VMMCALL_CODE(cpl,func) ((cpl << 29) | (func) | 0x80000000) - -/* CPL=0 VMMCALL Requests */ -#define VMMCALL_RESET_TO_REALMODE MAKE_VMMCALL_CODE(0,1) - -/* CPL=3 VMMCALL Requests */ -#define VMMCALL_DEBUG MAKE_VMMCALL_CODE(3,1) - -/* return the cpl required for the vmmcall cmd */ -static inline int get_vmmcall_cpl(int cmd) -{ - return (cmd & VMMCALL_CODE_CPL_MASK) >> 29; -} - -#endif /* __ASM_X86_HVM_SVM_VMMCALL_H__ */ diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h index 02bc3fa05c..bda54adfc3 100644 --- a/xen/include/asm-x86/hvm/vpt.h +++ b/xen/include/asm-x86/hvm/vpt.h @@ -92,6 +92,7 @@ typedef struct RTCState { struct timer second_timer; struct timer second_timer2; struct periodic_time pt; + int32_t time_offset_seconds; } RTCState; #define FREQUENCE_PMTIMER 3579545 /* Timer should run at 3.579545 MHz */ diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index b240e4b5ca..225605efd4 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -404,5 +404,6 @@ unsigned int domain_clamp_alloc_bitsize(struct domain *d, unsigned int bits); # define domain_clamp_alloc_bitsize(d, b) (b) #endif +unsigned long domain_get_maximum_gpfn(struct domain *d); #endif /* __ASM_X86_MM_H__ */ diff --git a/xen/include/asm-x86/paging.h b/xen/include/asm-x86/paging.h index 249e206a5a..0a3b01ce85 100644 --- a/xen/include/asm-x86/paging.h +++ b/xen/include/asm-x86/paging.h @@ -273,7 +273,7 @@ static inline void paging_write_p2m_entry(struct domain *d, unsigned long gfn, struct vcpu *v = current; if ( v->domain != d ) v = d->vcpu[0]; - if ( likely(paging_mode_enabled(d) && v->arch.paging.mode != NULL) ) + if ( likely(v && paging_mode_enabled(d) && v->arch.paging.mode != NULL) ) { return v->arch.paging.mode->write_p2m_entry(v, gfn, p, new, level); } diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 321219c853..a878d86303 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -455,16 +455,16 @@ extern idt_entry_t *idt_tables[]; extern struct tss_struct init_tss[NR_CPUS]; -#ifdef CONFIG_X86_32 - extern void init_int80_direct_trap(struct vcpu *v); + +#if defined(CONFIG_X86_32) + #define set_int80_direct_trap(_ed) \ (memcpy(idt_tables[(_ed)->processor] + 0x80, \ &((_ed)->arch.int80_desc), 8)) #else -#define init_int80_direct_trap(_ed) ((void)0) #define set_int80_direct_trap(_ed) ((void)0) #endif diff --git a/xen/include/public/arch-x86/xen-x86_32.h b/xen/include/public/arch-x86/xen-x86_32.h index 2633ff082f..6728b818cd 100644 --- a/xen/include/public/arch-x86/xen-x86_32.h +++ b/xen/include/public/arch-x86/xen-x86_32.h @@ -103,7 +103,7 @@ (hnd).p = val; \ } while ( 0 ) #define uint64_aligned_t uint64_t __attribute__((aligned(8))) -#define XEN_GUEST_HANDLE_64(name) __guest_handle_64_ ## name __attribute__((aligned(8))) +#define XEN_GUEST_HANDLE_64(name) __guest_handle_64_ ## name #endif #ifndef __ASSEMBLY__ diff --git a/xen/include/public/arch-x86/xen.h b/xen/include/public/arch-x86/xen.h index f927130058..9fe0b76204 100644 --- a/xen/include/public/arch-x86/xen.h +++ b/xen/include/public/arch-x86/xen.h @@ -126,6 +126,8 @@ struct vcpu_guest_context { #define VGCF_failsafe_disables_events (1<<_VGCF_failsafe_disables_events) #define _VGCF_syscall_disables_events 4 #define VGCF_syscall_disables_events (1<<_VGCF_syscall_disables_events) +#define _VGCF_online 5 +#define VGCF_online (1<<_VGCF_online) unsigned long flags; /* VGCF_* flags */ struct cpu_user_regs user_regs; /* User-level CPU registers */ struct trap_info trap_ctxt[256]; /* Virtual IDT */ diff --git a/xen/include/public/foreign/Makefile b/xen/include/public/foreign/Makefile index 7bf028e72a..c107c5ab7f 100644 --- a/xen/include/public/foreign/Makefile +++ b/xen/include/public/foreign/Makefile @@ -18,7 +18,7 @@ check-headers: checker ./checker > $(XEN_TARGET_ARCH).size diff -u reference.size $(XEN_TARGET_ARCH).size checker: checker.c $(headers) - $(HOSTCC) $(CFLAGS) -o $@ $< + $(HOSTCC) $(HOSTCFLAGS) -o $@ $< else check-headers: @echo "cross build: skipping check" diff --git a/xen/include/public/foreign/structs.py b/xen/include/public/foreign/structs.py index 79eeab3b8e..6ecd1aa3dd 100644 --- a/xen/include/public/foreign/structs.py +++ b/xen/include/public/foreign/structs.py @@ -41,6 +41,8 @@ defines = [ "__i386__", "VGCF_failsafe_disables_events", "_VGCF_syscall_disables_events", "VGCF_syscall_disables_events", + "_VGCF_online", + "VGCF_online", # ia64 "VGCF_EXTRA_REGS", diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h index f568050949..f03ad288bb 100644 --- a/xen/include/public/hvm/hvm_op.h +++ b/xen/include/public/hvm/hvm_op.h @@ -70,4 +70,12 @@ struct xen_hvm_set_pci_link_route { typedef struct xen_hvm_set_pci_link_route xen_hvm_set_pci_link_route_t; DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_pci_link_route_t); +/* Drain all outstanding qemu-dm IO responses from a domain's ioreq ring. */ +#define HVMOP_drain_io 5 +struct xen_hvm_drain_io { + domid_t domid; +}; +typedef struct xen_hvm_drain_io xen_hvm_drain_io_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_drain_io_t); + #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index 97a6bbfea2..7b1ef44d32 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -128,6 +128,11 @@ DEFINE_XEN_GUEST_HANDLE(xen_memory_exchange_t); #define XENMEM_current_reservation 3 #define XENMEM_maximum_reservation 4 +/* + * Returns the maximum GPFN in use by the guest, or -ve errcode on failure. + */ +#define XENMEM_maximum_gpfn 14 + /* * Returns a list of MFN bases of 2MB extents comprising the machine_to_phys * mapping table. Architectures which do not have a m2p table do not implement diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index dcd7ee7d26..e18d7243f6 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -140,6 +140,18 @@ struct xen_sysctl_getdomaininfolist { typedef struct xen_sysctl_getdomaininfolist xen_sysctl_getdomaininfolist_t; DEFINE_XEN_GUEST_HANDLE(xen_sysctl_getdomaininfolist_t); +/* + * Inject debug keys into Xen. + */ +#define XEN_SYSCTL_debug_keys 7 +struct xen_sysctl_debug_keys { + /* IN variables. */ + XEN_GUEST_HANDLE_64(char) keys; + uint32_t nr_keys; +}; +typedef struct xen_sysctl_debug_keys xen_sysctl_debug_keys_t; +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_debug_keys_t); + struct xen_sysctl { uint32_t cmd; uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */ @@ -150,6 +162,7 @@ struct xen_sysctl { struct xen_sysctl_sched_id sched_id; struct xen_sysctl_perfc_op perfc_op; struct xen_sysctl_getdomaininfolist getdomaininfolist; + struct xen_sysctl_debug_keys debug_keys; uint8_t pad[128]; } u; }; diff --git a/xen/include/public/vcpu.h b/xen/include/public/vcpu.h index 12df6dbe15..7252d0b793 100644 --- a/xen/include/public/vcpu.h +++ b/xen/include/public/vcpu.h @@ -42,13 +42,13 @@ * @extra_arg == pointer to vcpu_guest_context structure containing initial * state for the VCPU. */ -#define VCPUOP_initialise 0 +#define VCPUOP_initialise 0 /* * Bring up a VCPU. This makes the VCPU runnable. This operation will fail * if the VCPU has not been initialised (VCPUOP_initialise). */ -#define VCPUOP_up 1 +#define VCPUOP_up 1 /* * Bring down a VCPU (i.e., make it non-runnable). @@ -64,16 +64,16 @@ * practise to move a VCPU onto an 'idle' or default page table, LDT and * GDT before bringing it down. */ -#define VCPUOP_down 2 +#define VCPUOP_down 2 /* Returns 1 if the given VCPU is up. */ -#define VCPUOP_is_up 3 +#define VCPUOP_is_up 3 /* * Return information about the state and running time of a VCPU. * @extra_arg == pointer to vcpu_runstate_info structure. */ -#define VCPUOP_get_runstate_info 4 +#define VCPUOP_get_runstate_info 4 struct vcpu_runstate_info { /* VCPU's current state (RUNSTATE_*). */ int state; @@ -128,6 +128,38 @@ struct vcpu_register_runstate_memory_area { } addr; }; typedef struct vcpu_register_runstate_memory_area vcpu_register_runstate_memory_area_t; +DEFINE_XEN_GUEST_HANDLE(vcpu_register_runstate_memory_area_t); + +/* + * Set or stop a VCPU's periodic timer. Every VCPU has one periodic timer + * which can be set via these commands. Periods smaller than one millisecond + * may not be supported. + */ +#define VCPUOP_set_periodic_timer 6 /* arg == vcpu_set_periodic_timer_t */ +#define VCPUOP_stop_periodic_timer 7 /* arg == NULL */ +struct vcpu_set_periodic_timer { + uint64_t period_ns; +}; +typedef struct vcpu_set_periodic_timer vcpu_set_periodic_timer_t; +DEFINE_XEN_GUEST_HANDLE(vcpu_set_periodic_timer_t); + +/* + * Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot + * timer which can be set via these commands. + */ +#define VCPUOP_set_singleshot_timer 8 /* arg == vcpu_set_singleshot_timer_t */ +#define VCPUOP_stop_singleshot_timer 9 /* arg == NULL */ +struct vcpu_set_singleshot_timer { + uint64_t timeout_abs_ns; /* Absolute system time value in nanoseconds. */ + uint32_t flags; /* VCPU_SSHOTTMR_??? */ +}; +typedef struct vcpu_set_singleshot_timer vcpu_set_singleshot_timer_t; +DEFINE_XEN_GUEST_HANDLE(vcpu_set_singleshot_timer_t); + +/* Flags to VCPUOP_set_singleshot_timer. */ + /* Require the timeout to be in the future (return -ETIME if it's passed). */ +#define _VCPU_SSHOTTMR_future (0) +#define VCPU_SSHOTTMR_future (1U << _VCPU_SSHOTTMR_future) #endif /* __XEN_PUBLIC_VCPU_H__ */ diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h index 8de9acaaab..a94d4efdb0 100644 --- a/xen/include/xen/mm.h +++ b/xen/include/xen/mm.h @@ -92,6 +92,11 @@ extern struct list_head page_scrub_list; if ( !list_empty(&page_scrub_list) ) \ raise_softirq(PAGE_SCRUB_SOFTIRQ); \ } while ( 0 ) +#define page_scrub_kick() \ + do { \ + if ( !list_empty(&page_scrub_list) ) \ + cpumask_raise_softirq(cpu_online_map, PAGE_SCRUB_SOFTIRQ); \ + } while ( 0 ) unsigned long avail_scrub_pages(void); #include diff --git a/xen/include/xen/sched-if.h b/xen/include/xen/sched-if.h index d506d7a589..f6ba9faa5c 100644 --- a/xen/include/xen/sched-if.h +++ b/xen/include/xen/sched-if.h @@ -16,7 +16,6 @@ struct schedule_data { struct vcpu *idle; /* idle task for this cpu */ void *sched_priv; struct timer s_timer; /* scheduling timer */ - unsigned long tick; /* current periodic 'tick' */ } __cacheline_aligned; DECLARE_PER_CPU(struct schedule_data, schedule_data); @@ -61,7 +60,6 @@ struct scheduler { unsigned int sched_id; /* ID for this scheduler */ void (*init) (void); - void (*tick) (unsigned int cpu); int (*init_domain) (struct domain *); void (*destroy_domain) (struct domain *); diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 0ab2874129..0653180fe7 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -79,8 +79,10 @@ struct vcpu struct vcpu *next_in_list; - struct timer timer; /* one-shot timer for timeout values */ - unsigned long sleep_tick; /* tick at which this vcpu started sleep */ + uint64_t periodic_period; + uint64_t periodic_last_event; + struct timer periodic_timer; + struct timer singleshot_timer; struct timer poll_timer; /* timeout for SCHEDOP_poll */ @@ -332,7 +334,6 @@ void __domain_crash_synchronous(void) __attribute__((noreturn)); #define set_current_state(_s) do { current->state = (_s); } while (0) void scheduler_init(void); -void schedulers_start(void); int sched_init_vcpu(struct vcpu *v, unsigned int processor); void sched_destroy_vcpu(struct vcpu *v); int sched_init_domain(struct domain *d); @@ -497,6 +498,7 @@ void domain_pause_by_systemcontroller(struct domain *d); void domain_unpause_by_systemcontroller(struct domain *d); void cpu_init(void); +void vcpu_force_reschedule(struct vcpu *v); int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity); void vcpu_runstate_get(struct vcpu *v, struct vcpu_runstate_info *runstate); diff --git a/xen/include/xen/timer.h b/xen/include/xen/timer.h index 495e81c4c3..4378f0f386 100644 --- a/xen/include/xen/timer.h +++ b/xen/include/xen/timer.h @@ -35,7 +35,7 @@ struct timer { * The timer must *previously* have been initialised by init_timer(), or its * structure initialised to all-zeroes. */ -static __inline__ int active_timer(struct timer *timer) +static inline int active_timer(struct timer *timer) { return (timer->heap_offset != 0); } @@ -46,7 +46,7 @@ static __inline__ int active_timer(struct timer *timer) * time (and multiple times) on an inactive timer. It must *never* execute * concurrently with any other operation on the same timer. */ -static __inline__ void init_timer( +static inline void init_timer( struct timer *timer, void (*function)(void *), void *data, diff --git a/xen/include/xen/trace.h b/xen/include/xen/trace.h index 4f3649a394..cd1422bc09 100644 --- a/xen/include/xen/trace.h +++ b/xen/include/xen/trace.h @@ -41,11 +41,11 @@ void trace(u32 event, unsigned long d1, unsigned long d2, do { \ if ( unlikely(tb_init_done) ) \ trace(e, \ - (unsigned long)d1, \ - (unsigned long)d2, \ - (unsigned long)d3, \ - (unsigned long)d4, \ - (unsigned long)d5); \ + (unsigned long)(d1), \ + (unsigned long)(d2), \ + (unsigned long)(d3), \ + (unsigned long)(d4), \ + (unsigned long)(d5)); \ } while ( 0 ) /* Convenience macros for calling the trace function. */