Merge branch 'kvm-updates/2.6.35' of git://git.kernel.org/pub/scm/virt/kvm/kvm
* 'kvm-updates/2.6.35' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (269 commits) KVM: x86: Add missing locking to arch specific vcpu ioctls KVM: PPC: Add missing vcpu_load()/vcpu_put() in vcpu ioctls KVM: MMU: Segregate shadow pages with different cr0.wp KVM: x86: Check LMA bit before set_efer KVM: Don't allow lmsw to clear cr0.pe KVM: Add cpuid.txt file KVM: x86: Tell the guest we'll warn it about tsc stability x86, paravirt: don't compute pvclock adjustments if we trust the tsc x86: KVM guest: Try using new kvm clock msrs KVM: x86: export paravirtual cpuid flags in KVM_GET_SUPPORTED_CPUID KVM: x86: add new KVMCLOCK cpuid feature KVM: x86: change msr numbers for kvmclock x86, paravirt: Add a global synchronization point for pvclock x86, paravirt: Enable pvclock flags in vcpu_time_info structure KVM: x86: Inject #GP with the right rip on efer writes KVM: SVM: Don't allow nested guest to VMMCALL into host KVM: x86: Fix exception reinjection forced to true KVM: Fix wallclock version writing race KVM: MMU: Don't read pdptrs with mmu spinlock held in mmu_alloc_roots KVM: VMX: enable VMXON check with SMX enabled (Intel TXT) ...
This commit is contained in:
		
						commit
						98edb6ca41
					
				| @ -656,6 +656,7 @@ struct kvm_clock_data { | ||||
| 4.29 KVM_GET_VCPU_EVENTS | ||||
| 
 | ||||
| Capability: KVM_CAP_VCPU_EVENTS | ||||
| Extended by: KVM_CAP_INTR_SHADOW | ||||
| Architectures: x86 | ||||
| Type: vm ioctl | ||||
| Parameters: struct kvm_vcpu_event (out) | ||||
| @ -676,7 +677,7 @@ struct kvm_vcpu_events { | ||||
| 		__u8 injected; | ||||
| 		__u8 nr; | ||||
| 		__u8 soft; | ||||
| 		__u8 pad; | ||||
| 		__u8 shadow; | ||||
| 	} interrupt; | ||||
| 	struct { | ||||
| 		__u8 injected; | ||||
| @ -688,9 +689,13 @@ struct kvm_vcpu_events { | ||||
| 	__u32 flags; | ||||
| }; | ||||
| 
 | ||||
| KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that | ||||
| interrupt.shadow contains a valid state. Otherwise, this field is undefined. | ||||
| 
 | ||||
| 4.30 KVM_SET_VCPU_EVENTS | ||||
| 
 | ||||
| Capability: KVM_CAP_VCPU_EVENTS | ||||
| Extended by: KVM_CAP_INTR_SHADOW | ||||
| Architectures: x86 | ||||
| Type: vm ioctl | ||||
| Parameters: struct kvm_vcpu_event (in) | ||||
| @ -709,6 +714,183 @@ current in-kernel state. The bits are: | ||||
| KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel | ||||
| KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector | ||||
| 
 | ||||
| If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in | ||||
| the flags field to signal that interrupt.shadow contains a valid state and | ||||
| shall be written into the VCPU. | ||||
| 
 | ||||
| 4.32 KVM_GET_DEBUGREGS | ||||
| 
 | ||||
| Capability: KVM_CAP_DEBUGREGS | ||||
| Architectures: x86 | ||||
| Type: vm ioctl | ||||
| Parameters: struct kvm_debugregs (out) | ||||
| Returns: 0 on success, -1 on error | ||||
| 
 | ||||
| Reads debug registers from the vcpu. | ||||
| 
 | ||||
| struct kvm_debugregs { | ||||
| 	__u64 db[4]; | ||||
| 	__u64 dr6; | ||||
| 	__u64 dr7; | ||||
| 	__u64 flags; | ||||
| 	__u64 reserved[9]; | ||||
| }; | ||||
| 
 | ||||
| 4.33 KVM_SET_DEBUGREGS | ||||
| 
 | ||||
| Capability: KVM_CAP_DEBUGREGS | ||||
| Architectures: x86 | ||||
| Type: vm ioctl | ||||
| Parameters: struct kvm_debugregs (in) | ||||
| Returns: 0 on success, -1 on error | ||||
| 
 | ||||
| Writes debug registers into the vcpu. | ||||
| 
 | ||||
| See KVM_GET_DEBUGREGS for the data structure. The flags field is unused | ||||
| yet and must be cleared on entry. | ||||
| 
 | ||||
| 4.34 KVM_SET_USER_MEMORY_REGION | ||||
| 
 | ||||
| Capability: KVM_CAP_USER_MEM | ||||
| Architectures: all | ||||
| Type: vm ioctl | ||||
| Parameters: struct kvm_userspace_memory_region (in) | ||||
| Returns: 0 on success, -1 on error | ||||
| 
 | ||||
| struct kvm_userspace_memory_region { | ||||
| 	__u32 slot; | ||||
| 	__u32 flags; | ||||
| 	__u64 guest_phys_addr; | ||||
| 	__u64 memory_size; /* bytes */ | ||||
| 	__u64 userspace_addr; /* start of the userspace allocated memory */ | ||||
| }; | ||||
| 
 | ||||
| /* for kvm_memory_region::flags */ | ||||
| #define KVM_MEM_LOG_DIRTY_PAGES  1UL | ||||
| 
 | ||||
| This ioctl allows the user to create or modify a guest physical memory | ||||
| slot.  When changing an existing slot, it may be moved in the guest | ||||
| physical memory space, or its flags may be modified.  It may not be | ||||
| resized.  Slots may not overlap in guest physical address space. | ||||
| 
 | ||||
| Memory for the region is taken starting at the address denoted by the | ||||
| field userspace_addr, which must point at user addressable memory for | ||||
| the entire memory slot size.  Any object may back this memory, including | ||||
| anonymous memory, ordinary files, and hugetlbfs. | ||||
| 
 | ||||
| It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr | ||||
| be identical.  This allows large pages in the guest to be backed by large | ||||
| pages in the host. | ||||
| 
 | ||||
| The flags field supports just one flag, KVM_MEM_LOG_DIRTY_PAGES, which | ||||
| instructs kvm to keep track of writes to memory within the slot.  See | ||||
| the KVM_GET_DIRTY_LOG ioctl. | ||||
| 
 | ||||
| When the KVM_CAP_SYNC_MMU capability, changes in the backing of the memory | ||||
| region are automatically reflected into the guest.  For example, an mmap() | ||||
| that affects the region will be made visible immediately.  Another example | ||||
| is madvise(MADV_DROP). | ||||
| 
 | ||||
| It is recommended to use this API instead of the KVM_SET_MEMORY_REGION ioctl. | ||||
| The KVM_SET_MEMORY_REGION does not allow fine grained control over memory | ||||
| allocation and is deprecated. | ||||
| 
 | ||||
| 4.35 KVM_SET_TSS_ADDR | ||||
| 
 | ||||
| Capability: KVM_CAP_SET_TSS_ADDR | ||||
| Architectures: x86 | ||||
| Type: vm ioctl | ||||
| Parameters: unsigned long tss_address (in) | ||||
| Returns: 0 on success, -1 on error | ||||
| 
 | ||||
| This ioctl defines the physical address of a three-page region in the guest | ||||
| physical address space.  The region must be within the first 4GB of the | ||||
| guest physical address space and must not conflict with any memory slot | ||||
| or any mmio address.  The guest may malfunction if it accesses this memory | ||||
| region. | ||||
| 
 | ||||
| This ioctl is required on Intel-based hosts.  This is needed on Intel hardware | ||||
| because of a quirk in the virtualization implementation (see the internals | ||||
| documentation when it pops into existence). | ||||
| 
 | ||||
| 4.36 KVM_ENABLE_CAP | ||||
| 
 | ||||
| Capability: KVM_CAP_ENABLE_CAP | ||||
| Architectures: ppc | ||||
| Type: vcpu ioctl | ||||
| Parameters: struct kvm_enable_cap (in) | ||||
| Returns: 0 on success; -1 on error | ||||
| 
 | ||||
| +Not all extensions are enabled by default. Using this ioctl the application | ||||
| can enable an extension, making it available to the guest. | ||||
| 
 | ||||
| On systems that do not support this ioctl, it always fails. On systems that | ||||
| do support it, it only works for extensions that are supported for enablement. | ||||
| 
 | ||||
| To check if a capability can be enabled, the KVM_CHECK_EXTENSION ioctl should | ||||
| be used. | ||||
| 
 | ||||
| struct kvm_enable_cap { | ||||
|        /* in */ | ||||
|        __u32 cap; | ||||
| 
 | ||||
| The capability that is supposed to get enabled. | ||||
| 
 | ||||
|        __u32 flags; | ||||
| 
 | ||||
| A bitfield indicating future enhancements. Has to be 0 for now. | ||||
| 
 | ||||
|        __u64 args[4]; | ||||
| 
 | ||||
| Arguments for enabling a feature. If a feature needs initial values to | ||||
| function properly, this is the place to put them. | ||||
| 
 | ||||
|        __u8  pad[64]; | ||||
| }; | ||||
| 
 | ||||
| 4.37 KVM_GET_MP_STATE | ||||
| 
 | ||||
| Capability: KVM_CAP_MP_STATE | ||||
| Architectures: x86, ia64 | ||||
| Type: vcpu ioctl | ||||
| Parameters: struct kvm_mp_state (out) | ||||
| Returns: 0 on success; -1 on error | ||||
| 
 | ||||
| struct kvm_mp_state { | ||||
| 	__u32 mp_state; | ||||
| }; | ||||
| 
 | ||||
| Returns the vcpu's current "multiprocessing state" (though also valid on | ||||
| uniprocessor guests). | ||||
| 
 | ||||
| Possible values are: | ||||
| 
 | ||||
|  - KVM_MP_STATE_RUNNABLE:        the vcpu is currently running | ||||
|  - KVM_MP_STATE_UNINITIALIZED:   the vcpu is an application processor (AP) | ||||
|                                  which has not yet received an INIT signal | ||||
|  - KVM_MP_STATE_INIT_RECEIVED:   the vcpu has received an INIT signal, and is | ||||
|                                  now ready for a SIPI | ||||
|  - KVM_MP_STATE_HALTED:          the vcpu has executed a HLT instruction and | ||||
|                                  is waiting for an interrupt | ||||
|  - KVM_MP_STATE_SIPI_RECEIVED:   the vcpu has just received a SIPI (vector | ||||
|                                  accesible via KVM_GET_VCPU_EVENTS) | ||||
| 
 | ||||
| This ioctl is only useful after KVM_CREATE_IRQCHIP.  Without an in-kernel | ||||
| irqchip, the multiprocessing state must be maintained by userspace. | ||||
| 
 | ||||
| 4.38 KVM_SET_MP_STATE | ||||
| 
 | ||||
| Capability: KVM_CAP_MP_STATE | ||||
| Architectures: x86, ia64 | ||||
| Type: vcpu ioctl | ||||
| Parameters: struct kvm_mp_state (in) | ||||
| Returns: 0 on success; -1 on error | ||||
| 
 | ||||
| Sets the vcpu's current "multiprocessing state"; see KVM_GET_MP_STATE for | ||||
| arguments. | ||||
| 
 | ||||
| This ioctl is only useful after KVM_CREATE_IRQCHIP.  Without an in-kernel | ||||
| irqchip, the multiprocessing state must be maintained by userspace. | ||||
| 
 | ||||
| 5. The kvm_run structure | ||||
| 
 | ||||
| @ -820,6 +1002,13 @@ executed a memory-mapped I/O instruction which could not be satisfied | ||||
| by kvm.  The 'data' member contains the written data if 'is_write' is | ||||
| true, and should be filled by application code otherwise. | ||||
| 
 | ||||
| NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO and KVM_EXIT_OSI, the corresponding | ||||
| operations are complete (and guest state is consistent) only after userspace | ||||
| has re-entered the kernel with KVM_RUN.  The kernel side will first finish | ||||
| incomplete operations and then check for pending signals.  Userspace | ||||
| can re-enter the guest with an unmasked signal pending to complete | ||||
| pending operations. | ||||
| 
 | ||||
| 		/* KVM_EXIT_HYPERCALL */ | ||||
| 		struct { | ||||
| 			__u64 nr; | ||||
| @ -829,7 +1018,9 @@ true, and should be filled by application code otherwise. | ||||
| 			__u32 pad; | ||||
| 		} hypercall; | ||||
| 
 | ||||
| Unused. | ||||
| Unused.  This was once used for 'hypercall to userspace'.  To implement | ||||
| such functionality, use KVM_EXIT_IO (x86) or KVM_EXIT_MMIO (all except s390). | ||||
| Note KVM_EXIT_IO is significantly faster than KVM_EXIT_MMIO. | ||||
| 
 | ||||
| 		/* KVM_EXIT_TPR_ACCESS */ | ||||
| 		struct { | ||||
| @ -870,6 +1061,19 @@ s390 specific. | ||||
| 
 | ||||
| powerpc specific. | ||||
| 
 | ||||
| 		/* KVM_EXIT_OSI */ | ||||
| 		struct { | ||||
| 			__u64 gprs[32]; | ||||
| 		} osi; | ||||
| 
 | ||||
| MOL uses a special hypercall interface it calls 'OSI'. To enable it, we catch | ||||
| hypercalls and exit with this exit struct that contains all the guest gprs. | ||||
| 
 | ||||
| If exit_reason is KVM_EXIT_OSI, then the vcpu has triggered such a hypercall. | ||||
| Userspace can now handle the hypercall and when it's done modify the gprs as | ||||
| necessary. Upon guest entry all guest GPRs will then be replaced by the values | ||||
| in this struct. | ||||
| 
 | ||||
| 		/* Fix the size of the union. */ | ||||
| 		char padding[256]; | ||||
| 	}; | ||||
|  | ||||
							
								
								
									
										42
									
								
								Documentation/kvm/cpuid.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								Documentation/kvm/cpuid.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| KVM CPUID bits | ||||
| Glauber Costa <glommer@redhat.com>, Red Hat Inc, 2010 | ||||
| ===================================================== | ||||
| 
 | ||||
| A guest running on a kvm host, can check some of its features using | ||||
| cpuid. This is not always guaranteed to work, since userspace can | ||||
| mask-out some, or even all KVM-related cpuid features before launching | ||||
| a guest. | ||||
| 
 | ||||
| KVM cpuid functions are: | ||||
| 
 | ||||
| function: KVM_CPUID_SIGNATURE (0x40000000) | ||||
| returns : eax = 0, | ||||
|           ebx = 0x4b4d564b, | ||||
|           ecx = 0x564b4d56, | ||||
|           edx = 0x4d. | ||||
| Note that this value in ebx, ecx and edx corresponds to the string "KVMKVMKVM". | ||||
| This function queries the presence of KVM cpuid leafs. | ||||
| 
 | ||||
| 
 | ||||
| function: define KVM_CPUID_FEATURES (0x40000001) | ||||
| returns : ebx, ecx, edx = 0 | ||||
|           eax = and OR'ed group of (1 << flag), where each flags is: | ||||
| 
 | ||||
| 
 | ||||
| flag                               || value || meaning | ||||
| ============================================================================= | ||||
| KVM_FEATURE_CLOCKSOURCE            ||     0 || kvmclock available at msrs | ||||
|                                    ||       || 0x11 and 0x12. | ||||
| ------------------------------------------------------------------------------ | ||||
| KVM_FEATURE_NOP_IO_DELAY           ||     1 || not necessary to perform delays | ||||
|                                    ||       || on PIO operations. | ||||
| ------------------------------------------------------------------------------ | ||||
| KVM_FEATURE_MMU_OP                 ||     2 || deprecated. | ||||
| ------------------------------------------------------------------------------ | ||||
| KVM_FEATURE_CLOCKSOURCE2           ||     3 || kvmclock available at msrs | ||||
|                                    ||       || 0x4b564d00 and 0x4b564d01 | ||||
| ------------------------------------------------------------------------------ | ||||
| KVM_FEATURE_CLOCKSOURCE_STABLE_BIT ||    24 || host will warn if no guest-side | ||||
|                                    ||       || per-cpu warps are expected in | ||||
|                                    ||       || kvmclock. | ||||
| ------------------------------------------------------------------------------ | ||||
							
								
								
									
										304
									
								
								Documentation/kvm/mmu.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								Documentation/kvm/mmu.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,304 @@ | ||||
| The x86 kvm shadow mmu | ||||
| ====================== | ||||
| 
 | ||||
| The mmu (in arch/x86/kvm, files mmu.[ch] and paging_tmpl.h) is responsible | ||||
| for presenting a standard x86 mmu to the guest, while translating guest | ||||
| physical addresses to host physical addresses. | ||||
| 
 | ||||
| The mmu code attempts to satisfy the following requirements: | ||||
| 
 | ||||
| - correctness: the guest should not be able to determine that it is running | ||||
|                on an emulated mmu except for timing (we attempt to comply | ||||
|                with the specification, not emulate the characteristics of | ||||
|                a particular implementation such as tlb size) | ||||
| - security:    the guest must not be able to touch host memory not assigned | ||||
|                to it | ||||
| - performance: minimize the performance penalty imposed by the mmu | ||||
| - scaling:     need to scale to large memory and large vcpu guests | ||||
| - hardware:    support the full range of x86 virtualization hardware | ||||
| - integration: Linux memory management code must be in control of guest memory | ||||
|                so that swapping, page migration, page merging, transparent | ||||
|                hugepages, and similar features work without change | ||||
| - dirty tracking: report writes to guest memory to enable live migration | ||||
|                and framebuffer-based displays | ||||
| - footprint:   keep the amount of pinned kernel memory low (most memory | ||||
|                should be shrinkable) | ||||
| - reliablity:  avoid multipage or GFP_ATOMIC allocations | ||||
| 
 | ||||
| Acronyms | ||||
| ======== | ||||
| 
 | ||||
| pfn   host page frame number | ||||
| hpa   host physical address | ||||
| hva   host virtual address | ||||
| gfn   guest frame number | ||||
| gpa   guest physical address | ||||
| gva   guest virtual address | ||||
| ngpa  nested guest physical address | ||||
| ngva  nested guest virtual address | ||||
| pte   page table entry (used also to refer generically to paging structure | ||||
|       entries) | ||||
| gpte  guest pte (referring to gfns) | ||||
| spte  shadow pte (referring to pfns) | ||||
| tdp   two dimensional paging (vendor neutral term for NPT and EPT) | ||||
| 
 | ||||
| Virtual and real hardware supported | ||||
| =================================== | ||||
| 
 | ||||
| The mmu supports first-generation mmu hardware, which allows an atomic switch | ||||
| of the current paging mode and cr3 during guest entry, as well as | ||||
| two-dimensional paging (AMD's NPT and Intel's EPT).  The emulated hardware | ||||
| it exposes is the traditional 2/3/4 level x86 mmu, with support for global | ||||
| pages, pae, pse, pse36, cr0.wp, and 1GB pages.  Work is in progress to support | ||||
| exposing NPT capable hardware on NPT capable hosts. | ||||
| 
 | ||||
| Translation | ||||
| =========== | ||||
| 
 | ||||
| The primary job of the mmu is to program the processor's mmu to translate | ||||
| addresses for the guest.  Different translations are required at different | ||||
| times: | ||||
| 
 | ||||
| - when guest paging is disabled, we translate guest physical addresses to | ||||
|   host physical addresses (gpa->hpa) | ||||
| - when guest paging is enabled, we translate guest virtual addresses, to | ||||
|   guest physical addresses, to host physical addresses (gva->gpa->hpa) | ||||
| - when the guest launches a guest of its own, we translate nested guest | ||||
|   virtual addresses, to nested guest physical addresses, to guest physical | ||||
|   addresses, to host physical addresses (ngva->ngpa->gpa->hpa) | ||||
| 
 | ||||
| The primary challenge is to encode between 1 and 3 translations into hardware | ||||
| that support only 1 (traditional) and 2 (tdp) translations.  When the | ||||
| number of required translations matches the hardware, the mmu operates in | ||||
| direct mode; otherwise it operates in shadow mode (see below). | ||||
| 
 | ||||
| Memory | ||||
| ====== | ||||
| 
 | ||||
| Guest memory (gpa) is part of the user address space of the process that is | ||||
| using kvm.  Userspace defines the translation between guest addresses and user | ||||
| addresses (gpa->hva); note that two gpas may alias to the same gva, but not | ||||
| vice versa. | ||||
| 
 | ||||
| These gvas may be backed using any method available to the host: anonymous | ||||
| memory, file backed memory, and device memory.  Memory might be paged by the | ||||
| host at any time. | ||||
| 
 | ||||
| Events | ||||
| ====== | ||||
| 
 | ||||
| The mmu is driven by events, some from the guest, some from the host. | ||||
| 
 | ||||
| Guest generated events: | ||||
| - writes to control registers (especially cr3) | ||||
| - invlpg/invlpga instruction execution | ||||
| - access to missing or protected translations | ||||
| 
 | ||||
| Host generated events: | ||||
| - changes in the gpa->hpa translation (either through gpa->hva changes or | ||||
|   through hva->hpa changes) | ||||
| - memory pressure (the shrinker) | ||||
| 
 | ||||
| Shadow pages | ||||
| ============ | ||||
| 
 | ||||
| The principal data structure is the shadow page, 'struct kvm_mmu_page'.  A | ||||
| shadow page contains 512 sptes, which can be either leaf or nonleaf sptes.  A | ||||
| shadow page may contain a mix of leaf and nonleaf sptes. | ||||
| 
 | ||||
| A nonleaf spte allows the hardware mmu to reach the leaf pages and | ||||
| is not related to a translation directly.  It points to other shadow pages. | ||||
| 
 | ||||
| A leaf spte corresponds to either one or two translations encoded into | ||||
| one paging structure entry.  These are always the lowest level of the | ||||
| translation stack, with optional higher level translations left to NPT/EPT. | ||||
| Leaf ptes point at guest pages. | ||||
| 
 | ||||
| The following table shows translations encoded by leaf ptes, with higher-level | ||||
| translations in parentheses: | ||||
| 
 | ||||
|  Non-nested guests: | ||||
|   nonpaging:     gpa->hpa | ||||
|   paging:        gva->gpa->hpa | ||||
|   paging, tdp:   (gva->)gpa->hpa | ||||
|  Nested guests: | ||||
|   non-tdp:       ngva->gpa->hpa  (*) | ||||
|   tdp:           (ngva->)ngpa->gpa->hpa | ||||
| 
 | ||||
| (*) the guest hypervisor will encode the ngva->gpa translation into its page | ||||
|     tables if npt is not present | ||||
| 
 | ||||
| Shadow pages contain the following information: | ||||
|   role.level: | ||||
|     The level in the shadow paging hierarchy that this shadow page belongs to. | ||||
|     1=4k sptes, 2=2M sptes, 3=1G sptes, etc. | ||||
|   role.direct: | ||||
|     If set, leaf sptes reachable from this page are for a linear range. | ||||
|     Examples include real mode translation, large guest pages backed by small | ||||
|     host pages, and gpa->hpa translations when NPT or EPT is active. | ||||
|     The linear range starts at (gfn << PAGE_SHIFT) and its size is determined | ||||
|     by role.level (2MB for first level, 1GB for second level, 0.5TB for third | ||||
|     level, 256TB for fourth level) | ||||
|     If clear, this page corresponds to a guest page table denoted by the gfn | ||||
|     field. | ||||
|   role.quadrant: | ||||
|     When role.cr4_pae=0, the guest uses 32-bit gptes while the host uses 64-bit | ||||
|     sptes.  That means a guest page table contains more ptes than the host, | ||||
|     so multiple shadow pages are needed to shadow one guest page. | ||||
|     For first-level shadow pages, role.quadrant can be 0 or 1 and denotes the | ||||
|     first or second 512-gpte block in the guest page table.  For second-level | ||||
|     page tables, each 32-bit gpte is converted to two 64-bit sptes | ||||
|     (since each first-level guest page is shadowed by two first-level | ||||
|     shadow pages) so role.quadrant takes values in the range 0..3.  Each | ||||
|     quadrant maps 1GB virtual address space. | ||||
|   role.access: | ||||
|     Inherited guest access permissions in the form uwx.  Note execute | ||||
|     permission is positive, not negative. | ||||
|   role.invalid: | ||||
|     The page is invalid and should not be used.  It is a root page that is | ||||
|     currently pinned (by a cpu hardware register pointing to it); once it is | ||||
|     unpinned it will be destroyed. | ||||
|   role.cr4_pae: | ||||
|     Contains the value of cr4.pae for which the page is valid (e.g. whether | ||||
|     32-bit or 64-bit gptes are in use). | ||||
|   role.cr4_nxe: | ||||
|     Contains the value of efer.nxe for which the page is valid. | ||||
|   role.cr0_wp: | ||||
|     Contains the value of cr0.wp for which the page is valid. | ||||
|   gfn: | ||||
|     Either the guest page table containing the translations shadowed by this | ||||
|     page, or the base page frame for linear translations.  See role.direct. | ||||
|   spt: | ||||
|     A pageful of 64-bit sptes containing the translations for this page. | ||||
|     Accessed by both kvm and hardware. | ||||
|     The page pointed to by spt will have its page->private pointing back | ||||
|     at the shadow page structure. | ||||
|     sptes in spt point either at guest pages, or at lower-level shadow pages. | ||||
|     Specifically, if sp1 and sp2 are shadow pages, then sp1->spt[n] may point | ||||
|     at __pa(sp2->spt).  sp2 will point back at sp1 through parent_pte. | ||||
|     The spt array forms a DAG structure with the shadow page as a node, and | ||||
|     guest pages as leaves. | ||||
|   gfns: | ||||
|     An array of 512 guest frame numbers, one for each present pte.  Used to | ||||
|     perform a reverse map from a pte to a gfn. | ||||
|   slot_bitmap: | ||||
|     A bitmap containing one bit per memory slot.  If the page contains a pte | ||||
|     mapping a page from memory slot n, then bit n of slot_bitmap will be set | ||||
|     (if a page is aliased among several slots, then it is not guaranteed that | ||||
|     all slots will be marked). | ||||
|     Used during dirty logging to avoid scanning a shadow page if none if its | ||||
|     pages need tracking. | ||||
|   root_count: | ||||
|     A counter keeping track of how many hardware registers (guest cr3 or | ||||
|     pdptrs) are now pointing at the page.  While this counter is nonzero, the | ||||
|     page cannot be destroyed.  See role.invalid. | ||||
|   multimapped: | ||||
|     Whether there exist multiple sptes pointing at this page. | ||||
|   parent_pte/parent_ptes: | ||||
|     If multimapped is zero, parent_pte points at the single spte that points at | ||||
|     this page's spt.  Otherwise, parent_ptes points at a data structure | ||||
|     with a list of parent_ptes. | ||||
|   unsync: | ||||
|     If true, then the translations in this page may not match the guest's | ||||
|     translation.  This is equivalent to the state of the tlb when a pte is | ||||
|     changed but before the tlb entry is flushed.  Accordingly, unsync ptes | ||||
|     are synchronized when the guest executes invlpg or flushes its tlb by | ||||
|     other means.  Valid for leaf pages. | ||||
|   unsync_children: | ||||
|     How many sptes in the page point at pages that are unsync (or have | ||||
|     unsynchronized children). | ||||
|   unsync_child_bitmap: | ||||
|     A bitmap indicating which sptes in spt point (directly or indirectly) at | ||||
|     pages that may be unsynchronized.  Used to quickly locate all unsychronized | ||||
|     pages reachable from a given page. | ||||
| 
 | ||||
| Reverse map | ||||
| =========== | ||||
| 
 | ||||
| The mmu maintains a reverse mapping whereby all ptes mapping a page can be | ||||
| reached given its gfn.  This is used, for example, when swapping out a page. | ||||
| 
 | ||||
| Synchronized and unsynchronized pages | ||||
| ===================================== | ||||
| 
 | ||||
| The guest uses two events to synchronize its tlb and page tables: tlb flushes | ||||
| and page invalidations (invlpg). | ||||
| 
 | ||||
| A tlb flush means that we need to synchronize all sptes reachable from the | ||||
| guest's cr3.  This is expensive, so we keep all guest page tables write | ||||
| protected, and synchronize sptes to gptes when a gpte is written. | ||||
| 
 | ||||
| A special case is when a guest page table is reachable from the current | ||||
| guest cr3.  In this case, the guest is obliged to issue an invlpg instruction | ||||
| before using the translation.  We take advantage of that by removing write | ||||
| protection from the guest page, and allowing the guest to modify it freely. | ||||
| We synchronize modified gptes when the guest invokes invlpg.  This reduces | ||||
| the amount of emulation we have to do when the guest modifies multiple gptes, | ||||
| or when the a guest page is no longer used as a page table and is used for | ||||
| random guest data. | ||||
| 
 | ||||
| As a side effect we have to resynchronize all reachable unsynchronized shadow | ||||
| pages on a tlb flush. | ||||
| 
 | ||||
| 
 | ||||
| Reaction to events | ||||
| ================== | ||||
| 
 | ||||
| - guest page fault (or npt page fault, or ept violation) | ||||
| 
 | ||||
| This is the most complicated event.  The cause of a page fault can be: | ||||
| 
 | ||||
|   - a true guest fault (the guest translation won't allow the access) (*) | ||||
|   - access to a missing translation | ||||
|   - access to a protected translation | ||||
|     - when logging dirty pages, memory is write protected | ||||
|     - synchronized shadow pages are write protected (*) | ||||
|   - access to untranslatable memory (mmio) | ||||
| 
 | ||||
|   (*) not applicable in direct mode | ||||
| 
 | ||||
| Handling a page fault is performed as follows: | ||||
| 
 | ||||
|  - if needed, walk the guest page tables to determine the guest translation | ||||
|    (gva->gpa or ngpa->gpa) | ||||
|    - if permissions are insufficient, reflect the fault back to the guest | ||||
|  - determine the host page | ||||
|    - if this is an mmio request, there is no host page; call the emulator | ||||
|      to emulate the instruction instead | ||||
|  - walk the shadow page table to find the spte for the translation, | ||||
|    instantiating missing intermediate page tables as necessary | ||||
|  - try to unsynchronize the page | ||||
|    - if successful, we can let the guest continue and modify the gpte | ||||
|  - emulate the instruction | ||||
|    - if failed, unshadow the page and let the guest continue | ||||
|  - update any translations that were modified by the instruction | ||||
| 
 | ||||
| invlpg handling: | ||||
| 
 | ||||
|   - walk the shadow page hierarchy and drop affected translations | ||||
|   - try to reinstantiate the indicated translation in the hope that the | ||||
|     guest will use it in the near future | ||||
| 
 | ||||
| Guest control register updates: | ||||
| 
 | ||||
| - mov to cr3 | ||||
|   - look up new shadow roots | ||||
|   - synchronize newly reachable shadow pages | ||||
| 
 | ||||
| - mov to cr0/cr4/efer | ||||
|   - set up mmu context for new paging mode | ||||
|   - look up new shadow roots | ||||
|   - synchronize newly reachable shadow pages | ||||
| 
 | ||||
| Host translation updates: | ||||
| 
 | ||||
|   - mmu notifier called with updated hva | ||||
|   - look up affected sptes through reverse map | ||||
|   - drop (or update) translations | ||||
| 
 | ||||
| Further reading | ||||
| =============== | ||||
| 
 | ||||
| - NPT presentation from KVM Forum 2008 | ||||
|   http://www.linux-kvm.org/wiki/images/c/c8/KvmForum2008%24kdf2008_21.pdf | ||||
| 
 | ||||
| @ -979,11 +979,13 @@ long kvm_arch_vm_ioctl(struct file *filp, | ||||
| 		r = -EFAULT; | ||||
| 		if (copy_from_user(&irq_event, argp, sizeof irq_event)) | ||||
| 			goto out; | ||||
| 		r = -ENXIO; | ||||
| 		if (irqchip_in_kernel(kvm)) { | ||||
| 			__s32 status; | ||||
| 			status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, | ||||
| 				    irq_event.irq, irq_event.level); | ||||
| 			if (ioctl == KVM_IRQ_LINE_STATUS) { | ||||
| 				r = -EFAULT; | ||||
| 				irq_event.status = status; | ||||
| 				if (copy_to_user(argp, &irq_event, | ||||
| 							sizeof irq_event)) | ||||
| @ -1379,7 +1381,7 @@ static void kvm_release_vm_pages(struct kvm *kvm) | ||||
| 	int i, j; | ||||
| 	unsigned long base_gfn; | ||||
| 
 | ||||
| 	slots = rcu_dereference(kvm->memslots); | ||||
| 	slots = kvm_memslots(kvm); | ||||
| 	for (i = 0; i < slots->nmemslots; i++) { | ||||
| 		memslot = &slots->memslots[i]; | ||||
| 		base_gfn = memslot->base_gfn; | ||||
| @ -1535,8 +1537,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | ||||
| 			goto out; | ||||
| 
 | ||||
| 		if (copy_to_user(user_stack, stack, | ||||
| 				 sizeof(struct kvm_ia64_vcpu_stack))) | ||||
| 				 sizeof(struct kvm_ia64_vcpu_stack))) { | ||||
| 			r = -EFAULT; | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| @ -51,7 +51,7 @@ 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); | ||||
| 	return kvm_init(&vmm_info, 1024, 0, THIS_MODULE); | ||||
| } | ||||
| 
 | ||||
| static void __exit kvm_vmm_exit(void) | ||||
|  | ||||
| @ -21,6 +21,7 @@ | ||||
| /* operations for longs and pointers */ | ||||
| #define PPC_LL		stringify_in_c(ld) | ||||
| #define PPC_STL		stringify_in_c(std) | ||||
| #define PPC_STLU	stringify_in_c(stdu) | ||||
| #define PPC_LCMPI	stringify_in_c(cmpdi) | ||||
| #define PPC_LONG	stringify_in_c(.llong) | ||||
| #define PPC_LONG_ALIGN	stringify_in_c(.balign 8) | ||||
| @ -44,6 +45,7 @@ | ||||
| /* operations for longs and pointers */ | ||||
| #define PPC_LL		stringify_in_c(lwz) | ||||
| #define PPC_STL		stringify_in_c(stw) | ||||
| #define PPC_STLU	stringify_in_c(stwu) | ||||
| #define PPC_LCMPI	stringify_in_c(cmpwi) | ||||
| #define PPC_LONG	stringify_in_c(.long) | ||||
| #define PPC_LONG_ALIGN	stringify_in_c(.balign 4) | ||||
|  | ||||
| @ -77,4 +77,14 @@ struct kvm_debug_exit_arch { | ||||
| struct kvm_guest_debug_arch { | ||||
| }; | ||||
| 
 | ||||
| #define KVM_REG_MASK		0x001f | ||||
| #define KVM_REG_EXT_MASK	0xffe0 | ||||
| #define KVM_REG_GPR		0x0000 | ||||
| #define KVM_REG_FPR		0x0020 | ||||
| #define KVM_REG_QPR		0x0040 | ||||
| #define KVM_REG_FQPR		0x0060 | ||||
| 
 | ||||
| #define KVM_INTERRUPT_SET	-1U | ||||
| #define KVM_INTERRUPT_UNSET	-2U | ||||
| 
 | ||||
| #endif /* __LINUX_KVM_POWERPC_H */ | ||||
|  | ||||
| @ -88,6 +88,8 @@ | ||||
| 
 | ||||
| #define BOOK3S_HFLAG_DCBZ32			0x1 | ||||
| #define BOOK3S_HFLAG_SLB			0x2 | ||||
| #define BOOK3S_HFLAG_PAIRED_SINGLE		0x4 | ||||
| #define BOOK3S_HFLAG_NATIVE_PS			0x8 | ||||
| 
 | ||||
| #define RESUME_FLAG_NV          (1<<0)  /* Reload guest nonvolatile state? */ | ||||
| #define RESUME_FLAG_HOST        (1<<1)  /* Resume host? */ | ||||
|  | ||||
| @ -22,46 +22,47 @@ | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| #include <linux/kvm_host.h> | ||||
| #include <asm/kvm_book3s_64_asm.h> | ||||
| #include <asm/kvm_book3s_asm.h> | ||||
| 
 | ||||
| struct kvmppc_slb { | ||||
| 	u64 esid; | ||||
| 	u64 vsid; | ||||
| 	u64 orige; | ||||
| 	u64 origv; | ||||
| 	bool valid; | ||||
| 	bool Ks; | ||||
| 	bool Kp; | ||||
| 	bool nx; | ||||
| 	bool large;	/* PTEs are 16MB */ | ||||
| 	bool tb;	/* 1TB segment */ | ||||
| 	bool class; | ||||
| 	bool valid	: 1; | ||||
| 	bool Ks		: 1; | ||||
| 	bool Kp		: 1; | ||||
| 	bool nx		: 1; | ||||
| 	bool large	: 1;	/* PTEs are 16MB */ | ||||
| 	bool tb		: 1;	/* 1TB segment */ | ||||
| 	bool class	: 1; | ||||
| }; | ||||
| 
 | ||||
| struct kvmppc_sr { | ||||
| 	u32 raw; | ||||
| 	u32 vsid; | ||||
| 	bool Ks; | ||||
| 	bool Kp; | ||||
| 	bool nx; | ||||
| 	bool Ks		: 1; | ||||
| 	bool Kp		: 1; | ||||
| 	bool nx		: 1; | ||||
| 	bool valid	: 1; | ||||
| }; | ||||
| 
 | ||||
| struct kvmppc_bat { | ||||
| 	u64 raw; | ||||
| 	u32 bepi; | ||||
| 	u32 bepi_mask; | ||||
| 	bool vs; | ||||
| 	bool vp; | ||||
| 	u32 brpn; | ||||
| 	u8 wimg; | ||||
| 	u8 pp; | ||||
| 	bool vs		: 1; | ||||
| 	bool vp		: 1; | ||||
| }; | ||||
| 
 | ||||
| struct kvmppc_sid_map { | ||||
| 	u64 guest_vsid; | ||||
| 	u64 guest_esid; | ||||
| 	u64 host_vsid; | ||||
| 	bool valid; | ||||
| 	bool valid	: 1; | ||||
| }; | ||||
| 
 | ||||
| #define SID_MAP_BITS    9 | ||||
| @ -70,7 +71,7 @@ struct kvmppc_sid_map { | ||||
| 
 | ||||
| struct kvmppc_vcpu_book3s { | ||||
| 	struct kvm_vcpu vcpu; | ||||
| 	struct kvmppc_book3s_shadow_vcpu shadow_vcpu; | ||||
| 	struct kvmppc_book3s_shadow_vcpu *shadow_vcpu; | ||||
| 	struct kvmppc_sid_map sid_map[SID_MAP_NUM]; | ||||
| 	struct kvmppc_slb slb[64]; | ||||
| 	struct { | ||||
| @ -82,9 +83,10 @@ struct kvmppc_vcpu_book3s { | ||||
| 	struct kvmppc_bat ibat[8]; | ||||
| 	struct kvmppc_bat dbat[8]; | ||||
| 	u64 hid[6]; | ||||
| 	u64 gqr[8]; | ||||
| 	int slb_nr; | ||||
| 	u32 dsisr; | ||||
| 	u64 sdr1; | ||||
| 	u64 dsisr; | ||||
| 	u64 hior; | ||||
| 	u64 msr_mask; | ||||
| 	u64 vsid_first; | ||||
| @ -98,15 +100,15 @@ struct kvmppc_vcpu_book3s { | ||||
| #define CONTEXT_GUEST		1 | ||||
| #define CONTEXT_GUEST_END	2 | ||||
| 
 | ||||
| #define VSID_REAL	0xfffffffffff00000 | ||||
| #define VSID_REAL_DR	0xffffffffffe00000 | ||||
| #define VSID_REAL_IR	0xffffffffffd00000 | ||||
| #define VSID_BAT	0xffffffffffc00000 | ||||
| #define VSID_PR		0x8000000000000000 | ||||
| #define VSID_REAL	0x1fffffffffc00000ULL | ||||
| #define VSID_BAT	0x1fffffffffb00000ULL | ||||
| #define VSID_REAL_DR	0x2000000000000000ULL | ||||
| #define VSID_REAL_IR	0x4000000000000000ULL | ||||
| #define VSID_PR		0x8000000000000000ULL | ||||
| 
 | ||||
| extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, u64 ea, u64 ea_mask); | ||||
| extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong ea, ulong ea_mask); | ||||
| extern void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 vp, u64 vp_mask); | ||||
| extern void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, u64 pa_start, u64 pa_end); | ||||
| extern void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end); | ||||
| extern void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 new_msr); | ||||
| extern void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu); | ||||
| extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu); | ||||
| @ -114,11 +116,13 @@ extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte); | ||||
| extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr); | ||||
| extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu); | ||||
| extern struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data); | ||||
| extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr, bool data); | ||||
| extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr); | ||||
| extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data); | ||||
| extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data); | ||||
| extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec); | ||||
| extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, | ||||
| 			   bool upper, u32 val); | ||||
| extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr); | ||||
| extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
| extern u32 kvmppc_trampoline_lowmem; | ||||
| extern u32 kvmppc_trampoline_enter; | ||||
| @ -126,6 +130,8 @@ extern void kvmppc_rmcall(ulong srr0, ulong srr1); | ||||
| extern void kvmppc_load_up_fpu(void); | ||||
| extern void kvmppc_load_up_altivec(void); | ||||
| extern void kvmppc_load_up_vsx(void); | ||||
| extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst); | ||||
| extern ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst); | ||||
| 
 | ||||
| static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| @ -140,7 +146,108 @@ static inline ulong dsisr(void) | ||||
| } | ||||
| 
 | ||||
| extern void kvm_return_point(void); | ||||
| static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
| static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val) | ||||
| { | ||||
| 	if ( num < 14 ) { | ||||
| 		to_svcpu(vcpu)->gpr[num] = val; | ||||
| 		to_book3s(vcpu)->shadow_vcpu->gpr[num] = val; | ||||
| 	} else | ||||
| 		vcpu->arch.gpr[num] = val; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num) | ||||
| { | ||||
| 	if ( num < 14 ) | ||||
| 		return to_svcpu(vcpu)->gpr[num]; | ||||
| 	else | ||||
| 		return vcpu->arch.gpr[num]; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val) | ||||
| { | ||||
| 	to_svcpu(vcpu)->cr = val; | ||||
| 	to_book3s(vcpu)->shadow_vcpu->cr = val; | ||||
| } | ||||
| 
 | ||||
| static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return to_svcpu(vcpu)->cr; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val) | ||||
| { | ||||
| 	to_svcpu(vcpu)->xer = val; | ||||
| 	to_book3s(vcpu)->shadow_vcpu->xer = val; | ||||
| } | ||||
| 
 | ||||
| static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return to_svcpu(vcpu)->xer; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val) | ||||
| { | ||||
| 	to_svcpu(vcpu)->ctr = val; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return to_svcpu(vcpu)->ctr; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val) | ||||
| { | ||||
| 	to_svcpu(vcpu)->lr = val; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return to_svcpu(vcpu)->lr; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val) | ||||
| { | ||||
| 	to_svcpu(vcpu)->pc = val; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return to_svcpu(vcpu)->pc; | ||||
| } | ||||
| 
 | ||||
| static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	ulong pc = kvmppc_get_pc(vcpu); | ||||
| 	struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu); | ||||
| 
 | ||||
| 	/* Load the instruction manually if it failed to do so in the
 | ||||
| 	 * exit path */ | ||||
| 	if (svcpu->last_inst == KVM_INST_FETCH_FAILED) | ||||
| 		kvmppc_ld(vcpu, &pc, sizeof(u32), &svcpu->last_inst, false); | ||||
| 
 | ||||
| 	return svcpu->last_inst; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return to_svcpu(vcpu)->fault_dar; | ||||
| } | ||||
| 
 | ||||
| /* Magic register values loaded into r3 and r4 before the 'sc' assembly
 | ||||
|  * instruction for the OSI hypercalls */ | ||||
| #define OSI_SC_MAGIC_R3			0x113724FA | ||||
| #define OSI_SC_MAGIC_R4			0x77810F9B | ||||
| 
 | ||||
| #define INS_DCBZ			0x7c0007ec | ||||
| 
 | ||||
| /* Also add subarch specific defines */ | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S_32 | ||||
| #include <asm/kvm_book3s_32.h> | ||||
| #else | ||||
| #include <asm/kvm_book3s_64.h> | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __ASM_KVM_BOOK3S_H__ */ | ||||
|  | ||||
							
								
								
									
										42
									
								
								arch/powerpc/include/asm/kvm_book3s_32.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								arch/powerpc/include/asm/kvm_book3s_32.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| /*
 | ||||
|  * 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 SUSE Linux Products GmbH 2010 | ||||
|  * | ||||
|  * Authors: Alexander Graf <agraf@suse.de> | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __ASM_KVM_BOOK3S_32_H__ | ||||
| #define __ASM_KVM_BOOK3S_32_H__ | ||||
| 
 | ||||
| static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return to_book3s(vcpu)->shadow_vcpu; | ||||
| } | ||||
| 
 | ||||
| #define PTE_SIZE	12 | ||||
| #define VSID_ALL	0 | ||||
| #define SR_INVALID	0x00000001	/* VSID 1 should always be unused */ | ||||
| #define SR_KP		0x20000000 | ||||
| #define PTE_V		0x80000000 | ||||
| #define PTE_SEC		0x00000040 | ||||
| #define PTE_M		0x00000010 | ||||
| #define PTE_R		0x00000100 | ||||
| #define PTE_C		0x00000080 | ||||
| 
 | ||||
| #define SID_SHIFT	28 | ||||
| #define ESID_MASK	0xf0000000 | ||||
| #define VSID_MASK	0x00fffffff0000000ULL | ||||
| 
 | ||||
| #endif /* __ASM_KVM_BOOK3S_32_H__ */ | ||||
							
								
								
									
										28
									
								
								arch/powerpc/include/asm/kvm_book3s_64.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								arch/powerpc/include/asm/kvm_book3s_64.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| /*
 | ||||
|  * 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 SUSE Linux Products GmbH 2010 | ||||
|  * | ||||
|  * Authors: Alexander Graf <agraf@suse.de> | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __ASM_KVM_BOOK3S_64_H__ | ||||
| #define __ASM_KVM_BOOK3S_64_H__ | ||||
| 
 | ||||
| static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return &get_paca()->shadow_vcpu; | ||||
| } | ||||
| 
 | ||||
| #endif /* __ASM_KVM_BOOK3S_64_H__ */ | ||||
| @ -22,7 +22,7 @@ | ||||
| 
 | ||||
| #ifdef __ASSEMBLY__ | ||||
| 
 | ||||
| #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||||
| #ifdef CONFIG_KVM_BOOK3S_HANDLER | ||||
| 
 | ||||
| #include <asm/kvm_asm.h> | ||||
| 
 | ||||
| @ -55,7 +55,7 @@ kvmppc_resume_\intno: | ||||
| .macro DO_KVM intno | ||||
| .endm | ||||
| 
 | ||||
| #endif /* CONFIG_KVM_BOOK3S_64_HANDLER */ | ||||
| #endif /* CONFIG_KVM_BOOK3S_HANDLER */ | ||||
| 
 | ||||
| #else  /*__ASSEMBLY__ */ | ||||
| 
 | ||||
| @ -63,12 +63,33 @@ struct kvmppc_book3s_shadow_vcpu { | ||||
| 	ulong gpr[14]; | ||||
| 	u32 cr; | ||||
| 	u32 xer; | ||||
| 
 | ||||
| 	u32 fault_dsisr; | ||||
| 	u32 last_inst; | ||||
| 	ulong ctr; | ||||
| 	ulong lr; | ||||
| 	ulong pc; | ||||
| 	ulong shadow_srr1; | ||||
| 	ulong fault_dar; | ||||
| 
 | ||||
| 	ulong host_r1; | ||||
| 	ulong host_r2; | ||||
| 	ulong handler; | ||||
| 	ulong scratch0; | ||||
| 	ulong scratch1; | ||||
| 	ulong vmhandler; | ||||
| 	u8 in_guest; | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S_32 | ||||
| 	u32     sr[16];			/* Guest SRs */ | ||||
| #endif | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| 	u8 slb_max;			/* highest used guest slb entry */ | ||||
| 	struct  { | ||||
| 		u64     esid; | ||||
| 		u64     vsid; | ||||
| 	} slb[64];			/* guest SLB */ | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| #endif /*__ASSEMBLY__ */ | ||||
							
								
								
									
										96
									
								
								arch/powerpc/include/asm/kvm_booke.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								arch/powerpc/include/asm/kvm_booke.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,96 @@ | ||||
| /*
 | ||||
|  * 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 SUSE Linux Products GmbH 2010 | ||||
|  * | ||||
|  * Authors: Alexander Graf <agraf@suse.de> | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __ASM_KVM_BOOKE_H__ | ||||
| #define __ASM_KVM_BOOKE_H__ | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| #include <linux/kvm_host.h> | ||||
| 
 | ||||
| static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val) | ||||
| { | ||||
| 	vcpu->arch.gpr[num] = val; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num) | ||||
| { | ||||
| 	return vcpu->arch.gpr[num]; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val) | ||||
| { | ||||
| 	vcpu->arch.cr = val; | ||||
| } | ||||
| 
 | ||||
| static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return vcpu->arch.cr; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val) | ||||
| { | ||||
| 	vcpu->arch.xer = val; | ||||
| } | ||||
| 
 | ||||
| static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return vcpu->arch.xer; | ||||
| } | ||||
| 
 | ||||
| static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return vcpu->arch.last_inst; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val) | ||||
| { | ||||
| 	vcpu->arch.ctr = val; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return vcpu->arch.ctr; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val) | ||||
| { | ||||
| 	vcpu->arch.lr = val; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return vcpu->arch.lr; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val) | ||||
| { | ||||
| 	vcpu->arch.pc = val; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return vcpu->arch.pc; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return vcpu->arch.fault_dear; | ||||
| } | ||||
| 
 | ||||
| #endif /* __ASM_KVM_BOOKE_H__ */ | ||||
							
								
								
									
										85
									
								
								arch/powerpc/include/asm/kvm_fpu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								arch/powerpc/include/asm/kvm_fpu.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| /*
 | ||||
|  * 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 Novell Inc. 2010 | ||||
|  * | ||||
|  * Authors: Alexander Graf <agraf@suse.de> | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __ASM_KVM_FPU_H__ | ||||
| #define __ASM_KVM_FPU_H__ | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| extern void fps_fres(struct thread_struct *t, u32 *dst, u32 *src1); | ||||
| extern void fps_frsqrte(struct thread_struct *t, u32 *dst, u32 *src1); | ||||
| extern void fps_fsqrts(struct thread_struct *t, u32 *dst, u32 *src1); | ||||
| 
 | ||||
| extern void fps_fadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2); | ||||
| extern void fps_fdivs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2); | ||||
| extern void fps_fmuls(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2); | ||||
| extern void fps_fsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2); | ||||
| 
 | ||||
| extern void fps_fmadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2, | ||||
| 		       u32 *src3); | ||||
| extern void fps_fmsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2, | ||||
| 		       u32 *src3); | ||||
| extern void fps_fnmadds(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2, | ||||
| 		        u32 *src3); | ||||
| extern void fps_fnmsubs(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2, | ||||
| 		        u32 *src3); | ||||
| extern void fps_fsel(struct thread_struct *t, u32 *dst, u32 *src1, u32 *src2, | ||||
| 		     u32 *src3); | ||||
| 
 | ||||
| #define FPD_ONE_IN(name) extern void fpd_ ## name(u64 *fpscr, u32 *cr, \ | ||||
| 				u64 *dst, u64 *src1); | ||||
| #define FPD_TWO_IN(name) extern void fpd_ ## name(u64 *fpscr, u32 *cr, \ | ||||
| 				u64 *dst, u64 *src1, u64 *src2); | ||||
| #define FPD_THREE_IN(name) extern void fpd_ ## name(u64 *fpscr, u32 *cr, \ | ||||
| 				u64 *dst, u64 *src1, u64 *src2, u64 *src3); | ||||
| 
 | ||||
| extern void fpd_fcmpu(u64 *fpscr, u32 *cr, u64 *src1, u64 *src2); | ||||
| extern void fpd_fcmpo(u64 *fpscr, u32 *cr, u64 *src1, u64 *src2); | ||||
| 
 | ||||
| FPD_ONE_IN(fsqrts) | ||||
| FPD_ONE_IN(frsqrtes) | ||||
| FPD_ONE_IN(fres) | ||||
| FPD_ONE_IN(frsp) | ||||
| FPD_ONE_IN(fctiw) | ||||
| FPD_ONE_IN(fctiwz) | ||||
| FPD_ONE_IN(fsqrt) | ||||
| FPD_ONE_IN(fre) | ||||
| FPD_ONE_IN(frsqrte) | ||||
| FPD_ONE_IN(fneg) | ||||
| FPD_ONE_IN(fabs) | ||||
| FPD_TWO_IN(fadds) | ||||
| FPD_TWO_IN(fsubs) | ||||
| FPD_TWO_IN(fdivs) | ||||
| FPD_TWO_IN(fmuls) | ||||
| FPD_TWO_IN(fcpsgn) | ||||
| FPD_TWO_IN(fdiv) | ||||
| FPD_TWO_IN(fadd) | ||||
| FPD_TWO_IN(fmul) | ||||
| FPD_TWO_IN(fsub) | ||||
| FPD_THREE_IN(fmsubs) | ||||
| FPD_THREE_IN(fmadds) | ||||
| FPD_THREE_IN(fnmsubs) | ||||
| FPD_THREE_IN(fnmadds) | ||||
| FPD_THREE_IN(fsel) | ||||
| FPD_THREE_IN(fmsub) | ||||
| FPD_THREE_IN(fmadd) | ||||
| FPD_THREE_IN(fnmsub) | ||||
| FPD_THREE_IN(fnmadd) | ||||
| 
 | ||||
| #endif | ||||
| @ -66,7 +66,7 @@ struct kvm_vcpu_stat { | ||||
| 	u32 dec_exits; | ||||
| 	u32 ext_intr_exits; | ||||
| 	u32 halt_wakeup; | ||||
| #ifdef CONFIG_PPC64 | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| 	u32 pf_storage; | ||||
| 	u32 pf_instruc; | ||||
| 	u32 sp_storage; | ||||
| @ -124,12 +124,12 @@ struct kvm_arch { | ||||
| }; | ||||
| 
 | ||||
| struct kvmppc_pte { | ||||
| 	u64 eaddr; | ||||
| 	ulong eaddr; | ||||
| 	u64 vpage; | ||||
| 	u64 raddr; | ||||
| 	bool may_read; | ||||
| 	bool may_write; | ||||
| 	bool may_execute; | ||||
| 	ulong raddr; | ||||
| 	bool may_read		: 1; | ||||
| 	bool may_write		: 1; | ||||
| 	bool may_execute	: 1; | ||||
| }; | ||||
| 
 | ||||
| struct kvmppc_mmu { | ||||
| @ -145,7 +145,7 @@ struct kvmppc_mmu { | ||||
| 	int  (*xlate)(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *pte, bool data); | ||||
| 	void (*reset_msr)(struct kvm_vcpu *vcpu); | ||||
| 	void (*tlbie)(struct kvm_vcpu *vcpu, ulong addr, bool large); | ||||
| 	int  (*esid_to_vsid)(struct kvm_vcpu *vcpu, u64 esid, u64 *vsid); | ||||
| 	int  (*esid_to_vsid)(struct kvm_vcpu *vcpu, ulong esid, u64 *vsid); | ||||
| 	u64  (*ea_to_vp)(struct kvm_vcpu *vcpu, gva_t eaddr, bool data); | ||||
| 	bool (*is_dcbz32)(struct kvm_vcpu *vcpu); | ||||
| }; | ||||
| @ -160,7 +160,7 @@ struct hpte_cache { | ||||
| struct kvm_vcpu_arch { | ||||
| 	ulong host_stack; | ||||
| 	u32 host_pid; | ||||
| #ifdef CONFIG_PPC64 | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| 	ulong host_msr; | ||||
| 	ulong host_r2; | ||||
| 	void *host_retip; | ||||
| @ -175,7 +175,7 @@ struct kvm_vcpu_arch { | ||||
| 	ulong gpr[32]; | ||||
| 
 | ||||
| 	u64 fpr[32]; | ||||
| 	u32 fpscr; | ||||
| 	u64 fpscr; | ||||
| 
 | ||||
| #ifdef CONFIG_ALTIVEC | ||||
| 	vector128 vr[32]; | ||||
| @ -186,19 +186,23 @@ struct kvm_vcpu_arch { | ||||
| 	u64 vsr[32]; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| 	/* For Gekko paired singles */ | ||||
| 	u32 qpr[32]; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_BOOKE | ||||
| 	ulong pc; | ||||
| 	ulong ctr; | ||||
| 	ulong lr; | ||||
| 
 | ||||
| #ifdef CONFIG_BOOKE | ||||
| 	ulong xer; | ||||
| 	u32 cr; | ||||
| #endif | ||||
| 
 | ||||
| 	ulong msr; | ||||
| #ifdef CONFIG_PPC64 | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| 	ulong shadow_msr; | ||||
| 	ulong shadow_srr1; | ||||
| 	ulong hflags; | ||||
| 	ulong guest_owned_ext; | ||||
| #endif | ||||
| @ -253,20 +257,22 @@ struct kvm_vcpu_arch { | ||||
| 	struct dentry *debugfs_exit_timing; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_BOOKE | ||||
| 	u32 last_inst; | ||||
| #ifdef CONFIG_PPC64 | ||||
| 	ulong fault_dsisr; | ||||
| #endif | ||||
| 	ulong fault_dear; | ||||
| 	ulong fault_esr; | ||||
| 	ulong queued_dear; | ||||
| 	ulong queued_esr; | ||||
| #endif | ||||
| 	gpa_t paddr_accessed; | ||||
| 
 | ||||
| 	u8 io_gpr; /* GPR used as IO source/target */ | ||||
| 	u8 mmio_is_bigendian; | ||||
| 	u8 mmio_sign_extend; | ||||
| 	u8 dcr_needed; | ||||
| 	u8 dcr_is_write; | ||||
| 	u8 osi_needed; | ||||
| 	u8 osi_enabled; | ||||
| 
 | ||||
| 	u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ | ||||
| 
 | ||||
| @ -275,7 +281,7 @@ struct kvm_vcpu_arch { | ||||
| 	u64 dec_jiffies; | ||||
| 	unsigned long pending_exceptions; | ||||
| 
 | ||||
| #ifdef CONFIG_PPC64 | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| 	struct hpte_cache hpte_cache[HPTEG_CACHE_NUM]; | ||||
| 	int hpte_cache_offset; | ||||
| #endif | ||||
|  | ||||
| @ -30,6 +30,8 @@ | ||||
| #include <linux/kvm_host.h> | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| #include <asm/kvm_book3s.h> | ||||
| #else | ||||
| #include <asm/kvm_booke.h> | ||||
| #endif | ||||
| 
 | ||||
| enum emulation_result { | ||||
| @ -37,6 +39,7 @@ enum emulation_result { | ||||
| 	EMULATE_DO_MMIO,      /* kvm_run filled with MMIO request */ | ||||
| 	EMULATE_DO_DCR,       /* kvm_run filled with DCR request */ | ||||
| 	EMULATE_FAIL,         /* can't emulate this instruction */ | ||||
| 	EMULATE_AGAIN,        /* something went wrong. go again */ | ||||
| }; | ||||
| 
 | ||||
| extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); | ||||
| @ -48,8 +51,11 @@ extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu); | ||||
| extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
|                               unsigned int rt, unsigned int bytes, | ||||
|                               int is_bigendian); | ||||
| extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
|                                unsigned int rt, unsigned int bytes, | ||||
|                                int is_bigendian); | ||||
| extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
|                                u32 val, unsigned int bytes, int is_bigendian); | ||||
|                                u64 val, unsigned int bytes, int is_bigendian); | ||||
| 
 | ||||
| extern int kvmppc_emulate_instruction(struct kvm_run *run, | ||||
|                                       struct kvm_vcpu *vcpu); | ||||
| @ -63,6 +69,7 @@ extern void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, | ||||
| extern void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode); | ||||
| extern void kvmppc_mmu_switch_pid(struct kvm_vcpu *vcpu, u32 pid); | ||||
| extern void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu); | ||||
| extern int kvmppc_mmu_init(struct kvm_vcpu *vcpu); | ||||
| extern int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr); | ||||
| extern int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr); | ||||
| extern gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int gtlb_index, | ||||
| @ -88,6 +95,8 @@ extern void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu); | ||||
| extern void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu); | ||||
| extern void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, | ||||
|                                        struct kvm_interrupt *irq); | ||||
| extern void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, | ||||
|                                          struct kvm_interrupt *irq); | ||||
| 
 | ||||
| extern int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
|                                   unsigned int op, int *advance); | ||||
| @ -99,81 +108,37 @@ extern void kvmppc_booke_exit(void); | ||||
| 
 | ||||
| extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| 
 | ||||
| /* We assume we're always acting on the current vcpu */ | ||||
| 
 | ||||
| static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val) | ||||
| /*
 | ||||
|  * Cuts out inst bits with ordering according to spec. | ||||
|  * That means the leftmost bit is zero. All given bits are included. | ||||
|  */ | ||||
| static inline u32 kvmppc_get_field(u64 inst, int msb, int lsb) | ||||
| { | ||||
| 	if ( num < 14 ) { | ||||
| 		get_paca()->shadow_vcpu.gpr[num] = val; | ||||
| 		to_book3s(vcpu)->shadow_vcpu.gpr[num] = val; | ||||
| 	} else | ||||
| 		vcpu->arch.gpr[num] = val; | ||||
| 	u32 r; | ||||
| 	u32 mask; | ||||
| 
 | ||||
| 	BUG_ON(msb > lsb); | ||||
| 
 | ||||
| 	mask = (1 << (lsb - msb + 1)) - 1; | ||||
| 	r = (inst >> (63 - lsb)) & mask; | ||||
| 
 | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num) | ||||
| /*
 | ||||
|  * Replaces inst bits with ordering according to spec. | ||||
|  */ | ||||
| static inline u32 kvmppc_set_field(u64 inst, int msb, int lsb, int value) | ||||
| { | ||||
| 	if ( num < 14 ) | ||||
| 		return get_paca()->shadow_vcpu.gpr[num]; | ||||
| 	else | ||||
| 		return vcpu->arch.gpr[num]; | ||||
| 	u32 r; | ||||
| 	u32 mask; | ||||
| 
 | ||||
| 	BUG_ON(msb > lsb); | ||||
| 
 | ||||
| 	mask = ((1 << (lsb - msb + 1)) - 1) << (63 - lsb); | ||||
| 	r = (inst & ~mask) | ((value << (63 - lsb)) & mask); | ||||
| 
 | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val) | ||||
| { | ||||
| 	get_paca()->shadow_vcpu.cr = val; | ||||
| 	to_book3s(vcpu)->shadow_vcpu.cr = val; | ||||
| } | ||||
| 
 | ||||
| static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return get_paca()->shadow_vcpu.cr; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val) | ||||
| { | ||||
| 	get_paca()->shadow_vcpu.xer = val; | ||||
| 	to_book3s(vcpu)->shadow_vcpu.xer = val; | ||||
| } | ||||
| 
 | ||||
| static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return get_paca()->shadow_vcpu.xer; | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val) | ||||
| { | ||||
| 	vcpu->arch.gpr[num] = val; | ||||
| } | ||||
| 
 | ||||
| static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num) | ||||
| { | ||||
| 	return vcpu->arch.gpr[num]; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val) | ||||
| { | ||||
| 	vcpu->arch.cr = val; | ||||
| } | ||||
| 
 | ||||
| static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return vcpu->arch.cr; | ||||
| } | ||||
| 
 | ||||
| static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val) | ||||
| { | ||||
| 	vcpu->arch.xer = val; | ||||
| } | ||||
| 
 | ||||
| static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return vcpu->arch.xer; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __POWERPC_KVM_PPC_H__ */ | ||||
|  | ||||
| @ -27,6 +27,8 @@ extern int __init_new_context(void); | ||||
| extern void __destroy_context(int context_id); | ||||
| static inline void mmu_context_init(void) { } | ||||
| #else | ||||
| extern unsigned long __init_new_context(void); | ||||
| extern void __destroy_context(unsigned long context_id); | ||||
| extern void mmu_context_init(void); | ||||
| #endif | ||||
| 
 | ||||
|  | ||||
| @ -23,7 +23,7 @@ | ||||
| #include <asm/page.h> | ||||
| #include <asm/exception-64e.h> | ||||
| #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||||
| #include <asm/kvm_book3s_64_asm.h> | ||||
| #include <asm/kvm_book3s_asm.h> | ||||
| #endif | ||||
| 
 | ||||
| register struct paca_struct *local_paca asm("r13"); | ||||
| @ -137,15 +137,9 @@ struct paca_struct { | ||||
| 	u64 startpurr;			/* PURR/TB value snapshot */ | ||||
| 	u64 startspurr;			/* SPURR value snapshot */ | ||||
| 
 | ||||
| #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||||
| 	struct  { | ||||
| 		u64     esid; | ||||
| 		u64     vsid; | ||||
| 	} kvm_slb[64];			/* guest SLB */ | ||||
| #ifdef CONFIG_KVM_BOOK3S_HANDLER | ||||
| 	/* We use this to store guest state in */ | ||||
| 	struct kvmppc_book3s_shadow_vcpu shadow_vcpu; | ||||
| 	u8 kvm_slb_max;			/* highest used guest slb entry */ | ||||
| 	u8 kvm_in_guest;		/* are we inside the guest? */ | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -229,6 +229,9 @@ struct thread_struct { | ||||
| 	unsigned long	spefscr;	/* SPE & eFP status */ | ||||
| 	int		used_spe;	/* set if process has used spe */ | ||||
| #endif /* CONFIG_SPE */ | ||||
| #ifdef CONFIG_KVM_BOOK3S_32_HANDLER | ||||
| 	void*		kvm_shadow_vcpu; /* KVM internal data */ | ||||
| #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */ | ||||
| }; | ||||
| 
 | ||||
| #define ARCH_MIN_TASKALIGN 16 | ||||
|  | ||||
| @ -293,10 +293,12 @@ | ||||
| #define HID1_ABE	(1<<10)		/* 7450 Address Broadcast Enable */ | ||||
| #define HID1_PS		(1<<16)		/* 750FX PLL selection */ | ||||
| #define SPRN_HID2	0x3F8		/* Hardware Implementation Register 2 */ | ||||
| #define SPRN_HID2_GEKKO	0x398		/* Gekko HID2 Register */ | ||||
| #define SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */ | ||||
| #define SPRN_IABR2	0x3FA		/* 83xx */ | ||||
| #define SPRN_IBCR	0x135		/* 83xx Insn Breakpoint Control Reg */ | ||||
| #define SPRN_HID4	0x3F4		/* 970 HID4 */ | ||||
| #define SPRN_HID4_GEKKO	0x3F3		/* Gekko HID4 */ | ||||
| #define SPRN_HID5	0x3F6		/* 970 HID5 */ | ||||
| #define SPRN_HID6	0x3F9	/* BE HID 6 */ | ||||
| #define   HID6_LB	(0x0F<<12) /* Concurrent Large Page Modes */ | ||||
| @ -465,6 +467,14 @@ | ||||
| #define SPRN_VRSAVE	0x100	/* Vector Register Save Register */ | ||||
| #define SPRN_XER	0x001	/* Fixed Point Exception Register */ | ||||
| 
 | ||||
| #define SPRN_MMCR0_GEKKO 0x3B8 /* Gekko Monitor Mode Control Register 0 */ | ||||
| #define SPRN_MMCR1_GEKKO 0x3BC /* Gekko Monitor Mode Control Register 1 */ | ||||
| #define SPRN_PMC1_GEKKO  0x3B9 /* Gekko Performance Monitor Control 1 */ | ||||
| #define SPRN_PMC2_GEKKO  0x3BA /* Gekko Performance Monitor Control 2 */ | ||||
| #define SPRN_PMC3_GEKKO  0x3BD /* Gekko Performance Monitor Control 3 */ | ||||
| #define SPRN_PMC4_GEKKO  0x3BE /* Gekko Performance Monitor Control 4 */ | ||||
| #define SPRN_WPAR_GEKKO  0x399 /* Gekko Write Pipe Address Register */ | ||||
| 
 | ||||
| #define SPRN_SCOMC	0x114	/* SCOM Access Control */ | ||||
| #define SPRN_SCOMD	0x115	/* SCOM Access DATA */ | ||||
| 
 | ||||
|  | ||||
| @ -50,6 +50,9 @@ | ||||
| #endif | ||||
| #ifdef CONFIG_KVM | ||||
| #include <linux/kvm_host.h> | ||||
| #ifndef CONFIG_BOOKE | ||||
| #include <asm/kvm_book3s.h> | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_PPC32 | ||||
| @ -105,6 +108,9 @@ int main(void) | ||||
| 	DEFINE(THREAD_USED_SPE, offsetof(struct thread_struct, used_spe)); | ||||
| #endif /* CONFIG_SPE */ | ||||
| #endif /* CONFIG_PPC64 */ | ||||
| #ifdef CONFIG_KVM_BOOK3S_32_HANDLER | ||||
| 	DEFINE(THREAD_KVM_SVCPU, offsetof(struct thread_struct, kvm_shadow_vcpu)); | ||||
| #endif | ||||
| 
 | ||||
| 	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | ||||
| 	DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); | ||||
| @ -191,33 +197,9 @@ int main(void) | ||||
| 	DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset)); | ||||
| 	DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save)); | ||||
| #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||||
| 	DEFINE(PACA_KVM_IN_GUEST, offsetof(struct paca_struct, kvm_in_guest)); | ||||
| 	DEFINE(PACA_KVM_SLB, offsetof(struct paca_struct, kvm_slb)); | ||||
| 	DEFINE(PACA_KVM_SLB_MAX, offsetof(struct paca_struct, kvm_slb_max)); | ||||
| 	DEFINE(PACA_KVM_CR, offsetof(struct paca_struct, shadow_vcpu.cr)); | ||||
| 	DEFINE(PACA_KVM_XER, offsetof(struct paca_struct, shadow_vcpu.xer)); | ||||
| 	DEFINE(PACA_KVM_R0, offsetof(struct paca_struct, shadow_vcpu.gpr[0])); | ||||
| 	DEFINE(PACA_KVM_R1, offsetof(struct paca_struct, shadow_vcpu.gpr[1])); | ||||
| 	DEFINE(PACA_KVM_R2, offsetof(struct paca_struct, shadow_vcpu.gpr[2])); | ||||
| 	DEFINE(PACA_KVM_R3, offsetof(struct paca_struct, shadow_vcpu.gpr[3])); | ||||
| 	DEFINE(PACA_KVM_R4, offsetof(struct paca_struct, shadow_vcpu.gpr[4])); | ||||
| 	DEFINE(PACA_KVM_R5, offsetof(struct paca_struct, shadow_vcpu.gpr[5])); | ||||
| 	DEFINE(PACA_KVM_R6, offsetof(struct paca_struct, shadow_vcpu.gpr[6])); | ||||
| 	DEFINE(PACA_KVM_R7, offsetof(struct paca_struct, shadow_vcpu.gpr[7])); | ||||
| 	DEFINE(PACA_KVM_R8, offsetof(struct paca_struct, shadow_vcpu.gpr[8])); | ||||
| 	DEFINE(PACA_KVM_R9, offsetof(struct paca_struct, shadow_vcpu.gpr[9])); | ||||
| 	DEFINE(PACA_KVM_R10, offsetof(struct paca_struct, shadow_vcpu.gpr[10])); | ||||
| 	DEFINE(PACA_KVM_R11, offsetof(struct paca_struct, shadow_vcpu.gpr[11])); | ||||
| 	DEFINE(PACA_KVM_R12, offsetof(struct paca_struct, shadow_vcpu.gpr[12])); | ||||
| 	DEFINE(PACA_KVM_R13, offsetof(struct paca_struct, shadow_vcpu.gpr[13])); | ||||
| 	DEFINE(PACA_KVM_HOST_R1, offsetof(struct paca_struct, shadow_vcpu.host_r1)); | ||||
| 	DEFINE(PACA_KVM_HOST_R2, offsetof(struct paca_struct, shadow_vcpu.host_r2)); | ||||
| 	DEFINE(PACA_KVM_VMHANDLER, offsetof(struct paca_struct, | ||||
| 					    shadow_vcpu.vmhandler)); | ||||
| 	DEFINE(PACA_KVM_SCRATCH0, offsetof(struct paca_struct, | ||||
| 					   shadow_vcpu.scratch0)); | ||||
| 	DEFINE(PACA_KVM_SCRATCH1, offsetof(struct paca_struct, | ||||
| 					   shadow_vcpu.scratch1)); | ||||
| 	DEFINE(PACA_KVM_SVCPU, offsetof(struct paca_struct, shadow_vcpu)); | ||||
| 	DEFINE(SVCPU_SLB, offsetof(struct kvmppc_book3s_shadow_vcpu, slb)); | ||||
| 	DEFINE(SVCPU_SLB_MAX, offsetof(struct kvmppc_book3s_shadow_vcpu, slb_max)); | ||||
| #endif | ||||
| #endif /* CONFIG_PPC64 */ | ||||
| 
 | ||||
| @ -228,8 +210,8 @@ int main(void) | ||||
| 	/* Interrupt register frame */ | ||||
| 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); | ||||
| 	DEFINE(INT_FRAME_SIZE, STACK_INT_FRAME_SIZE); | ||||
| #ifdef CONFIG_PPC64 | ||||
| 	DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); | ||||
| #ifdef CONFIG_PPC64 | ||||
| 	/* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */ | ||||
| 	DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); | ||||
| 	DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); | ||||
| @ -412,9 +394,6 @@ int main(void) | ||||
| 	DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack)); | ||||
| 	DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); | ||||
| 	DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); | ||||
| 	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr)); | ||||
| 	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)); | ||||
| @ -422,27 +401,68 @@ int main(void) | ||||
| 	DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7)); | ||||
| 	DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_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)); | ||||
| 
 | ||||
| 	/* book3s_64 */ | ||||
| #ifdef CONFIG_PPC64 | ||||
| 	DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr)); | ||||
| 	/* book3s */ | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| 	DEFINE(VCPU_HOST_RETIP, offsetof(struct kvm_vcpu, arch.host_retip)); | ||||
| 	DEFINE(VCPU_HOST_R2, offsetof(struct kvm_vcpu, arch.host_r2)); | ||||
| 	DEFINE(VCPU_HOST_MSR, offsetof(struct kvm_vcpu, arch.host_msr)); | ||||
| 	DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr)); | ||||
| 	DEFINE(VCPU_SHADOW_SRR1, offsetof(struct kvm_vcpu, arch.shadow_srr1)); | ||||
| 	DEFINE(VCPU_TRAMPOLINE_LOWMEM, offsetof(struct kvm_vcpu, arch.trampoline_lowmem)); | ||||
| 	DEFINE(VCPU_TRAMPOLINE_ENTER, offsetof(struct kvm_vcpu, arch.trampoline_enter)); | ||||
| 	DEFINE(VCPU_HIGHMEM_HANDLER, offsetof(struct kvm_vcpu, arch.highmem_handler)); | ||||
| 	DEFINE(VCPU_RMCALL, offsetof(struct kvm_vcpu, arch.rmcall)); | ||||
| 	DEFINE(VCPU_HFLAGS, offsetof(struct kvm_vcpu, arch.hflags)); | ||||
| 	DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) - | ||||
| 			   offsetof(struct kvmppc_vcpu_book3s, vcpu)); | ||||
| 	DEFINE(SVCPU_CR, offsetof(struct kvmppc_book3s_shadow_vcpu, cr)); | ||||
| 	DEFINE(SVCPU_XER, offsetof(struct kvmppc_book3s_shadow_vcpu, xer)); | ||||
| 	DEFINE(SVCPU_CTR, offsetof(struct kvmppc_book3s_shadow_vcpu, ctr)); | ||||
| 	DEFINE(SVCPU_LR, offsetof(struct kvmppc_book3s_shadow_vcpu, lr)); | ||||
| 	DEFINE(SVCPU_PC, offsetof(struct kvmppc_book3s_shadow_vcpu, pc)); | ||||
| 	DEFINE(SVCPU_R0, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[0])); | ||||
| 	DEFINE(SVCPU_R1, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[1])); | ||||
| 	DEFINE(SVCPU_R2, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[2])); | ||||
| 	DEFINE(SVCPU_R3, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[3])); | ||||
| 	DEFINE(SVCPU_R4, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[4])); | ||||
| 	DEFINE(SVCPU_R5, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[5])); | ||||
| 	DEFINE(SVCPU_R6, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[6])); | ||||
| 	DEFINE(SVCPU_R7, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[7])); | ||||
| 	DEFINE(SVCPU_R8, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[8])); | ||||
| 	DEFINE(SVCPU_R9, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[9])); | ||||
| 	DEFINE(SVCPU_R10, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[10])); | ||||
| 	DEFINE(SVCPU_R11, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[11])); | ||||
| 	DEFINE(SVCPU_R12, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[12])); | ||||
| 	DEFINE(SVCPU_R13, offsetof(struct kvmppc_book3s_shadow_vcpu, gpr[13])); | ||||
| 	DEFINE(SVCPU_HOST_R1, offsetof(struct kvmppc_book3s_shadow_vcpu, host_r1)); | ||||
| 	DEFINE(SVCPU_HOST_R2, offsetof(struct kvmppc_book3s_shadow_vcpu, host_r2)); | ||||
| 	DEFINE(SVCPU_VMHANDLER, offsetof(struct kvmppc_book3s_shadow_vcpu, | ||||
| 					 vmhandler)); | ||||
| 	DEFINE(SVCPU_SCRATCH0, offsetof(struct kvmppc_book3s_shadow_vcpu, | ||||
| 					scratch0)); | ||||
| 	DEFINE(SVCPU_SCRATCH1, offsetof(struct kvmppc_book3s_shadow_vcpu, | ||||
| 					scratch1)); | ||||
| 	DEFINE(SVCPU_IN_GUEST, offsetof(struct kvmppc_book3s_shadow_vcpu, | ||||
| 					in_guest)); | ||||
| 	DEFINE(SVCPU_FAULT_DSISR, offsetof(struct kvmppc_book3s_shadow_vcpu, | ||||
| 					   fault_dsisr)); | ||||
| 	DEFINE(SVCPU_FAULT_DAR, offsetof(struct kvmppc_book3s_shadow_vcpu, | ||||
| 					 fault_dar)); | ||||
| 	DEFINE(SVCPU_LAST_INST, offsetof(struct kvmppc_book3s_shadow_vcpu, | ||||
| 					 last_inst)); | ||||
| 	DEFINE(SVCPU_SHADOW_SRR1, offsetof(struct kvmppc_book3s_shadow_vcpu, | ||||
| 					   shadow_srr1)); | ||||
| #ifdef CONFIG_PPC_BOOK3S_32 | ||||
| 	DEFINE(SVCPU_SR, offsetof(struct kvmppc_book3s_shadow_vcpu, sr)); | ||||
| #endif | ||||
| #else | ||||
| 	DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr)); | ||||
| 	DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer)); | ||||
| #endif /* CONFIG_PPC64 */ | ||||
| 	DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr)); | ||||
| 	DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr)); | ||||
| 	DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc)); | ||||
| 	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 /* CONFIG_PPC_BOOK3S */ | ||||
| #endif | ||||
| #ifdef CONFIG_44x | ||||
| 	DEFINE(PGD_T_LOG2, PGD_T_LOG2); | ||||
|  | ||||
| @ -33,6 +33,7 @@ | ||||
| #include <asm/asm-offsets.h> | ||||
| #include <asm/ptrace.h> | ||||
| #include <asm/bug.h> | ||||
| #include <asm/kvm_book3s_asm.h> | ||||
| 
 | ||||
| /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ | ||||
| #define LOAD_BAT(n, reg, RA, RB)	\ | ||||
| @ -303,6 +304,7 @@ __secondary_hold_acknowledge: | ||||
|  */ | ||||
| #define EXCEPTION(n, label, hdlr, xfer)		\ | ||||
| 	. = n;					\
 | ||||
| 	DO_KVM n;				\
 | ||||
| label:						\ | ||||
| 	EXCEPTION_PROLOG;			\
 | ||||
| 	addi	r3,r1,STACK_FRAME_OVERHEAD;	\
 | ||||
| @ -358,6 +360,7 @@ i##n:								\ | ||||
|  *	-- paulus. | ||||
|  */ | ||||
| 	. = 0x200 | ||||
| 	DO_KVM  0x200 | ||||
| 	mtspr	SPRN_SPRG_SCRATCH0,r10 | ||||
| 	mtspr	SPRN_SPRG_SCRATCH1,r11 | ||||
| 	mfcr	r10 | ||||
| @ -381,6 +384,7 @@ i##n:								\ | ||||
| 
 | ||||
| /* Data access exception. */ | ||||
| 	. = 0x300 | ||||
| 	DO_KVM  0x300 | ||||
| DataAccess: | ||||
| 	EXCEPTION_PROLOG | ||||
| 	mfspr	r10,SPRN_DSISR | ||||
| @ -397,6 +401,7 @@ DataAccess: | ||||
| 
 | ||||
| /* Instruction access exception. */ | ||||
| 	. = 0x400 | ||||
| 	DO_KVM  0x400 | ||||
| InstructionAccess: | ||||
| 	EXCEPTION_PROLOG | ||||
| 	andis.	r0,r9,0x4000		/* no pte found? */ | ||||
| @ -413,6 +418,7 @@ InstructionAccess: | ||||
| 
 | ||||
| /* Alignment exception */ | ||||
| 	. = 0x600 | ||||
| 	DO_KVM  0x600 | ||||
| Alignment: | ||||
| 	EXCEPTION_PROLOG | ||||
| 	mfspr	r4,SPRN_DAR | ||||
| @ -427,6 +433,7 @@ Alignment: | ||||
| 
 | ||||
| /* Floating-point unavailable */ | ||||
| 	. = 0x800 | ||||
| 	DO_KVM  0x800 | ||||
| FPUnavailable: | ||||
| BEGIN_FTR_SECTION | ||||
| /* | ||||
| @ -450,6 +457,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE) | ||||
| 
 | ||||
| /* System call */ | ||||
| 	. = 0xc00 | ||||
| 	DO_KVM  0xc00 | ||||
| SystemCall: | ||||
| 	EXCEPTION_PROLOG | ||||
| 	EXC_XFER_EE_LITE(0xc00, DoSyscall) | ||||
| @ -467,9 +475,11 @@ SystemCall: | ||||
|  * by executing an altivec instruction. | ||||
|  */ | ||||
| 	. = 0xf00 | ||||
| 	DO_KVM  0xf00 | ||||
| 	b	PerformanceMonitor | ||||
| 
 | ||||
| 	. = 0xf20 | ||||
| 	DO_KVM  0xf20 | ||||
| 	b	AltiVecUnavailable | ||||
| 
 | ||||
| /* | ||||
| @ -882,6 +892,10 @@ __secondary_start: | ||||
| 	RFI | ||||
| #endif /* CONFIG_SMP */ | ||||
| 
 | ||||
| #ifdef CONFIG_KVM_BOOK3S_HANDLER | ||||
| #include "../kvm/book3s_rmhandlers.S" | ||||
| #endif | ||||
| 
 | ||||
| /* | ||||
|  * Those generic dummy functions are kept for CPUs not | ||||
|  * included in CONFIG_6xx | ||||
|  | ||||
| @ -37,7 +37,7 @@ | ||||
| #include <asm/firmware.h> | ||||
| #include <asm/page_64.h> | ||||
| #include <asm/irqflags.h> | ||||
| #include <asm/kvm_book3s_64_asm.h> | ||||
| #include <asm/kvm_book3s_asm.h> | ||||
| 
 | ||||
| /* The physical memory is layed out such that the secondary processor | ||||
|  * spin code sits at 0x0000...0x00ff. On server, the vectors follow | ||||
| @ -169,7 +169,7 @@ exception_marker: | ||||
| /* KVM trampoline code needs to be close to the interrupt handlers */ | ||||
| 
 | ||||
| #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||||
| #include "../kvm/book3s_64_rmhandlers.S" | ||||
| #include "../kvm/book3s_rmhandlers.S" | ||||
| #endif | ||||
| 
 | ||||
| _GLOBAL(generic_secondary_thread_init) | ||||
|  | ||||
| @ -101,6 +101,10 @@ EXPORT_SYMBOL(pci_dram_offset); | ||||
| EXPORT_SYMBOL(start_thread); | ||||
| EXPORT_SYMBOL(kernel_thread); | ||||
| 
 | ||||
| #ifndef CONFIG_BOOKE | ||||
| EXPORT_SYMBOL_GPL(cvt_df); | ||||
| EXPORT_SYMBOL_GPL(cvt_fd); | ||||
| #endif | ||||
| EXPORT_SYMBOL(giveup_fpu); | ||||
| #ifdef CONFIG_ALTIVEC | ||||
| EXPORT_SYMBOL(giveup_altivec); | ||||
|  | ||||
| @ -147,7 +147,7 @@ static int __init kvmppc_44x_init(void) | ||||
| 	if (r) | ||||
| 		return r; | ||||
| 
 | ||||
| 	return kvm_init(NULL, sizeof(struct kvmppc_vcpu_44x), THIS_MODULE); | ||||
| 	return kvm_init(NULL, sizeof(struct kvmppc_vcpu_44x), 0, THIS_MODULE); | ||||
| } | ||||
| 
 | ||||
| static void __exit kvmppc_44x_exit(void) | ||||
|  | ||||
| @ -22,12 +22,34 @@ config KVM | ||||
| 	select ANON_INODES | ||||
| 	select KVM_MMIO | ||||
| 
 | ||||
| config KVM_BOOK3S_HANDLER | ||||
| 	bool | ||||
| 
 | ||||
| config KVM_BOOK3S_32_HANDLER | ||||
| 	bool | ||||
| 	select KVM_BOOK3S_HANDLER | ||||
| 
 | ||||
| config KVM_BOOK3S_64_HANDLER | ||||
| 	bool | ||||
| 	select KVM_BOOK3S_HANDLER | ||||
| 
 | ||||
| config KVM_BOOK3S_32 | ||||
| 	tristate "KVM support for PowerPC book3s_32 processors" | ||||
| 	depends on EXPERIMENTAL && PPC_BOOK3S_32 && !SMP && !PTE_64BIT | ||||
| 	select KVM | ||||
| 	select KVM_BOOK3S_32_HANDLER | ||||
| 	---help--- | ||||
| 	  Support running unmodified book3s_32 guest kernels | ||||
| 	  in virtual machines on book3s_32 host processors. | ||||
| 
 | ||||
| 	  This module provides access to the hardware capabilities through | ||||
| 	  a character device node named /dev/kvm. | ||||
| 
 | ||||
| 	  If unsure, say N. | ||||
| 
 | ||||
| config KVM_BOOK3S_64 | ||||
| 	tristate "KVM support for PowerPC book3s_64 processors" | ||||
| 	depends on EXPERIMENTAL && PPC64 | ||||
| 	depends on EXPERIMENTAL && PPC_BOOK3S_64 | ||||
| 	select KVM | ||||
| 	select KVM_BOOK3S_64_HANDLER | ||||
| 	---help--- | ||||
|  | ||||
| @ -14,7 +14,7 @@ CFLAGS_emulate.o  := -I. | ||||
| 
 | ||||
| common-objs-y += powerpc.o emulate.o | ||||
| obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o | ||||
| obj-$(CONFIG_KVM_BOOK3S_64_HANDLER) += book3s_64_exports.o | ||||
| obj-$(CONFIG_KVM_BOOK3S_HANDLER) += book3s_exports.o | ||||
| 
 | ||||
| AFLAGS_booke_interrupts.o := -I$(obj) | ||||
| 
 | ||||
| @ -40,17 +40,31 @@ kvm-objs-$(CONFIG_KVM_E500) := $(kvm-e500-objs) | ||||
| 
 | ||||
| kvm-book3s_64-objs := \
 | ||||
| 	$(common-objs-y) \
 | ||||
| 	fpu.o \
 | ||||
| 	book3s_paired_singles.o \
 | ||||
| 	book3s.o \
 | ||||
| 	book3s_64_emulate.o \
 | ||||
| 	book3s_64_interrupts.o \
 | ||||
| 	book3s_emulate.o \
 | ||||
| 	book3s_interrupts.o \
 | ||||
| 	book3s_64_mmu_host.o \
 | ||||
| 	book3s_64_mmu.o \
 | ||||
| 	book3s_32_mmu.o | ||||
| kvm-objs-$(CONFIG_KVM_BOOK3S_64) := $(kvm-book3s_64-objs) | ||||
| 
 | ||||
| kvm-book3s_32-objs := \
 | ||||
| 	$(common-objs-y) \
 | ||||
| 	fpu.o \
 | ||||
| 	book3s_paired_singles.o \
 | ||||
| 	book3s.o \
 | ||||
| 	book3s_emulate.o \
 | ||||
| 	book3s_interrupts.o \
 | ||||
| 	book3s_32_mmu_host.o \
 | ||||
| 	book3s_32_mmu.o | ||||
| kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs) | ||||
| 
 | ||||
| kvm-objs := $(kvm-objs-m) $(kvm-objs-y) | ||||
| 
 | ||||
| obj-$(CONFIG_KVM_440) += kvm.o | ||||
| obj-$(CONFIG_KVM_E500) += kvm.o | ||||
| obj-$(CONFIG_KVM_BOOK3S_64) += kvm.o | ||||
| obj-$(CONFIG_KVM_BOOK3S_32) += kvm.o | ||||
| 
 | ||||
|  | ||||
| @ -16,6 +16,7 @@ | ||||
| 
 | ||||
| #include <linux/kvm_host.h> | ||||
| #include <linux/err.h> | ||||
| #include <linux/slab.h> | ||||
| 
 | ||||
| #include <asm/reg.h> | ||||
| #include <asm/cputable.h> | ||||
| @ -29,6 +30,7 @@ | ||||
| #include <linux/gfp.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/vmalloc.h> | ||||
| #include <linux/highmem.h> | ||||
| 
 | ||||
| #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU | ||||
| 
 | ||||
| @ -36,7 +38,15 @@ | ||||
| /* #define EXIT_DEBUG_SIMPLE */ | ||||
| /* #define DEBUG_EXT */ | ||||
| 
 | ||||
| static void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr); | ||||
| static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, | ||||
| 			     ulong msr); | ||||
| 
 | ||||
| /* Some compatibility defines */ | ||||
| #ifdef CONFIG_PPC_BOOK3S_32 | ||||
| #define MSR_USER32 MSR_USER | ||||
| #define MSR_USER64 MSR_USER | ||||
| #define HW_PAGE_SIZE PAGE_SIZE | ||||
| #endif | ||||
| 
 | ||||
| struct kvm_stats_debugfs_item debugfs_entries[] = { | ||||
| 	{ "exits",       VCPU_STAT(sum_exits) }, | ||||
| @ -69,18 +79,26 @@ void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu) | ||||
| 
 | ||||
| void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||||
| { | ||||
| 	memcpy(get_paca()->kvm_slb, to_book3s(vcpu)->slb_shadow, sizeof(get_paca()->kvm_slb)); | ||||
| 	memcpy(&get_paca()->shadow_vcpu, &to_book3s(vcpu)->shadow_vcpu, | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| 	memcpy(to_svcpu(vcpu)->slb, to_book3s(vcpu)->slb_shadow, sizeof(to_svcpu(vcpu)->slb)); | ||||
| 	memcpy(&get_paca()->shadow_vcpu, to_book3s(vcpu)->shadow_vcpu, | ||||
| 	       sizeof(get_paca()->shadow_vcpu)); | ||||
| 	get_paca()->kvm_slb_max = to_book3s(vcpu)->slb_shadow_max; | ||||
| 	to_svcpu(vcpu)->slb_max = to_book3s(vcpu)->slb_shadow_max; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S_32 | ||||
| 	current->thread.kvm_shadow_vcpu = to_book3s(vcpu)->shadow_vcpu; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	memcpy(to_book3s(vcpu)->slb_shadow, get_paca()->kvm_slb, sizeof(get_paca()->kvm_slb)); | ||||
| 	memcpy(&to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu, | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| 	memcpy(to_book3s(vcpu)->slb_shadow, to_svcpu(vcpu)->slb, sizeof(to_svcpu(vcpu)->slb)); | ||||
| 	memcpy(to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu, | ||||
| 	       sizeof(get_paca()->shadow_vcpu)); | ||||
| 	to_book3s(vcpu)->slb_shadow_max = get_paca()->kvm_slb_max; | ||||
| 	to_book3s(vcpu)->slb_shadow_max = to_svcpu(vcpu)->slb_max; | ||||
| #endif | ||||
| 
 | ||||
| 	kvmppc_giveup_ext(vcpu, MSR_FP); | ||||
| 	kvmppc_giveup_ext(vcpu, MSR_VEC); | ||||
| @ -131,18 +149,22 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (((vcpu->arch.msr & (MSR_IR|MSR_DR)) != (old_msr & (MSR_IR|MSR_DR))) || | ||||
| 	    (vcpu->arch.msr & MSR_PR) != (old_msr & MSR_PR)) { | ||||
| 	if ((vcpu->arch.msr & (MSR_PR|MSR_IR|MSR_DR)) != | ||||
| 		   (old_msr & (MSR_PR|MSR_IR|MSR_DR))) { | ||||
| 		kvmppc_mmu_flush_segments(vcpu); | ||||
| 		kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc); | ||||
| 		kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Preload FPU if it's enabled */ | ||||
| 	if (vcpu->arch.msr & MSR_FP) | ||||
| 		kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); | ||||
| } | ||||
| 
 | ||||
| void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags) | ||||
| { | ||||
| 	vcpu->arch.srr0 = vcpu->arch.pc; | ||||
| 	vcpu->arch.srr0 = kvmppc_get_pc(vcpu); | ||||
| 	vcpu->arch.srr1 = vcpu->arch.msr | flags; | ||||
| 	vcpu->arch.pc = to_book3s(vcpu)->hior + vec; | ||||
| 	kvmppc_set_pc(vcpu, to_book3s(vcpu)->hior + vec); | ||||
| 	vcpu->arch.mmu.reset_msr(vcpu); | ||||
| } | ||||
| 
 | ||||
| @ -218,6 +240,12 @@ void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, | ||||
| 	kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); | ||||
| } | ||||
| 
 | ||||
| void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, | ||||
|                                   struct kvm_interrupt *irq) | ||||
| { | ||||
| 	kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); | ||||
| } | ||||
| 
 | ||||
| int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) | ||||
| { | ||||
| 	int deliver = 1; | ||||
| @ -302,7 +330,7 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) | ||||
| 		printk(KERN_EMERG "KVM: Check pending: %lx\n", vcpu->arch.pending_exceptions); | ||||
| #endif | ||||
| 	priority = __ffs(*pending); | ||||
| 	while (priority <= (sizeof(unsigned int) * 8)) { | ||||
| 	while (priority < BOOK3S_IRQPRIO_MAX) { | ||||
| 		if (kvmppc_book3s_irqprio_deliver(vcpu, priority) && | ||||
| 		    (priority != BOOK3S_IRQPRIO_DECREMENTER)) { | ||||
| 			/* DEC interrupts get cleared by mtdec */ | ||||
| @ -318,13 +346,18 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) | ||||
| 
 | ||||
| void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) | ||||
| { | ||||
| 	u32 host_pvr; | ||||
| 
 | ||||
| 	vcpu->arch.hflags &= ~BOOK3S_HFLAG_SLB; | ||||
| 	vcpu->arch.pvr = pvr; | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| 	if ((pvr >= 0x330000) && (pvr < 0x70330000)) { | ||||
| 		kvmppc_mmu_book3s_64_init(vcpu); | ||||
| 		to_book3s(vcpu)->hior = 0xfff00000; | ||||
| 		to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL; | ||||
| 	} else { | ||||
| 	} else | ||||
| #endif | ||||
| 	{ | ||||
| 		kvmppc_mmu_book3s_32_init(vcpu); | ||||
| 		to_book3s(vcpu)->hior = 0; | ||||
| 		to_book3s(vcpu)->msr_mask = 0xffffffffULL; | ||||
| @ -337,6 +370,32 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) | ||||
| 	    !strcmp(cur_cpu_spec->platform, "ppc970")) | ||||
| 		vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; | ||||
| 
 | ||||
| 	/* Cell performs badly if MSR_FEx are set. So let's hope nobody
 | ||||
| 	   really needs them in a VM on Cell and force disable them. */ | ||||
| 	if (!strcmp(cur_cpu_spec->platform, "ppc-cell-be")) | ||||
| 		to_book3s(vcpu)->msr_mask &= ~(MSR_FE0 | MSR_FE1); | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S_32 | ||||
| 	/* 32 bit Book3S always has 32 byte dcbz */ | ||||
| 	vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; | ||||
| #endif | ||||
| 
 | ||||
| 	/* On some CPUs we can execute paired single operations natively */ | ||||
| 	asm ( "mfpvr %0" : "=r"(host_pvr)); | ||||
| 	switch (host_pvr) { | ||||
| 	case 0x00080200:	/* lonestar 2.0 */ | ||||
| 	case 0x00088202:	/* lonestar 2.2 */ | ||||
| 	case 0x70000100:	/* gekko 1.0 */ | ||||
| 	case 0x00080100:	/* gekko 2.0 */ | ||||
| 	case 0x00083203:	/* gekko 2.3a */ | ||||
| 	case 0x00083213:	/* gekko 2.3b */ | ||||
| 	case 0x00083204:	/* gekko 2.4 */ | ||||
| 	case 0x00083214:	/* gekko 2.4e (8SE) - retail HW2 */ | ||||
| 	case 0x00087200:	/* broadway */ | ||||
| 		vcpu->arch.hflags |= BOOK3S_HFLAG_NATIVE_PS; | ||||
| 		/* Enable HID2.PSE - in case we need it later */ | ||||
| 		mtspr(SPRN_HID2_GEKKO, mfspr(SPRN_HID2_GEKKO) | (1 << 29)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To
 | ||||
| @ -350,34 +409,29 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) | ||||
|  */ | ||||
| static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) | ||||
| { | ||||
| 	bool touched = false; | ||||
| 	hva_t hpage; | ||||
| 	struct page *hpage; | ||||
| 	u64 hpage_offset; | ||||
| 	u32 *page; | ||||
| 	int i; | ||||
| 
 | ||||
| 	hpage = gfn_to_hva(vcpu->kvm, pte->raddr >> PAGE_SHIFT); | ||||
| 	if (kvm_is_error_hva(hpage)) | ||||
| 	hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT); | ||||
| 	if (is_error_page(hpage)) | ||||
| 		return; | ||||
| 
 | ||||
| 	hpage |= pte->raddr & ~PAGE_MASK; | ||||
| 	hpage &= ~0xFFFULL; | ||||
| 	hpage_offset = pte->raddr & ~PAGE_MASK; | ||||
| 	hpage_offset &= ~0xFFFULL; | ||||
| 	hpage_offset /= 4; | ||||
| 
 | ||||
| 	page = vmalloc(HW_PAGE_SIZE); | ||||
| 	get_page(hpage); | ||||
| 	page = kmap_atomic(hpage, KM_USER0); | ||||
| 
 | ||||
| 	if (copy_from_user(page, (void __user *)hpage, HW_PAGE_SIZE)) | ||||
| 		goto out; | ||||
| 	/* patch dcbz into reserved instruction, so we trap */ | ||||
| 	for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++) | ||||
| 		if ((page[i] & 0xff0007ff) == INS_DCBZ) | ||||
| 			page[i] &= 0xfffffff7; | ||||
| 
 | ||||
| 	for (i=0; i < HW_PAGE_SIZE / 4; i++) | ||||
| 		if ((page[i] & 0xff0007ff) == INS_DCBZ) { | ||||
| 			page[i] &= 0xfffffff7; // reserved instruction, so we trap
 | ||||
| 			touched = true; | ||||
| 		} | ||||
| 
 | ||||
| 	if (touched) | ||||
| 		copy_to_user((void __user *)hpage, page, HW_PAGE_SIZE); | ||||
| 
 | ||||
| out: | ||||
| 	vfree(page); | ||||
| 	kunmap_atomic(page, KM_USER0); | ||||
| 	put_page(hpage); | ||||
| } | ||||
| 
 | ||||
| static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data, | ||||
| @ -391,15 +445,7 @@ static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data, | ||||
| 	} else { | ||||
| 		pte->eaddr = eaddr; | ||||
| 		pte->raddr = eaddr & 0xffffffff; | ||||
| 		pte->vpage = eaddr >> 12; | ||||
| 		switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||||
| 		case 0: | ||||
| 			pte->vpage |= VSID_REAL; | ||||
| 		case MSR_DR: | ||||
| 			pte->vpage |= VSID_REAL_DR; | ||||
| 		case MSR_IR: | ||||
| 			pte->vpage |= VSID_REAL_IR; | ||||
| 		} | ||||
| 		pte->vpage = VSID_REAL | eaddr >> 12; | ||||
| 		pte->may_read = true; | ||||
| 		pte->may_write = true; | ||||
| 		pte->may_execute = true; | ||||
| @ -434,55 +480,55 @@ err: | ||||
| 	return kvmppc_bad_hva(); | ||||
| } | ||||
| 
 | ||||
| int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr) | ||||
| int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, | ||||
| 	      bool data) | ||||
| { | ||||
| 	struct kvmppc_pte pte; | ||||
| 	hva_t hva = eaddr; | ||||
| 
 | ||||
| 	vcpu->stat.st++; | ||||
| 
 | ||||
| 	if (kvmppc_xlate(vcpu, eaddr, false, &pte)) | ||||
| 		goto err; | ||||
| 	if (kvmppc_xlate(vcpu, *eaddr, data, &pte)) | ||||
| 		return -ENOENT; | ||||
| 
 | ||||
| 	hva = kvmppc_pte_to_hva(vcpu, &pte, false); | ||||
| 	if (kvm_is_error_hva(hva)) | ||||
| 		goto err; | ||||
| 	*eaddr = pte.raddr; | ||||
| 
 | ||||
| 	if (copy_to_user((void __user *)hva, ptr, size)) { | ||||
| 		printk(KERN_INFO "kvmppc_st at 0x%lx failed\n", hva); | ||||
| 		goto err; | ||||
| 	} | ||||
| 	if (!pte.may_write) | ||||
| 		return -EPERM; | ||||
| 
 | ||||
| 	return 0; | ||||
| 	if (kvm_write_guest(vcpu->kvm, pte.raddr, ptr, size)) | ||||
| 		return EMULATE_DO_MMIO; | ||||
| 
 | ||||
| err: | ||||
| 	return -ENOENT; | ||||
| 	return EMULATE_DONE; | ||||
| } | ||||
| 
 | ||||
| int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr, | ||||
| int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, | ||||
| 		      bool data) | ||||
| { | ||||
| 	struct kvmppc_pte pte; | ||||
| 	hva_t hva = eaddr; | ||||
| 	hva_t hva = *eaddr; | ||||
| 
 | ||||
| 	vcpu->stat.ld++; | ||||
| 
 | ||||
| 	if (kvmppc_xlate(vcpu, eaddr, data, &pte)) | ||||
| 		goto err; | ||||
| 	if (kvmppc_xlate(vcpu, *eaddr, data, &pte)) | ||||
| 		goto nopte; | ||||
| 
 | ||||
| 	*eaddr = pte.raddr; | ||||
| 
 | ||||
| 	hva = kvmppc_pte_to_hva(vcpu, &pte, true); | ||||
| 	if (kvm_is_error_hva(hva)) | ||||
| 		goto err; | ||||
| 		goto mmio; | ||||
| 
 | ||||
| 	if (copy_from_user(ptr, (void __user *)hva, size)) { | ||||
| 		printk(KERN_INFO "kvmppc_ld at 0x%lx failed\n", hva); | ||||
| 		goto err; | ||||
| 		goto mmio; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 	return EMULATE_DONE; | ||||
| 
 | ||||
| err: | ||||
| nopte: | ||||
| 	return -ENOENT; | ||||
| mmio: | ||||
| 	return EMULATE_DO_MMIO; | ||||
| } | ||||
| 
 | ||||
| static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn) | ||||
| @ -499,12 +545,11 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 	int page_found = 0; | ||||
| 	struct kvmppc_pte pte; | ||||
| 	bool is_mmio = false; | ||||
| 	bool dr = (vcpu->arch.msr & MSR_DR) ? true : false; | ||||
| 	bool ir = (vcpu->arch.msr & MSR_IR) ? true : false; | ||||
| 	u64 vsid; | ||||
| 
 | ||||
| 	if ( vec == BOOK3S_INTERRUPT_DATA_STORAGE ) { | ||||
| 		relocated = (vcpu->arch.msr & MSR_DR); | ||||
| 	} else { | ||||
| 		relocated = (vcpu->arch.msr & MSR_IR); | ||||
| 	} | ||||
| 	relocated = data ? dr : ir; | ||||
| 
 | ||||
| 	/* Resolve real address if translation turned on */ | ||||
| 	if (relocated) { | ||||
| @ -516,14 +561,25 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 		pte.raddr = eaddr & 0xffffffff; | ||||
| 		pte.eaddr = eaddr; | ||||
| 		pte.vpage = eaddr >> 12; | ||||
| 		switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||||
| 		case 0: | ||||
| 			pte.vpage |= VSID_REAL; | ||||
| 		case MSR_DR: | ||||
| 			pte.vpage |= VSID_REAL_DR; | ||||
| 		case MSR_IR: | ||||
| 			pte.vpage |= VSID_REAL_IR; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||||
| 	case 0: | ||||
| 		pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12)); | ||||
| 		break; | ||||
| 	case MSR_DR: | ||||
| 	case MSR_IR: | ||||
| 		vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid); | ||||
| 
 | ||||
| 		if ((vcpu->arch.msr & (MSR_DR|MSR_IR)) == MSR_DR) | ||||
| 			pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12)); | ||||
| 		else | ||||
| 			pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12)); | ||||
| 		pte.vpage |= vsid; | ||||
| 
 | ||||
| 		if (vsid == -1) | ||||
| 			page_found = -EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (vcpu->arch.mmu.is_dcbz32(vcpu) && | ||||
| @ -538,20 +594,20 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 
 | ||||
| 	if (page_found == -ENOENT) { | ||||
| 		/* Page not found in guest PTE entries */ | ||||
| 		vcpu->arch.dear = vcpu->arch.fault_dear; | ||||
| 		to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr; | ||||
| 		vcpu->arch.msr |= (vcpu->arch.shadow_srr1 & 0x00000000f8000000ULL); | ||||
| 		vcpu->arch.dear = kvmppc_get_fault_dar(vcpu); | ||||
| 		to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr; | ||||
| 		vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL); | ||||
| 		kvmppc_book3s_queue_irqprio(vcpu, vec); | ||||
| 	} else if (page_found == -EPERM) { | ||||
| 		/* Storage protection */ | ||||
| 		vcpu->arch.dear = vcpu->arch.fault_dear; | ||||
| 		to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr & ~DSISR_NOHPTE; | ||||
| 		vcpu->arch.dear = kvmppc_get_fault_dar(vcpu); | ||||
| 		to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE; | ||||
| 		to_book3s(vcpu)->dsisr |= DSISR_PROTFAULT; | ||||
| 		vcpu->arch.msr |= (vcpu->arch.shadow_srr1 & 0x00000000f8000000ULL); | ||||
| 		vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL); | ||||
| 		kvmppc_book3s_queue_irqprio(vcpu, vec); | ||||
| 	} else if (page_found == -EINVAL) { | ||||
| 		/* Page not found in guest SLB */ | ||||
| 		vcpu->arch.dear = vcpu->arch.fault_dear; | ||||
| 		vcpu->arch.dear = kvmppc_get_fault_dar(vcpu); | ||||
| 		kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80); | ||||
| 	} else if (!is_mmio && | ||||
| 		   kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) { | ||||
| @ -583,11 +639,13 @@ static inline int get_fpr_index(int i) | ||||
| } | ||||
| 
 | ||||
| /* Give up external provider (FPU, Altivec, VSX) */ | ||||
| static void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr) | ||||
| void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr) | ||||
| { | ||||
| 	struct thread_struct *t = ¤t->thread; | ||||
| 	u64 *vcpu_fpr = vcpu->arch.fpr; | ||||
| #ifdef CONFIG_VSX | ||||
| 	u64 *vcpu_vsx = vcpu->arch.vsr; | ||||
| #endif | ||||
| 	u64 *thread_fpr = (u64*)t->fpr; | ||||
| 	int i; | ||||
| 
 | ||||
| @ -629,21 +687,65 @@ static void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr) | ||||
| 	kvmppc_recalc_shadow_msr(vcpu); | ||||
| } | ||||
| 
 | ||||
| static int kvmppc_read_inst(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	ulong srr0 = kvmppc_get_pc(vcpu); | ||||
| 	u32 last_inst = kvmppc_get_last_inst(vcpu); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false); | ||||
| 	if (ret == -ENOENT) { | ||||
| 		vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 33, 33, 1); | ||||
| 		vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 34, 36, 0); | ||||
| 		vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 42, 47, 0); | ||||
| 		kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE); | ||||
| 		return EMULATE_AGAIN; | ||||
| 	} | ||||
| 
 | ||||
| 	return EMULATE_DONE; | ||||
| } | ||||
| 
 | ||||
| static int kvmppc_check_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr) | ||||
| { | ||||
| 
 | ||||
| 	/* Need to do paired single emulation? */ | ||||
| 	if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)) | ||||
| 		return EMULATE_DONE; | ||||
| 
 | ||||
| 	/* Read out the instruction */ | ||||
| 	if (kvmppc_read_inst(vcpu) == EMULATE_DONE) | ||||
| 		/* Need to emulate */ | ||||
| 		return EMULATE_FAIL; | ||||
| 
 | ||||
| 	return EMULATE_AGAIN; | ||||
| } | ||||
| 
 | ||||
| /* Handle external providers (FPU, Altivec, VSX) */ | ||||
| static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, | ||||
| 			     ulong msr) | ||||
| { | ||||
| 	struct thread_struct *t = ¤t->thread; | ||||
| 	u64 *vcpu_fpr = vcpu->arch.fpr; | ||||
| #ifdef CONFIG_VSX | ||||
| 	u64 *vcpu_vsx = vcpu->arch.vsr; | ||||
| #endif | ||||
| 	u64 *thread_fpr = (u64*)t->fpr; | ||||
| 	int i; | ||||
| 
 | ||||
| 	/* When we have paired singles, we emulate in software */ | ||||
| 	if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE) | ||||
| 		return RESUME_GUEST; | ||||
| 
 | ||||
| 	if (!(vcpu->arch.msr & msr)) { | ||||
| 		kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||||
| 		return RESUME_GUEST; | ||||
| 	} | ||||
| 
 | ||||
| 	/* We already own the ext */ | ||||
| 	if (vcpu->arch.guest_owned_ext & msr) { | ||||
| 		return RESUME_GUEST; | ||||
| 	} | ||||
| 
 | ||||
| #ifdef DEBUG_EXT | ||||
| 	printk(KERN_INFO "Loading up ext 0x%lx\n", msr); | ||||
| #endif | ||||
| @ -696,21 +798,33 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 	run->ready_for_interrupt_injection = 1; | ||||
| #ifdef EXIT_DEBUG | ||||
| 	printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | dec=0x%x | msr=0x%lx\n", | ||||
| 		exit_nr, vcpu->arch.pc, vcpu->arch.fault_dear, | ||||
| 		kvmppc_get_dec(vcpu), vcpu->arch.msr); | ||||
| 		exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu), | ||||
| 		kvmppc_get_dec(vcpu), to_svcpu(vcpu)->shadow_srr1); | ||||
| #elif defined (EXIT_DEBUG_SIMPLE) | ||||
| 	if ((exit_nr != 0x900) && (exit_nr != 0x500)) | ||||
| 		printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | msr=0x%lx\n", | ||||
| 			exit_nr, vcpu->arch.pc, vcpu->arch.fault_dear, | ||||
| 			exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu), | ||||
| 			vcpu->arch.msr); | ||||
| #endif | ||||
| 	kvm_resched(vcpu); | ||||
| 	switch (exit_nr) { | ||||
| 	case BOOK3S_INTERRUPT_INST_STORAGE: | ||||
| 		vcpu->stat.pf_instruc++; | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S_32 | ||||
| 		/* We set segments as unused segments when invalidating them. So
 | ||||
| 		 * treat the respective fault as segment fault. */ | ||||
| 		if (to_svcpu(vcpu)->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT] | ||||
| 		    == SR_INVALID) { | ||||
| 			kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); | ||||
| 			r = RESUME_GUEST; | ||||
| 			break; | ||||
| 		} | ||||
| #endif | ||||
| 
 | ||||
| 		/* only care about PTEG not found errors, but leave NX alone */ | ||||
| 		if (vcpu->arch.shadow_srr1 & 0x40000000) { | ||||
| 			r = kvmppc_handle_pagefault(run, vcpu, vcpu->arch.pc, exit_nr); | ||||
| 		if (to_svcpu(vcpu)->shadow_srr1 & 0x40000000) { | ||||
| 			r = kvmppc_handle_pagefault(run, vcpu, kvmppc_get_pc(vcpu), exit_nr); | ||||
| 			vcpu->stat.sp_instruc++; | ||||
| 		} else if (vcpu->arch.mmu.is_dcbz32(vcpu) && | ||||
| 			  (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { | ||||
| @ -719,37 +833,52 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 			 *     so we can't use the NX bit inside the guest. Let's cross our fingers, | ||||
| 			 *     that no guest that needs the dcbz hack does NX. | ||||
| 			 */ | ||||
| 			kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL); | ||||
| 			kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL); | ||||
| 			r = RESUME_GUEST; | ||||
| 		} else { | ||||
| 			vcpu->arch.msr |= vcpu->arch.shadow_srr1 & 0x58000000; | ||||
| 			vcpu->arch.msr |= to_svcpu(vcpu)->shadow_srr1 & 0x58000000; | ||||
| 			kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||||
| 			kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL); | ||||
| 			kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL); | ||||
| 			r = RESUME_GUEST; | ||||
| 		} | ||||
| 		break; | ||||
| 	case BOOK3S_INTERRUPT_DATA_STORAGE: | ||||
| 	{ | ||||
| 		ulong dar = kvmppc_get_fault_dar(vcpu); | ||||
| 		vcpu->stat.pf_storage++; | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S_32 | ||||
| 		/* We set segments as unused segments when invalidating them. So
 | ||||
| 		 * treat the respective fault as segment fault. */ | ||||
| 		if ((to_svcpu(vcpu)->sr[dar >> SID_SHIFT]) == SR_INVALID) { | ||||
| 			kvmppc_mmu_map_segment(vcpu, dar); | ||||
| 			r = RESUME_GUEST; | ||||
| 			break; | ||||
| 		} | ||||
| #endif | ||||
| 
 | ||||
| 		/* The only case we need to handle is missing shadow PTEs */ | ||||
| 		if (vcpu->arch.fault_dsisr & DSISR_NOHPTE) { | ||||
| 			r = kvmppc_handle_pagefault(run, vcpu, vcpu->arch.fault_dear, exit_nr); | ||||
| 		if (to_svcpu(vcpu)->fault_dsisr & DSISR_NOHPTE) { | ||||
| 			r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr); | ||||
| 		} else { | ||||
| 			vcpu->arch.dear = vcpu->arch.fault_dear; | ||||
| 			to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr; | ||||
| 			vcpu->arch.dear = dar; | ||||
| 			to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr; | ||||
| 			kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||||
| 			kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFULL); | ||||
| 			kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFUL); | ||||
| 			r = RESUME_GUEST; | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| 	case BOOK3S_INTERRUPT_DATA_SEGMENT: | ||||
| 		if (kvmppc_mmu_map_segment(vcpu, vcpu->arch.fault_dear) < 0) { | ||||
| 			vcpu->arch.dear = vcpu->arch.fault_dear; | ||||
| 		if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_fault_dar(vcpu)) < 0) { | ||||
| 			vcpu->arch.dear = kvmppc_get_fault_dar(vcpu); | ||||
| 			kvmppc_book3s_queue_irqprio(vcpu, | ||||
| 				BOOK3S_INTERRUPT_DATA_SEGMENT); | ||||
| 		} | ||||
| 		r = RESUME_GUEST; | ||||
| 		break; | ||||
| 	case BOOK3S_INTERRUPT_INST_SEGMENT: | ||||
| 		if (kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc) < 0) { | ||||
| 		if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)) < 0) { | ||||
| 			kvmppc_book3s_queue_irqprio(vcpu, | ||||
| 				BOOK3S_INTERRUPT_INST_SEGMENT); | ||||
| 		} | ||||
| @ -764,18 +893,22 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 		vcpu->stat.ext_intr_exits++; | ||||
| 		r = RESUME_GUEST; | ||||
| 		break; | ||||
| 	case BOOK3S_INTERRUPT_PERFMON: | ||||
| 		r = RESUME_GUEST; | ||||
| 		break; | ||||
| 	case BOOK3S_INTERRUPT_PROGRAM: | ||||
| 	{ | ||||
| 		enum emulation_result er; | ||||
| 		ulong flags; | ||||
| 
 | ||||
| 		flags = vcpu->arch.shadow_srr1 & 0x1f0000ull; | ||||
| program_interrupt: | ||||
| 		flags = to_svcpu(vcpu)->shadow_srr1 & 0x1f0000ull; | ||||
| 
 | ||||
| 		if (vcpu->arch.msr & MSR_PR) { | ||||
| #ifdef EXIT_DEBUG | ||||
| 			printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", vcpu->arch.pc, vcpu->arch.last_inst); | ||||
| 			printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu)); | ||||
| #endif | ||||
| 			if ((vcpu->arch.last_inst & 0xff0007ff) != | ||||
| 			if ((kvmppc_get_last_inst(vcpu) & 0xff0007ff) != | ||||
| 			    (INS_DCBZ & 0xfffffff7)) { | ||||
| 				kvmppc_core_queue_program(vcpu, flags); | ||||
| 				r = RESUME_GUEST; | ||||
| @ -789,33 +922,80 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 		case EMULATE_DONE: | ||||
| 			r = RESUME_GUEST_NV; | ||||
| 			break; | ||||
| 		case EMULATE_AGAIN: | ||||
| 			r = RESUME_GUEST; | ||||
| 			break; | ||||
| 		case EMULATE_FAIL: | ||||
| 			printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n", | ||||
| 			       __func__, vcpu->arch.pc, vcpu->arch.last_inst); | ||||
| 			       __func__, kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu)); | ||||
| 			kvmppc_core_queue_program(vcpu, flags); | ||||
| 			r = RESUME_GUEST; | ||||
| 			break; | ||||
| 		case EMULATE_DO_MMIO: | ||||
| 			run->exit_reason = KVM_EXIT_MMIO; | ||||
| 			r = RESUME_HOST_NV; | ||||
| 			break; | ||||
| 		default: | ||||
| 			BUG(); | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| 	case BOOK3S_INTERRUPT_SYSCALL: | ||||
| #ifdef EXIT_DEBUG | ||||
| 		printk(KERN_INFO "Syscall Nr %d\n", (int)kvmppc_get_gpr(vcpu, 0)); | ||||
| #endif | ||||
| 		vcpu->stat.syscall_exits++; | ||||
| 		kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||||
| 		r = RESUME_GUEST; | ||||
| 		// XXX make user settable
 | ||||
| 		if (vcpu->arch.osi_enabled && | ||||
| 		    (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) && | ||||
| 		    (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) { | ||||
| 			u64 *gprs = run->osi.gprs; | ||||
| 			int i; | ||||
| 
 | ||||
| 			run->exit_reason = KVM_EXIT_OSI; | ||||
| 			for (i = 0; i < 32; i++) | ||||
| 				gprs[i] = kvmppc_get_gpr(vcpu, i); | ||||
| 			vcpu->arch.osi_needed = 1; | ||||
| 			r = RESUME_HOST_NV; | ||||
| 
 | ||||
| 		} else { | ||||
| 			vcpu->stat.syscall_exits++; | ||||
| 			kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||||
| 			r = RESUME_GUEST; | ||||
| 		} | ||||
| 		break; | ||||
| 	case BOOK3S_INTERRUPT_FP_UNAVAIL: | ||||
| 		r = kvmppc_handle_ext(vcpu, exit_nr, MSR_FP); | ||||
| 		break; | ||||
| 	case BOOK3S_INTERRUPT_ALTIVEC: | ||||
| 		r = kvmppc_handle_ext(vcpu, exit_nr, MSR_VEC); | ||||
| 		break; | ||||
| 	case BOOK3S_INTERRUPT_VSX: | ||||
| 		r = kvmppc_handle_ext(vcpu, exit_nr, MSR_VSX); | ||||
| 	{ | ||||
| 		int ext_msr = 0; | ||||
| 
 | ||||
| 		switch (exit_nr) { | ||||
| 		case BOOK3S_INTERRUPT_FP_UNAVAIL: ext_msr = MSR_FP;  break; | ||||
| 		case BOOK3S_INTERRUPT_ALTIVEC:    ext_msr = MSR_VEC; break; | ||||
| 		case BOOK3S_INTERRUPT_VSX:        ext_msr = MSR_VSX; break; | ||||
| 		} | ||||
| 
 | ||||
| 		switch (kvmppc_check_ext(vcpu, exit_nr)) { | ||||
| 		case EMULATE_DONE: | ||||
| 			/* everything ok - let's enable the ext */ | ||||
| 			r = kvmppc_handle_ext(vcpu, exit_nr, ext_msr); | ||||
| 			break; | ||||
| 		case EMULATE_FAIL: | ||||
| 			/* we need to emulate this instruction */ | ||||
| 			goto program_interrupt; | ||||
| 			break; | ||||
| 		default: | ||||
| 			/* nothing to worry about - go again */ | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| 	case BOOK3S_INTERRUPT_ALIGNMENT: | ||||
| 		if (kvmppc_read_inst(vcpu) == EMULATE_DONE) { | ||||
| 			to_book3s(vcpu)->dsisr = kvmppc_alignment_dsisr(vcpu, | ||||
| 				kvmppc_get_last_inst(vcpu)); | ||||
| 			vcpu->arch.dear = kvmppc_alignment_dar(vcpu, | ||||
| 				kvmppc_get_last_inst(vcpu)); | ||||
| 			kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||||
| 		} | ||||
| 		r = RESUME_GUEST; | ||||
| 		break; | ||||
| 	case BOOK3S_INTERRUPT_MACHINE_CHECK: | ||||
| 	case BOOK3S_INTERRUPT_TRACE: | ||||
| @ -825,7 +1005,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 	default: | ||||
| 		/* Ugh - bork here! What did we get? */ | ||||
| 		printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n", | ||||
| 			exit_nr, vcpu->arch.pc, vcpu->arch.shadow_srr1); | ||||
| 			exit_nr, kvmppc_get_pc(vcpu), to_svcpu(vcpu)->shadow_srr1); | ||||
| 		r = RESUME_HOST; | ||||
| 		BUG(); | ||||
| 		break; | ||||
| @ -852,7 +1032,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 	} | ||||
| 
 | ||||
| #ifdef EXIT_DEBUG | ||||
| 	printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, vcpu->arch.pc, r); | ||||
| 	printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, kvmppc_get_pc(vcpu), r); | ||||
| #endif | ||||
| 
 | ||||
| 	return r; | ||||
| @ -867,10 +1047,12 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	regs->pc = vcpu->arch.pc; | ||||
| 	vcpu_load(vcpu); | ||||
| 
 | ||||
| 	regs->pc = kvmppc_get_pc(vcpu); | ||||
| 	regs->cr = kvmppc_get_cr(vcpu); | ||||
| 	regs->ctr = vcpu->arch.ctr; | ||||
| 	regs->lr = vcpu->arch.lr; | ||||
| 	regs->ctr = kvmppc_get_ctr(vcpu); | ||||
| 	regs->lr = kvmppc_get_lr(vcpu); | ||||
| 	regs->xer = kvmppc_get_xer(vcpu); | ||||
| 	regs->msr = vcpu->arch.msr; | ||||
| 	regs->srr0 = vcpu->arch.srr0; | ||||
| @ -887,6 +1069,8 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||||
| 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++) | ||||
| 		regs->gpr[i] = kvmppc_get_gpr(vcpu, i); | ||||
| 
 | ||||
| 	vcpu_put(vcpu); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -894,10 +1078,12 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	vcpu->arch.pc = regs->pc; | ||||
| 	vcpu_load(vcpu); | ||||
| 
 | ||||
| 	kvmppc_set_pc(vcpu, regs->pc); | ||||
| 	kvmppc_set_cr(vcpu, regs->cr); | ||||
| 	vcpu->arch.ctr = regs->ctr; | ||||
| 	vcpu->arch.lr = regs->lr; | ||||
| 	kvmppc_set_ctr(vcpu, regs->ctr); | ||||
| 	kvmppc_set_lr(vcpu, regs->lr); | ||||
| 	kvmppc_set_xer(vcpu, regs->xer); | ||||
| 	kvmppc_set_msr(vcpu, regs->msr); | ||||
| 	vcpu->arch.srr0 = regs->srr0; | ||||
| @ -913,6 +1099,8 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||||
| 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++) | ||||
| 		kvmppc_set_gpr(vcpu, i, regs->gpr[i]); | ||||
| 
 | ||||
| 	vcpu_put(vcpu); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -922,6 +1110,8 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, | ||||
| 	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); | ||||
| 	int i; | ||||
| 
 | ||||
| 	vcpu_load(vcpu); | ||||
| 
 | ||||
| 	sregs->pvr = vcpu->arch.pvr; | ||||
| 
 | ||||
| 	sregs->u.s.sdr1 = to_book3s(vcpu)->sdr1; | ||||
| @ -940,6 +1130,9 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, | ||||
| 			sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	vcpu_put(vcpu); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -949,6 +1142,8 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | ||||
| 	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); | ||||
| 	int i; | ||||
| 
 | ||||
| 	vcpu_load(vcpu); | ||||
| 
 | ||||
| 	kvmppc_set_pvr(vcpu, sregs->pvr); | ||||
| 
 | ||||
| 	vcpu3s->sdr1 = sregs->u.s.sdr1; | ||||
| @ -975,6 +1170,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | ||||
| 
 | ||||
| 	/* Flush the MMU after messing with the segments */ | ||||
| 	kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||||
| 
 | ||||
| 	vcpu_put(vcpu); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -1042,24 +1240,33 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) | ||||
| { | ||||
| 	struct kvmppc_vcpu_book3s *vcpu_book3s; | ||||
| 	struct kvm_vcpu *vcpu; | ||||
| 	int err; | ||||
| 	int err = -ENOMEM; | ||||
| 
 | ||||
| 	vcpu_book3s = (struct kvmppc_vcpu_book3s *)__get_free_pages( GFP_KERNEL | __GFP_ZERO, | ||||
| 			get_order(sizeof(struct kvmppc_vcpu_book3s))); | ||||
| 	if (!vcpu_book3s) { | ||||
| 		err = -ENOMEM; | ||||
| 	vcpu_book3s = vmalloc(sizeof(struct kvmppc_vcpu_book3s)); | ||||
| 	if (!vcpu_book3s) | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	memset(vcpu_book3s, 0, sizeof(struct kvmppc_vcpu_book3s)); | ||||
| 
 | ||||
| 	vcpu_book3s->shadow_vcpu = (struct kvmppc_book3s_shadow_vcpu *) | ||||
| 		kzalloc(sizeof(*vcpu_book3s->shadow_vcpu), GFP_KERNEL); | ||||
| 	if (!vcpu_book3s->shadow_vcpu) | ||||
| 		goto free_vcpu; | ||||
| 
 | ||||
| 	vcpu = &vcpu_book3s->vcpu; | ||||
| 	err = kvm_vcpu_init(vcpu, kvm, id); | ||||
| 	if (err) | ||||
| 		goto free_vcpu; | ||||
| 		goto free_shadow_vcpu; | ||||
| 
 | ||||
| 	vcpu->arch.host_retip = kvm_return_point; | ||||
| 	vcpu->arch.host_msr = mfmsr(); | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| 	/* default to book3s_64 (970fx) */ | ||||
| 	vcpu->arch.pvr = 0x3C0301; | ||||
| #else | ||||
| 	/* default to book3s_32 (750) */ | ||||
| 	vcpu->arch.pvr = 0x84202; | ||||
| #endif | ||||
| 	kvmppc_set_pvr(vcpu, vcpu->arch.pvr); | ||||
| 	vcpu_book3s->slb_nr = 64; | ||||
| 
 | ||||
| @ -1067,23 +1274,24 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) | ||||
| 	vcpu->arch.trampoline_lowmem = kvmppc_trampoline_lowmem; | ||||
| 	vcpu->arch.trampoline_enter = kvmppc_trampoline_enter; | ||||
| 	vcpu->arch.highmem_handler = (ulong)kvmppc_handler_highmem; | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| 	vcpu->arch.rmcall = *(ulong*)kvmppc_rmcall; | ||||
| #else | ||||
| 	vcpu->arch.rmcall = (ulong)kvmppc_rmcall; | ||||
| #endif | ||||
| 
 | ||||
| 	vcpu->arch.shadow_msr = MSR_USER64; | ||||
| 
 | ||||
| 	err = __init_new_context(); | ||||
| 	err = kvmppc_mmu_init(vcpu); | ||||
| 	if (err < 0) | ||||
| 		goto free_vcpu; | ||||
| 	vcpu_book3s->context_id = err; | ||||
| 
 | ||||
| 	vcpu_book3s->vsid_max = ((vcpu_book3s->context_id + 1) << USER_ESID_BITS) - 1; | ||||
| 	vcpu_book3s->vsid_first = vcpu_book3s->context_id << USER_ESID_BITS; | ||||
| 	vcpu_book3s->vsid_next = vcpu_book3s->vsid_first; | ||||
| 		goto free_shadow_vcpu; | ||||
| 
 | ||||
| 	return vcpu; | ||||
| 
 | ||||
| free_shadow_vcpu: | ||||
| 	kfree(vcpu_book3s->shadow_vcpu); | ||||
| free_vcpu: | ||||
| 	free_pages((long)vcpu_book3s, get_order(sizeof(struct kvmppc_vcpu_book3s))); | ||||
| 	vfree(vcpu_book3s); | ||||
| out: | ||||
| 	return ERR_PTR(err); | ||||
| } | ||||
| @ -1092,9 +1300,9 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||||
| 
 | ||||
| 	__destroy_context(vcpu_book3s->context_id); | ||||
| 	kvm_vcpu_uninit(vcpu); | ||||
| 	free_pages((long)vcpu_book3s, get_order(sizeof(struct kvmppc_vcpu_book3s))); | ||||
| 	kfree(vcpu_book3s->shadow_vcpu); | ||||
| 	vfree(vcpu_book3s); | ||||
| } | ||||
| 
 | ||||
| extern int __kvmppc_vcpu_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); | ||||
| @ -1102,8 +1310,12 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct thread_struct ext_bkp; | ||||
| #ifdef CONFIG_ALTIVEC | ||||
| 	bool save_vec = current->thread.used_vr; | ||||
| #endif | ||||
| #ifdef CONFIG_VSX | ||||
| 	bool save_vsx = current->thread.used_vsr; | ||||
| #endif | ||||
| 	ulong ext_msr; | ||||
| 
 | ||||
| 	/* No need to go into the guest when all we do is going out */ | ||||
| @ -1144,6 +1356,10 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | ||||
| 	/* XXX we get called with irq disabled - change that! */ | ||||
| 	local_irq_enable(); | ||||
| 
 | ||||
| 	/* Preload FPU if it's enabled */ | ||||
| 	if (vcpu->arch.msr & MSR_FP) | ||||
| 		kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); | ||||
| 
 | ||||
| 	ret = __kvmppc_vcpu_entry(kvm_run, vcpu); | ||||
| 
 | ||||
| 	local_irq_disable(); | ||||
| @ -1179,7 +1395,8 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | ||||
| 
 | ||||
| static int kvmppc_book3s_init(void) | ||||
| { | ||||
| 	return kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), THIS_MODULE); | ||||
| 	return kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), 0, | ||||
| 			THIS_MODULE); | ||||
| } | ||||
| 
 | ||||
| static void kvmppc_book3s_exit(void) | ||||
|  | ||||
| @ -37,7 +37,7 @@ | ||||
| #define dprintk(X...) do { } while(0) | ||||
| #endif | ||||
| 
 | ||||
| #ifdef DEBUG_PTE | ||||
| #ifdef DEBUG_MMU_PTE | ||||
| #define dprintk_pte(X...) printk(KERN_INFO X) | ||||
| #else | ||||
| #define dprintk_pte(X...) do { } while(0) | ||||
| @ -45,6 +45,9 @@ | ||||
| 
 | ||||
| #define PTEG_FLAG_ACCESSED	0x00000100 | ||||
| #define PTEG_FLAG_DIRTY		0x00000080 | ||||
| #ifndef SID_SHIFT | ||||
| #define SID_SHIFT		28 | ||||
| #endif | ||||
| 
 | ||||
| static inline bool check_debug_ip(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| @ -57,6 +60,8 @@ static inline bool check_debug_ip(struct kvm_vcpu *vcpu) | ||||
| 
 | ||||
| static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, | ||||
| 					  struct kvmppc_pte *pte, bool data); | ||||
| static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, | ||||
| 					     u64 *vsid); | ||||
| 
 | ||||
| static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr) | ||||
| { | ||||
| @ -66,13 +71,14 @@ static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t e | ||||
| static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr, | ||||
| 					 bool data) | ||||
| { | ||||
| 	struct kvmppc_sr *sre = find_sr(to_book3s(vcpu), eaddr); | ||||
| 	u64 vsid; | ||||
| 	struct kvmppc_pte pte; | ||||
| 
 | ||||
| 	if (!kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, &pte, data)) | ||||
| 		return pte.vpage; | ||||
| 
 | ||||
| 	return (((u64)eaddr >> 12) & 0xffff) | (((u64)sre->vsid) << 16); | ||||
| 	kvmppc_mmu_book3s_32_esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid); | ||||
| 	return (((u64)eaddr >> 12) & 0xffff) | (vsid << 16); | ||||
| } | ||||
| 
 | ||||
| static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu) | ||||
| @ -142,8 +148,13 @@ static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, | ||||
| 				    bat->bepi_mask); | ||||
| 		} | ||||
| 		if ((eaddr & bat->bepi_mask) == bat->bepi) { | ||||
| 			u64 vsid; | ||||
| 			kvmppc_mmu_book3s_32_esid_to_vsid(vcpu, | ||||
| 				eaddr >> SID_SHIFT, &vsid); | ||||
| 			vsid <<= 16; | ||||
| 			pte->vpage = (((u64)eaddr >> 12) & 0xffff) | vsid; | ||||
| 
 | ||||
| 			pte->raddr = bat->brpn | (eaddr & ~bat->bepi_mask); | ||||
| 			pte->vpage = (eaddr >> 12) | VSID_BAT; | ||||
| 			pte->may_read = bat->pp; | ||||
| 			pte->may_write = bat->pp > 1; | ||||
| 			pte->may_execute = true; | ||||
| @ -172,7 +183,7 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr, | ||||
| 	struct kvmppc_sr *sre; | ||||
| 	hva_t ptegp; | ||||
| 	u32 pteg[16]; | ||||
| 	u64 ptem = 0; | ||||
| 	u32 ptem = 0; | ||||
| 	int i; | ||||
| 	int found = 0; | ||||
| 
 | ||||
| @ -302,6 +313,7 @@ static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum, | ||||
| 	/* And then put in the new SR */ | ||||
| 	sre->raw = value; | ||||
| 	sre->vsid = (value & 0x0fffffff); | ||||
| 	sre->valid = (value & 0x80000000) ? false : true; | ||||
| 	sre->Ks = (value & 0x40000000) ? true : false; | ||||
| 	sre->Kp = (value & 0x20000000) ? true : false; | ||||
| 	sre->nx = (value & 0x10000000) ? true : false; | ||||
| @ -312,36 +324,48 @@ static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum, | ||||
| 
 | ||||
| static void kvmppc_mmu_book3s_32_tlbie(struct kvm_vcpu *vcpu, ulong ea, bool large) | ||||
| { | ||||
| 	kvmppc_mmu_pte_flush(vcpu, ea, ~0xFFFULL); | ||||
| 	kvmppc_mmu_pte_flush(vcpu, ea, 0x0FFFF000); | ||||
| } | ||||
| 
 | ||||
| static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, u64 esid, | ||||
| static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, | ||||
| 					     u64 *vsid) | ||||
| { | ||||
| 	ulong ea = esid << SID_SHIFT; | ||||
| 	struct kvmppc_sr *sr; | ||||
| 	u64 gvsid = esid; | ||||
| 
 | ||||
| 	if (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||||
| 		sr = find_sr(to_book3s(vcpu), ea); | ||||
| 		if (sr->valid) | ||||
| 			gvsid = sr->vsid; | ||||
| 	} | ||||
| 
 | ||||
| 	/* In case we only have one of MSR_IR or MSR_DR set, let's put
 | ||||
| 	   that in the real-mode context (and hope RM doesn't access | ||||
| 	   high memory) */ | ||||
| 	switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||||
| 	case 0: | ||||
| 		*vsid = (VSID_REAL >> 16) | esid; | ||||
| 		*vsid = VSID_REAL | esid; | ||||
| 		break; | ||||
| 	case MSR_IR: | ||||
| 		*vsid = (VSID_REAL_IR >> 16) | esid; | ||||
| 		*vsid = VSID_REAL_IR | gvsid; | ||||
| 		break; | ||||
| 	case MSR_DR: | ||||
| 		*vsid = (VSID_REAL_DR >> 16) | esid; | ||||
| 		*vsid = VSID_REAL_DR | gvsid; | ||||
| 		break; | ||||
| 	case MSR_DR|MSR_IR: | ||||
| 	{ | ||||
| 		ulong ea; | ||||
| 		ea = esid << SID_SHIFT; | ||||
| 		*vsid = find_sr(to_book3s(vcpu), ea)->vsid; | ||||
| 		if (!sr->valid) | ||||
| 			return -1; | ||||
| 
 | ||||
| 		*vsid = sr->vsid; | ||||
| 		break; | ||||
| 	} | ||||
| 	default: | ||||
| 		BUG(); | ||||
| 	} | ||||
| 
 | ||||
| 	if (vcpu->arch.msr & MSR_PR) | ||||
| 		*vsid |= VSID_PR; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										483
									
								
								arch/powerpc/kvm/book3s_32_mmu_host.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										483
									
								
								arch/powerpc/kvm/book3s_32_mmu_host.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,483 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved. | ||||
|  * | ||||
|  * Authors: | ||||
|  *     Alexander Graf <agraf@suse.de> | ||||
|  * | ||||
|  * 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. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/kvm_host.h> | ||||
| 
 | ||||
| #include <asm/kvm_ppc.h> | ||||
| #include <asm/kvm_book3s.h> | ||||
| #include <asm/mmu-hash32.h> | ||||
| #include <asm/machdep.h> | ||||
| #include <asm/mmu_context.h> | ||||
| #include <asm/hw_irq.h> | ||||
| 
 | ||||
| /* #define DEBUG_MMU */ | ||||
| /* #define DEBUG_SR */ | ||||
| 
 | ||||
| #ifdef DEBUG_MMU | ||||
| #define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__) | ||||
| #else | ||||
| #define dprintk_mmu(a, ...) do { } while(0) | ||||
| #endif | ||||
| 
 | ||||
| #ifdef DEBUG_SR | ||||
| #define dprintk_sr(a, ...) printk(KERN_INFO a, __VA_ARGS__) | ||||
| #else | ||||
| #define dprintk_sr(a, ...) do { } while(0) | ||||
| #endif | ||||
| 
 | ||||
| #if PAGE_SHIFT != 12 | ||||
| #error Unknown page size | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_SMP | ||||
| #error XXX need to grab mmu_hash_lock | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_PTE_64BIT | ||||
| #error Only 32 bit pages are supported for now | ||||
| #endif | ||||
| 
 | ||||
| static ulong htab; | ||||
| static u32 htabmask; | ||||
| 
 | ||||
| static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) | ||||
| { | ||||
| 	volatile u32 *pteg; | ||||
| 
 | ||||
| 	dprintk_mmu("KVM: Flushing SPTE: 0x%llx (0x%llx) -> 0x%llx\n", | ||||
| 		    pte->pte.eaddr, pte->pte.vpage, pte->host_va); | ||||
| 
 | ||||
| 	pteg = (u32*)pte->slot; | ||||
| 
 | ||||
| 	pteg[0] = 0; | ||||
| 	asm volatile ("sync"); | ||||
| 	asm volatile ("tlbie %0" : : "r" (pte->pte.eaddr) : "memory"); | ||||
| 	asm volatile ("sync"); | ||||
| 	asm volatile ("tlbsync"); | ||||
| 
 | ||||
| 	pte->host_va = 0; | ||||
| 
 | ||||
| 	if (pte->pte.may_write) | ||||
| 		kvm_release_pfn_dirty(pte->pfn); | ||||
| 	else | ||||
| 		kvm_release_pfn_clean(pte->pfn); | ||||
| } | ||||
| 
 | ||||
| void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%x & 0x%x\n", | ||||
| 		    vcpu->arch.hpte_cache_offset, guest_ea, ea_mask); | ||||
| 	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||||
| 
 | ||||
| 	guest_ea &= ea_mask; | ||||
| 	for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) { | ||||
| 		struct hpte_cache *pte; | ||||
| 
 | ||||
| 		pte = &vcpu->arch.hpte_cache[i]; | ||||
| 		if (!pte->host_va) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if ((pte->pte.eaddr & ea_mask) == guest_ea) { | ||||
| 			invalidate_pte(vcpu, pte); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Doing a complete flush -> start from scratch */ | ||||
| 	if (!ea_mask) | ||||
| 		vcpu->arch.hpte_cache_offset = 0; | ||||
| } | ||||
| 
 | ||||
| void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n", | ||||
| 		    vcpu->arch.hpte_cache_offset, guest_vp, vp_mask); | ||||
| 	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||||
| 
 | ||||
| 	guest_vp &= vp_mask; | ||||
| 	for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) { | ||||
| 		struct hpte_cache *pte; | ||||
| 
 | ||||
| 		pte = &vcpu->arch.hpte_cache[i]; | ||||
| 		if (!pte->host_va) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if ((pte->pte.vpage & vp_mask) == guest_vp) { | ||||
| 			invalidate_pte(vcpu, pte); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%llx & 0x%llx\n", | ||||
| 		    vcpu->arch.hpte_cache_offset, pa_start, pa_end); | ||||
| 	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||||
| 
 | ||||
| 	for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) { | ||||
| 		struct hpte_cache *pte; | ||||
| 
 | ||||
| 		pte = &vcpu->arch.hpte_cache[i]; | ||||
| 		if (!pte->host_va) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if ((pte->pte.raddr >= pa_start) && | ||||
| 		    (pte->pte.raddr < pa_end)) { | ||||
| 			invalidate_pte(vcpu, pte); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data) | ||||
| { | ||||
| 	int i; | ||||
| 	u64 guest_vp; | ||||
| 
 | ||||
| 	guest_vp = vcpu->arch.mmu.ea_to_vp(vcpu, ea, false); | ||||
| 	for (i=0; i<vcpu->arch.hpte_cache_offset; i++) { | ||||
| 		struct hpte_cache *pte; | ||||
| 
 | ||||
| 		pte = &vcpu->arch.hpte_cache[i]; | ||||
| 		if (!pte->host_va) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (pte->pte.vpage == guest_vp) | ||||
| 			return &pte->pte; | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static int kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	if (vcpu->arch.hpte_cache_offset == HPTEG_CACHE_NUM) | ||||
| 		kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||||
| 
 | ||||
| 	return vcpu->arch.hpte_cache_offset++; | ||||
| } | ||||
| 
 | ||||
| /* We keep 512 gvsid->hvsid entries, mapping the guest ones to the array using
 | ||||
|  * a hash, so we don't waste cycles on looping */ | ||||
| static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid) | ||||
| { | ||||
| 	return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^ | ||||
| 		     ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^ | ||||
| 		     ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^ | ||||
| 		     ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^ | ||||
| 		     ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^ | ||||
| 		     ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^ | ||||
| 		     ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^ | ||||
| 		     ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid) | ||||
| { | ||||
| 	struct kvmppc_sid_map *map; | ||||
| 	u16 sid_map_mask; | ||||
| 
 | ||||
| 	if (vcpu->arch.msr & MSR_PR) | ||||
| 		gvsid |= VSID_PR; | ||||
| 
 | ||||
| 	sid_map_mask = kvmppc_sid_hash(vcpu, gvsid); | ||||
| 	map = &to_book3s(vcpu)->sid_map[sid_map_mask]; | ||||
| 	if (map->guest_vsid == gvsid) { | ||||
| 		dprintk_sr("SR: Searching 0x%llx -> 0x%llx\n", | ||||
| 			    gvsid, map->host_vsid); | ||||
| 		return map; | ||||
| 	} | ||||
| 
 | ||||
| 	map = &to_book3s(vcpu)->sid_map[SID_MAP_MASK - sid_map_mask]; | ||||
| 	if (map->guest_vsid == gvsid) { | ||||
| 		dprintk_sr("SR: Searching 0x%llx -> 0x%llx\n", | ||||
| 			    gvsid, map->host_vsid); | ||||
| 		return map; | ||||
| 	} | ||||
| 
 | ||||
| 	dprintk_sr("SR: Searching 0x%llx -> not found\n", gvsid); | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static u32 *kvmppc_mmu_get_pteg(struct kvm_vcpu *vcpu, u32 vsid, u32 eaddr, | ||||
| 				bool primary) | ||||
| { | ||||
| 	u32 page, hash; | ||||
| 	ulong pteg = htab; | ||||
| 
 | ||||
| 	page = (eaddr & ~ESID_MASK) >> 12; | ||||
| 
 | ||||
| 	hash = ((vsid ^ page) << 6); | ||||
| 	if (!primary) | ||||
| 		hash = ~hash; | ||||
| 
 | ||||
| 	hash &= htabmask; | ||||
| 
 | ||||
| 	pteg |= hash; | ||||
| 
 | ||||
| 	dprintk_mmu("htab: %lx | hash: %x | htabmask: %x | pteg: %lx\n", | ||||
| 		htab, hash, htabmask, pteg); | ||||
| 
 | ||||
| 	return (u32*)pteg; | ||||
| } | ||||
| 
 | ||||
| extern char etext[]; | ||||
| 
 | ||||
| int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) | ||||
| { | ||||
| 	pfn_t hpaddr; | ||||
| 	u64 va; | ||||
| 	u64 vsid; | ||||
| 	struct kvmppc_sid_map *map; | ||||
| 	volatile u32 *pteg; | ||||
| 	u32 eaddr = orig_pte->eaddr; | ||||
| 	u32 pteg0, pteg1; | ||||
| 	register int rr = 0; | ||||
| 	bool primary = false; | ||||
| 	bool evict = false; | ||||
| 	int hpte_id; | ||||
| 	struct hpte_cache *pte; | ||||
| 
 | ||||
| 	/* Get host physical address for gpa */ | ||||
| 	hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); | ||||
| 	if (kvm_is_error_hva(hpaddr)) { | ||||
| 		printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", | ||||
| 				 orig_pte->eaddr); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	hpaddr <<= PAGE_SHIFT; | ||||
| 
 | ||||
| 	/* and write the mapping ea -> hpa into the pt */ | ||||
| 	vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid); | ||||
| 	map = find_sid_vsid(vcpu, vsid); | ||||
| 	if (!map) { | ||||
| 		kvmppc_mmu_map_segment(vcpu, eaddr); | ||||
| 		map = find_sid_vsid(vcpu, vsid); | ||||
| 	} | ||||
| 	BUG_ON(!map); | ||||
| 
 | ||||
| 	vsid = map->host_vsid; | ||||
| 	va = (vsid << SID_SHIFT) | (eaddr & ~ESID_MASK); | ||||
| 
 | ||||
| next_pteg: | ||||
| 	if (rr == 16) { | ||||
| 		primary = !primary; | ||||
| 		evict = true; | ||||
| 		rr = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	pteg = kvmppc_mmu_get_pteg(vcpu, vsid, eaddr, primary); | ||||
| 
 | ||||
| 	/* not evicting yet */ | ||||
| 	if (!evict && (pteg[rr] & PTE_V)) { | ||||
| 		rr += 2; | ||||
| 		goto next_pteg; | ||||
| 	} | ||||
| 
 | ||||
| 	dprintk_mmu("KVM: old PTEG: %p (%d)\n", pteg, rr); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[0], pteg[1]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[2], pteg[3]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[4], pteg[5]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[6], pteg[7]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[8], pteg[9]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[10], pteg[11]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[12], pteg[13]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[14], pteg[15]); | ||||
| 
 | ||||
| 	pteg0 = ((eaddr & 0x0fffffff) >> 22) | (vsid << 7) | PTE_V | | ||||
| 		(primary ? 0 : PTE_SEC); | ||||
| 	pteg1 = hpaddr | PTE_M | PTE_R | PTE_C; | ||||
| 
 | ||||
| 	if (orig_pte->may_write) { | ||||
| 		pteg1 |= PP_RWRW; | ||||
| 		mark_page_dirty(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); | ||||
| 	} else { | ||||
| 		pteg1 |= PP_RWRX; | ||||
| 	} | ||||
| 
 | ||||
| 	local_irq_disable(); | ||||
| 
 | ||||
| 	if (pteg[rr]) { | ||||
| 		pteg[rr] = 0; | ||||
| 		asm volatile ("sync"); | ||||
| 	} | ||||
| 	pteg[rr + 1] = pteg1; | ||||
| 	pteg[rr] = pteg0; | ||||
| 	asm volatile ("sync"); | ||||
| 
 | ||||
| 	local_irq_enable(); | ||||
| 
 | ||||
| 	dprintk_mmu("KVM: new PTEG: %p\n", pteg); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[0], pteg[1]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[2], pteg[3]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[4], pteg[5]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[6], pteg[7]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[8], pteg[9]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[10], pteg[11]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[12], pteg[13]); | ||||
| 	dprintk_mmu("KVM:   %08x - %08x\n", pteg[14], pteg[15]); | ||||
| 
 | ||||
| 
 | ||||
| 	/* Now tell our Shadow PTE code about the new page */ | ||||
| 
 | ||||
| 	hpte_id = kvmppc_mmu_hpte_cache_next(vcpu); | ||||
| 	pte = &vcpu->arch.hpte_cache[hpte_id]; | ||||
| 
 | ||||
| 	dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%llx (0x%llx) -> %lx\n", | ||||
| 		    orig_pte->may_write ? 'w' : '-', | ||||
| 		    orig_pte->may_execute ? 'x' : '-', | ||||
| 		    orig_pte->eaddr, (ulong)pteg, va, | ||||
| 		    orig_pte->vpage, hpaddr); | ||||
| 
 | ||||
| 	pte->slot = (ulong)&pteg[rr]; | ||||
| 	pte->host_va = va; | ||||
| 	pte->pte = *orig_pte; | ||||
| 	pte->pfn = hpaddr >> PAGE_SHIFT; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid) | ||||
| { | ||||
| 	struct kvmppc_sid_map *map; | ||||
| 	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||||
| 	u16 sid_map_mask; | ||||
| 	static int backwards_map = 0; | ||||
| 
 | ||||
| 	if (vcpu->arch.msr & MSR_PR) | ||||
| 		gvsid |= VSID_PR; | ||||
| 
 | ||||
| 	/* We might get collisions that trap in preceding order, so let's
 | ||||
| 	   map them differently */ | ||||
| 
 | ||||
| 	sid_map_mask = kvmppc_sid_hash(vcpu, gvsid); | ||||
| 	if (backwards_map) | ||||
| 		sid_map_mask = SID_MAP_MASK - sid_map_mask; | ||||
| 
 | ||||
| 	map = &to_book3s(vcpu)->sid_map[sid_map_mask]; | ||||
| 
 | ||||
| 	/* Make sure we're taking the other map next time */ | ||||
| 	backwards_map = !backwards_map; | ||||
| 
 | ||||
| 	/* Uh-oh ... out of mappings. Let's flush! */ | ||||
| 	if (vcpu_book3s->vsid_next >= vcpu_book3s->vsid_max) { | ||||
| 		vcpu_book3s->vsid_next = vcpu_book3s->vsid_first; | ||||
| 		memset(vcpu_book3s->sid_map, 0, | ||||
| 		       sizeof(struct kvmppc_sid_map) * SID_MAP_NUM); | ||||
| 		kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||||
| 		kvmppc_mmu_flush_segments(vcpu); | ||||
| 	} | ||||
| 	map->host_vsid = vcpu_book3s->vsid_next; | ||||
| 
 | ||||
| 	/* Would have to be 111 to be completely aligned with the rest of
 | ||||
| 	   Linux, but that is just way too little space! */ | ||||
| 	vcpu_book3s->vsid_next+=1; | ||||
| 
 | ||||
| 	map->guest_vsid = gvsid; | ||||
| 	map->valid = true; | ||||
| 
 | ||||
| 	return map; | ||||
| } | ||||
| 
 | ||||
| int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr) | ||||
| { | ||||
| 	u32 esid = eaddr >> SID_SHIFT; | ||||
| 	u64 gvsid; | ||||
| 	u32 sr; | ||||
| 	struct kvmppc_sid_map *map; | ||||
| 	struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu); | ||||
| 
 | ||||
| 	if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) { | ||||
| 		/* Invalidate an entry */ | ||||
| 		svcpu->sr[esid] = SR_INVALID; | ||||
| 		return -ENOENT; | ||||
| 	} | ||||
| 
 | ||||
| 	map = find_sid_vsid(vcpu, gvsid); | ||||
| 	if (!map) | ||||
| 		map = create_sid_map(vcpu, gvsid); | ||||
| 
 | ||||
| 	map->guest_esid = esid; | ||||
| 	sr = map->host_vsid | SR_KP; | ||||
| 	svcpu->sr[esid] = sr; | ||||
| 
 | ||||
| 	dprintk_sr("MMU: mtsr %d, 0x%x\n", esid, sr); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	int i; | ||||
| 	struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu); | ||||
| 
 | ||||
| 	dprintk_sr("MMU: flushing all segments (%d)\n", ARRAY_SIZE(svcpu->sr)); | ||||
| 	for (i = 0; i < ARRAY_SIZE(svcpu->sr); i++) | ||||
| 		svcpu->sr[i] = SR_INVALID; | ||||
| } | ||||
| 
 | ||||
| void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||||
| 	preempt_disable(); | ||||
| 	__destroy_context(to_book3s(vcpu)->context_id); | ||||
| 	preempt_enable(); | ||||
| } | ||||
| 
 | ||||
| /* From mm/mmu_context_hash32.c */ | ||||
| #define CTX_TO_VSID(ctx) (((ctx) * (897 * 16)) & 0xffffff) | ||||
| 
 | ||||
| int kvmppc_mmu_init(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); | ||||
| 	int err; | ||||
| 	ulong sdr1; | ||||
| 
 | ||||
| 	err = __init_new_context(); | ||||
| 	if (err < 0) | ||||
| 		return -1; | ||||
| 	vcpu3s->context_id = err; | ||||
| 
 | ||||
| 	vcpu3s->vsid_max = CTX_TO_VSID(vcpu3s->context_id + 1) - 1; | ||||
| 	vcpu3s->vsid_first = CTX_TO_VSID(vcpu3s->context_id); | ||||
| 
 | ||||
| #if 0 /* XXX still doesn't guarantee uniqueness */
 | ||||
| 	/* We could collide with the Linux vsid space because the vsid
 | ||||
| 	 * wraps around at 24 bits. We're safe if we do our own space | ||||
| 	 * though, so let's always set the highest bit. */ | ||||
| 
 | ||||
| 	vcpu3s->vsid_max |= 0x00800000; | ||||
| 	vcpu3s->vsid_first |= 0x00800000; | ||||
| #endif | ||||
| 	BUG_ON(vcpu3s->vsid_max < vcpu3s->vsid_first); | ||||
| 
 | ||||
| 	vcpu3s->vsid_next = vcpu3s->vsid_first; | ||||
| 
 | ||||
| 	/* Remember where the HTAB is */ | ||||
| 	asm ( "mfsdr1 %0" : "=r"(sdr1) ); | ||||
| 	htabmask = ((sdr1 & 0x1FF) << 16) | 0xFFC0; | ||||
| 	htab = (ulong)__va(sdr1 & 0xffff0000); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										143
									
								
								arch/powerpc/kvm/book3s_32_sr.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								arch/powerpc/kvm/book3s_32_sr.S
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,143 @@ | ||||
| /* | ||||
|  * 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 SUSE Linux Products GmbH 2009 | ||||
|  * | ||||
|  * Authors: Alexander Graf <agraf@suse.de>
 | ||||
|  */ | ||||
| 
 | ||||
| /****************************************************************************** | ||||
|  *                                                                            * | ||||
|  *                               Entry code                                   * | ||||
|  *                                                                            * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| .macro LOAD_GUEST_SEGMENTS
 | ||||
| 
 | ||||
| 	/* Required state: | ||||
| 	 * | ||||
| 	 * MSR = ~IR|DR | ||||
| 	 * R1 = host R1 | ||||
| 	 * R2 = host R2 | ||||
| 	 * R3 = shadow vcpu | ||||
| 	 * all other volatile GPRS = free | ||||
| 	 * SVCPU[CR]  = guest CR | ||||
| 	 * SVCPU[XER] = guest XER | ||||
| 	 * SVCPU[CTR] = guest CTR | ||||
| 	 * SVCPU[LR]  = guest LR | ||||
| 	 */ | ||||
| 
 | ||||
| #define XCHG_SR(n)	lwz	r9, (SVCPU_SR+(n*4))(r3);  \
 | ||||
| 			mtsr	n, r9 | ||||
| 
 | ||||
| 	XCHG_SR(0) | ||||
| 	XCHG_SR(1) | ||||
| 	XCHG_SR(2) | ||||
| 	XCHG_SR(3) | ||||
| 	XCHG_SR(4) | ||||
| 	XCHG_SR(5) | ||||
| 	XCHG_SR(6) | ||||
| 	XCHG_SR(7) | ||||
| 	XCHG_SR(8) | ||||
| 	XCHG_SR(9) | ||||
| 	XCHG_SR(10) | ||||
| 	XCHG_SR(11) | ||||
| 	XCHG_SR(12) | ||||
| 	XCHG_SR(13) | ||||
| 	XCHG_SR(14) | ||||
| 	XCHG_SR(15) | ||||
| 
 | ||||
| 	/* Clear BATs. */ | ||||
| 
 | ||||
| #define KVM_KILL_BAT(n, reg)		\ | ||||
|         mtspr   SPRN_IBAT##n##U,reg;	\ | ||||
|         mtspr   SPRN_IBAT##n##L,reg;	\ | ||||
|         mtspr   SPRN_DBAT##n##U,reg;	\ | ||||
|         mtspr   SPRN_DBAT##n##L,reg;	\ | ||||
| 
 | ||||
|         li	r9, 0 | ||||
| 	KVM_KILL_BAT(0, r9) | ||||
| 	KVM_KILL_BAT(1, r9) | ||||
| 	KVM_KILL_BAT(2, r9) | ||||
| 	KVM_KILL_BAT(3, r9) | ||||
| 
 | ||||
| .endm | ||||
| 
 | ||||
| /****************************************************************************** | ||||
|  *                                                                            * | ||||
|  *                               Exit code                                    * | ||||
|  *                                                                            * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| .macro LOAD_HOST_SEGMENTS
 | ||||
| 
 | ||||
| 	/* Register usage at this point: | ||||
| 	 * | ||||
| 	 * R1         = host R1 | ||||
| 	 * R2         = host R2 | ||||
| 	 * R12        = exit handler id | ||||
| 	 * R13        = shadow vcpu - SHADOW_VCPU_OFF | ||||
| 	 * SVCPU.*    = guest * | ||||
| 	 * SVCPU[CR]  = guest CR | ||||
| 	 * SVCPU[XER] = guest XER | ||||
| 	 * SVCPU[CTR] = guest CTR | ||||
| 	 * SVCPU[LR]  = guest LR | ||||
| 	 * | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* Restore BATs */ | ||||
| 
 | ||||
| 	/* We only overwrite the upper part, so we only restoree | ||||
| 	   the upper part. */ | ||||
| #define KVM_LOAD_BAT(n, reg, RA, RB)	\ | ||||
| 	lwz	RA,(n*16)+0(reg);	\
 | ||||
| 	lwz	RB,(n*16)+4(reg);	\
 | ||||
| 	mtspr	SPRN_IBAT##n##U,RA;	\ | ||||
| 	mtspr	SPRN_IBAT##n##L,RB;	\ | ||||
| 	lwz	RA,(n*16)+8(reg);	\
 | ||||
| 	lwz	RB,(n*16)+12(reg);	\
 | ||||
| 	mtspr	SPRN_DBAT##n##U,RA;	\ | ||||
| 	mtspr	SPRN_DBAT##n##L,RB;	\ | ||||
| 
 | ||||
| 	lis     r9, BATS@ha
 | ||||
| 	addi    r9, r9, BATS@l
 | ||||
| 	tophys(r9, r9) | ||||
| 	KVM_LOAD_BAT(0, r9, r10, r11) | ||||
| 	KVM_LOAD_BAT(1, r9, r10, r11) | ||||
| 	KVM_LOAD_BAT(2, r9, r10, r11) | ||||
| 	KVM_LOAD_BAT(3, r9, r10, r11) | ||||
| 
 | ||||
| 	/* Restore Segment Registers */ | ||||
| 
 | ||||
| 	/* 0xc - 0xf */ | ||||
| 
 | ||||
|         li      r0, 4 | ||||
|         mtctr   r0 | ||||
| 	LOAD_REG_IMMEDIATE(r3, 0x20000000 | (0x111 * 0xc)) | ||||
|         lis     r4, 0xc000 | ||||
| 3:      mtsrin  r3, r4 | ||||
|         addi    r3, r3, 0x111     /* increment VSID */ | ||||
|         addis   r4, r4, 0x1000    /* address of next segment */ | ||||
|         bdnz    3b | ||||
| 
 | ||||
| 	/* 0x0 - 0xb */ | ||||
| 
 | ||||
| 	/* 'current->mm' needs to be in r4 */ | ||||
| 	tophys(r4, r2) | ||||
| 	lwz	r4, MM(r4) | ||||
| 	tophys(r4, r4) | ||||
| 	/* This only clobbers r0, r3, r4 and r5 */ | ||||
| 	bl	switch_mmu_context | ||||
| 
 | ||||
| .endm | ||||
| @ -232,7 +232,7 @@ do_second: | ||||
| 			} | ||||
| 
 | ||||
| 			dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx " | ||||
| 				"-> 0x%llx\n", | ||||
| 				"-> 0x%lx\n", | ||||
| 				eaddr, avpn, gpte->vpage, gpte->raddr); | ||||
| 			found = true; | ||||
| 			break; | ||||
| @ -383,7 +383,7 @@ static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu) | ||||
| 
 | ||||
| 	if (vcpu->arch.msr & MSR_IR) { | ||||
| 		kvmppc_mmu_flush_segments(vcpu); | ||||
| 		kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc); | ||||
| 		kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -439,37 +439,43 @@ static void kvmppc_mmu_book3s_64_tlbie(struct kvm_vcpu *vcpu, ulong va, | ||||
| 	kvmppc_mmu_pte_vflush(vcpu, va >> 12, mask); | ||||
| } | ||||
| 
 | ||||
| static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, u64 esid, | ||||
| static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, | ||||
| 					     u64 *vsid) | ||||
| { | ||||
| 	switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||||
| 	case 0: | ||||
| 		*vsid = (VSID_REAL >> 16) | esid; | ||||
| 		break; | ||||
| 	case MSR_IR: | ||||
| 		*vsid = (VSID_REAL_IR >> 16) | esid; | ||||
| 		break; | ||||
| 	case MSR_DR: | ||||
| 		*vsid = (VSID_REAL_DR >> 16) | esid; | ||||
| 		break; | ||||
| 	case MSR_DR|MSR_IR: | ||||
| 	{ | ||||
| 		ulong ea; | ||||
| 		struct kvmppc_slb *slb; | ||||
| 		ea = esid << SID_SHIFT; | ||||
| 	ulong ea = esid << SID_SHIFT; | ||||
| 	struct kvmppc_slb *slb; | ||||
| 	u64 gvsid = esid; | ||||
| 
 | ||||
| 	if (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||||
| 		slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea); | ||||
| 		if (slb) | ||||
| 			*vsid = slb->vsid; | ||||
| 		else | ||||
| 			gvsid = slb->vsid; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||||
| 	case 0: | ||||
| 		*vsid = VSID_REAL | esid; | ||||
| 		break; | ||||
| 	case MSR_IR: | ||||
| 		*vsid = VSID_REAL_IR | gvsid; | ||||
| 		break; | ||||
| 	case MSR_DR: | ||||
| 		*vsid = VSID_REAL_DR | gvsid; | ||||
| 		break; | ||||
| 	case MSR_DR|MSR_IR: | ||||
| 		if (!slb) | ||||
| 			return -ENOENT; | ||||
| 
 | ||||
| 		*vsid = gvsid; | ||||
| 		break; | ||||
| 	} | ||||
| 	default: | ||||
| 		BUG(); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (vcpu->arch.msr & MSR_PR) | ||||
| 		*vsid |= VSID_PR; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -48,21 +48,25 @@ | ||||
| 
 | ||||
| static void invalidate_pte(struct hpte_cache *pte) | ||||
| { | ||||
| 	dprintk_mmu("KVM: Flushing SPT %d: 0x%llx (0x%llx) -> 0x%llx\n", | ||||
| 		    i, pte->pte.eaddr, pte->pte.vpage, pte->host_va); | ||||
| 	dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n", | ||||
| 		    pte->pte.eaddr, pte->pte.vpage, pte->host_va); | ||||
| 
 | ||||
| 	ppc_md.hpte_invalidate(pte->slot, pte->host_va, | ||||
| 			       MMU_PAGE_4K, MMU_SEGSIZE_256M, | ||||
| 			       false); | ||||
| 	pte->host_va = 0; | ||||
| 	kvm_release_pfn_dirty(pte->pfn); | ||||
| 
 | ||||
| 	if (pte->pte.may_write) | ||||
| 		kvm_release_pfn_dirty(pte->pfn); | ||||
| 	else | ||||
| 		kvm_release_pfn_clean(pte->pfn); | ||||
| } | ||||
| 
 | ||||
| void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, u64 guest_ea, u64 ea_mask) | ||||
| void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%llx & 0x%llx\n", | ||||
| 	dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n", | ||||
| 		    vcpu->arch.hpte_cache_offset, guest_ea, ea_mask); | ||||
| 	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||||
| 
 | ||||
| @ -106,12 +110,12 @@ void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, u64 pa_start, u64 pa_end) | ||||
| void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%llx & 0x%llx\n", | ||||
| 		    vcpu->arch.hpte_cache_offset, guest_pa, pa_mask); | ||||
| 	dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx & 0x%lx\n", | ||||
| 		    vcpu->arch.hpte_cache_offset, pa_start, pa_end); | ||||
| 	BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||||
| 
 | ||||
| 	for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) { | ||||
| @ -182,7 +186,7 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid) | ||||
| 	sid_map_mask = kvmppc_sid_hash(vcpu, gvsid); | ||||
| 	map = &to_book3s(vcpu)->sid_map[sid_map_mask]; | ||||
| 	if (map->guest_vsid == gvsid) { | ||||
| 		dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n", | ||||
| 		dprintk_slb("SLB: Searching: 0x%llx -> 0x%llx\n", | ||||
| 			    gvsid, map->host_vsid); | ||||
| 		return map; | ||||
| 	} | ||||
| @ -194,7 +198,8 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid) | ||||
| 		return map; | ||||
| 	} | ||||
| 
 | ||||
| 	dprintk_slb("SLB: Searching 0x%llx -> not found\n", gvsid); | ||||
| 	dprintk_slb("SLB: Searching %d/%d: 0x%llx -> not found\n", | ||||
| 		    sid_map_mask, SID_MAP_MASK - sid_map_mask, gvsid); | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| @ -212,7 +217,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) | ||||
| 	/* Get host physical address for gpa */ | ||||
| 	hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); | ||||
| 	if (kvm_is_error_hva(hpaddr)) { | ||||
| 		printk(KERN_INFO "Couldn't get guest page for gfn %llx!\n", orig_pte->eaddr); | ||||
| 		printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	hpaddr <<= PAGE_SHIFT; | ||||
| @ -227,10 +232,16 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) | ||||
| 	vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid); | ||||
| 	map = find_sid_vsid(vcpu, vsid); | ||||
| 	if (!map) { | ||||
| 		kvmppc_mmu_map_segment(vcpu, orig_pte->eaddr); | ||||
| 		ret = kvmppc_mmu_map_segment(vcpu, orig_pte->eaddr); | ||||
| 		WARN_ON(ret < 0); | ||||
| 		map = find_sid_vsid(vcpu, vsid); | ||||
| 	} | ||||
| 	BUG_ON(!map); | ||||
| 	if (!map) { | ||||
| 		printk(KERN_ERR "KVM: Segment map for 0x%llx (0x%lx) failed\n", | ||||
| 				vsid, orig_pte->eaddr); | ||||
| 		WARN_ON(true); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	vsid = map->host_vsid; | ||||
| 	va = hpt_va(orig_pte->eaddr, vsid, MMU_SEGSIZE_256M); | ||||
| @ -257,26 +268,26 @@ map_again: | ||||
| 
 | ||||
| 	if (ret < 0) { | ||||
| 		/* If we couldn't map a primary PTE, try a secondary */ | ||||
| #ifdef USE_SECONDARY | ||||
| 		hash = ~hash; | ||||
| 		vflags ^= HPTE_V_SECONDARY; | ||||
| 		attempt++; | ||||
| 		if (attempt % 2) | ||||
| 			vflags = HPTE_V_SECONDARY; | ||||
| 		else | ||||
| 			vflags = 0; | ||||
| #else | ||||
| 		attempt = 2; | ||||
| #endif | ||||
| 		goto map_again; | ||||
| 	} else { | ||||
| 		int hpte_id = kvmppc_mmu_hpte_cache_next(vcpu); | ||||
| 		struct hpte_cache *pte = &vcpu->arch.hpte_cache[hpte_id]; | ||||
| 
 | ||||
| 		dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%lx (0x%llx) -> %lx\n", | ||||
| 		dprintk_mmu("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx\n", | ||||
| 			    ((rflags & HPTE_R_PP) == 3) ? '-' : 'w', | ||||
| 			    (rflags & HPTE_R_N) ? '-' : 'x', | ||||
| 			    orig_pte->eaddr, hpteg, va, orig_pte->vpage, hpaddr); | ||||
| 
 | ||||
| 		/* The ppc_md code may give us a secondary entry even though we
 | ||||
| 		   asked for a primary. Fix up. */ | ||||
| 		if ((ret & _PTEIDX_SECONDARY) && !(vflags & HPTE_V_SECONDARY)) { | ||||
| 			hash = ~hash; | ||||
| 			hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); | ||||
| 		} | ||||
| 
 | ||||
| 		pte->slot = hpteg + (ret & 7); | ||||
| 		pte->host_va = va; | ||||
| 		pte->pte = *orig_pte; | ||||
| @ -321,6 +332,9 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid) | ||||
| 	map->guest_vsid = gvsid; | ||||
| 	map->valid = true; | ||||
| 
 | ||||
| 	dprintk_slb("SLB: New mapping at %d: 0x%llx -> 0x%llx\n", | ||||
| 		    sid_map_mask, gvsid, map->host_vsid); | ||||
| 
 | ||||
| 	return map; | ||||
| } | ||||
| 
 | ||||
| @ -331,14 +345,14 @@ static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid) | ||||
| 	int found_inval = -1; | ||||
| 	int r; | ||||
| 
 | ||||
| 	if (!get_paca()->kvm_slb_max) | ||||
| 		get_paca()->kvm_slb_max = 1; | ||||
| 	if (!to_svcpu(vcpu)->slb_max) | ||||
| 		to_svcpu(vcpu)->slb_max = 1; | ||||
| 
 | ||||
| 	/* Are we overwriting? */ | ||||
| 	for (i = 1; i < get_paca()->kvm_slb_max; i++) { | ||||
| 		if (!(get_paca()->kvm_slb[i].esid & SLB_ESID_V)) | ||||
| 	for (i = 1; i < to_svcpu(vcpu)->slb_max; i++) { | ||||
| 		if (!(to_svcpu(vcpu)->slb[i].esid & SLB_ESID_V)) | ||||
| 			found_inval = i; | ||||
| 		else if ((get_paca()->kvm_slb[i].esid & ESID_MASK) == esid) | ||||
| 		else if ((to_svcpu(vcpu)->slb[i].esid & ESID_MASK) == esid) | ||||
| 			return i; | ||||
| 	} | ||||
| 
 | ||||
| @ -352,11 +366,11 @@ static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid) | ||||
| 		max_slb_size = mmu_slb_size; | ||||
| 
 | ||||
| 	/* Overflowing -> purge */ | ||||
| 	if ((get_paca()->kvm_slb_max) == max_slb_size) | ||||
| 	if ((to_svcpu(vcpu)->slb_max) == max_slb_size) | ||||
| 		kvmppc_mmu_flush_segments(vcpu); | ||||
| 
 | ||||
| 	r = get_paca()->kvm_slb_max; | ||||
| 	get_paca()->kvm_slb_max++; | ||||
| 	r = to_svcpu(vcpu)->slb_max; | ||||
| 	to_svcpu(vcpu)->slb_max++; | ||||
| 
 | ||||
| 	return r; | ||||
| } | ||||
| @ -374,7 +388,7 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr) | ||||
| 
 | ||||
| 	if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) { | ||||
| 		/* Invalidate an entry */ | ||||
| 		get_paca()->kvm_slb[slb_index].esid = 0; | ||||
| 		to_svcpu(vcpu)->slb[slb_index].esid = 0; | ||||
| 		return -ENOENT; | ||||
| 	} | ||||
| 
 | ||||
| @ -388,8 +402,8 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr) | ||||
| 	slb_vsid &= ~SLB_VSID_KP; | ||||
| 	slb_esid |= slb_index; | ||||
| 
 | ||||
| 	get_paca()->kvm_slb[slb_index].esid = slb_esid; | ||||
| 	get_paca()->kvm_slb[slb_index].vsid = slb_vsid; | ||||
| 	to_svcpu(vcpu)->slb[slb_index].esid = slb_esid; | ||||
| 	to_svcpu(vcpu)->slb[slb_index].vsid = slb_vsid; | ||||
| 
 | ||||
| 	dprintk_slb("slbmte %#llx, %#llx\n", slb_vsid, slb_esid); | ||||
| 
 | ||||
| @ -398,11 +412,29 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr) | ||||
| 
 | ||||
| void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	get_paca()->kvm_slb_max = 1; | ||||
| 	get_paca()->kvm_slb[0].esid = 0; | ||||
| 	to_svcpu(vcpu)->slb_max = 1; | ||||
| 	to_svcpu(vcpu)->slb[0].esid = 0; | ||||
| } | ||||
| 
 | ||||
| void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||||
| 	__destroy_context(to_book3s(vcpu)->context_id); | ||||
| } | ||||
| 
 | ||||
| int kvmppc_mmu_init(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = __init_new_context(); | ||||
| 	if (err < 0) | ||||
| 		return -1; | ||||
| 	vcpu3s->context_id = err; | ||||
| 
 | ||||
| 	vcpu3s->vsid_max = ((vcpu3s->context_id + 1) << USER_ESID_BITS) - 1; | ||||
| 	vcpu3s->vsid_first = vcpu3s->context_id << USER_ESID_BITS; | ||||
| 	vcpu3s->vsid_next = vcpu3s->vsid_first; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -44,8 +44,7 @@ slb_exit_skip_ ## num: | ||||
|  *                                                                            * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| .global kvmppc_handler_trampoline_enter
 | ||||
| kvmppc_handler_trampoline_enter: | ||||
| .macro LOAD_GUEST_SEGMENTS
 | ||||
| 
 | ||||
| 	/* Required state: | ||||
| 	 * | ||||
| @ -53,20 +52,14 @@ kvmppc_handler_trampoline_enter: | ||||
| 	 * R13 = PACA | ||||
| 	 * R1 = host R1 | ||||
| 	 * R2 = host R2 | ||||
| 	 * R9 = guest IP | ||||
| 	 * R10 = guest MSR | ||||
| 	 * all other GPRS = free | ||||
| 	 * PACA[KVM_CR] = guest CR | ||||
| 	 * PACA[KVM_XER] = guest XER | ||||
| 	 * R3 = shadow vcpu | ||||
| 	 * all other volatile GPRS = free | ||||
| 	 * SVCPU[CR]  = guest CR | ||||
| 	 * SVCPU[XER] = guest XER | ||||
| 	 * SVCPU[CTR] = guest CTR | ||||
| 	 * SVCPU[LR]  = guest LR | ||||
| 	 */ | ||||
| 
 | ||||
| 	mtsrr0	r9 | ||||
| 	mtsrr1	r10 | ||||
| 
 | ||||
| 	/* Activate guest mode, so faults get handled by KVM */ | ||||
| 	li	r11, KVM_GUEST_MODE_GUEST | ||||
| 	stb	r11, PACA_KVM_IN_GUEST(r13) | ||||
| 
 | ||||
| 	/* Remove LPAR shadow entries */ | ||||
| 
 | ||||
| #if SLB_NUM_BOLTED == 3 | ||||
| @ -101,14 +94,14 @@ kvmppc_handler_trampoline_enter: | ||||
| 
 | ||||
| 	/* Fill SLB with our shadow */ | ||||
| 
 | ||||
| 	lbz	r12, PACA_KVM_SLB_MAX(r13) | ||||
| 	lbz	r12, SVCPU_SLB_MAX(r3) | ||||
| 	mulli	r12, r12, 16 | ||||
| 	addi	r12, r12, PACA_KVM_SLB | ||||
| 	add	r12, r12, r13 | ||||
| 	addi	r12, r12, SVCPU_SLB | ||||
| 	add	r12, r12, r3 | ||||
| 
 | ||||
| 	/* for (r11 = kvm_slb; r11 < kvm_slb + kvm_slb_size; r11+=slb_entry) */ | ||||
| 	li	r11, PACA_KVM_SLB | ||||
| 	add	r11, r11, r13 | ||||
| 	li	r11, SVCPU_SLB | ||||
| 	add	r11, r11, r3 | ||||
| 
 | ||||
| slb_loop_enter: | ||||
| 
 | ||||
| @ -127,34 +120,7 @@ slb_loop_enter_skip: | ||||
| 
 | ||||
| slb_do_enter: | ||||
| 
 | ||||
| 	/* Enter guest */ | ||||
| 
 | ||||
| 	ld	r0, (PACA_KVM_R0)(r13) | ||||
| 	ld	r1, (PACA_KVM_R1)(r13) | ||||
| 	ld	r2, (PACA_KVM_R2)(r13) | ||||
| 	ld	r3, (PACA_KVM_R3)(r13) | ||||
| 	ld	r4, (PACA_KVM_R4)(r13) | ||||
| 	ld	r5, (PACA_KVM_R5)(r13) | ||||
| 	ld	r6, (PACA_KVM_R6)(r13) | ||||
| 	ld	r7, (PACA_KVM_R7)(r13) | ||||
| 	ld	r8, (PACA_KVM_R8)(r13) | ||||
| 	ld	r9, (PACA_KVM_R9)(r13) | ||||
| 	ld	r10, (PACA_KVM_R10)(r13) | ||||
| 	ld	r12, (PACA_KVM_R12)(r13) | ||||
| 
 | ||||
| 	lwz	r11, (PACA_KVM_CR)(r13) | ||||
| 	mtcr	r11 | ||||
| 
 | ||||
| 	ld	r11, (PACA_KVM_XER)(r13) | ||||
| 	mtxer	r11 | ||||
| 
 | ||||
| 	ld	r11, (PACA_KVM_R11)(r13) | ||||
| 	ld	r13, (PACA_KVM_R13)(r13) | ||||
| 
 | ||||
| 	RFI | ||||
| kvmppc_handler_trampoline_enter_end: | ||||
| 
 | ||||
| 
 | ||||
| .endm | ||||
| 
 | ||||
| /****************************************************************************** | ||||
|  *                                                                            * | ||||
| @ -162,99 +128,22 @@ kvmppc_handler_trampoline_enter_end: | ||||
|  *                                                                            * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| .global kvmppc_handler_trampoline_exit
 | ||||
| kvmppc_handler_trampoline_exit: | ||||
| .macro LOAD_HOST_SEGMENTS
 | ||||
| 
 | ||||
| 	/* Register usage at this point: | ||||
| 	 * | ||||
| 	 * SPRG_SCRATCH0     = guest R13 | ||||
| 	 * R12               = exit handler id | ||||
| 	 * R13               = PACA | ||||
| 	 * PACA.KVM.SCRATCH0 = guest R12 | ||||
| 	 * PACA.KVM.SCRATCH1 = guest CR | ||||
| 	 * R1         = host R1 | ||||
| 	 * R2         = host R2 | ||||
| 	 * R12        = exit handler id | ||||
| 	 * R13        = shadow vcpu - SHADOW_VCPU_OFF [=PACA on PPC64] | ||||
| 	 * SVCPU.*    = guest * | ||||
| 	 * SVCPU[CR]  = guest CR | ||||
| 	 * SVCPU[XER] = guest XER | ||||
| 	 * SVCPU[CTR] = guest CTR | ||||
| 	 * SVCPU[LR]  = guest LR | ||||
| 	 * | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* Save registers */ | ||||
| 
 | ||||
| 	std	r0, PACA_KVM_R0(r13) | ||||
| 	std	r1, PACA_KVM_R1(r13) | ||||
| 	std	r2, PACA_KVM_R2(r13) | ||||
| 	std	r3, PACA_KVM_R3(r13) | ||||
| 	std	r4, PACA_KVM_R4(r13) | ||||
| 	std	r5, PACA_KVM_R5(r13) | ||||
| 	std	r6, PACA_KVM_R6(r13) | ||||
| 	std	r7, PACA_KVM_R7(r13) | ||||
| 	std	r8, PACA_KVM_R8(r13) | ||||
| 	std	r9, PACA_KVM_R9(r13) | ||||
| 	std	r10, PACA_KVM_R10(r13) | ||||
| 	std	r11, PACA_KVM_R11(r13) | ||||
| 
 | ||||
| 	/* Restore R1/R2 so we can handle faults */ | ||||
| 	ld	r1, PACA_KVM_HOST_R1(r13) | ||||
| 	ld	r2, PACA_KVM_HOST_R2(r13) | ||||
| 
 | ||||
| 	/* Save guest PC and MSR in GPRs */ | ||||
| 	mfsrr0	r3 | ||||
| 	mfsrr1	r4 | ||||
| 
 | ||||
| 	/* Get scratch'ed off registers */ | ||||
| 	mfspr	r9, SPRN_SPRG_SCRATCH0 | ||||
| 	std	r9, PACA_KVM_R13(r13) | ||||
| 
 | ||||
| 	ld	r8, PACA_KVM_SCRATCH0(r13) | ||||
| 	std	r8, PACA_KVM_R12(r13) | ||||
| 
 | ||||
| 	lwz	r7, PACA_KVM_SCRATCH1(r13) | ||||
| 	stw	r7, PACA_KVM_CR(r13) | ||||
| 
 | ||||
| 	/* Save more register state  */ | ||||
| 
 | ||||
| 	mfxer	r6 | ||||
| 	stw	r6, PACA_KVM_XER(r13) | ||||
| 
 | ||||
| 	mfdar	r5 | ||||
| 	mfdsisr	r6 | ||||
| 
 | ||||
| 	/* | ||||
| 	 * In order for us to easily get the last instruction, | ||||
| 	 * we got the #vmexit at, we exploit the fact that the | ||||
| 	 * virtual layout is still the same here, so we can just | ||||
| 	 * ld from the guest's PC address | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* We only load the last instruction when it's safe */ | ||||
| 	cmpwi	r12, BOOK3S_INTERRUPT_DATA_STORAGE | ||||
| 	beq	ld_last_inst | ||||
| 	cmpwi	r12, BOOK3S_INTERRUPT_PROGRAM | ||||
| 	beq	ld_last_inst | ||||
| 
 | ||||
| 	b	no_ld_last_inst | ||||
| 
 | ||||
| ld_last_inst: | ||||
| 	/* Save off the guest instruction we're at */ | ||||
| 
 | ||||
| 	/* Set guest mode to 'jump over instruction' so if lwz faults | ||||
| 	 * we'll just continue at the next IP. */ | ||||
| 	li	r9, KVM_GUEST_MODE_SKIP | ||||
| 	stb	r9, PACA_KVM_IN_GUEST(r13) | ||||
| 
 | ||||
| 	/*    1) enable paging for data */ | ||||
| 	mfmsr	r9 | ||||
| 	ori	r11, r9, MSR_DR			/* Enable paging for data */ | ||||
| 	mtmsr	r11 | ||||
| 	/*    2) fetch the instruction */ | ||||
| 	li	r0, KVM_INST_FETCH_FAILED	/* In case lwz faults */ | ||||
| 	lwz	r0, 0(r3) | ||||
| 	/*    3) disable paging again */ | ||||
| 	mtmsr	r9 | ||||
| 
 | ||||
| no_ld_last_inst: | ||||
| 
 | ||||
| 	/* Unset guest mode */ | ||||
| 	li	r9, KVM_GUEST_MODE_NONE | ||||
| 	stb	r9, PACA_KVM_IN_GUEST(r13) | ||||
| 
 | ||||
| 	/* Restore bolted entries from the shadow and fix it along the way */ | ||||
| 
 | ||||
| 	/* We don't store anything in entry 0, so we don't need to take care of it */ | ||||
| @ -275,28 +164,4 @@ no_ld_last_inst: | ||||
| 
 | ||||
| slb_do_exit: | ||||
| 
 | ||||
| 	/* Register usage at this point: | ||||
| 	 * | ||||
| 	 * R0         = guest last inst | ||||
| 	 * R1         = host R1 | ||||
| 	 * R2         = host R2 | ||||
| 	 * R3         = guest PC | ||||
| 	 * R4         = guest MSR | ||||
| 	 * R5         = guest DAR | ||||
| 	 * R6         = guest DSISR | ||||
| 	 * R12        = exit handler id | ||||
| 	 * R13        = PACA | ||||
| 	 * PACA.KVM.* = guest * | ||||
| 	 * | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* RFI into the highmem handler */ | ||||
| 	mfmsr	r7 | ||||
| 	ori	r7, r7, MSR_IR|MSR_DR|MSR_RI	/* Enable paging */ | ||||
| 	mtsrr1	r7 | ||||
| 	ld	r8, PACA_KVM_VMHANDLER(r13)	/* Highmem handler address */ | ||||
| 	mtsrr0	r8 | ||||
| 
 | ||||
| 	RFI | ||||
| kvmppc_handler_trampoline_exit_end: | ||||
| 
 | ||||
| .endm | ||||
|  | ||||
| @ -28,13 +28,16 @@ | ||||
| #define OP_31_XOP_MFMSR		83 | ||||
| #define OP_31_XOP_MTMSR		146 | ||||
| #define OP_31_XOP_MTMSRD	178 | ||||
| #define OP_31_XOP_MTSR		210 | ||||
| #define OP_31_XOP_MTSRIN	242 | ||||
| #define OP_31_XOP_TLBIEL	274 | ||||
| #define OP_31_XOP_TLBIE		306 | ||||
| #define OP_31_XOP_SLBMTE	402 | ||||
| #define OP_31_XOP_SLBIE		434 | ||||
| #define OP_31_XOP_SLBIA		498 | ||||
| #define OP_31_XOP_MFSR		595 | ||||
| #define OP_31_XOP_MFSRIN	659 | ||||
| #define OP_31_XOP_DCBA		758 | ||||
| #define OP_31_XOP_SLBMFEV	851 | ||||
| #define OP_31_XOP_EIOIO		854 | ||||
| #define OP_31_XOP_SLBMFEE	915 | ||||
| @ -42,6 +45,24 @@ | ||||
| /* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */ | ||||
| #define OP_31_XOP_DCBZ		1010 | ||||
| 
 | ||||
| #define OP_LFS			48 | ||||
| #define OP_LFD			50 | ||||
| #define OP_STFS			52 | ||||
| #define OP_STFD			54 | ||||
| 
 | ||||
| #define SPRN_GQR0		912 | ||||
| #define SPRN_GQR1		913 | ||||
| #define SPRN_GQR2		914 | ||||
| #define SPRN_GQR3		915 | ||||
| #define SPRN_GQR4		916 | ||||
| #define SPRN_GQR5		917 | ||||
| #define SPRN_GQR6		918 | ||||
| #define SPRN_GQR7		919 | ||||
| 
 | ||||
| /* Book3S_32 defines mfsrin(v) - but that messes up our abstract
 | ||||
|  * function pointers, so let's just disable the define. */ | ||||
| #undef mfsrin | ||||
| 
 | ||||
| int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
|                            unsigned int inst, int *advance) | ||||
| { | ||||
| @ -52,7 +73,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 		switch (get_xop(inst)) { | ||||
| 		case OP_19_XOP_RFID: | ||||
| 		case OP_19_XOP_RFI: | ||||
| 			vcpu->arch.pc = vcpu->arch.srr0; | ||||
| 			kvmppc_set_pc(vcpu, vcpu->arch.srr0); | ||||
| 			kvmppc_set_msr(vcpu, vcpu->arch.srr1); | ||||
| 			*advance = 0; | ||||
| 			break; | ||||
| @ -80,6 +101,18 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 		case OP_31_XOP_MTMSR: | ||||
| 			kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, get_rs(inst))); | ||||
| 			break; | ||||
| 		case OP_31_XOP_MFSR: | ||||
| 		{ | ||||
| 			int srnum; | ||||
| 
 | ||||
| 			srnum = kvmppc_get_field(inst, 12 + 32, 15 + 32); | ||||
| 			if (vcpu->arch.mmu.mfsrin) { | ||||
| 				u32 sr; | ||||
| 				sr = vcpu->arch.mmu.mfsrin(vcpu, srnum); | ||||
| 				kvmppc_set_gpr(vcpu, get_rt(inst), sr); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		case OP_31_XOP_MFSRIN: | ||||
| 		{ | ||||
| 			int srnum; | ||||
| @ -92,6 +125,11 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		case OP_31_XOP_MTSR: | ||||
| 			vcpu->arch.mmu.mtsrin(vcpu, | ||||
| 				(inst >> 16) & 0xf, | ||||
| 				kvmppc_get_gpr(vcpu, get_rs(inst))); | ||||
| 			break; | ||||
| 		case OP_31_XOP_MTSRIN: | ||||
| 			vcpu->arch.mmu.mtsrin(vcpu, | ||||
| 				(kvmppc_get_gpr(vcpu, get_rb(inst)) >> 28) & 0xf, | ||||
| @ -150,12 +188,17 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 				kvmppc_set_gpr(vcpu, get_rt(inst), t); | ||||
| 			} | ||||
| 			break; | ||||
| 		case OP_31_XOP_DCBA: | ||||
| 			/* Gets treated as NOP */ | ||||
| 			break; | ||||
| 		case OP_31_XOP_DCBZ: | ||||
| 		{ | ||||
| 			ulong rb = kvmppc_get_gpr(vcpu, get_rb(inst)); | ||||
| 			ulong ra = 0; | ||||
| 			ulong addr; | ||||
| 			ulong addr, vaddr; | ||||
| 			u32 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | ||||
| 			u32 dsisr; | ||||
| 			int r; | ||||
| 
 | ||||
| 			if (get_ra(inst)) | ||||
| 				ra = kvmppc_get_gpr(vcpu, get_ra(inst)); | ||||
| @ -163,15 +206,25 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 			addr = (ra + rb) & ~31ULL; | ||||
| 			if (!(vcpu->arch.msr & MSR_SF)) | ||||
| 				addr &= 0xffffffff; | ||||
| 			vaddr = addr; | ||||
| 
 | ||||
| 			r = kvmppc_st(vcpu, &addr, 32, zeros, true); | ||||
| 			if ((r == -ENOENT) || (r == -EPERM)) { | ||||
| 				*advance = 0; | ||||
| 				vcpu->arch.dear = vaddr; | ||||
| 				to_svcpu(vcpu)->fault_dar = vaddr; | ||||
| 
 | ||||
| 				dsisr = DSISR_ISSTORE; | ||||
| 				if (r == -ENOENT) | ||||
| 					dsisr |= DSISR_NOHPTE; | ||||
| 				else if (r == -EPERM) | ||||
| 					dsisr |= DSISR_PROTFAULT; | ||||
| 
 | ||||
| 				to_book3s(vcpu)->dsisr = dsisr; | ||||
| 				to_svcpu(vcpu)->fault_dsisr = dsisr; | ||||
| 
 | ||||
| 			if (kvmppc_st(vcpu, addr, 32, zeros)) { | ||||
| 				vcpu->arch.dear = addr; | ||||
| 				vcpu->arch.fault_dear = addr; | ||||
| 				to_book3s(vcpu)->dsisr = DSISR_PROTFAULT | | ||||
| 						      DSISR_ISSTORE; | ||||
| 				kvmppc_book3s_queue_irqprio(vcpu, | ||||
| 					BOOK3S_INTERRUPT_DATA_STORAGE); | ||||
| 				kvmppc_mmu_pte_flush(vcpu, addr, ~0xFFFULL); | ||||
| 			} | ||||
| 
 | ||||
| 			break; | ||||
| @ -184,6 +237,9 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 		emulated = EMULATE_FAIL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (emulated == EMULATE_FAIL) | ||||
| 		emulated = kvmppc_emulate_paired_single(run, vcpu); | ||||
| 
 | ||||
| 	return emulated; | ||||
| } | ||||
| 
 | ||||
| @ -207,6 +263,34 @@ void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static u32 kvmppc_read_bat(struct kvm_vcpu *vcpu, int sprn) | ||||
| { | ||||
| 	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||||
| 	struct kvmppc_bat *bat; | ||||
| 
 | ||||
| 	switch (sprn) { | ||||
| 	case SPRN_IBAT0U ... SPRN_IBAT3L: | ||||
| 		bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2]; | ||||
| 		break; | ||||
| 	case SPRN_IBAT4U ... SPRN_IBAT7L: | ||||
| 		bat = &vcpu_book3s->ibat[4 + ((sprn - SPRN_IBAT4U) / 2)]; | ||||
| 		break; | ||||
| 	case SPRN_DBAT0U ... SPRN_DBAT3L: | ||||
| 		bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2]; | ||||
| 		break; | ||||
| 	case SPRN_DBAT4U ... SPRN_DBAT7L: | ||||
| 		bat = &vcpu_book3s->dbat[4 + ((sprn - SPRN_DBAT4U) / 2)]; | ||||
| 		break; | ||||
| 	default: | ||||
| 		BUG(); | ||||
| 	} | ||||
| 
 | ||||
| 	if (sprn % 2) | ||||
| 		return bat->raw >> 32; | ||||
| 	else | ||||
| 		return bat->raw; | ||||
| } | ||||
| 
 | ||||
| static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u32 val) | ||||
| { | ||||
| 	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||||
| @ -217,13 +301,13 @@ static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u32 val) | ||||
| 		bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2]; | ||||
| 		break; | ||||
| 	case SPRN_IBAT4U ... SPRN_IBAT7L: | ||||
| 		bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT4U) / 2]; | ||||
| 		bat = &vcpu_book3s->ibat[4 + ((sprn - SPRN_IBAT4U) / 2)]; | ||||
| 		break; | ||||
| 	case SPRN_DBAT0U ... SPRN_DBAT3L: | ||||
| 		bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2]; | ||||
| 		break; | ||||
| 	case SPRN_DBAT4U ... SPRN_DBAT7L: | ||||
| 		bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT4U) / 2]; | ||||
| 		bat = &vcpu_book3s->dbat[4 + ((sprn - SPRN_DBAT4U) / 2)]; | ||||
| 		break; | ||||
| 	default: | ||||
| 		BUG(); | ||||
| @ -258,6 +342,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||||
| 		/* BAT writes happen so rarely that we're ok to flush
 | ||||
| 		 * everything here */ | ||||
| 		kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||||
| 		kvmppc_mmu_flush_segments(vcpu); | ||||
| 		break; | ||||
| 	case SPRN_HID0: | ||||
| 		to_book3s(vcpu)->hid[0] = spr_val; | ||||
| @ -268,7 +353,32 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||||
| 	case SPRN_HID2: | ||||
| 		to_book3s(vcpu)->hid[2] = spr_val; | ||||
| 		break; | ||||
| 	case SPRN_HID2_GEKKO: | ||||
| 		to_book3s(vcpu)->hid[2] = spr_val; | ||||
| 		/* HID2.PSE controls paired single on gekko */ | ||||
| 		switch (vcpu->arch.pvr) { | ||||
| 		case 0x00080200:	/* lonestar 2.0 */ | ||||
| 		case 0x00088202:	/* lonestar 2.2 */ | ||||
| 		case 0x70000100:	/* gekko 1.0 */ | ||||
| 		case 0x00080100:	/* gekko 2.0 */ | ||||
| 		case 0x00083203:	/* gekko 2.3a */ | ||||
| 		case 0x00083213:	/* gekko 2.3b */ | ||||
| 		case 0x00083204:	/* gekko 2.4 */ | ||||
| 		case 0x00083214:	/* gekko 2.4e (8SE) - retail HW2 */ | ||||
| 		case 0x00087200:	/* broadway */ | ||||
| 			if (vcpu->arch.hflags & BOOK3S_HFLAG_NATIVE_PS) { | ||||
| 				/* Native paired singles */ | ||||
| 			} else if (spr_val & (1 << 29)) { /* HID2.PSE */ | ||||
| 				vcpu->arch.hflags |= BOOK3S_HFLAG_PAIRED_SINGLE; | ||||
| 				kvmppc_giveup_ext(vcpu, MSR_FP); | ||||
| 			} else { | ||||
| 				vcpu->arch.hflags &= ~BOOK3S_HFLAG_PAIRED_SINGLE; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	case SPRN_HID4: | ||||
| 	case SPRN_HID4_GEKKO: | ||||
| 		to_book3s(vcpu)->hid[4] = spr_val; | ||||
| 		break; | ||||
| 	case SPRN_HID5: | ||||
| @ -278,12 +388,30 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||||
| 		    (mfmsr() & MSR_HV)) | ||||
| 			vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; | ||||
| 		break; | ||||
| 	case SPRN_GQR0: | ||||
| 	case SPRN_GQR1: | ||||
| 	case SPRN_GQR2: | ||||
| 	case SPRN_GQR3: | ||||
| 	case SPRN_GQR4: | ||||
| 	case SPRN_GQR5: | ||||
| 	case SPRN_GQR6: | ||||
| 	case SPRN_GQR7: | ||||
| 		to_book3s(vcpu)->gqr[sprn - SPRN_GQR0] = spr_val; | ||||
| 		break; | ||||
| 	case SPRN_ICTC: | ||||
| 	case SPRN_THRM1: | ||||
| 	case SPRN_THRM2: | ||||
| 	case SPRN_THRM3: | ||||
| 	case SPRN_CTRLF: | ||||
| 	case SPRN_CTRLT: | ||||
| 	case SPRN_L2CR: | ||||
| 	case SPRN_MMCR0_GEKKO: | ||||
| 	case SPRN_MMCR1_GEKKO: | ||||
| 	case SPRN_PMC1_GEKKO: | ||||
| 	case SPRN_PMC2_GEKKO: | ||||
| 	case SPRN_PMC3_GEKKO: | ||||
| 	case SPRN_PMC4_GEKKO: | ||||
| 	case SPRN_WPAR_GEKKO: | ||||
| 		break; | ||||
| 	default: | ||||
| 		printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn); | ||||
| @ -301,6 +429,12 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | ||||
| 	int emulated = EMULATE_DONE; | ||||
| 
 | ||||
| 	switch (sprn) { | ||||
| 	case SPRN_IBAT0U ... SPRN_IBAT3L: | ||||
| 	case SPRN_IBAT4U ... SPRN_IBAT7L: | ||||
| 	case SPRN_DBAT0U ... SPRN_DBAT3L: | ||||
| 	case SPRN_DBAT4U ... SPRN_DBAT7L: | ||||
| 		kvmppc_set_gpr(vcpu, rt, kvmppc_read_bat(vcpu, sprn)); | ||||
| 		break; | ||||
| 	case SPRN_SDR1: | ||||
| 		kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1); | ||||
| 		break; | ||||
| @ -320,19 +454,40 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | ||||
| 		kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[1]); | ||||
| 		break; | ||||
| 	case SPRN_HID2: | ||||
| 	case SPRN_HID2_GEKKO: | ||||
| 		kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[2]); | ||||
| 		break; | ||||
| 	case SPRN_HID4: | ||||
| 	case SPRN_HID4_GEKKO: | ||||
| 		kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[4]); | ||||
| 		break; | ||||
| 	case SPRN_HID5: | ||||
| 		kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hid[5]); | ||||
| 		break; | ||||
| 	case SPRN_GQR0: | ||||
| 	case SPRN_GQR1: | ||||
| 	case SPRN_GQR2: | ||||
| 	case SPRN_GQR3: | ||||
| 	case SPRN_GQR4: | ||||
| 	case SPRN_GQR5: | ||||
| 	case SPRN_GQR6: | ||||
| 	case SPRN_GQR7: | ||||
| 		kvmppc_set_gpr(vcpu, rt, | ||||
| 			       to_book3s(vcpu)->gqr[sprn - SPRN_GQR0]); | ||||
| 		break; | ||||
| 	case SPRN_THRM1: | ||||
| 	case SPRN_THRM2: | ||||
| 	case SPRN_THRM3: | ||||
| 	case SPRN_CTRLF: | ||||
| 	case SPRN_CTRLT: | ||||
| 	case SPRN_L2CR: | ||||
| 	case SPRN_MMCR0_GEKKO: | ||||
| 	case SPRN_MMCR1_GEKKO: | ||||
| 	case SPRN_PMC1_GEKKO: | ||||
| 	case SPRN_PMC2_GEKKO: | ||||
| 	case SPRN_PMC3_GEKKO: | ||||
| 	case SPRN_PMC4_GEKKO: | ||||
| 	case SPRN_WPAR_GEKKO: | ||||
| 		kvmppc_set_gpr(vcpu, rt, 0); | ||||
| 		break; | ||||
| 	default: | ||||
| @ -346,3 +501,73 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | ||||
| 	return emulated; | ||||
| } | ||||
| 
 | ||||
| u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst) | ||||
| { | ||||
| 	u32 dsisr = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This is what the spec says about DSISR bits (not mentioned = 0): | ||||
| 	 * | ||||
| 	 * 12:13		[DS]	Set to bits 30:31 | ||||
| 	 * 15:16		[X]	Set to bits 29:30 | ||||
| 	 * 17			[X]	Set to bit 25 | ||||
| 	 *			[D/DS]	Set to bit 5 | ||||
| 	 * 18:21		[X]	Set to bits 21:24 | ||||
| 	 *			[D/DS]	Set to bits 1:4 | ||||
| 	 * 22:26			Set to bits 6:10 (RT/RS/FRT/FRS) | ||||
| 	 * 27:31			Set to bits 11:15 (RA) | ||||
| 	 */ | ||||
| 
 | ||||
| 	switch (get_op(inst)) { | ||||
| 	/* D-form */ | ||||
| 	case OP_LFS: | ||||
| 	case OP_LFD: | ||||
| 	case OP_STFD: | ||||
| 	case OP_STFS: | ||||
| 		dsisr |= (inst >> 12) & 0x4000;	/* bit 17 */ | ||||
| 		dsisr |= (inst >> 17) & 0x3c00; /* bits 18:21 */ | ||||
| 		break; | ||||
| 	/* X-form */ | ||||
| 	case 31: | ||||
| 		dsisr |= (inst << 14) & 0x18000; /* bits 15:16 */ | ||||
| 		dsisr |= (inst << 8)  & 0x04000; /* bit 17 */ | ||||
| 		dsisr |= (inst << 3)  & 0x03c00; /* bits 18:21 */ | ||||
| 		break; | ||||
| 	default: | ||||
| 		printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	dsisr |= (inst >> 16) & 0x03ff; /* bits 22:31 */ | ||||
| 
 | ||||
| 	return dsisr; | ||||
| } | ||||
| 
 | ||||
| ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst) | ||||
| { | ||||
| 	ulong dar = 0; | ||||
| 	ulong ra; | ||||
| 
 | ||||
| 	switch (get_op(inst)) { | ||||
| 	case OP_LFS: | ||||
| 	case OP_LFD: | ||||
| 	case OP_STFD: | ||||
| 	case OP_STFS: | ||||
| 		ra = get_ra(inst); | ||||
| 		if (ra) | ||||
| 			dar = kvmppc_get_gpr(vcpu, ra); | ||||
| 		dar += (s32)((s16)inst); | ||||
| 		break; | ||||
| 	case 31: | ||||
| 		ra = get_ra(inst); | ||||
| 		if (ra) | ||||
| 			dar = kvmppc_get_gpr(vcpu, ra); | ||||
| 		dar += kvmppc_get_gpr(vcpu, get_rb(inst)); | ||||
| 		break; | ||||
| 	default: | ||||
| 		printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return dar; | ||||
| } | ||||
| @ -24,36 +24,56 @@ | ||||
| #include <asm/asm-offsets.h> | ||||
| #include <asm/exception-64s.h> | ||||
| 
 | ||||
| #define KVMPPC_HANDLE_EXIT .kvmppc_handle_exit | ||||
| #define ULONG_SIZE 8 | ||||
| #define VCPU_GPR(n)     (VCPU_GPRS + (n * ULONG_SIZE)) | ||||
| #if defined(CONFIG_PPC_BOOK3S_64) | ||||
| 
 | ||||
| .macro DISABLE_INTERRUPTS
 | ||||
|        mfmsr   r0 | ||||
|        rldicl  r0,r0,48,1 | ||||
|        rotldi  r0,r0,16 | ||||
|        mtmsrd  r0,1 | ||||
| .endm | ||||
| #define ULONG_SIZE 		8 | ||||
| #define FUNC(name) 		GLUE(.,name) | ||||
| 
 | ||||
| #define GET_SHADOW_VCPU(reg)    \ | ||||
|         addi    reg, r13, PACA_KVM_SVCPU | ||||
| 
 | ||||
| #define DISABLE_INTERRUPTS	\ | ||||
| 	mfmsr   r0;		\
 | ||||
| 	rldicl  r0,r0,48,1;	\
 | ||||
| 	rotldi  r0,r0,16;	\
 | ||||
| 	mtmsrd  r0,1;		\
 | ||||
| 
 | ||||
| #elif defined(CONFIG_PPC_BOOK3S_32) | ||||
| 
 | ||||
| #define ULONG_SIZE              4 | ||||
| #define FUNC(name)		name | ||||
| 
 | ||||
| #define GET_SHADOW_VCPU(reg)    \ | ||||
|         lwz     reg, (THREAD + THREAD_KVM_SVCPU)(r2) | ||||
| 
 | ||||
| #define DISABLE_INTERRUPTS	\ | ||||
| 	mfmsr   r0;		\
 | ||||
| 	rlwinm  r0,r0,0,17,15;	\
 | ||||
| 	mtmsr   r0;		\
 | ||||
| 
 | ||||
| #endif /* CONFIG_PPC_BOOK3S_XX */ | ||||
| 
 | ||||
| 
 | ||||
| #define VCPU_GPR(n)		(VCPU_GPRS + (n * ULONG_SIZE)) | ||||
| #define VCPU_LOAD_NVGPRS(vcpu) \ | ||||
| 	ld	r14, VCPU_GPR(r14)(vcpu); \
 | ||||
| 	ld	r15, VCPU_GPR(r15)(vcpu); \
 | ||||
| 	ld	r16, VCPU_GPR(r16)(vcpu); \
 | ||||
| 	ld	r17, VCPU_GPR(r17)(vcpu); \
 | ||||
| 	ld	r18, VCPU_GPR(r18)(vcpu); \
 | ||||
| 	ld	r19, VCPU_GPR(r19)(vcpu); \
 | ||||
| 	ld	r20, VCPU_GPR(r20)(vcpu); \
 | ||||
| 	ld	r21, VCPU_GPR(r21)(vcpu); \
 | ||||
| 	ld	r22, VCPU_GPR(r22)(vcpu); \
 | ||||
| 	ld	r23, VCPU_GPR(r23)(vcpu); \
 | ||||
| 	ld	r24, VCPU_GPR(r24)(vcpu); \
 | ||||
| 	ld	r25, VCPU_GPR(r25)(vcpu); \
 | ||||
| 	ld	r26, VCPU_GPR(r26)(vcpu); \
 | ||||
| 	ld	r27, VCPU_GPR(r27)(vcpu); \
 | ||||
| 	ld	r28, VCPU_GPR(r28)(vcpu); \
 | ||||
| 	ld	r29, VCPU_GPR(r29)(vcpu); \
 | ||||
| 	ld	r30, VCPU_GPR(r30)(vcpu); \
 | ||||
| 	ld	r31, VCPU_GPR(r31)(vcpu); \
 | ||||
| 	PPC_LL	r14, VCPU_GPR(r14)(vcpu); \
 | ||||
| 	PPC_LL	r15, VCPU_GPR(r15)(vcpu); \
 | ||||
| 	PPC_LL	r16, VCPU_GPR(r16)(vcpu); \
 | ||||
| 	PPC_LL	r17, VCPU_GPR(r17)(vcpu); \
 | ||||
| 	PPC_LL	r18, VCPU_GPR(r18)(vcpu); \
 | ||||
| 	PPC_LL	r19, VCPU_GPR(r19)(vcpu); \
 | ||||
| 	PPC_LL	r20, VCPU_GPR(r20)(vcpu); \
 | ||||
| 	PPC_LL	r21, VCPU_GPR(r21)(vcpu); \
 | ||||
| 	PPC_LL	r22, VCPU_GPR(r22)(vcpu); \
 | ||||
| 	PPC_LL	r23, VCPU_GPR(r23)(vcpu); \
 | ||||
| 	PPC_LL	r24, VCPU_GPR(r24)(vcpu); \
 | ||||
| 	PPC_LL	r25, VCPU_GPR(r25)(vcpu); \
 | ||||
| 	PPC_LL	r26, VCPU_GPR(r26)(vcpu); \
 | ||||
| 	PPC_LL	r27, VCPU_GPR(r27)(vcpu); \
 | ||||
| 	PPC_LL	r28, VCPU_GPR(r28)(vcpu); \
 | ||||
| 	PPC_LL	r29, VCPU_GPR(r29)(vcpu); \
 | ||||
| 	PPC_LL	r30, VCPU_GPR(r30)(vcpu); \
 | ||||
| 	PPC_LL	r31, VCPU_GPR(r31)(vcpu); \
 | ||||
| 
 | ||||
| /***************************************************************************** | ||||
|  *                                                                           * | ||||
| @ -69,11 +89,11 @@ _GLOBAL(__kvmppc_vcpu_entry) | ||||
| 
 | ||||
| kvm_start_entry: | ||||
| 	/* Write correct stack frame */ | ||||
| 	mflr    r0 | ||||
| 	std     r0,16(r1) | ||||
| 	mflr	r0 | ||||
| 	PPC_STL	r0,PPC_LR_STKOFF(r1) | ||||
| 
 | ||||
| 	/* Save host state to the stack */ | ||||
| 	stdu	r1, -SWITCH_FRAME_SIZE(r1) | ||||
| 	PPC_STLU r1, -SWITCH_FRAME_SIZE(r1) | ||||
| 
 | ||||
| 	/* Save r3 (kvm_run) and r4 (vcpu) */ | ||||
| 	SAVE_2GPRS(3, r1) | ||||
| @ -82,33 +102,28 @@ kvm_start_entry: | ||||
| 	SAVE_NVGPRS(r1) | ||||
| 
 | ||||
| 	/* Save LR */ | ||||
| 	std	r0, _LINK(r1) | ||||
| 	PPC_STL	r0, _LINK(r1) | ||||
| 
 | ||||
| 	/* Load non-volatile guest state from the vcpu */ | ||||
| 	VCPU_LOAD_NVGPRS(r4) | ||||
| 
 | ||||
| 	GET_SHADOW_VCPU(r5) | ||||
| 
 | ||||
| 	/* Save R1/R2 in the PACA */ | ||||
| 	std	r1, PACA_KVM_HOST_R1(r13) | ||||
| 	std	r2, PACA_KVM_HOST_R2(r13) | ||||
| 	PPC_STL	r1, SVCPU_HOST_R1(r5) | ||||
| 	PPC_STL	r2, SVCPU_HOST_R2(r5) | ||||
| 
 | ||||
| 	/* XXX swap in/out on load? */ | ||||
| 	ld	r3, VCPU_HIGHMEM_HANDLER(r4) | ||||
| 	std	r3, PACA_KVM_VMHANDLER(r13) | ||||
| 	PPC_LL	r3, VCPU_HIGHMEM_HANDLER(r4) | ||||
| 	PPC_STL	r3, SVCPU_VMHANDLER(r5) | ||||
| 
 | ||||
| kvm_start_lightweight: | ||||
| 
 | ||||
| 	ld	r9, VCPU_PC(r4)			/* r9 = vcpu->arch.pc */ | ||||
| 	ld	r10, VCPU_SHADOW_MSR(r4)	/* r10 = vcpu->arch.shadow_msr */ | ||||
| 
 | ||||
| 	/* Load some guest state in the respective registers */ | ||||
| 	ld	r5, VCPU_CTR(r4)	/* r5 = vcpu->arch.ctr */ | ||||
| 					/* will be swapped in by rmcall */ | ||||
| 
 | ||||
| 	ld	r3, VCPU_LR(r4)		/* r3 = vcpu->arch.lr */ | ||||
| 	mtlr	r3			/* LR = r3 */ | ||||
| 	PPC_LL	r10, VCPU_SHADOW_MSR(r4)	/* r10 = vcpu->arch.shadow_msr */ | ||||
| 
 | ||||
| 	DISABLE_INTERRUPTS | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| 	/* Some guests may need to have dcbz set to 32 byte length. | ||||
| 	 * | ||||
| 	 * Usually we ensure that by patching the guest's instructions | ||||
| @ -118,7 +133,7 @@ kvm_start_lightweight: | ||||
| 	 * because that's a lot faster. | ||||
| 	 */ | ||||
| 
 | ||||
| 	ld	r3, VCPU_HFLAGS(r4) | ||||
| 	PPC_LL	r3, VCPU_HFLAGS(r4) | ||||
| 	rldicl.	r3, r3, 0, 63		/* CR = ((r3 & 1) == 0) */ | ||||
| 	beq	no_dcbz32_on | ||||
| 
 | ||||
| @ -128,13 +143,15 @@ kvm_start_lightweight: | ||||
| 
 | ||||
| no_dcbz32_on: | ||||
| 
 | ||||
| 	ld	r6, VCPU_RMCALL(r4) | ||||
| #endif /* CONFIG_PPC_BOOK3S_64 */ | ||||
| 
 | ||||
| 	PPC_LL	r6, VCPU_RMCALL(r4) | ||||
| 	mtctr	r6 | ||||
| 
 | ||||
| 	ld	r3, VCPU_TRAMPOLINE_ENTER(r4) | ||||
| 	PPC_LL	r3, VCPU_TRAMPOLINE_ENTER(r4) | ||||
| 	LOAD_REG_IMMEDIATE(r4, MSR_KERNEL & ~(MSR_IR | MSR_DR)) | ||||
| 
 | ||||
| 	/* Jump to SLB patching handlder and into our guest */ | ||||
| 	/* Jump to segment patching handler and into our guest */ | ||||
| 	bctr | ||||
| 
 | ||||
| /* | ||||
| @ -149,31 +166,20 @@ kvmppc_handler_highmem: | ||||
| 	/* | ||||
| 	 * Register usage at this point: | ||||
| 	 * | ||||
| 	 * R0         = guest last inst | ||||
| 	 * R1         = host R1 | ||||
| 	 * R2         = host R2 | ||||
| 	 * R3         = guest PC | ||||
| 	 * R4         = guest MSR | ||||
| 	 * R5         = guest DAR | ||||
| 	 * R6         = guest DSISR | ||||
| 	 * R13        = PACA | ||||
| 	 * PACA.KVM.* = guest * | ||||
| 	 * R1       = host R1 | ||||
| 	 * R2       = host R2 | ||||
| 	 * R12      = exit handler id | ||||
| 	 * R13      = PACA | ||||
| 	 * SVCPU.*  = guest * | ||||
| 	 * | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* R7 = vcpu */ | ||||
| 	ld	r7, GPR4(r1) | ||||
| 	PPC_LL	r7, GPR4(r1) | ||||
| 
 | ||||
| 	/* Now save the guest state */ | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| 
 | ||||
| 	stw	r0, VCPU_LAST_INST(r7) | ||||
| 
 | ||||
| 	std	r3, VCPU_PC(r7) | ||||
| 	std	r4, VCPU_SHADOW_SRR1(r7) | ||||
| 	std	r5, VCPU_FAULT_DEAR(r7) | ||||
| 	std	r6, VCPU_FAULT_DSISR(r7) | ||||
| 
 | ||||
| 	ld	r5, VCPU_HFLAGS(r7) | ||||
| 	PPC_LL	r5, VCPU_HFLAGS(r7) | ||||
| 	rldicl.	r5, r5, 0, 63		/* CR = ((r5 & 1) == 0) */ | ||||
| 	beq	no_dcbz32_off | ||||
| 
 | ||||
| @ -184,35 +190,29 @@ kvmppc_handler_highmem: | ||||
| 
 | ||||
| no_dcbz32_off: | ||||
| 
 | ||||
| 	std	r14, VCPU_GPR(r14)(r7) | ||||
| 	std	r15, VCPU_GPR(r15)(r7) | ||||
| 	std	r16, VCPU_GPR(r16)(r7) | ||||
| 	std	r17, VCPU_GPR(r17)(r7) | ||||
| 	std	r18, VCPU_GPR(r18)(r7) | ||||
| 	std	r19, VCPU_GPR(r19)(r7) | ||||
| 	std	r20, VCPU_GPR(r20)(r7) | ||||
| 	std	r21, VCPU_GPR(r21)(r7) | ||||
| 	std	r22, VCPU_GPR(r22)(r7) | ||||
| 	std	r23, VCPU_GPR(r23)(r7) | ||||
| 	std	r24, VCPU_GPR(r24)(r7) | ||||
| 	std	r25, VCPU_GPR(r25)(r7) | ||||
| 	std	r26, VCPU_GPR(r26)(r7) | ||||
| 	std	r27, VCPU_GPR(r27)(r7) | ||||
| 	std	r28, VCPU_GPR(r28)(r7) | ||||
| 	std	r29, VCPU_GPR(r29)(r7) | ||||
| 	std	r30, VCPU_GPR(r30)(r7) | ||||
| 	std	r31, VCPU_GPR(r31)(r7) | ||||
| #endif /* CONFIG_PPC_BOOK3S_64 */ | ||||
| 
 | ||||
| 	/* Save guest CTR */ | ||||
| 	mfctr	r5 | ||||
| 	std	r5, VCPU_CTR(r7) | ||||
| 
 | ||||
| 	/* Save guest LR */ | ||||
| 	mflr	r5 | ||||
| 	std	r5, VCPU_LR(r7) | ||||
| 	PPC_STL	r14, VCPU_GPR(r14)(r7) | ||||
| 	PPC_STL	r15, VCPU_GPR(r15)(r7) | ||||
| 	PPC_STL	r16, VCPU_GPR(r16)(r7) | ||||
| 	PPC_STL	r17, VCPU_GPR(r17)(r7) | ||||
| 	PPC_STL	r18, VCPU_GPR(r18)(r7) | ||||
| 	PPC_STL	r19, VCPU_GPR(r19)(r7) | ||||
| 	PPC_STL	r20, VCPU_GPR(r20)(r7) | ||||
| 	PPC_STL	r21, VCPU_GPR(r21)(r7) | ||||
| 	PPC_STL	r22, VCPU_GPR(r22)(r7) | ||||
| 	PPC_STL	r23, VCPU_GPR(r23)(r7) | ||||
| 	PPC_STL	r24, VCPU_GPR(r24)(r7) | ||||
| 	PPC_STL	r25, VCPU_GPR(r25)(r7) | ||||
| 	PPC_STL	r26, VCPU_GPR(r26)(r7) | ||||
| 	PPC_STL	r27, VCPU_GPR(r27)(r7) | ||||
| 	PPC_STL	r28, VCPU_GPR(r28)(r7) | ||||
| 	PPC_STL	r29, VCPU_GPR(r29)(r7) | ||||
| 	PPC_STL	r30, VCPU_GPR(r30)(r7) | ||||
| 	PPC_STL	r31, VCPU_GPR(r31)(r7) | ||||
| 
 | ||||
| 	/* Restore host msr -> SRR1 */ | ||||
| 	ld	r6, VCPU_HOST_MSR(r7) | ||||
| 	PPC_LL	r6, VCPU_HOST_MSR(r7) | ||||
| 
 | ||||
| 	/* | ||||
| 	 * For some interrupts, we need to call the real Linux | ||||
| @ -228,9 +228,12 @@ no_dcbz32_off: | ||||
| 	beq	call_linux_handler | ||||
| 	cmpwi	r12, BOOK3S_INTERRUPT_DECREMENTER | ||||
| 	beq	call_linux_handler | ||||
| 	cmpwi	r12, BOOK3S_INTERRUPT_PERFMON | ||||
| 	beq	call_linux_handler | ||||
| 
 | ||||
| 	/* Back to EE=1 */ | ||||
| 	mtmsr	r6 | ||||
| 	sync | ||||
| 	b	kvm_return_point | ||||
| 
 | ||||
| call_linux_handler: | ||||
| @ -249,14 +252,14 @@ call_linux_handler: | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* Restore host IP -> SRR0 */ | ||||
| 	ld	r5, VCPU_HOST_RETIP(r7) | ||||
| 	PPC_LL	r5, VCPU_HOST_RETIP(r7) | ||||
| 
 | ||||
| 	/* XXX Better move to a safe function? | ||||
| 	 *     What if we get an HTAB flush in between mtsrr0 and mtsrr1? */ | ||||
| 
 | ||||
| 	mtlr	r12 | ||||
| 
 | ||||
| 	ld	r4, VCPU_TRAMPOLINE_LOWMEM(r7) | ||||
| 	PPC_LL	r4, VCPU_TRAMPOLINE_LOWMEM(r7) | ||||
| 	mtsrr0	r4 | ||||
| 	LOAD_REG_IMMEDIATE(r3, MSR_KERNEL & ~(MSR_IR | MSR_DR)) | ||||
| 	mtsrr1	r3 | ||||
| @ -274,7 +277,7 @@ kvm_return_point: | ||||
| 
 | ||||
| 	/* Restore r3 (kvm_run) and r4 (vcpu) */ | ||||
| 	REST_2GPRS(3, r1) | ||||
| 	bl	KVMPPC_HANDLE_EXIT | ||||
| 	bl	FUNC(kvmppc_handle_exit) | ||||
| 
 | ||||
| 	/* If RESUME_GUEST, get back in the loop */ | ||||
| 	cmpwi	r3, RESUME_GUEST | ||||
| @ -285,7 +288,7 @@ kvm_return_point: | ||||
| 
 | ||||
| kvm_exit_loop: | ||||
| 
 | ||||
| 	ld	r4, _LINK(r1) | ||||
| 	PPC_LL	r4, _LINK(r1) | ||||
| 	mtlr	r4 | ||||
| 
 | ||||
| 	/* Restore non-volatile host registers (r14 - r31) */ | ||||
| @ -296,8 +299,8 @@ kvm_exit_loop: | ||||
| 
 | ||||
| kvm_loop_heavyweight: | ||||
| 
 | ||||
| 	ld	r4, _LINK(r1) | ||||
| 	std     r4, (16 + SWITCH_FRAME_SIZE)(r1) | ||||
| 	PPC_LL	r4, _LINK(r1) | ||||
| 	PPC_STL r4, (PPC_LR_STKOFF + SWITCH_FRAME_SIZE)(r1) | ||||
| 
 | ||||
| 	/* Load vcpu and cpu_run */ | ||||
| 	REST_2GPRS(3, r1) | ||||
| @ -315,4 +318,3 @@ kvm_loop_lightweight: | ||||
| 
 | ||||
| 	/* Jump back into the beginning of this function */ | ||||
| 	b	kvm_start_lightweight | ||||
| 
 | ||||
							
								
								
									
										1289
									
								
								arch/powerpc/kvm/book3s_paired_singles.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1289
									
								
								arch/powerpc/kvm/book3s_paired_singles.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -22,7 +22,10 @@ | ||||
| #include <asm/reg.h> | ||||
| #include <asm/page.h> | ||||
| #include <asm/asm-offsets.h> | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| #include <asm/exception-64s.h> | ||||
| #endif | ||||
| 
 | ||||
| /***************************************************************************** | ||||
|  *                                                                           * | ||||
| @ -30,6 +33,39 @@ | ||||
|  *                                                                           * | ||||
|  ****************************************************************************/ | ||||
| 
 | ||||
| #if defined(CONFIG_PPC_BOOK3S_64) | ||||
| 
 | ||||
| #define LOAD_SHADOW_VCPU(reg)				\ | ||||
| 	mfspr	reg, SPRN_SPRG_PACA | ||||
| 
 | ||||
| #define SHADOW_VCPU_OFF		PACA_KVM_SVCPU | ||||
| #define MSR_NOIRQ		MSR_KERNEL & ~(MSR_IR | MSR_DR) | ||||
| #define FUNC(name) 		GLUE(.,name) | ||||
| 
 | ||||
| #elif defined(CONFIG_PPC_BOOK3S_32) | ||||
| 
 | ||||
| #define LOAD_SHADOW_VCPU(reg)						\ | ||||
| 	mfspr	reg, SPRN_SPRG_THREAD;					\
 | ||||
| 	lwz	reg, THREAD_KVM_SVCPU(reg);				\
 | ||||
| 	/* PPC32 can have a NULL pointer - let's check for that */	\ | ||||
| 	mtspr   SPRN_SPRG_SCRATCH1, r12;	/* Save r12 */		\
 | ||||
| 	mfcr	r12;							\
 | ||||
| 	cmpwi	reg, 0;							\
 | ||||
| 	bne	1f;							\
 | ||||
| 	mfspr	reg, SPRN_SPRG_SCRATCH0;				\
 | ||||
| 	mtcr	r12;							\
 | ||||
| 	mfspr	r12, SPRN_SPRG_SCRATCH1;				\
 | ||||
| 	b	kvmppc_resume_\intno;					\
 | ||||
| 1:;									\
 | ||||
| 	mtcr	r12;							\
 | ||||
| 	mfspr	r12, SPRN_SPRG_SCRATCH1;				\
 | ||||
| 	tophys(reg, reg) | ||||
| 
 | ||||
| #define SHADOW_VCPU_OFF		0 | ||||
| #define MSR_NOIRQ		MSR_KERNEL | ||||
| #define FUNC(name)		name | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| .macro INTERRUPT_TRAMPOLINE intno | ||||
| 
 | ||||
| @ -42,19 +78,19 @@ kvmppc_trampoline_\intno: | ||||
| 	 * First thing to do is to find out if we're coming | ||||
| 	 * from a KVM guest or a Linux process. | ||||
| 	 * | ||||
| 	 * To distinguish, we check a magic byte in the PACA | ||||
| 	 * To distinguish, we check a magic byte in the PACA/current | ||||
| 	 */ | ||||
| 	mfspr	r13, SPRN_SPRG_PACA		/* r13 = PACA */ | ||||
| 	std	r12, PACA_KVM_SCRATCH0(r13) | ||||
| 	LOAD_SHADOW_VCPU(r13) | ||||
| 	PPC_STL	r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) | ||||
| 	mfcr	r12 | ||||
| 	stw	r12, PACA_KVM_SCRATCH1(r13) | ||||
| 	lbz	r12, PACA_KVM_IN_GUEST(r13) | ||||
| 	stw	r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) | ||||
| 	lbz	r12, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13) | ||||
| 	cmpwi	r12, KVM_GUEST_MODE_NONE | ||||
| 	bne	..kvmppc_handler_hasmagic_\intno | ||||
| 	/* No KVM guest? Then jump back to the Linux handler! */ | ||||
| 	lwz	r12, PACA_KVM_SCRATCH1(r13) | ||||
| 	lwz	r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) | ||||
| 	mtcr	r12 | ||||
| 	ld	r12, PACA_KVM_SCRATCH0(r13) | ||||
| 	PPC_LL	r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) | ||||
| 	mfspr	r13, SPRN_SPRG_SCRATCH0		/* r13 = original r13 */ | ||||
| 	b	kvmppc_resume_\intno		/* Get back original handler */ | ||||
| 
 | ||||
| @ -76,9 +112,7 @@ kvmppc_trampoline_\intno: | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_SYSTEM_RESET | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_MACHINE_CHECK | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_DATA_STORAGE | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_DATA_SEGMENT | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_INST_STORAGE | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_INST_SEGMENT | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_EXTERNAL | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_ALIGNMENT | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_PROGRAM | ||||
| @ -88,7 +122,14 @@ INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_SYSCALL | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_TRACE | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_PERFMON | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_ALTIVEC | ||||
| 
 | ||||
| /* Those are only available on 64 bit machines */ | ||||
| 
 | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_DATA_SEGMENT | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_INST_SEGMENT | ||||
| INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_VSX | ||||
| #endif | ||||
| 
 | ||||
| /* | ||||
|  * Bring us back to the faulting code, but skip the | ||||
| @ -99,11 +140,11 @@ INTERRUPT_TRAMPOLINE	BOOK3S_INTERRUPT_VSX | ||||
|  * | ||||
|  * Input Registers: | ||||
|  * | ||||
|  * R12               = free | ||||
|  * R13               = PACA | ||||
|  * PACA.KVM.SCRATCH0 = guest R12 | ||||
|  * PACA.KVM.SCRATCH1 = guest CR | ||||
|  * SPRG_SCRATCH0     = guest R13 | ||||
|  * R12            = free | ||||
|  * R13            = Shadow VCPU (PACA) | ||||
|  * SVCPU.SCRATCH0 = guest R12 | ||||
|  * SVCPU.SCRATCH1 = guest CR | ||||
|  * SPRG_SCRATCH0  = guest R13 | ||||
|  * | ||||
|  */ | ||||
| kvmppc_handler_skip_ins: | ||||
| @ -114,9 +155,9 @@ kvmppc_handler_skip_ins: | ||||
| 	mtsrr0	r12 | ||||
| 
 | ||||
| 	/* Clean up all state */ | ||||
| 	lwz	r12, PACA_KVM_SCRATCH1(r13) | ||||
| 	lwz	r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) | ||||
| 	mtcr	r12 | ||||
| 	ld	r12, PACA_KVM_SCRATCH0(r13) | ||||
| 	PPC_LL	r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) | ||||
| 	mfspr	r13, SPRN_SPRG_SCRATCH0 | ||||
| 
 | ||||
| 	/* And get back into the code */ | ||||
| @ -147,41 +188,48 @@ kvmppc_handler_lowmem_trampoline_end: | ||||
|  * | ||||
|  * R3 = function | ||||
|  * R4 = MSR | ||||
|  * R5 = CTR | ||||
|  * R5 = scratch register | ||||
|  * | ||||
|  */ | ||||
| _GLOBAL(kvmppc_rmcall) | ||||
| 	mtmsr	r4		/* Disable relocation, so mtsrr | ||||
| 	LOAD_REG_IMMEDIATE(r5, MSR_NOIRQ) | ||||
| 	mtmsr	r5		/* Disable relocation and interrupts, so mtsrr | ||||
| 				   doesn't get interrupted */ | ||||
| 	mtctr	r5 | ||||
| 	sync | ||||
| 	mtsrr0	r3 | ||||
| 	mtsrr1	r4 | ||||
| 	RFI | ||||
| 
 | ||||
| #if defined(CONFIG_PPC_BOOK3S_32) | ||||
| #define STACK_LR	INT_FRAME_SIZE+4 | ||||
| #elif defined(CONFIG_PPC_BOOK3S_64) | ||||
| #define STACK_LR	_LINK | ||||
| #endif | ||||
| 
 | ||||
| /* | ||||
|  * Activate current's external feature (FPU/Altivec/VSX) | ||||
|  */ | ||||
| #define define_load_up(what) 				\ | ||||
| 							\ | ||||
| _GLOBAL(kvmppc_load_up_ ## what);			\ | ||||
| 	subi	r1, r1, INT_FRAME_SIZE;			\
 | ||||
| 	mflr	r3;					\
 | ||||
| 	std	r3, _LINK(r1);				\
 | ||||
| 	mfmsr	r4;					\
 | ||||
| 	std	r31, GPR3(r1);				\
 | ||||
| 	mr	r31, r4;				\
 | ||||
| 	li	r5, MSR_DR;				\
 | ||||
| 	oris	r5, r5, MSR_EE@h;			\
 | ||||
| 	andc	r4, r4, r5;				\
 | ||||
| 	mtmsr	r4;					\
 | ||||
| 							\ | ||||
| 	bl	.load_up_ ## what;			\ | ||||
| 							\ | ||||
| 	mtmsr	r31;					\
 | ||||
| 	ld	r3, _LINK(r1);				\
 | ||||
| 	ld	r31, GPR3(r1);				\
 | ||||
| 	addi	r1, r1, INT_FRAME_SIZE;			\
 | ||||
| 	mtlr	r3;					\
 | ||||
| #define define_load_up(what) 					\ | ||||
| 								\ | ||||
| _GLOBAL(kvmppc_load_up_ ## what);				\ | ||||
| 	PPC_STLU r1, -INT_FRAME_SIZE(r1);			\
 | ||||
| 	mflr	r3;						\
 | ||||
| 	PPC_STL	r3, STACK_LR(r1);				\
 | ||||
| 	PPC_STL	r20, _NIP(r1);					\
 | ||||
| 	mfmsr	r20;						\
 | ||||
| 	LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE);			\
 | ||||
| 	andc	r3,r20,r3;		/* Disable DR,EE */	\
 | ||||
| 	mtmsr	r3;						\
 | ||||
| 	sync;							\
 | ||||
| 								\ | ||||
| 	bl	FUNC(load_up_ ## what);				\ | ||||
| 								\ | ||||
| 	mtmsr	r20;			/* Enable DR,EE */	\
 | ||||
| 	sync;							\
 | ||||
| 	PPC_LL	r3, STACK_LR(r1);				\
 | ||||
| 	PPC_LL	r20, _NIP(r1);					\
 | ||||
| 	mtlr	r3;						\
 | ||||
| 	addi	r1, r1, INT_FRAME_SIZE;				\
 | ||||
| 	blr | ||||
| 
 | ||||
| define_load_up(fpu) | ||||
| @ -194,11 +242,10 @@ define_load_up(vsx) | ||||
| 
 | ||||
| .global kvmppc_trampoline_lowmem
 | ||||
| kvmppc_trampoline_lowmem: | ||||
| 	.long kvmppc_handler_lowmem_trampoline - _stext | ||||
| 	.long kvmppc_handler_lowmem_trampoline - CONFIG_KERNEL_START | ||||
| 
 | ||||
| .global kvmppc_trampoline_enter
 | ||||
| kvmppc_trampoline_enter: | ||||
| 	.long kvmppc_handler_trampoline_enter - _stext | ||||
| 
 | ||||
| #include "book3s_64_slb.S" | ||||
| 	.long kvmppc_handler_trampoline_enter - CONFIG_KERNEL_START | ||||
| 
 | ||||
| #include "book3s_segment.S" | ||||
							
								
								
									
										259
									
								
								arch/powerpc/kvm/book3s_segment.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								arch/powerpc/kvm/book3s_segment.S
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,259 @@ | ||||
| /* | ||||
|  * 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 SUSE Linux Products GmbH 2010 | ||||
|  * | ||||
|  * Authors: Alexander Graf <agraf@suse.de>
 | ||||
|  */ | ||||
| 
 | ||||
| /* Real mode helpers */ | ||||
| 
 | ||||
| #if defined(CONFIG_PPC_BOOK3S_64) | ||||
| 
 | ||||
| #define GET_SHADOW_VCPU(reg)    \ | ||||
| 	addi    reg, r13, PACA_KVM_SVCPU | ||||
| 
 | ||||
| #elif defined(CONFIG_PPC_BOOK3S_32) | ||||
| 
 | ||||
| #define GET_SHADOW_VCPU(reg)    			\ | ||||
| 	tophys(reg, r2);       			\
 | ||||
| 	lwz     reg, (THREAD + THREAD_KVM_SVCPU)(reg);	\
 | ||||
| 	tophys(reg, reg) | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| /* Disable for nested KVM */ | ||||
| #define USE_QUICK_LAST_INST | ||||
| 
 | ||||
| 
 | ||||
| /* Get helper functions for subarch specific functionality */ | ||||
| 
 | ||||
| #if defined(CONFIG_PPC_BOOK3S_64) | ||||
| #include "book3s_64_slb.S" | ||||
| #elif defined(CONFIG_PPC_BOOK3S_32) | ||||
| #include "book3s_32_sr.S" | ||||
| #endif | ||||
| 
 | ||||
| /****************************************************************************** | ||||
|  *                                                                            * | ||||
|  *                               Entry code                                   * | ||||
|  *                                                                            * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| .global kvmppc_handler_trampoline_enter
 | ||||
| kvmppc_handler_trampoline_enter: | ||||
| 
 | ||||
| 	/* Required state: | ||||
| 	 * | ||||
| 	 * MSR = ~IR|DR | ||||
| 	 * R13 = PACA | ||||
| 	 * R1 = host R1 | ||||
| 	 * R2 = host R2 | ||||
| 	 * R10 = guest MSR | ||||
| 	 * all other volatile GPRS = free | ||||
| 	 * SVCPU[CR] = guest CR | ||||
| 	 * SVCPU[XER] = guest XER | ||||
| 	 * SVCPU[CTR] = guest CTR | ||||
| 	 * SVCPU[LR] = guest LR | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* r3 = shadow vcpu */ | ||||
| 	GET_SHADOW_VCPU(r3) | ||||
| 
 | ||||
| 	/* Move SRR0 and SRR1 into the respective regs */ | ||||
| 	PPC_LL  r9, SVCPU_PC(r3) | ||||
| 	mtsrr0	r9 | ||||
| 	mtsrr1	r10 | ||||
| 
 | ||||
| 	/* Activate guest mode, so faults get handled by KVM */ | ||||
| 	li	r11, KVM_GUEST_MODE_GUEST | ||||
| 	stb	r11, SVCPU_IN_GUEST(r3) | ||||
| 
 | ||||
| 	/* Switch to guest segment. This is subarch specific. */ | ||||
| 	LOAD_GUEST_SEGMENTS | ||||
| 
 | ||||
| 	/* Enter guest */ | ||||
| 
 | ||||
| 	PPC_LL	r4, (SVCPU_CTR)(r3) | ||||
| 	PPC_LL	r5, (SVCPU_LR)(r3) | ||||
| 	lwz	r6, (SVCPU_CR)(r3) | ||||
| 	lwz	r7, (SVCPU_XER)(r3) | ||||
| 
 | ||||
| 	mtctr	r4 | ||||
| 	mtlr	r5 | ||||
| 	mtcr	r6 | ||||
| 	mtxer	r7 | ||||
| 
 | ||||
| 	PPC_LL	r0, (SVCPU_R0)(r3) | ||||
| 	PPC_LL	r1, (SVCPU_R1)(r3) | ||||
| 	PPC_LL	r2, (SVCPU_R2)(r3) | ||||
| 	PPC_LL	r4, (SVCPU_R4)(r3) | ||||
| 	PPC_LL	r5, (SVCPU_R5)(r3) | ||||
| 	PPC_LL	r6, (SVCPU_R6)(r3) | ||||
| 	PPC_LL	r7, (SVCPU_R7)(r3) | ||||
| 	PPC_LL	r8, (SVCPU_R8)(r3) | ||||
| 	PPC_LL	r9, (SVCPU_R9)(r3) | ||||
| 	PPC_LL	r10, (SVCPU_R10)(r3) | ||||
| 	PPC_LL	r11, (SVCPU_R11)(r3) | ||||
| 	PPC_LL	r12, (SVCPU_R12)(r3) | ||||
| 	PPC_LL	r13, (SVCPU_R13)(r3) | ||||
| 
 | ||||
| 	PPC_LL	r3, (SVCPU_R3)(r3) | ||||
| 
 | ||||
| 	RFI | ||||
| kvmppc_handler_trampoline_enter_end: | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /****************************************************************************** | ||||
|  *                                                                            * | ||||
|  *                               Exit code                                    * | ||||
|  *                                                                            * | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| .global kvmppc_handler_trampoline_exit
 | ||||
| kvmppc_handler_trampoline_exit: | ||||
| 
 | ||||
| 	/* Register usage at this point: | ||||
| 	 * | ||||
| 	 * SPRG_SCRATCH0  = guest R13 | ||||
| 	 * R12            = exit handler id | ||||
| 	 * R13            = shadow vcpu - SHADOW_VCPU_OFF [=PACA on PPC64] | ||||
| 	 * SVCPU.SCRATCH0 = guest R12 | ||||
| 	 * SVCPU.SCRATCH1 = guest CR | ||||
| 	 * | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* Save registers */ | ||||
| 
 | ||||
| 	PPC_STL	r0, (SHADOW_VCPU_OFF + SVCPU_R0)(r13) | ||||
| 	PPC_STL	r1, (SHADOW_VCPU_OFF + SVCPU_R1)(r13) | ||||
| 	PPC_STL	r2, (SHADOW_VCPU_OFF + SVCPU_R2)(r13) | ||||
| 	PPC_STL	r3, (SHADOW_VCPU_OFF + SVCPU_R3)(r13) | ||||
| 	PPC_STL	r4, (SHADOW_VCPU_OFF + SVCPU_R4)(r13) | ||||
| 	PPC_STL	r5, (SHADOW_VCPU_OFF + SVCPU_R5)(r13) | ||||
| 	PPC_STL	r6, (SHADOW_VCPU_OFF + SVCPU_R6)(r13) | ||||
| 	PPC_STL	r7, (SHADOW_VCPU_OFF + SVCPU_R7)(r13) | ||||
| 	PPC_STL	r8, (SHADOW_VCPU_OFF + SVCPU_R8)(r13) | ||||
| 	PPC_STL	r9, (SHADOW_VCPU_OFF + SVCPU_R9)(r13) | ||||
| 	PPC_STL	r10, (SHADOW_VCPU_OFF + SVCPU_R10)(r13) | ||||
| 	PPC_STL	r11, (SHADOW_VCPU_OFF + SVCPU_R11)(r13) | ||||
| 
 | ||||
| 	/* Restore R1/R2 so we can handle faults */ | ||||
| 	PPC_LL	r1, (SHADOW_VCPU_OFF + SVCPU_HOST_R1)(r13) | ||||
| 	PPC_LL	r2, (SHADOW_VCPU_OFF + SVCPU_HOST_R2)(r13) | ||||
| 
 | ||||
| 	/* Save guest PC and MSR */ | ||||
| 	mfsrr0	r3 | ||||
| 	mfsrr1	r4 | ||||
| 
 | ||||
| 	PPC_STL	r3, (SHADOW_VCPU_OFF + SVCPU_PC)(r13) | ||||
| 	PPC_STL	r4, (SHADOW_VCPU_OFF + SVCPU_SHADOW_SRR1)(r13) | ||||
| 
 | ||||
| 	/* Get scratch'ed off registers */ | ||||
| 	mfspr	r9, SPRN_SPRG_SCRATCH0 | ||||
| 	PPC_LL	r8, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) | ||||
| 	lwz	r7, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) | ||||
| 
 | ||||
| 	PPC_STL	r9, (SHADOW_VCPU_OFF + SVCPU_R13)(r13) | ||||
| 	PPC_STL	r8, (SHADOW_VCPU_OFF + SVCPU_R12)(r13) | ||||
| 	stw	r7, (SHADOW_VCPU_OFF + SVCPU_CR)(r13) | ||||
| 
 | ||||
| 	/* Save more register state  */ | ||||
| 
 | ||||
| 	mfxer	r5 | ||||
| 	mfdar	r6 | ||||
| 	mfdsisr	r7 | ||||
| 	mfctr	r8 | ||||
| 	mflr	r9 | ||||
| 
 | ||||
| 	stw	r5, (SHADOW_VCPU_OFF + SVCPU_XER)(r13) | ||||
| 	PPC_STL	r6, (SHADOW_VCPU_OFF + SVCPU_FAULT_DAR)(r13) | ||||
| 	stw	r7, (SHADOW_VCPU_OFF + SVCPU_FAULT_DSISR)(r13) | ||||
| 	PPC_STL	r8, (SHADOW_VCPU_OFF + SVCPU_CTR)(r13) | ||||
| 	PPC_STL	r9, (SHADOW_VCPU_OFF + SVCPU_LR)(r13) | ||||
| 
 | ||||
| 	/* | ||||
| 	 * In order for us to easily get the last instruction, | ||||
| 	 * we got the #vmexit at, we exploit the fact that the | ||||
| 	 * virtual layout is still the same here, so we can just | ||||
| 	 * ld from the guest's PC address | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* We only load the last instruction when it's safe */ | ||||
| 	cmpwi	r12, BOOK3S_INTERRUPT_DATA_STORAGE | ||||
| 	beq	ld_last_inst | ||||
| 	cmpwi	r12, BOOK3S_INTERRUPT_PROGRAM | ||||
| 	beq	ld_last_inst | ||||
| 	cmpwi	r12, BOOK3S_INTERRUPT_ALIGNMENT | ||||
| 	beq-	ld_last_inst | ||||
| 
 | ||||
| 	b	no_ld_last_inst | ||||
| 
 | ||||
| ld_last_inst: | ||||
| 	/* Save off the guest instruction we're at */ | ||||
| 
 | ||||
| 	/* In case lwz faults */ | ||||
| 	li	r0, KVM_INST_FETCH_FAILED | ||||
| 
 | ||||
| #ifdef USE_QUICK_LAST_INST | ||||
| 
 | ||||
| 	/* Set guest mode to 'jump over instruction' so if lwz faults | ||||
| 	 * we'll just continue at the next IP. */ | ||||
| 	li	r9, KVM_GUEST_MODE_SKIP | ||||
| 	stb	r9, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13) | ||||
| 
 | ||||
| 	/*    1) enable paging for data */ | ||||
| 	mfmsr	r9 | ||||
| 	ori	r11, r9, MSR_DR			/* Enable paging for data */ | ||||
| 	mtmsr	r11 | ||||
| 	sync | ||||
| 	/*    2) fetch the instruction */ | ||||
| 	lwz	r0, 0(r3) | ||||
| 	/*    3) disable paging again */ | ||||
| 	mtmsr	r9 | ||||
| 	sync | ||||
| 
 | ||||
| #endif | ||||
| 	stw	r0, (SHADOW_VCPU_OFF + SVCPU_LAST_INST)(r13) | ||||
| 
 | ||||
| no_ld_last_inst: | ||||
| 
 | ||||
| 	/* Unset guest mode */ | ||||
| 	li	r9, KVM_GUEST_MODE_NONE | ||||
| 	stb	r9, (SHADOW_VCPU_OFF + SVCPU_IN_GUEST)(r13) | ||||
| 
 | ||||
| 	/* Switch back to host MMU */ | ||||
| 	LOAD_HOST_SEGMENTS | ||||
| 
 | ||||
| 	/* Register usage at this point: | ||||
| 	 * | ||||
| 	 * R1       = host R1 | ||||
| 	 * R2       = host R2 | ||||
| 	 * R12      = exit handler id | ||||
| 	 * R13      = shadow vcpu - SHADOW_VCPU_OFF [=PACA on PPC64] | ||||
| 	 * SVCPU.*  = guest * | ||||
| 	 * | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* RFI into the highmem handler */ | ||||
| 	mfmsr	r7 | ||||
| 	ori	r7, r7, MSR_IR|MSR_DR|MSR_RI|MSR_ME	/* Enable paging */ | ||||
| 	mtsrr1	r7 | ||||
| 	/* Load highmem handler address */ | ||||
| 	PPC_LL	r8, (SHADOW_VCPU_OFF + SVCPU_VMHANDLER)(r13) | ||||
| 	mtsrr0	r8 | ||||
| 
 | ||||
| 	RFI | ||||
| kvmppc_handler_trampoline_exit_end: | ||||
| @ -133,6 +133,12 @@ void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, | ||||
| 	kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_EXTERNAL); | ||||
| } | ||||
| 
 | ||||
| void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, | ||||
|                                   struct kvm_interrupt *irq) | ||||
| { | ||||
| 	clear_bit(BOOKE_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions); | ||||
| } | ||||
| 
 | ||||
| /* Deliver the interrupt of the corresponding priority, if possible. */ | ||||
| static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, | ||||
|                                         unsigned int priority) | ||||
| @ -479,6 +485,8 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	vcpu_load(vcpu); | ||||
| 
 | ||||
| 	regs->pc = vcpu->arch.pc; | ||||
| 	regs->cr = kvmppc_get_cr(vcpu); | ||||
| 	regs->ctr = vcpu->arch.ctr; | ||||
| @ -499,6 +507,8 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||||
| 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++) | ||||
| 		regs->gpr[i] = kvmppc_get_gpr(vcpu, i); | ||||
| 
 | ||||
| 	vcpu_put(vcpu); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -506,6 +516,8 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	vcpu_load(vcpu); | ||||
| 
 | ||||
| 	vcpu->arch.pc = regs->pc; | ||||
| 	kvmppc_set_cr(vcpu, regs->cr); | ||||
| 	vcpu->arch.ctr = regs->ctr; | ||||
| @ -525,6 +537,8 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||||
| 	for (i = 0; i < ARRAY_SIZE(regs->gpr); i++) | ||||
| 		kvmppc_set_gpr(vcpu, i, regs->gpr[i]); | ||||
| 
 | ||||
| 	vcpu_put(vcpu); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -553,7 +567,12 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||||
| int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, | ||||
|                                   struct kvm_translation *tr) | ||||
| { | ||||
| 	return kvmppc_core_vcpu_translate(vcpu, tr); | ||||
| 	int r; | ||||
| 
 | ||||
| 	vcpu_load(vcpu); | ||||
| 	r = kvmppc_core_vcpu_translate(vcpu, tr); | ||||
| 	vcpu_put(vcpu); | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) | ||||
|  | ||||
| @ -161,7 +161,7 @@ static int __init kvmppc_e500_init(void) | ||||
| 	flush_icache_range(kvmppc_booke_handlers, | ||||
| 			kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); | ||||
| 
 | ||||
| 	return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), THIS_MODULE); | ||||
| 	return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); | ||||
| } | ||||
| 
 | ||||
| static void __init kvmppc_e500_exit(void) | ||||
|  | ||||
| @ -38,10 +38,12 @@ | ||||
| #define OP_31_XOP_LBZX      87 | ||||
| #define OP_31_XOP_STWX      151 | ||||
| #define OP_31_XOP_STBX      215 | ||||
| #define OP_31_XOP_LBZUX     119 | ||||
| #define OP_31_XOP_STBUX     247 | ||||
| #define OP_31_XOP_LHZX      279 | ||||
| #define OP_31_XOP_LHZUX     311 | ||||
| #define OP_31_XOP_MFSPR     339 | ||||
| #define OP_31_XOP_LHAX      343 | ||||
| #define OP_31_XOP_STHX      407 | ||||
| #define OP_31_XOP_STHUX     439 | ||||
| #define OP_31_XOP_MTSPR     467 | ||||
| @ -62,10 +64,12 @@ | ||||
| #define OP_STBU 39 | ||||
| #define OP_LHZ  40 | ||||
| #define OP_LHZU 41 | ||||
| #define OP_LHA  42 | ||||
| #define OP_LHAU 43 | ||||
| #define OP_STH  44 | ||||
| #define OP_STHU 45 | ||||
| 
 | ||||
| #ifdef CONFIG_PPC64 | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return 1; | ||||
| @ -82,7 +86,7 @@ void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) | ||||
| 	unsigned long dec_nsec; | ||||
| 
 | ||||
| 	pr_debug("mtDEC: %x\n", vcpu->arch.dec); | ||||
| #ifdef CONFIG_PPC64 | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| 	/* mtdec lowers the interrupt line when positive. */ | ||||
| 	kvmppc_core_dequeue_dec(vcpu); | ||||
| 
 | ||||
| @ -128,7 +132,7 @@ void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) | ||||
|  * from opcode tables in the future. */ | ||||
| int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	u32 inst = vcpu->arch.last_inst; | ||||
| 	u32 inst = kvmppc_get_last_inst(vcpu); | ||||
| 	u32 ea; | ||||
| 	int ra; | ||||
| 	int rb; | ||||
| @ -143,13 +147,9 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||||
| 
 | ||||
| 	pr_debug(KERN_INFO "Emulating opcode %d / %d\n", get_op(inst), get_xop(inst)); | ||||
| 
 | ||||
| 	/* Try again next time */ | ||||
| 	if (inst == KVM_INST_FETCH_FAILED) | ||||
| 		return EMULATE_DONE; | ||||
| 
 | ||||
| 	switch (get_op(inst)) { | ||||
| 	case OP_TRAP: | ||||
| #ifdef CONFIG_PPC64 | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| 	case OP_TRAP_64: | ||||
| 		kvmppc_core_queue_program(vcpu, SRR1_PROGTRAP); | ||||
| #else | ||||
| @ -171,6 +171,19 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||||
| 			emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); | ||||
| 			break; | ||||
| 
 | ||||
| 		case OP_31_XOP_LBZUX: | ||||
| 			rt = get_rt(inst); | ||||
| 			ra = get_ra(inst); | ||||
| 			rb = get_rb(inst); | ||||
| 
 | ||||
| 			ea = kvmppc_get_gpr(vcpu, rb); | ||||
| 			if (ra) | ||||
| 				ea += kvmppc_get_gpr(vcpu, ra); | ||||
| 
 | ||||
| 			emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1); | ||||
| 			kvmppc_set_gpr(vcpu, ra, ea); | ||||
| 			break; | ||||
| 
 | ||||
| 		case OP_31_XOP_STWX: | ||||
| 			rs = get_rs(inst); | ||||
| 			emulated = kvmppc_handle_store(run, vcpu, | ||||
| @ -200,6 +213,11 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||||
| 			kvmppc_set_gpr(vcpu, rs, ea); | ||||
| 			break; | ||||
| 
 | ||||
| 		case OP_31_XOP_LHAX: | ||||
| 			rt = get_rt(inst); | ||||
| 			emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1); | ||||
| 			break; | ||||
| 
 | ||||
| 		case OP_31_XOP_LHZX: | ||||
| 			rt = get_rt(inst); | ||||
| 			emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1); | ||||
| @ -450,6 +468,18 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||||
| 		kvmppc_set_gpr(vcpu, ra, vcpu->arch.paddr_accessed); | ||||
| 		break; | ||||
| 
 | ||||
| 	case OP_LHA: | ||||
| 		rt = get_rt(inst); | ||||
| 		emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1); | ||||
| 		break; | ||||
| 
 | ||||
| 	case OP_LHAU: | ||||
| 		ra = get_ra(inst); | ||||
| 		rt = get_rt(inst); | ||||
| 		emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1); | ||||
| 		kvmppc_set_gpr(vcpu, ra, vcpu->arch.paddr_accessed); | ||||
| 		break; | ||||
| 
 | ||||
| 	case OP_STH: | ||||
| 		rs = get_rs(inst); | ||||
| 		emulated = kvmppc_handle_store(run, vcpu, | ||||
| @ -472,7 +502,9 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||||
| 
 | ||||
| 	if (emulated == EMULATE_FAIL) { | ||||
| 		emulated = kvmppc_core_emulate_op(run, vcpu, inst, &advance); | ||||
| 		if (emulated == EMULATE_FAIL) { | ||||
| 		if (emulated == EMULATE_AGAIN) { | ||||
| 			advance = 0; | ||||
| 		} else if (emulated == EMULATE_FAIL) { | ||||
| 			advance = 0; | ||||
| 			printk(KERN_ERR "Couldn't emulate instruction 0x%08x " | ||||
| 			       "(op %d xop %d)\n", inst, get_op(inst), get_xop(inst)); | ||||
| @ -480,10 +512,11 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	trace_kvm_ppc_instr(inst, vcpu->arch.pc, emulated); | ||||
| 	trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated); | ||||
| 
 | ||||
| 	/* Advance past emulated instruction. */ | ||||
| 	if (advance) | ||||
| 		vcpu->arch.pc += 4; /* Advance past emulated instruction. */ | ||||
| 		kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4); | ||||
| 
 | ||||
| 	return emulated; | ||||
| } | ||||
|  | ||||
							
								
								
									
										273
									
								
								arch/powerpc/kvm/fpu.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								arch/powerpc/kvm/fpu.S
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,273 @@ | ||||
| /* | ||||
|  *  FPU helper code to use FPU operations from inside the kernel | ||||
|  * | ||||
|  *    Copyright (C) 2010 Alexander Graf (agraf@suse.de)
 | ||||
|  * | ||||
|  *  This program is free software; you can redistribute it and/or
 | ||||
|  *  modify it under the terms of the GNU General Public License | ||||
|  *  as published by the Free Software Foundation; either version
 | ||||
|  *  2 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <asm/reg.h> | ||||
| #include <asm/page.h> | ||||
| #include <asm/mmu.h> | ||||
| #include <asm/pgtable.h> | ||||
| #include <asm/cputable.h> | ||||
| #include <asm/cache.h> | ||||
| #include <asm/thread_info.h> | ||||
| #include <asm/ppc_asm.h> | ||||
| #include <asm/asm-offsets.h> | ||||
| 
 | ||||
| /* Instructions operating on single parameters */ | ||||
| 
 | ||||
| /* | ||||
|  * Single operation with one input operand | ||||
|  * | ||||
|  * R3 = (double*)&fpscr | ||||
|  * R4 = (short*)&result | ||||
|  * R5 = (short*)¶m1 | ||||
|  */ | ||||
| #define FPS_ONE_IN(name) 					\ | ||||
| _GLOBAL(fps_ ## name);							\ | ||||
| 	lfd	0,0(r3);		/* load up fpscr value */	\
 | ||||
| 	MTFSF_L(0);							\
 | ||||
| 	lfs	0,0(r5);						\
 | ||||
| 									\ | ||||
| 	name	0,0;							\
 | ||||
| 									\ | ||||
| 	stfs	0,0(r4);						\
 | ||||
| 	mffs	0;							\
 | ||||
| 	stfd	0,0(r3);	/* save new fpscr value */	\
 | ||||
| 	blr | ||||
| 
 | ||||
| /* | ||||
|  * Single operation with two input operands | ||||
|  * | ||||
|  * R3 = (double*)&fpscr | ||||
|  * R4 = (short*)&result | ||||
|  * R5 = (short*)¶m1 | ||||
|  * R6 = (short*)¶m2 | ||||
|  */ | ||||
| #define FPS_TWO_IN(name) 					\ | ||||
| _GLOBAL(fps_ ## name);							\ | ||||
| 	lfd	0,0(r3);		/* load up fpscr value */	\
 | ||||
| 	MTFSF_L(0);							\
 | ||||
| 	lfs	0,0(r5);						\
 | ||||
| 	lfs	1,0(r6);						\
 | ||||
| 									\ | ||||
| 	name	0,0,1;							\
 | ||||
| 									\ | ||||
| 	stfs	0,0(r4);						\
 | ||||
| 	mffs	0;							\
 | ||||
| 	stfd	0,0(r3);		/* save new fpscr value */	\
 | ||||
| 	blr | ||||
| 
 | ||||
| /* | ||||
|  * Single operation with three input operands | ||||
|  * | ||||
|  * R3 = (double*)&fpscr | ||||
|  * R4 = (short*)&result | ||||
|  * R5 = (short*)¶m1 | ||||
|  * R6 = (short*)¶m2 | ||||
|  * R7 = (short*)¶m3 | ||||
|  */ | ||||
| #define FPS_THREE_IN(name) 					\ | ||||
| _GLOBAL(fps_ ## name);							\ | ||||
| 	lfd	0,0(r3);		/* load up fpscr value */	\
 | ||||
| 	MTFSF_L(0);							\
 | ||||
| 	lfs	0,0(r5);						\
 | ||||
| 	lfs	1,0(r6);						\
 | ||||
| 	lfs	2,0(r7);						\
 | ||||
| 									\ | ||||
| 	name	0,0,1,2;						\
 | ||||
| 									\ | ||||
| 	stfs	0,0(r4);						\
 | ||||
| 	mffs	0;							\
 | ||||
| 	stfd	0,0(r3);		/* save new fpscr value */	\
 | ||||
| 	blr | ||||
| 
 | ||||
| FPS_ONE_IN(fres) | ||||
| FPS_ONE_IN(frsqrte) | ||||
| FPS_ONE_IN(fsqrts) | ||||
| FPS_TWO_IN(fadds) | ||||
| FPS_TWO_IN(fdivs) | ||||
| FPS_TWO_IN(fmuls) | ||||
| FPS_TWO_IN(fsubs) | ||||
| FPS_THREE_IN(fmadds) | ||||
| FPS_THREE_IN(fmsubs) | ||||
| FPS_THREE_IN(fnmadds) | ||||
| FPS_THREE_IN(fnmsubs) | ||||
| FPS_THREE_IN(fsel) | ||||
| 
 | ||||
| 
 | ||||
| /* Instructions operating on double parameters */ | ||||
| 
 | ||||
| /* | ||||
|  * Beginning of double instruction processing | ||||
|  * | ||||
|  * R3 = (double*)&fpscr | ||||
|  * R4 = (u32*)&cr | ||||
|  * R5 = (double*)&result | ||||
|  * R6 = (double*)¶m1 | ||||
|  * R7 = (double*)¶m2 [load_two] | ||||
|  * R8 = (double*)¶m3 [load_three] | ||||
|  * LR = instruction call function | ||||
|  */ | ||||
| fpd_load_three: | ||||
| 	lfd	2,0(r8)			/* load param3 */ | ||||
| fpd_load_two: | ||||
| 	lfd	1,0(r7)			/* load param2 */ | ||||
| fpd_load_one: | ||||
| 	lfd	0,0(r6)			/* load param1 */ | ||||
| fpd_load_none: | ||||
| 	lfd	3,0(r3)			/* load up fpscr value */ | ||||
| 	MTFSF_L(3) | ||||
| 	lwz	r6, 0(r4)		/* load cr */ | ||||
| 	mtcr	r6 | ||||
| 	blr | ||||
| 
 | ||||
| /* | ||||
|  * End of double instruction processing | ||||
|  * | ||||
|  * R3 = (double*)&fpscr | ||||
|  * R4 = (u32*)&cr | ||||
|  * R5 = (double*)&result | ||||
|  * LR = caller of instruction call function | ||||
|  */ | ||||
| fpd_return: | ||||
| 	mfcr	r6 | ||||
| 	stfd	0,0(r5)			/* save result */ | ||||
| 	mffs	0 | ||||
| 	stfd	0,0(r3)			/* save new fpscr value */ | ||||
| 	stw	r6,0(r4)		/* save new cr value */ | ||||
| 	blr | ||||
| 
 | ||||
| /* | ||||
|  * Double operation with no input operand | ||||
|  * | ||||
|  * R3 = (double*)&fpscr | ||||
|  * R4 = (u32*)&cr | ||||
|  * R5 = (double*)&result | ||||
|  */ | ||||
| #define FPD_NONE_IN(name) 						\ | ||||
| _GLOBAL(fpd_ ## name);							\ | ||||
| 	mflr	r12;							\
 | ||||
| 	bl	fpd_load_none;						\
 | ||||
| 	mtlr	r12;							\
 | ||||
| 									\ | ||||
| 	name.	0;			/* call instruction */		\
 | ||||
| 	b	fpd_return | ||||
| 
 | ||||
| /* | ||||
|  * Double operation with one input operand | ||||
|  * | ||||
|  * R3 = (double*)&fpscr | ||||
|  * R4 = (u32*)&cr | ||||
|  * R5 = (double*)&result | ||||
|  * R6 = (double*)¶m1 | ||||
|  */ | ||||
| #define FPD_ONE_IN(name) 						\ | ||||
| _GLOBAL(fpd_ ## name);							\ | ||||
| 	mflr	r12;							\
 | ||||
| 	bl	fpd_load_one;						\
 | ||||
| 	mtlr	r12;							\
 | ||||
| 									\ | ||||
| 	name.	0,0;			/* call instruction */		\
 | ||||
| 	b	fpd_return | ||||
| 
 | ||||
| /* | ||||
|  * Double operation with two input operands | ||||
|  * | ||||
|  * R3 = (double*)&fpscr | ||||
|  * R4 = (u32*)&cr | ||||
|  * R5 = (double*)&result | ||||
|  * R6 = (double*)¶m1 | ||||
|  * R7 = (double*)¶m2 | ||||
|  * R8 = (double*)¶m3 | ||||
|  */ | ||||
| #define FPD_TWO_IN(name) 						\ | ||||
| _GLOBAL(fpd_ ## name);							\ | ||||
| 	mflr	r12;							\
 | ||||
| 	bl	fpd_load_two;						\
 | ||||
| 	mtlr	r12;							\
 | ||||
| 									\ | ||||
| 	name.	0,0,1;			/* call instruction */		\
 | ||||
| 	b	fpd_return | ||||
| 
 | ||||
| /* | ||||
|  * CR Double operation with two input operands | ||||
|  * | ||||
|  * R3 = (double*)&fpscr | ||||
|  * R4 = (u32*)&cr | ||||
|  * R5 = (double*)¶m1 | ||||
|  * R6 = (double*)¶m2 | ||||
|  * R7 = (double*)¶m3 | ||||
|  */ | ||||
| #define FPD_TWO_IN_CR(name)						\ | ||||
| _GLOBAL(fpd_ ## name);							\ | ||||
| 	lfd	1,0(r6);		/* load param2 */		\
 | ||||
| 	lfd	0,0(r5);		/* load param1 */		\
 | ||||
| 	lfd	3,0(r3);		/* load up fpscr value */	\
 | ||||
| 	MTFSF_L(3);							\
 | ||||
| 	lwz	r6, 0(r4);		/* load cr */			\
 | ||||
| 	mtcr	r6;							\
 | ||||
| 									\ | ||||
| 	name	0,0,1;			/* call instruction */		\
 | ||||
| 	mfcr	r6;							\
 | ||||
| 	mffs	0;							\
 | ||||
| 	stfd	0,0(r3);		/* save new fpscr value */	\
 | ||||
| 	stw	r6,0(r4);		/* save new cr value */		\
 | ||||
| 	blr | ||||
| 
 | ||||
| /* | ||||
|  * Double operation with three input operands | ||||
|  * | ||||
|  * R3 = (double*)&fpscr | ||||
|  * R4 = (u32*)&cr | ||||
|  * R5 = (double*)&result | ||||
|  * R6 = (double*)¶m1 | ||||
|  * R7 = (double*)¶m2 | ||||
|  * R8 = (double*)¶m3 | ||||
|  */ | ||||
| #define FPD_THREE_IN(name) 						\ | ||||
| _GLOBAL(fpd_ ## name);							\ | ||||
| 	mflr	r12;							\
 | ||||
| 	bl	fpd_load_three;						\
 | ||||
| 	mtlr	r12;							\
 | ||||
| 									\ | ||||
| 	name.	0,0,1,2;		/* call instruction */		\
 | ||||
| 	b	fpd_return | ||||
| 
 | ||||
| FPD_ONE_IN(fsqrts) | ||||
| FPD_ONE_IN(frsqrtes) | ||||
| FPD_ONE_IN(fres) | ||||
| FPD_ONE_IN(frsp) | ||||
| FPD_ONE_IN(fctiw) | ||||
| FPD_ONE_IN(fctiwz) | ||||
| FPD_ONE_IN(fsqrt) | ||||
| FPD_ONE_IN(fre) | ||||
| FPD_ONE_IN(frsqrte) | ||||
| FPD_ONE_IN(fneg) | ||||
| FPD_ONE_IN(fabs) | ||||
| FPD_TWO_IN(fadds) | ||||
| FPD_TWO_IN(fsubs) | ||||
| FPD_TWO_IN(fdivs) | ||||
| FPD_TWO_IN(fmuls) | ||||
| FPD_TWO_IN_CR(fcmpu) | ||||
| FPD_TWO_IN(fcpsgn) | ||||
| FPD_TWO_IN(fdiv) | ||||
| FPD_TWO_IN(fadd) | ||||
| FPD_TWO_IN(fmul) | ||||
| FPD_TWO_IN_CR(fcmpo) | ||||
| FPD_TWO_IN(fsub) | ||||
| FPD_THREE_IN(fmsubs) | ||||
| FPD_THREE_IN(fmadds) | ||||
| FPD_THREE_IN(fnmsubs) | ||||
| FPD_THREE_IN(fnmadds) | ||||
| FPD_THREE_IN(fsel) | ||||
| FPD_THREE_IN(fmsub) | ||||
| FPD_THREE_IN(fmadd) | ||||
| FPD_THREE_IN(fnmsub) | ||||
| FPD_THREE_IN(fnmadd) | ||||
| @ -70,7 +70,7 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu) | ||||
| 	case EMULATE_FAIL: | ||||
| 		/* XXX Deliver Program interrupt to guest. */ | ||||
| 		printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__, | ||||
| 		       vcpu->arch.last_inst); | ||||
| 		       kvmppc_get_last_inst(vcpu)); | ||||
| 		r = RESUME_HOST; | ||||
| 		break; | ||||
| 	default: | ||||
| @ -148,6 +148,10 @@ int kvm_dev_ioctl_check_extension(long ext) | ||||
| 
 | ||||
| 	switch (ext) { | ||||
| 	case KVM_CAP_PPC_SEGSTATE: | ||||
| 	case KVM_CAP_PPC_PAIRED_SINGLES: | ||||
| 	case KVM_CAP_PPC_UNSET_IRQ: | ||||
| 	case KVM_CAP_ENABLE_CAP: | ||||
| 	case KVM_CAP_PPC_OSI: | ||||
| 		r = 1; | ||||
| 		break; | ||||
| 	case KVM_CAP_COALESCED_MMIO: | ||||
| @ -193,12 +197,17 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) | ||||
| { | ||||
| 	struct kvm_vcpu *vcpu; | ||||
| 	vcpu = kvmppc_core_vcpu_create(kvm, id); | ||||
| 	kvmppc_create_vcpu_debugfs(vcpu, id); | ||||
| 	if (!IS_ERR(vcpu)) | ||||
| 		kvmppc_create_vcpu_debugfs(vcpu, id); | ||||
| 	return vcpu; | ||||
| } | ||||
| 
 | ||||
| void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	/* Make sure we're not using the vcpu anymore */ | ||||
| 	hrtimer_cancel(&vcpu->arch.dec_timer); | ||||
| 	tasklet_kill(&vcpu->arch.tasklet); | ||||
| 
 | ||||
| 	kvmppc_remove_vcpu_debugfs(vcpu); | ||||
| 	kvmppc_core_vcpu_free(vcpu); | ||||
| } | ||||
| @ -278,7 +287,7 @@ static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu, | ||||
| static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu, | ||||
|                                       struct kvm_run *run) | ||||
| { | ||||
| 	ulong gpr; | ||||
| 	u64 gpr; | ||||
| 
 | ||||
| 	if (run->mmio.len > sizeof(gpr)) { | ||||
| 		printk(KERN_ERR "bad MMIO length: %d\n", run->mmio.len); | ||||
| @ -287,6 +296,7 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu, | ||||
| 
 | ||||
| 	if (vcpu->arch.mmio_is_bigendian) { | ||||
| 		switch (run->mmio.len) { | ||||
| 		case 8: gpr = *(u64 *)run->mmio.data; break; | ||||
| 		case 4: gpr = *(u32 *)run->mmio.data; break; | ||||
| 		case 2: gpr = *(u16 *)run->mmio.data; break; | ||||
| 		case 1: gpr = *(u8 *)run->mmio.data; break; | ||||
| @ -300,7 +310,43 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (vcpu->arch.mmio_sign_extend) { | ||||
| 		switch (run->mmio.len) { | ||||
| #ifdef CONFIG_PPC64 | ||||
| 		case 4: | ||||
| 			gpr = (s64)(s32)gpr; | ||||
| 			break; | ||||
| #endif | ||||
| 		case 2: | ||||
| 			gpr = (s64)(s16)gpr; | ||||
| 			break; | ||||
| 		case 1: | ||||
| 			gpr = (s64)(s8)gpr; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr); | ||||
| 
 | ||||
| 	switch (vcpu->arch.io_gpr & KVM_REG_EXT_MASK) { | ||||
| 	case KVM_REG_GPR: | ||||
| 		kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr); | ||||
| 		break; | ||||
| 	case KVM_REG_FPR: | ||||
| 		vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr; | ||||
| 		break; | ||||
| #ifdef CONFIG_PPC_BOOK3S | ||||
| 	case KVM_REG_QPR: | ||||
| 		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr; | ||||
| 		break; | ||||
| 	case KVM_REG_FQPR: | ||||
| 		vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr; | ||||
| 		vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr; | ||||
| 		break; | ||||
| #endif | ||||
| 	default: | ||||
| 		BUG(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| @ -319,12 +365,25 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 	vcpu->arch.mmio_is_bigendian = is_bigendian; | ||||
| 	vcpu->mmio_needed = 1; | ||||
| 	vcpu->mmio_is_write = 0; | ||||
| 	vcpu->arch.mmio_sign_extend = 0; | ||||
| 
 | ||||
| 	return EMULATE_DO_MMIO; | ||||
| } | ||||
| 
 | ||||
| /* Same as above, but sign extends */ | ||||
| int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
|                         unsigned int rt, unsigned int bytes, int is_bigendian) | ||||
| { | ||||
| 	int r; | ||||
| 
 | ||||
| 	r = kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian); | ||||
| 	vcpu->arch.mmio_sign_extend = 1; | ||||
| 
 | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
|                         u32 val, unsigned int bytes, int is_bigendian) | ||||
|                         u64 val, unsigned int bytes, int is_bigendian) | ||||
| { | ||||
| 	void *data = run->mmio.data; | ||||
| 
 | ||||
| @ -342,6 +401,7 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||||
| 	/* Store the value at the lowest bytes in 'data'. */ | ||||
| 	if (is_bigendian) { | ||||
| 		switch (bytes) { | ||||
| 		case 8: *(u64 *)data = val; break; | ||||
| 		case 4: *(u32 *)data = val; break; | ||||
| 		case 2: *(u16 *)data = val; break; | ||||
| 		case 1: *(u8  *)data = val; break; | ||||
| @ -376,6 +436,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||||
| 		if (!vcpu->arch.dcr_is_write) | ||||
| 			kvmppc_complete_dcr_load(vcpu, run); | ||||
| 		vcpu->arch.dcr_needed = 0; | ||||
| 	} else if (vcpu->arch.osi_needed) { | ||||
| 		u64 *gprs = run->osi.gprs; | ||||
| 		int i; | ||||
| 
 | ||||
| 		for (i = 0; i < 32; i++) | ||||
| 			kvmppc_set_gpr(vcpu, i, gprs[i]); | ||||
| 		vcpu->arch.osi_needed = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	kvmppc_core_deliver_interrupts(vcpu); | ||||
| @ -396,7 +463,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||||
| 
 | ||||
| int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) | ||||
| { | ||||
| 	kvmppc_core_queue_external(vcpu, irq); | ||||
| 	if (irq->irq == KVM_INTERRUPT_UNSET) | ||||
| 		kvmppc_core_dequeue_external(vcpu, irq); | ||||
| 	else | ||||
| 		kvmppc_core_queue_external(vcpu, irq); | ||||
| 
 | ||||
| 	if (waitqueue_active(&vcpu->wq)) { | ||||
| 		wake_up_interruptible(&vcpu->wq); | ||||
| @ -406,6 +476,27 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, | ||||
| 				     struct kvm_enable_cap *cap) | ||||
| { | ||||
| 	int r; | ||||
| 
 | ||||
| 	if (cap->flags) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	switch (cap->cap) { | ||||
| 	case KVM_CAP_PPC_OSI: | ||||
| 		r = 0; | ||||
| 		vcpu->arch.osi_enabled = true; | ||||
| 		break; | ||||
| 	default: | ||||
| 		r = -EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, | ||||
|                                     struct kvm_mp_state *mp_state) | ||||
| { | ||||
| @ -434,6 +525,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | ||||
| 		r = kvm_vcpu_ioctl_interrupt(vcpu, &irq); | ||||
| 		break; | ||||
| 	} | ||||
| 	case KVM_ENABLE_CAP: | ||||
| 	{ | ||||
| 		struct kvm_enable_cap cap; | ||||
| 		r = -EFAULT; | ||||
| 		if (copy_from_user(&cap, argp, sizeof(cap))) | ||||
| 			goto out; | ||||
| 		r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap); | ||||
| 		break; | ||||
| 	} | ||||
| 	default: | ||||
| 		r = -EINVAL; | ||||
| 	} | ||||
|  | ||||
| @ -60,11 +60,7 @@ | ||||
| static unsigned long next_mmu_context; | ||||
| static unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Set up the context for a new address space. | ||||
|  */ | ||||
| int init_new_context(struct task_struct *t, struct mm_struct *mm) | ||||
| unsigned long __init_new_context(void) | ||||
| { | ||||
| 	unsigned long ctx = next_mmu_context; | ||||
| 
 | ||||
| @ -74,11 +70,30 @@ int init_new_context(struct task_struct *t, struct mm_struct *mm) | ||||
| 			ctx = 0; | ||||
| 	} | ||||
| 	next_mmu_context = (ctx + 1) & LAST_CONTEXT; | ||||
| 	mm->context.id = ctx; | ||||
| 
 | ||||
| 	return ctx; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(__init_new_context); | ||||
| 
 | ||||
| /*
 | ||||
|  * Set up the context for a new address space. | ||||
|  */ | ||||
| int init_new_context(struct task_struct *t, struct mm_struct *mm) | ||||
| { | ||||
| 	mm->context.id = __init_new_context(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Free a context ID. Make sure to call this with preempt disabled! | ||||
|  */ | ||||
| void __destroy_context(unsigned long ctx) | ||||
| { | ||||
| 	clear_bit(ctx, context_map); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(__destroy_context); | ||||
| 
 | ||||
| /*
 | ||||
|  * We're finished using the context for an address space. | ||||
|  */ | ||||
| @ -86,7 +101,7 @@ void destroy_context(struct mm_struct *mm) | ||||
| { | ||||
| 	preempt_disable(); | ||||
| 	if (mm->context.id != NO_CONTEXT) { | ||||
| 		clear_bit(mm->context.id, context_map); | ||||
| 		__destroy_context(mm->context.id); | ||||
| 		mm->context.id = NO_CONTEXT; | ||||
| 	} | ||||
| 	preempt_enable(); | ||||
|  | ||||
| @ -341,11 +341,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, | ||||
| 
 | ||||
| 	rc = kvm_vcpu_init(vcpu, kvm, id); | ||||
| 	if (rc) | ||||
| 		goto out_free_cpu; | ||||
| 		goto out_free_sie_block; | ||||
| 	VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu, | ||||
| 		 vcpu->arch.sie_block); | ||||
| 
 | ||||
| 	return vcpu; | ||||
| out_free_sie_block: | ||||
| 	free_page((unsigned long)(vcpu->arch.sie_block)); | ||||
| out_free_cpu: | ||||
| 	kfree(vcpu); | ||||
| out_nomem: | ||||
| @ -750,7 +752,7 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) | ||||
| static int __init kvm_s390_init(void) | ||||
| { | ||||
| 	int ret; | ||||
| 	ret = kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE); | ||||
| 	ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
|  | ||||
| @ -72,7 +72,7 @@ static inline void kvm_s390_vcpu_set_mem(struct kvm_vcpu *vcpu) | ||||
| 	struct kvm_memslots *memslots; | ||||
| 
 | ||||
| 	idx = srcu_read_lock(&vcpu->kvm->srcu); | ||||
| 	memslots = rcu_dereference(vcpu->kvm->memslots); | ||||
| 	memslots = kvm_memslots(vcpu->kvm); | ||||
| 
 | ||||
| 	mem = &memslots->memslots[0]; | ||||
| 
 | ||||
|  | ||||
| @ -21,6 +21,7 @@ | ||||
| #define __KVM_HAVE_PIT_STATE2 | ||||
| #define __KVM_HAVE_XEN_HVM | ||||
| #define __KVM_HAVE_VCPU_EVENTS | ||||
| #define __KVM_HAVE_DEBUGREGS | ||||
| 
 | ||||
| /* Architectural interrupt line count. */ | ||||
| #define KVM_NR_INTERRUPTS 256 | ||||
| @ -257,6 +258,11 @@ struct kvm_reinject_control { | ||||
| /* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */ | ||||
| #define KVM_VCPUEVENT_VALID_NMI_PENDING	0x00000001 | ||||
| #define KVM_VCPUEVENT_VALID_SIPI_VECTOR	0x00000002 | ||||
| #define KVM_VCPUEVENT_VALID_SHADOW	0x00000004 | ||||
| 
 | ||||
| /* Interrupt shadow states */ | ||||
| #define KVM_X86_SHADOW_INT_MOV_SS	0x01 | ||||
| #define KVM_X86_SHADOW_INT_STI		0x02 | ||||
| 
 | ||||
| /* for KVM_GET/SET_VCPU_EVENTS */ | ||||
| struct kvm_vcpu_events { | ||||
| @ -271,7 +277,7 @@ struct kvm_vcpu_events { | ||||
| 		__u8 injected; | ||||
| 		__u8 nr; | ||||
| 		__u8 soft; | ||||
| 		__u8 pad; | ||||
| 		__u8 shadow; | ||||
| 	} interrupt; | ||||
| 	struct { | ||||
| 		__u8 injected; | ||||
| @ -284,4 +290,13 @@ struct kvm_vcpu_events { | ||||
| 	__u32 reserved[10]; | ||||
| }; | ||||
| 
 | ||||
| /* for KVM_GET/SET_DEBUGREGS */ | ||||
| struct kvm_debugregs { | ||||
| 	__u64 db[4]; | ||||
| 	__u64 dr6; | ||||
| 	__u64 dr7; | ||||
| 	__u64 flags; | ||||
| 	__u64 reserved[9]; | ||||
| }; | ||||
| 
 | ||||
| #endif /* _ASM_X86_KVM_H */ | ||||
|  | ||||
| @ -11,6 +11,8 @@ | ||||
| #ifndef _ASM_X86_KVM_X86_EMULATE_H | ||||
| #define _ASM_X86_KVM_X86_EMULATE_H | ||||
| 
 | ||||
| #include <asm/desc_defs.h> | ||||
| 
 | ||||
| struct x86_emulate_ctxt; | ||||
| 
 | ||||
| /*
 | ||||
| @ -62,6 +64,15 @@ struct x86_emulate_ops { | ||||
| 	int (*read_std)(unsigned long addr, void *val, | ||||
| 			unsigned int bytes, struct kvm_vcpu *vcpu, u32 *error); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * write_std: Write bytes of standard (non-emulated/special) memory. | ||||
| 	 *            Used for descriptor writing. | ||||
| 	 *  @addr:  [IN ] Linear address to which to write. | ||||
| 	 *  @val:   [OUT] Value write to memory, zero-extended to 'u_long'. | ||||
| 	 *  @bytes: [IN ] Number of bytes to write to memory. | ||||
| 	 */ | ||||
| 	int (*write_std)(unsigned long addr, void *val, | ||||
| 			 unsigned int bytes, struct kvm_vcpu *vcpu, u32 *error); | ||||
| 	/*
 | ||||
| 	 * fetch: Read bytes of standard (non-emulated/special) memory. | ||||
| 	 *        Used for instruction fetch. | ||||
| @ -109,6 +120,23 @@ struct x86_emulate_ops { | ||||
| 				unsigned int bytes, | ||||
| 				struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
| 	int (*pio_in_emulated)(int size, unsigned short port, void *val, | ||||
| 			       unsigned int count, struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
| 	int (*pio_out_emulated)(int size, unsigned short port, const void *val, | ||||
| 				unsigned int count, struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
| 	bool (*get_cached_descriptor)(struct desc_struct *desc, | ||||
| 				      int seg, struct kvm_vcpu *vcpu); | ||||
| 	void (*set_cached_descriptor)(struct desc_struct *desc, | ||||
| 				      int seg, struct kvm_vcpu *vcpu); | ||||
| 	u16 (*get_segment_selector)(int seg, struct kvm_vcpu *vcpu); | ||||
| 	void (*set_segment_selector)(u16 sel, int seg, struct kvm_vcpu *vcpu); | ||||
| 	void (*get_gdt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu); | ||||
| 	ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu); | ||||
| 	void (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu); | ||||
| 	int (*cpl)(struct kvm_vcpu *vcpu); | ||||
| 	void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags); | ||||
| }; | ||||
| 
 | ||||
| /* Type, address-of, and value of an instruction's operand. */ | ||||
| @ -124,6 +152,12 @@ struct fetch_cache { | ||||
| 	unsigned long end; | ||||
| }; | ||||
| 
 | ||||
| struct read_cache { | ||||
| 	u8 data[1024]; | ||||
| 	unsigned long pos; | ||||
| 	unsigned long end; | ||||
| }; | ||||
| 
 | ||||
| struct decode_cache { | ||||
| 	u8 twobyte; | ||||
| 	u8 b; | ||||
| @ -139,7 +173,7 @@ struct decode_cache { | ||||
| 	u8 seg_override; | ||||
| 	unsigned int d; | ||||
| 	unsigned long regs[NR_VCPU_REGS]; | ||||
| 	unsigned long eip, eip_orig; | ||||
| 	unsigned long eip; | ||||
| 	/* modrm */ | ||||
| 	u8 modrm; | ||||
| 	u8 modrm_mod; | ||||
| @ -151,16 +185,15 @@ struct decode_cache { | ||||
| 	void *modrm_ptr; | ||||
| 	unsigned long modrm_val; | ||||
| 	struct fetch_cache fetch; | ||||
| 	struct read_cache io_read; | ||||
| }; | ||||
| 
 | ||||
| #define X86_SHADOW_INT_MOV_SS  1 | ||||
| #define X86_SHADOW_INT_STI     2 | ||||
| 
 | ||||
| struct x86_emulate_ctxt { | ||||
| 	/* Register state before/after emulation. */ | ||||
| 	struct kvm_vcpu *vcpu; | ||||
| 
 | ||||
| 	unsigned long eflags; | ||||
| 	unsigned long eip; /* eip before instruction emulation */ | ||||
| 	/* Emulated execution mode, represented by an X86EMUL_MODE value. */ | ||||
| 	int mode; | ||||
| 	u32 cs_base; | ||||
| @ -168,6 +201,7 @@ struct x86_emulate_ctxt { | ||||
| 	/* interruptibility state, as a result of execution of STI or MOV SS */ | ||||
| 	int interruptibility; | ||||
| 
 | ||||
| 	bool restart; /* restart string instruction after writeback */ | ||||
| 	/* decode cache */ | ||||
| 	struct decode_cache decode; | ||||
| }; | ||||
| @ -194,5 +228,9 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, | ||||
| 		    struct x86_emulate_ops *ops); | ||||
| int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, | ||||
| 		     struct x86_emulate_ops *ops); | ||||
| int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | ||||
| 			 struct x86_emulate_ops *ops, | ||||
| 			 u16 tss_selector, int reason, | ||||
| 			 bool has_error_code, u32 error_code); | ||||
| 
 | ||||
| #endif /* _ASM_X86_KVM_X86_EMULATE_H */ | ||||
|  | ||||
| @ -171,15 +171,15 @@ struct kvm_pte_chain { | ||||
| union kvm_mmu_page_role { | ||||
| 	unsigned word; | ||||
| 	struct { | ||||
| 		unsigned glevels:4; | ||||
| 		unsigned level:4; | ||||
| 		unsigned cr4_pae:1; | ||||
| 		unsigned quadrant:2; | ||||
| 		unsigned pad_for_nice_hex_output:6; | ||||
| 		unsigned direct:1; | ||||
| 		unsigned access:3; | ||||
| 		unsigned invalid:1; | ||||
| 		unsigned cr4_pge:1; | ||||
| 		unsigned nxe:1; | ||||
| 		unsigned cr0_wp:1; | ||||
| 	}; | ||||
| }; | ||||
| 
 | ||||
| @ -187,8 +187,6 @@ struct kvm_mmu_page { | ||||
| 	struct list_head link; | ||||
| 	struct hlist_node hash_link; | ||||
| 
 | ||||
| 	struct list_head oos_link; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The following two entries are used to key the shadow page in the | ||||
| 	 * hash table. | ||||
| @ -204,9 +202,9 @@ struct kvm_mmu_page { | ||||
| 	 * in this shadow page. | ||||
| 	 */ | ||||
| 	DECLARE_BITMAP(slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS); | ||||
| 	int multimapped;         /* More than one parent_pte? */ | ||||
| 	int root_count;          /* Currently serving as active root */ | ||||
| 	bool multimapped;         /* More than one parent_pte? */ | ||||
| 	bool unsync; | ||||
| 	int root_count;          /* Currently serving as active root */ | ||||
| 	unsigned int unsync_children; | ||||
| 	union { | ||||
| 		u64 *parent_pte;               /* !multimapped */ | ||||
| @ -224,14 +222,9 @@ struct kvm_pv_mmu_op_buffer { | ||||
| 
 | ||||
| struct kvm_pio_request { | ||||
| 	unsigned long count; | ||||
| 	int cur_count; | ||||
| 	gva_t guest_gva; | ||||
| 	int in; | ||||
| 	int port; | ||||
| 	int size; | ||||
| 	int string; | ||||
| 	int down; | ||||
| 	int rep; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
| @ -320,6 +313,7 @@ struct kvm_vcpu_arch { | ||||
| 	struct kvm_queued_exception { | ||||
| 		bool pending; | ||||
| 		bool has_error_code; | ||||
| 		bool reinject; | ||||
| 		u8 nr; | ||||
| 		u32 error_code; | ||||
| 	} exception; | ||||
| @ -362,8 +356,8 @@ struct kvm_vcpu_arch { | ||||
| 	u64 *mce_banks; | ||||
| 
 | ||||
| 	/* used for guest single stepping over the given code position */ | ||||
| 	u16 singlestep_cs; | ||||
| 	unsigned long singlestep_rip; | ||||
| 
 | ||||
| 	/* fields used by HYPER-V emulation */ | ||||
| 	u64 hv_vapic; | ||||
| }; | ||||
| @ -389,6 +383,7 @@ struct kvm_arch { | ||||
| 	unsigned int n_free_mmu_pages; | ||||
| 	unsigned int n_requested_mmu_pages; | ||||
| 	unsigned int n_alloc_mmu_pages; | ||||
| 	atomic_t invlpg_counter; | ||||
| 	struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; | ||||
| 	/*
 | ||||
| 	 * Hash table of struct kvm_mmu_page. | ||||
| @ -461,11 +456,6 @@ struct kvm_vcpu_stat { | ||||
| 	u32 nmi_injections; | ||||
| }; | ||||
| 
 | ||||
| struct descriptor_table { | ||||
| 	u16 limit; | ||||
| 	unsigned long base; | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| struct kvm_x86_ops { | ||||
| 	int (*cpu_has_kvm_support)(void);          /* __init */ | ||||
| 	int (*disabled_by_bios)(void);             /* __init */ | ||||
| @ -503,12 +493,11 @@ struct kvm_x86_ops { | ||||
| 	void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3); | ||||
| 	void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4); | ||||
| 	void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer); | ||||
| 	void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); | ||||
| 	void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); | ||||
| 	void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); | ||||
| 	void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); | ||||
| 	int (*get_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long *dest); | ||||
| 	int (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value); | ||||
| 	void (*get_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); | ||||
| 	void (*set_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); | ||||
| 	void (*get_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); | ||||
| 	void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); | ||||
| 	void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value); | ||||
| 	void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg); | ||||
| 	unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); | ||||
| 	void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags); | ||||
| @ -527,7 +516,8 @@ struct kvm_x86_ops { | ||||
| 	void (*set_irq)(struct kvm_vcpu *vcpu); | ||||
| 	void (*set_nmi)(struct kvm_vcpu *vcpu); | ||||
| 	void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr, | ||||
| 				bool has_error_code, u32 error_code); | ||||
| 				bool has_error_code, u32 error_code, | ||||
| 				bool reinject); | ||||
| 	int (*interrupt_allowed)(struct kvm_vcpu *vcpu); | ||||
| 	int (*nmi_allowed)(struct kvm_vcpu *vcpu); | ||||
| 	bool (*get_nmi_mask)(struct kvm_vcpu *vcpu); | ||||
| @ -541,6 +531,8 @@ struct kvm_x86_ops { | ||||
| 	int (*get_lpage_level)(void); | ||||
| 	bool (*rdtscp_supported)(void); | ||||
| 
 | ||||
| 	void (*set_supported_cpuid)(u32 func, struct kvm_cpuid_entry2 *entry); | ||||
| 
 | ||||
| 	const struct trace_print_flags *exit_reasons_str; | ||||
| }; | ||||
| 
 | ||||
| @ -587,23 +579,14 @@ int emulate_instruction(struct kvm_vcpu *vcpu, | ||||
| void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context); | ||||
| void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); | ||||
| void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); | ||||
| void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, | ||||
| 		   unsigned long *rflags); | ||||
| 
 | ||||
| unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr); | ||||
| void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value, | ||||
| 		     unsigned long *rflags); | ||||
| void kvm_enable_efer_bits(u64); | ||||
| int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data); | ||||
| int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); | ||||
| 
 | ||||
| struct x86_emulate_ctxt; | ||||
| 
 | ||||
| int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, | ||||
| 		     int size, unsigned port); | ||||
| int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in, | ||||
| 			   int size, unsigned long count, int down, | ||||
| 			    gva_t address, int rep, unsigned port); | ||||
| int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port); | ||||
| void kvm_emulate_cpuid(struct kvm_vcpu *vcpu); | ||||
| int kvm_emulate_halt(struct kvm_vcpu *vcpu); | ||||
| int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); | ||||
| @ -616,12 +599,15 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, | ||||
| void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); | ||||
| int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg); | ||||
| 
 | ||||
| int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason); | ||||
| int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, | ||||
| 		    bool has_error_code, u32 error_code); | ||||
| 
 | ||||
| void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); | ||||
| void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); | ||||
| void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4); | ||||
| void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8); | ||||
| int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val); | ||||
| int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val); | ||||
| unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu); | ||||
| void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw); | ||||
| void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l); | ||||
| @ -634,6 +620,8 @@ void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags); | ||||
| 
 | ||||
| void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr); | ||||
| void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code); | ||||
| void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr); | ||||
| void kvm_requeue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code); | ||||
| void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2, | ||||
| 			   u32 error_code); | ||||
| bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl); | ||||
| @ -649,8 +637,6 @@ int emulator_write_emulated(unsigned long addr, | ||||
| 			    unsigned int bytes, | ||||
| 			    struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
| unsigned long segment_base(u16 selector); | ||||
| 
 | ||||
| void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu); | ||||
| void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | ||||
| 		       const u8 *new, int bytes, | ||||
| @ -675,7 +661,6 @@ void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva); | ||||
| void kvm_enable_tdp(void); | ||||
| void kvm_disable_tdp(void); | ||||
| 
 | ||||
| int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3); | ||||
| int complete_pio(struct kvm_vcpu *vcpu); | ||||
| bool kvm_check_iopl(struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
| @ -724,23 +709,6 @@ static inline void kvm_load_ldt(u16 sel) | ||||
| 	asm("lldt %0" : : "rm"(sel)); | ||||
| } | ||||
| 
 | ||||
| static inline void kvm_get_idt(struct descriptor_table *table) | ||||
| { | ||||
| 	asm("sidt %0" : "=m"(*table)); | ||||
| } | ||||
| 
 | ||||
| static inline void kvm_get_gdt(struct descriptor_table *table) | ||||
| { | ||||
| 	asm("sgdt %0" : "=m"(*table)); | ||||
| } | ||||
| 
 | ||||
| static inline unsigned long kvm_read_tr_base(void) | ||||
| { | ||||
| 	u16 tr; | ||||
| 	asm("str %0" : "=g"(tr)); | ||||
| 	return segment_base(tr); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_X86_64 | ||||
| static inline unsigned long read_msr(unsigned long msr) | ||||
| { | ||||
| @ -826,4 +794,6 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v); | ||||
| void kvm_define_shared_msr(unsigned index, u32 msr); | ||||
| void kvm_set_shared_msr(unsigned index, u64 val, u64 mask); | ||||
| 
 | ||||
| bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip); | ||||
| 
 | ||||
| #endif /* _ASM_X86_KVM_HOST_H */ | ||||
|  | ||||
| @ -16,10 +16,23 @@ | ||||
| #define KVM_FEATURE_CLOCKSOURCE		0 | ||||
| #define KVM_FEATURE_NOP_IO_DELAY	1 | ||||
| #define KVM_FEATURE_MMU_OP		2 | ||||
| /* This indicates that the new set of kvmclock msrs
 | ||||
|  * are available. The use of 0x11 and 0x12 is deprecated | ||||
|  */ | ||||
| #define KVM_FEATURE_CLOCKSOURCE2        3 | ||||
| 
 | ||||
| /* The last 8 bits are used to indicate how to interpret the flags field
 | ||||
|  * in pvclock structure. If no bits are set, all flags are ignored. | ||||
|  */ | ||||
| #define KVM_FEATURE_CLOCKSOURCE_STABLE_BIT	24 | ||||
| 
 | ||||
| #define MSR_KVM_WALL_CLOCK  0x11 | ||||
| #define MSR_KVM_SYSTEM_TIME 0x12 | ||||
| 
 | ||||
| /* Custom MSRs falls in the range 0x4b564d00-0x4b564dff */ | ||||
| #define MSR_KVM_WALL_CLOCK_NEW  0x4b564d00 | ||||
| #define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01 | ||||
| 
 | ||||
| #define KVM_MAX_MMU_OP_BATCH           32 | ||||
| 
 | ||||
| /* Operations for KVM_HC_MMU_OP */ | ||||
|  | ||||
| @ -202,8 +202,9 @@ | ||||
| #define MSR_IA32_EBL_CR_POWERON		0x0000002a | ||||
| #define MSR_IA32_FEATURE_CONTROL        0x0000003a | ||||
| 
 | ||||
| #define FEATURE_CONTROL_LOCKED		(1<<0) | ||||
| #define FEATURE_CONTROL_VMXON_ENABLED	(1<<2) | ||||
| #define FEATURE_CONTROL_LOCKED				(1<<0) | ||||
| #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX	(1<<1) | ||||
| #define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX	(1<<2) | ||||
| 
 | ||||
| #define MSR_IA32_APICBASE		0x0000001b | ||||
| #define MSR_IA32_APICBASE_BSP		(1<<8) | ||||
|  | ||||
| @ -29,7 +29,8 @@ struct pvclock_vcpu_time_info { | ||||
| 	u64   system_time; | ||||
| 	u32   tsc_to_system_mul; | ||||
| 	s8    tsc_shift; | ||||
| 	u8    pad[3]; | ||||
| 	u8    flags; | ||||
| 	u8    pad[2]; | ||||
| } __attribute__((__packed__)); /* 32 bytes */ | ||||
| 
 | ||||
| struct pvclock_wall_clock { | ||||
| @ -38,5 +39,6 @@ struct pvclock_wall_clock { | ||||
| 	u32   nsec; | ||||
| } __attribute__((__packed__)); | ||||
| 
 | ||||
| #define PVCLOCK_TSC_STABLE_BIT	(1 << 0) | ||||
| #endif /* __ASSEMBLY__ */ | ||||
| #endif /* _ASM_X86_PVCLOCK_ABI_H */ | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| 
 | ||||
| /* some helper functions for xen and kvm pv clock sources */ | ||||
| cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src); | ||||
| void pvclock_set_flags(u8 flags); | ||||
| unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src); | ||||
| void pvclock_read_wallclock(struct pvclock_wall_clock *wall, | ||||
| 			    struct pvclock_vcpu_time_info *vcpu, | ||||
|  | ||||
| @ -81,7 +81,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area { | ||||
| 	u32 event_inj_err; | ||||
| 	u64 nested_cr3; | ||||
| 	u64 lbr_ctl; | ||||
| 	u8 reserved_5[832]; | ||||
| 	u64 reserved_5; | ||||
| 	u64 next_rip; | ||||
| 	u8 reserved_6[816]; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| @ -115,6 +117,10 @@ struct __attribute__ ((__packed__)) vmcb_control_area { | ||||
| #define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT) | ||||
| #define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT) | ||||
| 
 | ||||
| #define SVM_VM_CR_VALID_MASK	0x001fULL | ||||
| #define SVM_VM_CR_SVM_LOCK_MASK 0x0008ULL | ||||
| #define SVM_VM_CR_SVM_DIS_MASK  0x0010ULL | ||||
| 
 | ||||
| struct __attribute__ ((__packed__)) vmcb_seg { | ||||
| 	u16 selector; | ||||
| 	u16 attrib; | ||||
| @ -238,6 +244,7 @@ struct __attribute__ ((__packed__)) vmcb { | ||||
| 
 | ||||
| #define SVM_EXITINFOSHIFT_TS_REASON_IRET 36 | ||||
| #define SVM_EXITINFOSHIFT_TS_REASON_JMP 38 | ||||
| #define SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE 44 | ||||
| 
 | ||||
| #define	SVM_EXIT_READ_CR0 	0x000 | ||||
| #define	SVM_EXIT_READ_CR3 	0x003 | ||||
|  | ||||
| @ -25,6 +25,8 @@ | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * Definitions of Primary Processor-Based VM-Execution Controls. | ||||
|  */ | ||||
| @ -120,6 +122,8 @@ enum vmcs_field { | ||||
| 	GUEST_IA32_DEBUGCTL_HIGH        = 0x00002803, | ||||
| 	GUEST_IA32_PAT			= 0x00002804, | ||||
| 	GUEST_IA32_PAT_HIGH		= 0x00002805, | ||||
| 	GUEST_IA32_EFER			= 0x00002806, | ||||
| 	GUEST_IA32_EFER_HIGH		= 0x00002807, | ||||
| 	GUEST_PDPTR0                    = 0x0000280a, | ||||
| 	GUEST_PDPTR0_HIGH               = 0x0000280b, | ||||
| 	GUEST_PDPTR1                    = 0x0000280c, | ||||
| @ -130,6 +134,8 @@ enum vmcs_field { | ||||
| 	GUEST_PDPTR3_HIGH               = 0x00002811, | ||||
| 	HOST_IA32_PAT			= 0x00002c00, | ||||
| 	HOST_IA32_PAT_HIGH		= 0x00002c01, | ||||
| 	HOST_IA32_EFER			= 0x00002c02, | ||||
| 	HOST_IA32_EFER_HIGH		= 0x00002c03, | ||||
| 	PIN_BASED_VM_EXEC_CONTROL       = 0x00004000, | ||||
| 	CPU_BASED_VM_EXEC_CONTROL       = 0x00004002, | ||||
| 	EXCEPTION_BITMAP                = 0x00004004, | ||||
| @ -394,6 +400,10 @@ enum vmcs_field { | ||||
| #define ASM_VMX_INVEPT		  ".byte 0x66, 0x0f, 0x38, 0x80, 0x08" | ||||
| #define ASM_VMX_INVVPID		  ".byte 0x66, 0x0f, 0x38, 0x81, 0x08" | ||||
| 
 | ||||
| 
 | ||||
| struct vmx_msr_entry { | ||||
| 	u32 index; | ||||
| 	u32 reserved; | ||||
| 	u64 value; | ||||
| } __aligned(16); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -29,6 +29,8 @@ | ||||
| #define KVM_SCALE 22 | ||||
| 
 | ||||
| static int kvmclock = 1; | ||||
| static int msr_kvm_system_time = MSR_KVM_SYSTEM_TIME; | ||||
| static int msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK; | ||||
| 
 | ||||
| static int parse_no_kvmclock(char *arg) | ||||
| { | ||||
| @ -54,7 +56,8 @@ static unsigned long kvm_get_wallclock(void) | ||||
| 
 | ||||
| 	low = (int)__pa_symbol(&wall_clock); | ||||
| 	high = ((u64)__pa_symbol(&wall_clock) >> 32); | ||||
| 	native_write_msr(MSR_KVM_WALL_CLOCK, low, high); | ||||
| 
 | ||||
| 	native_write_msr(msr_kvm_wall_clock, low, high); | ||||
| 
 | ||||
| 	vcpu_time = &get_cpu_var(hv_clock); | ||||
| 	pvclock_read_wallclock(&wall_clock, vcpu_time, &ts); | ||||
| @ -130,7 +133,8 @@ static int kvm_register_clock(char *txt) | ||||
| 	high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32); | ||||
| 	printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n", | ||||
| 	       cpu, high, low, txt); | ||||
| 	return native_write_msr_safe(MSR_KVM_SYSTEM_TIME, low, high); | ||||
| 
 | ||||
| 	return native_write_msr_safe(msr_kvm_system_time, low, high); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_X86_LOCAL_APIC | ||||
| @ -165,14 +169,14 @@ static void __init kvm_smp_prepare_boot_cpu(void) | ||||
| #ifdef CONFIG_KEXEC | ||||
| static void kvm_crash_shutdown(struct pt_regs *regs) | ||||
| { | ||||
| 	native_write_msr_safe(MSR_KVM_SYSTEM_TIME, 0, 0); | ||||
| 	native_write_msr(msr_kvm_system_time, 0, 0); | ||||
| 	native_machine_crash_shutdown(regs); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static void kvm_shutdown(void) | ||||
| { | ||||
| 	native_write_msr_safe(MSR_KVM_SYSTEM_TIME, 0, 0); | ||||
| 	native_write_msr(msr_kvm_system_time, 0, 0); | ||||
| 	native_machine_shutdown(); | ||||
| } | ||||
| 
 | ||||
| @ -181,27 +185,37 @@ void __init kvmclock_init(void) | ||||
| 	if (!kvm_para_available()) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) { | ||||
| 		if (kvm_register_clock("boot clock")) | ||||
| 			return; | ||||
| 		pv_time_ops.sched_clock = kvm_clock_read; | ||||
| 		x86_platform.calibrate_tsc = kvm_get_tsc_khz; | ||||
| 		x86_platform.get_wallclock = kvm_get_wallclock; | ||||
| 		x86_platform.set_wallclock = kvm_set_wallclock; | ||||
| 	if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE2)) { | ||||
| 		msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW; | ||||
| 		msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW; | ||||
| 	} else if (!(kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE))) | ||||
| 		return; | ||||
| 
 | ||||
| 	printk(KERN_INFO "kvm-clock: Using msrs %x and %x", | ||||
| 		msr_kvm_system_time, msr_kvm_wall_clock); | ||||
| 
 | ||||
| 	if (kvm_register_clock("boot clock")) | ||||
| 		return; | ||||
| 	pv_time_ops.sched_clock = kvm_clock_read; | ||||
| 	x86_platform.calibrate_tsc = kvm_get_tsc_khz; | ||||
| 	x86_platform.get_wallclock = kvm_get_wallclock; | ||||
| 	x86_platform.set_wallclock = kvm_set_wallclock; | ||||
| #ifdef CONFIG_X86_LOCAL_APIC | ||||
| 		x86_cpuinit.setup_percpu_clockev = | ||||
| 			kvm_setup_secondary_clock; | ||||
| 	x86_cpuinit.setup_percpu_clockev = | ||||
| 		kvm_setup_secondary_clock; | ||||
| #endif | ||||
| #ifdef CONFIG_SMP | ||||
| 		smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu; | ||||
| 	smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu; | ||||
| #endif | ||||
| 		machine_ops.shutdown  = kvm_shutdown; | ||||
| 	machine_ops.shutdown  = kvm_shutdown; | ||||
| #ifdef CONFIG_KEXEC | ||||
| 		machine_ops.crash_shutdown  = kvm_crash_shutdown; | ||||
| 	machine_ops.crash_shutdown  = kvm_crash_shutdown; | ||||
| #endif | ||||
| 		kvm_get_preset_lpj(); | ||||
| 		clocksource_register(&kvm_clock); | ||||
| 		pv_info.paravirt_enabled = 1; | ||||
| 		pv_info.name = "KVM"; | ||||
| 	} | ||||
| 	kvm_get_preset_lpj(); | ||||
| 	clocksource_register(&kvm_clock); | ||||
| 	pv_info.paravirt_enabled = 1; | ||||
| 	pv_info.name = "KVM"; | ||||
| 
 | ||||
| 	if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT)) | ||||
| 		pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT); | ||||
| } | ||||
|  | ||||
| @ -31,8 +31,16 @@ struct pvclock_shadow_time { | ||||
| 	u32 tsc_to_nsec_mul; | ||||
| 	int tsc_shift; | ||||
| 	u32 version; | ||||
| 	u8  flags; | ||||
| }; | ||||
| 
 | ||||
| static u8 valid_flags __read_mostly = 0; | ||||
| 
 | ||||
| void pvclock_set_flags(u8 flags) | ||||
| { | ||||
| 	valid_flags = flags; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, | ||||
|  * yielding a 64-bit result. | ||||
| @ -91,6 +99,7 @@ static unsigned pvclock_get_time_values(struct pvclock_shadow_time *dst, | ||||
| 		dst->system_timestamp  = src->system_time; | ||||
| 		dst->tsc_to_nsec_mul   = src->tsc_to_system_mul; | ||||
| 		dst->tsc_shift         = src->tsc_shift; | ||||
| 		dst->flags             = src->flags; | ||||
| 		rmb();		/* test version after fetching data */ | ||||
| 	} while ((src->version & 1) || (dst->version != src->version)); | ||||
| 
 | ||||
| @ -109,11 +118,14 @@ unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src) | ||||
| 	return pv_tsc_khz; | ||||
| } | ||||
| 
 | ||||
| static atomic64_t last_value = ATOMIC64_INIT(0); | ||||
| 
 | ||||
| cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) | ||||
| { | ||||
| 	struct pvclock_shadow_time shadow; | ||||
| 	unsigned version; | ||||
| 	cycle_t ret, offset; | ||||
| 	u64 last; | ||||
| 
 | ||||
| 	do { | ||||
| 		version = pvclock_get_time_values(&shadow, src); | ||||
| @ -123,6 +135,31 @@ cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) | ||||
| 		barrier(); | ||||
| 	} while (version != src->version); | ||||
| 
 | ||||
| 	if ((valid_flags & PVCLOCK_TSC_STABLE_BIT) && | ||||
| 		(shadow.flags & PVCLOCK_TSC_STABLE_BIT)) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Assumption here is that last_value, a global accumulator, always goes | ||||
| 	 * forward. If we are less than that, we should not be much smaller. | ||||
| 	 * We assume there is an error marging we're inside, and then the correction | ||||
| 	 * does not sacrifice accuracy. | ||||
| 	 * | ||||
| 	 * For reads: global may have changed between test and return, | ||||
| 	 * but this means someone else updated poked the clock at a later time. | ||||
| 	 * We just need to make sure we are not seeing a backwards event. | ||||
| 	 * | ||||
| 	 * For updates: last_value = ret is not enough, since two vcpus could be | ||||
| 	 * updating at the same time, and one of them could be slightly behind, | ||||
| 	 * making the assumption that last_value always go forward fail to hold. | ||||
| 	 */ | ||||
| 	last = atomic64_read(&last_value); | ||||
| 	do { | ||||
| 		if (ret < last) | ||||
| 			return last; | ||||
| 		last = atomic64_cmpxchg(&last_value, last, ret); | ||||
| 	} while (unlikely(last != ret)); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -46,6 +46,7 @@ | ||||
| 
 | ||||
| /* Global pointer to shared data; NULL means no measured launch. */ | ||||
| struct tboot *tboot __read_mostly; | ||||
| EXPORT_SYMBOL(tboot); | ||||
| 
 | ||||
| /* timeout for APs (in secs) to enter wait-for-SIPI state during shutdown */ | ||||
| #define AP_WAIT_TIMEOUT		1 | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -33,6 +33,29 @@ | ||||
| #include <linux/kvm_host.h> | ||||
| #include "trace.h" | ||||
| 
 | ||||
| static void pic_lock(struct kvm_pic *s) | ||||
| 	__acquires(&s->lock) | ||||
| { | ||||
| 	raw_spin_lock(&s->lock); | ||||
| } | ||||
| 
 | ||||
| static void pic_unlock(struct kvm_pic *s) | ||||
| 	__releases(&s->lock) | ||||
| { | ||||
| 	bool wakeup = s->wakeup_needed; | ||||
| 	struct kvm_vcpu *vcpu; | ||||
| 
 | ||||
| 	s->wakeup_needed = false; | ||||
| 
 | ||||
| 	raw_spin_unlock(&s->lock); | ||||
| 
 | ||||
| 	if (wakeup) { | ||||
| 		vcpu = s->kvm->bsp_vcpu; | ||||
| 		if (vcpu) | ||||
| 			kvm_vcpu_kick(vcpu); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void pic_clear_isr(struct kvm_kpic_state *s, int irq) | ||||
| { | ||||
| 	s->isr &= ~(1 << irq); | ||||
| @ -45,19 +68,19 @@ static void pic_clear_isr(struct kvm_kpic_state *s, int irq) | ||||
| 	 * Other interrupt may be delivered to PIC while lock is dropped but | ||||
| 	 * it should be safe since PIC state is already updated at this stage. | ||||
| 	 */ | ||||
| 	raw_spin_unlock(&s->pics_state->lock); | ||||
| 	pic_unlock(s->pics_state); | ||||
| 	kvm_notify_acked_irq(s->pics_state->kvm, SELECT_PIC(irq), irq); | ||||
| 	raw_spin_lock(&s->pics_state->lock); | ||||
| 	pic_lock(s->pics_state); | ||||
| } | ||||
| 
 | ||||
| void kvm_pic_clear_isr_ack(struct kvm *kvm) | ||||
| { | ||||
| 	struct kvm_pic *s = pic_irqchip(kvm); | ||||
| 
 | ||||
| 	raw_spin_lock(&s->lock); | ||||
| 	pic_lock(s); | ||||
| 	s->pics[0].isr_ack = 0xff; | ||||
| 	s->pics[1].isr_ack = 0xff; | ||||
| 	raw_spin_unlock(&s->lock); | ||||
| 	pic_unlock(s); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -158,9 +181,9 @@ static void pic_update_irq(struct kvm_pic *s) | ||||
| 
 | ||||
| void kvm_pic_update_irq(struct kvm_pic *s) | ||||
| { | ||||
| 	raw_spin_lock(&s->lock); | ||||
| 	pic_lock(s); | ||||
| 	pic_update_irq(s); | ||||
| 	raw_spin_unlock(&s->lock); | ||||
| 	pic_unlock(s); | ||||
| } | ||||
| 
 | ||||
| int kvm_pic_set_irq(void *opaque, int irq, int level) | ||||
| @ -168,14 +191,14 @@ int kvm_pic_set_irq(void *opaque, int irq, int level) | ||||
| 	struct kvm_pic *s = opaque; | ||||
| 	int ret = -1; | ||||
| 
 | ||||
| 	raw_spin_lock(&s->lock); | ||||
| 	pic_lock(s); | ||||
| 	if (irq >= 0 && irq < PIC_NUM_PINS) { | ||||
| 		ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); | ||||
| 		pic_update_irq(s); | ||||
| 		trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr, | ||||
| 				      s->pics[irq >> 3].imr, ret == 0); | ||||
| 	} | ||||
| 	raw_spin_unlock(&s->lock); | ||||
| 	pic_unlock(s); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| @ -205,7 +228,7 @@ int kvm_pic_read_irq(struct kvm *kvm) | ||||
| 	int irq, irq2, intno; | ||||
| 	struct kvm_pic *s = pic_irqchip(kvm); | ||||
| 
 | ||||
| 	raw_spin_lock(&s->lock); | ||||
| 	pic_lock(s); | ||||
| 	irq = pic_get_irq(&s->pics[0]); | ||||
| 	if (irq >= 0) { | ||||
| 		pic_intack(&s->pics[0], irq); | ||||
| @ -230,7 +253,7 @@ int kvm_pic_read_irq(struct kvm *kvm) | ||||
| 		intno = s->pics[0].irq_base + irq; | ||||
| 	} | ||||
| 	pic_update_irq(s); | ||||
| 	raw_spin_unlock(&s->lock); | ||||
| 	pic_unlock(s); | ||||
| 
 | ||||
| 	return intno; | ||||
| } | ||||
| @ -444,7 +467,7 @@ static int picdev_write(struct kvm_io_device *this, | ||||
| 			printk(KERN_ERR "PIC: non byte write\n"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	raw_spin_lock(&s->lock); | ||||
| 	pic_lock(s); | ||||
| 	switch (addr) { | ||||
| 	case 0x20: | ||||
| 	case 0x21: | ||||
| @ -457,7 +480,7 @@ static int picdev_write(struct kvm_io_device *this, | ||||
| 		elcr_ioport_write(&s->pics[addr & 1], addr, data); | ||||
| 		break; | ||||
| 	} | ||||
| 	raw_spin_unlock(&s->lock); | ||||
| 	pic_unlock(s); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -474,7 +497,7 @@ static int picdev_read(struct kvm_io_device *this, | ||||
| 			printk(KERN_ERR "PIC: non byte read\n"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	raw_spin_lock(&s->lock); | ||||
| 	pic_lock(s); | ||||
| 	switch (addr) { | ||||
| 	case 0x20: | ||||
| 	case 0x21: | ||||
| @ -488,7 +511,7 @@ static int picdev_read(struct kvm_io_device *this, | ||||
| 		break; | ||||
| 	} | ||||
| 	*(unsigned char *)val = data; | ||||
| 	raw_spin_unlock(&s->lock); | ||||
| 	pic_unlock(s); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -505,7 +528,7 @@ static void pic_irq_request(void *opaque, int level) | ||||
| 	s->output = level; | ||||
| 	if (vcpu && level && (s->pics[0].isr_ack & (1 << irq))) { | ||||
| 		s->pics[0].isr_ack &= ~(1 << irq); | ||||
| 		kvm_vcpu_kick(vcpu); | ||||
| 		s->wakeup_needed = true; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -63,6 +63,7 @@ struct kvm_kpic_state { | ||||
| 
 | ||||
| struct kvm_pic { | ||||
| 	raw_spinlock_t lock; | ||||
| 	bool wakeup_needed; | ||||
| 	unsigned pending_acks; | ||||
| 	struct kvm *kvm; | ||||
| 	struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */ | ||||
|  | ||||
| @ -10,9 +10,7 @@ struct kvm_timer { | ||||
| }; | ||||
| 
 | ||||
| struct kvm_timer_ops { | ||||
|         bool (*is_periodic)(struct kvm_timer *); | ||||
| 	bool (*is_periodic)(struct kvm_timer *); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| enum hrtimer_restart kvm_timer_fn(struct hrtimer *data); | ||||
| 
 | ||||
|  | ||||
| @ -148,7 +148,6 @@ module_param(oos_shadow, bool, 0644); | ||||
| 
 | ||||
| #include <trace/events/kvm.h> | ||||
| 
 | ||||
| #undef TRACE_INCLUDE_FILE | ||||
| #define CREATE_TRACE_POINTS | ||||
| #include "mmutrace.h" | ||||
| 
 | ||||
| @ -174,12 +173,7 @@ struct kvm_shadow_walk_iterator { | ||||
| 	     shadow_walk_okay(&(_walker));			\ | ||||
| 	     shadow_walk_next(&(_walker))) | ||||
| 
 | ||||
| 
 | ||||
| struct kvm_unsync_walk { | ||||
| 	int (*entry) (struct kvm_mmu_page *sp, struct kvm_unsync_walk *walk); | ||||
| }; | ||||
| 
 | ||||
| typedef int (*mmu_parent_walk_fn) (struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp); | ||||
| typedef int (*mmu_parent_walk_fn) (struct kvm_mmu_page *sp); | ||||
| 
 | ||||
| static struct kmem_cache *pte_chain_cache; | ||||
| static struct kmem_cache *rmap_desc_cache; | ||||
| @ -223,7 +217,7 @@ void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask, | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kvm_mmu_set_mask_ptes); | ||||
| 
 | ||||
| static int is_write_protection(struct kvm_vcpu *vcpu) | ||||
| static bool is_write_protection(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	return kvm_read_cr0_bits(vcpu, X86_CR0_WP); | ||||
| } | ||||
| @ -327,7 +321,6 @@ static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache, | ||||
| 		page = alloc_page(GFP_KERNEL); | ||||
| 		if (!page) | ||||
| 			return -ENOMEM; | ||||
| 		set_page_private(page, 0); | ||||
| 		cache->objects[cache->nobjs++] = page_address(page); | ||||
| 	} | ||||
| 	return 0; | ||||
| @ -438,9 +431,9 @@ static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn) | ||||
| 	int i; | ||||
| 
 | ||||
| 	gfn = unalias_gfn(kvm, gfn); | ||||
| 	slot = gfn_to_memslot_unaliased(kvm, gfn); | ||||
| 	for (i = PT_DIRECTORY_LEVEL; | ||||
| 	     i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) { | ||||
| 		slot          = gfn_to_memslot_unaliased(kvm, gfn); | ||||
| 		write_count   = slot_largepage_idx(gfn, slot, i); | ||||
| 		*write_count -= 1; | ||||
| 		WARN_ON(*write_count < 0); | ||||
| @ -654,7 +647,6 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) | ||||
| static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte) | ||||
| { | ||||
| 	struct kvm_rmap_desc *desc; | ||||
| 	struct kvm_rmap_desc *prev_desc; | ||||
| 	u64 *prev_spte; | ||||
| 	int i; | ||||
| 
 | ||||
| @ -666,7 +658,6 @@ static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte) | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul); | ||||
| 	prev_desc = NULL; | ||||
| 	prev_spte = NULL; | ||||
| 	while (desc) { | ||||
| 		for (i = 0; i < RMAP_EXT && desc->sptes[i]; ++i) { | ||||
| @ -794,7 +785,7 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | ||||
| 	int retval = 0; | ||||
| 	struct kvm_memslots *slots; | ||||
| 
 | ||||
| 	slots = rcu_dereference(kvm->memslots); | ||||
| 	slots = kvm_memslots(kvm); | ||||
| 
 | ||||
| 	for (i = 0; i < slots->nmemslots; i++) { | ||||
| 		struct kvm_memory_slot *memslot = &slots->memslots[i]; | ||||
| @ -925,7 +916,6 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, | ||||
| 	sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache, PAGE_SIZE); | ||||
| 	set_page_private(virt_to_page(sp->spt), (unsigned long)sp); | ||||
| 	list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages); | ||||
| 	INIT_LIST_HEAD(&sp->oos_link); | ||||
| 	bitmap_zero(sp->slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS); | ||||
| 	sp->multimapped = 0; | ||||
| 	sp->parent_pte = parent_pte; | ||||
| @ -1009,8 +999,7 @@ static void mmu_page_remove_parent_pte(struct kvm_mmu_page *sp, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void mmu_parent_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, | ||||
| 			    mmu_parent_walk_fn fn) | ||||
| static void mmu_parent_walk(struct kvm_mmu_page *sp, mmu_parent_walk_fn fn) | ||||
| { | ||||
| 	struct kvm_pte_chain *pte_chain; | ||||
| 	struct hlist_node *node; | ||||
| @ -1019,8 +1008,8 @@ static void mmu_parent_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, | ||||
| 
 | ||||
| 	if (!sp->multimapped && sp->parent_pte) { | ||||
| 		parent_sp = page_header(__pa(sp->parent_pte)); | ||||
| 		fn(vcpu, parent_sp); | ||||
| 		mmu_parent_walk(vcpu, parent_sp, fn); | ||||
| 		fn(parent_sp); | ||||
| 		mmu_parent_walk(parent_sp, fn); | ||||
| 		return; | ||||
| 	} | ||||
| 	hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link) | ||||
| @ -1028,8 +1017,8 @@ static void mmu_parent_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, | ||||
| 			if (!pte_chain->parent_ptes[i]) | ||||
| 				break; | ||||
| 			parent_sp = page_header(__pa(pte_chain->parent_ptes[i])); | ||||
| 			fn(vcpu, parent_sp); | ||||
| 			mmu_parent_walk(vcpu, parent_sp, fn); | ||||
| 			fn(parent_sp); | ||||
| 			mmu_parent_walk(parent_sp, fn); | ||||
| 		} | ||||
| } | ||||
| 
 | ||||
| @ -1066,16 +1055,15 @@ static void kvm_mmu_update_parents_unsync(struct kvm_mmu_page *sp) | ||||
| 		} | ||||
| } | ||||
| 
 | ||||
| static int unsync_walk_fn(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | ||||
| static int unsync_walk_fn(struct kvm_mmu_page *sp) | ||||
| { | ||||
| 	kvm_mmu_update_parents_unsync(sp); | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static void kvm_mmu_mark_parents_unsync(struct kvm_vcpu *vcpu, | ||||
| 					struct kvm_mmu_page *sp) | ||||
| static void kvm_mmu_mark_parents_unsync(struct kvm_mmu_page *sp) | ||||
| { | ||||
| 	mmu_parent_walk(vcpu, sp, unsync_walk_fn); | ||||
| 	mmu_parent_walk(sp, unsync_walk_fn); | ||||
| 	kvm_mmu_update_parents_unsync(sp); | ||||
| } | ||||
| 
 | ||||
| @ -1201,6 +1189,7 @@ static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm *kvm, gfn_t gfn) | ||||
| static void kvm_unlink_unsync_page(struct kvm *kvm, struct kvm_mmu_page *sp) | ||||
| { | ||||
| 	WARN_ON(!sp->unsync); | ||||
| 	trace_kvm_mmu_sync_page(sp); | ||||
| 	sp->unsync = 0; | ||||
| 	--kvm->stat.mmu_unsync; | ||||
| } | ||||
| @ -1209,12 +1198,11 @@ static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp); | ||||
| 
 | ||||
| static int kvm_sync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | ||||
| { | ||||
| 	if (sp->role.glevels != vcpu->arch.mmu.root_level) { | ||||
| 	if (sp->role.cr4_pae != !!is_pae(vcpu)) { | ||||
| 		kvm_mmu_zap_page(vcpu->kvm, sp); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	trace_kvm_mmu_sync_page(sp); | ||||
| 	if (rmap_write_protect(vcpu->kvm, sp->gfn)) | ||||
| 		kvm_flush_remote_tlbs(vcpu->kvm); | ||||
| 	kvm_unlink_unsync_page(vcpu->kvm, sp); | ||||
| @ -1331,6 +1319,8 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, | ||||
| 	role = vcpu->arch.mmu.base_role; | ||||
| 	role.level = level; | ||||
| 	role.direct = direct; | ||||
| 	if (role.direct) | ||||
| 		role.cr4_pae = 0; | ||||
| 	role.access = access; | ||||
| 	if (vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) { | ||||
| 		quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); | ||||
| @ -1351,7 +1341,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, | ||||
| 			mmu_page_add_parent_pte(vcpu, sp, parent_pte); | ||||
| 			if (sp->unsync_children) { | ||||
| 				set_bit(KVM_REQ_MMU_SYNC, &vcpu->requests); | ||||
| 				kvm_mmu_mark_parents_unsync(vcpu, sp); | ||||
| 				kvm_mmu_mark_parents_unsync(sp); | ||||
| 			} | ||||
| 			trace_kvm_mmu_get_page(sp, false); | ||||
| 			return sp; | ||||
| @ -1573,13 +1563,14 @@ static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn) | ||||
| 	r = 0; | ||||
| 	index = kvm_page_table_hashfn(gfn); | ||||
| 	bucket = &kvm->arch.mmu_page_hash[index]; | ||||
| restart: | ||||
| 	hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) | ||||
| 		if (sp->gfn == gfn && !sp->role.direct) { | ||||
| 			pgprintk("%s: gfn %lx role %x\n", __func__, gfn, | ||||
| 				 sp->role.word); | ||||
| 			r = 1; | ||||
| 			if (kvm_mmu_zap_page(kvm, sp)) | ||||
| 				n = bucket->first; | ||||
| 				goto restart; | ||||
| 		} | ||||
| 	return r; | ||||
| } | ||||
| @ -1593,13 +1584,14 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) | ||||
| 
 | ||||
| 	index = kvm_page_table_hashfn(gfn); | ||||
| 	bucket = &kvm->arch.mmu_page_hash[index]; | ||||
| restart: | ||||
| 	hlist_for_each_entry_safe(sp, node, nn, bucket, hash_link) { | ||||
| 		if (sp->gfn == gfn && !sp->role.direct | ||||
| 		    && !sp->role.invalid) { | ||||
| 			pgprintk("%s: zap %lx %x\n", | ||||
| 				 __func__, gfn, sp->role.word); | ||||
| 			if (kvm_mmu_zap_page(kvm, sp)) | ||||
| 				nn = bucket->first; | ||||
| 				goto restart; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -1626,20 +1618,6 @@ static void mmu_convert_notrap(struct kvm_mmu_page *sp) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva) | ||||
| { | ||||
| 	struct page *page; | ||||
| 
 | ||||
| 	gpa_t gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, NULL); | ||||
| 
 | ||||
| 	if (gpa == UNMAPPED_GVA) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); | ||||
| 
 | ||||
| 	return page; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * The function is based on mtrr_type_lookup() in | ||||
|  * arch/x86/kernel/cpu/mtrr/generic.c | ||||
| @ -1752,7 +1730,6 @@ static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | ||||
| 	struct kvm_mmu_page *s; | ||||
| 	struct hlist_node *node, *n; | ||||
| 
 | ||||
| 	trace_kvm_mmu_unsync_page(sp); | ||||
| 	index = kvm_page_table_hashfn(sp->gfn); | ||||
| 	bucket = &vcpu->kvm->arch.mmu_page_hash[index]; | ||||
| 	/* don't unsync if pagetable is shadowed with multiple roles */ | ||||
| @ -1762,10 +1739,11 @@ static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | ||||
| 		if (s->role.word != sp->role.word) | ||||
| 			return 1; | ||||
| 	} | ||||
| 	trace_kvm_mmu_unsync_page(sp); | ||||
| 	++vcpu->kvm->stat.mmu_unsync; | ||||
| 	sp->unsync = 1; | ||||
| 
 | ||||
| 	kvm_mmu_mark_parents_unsync(vcpu, sp); | ||||
| 	kvm_mmu_mark_parents_unsync(sp); | ||||
| 
 | ||||
| 	mmu_convert_notrap(sp); | ||||
| 	return 0; | ||||
| @ -2081,21 +2059,23 @@ static int mmu_alloc_roots(struct kvm_vcpu *vcpu) | ||||
| 		hpa_t root = vcpu->arch.mmu.root_hpa; | ||||
| 
 | ||||
| 		ASSERT(!VALID_PAGE(root)); | ||||
| 		if (tdp_enabled) | ||||
| 			direct = 1; | ||||
| 		if (mmu_check_root(vcpu, root_gfn)) | ||||
| 			return 1; | ||||
| 		if (tdp_enabled) { | ||||
| 			direct = 1; | ||||
| 			root_gfn = 0; | ||||
| 		} | ||||
| 		spin_lock(&vcpu->kvm->mmu_lock); | ||||
| 		sp = kvm_mmu_get_page(vcpu, root_gfn, 0, | ||||
| 				      PT64_ROOT_LEVEL, direct, | ||||
| 				      ACC_ALL, NULL); | ||||
| 		root = __pa(sp->spt); | ||||
| 		++sp->root_count; | ||||
| 		spin_unlock(&vcpu->kvm->mmu_lock); | ||||
| 		vcpu->arch.mmu.root_hpa = root; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	direct = !is_paging(vcpu); | ||||
| 	if (tdp_enabled) | ||||
| 		direct = 1; | ||||
| 	for (i = 0; i < 4; ++i) { | ||||
| 		hpa_t root = vcpu->arch.mmu.pae_root[i]; | ||||
| 
 | ||||
| @ -2111,11 +2091,18 @@ static int mmu_alloc_roots(struct kvm_vcpu *vcpu) | ||||
| 			root_gfn = 0; | ||||
| 		if (mmu_check_root(vcpu, root_gfn)) | ||||
| 			return 1; | ||||
| 		if (tdp_enabled) { | ||||
| 			direct = 1; | ||||
| 			root_gfn = i << 30; | ||||
| 		} | ||||
| 		spin_lock(&vcpu->kvm->mmu_lock); | ||||
| 		sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, | ||||
| 				      PT32_ROOT_LEVEL, direct, | ||||
| 				      ACC_ALL, NULL); | ||||
| 		root = __pa(sp->spt); | ||||
| 		++sp->root_count; | ||||
| 		spin_unlock(&vcpu->kvm->mmu_lock); | ||||
| 
 | ||||
| 		vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK; | ||||
| 	} | ||||
| 	vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root); | ||||
| @ -2299,13 +2286,19 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level) | ||||
| 		/* no rsvd bits for 2 level 4K page table entries */ | ||||
| 		context->rsvd_bits_mask[0][1] = 0; | ||||
| 		context->rsvd_bits_mask[0][0] = 0; | ||||
| 		context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[0][0]; | ||||
| 
 | ||||
| 		if (!is_pse(vcpu)) { | ||||
| 			context->rsvd_bits_mask[1][1] = 0; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (is_cpuid_PSE36()) | ||||
| 			/* 36bits PSE 4MB page */ | ||||
| 			context->rsvd_bits_mask[1][1] = rsvd_bits(17, 21); | ||||
| 		else | ||||
| 			/* 32 bits PSE 4MB page */ | ||||
| 			context->rsvd_bits_mask[1][1] = rsvd_bits(13, 21); | ||||
| 		context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0]; | ||||
| 		break; | ||||
| 	case PT32E_ROOT_LEVEL: | ||||
| 		context->rsvd_bits_mask[0][2] = | ||||
| @ -2318,7 +2311,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level) | ||||
| 		context->rsvd_bits_mask[1][1] = exb_bit_rsvd | | ||||
| 			rsvd_bits(maxphyaddr, 62) | | ||||
| 			rsvd_bits(13, 20);		/* large page */ | ||||
| 		context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0]; | ||||
| 		context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[0][0]; | ||||
| 		break; | ||||
| 	case PT64_ROOT_LEVEL: | ||||
| 		context->rsvd_bits_mask[0][3] = exb_bit_rsvd | | ||||
| @ -2336,7 +2329,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level) | ||||
| 		context->rsvd_bits_mask[1][1] = exb_bit_rsvd | | ||||
| 			rsvd_bits(maxphyaddr, 51) | | ||||
| 			rsvd_bits(13, 20);		/* large page */ | ||||
| 		context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[1][0]; | ||||
| 		context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[0][0]; | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| @ -2438,7 +2431,8 @@ static int init_kvm_softmmu(struct kvm_vcpu *vcpu) | ||||
| 	else | ||||
| 		r = paging32_init_context(vcpu); | ||||
| 
 | ||||
| 	vcpu->arch.mmu.base_role.glevels = vcpu->arch.mmu.root_level; | ||||
| 	vcpu->arch.mmu.base_role.cr4_pae = !!is_pae(vcpu); | ||||
| 	vcpu->arch.mmu.base_role.cr0_wp = is_write_protection(vcpu); | ||||
| 
 | ||||
| 	return r; | ||||
| } | ||||
| @ -2478,7 +2472,9 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu) | ||||
| 		goto out; | ||||
| 	spin_lock(&vcpu->kvm->mmu_lock); | ||||
| 	kvm_mmu_free_some_pages(vcpu); | ||||
| 	spin_unlock(&vcpu->kvm->mmu_lock); | ||||
| 	r = mmu_alloc_roots(vcpu); | ||||
| 	spin_lock(&vcpu->kvm->mmu_lock); | ||||
| 	mmu_sync_roots(vcpu); | ||||
| 	spin_unlock(&vcpu->kvm->mmu_lock); | ||||
| 	if (r) | ||||
| @ -2527,7 +2523,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, | ||||
|         } | ||||
| 
 | ||||
| 	++vcpu->kvm->stat.mmu_pte_updated; | ||||
| 	if (sp->role.glevels == PT32_ROOT_LEVEL) | ||||
| 	if (!sp->role.cr4_pae) | ||||
| 		paging32_update_pte(vcpu, sp, spte, new); | ||||
| 	else | ||||
| 		paging64_update_pte(vcpu, sp, spte, new); | ||||
| @ -2562,36 +2558,11 @@ static bool last_updated_pte_accessed(struct kvm_vcpu *vcpu) | ||||
| } | ||||
| 
 | ||||
| static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | ||||
| 					  const u8 *new, int bytes) | ||||
| 					  u64 gpte) | ||||
| { | ||||
| 	gfn_t gfn; | ||||
| 	int r; | ||||
| 	u64 gpte = 0; | ||||
| 	pfn_t pfn; | ||||
| 
 | ||||
| 	if (bytes != 4 && bytes != 8) | ||||
| 		return; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Assume that the pte write on a page table of the same type | ||||
| 	 * as the current vcpu paging mode.  This is nearly always true | ||||
| 	 * (might be false while changing modes).  Note it is verified later | ||||
| 	 * by update_pte(). | ||||
| 	 */ | ||||
| 	if (is_pae(vcpu)) { | ||||
| 		/* Handle a 32-bit guest writing two halves of a 64-bit gpte */ | ||||
| 		if ((bytes == 4) && (gpa % 4 == 0)) { | ||||
| 			r = kvm_read_guest(vcpu->kvm, gpa & ~(u64)7, &gpte, 8); | ||||
| 			if (r) | ||||
| 				return; | ||||
| 			memcpy((void *)&gpte + (gpa % 8), new, 4); | ||||
| 		} else if ((bytes == 8) && (gpa % 8 == 0)) { | ||||
| 			memcpy((void *)&gpte, new, 8); | ||||
| 		} | ||||
| 	} else { | ||||
| 		if ((bytes == 4) && (gpa % 4 == 0)) | ||||
| 			memcpy((void *)&gpte, new, 4); | ||||
| 	} | ||||
| 	if (!is_present_gpte(gpte)) | ||||
| 		return; | ||||
| 	gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; | ||||
| @ -2640,10 +2611,46 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | ||||
| 	int flooded = 0; | ||||
| 	int npte; | ||||
| 	int r; | ||||
| 	int invlpg_counter; | ||||
| 
 | ||||
| 	pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes); | ||||
| 	mmu_guess_page_from_pte_write(vcpu, gpa, new, bytes); | ||||
| 
 | ||||
| 	invlpg_counter = atomic_read(&vcpu->kvm->arch.invlpg_counter); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Assume that the pte write on a page table of the same type | ||||
| 	 * as the current vcpu paging mode.  This is nearly always true | ||||
| 	 * (might be false while changing modes).  Note it is verified later | ||||
| 	 * by update_pte(). | ||||
| 	 */ | ||||
| 	if ((is_pae(vcpu) && bytes == 4) || !new) { | ||||
| 		/* Handle a 32-bit guest writing two halves of a 64-bit gpte */ | ||||
| 		if (is_pae(vcpu)) { | ||||
| 			gpa &= ~(gpa_t)7; | ||||
| 			bytes = 8; | ||||
| 		} | ||||
| 		r = kvm_read_guest(vcpu->kvm, gpa, &gentry, min(bytes, 8)); | ||||
| 		if (r) | ||||
| 			gentry = 0; | ||||
| 		new = (const u8 *)&gentry; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (bytes) { | ||||
| 	case 4: | ||||
| 		gentry = *(const u32 *)new; | ||||
| 		break; | ||||
| 	case 8: | ||||
| 		gentry = *(const u64 *)new; | ||||
| 		break; | ||||
| 	default: | ||||
| 		gentry = 0; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	mmu_guess_page_from_pte_write(vcpu, gpa, gentry); | ||||
| 	spin_lock(&vcpu->kvm->mmu_lock); | ||||
| 	if (atomic_read(&vcpu->kvm->arch.invlpg_counter) != invlpg_counter) | ||||
| 		gentry = 0; | ||||
| 	kvm_mmu_access_page(vcpu, gfn); | ||||
| 	kvm_mmu_free_some_pages(vcpu); | ||||
| 	++vcpu->kvm->stat.mmu_pte_write; | ||||
| @ -2662,10 +2669,12 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | ||||
| 	} | ||||
| 	index = kvm_page_table_hashfn(gfn); | ||||
| 	bucket = &vcpu->kvm->arch.mmu_page_hash[index]; | ||||
| 
 | ||||
| restart: | ||||
| 	hlist_for_each_entry_safe(sp, node, n, bucket, hash_link) { | ||||
| 		if (sp->gfn != gfn || sp->role.direct || sp->role.invalid) | ||||
| 			continue; | ||||
| 		pte_size = sp->role.glevels == PT32_ROOT_LEVEL ? 4 : 8; | ||||
| 		pte_size = sp->role.cr4_pae ? 8 : 4; | ||||
| 		misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1); | ||||
| 		misaligned |= bytes < 4; | ||||
| 		if (misaligned || flooded) { | ||||
| @ -2682,14 +2691,14 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | ||||
| 			pgprintk("misaligned: gpa %llx bytes %d role %x\n", | ||||
| 				 gpa, bytes, sp->role.word); | ||||
| 			if (kvm_mmu_zap_page(vcpu->kvm, sp)) | ||||
| 				n = bucket->first; | ||||
| 				goto restart; | ||||
| 			++vcpu->kvm->stat.mmu_flooded; | ||||
| 			continue; | ||||
| 		} | ||||
| 		page_offset = offset; | ||||
| 		level = sp->role.level; | ||||
| 		npte = 1; | ||||
| 		if (sp->role.glevels == PT32_ROOT_LEVEL) { | ||||
| 		if (!sp->role.cr4_pae) { | ||||
| 			page_offset <<= 1;	/* 32->64 */ | ||||
| 			/*
 | ||||
| 			 * A 32-bit pde maps 4MB while the shadow pdes map | ||||
| @ -2707,20 +2716,11 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | ||||
| 				continue; | ||||
| 		} | ||||
| 		spte = &sp->spt[page_offset / sizeof(*spte)]; | ||||
| 		if ((gpa & (pte_size - 1)) || (bytes < pte_size)) { | ||||
| 			gentry = 0; | ||||
| 			r = kvm_read_guest_atomic(vcpu->kvm, | ||||
| 						  gpa & ~(u64)(pte_size - 1), | ||||
| 						  &gentry, pte_size); | ||||
| 			new = (const void *)&gentry; | ||||
| 			if (r < 0) | ||||
| 				new = NULL; | ||||
| 		} | ||||
| 		while (npte--) { | ||||
| 			entry = *spte; | ||||
| 			mmu_pte_write_zap_pte(vcpu, sp, spte); | ||||
| 			if (new) | ||||
| 				mmu_pte_write_new_pte(vcpu, sp, spte, new); | ||||
| 			if (gentry) | ||||
| 				mmu_pte_write_new_pte(vcpu, sp, spte, &gentry); | ||||
| 			mmu_pte_write_flush_tlb(vcpu, entry, *spte); | ||||
| 			++spte; | ||||
| 		} | ||||
| @ -2900,22 +2900,23 @@ void kvm_mmu_zap_all(struct kvm *kvm) | ||||
| 	struct kvm_mmu_page *sp, *node; | ||||
| 
 | ||||
| 	spin_lock(&kvm->mmu_lock); | ||||
| restart: | ||||
| 	list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link) | ||||
| 		if (kvm_mmu_zap_page(kvm, sp)) | ||||
| 			node = container_of(kvm->arch.active_mmu_pages.next, | ||||
| 					    struct kvm_mmu_page, link); | ||||
| 			goto restart; | ||||
| 
 | ||||
| 	spin_unlock(&kvm->mmu_lock); | ||||
| 
 | ||||
| 	kvm_flush_remote_tlbs(kvm); | ||||
| } | ||||
| 
 | ||||
| static void kvm_mmu_remove_one_alloc_mmu_page(struct kvm *kvm) | ||||
| static int kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm) | ||||
| { | ||||
| 	struct kvm_mmu_page *page; | ||||
| 
 | ||||
| 	page = container_of(kvm->arch.active_mmu_pages.prev, | ||||
| 			    struct kvm_mmu_page, link); | ||||
| 	kvm_mmu_zap_page(kvm, page); | ||||
| 	return kvm_mmu_zap_page(kvm, page) + 1; | ||||
| } | ||||
| 
 | ||||
| static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask) | ||||
| @ -2927,7 +2928,7 @@ static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask) | ||||
| 	spin_lock(&kvm_lock); | ||||
| 
 | ||||
| 	list_for_each_entry(kvm, &vm_list, vm_list) { | ||||
| 		int npages, idx; | ||||
| 		int npages, idx, freed_pages; | ||||
| 
 | ||||
| 		idx = srcu_read_lock(&kvm->srcu); | ||||
| 		spin_lock(&kvm->mmu_lock); | ||||
| @ -2935,8 +2936,8 @@ static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask) | ||||
| 			 kvm->arch.n_free_mmu_pages; | ||||
| 		cache_count += npages; | ||||
| 		if (!kvm_freed && nr_to_scan > 0 && npages > 0) { | ||||
| 			kvm_mmu_remove_one_alloc_mmu_page(kvm); | ||||
| 			cache_count--; | ||||
| 			freed_pages = kvm_mmu_remove_some_alloc_mmu_pages(kvm); | ||||
| 			cache_count -= freed_pages; | ||||
| 			kvm_freed = kvm; | ||||
| 		} | ||||
| 		nr_to_scan--; | ||||
| @ -3011,7 +3012,8 @@ unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm) | ||||
| 	unsigned int  nr_pages = 0; | ||||
| 	struct kvm_memslots *slots; | ||||
| 
 | ||||
| 	slots = rcu_dereference(kvm->memslots); | ||||
| 	slots = kvm_memslots(kvm); | ||||
| 
 | ||||
| 	for (i = 0; i < slots->nmemslots; i++) | ||||
| 		nr_pages += slots->memslots[i].npages; | ||||
| 
 | ||||
| @ -3174,8 +3176,7 @@ static gva_t canonicalize(gva_t gva) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| typedef void (*inspect_spte_fn) (struct kvm *kvm, struct kvm_mmu_page *sp, | ||||
| 				 u64 *sptep); | ||||
| typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); | ||||
| 
 | ||||
| static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp, | ||||
| 			    inspect_spte_fn fn) | ||||
| @ -3191,7 +3192,7 @@ static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp, | ||||
| 				child = page_header(ent & PT64_BASE_ADDR_MASK); | ||||
| 				__mmu_spte_walk(kvm, child, fn); | ||||
| 			} else | ||||
| 				fn(kvm, sp, &sp->spt[i]); | ||||
| 				fn(kvm, &sp->spt[i]); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -3282,11 +3283,13 @@ static void audit_mappings(struct kvm_vcpu *vcpu) | ||||
| 
 | ||||
| static int count_rmaps(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	struct kvm *kvm = vcpu->kvm; | ||||
| 	struct kvm_memslots *slots; | ||||
| 	int nmaps = 0; | ||||
| 	int i, j, k, idx; | ||||
| 
 | ||||
| 	idx = srcu_read_lock(&kvm->srcu); | ||||
| 	slots = rcu_dereference(kvm->memslots); | ||||
| 	slots = kvm_memslots(kvm); | ||||
| 	for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { | ||||
| 		struct kvm_memory_slot *m = &slots->memslots[i]; | ||||
| 		struct kvm_rmap_desc *d; | ||||
| @ -3315,7 +3318,7 @@ static int count_rmaps(struct kvm_vcpu *vcpu) | ||||
| 	return nmaps; | ||||
| } | ||||
| 
 | ||||
| void inspect_spte_has_rmap(struct kvm *kvm, struct kvm_mmu_page *sp, u64 *sptep) | ||||
| void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep) | ||||
| { | ||||
| 	unsigned long *rmapp; | ||||
| 	struct kvm_mmu_page *rev_sp; | ||||
| @ -3331,14 +3334,14 @@ void inspect_spte_has_rmap(struct kvm *kvm, struct kvm_mmu_page *sp, u64 *sptep) | ||||
| 			printk(KERN_ERR "%s: no memslot for gfn %ld\n", | ||||
| 					 audit_msg, gfn); | ||||
| 			printk(KERN_ERR "%s: index %ld of sp (gfn=%lx)\n", | ||||
| 					audit_msg, sptep - rev_sp->spt, | ||||
| 			       audit_msg, (long int)(sptep - rev_sp->spt), | ||||
| 					rev_sp->gfn); | ||||
| 			dump_stack(); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		rmapp = gfn_to_rmap(kvm, rev_sp->gfns[sptep - rev_sp->spt], | ||||
| 				    is_large_pte(*sptep)); | ||||
| 				    rev_sp->role.level); | ||||
| 		if (!*rmapp) { | ||||
| 			if (!printk_ratelimit()) | ||||
| 				return; | ||||
| @ -3373,7 +3376,7 @@ static void check_writable_mappings_rmap(struct kvm_vcpu *vcpu) | ||||
| 				continue; | ||||
| 			if (!(ent & PT_WRITABLE_MASK)) | ||||
| 				continue; | ||||
| 			inspect_spte_has_rmap(vcpu->kvm, sp, &pt[i]); | ||||
| 			inspect_spte_has_rmap(vcpu->kvm, &pt[i]); | ||||
| 		} | ||||
| 	} | ||||
| 	return; | ||||
|  | ||||
| @ -6,14 +6,12 @@ | ||||
| 
 | ||||
| #undef TRACE_SYSTEM | ||||
| #define TRACE_SYSTEM kvmmmu | ||||
| #define TRACE_INCLUDE_PATH . | ||||
| #define TRACE_INCLUDE_FILE mmutrace | ||||
| 
 | ||||
| #define KVM_MMU_PAGE_FIELDS \ | ||||
| 	__field(__u64, gfn) \ | ||||
| 	__field(__u32, role) \ | ||||
| 	__field(__u32, root_count) \ | ||||
| 	__field(__u32, unsync) | ||||
| 	__field(bool, unsync) | ||||
| 
 | ||||
| #define KVM_MMU_PAGE_ASSIGN(sp)			     \ | ||||
| 	__entry->gfn = sp->gfn;			     \ | ||||
| @ -30,14 +28,14 @@ | ||||
| 								        \ | ||||
| 	role.word = __entry->role;					\ | ||||
| 									\ | ||||
| 	trace_seq_printf(p, "sp gfn %llx %u/%u q%u%s %s%s %spge"	\ | ||||
| 	trace_seq_printf(p, "sp gfn %llx %u%s q%u%s %s%s"		\ | ||||
| 			 " %snxe root %u %s%c",				\ | ||||
| 			 __entry->gfn, role.level, role.glevels,	\ | ||||
| 			 __entry->gfn, role.level,			\ | ||||
| 			 role.cr4_pae ? " pae" : "",			\ | ||||
| 			 role.quadrant,					\ | ||||
| 			 role.direct ? " direct" : "",			\ | ||||
| 			 access_str[role.access],			\ | ||||
| 			 role.invalid ? " invalid" : "",		\ | ||||
| 			 role.cr4_pge ? "" : "!",			\ | ||||
| 			 role.nxe ? "" : "!",				\ | ||||
| 			 __entry->root_count,				\ | ||||
| 			 __entry->unsync ? "unsync" : "sync", 0);	\ | ||||
| @ -94,15 +92,15 @@ TRACE_EVENT( | ||||
| 	TP_printk("pte %llx level %u", __entry->pte, __entry->level) | ||||
| ); | ||||
| 
 | ||||
| /* We set a pte accessed bit */ | ||||
| TRACE_EVENT( | ||||
| 	kvm_mmu_set_accessed_bit, | ||||
| DECLARE_EVENT_CLASS(kvm_mmu_set_bit_class, | ||||
| 
 | ||||
| 	TP_PROTO(unsigned long table_gfn, unsigned index, unsigned size), | ||||
| 
 | ||||
| 	TP_ARGS(table_gfn, index, size), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		__field(__u64, gpa) | ||||
| 		), | ||||
| 	), | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		__entry->gpa = ((u64)table_gfn << PAGE_SHIFT) | ||||
| @ -112,22 +110,20 @@ TRACE_EVENT( | ||||
| 	TP_printk("gpa %llx", __entry->gpa) | ||||
| ); | ||||
| 
 | ||||
| /* We set a pte dirty bit */ | ||||
| TRACE_EVENT( | ||||
| 	kvm_mmu_set_dirty_bit, | ||||
| /* We set a pte accessed bit */ | ||||
| DEFINE_EVENT(kvm_mmu_set_bit_class, kvm_mmu_set_accessed_bit, | ||||
| 
 | ||||
| 	TP_PROTO(unsigned long table_gfn, unsigned index, unsigned size), | ||||
| 	TP_ARGS(table_gfn, index, size), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		__field(__u64, gpa) | ||||
| 		), | ||||
| 	TP_ARGS(table_gfn, index, size) | ||||
| ); | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		__entry->gpa = ((u64)table_gfn << PAGE_SHIFT) | ||||
| 				+ index * size; | ||||
| 		), | ||||
| /* We set a pte dirty bit */ | ||||
| DEFINE_EVENT(kvm_mmu_set_bit_class, kvm_mmu_set_dirty_bit, | ||||
| 
 | ||||
| 	TP_printk("gpa %llx", __entry->gpa) | ||||
| 	TP_PROTO(unsigned long table_gfn, unsigned index, unsigned size), | ||||
| 
 | ||||
| 	TP_ARGS(table_gfn, index, size) | ||||
| ); | ||||
| 
 | ||||
| TRACE_EVENT( | ||||
| @ -166,55 +162,45 @@ TRACE_EVENT( | ||||
| 		  __entry->created ? "new" : "existing") | ||||
| ); | ||||
| 
 | ||||
| TRACE_EVENT( | ||||
| 	kvm_mmu_sync_page, | ||||
| DECLARE_EVENT_CLASS(kvm_mmu_page_class, | ||||
| 
 | ||||
| 	TP_PROTO(struct kvm_mmu_page *sp), | ||||
| 	TP_ARGS(sp), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		KVM_MMU_PAGE_FIELDS | ||||
| 		), | ||||
| 	), | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		KVM_MMU_PAGE_ASSIGN(sp) | ||||
| 		), | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("%s", KVM_MMU_PAGE_PRINTK()) | ||||
| ); | ||||
| 
 | ||||
| TRACE_EVENT( | ||||
| 	kvm_mmu_unsync_page, | ||||
| DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_sync_page, | ||||
| 	TP_PROTO(struct kvm_mmu_page *sp), | ||||
| 	TP_ARGS(sp), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		KVM_MMU_PAGE_FIELDS | ||||
| 		), | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		KVM_MMU_PAGE_ASSIGN(sp) | ||||
| 		), | ||||
| 
 | ||||
| 	TP_printk("%s", KVM_MMU_PAGE_PRINTK()) | ||||
| 	TP_ARGS(sp) | ||||
| ); | ||||
| 
 | ||||
| TRACE_EVENT( | ||||
| 	kvm_mmu_zap_page, | ||||
| DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_unsync_page, | ||||
| 	TP_PROTO(struct kvm_mmu_page *sp), | ||||
| 	TP_ARGS(sp), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		KVM_MMU_PAGE_FIELDS | ||||
| 		), | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		KVM_MMU_PAGE_ASSIGN(sp) | ||||
| 		), | ||||
| 
 | ||||
| 	TP_printk("%s", KVM_MMU_PAGE_PRINTK()) | ||||
| 	TP_ARGS(sp) | ||||
| ); | ||||
| 
 | ||||
| DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_zap_page, | ||||
| 	TP_PROTO(struct kvm_mmu_page *sp), | ||||
| 
 | ||||
| 	TP_ARGS(sp) | ||||
| ); | ||||
| #endif /* _TRACE_KVMMMU_H */ | ||||
| 
 | ||||
| #undef TRACE_INCLUDE_PATH | ||||
| #define TRACE_INCLUDE_PATH . | ||||
| #undef TRACE_INCLUDE_FILE | ||||
| #define TRACE_INCLUDE_FILE mmutrace | ||||
| 
 | ||||
| /* This part must be outside protection */ | ||||
| #include <trace/define_trace.h> | ||||
|  | ||||
| @ -170,7 +170,7 @@ walk: | ||||
| 			goto access_error; | ||||
| 
 | ||||
| #if PTTYPE == 64 | ||||
| 		if (fetch_fault && is_nx(vcpu) && (pte & PT64_NX_MASK)) | ||||
| 		if (fetch_fault && (pte & PT64_NX_MASK)) | ||||
| 			goto access_error; | ||||
| #endif | ||||
| 
 | ||||
| @ -190,10 +190,10 @@ walk: | ||||
| 
 | ||||
| 		if ((walker->level == PT_PAGE_TABLE_LEVEL) || | ||||
| 		    ((walker->level == PT_DIRECTORY_LEVEL) && | ||||
| 				(pte & PT_PAGE_SIZE_MASK)  && | ||||
| 				is_large_pte(pte) && | ||||
| 				(PTTYPE == 64 || is_pse(vcpu))) || | ||||
| 		    ((walker->level == PT_PDPE_LEVEL) && | ||||
| 				(pte & PT_PAGE_SIZE_MASK)  && | ||||
| 				is_large_pte(pte) && | ||||
| 				is_long_mode(vcpu))) { | ||||
| 			int lvl = walker->level; | ||||
| 
 | ||||
| @ -258,11 +258,17 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, | ||||
| 	pt_element_t gpte; | ||||
| 	unsigned pte_access; | ||||
| 	pfn_t pfn; | ||||
| 	u64 new_spte; | ||||
| 
 | ||||
| 	gpte = *(const pt_element_t *)pte; | ||||
| 	if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) { | ||||
| 		if (!is_present_gpte(gpte)) | ||||
| 			__set_spte(spte, shadow_notrap_nonpresent_pte); | ||||
| 		if (!is_present_gpte(gpte)) { | ||||
| 			if (page->unsync) | ||||
| 				new_spte = shadow_trap_nonpresent_pte; | ||||
| 			else | ||||
| 				new_spte = shadow_notrap_nonpresent_pte; | ||||
| 			__set_spte(spte, new_spte); | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 	pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte); | ||||
| @ -457,6 +463,7 @@ out_unlock: | ||||
| static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) | ||||
| { | ||||
| 	struct kvm_shadow_walk_iterator iterator; | ||||
| 	gpa_t pte_gpa = -1; | ||||
| 	int level; | ||||
| 	u64 *sptep; | ||||
| 	int need_flush = 0; | ||||
| @ -467,9 +474,16 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) | ||||
| 		level = iterator.level; | ||||
| 		sptep = iterator.sptep; | ||||
| 
 | ||||
| 		if (level == PT_PAGE_TABLE_LEVEL  || | ||||
| 		    ((level == PT_DIRECTORY_LEVEL && is_large_pte(*sptep))) || | ||||
| 		    ((level == PT_PDPE_LEVEL && is_large_pte(*sptep)))) { | ||||
| 		if (is_last_spte(*sptep, level)) { | ||||
| 			struct kvm_mmu_page *sp = page_header(__pa(sptep)); | ||||
| 			int offset, shift; | ||||
| 
 | ||||
| 			shift = PAGE_SHIFT - | ||||
| 				  (PT_LEVEL_BITS - PT64_LEVEL_BITS) * level; | ||||
| 			offset = sp->role.quadrant << shift; | ||||
| 
 | ||||
| 			pte_gpa = (sp->gfn << PAGE_SHIFT) + offset; | ||||
| 			pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t); | ||||
| 
 | ||||
| 			if (is_shadow_present_pte(*sptep)) { | ||||
| 				rmap_remove(vcpu->kvm, sptep); | ||||
| @ -487,7 +501,17 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) | ||||
| 
 | ||||
| 	if (need_flush) | ||||
| 		kvm_flush_remote_tlbs(vcpu->kvm); | ||||
| 
 | ||||
| 	atomic_inc(&vcpu->kvm->arch.invlpg_counter); | ||||
| 
 | ||||
| 	spin_unlock(&vcpu->kvm->mmu_lock); | ||||
| 
 | ||||
| 	if (pte_gpa == -1) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (mmu_topup_memory_caches(vcpu)) | ||||
| 		return; | ||||
| 	kvm_mmu_pte_write(vcpu, pte_gpa, NULL, sizeof(pt_element_t), 0); | ||||
| } | ||||
| 
 | ||||
| static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr, u32 access, | ||||
| @ -551,12 +575,15 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | ||||
| { | ||||
| 	int i, offset, nr_present; | ||||
| 	bool reset_host_protection; | ||||
| 	gpa_t first_pte_gpa; | ||||
| 
 | ||||
| 	offset = nr_present = 0; | ||||
| 
 | ||||
| 	if (PTTYPE == 32) | ||||
| 		offset = sp->role.quadrant << PT64_LEVEL_BITS; | ||||
| 
 | ||||
| 	first_pte_gpa = gfn_to_gpa(sp->gfn) + offset * sizeof(pt_element_t); | ||||
| 
 | ||||
| 	for (i = 0; i < PT64_ENT_PER_PAGE; i++) { | ||||
| 		unsigned pte_access; | ||||
| 		pt_element_t gpte; | ||||
| @ -566,8 +593,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | ||||
| 		if (!is_shadow_present_pte(sp->spt[i])) | ||||
| 			continue; | ||||
| 
 | ||||
| 		pte_gpa = gfn_to_gpa(sp->gfn); | ||||
| 		pte_gpa += (i+offset) * sizeof(pt_element_t); | ||||
| 		pte_gpa = first_pte_gpa + i * sizeof(pt_element_t); | ||||
| 
 | ||||
| 		if (kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &gpte, | ||||
| 					  sizeof(pt_element_t))) | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -12,7 +12,8 @@ static int __kvm_timer_fn(struct kvm_vcpu *vcpu, struct kvm_timer *ktimer) | ||||
| 	/*
 | ||||
| 	 * There is a race window between reading and incrementing, but we do | ||||
| 	 * not care about potentially loosing timer events in the !reinject | ||||
| 	 * case anyway. | ||||
| 	 * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked | ||||
| 	 * in vcpu_enter_guest. | ||||
| 	 */ | ||||
| 	if (ktimer->reinject || !atomic_read(&ktimer->pending)) { | ||||
| 		atomic_inc(&ktimer->pending); | ||||
|  | ||||
| @ -5,8 +5,6 @@ | ||||
| 
 | ||||
| #undef TRACE_SYSTEM | ||||
| #define TRACE_SYSTEM kvm | ||||
| #define TRACE_INCLUDE_PATH arch/x86/kvm | ||||
| #define TRACE_INCLUDE_FILE trace | ||||
| 
 | ||||
| /*
 | ||||
|  * Tracepoint for guest mode entry. | ||||
| @ -184,8 +182,8 @@ TRACE_EVENT(kvm_apic, | ||||
|  * Tracepoint for kvm guest exit: | ||||
|  */ | ||||
| TRACE_EVENT(kvm_exit, | ||||
| 	TP_PROTO(unsigned int exit_reason, unsigned long guest_rip), | ||||
| 	TP_ARGS(exit_reason, guest_rip), | ||||
| 	TP_PROTO(unsigned int exit_reason, struct kvm_vcpu *vcpu), | ||||
| 	TP_ARGS(exit_reason, vcpu), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		__field(	unsigned int,	exit_reason	) | ||||
| @ -194,7 +192,7 @@ TRACE_EVENT(kvm_exit, | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		__entry->exit_reason	= exit_reason; | ||||
| 		__entry->guest_rip	= guest_rip; | ||||
| 		__entry->guest_rip	= kvm_rip_read(vcpu); | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("reason %s rip 0x%lx", | ||||
| @ -221,6 +219,38 @@ TRACE_EVENT(kvm_inj_virq, | ||||
| 	TP_printk("irq %u", __entry->irq) | ||||
| ); | ||||
| 
 | ||||
| #define EXS(x) { x##_VECTOR, "#" #x } | ||||
| 
 | ||||
| #define kvm_trace_sym_exc						\ | ||||
| 	EXS(DE), EXS(DB), EXS(BP), EXS(OF), EXS(BR), EXS(UD), EXS(NM),	\ | ||||
| 	EXS(DF), EXS(TS), EXS(NP), EXS(SS), EXS(GP), EXS(PF),		\ | ||||
| 	EXS(MF), EXS(MC) | ||||
| 
 | ||||
| /*
 | ||||
|  * Tracepoint for kvm interrupt injection: | ||||
|  */ | ||||
| TRACE_EVENT(kvm_inj_exception, | ||||
| 	TP_PROTO(unsigned exception, bool has_error, unsigned error_code), | ||||
| 	TP_ARGS(exception, has_error, error_code), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		__field(	u8,	exception	) | ||||
| 		__field(	u8,	has_error	) | ||||
| 		__field(	u32,	error_code	) | ||||
| 	), | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		__entry->exception	= exception; | ||||
| 		__entry->has_error	= has_error; | ||||
| 		__entry->error_code	= error_code; | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("%s (0x%x)", | ||||
| 		  __print_symbolic(__entry->exception, kvm_trace_sym_exc), | ||||
| 		  /* FIXME: don't print error_code if not present */ | ||||
| 		  __entry->has_error ? __entry->error_code : 0) | ||||
| ); | ||||
| 
 | ||||
| /*
 | ||||
|  * Tracepoint for page fault. | ||||
|  */ | ||||
| @ -413,12 +443,34 @@ TRACE_EVENT(kvm_nested_vmrun, | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("rip: 0x%016llx vmcb: 0x%016llx nrip: 0x%016llx int_ctl: 0x%08x " | ||||
| 		  "event_inj: 0x%08x npt: %s\n", | ||||
| 		  "event_inj: 0x%08x npt: %s", | ||||
| 		__entry->rip, __entry->vmcb, __entry->nested_rip, | ||||
| 		__entry->int_ctl, __entry->event_inj, | ||||
| 		__entry->npt ? "on" : "off") | ||||
| ); | ||||
| 
 | ||||
| TRACE_EVENT(kvm_nested_intercepts, | ||||
| 	    TP_PROTO(__u16 cr_read, __u16 cr_write, __u32 exceptions, __u64 intercept), | ||||
| 	    TP_ARGS(cr_read, cr_write, exceptions, intercept), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		__field(	__u16,		cr_read		) | ||||
| 		__field(	__u16,		cr_write	) | ||||
| 		__field(	__u32,		exceptions	) | ||||
| 		__field(	__u64,		intercept	) | ||||
| 	), | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		__entry->cr_read	= cr_read; | ||||
| 		__entry->cr_write	= cr_write; | ||||
| 		__entry->exceptions	= exceptions; | ||||
| 		__entry->intercept	= intercept; | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("cr_read: %04x cr_write: %04x excp: %08x intercept: %016llx", | ||||
| 		__entry->cr_read, __entry->cr_write, __entry->exceptions, | ||||
| 		__entry->intercept) | ||||
| ); | ||||
| /*
 | ||||
|  * Tracepoint for #VMEXIT while nested | ||||
|  */ | ||||
| @ -447,7 +499,7 @@ TRACE_EVENT(kvm_nested_vmexit, | ||||
| 		__entry->exit_int_info_err	= exit_int_info_err; | ||||
| 	), | ||||
| 	TP_printk("rip: 0x%016llx reason: %s ext_inf1: 0x%016llx " | ||||
| 		  "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x\n", | ||||
| 		  "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x", | ||||
| 		  __entry->rip, | ||||
| 		  ftrace_print_symbols_seq(p, __entry->exit_code, | ||||
| 					   kvm_x86_ops->exit_reasons_str), | ||||
| @ -482,7 +534,7 @@ TRACE_EVENT(kvm_nested_vmexit_inject, | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("reason: %s ext_inf1: 0x%016llx " | ||||
| 		  "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x\n", | ||||
| 		  "ext_inf2: 0x%016llx ext_int: 0x%08x ext_int_err: 0x%08x", | ||||
| 		  ftrace_print_symbols_seq(p, __entry->exit_code, | ||||
| 					   kvm_x86_ops->exit_reasons_str), | ||||
| 		__entry->exit_info1, __entry->exit_info2, | ||||
| @ -504,7 +556,7 @@ TRACE_EVENT(kvm_nested_intr_vmexit, | ||||
| 		__entry->rip	=	rip | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("rip: 0x%016llx\n", __entry->rip) | ||||
| 	TP_printk("rip: 0x%016llx", __entry->rip) | ||||
| ); | ||||
| 
 | ||||
| /*
 | ||||
| @ -526,7 +578,7 @@ TRACE_EVENT(kvm_invlpga, | ||||
| 		__entry->address	=	address; | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("rip: 0x%016llx asid: %d address: 0x%016llx\n", | ||||
| 	TP_printk("rip: 0x%016llx asid: %d address: 0x%016llx", | ||||
| 		  __entry->rip, __entry->asid, __entry->address) | ||||
| ); | ||||
| 
 | ||||
| @ -547,11 +599,102 @@ TRACE_EVENT(kvm_skinit, | ||||
| 		__entry->slb		=	slb; | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk("rip: 0x%016llx slb: 0x%08x\n", | ||||
| 	TP_printk("rip: 0x%016llx slb: 0x%08x", | ||||
| 		  __entry->rip, __entry->slb) | ||||
| ); | ||||
| 
 | ||||
| #define __print_insn(insn, ilen) ({		                 \ | ||||
| 	int i;							 \ | ||||
| 	const char *ret = p->buffer + p->len;			 \ | ||||
| 								 \ | ||||
| 	for (i = 0; i < ilen; ++i)				 \ | ||||
| 		trace_seq_printf(p, " %02x", insn[i]);		 \ | ||||
| 	trace_seq_printf(p, "%c", 0);				 \ | ||||
| 	ret;							 \ | ||||
| 	}) | ||||
| 
 | ||||
| #define KVM_EMUL_INSN_F_CR0_PE (1 << 0) | ||||
| #define KVM_EMUL_INSN_F_EFL_VM (1 << 1) | ||||
| #define KVM_EMUL_INSN_F_CS_D   (1 << 2) | ||||
| #define KVM_EMUL_INSN_F_CS_L   (1 << 3) | ||||
| 
 | ||||
| #define kvm_trace_symbol_emul_flags	                  \ | ||||
| 	{ 0,   			    "real" },		  \ | ||||
| 	{ KVM_EMUL_INSN_F_CR0_PE			  \ | ||||
| 	  | KVM_EMUL_INSN_F_EFL_VM, "vm16" },		  \ | ||||
| 	{ KVM_EMUL_INSN_F_CR0_PE,   "prot16" },		  \ | ||||
| 	{ KVM_EMUL_INSN_F_CR0_PE			  \ | ||||
| 	  | KVM_EMUL_INSN_F_CS_D,   "prot32" },		  \ | ||||
| 	{ KVM_EMUL_INSN_F_CR0_PE			  \ | ||||
| 	  | KVM_EMUL_INSN_F_CS_L,   "prot64" } | ||||
| 
 | ||||
| #define kei_decode_mode(mode) ({			\ | ||||
| 	u8 flags = 0xff;				\ | ||||
| 	switch (mode) {					\ | ||||
| 	case X86EMUL_MODE_REAL:				\ | ||||
| 		flags = 0;				\ | ||||
| 		break;					\ | ||||
| 	case X86EMUL_MODE_VM86:				\ | ||||
| 		flags = KVM_EMUL_INSN_F_EFL_VM;		\ | ||||
| 		break;					\ | ||||
| 	case X86EMUL_MODE_PROT16:			\ | ||||
| 		flags = KVM_EMUL_INSN_F_CR0_PE;		\ | ||||
| 		break;					\ | ||||
| 	case X86EMUL_MODE_PROT32:			\ | ||||
| 		flags = KVM_EMUL_INSN_F_CR0_PE		\ | ||||
| 			| KVM_EMUL_INSN_F_CS_D;		\ | ||||
| 		break;					\ | ||||
| 	case X86EMUL_MODE_PROT64:			\ | ||||
| 		flags = KVM_EMUL_INSN_F_CR0_PE		\ | ||||
| 			| KVM_EMUL_INSN_F_CS_L;		\ | ||||
| 		break;					\ | ||||
| 	}						\ | ||||
| 	flags;						\ | ||||
| 	}) | ||||
| 
 | ||||
| TRACE_EVENT(kvm_emulate_insn, | ||||
| 	TP_PROTO(struct kvm_vcpu *vcpu, __u8 failed), | ||||
| 	TP_ARGS(vcpu, failed), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		__field(    __u64, rip                       ) | ||||
| 		__field(    __u32, csbase                    ) | ||||
| 		__field(    __u8,  len                       ) | ||||
| 		__array(    __u8,  insn,    15	             ) | ||||
| 		__field(    __u8,  flags       	   	     ) | ||||
| 		__field(    __u8,  failed                    ) | ||||
| 		), | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		__entry->rip = vcpu->arch.emulate_ctxt.decode.fetch.start; | ||||
| 		__entry->csbase = kvm_x86_ops->get_segment_base(vcpu, VCPU_SREG_CS); | ||||
| 		__entry->len = vcpu->arch.emulate_ctxt.decode.eip | ||||
| 			       - vcpu->arch.emulate_ctxt.decode.fetch.start; | ||||
| 		memcpy(__entry->insn, | ||||
| 		       vcpu->arch.emulate_ctxt.decode.fetch.data, | ||||
| 		       15); | ||||
| 		__entry->flags = kei_decode_mode(vcpu->arch.emulate_ctxt.mode); | ||||
| 		__entry->failed = failed; | ||||
| 		), | ||||
| 
 | ||||
| 	TP_printk("%x:%llx:%s (%s)%s", | ||||
| 		  __entry->csbase, __entry->rip, | ||||
| 		  __print_insn(__entry->insn, __entry->len), | ||||
| 		  __print_symbolic(__entry->flags, | ||||
| 				   kvm_trace_symbol_emul_flags), | ||||
| 		  __entry->failed ? " failed" : "" | ||||
| 		) | ||||
| 	); | ||||
| 
 | ||||
| #define trace_kvm_emulate_insn_start(vcpu) trace_kvm_emulate_insn(vcpu, 0) | ||||
| #define trace_kvm_emulate_insn_failed(vcpu) trace_kvm_emulate_insn(vcpu, 1) | ||||
| 
 | ||||
| #endif /* _TRACE_KVM_H */ | ||||
| 
 | ||||
| #undef TRACE_INCLUDE_PATH | ||||
| #define TRACE_INCLUDE_PATH arch/x86/kvm | ||||
| #undef TRACE_INCLUDE_FILE | ||||
| #define TRACE_INCLUDE_FILE trace | ||||
| 
 | ||||
| /* This part must be outside protection */ | ||||
| #include <trace/define_trace.h> | ||||
|  | ||||
| @ -27,6 +27,7 @@ | ||||
| #include <linux/moduleparam.h> | ||||
| #include <linux/ftrace_event.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/tboot.h> | ||||
| #include "kvm_cache_regs.h" | ||||
| #include "x86.h" | ||||
| 
 | ||||
| @ -98,6 +99,8 @@ module_param(ple_gap, int, S_IRUGO); | ||||
| static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW; | ||||
| module_param(ple_window, int, S_IRUGO); | ||||
| 
 | ||||
| #define NR_AUTOLOAD_MSRS 1 | ||||
| 
 | ||||
| struct vmcs { | ||||
| 	u32 revision_id; | ||||
| 	u32 abort; | ||||
| @ -125,6 +128,11 @@ struct vcpu_vmx { | ||||
| 	u64 		      msr_guest_kernel_gs_base; | ||||
| #endif | ||||
| 	struct vmcs          *vmcs; | ||||
| 	struct msr_autoload { | ||||
| 		unsigned nr; | ||||
| 		struct vmx_msr_entry guest[NR_AUTOLOAD_MSRS]; | ||||
| 		struct vmx_msr_entry host[NR_AUTOLOAD_MSRS]; | ||||
| 	} msr_autoload; | ||||
| 	struct { | ||||
| 		int           loaded; | ||||
| 		u16           fs_sel, gs_sel, ldt_sel; | ||||
| @ -234,56 +242,56 @@ static const u32 vmx_msr_index[] = { | ||||
| }; | ||||
| #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) | ||||
| 
 | ||||
| static inline int is_page_fault(u32 intr_info) | ||||
| static inline bool is_page_fault(u32 intr_info) | ||||
| { | ||||
| 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | | ||||
| 			     INTR_INFO_VALID_MASK)) == | ||||
| 		(INTR_TYPE_HARD_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK); | ||||
| } | ||||
| 
 | ||||
| static inline int is_no_device(u32 intr_info) | ||||
| static inline bool is_no_device(u32 intr_info) | ||||
| { | ||||
| 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | | ||||
| 			     INTR_INFO_VALID_MASK)) == | ||||
| 		(INTR_TYPE_HARD_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK); | ||||
| } | ||||
| 
 | ||||
| static inline int is_invalid_opcode(u32 intr_info) | ||||
| static inline bool is_invalid_opcode(u32 intr_info) | ||||
| { | ||||
| 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | | ||||
| 			     INTR_INFO_VALID_MASK)) == | ||||
| 		(INTR_TYPE_HARD_EXCEPTION | UD_VECTOR | INTR_INFO_VALID_MASK); | ||||
| } | ||||
| 
 | ||||
| static inline int is_external_interrupt(u32 intr_info) | ||||
| static inline bool is_external_interrupt(u32 intr_info) | ||||
| { | ||||
| 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) | ||||
| 		== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); | ||||
| } | ||||
| 
 | ||||
| static inline int is_machine_check(u32 intr_info) | ||||
| static inline bool is_machine_check(u32 intr_info) | ||||
| { | ||||
| 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | | ||||
| 			     INTR_INFO_VALID_MASK)) == | ||||
| 		(INTR_TYPE_HARD_EXCEPTION | MC_VECTOR | INTR_INFO_VALID_MASK); | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_vmx_msr_bitmap(void) | ||||
| static inline bool cpu_has_vmx_msr_bitmap(void) | ||||
| { | ||||
| 	return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS; | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_vmx_tpr_shadow(void) | ||||
| static inline bool cpu_has_vmx_tpr_shadow(void) | ||||
| { | ||||
| 	return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW; | ||||
| } | ||||
| 
 | ||||
| static inline int vm_need_tpr_shadow(struct kvm *kvm) | ||||
| static inline bool vm_need_tpr_shadow(struct kvm *kvm) | ||||
| { | ||||
| 	return (cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)); | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_secondary_exec_ctrls(void) | ||||
| static inline bool cpu_has_secondary_exec_ctrls(void) | ||||
| { | ||||
| 	return vmcs_config.cpu_based_exec_ctrl & | ||||
| 		CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; | ||||
| @ -303,80 +311,80 @@ static inline bool cpu_has_vmx_flexpriority(void) | ||||
| 
 | ||||
| static inline bool cpu_has_vmx_ept_execute_only(void) | ||||
| { | ||||
| 	return !!(vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT); | ||||
| 	return vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT; | ||||
| } | ||||
| 
 | ||||
| static inline bool cpu_has_vmx_eptp_uncacheable(void) | ||||
| { | ||||
| 	return !!(vmx_capability.ept & VMX_EPTP_UC_BIT); | ||||
| 	return vmx_capability.ept & VMX_EPTP_UC_BIT; | ||||
| } | ||||
| 
 | ||||
| static inline bool cpu_has_vmx_eptp_writeback(void) | ||||
| { | ||||
| 	return !!(vmx_capability.ept & VMX_EPTP_WB_BIT); | ||||
| 	return vmx_capability.ept & VMX_EPTP_WB_BIT; | ||||
| } | ||||
| 
 | ||||
| static inline bool cpu_has_vmx_ept_2m_page(void) | ||||
| { | ||||
| 	return !!(vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT); | ||||
| 	return vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT; | ||||
| } | ||||
| 
 | ||||
| static inline bool cpu_has_vmx_ept_1g_page(void) | ||||
| { | ||||
| 	return !!(vmx_capability.ept & VMX_EPT_1GB_PAGE_BIT); | ||||
| 	return vmx_capability.ept & VMX_EPT_1GB_PAGE_BIT; | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_vmx_invept_individual_addr(void) | ||||
| static inline bool cpu_has_vmx_invept_individual_addr(void) | ||||
| { | ||||
| 	return !!(vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT); | ||||
| 	return vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT; | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_vmx_invept_context(void) | ||||
| static inline bool cpu_has_vmx_invept_context(void) | ||||
| { | ||||
| 	return !!(vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT); | ||||
| 	return vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT; | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_vmx_invept_global(void) | ||||
| static inline bool cpu_has_vmx_invept_global(void) | ||||
| { | ||||
| 	return !!(vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT); | ||||
| 	return vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT; | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_vmx_ept(void) | ||||
| static inline bool cpu_has_vmx_ept(void) | ||||
| { | ||||
| 	return vmcs_config.cpu_based_2nd_exec_ctrl & | ||||
| 		SECONDARY_EXEC_ENABLE_EPT; | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_vmx_unrestricted_guest(void) | ||||
| static inline bool cpu_has_vmx_unrestricted_guest(void) | ||||
| { | ||||
| 	return vmcs_config.cpu_based_2nd_exec_ctrl & | ||||
| 		SECONDARY_EXEC_UNRESTRICTED_GUEST; | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_vmx_ple(void) | ||||
| static inline bool cpu_has_vmx_ple(void) | ||||
| { | ||||
| 	return vmcs_config.cpu_based_2nd_exec_ctrl & | ||||
| 		SECONDARY_EXEC_PAUSE_LOOP_EXITING; | ||||
| } | ||||
| 
 | ||||
| static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm) | ||||
| static inline bool vm_need_virtualize_apic_accesses(struct kvm *kvm) | ||||
| { | ||||
| 	return flexpriority_enabled && irqchip_in_kernel(kvm); | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_vmx_vpid(void) | ||||
| static inline bool cpu_has_vmx_vpid(void) | ||||
| { | ||||
| 	return vmcs_config.cpu_based_2nd_exec_ctrl & | ||||
| 		SECONDARY_EXEC_ENABLE_VPID; | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_vmx_rdtscp(void) | ||||
| static inline bool cpu_has_vmx_rdtscp(void) | ||||
| { | ||||
| 	return vmcs_config.cpu_based_2nd_exec_ctrl & | ||||
| 		SECONDARY_EXEC_RDTSCP; | ||||
| } | ||||
| 
 | ||||
| static inline int cpu_has_virtual_nmis(void) | ||||
| static inline bool cpu_has_virtual_nmis(void) | ||||
| { | ||||
| 	return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS; | ||||
| } | ||||
| @ -595,16 +603,56 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu) | ||||
| 	vmcs_write32(EXCEPTION_BITMAP, eb); | ||||
| } | ||||
| 
 | ||||
| static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct msr_autoload *m = &vmx->msr_autoload; | ||||
| 
 | ||||
| 	for (i = 0; i < m->nr; ++i) | ||||
| 		if (m->guest[i].index == msr) | ||||
| 			break; | ||||
| 
 | ||||
| 	if (i == m->nr) | ||||
| 		return; | ||||
| 	--m->nr; | ||||
| 	m->guest[i] = m->guest[m->nr]; | ||||
| 	m->host[i] = m->host[m->nr]; | ||||
| 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr); | ||||
| 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr); | ||||
| } | ||||
| 
 | ||||
| static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, | ||||
| 				  u64 guest_val, u64 host_val) | ||||
| { | ||||
| 	unsigned i; | ||||
| 	struct msr_autoload *m = &vmx->msr_autoload; | ||||
| 
 | ||||
| 	for (i = 0; i < m->nr; ++i) | ||||
| 		if (m->guest[i].index == msr) | ||||
| 			break; | ||||
| 
 | ||||
| 	if (i == m->nr) { | ||||
| 		++m->nr; | ||||
| 		vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr); | ||||
| 		vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr); | ||||
| 	} | ||||
| 
 | ||||
| 	m->guest[i].index = msr; | ||||
| 	m->guest[i].value = guest_val; | ||||
| 	m->host[i].index = msr; | ||||
| 	m->host[i].value = host_val; | ||||
| } | ||||
| 
 | ||||
| static void reload_tss(void) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * VT restores TR but not its size.  Useless. | ||||
| 	 */ | ||||
| 	struct descriptor_table gdt; | ||||
| 	struct desc_ptr gdt; | ||||
| 	struct desc_struct *descs; | ||||
| 
 | ||||
| 	kvm_get_gdt(&gdt); | ||||
| 	descs = (void *)gdt.base; | ||||
| 	native_store_gdt(&gdt); | ||||
| 	descs = (void *)gdt.address; | ||||
| 	descs[GDT_ENTRY_TSS].type = 9; /* available TSS */ | ||||
| 	load_TR_desc(); | ||||
| } | ||||
| @ -631,9 +679,57 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) | ||||
| 	guest_efer |= host_efer & ignore_bits; | ||||
| 	vmx->guest_msrs[efer_offset].data = guest_efer; | ||||
| 	vmx->guest_msrs[efer_offset].mask = ~ignore_bits; | ||||
| 
 | ||||
| 	clear_atomic_switch_msr(vmx, MSR_EFER); | ||||
| 	/* On ept, can't emulate nx, and must switch nx atomically */ | ||||
| 	if (enable_ept && ((vmx->vcpu.arch.efer ^ host_efer) & EFER_NX)) { | ||||
| 		guest_efer = vmx->vcpu.arch.efer; | ||||
| 		if (!(guest_efer & EFER_LMA)) | ||||
| 			guest_efer &= ~EFER_LME; | ||||
| 		add_atomic_switch_msr(vmx, MSR_EFER, guest_efer, host_efer); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static unsigned long segment_base(u16 selector) | ||||
| { | ||||
| 	struct desc_ptr gdt; | ||||
| 	struct desc_struct *d; | ||||
| 	unsigned long table_base; | ||||
| 	unsigned long v; | ||||
| 
 | ||||
| 	if (!(selector & ~3)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	native_store_gdt(&gdt); | ||||
| 	table_base = gdt.address; | ||||
| 
 | ||||
| 	if (selector & 4) {           /* from ldt */ | ||||
| 		u16 ldt_selector = kvm_read_ldt(); | ||||
| 
 | ||||
| 		if (!(ldt_selector & ~3)) | ||||
| 			return 0; | ||||
| 
 | ||||
| 		table_base = segment_base(ldt_selector); | ||||
| 	} | ||||
| 	d = (struct desc_struct *)(table_base + (selector & ~7)); | ||||
| 	v = get_desc_base(d); | ||||
| #ifdef CONFIG_X86_64 | ||||
|        if (d->s == 0 && (d->type == 2 || d->type == 9 || d->type == 11)) | ||||
|                v |= ((unsigned long)((struct ldttss_desc64 *)d)->base3) << 32; | ||||
| #endif | ||||
| 	return v; | ||||
| } | ||||
| 
 | ||||
| static inline unsigned long kvm_read_tr_base(void) | ||||
| { | ||||
| 	u16 tr; | ||||
| 	asm("str %0" : "=g"(tr)); | ||||
| 	return segment_base(tr); | ||||
| } | ||||
| 
 | ||||
| static void vmx_save_host_state(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	struct vcpu_vmx *vmx = to_vmx(vcpu); | ||||
| @ -758,7 +854,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||||
| 	} | ||||
| 
 | ||||
| 	if (vcpu->cpu != cpu) { | ||||
| 		struct descriptor_table dt; | ||||
| 		struct desc_ptr dt; | ||||
| 		unsigned long sysenter_esp; | ||||
| 
 | ||||
| 		vcpu->cpu = cpu; | ||||
| @ -767,8 +863,8 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||||
| 		 * processors. | ||||
| 		 */ | ||||
| 		vmcs_writel(HOST_TR_BASE, kvm_read_tr_base()); /* 22.2.4 */ | ||||
| 		kvm_get_gdt(&dt); | ||||
| 		vmcs_writel(HOST_GDTR_BASE, dt.base);   /* 22.2.4 */ | ||||
| 		native_store_gdt(&dt); | ||||
| 		vmcs_writel(HOST_GDTR_BASE, dt.address);   /* 22.2.4 */ | ||||
| 
 | ||||
| 		rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); | ||||
| 		vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ | ||||
| @ -846,9 +942,9 @@ static u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	if (interruptibility & GUEST_INTR_STATE_STI) | ||||
| 		ret |= X86_SHADOW_INT_STI; | ||||
| 		ret |= KVM_X86_SHADOW_INT_STI; | ||||
| 	if (interruptibility & GUEST_INTR_STATE_MOV_SS) | ||||
| 		ret |= X86_SHADOW_INT_MOV_SS; | ||||
| 		ret |= KVM_X86_SHADOW_INT_MOV_SS; | ||||
| 
 | ||||
| 	return ret & mask; | ||||
| } | ||||
| @ -860,9 +956,9 @@ static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) | ||||
| 
 | ||||
| 	interruptibility &= ~(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS); | ||||
| 
 | ||||
| 	if (mask & X86_SHADOW_INT_MOV_SS) | ||||
| 	if (mask & KVM_X86_SHADOW_INT_MOV_SS) | ||||
| 		interruptibility |= GUEST_INTR_STATE_MOV_SS; | ||||
| 	if (mask & X86_SHADOW_INT_STI) | ||||
| 	else if (mask & KVM_X86_SHADOW_INT_STI) | ||||
| 		interruptibility |= GUEST_INTR_STATE_STI; | ||||
| 
 | ||||
| 	if ((interruptibility != interruptibility_old)) | ||||
| @ -882,7 +978,8 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) | ||||
| } | ||||
| 
 | ||||
| static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, | ||||
| 				bool has_error_code, u32 error_code) | ||||
| 				bool has_error_code, u32 error_code, | ||||
| 				bool reinject) | ||||
| { | ||||
| 	struct vcpu_vmx *vmx = to_vmx(vcpu); | ||||
| 	u32 intr_info = nr | INTR_INFO_VALID_MASK; | ||||
| @ -1176,9 +1273,16 @@ static __init int vmx_disabled_by_bios(void) | ||||
| 	u64 msr; | ||||
| 
 | ||||
| 	rdmsrl(MSR_IA32_FEATURE_CONTROL, msr); | ||||
| 	return (msr & (FEATURE_CONTROL_LOCKED | | ||||
| 		       FEATURE_CONTROL_VMXON_ENABLED)) | ||||
| 	    == FEATURE_CONTROL_LOCKED; | ||||
| 	if (msr & FEATURE_CONTROL_LOCKED) { | ||||
| 		if (!(msr & FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX) | ||||
| 			&& tboot_enabled()) | ||||
| 			return 1; | ||||
| 		if (!(msr & FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX) | ||||
| 			&& !tboot_enabled()) | ||||
| 			return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 	/* locked but not enabled */ | ||||
| } | ||||
| 
 | ||||
| @ -1186,21 +1290,23 @@ static int hardware_enable(void *garbage) | ||||
| { | ||||
| 	int cpu = raw_smp_processor_id(); | ||||
| 	u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); | ||||
| 	u64 old; | ||||
| 	u64 old, test_bits; | ||||
| 
 | ||||
| 	if (read_cr4() & X86_CR4_VMXE) | ||||
| 		return -EBUSY; | ||||
| 
 | ||||
| 	INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu)); | ||||
| 	rdmsrl(MSR_IA32_FEATURE_CONTROL, old); | ||||
| 	if ((old & (FEATURE_CONTROL_LOCKED | | ||||
| 		    FEATURE_CONTROL_VMXON_ENABLED)) | ||||
| 	    != (FEATURE_CONTROL_LOCKED | | ||||
| 		FEATURE_CONTROL_VMXON_ENABLED)) | ||||
| 
 | ||||
| 	test_bits = FEATURE_CONTROL_LOCKED; | ||||
| 	test_bits |= FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; | ||||
| 	if (tboot_enabled()) | ||||
| 		test_bits |= FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX; | ||||
| 
 | ||||
| 	if ((old & test_bits) != test_bits) { | ||||
| 		/* enable and lock */ | ||||
| 		wrmsrl(MSR_IA32_FEATURE_CONTROL, old | | ||||
| 		       FEATURE_CONTROL_LOCKED | | ||||
| 		       FEATURE_CONTROL_VMXON_ENABLED); | ||||
| 		wrmsrl(MSR_IA32_FEATURE_CONTROL, old | test_bits); | ||||
| 	} | ||||
| 	write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */ | ||||
| 	asm volatile (ASM_VMX_VMXON_RAX | ||||
| 		      : : "a"(&phys_addr), "m"(phys_addr) | ||||
| @ -1521,7 +1627,7 @@ static gva_t rmode_tss_base(struct kvm *kvm) | ||||
| 		struct kvm_memslots *slots; | ||||
| 		gfn_t base_gfn; | ||||
| 
 | ||||
| 		slots = rcu_dereference(kvm->memslots); | ||||
| 		slots = kvm_memslots(kvm); | ||||
| 		base_gfn = kvm->memslots->memslots[0].base_gfn + | ||||
| 				 kvm->memslots->memslots[0].npages - 3; | ||||
| 		return base_gfn << PAGE_SHIFT; | ||||
| @ -1649,6 +1755,7 @@ static void exit_lmode(struct kvm_vcpu *vcpu) | ||||
| 	vmcs_write32(VM_ENTRY_CONTROLS, | ||||
| 		     vmcs_read32(VM_ENTRY_CONTROLS) | ||||
| 		     & ~VM_ENTRY_IA32E_MODE); | ||||
| 	vmx_set_efer(vcpu, vcpu->arch.efer); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| @ -1934,28 +2041,28 @@ static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) | ||||
| 	*l = (ar >> 13) & 1; | ||||
| } | ||||
| 
 | ||||
| static void vmx_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) | ||||
| static void vmx_get_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) | ||||
| { | ||||
| 	dt->limit = vmcs_read32(GUEST_IDTR_LIMIT); | ||||
| 	dt->base = vmcs_readl(GUEST_IDTR_BASE); | ||||
| 	dt->size = vmcs_read32(GUEST_IDTR_LIMIT); | ||||
| 	dt->address = vmcs_readl(GUEST_IDTR_BASE); | ||||
| } | ||||
| 
 | ||||
| static void vmx_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) | ||||
| static void vmx_set_idt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) | ||||
| { | ||||
| 	vmcs_write32(GUEST_IDTR_LIMIT, dt->limit); | ||||
| 	vmcs_writel(GUEST_IDTR_BASE, dt->base); | ||||
| 	vmcs_write32(GUEST_IDTR_LIMIT, dt->size); | ||||
| 	vmcs_writel(GUEST_IDTR_BASE, dt->address); | ||||
| } | ||||
| 
 | ||||
| static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) | ||||
| static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) | ||||
| { | ||||
| 	dt->limit = vmcs_read32(GUEST_GDTR_LIMIT); | ||||
| 	dt->base = vmcs_readl(GUEST_GDTR_BASE); | ||||
| 	dt->size = vmcs_read32(GUEST_GDTR_LIMIT); | ||||
| 	dt->address = vmcs_readl(GUEST_GDTR_BASE); | ||||
| } | ||||
| 
 | ||||
| static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) | ||||
| static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct desc_ptr *dt) | ||||
| { | ||||
| 	vmcs_write32(GUEST_GDTR_LIMIT, dt->limit); | ||||
| 	vmcs_writel(GUEST_GDTR_BASE, dt->base); | ||||
| 	vmcs_write32(GUEST_GDTR_LIMIT, dt->size); | ||||
| 	vmcs_writel(GUEST_GDTR_BASE, dt->address); | ||||
| } | ||||
| 
 | ||||
| static bool rmode_segment_valid(struct kvm_vcpu *vcpu, int seg) | ||||
| @ -2296,6 +2403,16 @@ static void allocate_vpid(struct vcpu_vmx *vmx) | ||||
| 	spin_unlock(&vmx_vpid_lock); | ||||
| } | ||||
| 
 | ||||
| static void free_vpid(struct vcpu_vmx *vmx) | ||||
| { | ||||
| 	if (!enable_vpid) | ||||
| 		return; | ||||
| 	spin_lock(&vmx_vpid_lock); | ||||
| 	if (vmx->vpid != 0) | ||||
| 		__clear_bit(vmx->vpid, vmx_vpid_bitmap); | ||||
| 	spin_unlock(&vmx_vpid_lock); | ||||
| } | ||||
| 
 | ||||
| static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr) | ||||
| { | ||||
| 	int f = sizeof(unsigned long); | ||||
| @ -2334,7 +2451,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) | ||||
| 	u32 junk; | ||||
| 	u64 host_pat, tsc_this, tsc_base; | ||||
| 	unsigned long a; | ||||
| 	struct descriptor_table dt; | ||||
| 	struct desc_ptr dt; | ||||
| 	int i; | ||||
| 	unsigned long kvm_vmx_return; | ||||
| 	u32 exec_control; | ||||
| @ -2415,14 +2532,16 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) | ||||
| 
 | ||||
| 	vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8);  /* 22.2.4 */ | ||||
| 
 | ||||
| 	kvm_get_idt(&dt); | ||||
| 	vmcs_writel(HOST_IDTR_BASE, dt.base);   /* 22.2.4 */ | ||||
| 	native_store_idt(&dt); | ||||
| 	vmcs_writel(HOST_IDTR_BASE, dt.address);   /* 22.2.4 */ | ||||
| 
 | ||||
| 	asm("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return)); | ||||
| 	vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */ | ||||
| 	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); | ||||
| 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0); | ||||
| 	vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host)); | ||||
| 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); | ||||
| 	vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest)); | ||||
| 
 | ||||
| 	rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk); | ||||
| 	vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs); | ||||
| @ -2947,22 +3066,20 @@ static int handle_io(struct kvm_vcpu *vcpu) | ||||
| 	int size, in, string; | ||||
| 	unsigned port; | ||||
| 
 | ||||
| 	++vcpu->stat.io_exits; | ||||
| 	exit_qualification = vmcs_readl(EXIT_QUALIFICATION); | ||||
| 	string = (exit_qualification & 16) != 0; | ||||
| 
 | ||||
| 	if (string) { | ||||
| 		if (emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO) | ||||
| 			return 0; | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	size = (exit_qualification & 7) + 1; | ||||
| 	in = (exit_qualification & 8) != 0; | ||||
| 	port = exit_qualification >> 16; | ||||
| 
 | ||||
| 	++vcpu->stat.io_exits; | ||||
| 
 | ||||
| 	if (string || in) | ||||
| 		return !(emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO); | ||||
| 
 | ||||
| 	port = exit_qualification >> 16; | ||||
| 	size = (exit_qualification & 7) + 1; | ||||
| 	skip_emulated_instruction(vcpu); | ||||
| 	return kvm_emulate_pio(vcpu, in, size, port); | ||||
| 
 | ||||
| 	return kvm_fast_pio_out(vcpu, size, port); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| @ -3053,19 +3170,9 @@ static int handle_cr(struct kvm_vcpu *vcpu) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int check_dr_alias(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) { | ||||
| 		kvm_queue_exception(vcpu, UD_VECTOR); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int handle_dr(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	unsigned long exit_qualification; | ||||
| 	unsigned long val; | ||||
| 	int dr, reg; | ||||
| 
 | ||||
| 	/* Do not handle if the CPL > 0, will trigger GP on re-entry */ | ||||
| @ -3100,67 +3207,20 @@ static int handle_dr(struct kvm_vcpu *vcpu) | ||||
| 	dr = exit_qualification & DEBUG_REG_ACCESS_NUM; | ||||
| 	reg = DEBUG_REG_ACCESS_REG(exit_qualification); | ||||
| 	if (exit_qualification & TYPE_MOV_FROM_DR) { | ||||
| 		switch (dr) { | ||||
| 		case 0 ... 3: | ||||
| 			val = vcpu->arch.db[dr]; | ||||
| 			break; | ||||
| 		case 4: | ||||
| 			if (check_dr_alias(vcpu) < 0) | ||||
| 				return 1; | ||||
| 			/* fall through */ | ||||
| 		case 6: | ||||
| 			val = vcpu->arch.dr6; | ||||
| 			break; | ||||
| 		case 5: | ||||
| 			if (check_dr_alias(vcpu) < 0) | ||||
| 				return 1; | ||||
| 			/* fall through */ | ||||
| 		default: /* 7 */ | ||||
| 			val = vcpu->arch.dr7; | ||||
| 			break; | ||||
| 		} | ||||
| 		kvm_register_write(vcpu, reg, val); | ||||
| 	} else { | ||||
| 		val = vcpu->arch.regs[reg]; | ||||
| 		switch (dr) { | ||||
| 		case 0 ... 3: | ||||
| 			vcpu->arch.db[dr] = val; | ||||
| 			if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) | ||||
| 				vcpu->arch.eff_db[dr] = val; | ||||
| 			break; | ||||
| 		case 4: | ||||
| 			if (check_dr_alias(vcpu) < 0) | ||||
| 				return 1; | ||||
| 			/* fall through */ | ||||
| 		case 6: | ||||
| 			if (val & 0xffffffff00000000ULL) { | ||||
| 				kvm_inject_gp(vcpu, 0); | ||||
| 				return 1; | ||||
| 			} | ||||
| 			vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1; | ||||
| 			break; | ||||
| 		case 5: | ||||
| 			if (check_dr_alias(vcpu) < 0) | ||||
| 				return 1; | ||||
| 			/* fall through */ | ||||
| 		default: /* 7 */ | ||||
| 			if (val & 0xffffffff00000000ULL) { | ||||
| 				kvm_inject_gp(vcpu, 0); | ||||
| 				return 1; | ||||
| 			} | ||||
| 			vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1; | ||||
| 			if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) { | ||||
| 				vmcs_writel(GUEST_DR7, vcpu->arch.dr7); | ||||
| 				vcpu->arch.switch_db_regs = | ||||
| 					(val & DR7_BP_EN_MASK); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 		unsigned long val; | ||||
| 		if (!kvm_get_dr(vcpu, dr, &val)) | ||||
| 			kvm_register_write(vcpu, reg, val); | ||||
| 	} else | ||||
| 		kvm_set_dr(vcpu, dr, vcpu->arch.regs[reg]); | ||||
| 	skip_emulated_instruction(vcpu); | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val) | ||||
| { | ||||
| 	vmcs_writel(GUEST_DR7, val); | ||||
| } | ||||
| 
 | ||||
| static int handle_cpuid(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	kvm_emulate_cpuid(vcpu); | ||||
| @ -3292,6 +3352,8 @@ static int handle_task_switch(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	struct vcpu_vmx *vmx = to_vmx(vcpu); | ||||
| 	unsigned long exit_qualification; | ||||
| 	bool has_error_code = false; | ||||
| 	u32 error_code = 0; | ||||
| 	u16 tss_selector; | ||||
| 	int reason, type, idt_v; | ||||
| 
 | ||||
| @ -3314,6 +3376,13 @@ static int handle_task_switch(struct kvm_vcpu *vcpu) | ||||
| 			kvm_clear_interrupt_queue(vcpu); | ||||
| 			break; | ||||
| 		case INTR_TYPE_HARD_EXCEPTION: | ||||
| 			if (vmx->idt_vectoring_info & | ||||
| 			    VECTORING_INFO_DELIVER_CODE_MASK) { | ||||
| 				has_error_code = true; | ||||
| 				error_code = | ||||
| 					vmcs_read32(IDT_VECTORING_ERROR_CODE); | ||||
| 			} | ||||
| 			/* fall through */ | ||||
| 		case INTR_TYPE_SOFT_EXCEPTION: | ||||
| 			kvm_clear_exception_queue(vcpu); | ||||
| 			break; | ||||
| @ -3328,8 +3397,13 @@ static int handle_task_switch(struct kvm_vcpu *vcpu) | ||||
| 		       type != INTR_TYPE_NMI_INTR)) | ||||
| 		skip_emulated_instruction(vcpu); | ||||
| 
 | ||||
| 	if (!kvm_task_switch(vcpu, tss_selector, reason)) | ||||
| 	if (kvm_task_switch(vcpu, tss_selector, reason, | ||||
| 				has_error_code, error_code) == EMULATE_FAIL) { | ||||
| 		vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; | ||||
| 		vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; | ||||
| 		vcpu->run->internal.ndata = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* clear all local breakpoint enable flags */ | ||||
| 	vmcs_writel(GUEST_DR7, vmcs_readl(GUEST_DR7) & ~55); | ||||
| @ -3574,7 +3648,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu) | ||||
| 	u32 exit_reason = vmx->exit_reason; | ||||
| 	u32 vectoring_info = vmx->idt_vectoring_info; | ||||
| 
 | ||||
| 	trace_kvm_exit(exit_reason, kvm_rip_read(vcpu)); | ||||
| 	trace_kvm_exit(exit_reason, vcpu); | ||||
| 
 | ||||
| 	/* If guest state is invalid, start emulating */ | ||||
| 	if (vmx->emulation_required && emulate_invalid_guest_state) | ||||
| @ -3923,10 +3997,7 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu) | ||||
| { | ||||
| 	struct vcpu_vmx *vmx = to_vmx(vcpu); | ||||
| 
 | ||||
| 	spin_lock(&vmx_vpid_lock); | ||||
| 	if (vmx->vpid != 0) | ||||
| 		__clear_bit(vmx->vpid, vmx_vpid_bitmap); | ||||
| 	spin_unlock(&vmx_vpid_lock); | ||||
| 	free_vpid(vmx); | ||||
| 	vmx_free_vmcs(vcpu); | ||||
| 	kfree(vmx->guest_msrs); | ||||
| 	kvm_vcpu_uninit(vcpu); | ||||
| @ -3988,6 +4059,7 @@ free_msrs: | ||||
| uninit_vcpu: | ||||
| 	kvm_vcpu_uninit(&vmx->vcpu); | ||||
| free_vcpu: | ||||
| 	free_vpid(vmx); | ||||
| 	kmem_cache_free(kvm_vcpu_cache, vmx); | ||||
| 	return ERR_PTR(err); | ||||
| } | ||||
| @ -4118,6 +4190,10 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void vmx_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static struct kvm_x86_ops vmx_x86_ops = { | ||||
| 	.cpu_has_kvm_support = cpu_has_kvm_support, | ||||
| 	.disabled_by_bios = vmx_disabled_by_bios, | ||||
| @ -4154,6 +4230,7 @@ static struct kvm_x86_ops vmx_x86_ops = { | ||||
| 	.set_idt = vmx_set_idt, | ||||
| 	.get_gdt = vmx_get_gdt, | ||||
| 	.set_gdt = vmx_set_gdt, | ||||
| 	.set_dr7 = vmx_set_dr7, | ||||
| 	.cache_reg = vmx_cache_reg, | ||||
| 	.get_rflags = vmx_get_rflags, | ||||
| 	.set_rflags = vmx_set_rflags, | ||||
| @ -4189,6 +4266,8 @@ static struct kvm_x86_ops vmx_x86_ops = { | ||||
| 	.cpuid_update = vmx_cpuid_update, | ||||
| 
 | ||||
| 	.rdtscp_supported = vmx_rdtscp_supported, | ||||
| 
 | ||||
| 	.set_supported_cpuid = vmx_set_supported_cpuid, | ||||
| }; | ||||
| 
 | ||||
| static int __init vmx_init(void) | ||||
| @ -4236,7 +4315,8 @@ static int __init vmx_init(void) | ||||
| 
 | ||||
| 	set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ | ||||
| 
 | ||||
| 	r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); | ||||
| 	r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), | ||||
| 		     __alignof__(struct vcpu_vmx), THIS_MODULE); | ||||
| 	if (r) | ||||
| 		goto out3; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										1599
									
								
								arch/x86/kvm/x86.c
									
									
									
									
									
								
							
							
						
						
									
										1599
									
								
								arch/x86/kvm/x86.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -65,6 +65,13 @@ static inline int is_paging(struct kvm_vcpu *vcpu) | ||||
| 	return kvm_read_cr0_bits(vcpu, X86_CR0_PG); | ||||
| } | ||||
| 
 | ||||
| static inline struct kvm_mem_aliases *kvm_aliases(struct kvm *kvm) | ||||
| { | ||||
| 	return rcu_dereference_check(kvm->arch.aliases, | ||||
| 			srcu_read_lock_held(&kvm->srcu) | ||||
| 			|| lockdep_is_held(&kvm->slots_lock)); | ||||
| } | ||||
| 
 | ||||
| void kvm_before_handle_nmi(struct kvm_vcpu *vcpu); | ||||
| void kvm_after_handle_nmi(struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
|  | ||||
| @ -160,6 +160,7 @@ struct kvm_pit_config { | ||||
| #define KVM_EXIT_DCR              15 | ||||
| #define KVM_EXIT_NMI              16 | ||||
| #define KVM_EXIT_INTERNAL_ERROR   17 | ||||
| #define KVM_EXIT_OSI              18 | ||||
| 
 | ||||
| /* For KVM_EXIT_INTERNAL_ERROR */ | ||||
| #define KVM_INTERNAL_ERROR_EMULATION 1 | ||||
| @ -259,6 +260,10 @@ struct kvm_run { | ||||
| 			__u32 ndata; | ||||
| 			__u64 data[16]; | ||||
| 		} internal; | ||||
| 		/* KVM_EXIT_OSI */ | ||||
| 		struct { | ||||
| 			__u64 gprs[32]; | ||||
| 		} osi; | ||||
| 		/* Fix the size of the union. */ | ||||
| 		char padding[256]; | ||||
| 	}; | ||||
| @ -400,6 +405,15 @@ struct kvm_ioeventfd { | ||||
| 	__u8  pad[36]; | ||||
| }; | ||||
| 
 | ||||
| /* for KVM_ENABLE_CAP */ | ||||
| struct kvm_enable_cap { | ||||
| 	/* in */ | ||||
| 	__u32 cap; | ||||
| 	__u32 flags; | ||||
| 	__u64 args[4]; | ||||
| 	__u8  pad[64]; | ||||
| }; | ||||
| 
 | ||||
| #define KVMIO 0xAE | ||||
| 
 | ||||
| /*
 | ||||
| @ -501,7 +515,15 @@ struct kvm_ioeventfd { | ||||
| #define KVM_CAP_HYPERV_VAPIC 45 | ||||
| #define KVM_CAP_HYPERV_SPIN 46 | ||||
| #define KVM_CAP_PCI_SEGMENT 47 | ||||
| #define KVM_CAP_PPC_PAIRED_SINGLES 48 | ||||
| #define KVM_CAP_INTR_SHADOW 49 | ||||
| #ifdef __KVM_HAVE_DEBUGREGS | ||||
| #define KVM_CAP_DEBUGREGS 50 | ||||
| #endif | ||||
| #define KVM_CAP_X86_ROBUST_SINGLESTEP 51 | ||||
| #define KVM_CAP_PPC_OSI 52 | ||||
| #define KVM_CAP_PPC_UNSET_IRQ 53 | ||||
| #define KVM_CAP_ENABLE_CAP 54 | ||||
| 
 | ||||
| #ifdef KVM_CAP_IRQ_ROUTING | ||||
| 
 | ||||
| @ -688,6 +710,10 @@ struct kvm_clock_data { | ||||
| /* Available with KVM_CAP_VCPU_EVENTS */ | ||||
| #define KVM_GET_VCPU_EVENTS       _IOR(KVMIO,  0x9f, struct kvm_vcpu_events) | ||||
| #define KVM_SET_VCPU_EVENTS       _IOW(KVMIO,  0xa0, struct kvm_vcpu_events) | ||||
| /* Available with KVM_CAP_DEBUGREGS */ | ||||
| #define KVM_GET_DEBUGREGS         _IOR(KVMIO,  0xa1, struct kvm_debugregs) | ||||
| #define KVM_SET_DEBUGREGS         _IOW(KVMIO,  0xa2, struct kvm_debugregs) | ||||
| #define KVM_ENABLE_CAP            _IOW(KVMIO,  0xa3, struct kvm_enable_cap) | ||||
| 
 | ||||
| #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0) | ||||
| 
 | ||||
|  | ||||
| @ -105,6 +105,12 @@ struct kvm_vcpu { | ||||
| 	struct kvm_vcpu_arch arch; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Some of the bitops functions do not support too long bitmaps. | ||||
|  * This number must be determined not to exceed such limits. | ||||
|  */ | ||||
| #define KVM_MEM_MAX_NR_PAGES ((1UL << 31) - 1) | ||||
| 
 | ||||
| struct kvm_memory_slot { | ||||
| 	gfn_t base_gfn; | ||||
| 	unsigned long npages; | ||||
| @ -237,17 +243,23 @@ void kvm_vcpu_uninit(struct kvm_vcpu *vcpu); | ||||
| void vcpu_load(struct kvm_vcpu *vcpu); | ||||
| void vcpu_put(struct kvm_vcpu *vcpu); | ||||
| 
 | ||||
| int kvm_init(void *opaque, unsigned int vcpu_size, | ||||
| int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, | ||||
| 		  struct module *module); | ||||
| void kvm_exit(void); | ||||
| 
 | ||||
| void kvm_get_kvm(struct kvm *kvm); | ||||
| void kvm_put_kvm(struct kvm *kvm); | ||||
| 
 | ||||
| static inline struct kvm_memslots *kvm_memslots(struct kvm *kvm) | ||||
| { | ||||
| 	return rcu_dereference_check(kvm->memslots, | ||||
| 			srcu_read_lock_held(&kvm->srcu) | ||||
| 			|| lockdep_is_held(&kvm->slots_lock)); | ||||
| } | ||||
| 
 | ||||
| #define HPA_MSB ((sizeof(hpa_t) * 8) - 1) | ||||
| #define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB) | ||||
| static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } | ||||
| struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva); | ||||
| 
 | ||||
| extern struct page *bad_page; | ||||
| extern pfn_t bad_pfn; | ||||
|  | ||||
| @ -150,6 +150,7 @@ extern int tboot_force_iommu(void); | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| #define tboot_enabled()			0 | ||||
| #define tboot_probe()			do { } while (0) | ||||
| #define tboot_shutdown(shutdown_type)	do { } while (0) | ||||
| #define tboot_sleep(sleep_state, pm1a_control, pm1b_control)	\ | ||||
|  | ||||
| @ -5,7 +5,6 @@ | ||||
| 
 | ||||
| #undef TRACE_SYSTEM | ||||
| #define TRACE_SYSTEM kvm | ||||
| #define TRACE_INCLUDE_FILE kvm | ||||
| 
 | ||||
| #if defined(__KVM_HAVE_IOAPIC) | ||||
| TRACE_EVENT(kvm_set_irq, | ||||
|  | ||||
| @ -316,12 +316,16 @@ static int assigned_device_enable_host_msix(struct kvm *kvm, | ||||
| 				kvm_assigned_dev_intr, 0, | ||||
| 				"kvm_assigned_msix_device", | ||||
| 				(void *)dev); | ||||
| 		/* FIXME: free requested_irq's on failure */ | ||||
| 		if (r) | ||||
| 			return r; | ||||
| 			goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| err: | ||||
| 	for (i -= 1; i >= 0; i--) | ||||
| 		free_irq(dev->host_msix_entries[i].vector, (void *)dev); | ||||
| 	pci_disable_msix(dev->dev); | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -120,8 +120,10 @@ int kvm_coalesced_mmio_init(struct kvm *kvm) | ||||
| 	return ret; | ||||
| 
 | ||||
| out_free_dev: | ||||
| 	kvm->coalesced_mmio_dev = NULL; | ||||
| 	kfree(dev); | ||||
| out_free_page: | ||||
| 	kvm->coalesced_mmio_ring = NULL; | ||||
| 	__free_page(page); | ||||
| out_err: | ||||
| 	return ret; | ||||
| @ -139,7 +141,7 @@ int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm, | ||||
| 	struct kvm_coalesced_mmio_dev *dev = kvm->coalesced_mmio_dev; | ||||
| 
 | ||||
| 	if (dev == NULL) | ||||
| 		return -EINVAL; | ||||
| 		return -ENXIO; | ||||
| 
 | ||||
| 	mutex_lock(&kvm->slots_lock); | ||||
| 	if (dev->nb_zones >= KVM_COALESCED_MMIO_ZONE_MAX) { | ||||
| @ -162,7 +164,7 @@ int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm, | ||||
| 	struct kvm_coalesced_mmio_zone *z; | ||||
| 
 | ||||
| 	if (dev == NULL) | ||||
| 		return -EINVAL; | ||||
| 		return -ENXIO; | ||||
| 
 | ||||
| 	mutex_lock(&kvm->slots_lock); | ||||
| 
 | ||||
|  | ||||
| @ -127,7 +127,7 @@ static int kvm_iommu_map_memslots(struct kvm *kvm) | ||||
| 	int i, r = 0; | ||||
| 	struct kvm_memslots *slots; | ||||
| 
 | ||||
| 	slots = rcu_dereference(kvm->memslots); | ||||
| 	slots = kvm_memslots(kvm); | ||||
| 
 | ||||
| 	for (i = 0; i < slots->nmemslots; i++) { | ||||
| 		r = kvm_iommu_map_pages(kvm, &slots->memslots[i]); | ||||
| @ -286,7 +286,7 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm) | ||||
| 	int i; | ||||
| 	struct kvm_memslots *slots; | ||||
| 
 | ||||
| 	slots = rcu_dereference(kvm->memslots); | ||||
| 	slots = kvm_memslots(kvm); | ||||
| 
 | ||||
| 	for (i = 0; i < slots->nmemslots; i++) { | ||||
| 		kvm_iommu_put_pages(kvm, slots->memslots[i].base_gfn, | ||||
|  | ||||
| @ -422,9 +422,6 @@ static struct kvm *kvm_create_vm(void) | ||||
| 	spin_lock(&kvm_lock); | ||||
| 	list_add(&kvm->vm_list, &vm_list); | ||||
| 	spin_unlock(&kvm_lock); | ||||
| #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET | ||||
| 	kvm_coalesced_mmio_init(kvm); | ||||
| #endif | ||||
| out: | ||||
| 	return kvm; | ||||
| 
 | ||||
| @ -560,6 +557,10 @@ int __kvm_set_memory_region(struct kvm *kvm, | ||||
| 	base_gfn = mem->guest_phys_addr >> PAGE_SHIFT; | ||||
| 	npages = mem->memory_size >> PAGE_SHIFT; | ||||
| 
 | ||||
| 	r = -EINVAL; | ||||
| 	if (npages > KVM_MEM_MAX_NR_PAGES) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if (!npages) | ||||
| 		mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES; | ||||
| 
 | ||||
| @ -833,7 +834,7 @@ EXPORT_SYMBOL_GPL(kvm_is_error_hva); | ||||
| struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn) | ||||
| { | ||||
| 	int i; | ||||
| 	struct kvm_memslots *slots = rcu_dereference(kvm->memslots); | ||||
| 	struct kvm_memslots *slots = kvm_memslots(kvm); | ||||
| 
 | ||||
| 	for (i = 0; i < slots->nmemslots; ++i) { | ||||
| 		struct kvm_memory_slot *memslot = &slots->memslots[i]; | ||||
| @ -855,7 +856,7 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) | ||||
| int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn) | ||||
| { | ||||
| 	int i; | ||||
| 	struct kvm_memslots *slots = rcu_dereference(kvm->memslots); | ||||
| 	struct kvm_memslots *slots = kvm_memslots(kvm); | ||||
| 
 | ||||
| 	gfn = unalias_gfn_instantiation(kvm, gfn); | ||||
| 	for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { | ||||
| @ -899,7 +900,7 @@ out: | ||||
| int memslot_id(struct kvm *kvm, gfn_t gfn) | ||||
| { | ||||
| 	int i; | ||||
| 	struct kvm_memslots *slots = rcu_dereference(kvm->memslots); | ||||
| 	struct kvm_memslots *slots = kvm_memslots(kvm); | ||||
| 	struct kvm_memory_slot *memslot = NULL; | ||||
| 
 | ||||
| 	gfn = unalias_gfn(kvm, gfn); | ||||
| @ -914,6 +915,11 @@ int memslot_id(struct kvm *kvm, gfn_t gfn) | ||||
| 	return memslot - slots->memslots; | ||||
| } | ||||
| 
 | ||||
| static unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn) | ||||
| { | ||||
| 	return slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE; | ||||
| } | ||||
| 
 | ||||
| unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) | ||||
| { | ||||
| 	struct kvm_memory_slot *slot; | ||||
| @ -922,7 +928,7 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) | ||||
| 	slot = gfn_to_memslot_unaliased(kvm, gfn); | ||||
| 	if (!slot || slot->flags & KVM_MEMSLOT_INVALID) | ||||
| 		return bad_hva(); | ||||
| 	return (slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE); | ||||
| 	return gfn_to_hva_memslot(slot, gfn); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(gfn_to_hva); | ||||
| 
 | ||||
| @ -972,11 +978,6 @@ pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn) | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(gfn_to_pfn); | ||||
| 
 | ||||
| static unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn) | ||||
| { | ||||
| 	return (slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE); | ||||
| } | ||||
| 
 | ||||
| pfn_t gfn_to_pfn_memslot(struct kvm *kvm, | ||||
| 			 struct kvm_memory_slot *slot, gfn_t gfn) | ||||
| { | ||||
| @ -1190,13 +1191,8 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn) | ||||
| 	memslot = gfn_to_memslot_unaliased(kvm, gfn); | ||||
| 	if (memslot && memslot->dirty_bitmap) { | ||||
| 		unsigned long rel_gfn = gfn - memslot->base_gfn; | ||||
| 		unsigned long *p = memslot->dirty_bitmap + | ||||
| 					rel_gfn / BITS_PER_LONG; | ||||
| 		int offset = rel_gfn % BITS_PER_LONG; | ||||
| 
 | ||||
| 		/* avoid RMW */ | ||||
| 		if (!generic_test_le_bit(offset, p)) | ||||
| 			generic___set_le_bit(offset, p); | ||||
| 		generic___set_le_bit(rel_gfn, memslot->dirty_bitmap); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -1609,7 +1605,6 @@ static long kvm_vm_ioctl(struct file *filp, | ||||
| 		r = -EFAULT; | ||||
| 		if (copy_from_user(&zone, argp, sizeof zone)) | ||||
| 			goto out; | ||||
| 		r = -ENXIO; | ||||
| 		r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone); | ||||
| 		if (r) | ||||
| 			goto out; | ||||
| @ -1621,7 +1616,6 @@ static long kvm_vm_ioctl(struct file *filp, | ||||
| 		r = -EFAULT; | ||||
| 		if (copy_from_user(&zone, argp, sizeof zone)) | ||||
| 			goto out; | ||||
| 		r = -ENXIO; | ||||
| 		r = kvm_vm_ioctl_unregister_coalesced_mmio(kvm, &zone); | ||||
| 		if (r) | ||||
| 			goto out; | ||||
| @ -1755,12 +1749,19 @@ static struct file_operations kvm_vm_fops = { | ||||
| 
 | ||||
| static int kvm_dev_ioctl_create_vm(void) | ||||
| { | ||||
| 	int fd; | ||||
| 	int fd, r; | ||||
| 	struct kvm *kvm; | ||||
| 
 | ||||
| 	kvm = kvm_create_vm(); | ||||
| 	if (IS_ERR(kvm)) | ||||
| 		return PTR_ERR(kvm); | ||||
| #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET | ||||
| 	r = kvm_coalesced_mmio_init(kvm); | ||||
| 	if (r < 0) { | ||||
| 		kvm_put_kvm(kvm); | ||||
| 		return r; | ||||
| 	} | ||||
| #endif | ||||
| 	fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, O_RDWR); | ||||
| 	if (fd < 0) | ||||
| 		kvm_put_kvm(kvm); | ||||
| @ -1928,11 +1929,6 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, | ||||
| 		       cpu); | ||||
| 		hardware_disable(NULL); | ||||
| 		break; | ||||
| 	case CPU_UP_CANCELED: | ||||
| 		printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n", | ||||
| 		       cpu); | ||||
| 		smp_call_function_single(cpu, hardware_disable, NULL, 1); | ||||
| 		break; | ||||
| 	case CPU_ONLINE: | ||||
| 		printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n", | ||||
| 		       cpu); | ||||
| @ -1991,7 +1987,9 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | ||||
| 		     int len, const void *val) | ||||
| { | ||||
| 	int i; | ||||
| 	struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]); | ||||
| 	struct kvm_io_bus *bus; | ||||
| 
 | ||||
| 	bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); | ||||
| 	for (i = 0; i < bus->dev_count; i++) | ||||
| 		if (!kvm_iodevice_write(bus->devs[i], addr, len, val)) | ||||
| 			return 0; | ||||
| @ -2003,8 +2001,9 @@ int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | ||||
| 		    int len, void *val) | ||||
| { | ||||
| 	int i; | ||||
| 	struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]); | ||||
| 	struct kvm_io_bus *bus; | ||||
| 
 | ||||
| 	bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); | ||||
| 	for (i = 0; i < bus->dev_count; i++) | ||||
| 		if (!kvm_iodevice_read(bus->devs[i], addr, len, val)) | ||||
| 			return 0; | ||||
| @ -2179,7 +2178,7 @@ static void kvm_sched_out(struct preempt_notifier *pn, | ||||
| 	kvm_arch_vcpu_put(vcpu); | ||||
| } | ||||
| 
 | ||||
| int kvm_init(void *opaque, unsigned int vcpu_size, | ||||
| int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, | ||||
| 		  struct module *module) | ||||
| { | ||||
| 	int r; | ||||
| @ -2229,8 +2228,9 @@ int kvm_init(void *opaque, unsigned int vcpu_size, | ||||
| 		goto out_free_4; | ||||
| 
 | ||||
| 	/* A kmem cache lets us meet the alignment requirements of fx_save. */ | ||||
| 	kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size, | ||||
| 					   __alignof__(struct kvm_vcpu), | ||||
| 	if (!vcpu_align) | ||||
| 		vcpu_align = __alignof__(struct kvm_vcpu); | ||||
| 	kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size, vcpu_align, | ||||
| 					   0, NULL); | ||||
| 	if (!kvm_vcpu_cache) { | ||||
| 		r = -ENOMEM; | ||||
| @ -2279,7 +2279,6 @@ EXPORT_SYMBOL_GPL(kvm_init); | ||||
| 
 | ||||
| void kvm_exit(void) | ||||
| { | ||||
| 	tracepoint_synchronize_unregister(); | ||||
| 	kvm_exit_debug(); | ||||
| 	misc_deregister(&kvm_dev); | ||||
| 	kmem_cache_destroy(kvm_vcpu_cache); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user