提交 1dbbb607 编写于 作者: S Steve French

Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6

......@@ -329,8 +329,6 @@ sgi-visws.txt
- short blurb on the SGI Visual Workstations.
sh/
- directory with info on porting Linux to a new architecture.
smart-config.txt
- description of the Smart Config makefile feature.
sound/
- directory with info on sound card support.
sparc/
......
......@@ -42,6 +42,8 @@ Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable.
Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of
the boot command line
Protocol 2.09: (kernel 2.6.26) Added a field of 64-bit physical
pointer to single linked list of struct setup_data.
**** MEMORY LAYOUT
......@@ -172,6 +174,8 @@ Offset Proto Name Meaning
0240/8 2.07+ hardware_subarch_data Subarchitecture-specific data
0248/4 2.08+ payload_offset Offset of kernel payload
024C/4 2.08+ payload_length Length of kernel payload
0250/8 2.09+ setup_data 64-bit physical pointer to linked list
of struct setup_data
(1) For backwards compatibility, if the setup_sects field contains 0, the
real value is 4.
......@@ -572,6 +576,28 @@ command line is entered using the following protocol:
covered by setup_move_size, so you may need to adjust this
field.
Field name: setup_data
Type: write (obligatory)
Offset/size: 0x250/8
Protocol: 2.09+
The 64-bit physical pointer to NULL terminated single linked list of
struct setup_data. This is used to define a more extensible boot
parameters passing mechanism. The definition of struct setup_data is
as follow:
struct setup_data {
u64 next;
u32 type;
u32 len;
u8 data[0];
};
Where, the next is a 64-bit physical pointer to the next node of
linked list, the next field of the last node is 0; the type is used
to identify the contents of data; the len is the length of data
field; the data holds the real payload.
**** MEMORY LAYOUT OF THE REAL-MODE CODE
......
Currently, kvm module in EXPERIMENTAL stage on IA64. This means that
interfaces are not stable enough to use. So, plase had better don't run
critical applications in virtual machine. We will try our best to make it
strong in future versions!
Guide: How to boot up guests on kvm/ia64
This guide is to describe how to enable kvm support for IA-64 systems.
1. Get the kvm source from git.kernel.org.
Userspace source:
git clone git://git.kernel.org/pub/scm/virt/kvm/kvm-userspace.git
Kernel Source:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/xiantao/kvm-ia64.git
2. Compile the source code.
2.1 Compile userspace code:
(1)cd ./kvm-userspace
(2)./configure
(3)cd kernel
(4)make sync LINUX= $kernel_dir (kernel_dir is the directory of kernel source.)
(5)cd ..
(6)make qemu
(7)cd qemu; make install
2.2 Compile kernel source code:
(1) cd ./$kernel_dir
(2) Make menuconfig
(3) Enter into virtualization option, and choose kvm.
(4) make
(5) Once (4) done, make modules_install
(6) Make initrd, and use new kernel to reboot up host machine.
(7) Once (6) done, cd $kernel_dir/arch/ia64/kvm
(8) insmod kvm.ko; insmod kvm-intel.ko
Note: For step 2, please make sure that host page size == TARGET_PAGE_SIZE of qemu, otherwise, may fail.
3. Get Guest Firmware named as Flash.fd, and put it under right place:
(1) If you have the guest firmware (binary) released by Intel Corp for Xen, use it directly.
(2) If you have no firmware at hand, Please download its source from
hg clone http://xenbits.xensource.com/ext/efi-vfirmware.hg
you can get the firmware's binary in the directory of efi-vfirmware.hg/binaries.
(3) Rename the firware you owned to Flash.fd, and copy it to /usr/local/share/qemu
4. Boot up Linux or Windows guests:
4.1 Create or install a image for guest boot. If you have xen experience, it should be easy.
4.2 Boot up guests use the following command.
/usr/local/bin/qemu-system-ia64 -smp xx -m 512 -hda $your_image
(xx is the number of virtual processors for the guest, now the maximum value is 4)
5. Known possibile issue on some platforms with old Firmware.
If meet strange host crashe issues, try to solve it through either of the following ways:
(1): Upgrade your Firmware to the latest one.
(2): Applying the below patch to kernel source.
diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S
index 0b53344..f02b0f7 100644
--- a/arch/ia64/kernel/pal.S
+++ b/arch/ia64/kernel/pal.S
@@ -84,7 +84,8 @@ GLOBAL_ENTRY(ia64_pal_call_static)
mov ar.pfs = loc1
mov rp = loc0
;;
- srlz.d // seralize restoration of psr.l
+ srlz.i // seralize restoration of psr.l
+ ;;
br.ret.sptk.many b0
END(ia64_pal_call_static)
6. Bug report:
If you found any issues when use kvm/ia64, Please post the bug info to kvm-ia64-devel mailing list.
https://lists.sourceforge.net/lists/listinfo/kvm-ia64-devel/
Thanks for your interest! Let's work together, and make kvm/ia64 stronger and stronger!
Xiantao Zhang <xiantao.zhang@intel.com>
2008.3.10
/*
* IDE ATAPI streaming tape driver.
*
* This driver is a part of the Linux ide driver.
*
* The driver, in co-operation with ide.c, basically traverses the
* request-list for the block device interface. The character device
* interface, on the other hand, creates new requests, adds them
* to the request-list of the block device, and waits for their completion.
*
* Pipelined operation mode is now supported on both reads and writes.
*
* The block device major and minor numbers are determined from the
* tape's relative position in the ide interfaces, as explained in ide.c.
*
* The character device interface consists of the following devices:
*
* ht0 major 37, minor 0 first IDE tape, rewind on close.
* ht1 major 37, minor 1 second IDE tape, rewind on close.
* ...
* nht0 major 37, minor 128 first IDE tape, no rewind on close.
* nht1 major 37, minor 129 second IDE tape, no rewind on close.
* ...
*
* The general magnetic tape commands compatible interface, as defined by
* include/linux/mtio.h, is accessible through the character device.
*
* General ide driver configuration options, such as the interrupt-unmask
* flag, can be configured by issuing an ioctl to the block device interface,
* as any other ide device.
*
* Our own ide-tape ioctl's can be issued to either the block device or
* the character device interface.
*
* Maximal throughput with minimal bus load will usually be achieved in the
* following scenario:
*
* 1. ide-tape is operating in the pipelined operation mode.
* 2. No buffering is performed by the user backup program.
*
* Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
*
* Here are some words from the first releases of hd.c, which are quoted
* in ide.c and apply here as well:
*
* | Special care is recommended. Have Fun!
*
*
* An overview of the pipelined operation mode.
*
* In the pipelined write mode, we will usually just add requests to our
* pipeline and return immediately, before we even start to service them. The
* user program will then have enough time to prepare the next request while
* we are still busy servicing previous requests. In the pipelined read mode,
* the situation is similar - we add read-ahead requests into the pipeline,
* before the user even requested them.
*
* The pipeline can be viewed as a "safety net" which will be activated when
* the system load is high and prevents the user backup program from keeping up
* with the current tape speed. At this point, the pipeline will get
* shorter and shorter but the tape will still be streaming at the same speed.
* Assuming we have enough pipeline stages, the system load will hopefully
* decrease before the pipeline is completely empty, and the backup program
* will be able to "catch up" and refill the pipeline again.
*
* When using the pipelined mode, it would be best to disable any type of
* buffering done by the user program, as ide-tape already provides all the
* benefits in the kernel, where it can be done in a more efficient way.
* As we will usually not block the user program on a request, the most
* efficient user code will then be a simple read-write-read-... cycle.
* Any additional logic will usually just slow down the backup process.
*
* Using the pipelined mode, I get a constant over 400 KBps throughput,
* which seems to be the maximum throughput supported by my tape.
*
* However, there are some downfalls:
*
* 1. We use memory (for data buffers) in proportional to the number
* of pipeline stages (each stage is about 26 KB with my tape).
* 2. In the pipelined write mode, we cheat and postpone error codes
* to the user task. In read mode, the actual tape position
* will be a bit further than the last requested block.
*
* Concerning (1):
*
* 1. We allocate stages dynamically only when we need them. When
* we don't need them, we don't consume additional memory. In
* case we can't allocate stages, we just manage without them
* (at the expense of decreased throughput) so when Linux is
* tight in memory, we will not pose additional difficulties.
*
* 2. The maximum number of stages (which is, in fact, the maximum
* amount of memory) which we allocate is limited by the compile
* time parameter IDETAPE_MAX_PIPELINE_STAGES.
*
* 3. The maximum number of stages is a controlled parameter - We
* don't start from the user defined maximum number of stages
* but from the lower IDETAPE_MIN_PIPELINE_STAGES (again, we
* will not even allocate this amount of stages if the user
* program can't handle the speed). We then implement a feedback
* loop which checks if the pipeline is empty, and if it is, we
* increase the maximum number of stages as necessary until we
* reach the optimum value which just manages to keep the tape
* busy with minimum allocated memory or until we reach
* IDETAPE_MAX_PIPELINE_STAGES.
*
* Concerning (2):
*
* In pipelined write mode, ide-tape can not return accurate error codes
* to the user program since we usually just add the request to the
* pipeline without waiting for it to be serviced. In case an error
* occurs, I will report it on the next user request.
*
* In the pipelined read mode, subsequent read requests or forward
* filemark spacing will perform correctly, as we preserve all blocks
* and filemarks which we encountered during our excess read-ahead.
*
* For accurate tape positioning and error reporting, disabling
* pipelined mode might be the best option.
*
* You can enable/disable/tune the pipelined operation mode by adjusting
* the compile time parameters below.
*
*
* Possible improvements.
*
* 1. Support for the ATAPI overlap protocol.
*
* In order to maximize bus throughput, we currently use the DSC
* overlap method which enables ide.c to service requests from the
* other device while the tape is busy executing a command. The
* DSC overlap method involves polling the tape's status register
* for the DSC bit, and servicing the other device while the tape
* isn't ready.
*
* In the current QIC development standard (December 1995),
* it is recommended that new tape drives will *in addition*
* implement the ATAPI overlap protocol, which is used for the
* same purpose - efficient use of the IDE bus, but is interrupt
* driven and thus has much less CPU overhead.
*
* ATAPI overlap is likely to be supported in most new ATAPI
* devices, including new ATAPI cdroms, and thus provides us
* a method by which we can achieve higher throughput when
* sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
*/
IDE ATAPI streaming tape driver.
This driver is a part of the Linux ide driver.
The driver, in co-operation with ide.c, basically traverses the
request-list for the block device interface. The character device
interface, on the other hand, creates new requests, adds them
to the request-list of the block device, and waits for their completion.
The block device major and minor numbers are determined from the
tape's relative position in the ide interfaces, as explained in ide.c.
The character device interface consists of the following devices:
ht0 major 37, minor 0 first IDE tape, rewind on close.
ht1 major 37, minor 1 second IDE tape, rewind on close.
...
nht0 major 37, minor 128 first IDE tape, no rewind on close.
nht1 major 37, minor 129 second IDE tape, no rewind on close.
...
The general magnetic tape commands compatible interface, as defined by
include/linux/mtio.h, is accessible through the character device.
General ide driver configuration options, such as the interrupt-unmask
flag, can be configured by issuing an ioctl to the block device interface,
as any other ide device.
Our own ide-tape ioctl's can be issued to either the block device or
the character device interface.
Maximal throughput with minimal bus load will usually be achieved in the
following scenario:
1. ide-tape is operating in the pipelined operation mode.
2. No buffering is performed by the user backup program.
Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
Here are some words from the first releases of hd.c, which are quoted
in ide.c and apply here as well:
| Special care is recommended. Have Fun!
Possible improvements:
1. Support for the ATAPI overlap protocol.
In order to maximize bus throughput, we currently use the DSC
overlap method which enables ide.c to service requests from the
other device while the tape is busy executing a command. The
DSC overlap method involves polling the tape's status register
for the DSC bit, and servicing the other device while the tape
isn't ready.
In the current QIC development standard (December 1995),
it is recommended that new tape drives will *in addition*
implement the ATAPI overlap protocol, which is used for the
same purpose - efficient use of the IDE bus, but is interrupt
driven and thus has much less CPU overhead.
ATAPI overlap is likely to be supported in most new ATAPI
devices, including new ATAPI cdroms, and thus provides us
a method by which we can achieve higher throughput when
sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
......@@ -82,27 +82,26 @@ Drives are normally found by auto-probing and/or examining the CMOS/BIOS data.
For really weird situations, the apparent (fdisk) geometry can also be specified
on the kernel "command line" using LILO. The format of such lines is:
hdx=cyls,heads,sects
or hdx=cdrom
ide_core.chs=[interface_number.device_number]:cyls,heads,sects
or ide_core.cdrom=[interface_number.device_number]
where hdx can be any of hda through hdh, Three values are required
(cyls,heads,sects). For example:
For example:
hdc=1050,32,64 hdd=cdrom
ide_core.chs=1.0:1050,32,64 ide_core.cdrom=1.1
either {hda,hdb} or {hdc,hdd}. The results of successful auto-probing may
override the physical geometry/irq specified, though the "original" geometry
may be retained as the "logical" geometry for partitioning purposes (fdisk).
The results of successful auto-probing may override the physical geometry/irq
specified, though the "original" geometry may be retained as the "logical"
geometry for partitioning purposes (fdisk).
If the auto-probing during boot time confuses a drive (ie. the drive works
with hd.c but not with ide.c), then an command line option may be specified
for each drive for which you'd like the drive to skip the hardware
probe/identification sequence. For example:
hdb=noprobe
ide_core.noprobe=0.1
or
hdc=768,16,32
hdc=noprobe
ide_core.chs=1.0:768,16,32
ide_core.noprobe=1.0
Note that when only one IDE device is attached to an interface, it should be
jumpered as "single" or "master", *not* "slave". Many folks have had
......@@ -118,9 +117,9 @@ If for some reason your cdrom drive is *not* found at boot time, you can force
the probe to look harder by supplying a kernel command line parameter
via LILO, such as:
hdc=cdrom /* hdc = "master" on second interface */
ide_core.cdrom=1.0 /* "master" on second interface (hdc) */
or
hdd=cdrom /* hdd = "slave" on second interface */
ide_core.cdrom=1.1 /* "slave" on second interface (hdd) */
For example, a GW2000 system might have a hard drive on the primary
interface (/dev/hda) and an IDE cdrom drive on the secondary interface
......@@ -174,9 +173,7 @@ to /etc/modprobe.conf.
When ide.c is used as a module, you can pass command line parameters to the
driver using the "options=" keyword to insmod, while replacing any ',' with
';'. For example:
insmod ide.o options="hda=nodma hdb=nodma"
';'.
================================================================================
......@@ -184,57 +181,6 @@ driver using the "options=" keyword to insmod, while replacing any ',' with
Summary of ide driver parameters for kernel command line
--------------------------------------------------------
"hdx=" is recognized for all "x" from "a" to "u", such as "hdc".
"idex=" is recognized for all "x" from "0" to "9", such as "ide1".
"hdx=noprobe" : drive may be present, but do not probe for it
"hdx=none" : drive is NOT present, ignore cmos and do not probe
"hdx=nowerr" : ignore the WRERR_STAT bit on this drive
"hdx=cdrom" : drive is present, and is a cdrom drive
"hdx=cyl,head,sect" : disk drive is present, with specified geometry
"hdx=autotune" : driver will attempt to tune interface speed
to the fastest PIO mode supported,
if possible for this drive only.
Not fully supported by all chipset types,
and quite likely to cause trouble with
older/odd IDE drives.
"hdx=nodma" : disallow DMA
"idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz,
where "xx" is between 20 and 66 inclusive,
used when tuning chipset PIO modes.
For PCI bus, 25 is correct for a P75 system,
30 is correct for P90,P120,P180 systems,
and 33 is used for P100,P133,P166 systems.
If in doubt, use idebus=33 for PCI.
As for VLB, it is safest to not specify it.
Bigger values are safer than smaller ones.
"idex=serialize" : do not overlap operations on idex. Please note
that you will have to specify this option for
both the respective primary and secondary channel
to take effect.
"idex=reset" : reset interface after probe
"idex=ata66" : informs the interface that it has an 80c cable
for chipsets that are ATA-66 capable, but the
ability to bit test for detection is currently
unknown.
"ide=doubler" : probe/support IDE doublers on Amiga
There may be more options than shown -- use the source, Luke!
Everything else is rejected with a "BAD OPTION" message.
For legacy IDE VLB host drivers (ali14xx/dtc2278/ht6560b/qd65xx/umc8672)
you need to explicitly enable probing by using "probe" kernel parameter,
i.e. to enable probing for ALI M14xx chipsets (ali14xx host driver) use:
......@@ -251,6 +197,33 @@ are detected automatically).
You also need to use "probe" kernel parameter for ide-4drives driver
(support for IDE generic chipset with four drives on one port).
To enable support for IDE doublers on Amiga use "doubler" kernel parameter
for gayle host driver (i.e. "gayle.doubler" if the driver is built-in).
To force ignoring cable detection (this should be needed only if you're using
short 40-wires cable which cannot be automatically detected - if this is not
a case please report it as a bug instead) use "ignore_cable" kernel parameter:
* "ide_core.ignore_cable=[interface_number]" boot option if IDE is built-in
(i.e. "ide_core.ignore_cable=1" to force ignoring cable for "ide1")
* "ignore_cable=[interface_number]" module parameter (for ide_core module)
if IDE is compiled as module
Other kernel parameters for ide_core are:
* "nodma=[interface_number.device_number]" to disallow DMA for a device
* "noflush=[interface_number.device_number]" to disable flush requests
* "noprobe=[interface_number.device_number]" to skip probing
* "nowerr=[interface_number.device_number]" to ignore the WRERR_STAT bit
* "cdrom=[interface_number.device_number]" to force device as a CD-ROM
* "chs=[interface_number.device_number]" to force device as a disk (using CHS)
================================================================================
Some Terminology
......
......@@ -183,6 +183,8 @@ Code Seq# Include File Comments
0xAC 00-1F linux/raw.h
0xAD 00 Netfilter device in development:
<mailto:rusty@rustcorp.com.au>
0xAE all linux/kvm.h Kernel-based Virtual Machine
<mailto:kvm-devel@lists.sourceforge.net>
0xB0 all RATIO devices in development:
<mailto:vgo@ratio.de>
0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
......
......@@ -772,10 +772,6 @@ and is between 256 and 4096 characters. It is defined in the file
Format: ide=nodma or ide=doubler
See Documentation/ide/ide.txt.
ide?= [HW] (E)IDE subsystem
Format: ide?=ata66 or chipset specific parameters.
See Documentation/ide/ide.txt.
idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed
See Documentation/ide/ide.txt.
......
......@@ -46,8 +46,6 @@ Two files are introduced:
a) 'include/asm-mips/mach-au1x00/au1xxx_ide.h'
containes : struct _auide_hwif
struct drive_list_entry dma_white_list
struct drive_list_entry dma_black_list
timing parameters for PIO mode 0/1/2/3/4
timing parameters for MWDMA 0/1/2
......@@ -63,12 +61,6 @@ Four configs variables are introduced:
CONFIG_BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ - maximum transfer size
per descriptor
If MWDMA is enabled and the connected hard disc is not on the white list, the
kernel switches to a "safe mwdma mode" at boot time. In this mode the IDE
performance is substantial slower then in full speed mwdma. In this case
please add your hard disc to the white list (follow instruction from 'ADD NEW
HARD DISC TO WHITE OR BLACK LIST' section).
SUPPORTED IDE MODES
-------------------
......@@ -120,44 +112,6 @@ CONFIG_IDEDMA_AUTO=y
Also undefine 'IDE_AU1XXX_BURSTMODE' in 'drivers/ide/mips/au1xxx-ide.c' to
disable the burst support on DBDMA controller.
ADD NEW HARD DISC TO WHITE OR BLACK LIST
----------------------------------------
Step 1 : detect the model name of your hard disc
a) connect your hard disc to the AU1XXX
b) boot your kernel and get the hard disc model.
Example boot log:
--snipped--
Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
Au1xxx IDE(builtin) configured for MWDMA2
Probing IDE interface ide0...
hda: Maxtor 6E040L0, ATA DISK drive
ide0 at 0xac800000-0xac800007,0xac8001c0 on irq 64
hda: max request size: 64KiB
hda: 80293248 sectors (41110 MB) w/2048KiB Cache, CHS=65535/16/63, (U)DMA
--snipped--
In this example 'Maxtor 6E040L0'.
Step 2 : edit 'include/asm-mips/mach-au1x00/au1xxx_ide.h'
Add your hard disc to the dma_white_list or dma_black_list structur.
Step 3 : Recompile the kernel
Enable MWDMA support in the kernel configuration. Recompile the kernel and
reboot.
Step 4 : Tests
If you have add a hard disc to the white list, please run some stress tests
for verification.
ACKNOWLEDGMENTS
---------------
......
Hollis Blanchard <hollisb@us.ibm.com>
15 Apr 2008
Various notes on the implementation of KVM for PowerPC 440:
To enforce isolation, host userspace, guest kernel, and guest userspace all
run at user privilege level. Only the host kernel runs in supervisor mode.
Executing privileged instructions in the guest traps into KVM (in the host
kernel), where we decode and emulate them. Through this technique, unmodified
440 Linux kernels can be run (slowly) as guests. Future performance work will
focus on reducing the overhead and frequency of these traps.
The usual code flow is started from userspace invoking an "run" ioctl, which
causes KVM to switch into guest context. We use IVPR to hijack the host
interrupt vectors while running the guest, which allows us to direct all
interrupts to kvmppc_handle_interrupt(). At this point, we could either
- handle the interrupt completely (e.g. emulate "mtspr SPRG0"), or
- let the host interrupt handler run (e.g. when the decrementer fires), or
- return to host userspace (e.g. when the guest performs device MMIO)
Address spaces: We take advantage of the fact that Linux doesn't use the AS=1
address space (in host or guest), which gives us virtual address space to use
for guest mappings. While the guest is running, the host kernel remains mapped
in AS=0, but the guest can only use AS=1 mappings.
TLB entries: The TLB entries covering the host linear mapping remain
present while running the guest. This reduces the overhead of lightweight
exits, which are handled by KVM running in the host kernel. We keep three
copies of the TLB:
- guest TLB: contents of the TLB as the guest sees it
- shadow TLB: the TLB that is actually in hardware while guest is running
- host TLB: to restore TLB state when context switching guest -> host
When a TLB miss occurs because a mapping was not present in the shadow TLB,
but was present in the guest TLB, KVM handles the fault without invoking the
guest. Large guest pages are backed by multiple 4KB shadow pages through this
mechanism.
IO: MMIO and DCR accesses are emulated by userspace. We use virtio for network
and block IO, so those drivers must be enabled in the guest. It's possible
that some qemu device emulation (e.g. e1000 or rtl8139) may also work with
little effort.
*** BIG FAT WARNING ***
The kvm module is currently in EXPERIMENTAL state for s390. This means that
the interface to the module is not yet considered to remain stable. Thus, be
prepared that we keep breaking your userspace application and guest
compatibility over and over again until we feel happy with the result. Make sure
your guest kernel, your host kernel, and your userspace launcher are in a
consistent state.
This Documentation describes the unique ioctl calls to /dev/kvm, the resulting
kvm-vm file descriptors, and the kvm-vcpu file descriptors that differ from x86.
1. ioctl calls to /dev/kvm
KVM does support the following ioctls on s390 that are common with other
architectures and do behave the same:
KVM_GET_API_VERSION
KVM_CREATE_VM (*) see note
KVM_CHECK_EXTENSION
KVM_GET_VCPU_MMAP_SIZE
Notes:
* KVM_CREATE_VM may fail on s390, if the calling process has multiple
threads and has not called KVM_S390_ENABLE_SIE before.
In addition, on s390 the following architecture specific ioctls are supported:
ioctl: KVM_S390_ENABLE_SIE
args: none
see also: include/linux/kvm.h
This call causes the kernel to switch on PGSTE in the user page table. This
operation is needed in order to run a virtual machine, and it requires the
calling process to be single-threaded. Note that the first call to KVM_CREATE_VM
will implicitly try to switch on PGSTE if the user process has not called
KVM_S390_ENABLE_SIE before. User processes that want to launch multiple threads
before creating a virtual machine have to call KVM_S390_ENABLE_SIE, or will
observe an error calling KVM_CREATE_VM. Switching on PGSTE is a one-time
operation, is not reversible, and will persist over the entire lifetime of
the calling process. It does not have any user-visible effect other than a small
performance penalty.
2. ioctl calls to the kvm-vm file descriptor
KVM does support the following ioctls on s390 that are common with other
architectures and do behave the same:
KVM_CREATE_VCPU
KVM_SET_USER_MEMORY_REGION (*) see note
KVM_GET_DIRTY_LOG (**) see note
Notes:
* kvm does only allow exactly one memory slot on s390, which has to start
at guest absolute address zero and at a user address that is aligned on any
page boundary. This hardware "limitation" allows us to have a few unique
optimizations. The memory slot doesn't have to be filled
with memory actually, it may contain sparse holes. That said, with different
user memory layout this does still allow a large flexibility when
doing the guest memory setup.
** KVM_GET_DIRTY_LOG doesn't work properly yet. The user will receive an empty
log. This ioctl call is only needed for guest migration, and we intend to
implement this one in the future.
In addition, on s390 the following architecture specific ioctls for the kvm-vm
file descriptor are supported:
ioctl: KVM_S390_INTERRUPT
args: struct kvm_s390_interrupt *
see also: include/linux/kvm.h
This ioctl is used to submit a floating interrupt for a virtual machine.
Floating interrupts may be delivered to any virtual cpu in the configuration.
Only some interrupt types defined in include/linux/kvm.h make sense when
submitted as floating interrupts. The following interrupts are not considered
to be useful as floating interrupts, and a call to inject them will result in
-EINVAL error code: program interrupts and interprocessor signals. Valid
floating interrupts are:
KVM_S390_INT_VIRTIO
KVM_S390_INT_SERVICE
3. ioctl calls to the kvm-vcpu file descriptor
KVM does support the following ioctls on s390 that are common with other
architectures and do behave the same:
KVM_RUN
KVM_GET_REGS
KVM_SET_REGS
KVM_GET_SREGS
KVM_SET_SREGS
KVM_GET_FPU
KVM_SET_FPU
In addition, on s390 the following architecture specific ioctls for the
kvm-vcpu file descriptor are supported:
ioctl: KVM_S390_INTERRUPT
args: struct kvm_s390_interrupt *
see also: include/linux/kvm.h
This ioctl is used to submit an interrupt for a specific virtual cpu.
Only some interrupt types defined in include/linux/kvm.h make sense when
submitted for a specific cpu. The following interrupts are not considered
to be useful, and a call to inject them will result in -EINVAL error code:
service processor calls and virtio interrupts. Valid interrupt types are:
KVM_S390_PROGRAM_INT
KVM_S390_SIGP_STOP
KVM_S390_RESTART
KVM_S390_SIGP_SET_PREFIX
KVM_S390_INT_EMERGENCY
ioctl: KVM_S390_STORE_STATUS
args: unsigned long
see also: include/linux/kvm.h
This ioctl stores the state of the cpu at the guest real address given as
argument, unless one of the following values defined in include/linux/kvm.h
is given as arguement:
KVM_S390_STORE_STATUS_NOADDR - the CPU stores its status to the save area in
absolute lowcore as defined by the principles of operation
KVM_S390_STORE_STATUS_PREFIXED - the CPU stores its status to the save area in
its prefix page just like the dump tool that comes with zipl. This is useful
to create a system dump for use with lkcdutils or crash.
ioctl: KVM_S390_SET_INITIAL_PSW
args: struct kvm_s390_psw *
see also: include/linux/kvm.h
This ioctl can be used to set the processor status word (psw) of a stopped cpu
prior to running it with KVM_RUN. Note that this call is not required to modify
the psw during sie intercepts that fall back to userspace because struct kvm_run
does contain the psw, and this value is evaluated during reentry of KVM_RUN
after the intercept exit was recognized.
ioctl: KVM_S390_INITIAL_RESET
args: none
see also: include/linux/kvm.h
This ioctl can be used to perform an initial cpu reset as defined by the
principles of operation. The target cpu has to be in stopped state.
Smart CONFIG_* Dependencies
1 August 1999
Michael Chastain <mec@shout.net>
Werner Almesberger <almesber@lrc.di.epfl.ch>
Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>
Here is the problem:
Suppose that drivers/net/foo.c has the following lines:
#include <linux/config.h>
...
#ifdef CONFIG_FOO_AUTOFROB
/* Code for auto-frobbing */
#else
/* Manual frobbing only */
#endif
...
#ifdef CONFIG_FOO_MODEL_TWO
/* Code for model two */
#endif
Now suppose the user (the person building kernels) reconfigures the
kernel to change some unrelated setting. This will regenerate the
file include/linux/autoconf.h, which will cause include/linux/config.h
to be out of date, which will cause drivers/net/foo.c to be recompiled.
Most kernel sources, perhaps 80% of them, have at least one CONFIG_*
dependency somewhere. So changing _any_ CONFIG_* setting requires
almost _all_ of the kernel to be recompiled.
Here is the solution:
We've made the dependency generator, mkdep.c, smarter. Instead of
generating this dependency:
drivers/net/foo.c: include/linux/config.h
It now generates these dependencies:
drivers/net/foo.c: \
include/config/foo/autofrob.h \
include/config/foo/model/two.h
So drivers/net/foo.c depends only on the CONFIG_* lines that
it actually uses.
A new program, split-include.c, runs at the beginning of
compilation (make bzImage or make zImage). split-include reads
include/linux/autoconf.h and updates the include/config/ tree,
writing one file per option. It updates only the files for options
that have changed.
Flag Dependencies
Martin Von Loewis contributed another feature to this patch:
'flag dependencies'. The idea is that a .o file depends on
the compilation flags used to build it. The file foo.o has
its flags stored in .flags.foo.o.
Suppose the user changes the foo driver from resident to modular.
'make' will notice that the current foo.o was not compiled with
-DMODULE and will recompile foo.c.
All .o files made from C source have flag dependencies. So do .o
files made with ld, and .a files made with ar. However, .o files
made from assembly source do not have flag dependencies (nobody
needs this yet, but it would be good to fix).
Per-source-file Flags
Flag dependencies also work with per-source-file flags.
You can specify compilation flags for individual source files
like this:
CFLAGS_foo.o = -DSPECIAL_FOO_DEFINE
This helps clean up drivers/net/Makefile, drivers/scsi/Makefile,
and several other Makefiles.
Credit
Werner Almesberger had the original idea and wrote the first
version of this patch.
Michael Chastain picked it up and continued development. He is
now the principal author and maintainer. Please report any bugs
to him.
Martin von Loewis wrote flag dependencies, with some modifications
by Michael Chastain.
Thanks to all of the beta testers.
......@@ -2329,6 +2329,13 @@ L: kvm-devel@lists.sourceforge.net
W: kvm.sourceforge.net
S: Supported
KERNEL VIRTUAL MACHINE (KVM) FOR POWERPC
P: Hollis Blanchard
M: hollisb@us.ibm.com
L: kvm-ppc-devel@lists.sourceforge.net
W: kvm.sourceforge.net
S: Supported
KERNEL VIRTUAL MACHINE For Itanium(KVM/IA64)
P: Anthony Xu
M: anthony.xu@intel.com
......@@ -2338,6 +2345,16 @@ L: kvm-ia64-devel@lists.sourceforge.net
W: kvm.sourceforge.net
S: Supported
KERNEL VIRTUAL MACHINE for s390 (KVM/s390)
P: Carsten Otte
M: cotte@de.ibm.com
P: Christian Borntraeger
M: borntraeger@de.ibm.com
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
KEXEC
P: Eric Biederman
M: ebiederm@xmission.com
......
......@@ -19,6 +19,7 @@ config IA64
select HAVE_OPROFILE
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_KVM
default y
help
The Itanium Processor Family is Intel's 64-bit successor to
......@@ -589,6 +590,8 @@ config MSPEC
source "fs/Kconfig"
source "arch/ia64/kvm/Kconfig"
source "lib/Kconfig"
#
......
......@@ -57,6 +57,7 @@ core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/
core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/
core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/
core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/
core-$(CONFIG_KVM) += arch/ia64/kvm/
drivers-$(CONFIG_PCI) += arch/ia64/pci/
drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/
......
#
# KVM configuration
#
config HAVE_KVM
bool
menuconfig VIRTUALIZATION
bool "Virtualization"
depends on HAVE_KVM || IA64
default y
---help---
Say Y here to get to see options for using your Linux host to run other
operating systems inside virtual machines (guests).
This option alone does not add any kernel code.
If you say N, all options in this submenu will be skipped and disabled.
if VIRTUALIZATION
config KVM
tristate "Kernel-based Virtual Machine (KVM) support"
depends on HAVE_KVM && EXPERIMENTAL
select PREEMPT_NOTIFIERS
select ANON_INODES
---help---
Support hosting fully virtualized guest machines using hardware
virtualization extensions. You will need a fairly recent
processor equipped with virtualization extensions. You will also
need to select one or more of the processor modules below.
This module provides access to the hardware capabilities through
a character device node named /dev/kvm.
To compile this as a module, choose M here: the module
will be called kvm.
If unsure, say N.
config KVM_INTEL
tristate "KVM for Intel Itanium 2 processors support"
depends on KVM && m
---help---
Provides support for KVM on Itanium 2 processors equipped with the VT
extensions.
config KVM_TRACE
bool
endif # VIRTUALIZATION
#This Make file is to generate asm-offsets.h and build source.
#
#Generate asm-offsets.h for vmm module build
offsets-file := asm-offsets.h
always := $(offsets-file)
targets := $(offsets-file)
targets += arch/ia64/kvm/asm-offsets.s
clean-files := $(addprefix $(objtree)/,$(targets) $(obj)/memcpy.S $(obj)/memset.S)
# Default sed regexp - multiline due to syntax constraints
define sed-y
"/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"
endef
quiet_cmd_offsets = GEN $@
define cmd_offsets
(set -e; \
echo "#ifndef __ASM_KVM_OFFSETS_H__"; \
echo "#define __ASM_KVM_OFFSETS_H__"; \
echo "/*"; \
echo " * DO NOT MODIFY."; \
echo " *"; \
echo " * This file was generated by Makefile"; \
echo " *"; \
echo " */"; \
echo ""; \
sed -ne $(sed-y) $<; \
echo ""; \
echo "#endif" ) > $@
endef
# We use internal rules to avoid the "is up to date" message from make
arch/ia64/kvm/asm-offsets.s: arch/ia64/kvm/asm-offsets.c
$(call if_changed_dep,cc_s_c)
$(obj)/$(offsets-file): arch/ia64/kvm/asm-offsets.s
$(call cmd,offsets)
#
# Makefile for Kernel-based Virtual Machine module
#
EXTRA_CFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
$(addprefix $(objtree)/,$(obj)/memcpy.S $(obj)/memset.S):
$(shell ln -snf ../lib/memcpy.S $(src)/memcpy.S)
$(shell ln -snf ../lib/memset.S $(src)/memset.S)
common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o)
kvm-objs := $(common-objs) kvm-ia64.o kvm_fw.o
obj-$(CONFIG_KVM) += kvm.o
FORCE : $(obj)/$(offsets-file)
EXTRA_CFLAGS_vcpu.o += -mfixed-range=f2-f5,f12-f127
kvm-intel-objs = vmm.o vmm_ivt.o trampoline.o vcpu.o optvfault.o mmio.o \
vtlb.o process.o
#Add link memcpy and memset to avoid possible structure assignment error
kvm-intel-objs += memset.o memcpy.o
obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
/*
* asm-offsets.c Generate definitions needed by assembly language modules.
* This code generates raw asm output which is post-processed
* to extract and format the required data.
*
* Anthony Xu <anthony.xu@intel.com>
* Xiantao Zhang <xiantao.zhang@intel.com>
* Copyright (c) 2007 Intel Corporation KVM support.
*
* 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.
*
*/
#include <linux/autoconf.h>
#include <linux/kvm_host.h>
#include "vcpu.h"
#define task_struct kvm_vcpu
#define DEFINE(sym, val) \
asm volatile("\n->" #sym " (%0) " #val : : "i" (val))
#define BLANK() asm volatile("\n->" : :)
#define OFFSET(_sym, _str, _mem) \
DEFINE(_sym, offsetof(_str, _mem));
void foo(void)
{
DEFINE(VMM_TASK_SIZE, sizeof(struct kvm_vcpu));
DEFINE(VMM_PT_REGS_SIZE, sizeof(struct kvm_pt_regs));
BLANK();
DEFINE(VMM_VCPU_META_RR0_OFFSET,
offsetof(struct kvm_vcpu, arch.metaphysical_rr0));
DEFINE(VMM_VCPU_META_SAVED_RR0_OFFSET,
offsetof(struct kvm_vcpu,
arch.metaphysical_saved_rr0));
DEFINE(VMM_VCPU_VRR0_OFFSET,
offsetof(struct kvm_vcpu, arch.vrr[0]));
DEFINE(VMM_VPD_IRR0_OFFSET,
offsetof(struct vpd, irr[0]));
DEFINE(VMM_VCPU_ITC_CHECK_OFFSET,
offsetof(struct kvm_vcpu, arch.itc_check));
DEFINE(VMM_VCPU_IRQ_CHECK_OFFSET,
offsetof(struct kvm_vcpu, arch.irq_check));
DEFINE(VMM_VPD_VHPI_OFFSET,
offsetof(struct vpd, vhpi));
DEFINE(VMM_VCPU_VSA_BASE_OFFSET,
offsetof(struct kvm_vcpu, arch.vsa_base));
DEFINE(VMM_VCPU_VPD_OFFSET,
offsetof(struct kvm_vcpu, arch.vpd));
DEFINE(VMM_VCPU_IRQ_CHECK,
offsetof(struct kvm_vcpu, arch.irq_check));
DEFINE(VMM_VCPU_TIMER_PENDING,
offsetof(struct kvm_vcpu, arch.timer_pending));
DEFINE(VMM_VCPU_META_SAVED_RR0_OFFSET,
offsetof(struct kvm_vcpu, arch.metaphysical_saved_rr0));
DEFINE(VMM_VCPU_MODE_FLAGS_OFFSET,
offsetof(struct kvm_vcpu, arch.mode_flags));
DEFINE(VMM_VCPU_ITC_OFS_OFFSET,
offsetof(struct kvm_vcpu, arch.itc_offset));
DEFINE(VMM_VCPU_LAST_ITC_OFFSET,
offsetof(struct kvm_vcpu, arch.last_itc));
DEFINE(VMM_VCPU_SAVED_GP_OFFSET,
offsetof(struct kvm_vcpu, arch.saved_gp));
BLANK();
DEFINE(VMM_PT_REGS_B6_OFFSET,
offsetof(struct kvm_pt_regs, b6));
DEFINE(VMM_PT_REGS_B7_OFFSET,
offsetof(struct kvm_pt_regs, b7));
DEFINE(VMM_PT_REGS_AR_CSD_OFFSET,
offsetof(struct kvm_pt_regs, ar_csd));
DEFINE(VMM_PT_REGS_AR_SSD_OFFSET,
offsetof(struct kvm_pt_regs, ar_ssd));
DEFINE(VMM_PT_REGS_R8_OFFSET,
offsetof(struct kvm_pt_regs, r8));
DEFINE(VMM_PT_REGS_R9_OFFSET,
offsetof(struct kvm_pt_regs, r9));
DEFINE(VMM_PT_REGS_R10_OFFSET,
offsetof(struct kvm_pt_regs, r10));
DEFINE(VMM_PT_REGS_R11_OFFSET,
offsetof(struct kvm_pt_regs, r11));
DEFINE(VMM_PT_REGS_CR_IPSR_OFFSET,
offsetof(struct kvm_pt_regs, cr_ipsr));
DEFINE(VMM_PT_REGS_CR_IIP_OFFSET,
offsetof(struct kvm_pt_regs, cr_iip));
DEFINE(VMM_PT_REGS_CR_IFS_OFFSET,
offsetof(struct kvm_pt_regs, cr_ifs));
DEFINE(VMM_PT_REGS_AR_UNAT_OFFSET,
offsetof(struct kvm_pt_regs, ar_unat));
DEFINE(VMM_PT_REGS_AR_PFS_OFFSET,
offsetof(struct kvm_pt_regs, ar_pfs));
DEFINE(VMM_PT_REGS_AR_RSC_OFFSET,
offsetof(struct kvm_pt_regs, ar_rsc));
DEFINE(VMM_PT_REGS_AR_RNAT_OFFSET,
offsetof(struct kvm_pt_regs, ar_rnat));
DEFINE(VMM_PT_REGS_AR_BSPSTORE_OFFSET,
offsetof(struct kvm_pt_regs, ar_bspstore));
DEFINE(VMM_PT_REGS_PR_OFFSET,
offsetof(struct kvm_pt_regs, pr));
DEFINE(VMM_PT_REGS_B0_OFFSET,
offsetof(struct kvm_pt_regs, b0));
DEFINE(VMM_PT_REGS_LOADRS_OFFSET,
offsetof(struct kvm_pt_regs, loadrs));
DEFINE(VMM_PT_REGS_R1_OFFSET,
offsetof(struct kvm_pt_regs, r1));
DEFINE(VMM_PT_REGS_R12_OFFSET,
offsetof(struct kvm_pt_regs, r12));
DEFINE(VMM_PT_REGS_R13_OFFSET,
offsetof(struct kvm_pt_regs, r13));
DEFINE(VMM_PT_REGS_AR_FPSR_OFFSET,
offsetof(struct kvm_pt_regs, ar_fpsr));
DEFINE(VMM_PT_REGS_R15_OFFSET,
offsetof(struct kvm_pt_regs, r15));
DEFINE(VMM_PT_REGS_R14_OFFSET,
offsetof(struct kvm_pt_regs, r14));
DEFINE(VMM_PT_REGS_R2_OFFSET,
offsetof(struct kvm_pt_regs, r2));
DEFINE(VMM_PT_REGS_R3_OFFSET,
offsetof(struct kvm_pt_regs, r3));
DEFINE(VMM_PT_REGS_R16_OFFSET,
offsetof(struct kvm_pt_regs, r16));
DEFINE(VMM_PT_REGS_R17_OFFSET,
offsetof(struct kvm_pt_regs, r17));
DEFINE(VMM_PT_REGS_R18_OFFSET,
offsetof(struct kvm_pt_regs, r18));
DEFINE(VMM_PT_REGS_R19_OFFSET,
offsetof(struct kvm_pt_regs, r19));
DEFINE(VMM_PT_REGS_R20_OFFSET,
offsetof(struct kvm_pt_regs, r20));
DEFINE(VMM_PT_REGS_R21_OFFSET,
offsetof(struct kvm_pt_regs, r21));
DEFINE(VMM_PT_REGS_R22_OFFSET,
offsetof(struct kvm_pt_regs, r22));
DEFINE(VMM_PT_REGS_R23_OFFSET,
offsetof(struct kvm_pt_regs, r23));
DEFINE(VMM_PT_REGS_R24_OFFSET,
offsetof(struct kvm_pt_regs, r24));
DEFINE(VMM_PT_REGS_R25_OFFSET,
offsetof(struct kvm_pt_regs, r25));
DEFINE(VMM_PT_REGS_R26_OFFSET,
offsetof(struct kvm_pt_regs, r26));
DEFINE(VMM_PT_REGS_R27_OFFSET,
offsetof(struct kvm_pt_regs, r27));
DEFINE(VMM_PT_REGS_R28_OFFSET,
offsetof(struct kvm_pt_regs, r28));
DEFINE(VMM_PT_REGS_R29_OFFSET,
offsetof(struct kvm_pt_regs, r29));
DEFINE(VMM_PT_REGS_R30_OFFSET,
offsetof(struct kvm_pt_regs, r30));
DEFINE(VMM_PT_REGS_R31_OFFSET,
offsetof(struct kvm_pt_regs, r31));
DEFINE(VMM_PT_REGS_AR_CCV_OFFSET,
offsetof(struct kvm_pt_regs, ar_ccv));
DEFINE(VMM_PT_REGS_F6_OFFSET,
offsetof(struct kvm_pt_regs, f6));
DEFINE(VMM_PT_REGS_F7_OFFSET,
offsetof(struct kvm_pt_regs, f7));
DEFINE(VMM_PT_REGS_F8_OFFSET,
offsetof(struct kvm_pt_regs, f8));
DEFINE(VMM_PT_REGS_F9_OFFSET,
offsetof(struct kvm_pt_regs, f9));
DEFINE(VMM_PT_REGS_F10_OFFSET,
offsetof(struct kvm_pt_regs, f10));
DEFINE(VMM_PT_REGS_F11_OFFSET,
offsetof(struct kvm_pt_regs, f11));
DEFINE(VMM_PT_REGS_R4_OFFSET,
offsetof(struct kvm_pt_regs, r4));
DEFINE(VMM_PT_REGS_R5_OFFSET,
offsetof(struct kvm_pt_regs, r5));
DEFINE(VMM_PT_REGS_R6_OFFSET,
offsetof(struct kvm_pt_regs, r6));
DEFINE(VMM_PT_REGS_R7_OFFSET,
offsetof(struct kvm_pt_regs, r7));
DEFINE(VMM_PT_REGS_EML_UNAT_OFFSET,
offsetof(struct kvm_pt_regs, eml_unat));
DEFINE(VMM_VCPU_IIPA_OFFSET,
offsetof(struct kvm_vcpu, arch.cr_iipa));
DEFINE(VMM_VCPU_OPCODE_OFFSET,
offsetof(struct kvm_vcpu, arch.opcode));
DEFINE(VMM_VCPU_CAUSE_OFFSET, offsetof(struct kvm_vcpu, arch.cause));
DEFINE(VMM_VCPU_ISR_OFFSET,
offsetof(struct kvm_vcpu, arch.cr_isr));
DEFINE(VMM_PT_REGS_R16_SLOT,
(((offsetof(struct kvm_pt_regs, r16)
- sizeof(struct kvm_pt_regs)) >> 3) & 0x3f));
DEFINE(VMM_VCPU_MODE_FLAGS_OFFSET,
offsetof(struct kvm_vcpu, arch.mode_flags));
DEFINE(VMM_VCPU_GP_OFFSET, offsetof(struct kvm_vcpu, arch.__gp));
BLANK();
DEFINE(VMM_VPD_BASE_OFFSET, offsetof(struct kvm_vcpu, arch.vpd));
DEFINE(VMM_VPD_VIFS_OFFSET, offsetof(struct vpd, ifs));
DEFINE(VMM_VLSAPIC_INSVC_BASE_OFFSET,
offsetof(struct kvm_vcpu, arch.insvc[0]));
DEFINE(VMM_VPD_VPTA_OFFSET, offsetof(struct vpd, pta));
DEFINE(VMM_VPD_VPSR_OFFSET, offsetof(struct vpd, vpsr));
DEFINE(VMM_CTX_R4_OFFSET, offsetof(union context, gr[4]));
DEFINE(VMM_CTX_R5_OFFSET, offsetof(union context, gr[5]));
DEFINE(VMM_CTX_R12_OFFSET, offsetof(union context, gr[12]));
DEFINE(VMM_CTX_R13_OFFSET, offsetof(union context, gr[13]));
DEFINE(VMM_CTX_KR0_OFFSET, offsetof(union context, ar[0]));
DEFINE(VMM_CTX_KR1_OFFSET, offsetof(union context, ar[1]));
DEFINE(VMM_CTX_B0_OFFSET, offsetof(union context, br[0]));
DEFINE(VMM_CTX_B1_OFFSET, offsetof(union context, br[1]));
DEFINE(VMM_CTX_B2_OFFSET, offsetof(union context, br[2]));
DEFINE(VMM_CTX_RR0_OFFSET, offsetof(union context, rr[0]));
DEFINE(VMM_CTX_RSC_OFFSET, offsetof(union context, ar[16]));
DEFINE(VMM_CTX_BSPSTORE_OFFSET, offsetof(union context, ar[18]));
DEFINE(VMM_CTX_RNAT_OFFSET, offsetof(union context, ar[19]));
DEFINE(VMM_CTX_FCR_OFFSET, offsetof(union context, ar[21]));
DEFINE(VMM_CTX_EFLAG_OFFSET, offsetof(union context, ar[24]));
DEFINE(VMM_CTX_CFLG_OFFSET, offsetof(union context, ar[27]));
DEFINE(VMM_CTX_FSR_OFFSET, offsetof(union context, ar[28]));
DEFINE(VMM_CTX_FIR_OFFSET, offsetof(union context, ar[29]));
DEFINE(VMM_CTX_FDR_OFFSET, offsetof(union context, ar[30]));
DEFINE(VMM_CTX_UNAT_OFFSET, offsetof(union context, ar[36]));
DEFINE(VMM_CTX_FPSR_OFFSET, offsetof(union context, ar[40]));
DEFINE(VMM_CTX_PFS_OFFSET, offsetof(union context, ar[64]));
DEFINE(VMM_CTX_LC_OFFSET, offsetof(union context, ar[65]));
DEFINE(VMM_CTX_DCR_OFFSET, offsetof(union context, cr[0]));
DEFINE(VMM_CTX_IVA_OFFSET, offsetof(union context, cr[2]));
DEFINE(VMM_CTX_PTA_OFFSET, offsetof(union context, cr[8]));
DEFINE(VMM_CTX_IBR0_OFFSET, offsetof(union context, ibr[0]));
DEFINE(VMM_CTX_DBR0_OFFSET, offsetof(union context, dbr[0]));
DEFINE(VMM_CTX_F2_OFFSET, offsetof(union context, fr[2]));
DEFINE(VMM_CTX_F3_OFFSET, offsetof(union context, fr[3]));
DEFINE(VMM_CTX_F32_OFFSET, offsetof(union context, fr[32]));
DEFINE(VMM_CTX_F33_OFFSET, offsetof(union context, fr[33]));
DEFINE(VMM_CTX_PKR0_OFFSET, offsetof(union context, pkr[0]));
DEFINE(VMM_CTX_PSR_OFFSET, offsetof(union context, psr));
BLANK();
}
此差异已折叠。
/*
* PAL/SAL call delegation
*
* Copyright (c) 2004 Li Susie <susie.li@intel.com>
* Copyright (c) 2005 Yu Ke <ke.yu@intel.com>
* Copyright (c) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
*
* 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.
*/
#include <linux/kvm_host.h>
#include <linux/smp.h>
#include "vti.h"
#include "misc.h"
#include <asm/pal.h>
#include <asm/sal.h>
#include <asm/tlb.h>
/*
* Handy macros to make sure that the PAL return values start out
* as something meaningful.
*/
#define INIT_PAL_STATUS_UNIMPLEMENTED(x) \
{ \
x.status = PAL_STATUS_UNIMPLEMENTED; \
x.v0 = 0; \
x.v1 = 0; \
x.v2 = 0; \
}
#define INIT_PAL_STATUS_SUCCESS(x) \
{ \
x.status = PAL_STATUS_SUCCESS; \
x.v0 = 0; \
x.v1 = 0; \
x.v2 = 0; \
}
static void kvm_get_pal_call_data(struct kvm_vcpu *vcpu,
u64 *gr28, u64 *gr29, u64 *gr30, u64 *gr31) {
struct exit_ctl_data *p;
if (vcpu) {
p = &vcpu->arch.exit_data;
if (p->exit_reason == EXIT_REASON_PAL_CALL) {
*gr28 = p->u.pal_data.gr28;
*gr29 = p->u.pal_data.gr29;
*gr30 = p->u.pal_data.gr30;
*gr31 = p->u.pal_data.gr31;
return ;
}
}
printk(KERN_DEBUG"Failed to get vcpu pal data!!!\n");
}
static void set_pal_result(struct kvm_vcpu *vcpu,
struct ia64_pal_retval result) {
struct exit_ctl_data *p;
p = kvm_get_exit_data(vcpu);
if (p && p->exit_reason == EXIT_REASON_PAL_CALL) {
p->u.pal_data.ret = result;
return ;
}
INIT_PAL_STATUS_UNIMPLEMENTED(p->u.pal_data.ret);
}
static void set_sal_result(struct kvm_vcpu *vcpu,
struct sal_ret_values result) {
struct exit_ctl_data *p;
p = kvm_get_exit_data(vcpu);
if (p && p->exit_reason == EXIT_REASON_SAL_CALL) {
p->u.sal_data.ret = result;
return ;
}
printk(KERN_WARNING"Failed to set sal result!!\n");
}
struct cache_flush_args {
u64 cache_type;
u64 operation;
u64 progress;
long status;
};
cpumask_t cpu_cache_coherent_map;
static void remote_pal_cache_flush(void *data)
{
struct cache_flush_args *args = data;
long status;
u64 progress = args->progress;
status = ia64_pal_cache_flush(args->cache_type, args->operation,
&progress, NULL);
if (status != 0)
args->status = status;
}
static struct ia64_pal_retval pal_cache_flush(struct kvm_vcpu *vcpu)
{
u64 gr28, gr29, gr30, gr31;
struct ia64_pal_retval result = {0, 0, 0, 0};
struct cache_flush_args args = {0, 0, 0, 0};
long psr;
gr28 = gr29 = gr30 = gr31 = 0;
kvm_get_pal_call_data(vcpu, &gr28, &gr29, &gr30, &gr31);
if (gr31 != 0)
printk(KERN_ERR"vcpu:%p called cache_flush error!\n", vcpu);
/* Always call Host Pal in int=1 */
gr30 &= ~PAL_CACHE_FLUSH_CHK_INTRS;
args.cache_type = gr29;
args.operation = gr30;
smp_call_function(remote_pal_cache_flush,
(void *)&args, 1, 1);
if (args.status != 0)
printk(KERN_ERR"pal_cache_flush error!,"
"status:0x%lx\n", args.status);
/*
* Call Host PAL cache flush
* Clear psr.ic when call PAL_CACHE_FLUSH
*/
local_irq_save(psr);
result.status = ia64_pal_cache_flush(gr29, gr30, &result.v1,
&result.v0);
local_irq_restore(psr);
if (result.status != 0)
printk(KERN_ERR"vcpu:%p crashed due to cache_flush err:%ld"
"in1:%lx,in2:%lx\n",
vcpu, result.status, gr29, gr30);
#if 0
if (gr29 == PAL_CACHE_TYPE_COHERENT) {
cpus_setall(vcpu->arch.cache_coherent_map);
cpu_clear(vcpu->cpu, vcpu->arch.cache_coherent_map);
cpus_setall(cpu_cache_coherent_map);
cpu_clear(vcpu->cpu, cpu_cache_coherent_map);
}
#endif
return result;
}
struct ia64_pal_retval pal_cache_summary(struct kvm_vcpu *vcpu)
{
struct ia64_pal_retval result;
PAL_CALL(result, PAL_CACHE_SUMMARY, 0, 0, 0);
return result;
}
static struct ia64_pal_retval pal_freq_base(struct kvm_vcpu *vcpu)
{
struct ia64_pal_retval result;
PAL_CALL(result, PAL_FREQ_BASE, 0, 0, 0);
/*
* PAL_FREQ_BASE may not be implemented in some platforms,
* call SAL instead.
*/
if (result.v0 == 0) {
result.status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
&result.v0,
&result.v1);
result.v2 = 0;
}
return result;
}
static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
{
struct ia64_pal_retval result;
PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0);
return result;
}
static struct ia64_pal_retval pal_logical_to_physica(struct kvm_vcpu *vcpu)
{
struct ia64_pal_retval result;
INIT_PAL_STATUS_UNIMPLEMENTED(result);
return result;
}
static struct ia64_pal_retval pal_platform_addr(struct kvm_vcpu *vcpu)
{
struct ia64_pal_retval result;
INIT_PAL_STATUS_SUCCESS(result);
return result;
}
static struct ia64_pal_retval pal_proc_get_features(struct kvm_vcpu *vcpu)
{
struct ia64_pal_retval result = {0, 0, 0, 0};
long in0, in1, in2, in3;
kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
result.status = ia64_pal_proc_get_features(&result.v0, &result.v1,
&result.v2, in2);
return result;
}
static struct ia64_pal_retval pal_cache_info(struct kvm_vcpu *vcpu)
{
pal_cache_config_info_t ci;
long status;
unsigned long in0, in1, in2, in3, r9, r10;
kvm_get_pal_call_data(vcpu, &in0, &in1, &in2, &in3);
status = ia64_pal_cache_config_info(in1, in2, &ci);
r9 = ci.pcci_info_1.pcci1_data;
r10 = ci.pcci_info_2.pcci2_data;
return ((struct ia64_pal_retval){status, r9, r10, 0});
}
#define GUEST_IMPL_VA_MSB 59
#define GUEST_RID_BITS 18
static struct ia64_pal_retval pal_vm_summary(struct kvm_vcpu *vcpu)
{
pal_vm_info_1_u_t vminfo1;
pal_vm_info_2_u_t vminfo2;
struct ia64_pal_retval result;
PAL_CALL(result, PAL_VM_SUMMARY, 0, 0, 0);
if (!result.status) {
vminfo1.pvi1_val = result.v0;
vminfo1.pal_vm_info_1_s.max_itr_entry = 8;
vminfo1.pal_vm_info_1_s.max_dtr_entry = 8;
result.v0 = vminfo1.pvi1_val;
vminfo2.pal_vm_info_2_s.impl_va_msb = GUEST_IMPL_VA_MSB;
vminfo2.pal_vm_info_2_s.rid_size = GUEST_RID_BITS;
result.v1 = vminfo2.pvi2_val;
}
return result;
}
static struct ia64_pal_retval pal_vm_info(struct kvm_vcpu *vcpu)
{
struct ia64_pal_retval result;
INIT_PAL_STATUS_UNIMPLEMENTED(result);
return result;
}
static u64 kvm_get_pal_call_index(struct kvm_vcpu *vcpu)
{
u64 index = 0;
struct exit_ctl_data *p;
p = kvm_get_exit_data(vcpu);
if (p && (p->exit_reason == EXIT_REASON_PAL_CALL))
index = p->u.pal_data.gr28;
return index;
}
int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
u64 gr28;
struct ia64_pal_retval result;
int ret = 1;
gr28 = kvm_get_pal_call_index(vcpu);
/*printk("pal_call index:%lx\n",gr28);*/
switch (gr28) {
case PAL_CACHE_FLUSH:
result = pal_cache_flush(vcpu);
break;
case PAL_CACHE_SUMMARY:
result = pal_cache_summary(vcpu);
break;
case PAL_HALT_LIGHT:
{
vcpu->arch.timer_pending = 1;
INIT_PAL_STATUS_SUCCESS(result);
if (kvm_highest_pending_irq(vcpu) == -1)
ret = kvm_emulate_halt(vcpu);
}
break;
case PAL_FREQ_RATIOS:
result = pal_freq_ratios(vcpu);
break;
case PAL_FREQ_BASE:
result = pal_freq_base(vcpu);
break;
case PAL_LOGICAL_TO_PHYSICAL :
result = pal_logical_to_physica(vcpu);
break;
case PAL_VM_SUMMARY :
result = pal_vm_summary(vcpu);
break;
case PAL_VM_INFO :
result = pal_vm_info(vcpu);
break;
case PAL_PLATFORM_ADDR :
result = pal_platform_addr(vcpu);
break;
case PAL_CACHE_INFO:
result = pal_cache_info(vcpu);
break;
case PAL_PTCE_INFO:
INIT_PAL_STATUS_SUCCESS(result);
result.v1 = (1L << 32) | 1L;
break;
case PAL_VM_PAGE_SIZE:
result.status = ia64_pal_vm_page_size(&result.v0,
&result.v1);
break;
case PAL_RSE_INFO:
result.status = ia64_pal_rse_info(&result.v0,
(pal_hints_u_t *)&result.v1);
break;
case PAL_PROC_GET_FEATURES:
result = pal_proc_get_features(vcpu);
break;
case PAL_DEBUG_INFO:
result.status = ia64_pal_debug_info(&result.v0,
&result.v1);
break;
case PAL_VERSION:
result.status = ia64_pal_version(
(pal_version_u_t *)&result.v0,
(pal_version_u_t *)&result.v1);
break;
case PAL_FIXED_ADDR:
result.status = PAL_STATUS_SUCCESS;
result.v0 = vcpu->vcpu_id;
break;
default:
INIT_PAL_STATUS_UNIMPLEMENTED(result);
printk(KERN_WARNING"kvm: Unsupported pal call,"
" index:0x%lx\n", gr28);
}
set_pal_result(vcpu, result);
return ret;
}
static struct sal_ret_values sal_emulator(struct kvm *kvm,
long index, unsigned long in1,
unsigned long in2, unsigned long in3,
unsigned long in4, unsigned long in5,
unsigned long in6, unsigned long in7)
{
unsigned long r9 = 0;
unsigned long r10 = 0;
long r11 = 0;
long status;
status = 0;
switch (index) {
case SAL_FREQ_BASE:
status = ia64_sal_freq_base(in1, &r9, &r10);
break;
case SAL_PCI_CONFIG_READ:
printk(KERN_WARNING"kvm: Not allowed to call here!"
" SAL_PCI_CONFIG_READ\n");
break;
case SAL_PCI_CONFIG_WRITE:
printk(KERN_WARNING"kvm: Not allowed to call here!"
" SAL_PCI_CONFIG_WRITE\n");
break;
case SAL_SET_VECTORS:
if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
status = -2;
} else {
kvm->arch.rdv_sal_data.boot_ip = in2;
kvm->arch.rdv_sal_data.boot_gp = in3;
}
printk("Rendvous called! iip:%lx\n\n", in2);
} else
printk(KERN_WARNING"kvm: CALLED SAL_SET_VECTORS %lu."
"ignored...\n", in1);
break;
case SAL_GET_STATE_INFO:
/* No more info. */
status = -5;
r9 = 0;
break;
case SAL_GET_STATE_INFO_SIZE:
/* Return a dummy size. */
status = 0;
r9 = 128;
break;
case SAL_CLEAR_STATE_INFO:
/* Noop. */
break;
case SAL_MC_RENDEZ:
printk(KERN_WARNING
"kvm: called SAL_MC_RENDEZ. ignored...\n");
break;
case SAL_MC_SET_PARAMS:
printk(KERN_WARNING
"kvm: called SAL_MC_SET_PARAMS.ignored!\n");
break;
case SAL_CACHE_FLUSH:
if (1) {
/*Flush using SAL.
This method is faster but has a side
effect on other vcpu running on
this cpu. */
status = ia64_sal_cache_flush(in1);
} else {
/*Maybe need to implement the method
without side effect!*/
status = 0;
}
break;
case SAL_CACHE_INIT:
printk(KERN_WARNING
"kvm: called SAL_CACHE_INIT. ignored...\n");
break;
case SAL_UPDATE_PAL:
printk(KERN_WARNING
"kvm: CALLED SAL_UPDATE_PAL. ignored...\n");
break;
default:
printk(KERN_WARNING"kvm: called SAL_CALL with unknown index."
" index:%ld\n", index);
status = -1;
break;
}
return ((struct sal_ret_values) {status, r9, r10, r11});
}
static void kvm_get_sal_call_data(struct kvm_vcpu *vcpu, u64 *in0, u64 *in1,
u64 *in2, u64 *in3, u64 *in4, u64 *in5, u64 *in6, u64 *in7){
struct exit_ctl_data *p;
p = kvm_get_exit_data(vcpu);
if (p) {
if (p->exit_reason == EXIT_REASON_SAL_CALL) {
*in0 = p->u.sal_data.in0;
*in1 = p->u.sal_data.in1;
*in2 = p->u.sal_data.in2;
*in3 = p->u.sal_data.in3;
*in4 = p->u.sal_data.in4;
*in5 = p->u.sal_data.in5;
*in6 = p->u.sal_data.in6;
*in7 = p->u.sal_data.in7;
return ;
}
}
*in0 = 0;
}
void kvm_sal_emul(struct kvm_vcpu *vcpu)
{
struct sal_ret_values result;
u64 index, in1, in2, in3, in4, in5, in6, in7;
kvm_get_sal_call_data(vcpu, &index, &in1, &in2,
&in3, &in4, &in5, &in6, &in7);
result = sal_emulator(vcpu->kvm, index, in1, in2, in3,
in4, in5, in6, in7);
set_sal_result(vcpu, result);
}
/*
* kvm_minstate.h: min save macros
* Copyright (c) 2007, Intel Corporation.
*
* Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com)
* Xiantao Zhang (xiantao.zhang@intel.com)
*
* 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.
*
*/
#include <asm/asmmacro.h>
#include <asm/types.h>
#include <asm/kregs.h>
#include "asm-offsets.h"
#define KVM_MINSTATE_START_SAVE_MIN \
mov ar.rsc = 0;/* set enforced lazy mode, pl 0, little-endian, loadrs=0 */\
;; \
mov.m r28 = ar.rnat; \
addl r22 = VMM_RBS_OFFSET,r1; /* compute base of RBS */ \
;; \
lfetch.fault.excl.nt1 [r22]; \
addl r1 = IA64_STK_OFFSET-VMM_PT_REGS_SIZE,r1; /* compute base of memory stack */ \
mov r23 = ar.bspstore; /* save ar.bspstore */ \
;; \
mov ar.bspstore = r22; /* switch to kernel RBS */\
;; \
mov r18 = ar.bsp; \
mov ar.rsc = 0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */
#define KVM_MINSTATE_END_SAVE_MIN \
bsw.1; /* switch back to bank 1 (must be last in insn group) */\
;;
#define PAL_VSA_SYNC_READ \
/* begin to call pal vps sync_read */ \
add r25 = VMM_VPD_BASE_OFFSET, r21; \
adds r20 = VMM_VCPU_VSA_BASE_OFFSET, r21; /* entry point */ \
;; \
ld8 r25 = [r25]; /* read vpd base */ \
ld8 r20 = [r20]; \
;; \
add r20 = PAL_VPS_SYNC_READ,r20; \
;; \
{ .mii; \
nop 0x0; \
mov r24 = ip; \
mov b0 = r20; \
;; \
}; \
{ .mmb; \
add r24 = 0x20, r24; \
nop 0x0; \
br.cond.sptk b0; /* call the service */ \
;; \
};
#define KVM_MINSTATE_GET_CURRENT(reg) mov reg=r21
/*
* KVM_DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves
* the minimum state necessary that allows us to turn psr.ic back
* on.
*
* Assumed state upon entry:
* psr.ic: off
* r31: contains saved predicates (pr)
*
* Upon exit, the state is as follows:
* psr.ic: off
* r2 = points to &pt_regs.r16
* r8 = contents of ar.ccv
* r9 = contents of ar.csd
* r10 = contents of ar.ssd
* r11 = FPSR_DEFAULT
* r12 = kernel sp (kernel virtual address)
* r13 = points to current task_struct (kernel virtual address)
* p15 = TRUE if psr.i is set in cr.ipsr
* predicate registers (other than p2, p3, and p15), b6, r3, r14, r15:
* preserved
*
* Note that psr.ic is NOT turned on by this macro. This is so that
* we can pass interruption state as arguments to a handler.
*/
#define PT(f) (VMM_PT_REGS_##f##_OFFSET)
#define KVM_DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \
KVM_MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \
mov r27 = ar.rsc; /* M */ \
mov r20 = r1; /* A */ \
mov r25 = ar.unat; /* M */ \
mov r29 = cr.ipsr; /* M */ \
mov r26 = ar.pfs; /* I */ \
mov r18 = cr.isr; \
COVER; /* B;; (or nothing) */ \
;; \
tbit.z p0,p15 = r29,IA64_PSR_I_BIT; \
mov r1 = r16; \
/* mov r21=r16; */ \
/* switch from user to kernel RBS: */ \
;; \
invala; /* M */ \
SAVE_IFS; \
;; \
KVM_MINSTATE_START_SAVE_MIN \
adds r17 = 2*L1_CACHE_BYTES,r1;/* cache-line size */ \
adds r16 = PT(CR_IPSR),r1; \
;; \
lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \
st8 [r16] = r29; /* save cr.ipsr */ \
;; \
lfetch.fault.excl.nt1 [r17]; \
tbit.nz p15,p0 = r29,IA64_PSR_I_BIT; \
mov r29 = b0 \
;; \
adds r16 = PT(R8),r1; /* initialize first base pointer */\
adds r17 = PT(R9),r1; /* initialize second base pointer */\
;; \
.mem.offset 0,0; st8.spill [r16] = r8,16; \
.mem.offset 8,0; st8.spill [r17] = r9,16; \
;; \
.mem.offset 0,0; st8.spill [r16] = r10,24; \
.mem.offset 8,0; st8.spill [r17] = r11,24; \
;; \
mov r9 = cr.iip; /* M */ \
mov r10 = ar.fpsr; /* M */ \
;; \
st8 [r16] = r9,16; /* save cr.iip */ \
st8 [r17] = r30,16; /* save cr.ifs */ \
sub r18 = r18,r22; /* r18=RSE.ndirty*8 */ \
;; \
st8 [r16] = r25,16; /* save ar.unat */ \
st8 [r17] = r26,16; /* save ar.pfs */ \
shl r18 = r18,16; /* calu ar.rsc used for "loadrs" */\
;; \
st8 [r16] = r27,16; /* save ar.rsc */ \
st8 [r17] = r28,16; /* save ar.rnat */ \
;; /* avoid RAW on r16 & r17 */ \
st8 [r16] = r23,16; /* save ar.bspstore */ \
st8 [r17] = r31,16; /* save predicates */ \
;; \
st8 [r16] = r29,16; /* save b0 */ \
st8 [r17] = r18,16; /* save ar.rsc value for "loadrs" */\
;; \
.mem.offset 0,0; st8.spill [r16] = r20,16;/* save original r1 */ \
.mem.offset 8,0; st8.spill [r17] = r12,16; \
adds r12 = -16,r1; /* switch to kernel memory stack */ \
;; \
.mem.offset 0,0; st8.spill [r16] = r13,16; \
.mem.offset 8,0; st8.spill [r17] = r10,16; /* save ar.fpsr */\
mov r13 = r21; /* establish `current' */ \
;; \
.mem.offset 0,0; st8.spill [r16] = r15,16; \
.mem.offset 8,0; st8.spill [r17] = r14,16; \
;; \
.mem.offset 0,0; st8.spill [r16] = r2,16; \
.mem.offset 8,0; st8.spill [r17] = r3,16; \
adds r2 = VMM_PT_REGS_R16_OFFSET,r1; \
;; \
adds r16 = VMM_VCPU_IIPA_OFFSET,r13; \
adds r17 = VMM_VCPU_ISR_OFFSET,r13; \
mov r26 = cr.iipa; \
mov r27 = cr.isr; \
;; \
st8 [r16] = r26; \
st8 [r17] = r27; \
;; \
EXTRA; \
mov r8 = ar.ccv; \
mov r9 = ar.csd; \
mov r10 = ar.ssd; \
movl r11 = FPSR_DEFAULT; /* L-unit */ \
adds r17 = VMM_VCPU_GP_OFFSET,r13; \
;; \
ld8 r1 = [r17];/* establish kernel global pointer */ \
;; \
PAL_VSA_SYNC_READ \
KVM_MINSTATE_END_SAVE_MIN
/*
* SAVE_REST saves the remainder of pt_regs (with psr.ic on).
*
* Assumed state upon entry:
* psr.ic: on
* r2: points to &pt_regs.f6
* r3: points to &pt_regs.f7
* r8: contents of ar.ccv
* r9: contents of ar.csd
* r10: contents of ar.ssd
* r11: FPSR_DEFAULT
*
* Registers r14 and r15 are guaranteed not to be touched by SAVE_REST.
*/
#define KVM_SAVE_REST \
.mem.offset 0,0; st8.spill [r2] = r16,16; \
.mem.offset 8,0; st8.spill [r3] = r17,16; \
;; \
.mem.offset 0,0; st8.spill [r2] = r18,16; \
.mem.offset 8,0; st8.spill [r3] = r19,16; \
;; \
.mem.offset 0,0; st8.spill [r2] = r20,16; \
.mem.offset 8,0; st8.spill [r3] = r21,16; \
mov r18=b6; \
;; \
.mem.offset 0,0; st8.spill [r2] = r22,16; \
.mem.offset 8,0; st8.spill [r3] = r23,16; \
mov r19 = b7; \
;; \
.mem.offset 0,0; st8.spill [r2] = r24,16; \
.mem.offset 8,0; st8.spill [r3] = r25,16; \
;; \
.mem.offset 0,0; st8.spill [r2] = r26,16; \
.mem.offset 8,0; st8.spill [r3] = r27,16; \
;; \
.mem.offset 0,0; st8.spill [r2] = r28,16; \
.mem.offset 8,0; st8.spill [r3] = r29,16; \
;; \
.mem.offset 0,0; st8.spill [r2] = r30,16; \
.mem.offset 8,0; st8.spill [r3] = r31,32; \
;; \
mov ar.fpsr = r11; \
st8 [r2] = r8,8; \
adds r24 = PT(B6)-PT(F7),r3; \
adds r25 = PT(B7)-PT(F7),r3; \
;; \
st8 [r24] = r18,16; /* b6 */ \
st8 [r25] = r19,16; /* b7 */ \
adds r2 = PT(R4)-PT(F6),r2; \
adds r3 = PT(R5)-PT(F7),r3; \
;; \
st8 [r24] = r9; /* ar.csd */ \
st8 [r25] = r10; /* ar.ssd */ \
;; \
mov r18 = ar.unat; \
adds r19 = PT(EML_UNAT)-PT(R4),r2; \
;; \
st8 [r19] = r18; /* eml_unat */ \
#define KVM_SAVE_EXTRA \
.mem.offset 0,0; st8.spill [r2] = r4,16; \
.mem.offset 8,0; st8.spill [r3] = r5,16; \
;; \
.mem.offset 0,0; st8.spill [r2] = r6,16; \
.mem.offset 8,0; st8.spill [r3] = r7; \
;; \
mov r26 = ar.unat; \
;; \
st8 [r2] = r26;/* eml_unat */ \
#define KVM_SAVE_MIN_WITH_COVER KVM_DO_SAVE_MIN(cover, mov r30 = cr.ifs,)
#define KVM_SAVE_MIN_WITH_COVER_R19 KVM_DO_SAVE_MIN(cover, mov r30 = cr.ifs, mov r15 = r19)
#define KVM_SAVE_MIN KVM_DO_SAVE_MIN( , mov r30 = r0, )
#ifndef __KVM_IA64_LAPIC_H
#define __KVM_IA64_LAPIC_H
#include <linux/kvm_host.h>
/*
* vlsapic
*/
struct kvm_lapic{
struct kvm_vcpu *vcpu;
uint64_t insvc[4];
uint64_t vhpi;
uint8_t xtp;
uint8_t pal_init_pending;
uint8_t pad[2];
};
int kvm_create_lapic(struct kvm_vcpu *vcpu);
void kvm_free_lapic(struct kvm_vcpu *vcpu);
int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig);
#endif
#ifndef __KVM_IA64_MISC_H
#define __KVM_IA64_MISC_H
#include <linux/kvm_host.h>
/*
* misc.h
* Copyright (C) 2007, Intel Corporation.
* Xiantao Zhang (xiantao.zhang@intel.com)
*
* 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.
*
*/
/*
*Return p2m base address at host side!
*/
static inline uint64_t *kvm_host_get_pmt(struct kvm *kvm)
{
return (uint64_t *)(kvm->arch.vm_base + KVM_P2M_OFS);
}
static inline void kvm_set_pmt_entry(struct kvm *kvm, gfn_t gfn,
u64 paddr, u64 mem_flags)
{
uint64_t *pmt_base = kvm_host_get_pmt(kvm);
unsigned long pte;
pte = PAGE_ALIGN(paddr) | mem_flags;
pmt_base[gfn] = pte;
}
/*Function for translating host address to guest address*/
static inline void *to_guest(struct kvm *kvm, void *addr)
{
return (void *)((unsigned long)(addr) - kvm->arch.vm_base +
KVM_VM_DATA_BASE);
}
/*Function for translating guest address to host address*/
static inline void *to_host(struct kvm *kvm, void *addr)
{
return (void *)((unsigned long)addr - KVM_VM_DATA_BASE
+ kvm->arch.vm_base);
}
/* Get host context of the vcpu */
static inline union context *kvm_get_host_context(struct kvm_vcpu *vcpu)
{
union context *ctx = &vcpu->arch.host;
return to_guest(vcpu->kvm, ctx);
}
/* Get guest context of the vcpu */
static inline union context *kvm_get_guest_context(struct kvm_vcpu *vcpu)
{
union context *ctx = &vcpu->arch.guest;
return to_guest(vcpu->kvm, ctx);
}
/* kvm get exit data from gvmm! */
static inline struct exit_ctl_data *kvm_get_exit_data(struct kvm_vcpu *vcpu)
{
return &vcpu->arch.exit_data;
}
/*kvm get vcpu ioreq for kvm module!*/
static inline struct kvm_mmio_req *kvm_get_vcpu_ioreq(struct kvm_vcpu *vcpu)
{
struct exit_ctl_data *p_ctl_data;
if (vcpu) {
p_ctl_data = kvm_get_exit_data(vcpu);
if (p_ctl_data->exit_reason == EXIT_REASON_MMIO_INSTRUCTION)
return &p_ctl_data->u.ioreq;
}
return NULL;
}
#endif
/*
* mmio.c: MMIO emulation components.
* Copyright (c) 2004, Intel Corporation.
* Yaozu Dong (Eddie Dong) (Eddie.dong@intel.com)
* Kun Tian (Kevin Tian) (Kevin.tian@intel.com)
*
* Copyright (c) 2007 Intel Corporation KVM support.
* Xuefei Xu (Anthony Xu) (anthony.xu@intel.com)
* Xiantao Zhang (xiantao.zhang@intel.com)
*
* 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.
*
*/
#include <linux/kvm_host.h>
#include "vcpu.h"
static void vlsapic_write_xtp(struct kvm_vcpu *v, uint8_t val)
{
VLSAPIC_XTP(v) = val;
}
/*
* LSAPIC OFFSET
*/
#define PIB_LOW_HALF(ofst) !(ofst & (1 << 20))
#define PIB_OFST_INTA 0x1E0000
#define PIB_OFST_XTP 0x1E0008
/*
* execute write IPI op.
*/
static void vlsapic_write_ipi(struct kvm_vcpu *vcpu,
uint64_t addr, uint64_t data)
{
struct exit_ctl_data *p = &current_vcpu->arch.exit_data;
unsigned long psr;
local_irq_save(psr);
p->exit_reason = EXIT_REASON_IPI;
p->u.ipi_data.addr.val = addr;
p->u.ipi_data.data.val = data;
vmm_transition(current_vcpu);
local_irq_restore(psr);
}
void lsapic_write(struct kvm_vcpu *v, unsigned long addr,
unsigned long length, unsigned long val)
{
addr &= (PIB_SIZE - 1);
switch (addr) {
case PIB_OFST_INTA:
/*panic_domain(NULL, "Undefined write on PIB INTA\n");*/
panic_vm(v);
break;
case PIB_OFST_XTP:
if (length == 1) {
vlsapic_write_xtp(v, val);
} else {
/*panic_domain(NULL,
"Undefined write on PIB XTP\n");*/
panic_vm(v);
}
break;
default:
if (PIB_LOW_HALF(addr)) {
/*lower half */
if (length != 8)
/*panic_domain(NULL,
"Can't LHF write with size %ld!\n",
length);*/
panic_vm(v);
else
vlsapic_write_ipi(v, addr, val);
} else { /* upper half
printk("IPI-UHF write %lx\n",addr);*/
panic_vm(v);
}
break;
}
}
unsigned long lsapic_read(struct kvm_vcpu *v, unsigned long addr,
unsigned long length)
{
uint64_t result = 0;
addr &= (PIB_SIZE - 1);
switch (addr) {
case PIB_OFST_INTA:
if (length == 1) /* 1 byte load */
; /* There is no i8259, there is no INTA access*/
else
/*panic_domain(NULL,"Undefined read on PIB INTA\n"); */
panic_vm(v);
break;
case PIB_OFST_XTP:
if (length == 1) {
result = VLSAPIC_XTP(v);
/* printk("read xtp %lx\n", result); */
} else {
/*panic_domain(NULL,
"Undefined read on PIB XTP\n");*/
panic_vm(v);
}
break;
default:
panic_vm(v);
break;
}
return result;
}
static void mmio_access(struct kvm_vcpu *vcpu, u64 src_pa, u64 *dest,
u16 s, int ma, int dir)
{
unsigned long iot;
struct exit_ctl_data *p = &vcpu->arch.exit_data;
unsigned long psr;
iot = __gpfn_is_io(src_pa >> PAGE_SHIFT);
local_irq_save(psr);
/*Intercept the acces for PIB range*/
if (iot == GPFN_PIB) {
if (!dir)
lsapic_write(vcpu, src_pa, s, *dest);
else
*dest = lsapic_read(vcpu, src_pa, s);
goto out;
}
p->exit_reason = EXIT_REASON_MMIO_INSTRUCTION;
p->u.ioreq.addr = src_pa;
p->u.ioreq.size = s;
p->u.ioreq.dir = dir;
if (dir == IOREQ_WRITE)
p->u.ioreq.data = *dest;
p->u.ioreq.state = STATE_IOREQ_READY;
vmm_transition(vcpu);
if (p->u.ioreq.state == STATE_IORESP_READY) {
if (dir == IOREQ_READ)
*dest = p->u.ioreq.data;
} else
panic_vm(vcpu);
out:
local_irq_restore(psr);
return ;
}
/*
dir 1: read 0:write
inst_type 0:integer 1:floating point
*/
#define SL_INTEGER 0 /* store/load interger*/
#define SL_FLOATING 1 /* store/load floating*/
void emulate_io_inst(struct kvm_vcpu *vcpu, u64 padr, u64 ma)
{
struct kvm_pt_regs *regs;
IA64_BUNDLE bundle;
int slot, dir = 0;
int inst_type = -1;
u16 size = 0;
u64 data, slot1a, slot1b, temp, update_reg;
s32 imm;
INST64 inst;
regs = vcpu_regs(vcpu);
if (fetch_code(vcpu, regs->cr_iip, &bundle)) {
/* if fetch code fail, return and try again */
return;
}
slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri;
if (!slot)
inst.inst = bundle.slot0;
else if (slot == 1) {
slot1a = bundle.slot1a;
slot1b = bundle.slot1b;
inst.inst = slot1a + (slot1b << 18);
} else if (slot == 2)
inst.inst = bundle.slot2;
/* Integer Load/Store */
if (inst.M1.major == 4 && inst.M1.m == 0 && inst.M1.x == 0) {
inst_type = SL_INTEGER;
size = (inst.M1.x6 & 0x3);
if ((inst.M1.x6 >> 2) > 0xb) {
/*write*/
dir = IOREQ_WRITE;
data = vcpu_get_gr(vcpu, inst.M4.r2);
} else if ((inst.M1.x6 >> 2) < 0xb) {
/*read*/
dir = IOREQ_READ;
}
} else if (inst.M2.major == 4 && inst.M2.m == 1 && inst.M2.x == 0) {
/* Integer Load + Reg update */
inst_type = SL_INTEGER;
dir = IOREQ_READ;
size = (inst.M2.x6 & 0x3);
temp = vcpu_get_gr(vcpu, inst.M2.r3);
update_reg = vcpu_get_gr(vcpu, inst.M2.r2);
temp += update_reg;
vcpu_set_gr(vcpu, inst.M2.r3, temp, 0);
} else if (inst.M3.major == 5) {
/*Integer Load/Store + Imm update*/
inst_type = SL_INTEGER;
size = (inst.M3.x6&0x3);
if ((inst.M5.x6 >> 2) > 0xb) {
/*write*/
dir = IOREQ_WRITE;
data = vcpu_get_gr(vcpu, inst.M5.r2);
temp = vcpu_get_gr(vcpu, inst.M5.r3);
imm = (inst.M5.s << 31) | (inst.M5.i << 30) |
(inst.M5.imm7 << 23);
temp += imm >> 23;
vcpu_set_gr(vcpu, inst.M5.r3, temp, 0);
} else if ((inst.M3.x6 >> 2) < 0xb) {
/*read*/
dir = IOREQ_READ;
temp = vcpu_get_gr(vcpu, inst.M3.r3);
imm = (inst.M3.s << 31) | (inst.M3.i << 30) |
(inst.M3.imm7 << 23);
temp += imm >> 23;
vcpu_set_gr(vcpu, inst.M3.r3, temp, 0);
}
} else if (inst.M9.major == 6 && inst.M9.x6 == 0x3B
&& inst.M9.m == 0 && inst.M9.x == 0) {
/* Floating-point spill*/
struct ia64_fpreg v;
inst_type = SL_FLOATING;
dir = IOREQ_WRITE;
vcpu_get_fpreg(vcpu, inst.M9.f2, &v);
/* Write high word. FIXME: this is a kludge! */
v.u.bits[1] &= 0x3ffff;
mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE);
data = v.u.bits[0];
size = 3;
} else if (inst.M10.major == 7 && inst.M10.x6 == 0x3B) {
/* Floating-point spill + Imm update */
struct ia64_fpreg v;
inst_type = SL_FLOATING;
dir = IOREQ_WRITE;
vcpu_get_fpreg(vcpu, inst.M10.f2, &v);
temp = vcpu_get_gr(vcpu, inst.M10.r3);
imm = (inst.M10.s << 31) | (inst.M10.i << 30) |
(inst.M10.imm7 << 23);
temp += imm >> 23;
vcpu_set_gr(vcpu, inst.M10.r3, temp, 0);
/* Write high word.FIXME: this is a kludge! */
v.u.bits[1] &= 0x3ffff;
mmio_access(vcpu, padr + 8, &v.u.bits[1], 8, ma, IOREQ_WRITE);
data = v.u.bits[0];
size = 3;
} else if (inst.M10.major == 7 && inst.M10.x6 == 0x31) {
/* Floating-point stf8 + Imm update */
struct ia64_fpreg v;
inst_type = SL_FLOATING;
dir = IOREQ_WRITE;
size = 3;
vcpu_get_fpreg(vcpu, inst.M10.f2, &v);
data = v.u.bits[0]; /* Significand. */
temp = vcpu_get_gr(vcpu, inst.M10.r3);
imm = (inst.M10.s << 31) | (inst.M10.i << 30) |
(inst.M10.imm7 << 23);
temp += imm >> 23;
vcpu_set_gr(vcpu, inst.M10.r3, temp, 0);
} else if (inst.M15.major == 7 && inst.M15.x6 >= 0x2c
&& inst.M15.x6 <= 0x2f) {
temp = vcpu_get_gr(vcpu, inst.M15.r3);
imm = (inst.M15.s << 31) | (inst.M15.i << 30) |
(inst.M15.imm7 << 23);
temp += imm >> 23;
vcpu_set_gr(vcpu, inst.M15.r3, temp, 0);
vcpu_increment_iip(vcpu);
return;
} else if (inst.M12.major == 6 && inst.M12.m == 1
&& inst.M12.x == 1 && inst.M12.x6 == 1) {
/* Floating-point Load Pair + Imm ldfp8 M12*/
struct ia64_fpreg v;
inst_type = SL_FLOATING;
dir = IOREQ_READ;
size = 8; /*ldfd*/
mmio_access(vcpu, padr, &data, size, ma, dir);
v.u.bits[0] = data;
v.u.bits[1] = 0x1003E;
vcpu_set_fpreg(vcpu, inst.M12.f1, &v);
padr += 8;
mmio_access(vcpu, padr, &data, size, ma, dir);
v.u.bits[0] = data;
v.u.bits[1] = 0x1003E;
vcpu_set_fpreg(vcpu, inst.M12.f2, &v);
padr += 8;
vcpu_set_gr(vcpu, inst.M12.r3, padr, 0);
vcpu_increment_iip(vcpu);
return;
} else {
inst_type = -1;
panic_vm(vcpu);
}
size = 1 << size;
if (dir == IOREQ_WRITE) {
mmio_access(vcpu, padr, &data, size, ma, dir);
} else {
mmio_access(vcpu, padr, &data, size, ma, dir);
if (inst_type == SL_INTEGER)
vcpu_set_gr(vcpu, inst.M1.r1, data, 0);
else
panic_vm(vcpu);
}
vcpu_increment_iip(vcpu);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* vmm.c: vmm module interface with kvm module
*
* Copyright (c) 2007, Intel Corporation.
*
* Xiantao Zhang (xiantao.zhang@intel.com)
*
* 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.
*/
#include<linux/module.h>
#include<asm/fpswa.h>
#include "vcpu.h"
MODULE_AUTHOR("Intel");
MODULE_LICENSE("GPL");
extern char kvm_ia64_ivt;
extern fpswa_interface_t *vmm_fpswa_interface;
struct kvm_vmm_info vmm_info = {
.module = THIS_MODULE,
.vmm_entry = vmm_entry,
.tramp_entry = vmm_trampoline,
.vmm_ivt = (unsigned long)&kvm_ia64_ivt,
};
static int __init kvm_vmm_init(void)
{
vmm_fpswa_interface = fpswa_interface;
/*Register vmm data to kvm side*/
return kvm_init(&vmm_info, 1024, THIS_MODULE);
}
static void __exit kvm_vmm_exit(void)
{
kvm_exit();
return ;
}
void vmm_spin_lock(spinlock_t *lock)
{
_vmm_raw_spin_lock(lock);
}
void vmm_spin_unlock(spinlock_t *lock)
{
_vmm_raw_spin_unlock(lock);
}
module_init(kvm_vmm_init)
module_exit(kvm_vmm_exit)
此差异已折叠。
/*
* vti.h: prototype for generial vt related interface
* Copyright (c) 2004, Intel Corporation.
*
* Xuefei Xu (Anthony Xu) (anthony.xu@intel.com)
* Fred Yang (fred.yang@intel.com)
* Kun Tian (Kevin Tian) (kevin.tian@intel.com)
*
* Copyright (c) 2007, Intel Corporation.
* Zhang xiantao <xiantao.zhang@intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef _KVM_VT_I_H
#define _KVM_VT_I_H
#ifndef __ASSEMBLY__
#include <asm/page.h>
#include <linux/kvm_host.h>
/* define itr.i and itr.d in ia64_itr function */
#define ITR 0x01
#define DTR 0x02
#define IaDTR 0x03
#define IA64_TR_VMM 6 /*itr6, dtr6 : maps vmm code, vmbuffer*/
#define IA64_TR_VM_DATA 7 /*dtr7 : maps current vm data*/
#define RR6 (6UL<<61)
#define RR7 (7UL<<61)
/* config_options in pal_vp_init_env */
#define VP_INITIALIZE 1UL
#define VP_FR_PMC 1UL<<1
#define VP_OPCODE 1UL<<8
#define VP_CAUSE 1UL<<9
#define VP_FW_ACC 1UL<<63
/* init vp env with initializing vm_buffer */
#define VP_INIT_ENV_INITALIZE (VP_INITIALIZE | VP_FR_PMC |\
VP_OPCODE | VP_CAUSE | VP_FW_ACC)
/* init vp env without initializing vm_buffer */
#define VP_INIT_ENV VP_FR_PMC | VP_OPCODE | VP_CAUSE | VP_FW_ACC
#define PAL_VP_CREATE 265
/* Stacked Virt. Initializes a new VPD for the operation of
* a new virtual processor in the virtual environment.
*/
#define PAL_VP_ENV_INFO 266
/*Stacked Virt. Returns the parameters needed to enter a virtual environment.*/
#define PAL_VP_EXIT_ENV 267
/*Stacked Virt. Allows a logical processor to exit a virtual environment.*/
#define PAL_VP_INIT_ENV 268
/*Stacked Virt. Allows a logical processor to enter a virtual environment.*/
#define PAL_VP_REGISTER 269
/*Stacked Virt. Register a different host IVT for the virtual processor.*/
#define PAL_VP_RESUME 270
/* Renamed from PAL_VP_RESUME */
#define PAL_VP_RESTORE 270
/*Stacked Virt. Resumes virtual processor operation on the logical processor.*/
#define PAL_VP_SUSPEND 271
/* Renamed from PAL_VP_SUSPEND */
#define PAL_VP_SAVE 271
/* Stacked Virt. Suspends operation for the specified virtual processor on
* the logical processor.
*/
#define PAL_VP_TERMINATE 272
/* Stacked Virt. Terminates operation for the specified virtual processor.*/
union vac {
unsigned long value;
struct {
int a_int:1;
int a_from_int_cr:1;
int a_to_int_cr:1;
int a_from_psr:1;
int a_from_cpuid:1;
int a_cover:1;
int a_bsw:1;
long reserved:57;
};
};
union vdc {
unsigned long value;
struct {
int d_vmsw:1;
int d_extint:1;
int d_ibr_dbr:1;
int d_pmc:1;
int d_to_pmd:1;
int d_itm:1;
long reserved:58;
};
};
struct vpd {
union vac vac;
union vdc vdc;
unsigned long virt_env_vaddr;
unsigned long reserved1[29];
unsigned long vhpi;
unsigned long reserved2[95];
unsigned long vgr[16];
unsigned long vbgr[16];
unsigned long vnat;
unsigned long vbnat;
unsigned long vcpuid[5];
unsigned long reserved3[11];
unsigned long vpsr;
unsigned long vpr;
unsigned long reserved4[76];
union {
unsigned long vcr[128];
struct {
unsigned long dcr;
unsigned long itm;
unsigned long iva;
unsigned long rsv1[5];
unsigned long pta;
unsigned long rsv2[7];
unsigned long ipsr;
unsigned long isr;
unsigned long rsv3;
unsigned long iip;
unsigned long ifa;
unsigned long itir;
unsigned long iipa;
unsigned long ifs;
unsigned long iim;
unsigned long iha;
unsigned long rsv4[38];
unsigned long lid;
unsigned long ivr;
unsigned long tpr;
unsigned long eoi;
unsigned long irr[4];
unsigned long itv;
unsigned long pmv;
unsigned long cmcv;
unsigned long rsv5[5];
unsigned long lrr0;
unsigned long lrr1;
unsigned long rsv6[46];
};
};
unsigned long reserved5[128];
unsigned long reserved6[3456];
unsigned long vmm_avail[128];
unsigned long reserved7[4096];
};
#define PAL_PROC_VM_BIT (1UL << 40)
#define PAL_PROC_VMSW_BIT (1UL << 54)
static inline s64 ia64_pal_vp_env_info(u64 *buffer_size,
u64 *vp_env_info)
{
struct ia64_pal_retval iprv;
PAL_CALL_STK(iprv, PAL_VP_ENV_INFO, 0, 0, 0);
*buffer_size = iprv.v0;
*vp_env_info = iprv.v1;
return iprv.status;
}
static inline s64 ia64_pal_vp_exit_env(u64 iva)
{
struct ia64_pal_retval iprv;
PAL_CALL_STK(iprv, PAL_VP_EXIT_ENV, (u64)iva, 0, 0);
return iprv.status;
}
static inline s64 ia64_pal_vp_init_env(u64 config_options, u64 pbase_addr,
u64 vbase_addr, u64 *vsa_base)
{
struct ia64_pal_retval iprv;
PAL_CALL_STK(iprv, PAL_VP_INIT_ENV, config_options, pbase_addr,
vbase_addr);
*vsa_base = iprv.v0;
return iprv.status;
}
static inline s64 ia64_pal_vp_restore(u64 *vpd, u64 pal_proc_vector)
{
struct ia64_pal_retval iprv;
PAL_CALL_STK(iprv, PAL_VP_RESTORE, (u64)vpd, pal_proc_vector, 0);
return iprv.status;
}
static inline s64 ia64_pal_vp_save(u64 *vpd, u64 pal_proc_vector)
{
struct ia64_pal_retval iprv;
PAL_CALL_STK(iprv, PAL_VP_SAVE, (u64)vpd, pal_proc_vector, 0);
return iprv.status;
}
#endif
/*VPD field offset*/
#define VPD_VAC_START_OFFSET 0
#define VPD_VDC_START_OFFSET 8
#define VPD_VHPI_START_OFFSET 256
#define VPD_VGR_START_OFFSET 1024
#define VPD_VBGR_START_OFFSET 1152
#define VPD_VNAT_START_OFFSET 1280
#define VPD_VBNAT_START_OFFSET 1288
#define VPD_VCPUID_START_OFFSET 1296
#define VPD_VPSR_START_OFFSET 1424
#define VPD_VPR_START_OFFSET 1432
#define VPD_VRSE_CFLE_START_OFFSET 1440
#define VPD_VCR_START_OFFSET 2048
#define VPD_VTPR_START_OFFSET 2576
#define VPD_VRR_START_OFFSET 3072
#define VPD_VMM_VAIL_START_OFFSET 31744
/*Virtualization faults*/
#define EVENT_MOV_TO_AR 1
#define EVENT_MOV_TO_AR_IMM 2
#define EVENT_MOV_FROM_AR 3
#define EVENT_MOV_TO_CR 4
#define EVENT_MOV_FROM_CR 5
#define EVENT_MOV_TO_PSR 6
#define EVENT_MOV_FROM_PSR 7
#define EVENT_ITC_D 8
#define EVENT_ITC_I 9
#define EVENT_MOV_TO_RR 10
#define EVENT_MOV_TO_DBR 11
#define EVENT_MOV_TO_IBR 12
#define EVENT_MOV_TO_PKR 13
#define EVENT_MOV_TO_PMC 14
#define EVENT_MOV_TO_PMD 15
#define EVENT_ITR_D 16
#define EVENT_ITR_I 17
#define EVENT_MOV_FROM_RR 18
#define EVENT_MOV_FROM_DBR 19
#define EVENT_MOV_FROM_IBR 20
#define EVENT_MOV_FROM_PKR 21
#define EVENT_MOV_FROM_PMC 22
#define EVENT_MOV_FROM_CPUID 23
#define EVENT_SSM 24
#define EVENT_RSM 25
#define EVENT_PTC_L 26
#define EVENT_PTC_G 27
#define EVENT_PTC_GA 28
#define EVENT_PTR_D 29
#define EVENT_PTR_I 30
#define EVENT_THASH 31
#define EVENT_TTAG 32
#define EVENT_TPA 33
#define EVENT_TAK 34
#define EVENT_PTC_E 35
#define EVENT_COVER 36
#define EVENT_RFI 37
#define EVENT_BSW_0 38
#define EVENT_BSW_1 39
#define EVENT_VMSW 40
/**PAL virtual services offsets */
#define PAL_VPS_RESUME_NORMAL 0x0000
#define PAL_VPS_RESUME_HANDLER 0x0400
#define PAL_VPS_SYNC_READ 0x0800
#define PAL_VPS_SYNC_WRITE 0x0c00
#define PAL_VPS_SET_PENDING_INTERRUPT 0x1000
#define PAL_VPS_THASH 0x1400
#define PAL_VPS_TTAG 0x1800
#define PAL_VPS_RESTORE 0x1c00
#define PAL_VPS_SAVE 0x2000
#endif/* _VT_I_H*/
此差异已折叠。
......@@ -803,3 +803,4 @@ config PPC_CLOCK
config PPC_LIB_RHEAP
bool
source "arch/powerpc/kvm/Kconfig"
......@@ -151,6 +151,9 @@ config BOOTX_TEXT
config PPC_EARLY_DEBUG
bool "Early debugging (dangerous)"
# PPC_EARLY_DEBUG on 440 leaves AS=1 mappings above the TLB high water
# mark, which doesn't work with current 440 KVM.
depends on !KVM
help
Say Y to enable some early debugging facilities that may be available
for your processor/board combination. Those facilities are hacks
......
......@@ -145,6 +145,7 @@ core-y += arch/powerpc/kernel/ \
arch/powerpc/platforms/
core-$(CONFIG_MATH_EMULATION) += arch/powerpc/math-emu/
core-$(CONFIG_XMON) += arch/powerpc/xmon/
core-$(CONFIG_KVM) += arch/powerpc/kvm/
drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
......
......@@ -23,6 +23,9 @@
#include <linux/mm.h>
#include <linux/suspend.h>
#include <linux/hrtimer.h>
#ifdef CONFIG_KVM
#include <linux/kvm_host.h>
#endif
#ifdef CONFIG_PPC64
#include <linux/time.h>
#include <linux/hardirq.h>
......@@ -324,5 +327,30 @@ int main(void)
DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE);
#ifdef CONFIG_KVM
DEFINE(TLBE_BYTES, sizeof(struct tlbe));
DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
DEFINE(VCPU_HOST_TLB, offsetof(struct kvm_vcpu, arch.host_tlb));
DEFINE(VCPU_SHADOW_TLB, offsetof(struct kvm_vcpu, arch.shadow_tlb));
DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.msr));
DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4));
DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6));
DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7));
DEFINE(VCPU_PID, offsetof(struct kvm_vcpu, arch.pid));
DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
#endif
return 0;
}
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright IBM Corp. 2007
*
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
*/
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kvm_host.h>
#include <linux/highmem.h>
#include <asm/mmu-44x.h>
#include <asm/kvm_ppc.h>
#include "44x_tlb.h"
#define PPC44x_TLB_USER_PERM_MASK (PPC44x_TLB_UX|PPC44x_TLB_UR|PPC44x_TLB_UW)
#define PPC44x_TLB_SUPER_PERM_MASK (PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW)
static unsigned int kvmppc_tlb_44x_pos;
static u32 kvmppc_44x_tlb_shadow_attrib(u32 attrib, int usermode)
{
/* Mask off reserved bits. */
attrib &= PPC44x_TLB_PERM_MASK|PPC44x_TLB_ATTR_MASK;
if (!usermode) {
/* Guest is in supervisor mode, so we need to translate guest
* supervisor permissions into user permissions. */
attrib &= ~PPC44x_TLB_USER_PERM_MASK;
attrib |= (attrib & PPC44x_TLB_SUPER_PERM_MASK) << 3;
}
/* Make sure host can always access this memory. */
attrib |= PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW;
return attrib;
}
/* Search the guest TLB for a matching entry. */
int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid,
unsigned int as)
{
int i;
/* XXX Replace loop with fancy data structures. */
for (i = 0; i < PPC44x_TLB_SIZE; i++) {
struct tlbe *tlbe = &vcpu->arch.guest_tlb[i];
unsigned int tid;
if (eaddr < get_tlb_eaddr(tlbe))
continue;
if (eaddr > get_tlb_end(tlbe))
continue;
tid = get_tlb_tid(tlbe);
if (tid && (tid != pid))
continue;
if (!get_tlb_v(tlbe))
continue;
if (get_tlb_ts(tlbe) != as)
continue;
return i;
}
return -1;
}
struct tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu, gva_t eaddr)
{
unsigned int as = !!(vcpu->arch.msr & MSR_IS);
unsigned int index;
index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
if (index == -1)
return NULL;
return &vcpu->arch.guest_tlb[index];
}
struct tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu, gva_t eaddr)
{
unsigned int as = !!(vcpu->arch.msr & MSR_DS);
unsigned int index;
index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
if (index == -1)
return NULL;
return &vcpu->arch.guest_tlb[index];
}
static int kvmppc_44x_tlbe_is_writable(struct tlbe *tlbe)
{
return tlbe->word2 & (PPC44x_TLB_SW|PPC44x_TLB_UW);
}
/* Must be called with mmap_sem locked for writing. */
static void kvmppc_44x_shadow_release(struct kvm_vcpu *vcpu,
unsigned int index)
{
struct tlbe *stlbe = &vcpu->arch.shadow_tlb[index];
struct page *page = vcpu->arch.shadow_pages[index];
kunmap(vcpu->arch.shadow_pages[index]);
if (get_tlb_v(stlbe)) {
if (kvmppc_44x_tlbe_is_writable(stlbe))
kvm_release_page_dirty(page);
else
kvm_release_page_clean(page);
}
}
/* Caller must ensure that the specified guest TLB entry is safe to insert into
* the shadow TLB. */
void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid,
u32 flags)
{
struct page *new_page;
struct tlbe *stlbe;
hpa_t hpaddr;
unsigned int victim;
/* Future optimization: don't overwrite the TLB entry containing the
* current PC (or stack?). */
victim = kvmppc_tlb_44x_pos++;
if (kvmppc_tlb_44x_pos > tlb_44x_hwater)
kvmppc_tlb_44x_pos = 0;
stlbe = &vcpu->arch.shadow_tlb[victim];
/* Get reference to new page. */
down_write(&current->mm->mmap_sem);
new_page = gfn_to_page(vcpu->kvm, gfn);
if (is_error_page(new_page)) {
printk(KERN_ERR "Couldn't get guest page!\n");
kvm_release_page_clean(new_page);
return;
}
hpaddr = page_to_phys(new_page);
/* Drop reference to old page. */
kvmppc_44x_shadow_release(vcpu, victim);
up_write(&current->mm->mmap_sem);
vcpu->arch.shadow_pages[victim] = new_page;
/* XXX Make sure (va, size) doesn't overlap any other
* entries. 440x6 user manual says the result would be
* "undefined." */
/* XXX what about AS? */
stlbe->tid = asid & 0xff;
/* Force TS=1 for all guest mappings. */
/* For now we hardcode 4KB mappings, but it will be important to
* use host large pages in the future. */
stlbe->word0 = (gvaddr & PAGE_MASK) | PPC44x_TLB_VALID | PPC44x_TLB_TS
| PPC44x_TLB_4K;
stlbe->word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf);
stlbe->word2 = kvmppc_44x_tlb_shadow_attrib(flags,
vcpu->arch.msr & MSR_PR);
}
void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, u64 eaddr, u64 asid)
{
unsigned int pid = asid & 0xff;
int i;
/* XXX Replace loop with fancy data structures. */
down_write(&current->mm->mmap_sem);
for (i = 0; i <= tlb_44x_hwater; i++) {
struct tlbe *stlbe = &vcpu->arch.shadow_tlb[i];
unsigned int tid;
if (!get_tlb_v(stlbe))
continue;
if (eaddr < get_tlb_eaddr(stlbe))
continue;
if (eaddr > get_tlb_end(stlbe))
continue;
tid = get_tlb_tid(stlbe);
if (tid && (tid != pid))
continue;
kvmppc_44x_shadow_release(vcpu, i);
stlbe->word0 = 0;
}
up_write(&current->mm->mmap_sem);
}
/* Invalidate all mappings, so that when they fault back in they will get the
* proper permission bits. */
void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode)
{
int i;
/* XXX Replace loop with fancy data structures. */
down_write(&current->mm->mmap_sem);
for (i = 0; i <= tlb_44x_hwater; i++) {
kvmppc_44x_shadow_release(vcpu, i);
vcpu->arch.shadow_tlb[i].word0 = 0;
}
up_write(&current->mm->mmap_sem);
}
此差异已折叠。
#
# KVM configuration
#
menuconfig VIRTUALIZATION
bool "Virtualization"
---help---
Say Y here to get to see options for using your Linux host to run
other operating systems inside virtual machines (guests).
This option alone does not add any kernel code.
If you say N, all options in this submenu will be skipped and
disabled.
if VIRTUALIZATION
config KVM
bool "Kernel-based Virtual Machine (KVM) support"
depends on 44x && EXPERIMENTAL
select PREEMPT_NOTIFIERS
select ANON_INODES
# We can only run on Book E hosts so far
select KVM_BOOKE_HOST
---help---
Support hosting virtualized guest machines. You will also
need to select one or more of the processor modules below.
This module provides access to the hardware capabilities through
a character device node named /dev/kvm.
If unsure, say N.
config KVM_BOOKE_HOST
bool "KVM host support for Book E PowerPC processors"
depends on KVM && 44x
---help---
Provides host support for KVM on Book E PowerPC processors. Currently
this works on 440 processors only.
source drivers/virtio/Kconfig
endif # VIRTUALIZATION
#
# Makefile for Kernel-based Virtual Machine module
#
EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm
common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o)
kvm-objs := $(common-objs) powerpc.o emulate.o booke_guest.o
obj-$(CONFIG_KVM) += kvm.o
AFLAGS_booke_interrupts.o := -I$(obj)
kvm-booke-host-objs := booke_host.o booke_interrupts.o 44x_tlb.o
obj-$(CONFIG_KVM_BOOKE_HOST) += kvm-booke-host.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -87,7 +87,7 @@ LDFLAGS_vmlinux := -e start
head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \
arch/s390/appldata/ arch/s390/hypfs/
arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/
libs-y += arch/s390/lib/
drivers-y += drivers/s390/
drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/
......
此差异已折叠。
此差异已折叠。
......@@ -110,6 +110,7 @@ void account_system_vtime(struct task_struct *tsk)
S390_lowcore.steal_clock -= cputime << 12;
account_system_time(tsk, 0, cputime);
}
EXPORT_SYMBOL_GPL(account_system_vtime);
static inline void set_vtimer(__u64 expires)
{
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册