Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 80694
b: refs/heads/master
c: f78e0e2
h: refs/heads/master
v: v3
  • Loading branch information
Sheng Yang authored and Avi Kivity committed Jan 30, 2008
1 parent 79caec0 commit 771ed56
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 31 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a03490ed29d2771c675d4d9c0ffe22e19a1757f3
refs/heads/master: f78e0e2ee498e8f847500b565792c7d7634dcf54
4 changes: 4 additions & 0 deletions trunk/drivers/kvm/kvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ struct kvm {
struct kvm_ioapic *vioapic;
int round_robin_prev_vcpu;
unsigned int tss_addr;
struct page *apic_access_page;
};

static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
Expand Down Expand Up @@ -522,6 +523,9 @@ int is_error_page(struct page *page);
int kvm_set_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
int user_alloc);
int __kvm_set_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
int user_alloc);
gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
void kvm_release_page(struct page *page);
Expand Down
56 changes: 39 additions & 17 deletions trunk/drivers/kvm/kvm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,10 +362,12 @@ EXPORT_SYMBOL_GPL(fx_init);
* space.
*
* Discontiguous memory is allowed, mostly for framebuffers.
*
* Must be called holding kvm->lock.
*/
int kvm_set_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
int user_alloc)
int __kvm_set_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
int user_alloc)
{
int r;
gfn_t base_gfn;
Expand All @@ -392,8 +394,6 @@ int kvm_set_memory_region(struct kvm *kvm,
if (!npages)
mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES;

mutex_lock(&kvm->lock);

new = old = *memslot;

new.base_gfn = base_gfn;
Expand All @@ -403,7 +403,7 @@ int kvm_set_memory_region(struct kvm *kvm,
/* Disallow changing a memory slot's size. */
r = -EINVAL;
if (npages && old.npages && npages != old.npages)
goto out_unlock;
goto out_free;

/* Check for overlaps */
r = -EEXIST;
Expand All @@ -414,7 +414,7 @@ int kvm_set_memory_region(struct kvm *kvm,
continue;
if (!((base_gfn + npages <= s->base_gfn) ||
(base_gfn >= s->base_gfn + s->npages)))
goto out_unlock;
goto out_free;
}

/* Free page dirty bitmap if unneeded */
Expand All @@ -428,7 +428,7 @@ int kvm_set_memory_region(struct kvm *kvm,
new.rmap = vmalloc(npages * sizeof(struct page *));

if (!new.rmap)
goto out_unlock;
goto out_free;

memset(new.rmap, 0, npages * sizeof(*new.rmap));

Expand All @@ -445,7 +445,7 @@ int kvm_set_memory_region(struct kvm *kvm,
up_write(&current->mm->mmap_sem);

if (IS_ERR((void *)new.userspace_addr))
goto out_unlock;
goto out_free;
}
} else {
if (!old.user_alloc && old.rmap) {
Expand All @@ -468,7 +468,7 @@ int kvm_set_memory_region(struct kvm *kvm,

new.dirty_bitmap = vmalloc(dirty_bytes);
if (!new.dirty_bitmap)
goto out_unlock;
goto out_free;
memset(new.dirty_bitmap, 0, dirty_bytes);
}

Expand Down Expand Up @@ -498,18 +498,28 @@ int kvm_set_memory_region(struct kvm *kvm,
kvm_mmu_slot_remove_write_access(kvm, mem->slot);
kvm_flush_remote_tlbs(kvm);

mutex_unlock(&kvm->lock);

kvm_free_physmem_slot(&old, &new);
return 0;

out_unlock:
mutex_unlock(&kvm->lock);
out_free:
kvm_free_physmem_slot(&new, &old);
out:
return r;

}
EXPORT_SYMBOL_GPL(__kvm_set_memory_region);

int kvm_set_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
int user_alloc)
{
int r;

mutex_lock(&kvm->lock);
r = __kvm_set_memory_region(kvm, mem, user_alloc);
mutex_unlock(&kvm->lock);
return r;
}
EXPORT_SYMBOL_GPL(kvm_set_memory_region);

int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
Expand Down Expand Up @@ -888,14 +898,21 @@ static int emulator_read_emulated(unsigned long addr,
memcpy(val, vcpu->mmio_data, bytes);
vcpu->mmio_read_completed = 0;
return X86EMUL_CONTINUE;
} else if (emulator_read_std(addr, val, bytes, vcpu)
== X86EMUL_CONTINUE)
return X86EMUL_CONTINUE;
}

gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);

/* For APIC access vmexit */
if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
goto mmio;

if (emulator_read_std(addr, val, bytes, vcpu)
== X86EMUL_CONTINUE)
return X86EMUL_CONTINUE;
if (gpa == UNMAPPED_GVA)
return X86EMUL_PROPAGATE_FAULT;

mmio:
/*
* Is this MMIO handled locally?
*/
Expand Down Expand Up @@ -938,9 +955,14 @@ static int emulator_write_emulated_onepage(unsigned long addr,
return X86EMUL_PROPAGATE_FAULT;
}

/* For APIC access vmexit */
if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
goto mmio;

if (emulator_write_phys(vcpu, gpa, val, bytes))
return X86EMUL_CONTINUE;

mmio:
/*
* Is this MMIO handled locally?
*/
Expand Down
117 changes: 104 additions & 13 deletions trunk/drivers/kvm/vmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ static struct vmcs_config {
u32 revision_id;
u32 pin_based_exec_ctrl;
u32 cpu_based_exec_ctrl;
u32 cpu_based_2nd_exec_ctrl;
u32 vmexit_ctrl;
u32 vmentry_ctrl;
} vmcs_config;
Expand Down Expand Up @@ -179,6 +180,29 @@ static inline int 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)
{
return (vmcs_config.cpu_based_exec_ctrl &
CPU_BASED_ACTIVATE_SECONDARY_CONTROLS);
}

static inline int vm_need_secondary_exec_ctrls(struct kvm *kvm)
{
return ((cpu_has_secondary_exec_ctrls()) && (irqchip_in_kernel(kvm)));
}

static inline int cpu_has_vmx_virtualize_apic_accesses(void)
{
return (vmcs_config.cpu_based_2nd_exec_ctrl &
SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
}

static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
{
return ((cpu_has_vmx_virtualize_apic_accesses()) &&
(irqchip_in_kernel(kvm)));
}

static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
{
int i;
Expand Down Expand Up @@ -918,6 +942,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
u32 min, opt;
u32 _pin_based_exec_control = 0;
u32 _cpu_based_exec_control = 0;
u32 _cpu_based_2nd_exec_control = 0;
u32 _vmexit_control = 0;
u32 _vmentry_control = 0;

Expand All @@ -935,11 +960,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
CPU_BASED_USE_IO_BITMAPS |
CPU_BASED_MOV_DR_EXITING |
CPU_BASED_USE_TSC_OFFSETING;
#ifdef CONFIG_X86_64
opt = CPU_BASED_TPR_SHADOW;
#else
opt = 0;
#endif
opt = CPU_BASED_TPR_SHADOW |
CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
&_cpu_based_exec_control) < 0)
return -EIO;
Expand All @@ -948,6 +970,18 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
_cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING &
~CPU_BASED_CR8_STORE_EXITING;
#endif
if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) {
min = 0;
opt = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS2,
&_cpu_based_2nd_exec_control) < 0)
return -EIO;
}
#ifndef CONFIG_X86_64
if (!(_cpu_based_2nd_exec_control &
SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES))
_cpu_based_exec_control &= ~CPU_BASED_TPR_SHADOW;
#endif

