mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
merge with xen-unstable.hg
This commit is contained in:
commit
989c3fcf11
126 files changed
+6044
-1130
No files matched your search
@@ -130,6 +130,7 @@ distclean:
|
||||
rm -rf dist patches/tmp
|
||||
for i in $(ALLKERNELS) ; do $(MAKE) $$i-delete ; done
|
||||
for i in $(ALLSPARSETREES) ; do $(MAKE) $$i-mrproper ; done
|
||||
rm -rf patches/*/.makedep
|
||||
|
||||
# Linux name for GNU distclean
|
||||
.PHONY: mrproper
|
||||
|
||||
@@ -59,10 +59,6 @@ ifneq ($(PATCHDIRS),)
|
||||
$(patsubst patches/%,patches/%/.makedep,$(PATCHDIRS)): patches/%/.makedep:
|
||||
@echo 'ref-$*/.valid-ref: $$(wildcard patches/$*/*.patch)' >$@
|
||||
|
||||
.PHONY: clean
|
||||
clean::
|
||||
rm -f patches/*/.makedep
|
||||
|
||||
ref-%/.valid-ref: pristine-%/.valid-pristine
|
||||
set -e
|
||||
rm -rf $(@D)
|
||||
@@ -111,7 +107,8 @@ linux-2.6-xen.patch: ref-linux-$(LINUX_VER)/.valid-ref
|
||||
rm -rf tmp-$@
|
||||
|
||||
%-mrproper:
|
||||
rm -rf pristine-$(*)* ref-$(*)* $*.tar.bz2
|
||||
$(MAKE) -f buildconfigs/mk.$*-xen mrpropper
|
||||
rm -rf pristine-$(*)* ref-$(*)*
|
||||
rm -rf $*-xen.patch
|
||||
|
||||
.PHONY: config-update-pae
|
||||
|
||||
@@ -1902,6 +1902,7 @@ CONFIG_HANGCHECK_TIMER=m
|
||||
# TPM devices
|
||||
#
|
||||
CONFIG_TCG_TPM=m
|
||||
CONFIG_TCG_TIS=m
|
||||
CONFIG_TCG_NSC=m
|
||||
CONFIG_TCG_ATMEL=m
|
||||
CONFIG_TCG_INFINEON=m
|
||||
|
||||
@@ -1765,6 +1765,7 @@ CONFIG_HANGCHECK_TIMER=m
|
||||
# TPM devices
|
||||
#
|
||||
CONFIG_TCG_TPM=m
|
||||
CONFIG_TCG_TIS=m
|
||||
CONFIG_TCG_NSC=m
|
||||
CONFIG_TCG_ATMEL=m
|
||||
CONFIG_TCG_INFINEON=m
|
||||
|
||||
@@ -47,8 +47,14 @@ config: $(LINUX_DIR)/include/linux/autoconf.h
|
||||
|
||||
.PHONY: clean
|
||||
clean::
|
||||
$(MAKE) -C $(LINUX_DIR) ARCH=$(LINUX_ARCH) clean
|
||||
[ ! -d $(LINUX_DIR) ] || \
|
||||
$(MAKE) -C $(LINUX_DIR) ARCH=$(LINUX_ARCH) clean
|
||||
|
||||
|
||||
.PHONY: delete
|
||||
delete:
|
||||
rm -rf tmp-linux-$(LINUX_VER) $(LINUX_DIR)
|
||||
|
||||
.PHONY: mrpropper
|
||||
mrpropper:
|
||||
rm -f linux-$(LINUX_VER).tar.bz2
|
||||
+85
-8
@@ -875,14 +875,43 @@ defined in the I<policy>. Unless specified, the default I<policy> is
|
||||
the currently enforced access control policy. The default for I<type>
|
||||
is 'dom'. The labels are arranged in alphabetical order.
|
||||
|
||||
=item B<addlabel> I<configfile> I<label> [I<policy>]
|
||||
=item B<addlabel> I<label> dom I<configfile> [I<policy>]
|
||||
|
||||
=item B<addlabel> I<label> res I<resource> [I<policy>]
|
||||
|
||||
Adds the security label with name I<label> to a domain
|
||||
I<configfile>. Unless specified, the default I<policy> is the
|
||||
I<configfile> (dom) or to the global resource label file for the
|
||||
given I<resource> (res). Unless specified, the default I<policy> is the
|
||||
currently enforced access control policy. This subcommand also
|
||||
verifies that the I<policy> definition supports the specified I<label>
|
||||
name.
|
||||
|
||||
=item B<rmlabel> dom I<configfile>
|
||||
|
||||
=item B<rmlabel> res I<resource>
|
||||
|
||||
Works the same as the I<addlabel> command (above), except that this
|
||||
command will remove the label from the domain I<configfile> (dom) or
|
||||
the global resource label file (res).
|
||||
|
||||
=item B<getlabel> dom I<configfile>
|
||||
|
||||
=item B<getlabel> res I<resource>
|
||||
|
||||
Shows the label for the given I<configfile> or I<resource>
|
||||
|
||||
=item B<resources>
|
||||
|
||||
Lists all resources in the global resource label file. Each resource
|
||||
is listed with its associated label and policy name.
|
||||
|
||||
=item B<dry-run> I<configfile>
|
||||
|
||||
Determines if the specified I<configfile> describes a domain with a valid
|
||||
security configuration for type enforcement. The test shows the policy
|
||||
decision made for each resource label against the domain label as well as
|
||||
the overall decision.
|
||||
|
||||
B<CONFIGURING SECURITY>
|
||||
|
||||
=over 4
|
||||
@@ -960,17 +989,18 @@ B<ATTACHING A SECURITY LABEL TO A DOMAIN>
|
||||
|
||||
=over 4
|
||||
|
||||
This subcommand attaches a security label to a domain configuration
|
||||
file, here a HomeBanking label. The example policy ensures that this
|
||||
domain does not share information with other non-hombanking user
|
||||
domains (i.e., domains labeled as dom_Fun or dom_Boinc) and that it
|
||||
will not run simultaneously with domains labeled as dom_Fun.
|
||||
The I<addlabel> subcommand can attach a security label to a domain
|
||||
configuration file, here a HomeBanking label. The example policy
|
||||
ensures that this domain does not share information with other
|
||||
non-hombanking user domains (i.e., domains labeled as dom_Fun or
|
||||
dom_Boinc) and that it will not run simultaneously with domains
|
||||
labeled as dom_Fun.
|
||||
|
||||
We assume that the specified myconfig.xm configuration file actually
|
||||
instantiates a domain that runs workloads related to home-banking,
|
||||
probably just a browser environment for online-banking.
|
||||
|
||||
xm addlabel myconfig.xm dom_HomeBanking
|
||||
xm addlabel dom_HomeBanking dom myconfig.xm
|
||||
|
||||
The very simple configuration file might now look as printed
|
||||
below. The I<addlabel> subcommand added the B<access_control> entry at
|
||||
@@ -997,6 +1027,38 @@ permitted".
|
||||
|
||||
=back
|
||||
|
||||
B<ATTACHING A SECURITY LABEL TO A RESOURCE>
|
||||
|
||||
=over 4
|
||||
|
||||
The I<addlabel> subcommand can also be used to attach a security
|
||||
label to a resource. Following the home banking example from above,
|
||||
we can label a disk resource (e.g., a physical partition or a file)
|
||||
to make it accessible to the home banking domain. The example policy
|
||||
provides a resource label, res_LogicalDiskPartition1(hda1), that is
|
||||
compatible with the HomeBanking domain label.
|
||||
|
||||
xm addlabel "res_LogicalDiskPartition1(hda1)" res phy:hda6
|
||||
|
||||
After labeling this disk resource, it can be attached to the domain
|
||||
by adding a line to the domain configuration file. The line below
|
||||
attaches this disk to the domain at boot time.
|
||||
|
||||
disk = [ 'phy:hda6,sda2,w' ]
|
||||
|
||||
Alternatively, the resource can be attached after booting the domain
|
||||
by using the I<block-attach> subcommand.
|
||||
|
||||
xm block-attach homebanking phy:hda6 sda2 w
|
||||
|
||||
Note that labeled resources cannot be used when security is turned
|
||||
off. Any attempt to use labeled resources with security turned off
|
||||
will result in a failure with a corresponding error message. The
|
||||
solution is to enable security or, if security is no longer desired,
|
||||
to remove the resource label using the I<rmlabel> subcommand.
|
||||
|
||||
=back
|
||||
|
||||
B<STARTING AND LISTING LABELED DOMAINS>
|
||||
|
||||
=over 4
|
||||
@@ -1011,6 +1073,21 @@ B<STARTING AND LISTING LABELED DOMAINS>
|
||||
|
||||
=back
|
||||
|
||||
B<LISTING LABELED RESOURCES>
|
||||
|
||||
=over 4
|
||||
|
||||
xm resources
|
||||
|
||||
phy:hda6
|
||||
policy: example.chwall_ste.client_v1
|
||||
label: res_LogicalDiskPartition1(hda1)
|
||||
file:/xen/disk_image/disk.img
|
||||
policy: example.chwall_ste.client_v1
|
||||
label: res_LogicalDiskPartition2(hda2)
|
||||
|
||||
=back
|
||||
|
||||
B<POLICY REPRESENTATIONS>
|
||||
|
||||
=over 4
|
||||
|
||||
+33
-13
@@ -1,5 +1,5 @@
|
||||
Copyright: IBM Corporation (C), Intel Corporation
|
||||
17 August 2005
|
||||
29 June 2006
|
||||
Authors: Stefan Berger <stefanb@us.ibm.com> (IBM),
|
||||
Employees of Intel Corp
|
||||
|
||||
@@ -9,24 +9,34 @@ instance and doing a short test to verify success. It is assumed
|
||||
that the user is fairly familiar with compiling and installing XEN
|
||||
and Linux on a machine.
|
||||
|
||||
Production Prerequisites: An x86-based machine machine with an ATMEL or
|
||||
National Semiconductor (NSC) TPM on the motherboard.
|
||||
Production Prerequisites: An x86-based machine machine with a
|
||||
Linux-supported TPM on the motherboard (NSC, Atmel, Infineon, TPM V1.2).
|
||||
Development Prerequisites: An emulator for TESTING ONLY is provided
|
||||
|
||||
|
||||
Compiling XEN tree:
|
||||
-------------------
|
||||
Compiling the XEN tree:
|
||||
-----------------------
|
||||
|
||||
Compile the XEN tree as usual after the following lines set in the
|
||||
linux-2.6.??-xen/.config file:
|
||||
|
||||
CONFIG_XEN_TPMDEV_BACKEND=y
|
||||
CONFIG_XEN_TPMDEV_BACKEND=m
|
||||
|
||||
CONFIG_TCG_TPM=y
|
||||
CONFIG_TCG_TPM=m
|
||||
CONFIG_TCG_TIS=m (supported after 2.6.17-rc4)
|
||||
CONFIG_TCG_NSC=m
|
||||
CONFIG_TCG_ATMEL=m
|
||||
CONFIG_TCG_INFINEON=m
|
||||
CONFIG_TCG_XEN=m
|
||||
<possible other TPM drivers supported by Linux>
|
||||
|
||||
If the frontend driver needs to be compiled into the user domain
|
||||
kernel, then the following two lines should be changed.
|
||||
|
||||
CONFIG_TCG_TPM=y
|
||||
CONFIG_TCG_XEN=y
|
||||
|
||||
|
||||
You must also enable the virtual TPM to be built:
|
||||
|
||||
In Config.mk in the Xen root directory set the line
|
||||
@@ -63,7 +73,7 @@ an example of how a user domain can be configured to have a TPM
|
||||
available. It works similar to making a network interface
|
||||
available to a domain.
|
||||
|
||||
kernel = "/boot/vmlinuz-2.6.12-xenU"
|
||||
kernel = "/boot/vmlinuz-2.6.x"
|
||||
ramdisk = "/xen/initrd_domU/U1_ramdisk.img"
|
||||
memory = 32
|
||||
name = "TPMUserDomain0"
|
||||
@@ -92,7 +102,7 @@ leave out the 'vtpm' line in the configuration file.
|
||||
Running the TPM:
|
||||
----------------
|
||||
|
||||
To run the vTPM, dev device /dev/vtpm must be available.
|
||||
To run the vTPM, the device /dev/vtpm must be available.
|
||||
Verify that 'ls -l /dev/vtpm' shows the following output:
|
||||
|
||||
crw------- 1 root root 10, 225 Aug 11 06:58 /dev/vtpm
|
||||
@@ -101,16 +111,26 @@ If it is not available, run the following command as 'root'.
|
||||
mknod /dev/vtpm c 10 225
|
||||
|
||||
Make sure that the vTPM is running in domain 0. To do this run the
|
||||
following
|
||||
following:
|
||||
|
||||
modprobe tpmbk
|
||||
|
||||
/usr/bin/vtpm_managerd
|
||||
|
||||
Start a user domain using the 'xm create' command. Once you are in the
|
||||
shell of the user domain, you should be able to do the following:
|
||||
shell of the user domain, you should be able to do the following as
|
||||
user 'root':
|
||||
|
||||
> cd /sys/devices/vtpm
|
||||
Insert the TPM frontend into the kernel if it has been compiled as a
|
||||
kernel module.
|
||||
|
||||
> modprobe tpm_xenu
|
||||
|
||||
Check the status of the TPM
|
||||
|
||||
> cd /sys/devices/xen/vtpm-0
|
||||
> ls
|
||||
cancel caps pcrs pubek
|
||||
[...] cancel caps pcrs pubek [...]
|
||||
> cat pcrs
|
||||
PCR-00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
PCR-01: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
+477
-21
@@ -2203,6 +2203,33 @@ ne2000 & Enable ne2000, default = 0 (disabled; use pcnet)\\
|
||||
|
||||
serial & Enable redirection of VMX serial output to pty device\\
|
||||
|
||||
\end{tabular}
|
||||
|
||||
\begin{tabular}{lp{10cm}}
|
||||
|
||||
usb & Enable USB support without defining a specific USB device.
|
||||
This option defaults to 0 (disabled) unless the option usbdevice is
|
||||
specified in which case this option then defaults to 1 (enabled).\\
|
||||
|
||||
usbdevice & Enable USB support and also enable support for the given
|
||||
device. Devices that can be specified are {\small {\tt mouse}} (a PS/2 style
|
||||
mouse), {\small {\tt tablet}} (an absolute pointing device) and
|
||||
{\small {\tt host:id1:id2}} (a physical USB device on the host machine whose
|
||||
ids are {\small {\tt id1}} and {\small {\tt id2}}). The advantage
|
||||
of {\small {\tt tablet}} is that Windows guests will automatically recognize
|
||||
and support this device so specifying the config line
|
||||
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
usbdevice='tablet'
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
will create a mouse that works transparently with Windows guests under VNC.
|
||||
Linux doesn't recognize the USB tablet yet so Linux guests under VNC will
|
||||
still need the Summagraphics emulation.
|
||||
Details about mouse emulation are provided in section \textbf{A.4.3}.\\
|
||||
|
||||
localtime & Set the real time clock to local time [default=0, that is, set to UTC].\\
|
||||
|
||||
enable-audio & Enable audio support. This is under development.\\
|
||||
@@ -2317,29 +2344,458 @@ Simply follow the usual method of creating the guest, using the -f parameter and
|
||||
|
||||
In the default configuration, VNC is on and SDL is off. Therefore VNC windows will open when VMX guests are created. If you want to use SDL to create VMX guests, set {\small {\tt sdl=1}} in your VMX configuration file. You can also turn off VNC by setting {\small {\tt vnc=0}}.
|
||||
|
||||
\subsection{Use mouse in VNC window}
|
||||
The default PS/2 mouse will not work properly in VMX by a VNC window. Summagraphics mouse emulation does work in this environment. A Summagraphics mouse can be enabled by reconfiguring 2 services:
|
||||
\subsection{Mouse issues, especially under VNC}
|
||||
Mouse handling when using VNC is a little problematic.
|
||||
The problem is that the VNC viewer provides a virtual pointer which is
|
||||
located at an absolute location in the VNC window and only absolute
|
||||
coordinates are provided.
|
||||
The VMX device model converts these absolute mouse coordinates
|
||||
into the relative motion deltas that are expected by the PS/2
|
||||
mouse driver running in the guest.
|
||||
Unfortunately,
|
||||
it is impossible to keep these generated mouse deltas
|
||||
accurate enough for the guest cursor to exactly match
|
||||
the VNC pointer.
|
||||
This can lead to situations where the guest's cursor
|
||||
is in the center of the screen and there's no way to
|
||||
move that cursor to the left
|
||||
(it can happen that the VNC pointer is at the left
|
||||
edge of the screen and,
|
||||
therefore,
|
||||
there are no longer any left mouse deltas that
|
||||
can be provided by the device model emulation code.)
|
||||
|
||||
{\small {\tt 1. General Purpose Mouse (GPM). The GPM daemon is configured in different ways in different Linux distributions. On a Redhat distribution, this is accomplished by changing the file `/etc/sysconfig/mouse' to have the following:\\
|
||||
MOUSETYPE="summa"\\
|
||||
XMOUSETYPE="SUMMA"\\
|
||||
DEVICE=/dev/ttyS0\\
|
||||
\\
|
||||
2. X11. For all Linux distributions, change the Mouse0 stanza in `/etc/X11/xorg.conf' to:\\
|
||||
Section "InputDevice"\\
|
||||
Identifier "Mouse0"\\
|
||||
Driver "summa"\\
|
||||
Option "Device" "/dev/ttyS0"\\
|
||||
Option "InputFashion" "Tablet"\\
|
||||
Option "Mode" "Absolute"\\
|
||||
Option "Name" "EasyPen"\\
|
||||
Option "Compatible" "True"\\
|
||||
Option "Protocol" "Auto"\\
|
||||
Option "SendCoreEvents" "on"\\
|
||||
Option "Vendor" "GENIUS"\\
|
||||
EndSection}}
|
||||
To deal with these mouse issues there are 4 different
|
||||
mouse emulations available from the VMX device model:
|
||||
|
||||
If the Summagraphics mouse isn't the default mouse, you can manually kill 'gpm' and restart it with the command "gpm -m /dev/ttyS0 -t summa". Note that Summagraphics mouse makes no sense in an SDL window and is therefore not available in this environment.
|
||||
\begin{description}
|
||||
\item[PS/2 mouse over the PS/2 port.]
|
||||
This is the default mouse
|
||||
that works perfectly well under SDL.
|
||||
Under VNC the guest cursor will get
|
||||
out of sync with the VNC pointer.
|
||||
When this happens you can re-synchronize
|
||||
the guest cursor to the VNC pointer by
|
||||
holding down the
|
||||
\textbf{left-ctl}
|
||||
and
|
||||
\textbf{left-alt}
|
||||
keys together.
|
||||
While these keys are down VNC pointer motions
|
||||
will not be reported to the guest so
|
||||
that the VNC pointer can be moved
|
||||
to a place where it is possible
|
||||
to move the guest cursor again.
|
||||
|
||||
\item[Summagraphics mouse over the serial port.]
|
||||
The device model also provides emulation
|
||||
for a Summagraphics tablet,
|
||||
an absolute pointer device.
|
||||
This emulation is provided over the second
|
||||
serial port,
|
||||
\textbf{/dev/ttyS1}
|
||||
for Linux guests and
|
||||
\textbf{COM2}
|
||||
for Windows guests.
|
||||
Unfortunately,
|
||||
neither Linux nor Windows provides
|
||||
default support for the Summagraphics
|
||||
tablet so the guest will have to be
|
||||
manually configured for this mouse.
|
||||
|
||||
\textbf{Linux configuration.}
|
||||
|
||||
First,
|
||||
configure the GPM service to use the Summagraphics tablet.
|
||||
This can vary between distributions but,
|
||||
typically,
|
||||
all that needs to be done is modify the file
|
||||
\path{/etc/sysconfig/mouse} to contain the lines:
|
||||
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
MOUSETYPE="summa"
|
||||
XMOUSETYPE="SUMMA"
|
||||
DEVICE=/dev/ttyS1
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
and then restart the GPM daemon.
|
||||
|
||||
Next,
|
||||
modify the X11 config
|
||||
\path{/etc/X11/xorg.conf}
|
||||
to support the Summgraphics tablet by replacing
|
||||
the input device stanza with the following:
|
||||
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
Section "InputDevice"
|
||||
Identifier "Mouse0"
|
||||
Driver "summa"
|
||||
Option "Device" "/dev/ttyS1"
|
||||
Option "InputFashion" "Tablet"
|
||||
Option "Mode" "Absolute"
|
||||
Option "Name" "EasyPen"
|
||||
Option "Compatible" "True"
|
||||
Option "Protocol" "Auto"
|
||||
Option "SendCoreEvents" "on"
|
||||
Option "Vendor" "GENIUS"
|
||||
EndSection
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
Restart X and the X cursor should now properly
|
||||
track the VNC pointer.
|
||||
|
||||
|
||||
\textbf{Windows configuration.}
|
||||
|
||||
Get the file
|
||||
\path{http://www.cad-plan.de/files/download/tw2k.exe}
|
||||
and execute that file on the guest,
|
||||
answering the questions as follows:
|
||||
|
||||
\begin{enumerate}
|
||||
\item When the program asks for \textbf{model},
|
||||
scroll down and selese \textbf{SummaSketch (MM Compatible)}.
|
||||
|
||||
\item When the program asks for \textbf{COM Port} specify \textbf{com2}.
|
||||
|
||||
\item When the programs asks for a \textbf{Cursor Type} specify
|
||||
\textbf{4 button cursor/puck}.
|
||||
|
||||
\item The guest system will then reboot and,
|
||||
when it comes back up,
|
||||
the guest cursor will now properly track
|
||||
the VNC pointer.
|
||||
\end{enumerate}
|
||||
|
||||
\item[PS/2 mouse over USB port.]
|
||||
This is just the same PS/2 emulation except it is
|
||||
provided over a USB port.
|
||||
This emulation is enabled by the configuration flag:
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
usbdevice='mouse'
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
\item[USB tablet over USB port.]
|
||||
The USB tablet is an absolute pointing device
|
||||
that has the advantage that it is automatically
|
||||
supported under Windows guests,
|
||||
although Linux guests still require some
|
||||
manual configuration.
|
||||
This mouse emulation is enabled by the
|
||||
configuration flag:
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
usbdevice='tablet'
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
\textbf{Linux configuration.}
|
||||
|
||||
Unfortunately,
|
||||
there is no GPM support for the
|
||||
USB tablet at this point in time.
|
||||
If you intend to use a GPM pointing
|
||||
device under VNC you should
|
||||
configure the guest for Summagraphics
|
||||
emulation.
|
||||
|
||||
Support for X11 is available by following
|
||||
the instructions at\\
|
||||
\verb+http://stz-softwaretechnik.com/~ke/touchscreen/evtouch.html+\\
|
||||
with one minor change.
|
||||
The
|
||||
\path{xorg.conf}
|
||||
given in those instructions
|
||||
uses the wrong values for the X \& Y minimums and maximums,
|
||||
use the following config stanza instead:
|
||||
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
Section "InputDevice"
|
||||
Identifier "Tablet"
|
||||
Driver "evtouch"
|
||||
Option "Device" "/dev/input/event2"
|
||||
Option "DeviceName" "touchscreen"
|
||||
Option "MinX" "0"
|
||||
Option "MinY" "0"
|
||||
Option "MaxX" "32256"
|
||||
Option "MaxY" "32256"
|
||||
Option "ReportingMode" "Raw"
|
||||
Option "Emulate3Buttons"
|
||||
Option "Emulate3Timeout" "50"
|
||||
Option "SendCoreEvents" "On"
|
||||
EndSection
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
\textbf{Windows configuration.}
|
||||
|
||||
Just enabling the USB tablet in the
|
||||
guest's configuration file is sufficient,
|
||||
Windows will automatically recognize and
|
||||
configure device drivers for this
|
||||
pointing device.
|
||||
|
||||
\end{description}
|
||||
|
||||
\subsection{USB Support}
|
||||
There is support for an emulated USB mouse,
|
||||
an emulated USB tablet
|
||||
and physical low speed USB devices
|
||||
(support for high speed USB 2.0 devices is
|
||||
still under development).
|
||||
|
||||
\begin{description}
|
||||
\item[USB PS/2 style mouse.]
|
||||
Details on the USB mouse emulation are
|
||||
given in sections
|
||||
\textbf{A.2}
|
||||
and
|
||||
\textbf{A.4.3}.
|
||||
Enabling USB PS/2 style mouse emulation
|
||||
is just a matter of adding the line
|
||||
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
usbdevice='mouse'
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
to the configuration file.
|
||||
\item[USB tablet.]
|
||||
Details on the USB tablet emulation are
|
||||
given in sections
|
||||
\textbf{A.2}
|
||||
and
|
||||
\textbf{A.4.3}.
|
||||
Enabling USB tablet emulation
|
||||
is just a matter of adding the line
|
||||
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
usbdevice='tablet'
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
to the configuration file.
|
||||
\item[USB physical devices.]
|
||||
Access to a physical (low speed) USB device
|
||||
is enabled by adding a line of the form
|
||||
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
usbdevice='host:vid:pid'
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
into the the configuration file.\footnote{
|
||||
There is an alternate
|
||||
way of specifying a USB device that
|
||||
uses the syntax
|
||||
\textbf{host:bus.addr}
|
||||
but this syntax suffers from
|
||||
a major problem that makes
|
||||
it effectively useless.
|
||||
The problem is that the
|
||||
\textbf{addr}
|
||||
portion of this address
|
||||
changes every time the USB device
|
||||
is plugged into the system.
|
||||
For this reason this addressing
|
||||
scheme is not recommended and
|
||||
will not be documented further.
|
||||
}
|
||||
\textbf{vid}
|
||||
and
|
||||
\textbf{pid}
|
||||
are a
|
||||
product id and
|
||||
vendor id
|
||||
that uniquely identify
|
||||
the USB device.
|
||||
These ids can be identified
|
||||
in two ways:
|
||||
|
||||
\begin{enumerate}
|
||||
\item Through the control window.
|
||||
As described in section
|
||||
\textbf{A.4.6}
|
||||
the control window
|
||||
is activated by pressing
|
||||
\textbf{ctl-alt-2}
|
||||
in the guest VGA window.
|
||||
As long as USB support is
|
||||
enabled in the guest by including
|
||||
the config file line
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
usb=1
|
||||
\end{verbatim}
|
||||
}
|
||||
then executing the command
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
info usbhost
|
||||
\end{verbatim}
|
||||
}
|
||||
in the control window
|
||||
will display a list of all
|
||||
usb devices and their ids.
|
||||
For example,
|
||||
this output:
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
Device 1.3, speed 1.5 Mb/s
|
||||
Class 00: USB device 04b3:310b
|
||||
\end{verbatim}
|
||||
}
|
||||
was created from a USB mouse with
|
||||
vendor id
|
||||
\textbf{04b3}
|
||||
and product id
|
||||
\textbf{310b}.
|
||||
This device could be made available
|
||||
to the VMX guest by including the
|
||||
config file entry
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
usbdevice='host:04be:310b'
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
It is also possible to
|
||||
enable access to a USB
|
||||
device dynamically through
|
||||
the control window.
|
||||
The control window command
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
usb_add host:vid:pid
|
||||
\end{verbatim}
|
||||
}
|
||||
will also allow access to a
|
||||
USB device with vendor id
|
||||
\textbf{vid}
|
||||
and product id
|
||||
\textbf{pid}.
|
||||
\item Through the
|
||||
\path{/proc} file system.
|
||||
The contents of the pseudo file
|
||||
\path{/proc/bus/usb/devices}
|
||||
can also be used to identify
|
||||
vendor and product ids.
|
||||
Looking at this file,
|
||||
the line starting with
|
||||
\textbf{P:}
|
||||
has a field
|
||||
\textbf{Vendor}
|
||||
giving the vendor id and
|
||||
another field
|
||||
\textbf{ProdID}
|
||||
giving the product id.
|
||||
The contents of
|
||||
\path{/proc/bus/usb/devices}
|
||||
for the example mouse is as
|
||||
follows:
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#= 3 Spd=1.5 MxCh= 0
|
||||
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
|
||||
P: Vendor=04b3 ProdID=310b Rev= 1.60
|
||||
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
|
||||
I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=(none)
|
||||
E: Ad=81(I) Atr=03(Int.) MxPS= 4 Ivl=10ms
|
||||
\end{verbatim}
|
||||
}
|
||||
Note that the
|
||||
\textbf{P:}
|
||||
line correctly identifies the
|
||||
vendor id and product id
|
||||
for this mouse as
|
||||
\textbf{04b3:310b}.
|
||||
\end{enumerate}
|
||||
There is one other issue to
|
||||
be aware of when accessing a
|
||||
physical USB device from the guest.
|
||||
The Dom0 kernel must not have
|
||||
a device driver loaded for
|
||||
the device that the guest wishes
|
||||
to access.
|
||||
This means that the Dom0
|
||||
kernel must not have that
|
||||
device driver compiled into
|
||||
the kernel or,
|
||||
if using modules,
|
||||
that driver module must
|
||||
not be loaded.
|
||||
Note that this is the device
|
||||
specific USB driver that must
|
||||
not be loaded,
|
||||
either the
|
||||
\textbf{UHCI}
|
||||
or
|
||||
\textbf{OHCI}
|
||||
USB controller driver must
|
||||
still be loaded.
|
||||
|
||||
Going back to the USB mouse
|
||||
as an example,
|
||||
if \textbf{lsmod}
|
||||
gives the output:
|
||||
|
||||
{\small
|
||||
\begin{verbatim}
|
||||
Module Size Used by
|
||||
usbmouse 4128 0
|
||||
usbhid 28996 0
|
||||
uhci_hcd 35409 0
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
then the USB mouse is being
|
||||
used by the Dom0 kernel and is
|
||||
not available to the guest.
|
||||
Executing the command
|
||||
\textbf{rmmod usbhid}\footnote{
|
||||
Turns out the
|
||||
\textbf{usbhid}
|
||||
driver is the significant
|
||||
one for the USB mouse,
|
||||
the presence or absence of
|
||||
the module
|
||||
\textbf{usbmouse}
|
||||
has no effect on whether or
|
||||
not the guest can see a USB mouse.}
|
||||
will remove the USB mouse
|
||||
driver from the Dom0 kernel
|
||||
and the mouse will now be
|
||||
accessible by the VMX guest.
|
||||
|
||||
Be aware the the Linux USB
|
||||
hotplug system will reload
|
||||
the drivers if a USB device
|
||||
is removed and plugged back
|
||||
in.
|
||||
This means that just unloading
|
||||
the driver module might not
|
||||
be sufficient if the USB device
|
||||
is removed and added back.
|
||||
A more reliable technique is
|
||||
to first
|
||||
\textbf{rmmod}
|
||||
the driver and then rename the
|
||||
driver file in the
|
||||
\path{/lib/modules}
|
||||
directory,
|
||||
just to make sure it doesn't get
|
||||
reloaded.
|
||||
\end{description}
|
||||
|
||||
\subsection{Destroy VMX guests}
|
||||
VMX guests can be destroyed in the same way as can paravirtualized guests. We recommend that you type the command
|
||||
|
||||
@@ -53,7 +53,7 @@ int xencons_ring_send(const char *data, unsigned len)
|
||||
|
||||
|
||||
|
||||
static void handle_input(int port, struct pt_regs *regs)
|
||||
static void handle_input(int port, struct pt_regs *regs, void *ign)
|
||||
{
|
||||
struct xencons_interface *intf = xencons_interface();
|
||||
XENCONS_RING_IDX cons, prod;
|
||||
@@ -83,7 +83,8 @@ int xencons_ring_init(void)
|
||||
if (!start_info.console_evtchn)
|
||||
return 0;
|
||||
|
||||
err = bind_evtchn(start_info.console_evtchn, handle_input);
|
||||
err = bind_evtchn(start_info.console_evtchn, handle_input,
|
||||
NULL);
|
||||
if (err <= 0) {
|
||||
printk("XEN console request chn bind failed %i\n", err);
|
||||
return err;
|
||||
|
||||
+54
-30
@@ -22,9 +22,18 @@
|
||||
#include <events.h>
|
||||
#include <lib.h>
|
||||
|
||||
#define NR_EVS 1024
|
||||
|
||||
/* this represents a event handler. Chaining or sharing is not allowed */
|
||||
typedef struct _ev_action_t {
|
||||
void (*handler)(int, struct pt_regs *, void *);
|
||||
void *data;
|
||||
u32 count;
|
||||
} ev_action_t;
|
||||
|
||||
|
||||
static ev_action_t ev_actions[NR_EVS];
|
||||
void default_handler(int port, struct pt_regs *regs);
|
||||
void default_handler(int port, struct pt_regs *regs, void *data);
|
||||
|
||||
|
||||
/*
|
||||
@@ -35,42 +44,33 @@ int do_event(u32 port, struct pt_regs *regs)
|
||||
ev_action_t *action;
|
||||
if (port >= NR_EVS) {
|
||||
printk("Port number too large: %d\n", port);
|
||||
goto out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
action = &ev_actions[port];
|
||||
action->count++;
|
||||
|
||||
if (!action->handler)
|
||||
{
|
||||
printk("Spurious event on port %d\n", port);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (action->status & EVS_DISABLED)
|
||||
{
|
||||
printk("Event on port %d disabled\n", port);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* call the handler */
|
||||
action->handler(port, regs);
|
||||
|
||||
action->handler(port, regs, action->data);
|
||||
|
||||
out:
|
||||
clear_evtchn(port);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int bind_evtchn( u32 port, void (*handler)(int, struct pt_regs *) )
|
||||
int bind_evtchn( u32 port, void (*handler)(int, struct pt_regs *, void *),
|
||||
void *data )
|
||||
{
|
||||
if(ev_actions[port].handler != default_handler)
|
||||
printk("WARN: Handler for port %d already registered, replacing\n",
|
||||
port);
|
||||
|
||||
ev_actions[port].data = data;
|
||||
wmb();
|
||||
ev_actions[port].handler = handler;
|
||||
ev_actions[port].status &= ~EVS_DISABLED;
|
||||
|
||||
|
||||
/* Finally unmask the port */
|
||||
unmask_evtchn(port);
|
||||
|
||||
@@ -82,13 +82,14 @@ void unbind_evtchn( u32 port )
|
||||
if (ev_actions[port].handler == default_handler)
|
||||
printk("WARN: No handler for port %d when unbinding\n", port);
|
||||
ev_actions[port].handler = default_handler;
|
||||
ev_actions[port].status |= EVS_DISABLED;
|
||||
wmb();
|
||||
ev_actions[port].data = NULL;
|
||||
}
|
||||
|
||||
int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *) )
|
||||
int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *, void *data),
|
||||
void *data)
|
||||
{
|
||||
evtchn_op_t op;
|
||||
int ret = 0;
|
||||
|
||||
/* Try to bind the virq to a port */
|
||||
op.cmd = EVTCHNOP_bind_virq;
|
||||
@@ -97,13 +98,11 @@ int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *) )
|
||||
|
||||
if ( HYPERVISOR_event_channel_op(&op) != 0 )
|
||||
{
|
||||
ret = 1;
|
||||
printk("Failed to bind virtual IRQ %d\n", virq);
|
||||
goto out;
|
||||
return 1;
|
||||
}
|
||||
bind_evtchn(op.u.bind_virq.port, handler);
|
||||
out:
|
||||
return ret;
|
||||
bind_evtchn(op.u.bind_virq.port, handler, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void unbind_virq( u32 port )
|
||||
@@ -137,13 +136,38 @@ void init_events(void)
|
||||
#endif
|
||||
/* inintialise event handler */
|
||||
for ( i = 0; i < NR_EVS; i++ )
|
||||
{
|
||||
ev_actions[i].status = EVS_DISABLED;
|
||||
{
|
||||
ev_actions[i].handler = default_handler;
|
||||
mask_evtchn(i);
|
||||
}
|
||||
}
|
||||
|
||||
void default_handler(int port, struct pt_regs *regs) {
|
||||
void default_handler(int port, struct pt_regs *regs, void *ignore)
|
||||
{
|
||||
printk("[Port %d] - event received\n", port);
|
||||
}
|
||||
|
||||
/* Unfortunate confusion of terminology: the port is unbound as far
|
||||
as Xen is concerned, but we automatically bind a handler to it
|
||||
from inside mini-os. */
|
||||
int evtchn_alloc_unbound(void (*handler)(int, struct pt_regs *regs,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
u32 port;
|
||||
evtchn_op_t op;
|
||||
int err;
|
||||
|
||||
op.cmd = EVTCHNOP_alloc_unbound;
|
||||
op.u.alloc_unbound.dom = DOMID_SELF;
|
||||
op.u.alloc_unbound.remote_dom = 0;
|
||||
|
||||
err = HYPERVISOR_event_channel_op(&op);
|
||||
if (err) {
|
||||
printk("Failed to alloc unbound evtchn: %d.\n", err);
|
||||
return -1;
|
||||
}
|
||||
port = op.u.alloc_unbound.port;
|
||||
bind_evtchn(port, handler, data);
|
||||
return port;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
****************************************************************************
|
||||
* (C) 2006 - Cambridge University
|
||||
****************************************************************************
|
||||
*
|
||||
* File: gnttab.c
|
||||
* Author: Steven Smith (sos22@cam.ac.uk)
|
||||
* Changes: Grzegorz Milos (gm281@cam.ac.uk)
|
||||
*
|
||||
* Date: July 2006
|
||||
*
|
||||
* Environment: Xen Minimal OS
|
||||
* Description: Simple grant tables implementation. About as stupid as it's
|
||||
* possible to be and still work.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
#include <os.h>
|
||||
#include <mm.h>
|
||||
#include <gnttab.h>
|
||||
|
||||
#define NR_RESERVED_ENTRIES 8
|
||||
|
||||
#define NR_GRANT_FRAMES 4
|
||||
#define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t))
|
||||
#define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
|
||||
|
||||
static grant_entry_t *gnttab_table;
|
||||
static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
|
||||
static grant_ref_t gnttab_free_head;
|
||||
|
||||
static grant_ref_t
|
||||
get_free_entries(int count)
|
||||
{
|
||||
grant_ref_t ref;
|
||||
grant_ref_t head;
|
||||
|
||||
ref = head = gnttab_free_head;
|
||||
while (count-- > 1)
|
||||
head = gnttab_list[head];
|
||||
gnttab_free_head = gnttab_list[head];
|
||||
gnttab_list[head] = GNTTAB_LIST_END;
|
||||
return ref;
|
||||
}
|
||||
|
||||
static void
|
||||
put_free_entry(grant_ref_t gref)
|
||||
{
|
||||
gnttab_list[gref] = gnttab_free_head;
|
||||
gnttab_free_head = gref;
|
||||
}
|
||||
|
||||
grant_ref_t
|
||||
gnttab_grant_access(domid_t domid, unsigned long frame, int readonly)
|
||||
{
|
||||
grant_ref_t ref;
|
||||
|
||||
ref = get_free_entries(1);
|
||||
gnttab_table[ref].frame = frame;
|
||||
gnttab_table[ref].domid = domid;
|
||||
wmb();
|
||||
readonly *= GTF_readonly;
|
||||
gnttab_table[ref].flags = GTF_permit_access | readonly;
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
grant_ref_t
|
||||
gnttab_grant_transfer(domid_t domid, unsigned long pfn)
|
||||
{
|
||||
grant_ref_t ref;
|
||||
|
||||
ref = get_free_entries(1);
|
||||
gnttab_table[ref].frame = pfn;
|
||||
gnttab_table[ref].domid = domid;
|
||||
wmb();
|
||||
gnttab_table[ref].flags = GTF_accept_transfer;
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
int
|
||||
gnttab_end_access(grant_ref_t ref)
|
||||
{
|
||||
u16 flags, nflags;
|
||||
|
||||
nflags = gnttab_table[ref].flags;
|
||||
do {
|
||||
if ((flags = nflags) & (GTF_reading|GTF_writing)) {
|
||||
printk("WARNING: g.e. still in use!\n");
|
||||
return 0;
|
||||
}
|
||||
} while ((nflags = synch_cmpxchg(&gnttab_table[ref].flags, flags, 0)) !=
|
||||
flags);
|
||||
|
||||
put_free_entry(ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
gnttab_end_transfer(grant_ref_t ref)
|
||||
{
|
||||
unsigned long frame;
|
||||
u16 flags;
|
||||
|
||||
while (!((flags = gnttab_table[ref].flags) & GTF_transfer_committed)) {
|
||||
if (synch_cmpxchg(&gnttab_table[ref].flags, flags, 0) == flags) {
|
||||
printk("Release unused transfer grant.\n");
|
||||
put_free_entry(ref);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If a transfer is in progress then wait until it is completed. */
|
||||
while (!(flags & GTF_transfer_completed)) {
|
||||
flags = gnttab_table[ref].flags;
|
||||
}
|
||||
|
||||
/* Read the frame number /after/ reading completion status. */
|
||||
rmb();
|
||||
frame = gnttab_table[ref].frame;
|
||||
|
||||
put_free_entry(ref);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
grant_ref_t
|
||||
gnttab_alloc_and_grant(void **map)
|
||||
{
|
||||
unsigned long mfn;
|
||||
grant_ref_t gref;
|
||||
|
||||
*map = (void *)alloc_page();
|
||||
mfn = virt_to_mfn(*map);
|
||||
gref = gnttab_grant_access(0, mfn, 0);
|
||||
return gref;
|
||||
}
|
||||
|
||||
void
|
||||
init_gnttab(void)
|
||||
{
|
||||
struct gnttab_setup_table setup;
|
||||
unsigned long frames[NR_GRANT_FRAMES];
|
||||
int i;
|
||||
|
||||
for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
|
||||
gnttab_list[i] = i + 1;
|
||||
gnttab_free_head = NR_RESERVED_ENTRIES;
|
||||
|
||||
setup.dom = DOMID_SELF;
|
||||
setup.nr_frames = NR_GRANT_FRAMES;
|
||||
set_xen_guest_handle(setup.frame_list, frames);
|
||||
|
||||
HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
|
||||
gnttab_table = map_frames(frames, NR_GRANT_FRAMES);
|
||||
printk("gnttab_table mapped at %p.\n", gnttab_table);
|
||||
}
|
||||
@@ -22,28 +22,18 @@
|
||||
#include<traps.h>
|
||||
#include <xen/event_channel.h>
|
||||
|
||||
#define NR_EVS 1024
|
||||
|
||||
/* ev handler status */
|
||||
#define EVS_INPROGRESS 1 /* Event handler active - do not enter! */
|
||||
#define EVS_DISABLED 2 /* Event disabled - do not enter! */
|
||||
#define EVS_PENDING 4 /* Event pending - replay on enable */
|
||||
#define EVS_REPLAY 8 /* Event has been replayed but not acked yet */
|
||||
|
||||
/* this represents a event handler. Chaining or sharing is not allowed */
|
||||
typedef struct _ev_action_t {
|
||||
void (*handler)(int, struct pt_regs *);
|
||||
unsigned int status; /* IRQ status */
|
||||
u32 count;
|
||||
} ev_action_t;
|
||||
|
||||
/* prototypes */
|
||||
int do_event(u32 port, struct pt_regs *regs);
|
||||
int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *) );
|
||||
int bind_evtchn( u32 virq, void (*handler)(int, struct pt_regs *) );
|
||||
int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *, void *data),
|
||||
void *data);
|
||||
int bind_evtchn( u32 virq, void (*handler)(int, struct pt_regs *, void *data),
|
||||
void *data );
|
||||
void unbind_evtchn( u32 port );
|
||||
void init_events(void);
|
||||
void unbind_virq( u32 port );
|
||||
int evtchn_alloc_unbound(void (*handler)(int, struct pt_regs *regs,
|
||||
void *data),
|
||||
void *data);
|
||||
|
||||
static inline int notify_remote_via_evtchn(int port)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef __GNTTAB_H__
|
||||
#define __GNTTAB_H__
|
||||
|
||||
#include <xen/grant_table.h>
|
||||
|
||||
void init_gnttab(void);
|
||||
grant_ref_t gnttab_alloc_and_grant(void **map);
|
||||
grant_ref_t gnttab_grant_access(domid_t domid, unsigned long frame,
|
||||
int readonly);
|
||||
grant_ref_t gnttab_grant_transfer(domid_t domid, unsigned long pfn);
|
||||
unsigned long gnttab_end_transfer(grant_ref_t gref);
|
||||
int gnttab_end_access(grant_ref_t ref);
|
||||
|
||||
#endif /* !__GNTTAB_H__ */
|
||||
@@ -89,6 +89,7 @@ size_t strlen(const char *s);
|
||||
char *strchr(const char *s, int c);
|
||||
char *strstr(const char *s1, const char *s2);
|
||||
char * strcat(char * dest, const char * src);
|
||||
char *strdup(const char *s);
|
||||
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
@@ -98,6 +99,18 @@ struct kvec {
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
#define ASSERT(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
printk("ASSERTION FAILED: %s at %s:%d.\n", \
|
||||
# x , \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
BUG(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* Consistency check as much as possible. */
|
||||
void sanity_check(void);
|
||||
|
||||
#endif /* _LIB_H_ */
|
||||
@@ -196,9 +196,11 @@ static __inline__ paddr_t machine_to_phys(maddr_t machine)
|
||||
#define to_virt(x) ((void *)((unsigned long)(x)+VIRT_START))
|
||||
|
||||
#define virt_to_pfn(_virt) (PFN_DOWN(to_phys(_virt)))
|
||||
#define virt_to_mfn(_virt) (pfn_to_mfn(virt_to_pfn(_virt)))
|
||||
#define mach_to_virt(_mach) (to_virt(machine_to_phys(_mach)))
|
||||
#define virt_to_mach(_virt) (phys_to_machine(to_phys(_virt)))
|
||||
#define mfn_to_virt(_mfn) (to_virt(mfn_to_pfn(_mfn) << PAGE_SHIFT))
|
||||
#define pfn_to_virt(_pfn) (to_virt(_pfn << PAGE_SHIFT))
|
||||
#define pfn_to_virt(_pfn) (to_virt((_pfn) << PAGE_SHIFT))
|
||||
|
||||
/* Pagetable walking. */
|
||||
#define pte_to_mfn(_pte) (((_pte) & (PADDR_MASK&PAGE_MASK)) >> L1_PAGETABLE_SHIFT)
|
||||
@@ -206,7 +208,7 @@ static __inline__ paddr_t machine_to_phys(maddr_t machine)
|
||||
|
||||
void init_mm(void);
|
||||
unsigned long alloc_pages(int order);
|
||||
#define alloc_page() alloc_pages(0);
|
||||
#define alloc_page() alloc_pages(0)
|
||||
void free_pages(void *pointer, int order);
|
||||
|
||||
static __inline__ int get_order(unsigned long size)
|
||||
@@ -219,4 +221,6 @@ static __inline__ int get_order(unsigned long size)
|
||||
}
|
||||
|
||||
|
||||
void *map_frames(unsigned long *f, unsigned long n);
|
||||
|
||||
#endif /* _MM_H_ */
|
||||
@@ -445,7 +445,62 @@ static __inline__ unsigned long __ffs(unsigned long word)
|
||||
|
||||
|
||||
/********************* common i386 and x86_64 ****************************/
|
||||
struct __synch_xchg_dummy { unsigned long a[100]; };
|
||||
#define __synch_xg(x) ((struct __synch_xchg_dummy *)(x))
|
||||
|
||||
#define synch_cmpxchg(ptr, old, new) \
|
||||
((__typeof__(*(ptr)))__synch_cmpxchg((ptr),\
|
||||
(unsigned long)(old), \
|
||||
(unsigned long)(new), \
|
||||
sizeof(*(ptr))))
|
||||
|
||||
static inline unsigned long __synch_cmpxchg(volatile void *ptr,
|
||||
unsigned long old,
|
||||
unsigned long new, int size)
|
||||
{
|
||||
unsigned long prev;
|
||||
switch (size) {
|
||||
case 1:
|
||||
__asm__ __volatile__("lock; cmpxchgb %b1,%2"
|
||||
: "=a"(prev)
|
||||
: "q"(new), "m"(*__synch_xg(ptr)),
|
||||
"0"(old)
|
||||
: "memory");
|
||||
return prev;
|
||||
case 2:
|
||||
__asm__ __volatile__("lock; cmpxchgw %w1,%2"
|
||||
: "=a"(prev)
|
||||
: "r"(new), "m"(*__synch_xg(ptr)),
|
||||
"0"(old)
|
||||
: "memory");
|
||||
return prev;
|
||||
#ifdef __x86_64__
|
||||
case 4:
|
||||
__asm__ __volatile__("lock; cmpxchgl %k1,%2"
|
||||
: "=a"(prev)
|
||||
: "r"(new), "m"(*__synch_xg(ptr)),
|
||||
"0"(old)
|
||||
: "memory");
|
||||
return prev;
|
||||
case 8:
|
||||
__asm__ __volatile__("lock; cmpxchgq %1,%2"
|
||||
: "=a"(prev)
|
||||
: "r"(new), "m"(*__synch_xg(ptr)),
|
||||
"0"(old)
|
||||
: "memory");
|
||||
return prev;
|
||||
#else
|
||||
case 4:
|
||||
__asm__ __volatile__("lock; cmpxchgl %1,%2"
|
||||
: "=a"(prev)
|
||||
: "r"(new), "m"(*__synch_xg(ptr)),
|
||||
"0"(old)
|
||||
: "memory");
|
||||
return prev;
|
||||
#endif
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
static __inline__ void synch_set_bit(int nr, volatile void * addr)
|
||||
|
||||
@@ -1,34 +1,51 @@
|
||||
#ifndef XENBUS_H__
|
||||
#define XENBUS_H__
|
||||
|
||||
typedef unsigned long xenbus_transaction_t;
|
||||
#define XBT_NIL ((xenbus_transaction_t)0)
|
||||
|
||||
/* Initialize the XenBus system. */
|
||||
void init_xenbus(void);
|
||||
|
||||
/* Read the value associated with a path. Returns a malloc'd error
|
||||
string on failure and sets *value to NULL. On success, *value is
|
||||
set to a malloc'd copy of the value. */
|
||||
char *xenbus_read(const char *path, char **value);
|
||||
char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value);
|
||||
|
||||
/* Associates a value with a path. Returns a malloc'd error string on
|
||||
failure. */
|
||||
char *xenbus_write(const char *path, const char *value);
|
||||
char *xenbus_write(xenbus_transaction_t xbt, const char *path, const char *value);
|
||||
|
||||
/* Removes the value associated with a path. Returns a malloc'd error
|
||||
string on failure. */
|
||||
char *xenbus_rm(const char *path);
|
||||
char *xenbus_rm(xenbus_transaction_t xbt, const char *path);
|
||||
|
||||
/* List the contents of a directory. Returns a malloc'd error string
|
||||
on failure and sets *contents to NULL. On success, *contents is
|
||||
set to a malloc'd array of pointers to malloc'd strings. The array
|
||||
is NULL terminated. May block. */
|
||||
char *xenbus_ls(const char *prefix, char ***contents);
|
||||
char *xenbus_ls(xenbus_transaction_t xbt, const char *prefix, char ***contents);
|
||||
|
||||
/* Reads permissions associated with a path. Returns a malloc'd error
|
||||
string on failure and sets *value to NULL. On success, *value is
|
||||
set to a malloc'd copy of the value. */
|
||||
char *xenbus_get_perms(const char *path, char **value);
|
||||
char *xenbus_get_perms(xenbus_transaction_t xbt, const char *path, char **value);
|
||||
|
||||
/* Sets the permissions associated with a path. Returns a malloc'd
|
||||
error string on failure. */
|
||||
char *xenbus_set_perms(const char *path, domid_t dom, char perm);
|
||||
char *xenbus_set_perms(xenbus_transaction_t xbt, const char *path, domid_t dom, char perm);
|
||||
|
||||
/* Start a xenbus transaction. Returns the transaction in xbt on
|
||||
success or a malloc'd error string otherwise. */
|
||||
char *xenbus_transaction_start(xenbus_transaction_t *xbt);
|
||||
|
||||
/* End a xenbus transaction. Returns a malloc'd error string if it
|
||||
fails. abort says whether the transaction should be aborted.
|
||||
Returns 1 in *retry iff the transaction should be retried. */
|
||||
char *xenbus_transaction_end(xenbus_transaction_t, int abort,
|
||||
int *retry);
|
||||
|
||||
/* Read path and parse it as an integer. Returns -1 on error. */
|
||||
int xenbus_read_integer(char *path);
|
||||
|
||||
#endif /* XENBUS_H__ */
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <lib.h>
|
||||
#include <sched.h>
|
||||
#include <xenbus.h>
|
||||
#include <gnttab.h>
|
||||
#include <xen/features.h>
|
||||
#include <xen/version.h>
|
||||
|
||||
@@ -104,7 +105,8 @@ void test_xenbus(void);
|
||||
|
||||
void xenbus_tester(void *p)
|
||||
{
|
||||
test_xenbus();
|
||||
printk("Xenbus tests disabled, because of a Xend bug.\n");
|
||||
/* test_xenbus(); */
|
||||
}
|
||||
|
||||
/* This should be overridden by the application we are linked against. */
|
||||
@@ -176,7 +178,10 @@ void start_kernel(start_info_t *si)
|
||||
|
||||
/* Init the console driver. */
|
||||
init_console();
|
||||
|
||||
|
||||
/* Init grant tables */
|
||||
init_gnttab();
|
||||
|
||||
/* Init scheduler. */
|
||||
init_sched();
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <os.h>
|
||||
#include <types.h>
|
||||
#include <lib.h>
|
||||
#include <xmalloc.h>
|
||||
|
||||
int memcmp(const void * cs,const void * ct,size_t count)
|
||||
{
|
||||
@@ -156,4 +157,13 @@ char * strstr(const char * s1,const char * s2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strdup(const char *x)
|
||||
{
|
||||
int l = strlen(x);
|
||||
char *res = malloc(l + 1);
|
||||
if (!res) return NULL;
|
||||
memcpy(res, x, l + 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
+122
-1
@@ -343,7 +343,7 @@ void free_pages(void *pointer, int order)
|
||||
break;
|
||||
|
||||
/* Merge with successor */
|
||||
freed_ct = (chunk_tail_t *)((char *)to_merge_ch + mask);
|
||||
freed_ct = (chunk_tail_t *)((char *)to_merge_ch + mask) - 1;
|
||||
}
|
||||
|
||||
/* We are commited to merging, unlink the chunk */
|
||||
@@ -612,6 +612,107 @@ void mem_test(unsigned long *start_add, unsigned long *end_add)
|
||||
|
||||
}
|
||||
|
||||
static pgentry_t *demand_map_pgt;
|
||||
static void *demand_map_area_start;
|
||||
|
||||
static void init_demand_mapping_area(unsigned long max_pfn)
|
||||
{
|
||||
unsigned long mfn;
|
||||
pgentry_t *tab;
|
||||
unsigned long start_addr;
|
||||
unsigned long pt_pfn;
|
||||
unsigned offset;
|
||||
|
||||
/* Round up to four megs. + 1024 rather than + 1023 since we want
|
||||
to be sure we don't end up in the same place we started. */
|
||||
max_pfn = (max_pfn + L1_PAGETABLE_ENTRIES) & ~(L1_PAGETABLE_ENTRIES - 1);
|
||||
if (max_pfn == 0 ||
|
||||
(unsigned long)pfn_to_virt(max_pfn + L1_PAGETABLE_ENTRIES) >=
|
||||
HYPERVISOR_VIRT_START) {
|
||||
printk("Too much memory; no room for demand map hole.\n");
|
||||
do_exit();
|
||||
}
|
||||
|
||||
demand_map_area_start = pfn_to_virt(max_pfn);
|
||||
printk("Demand map pfns start at %lx (%p).\n", max_pfn,
|
||||
demand_map_area_start);
|
||||
start_addr = (unsigned long)demand_map_area_start;
|
||||
|
||||
tab = (pgentry_t *)start_info.pt_base;
|
||||
mfn = virt_to_mfn(start_info.pt_base);
|
||||
pt_pfn = virt_to_pfn(alloc_page());
|
||||
|
||||
#if defined(__x86_64__)
|
||||
offset = l4_table_offset(start_addr);
|
||||
if (!(tab[offset] & _PAGE_PRESENT)) {
|
||||
new_pt_frame(&pt_pfn, mfn, offset, L3_FRAME);
|
||||
pt_pfn = virt_to_pfn(alloc_page());
|
||||
}
|
||||
ASSERT(tab[offset] & _PAGE_PRESENT);
|
||||
mfn = pte_to_mfn(tab[offset]);
|
||||
tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
|
||||
#endif
|
||||
#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
|
||||
offset = l3_table_offset(start_addr);
|
||||
if (!(tab[offset] & _PAGE_PRESENT)) {
|
||||
new_pt_frame(&pt_pfn, mfn, offset, L2_FRAME);
|
||||
pt_pfn = virt_to_pfn(alloc_page());
|
||||
}
|
||||
ASSERT(tab[offset] & _PAGE_PRESENT);
|
||||
mfn = pte_to_mfn(tab[offset]);
|
||||
tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
|
||||
#endif
|
||||
offset = l2_table_offset(start_addr);
|
||||
if (tab[offset] & _PAGE_PRESENT) {
|
||||
printk("Demand map area already has a page table covering it?\n");
|
||||
BUG();
|
||||
}
|
||||
demand_map_pgt = pfn_to_virt(pt_pfn);
|
||||
new_pt_frame(&pt_pfn, mfn, offset, L1_FRAME);
|
||||
ASSERT(tab[offset] & _PAGE_PRESENT);
|
||||
}
|
||||
|
||||
void *map_frames(unsigned long *f, unsigned long n)
|
||||
{
|
||||
unsigned long x;
|
||||
unsigned long y = 0;
|
||||
mmu_update_t mmu_updates[16];
|
||||
int rc;
|
||||
|
||||
if (n > 16) {
|
||||
printk("Tried to map too many (%ld) frames at once.\n", n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find a run of n contiguous frames */
|
||||
for (x = 0; x <= 1024 - n; x += y + 1) {
|
||||
for (y = 0; y < n; y++)
|
||||
if (demand_map_pgt[y] & _PAGE_PRESENT)
|
||||
break;
|
||||
if (y == n)
|
||||
break;
|
||||
}
|
||||
if (y != n) {
|
||||
printk("Failed to map %ld frames!\n", n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Found it at x. Map it in. */
|
||||
for (y = 0; y < n; y++) {
|
||||
mmu_updates[y].ptr = virt_to_mach(&demand_map_pgt[x + y]);
|
||||
mmu_updates[y].val = (f[y] << PAGE_SHIFT) | L1_PROT;
|
||||
}
|
||||
|
||||
rc = HYPERVISOR_mmu_update(mmu_updates, n, NULL, DOMID_SELF);
|
||||
if (rc < 0) {
|
||||
printk("Map %ld failed: %d.\n", n, rc);
|
||||
return NULL;
|
||||
} else {
|
||||
return (void *)(unsigned long)((unsigned long)demand_map_area_start +
|
||||
x * PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void init_mm(void)
|
||||
{
|
||||
|
||||
@@ -643,4 +744,24 @@ void init_mm(void)
|
||||
(u_long)to_virt(PFN_PHYS(max_pfn)), PFN_PHYS(max_pfn));
|
||||
init_page_allocator(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn));
|
||||
printk("MM: done\n");
|
||||
|
||||
init_demand_mapping_area(max_pfn);
|
||||
printk("Initialised demand area.\n");
|
||||
}
|
||||
|
||||
void sanity_check(void)
|
||||
{
|
||||
int x;
|
||||
chunk_head_t *head;
|
||||
|
||||
for (x = 0; x < FREELIST_SIZE; x++) {
|
||||
for (head = free_head[x]; !FREELIST_EMPTY(head); head = head->next) {
|
||||
ASSERT(!allocated_in_map(virt_to_pfn(head)));
|
||||
if (head->next)
|
||||
ASSERT(head->next->pprev == &head->next);
|
||||
}
|
||||
if (free_head[x]) {
|
||||
ASSERT(free_head[x]->pprev == &free_head[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,7 +215,7 @@ void block_domain(u32 millisecs)
|
||||
/*
|
||||
* Just a dummy
|
||||
*/
|
||||
static void timer_handler(int ev, struct pt_regs *regs)
|
||||
static void timer_handler(int ev, struct pt_regs *regs, void *ign)
|
||||
{
|
||||
static int i;
|
||||
|
||||
@@ -233,5 +233,5 @@ static void timer_handler(int ev, struct pt_regs *regs)
|
||||
void init_time(void)
|
||||
{
|
||||
printk("Initialising timer interface\n");
|
||||
bind_virq(VIRQ_TIMER, &timer_handler);
|
||||
bind_virq(VIRQ_TIMER, &timer_handler, NULL);
|
||||
}
|
||||
@@ -112,7 +112,7 @@ static void xenbus_thread_func(void *ign)
|
||||
}
|
||||
}
|
||||
|
||||
static void xenbus_evtchn_handler(int port, struct pt_regs *regs)
|
||||
static void xenbus_evtchn_handler(int port, struct pt_regs *regs, void *ign)
|
||||
{
|
||||
wake_up(&xb_waitq);
|
||||
}
|
||||
@@ -174,7 +174,8 @@ void init_xenbus(void)
|
||||
create_thread("xenstore", xenbus_thread_func, NULL);
|
||||
DEBUG("buf at %p.\n", xenstore_buf);
|
||||
err = bind_evtchn(start_info.store_evtchn,
|
||||
xenbus_evtchn_handler);
|
||||
xenbus_evtchn_handler,
|
||||
NULL);
|
||||
DEBUG("xenbus on irq %d\n", err);
|
||||
}
|
||||
|
||||
@@ -187,8 +188,8 @@ struct write_req {
|
||||
by xenbus as if sent atomically. The header is added
|
||||
automatically, using type %type, req_id %req_id, and trans_id
|
||||
%trans_id. */
|
||||
static void xb_write(int type, int req_id, int trans_id,
|
||||
const struct write_req *req, int nr_reqs)
|
||||
static void xb_write(int type, int req_id, xenbus_transaction_t trans_id,
|
||||
const struct write_req *req, int nr_reqs)
|
||||
{
|
||||
XENSTORE_RING_IDX prod;
|
||||
int r;
|
||||
@@ -266,9 +267,9 @@ static void xb_write(int type, int req_id, int trans_id,
|
||||
freed by the caller. */
|
||||
static struct xsd_sockmsg *
|
||||
xenbus_msg_reply(int type,
|
||||
int trans,
|
||||
struct write_req *io,
|
||||
int nr_reqs)
|
||||
xenbus_transaction_t trans,
|
||||
struct write_req *io,
|
||||
int nr_reqs)
|
||||
{
|
||||
int id;
|
||||
DEFINE_WAIT(w);
|
||||
@@ -322,14 +323,14 @@ static void xenbus_debug_msg(const char *msg)
|
||||
/* List the contents of a directory. Returns a malloc()ed array of
|
||||
pointers to malloc()ed strings. The array is NULL terminated. May
|
||||
block. */
|
||||
char *xenbus_ls(const char *pre, char ***contents)
|
||||
char *xenbus_ls(xenbus_transaction_t xbt, const char *pre, char ***contents)
|
||||
{
|
||||
struct xsd_sockmsg *reply, *repmsg;
|
||||
struct write_req req[] = { { pre, strlen(pre)+1 } };
|
||||
int nr_elems, x, i;
|
||||
char **res;
|
||||
|
||||
repmsg = xenbus_msg_reply(XS_DIRECTORY, 0, req, ARRAY_SIZE(req));
|
||||
repmsg = xenbus_msg_reply(XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
|
||||
char *msg = errmsg(repmsg);
|
||||
if (msg) {
|
||||
*contents = NULL;
|
||||
@@ -351,12 +352,12 @@ char *xenbus_ls(const char *pre, char ***contents)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *xenbus_read(const char *path, char **value)
|
||||
char *xenbus_read(xenbus_transaction_t xbt, const char *path, char **value)
|
||||
{
|
||||
struct write_req req[] = { {path, strlen(path) + 1} };
|
||||
struct xsd_sockmsg *rep;
|
||||
char *res;
|
||||
rep = xenbus_msg_reply(XS_READ, 0, req, ARRAY_SIZE(req));
|
||||
rep = xenbus_msg_reply(XS_READ, xbt, req, ARRAY_SIZE(req));
|
||||
char *msg = errmsg(rep);
|
||||
if (msg) {
|
||||
*value = NULL;
|
||||
@@ -370,14 +371,14 @@ char *xenbus_read(const char *path, char **value)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *xenbus_write(const char *path, const char *value)
|
||||
char *xenbus_write(xenbus_transaction_t xbt, const char *path, const char *value)
|
||||
{
|
||||
struct write_req req[] = {
|
||||
{path, strlen(path) + 1},
|
||||
{value, strlen(value) + 1},
|
||||
};
|
||||
struct xsd_sockmsg *rep;
|
||||
rep = xenbus_msg_reply(XS_WRITE, 0, req, ARRAY_SIZE(req));
|
||||
rep = xenbus_msg_reply(XS_WRITE, xbt, req, ARRAY_SIZE(req));
|
||||
char *msg = errmsg(rep);
|
||||
if (msg)
|
||||
return msg;
|
||||
@@ -385,11 +386,11 @@ char *xenbus_write(const char *path, const char *value)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *xenbus_rm(const char *path)
|
||||
char *xenbus_rm(xenbus_transaction_t xbt, const char *path)
|
||||
{
|
||||
struct write_req req[] = { {path, strlen(path) + 1} };
|
||||
struct xsd_sockmsg *rep;
|
||||
rep = xenbus_msg_reply(XS_RM, 0, req, ARRAY_SIZE(req));
|
||||
rep = xenbus_msg_reply(XS_RM, xbt, req, ARRAY_SIZE(req));
|
||||
char *msg = errmsg(rep);
|
||||
if (msg)
|
||||
return msg;
|
||||
@@ -397,12 +398,12 @@ char *xenbus_rm(const char *path)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *xenbus_get_perms(const char *path, char **value)
|
||||
char *xenbus_get_perms(xenbus_transaction_t xbt, const char *path, char **value)
|
||||
{
|
||||
struct write_req req[] = { {path, strlen(path) + 1} };
|
||||
struct xsd_sockmsg *rep;
|
||||
char *res;
|
||||
rep = xenbus_msg_reply(XS_GET_PERMS, 0, req, ARRAY_SIZE(req));
|
||||
rep = xenbus_msg_reply(XS_GET_PERMS, xbt, req, ARRAY_SIZE(req));
|
||||
char *msg = errmsg(rep);
|
||||
if (msg) {
|
||||
*value = NULL;
|
||||
@@ -417,7 +418,7 @@ char *xenbus_get_perms(const char *path, char **value)
|
||||
}
|
||||
|
||||
#define PERM_MAX_SIZE 32
|
||||
char *xenbus_set_perms(const char *path, domid_t dom, char perm)
|
||||
char *xenbus_set_perms(xenbus_transaction_t xbt, const char *path, domid_t dom, char perm)
|
||||
{
|
||||
char value[PERM_MAX_SIZE];
|
||||
snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, dom);
|
||||
@@ -426,7 +427,7 @@ char *xenbus_set_perms(const char *path, domid_t dom, char perm)
|
||||
{value, strlen(value) + 1},
|
||||
};
|
||||
struct xsd_sockmsg *rep;
|
||||
rep = xenbus_msg_reply(XS_SET_PERMS, 0, req, ARRAY_SIZE(req));
|
||||
rep = xenbus_msg_reply(XS_SET_PERMS, xbt, req, ARRAY_SIZE(req));
|
||||
char *msg = errmsg(rep);
|
||||
if (msg)
|
||||
return msg;
|
||||
@@ -434,13 +435,72 @@ char *xenbus_set_perms(const char *path, domid_t dom, char perm)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *xenbus_transaction_start(xenbus_transaction_t *xbt)
|
||||
{
|
||||
/* xenstored becomes angry if you send a length 0 message, so just
|
||||
shove a nul terminator on the end */
|
||||
struct write_req req = { "", 1};
|
||||
struct xsd_sockmsg *rep;
|
||||
char *err;
|
||||
|
||||
rep = xenbus_msg_reply(XS_TRANSACTION_START, 0, &req, 1);
|
||||
err = errmsg(rep);
|
||||
if (err)
|
||||
return err;
|
||||
sscanf((char *)(rep + 1), "%u", xbt);
|
||||
free(rep);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *
|
||||
xenbus_transaction_end(xenbus_transaction_t t, int abort, int *retry)
|
||||
{
|
||||
struct xsd_sockmsg *rep;
|
||||
struct write_req req;
|
||||
char *err;
|
||||
|
||||
*retry = 0;
|
||||
|
||||
req.data = abort ? "F" : "T";
|
||||
req.len = 2;
|
||||
rep = xenbus_msg_reply(XS_TRANSACTION_END, t, &req, 1);
|
||||
err = errmsg(rep);
|
||||
if (err) {
|
||||
if (!strcmp(err, "EAGAIN")) {
|
||||
*retry = 1;
|
||||
free(err);
|
||||
return NULL;
|
||||
} else {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
free(rep);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int xenbus_read_integer(char *path)
|
||||
{
|
||||
char *res, *buf;
|
||||
int t;
|
||||
|
||||
res = xenbus_read(XBT_NIL, path, &buf);
|
||||
if (res) {
|
||||
printk("Failed to read %s.\n", path);
|
||||
free(res);
|
||||
return -1;
|
||||
}
|
||||
sscanf(buf, "%d", &t);
|
||||
free(buf);
|
||||
return t;
|
||||
}
|
||||
|
||||
static void do_ls_test(const char *pre)
|
||||
{
|
||||
char **dirs;
|
||||
int x;
|
||||
|
||||
DEBUG("ls %s...\n", pre);
|
||||
char *msg = xenbus_ls(pre, &dirs);
|
||||
char *msg = xenbus_ls(XBT_NIL, pre, &dirs);
|
||||
if (msg) {
|
||||
DEBUG("Error in xenbus ls: %s\n", msg);
|
||||
free(msg);
|
||||
@@ -458,7 +518,7 @@ static void do_read_test(const char *path)
|
||||
{
|
||||
char *res;
|
||||
DEBUG("Read %s...\n", path);
|
||||
char *msg = xenbus_read(path, &res);
|
||||
char *msg = xenbus_read(XBT_NIL, path, &res);
|
||||
if (msg) {
|
||||
DEBUG("Error in xenbus read: %s\n", msg);
|
||||
free(msg);
|
||||
@@ -471,7 +531,7 @@ static void do_read_test(const char *path)
|
||||
static void do_write_test(const char *path, const char *val)
|
||||
{
|
||||
DEBUG("Write %s to %s...\n", val, path);
|
||||
char *msg = xenbus_write(path, val);
|
||||
char *msg = xenbus_write(XBT_NIL, path, val);
|
||||
if (msg) {
|
||||
DEBUG("Result %s\n", msg);
|
||||
free(msg);
|
||||
@@ -483,7 +543,7 @@ static void do_write_test(const char *path, const char *val)
|
||||
static void do_rm_test(const char *path)
|
||||
{
|
||||
DEBUG("rm %s...\n", path);
|
||||
char *msg = xenbus_rm(path);
|
||||
char *msg = xenbus_rm(XBT_NIL, path);
|
||||
if (msg) {
|
||||
DEBUG("Result %s\n", msg);
|
||||
free(msg);
|
||||
|
||||
@@ -442,6 +442,7 @@ void flush_tlb_mm(struct mm_struct * mm)
|
||||
{ xen_tlb_flush_mask(&mm->cpu_vm_mask); }
|
||||
void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
|
||||
{ xen_invlpg_mask(&vma->vm_mm->cpu_vm_mask, va); }
|
||||
EXPORT_SYMBOL(flush_tlb_page);
|
||||
void flush_tlb_all(void)
|
||||
{ xen_tlb_flush_all(); }
|
||||
|
||||
|
||||
@@ -989,12 +989,11 @@ static void stop_hz_timer(void)
|
||||
|
||||
smp_mb();
|
||||
|
||||
/* Leave ourselves in 'tick mode' if rcu or softirq pending. */
|
||||
if (rcu_needs_cpu(cpu) || local_softirq_pending()) {
|
||||
/* Leave ourselves in 'tick mode' if rcu or softirq or timer pending. */
|
||||
if (rcu_needs_cpu(cpu) || local_softirq_pending() ||
|
||||
(j = next_timer_interrupt(), time_before_eq(j, jiffies))) {
|
||||
cpu_clear(cpu, nohz_cpu_mask);
|
||||
j = jiffies + 1;
|
||||
} else {
|
||||
j = next_timer_interrupt();
|
||||
}
|
||||
|
||||
BUG_ON(HYPERVISOR_set_timer_op(jiffies_to_st(j)) != 0);
|
||||
|
||||
@@ -60,7 +60,7 @@ void *kmap_atomic_pte(struct page *page, enum km_type type)
|
||||
|
||||
void kunmap_atomic(void *kvaddr, enum km_type type)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_HIGHMEM
|
||||
#if defined(CONFIG_DEBUG_HIGHMEM) || defined(CONFIG_XEN)
|
||||
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
|
||||
enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
|
||||
|
||||
@@ -69,7 +69,9 @@ void kunmap_atomic(void *kvaddr, enum km_type type)
|
||||
preempt_check_resched();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DEBUG_HIGHMEM)
|
||||
if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx))
|
||||
BUG();
|
||||
|
||||
@@ -79,6 +81,14 @@ void kunmap_atomic(void *kvaddr, enum km_type type)
|
||||
*/
|
||||
pte_clear(&init_mm, vaddr, kmap_pte-idx);
|
||||
__flush_tlb_one(vaddr);
|
||||
#elif defined(CONFIG_XEN)
|
||||
/*
|
||||
* We must ensure there are no dangling pagetable references when
|
||||
* returning memory to Xen (decrease_reservation).
|
||||
* XXX TODO: We could make this faster by only zapping when
|
||||
* kmap_flush_unused is called but that is trickier and more invasive.
|
||||
*/
|
||||
pte_clear(&init_mm, vaddr, kmap_pte-idx);
|
||||
#endif
|
||||
|
||||
dec_preempt_count();
|
||||
|
||||
@@ -271,10 +271,6 @@ static unsigned long discontig_frames[1<<MAX_CONTIG_ORDER];
|
||||
int xen_create_contiguous_region(
|
||||
unsigned long vstart, unsigned int order, unsigned int address_bits)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned long *in_frames = discontig_frames, out_frame;
|
||||
unsigned long frame, i, flags;
|
||||
long rc;
|
||||
@@ -301,7 +297,7 @@ int xen_create_contiguous_region(
|
||||
if (xen_feature(XENFEAT_auto_translated_physmap))
|
||||
return 0;
|
||||
|
||||
if (order > MAX_CONTIG_ORDER)
|
||||
if (unlikely(order > MAX_CONTIG_ORDER))
|
||||
return -ENOMEM;
|
||||
|
||||
set_xen_guest_handle(exchange.in.extent_start, in_frames);
|
||||
@@ -313,11 +309,7 @@ int xen_create_contiguous_region(
|
||||
|
||||
/* 1. Zap current PTEs, remembering MFNs. */
|
||||
for (i = 0; i < (1UL<<order); i++) {
|
||||
pgd = pgd_offset_k(vstart + (i*PAGE_SIZE));
|
||||
pud = pud_offset(pgd, (vstart + (i*PAGE_SIZE)));
|
||||
pmd = pmd_offset(pud, (vstart + (i*PAGE_SIZE)));
|
||||
pte = pte_offset_kernel(pmd, (vstart + (i*PAGE_SIZE)));
|
||||
in_frames[i] = pte_mfn(*pte);
|
||||
in_frames[i] = pfn_to_mfn((__pa(vstart) >> PAGE_SHIFT) + i);
|
||||
if (HYPERVISOR_update_va_mapping(vstart + (i*PAGE_SIZE),
|
||||
__pte_ma(0), 0))
|
||||
BUG();
|
||||
@@ -372,10 +364,6 @@ int xen_create_contiguous_region(
|
||||
|
||||
void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
unsigned long *out_frames = discontig_frames, in_frame;
|
||||
unsigned long frame, i, flags;
|
||||
long rc;
|
||||
@@ -397,7 +385,7 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
|
||||
!test_bit(__pa(vstart) >> PAGE_SHIFT, contiguous_bitmap))
|
||||
return;
|
||||
|
||||
if (order > MAX_CONTIG_ORDER)
|
||||
if (unlikely(order > MAX_CONTIG_ORDER))
|
||||
return;
|
||||
|
||||
set_xen_guest_handle(exchange.in.extent_start, &in_frame);
|
||||
@@ -410,16 +398,13 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
|
||||
contiguous_bitmap_clear(__pa(vstart) >> PAGE_SHIFT, 1UL << order);
|
||||
|
||||
/* 1. Find start MFN of contiguous extent. */
|
||||
pgd = pgd_offset_k(vstart);
|
||||
pud = pud_offset(pgd, vstart);
|
||||
pmd = pmd_offset(pud, vstart);
|
||||
pte = pte_offset_kernel(pmd, vstart);
|
||||
in_frame = pte_mfn(*pte);
|
||||
in_frame = pfn_to_mfn(__pa(vstart) >> PAGE_SHIFT);
|
||||
|
||||
/* 2. Zap current PTEs. */
|
||||
for (i = 0; i < (1UL<<order); i++) {
|
||||
if (HYPERVISOR_update_va_mapping(vstart + (i*PAGE_SIZE),
|
||||
__pte_ma(0), 0));
|
||||
__pte_ma(0), 0))
|
||||
BUG();
|
||||
set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i,
|
||||
INVALID_P2M_ENTRY);
|
||||
out_frames[i] = (__pa(vstart) >> PAGE_SHIFT) + i;
|
||||
@@ -430,7 +415,7 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
|
||||
success = (exchange.nr_exchanged == 1);
|
||||
BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
|
||||
BUG_ON(success && (rc != 0));
|
||||
if (rc == -ENOSYS) {
|
||||
if (unlikely(rc == -ENOSYS)) {
|
||||
/* Compatibility when XENMEM_exchange is unsupported. */
|
||||
if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
|
||||
&exchange.in) != 1)
|
||||
|
||||
@@ -20,9 +20,18 @@ config TCG_TPM
|
||||
Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI
|
||||
and CONFIG_PNPACPI.
|
||||
|
||||
config TCG_TIS
|
||||
tristate "TPM Interface Specification 1.2 Interface"
|
||||
depends on TCG_TPM
|
||||
---help---
|
||||
If you have a TPM security chip that is compliant with the
|
||||
TCG TIS 1.2 TPM specification say Yes and it will be accessible
|
||||
from within Linux. To compile this driver as a module, choose
|
||||
M here; the module will be called tpm_tis.
|
||||
|
||||
config TCG_NSC
|
||||
tristate "National Semiconductor TPM Interface"
|
||||
depends on TCG_TPM && !XEN_UNPRIVILEGED_GUEST
|
||||
depends on TCG_TPM && PNPACPI
|
||||
---help---
|
||||
If you have a TPM security chip from National Semicondutor
|
||||
say Yes and it will be accessible from within Linux. To
|
||||
@@ -31,7 +40,7 @@ config TCG_NSC
|
||||
|
||||
config TCG_ATMEL
|
||||
tristate "Atmel TPM Interface"
|
||||
depends on TCG_TPM && !XEN_UNPRIVILEGED_GUEST
|
||||
depends on TCG_TPM
|
||||
---help---
|
||||
If you have a TPM security chip from Atmel say Yes and it
|
||||
will be accessible from within Linux. To compile this driver
|
||||
|
||||
@@ -5,6 +5,7 @@ obj-$(CONFIG_TCG_TPM) += tpm.o
|
||||
ifdef CONFIG_ACPI
|
||||
obj-$(CONFIG_TCG_TPM) += tpm_bios.o
|
||||
endif
|
||||
obj-$(CONFIG_TCG_TIS) += tpm_tis.o
|
||||
obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
|
||||
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
|
||||
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -24,6 +24,14 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
enum tpm_bufsize {
|
||||
TPM_MIN_BUFFERSIZE = 2048,
|
||||
TPM_MAX_BUFFERSIZE = 64 * 1024,
|
||||
};
|
||||
#endif
|
||||
|
||||
enum tpm_timeout {
|
||||
TPM_TIMEOUT = 5, /* msecs */
|
||||
@@ -41,19 +49,33 @@ extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
|
||||
char *);
|
||||
extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
|
||||
char *);
|
||||
extern ssize_t tpm_show_caps_1_2(struct device *, struct device_attribute *attr,
|
||||
char *);
|
||||
extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
|
||||
const char *, size_t);
|
||||
extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr,
|
||||
char *);
|
||||
extern ssize_t tpm_show_active(struct device *, struct device_attribute *attr,
|
||||
char *);
|
||||
extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr,
|
||||
char *);
|
||||
extern ssize_t tpm_show_temp_deactivated(struct device *,
|
||||
struct device_attribute *attr, char *);
|
||||
|
||||
struct tpm_chip;
|
||||
|
||||
struct tpm_vendor_specific {
|
||||
u8 req_complete_mask;
|
||||
u8 req_complete_val;
|
||||
u8 req_canceled;
|
||||
const u8 req_complete_mask;
|
||||
const u8 req_complete_val;
|
||||
const u8 req_canceled;
|
||||
#ifdef CONFIG_XEN
|
||||
u32 buffersize;
|
||||
#endif
|
||||
void __iomem *iobase; /* ioremapped address */
|
||||
unsigned long base; /* TPM base address */
|
||||
|
||||
int irq;
|
||||
|
||||
int region_size;
|
||||
int have_region;
|
||||
|
||||
@@ -63,6 +85,13 @@ struct tpm_vendor_specific {
|
||||
u8 (*status) (struct tpm_chip *);
|
||||
struct miscdevice miscdev;
|
||||
struct attribute_group *attr_group;
|
||||
struct list_head list;
|
||||
int locality;
|
||||
unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
|
||||
unsigned long duration[3]; /* jiffies */
|
||||
|
||||
wait_queue_head_t read_queue;
|
||||
wait_queue_head_t int_queue;
|
||||
};
|
||||
|
||||
struct tpm_chip {
|
||||
@@ -75,20 +104,27 @@ struct tpm_chip {
|
||||
/* Data passed to and from the tpm via the read/write calls */
|
||||
u8 *data_buffer;
|
||||
atomic_t data_pending;
|
||||
#ifdef CONFIG_XEN
|
||||
atomic_t data_position;
|
||||
#endif
|
||||
struct semaphore buffer_mutex;
|
||||
|
||||
struct timer_list user_read_timer; /* user needs to claim result */
|
||||
struct work_struct work;
|
||||
struct semaphore tpm_mutex; /* tpm is processing */
|
||||
|
||||
struct tpm_vendor_specific *vendor;
|
||||
struct tpm_vendor_specific vendor;
|
||||
|
||||
struct dentry **bios_dir;
|
||||
|
||||
struct list_head list;
|
||||
#ifdef CONFIG_XEN
|
||||
void *priv;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
|
||||
|
||||
static inline int tpm_read_index(int base, int index)
|
||||
{
|
||||
outb(index, base);
|
||||
@@ -101,13 +137,35 @@ static inline void tpm_write_index(int base, int index, int value)
|
||||
outb(value & 0xFF, base+1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
static inline u32 get_chip_buffersize(struct tpm_chip *chip)
|
||||
{
|
||||
return chip->vendor->buffersize;
|
||||
u32 size = chip->vendor.buffersize;
|
||||
if (size > TPM_MAX_BUFFERSIZE) {
|
||||
return TPM_MAX_BUFFERSIZE;
|
||||
} else if (size < TPM_MIN_BUFFERSIZE) {
|
||||
return TPM_MIN_BUFFERSIZE;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
extern int tpm_register_hardware(struct device *,
|
||||
struct tpm_vendor_specific *);
|
||||
static inline void *chip_get_private(const struct tpm_chip *chip)
|
||||
{
|
||||
return chip->priv;
|
||||
}
|
||||
|
||||
static inline void chip_set_private(struct tpm_chip *chip, void *priv)
|
||||
{
|
||||
chip->priv = priv;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void tpm_get_timeouts(struct tpm_chip *);
|
||||
extern void tpm_gen_interrupt(struct tpm_chip *);
|
||||
extern void tpm_continue_selftest(struct tpm_chip *);
|
||||
extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
|
||||
extern struct tpm_chip* tpm_register_hardware(struct device *,
|
||||
const struct tpm_vendor_specific *);
|
||||
extern int tpm_open(struct inode *, struct file *);
|
||||
extern int tpm_release(struct inode *, struct file *);
|
||||
extern ssize_t tpm_write(struct file *, const char __user *, size_t,
|
||||
@@ -121,7 +179,7 @@ extern int tpm_pm_resume(struct device *);
|
||||
extern struct dentry ** tpm_bios_log_setup(char *);
|
||||
extern void tpm_bios_log_teardown(struct dentry **);
|
||||
#else
|
||||
static inline struct dentry* tpm_bios_log_setup(char *name)
|
||||
static inline struct dentry ** tpm_bios_log_setup(char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,6 @@ enum {
|
||||
STATUS_READY = 0x04
|
||||
};
|
||||
|
||||
#define MIN(x,y) ((x) < (y)) ? (x) : (y)
|
||||
|
||||
struct transmission {
|
||||
struct list_head next;
|
||||
|
||||
@@ -49,26 +47,6 @@ enum {
|
||||
TRANSMISSION_FLAG_WAS_QUEUED = 0x1
|
||||
};
|
||||
|
||||
struct vtpm_state {
|
||||
struct transmission *current_request;
|
||||
spinlock_t req_list_lock;
|
||||
wait_queue_head_t req_wait_queue;
|
||||
|
||||
struct list_head queued_requests;
|
||||
|
||||
struct transmission *current_response;
|
||||
spinlock_t resp_list_lock;
|
||||
wait_queue_head_t resp_wait_queue; // processes waiting for responses
|
||||
|
||||
struct transmission *req_cancelled; // if a cancellation was encounterd
|
||||
|
||||
u8 vd_status;
|
||||
u8 flags;
|
||||
|
||||
unsigned long disconnect_time;
|
||||
|
||||
struct tpm_virtual_device *tpmvd;
|
||||
};
|
||||
|
||||
enum {
|
||||
DATAEX_FLAG_QUEUED_ONLY = 0x1
|
||||
@@ -76,7 +54,6 @@ enum {
|
||||
|
||||
|
||||
/* local variables */
|
||||
static struct vtpm_state *vtpms;
|
||||
|
||||
/* local function prototypes */
|
||||
static int _vtpm_send_queued(struct tpm_chip *chip);
|
||||
@@ -160,11 +137,16 @@ static inline void transmission_free(struct transmission *t)
|
||||
/*
|
||||
* Lower layer uses this function to make a response available.
|
||||
*/
|
||||
int vtpm_vd_recv(const unsigned char *buffer, size_t count, const void *ptr)
|
||||
int vtpm_vd_recv(const struct tpm_chip *chip,
|
||||
const unsigned char *buffer, size_t count,
|
||||
void *ptr)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret_size = 0;
|
||||
struct transmission *t;
|
||||
struct vtpm_state *vtpms;
|
||||
|
||||
vtpms = (struct vtpm_state *)chip_get_private(chip);
|
||||
|
||||
/*
|
||||
* The list with requests must contain one request
|
||||
@@ -173,26 +155,11 @@ int vtpm_vd_recv(const unsigned char *buffer, size_t count, const void *ptr)
|
||||
*/
|
||||
spin_lock_irqsave(&vtpms->resp_list_lock, flags);
|
||||
if (vtpms->current_request != ptr) {
|
||||
printk("WARNING: The request pointer is different than the "
|
||||
"pointer the shared memory driver returned to me. "
|
||||
"%p != %p\n",
|
||||
vtpms->current_request, ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the request has been cancelled, just quit here
|
||||
*/
|
||||
if (vtpms->req_cancelled == (struct transmission *)ptr) {
|
||||
if (vtpms->current_request == vtpms->req_cancelled) {
|
||||
vtpms->current_request = NULL;
|
||||
}
|
||||
transmission_free(vtpms->req_cancelled);
|
||||
vtpms->req_cancelled = NULL;
|
||||
spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (NULL != (t = vtpms->current_request)) {
|
||||
if ((t = vtpms->current_request)) {
|
||||
transmission_free(t);
|
||||
vtpms->current_request = NULL;
|
||||
}
|
||||
@@ -217,8 +184,12 @@ int vtpm_vd_recv(const unsigned char *buffer, size_t count, const void *ptr)
|
||||
/*
|
||||
* Lower layer indicates its status (connected/disconnected)
|
||||
*/
|
||||
void vtpm_vd_status(u8 vd_status)
|
||||
void vtpm_vd_status(const struct tpm_chip *chip, u8 vd_status)
|
||||
{
|
||||
struct vtpm_state *vtpms;
|
||||
|
||||
vtpms = (struct vtpm_state *)chip_get_private(chip);
|
||||
|
||||
vtpms->vd_status = vd_status;
|
||||
if ((vtpms->vd_status & TPM_VD_STATUS_CONNECTED) == 0) {
|
||||
vtpms->disconnect_time = jiffies;
|
||||
@@ -233,6 +204,9 @@ static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long flags;
|
||||
struct vtpm_state *vtpms;
|
||||
|
||||
vtpms = (struct vtpm_state *)chip_get_private(chip);
|
||||
|
||||
/*
|
||||
* Check if the previous operation only queued the command
|
||||
@@ -251,7 +225,7 @@ static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
* Return a response of up to 30 '0's.
|
||||
*/
|
||||
|
||||
count = MIN(count, 30);
|
||||
count = min_t(size_t, count, 30);
|
||||
memset(buf, 0x0, count);
|
||||
return count;
|
||||
}
|
||||
@@ -270,7 +244,7 @@ static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
if (vtpms->current_response) {
|
||||
struct transmission *t = vtpms->current_response;
|
||||
vtpms->current_response = NULL;
|
||||
rc = MIN(count, t->response_len);
|
||||
rc = min(count, t->response_len);
|
||||
memcpy(buf, t->response, rc);
|
||||
transmission_free(t);
|
||||
}
|
||||
@@ -284,6 +258,9 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
int rc = 0;
|
||||
unsigned long flags;
|
||||
struct transmission *t = transmission_alloc();
|
||||
struct vtpm_state *vtpms;
|
||||
|
||||
vtpms = (struct vtpm_state *)chip_get_private(chip);
|
||||
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
@@ -327,8 +304,7 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
|
||||
vtpms->current_request = t;
|
||||
|
||||
rc = vtpm_vd_send(chip,
|
||||
vtpms->tpmvd->tpm_private,
|
||||
rc = vtpm_vd_send(vtpms->tpm_private,
|
||||
buf,
|
||||
count,
|
||||
t);
|
||||
@@ -373,6 +349,8 @@ static int _vtpm_send_queued(struct tpm_chip *chip)
|
||||
int error = 0;
|
||||
long flags;
|
||||
unsigned char buffer[1];
|
||||
struct vtpm_state *vtpms;
|
||||
vtpms = (struct vtpm_state *)chip_get_private(chip);
|
||||
|
||||
spin_lock_irqsave(&vtpms->req_list_lock, flags);
|
||||
|
||||
@@ -387,8 +365,7 @@ static int _vtpm_send_queued(struct tpm_chip *chip)
|
||||
vtpms->current_request = qt;
|
||||
spin_unlock_irqrestore(&vtpms->req_list_lock, flags);
|
||||
|
||||
rc = vtpm_vd_send(chip,
|
||||
vtpms->tpmvd->tpm_private,
|
||||
rc = vtpm_vd_send(vtpms->tpm_private,
|
||||
qt->request,
|
||||
qt->request_len,
|
||||
qt);
|
||||
@@ -427,9 +404,21 @@ static int _vtpm_send_queued(struct tpm_chip *chip)
|
||||
static void vtpm_cancel(struct tpm_chip *chip)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct vtpm_state *vtpms = (struct vtpm_state *)chip_get_private(chip);
|
||||
|
||||
spin_lock_irqsave(&vtpms->resp_list_lock,flags);
|
||||
|
||||
vtpms->req_cancelled = vtpms->current_request;
|
||||
if (!vtpms->current_response && vtpms->current_request) {
|
||||
spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
|
||||
interruptible_sleep_on(&vtpms->resp_wait_queue);
|
||||
spin_lock_irqsave(&vtpms->resp_list_lock,flags);
|
||||
}
|
||||
|
||||
if (vtpms->current_response) {
|
||||
struct transmission *t = vtpms->current_response;
|
||||
vtpms->current_response = NULL;
|
||||
transmission_free(t);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&vtpms->resp_list_lock,flags);
|
||||
}
|
||||
@@ -438,6 +427,9 @@ static u8 vtpm_status(struct tpm_chip *chip)
|
||||
{
|
||||
u8 rc = 0;
|
||||
unsigned long flags;
|
||||
struct vtpm_state *vtpms;
|
||||
|
||||
vtpms = (struct vtpm_state *)chip_get_private(chip);
|
||||
|
||||
spin_lock_irqsave(&vtpms->resp_list_lock, flags);
|
||||
/*
|
||||
@@ -449,7 +441,10 @@ static u8 vtpm_status(struct tpm_chip *chip)
|
||||
if (vtpms->current_response ||
|
||||
0 != (vtpms->flags & DATAEX_FLAG_QUEUED_ONLY)) {
|
||||
rc = STATUS_DATA_AVAIL;
|
||||
} else if (!vtpms->current_response && !vtpms->current_request) {
|
||||
rc = STATUS_READY;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&vtpms->resp_list_lock, flags);
|
||||
return rc;
|
||||
}
|
||||
@@ -465,12 +460,21 @@ static struct file_operations vtpm_ops = {
|
||||
|
||||
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
|
||||
static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
|
||||
static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
|
||||
static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
|
||||
static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
|
||||
static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
|
||||
NULL);
|
||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
|
||||
static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
|
||||
|
||||
static struct attribute *vtpm_attrs[] = {
|
||||
&dev_attr_pubek.attr,
|
||||
&dev_attr_pcrs.attr,
|
||||
&dev_attr_enabled.attr,
|
||||
&dev_attr_active.attr,
|
||||
&dev_attr_owned.attr,
|
||||
&dev_attr_temp_deactivated.attr,
|
||||
&dev_attr_caps.attr,
|
||||
&dev_attr_cancel.attr,
|
||||
NULL,
|
||||
@@ -478,6 +482,8 @@ static struct attribute *vtpm_attrs[] = {
|
||||
|
||||
static struct attribute_group vtpm_attr_grp = { .attrs = vtpm_attrs };
|
||||
|
||||
#define TPM_LONG_TIMEOUT (10 * 60 * HZ)
|
||||
|
||||
static struct tpm_vendor_specific tpm_vtpm = {
|
||||
.recv = vtpm_recv,
|
||||
.send = vtpm_send,
|
||||
@@ -486,61 +492,56 @@ static struct tpm_vendor_specific tpm_vtpm = {
|
||||
.req_complete_mask = STATUS_BUSY | STATUS_DATA_AVAIL,
|
||||
.req_complete_val = STATUS_DATA_AVAIL,
|
||||
.req_canceled = STATUS_READY,
|
||||
.base = 0,
|
||||
.attr_group = &vtpm_attr_grp,
|
||||
.miscdev = {
|
||||
.fops = &vtpm_ops,
|
||||
},
|
||||
.duration = {
|
||||
TPM_LONG_TIMEOUT,
|
||||
TPM_LONG_TIMEOUT,
|
||||
TPM_LONG_TIMEOUT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *pdev;
|
||||
|
||||
int __init init_vtpm(struct tpm_virtual_device *tvd)
|
||||
struct tpm_chip *init_vtpm(struct device *dev,
|
||||
struct tpm_virtual_device *tvd,
|
||||
struct tpm_private *tp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* vtpms is global - only allow one user */
|
||||
if (vtpms)
|
||||
return -EBUSY;
|
||||
long rc;
|
||||
struct tpm_chip *chip;
|
||||
struct vtpm_state *vtpms;
|
||||
|
||||
vtpms = kzalloc(sizeof(struct vtpm_state), GFP_KERNEL);
|
||||
if (!vtpms)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
vtpm_state_init(vtpms);
|
||||
vtpms->tpmvd = tvd;
|
||||
|
||||
pdev = platform_device_register_simple("tpm_vtpm", -1, NULL, 0);
|
||||
if (IS_ERR(pdev)) {
|
||||
rc = PTR_ERR(pdev);
|
||||
goto err_free_mem;
|
||||
}
|
||||
vtpms->tpm_private = tp;
|
||||
|
||||
if (tvd)
|
||||
tpm_vtpm.buffersize = tvd->max_tx_size;
|
||||
|
||||
if ((rc = tpm_register_hardware(&pdev->dev, &tpm_vtpm)) < 0) {
|
||||
goto err_unreg_pdev;
|
||||
chip = tpm_register_hardware(dev, &tpm_vtpm);
|
||||
if (!chip) {
|
||||
rc = -ENODEV;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
return 0;
|
||||
chip_set_private(chip, vtpms);
|
||||
|
||||
return chip;
|
||||
|
||||
err_unreg_pdev:
|
||||
platform_device_unregister(pdev);
|
||||
err_free_mem:
|
||||
kfree(vtpms);
|
||||
vtpms = NULL;
|
||||
|
||||
return rc;
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void __exit cleanup_vtpm(void)
|
||||
void cleanup_vtpm(struct device *dev)
|
||||
{
|
||||
struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
|
||||
if (chip) {
|
||||
tpm_remove_hardware(chip->dev);
|
||||
platform_device_unregister(pdev);
|
||||
}
|
||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||
struct vtpm_state *vtpms = (struct vtpm_state*)chip_get_private(chip);
|
||||
tpm_remove_hardware(dev);
|
||||
kfree(vtpms);
|
||||
vtpms = NULL;
|
||||
}
|
||||
@@ -12,6 +12,26 @@ struct tpm_virtual_device {
|
||||
* for allocation of buffers.
|
||||
*/
|
||||
unsigned int max_tx_size;
|
||||
};
|
||||
|
||||
struct vtpm_state {
|
||||
struct transmission *current_request;
|
||||
spinlock_t req_list_lock;
|
||||
wait_queue_head_t req_wait_queue;
|
||||
|
||||
struct list_head queued_requests;
|
||||
|
||||
struct transmission *current_response;
|
||||
spinlock_t resp_list_lock;
|
||||
wait_queue_head_t resp_wait_queue; // processes waiting for responses
|
||||
|
||||
u8 vd_status;
|
||||
u8 flags;
|
||||
|
||||
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.
|
||||
@@ -19,20 +39,30 @@ struct tpm_virtual_device {
|
||||
struct tpm_private *tpm_private;
|
||||
};
|
||||
|
||||
|
||||
enum vdev_status {
|
||||
TPM_VD_STATUS_DISCONNECTED = 0x0,
|
||||
TPM_VD_STATUS_CONNECTED = 0x1
|
||||
};
|
||||
|
||||
/* this function is called from tpm_vtpm.c */
|
||||
int vtpm_vd_send(struct tpm_chip *tc,
|
||||
struct tpm_private * tp,
|
||||
int vtpm_vd_send(struct tpm_private * tp,
|
||||
const u8 * buf, size_t count, void *ptr);
|
||||
|
||||
/* these functions are offered by tpm_vtpm.c */
|
||||
int __init init_vtpm(struct tpm_virtual_device *);
|
||||
void __exit cleanup_vtpm(void);
|
||||
int vtpm_vd_recv(const unsigned char *buffer, size_t count, const void *ptr);
|
||||
void vtpm_vd_status(u8 status);
|
||||
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,
|
||||
const unsigned char *buffer, size_t count, void *ptr);
|
||||
void vtpm_vd_status(const struct tpm_chip *, u8 status);
|
||||
|
||||
static inline struct tpm_private *tpm_private_from_dev(struct device *dev)
|
||||
{
|
||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||
struct vtpm_state *vtpms = chip_get_private(chip);
|
||||
return vtpms->tpm_private;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -34,6 +34,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/uaccess.h>
|
||||
@@ -41,12 +42,15 @@
|
||||
#include <xen/interface/grant_table.h>
|
||||
#include <xen/interface/io/tpmif.h>
|
||||
#include <xen/xenbus.h>
|
||||
#include "tpm.h"
|
||||
#include "tpm_vtpm.h"
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
/* local structures */
|
||||
struct tpm_private {
|
||||
struct tpm_chip *chip;
|
||||
|
||||
tpmif_tx_interface_t *tx;
|
||||
atomic_t refcnt;
|
||||
unsigned int evtchn;
|
||||
@@ -60,6 +64,7 @@ struct tpm_private {
|
||||
|
||||
atomic_t tx_busy;
|
||||
void *tx_remember;
|
||||
|
||||
domid_t backend_id;
|
||||
wait_queue_head_t wait_q;
|
||||
|
||||
@@ -95,6 +100,7 @@ static int tpm_xmit(struct tpm_private *tp,
|
||||
const u8 * buf, size_t count, int userbuffer,
|
||||
void *remember);
|
||||
static void destroy_tpmring(struct tpm_private *tp);
|
||||
void __exit tpmif_exit(void);
|
||||
|
||||
#define DPRINTK(fmt, args...) \
|
||||
pr_debug("xen_tpm_fr (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args)
|
||||
@@ -199,8 +205,7 @@ static DEFINE_MUTEX(suspend_lock);
|
||||
/*
|
||||
* Send data via this module by calling this function
|
||||
*/
|
||||
int vtpm_vd_send(struct tpm_chip *chip,
|
||||
struct tpm_private *tp,
|
||||
int vtpm_vd_send(struct tpm_private *tp,
|
||||
const u8 * buf, size_t count, void *ptr)
|
||||
{
|
||||
int sent;
|
||||
@@ -331,7 +336,7 @@ out:
|
||||
static void backend_changed(struct xenbus_device *dev,
|
||||
enum xenbus_state backend_state)
|
||||
{
|
||||
struct tpm_private *tp = dev->dev.driver_data;
|
||||
struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
|
||||
DPRINTK("\n");
|
||||
|
||||
switch (backend_state) {
|
||||
@@ -358,6 +363,9 @@ 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)
|
||||
@@ -369,6 +377,12 @@ static int tpmfront_probe(struct xenbus_device *dev,
|
||||
if (!tp)
|
||||
return -ENOMEM;
|
||||
|
||||
tp->chip = init_vtpm(&dev->dev, &tvd, tp);
|
||||
|
||||
if (IS_ERR(tp->chip)) {
|
||||
return PTR_ERR(tp->chip);
|
||||
}
|
||||
|
||||
err = xenbus_scanf(XBT_NIL, dev->nodename,
|
||||
"handle", "%i", &handle);
|
||||
if (XENBUS_EXIST_ERR(err))
|
||||
@@ -380,12 +394,10 @@ static int tpmfront_probe(struct xenbus_device *dev,
|
||||
}
|
||||
|
||||
tp->dev = dev;
|
||||
dev->dev.driver_data = tp;
|
||||
|
||||
err = talk_to_backend(dev, tp);
|
||||
if (err) {
|
||||
tpm_private_put();
|
||||
dev->dev.driver_data = NULL;
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
@@ -394,16 +406,16 @@ static int tpmfront_probe(struct xenbus_device *dev,
|
||||
|
||||
static int tpmfront_remove(struct xenbus_device *dev)
|
||||
{
|
||||
struct tpm_private *tp = (struct tpm_private *)dev->dev.driver_data;
|
||||
struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
|
||||
destroy_tpmring(tp);
|
||||
cleanup_vtpm(&dev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpmfront_suspend(struct xenbus_device *dev)
|
||||
{
|
||||
struct tpm_private *tp = (struct tpm_private *)dev->dev.driver_data;
|
||||
struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
|
||||
u32 ctr;
|
||||
|
||||
/* lock, so no app can send */
|
||||
mutex_lock(&suspend_lock);
|
||||
tp->is_suspended = 1;
|
||||
@@ -431,7 +443,7 @@ static int tpmfront_suspend(struct xenbus_device *dev)
|
||||
|
||||
static int tpmfront_resume(struct xenbus_device *dev)
|
||||
{
|
||||
struct tpm_private *tp = (struct tpm_private *)dev->dev.driver_data;
|
||||
struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
|
||||
destroy_tpmring(tp);
|
||||
return talk_to_backend(dev, tp);
|
||||
}
|
||||
@@ -548,7 +560,7 @@ static void tpmif_rx_action(unsigned long priv)
|
||||
offset += tocopy;
|
||||
}
|
||||
|
||||
vtpm_vd_recv(buffer, received, tp->tx_remember);
|
||||
vtpm_vd_recv(tp->chip, buffer, received, tp->tx_remember);
|
||||
kfree(buffer);
|
||||
|
||||
exit:
|
||||
@@ -638,6 +650,7 @@ static int tpm_xmit(struct tpm_private *tp,
|
||||
|
||||
atomic_set(&tp->tx_busy, 1);
|
||||
tp->tx_remember = remember;
|
||||
|
||||
mb();
|
||||
|
||||
DPRINTK("Notifying backend via event channel %d\n",
|
||||
@@ -657,9 +670,9 @@ static void tpmif_notify_upperlayer(struct tpm_private *tp)
|
||||
* to the BE.
|
||||
*/
|
||||
if (tp->is_connected) {
|
||||
vtpm_vd_status(TPM_VD_STATUS_CONNECTED);
|
||||
vtpm_vd_status(tp->chip, TPM_VD_STATUS_CONNECTED);
|
||||
} else {
|
||||
vtpm_vd_status(TPM_VD_STATUS_DISCONNECTED);
|
||||
vtpm_vd_status(tp->chip, TPM_VD_STATUS_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,13 +712,10 @@ static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected)
|
||||
* =================================================================
|
||||
*/
|
||||
|
||||
struct tpm_virtual_device tvd = {
|
||||
.max_tx_size = PAGE_SIZE * TPMIF_TX_RING_SIZE,
|
||||
};
|
||||
|
||||
static int __init tpmif_init(void)
|
||||
{
|
||||
int rc;
|
||||
long rc = 0;
|
||||
struct tpm_private *tp;
|
||||
|
||||
if ((xen_start_info->flags & SIF_INITDOMAIN)) {
|
||||
@@ -718,11 +728,6 @@ static int __init tpmif_init(void)
|
||||
goto failexit;
|
||||
}
|
||||
|
||||
tvd.tpm_private = tp;
|
||||
rc = init_vtpm(&tvd);
|
||||
if (rc)
|
||||
goto init_vtpm_failed;
|
||||
|
||||
IPRINTK("Initialising the vTPM driver.\n");
|
||||
if ( gnttab_alloc_grant_references ( TPMIF_TX_RING_SIZE,
|
||||
&gref_head ) < 0) {
|
||||
@@ -734,19 +739,16 @@ static int __init tpmif_init(void)
|
||||
return 0;
|
||||
|
||||
gnttab_alloc_failed:
|
||||
cleanup_vtpm();
|
||||
init_vtpm_failed:
|
||||
tpm_private_put();
|
||||
failexit:
|
||||
|
||||
return rc;
|
||||
return (int)rc;
|
||||
}
|
||||
|
||||
|
||||
static void __exit tpmif_exit(void)
|
||||
void __exit tpmif_exit(void)
|
||||
{
|
||||
exit_tpm_xenbus();
|
||||
cleanup_vtpm();
|
||||
tpm_private_put();
|
||||
gnttab_free_grant_references(gref_head);
|
||||
}
|
||||
|
||||
@@ -75,6 +75,9 @@ DEFINE_SPINLOCK(balloon_lock);
|
||||
static unsigned long current_pages;
|
||||
static unsigned long target_pages;
|
||||
|
||||
/* We increase/decrease in batches which fit in a page */
|
||||
static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)];
|
||||
|
||||
/* VM /proc information for memory */
|
||||
extern unsigned long totalram_pages;
|
||||
|
||||
@@ -96,6 +99,11 @@ static void balloon_process(void *unused);
|
||||
static DECLARE_WORK(balloon_worker, balloon_process, NULL);
|
||||
static struct timer_list balloon_timer;
|
||||
|
||||
/* When ballooning out (allocating memory to return to Xen) we don't really
|
||||
want the kernel to try too hard since that can trigger the oom killer. */
|
||||
#define GFP_BALLOON \
|
||||
(GFP_HIGHUSER | __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC)
|
||||
|
||||
#define PAGE_TO_LIST(p) (&(p)->lru)
|
||||
#define LIST_TO_PAGE(l) list_entry((l), struct page, lru)
|
||||
#define UNLIST_PAGE(p) \
|
||||
@@ -172,7 +180,7 @@ static unsigned long current_target(void)
|
||||
|
||||
static int increase_reservation(unsigned long nr_pages)
|
||||
{
|
||||
unsigned long *frame_list, frame, pfn, i, flags;
|
||||
unsigned long pfn, i, flags;
|
||||
struct page *page;
|
||||
long rc;
|
||||
struct xen_memory_reservation reservation = {
|
||||
@@ -181,15 +189,8 @@ static int increase_reservation(unsigned long nr_pages)
|
||||
.domid = DOMID_SELF
|
||||
};
|
||||
|
||||
if (nr_pages > (PAGE_SIZE / sizeof(unsigned long)))
|
||||
nr_pages = PAGE_SIZE / sizeof(unsigned long);
|
||||
|
||||
frame_list = (unsigned long *)__get_free_page(GFP_KERNEL);
|
||||
if (frame_list == NULL) {
|
||||
frame_list = &frame;
|
||||
if (nr_pages > 1)
|
||||
nr_pages = 1;
|
||||
}
|
||||
if (nr_pages > ARRAY_SIZE(frame_list))
|
||||
nr_pages = ARRAY_SIZE(frame_list);
|
||||
|
||||
balloon_lock(flags);
|
||||
|
||||
@@ -253,15 +254,12 @@ static int increase_reservation(unsigned long nr_pages)
|
||||
out:
|
||||
balloon_unlock(flags);
|
||||
|
||||
if (frame_list != &frame)
|
||||
free_page((unsigned long)frame_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decrease_reservation(unsigned long nr_pages)
|
||||
{
|
||||
unsigned long *frame_list, frame, pfn, i, flags;
|
||||
unsigned long pfn, i, flags;
|
||||
struct page *page;
|
||||
void *v;
|
||||
int need_sleep = 0;
|
||||
@@ -272,18 +270,11 @@ static int decrease_reservation(unsigned long nr_pages)
|
||||
.domid = DOMID_SELF
|
||||
};
|
||||
|
||||
if (nr_pages > (PAGE_SIZE / sizeof(unsigned long)))
|
||||
nr_pages = PAGE_SIZE / sizeof(unsigned long);
|
||||
|
||||
frame_list = (unsigned long *)__get_free_page(GFP_KERNEL);
|
||||
if (frame_list == NULL) {
|
||||
frame_list = &frame;
|
||||
if (nr_pages > 1)
|
||||
nr_pages = 1;
|
||||
}
|
||||
if (nr_pages > ARRAY_SIZE(frame_list))
|
||||
nr_pages = ARRAY_SIZE(frame_list);
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
if ((page = alloc_page(GFP_HIGHUSER)) == NULL) {
|
||||
if ((page = alloc_page(GFP_BALLOON)) == NULL) {
|
||||
nr_pages = i;
|
||||
need_sleep = 1;
|
||||
break;
|
||||
@@ -331,9 +322,6 @@ static int decrease_reservation(unsigned long nr_pages)
|
||||
|
||||
balloon_unlock(flags);
|
||||
|
||||
if (frame_list != &frame)
|
||||
free_page((unsigned long)frame_list);
|
||||
|
||||
return need_sleep;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,8 +76,6 @@ static void update_blkif_status(blkif_t *blkif)
|
||||
* sysfs interface for VBD I/O requests
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
|
||||
#define VBD_SHOW(name, format, args...) \
|
||||
static ssize_t show_##name(struct device *_dev, \
|
||||
struct device_attribute *attr, \
|
||||
@@ -106,57 +104,40 @@ static struct attribute_group vbdstat_group = {
|
||||
.attrs = vbdstat_attrs,
|
||||
};
|
||||
|
||||
VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor);
|
||||
VBD_SHOW(mode, "%s\n", be->mode);
|
||||
|
||||
int xenvbd_sysfs_addif(struct xenbus_device *dev)
|
||||
{
|
||||
int error = 0;
|
||||
int error;
|
||||
|
||||
error = sysfs_create_group(&dev->dev.kobj,
|
||||
&vbdstat_group);
|
||||
error = device_create_file(&dev->dev, &dev_attr_physical_device);
|
||||
if (error)
|
||||
goto fail1;
|
||||
|
||||
error = device_create_file(&dev->dev, &dev_attr_mode);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
goto fail2;
|
||||
|
||||
error = sysfs_create_group(&dev->dev.kobj, &vbdstat_group);
|
||||
if (error)
|
||||
goto fail3;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
sysfs_remove_group(&dev->dev.kobj,
|
||||
&vbdstat_group);
|
||||
|
||||
fail3: sysfs_remove_group(&dev->dev.kobj, &vbdstat_group);
|
||||
fail2: device_remove_file(&dev->dev, &dev_attr_mode);
|
||||
fail1: device_remove_file(&dev->dev, &dev_attr_physical_device);
|
||||
return error;
|
||||
}
|
||||
|
||||
void xenvbd_sysfs_delif(struct xenbus_device *dev)
|
||||
{
|
||||
sysfs_remove_group(&dev->dev.kobj,
|
||||
&vbdstat_group);
|
||||
sysfs_remove_group(&dev->dev.kobj, &vbdstat_group);
|
||||
device_remove_file(&dev->dev, &dev_attr_mode);
|
||||
device_remove_file(&dev->dev, &dev_attr_physical_device);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define xenvbd_sysfs_addif(dev) (0)
|
||||
#define xenvbd_sysfs_delif(dev) ((void)0)
|
||||
|
||||
#endif /* CONFIG_SYSFS */
|
||||
|
||||
static ssize_t show_physical_device(struct device *_dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct xenbus_device *dev = to_xenbus_device(_dev);
|
||||
struct backend_info *be = dev->dev.driver_data;
|
||||
return sprintf(buf, "%x:%x\n", be->major, be->minor);
|
||||
}
|
||||
DEVICE_ATTR(physical_device, S_IRUSR | S_IRGRP | S_IROTH,
|
||||
show_physical_device, NULL);
|
||||
|
||||
|
||||
static ssize_t show_mode(struct device *_dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct xenbus_device *dev = to_xenbus_device(_dev);
|
||||
struct backend_info *be = dev->dev.driver_data;
|
||||
return sprintf(buf, "%s\n", be->mode);
|
||||
}
|
||||
DEVICE_ATTR(mode, S_IRUSR | S_IRGRP | S_IROTH, show_mode, NULL);
|
||||
|
||||
|
||||
static int blkback_remove(struct xenbus_device *dev)
|
||||
{
|
||||
struct backend_info *be = dev->dev.driver_data;
|
||||
@@ -176,9 +157,8 @@ static int blkback_remove(struct xenbus_device *dev)
|
||||
be->blkif = NULL;
|
||||
}
|
||||
|
||||
device_remove_file(&dev->dev, &dev_attr_physical_device);
|
||||
device_remove_file(&dev->dev, &dev_attr_mode);
|
||||
xenvbd_sysfs_delif(dev);
|
||||
if (be->major || be->minor)
|
||||
xenvbd_sysfs_delif(dev);
|
||||
|
||||
kfree(be);
|
||||
dev->dev.driver_data = NULL;
|
||||
@@ -293,15 +273,18 @@ static void backend_changed(struct xenbus_watch *watch,
|
||||
err = vbd_create(be->blkif, handle, major, minor,
|
||||
(NULL == strchr(be->mode, 'w')));
|
||||
if (err) {
|
||||
be->major = 0;
|
||||
be->minor = 0;
|
||||
be->major = be->minor = 0;
|
||||
xenbus_dev_fatal(dev, err, "creating vbd structure");
|
||||
return;
|
||||
}
|
||||
|
||||
device_create_file(&dev->dev, &dev_attr_physical_device);
|
||||
device_create_file(&dev->dev, &dev_attr_mode);
|
||||
xenvbd_sysfs_addif(dev);
|
||||
err = xenvbd_sysfs_addif(dev);
|
||||
if (err) {
|
||||
vbd_free(&be->blkif->vbd);
|
||||
be->major = be->minor = 0;
|
||||
xenbus_dev_fatal(dev, err, "creating sysfs entries");
|
||||
return;
|
||||
}
|
||||
|
||||
/* We're potentially connected now */
|
||||
update_blkif_status(be->blkif);
|
||||
|
||||
@@ -267,7 +267,8 @@ void xencons_force_flush(void)
|
||||
/******************** User-space console driver (/dev/console) ************/
|
||||
|
||||
#define DRV(_d) (_d)
|
||||
#define TTY_INDEX(_tty) ((_tty)->index)
|
||||
#define DUMMY_TTY(_tty) ((xc_mode != XC_SERIAL) && \
|
||||
((_tty)->index != (xc_num - 1)))
|
||||
|
||||
static struct termios *xencons_termios[MAX_NR_CONSOLES];
|
||||
static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
|
||||
@@ -391,7 +392,7 @@ static void xencons_send_xchar(struct tty_struct *tty, char ch)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (TTY_INDEX(tty) != 0)
|
||||
if (DUMMY_TTY(tty))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&xencons_lock, flags);
|
||||
@@ -402,7 +403,7 @@ static void xencons_send_xchar(struct tty_struct *tty, char ch)
|
||||
|
||||
static void xencons_throttle(struct tty_struct *tty)
|
||||
{
|
||||
if (TTY_INDEX(tty) != 0)
|
||||
if (DUMMY_TTY(tty))
|
||||
return;
|
||||
|
||||
if (I_IXOFF(tty))
|
||||
@@ -411,7 +412,7 @@ static void xencons_throttle(struct tty_struct *tty)
|
||||
|
||||
static void xencons_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
if (TTY_INDEX(tty) != 0)
|
||||
if (DUMMY_TTY(tty))
|
||||
return;
|
||||
|
||||
if (I_IXOFF(tty)) {
|
||||
@@ -426,7 +427,7 @@ static void xencons_flush_buffer(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (TTY_INDEX(tty) != 0)
|
||||
if (DUMMY_TTY(tty))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&xencons_lock, flags);
|
||||
@@ -451,7 +452,7 @@ static int xencons_write(
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
if (TTY_INDEX(tty) != 0)
|
||||
if (DUMMY_TTY(tty))
|
||||
return count;
|
||||
|
||||
spin_lock_irqsave(&xencons_lock, flags);
|
||||
@@ -472,7 +473,7 @@ static void xencons_put_char(struct tty_struct *tty, u_char ch)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (TTY_INDEX(tty) != 0)
|
||||
if (DUMMY_TTY(tty))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&xencons_lock, flags);
|
||||
@@ -484,7 +485,7 @@ static void xencons_flush_chars(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (TTY_INDEX(tty) != 0)
|
||||
if (DUMMY_TTY(tty))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&xencons_lock, flags);
|
||||
@@ -496,7 +497,7 @@ static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
{
|
||||
unsigned long orig_jiffies = jiffies;
|
||||
|
||||
if (TTY_INDEX(tty) != 0)
|
||||
if (DUMMY_TTY(tty))
|
||||
return;
|
||||
|
||||
while (DRV(tty->driver)->chars_in_buffer(tty)) {
|
||||
@@ -515,7 +516,7 @@ static int xencons_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (TTY_INDEX(tty) != 0)
|
||||
if (DUMMY_TTY(tty))
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&xencons_lock, flags);
|
||||
@@ -532,7 +533,7 @@ static void xencons_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (TTY_INDEX(tty) != 0)
|
||||
if (DUMMY_TTY(tty))
|
||||
return;
|
||||
|
||||
if (tty->count == 1) {
|
||||
@@ -588,8 +589,7 @@ static int __init xencons_init(void)
|
||||
DRV(xencons_driver)->init_termios = tty_std_termios;
|
||||
DRV(xencons_driver)->flags =
|
||||
TTY_DRIVER_REAL_RAW |
|
||||
TTY_DRIVER_RESET_TERMIOS |
|
||||
TTY_DRIVER_NO_DEVFS;
|
||||
TTY_DRIVER_RESET_TERMIOS;
|
||||
DRV(xencons_driver)->termios = xencons_termios;
|
||||
DRV(xencons_driver)->termios_locked = xencons_termios_locked;
|
||||
|
||||
@@ -599,8 +599,8 @@ static int __init xencons_init(void)
|
||||
DRV(xencons_driver)->name_base = 0 + xc_num;
|
||||
} else {
|
||||
DRV(xencons_driver)->name = "tty";
|
||||
DRV(xencons_driver)->minor_start = xc_num;
|
||||
DRV(xencons_driver)->name_base = xc_num;
|
||||
DRV(xencons_driver)->minor_start = 1;
|
||||
DRV(xencons_driver)->name_base = 1;
|
||||
}
|
||||
|
||||
tty_set_operations(xencons_driver, &xencons_ops);
|
||||
@@ -615,8 +615,6 @@ static int __init xencons_init(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
tty_register_device(xencons_driver, 0, NULL);
|
||||
|
||||
if (xen_start_info->flags & SIF_INITDOMAIN) {
|
||||
xencons_priv_irq = bind_virq_to_irqhandler(
|
||||
VIRQ_CONSOLE,
|
||||
@@ -629,8 +627,7 @@ static int __init xencons_init(void)
|
||||
}
|
||||
|
||||
printk("Xen virtual console successfully installed as %s%d\n",
|
||||
DRV(xencons_driver)->name,
|
||||
DRV(xencons_driver)->name_base );
|
||||
DRV(xencons_driver)->name, xc_num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -219,7 +219,10 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs)
|
||||
|
||||
vcpu_info->evtchn_upcall_pending = 0;
|
||||
|
||||
/* NB. No need for a barrier here -- XCHG is a barrier on x86. */
|
||||
#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
|
||||
/* Clear master pending flag /before/ clearing selector flag. */
|
||||
rmb();
|
||||
#endif
|
||||
l1 = xchg(&vcpu_info->evtchn_pending_sel, 0);
|
||||
while (l1 != 0) {
|
||||
l1i = __ffs(l1);
|
||||
|
||||
@@ -169,7 +169,7 @@ int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
|
||||
printk(KERN_ALERT "WARNING: g.e. still in use!\n");
|
||||
return 0;
|
||||
}
|
||||
} while ((nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) !=
|
||||
} while ((nflags = synch_cmpxchg_subword(&shared[ref].flags, flags, 0)) !=
|
||||
flags);
|
||||
|
||||
return 1;
|
||||
@@ -224,7 +224,7 @@ unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
|
||||
* reference and return failure (== 0).
|
||||
*/
|
||||
while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
|
||||
if (synch_cmpxchg(&shared[ref].flags, flags, 0) == flags)
|
||||
if (synch_cmpxchg_subword(&shared[ref].flags, flags, 0) == flags)
|
||||
return 0;
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/hypervisor.h>
|
||||
#include <xen/features.h>
|
||||
#include <xen/hypervisor_sysfs.h>
|
||||
#include <xen/xenbus.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Mike D. Day <ncmike@us.ibm.com>");
|
||||
@@ -97,6 +99,37 @@ static void xen_sysfs_version_destroy(void)
|
||||
sysfs_remove_group(&hypervisor_subsys.kset.kobj, &version_group);
|
||||
}
|
||||
|
||||
/* UUID */
|
||||
|
||||
static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
|
||||
{
|
||||
char *vm, *val;
|
||||
int ret;
|
||||
|
||||
vm = xenbus_read(XBT_NIL, "vm", "", NULL);
|
||||
if (IS_ERR(vm))
|
||||
return PTR_ERR(vm);
|
||||
val = xenbus_read(XBT_NIL, vm, "uuid", NULL);
|
||||
kfree(vm);
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
ret = sprintf(buffer, "%s\n", val);
|
||||
kfree(val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
HYPERVISOR_ATTR_RO(uuid);
|
||||
|
||||
static int __init xen_sysfs_uuid_init(void)
|
||||
{
|
||||
return sysfs_create_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr);
|
||||
}
|
||||
|
||||
static void xen_sysfs_uuid_destroy(void)
|
||||
{
|
||||
sysfs_remove_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr);
|
||||
}
|
||||
|
||||
/* xen compilation attributes */
|
||||
|
||||
static ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer)
|
||||
@@ -314,10 +347,15 @@ static int __init hyper_sysfs_init(void)
|
||||
ret = xen_compilation_init();
|
||||
if (ret)
|
||||
goto comp_out;
|
||||
ret = xen_sysfs_uuid_init();
|
||||
if (ret)
|
||||
goto uuid_out;
|
||||
ret = xen_properties_init();
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
xen_sysfs_uuid_destroy();
|
||||
uuid_out:
|
||||
xen_compilation_destroy();
|
||||
comp_out:
|
||||
xen_sysfs_version_destroy();
|
||||
@@ -331,6 +369,7 @@ static void hyper_sysfs_exit(void)
|
||||
{
|
||||
xen_properties_destroy();
|
||||
xen_compilation_destroy();
|
||||
xen_sysfs_uuid_destroy();
|
||||
xen_sysfs_version_destroy();
|
||||
xen_sysfs_type_destroy();
|
||||
|
||||
|
||||
@@ -496,9 +496,9 @@ static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end)
|
||||
|
||||
do {
|
||||
make_tx_response(netif, txp, NETIF_RSP_ERROR);
|
||||
if (++cons >= end)
|
||||
if (cons >= end)
|
||||
break;
|
||||
txp = RING_GET_REQUEST(&netif->tx, cons);
|
||||
txp = RING_GET_REQUEST(&netif->tx, cons++);
|
||||
} while (1);
|
||||
netif->tx.req_cons = cons;
|
||||
netif_schedule_work(netif);
|
||||
@@ -663,6 +663,57 @@ static void netbk_fill_frags(struct sk_buff *skb)
|
||||
}
|
||||
}
|
||||
|
||||
int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras,
|
||||
int work_to_do)
|
||||
{
|
||||
struct netif_extra_info *extra;
|
||||
RING_IDX cons = netif->tx.req_cons;
|
||||
|
||||
do {
|
||||
if (unlikely(work_to_do-- <= 0)) {
|
||||
DPRINTK("Missing extra info\n");
|
||||
return -EBADR;
|
||||
}
|
||||
|
||||
extra = (struct netif_extra_info *)
|
||||
RING_GET_REQUEST(&netif->tx, cons);
|
||||
if (unlikely(!extra->type ||
|
||||
extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
|
||||
netif->tx.req_cons = ++cons;
|
||||
DPRINTK("Invalid extra type: %d\n", extra->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&extras[extra->type - 1], extra, sizeof(*extra));
|
||||
netif->tx.req_cons = ++cons;
|
||||
} while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
|
||||
|
||||
return work_to_do;
|
||||
}
|
||||
|
||||
static int netbk_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso)
|
||||
{
|
||||
if (!gso->u.gso.size) {
|
||||
DPRINTK("GSO size must not be zero.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Currently only TCPv4 S.O. is supported. */
|
||||
if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
|
||||
DPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
skb_shinfo(skb)->gso_size = gso->u.gso.size;
|
||||
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
|
||||
|
||||
/* Header must be checked, and gso_segs computed. */
|
||||
skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
|
||||
skb_shinfo(skb)->gso_segs = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called after netfront has transmitted */
|
||||
static void net_tx_action(unsigned long unused)
|
||||
{
|
||||
@@ -670,7 +721,7 @@ static void net_tx_action(unsigned long unused)
|
||||
struct sk_buff *skb;
|
||||
netif_t *netif;
|
||||
netif_tx_request_t txreq;
|
||||
struct netif_tx_extra txtra;
|
||||
struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
|
||||
u16 pending_idx;
|
||||
RING_IDX i;
|
||||
gnttab_map_grant_ref_t *mop;
|
||||
@@ -732,16 +783,15 @@ static void net_tx_action(unsigned long unused)
|
||||
work_to_do--;
|
||||
netif->tx.req_cons = ++i;
|
||||
|
||||
memset(extras, 0, sizeof(extras));
|
||||
if (txreq.flags & NETTXF_extra_info) {
|
||||
if (work_to_do-- <= 0) {
|
||||
DPRINTK("Missing extra info\n");
|
||||
work_to_do = netbk_get_extras(netif, extras,
|
||||
work_to_do);
|
||||
i = netif->tx.req_cons;
|
||||
if (unlikely(work_to_do < 0)) {
|
||||
netbk_tx_err(netif, &txreq, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(&txtra, RING_GET_REQUEST(&netif->tx, i),
|
||||
sizeof(txtra));
|
||||
netif->tx.req_cons = ++i;
|
||||
}
|
||||
|
||||
ret = netbk_count_requests(netif, &txreq, work_to_do);
|
||||
@@ -751,7 +801,7 @@ static void net_tx_action(unsigned long unused)
|
||||
}
|
||||
i += ret;
|
||||
|
||||
if (unlikely(ret > MAX_SKB_FRAGS + 1)) {
|
||||
if (unlikely(ret > MAX_SKB_FRAGS)) {
|
||||
DPRINTK("Too many frags\n");
|
||||
netbk_tx_err(netif, &txreq, i);
|
||||
continue;
|
||||
@@ -788,10 +838,15 @@ static void net_tx_action(unsigned long unused)
|
||||
/* Packets passed to netif_rx() must have some headroom. */
|
||||
skb_reserve(skb, 16);
|
||||
|
||||
if (txreq.flags & NETTXF_gso) {
|
||||
skb_shinfo(skb)->gso_size = txtra.u.gso.size;
|
||||
skb_shinfo(skb)->gso_segs = txtra.u.gso.segs;
|
||||
skb_shinfo(skb)->gso_type = txtra.u.gso.type;
|
||||
if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
|
||||
struct netif_extra_info *gso;
|
||||
gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
|
||||
|
||||
if (netbk_set_skb_gso(skb, gso)) {
|
||||
kfree_skb(skb);
|
||||
netbk_tx_err(netif, &txreq, i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
gnttab_set_map_op(mop, MMAP_VADDR(pending_idx),
|
||||
|
||||
@@ -101,11 +101,14 @@ static int netback_probe(struct xenbus_device *dev,
|
||||
goto abort_transaction;
|
||||
}
|
||||
|
||||
err = xenbus_printf(xbt, dev->nodename, "feature-tso", "%d", 1);
|
||||
#if 0 /* KAF: After the protocol is finalised. */
|
||||
err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
|
||||
"%d", 1);
|
||||
if (err) {
|
||||
message = "writing feature-tso";
|
||||
message = "writing feature-gso-tcpv4";
|
||||
goto abort_transaction;
|
||||
}
|
||||
#endif
|
||||
|
||||
err = xenbus_transaction_end(xbt, 0);
|
||||
} while (err == -EAGAIN);
|
||||
|
||||
@@ -463,7 +463,7 @@ static int network_open(struct net_device *dev)
|
||||
|
||||
static inline int netfront_tx_slot_available(struct netfront_info *np)
|
||||
{
|
||||
return RING_FREE_REQUESTS(&np->tx) >= MAX_SKB_FRAGS + 1;
|
||||
return RING_FREE_REQUESTS(&np->tx) >= MAX_SKB_FRAGS + 2;
|
||||
}
|
||||
|
||||
static inline void network_maybe_wake_tx(struct net_device *dev)
|
||||
@@ -491,7 +491,13 @@ static void network_tx_buf_gc(struct net_device *dev)
|
||||
rmb(); /* Ensure we see responses up to 'rp'. */
|
||||
|
||||
for (cons = np->tx.rsp_cons; cons != prod; cons++) {
|
||||
id = RING_GET_RESPONSE(&np->tx, cons)->id;
|
||||
struct netif_tx_response *txrsp;
|
||||
|
||||
txrsp = RING_GET_RESPONSE(&np->tx, cons);
|
||||
if (txrsp->status == NETIF_RSP_NULL)
|
||||
continue;
|
||||
|
||||
id = txrsp->id;
|
||||
skb = np->tx_skbs[id];
|
||||
if (unlikely(gnttab_query_foreign_access(
|
||||
np->grant_tx_ref[id]) != 0)) {
|
||||
@@ -719,6 +725,7 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
unsigned short id;
|
||||
struct netfront_info *np = netdev_priv(dev);
|
||||
struct netif_tx_request *tx;
|
||||
struct netif_extra_info *extra;
|
||||
char *data = skb->data;
|
||||
RING_IDX i;
|
||||
grant_ref_t ref;
|
||||
@@ -739,7 +746,8 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
spin_lock_irq(&np->tx_lock);
|
||||
|
||||
if (unlikely(!netif_carrier_ok(dev) ||
|
||||
(frags > 1 && !xennet_can_sg(dev)))) {
|
||||
(frags > 1 && !xennet_can_sg(dev)) ||
|
||||
netif_needs_gso(dev, skb))) {
|
||||
spin_unlock_irq(&np->tx_lock);
|
||||
goto drop;
|
||||
}
|
||||
@@ -762,11 +770,30 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
tx->size = len;
|
||||
|
||||
tx->flags = 0;
|
||||
extra = NULL;
|
||||
|
||||
if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
|
||||
tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
|
||||
if (skb->proto_data_valid) /* remote but checksummed? */
|
||||
tx->flags |= NETTXF_data_validated;
|
||||
|
||||
if (skb_shinfo(skb)->gso_size) {
|
||||
struct netif_extra_info *gso = (struct netif_extra_info *)
|
||||
RING_GET_REQUEST(&np->tx, ++i);
|
||||
|
||||
if (extra)
|
||||
extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
|
||||
else
|
||||
tx->flags |= NETTXF_extra_info;
|
||||
|
||||
gso->u.gso.size = skb_shinfo(skb)->gso_size;
|
||||
gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
|
||||
|
||||
gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
|
||||
gso->flags = 0;
|
||||
extra = gso;
|
||||
}
|
||||
|
||||
np->tx.req_prod_pvt = i + 1;
|
||||
|
||||
xennet_make_frags(skb, dev, tx);
|
||||
@@ -1065,9 +1092,33 @@ static int xennet_set_sg(struct net_device *dev, u32 data)
|
||||
return ethtool_op_set_sg(dev, data);
|
||||
}
|
||||
|
||||
static int xennet_set_tso(struct net_device *dev, u32 data)
|
||||
{
|
||||
if (data) {
|
||||
struct netfront_info *np = netdev_priv(dev);
|
||||
int val;
|
||||
|
||||
if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
|
||||
"feature-gso-tcpv4", "%d", &val) < 0)
|
||||
val = 0;
|
||||
#if 0 /* KAF: After the protocol is finalised. */
|
||||
if (!val)
|
||||
#endif
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return ethtool_op_set_tso(dev, data);
|
||||
}
|
||||
|
||||
static void xennet_set_features(struct net_device *dev)
|
||||
{
|
||||
xennet_set_sg(dev, 1);
|
||||
/* Turn off all GSO bits except ROBUST. */
|
||||
dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
|
||||
dev->features |= NETIF_F_GSO_ROBUST;
|
||||
xennet_set_sg(dev, 0);
|
||||
|
||||
if (!xennet_set_sg(dev, 1))
|
||||
xennet_set_tso(dev, 1);
|
||||
}
|
||||
|
||||
static void network_connect(struct net_device *dev)
|
||||
@@ -1148,6 +1199,8 @@ static struct ethtool_ops network_ethtool_ops =
|
||||
.set_tx_csum = ethtool_op_set_tx_csum,
|
||||
.get_sg = ethtool_op_get_sg,
|
||||
.set_sg = xennet_set_sg,
|
||||
.get_tso = ethtool_op_get_tso,
|
||||
.set_tso = xennet_set_tso,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
|
||||
@@ -886,29 +886,6 @@ void unregister_xenstore_notifier(struct notifier_block *nb)
|
||||
EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
|
||||
|
||||
|
||||
static int all_devices_ready_(struct device *dev, void *data)
|
||||
{
|
||||
struct xenbus_device *xendev = to_xenbus_device(dev);
|
||||
int *result = data;
|
||||
|
||||
if (xendev->state != XenbusStateConnected) {
|
||||
*result = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int all_devices_ready(void)
|
||||
{
|
||||
int ready = 1;
|
||||
bus_for_each_dev(&xenbus_frontend.bus, NULL, &ready,
|
||||
all_devices_ready_);
|
||||
return ready;
|
||||
}
|
||||
|
||||
|
||||
void xenbus_probe(void *unused)
|
||||
{
|
||||
BUG_ON((xenstored_ready <= 0));
|
||||
@@ -1060,6 +1037,43 @@ static int __init xenbus_probe_init(void)
|
||||
postcore_initcall(xenbus_probe_init);
|
||||
|
||||
|
||||
static int is_disconnected_device(struct device *dev, void *data)
|
||||
{
|
||||
struct xenbus_device *xendev = to_xenbus_device(dev);
|
||||
|
||||
/*
|
||||
* A device with no driver will never connect. We care only about
|
||||
* devices which should currently be in the process of connecting.
|
||||
*/
|
||||
if (!dev->driver)
|
||||
return 0;
|
||||
|
||||
return (xendev->state != XenbusStateConnected);
|
||||
}
|
||||
|
||||
static int exists_disconnected_device(void)
|
||||
{
|
||||
return bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL,
|
||||
is_disconnected_device);
|
||||
}
|
||||
|
||||
static int print_device_status(struct device *dev, void *data)
|
||||
{
|
||||
struct xenbus_device *xendev = to_xenbus_device(dev);
|
||||
|
||||
if (!dev->driver) {
|
||||
/* Information only: is this too noisy? */
|
||||
printk(KERN_INFO "XENBUS: Device with no driver: %s\n",
|
||||
xendev->nodename);
|
||||
} else if (xendev->state != XenbusStateConnected) {
|
||||
printk(KERN_WARNING "XENBUS: Timeout connecting "
|
||||
"to device: %s (state %d)\n",
|
||||
xendev->nodename, xendev->state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* On a 10 second timeout, wait for all devices currently configured. We need
|
||||
* to do this to guarantee that the filesystems and / or network devices
|
||||
@@ -1081,13 +1095,12 @@ static int __init wait_for_devices(void)
|
||||
if (!is_running_on_xen())
|
||||
return -ENODEV;
|
||||
|
||||
while (time_before(jiffies, timeout)) {
|
||||
if (all_devices_ready())
|
||||
return 0;
|
||||
while (time_before(jiffies, timeout) && exists_disconnected_device())
|
||||
schedule_timeout_interruptible(HZ/10);
|
||||
}
|
||||
|
||||
printk(KERN_WARNING "XENBUS: Timeout connecting to devices!\n");
|
||||
bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL,
|
||||
print_device_status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,4 +138,6 @@ static __inline__ int synch_var_test_bit(int nr, volatile void * addr)
|
||||
synch_const_test_bit((nr),(addr)) : \
|
||||
synch_var_test_bit((nr),(addr)))
|
||||
|
||||
#define synch_cmpxchg_subword synch_cmpxchg
|
||||
|
||||
#endif /* __XEN_SYNCH_BITOPS_H__ */
|
||||
@@ -58,4 +58,6 @@ static __inline__ int synch_var_test_bit(int nr, volatile void * addr)
|
||||
synch_const_test_bit((nr),(addr)) : \
|
||||
synch_var_test_bit((nr),(addr)))
|
||||
|
||||
#define synch_cmpxchg_subword synch_cmpxchg
|
||||
|
||||
#endif /* __XEN_SYNCH_BITOPS_H__ */
|
||||
@@ -0,0 +1,26 @@
|
||||
diff -pruN ../pristine-linux-2.6.16.13/kernel/timer.c ./kernel/timer.c
|
||||
--- ../pristine-linux-2.6.16.13/kernel/timer.c 2006-05-02 22:38:44.000000000 +0100
|
||||
+++ ./kernel/timer.c 2006-06-29 14:34:12.788957720 +0100
|
||||
@@ -555,6 +555,22 @@ found:
|
||||
}
|
||||
spin_unlock(&base->t_base.lock);
|
||||
|
||||
+ /*
|
||||
+ * It can happen that other CPUs service timer IRQs and increment
|
||||
+ * jiffies, but we have not yet got a local timer tick to process
|
||||
+ * the timer wheels. In that case, the expiry time can be before
|
||||
+ * jiffies, but since the high-resolution timer here is relative to
|
||||
+ * jiffies, the default expression when high-resolution timers are
|
||||
+ * not active,
|
||||
+ *
|
||||
+ * time_before(MAX_JIFFY_OFFSET + jiffies, expires)
|
||||
+ *
|
||||
+ * would falsely evaluate to true. If that is the case, just
|
||||
+ * return jiffies so that we can immediately fire the local timer
|
||||
+ */
|
||||
+ if (time_before(expires, jiffies))
|
||||
+ return jiffies;
|
||||
+
|
||||
if (time_before(hr_expires, expires))
|
||||
return hr_expires;
|
||||
|
||||
@@ -2225,7 +2225,7 @@ index d64e2ec..7494823 100644
|
||||
err = ipcomp_compress(x, skb);
|
||||
iph = skb->nh.iph;
|
||||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
||||
index 00aa80e..84130c9 100644
|
||||
index 00aa80e..30c81a8 100644
|
||||
--- a/net/ipv4/tcp.c
|
||||
+++ b/net/ipv4/tcp.c
|
||||
@@ -257,6 +257,7 @@ #include <linux/smp_lock.h>
|
||||
@@ -2281,7 +2281,7 @@ index 00aa80e..84130c9 100644
|
||||
|
||||
from += copy;
|
||||
copied += copy;
|
||||
@@ -2026,6 +2021,71 @@ int tcp_getsockopt(struct sock *sk, int
|
||||
@@ -2026,6 +2021,77 @@ int tcp_getsockopt(struct sock *sk, int
|
||||
}
|
||||
|
||||
|
||||
@@ -2306,13 +2306,19 @@ index 00aa80e..84130c9 100644
|
||||
+ if (!pskb_may_pull(skb, thlen))
|
||||
+ goto out;
|
||||
+
|
||||
+ segs = NULL;
|
||||
+ if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST))
|
||||
+ goto out;
|
||||
+
|
||||
+ oldlen = (u16)~skb->len;
|
||||
+ __skb_pull(skb, thlen);
|
||||
+
|
||||
+ if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
|
||||
+ /* Packet is from an untrusted source, reset gso_segs. */
|
||||
+ int mss = skb_shinfo(skb)->gso_size;
|
||||
+
|
||||
+ skb_shinfo(skb)->gso_segs = (skb->len + mss - 1) / mss;
|
||||
+
|
||||
+ segs = NULL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ segs = skb_segment(skb, features);
|
||||
+ if (IS_ERR(segs))
|
||||
+ goto out;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -123,6 +123,21 @@ diff -pru ../pristine-linux-2.6.16.13/drivers/oprofile/buffer_sync.c ./drivers/o
|
||||
}
|
||||
}
|
||||
}
|
||||
diff -pru ../pristine-linux-2.6.16.13/drivers/oprofile/buffer_sync.h ./drivers/oprofile/buffer_sync.h
|
||||
--- ../pristine-linux-2.6.16.13/drivers/oprofile/buffer_sync.h 2006-05-03 05:38:44.000000000 +0800
|
||||
+++ ./drivers/oprofile/buffer_sync.h 2006-06-27 12:12:09.000000000 +0800
|
||||
@@ -9,6 +9,11 @@
|
||||
|
||||
#ifndef OPROFILE_BUFFER_SYNC_H
|
||||
#define OPROFILE_BUFFER_SYNC_H
|
||||
+
|
||||
+#define NO_DOMAIN_SWITCH -1
|
||||
+#define DOMAIN_SWITCH_START_EVENT1 0
|
||||
+#define DOMAIN_SWITCH_START_EVENT2 1
|
||||
+#define DOMAIN_SWITCH_STOP_EVENT1 2
|
||||
|
||||
/* add the necessary profiling hooks */
|
||||
int sync_start(void);
|
||||
diff -pru ../pristine-linux-2.6.16.13/drivers/oprofile/cpu_buffer.c ./drivers/oprofile/cpu_buffer.c
|
||||
--- ../pristine-linux-2.6.16.13/drivers/oprofile/cpu_buffer.c 2006-05-03 05:38:44.000000000 +0800
|
||||
+++ ./drivers/oprofile/cpu_buffer.c 2006-06-19 22:43:53.000000000 +0800
|
||||
|
||||
@@ -26,7 +26,7 @@ XEN_SCRIPTS += network-route vif-route
|
||||
XEN_SCRIPTS += network-nat vif-nat
|
||||
XEN_SCRIPTS += block
|
||||
XEN_SCRIPTS += block-enbd block-nbd
|
||||
XEN_SCRIPTS += vtpm vtpm-delete
|
||||
XEN_SCRIPTS += vtpm vtpm-delete vtpm-addtodb
|
||||
XEN_SCRIPTS += xen-hotplug-cleanup
|
||||
XEN_SCRIPTS += external-device-migrate
|
||||
XEN_SCRIPT_DATA = xen-script-common.sh locking.sh logging.sh
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script must be called with the following parameters to have
|
||||
# an entry added to the TPM-to-domain associations table in /etc/xen/vtpm.db
|
||||
# vtpm-addtodb <dom name> <instance number>
|
||||
|
||||
dir=$(dirname "$0")
|
||||
. "$dir/vtpm-common.sh"
|
||||
|
||||
vtpmdb_add_instance $1 $2
|
||||
@@ -347,16 +347,9 @@ function isLocalAddress() {
|
||||
# 2nd: name of the domain to migrate
|
||||
# 3rd: the migration step to perform
|
||||
function vtpm_migration_step() {
|
||||
local instance res
|
||||
instance=$(vtpmdb_find_instance $2)
|
||||
if [ "$instance" == "" ]; then
|
||||
echo "Error: Translation of domain name ($2) to instance failed. Check /etc/xen/vtpm.db"
|
||||
log err "Error during translation of domain name"
|
||||
else
|
||||
res=$(isLocalAddress $1)
|
||||
if [ "$res" == "0" ]; then
|
||||
vtpm_migrate $1 $2 $3
|
||||
fi
|
||||
local res=$(isLocalAddress $1)
|
||||
if [ "$res" == "0" ]; then
|
||||
vtpm_migrate $1 $2 $3
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -45,9 +45,9 @@ LDFLAGS = -m32 -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR)
|
||||
.PHONY: all
|
||||
all: hvmloader
|
||||
|
||||
hvmloader: roms.h hvmloader.c acpi_madt.c
|
||||
$(CC) $(CFLAGS) -c hvmloader.c acpi_madt.c
|
||||
$(CC) $(LDFLAGS) -o hvmloader.tmp hvmloader.o acpi_madt.o
|
||||
hvmloader: roms.h hvmloader.c acpi_madt.c mp_tables.c
|
||||
$(CC) $(CFLAGS) -c hvmloader.c acpi_madt.c mp_tables.c
|
||||
$(CC) $(LDFLAGS) -o hvmloader.tmp hvmloader.o acpi_madt.o mp_tables.o
|
||||
$(OBJCOPY) hvmloader.tmp hvmloader
|
||||
rm -f hvmloader.tmp
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ static int validate_hvm_info(struct hvm_info_table *t)
|
||||
}
|
||||
|
||||
/* xc_vmx_builder wrote hvm info at 0x9F800. Return it. */
|
||||
static struct hvm_info_table *
|
||||
struct hvm_info_table *
|
||||
get_hvm_info_table(void)
|
||||
{
|
||||
struct hvm_info_table *t;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
#include "roms.h"
|
||||
#include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
|
||||
#include <xen/hvm/hvm_info_table.h>
|
||||
|
||||
/* memory map */
|
||||
#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
|
||||
@@ -71,6 +72,8 @@ asm(
|
||||
|
||||
extern int get_acpi_enabled(void);
|
||||
extern int acpi_madt_update(unsigned char* acpi_start);
|
||||
extern void create_mp_tables(void);
|
||||
struct hvm_info_table *get_hvm_info_table(void);
|
||||
|
||||
static inline void
|
||||
outw(unsigned short addr, unsigned short val)
|
||||
@@ -162,10 +165,15 @@ check_amd(void)
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
struct hvm_info_table *t = get_hvm_info_table();
|
||||
|
||||
puts("HVM Loader\n");
|
||||
|
||||
puts("Loading ROMBIOS ...\n");
|
||||
memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
|
||||
if (t->apic_enabled)
|
||||
create_mp_tables();
|
||||
|
||||
if (cirrus_check()) {
|
||||
puts("Loading Cirrus VGABIOS ...\n");
|
||||
memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
|
||||
|
||||
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
* mp_tables.c: Dynamically writes MP table info into the ROMBIOS.
|
||||
*
|
||||
* In order to work with various VCPU counts, this code reads the VCPU count
|
||||
* for the HVM partition and creates the correct MP tables for the VCPU count
|
||||
* and places the information into a predetermined location set aside in the
|
||||
* ROMBIOS during build time.
|
||||
*
|
||||
* Please note that many of the values, such as the CPU's
|
||||
* family/model/stepping, are hard-coded based upon the values that were used
|
||||
* in the ROMBIOS and may need to be modified or calculated dynamically to
|
||||
* correspond with what an HVM guest's CPUID returns.
|
||||
*
|
||||
* Travis Betak, travis.betak@amd.com
|
||||
* Copyright (c) 2006, AMD.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/* FIXME find a header that already has types defined!!! */
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed int int32_t;
|
||||
#ifdef __i386__
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef signed long long int64_t;
|
||||
#else
|
||||
typedef unsigned long uint64_t;
|
||||
typedef signed long int64_t;
|
||||
#endif
|
||||
|
||||
#define ROMBIOS_SEG 0xF000
|
||||
#define ROMBIOS_BEGIN 0x000F0000
|
||||
#define ROMBIOS_SIZE 0x00010000
|
||||
#define ROMBIOS_MAXOFFSET 0x0000FFFF
|
||||
#define ROMBIOS_END (ROMBIOS_BEGIN + ROMBIOS_SIZE)
|
||||
|
||||
/* number of non-processor MP table entries */
|
||||
#define NR_NONPROC_ENTRIES 18
|
||||
|
||||
#define ENTRY_TYPE_PROCESSOR 0
|
||||
#define ENTRY_TYPE_BUS 1
|
||||
#define ENTRY_TYPE_IOAPIC 2
|
||||
#define ENTRY_TYPE_IO_INTR 3
|
||||
#define ENTRY_TYPE_LOCAL_INTR 4
|
||||
|
||||
#define CPU_FLAG_ENABLED 0x01
|
||||
#define CPU_FLAG_BSP 0x02
|
||||
|
||||
/* TODO change this to correspond with what the guest's see's from CPUID */
|
||||
#define CPU_SIG_FAMILY 0x06
|
||||
#define CPU_SIG_MODEL 0x00
|
||||
#define CPU_SIG_STEPPING 0x00
|
||||
#define CPU_SIGNATURE ((CPU_SIG_FAMILY << 8) \
|
||||
| (CPU_SIG_MODEL << 4) \
|
||||
| (CPU_SIG_STEPPING))
|
||||
#define CPU_FEATURE_FPU (1U << 0)
|
||||
#define CPU_FEATURE_MCE (1U << 7)
|
||||
#define CPU_FEATURE_CX8 (1U << 8)
|
||||
#define CPU_FEATURE_APIC (1U << 9)
|
||||
#define CPU_FEATURES (CPU_FEATURE_FPU | CPU_FEATURE_APIC)
|
||||
|
||||
#define BUS_TYPE_LENGTH 6
|
||||
#define BUS_TYPE_STR_ISA "ISA "
|
||||
|
||||
#define LAPIC_BASE_ADDR 0xFEE00000
|
||||
|
||||
#define IOAPIC_VERSION 0x11
|
||||
#define IOAPIC_BASE_ADDR 0xFEC00000
|
||||
#define IOAPIC_FLAG_ENABLED (1U << 0)
|
||||
|
||||
#define INTR_TYPE_INT 0
|
||||
#define INTR_TYPE_NMI 1
|
||||
#define INTR_TYPE_SMI 2
|
||||
#define INTR_TYPE_EXTINT 3
|
||||
|
||||
#define INTR_FLAGS 0
|
||||
|
||||
#define INTR_MAX_NR 16
|
||||
|
||||
extern int puts(const char *); /* for printing */
|
||||
extern int get_vcpu_nr(void); /* for the guest's VCPU count */
|
||||
|
||||
/*
|
||||
* The following structures are defined in the MuliProcessor Specifiation v1.4
|
||||
*/
|
||||
|
||||
/* MP Floating Pointer Structure */
|
||||
struct mp_floating_pointer_struct {
|
||||
uint8_t signature[4];
|
||||
uint32_t mp_table;
|
||||
uint8_t length;
|
||||
uint8_t revision;
|
||||
uint8_t checksum;
|
||||
uint8_t feature[5];
|
||||
};
|
||||
|
||||
/* MP Configuration Table */
|
||||
struct mp_config_table {
|
||||
uint8_t signature[4];
|
||||
uint16_t length;
|
||||
uint8_t revision;
|
||||
uint8_t checksum;
|
||||
uint8_t oem_id[8];
|
||||
uint8_t vendor_id[12];
|
||||
uint32_t oem_table;
|
||||
uint16_t oem_table_sz;
|
||||
uint16_t nr_entries;
|
||||
uint32_t lapic;
|
||||
uint16_t extended_length;
|
||||
uint8_t extended_checksum;
|
||||
uint8_t reserved;
|
||||
};
|
||||
|
||||
/* MP Processor Entry */
|
||||
struct mp_proc_entry {
|
||||
uint8_t type;
|
||||
uint8_t lapic_id;
|
||||
uint8_t lapic_version;
|
||||
uint8_t cpu_flags;
|
||||
uint32_t cpu_signature;
|
||||
uint32_t feature_flags;
|
||||
uint8_t reserved[8];
|
||||
};
|
||||
|
||||
/* MP Bus Entry */
|
||||
struct mp_bus_entry {
|
||||
uint8_t type;
|
||||
uint8_t bus_id;
|
||||
uint8_t bus_type_str[6];
|
||||
};
|
||||
|
||||
/* MP IOAPIC Entry */
|
||||
struct mp_ioapic_entry {
|
||||
uint8_t type;
|
||||
uint8_t ioapic_id;
|
||||
uint8_t ioapic_version;
|
||||
uint8_t ioapic_flags;
|
||||
uint32_t ioapic_addr;
|
||||
};
|
||||
|
||||
/* MP IO Interrupt Entry */
|
||||
struct mp_io_intr_entry {
|
||||
uint8_t type;
|
||||
uint8_t intr_type;
|
||||
uint16_t io_intr_flags;
|
||||
uint8_t src_bus_id;
|
||||
uint8_t src_bus_irq;
|
||||
uint8_t dst_ioapic_id;
|
||||
uint8_t dst_ioapic_intin;
|
||||
};
|
||||
|
||||
/* MP Local Interrupt Entry */
|
||||
struct mp_local_intr_entry {
|
||||
uint8_t type;
|
||||
uint8_t intr_type;
|
||||
uint16_t local_intr_flags;
|
||||
uint8_t src_bus_id;
|
||||
uint8_t src_bus_irq;
|
||||
uint8_t dst_lapic_id;
|
||||
uint8_t dst_lapic_lintin;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* fill_mp_config_table - fills in the information for the MP config table
|
||||
*
|
||||
* When calculating the length and nr_entries fields, keep in mind that there
|
||||
* are always 18 non-processor entries and N processor entries
|
||||
*
|
||||
* N vcpu entries
|
||||
* 1 bus entry
|
||||
* 1 IOAPIC entry
|
||||
* + 16 IO intr. entries
|
||||
* ----------------------
|
||||
* 18 + N total entries
|
||||
*/
|
||||
void fill_mp_config_table(struct mp_config_table *mpct)
|
||||
{
|
||||
int vcpu_nr;
|
||||
|
||||
vcpu_nr = get_vcpu_nr();
|
||||
|
||||
/* fill in the MP configuration table signature, "PCMP" */
|
||||
mpct->signature[0] = 'P';
|
||||
mpct->signature[1] = 'C';
|
||||
mpct->signature[2] = 'M';
|
||||
mpct->signature[3] = 'P';
|
||||
|
||||
mpct->length = sizeof(struct mp_config_table)
|
||||
+ vcpu_nr * sizeof(struct mp_proc_entry)
|
||||
+ sizeof(struct mp_ioapic_entry)
|
||||
+ sizeof(struct mp_bus_entry)
|
||||
+ 16 * sizeof(struct mp_local_intr_entry);
|
||||
|
||||
mpct->revision = 4;
|
||||
|
||||
/*
|
||||
* We'll fill in the checksum later after all of the
|
||||
* entries have been created
|
||||
*/
|
||||
mpct->checksum = 0;
|
||||
|
||||
/* fill in the OEM ID string, "_HVMCPU_" */
|
||||
mpct->oem_id[0] = '_'; mpct->oem_id[3] = 'M'; mpct->oem_id[6] = 'U';
|
||||
mpct->oem_id[1] = 'H'; mpct->oem_id[4] = 'C'; mpct->oem_id[7] = '_';
|
||||
mpct->oem_id[2] = 'V'; mpct->oem_id[5] = 'P';
|
||||
|
||||
/* fill in the Vendor ID string, "XEN " */
|
||||
mpct->vendor_id[0] = 'X'; mpct->vendor_id[6] = ' ';
|
||||
mpct->vendor_id[1] = 'E'; mpct->vendor_id[7] = ' ';
|
||||
mpct->vendor_id[2] = 'N'; mpct->vendor_id[8] = ' ';
|
||||
mpct->vendor_id[3] = ' '; mpct->vendor_id[9] = ' ';
|
||||
mpct->vendor_id[4] = ' '; mpct->vendor_id[10] = ' ';
|
||||
mpct->vendor_id[5] = ' '; mpct->vendor_id[11] = ' ';
|
||||
|
||||
mpct->oem_table = 0;
|
||||
mpct->oem_table_sz = 0;
|
||||
|
||||
mpct->nr_entries = vcpu_nr + NR_NONPROC_ENTRIES;
|
||||
|
||||
mpct->lapic = LAPIC_BASE_ADDR;
|
||||
mpct->extended_length = 0;
|
||||
mpct->extended_checksum = 0;
|
||||
}
|
||||
|
||||
|
||||
/* calculates the checksum for the MP configuration table */
|
||||
void fill_mp_config_table_checksum(struct mp_config_table *mpct)
|
||||
{
|
||||
int i;
|
||||
uint8_t checksum;
|
||||
|
||||
checksum = 0;
|
||||
for (i = 0; i < mpct->length; ++i)
|
||||
checksum += ((uint8_t *)(mpct))[i];
|
||||
mpct->checksum = -checksum;
|
||||
}
|
||||
|
||||
|
||||
/* fills in an MP processor entry for VCPU 'vcpu_id' */
|
||||
void fill_mp_proc_entry(struct mp_proc_entry *mppe, int vcpu_id)
|
||||
{
|
||||
mppe->type = ENTRY_TYPE_PROCESSOR;
|
||||
mppe->lapic_id = vcpu_id;
|
||||
mppe->lapic_version = 0x11;
|
||||
mppe->cpu_flags = CPU_FLAG_ENABLED;
|
||||
if (vcpu_id == 0)
|
||||
mppe->cpu_flags |= CPU_FLAG_BSP;
|
||||
mppe->cpu_signature = CPU_SIGNATURE;
|
||||
mppe->feature_flags = CPU_FEATURES;
|
||||
}
|
||||
|
||||
|
||||
/* fills in an MP bus entry of type 'type' and bus ID 'bus_id' */
|
||||
void fill_mp_bus_entry(struct mp_bus_entry *mpbe, int bus_id, const char *type)
|
||||
{
|
||||
int i;
|
||||
|
||||
mpbe->type = ENTRY_TYPE_BUS;
|
||||
mpbe->bus_id = bus_id;
|
||||
for (i = 0; i < BUS_TYPE_LENGTH; ++i)
|
||||
mpbe->bus_type_str[i] = type[i]; /* FIXME length check? */
|
||||
}
|
||||
|
||||
|
||||
/* fills in an MP IOAPIC entry for IOAPIC 'ioapic_id' */
|
||||
void fill_mp_ioapic_entry(struct mp_ioapic_entry *mpie, int ioapic_id)
|
||||
{
|
||||
mpie->type = ENTRY_TYPE_IOAPIC;
|
||||
mpie->ioapic_id = ioapic_id;
|
||||
mpie->ioapic_version = IOAPIC_VERSION;
|
||||
mpie->ioapic_flags = IOAPIC_FLAG_ENABLED;
|
||||
mpie->ioapic_addr = IOAPIC_BASE_ADDR;
|
||||
}
|
||||
|
||||
|
||||
/* fills in an IO interrupt entry for IOAPIC 'ioapic_id' */
|
||||
void fill_mp_io_intr_entry(struct mp_io_intr_entry *mpiie,
|
||||
int src_bus_irq, int ioapic_id, int dst_ioapic_intin)
|
||||
{
|
||||
mpiie->type = ENTRY_TYPE_IO_INTR;
|
||||
mpiie->intr_type = INTR_TYPE_INT;
|
||||
mpiie->io_intr_flags = INTR_FLAGS;
|
||||
mpiie->src_bus_id = 0;
|
||||
mpiie->src_bus_irq = src_bus_irq;
|
||||
mpiie->dst_ioapic_id = ioapic_id;
|
||||
mpiie->dst_ioapic_intin = dst_ioapic_intin;
|
||||
}
|
||||
|
||||
|
||||
/* fill in the mp floating processor structure */
|
||||
void fill_mpfps(struct mp_floating_pointer_struct *mpfps, uint32_t mpct)
|
||||
{
|
||||
int i;
|
||||
uint8_t checksum;
|
||||
|
||||
|
||||
mpfps->signature[0] = '_';
|
||||
mpfps->signature[1] = 'M';
|
||||
mpfps->signature[2] = 'P';
|
||||
mpfps->signature[3] = '_';
|
||||
|
||||
mpfps->mp_table = mpct;
|
||||
mpfps->length = 1;
|
||||
mpfps->revision = 4;
|
||||
mpfps->checksum = 0;
|
||||
for (i = 0; i < 5; ++i)
|
||||
mpfps->feature[i] = 0;
|
||||
|
||||
/* compute the checksum for our new table */
|
||||
checksum = 0;
|
||||
for (i = 0; i < sizeof(struct mp_floating_pointer_struct); ++i)
|
||||
checksum += ((uint8_t *)(mpfps))[i];
|
||||
mpfps->checksum = -checksum;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* find_mp_table_start - searchs through BIOS memory for '___HVMMP' signature
|
||||
*
|
||||
* The '___HVMMP' signature is created by the ROMBIOS and designates a chunk
|
||||
* of space inside the ROMBIOS that is safe for us to write our MP table info
|
||||
*/
|
||||
void* get_mp_table_start(void)
|
||||
{
|
||||
char *bios_mem;
|
||||
for (bios_mem = (char *)ROMBIOS_BEGIN;
|
||||
bios_mem != (char *)ROMBIOS_END;
|
||||
++bios_mem)
|
||||
if (bios_mem[0] == '_' && bios_mem[1] == '_' &&
|
||||
bios_mem[2] == '_' && bios_mem[3] == 'H' &&
|
||||
bios_mem[4] == 'V' && bios_mem[5] == 'M' &&
|
||||
bios_mem[6] == 'M' && bios_mem[7] == 'P')
|
||||
return bios_mem;
|
||||
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
|
||||
/* recalculate the new ROMBIOS checksum after adding MP tables */
|
||||
void reset_bios_checksum(void)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t checksum;
|
||||
|
||||
checksum = 0;
|
||||
for (i = 0; i < ROMBIOS_MAXOFFSET; ++i)
|
||||
checksum += ((uint8_t *)(ROMBIOS_BEGIN))[i];
|
||||
|
||||
*((uint8_t *)(ROMBIOS_BEGIN + ROMBIOS_MAXOFFSET)) = -checksum;
|
||||
}
|
||||
|
||||
|
||||
/* create_mp_tables - creates MP tables for the guest based upon config data */
|
||||
void create_mp_tables(void)
|
||||
{
|
||||
void *mp_table_base;
|
||||
char *p;
|
||||
struct mp_config_table *mp_config_table;
|
||||
int vcpu_nr;
|
||||
int i;
|
||||
|
||||
vcpu_nr = get_vcpu_nr();
|
||||
|
||||
puts("Creating MP tables ...\n");
|
||||
|
||||
/* find the 'safe' place in ROMBIOS for the MP tables */
|
||||
mp_table_base = get_mp_table_start();
|
||||
if (mp_table_base == (void *)-1) {
|
||||
puts("Couldn't find start point for MP tables\n");
|
||||
return;
|
||||
}
|
||||
p = mp_table_base;
|
||||
|
||||
fill_mp_config_table((struct mp_config_table *)p);
|
||||
|
||||
/* save the location of the MP config table for a little later*/
|
||||
mp_config_table = (struct mp_config_table *)p;
|
||||
p += sizeof(struct mp_config_table);
|
||||
|
||||
for (i = 0; i < vcpu_nr; ++i) {
|
||||
fill_mp_proc_entry((struct mp_proc_entry *)p, i);
|
||||
p += sizeof(struct mp_proc_entry);
|
||||
}
|
||||
|
||||
fill_mp_bus_entry((struct mp_bus_entry *)p, 0, BUS_TYPE_STR_ISA);
|
||||
p += sizeof(struct mp_bus_entry);
|
||||
|
||||
fill_mp_ioapic_entry((struct mp_ioapic_entry *)p, vcpu_nr);
|
||||
p += sizeof(struct mp_ioapic_entry);
|
||||
|
||||
for (i = 0; i < INTR_MAX_NR; ++i) {
|
||||
fill_mp_io_intr_entry((struct mp_io_intr_entry *)p,
|
||||
i, vcpu_nr, i);
|
||||
p += sizeof(struct mp_io_intr_entry);
|
||||
}
|
||||
|
||||
/* find the next 16-byte boundary to place the mp floating pointer */
|
||||
while ((unsigned long)p & 0xF)
|
||||
++p;
|
||||
|
||||
fill_mpfps((struct mp_floating_pointer_struct *)p,
|
||||
(uint32_t)mp_table_base);
|
||||
|
||||
/* calculate the MP configuration table's checksum */
|
||||
fill_mp_config_table_checksum(mp_config_table);
|
||||
|
||||
/* finally, recalculate the ROMBIOS checksum */
|
||||
reset_bios_checksum();
|
||||
}
|
||||
@@ -1,13 +1,9 @@
|
||||
BIOS_BUILDS = BIOS-bochs-latest
|
||||
#BIOS_BUILDS += BIOS-bochs-2-processors
|
||||
#BIOS_BUILDS += BIOS-bochs-4-processors
|
||||
#BIOS_BUILDS += BIOS-bochs-8-processors
|
||||
|
||||
.PHONY: all
|
||||
all: bios
|
||||
|
||||
.PHONY: bios
|
||||
bios: biossums ${BIOS_BUILDS}
|
||||
bios: biossums BIOS-bochs-latest
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@@ -26,36 +22,6 @@ BIOS-bochs-latest: rombios.c biossums
|
||||
./biossums BIOS-bochs-latest
|
||||
rm -f _rombios_.s
|
||||
|
||||
BIOS-bochs-2-processors: rombios.c biossums
|
||||
gcc -DBX_SMP_PROCESSORS=2 -E -P $< > _rombios2_.c
|
||||
bcc -o rombios2.s -C-c -D__i86__ -0 -S _rombios2_.c
|
||||
sed -e 's/^\.text//' -e 's/^\.data//' rombios2.s > _rombios2_.s
|
||||
as86 _rombios2_.s -b tmp2.bin -u- -w- -g -0 -j -O -l rombios2.txt
|
||||
-perl makesym.perl < rombios2.txt > rombios2.sym
|
||||
mv tmp2.bin BIOS-bochs-2-processors
|
||||
./biossums BIOS-bochs-2-processors
|
||||
rm -f _rombios2_.s
|
||||
|
||||
BIOS-bochs-4-processors: rombios.c biossums
|
||||
gcc -DBX_SMP_PROCESSORS=4 -E -P $< > _rombios4_.c
|
||||
bcc -o rombios4.s -C-c -D__i86__ -0 -S _rombios4_.c
|
||||
sed -e 's/^\.text//' -e 's/^\.data//' rombios4.s > _rombios4_.s
|
||||
as86 _rombios4_.s -b tmp4.bin -u- -w- -g -0 -j -O -l rombios4.txt
|
||||
-perl makesym.perl < rombios4.txt > rombios4.sym
|
||||
mv tmp4.bin BIOS-bochs-4-processors
|
||||
./biossums BIOS-bochs-4-processors
|
||||
rm -f _rombios4_.s
|
||||
|
||||
BIOS-bochs-8-processors: rombios.c biossums
|
||||
gcc -DBX_SMP_PROCESSORS=8 -E -P $< > _rombios8_.c
|
||||
bcc -o rombios8.s -C-c -D__i86__ -0 -S _rombios8_.c
|
||||
sed -e 's/^\.text//' -e 's/^\.data//' rombios8.s > _rombios8_.s
|
||||
as86 _rombios8_.s -b tmp8.bin -u- -w- -g -0 -j -O -l rombios8.txt
|
||||
-perl makesym.perl < rombios8.txt > rombios8.sym
|
||||
mv tmp8.bin BIOS-bochs-8-processors
|
||||
./biossums BIOS-bochs-8-processors
|
||||
rm -f _rombios8_.s
|
||||
|
||||
biossums: biossums.c
|
||||
gcc -o biossums biossums.c
|
||||
|
||||
@@ -10514,6 +10514,34 @@ static Bit8u vgafont8[128*8]=
|
||||
0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
|
||||
};
|
||||
|
||||
#ifdef HVMASSIST
|
||||
//
|
||||
// MP Tables
|
||||
// just carve out some blank space for HVMLOADER to write the MP tables to
|
||||
//
|
||||
// NOTE: There should be enough space for a 32 processor entry MP table
|
||||
//
|
||||
ASM_START
|
||||
.org 0xcc00
|
||||
db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 64 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 128 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 192 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 256 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 320 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 384 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 448 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 512 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 576 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 640 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 704 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 768 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 832 bytes
|
||||
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 896 bytes
|
||||
ASM_END
|
||||
|
||||
#else // !HVMASSIST
|
||||
|
||||
ASM_START
|
||||
.org 0xcc00
|
||||
// bcc-generated data will be placed here
|
||||
@@ -10835,3 +10863,5 @@ db 0,0,0,0 ;; MP feature bytes 2-5.
|
||||
#endif
|
||||
|
||||
ASM_END
|
||||
|
||||
#endif // HVMASSIST
|
||||
@@ -476,6 +476,6 @@ void pci_piix4_acpi_init(PCIBus *bus)
|
||||
|
||||
pci_register_io_region((PCIDevice *)d, 4, 0x10,
|
||||
PCI_ADDRESS_SPACE_IO, acpi_map);
|
||||
pmtimer_state = pmtimer_init();
|
||||
/*pmtimer_state = pmtimer_init();*/
|
||||
acpi_reset (d);
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#define ELFSIZE 32
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include "xg_private.h"
|
||||
#include "xc_elf.h"
|
||||
#include <stdlib.h>
|
||||
@@ -188,7 +189,7 @@ static int setup_guest(int xc_handle,
|
||||
unsigned char e820_map_nr;
|
||||
|
||||
struct domain_setup_info dsi;
|
||||
unsigned long long v_end;
|
||||
uint64_t v_end;
|
||||
|
||||
unsigned long shared_page_frame = 0;
|
||||
shared_iopage_t *sp;
|
||||
@@ -208,11 +209,11 @@ static int setup_guest(int xc_handle,
|
||||
v_end = (unsigned long long)memsize << 20;
|
||||
|
||||
IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n"
|
||||
" Loaded HVM loader: %08lx->%08lx\n"
|
||||
" TOTAL: %08lx->%016llx\n",
|
||||
" Loaded HVM loader: %016"PRIx64"->%016"PRIx64"\n"
|
||||
" TOTAL: %016"PRIx64"->%016"PRIx64"\n",
|
||||
dsi.v_kernstart, dsi.v_kernend,
|
||||
dsi.v_start, v_end);
|
||||
IPRINTF(" ENTRY ADDRESS: %08lx\n", dsi.v_kernentry);
|
||||
IPRINTF(" ENTRY ADDRESS: %016"PRIx64"\n", dsi.v_kernentry);
|
||||
|
||||
if ( (v_end - dsi.v_start) > ((unsigned long long)nr_pages << PAGE_SHIFT) )
|
||||
{
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
#include <inttypes.h>
|
||||
#include <zlib.h>
|
||||
|
||||
/* Handy for printing out '0' prepended values at native pointer size */
|
||||
#define _p(a) ((void *) ((ulong)a))
|
||||
|
||||
#if defined(__i386__)
|
||||
#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
|
||||
#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
|
||||
@@ -519,8 +522,6 @@ static int setup_guest(int xc_handle,
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
#define _p(a) ((void *) (a))
|
||||
|
||||
IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n"
|
||||
" Loaded kernel: %p->%p\n"
|
||||
" Init. ramdisk: %p->%p\n"
|
||||
@@ -795,9 +796,9 @@ static int setup_guest(int xc_handle,
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
#define NR(_l,_h,_s) \
|
||||
(((((_h) + ((1UL<<(_s))-1)) & ~((1UL<<(_s))-1)) - \
|
||||
((_l) & ~((1UL<<(_s))-1))) >> (_s))
|
||||
#define NR(_l,_h,_s) \
|
||||
(((((unsigned long)(_h) + ((1UL<<(_s))-1)) & ~((1UL<<(_s))-1)) - \
|
||||
((unsigned long)(_l) & ~((1UL<<(_s))-1))) >> (_s))
|
||||
#if defined(__i386__)
|
||||
if ( dsi.pae_kernel != PAEKERN_no )
|
||||
{
|
||||
@@ -826,8 +827,6 @@ static int setup_guest(int xc_handle,
|
||||
#endif
|
||||
}
|
||||
|
||||
#define _p(a) ((void *) (a))
|
||||
|
||||
IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n");
|
||||
IPRINTF(" Loaded kernel: %p->%p\n", _p(dsi.v_kernstart),
|
||||
_p(dsi.v_kernend));
|
||||
@@ -848,8 +847,8 @@ static int setup_guest(int xc_handle,
|
||||
if ( ((v_end - dsi.v_start)>>PAGE_SHIFT) > nr_pages )
|
||||
{
|
||||
PERROR("Initial guest OS requires too much space\n"
|
||||
"(%luMB is greater than %luMB limit)\n",
|
||||
(v_end-dsi.v_start)>>20, nr_pages>>(20-PAGE_SHIFT));
|
||||
"(%pMB is greater than %luMB limit)\n",
|
||||
_p((v_end-dsi.v_start)>>20), nr_pages>>(20-PAGE_SHIFT));
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
@@ -1083,7 +1082,8 @@ static int setup_guest(int xc_handle,
|
||||
if ( hypercall_pfn >= nr_pages )
|
||||
goto error_out;
|
||||
op.u.hypercall_init.domain = (domid_t)dom;
|
||||
op.u.hypercall_init.mfn = page_array[hypercall_pfn];
|
||||
op.u.hypercall_init.gmfn = shadow_mode_enabled ?
|
||||
hypercall_pfn : page_array[hypercall_pfn];
|
||||
op.cmd = DOM0_HYPERCALL_INIT;
|
||||
if ( xc_dom0_op(xc_handle, &op) )
|
||||
goto error_out;
|
||||
|
||||
@@ -415,11 +415,11 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
|
||||
** which entries do not require canonicalization (in particular, those
|
||||
** entries which map the virtual address reserved for the hypervisor).
|
||||
*/
|
||||
void canonicalize_pagetable(unsigned long type, unsigned long pfn,
|
||||
const void *spage, void *dpage)
|
||||
int canonicalize_pagetable(unsigned long type, unsigned long pfn,
|
||||
const void *spage, void *dpage)
|
||||
{
|
||||
|
||||
int i, pte_last, xen_start, xen_end;
|
||||
int i, pte_last, xen_start, xen_end, race = 0;
|
||||
uint64_t pte;
|
||||
|
||||
/*
|
||||
@@ -481,7 +481,8 @@ void canonicalize_pagetable(unsigned long type, unsigned long pfn,
|
||||
is quite feasible under live migration */
|
||||
DPRINTF("PT Race: [%08lx,%d] pte=%llx, mfn=%08lx\n",
|
||||
type, i, (unsigned long long)pte, mfn);
|
||||
pfn = 0; /* zap it - we'll retransmit this page later */
|
||||
pfn = 0; /* zap it - we'll retransmit this page later */
|
||||
race = 1; /* inform the caller of race; fatal if !live */
|
||||
} else
|
||||
pfn = mfn_to_pfn(mfn);
|
||||
|
||||
@@ -496,7 +497,7 @@ void canonicalize_pagetable(unsigned long type, unsigned long pfn,
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
return race;
|
||||
}
|
||||
|
||||
|
||||
@@ -567,7 +568,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
int rc = 1, i, j, last_iter, iter = 0;
|
||||
int live = (flags & XCFLAGS_LIVE);
|
||||
int debug = (flags & XCFLAGS_DEBUG);
|
||||
int sent_last_iter, skip_this_iter;
|
||||
int race = 0, sent_last_iter, skip_this_iter;
|
||||
|
||||
/* The new domain's shared-info frame number. */
|
||||
unsigned long shared_info_frame;
|
||||
@@ -1000,7 +1001,11 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
if (pagetype >= L1TAB && pagetype <= L4TAB) {
|
||||
|
||||
/* We have a pagetable page: need to rewrite it. */
|
||||
canonicalize_pagetable(pagetype, pfn, spage, page);
|
||||
race =
|
||||
canonicalize_pagetable(pagetype, pfn, spage, page);
|
||||
|
||||
if(race && !live)
|
||||
goto out;
|
||||
|
||||
if (ratewrite(io_fd, page, PAGE_SIZE) != PAGE_SIZE) {
|
||||
ERR("Error when writing to state file (4)");
|
||||
|
||||
+18
-11
@@ -68,7 +68,7 @@ static int parseelfimage(const char *image,
|
||||
Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
|
||||
Elf_Phdr *phdr;
|
||||
Elf_Shdr *shdr;
|
||||
unsigned long kernstart = ~0UL, kernend=0UL, vaddr, virt_base, elf_pa_off;
|
||||
Elf_Addr kernstart = ~0, kernend = 0, vaddr, virt_base, elf_pa_off;
|
||||
const char *shstrtab;
|
||||
char *guestinfo=NULL, *p;
|
||||
int h, virt_base_defined, elf_pa_off_defined;
|
||||
@@ -162,15 +162,19 @@ static int parseelfimage(const char *image,
|
||||
/* Initial guess for virt_base is 0 if it is not explicitly defined. */
|
||||
p = strstr(guestinfo, "VIRT_BASE=");
|
||||
virt_base_defined = (p != NULL);
|
||||
virt_base = virt_base_defined ? strtoul(p+10, &p, 0) : 0;
|
||||
virt_base = virt_base_defined ? strtoull(p+10, &p, 0) : 0;
|
||||
|
||||
/* Initial guess for elf_pa_off is virt_base if not explicitly defined. */
|
||||
p = strstr(guestinfo, "ELF_PADDR_OFFSET=");
|
||||
elf_pa_off_defined = (p != NULL);
|
||||
elf_pa_off = elf_pa_off_defined ? strtoul(p+17, &p, 0) : virt_base;
|
||||
elf_pa_off = elf_pa_off_defined ? strtoull(p+17, &p, 0) : virt_base;
|
||||
|
||||
if ( elf_pa_off_defined && !virt_base_defined )
|
||||
goto bad_image;
|
||||
{
|
||||
ERROR("Neither ELF_PADDR_OFFSET nor VIRT_BASE found in __xen_guest"
|
||||
" section.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for ( h = 0; h < ehdr->e_phnum; h++ )
|
||||
{
|
||||
@@ -179,7 +183,11 @@ static int parseelfimage(const char *image,
|
||||
continue;
|
||||
vaddr = phdr->p_paddr - elf_pa_off + virt_base;
|
||||
if ( (vaddr + phdr->p_memsz) < vaddr )
|
||||
goto bad_image;
|
||||
{
|
||||
ERROR("ELF program header %d is too large.", h);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ( vaddr < kernstart )
|
||||
kernstart = vaddr;
|
||||
if ( (vaddr + phdr->p_memsz) > kernend )
|
||||
@@ -196,13 +204,16 @@ static int parseelfimage(const char *image,
|
||||
|
||||
dsi->v_kernentry = ehdr->e_entry;
|
||||
if ( (p = strstr(guestinfo, "VIRT_ENTRY=")) != NULL )
|
||||
dsi->v_kernentry = strtoul(p+11, &p, 0);
|
||||
dsi->v_kernentry = strtoull(p+11, &p, 0);
|
||||
|
||||
if ( (kernstart > kernend) ||
|
||||
(dsi->v_kernentry < kernstart) ||
|
||||
(dsi->v_kernentry > kernend) ||
|
||||
(dsi->v_start > kernstart) )
|
||||
goto bad_image;
|
||||
{
|
||||
ERROR("ELF start or entries are out of bounds.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ( (p = strstr(guestinfo, "BSD_SYMTAB")) != NULL )
|
||||
dsi->load_symtab = 1;
|
||||
@@ -214,10 +225,6 @@ static int parseelfimage(const char *image,
|
||||
loadelfsymtab(image, 0, 0, NULL, dsi);
|
||||
|
||||
return 0;
|
||||
|
||||
bad_image:
|
||||
ERROR("Malformed ELF image.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -26,7 +26,7 @@ unsigned int get_pfn_type(int xc_handle,
|
||||
{
|
||||
DECLARE_DOM0_OP;
|
||||
op.cmd = DOM0_GETPAGEFRAMEINFO;
|
||||
op.u.getpageframeinfo.mfn = mfn;
|
||||
op.u.getpageframeinfo.gmfn = mfn;
|
||||
op.u.getpageframeinfo.domain = (domid_t)dom;
|
||||
if ( do_dom0_op(xc_handle, &op) < 0 )
|
||||
{
|
||||
|
||||
@@ -132,13 +132,13 @@ typedef unsigned long l4_pgentry_t;
|
||||
|
||||
struct domain_setup_info
|
||||
{
|
||||
unsigned long v_start;
|
||||
unsigned long v_end;
|
||||
unsigned long v_kernstart;
|
||||
unsigned long v_kernend;
|
||||
unsigned long v_kernentry;
|
||||
uint64_t v_start;
|
||||
uint64_t v_end;
|
||||
uint64_t v_kernstart;
|
||||
uint64_t v_kernend;
|
||||
uint64_t v_kernentry;
|
||||
|
||||
unsigned long elf_paddr_offset;
|
||||
uint64_t elf_paddr_offset;
|
||||
|
||||
#define PAEKERN_no 0
|
||||
#define PAEKERN_yes 1
|
||||
|
||||
@@ -43,7 +43,7 @@ MAX_BYTES = 1 << 20 # 1MB
|
||||
BACKUP_COUNT = 5
|
||||
|
||||
STDERR_FORMAT = "[%(name)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s"
|
||||
LOGFILE_FORMAT = "[%(asctime)s %(name)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s"
|
||||
LOGFILE_FORMAT = "[%(asctime)s %(name)s %(process)d] %(levelname)s (%(module)s:%(lineno)d) %(message)s"
|
||||
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ import sys
|
||||
import traceback
|
||||
import tempfile
|
||||
import os, stat
|
||||
import re
|
||||
import commands
|
||||
import shutil
|
||||
import string
|
||||
from xen.util.security import ACMError, err
|
||||
|
||||
@@ -21,11 +21,8 @@
|
||||
"""
|
||||
import os
|
||||
import os.path
|
||||
import string
|
||||
import sys
|
||||
import socket
|
||||
import commands
|
||||
import time
|
||||
import re
|
||||
import xmlrpclib
|
||||
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
"""
|
||||
import sys
|
||||
import traceback
|
||||
import os
|
||||
import commands
|
||||
import shutil
|
||||
import string
|
||||
from xen.util.security import ACMError, err, dump_policy
|
||||
|
||||
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
"""
|
||||
import sys
|
||||
import traceback
|
||||
import os
|
||||
import commands
|
||||
import shutil
|
||||
import string
|
||||
from xen.util.security import ACMError, err, list_labels, active_policy
|
||||
from xen.util.security import vm_label_re, res_label_re, all_label_re
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
"""
|
||||
import sys
|
||||
import traceback
|
||||
import os
|
||||
import commands
|
||||
import shutil
|
||||
import string
|
||||
from xen.util.security import ACMError, err, load_policy
|
||||
|
||||
|
||||
|
||||
@@ -556,7 +556,7 @@ def xm_vcpu_list(args):
|
||||
|
||||
|
||||
def xm_reboot(args):
|
||||
arg_check(args, "reboot", 1, 4)
|
||||
arg_check(args, "reboot", 1, 3)
|
||||
from xen.xm import shutdown
|
||||
shutdown.main(["shutdown", "-R"] + args)
|
||||
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
"""
|
||||
import sys
|
||||
import traceback
|
||||
import os
|
||||
import commands
|
||||
import shutil
|
||||
import string
|
||||
from xen.util.security import ACMError, err, make_policy
|
||||
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
"""Domain shutdown.
|
||||
"""
|
||||
import string
|
||||
import sys
|
||||
import time
|
||||
|
||||
from xen.xend.XendClient import server
|
||||
@@ -92,7 +90,8 @@ def main_all(opts, args):
|
||||
shutdown(opts, None, mode, opts.vals.wait)
|
||||
|
||||
def main_dom(opts, args):
|
||||
if len(args) < 1: opts.err('Missing domain')
|
||||
if len(args) == 0: opts.err('No domain parameter given')
|
||||
if len(args) > 1: opts.err('No multiple domain parameters allowed')
|
||||
dom = args[0]
|
||||
mode = shutdown_mode(opts)
|
||||
shutdown(opts, [ dom ], mode, opts.vals.wait)
|
||||
|
||||
+19
-7
@@ -36,6 +36,7 @@ import sys
|
||||
# constants
|
||||
NSAMPLES = 100
|
||||
NDOMAINS = 32
|
||||
IDLE_DOMAIN = 31 # idle domain's ID
|
||||
|
||||
# the struct strings for qos_info
|
||||
ST_DOM_INFO = "6Q4i32s"
|
||||
@@ -253,6 +254,14 @@ def display(scr, row, col, str, attr=0):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# diplay domain id
|
||||
def display_domain_id(scr, row, col, dom):
|
||||
if dom == IDLE_DOMAIN:
|
||||
display(scr, row, col-1, "Idle")
|
||||
else:
|
||||
display(scr, row, col, "%d" % dom)
|
||||
|
||||
|
||||
# the live monitoring code
|
||||
def show_livestats(cpu):
|
||||
ncpu = 1 # number of cpu's on this platform
|
||||
@@ -361,7 +370,7 @@ def show_livestats(cpu):
|
||||
# display gotten
|
||||
row += 1
|
||||
col = 2
|
||||
display(stdscr, row, col, "%d" % dom)
|
||||
display_domain_id(stdscr, row, col, dom)
|
||||
col += 4
|
||||
display(stdscr, row, col, "%s" % time_scale(h2[dom][0][0]))
|
||||
col += 12
|
||||
@@ -386,7 +395,7 @@ def show_livestats(cpu):
|
||||
if options.allocated:
|
||||
row += 1
|
||||
col = 2
|
||||
display(stdscr, row, col, "%d" % dom)
|
||||
display_domain_id(stdscr, row, col, dom)
|
||||
col += 28
|
||||
display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][1]))
|
||||
col += 42
|
||||
@@ -398,7 +407,7 @@ def show_livestats(cpu):
|
||||
if options.blocked:
|
||||
row += 1
|
||||
col = 2
|
||||
display(stdscr, row, col, "%d" % dom)
|
||||
display_domain_id(stdscr, row, col, dom)
|
||||
col += 4
|
||||
display(stdscr, row, col, "%s" % time_scale(h2[dom][2][0]))
|
||||
col += 12
|
||||
@@ -418,7 +427,7 @@ def show_livestats(cpu):
|
||||
if options.waited:
|
||||
row += 1
|
||||
col = 2
|
||||
display(stdscr, row, col, "%d" % dom)
|
||||
display_domain_id(stdscr, row, col, dom)
|
||||
col += 4
|
||||
display(stdscr, row, col, "%s" % time_scale(h2[dom][3][0]))
|
||||
col += 12
|
||||
@@ -438,7 +447,7 @@ def show_livestats(cpu):
|
||||
if options.excount:
|
||||
row += 1
|
||||
col = 2
|
||||
display(stdscr, row, col, "%d" % dom)
|
||||
display_domain_id(stdscr, row, col, dom)
|
||||
|
||||
col += 28
|
||||
display(stdscr, row, col, "%d/s" % h2[dom][4])
|
||||
@@ -451,7 +460,7 @@ def show_livestats(cpu):
|
||||
if options.iocount:
|
||||
row += 1
|
||||
col = 2
|
||||
display(stdscr, row, col, "%d" % dom)
|
||||
display_domain_id(stdscr, row, col, dom)
|
||||
col += 4
|
||||
display(stdscr, row, col, "%d/s" % h2[dom][5][0])
|
||||
col += 24
|
||||
@@ -558,7 +567,10 @@ def writelog():
|
||||
curr = last = time.time()
|
||||
outfiles = {}
|
||||
for dom in range(0, NDOMAINS):
|
||||
outfiles[dom] = Delayed("%s-dom%d.log" % (options.prefix, dom), 'w')
|
||||
if dom == IDLE_DOMAIN:
|
||||
outfiles[dom] = Delayed("%s-idle.log" % options.prefix, 'w')
|
||||
else:
|
||||
outfiles[dom] = Delayed("%s-dom%d.log" % (options.prefix, dom), 'w')
|
||||
outfiles[dom].delayed_write("# passed cpu dom cpu(tot) cpu(%) cpu/ex allocated/ex blocked(tot) blocked(%) blocked/io waited(tot) waited(%) waited/ex ex/s io(tot) io/ex\n")
|
||||
|
||||
while options.duration == 0 or interval < (options.duration * 1000):
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <xs.h>
|
||||
#include "xenstat.h"
|
||||
|
||||
@@ -36,6 +41,7 @@ struct xenstat_handle {
|
||||
struct xs_handle *xshandle; /* xenstore handle */
|
||||
int page_size;
|
||||
FILE *procnetdev;
|
||||
DIR *sysfsvbd;
|
||||
char xen_version[VERSION_SIZE]; /* xen version running on this node */
|
||||
};
|
||||
|
||||
@@ -62,6 +68,8 @@ struct xenstat_domain {
|
||||
unsigned int ssid;
|
||||
unsigned int num_networks;
|
||||
xenstat_network *networks; /* Array of length num_networks */
|
||||
unsigned int num_vbds;
|
||||
xenstat_vbd *vbds;
|
||||
};
|
||||
|
||||
struct xenstat_vcpu {
|
||||
@@ -83,6 +91,15 @@ struct xenstat_network {
|
||||
unsigned long long tdrop;
|
||||
};
|
||||
|
||||
struct xenstat_vbd {
|
||||
unsigned int dev;
|
||||
unsigned long long oo_reqs;
|
||||
unsigned long long rd_reqs;
|
||||
unsigned long long wr_reqs;
|
||||
};
|
||||
#define SYSFS_VBD_PATH "/sys/devices/xen-backend/"
|
||||
|
||||
|
||||
/*
|
||||
* Data-collection types
|
||||
*/
|
||||
@@ -108,12 +125,15 @@ typedef struct xenstat_collector {
|
||||
static int xenstat_collect_vcpus(xenstat_node * node);
|
||||
static int xenstat_collect_networks(xenstat_node * node);
|
||||
static int xenstat_collect_xen_version(xenstat_node * node);
|
||||
static int xenstat_collect_vbds(xenstat_node * node);
|
||||
static void xenstat_free_vcpus(xenstat_node * node);
|
||||
static void xenstat_free_networks(xenstat_node * node);
|
||||
static void xenstat_free_xen_version(xenstat_node * node);
|
||||
static void xenstat_free_vbds(xenstat_node * node);
|
||||
static void xenstat_uninit_vcpus(xenstat_handle * handle);
|
||||
static void xenstat_uninit_networks(xenstat_handle * handle);
|
||||
static void xenstat_uninit_xen_version(xenstat_handle * handle);
|
||||
static void xenstat_uninit_vbds(xenstat_handle * handle);
|
||||
static char *xenstat_get_domain_name(xenstat_handle * handle, unsigned int domain_id);
|
||||
|
||||
static xenstat_collector collectors[] = {
|
||||
@@ -122,7 +142,9 @@ static xenstat_collector collectors[] = {
|
||||
{ XENSTAT_NETWORK, xenstat_collect_networks,
|
||||
xenstat_free_networks, xenstat_uninit_networks },
|
||||
{ XENSTAT_XEN_VERSION, xenstat_collect_xen_version,
|
||||
xenstat_free_xen_version, xenstat_uninit_xen_version }
|
||||
xenstat_free_xen_version, xenstat_uninit_xen_version },
|
||||
{ XENSTAT_VBD, xenstat_collect_vbds,
|
||||
xenstat_free_vbds, xenstat_uninit_vbds }
|
||||
};
|
||||
|
||||
#define NUM_COLLECTORS (sizeof(collectors)/sizeof(xenstat_collector))
|
||||
@@ -259,6 +281,8 @@ xenstat_node *xenstat_get_node(xenstat_handle * handle, unsigned int flags)
|
||||
domain->ssid = domaininfo[i].ssidref;
|
||||
domain->num_networks = 0;
|
||||
domain->networks = NULL;
|
||||
domain->num_vbds = 0;
|
||||
domain->vbds = NULL;
|
||||
|
||||
domain++;
|
||||
}
|
||||
@@ -451,6 +475,21 @@ xenstat_network *xenstat_domain_network(xenstat_domain * domain,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the number of VBDs for a given domain */
|
||||
unsigned int xenstat_domain_num_vbds(xenstat_domain * domain)
|
||||
{
|
||||
return domain->num_vbds;
|
||||
}
|
||||
|
||||
/* Get the VBD handle to obtain VBD stats */
|
||||
xenstat_vbd *xenstat_domain_vbd(xenstat_domain * domain,
|
||||
unsigned int vbd)
|
||||
{
|
||||
if (domain->vbds && 0 <= vbd && vbd < domain->num_vbds)
|
||||
return &(domain->vbds[vbd]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* VCPU functions
|
||||
*/
|
||||
@@ -710,6 +749,139 @@ static void xenstat_uninit_xen_version(xenstat_handle * handle)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* VBD functions
|
||||
*/
|
||||
|
||||
static int read_attributes_vbd(const char *vbd_directory, const char *what, char *ret, int cap)
|
||||
{
|
||||
static char file_name[80];
|
||||
int fd, num_read;
|
||||
|
||||
sprintf(file_name, "%s/%s/%s", SYSFS_VBD_PATH, vbd_directory, what);
|
||||
fd = open(file_name, O_RDONLY, 0);
|
||||
if (fd==-1) return -1;
|
||||
num_read = read(fd, ret, cap - 1);
|
||||
close(fd);
|
||||
if (num_read<=0) return -1;
|
||||
ret[num_read] = '\0';
|
||||
return num_read;
|
||||
}
|
||||
|
||||
/* Collect information about VBDs */
|
||||
static int xenstat_collect_vbds(xenstat_node * node)
|
||||
{
|
||||
struct dirent *dp;
|
||||
|
||||
if (node->handle->sysfsvbd == NULL) {
|
||||
node->handle->sysfsvbd = opendir(SYSFS_VBD_PATH);
|
||||
if (node->handle->sysfsvbd == NULL) {
|
||||
perror("Error opening " SYSFS_VBD_PATH);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rewinddir(node->handle->sysfsvbd);
|
||||
|
||||
for(dp = readdir(node->handle->sysfsvbd); dp != NULL ;
|
||||
dp = readdir(node->handle->sysfsvbd)) {
|
||||
xenstat_domain *domain;
|
||||
xenstat_vbd vbd;
|
||||
unsigned int domid;
|
||||
int ret;
|
||||
char buf[256];
|
||||
|
||||
|
||||
ret = sscanf(dp->d_name, "vbd-%u-%u", &domid, &vbd.dev);
|
||||
if (ret != 2) {
|
||||
continue;
|
||||
}
|
||||
printf("%s is VBD.\n",dp->d_name);
|
||||
|
||||
domain = xenstat_node_domain(node, domid);
|
||||
if (domain == NULL) {
|
||||
fprintf(stderr,
|
||||
"Found interface vbd-%u-%u but domain %u"
|
||||
" does not exist.\n",
|
||||
domid, vbd.dev, domid);
|
||||
continue;
|
||||
}
|
||||
|
||||
if((read_attributes_vbd(dp->d_name, "statistics/oo_req", buf, 256)<=0)
|
||||
|| ((ret = sscanf(buf, "%llu", &vbd.oo_reqs)) != 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if((read_attributes_vbd(dp->d_name, "statistics/rd_req", buf, 256)<=0)
|
||||
|| ((ret = sscanf(buf, "%llu", &vbd.rd_reqs)) != 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if((read_attributes_vbd(dp->d_name, "statistics/wr_req", buf, 256)<=0)
|
||||
|| ((ret = sscanf(buf, "%llu", &vbd.wr_reqs)) != 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (domain->vbds == NULL) {
|
||||
domain->num_vbds = 1;
|
||||
domain->vbds = malloc(sizeof(xenstat_vbd));
|
||||
} else {
|
||||
domain->num_vbds++;
|
||||
domain->vbds = realloc(domain->vbds,
|
||||
domain->num_vbds *
|
||||
sizeof(xenstat_vbd));
|
||||
}
|
||||
if (domain->vbds == NULL)
|
||||
return 0;
|
||||
domain->vbds[domain->num_vbds - 1] = vbd;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Free VBD information */
|
||||
static void xenstat_free_vbds(xenstat_node * node)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < node->num_domains; i++)
|
||||
free(node->domains[i].vbds);
|
||||
}
|
||||
|
||||
/* Free VBD information in handle */
|
||||
static void xenstat_uninit_vbds(xenstat_handle * handle)
|
||||
{
|
||||
if (handle->sysfsvbd)
|
||||
closedir(handle->sysfsvbd);
|
||||
}
|
||||
|
||||
/* Get the major number of VBD device */
|
||||
unsigned int xenstat_vbd_dev(xenstat_vbd * vbd)
|
||||
{
|
||||
return vbd->dev;
|
||||
}
|
||||
|
||||
/* Get the number of OO(Out of) requests */
|
||||
unsigned long long xenstat_vbd_oo_reqs(xenstat_vbd * vbd)
|
||||
{
|
||||
return vbd->oo_reqs;
|
||||
}
|
||||
|
||||
/* Get the number of READ requests */
|
||||
unsigned long long xenstat_vbd_rd_reqs(xenstat_vbd * vbd)
|
||||
{
|
||||
return vbd->rd_reqs;
|
||||
}
|
||||
|
||||
/* Get the number of WRITE requests */
|
||||
unsigned long long xenstat_vbd_wr_reqs(xenstat_vbd * vbd)
|
||||
{
|
||||
return vbd->wr_reqs;
|
||||
}
|
||||
|
||||
static char *xenstat_get_domain_name(xenstat_handle *handle, unsigned int domain_id)
|
||||
{
|
||||
char path[80];
|
||||
|
||||
@@ -23,6 +23,7 @@ typedef struct xenstat_domain xenstat_domain;
|
||||
typedef struct xenstat_node xenstat_node;
|
||||
typedef struct xenstat_vcpu xenstat_vcpu;
|
||||
typedef struct xenstat_network xenstat_network;
|
||||
typedef struct xenstat_vbd xenstat_vbd;
|
||||
|
||||
/* Initialize the xenstat library. Returns a handle to be used with
|
||||
* subsequent calls to the xenstat library, or NULL if an error occurs. */
|
||||
@@ -35,7 +36,8 @@ void xenstat_uninit(xenstat_handle * handle);
|
||||
#define XENSTAT_VCPU 0x1
|
||||
#define XENSTAT_NETWORK 0x2
|
||||
#define XENSTAT_XEN_VERSION 0x4
|
||||
#define XENSTAT_ALL (XENSTAT_VCPU|XENSTAT_NETWORK|XENSTAT_XEN_VERSION)
|
||||
#define XENSTAT_VBD 0x8
|
||||
#define XENSTAT_ALL (XENSTAT_VCPU|XENSTAT_NETWORK|XENSTAT_XEN_VERSION|XENSTAT_VBD)
|
||||
|
||||
/* Get all available information about a node */
|
||||
xenstat_node *xenstat_get_node(xenstat_handle * handle, unsigned int flags);
|
||||
@@ -117,6 +119,13 @@ unsigned int xenstat_domain_num_networks(xenstat_domain *);
|
||||
xenstat_network *xenstat_domain_network(xenstat_domain * domain,
|
||||
unsigned int network);
|
||||
|
||||
/* Get the number of VBDs for a given domain */
|
||||
unsigned int xenstat_domain_num_vbds(xenstat_domain *);
|
||||
|
||||
/* Get the VBD handle to obtain VBD stats */
|
||||
xenstat_vbd *xenstat_domain_vbd(xenstat_domain * domain,
|
||||
unsigned int vbd);
|
||||
|
||||
/*
|
||||
* VCPU functions - extract information from a xenstat_vcpu
|
||||
*/
|
||||
@@ -156,3 +165,14 @@ unsigned long long xenstat_network_terrs(xenstat_network * network);
|
||||
|
||||
/* Get the number of transmit drops for this network */
|
||||
unsigned long long xenstat_network_tdrop(xenstat_network * network);
|
||||
|
||||
/*
|
||||
* VBD functions - extract information from a xen_vbd
|
||||
*/
|
||||
/* Get the device number for Virtual Block Device */
|
||||
unsigned int xenstat_vbd_dev(xenstat_vbd * vbd);
|
||||
|
||||
/* Get the number of OO/RD/WR requests for vbd */
|
||||
unsigned long long xenstat_vbd_oo_reqs(xenstat_vbd * vbd);
|
||||
unsigned long long xenstat_vbd_rd_reqs(xenstat_vbd * vbd);
|
||||
unsigned long long xenstat_vbd_wr_reqs(xenstat_vbd * vbd);
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
#include <xenstat.h>
|
||||
|
||||
@@ -65,6 +66,7 @@ static int handle_key(int);
|
||||
static int compare(unsigned long long, unsigned long long);
|
||||
static int compare_domains(xenstat_domain **, xenstat_domain **);
|
||||
static unsigned long long tot_net_bytes( xenstat_domain *, int);
|
||||
static unsigned long long tot_vbd_reqs( xenstat_domain *, int);
|
||||
|
||||
/* Field functions */
|
||||
static int compare_state(xenstat_domain *domain1, xenstat_domain *domain2);
|
||||
@@ -91,6 +93,15 @@ static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2);
|
||||
static void print_ssid(xenstat_domain *domain);
|
||||
static int compare_name(xenstat_domain *domain1, xenstat_domain *domain2);
|
||||
static void print_name(xenstat_domain *domain);
|
||||
static int compare_vbds(xenstat_domain *domain1, xenstat_domain *domain2);
|
||||
static void print_vbds(xenstat_domain *domain);
|
||||
static int compare_vbd_oo(xenstat_domain *domain1, xenstat_domain *domain2);
|
||||
static void print_vbd_oo(xenstat_domain *domain);
|
||||
static int compare_vbd_rd(xenstat_domain *domain1, xenstat_domain *domain2);
|
||||
static void print_vbd_rd(xenstat_domain *domain);
|
||||
static int compare_vbd_wr(xenstat_domain *domain1, xenstat_domain *domain2);
|
||||
static void print_vbd_wr(xenstat_domain *domain);
|
||||
|
||||
|
||||
/* Section printing functions */
|
||||
static void do_summary(void);
|
||||
@@ -99,6 +110,7 @@ static void do_bottom_line(void);
|
||||
static void do_domain(xenstat_domain *);
|
||||
static void do_vcpu(xenstat_domain *);
|
||||
static void do_network(xenstat_domain *);
|
||||
static void do_vbd(xenstat_domain *);
|
||||
static void top(void);
|
||||
|
||||
/* Field types */
|
||||
@@ -116,6 +128,10 @@ typedef enum field_id {
|
||||
FIELD_NETS,
|
||||
FIELD_NET_TX,
|
||||
FIELD_NET_RX,
|
||||
FIELD_VBDS,
|
||||
FIELD_VBD_OO,
|
||||
FIELD_VBD_RD,
|
||||
FIELD_VBD_WR,
|
||||
FIELD_SSID
|
||||
} field_id;
|
||||
|
||||
@@ -140,6 +156,10 @@ field fields[] = {
|
||||
{ FIELD_NETS, "NETS", 4, compare_nets, print_nets },
|
||||
{ FIELD_NET_TX, "NETTX(k)", 8, compare_net_tx, print_net_tx },
|
||||
{ FIELD_NET_RX, "NETRX(k)", 8, compare_net_rx, print_net_rx },
|
||||
{ FIELD_VBDS, "VBDS", 4, compare_vbds, print_vbds },
|
||||
{ FIELD_VBD_OO, "VBD_OO", 8, compare_vbd_oo, print_vbd_oo },
|
||||
{ FIELD_VBD_RD, "VBD_RD", 8, compare_vbd_rd, print_vbd_rd },
|
||||
{ FIELD_VBD_WR, "VBD_WR", 8, compare_vbd_wr, print_vbd_wr },
|
||||
{ FIELD_SSID, "SSID", 4, compare_ssid, print_ssid }
|
||||
};
|
||||
|
||||
@@ -158,6 +178,7 @@ unsigned int loop = 1;
|
||||
unsigned int iterations = 0;
|
||||
int show_vcpus = 0;
|
||||
int show_networks = 0;
|
||||
int show_vbds = 0;
|
||||
int repeat_header = 0;
|
||||
#define PROMPT_VAL_LEN 80
|
||||
char *prompt = NULL;
|
||||
@@ -180,6 +201,7 @@ static void usage(const char *program)
|
||||
"-V, --version output version information and exit\n"
|
||||
"-d, --delay=SECONDS seconds between updates (default 3)\n"
|
||||
"-n, --networks output vif network data\n"
|
||||
"-b, --vbds output vbd block device data\n"
|
||||
"-r, --repeat-header repeat table header before each domain\n"
|
||||
"-v, --vcpus output vcpu data\n"
|
||||
"-b, --batch output in batch mode, no user input accepted\n"
|
||||
@@ -290,6 +312,9 @@ static int handle_key(int ch)
|
||||
case 'n': case 'N':
|
||||
show_networks ^= 1;
|
||||
break;
|
||||
case 'b': case 'B':
|
||||
show_vbds ^= 1;
|
||||
break;
|
||||
case 'r': case 'R':
|
||||
repeat_header ^= 1;
|
||||
break;
|
||||
@@ -585,6 +610,96 @@ static unsigned long long tot_net_bytes(xenstat_domain *domain, int rx_flag)
|
||||
return total;
|
||||
}
|
||||
|
||||
/* Compares number of virtual block devices of two domains,
|
||||
returning -1,0,1 for * <,=,> */
|
||||
static int compare_vbds(xenstat_domain *domain1, xenstat_domain *domain2)
|
||||
{
|
||||
return -compare(xenstat_domain_num_vbds(domain1),
|
||||
xenstat_domain_num_vbds(domain2));
|
||||
}
|
||||
|
||||
/* Prints number of virtual block devices statistic */
|
||||
static void print_vbds(xenstat_domain *domain)
|
||||
{
|
||||
print("%4u", xenstat_domain_num_vbds(domain));
|
||||
}
|
||||
|
||||
/* Compares number of total VBD OO requests of two domains,
|
||||
returning -1,0,1 * for <,=,> */
|
||||
static int compare_vbd_oo(xenstat_domain *domain1, xenstat_domain *domain2)
|
||||
{
|
||||
return -compare(tot_vbd_reqs(domain1, FIELD_VBD_OO),
|
||||
tot_vbd_reqs(domain2, FIELD_VBD_OO));
|
||||
}
|
||||
|
||||
/* Prints number of total VBD OO requests statistic */
|
||||
static void print_vbd_oo(xenstat_domain *domain)
|
||||
{
|
||||
print("%8llu", tot_vbd_reqs(domain, FIELD_VBD_OO));
|
||||
}
|
||||
|
||||
/* Compares number of total VBD READ requests of two domains,
|
||||
returning -1,0,1 * for <,=,> */
|
||||
static int compare_vbd_rd(xenstat_domain *domain1, xenstat_domain *domain2)
|
||||
{
|
||||
return -compare(tot_vbd_reqs(domain1, FIELD_VBD_RD),
|
||||
tot_vbd_reqs(domain2, FIELD_VBD_RD));
|
||||
}
|
||||
|
||||
/* Prints number of total VBD READ requests statistic */
|
||||
static void print_vbd_rd(xenstat_domain *domain)
|
||||
{
|
||||
print("%8llu", tot_vbd_reqs(domain, FIELD_VBD_RD));
|
||||
}
|
||||
|
||||
/* Compares number of total VBD WRITE requests of two domains,
|
||||
returning -1,0,1 * for <,=,> */
|
||||
static int compare_vbd_wr(xenstat_domain *domain1, xenstat_domain *domain2)
|
||||
{
|
||||
return -compare(tot_vbd_reqs(domain1,FIELD_VBD_WR),
|
||||
tot_vbd_reqs(domain2,FIELD_VBD_WR));
|
||||
}
|
||||
|
||||
/* Prints number of total VBD WRITE requests statistic */
|
||||
static void print_vbd_wr(xenstat_domain *domain)
|
||||
{
|
||||
print("%8llu", tot_vbd_reqs(domain,FIELD_VBD_WR));
|
||||
}
|
||||
|
||||
/* Gets number of total VBD requests statistic,
|
||||
* if flag is FIELD_VBD_OO, then OO requests,
|
||||
* if flag is FIELD_VBD_RD, then READ requests and
|
||||
* if flag is FIELD_VBD_WR, then WRITE requests.
|
||||
*/
|
||||
static unsigned long long tot_vbd_reqs(xenstat_domain *domain, int flag)
|
||||
{
|
||||
int i = 0;
|
||||
xenstat_vbd *vbd;
|
||||
unsigned num_vbds = 0;
|
||||
unsigned long long total = 0;
|
||||
|
||||
num_vbds = xenstat_domain_num_vbds(domain);
|
||||
|
||||
for ( i=0 ; i < num_vbds ; i++) {
|
||||
vbd = xenstat_domain_vbd(domain,i);
|
||||
switch(flag) {
|
||||
case FIELD_VBD_OO:
|
||||
total += xenstat_vbd_oo_reqs(vbd);
|
||||
break;
|
||||
case FIELD_VBD_RD:
|
||||
total += xenstat_vbd_rd_reqs(vbd);
|
||||
break;
|
||||
case FIELD_VBD_WR:
|
||||
total += xenstat_vbd_wr_reqs(vbd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/* Compares security id (ssid) of two domains, returning -1,0,1 for <,=,> */
|
||||
static int compare_ssid(xenstat_domain *domain1, xenstat_domain *domain2)
|
||||
{
|
||||
@@ -680,6 +795,13 @@ void do_bottom_line(void)
|
||||
addch(A_REVERSE | 'N');
|
||||
attr_addstr(show_networks ? COLOR_PAIR(1) : 0, "etworks");
|
||||
addstr(" ");
|
||||
|
||||
/* VBDs */
|
||||
attr_addstr(show_vbds ? COLOR_PAIR(1) : 0, "v");
|
||||
addch(A_REVERSE | 'B');
|
||||
attr_addstr(show_vbds ? COLOR_PAIR(1) : 0, "ds");
|
||||
addstr(" ");
|
||||
|
||||
|
||||
/* vcpus */
|
||||
addch(A_REVERSE | 'V');
|
||||
@@ -769,6 +891,28 @@ void do_network(xenstat_domain *domain)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Output all VBD information */
|
||||
void do_vbd(xenstat_domain *domain)
|
||||
{
|
||||
int i = 0;
|
||||
xenstat_vbd *vbd;
|
||||
unsigned num_vbds = 0;
|
||||
|
||||
num_vbds = xenstat_domain_num_vbds(domain);
|
||||
|
||||
for (i=0 ; i< num_vbds; i++) {
|
||||
vbd = xenstat_domain_vbd(domain,i);
|
||||
|
||||
print("VBD %4u [%2x:%2x] OO: %8llu RD: %8llu WR: %8llu\n",
|
||||
xenstat_vbd_dev(vbd),
|
||||
MAJOR(xenstat_vbd_dev(vbd)), MINOR(xenstat_vbd_dev(vbd)),
|
||||
xenstat_vbd_oo_reqs(vbd),
|
||||
xenstat_vbd_rd_reqs(vbd),
|
||||
xenstat_vbd_wr_reqs(vbd));
|
||||
}
|
||||
}
|
||||
|
||||
static void top(void)
|
||||
{
|
||||
xenstat_domain **domains;
|
||||
@@ -812,6 +956,8 @@ static void top(void)
|
||||
do_vcpu(domains[i]);
|
||||
if (show_networks)
|
||||
do_network(domains[i]);
|
||||
if (show_vbds)
|
||||
do_vbd(domains[i]);
|
||||
}
|
||||
|
||||
if(!batch)
|
||||
@@ -827,6 +973,7 @@ int main(int argc, char **argv)
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "networks", no_argument, NULL, 'n' },
|
||||
{ "vbds", no_argument, NULL, 'x' },
|
||||
{ "repeat-header", no_argument, NULL, 'r' },
|
||||
{ "vcpus", no_argument, NULL, 'v' },
|
||||
{ "delay", required_argument, NULL, 'd' },
|
||||
@@ -834,7 +981,7 @@ int main(int argc, char **argv)
|
||||
{ "iterations", required_argument, NULL, 'i' },
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
const char *sopts = "hVbnvd:bi:";
|
||||
const char *sopts = "hVnxrvd:bi:";
|
||||
|
||||
if (atexit(cleanup) != 0)
|
||||
fail("Failed to install cleanup handler.\n");
|
||||
@@ -852,6 +999,9 @@ int main(int argc, char **argv)
|
||||
case 'n':
|
||||
show_networks = 1;
|
||||
break;
|
||||
case 'x':
|
||||
show_vbds = 1;
|
||||
break;
|
||||
case 'r':
|
||||
repeat_header = 1;
|
||||
break;
|
||||
|
||||
@@ -14,16 +14,15 @@ import os.path
|
||||
|
||||
config = {"vtpm":"instance=1,backend=0"}
|
||||
domain = XmTestDomain(extraConfig=config)
|
||||
domName = domain.getName()
|
||||
|
||||
try:
|
||||
console = domain.start()
|
||||
except DomainError, e:
|
||||
if verbose:
|
||||
print e.extra
|
||||
vtpm_cleanup(domain.getName())
|
||||
FAIL("Unable to create domain")
|
||||
|
||||
domName = domain.getName()
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Unable to create domain (%s)" % domName)
|
||||
|
||||
try:
|
||||
console.sendInput("input")
|
||||
@@ -33,11 +32,11 @@ except ConsoleError, e:
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/platform/tpm_vtpm/pcrs")
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
if re.search("No such file",run["output"]):
|
||||
vtpm_cleanup(domName)
|
||||
|
||||
@@ -15,6 +15,7 @@ import os.path
|
||||
|
||||
config = {"vtpm":"instance=1,backend=0"}
|
||||
domain = XmTestDomain(extraConfig=config)
|
||||
domName = domain.getName()
|
||||
consoleHistory = ""
|
||||
|
||||
try:
|
||||
@@ -22,10 +23,8 @@ try:
|
||||
except DomainError, e:
|
||||
if verbose:
|
||||
print e.extra
|
||||
vtpm_cleanup(domain.getName())
|
||||
FAIL("Unable to create domain")
|
||||
|
||||
domName = domain.getName()
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Unable to create domain (%s)" % domName)
|
||||
|
||||
try:
|
||||
console.sendInput("input")
|
||||
@@ -35,11 +34,11 @@ except ConsoleError, e:
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/platform/tpm_vtpm/pcrs")
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
if re.search("No such file",run["output"]):
|
||||
vtpm_cleanup(domName)
|
||||
@@ -48,50 +47,59 @@ if re.search("No such file",run["output"]):
|
||||
consoleHistory = console.getHistory()
|
||||
domain.closeConsole()
|
||||
|
||||
try:
|
||||
status, ouptut = traceCommand("xm save %s %s.save" %
|
||||
(domName, domName),
|
||||
timeout=30)
|
||||
loop = 0
|
||||
while loop < 3:
|
||||
try:
|
||||
status, ouptut = traceCommand("xm save %s %s.save" %
|
||||
(domName, domName),
|
||||
timeout=30)
|
||||
|
||||
except TimeoutError, e:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
except TimeoutError, e:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
if status != 0:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("xm save did not succeed")
|
||||
if status != 0:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("xm save did not succeed")
|
||||
|
||||
try:
|
||||
status, ouptut = traceCommand("xm restore %s.save" %
|
||||
(domName),
|
||||
timeout=30)
|
||||
except TimeoutError, e:
|
||||
os.remove("%s.save" % domName)
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
status, ouptut = traceCommand("xm restore %s.save" %
|
||||
(domName),
|
||||
timeout=30)
|
||||
except TimeoutError, e:
|
||||
os.remove("%s.save" % domName)
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
os.remove("%s.save" % domName)
|
||||
if status != 0:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("xm restore did not succeed")
|
||||
|
||||
if status != 0:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("xm restore did not succeed")
|
||||
try:
|
||||
console = domain.getConsole()
|
||||
except ConsoleError, e:
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
console = domain.getConsole()
|
||||
except ConsoleError, e:
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/platform/tpm_vtpm/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side")
|
||||
|
||||
loop += 1
|
||||
|
||||
domain.closeConsole()
|
||||
|
||||
@@ -99,5 +107,3 @@ domain.stop()
|
||||
|
||||
vtpm_cleanup(domName)
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side")
|
||||
@@ -16,6 +16,7 @@ import os.path
|
||||
|
||||
config = {"vtpm":"instance=1,backend=0"}
|
||||
domain = XmTestDomain(extraConfig=config)
|
||||
domName = domain.getName()
|
||||
consoleHistory = ""
|
||||
|
||||
try:
|
||||
@@ -23,10 +24,8 @@ try:
|
||||
except DomainError, e:
|
||||
if verbose:
|
||||
print e.extra
|
||||
vtpm_cleanup(domain.getName())
|
||||
FAIL("Unable to create domain")
|
||||
|
||||
domName = domain.getName()
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Unable to create domain (%s)" % domName)
|
||||
|
||||
try:
|
||||
console.sendInput("input")
|
||||
@@ -36,11 +35,11 @@ except ConsoleError, e:
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/platform/tpm_vtpm/pcrs")
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
if re.search("No such file",run["output"]):
|
||||
vtpm_cleanup(domName)
|
||||
@@ -83,11 +82,17 @@ while loop < 3:
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/platform/tpm_vtpm/pcrs")
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side")
|
||||
|
||||
loop += 1
|
||||
|
||||
domain.closeConsole()
|
||||
@@ -95,6 +100,3 @@ domain.closeConsole()
|
||||
domain.stop()
|
||||
|
||||
vtpm_cleanup(domName)
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side")
|
||||
@@ -16,6 +16,7 @@ import os.path
|
||||
|
||||
config = {"vtpm":"instance=1,backend=0"}
|
||||
domain = XmTestDomain(extraConfig=config)
|
||||
domName = domain.getName()
|
||||
consoleHistory = ""
|
||||
|
||||
try:
|
||||
@@ -23,10 +24,8 @@ try:
|
||||
except DomainError, e:
|
||||
if verbose:
|
||||
print e.extra
|
||||
vtpm_cleanup(domain.getName())
|
||||
FAIL("Unable to create domain")
|
||||
|
||||
domName = domain.getName()
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Unable to create domain (%s)" % domName)
|
||||
|
||||
try:
|
||||
console.sendInput("input")
|
||||
@@ -36,11 +35,11 @@ except ConsoleError, e:
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/platform/tpm_vtpm/pcrs")
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
if re.search("No such file",run["output"]):
|
||||
vtpm_cleanup(domName)
|
||||
@@ -83,11 +82,17 @@ while loop < 3:
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/platform/tpm_vtpm/pcrs")
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side")
|
||||
|
||||
loop += 1
|
||||
|
||||
domain.closeConsole()
|
||||
@@ -95,6 +100,3 @@ domain.closeConsole()
|
||||
domain.stop()
|
||||
|
||||
vtpm_cleanup(domName)
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side")
|
||||
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) International Business Machines Corp., 2006
|
||||
# Author: Stefan Berger <stefanb@us.ibm.com>
|
||||
|
||||
# Positive Test: create domain with virtual TPM attached at build time,
|
||||
# extend a pcr
|
||||
# check list of pcrs; suspend and resume the domain and
|
||||
# check list of pcrs again and validate extended pcr
|
||||
|
||||
from XmTestLib import *
|
||||
from vtpm_utils import *
|
||||
import commands
|
||||
import os
|
||||
import os.path
|
||||
|
||||
config = {"vtpm":"instance=1,backend=0"}
|
||||
domain = XmTestDomain(extraConfig=config)
|
||||
domName = domain.getName()
|
||||
consoleHistory = ""
|
||||
|
||||
try:
|
||||
console = domain.start()
|
||||
except DomainError, e:
|
||||
if verbose:
|
||||
print e.extra
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Unable to create domain (%s)" % domName)
|
||||
|
||||
try:
|
||||
console.sendInput("input")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("mknod /dev/tpm0 c 10 224")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Error while creating /dev/tpm0")
|
||||
|
||||
try:
|
||||
run = console.runCmd("echo -ne \"\\x00\\xc1\\x00\\x00\\x00\\x22\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\0xf\\x10\\x11\\x12\\x13\\x14\" > /dev/tpm0")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Error while extending PCR 0")
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
|
||||
if re.search("No such file",run["output"]):
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("TPM frontend support not compiled into (domU?) kernel")
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side: \n%s" % run["output"])
|
||||
|
||||
if not re.search("PCR-00: 1E A7 BD",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
FAIL("Extend did not lead to expected result (1E A7 BD ...): \n%s" % run["output"])
|
||||
|
||||
consoleHistory = console.getHistory()
|
||||
domain.closeConsole()
|
||||
|
||||
loop = 0
|
||||
while loop < 3:
|
||||
try:
|
||||
status, ouptut = traceCommand("xm save %s %s.save" %
|
||||
(domName, domName),
|
||||
timeout=30)
|
||||
|
||||
except TimeoutError, e:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
if status != 0:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("xm save did not succeed")
|
||||
|
||||
try:
|
||||
status, ouptut = traceCommand("xm restore %s.save" %
|
||||
(domName),
|
||||
timeout=30)
|
||||
except TimeoutError, e:
|
||||
os.remove("%s.save" % domName)
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
os.remove("%s.save" % domName)
|
||||
|
||||
if status != 0:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("xm restore did not succeed")
|
||||
|
||||
try:
|
||||
console = domain.getConsole()
|
||||
except ConsoleError, e:
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side")
|
||||
|
||||
if not re.search("PCR-00: 1E A7 BD",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM lost PCR 0 value: \n%s" % run["output"])
|
||||
|
||||
loop += 1
|
||||
|
||||
domain.closeConsole()
|
||||
|
||||
domain.stop()
|
||||
|
||||
vtpm_cleanup(domName)
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) International Business Machines Corp., 2006
|
||||
# Author: Stefan Berger <stefanb@us.ibm.com>
|
||||
|
||||
# Positive Test: create domain with virtual TPM attached at build time,
|
||||
# extend a pcr
|
||||
# check list of pcrs; locally migrate the domain and
|
||||
# check list of pcrs again and validate extended pcr
|
||||
# This test does local live migration.
|
||||
|
||||
from XmTestLib import *
|
||||
from vtpm_utils import *
|
||||
import commands
|
||||
import os
|
||||
import os.path
|
||||
|
||||
config = {"vtpm":"instance=1,backend=0"}
|
||||
domain = XmTestDomain(extraConfig=config)
|
||||
domName = domain.getName()
|
||||
consoleHistory = ""
|
||||
|
||||
try:
|
||||
console = domain.start()
|
||||
except DomainError, e:
|
||||
if verbose:
|
||||
print e.extra
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Unable to create domain (%s)" % domName)
|
||||
|
||||
try:
|
||||
console.sendInput("input")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("mknod /dev/tpm0 c 10 224")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Error while creating /dev/tpm0")
|
||||
|
||||
try:
|
||||
run = console.runCmd("echo -ne \"\\x00\\xc1\\x00\\x00\\x00\\x22\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\0xf\\x10\\x11\\x12\\x13\\x14\" > /dev/tpm0")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Error while extending PCR 0")
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
|
||||
if re.search("No such file",run["output"]):
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("TPM frontend support not compiled into (domU?) kernel")
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side: \n%s" % run["output"])
|
||||
|
||||
if not re.search("PCR-00: 1E A7 BD",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
FAIL("Extend did not lead to expected result (1E A7 BD ...): \n%s" % run["output"])
|
||||
|
||||
consoleHistory = console.getHistory()
|
||||
domain.closeConsole()
|
||||
|
||||
old_domid = domid(domName)
|
||||
|
||||
loop = 0
|
||||
while loop < 3:
|
||||
try:
|
||||
status, ouptut = traceCommand("xm migrate -l %s localhost" %
|
||||
domName,
|
||||
timeout=90)
|
||||
except TimeoutError, e:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
if status != 0:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("xm migrate did not succeed. External device migration activated?")
|
||||
|
||||
|
||||
domName = domain.getName()
|
||||
new_domid = domid(domName)
|
||||
|
||||
if (old_domid == new_domid):
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("xm migrate failed, domain id is still %s (loop=%d)" %
|
||||
(old_domid,loop))
|
||||
|
||||
try:
|
||||
console = domain.getConsole()
|
||||
except ConsoleError, e:
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side")
|
||||
|
||||
if not re.search("PCR-00: 1E A7 BD",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM lost PCR 0 value: \n%s" % run["output"])
|
||||
|
||||
loop += 1
|
||||
|
||||
domain.closeConsole()
|
||||
|
||||
domain.stop()
|
||||
|
||||
vtpm_cleanup(domName)
|
||||
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) International Business Machines Corp., 2006
|
||||
# Author: Stefan Berger <stefanb@us.ibm.com>
|
||||
|
||||
# Positive Test: create domain with virtual TPM attached at build time,
|
||||
# extend a pcr
|
||||
# check list of pcrs; locally migrate the domain and
|
||||
# check list of pcrs again and validate extended pcr
|
||||
# This test does local (non-live) migration.
|
||||
|
||||
from XmTestLib import *
|
||||
from vtpm_utils import *
|
||||
import commands
|
||||
import os
|
||||
import os.path
|
||||
|
||||
config = {"vtpm":"instance=1,backend=0"}
|
||||
domain = XmTestDomain(extraConfig=config)
|
||||
domName = domain.getName()
|
||||
consoleHistory = ""
|
||||
|
||||
try:
|
||||
console = domain.start()
|
||||
except DomainError, e:
|
||||
if verbose:
|
||||
print e.extra
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Unable to create domain (%s)" % domName)
|
||||
|
||||
try:
|
||||
console.sendInput("input")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("mknod /dev/tpm0 c 10 224")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Error while creating /dev/tpm0")
|
||||
|
||||
try:
|
||||
run = console.runCmd("echo -ne \"\\x00\\xc1\\x00\\x00\\x00\\x22\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\0xf\\x10\\x11\\x12\\x13\\x14\" > /dev/tpm0")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Error while extending PCR 0")
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
|
||||
if re.search("No such file",run["output"]):
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("TPM frontend support not compiled into (domU?) kernel")
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side: \n%s" % run["output"])
|
||||
|
||||
if not re.search("PCR-00: 1E A7 BD",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
FAIL("Extend did not lead to expected result (1E A7 BD ...): \n%s" % run["output"])
|
||||
|
||||
consoleHistory = console.getHistory()
|
||||
domain.closeConsole()
|
||||
|
||||
old_domid = domid(domName)
|
||||
|
||||
loop = 0
|
||||
while loop < 3:
|
||||
try:
|
||||
status, ouptut = traceCommand("xm migrate %s localhost" %
|
||||
domName,
|
||||
timeout=90)
|
||||
except TimeoutError, e:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
if status != 0:
|
||||
saveLog(consoleHistory)
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("xm migrate did not succeed. External device migration activated?")
|
||||
|
||||
|
||||
domName = domain.getName()
|
||||
new_domid = domid(domName)
|
||||
|
||||
if (old_domid == new_domid):
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("xm migrate failed, domain id is still %s (loop=%d)" %
|
||||
(old_domid,loop))
|
||||
|
||||
try:
|
||||
console = domain.getConsole()
|
||||
except ConsoleError, e:
|
||||
vtpm_cleanup(domName)
|
||||
FAIL(str(e))
|
||||
|
||||
try:
|
||||
run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs")
|
||||
except ConsoleError, e:
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("No result from dumping the PCRs")
|
||||
|
||||
if not re.search("PCR-00:",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM is not working correctly on /dev/vtpm on backend side")
|
||||
|
||||
if not re.search("PCR-00: 1E A7 BD",run["output"]):
|
||||
saveLog(console.getHistory())
|
||||
vtpm_cleanup(domName)
|
||||
FAIL("Virtual TPM lost PCR 0 value: \n%s" % run["output"])
|
||||
|
||||
loop += 1
|
||||
|
||||
domain.closeConsole()
|
||||
|
||||
domain.stop()
|
||||
|
||||
vtpm_cleanup(domName)
|
||||
@@ -4,7 +4,10 @@ TESTS = 01_vtpm-list_pos.test \
|
||||
02_vtpm-cat_pcrs.test \
|
||||
03_vtpm-susp_res.test \
|
||||
04_vtpm-loc_migr.test \
|
||||
05_vtpm-loc_migr.test
|
||||
05_vtpm-loc_migr.test \
|
||||
06_vtpm-susp_res_pcrs.test \
|
||||
07_vtpm-mig_pcrs.test \
|
||||
08_vtpm-mig_pcrs.test
|
||||
|
||||
XFAIL_TESTS =
|
||||
|
||||
|
||||
@@ -16,4 +16,4 @@ if output == "":
|
||||
FAIL("virtual TPM manager must be started to run this test")
|
||||
|
||||
def vtpm_cleanup(domName):
|
||||
traceCommand("/etc/xen/scripts/vtpm-delete %s" % domName)
|
||||
traceCommand("/etc/xen/scripts/vtpm-delete %s" % domName)
|
||||
@@ -36,7 +36,7 @@ long arch_do_dom0_op(dom0_op_t *op, XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
case DOM0_GETPAGEFRAMEINFO:
|
||||
{
|
||||
struct page_info *page;
|
||||
unsigned long mfn = op->u.getpageframeinfo.mfn;
|
||||
unsigned long mfn = op->u.getpageframeinfo.gmfn;
|
||||
domid_t dom = op->u.getpageframeinfo.domain;
|
||||
struct domain *d;
|
||||
|
||||
|
||||
@@ -425,8 +425,9 @@ void start_kernel(void)
|
||||
|
||||
scheduler_init();
|
||||
idle_vcpu[0] = (struct vcpu*) ia64_r13;
|
||||
idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
|
||||
BUG_ON(idle_domain == NULL);
|
||||
idle_domain = domain_create(IDLE_DOMAIN_ID);
|
||||
if ( (idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL) )
|
||||
BUG();
|
||||
|
||||
late_setup_arch(&cmdline);
|
||||
alloc_dom_xen_and_dom_io();
|
||||
@@ -503,9 +504,8 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus);
|
||||
}
|
||||
|
||||
/* Create initial domain 0. */
|
||||
dom0 = domain_create(0, 0);
|
||||
|
||||
if ( dom0 == NULL )
|
||||
dom0 = domain_create(0);
|
||||
if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
|
||||
panic("Error creating domain 0\n");
|
||||
|
||||
set_bit(_DOMF_privileged, &dom0->domain_flags);
|
||||
|
||||
@@ -207,7 +207,7 @@ long arch_do_dom0_op(struct dom0_op *op, XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
case DOM0_GETPAGEFRAMEINFO:
|
||||
{
|
||||
struct page_info *page;
|
||||
unsigned long mfn = op->u.getpageframeinfo.mfn;
|
||||
unsigned long mfn = op->u.getpageframeinfo.gmfn;
|
||||
domid_t dom = op->u.getpageframeinfo.domain;
|
||||
struct domain *d;
|
||||
|
||||
@@ -407,15 +407,17 @@ long arch_do_dom0_op(struct dom0_op *op, XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
|
||||
case DOM0_HYPERCALL_INIT:
|
||||
{
|
||||
struct domain *d;
|
||||
unsigned long mfn = op->u.hypercall_init.mfn;
|
||||
struct domain *d = find_domain_by_id(op->u.hypercall_init.domain);
|
||||
unsigned long gmfn = op->u.hypercall_init.gmfn;
|
||||
unsigned long mfn;
|
||||
void *hypercall_page;
|
||||
|
||||
ret = -ESRCH;
|
||||
if ( unlikely((d = find_domain_by_id(
|
||||
op->u.hypercall_init.domain)) == NULL) )
|
||||
if ( unlikely(d == NULL) )
|
||||
break;
|
||||
|
||||
mfn = gmfn_to_mfn(d, gmfn);
|
||||
|
||||
ret = -EACCES;
|
||||
if ( !mfn_valid(mfn) ||
|
||||
!get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
|
||||
|
||||
@@ -67,16 +67,11 @@ static void default_idle(void)
|
||||
|
||||
void idle_loop(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
page_scrub_schedule_work();
|
||||
|
||||
default_idle();
|
||||
|
||||
if ( softirq_pending(cpu) )
|
||||
do_softirq();
|
||||
do_softirq();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -956,7 +951,7 @@ void domain_relinquish_resources(struct domain *d)
|
||||
}
|
||||
}
|
||||
|
||||
if ( hvm_guest(d->vcpu[0]) )
|
||||
if ( d->vcpu[0] && hvm_guest(d->vcpu[0]) )
|
||||
hvm_relinquish_guest_resources(d);
|
||||
|
||||
shadow_mode_disable(d);
|
||||
|
||||
+45
-44
@@ -962,8 +962,8 @@ static void svm_vmexit_do_cpuid(struct vmcb_struct *vmcb, unsigned long input,
|
||||
!vlapic_global_enabled((VLAPIC(v))) )
|
||||
{
|
||||
/* Since the apic is disabled, avoid any confusion
|
||||
about SMP cpus being available */
|
||||
clear_bit(X86_FEATURE_APIC, &edx);
|
||||
about SMP cpus being available */
|
||||
clear_bit(X86_FEATURE_APIC, &edx);
|
||||
}
|
||||
|
||||
#if CONFIG_PAGING_LEVELS < 3
|
||||
@@ -974,52 +974,51 @@ static void svm_vmexit_do_cpuid(struct vmcb_struct *vmcb, unsigned long input,
|
||||
if ( v->domain->arch.ops->guest_paging_levels == PAGING_L2 )
|
||||
{
|
||||
if ( !v->domain->arch.hvm_domain.pae_enabled )
|
||||
{
|
||||
clear_bit(X86_FEATURE_PAE, &edx);
|
||||
}
|
||||
clear_bit(X86_FEATURE_PAE, &edx);
|
||||
clear_bit(X86_FEATURE_PSE, &edx);
|
||||
clear_bit(X86_FEATURE_PSE36, &edx);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/* Clear out reserved bits. */
|
||||
ecx &= ~SVM_VCPU_CPUID_L1_ECX_RESERVED;
|
||||
edx &= ~SVM_VCPU_CPUID_L1_EDX_RESERVED;
|
||||
|
||||
clear_bit(X86_FEATURE_MWAIT & 31, &ecx);
|
||||
|
||||
/* Guest should only see one logical processor.
|
||||
* See details on page 23 of AMD CPUID Specification.
|
||||
*/
|
||||
clear_bit(X86_FEATURE_HT, &edx); /* clear the hyperthread bit */
|
||||
ebx &= 0xFF00FFFF; /* clear the logical processor count when HTT=0 */
|
||||
ebx |= 0x00010000; /* set to 1 just for precaution */
|
||||
/* Guest should only see one logical processor.
|
||||
* See details on page 23 of AMD CPUID Specification.
|
||||
*/
|
||||
clear_bit(X86_FEATURE_HT, &edx); /* clear the hyperthread bit */
|
||||
ebx &= 0xFF00FFFF; /* clear the logical processor count when HTT=0 */
|
||||
ebx |= 0x00010000; /* set to 1 just for precaution */
|
||||
|
||||
/* Disable machine check architecture */
|
||||
clear_bit(X86_FEATURE_MCA, &edx);
|
||||
clear_bit(X86_FEATURE_MCE, &edx);
|
||||
/* Disable machine check architecture */
|
||||
clear_bit(X86_FEATURE_MCA, &edx);
|
||||
clear_bit(X86_FEATURE_MCE, &edx);
|
||||
}
|
||||
else if ( ( input > 0x00000005 ) && ( input < 0x80000000 ) )
|
||||
else if ( (input > 0x00000005) && (input < 0x80000000) )
|
||||
{
|
||||
eax = ebx = ecx = edx = 0x0;
|
||||
if ( !cpuid_hypervisor_leaves(input, &eax, &ebx, &ecx, &edx) )
|
||||
eax = ebx = ecx = edx = 0;
|
||||
}
|
||||
else if ( input == 0x80000001 )
|
||||
{
|
||||
/* We duplicate some CPUID_00000001 code because many bits of
|
||||
CPUID_80000001_EDX overlaps with CPUID_00000001_EDX. */
|
||||
/* We duplicate some CPUID_00000001 code because many bits of
|
||||
CPUID_80000001_EDX overlaps with CPUID_00000001_EDX. */
|
||||
|
||||
if ( !hvm_apic_support(v->domain) ||
|
||||
!vlapic_global_enabled((VLAPIC(v))) )
|
||||
!vlapic_global_enabled((VLAPIC(v))) )
|
||||
{
|
||||
/* Since the apic is disabled, avoid any confusion
|
||||
about SMP cpus being available */
|
||||
clear_bit(X86_FEATURE_APIC, &edx);
|
||||
about SMP cpus being available */
|
||||
clear_bit(X86_FEATURE_APIC, &edx);
|
||||
}
|
||||
|
||||
/* Clear the Cmp_Legacy bit
|
||||
* This bit is supposed to be zero when HTT = 0.
|
||||
* See details on page 23 of AMD CPUID Specification.
|
||||
*/
|
||||
clear_bit(X86_FEATURE_CMP_LEGACY & 31, &ecx);
|
||||
/* Clear the Cmp_Legacy bit
|
||||
* This bit is supposed to be zero when HTT = 0.
|
||||
* See details on page 23 of AMD CPUID Specification.
|
||||
*/
|
||||
clear_bit(X86_FEATURE_CMP_LEGACY & 31, &ecx);
|
||||
|
||||
#ifdef __i386__
|
||||
/* Mask feature for Intel ia32e or AMD long mode. */
|
||||
@@ -1030,7 +1029,7 @@ static void svm_vmexit_do_cpuid(struct vmcb_struct *vmcb, unsigned long input,
|
||||
#endif
|
||||
|
||||
#if CONFIG_PAGING_LEVELS < 3
|
||||
clear_bit(X86_FEATURE_NX & 31, &edx);
|
||||
clear_bit(X86_FEATURE_NX & 31, &edx);
|
||||
clear_bit(X86_FEATURE_PAE, &edx);
|
||||
clear_bit(X86_FEATURE_PSE, &edx);
|
||||
clear_bit(X86_FEATURE_PSE36, &edx);
|
||||
@@ -1039,29 +1038,29 @@ static void svm_vmexit_do_cpuid(struct vmcb_struct *vmcb, unsigned long input,
|
||||
{
|
||||
if ( !v->domain->arch.hvm_domain.pae_enabled )
|
||||
{
|
||||
clear_bit(X86_FEATURE_NX & 31, &edx);
|
||||
clear_bit(X86_FEATURE_PAE, &edx);
|
||||
clear_bit(X86_FEATURE_NX & 31, &edx);
|
||||
clear_bit(X86_FEATURE_PAE, &edx);
|
||||
}
|
||||
clear_bit(X86_FEATURE_PSE, &edx);
|
||||
clear_bit(X86_FEATURE_PSE36, &edx);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Make SVM feature invisible to the guest. */
|
||||
clear_bit(X86_FEATURE_SVME & 31, &ecx);
|
||||
|
||||
/* So far, we do not support 3DNow for the guest. */
|
||||
clear_bit(X86_FEATURE_3DNOW & 31, &edx);
|
||||
clear_bit(X86_FEATURE_3DNOWEXT & 31, &edx);
|
||||
|
||||
/* So far, we do not support 3DNow for the guest. */
|
||||
clear_bit(X86_FEATURE_3DNOW & 31, &edx);
|
||||
clear_bit(X86_FEATURE_3DNOWEXT & 31, &edx);
|
||||
}
|
||||
else if ( ( input == 0x80000007 ) || ( input == 0x8000000A ) )
|
||||
{
|
||||
/* Mask out features of power management and SVM extension. */
|
||||
eax = ebx = ecx = edx = 0;
|
||||
/* Mask out features of power management and SVM extension. */
|
||||
eax = ebx = ecx = edx = 0;
|
||||
}
|
||||
else if ( input == 0x80000008 )
|
||||
{
|
||||
ecx &= 0xFFFFFF00; /* Make sure Number of CPU core is 1 when HTT=0 */
|
||||
ecx &= 0xFFFFFF00; /* Make sure Number of CPU core is 1 when HTT=0 */
|
||||
}
|
||||
|
||||
regs->eax = (unsigned long)eax;
|
||||
@@ -1214,8 +1213,9 @@ static void svm_dr_access (struct vcpu *v, unsigned int reg, unsigned int type,
|
||||
}
|
||||
|
||||
|
||||
static void svm_get_prefix_info(struct vmcb_struct *vmcb,
|
||||
unsigned int dir, segment_selector_t **seg, unsigned int *asize)
|
||||
static void svm_get_prefix_info(
|
||||
struct vmcb_struct *vmcb,
|
||||
unsigned int dir, segment_selector_t **seg, unsigned int *asize)
|
||||
{
|
||||
unsigned char inst[MAX_INST_LEN];
|
||||
int i;
|
||||
@@ -1287,9 +1287,10 @@ static void svm_get_prefix_info(struct vmcb_struct *vmcb,
|
||||
|
||||
|
||||
/* Get the address of INS/OUTS instruction */
|
||||
static inline int svm_get_io_address(struct vcpu *v,
|
||||
struct cpu_user_regs *regs, unsigned int dir,
|
||||
unsigned long *count, unsigned long *addr)
|
||||
static inline int svm_get_io_address(
|
||||
struct vcpu *v,
|
||||
struct cpu_user_regs *regs, unsigned int dir,
|
||||
unsigned long *count, unsigned long *addr)
|
||||
{
|
||||
unsigned long reg;
|
||||
unsigned int asize = 0;
|
||||
@@ -2697,9 +2698,9 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
|
||||
|
||||
if (exit_reason == -1)
|
||||
{
|
||||
svm_dump_vmcb(__func__, vmcb);
|
||||
printk("%s: exit_reason == -1 - Did someone clobber the VMCB\n",
|
||||
__func__);
|
||||
BUG();
|
||||
domain_crash_synchronous();
|
||||
}
|
||||
|
||||
|
||||
+85
-81
@@ -36,38 +36,57 @@
|
||||
#include <xen/kernel.h>
|
||||
#include <asm/shadow.h>
|
||||
#include <xen/keyhandler.h>
|
||||
|
||||
#if CONFIG_PAGING_LEVELS >= 3
|
||||
#include <asm/shadow_64.h>
|
||||
#endif
|
||||
|
||||
int vmcs_size;
|
||||
static int vmcs_size;
|
||||
static int vmcs_order;
|
||||
static u32 vmcs_revision_id;
|
||||
|
||||
struct vmcs_struct *vmx_alloc_vmcs(void)
|
||||
void vmx_init_vmcs_config(void)
|
||||
{
|
||||
struct vmcs_struct *vmcs;
|
||||
u32 vmx_msr_low, vmx_msr_high;
|
||||
|
||||
rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high);
|
||||
vmcs_size = vmx_msr_high & 0x1fff;
|
||||
vmcs = alloc_xenheap_pages(get_order_from_bytes(vmcs_size));
|
||||
memset((char *)vmcs, 0, vmcs_size); /* don't remove this */
|
||||
if ( vmcs_size )
|
||||
return;
|
||||
|
||||
rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high);
|
||||
|
||||
vmcs_revision_id = vmx_msr_low;
|
||||
|
||||
vmcs_size = vmx_msr_high & 0x1fff;
|
||||
vmcs_order = get_order_from_bytes(vmcs_size);
|
||||
}
|
||||
|
||||
static struct vmcs_struct *vmx_alloc_vmcs(void)
|
||||
{
|
||||
struct vmcs_struct *vmcs;
|
||||
|
||||
if ( (vmcs = alloc_xenheap_pages(vmcs_order)) == NULL )
|
||||
{
|
||||
DPRINTK("Failed to allocate VMCS.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(vmcs, 0, vmcs_size); /* don't remove this */
|
||||
vmcs->vmcs_revision_id = vmcs_revision_id;
|
||||
|
||||
vmcs->vmcs_revision_id = vmx_msr_low;
|
||||
return vmcs;
|
||||
}
|
||||
|
||||
static void free_vmcs(struct vmcs_struct *vmcs)
|
||||
static void vmx_free_vmcs(struct vmcs_struct *vmcs)
|
||||
{
|
||||
int order;
|
||||
|
||||
order = get_order_from_bytes(vmcs_size);
|
||||
free_xenheap_pages(vmcs, order);
|
||||
free_xenheap_pages(vmcs, vmcs_order);
|
||||
}
|
||||
|
||||
static void __vmx_clear_vmcs(void *info)
|
||||
{
|
||||
struct vcpu *v = info;
|
||||
|
||||
__vmpclear(virt_to_maddr(v->arch.hvm_vmx.vmcs));
|
||||
|
||||
v->arch.hvm_vmx.active_cpu = -1;
|
||||
v->arch.hvm_vmx.launched = 0;
|
||||
}
|
||||
@@ -127,11 +146,19 @@ void vmx_vmcs_exit(struct vcpu *v)
|
||||
vcpu_unpause(v);
|
||||
}
|
||||
|
||||
struct vmcs_struct *vmx_alloc_host_vmcs(void)
|
||||
{
|
||||
return vmx_alloc_vmcs();
|
||||
}
|
||||
|
||||
void vmx_free_host_vmcs(struct vmcs_struct *vmcs)
|
||||
{
|
||||
vmx_free_vmcs(vmcs);
|
||||
}
|
||||
|
||||
static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx)
|
||||
{
|
||||
int error = 0;
|
||||
void *io_bitmap_a;
|
||||
void *io_bitmap_b;
|
||||
|
||||
error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL,
|
||||
MONITOR_PIN_BASED_EXEC_CONTROLS);
|
||||
@@ -140,19 +167,8 @@ static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx)
|
||||
|
||||
error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS);
|
||||
|
||||
/* need to use 0x1000 instead of PAGE_SIZE */
|
||||
io_bitmap_a = (void*) alloc_xenheap_pages(get_order_from_bytes(0x1000));
|
||||
io_bitmap_b = (void*) alloc_xenheap_pages(get_order_from_bytes(0x1000));
|
||||
memset(io_bitmap_a, 0xff, 0x1000);
|
||||
/* don't bother debug port access */
|
||||
clear_bit(PC_DEBUG_PORT, io_bitmap_a);
|
||||
memset(io_bitmap_b, 0xff, 0x1000);
|
||||
|
||||
error |= __vmwrite(IO_BITMAP_A, (u64) virt_to_maddr(io_bitmap_a));
|
||||
error |= __vmwrite(IO_BITMAP_B, (u64) virt_to_maddr(io_bitmap_b));
|
||||
|
||||
arch_vmx->io_bitmap_a = io_bitmap_a;
|
||||
arch_vmx->io_bitmap_b = io_bitmap_b;
|
||||
error |= __vmwrite(IO_BITMAP_A, (u64)virt_to_maddr(arch_vmx->io_bitmap_a));
|
||||
error |= __vmwrite(IO_BITMAP_B, (u64)virt_to_maddr(arch_vmx->io_bitmap_b));
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -428,84 +444,71 @@ static inline int construct_vmcs_host(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to extend to support full virtualization.
|
||||
* the working VMCS pointer has been set properly
|
||||
* just before entering this function.
|
||||
*/
|
||||
static int construct_vmcs(struct vcpu *v,
|
||||
cpu_user_regs_t *regs)
|
||||
{
|
||||
struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
|
||||
int error;
|
||||
long rc;
|
||||
|
||||
memset(arch_vmx, 0, sizeof(struct arch_vmx_struct));
|
||||
|
||||
spin_lock_init(&arch_vmx->vmcs_lock);
|
||||
arch_vmx->active_cpu = -1;
|
||||
|
||||
/*
|
||||
* Create a new VMCS
|
||||
*/
|
||||
if (!(arch_vmx->vmcs = vmx_alloc_vmcs())) {
|
||||
printk("Failed to create a new VMCS\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vmx_clear_vmcs(v);
|
||||
vmx_load_vmcs(v);
|
||||
|
||||
if ((error = construct_vmcs_controls(arch_vmx))) {
|
||||
printk("construct_vmcs: construct_vmcs_controls failed\n");
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
if ( (error = construct_vmcs_controls(arch_vmx)) ) {
|
||||
printk("construct_vmcs: construct_vmcs_controls failed.\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
/* host selectors */
|
||||
if ((error = construct_vmcs_host())) {
|
||||
printk("construct_vmcs: construct_vmcs_host failed\n");
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
if ( (error = construct_vmcs_host()) ) {
|
||||
printk("construct_vmcs: construct_vmcs_host failed.\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
/* guest selectors */
|
||||
if ((error = construct_init_vmcs_guest(regs))) {
|
||||
printk("construct_vmcs: construct_vmcs_guest failed\n");
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
if ( (error = construct_init_vmcs_guest(regs)) ) {
|
||||
printk("construct_vmcs: construct_vmcs_guest failed.\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
if ((error |= __vmwrite(EXCEPTION_BITMAP,
|
||||
MONITOR_DEFAULT_EXCEPTION_BITMAP))) {
|
||||
printk("construct_vmcs: setting Exception bitmap failed\n");
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
if ( (error = __vmwrite(EXCEPTION_BITMAP,
|
||||
MONITOR_DEFAULT_EXCEPTION_BITMAP)) ) {
|
||||
printk("construct_vmcs: setting exception bitmap failed.\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
if (regs->eflags & EF_TF)
|
||||
__vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
|
||||
if ( regs->eflags & EF_TF )
|
||||
error = __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
|
||||
else
|
||||
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
|
||||
error = __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int vmx_create_vmcs(struct vcpu *v)
|
||||
{
|
||||
if ( (v->arch.hvm_vmx.vmcs = vmx_alloc_vmcs()) == NULL )
|
||||
return -ENOMEM;
|
||||
__vmx_clear_vmcs(v);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
vmx_destroy_vmcs(v);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void vmx_destroy_vmcs(struct vcpu *v)
|
||||
{
|
||||
struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
|
||||
|
||||
if ( arch_vmx->vmcs == NULL )
|
||||
return;
|
||||
|
||||
vmx_clear_vmcs(v);
|
||||
|
||||
free_vmcs(arch_vmx->vmcs);
|
||||
arch_vmx->vmcs = NULL;
|
||||
free_xenheap_pages(arch_vmx->io_bitmap_a, IO_BITMAP_ORDER);
|
||||
free_xenheap_pages(arch_vmx->io_bitmap_b, IO_BITMAP_ORDER);
|
||||
|
||||
free_xenheap_pages(arch_vmx->io_bitmap_a, get_order_from_bytes(0x1000));
|
||||
arch_vmx->io_bitmap_a = NULL;
|
||||
|
||||
free_xenheap_pages(arch_vmx->io_bitmap_b, get_order_from_bytes(0x1000));
|
||||
arch_vmx->io_bitmap_b = NULL;
|
||||
|
||||
vmx_free_vmcs(arch_vmx->vmcs);
|
||||
arch_vmx->vmcs = NULL;
|
||||
}
|
||||
|
||||
void vm_launch_fail(unsigned long eflags)
|
||||
@@ -544,19 +547,20 @@ void arch_vmx_do_resume(struct vcpu *v)
|
||||
|
||||
void arch_vmx_do_launch(struct vcpu *v)
|
||||
{
|
||||
int error;
|
||||
cpu_user_regs_t *regs = ¤t->arch.guest_context.user_regs;
|
||||
|
||||
error = construct_vmcs(v, regs);
|
||||
if ( error < 0 )
|
||||
vmx_load_vmcs(v);
|
||||
|
||||
if ( construct_vmcs(v, regs) < 0 )
|
||||
{
|
||||
if (v->vcpu_id == 0) {
|
||||
printk("Failed to construct a new VMCS for BSP.\n");
|
||||
if ( v->vcpu_id == 0 ) {
|
||||
printk("Failed to construct VMCS for BSP.\n");
|
||||
} else {
|
||||
printk("Failed to construct a new VMCS for AP %d\n", v->vcpu_id);
|
||||
printk("Failed to construct VMCS for AP %d.\n", v->vcpu_id);
|
||||
}
|
||||
domain_crash_synchronous();
|
||||
}
|
||||
|
||||
vmx_do_launch(v);
|
||||
reset_stack_and_jump(vmx_asm_do_vmentry);
|
||||
}
|
||||
|
||||
+111
-53
@@ -54,34 +54,73 @@ static unsigned long trace_values[NR_CPUS][5];
|
||||
static void vmx_ctxt_switch_from(struct vcpu *v);
|
||||
static void vmx_ctxt_switch_to(struct vcpu *v);
|
||||
|
||||
void vmx_final_setup_guest(struct vcpu *v)
|
||||
static int vmx_initialize_guest_resources(struct vcpu *v)
|
||||
{
|
||||
struct domain *d = v->domain;
|
||||
struct vcpu *vc;
|
||||
void *io_bitmap_a, *io_bitmap_b;
|
||||
int rc;
|
||||
|
||||
v->arch.schedule_tail = arch_vmx_do_launch;
|
||||
v->arch.ctxt_switch_from = vmx_ctxt_switch_from;
|
||||
v->arch.ctxt_switch_to = vmx_ctxt_switch_to;
|
||||
|
||||
if ( v->vcpu_id == 0 )
|
||||
if ( v->vcpu_id != 0 )
|
||||
return 1;
|
||||
|
||||
for_each_vcpu ( d, vc )
|
||||
{
|
||||
struct domain *d = v->domain;
|
||||
struct vcpu *vc;
|
||||
|
||||
/* Initialize monitor page table */
|
||||
for_each_vcpu(d, vc)
|
||||
vc->arch.monitor_table = pagetable_null();
|
||||
vc->arch.monitor_table = pagetable_null();
|
||||
|
||||
/*
|
||||
* Required to do this once per domain
|
||||
* XXX todo: add a seperate function to do these.
|
||||
*/
|
||||
memset(&d->shared_info->evtchn_mask[0], 0xff,
|
||||
sizeof(d->shared_info->evtchn_mask));
|
||||
memset(&vc->arch.hvm_vmx, 0, sizeof(struct arch_vmx_struct));
|
||||
|
||||
/* Put the domain in shadow mode even though we're going to be using
|
||||
* the shared 1:1 page table initially. It shouldn't hurt */
|
||||
shadow_mode_enable(d,
|
||||
SHM_enable|SHM_refcounts|
|
||||
SHM_translate|SHM_external|SHM_wr_pt_pte);
|
||||
if ( (rc = vmx_create_vmcs(vc)) != 0 )
|
||||
{
|
||||
DPRINTK("Failed to create VMCS for vcpu %d: err=%d.\n",
|
||||
vc->vcpu_id, rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_init(&vc->arch.hvm_vmx.vmcs_lock);
|
||||
|
||||
if ( (io_bitmap_a = alloc_xenheap_pages(IO_BITMAP_ORDER)) == NULL )
|
||||
{
|
||||
DPRINTK("Failed to allocate io bitmap b for vcpu %d.\n",
|
||||
vc->vcpu_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( (io_bitmap_b = alloc_xenheap_pages(IO_BITMAP_ORDER)) == NULL )
|
||||
{
|
||||
DPRINTK("Failed to allocate io bitmap b for vcpu %d.\n",
|
||||
vc->vcpu_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(io_bitmap_a, 0xff, 0x1000);
|
||||
memset(io_bitmap_b, 0xff, 0x1000);
|
||||
|
||||
/* don't bother debug port access */
|
||||
clear_bit(PC_DEBUG_PORT, io_bitmap_a);
|
||||
|
||||
vc->arch.hvm_vmx.io_bitmap_a = io_bitmap_a;
|
||||
vc->arch.hvm_vmx.io_bitmap_b = io_bitmap_b;
|
||||
}
|
||||
|
||||
/*
|
||||
* Required to do this once per domain XXX todo: add a seperate function
|
||||
* to do these.
|
||||
*/
|
||||
memset(&d->shared_info->evtchn_mask[0], 0xff,
|
||||
sizeof(d->shared_info->evtchn_mask));
|
||||
|
||||
/* Put the domain in shadow mode even though we're going to be using
|
||||
* the shared 1:1 page table initially. It shouldn't hurt */
|
||||
shadow_mode_enable(
|
||||
d, SHM_enable|SHM_refcounts|SHM_translate|SHM_external|SHM_wr_pt_pte);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void vmx_relinquish_guest_resources(struct domain *d)
|
||||
@@ -90,9 +129,9 @@ static void vmx_relinquish_guest_resources(struct domain *d)
|
||||
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
vmx_destroy_vmcs(v);
|
||||
if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
|
||||
continue;
|
||||
vmx_destroy_vmcs(v);
|
||||
free_monitor_pagetable(v);
|
||||
kill_timer(&v->arch.hvm_vmx.hlt_timer);
|
||||
if ( hvm_apic_support(v->domain) && (VLAPIC(v) != NULL) )
|
||||
@@ -444,12 +483,6 @@ void stop_vmx(void)
|
||||
__vmxoff();
|
||||
}
|
||||
|
||||
int vmx_initialize_guest_resources(struct vcpu *v)
|
||||
{
|
||||
vmx_final_setup_guest(v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void vmx_migrate_timers(struct vcpu *v)
|
||||
{
|
||||
struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
|
||||
@@ -638,58 +671,61 @@ static int check_vmx_controls(u32 ctrls, u32 msr)
|
||||
|
||||
int start_vmx(void)
|
||||
{
|
||||
struct vmcs_struct *vmcs;
|
||||
u32 ecx;
|
||||
u32 eax, edx;
|
||||
u64 phys_vmcs; /* debugging */
|
||||
struct vmcs_struct *vmcs;
|
||||
|
||||
/*
|
||||
* Xen does not fill x86_capability words except 0.
|
||||
*/
|
||||
ecx = cpuid_ecx(1);
|
||||
boot_cpu_data.x86_capability[4] = ecx;
|
||||
boot_cpu_data.x86_capability[4] = cpuid_ecx(1);
|
||||
|
||||
if (!(test_bit(X86_FEATURE_VMXE, &boot_cpu_data.x86_capability)))
|
||||
return 0;
|
||||
|
||||
rdmsr(IA32_FEATURE_CONTROL_MSR, eax, edx);
|
||||
|
||||
if (eax & IA32_FEATURE_CONTROL_MSR_LOCK) {
|
||||
if ((eax & IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON) == 0x0) {
|
||||
if ( eax & IA32_FEATURE_CONTROL_MSR_LOCK )
|
||||
{
|
||||
if ( (eax & IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON) == 0x0 )
|
||||
{
|
||||
printk("VMX disabled by Feature Control MSR.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
wrmsr(IA32_FEATURE_CONTROL_MSR,
|
||||
IA32_FEATURE_CONTROL_MSR_LOCK |
|
||||
IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON, 0);
|
||||
}
|
||||
|
||||
if (!check_vmx_controls(MONITOR_PIN_BASED_EXEC_CONTROLS,
|
||||
MSR_IA32_VMX_PINBASED_CTLS_MSR))
|
||||
if ( !check_vmx_controls(MONITOR_PIN_BASED_EXEC_CONTROLS,
|
||||
MSR_IA32_VMX_PINBASED_CTLS_MSR) )
|
||||
return 0;
|
||||
if (!check_vmx_controls(MONITOR_CPU_BASED_EXEC_CONTROLS,
|
||||
MSR_IA32_VMX_PROCBASED_CTLS_MSR))
|
||||
if ( !check_vmx_controls(MONITOR_CPU_BASED_EXEC_CONTROLS,
|
||||
MSR_IA32_VMX_PROCBASED_CTLS_MSR) )
|
||||
return 0;
|
||||
if (!check_vmx_controls(MONITOR_VM_EXIT_CONTROLS,
|
||||
MSR_IA32_VMX_EXIT_CTLS_MSR))
|
||||
if ( !check_vmx_controls(MONITOR_VM_EXIT_CONTROLS,
|
||||
MSR_IA32_VMX_EXIT_CTLS_MSR) )
|
||||
return 0;
|
||||
if (!check_vmx_controls(MONITOR_VM_ENTRY_CONTROLS,
|
||||
MSR_IA32_VMX_ENTRY_CTLS_MSR))
|
||||
if ( !check_vmx_controls(MONITOR_VM_ENTRY_CONTROLS,
|
||||
MSR_IA32_VMX_ENTRY_CTLS_MSR) )
|
||||
return 0;
|
||||
|
||||
set_in_cr4(X86_CR4_VMXE); /* Enable VMXE */
|
||||
set_in_cr4(X86_CR4_VMXE);
|
||||
|
||||
if (!(vmcs = vmx_alloc_vmcs())) {
|
||||
printk("Failed to allocate VMCS\n");
|
||||
vmx_init_vmcs_config();
|
||||
|
||||
if ( (vmcs = vmx_alloc_host_vmcs()) == NULL )
|
||||
{
|
||||
printk("Failed to allocate host VMCS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
phys_vmcs = (u64) virt_to_maddr(vmcs);
|
||||
|
||||
if (__vmxon(phys_vmcs)) {
|
||||
if ( __vmxon(virt_to_maddr(vmcs)) )
|
||||
{
|
||||
printk("VMXON failed\n");
|
||||
vmx_free_host_vmcs(vmcs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -832,7 +868,7 @@ static void vmx_vmexit_do_cpuid(struct cpu_user_regs *regs)
|
||||
cpuid_count(input, count, &eax, &ebx, &ecx, &edx);
|
||||
eax &= NUM_CORES_RESET_MASK;
|
||||
}
|
||||
else
|
||||
else if ( !cpuid_hypervisor_leaves(input, &eax, &ebx, &ecx, &edx) )
|
||||
{
|
||||
cpuid(input, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
@@ -857,10 +893,14 @@ static void vmx_vmexit_do_cpuid(struct cpu_user_regs *regs)
|
||||
#else
|
||||
if ( v->domain->arch.ops->guest_paging_levels == PAGING_L2 )
|
||||
{
|
||||
if ( !v->domain->arch.hvm_domain.pae_enabled )
|
||||
if ( v->domain->arch.hvm_domain.pae_enabled )
|
||||
clear_bit(X86_FEATURE_PSE36, &edx);
|
||||
else
|
||||
{
|
||||
clear_bit(X86_FEATURE_PAE, &edx);
|
||||
clear_bit(X86_FEATURE_PSE, &edx);
|
||||
clear_bit(X86_FEATURE_PSE36, &edx);
|
||||
clear_bit(X86_FEATURE_PSE, &edx);
|
||||
clear_bit(X86_FEATURE_PSE36, &edx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2053,8 +2093,26 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
|
||||
|
||||
if ( unlikely(exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) )
|
||||
{
|
||||
printk("Failed vm entry (reason 0x%x)\n", exit_reason);
|
||||
printk("*********** VMCS Area **************\n");
|
||||
unsigned int failed_vmentry_reason = exit_reason & 0xFFFF;
|
||||
|
||||
__vmread(EXIT_QUALIFICATION, &exit_qualification);
|
||||
printk("Failed vm entry (exit reason 0x%x) ", exit_reason);
|
||||
switch ( failed_vmentry_reason ) {
|
||||
case EXIT_REASON_INVALID_GUEST_STATE:
|
||||
printk("caused by invalid guest state (%ld).\n", exit_qualification);
|
||||
break;
|
||||
case EXIT_REASON_MSR_LOADING:
|
||||
printk("caused by MSR entry %ld loading.\n", exit_qualification);
|
||||
break;
|
||||
case EXIT_REASON_MACHINE_CHECK:
|
||||
printk("caused by machine check.\n");
|
||||
break;
|
||||
default:
|
||||
printk("reason not known yet!");
|
||||
break;
|
||||
}
|
||||
|
||||
printk("************* VMCS Area **************\n");
|
||||
vmcs_dump_vcpu();
|
||||
printk("**************************************\n");
|
||||
domain_crash_synchronous();
|
||||
|
||||
@@ -439,8 +439,9 @@ void __init __start_xen(multiboot_info_t *mbi)
|
||||
|
||||
scheduler_init();
|
||||
|
||||
idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
|
||||
BUG_ON(idle_domain == NULL);
|
||||
idle_domain = domain_create(IDLE_DOMAIN_ID);
|
||||
if ( (idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL) )
|
||||
BUG();
|
||||
|
||||
set_current(idle_domain->vcpu[0]);
|
||||
this_cpu(curr_vcpu) = idle_domain->vcpu[0];
|
||||
@@ -537,8 +538,8 @@ void __init __start_xen(multiboot_info_t *mbi)
|
||||
acm_init(&initrdidx, mbi, initial_images_start);
|
||||
|
||||
/* Create initial domain 0. */
|
||||
dom0 = domain_create(0, 0);
|
||||
if ( dom0 == NULL )
|
||||
dom0 = domain_create(0);
|
||||
if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
|
||||
panic("Error creating domain 0\n");
|
||||
|
||||
set_bit(_DOMF_privileged, &dom0->domain_flags);
|
||||
@@ -624,7 +625,7 @@ void arch_get_xen_caps(xen_capabilities_info_t info)
|
||||
if ( hvm_enabled )
|
||||
{
|
||||
p += sprintf(p, "hvm-%d.%d-x86_32 ", XEN_VERSION, XEN_SUBVERSION);
|
||||
//p += sprintf(p, "hvm-%d.%d-x86_32p ", XEN_VERSION, XEN_SUBVERSION);
|
||||
p += sprintf(p, "hvm-%d.%d-x86_32p ", XEN_VERSION, XEN_SUBVERSION);
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_X86_64)
|
||||
|
||||
@@ -1726,6 +1726,7 @@ static int resync_all(struct domain *d, u32 stype)
|
||||
{
|
||||
guest_l1_pgentry_t tmp_gl1e = guest_l1e_empty();
|
||||
validate_pte_change(d, tmp_gl1e, sl1e_p);
|
||||
unshadow_l1 = 1;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
@@ -3676,20 +3677,19 @@ static inline int l2e_rw_fault(
|
||||
put_page_from_l1e(old_sl1e, d);
|
||||
}
|
||||
|
||||
l1_p[gpfn - start_gpfn] = sl1e;
|
||||
|
||||
if (rw) {
|
||||
/* shadow_mark_va_out_of_sync() need modificatin for 2M pages*/
|
||||
if ( mfn_is_page_table(mfn) )
|
||||
shadow_mark_va_out_of_sync_2mp(v, gpfn, mfn,
|
||||
l2e_get_paddr(sl2e) | (sizeof(l1_pgentry_t) * (gpfn - start_gpfn)));
|
||||
}
|
||||
|
||||
l1_p[gpfn - start_gpfn] = sl1e;
|
||||
}
|
||||
|
||||
unmap_domain_page(l1_p);
|
||||
*gl2e_p = gl2e;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3724,7 +3724,13 @@ static inline int guest_page_fault(
|
||||
}
|
||||
|
||||
if ( guest_l2e_get_flags(*gpl2e) & _PAGE_PSE )
|
||||
{
|
||||
printk("None-PAE HVM guests can NOT use PSE, "
|
||||
"because we don't support 4MBytes PSE pages.\n");
|
||||
printk("remove pae=1 from your config file.\n");
|
||||
domain_crash_synchronous();
|
||||
return 0;
|
||||
}
|
||||
|
||||
__guest_get_l1e(v, va, gpl1e);
|
||||
|
||||
|
||||
@@ -1197,8 +1197,7 @@ int __devinit __cpu_up(unsigned int cpu)
|
||||
cpu_set(cpu, smp_commenced_mask);
|
||||
while (!cpu_isset(cpu, cpu_online_map)) {
|
||||
mb();
|
||||
if (softirq_pending(0))
|
||||
do_softirq();
|
||||
process_pending_timers();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+30
-3
@@ -426,10 +426,32 @@ DO_ERROR_NOCODE(16, "fpu error", coprocessor_error)
|
||||
DO_ERROR(17, "alignment check", alignment_check)
|
||||
DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error)
|
||||
|
||||
int cpuid_hypervisor_leaves(
|
||||
uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
|
||||
{
|
||||
if ( (idx < 0x40000000) || (idx > 0x40000000) )
|
||||
return 0;
|
||||
|
||||
switch ( idx - 0x40000000 )
|
||||
{
|
||||
case 0:
|
||||
*eax = 0x40000000;
|
||||
*ebx = 0x006e6558; /* "Xen\0" */
|
||||
*ecx = *edx = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int emulate_forced_invalid_op(struct cpu_user_regs *regs)
|
||||
{
|
||||
char signature[5], instr[2];
|
||||
unsigned long a, b, c, d, eip;
|
||||
uint32_t a, b, c, d;
|
||||
unsigned long eip;
|
||||
|
||||
a = regs->eax;
|
||||
b = regs->ebx;
|
||||
@@ -466,6 +488,10 @@ static int emulate_forced_invalid_op(struct cpu_user_regs *regs)
|
||||
if ( !IS_PRIV(current->domain) )
|
||||
clear_bit(X86_FEATURE_MTRR, &d);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)cpuid_hypervisor_leaves(regs->eax, &a, &b, &c, &d);
|
||||
}
|
||||
|
||||
regs->eax = a;
|
||||
regs->ebx = b;
|
||||
@@ -1397,13 +1423,14 @@ static void nmi_softirq(void)
|
||||
static void nmi_dom0_report(unsigned int reason_idx)
|
||||
{
|
||||
struct domain *d;
|
||||
struct vcpu *v;
|
||||
|
||||
if ( (d = dom0) == NULL )
|
||||
if ( ((d = dom0) == NULL) || ((v = d->vcpu[0]) == NULL) )
|
||||
return;
|
||||
|
||||
set_bit(reason_idx, &d->shared_info->arch.nmi_reason);
|
||||
|
||||
if ( test_and_set_bit(_VCPUF_nmi_pending, &d->vcpu[0]->vcpu_flags) )
|
||||
if ( test_and_set_bit(_VCPUF_nmi_pending, &v->vcpu_flags) )
|
||||
raise_softirq(NMI_SOFTIRQ); /* not safe to wake up a vcpu here */
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ static uint8_t opcode_table[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 0xC0 - 0xC7 */
|
||||
ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, 0, 0,
|
||||
0, 0, ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
|
||||
0, 0, ByteOp|DstMem|SrcImm|ModRM|Mov, DstMem|SrcImm|ModRM|Mov,
|
||||
/* 0xC8 - 0xCF */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 0xD0 - 0xD7 */
|
||||
|
||||
+52
-48
@@ -90,6 +90,44 @@ static void getdomaininfo(struct domain *d, dom0_getdomaininfo_t *info)
|
||||
memcpy(info->handle, d->handle, sizeof(xen_domain_handle_t));
|
||||
}
|
||||
|
||||
static unsigned int default_vcpu0_location(void)
|
||||
{
|
||||
struct domain *d;
|
||||
struct vcpu *v;
|
||||
unsigned int i, cpu, cnt[NR_CPUS] = { 0 };
|
||||
cpumask_t cpu_exclude_map;
|
||||
|
||||
/* Do an initial CPU placement. Pick the least-populated CPU. */
|
||||
read_lock(&domlist_lock);
|
||||
for_each_domain ( d )
|
||||
for_each_vcpu ( d, v )
|
||||
if ( !test_bit(_VCPUF_down, &v->vcpu_flags) )
|
||||
cnt[v->processor]++;
|
||||
read_unlock(&domlist_lock);
|
||||
|
||||
/*
|
||||
* If we're on a HT system, we only auto-allocate to a non-primary HT. We
|
||||
* favour high numbered CPUs in the event of a tie.
|
||||
*/
|
||||
cpu = first_cpu(cpu_sibling_map[0]);
|
||||
if ( cpus_weight(cpu_sibling_map[0]) > 1 )
|
||||
cpu = next_cpu(cpu, cpu_sibling_map[0]);
|
||||
cpu_exclude_map = cpu_sibling_map[0];
|
||||
for_each_online_cpu ( i )
|
||||
{
|
||||
if ( cpu_isset(i, cpu_exclude_map) )
|
||||
continue;
|
||||
if ( (i == first_cpu(cpu_sibling_map[i])) &&
|
||||
(cpus_weight(cpu_sibling_map[i]) > 1) )
|
||||
continue;
|
||||
cpus_or(cpu_exclude_map, cpu_exclude_map, cpu_sibling_map[i]);
|
||||
if ( cnt[i] <= cnt[cpu] )
|
||||
cpu = i;
|
||||
}
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
{
|
||||
long ret = 0;
|
||||
@@ -150,7 +188,7 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
if ( d != NULL )
|
||||
{
|
||||
ret = -EINVAL;
|
||||
if ( (d != current->domain) &&
|
||||
if ( (d != current->domain) && (d->vcpu[0] != NULL) &&
|
||||
test_bit(_VCPUF_initialised, &d->vcpu[0]->vcpu_flags) )
|
||||
{
|
||||
domain_unpause_by_systemcontroller(d);
|
||||
@@ -164,11 +202,7 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
case DOM0_CREATEDOMAIN:
|
||||
{
|
||||
struct domain *d;
|
||||
unsigned int pro;
|
||||
domid_t dom;
|
||||
struct vcpu *v;
|
||||
unsigned int i, cnt[NR_CPUS] = { 0 };
|
||||
cpumask_t cpu_exclude_map;
|
||||
static domid_t rover = 0;
|
||||
|
||||
/*
|
||||
@@ -202,36 +236,8 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
rover = dom;
|
||||
}
|
||||
|
||||
/* Do an initial CPU placement. Pick the least-populated CPU. */
|
||||
read_lock(&domlist_lock);
|
||||
for_each_domain ( d )
|
||||
for_each_vcpu ( d, v )
|
||||
if ( !test_bit(_VCPUF_down, &v->vcpu_flags) )
|
||||
cnt[v->processor]++;
|
||||
read_unlock(&domlist_lock);
|
||||
|
||||
/*
|
||||
* If we're on a HT system, we only auto-allocate to a non-primary HT.
|
||||
* We favour high numbered CPUs in the event of a tie.
|
||||
*/
|
||||
pro = first_cpu(cpu_sibling_map[0]);
|
||||
if ( cpus_weight(cpu_sibling_map[0]) > 1 )
|
||||
pro = next_cpu(pro, cpu_sibling_map[0]);
|
||||
cpu_exclude_map = cpu_sibling_map[0];
|
||||
for_each_online_cpu ( i )
|
||||
{
|
||||
if ( cpu_isset(i, cpu_exclude_map) )
|
||||
continue;
|
||||
if ( (i == first_cpu(cpu_sibling_map[i])) &&
|
||||
(cpus_weight(cpu_sibling_map[i]) > 1) )
|
||||
continue;
|
||||
cpus_or(cpu_exclude_map, cpu_exclude_map, cpu_sibling_map[i]);
|
||||
if ( cnt[i] <= cnt[pro] )
|
||||
pro = i;
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
if ( (d = domain_create(dom, pro)) == NULL )
|
||||
if ( (d = domain_create(dom)) == NULL )
|
||||
break;
|
||||
|
||||
memcpy(d->handle, op->u.createdomain.handle,
|
||||
@@ -258,14 +264,8 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
if ( (d = find_domain_by_id(op->u.max_vcpus.domain)) == NULL )
|
||||
break;
|
||||
|
||||
/*
|
||||
* Can only create new VCPUs while the domain is not fully constructed
|
||||
* (and hence not runnable). Xen needs auditing for races before
|
||||
* removing this check.
|
||||
*/
|
||||
ret = -EINVAL;
|
||||
if ( test_bit(_VCPUF_initialised, &d->vcpu[0]->vcpu_flags) )
|
||||
goto maxvcpu_out;
|
||||
/* Needed, for example, to ensure writable p.t. state is synced. */
|
||||
domain_pause(d);
|
||||
|
||||
/* We cannot reduce maximum VCPUs. */
|
||||
ret = -EINVAL;
|
||||
@@ -275,17 +275,21 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op)
|
||||
ret = -ENOMEM;
|
||||
for ( i = 0; i < max; i++ )
|
||||
{
|
||||
if ( d->vcpu[i] == NULL )
|
||||
{
|
||||
cpu = (d->vcpu[i-1]->processor + 1) % num_online_cpus();
|
||||
if ( alloc_vcpu(d, i, cpu) == NULL )
|
||||
goto maxvcpu_out;
|
||||
}
|
||||
if ( d->vcpu[i] != NULL )
|
||||
continue;
|
||||
|
||||
cpu = (i == 0) ?
|
||||
default_vcpu0_location() :
|
||||
(d->vcpu[i-1]->processor + 1) % num_online_cpus();
|
||||
|
||||
if ( alloc_vcpu(d, i, cpu) == NULL )
|
||||
goto maxvcpu_out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
maxvcpu_out:
|
||||
domain_unpause(d);
|
||||
put_domain(d);
|
||||
}
|
||||
break;
|
||||
|
||||
Loaded 100 of 126 files, more files were not shown because too many files have changed in this diff.
Show more