min = 0;
#ifdef CONFIG_X86_64
Expand Down Expand Up @@ -985,6 +1019,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)

vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control;
vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control;
vmcs_conf->cpu_based_2nd_exec_ctrl = _cpu_based_2nd_exec_control;
vmcs_conf->vmexit_ctrl = _vmexit_control;
vmcs_conf->vmentry_ctrl = _vmentry_control;

Expand Down Expand Up @@ -1427,6 +1462,27 @@ static void seg_setup(int seg)
vmcs_write32(sf->ar_bytes, 0x93);
}

static int alloc_apic_access_page(struct kvm *kvm)
{
struct kvm_userspace_memory_region kvm_userspace_mem;
int r = 0;

mutex_lock(&kvm->lock);
if (kvm->apic_access_page)
goto out;
kvm_userspace_mem.slot = APIC_ACCESS_PAGE_PRIVATE_MEMSLOT;
kvm_userspace_mem.flags = 0;
kvm_userspace_mem.guest_phys_addr = 0xfee00000ULL;
kvm_userspace_mem.memory_size = PAGE_SIZE;
r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, 0);
if (r)
goto out;
kvm->apic_access_page = gfn_to_page(kvm, 0xfee00);
out:
mutex_unlock(&kvm->lock);
return r;
}

/*
* Sets up the vmcs for emulated real mode.
*/
Expand Down Expand Up @@ -1458,8 +1514,14 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
CPU_BASED_CR8_LOAD_EXITING;
#endif
}
if (!vm_need_secondary_exec_ctrls(vmx->vcpu.kvm))
exec_control &= ~CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);

if (vm_need_secondary_exec_ctrls(vmx->vcpu.kvm))
vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
vmcs_config.cpu_based_2nd_exec_ctrl);

vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, !!bypass_guest_pf);
vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, !!bypass_guest_pf);
vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */
Expand Down Expand Up @@ -1528,6 +1590,10 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);

if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm))
if (alloc_apic_access_page(vmx->vcpu.kvm) != 0)
return -ENOMEM;

return 0;
}

Expand Down Expand Up @@ -1616,13 +1682,17 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)

vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */

#ifdef CONFIG_X86_64
vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
if (vm_need_tpr_shadow(vmx->vcpu.kvm))
vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
page_to_phys(vmx->vcpu.apic->regs_page));
vmcs_write32(TPR_THRESHOLD, 0);
#endif
if (cpu_has_vmx_tpr_shadow()) {
vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
if (vm_need_tpr_shadow(vmx->vcpu.kvm))
vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
page_to_phys(vmx->vcpu.apic->regs_page));
vmcs_write32(TPR_THRESHOLD, 0);
}

if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm))
vmcs_write64(APIC_ACCESS_ADDR,
page_to_phys(vmx->vcpu.kvm->apic_access_page));

vmx->vcpu.cr0 = 0x60000010;
vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); /* enter rmode */
Expand Down Expand Up @@ -2094,6 +2164,26 @@ static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}

static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
u64 exit_qualification;
enum emulation_result er;
unsigned long offset;

exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
offset = exit_qualification & 0xffful;

er = emulate_instruction(vcpu, kvm_run, 0, 0, 0);

if (er != EMULATE_DONE) {
printk(KERN_ERR
"Fail to handle apic access vmexit! Offset is 0x%lx\n",
offset);
return -ENOTSUPP;
}
return 1;
}

/*
* The exit handlers return 1 if the exit was handled fully and guest execution
* may resume. Otherwise they set the kvm_run parameter to indicate what needs
Expand All @@ -2113,7 +2203,8 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
[EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window,
[EXIT_REASON_HLT] = handle_halt,
[EXIT_REASON_VMCALL] = handle_vmcall,
[EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold
[EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold,
[EXIT_REASON_APIC_ACCESS] = handle_apic_access,
};

static const int kvm_vmx_max_exit_handlers =
Expand Down
5 changes: 5 additions & 0 deletions trunk/drivers/kvm/vmx.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ enum vmcs_field {
TSC_OFFSET_HIGH = 0x00002011,
VIRTUAL_APIC_PAGE_ADDR = 0x00002012,
VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013,
APIC_ACCESS_ADDR = 0x00002014,
APIC_ACCESS_ADDR_HIGH = 0x00002015,
VMCS_LINK_POINTER = 0x00002800,
VMCS_LINK_POINTER_HIGH = 0x00002801,
GUEST_IA32_DEBUGCTL = 0x00002802,
Expand Down Expand Up @@ -214,6 +216,7 @@ enum vmcs_field {
#define EXIT_REASON_MSR_WRITE 32
#define EXIT_REASON_MWAIT_INSTRUCTION 36
#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
#define EXIT_REASON_APIC_ACCESS 44

/*
* Interruption-information format
Expand Down Expand Up @@ -307,4 +310,6 @@ enum vmcs_field {
#define MSR_IA32_FEATURE_CONTROL_LOCKED 0x1
#define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED 0x4

#define APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 9

#endif

0 comments on commit 771ed56

Please sign in to comment.