Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 197697
b: refs/heads/master
c: 7972995
h: refs/heads/master
i:
  197695: f449065
v: v3
  • Loading branch information
Gleb Natapov authored and Avi Kivity committed May 17, 2010
1 parent 0e71275 commit f18d06c
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 231 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: cf8f70bfe38b326bb80b10f76d6544f571040229
refs/heads/master: 7972995b0c346de76fe260ce0fd6bcc8ffab724a
8 changes: 0 additions & 8 deletions trunk/arch/x86/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,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;
};

/*
Expand Down Expand Up @@ -591,9 +586,6 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
struct x86_emulate_ctxt;

int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short 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);
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);
Expand Down
48 changes: 15 additions & 33 deletions trunk/arch/x86/kvm/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ static u32 opcode_table[256] = {
0, 0, 0, 0,
/* 0x68 - 0x6F */
SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0,
SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */
SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */
DstDI | ByteOp | Mov | String, DstDI | Mov | String, /* insb, insw/insd */
SrcSI | ByteOp | ImplicitOps | String, SrcSI | ImplicitOps | String, /* outsb, outsw/outsd */
/* 0x70 - 0x77 */
SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
Expand Down Expand Up @@ -2615,47 +2615,29 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
break;
case 0x6c: /* insb */
case 0x6d: /* insw/insd */
c->dst.bytes = min(c->dst.bytes, 4u);
if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
(c->d & ByteOp) ? 1 : c->op_bytes)) {
c->dst.bytes)) {
kvm_inject_gp(ctxt->vcpu, 0);
goto done;
}
if (kvm_emulate_pio_string(ctxt->vcpu,
1,
(c->d & ByteOp) ? 1 : c->op_bytes,
c->rep_prefix ?
address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
(ctxt->eflags & EFLG_DF),
register_address(c, es_base(ctxt),
c->regs[VCPU_REGS_RDI]),
c->rep_prefix,
c->regs[VCPU_REGS_RDX]) == 0) {
c->eip = saved_eip;
return -1;
}
return 0;
if (!ops->pio_in_emulated(c->dst.bytes, c->regs[VCPU_REGS_RDX],
&c->dst.val, 1, ctxt->vcpu))
goto done; /* IO is needed, skip writeback */
break;
case 0x6e: /* outsb */
case 0x6f: /* outsw/outsd */
c->src.bytes = min(c->src.bytes, 4u);
if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
(c->d & ByteOp) ? 1 : c->op_bytes)) {
c->src.bytes)) {
kvm_inject_gp(ctxt->vcpu, 0);
goto done;
}
if (kvm_emulate_pio_string(ctxt->vcpu,
0,
(c->d & ByteOp) ? 1 : c->op_bytes,
c->rep_prefix ?
address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
(ctxt->eflags & EFLG_DF),
register_address(c,
seg_override_base(ctxt, c),
c->regs[VCPU_REGS_RSI]),
c->rep_prefix,
c->regs[VCPU_REGS_RDX]) == 0) {
c->eip = saved_eip;
return -1;
}
return 0;
ops->pio_out_emulated(c->src.bytes, c->regs[VCPU_REGS_RDX],
&c->src.val, 1, ctxt->vcpu);

c->dst.type = OP_NONE; /* nothing to writeback */
break;
case 0x70 ... 0x7f: /* jcc (short) */
if (test_cc(c->b, ctxt->eflags))
jmp_rel(c, c->src.val);
Expand Down
206 changes: 17 additions & 189 deletions trunk/arch/x86/kvm/x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -3150,18 +3150,17 @@ static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes,
return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
}

static int kvm_write_guest_virt_helper(gva_t addr, void *val,
static int kvm_write_guest_virt_system(gva_t addr, void *val,
unsigned int bytes,
struct kvm_vcpu *vcpu, u32 access,
struct kvm_vcpu *vcpu,
u32 *error)
{
void *data = val;
int r = X86EMUL_CONTINUE;

access |= PFERR_WRITE_MASK;

while (bytes) {
gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error);
gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr,
PFERR_WRITE_MASK, error);
unsigned offset = addr & (PAGE_SIZE-1);
unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
int ret;
Expand All @@ -3184,20 +3183,6 @@ static int kvm_write_guest_virt_helper(gva_t addr, void *val,
return r;
}

static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes,
struct kvm_vcpu *vcpu, u32 *error)
{
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, access, error);
}

static int kvm_write_guest_virt_system(gva_t addr, void *val,
unsigned int bytes,
struct kvm_vcpu *vcpu, u32 *error)
{
return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
}

static int emulator_read_emulated(unsigned long addr,
void *val,
unsigned int bytes,
Expand Down Expand Up @@ -3423,23 +3408,20 @@ static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
static int emulator_pio_in_emulated(int size, unsigned short port, void *val,
unsigned int count, struct kvm_vcpu *vcpu)
{
if (vcpu->arch.pio.cur_count)
if (vcpu->arch.pio.count)
goto data_avail;

trace_kvm_pio(1, port, size, 1);

vcpu->arch.pio.port = port;
vcpu->arch.pio.in = 1;
vcpu->arch.pio.string = 0;
vcpu->arch.pio.down = 0;
vcpu->arch.pio.rep = 0;
vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count;
vcpu->arch.pio.count = count;
vcpu->arch.pio.size = size;

if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
data_avail:
memcpy(val, vcpu->arch.pio_data, size * count);
vcpu->arch.pio.cur_count = 0;
vcpu->arch.pio.count = 0;
return 1;
}

Expand All @@ -3461,16 +3443,13 @@ static int emulator_pio_out_emulated(int size, unsigned short port,

vcpu->arch.pio.port = port;
vcpu->arch.pio.in = 0;
vcpu->arch.pio.string = 0;
vcpu->arch.pio.down = 0;
vcpu->arch.pio.rep = 0;
vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count;
vcpu->arch.pio.count = count;
vcpu->arch.pio.size = size;

memcpy(vcpu->arch.pio_data, val, size * count);

if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
vcpu->arch.pio.cur_count = 0;
vcpu->arch.pio.count = 0;
return 1;
}

Expand Down Expand Up @@ -3717,7 +3696,6 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
cache_all_regs(vcpu);

vcpu->mmio_is_write = 0;
vcpu->arch.pio.string = 0;

if (!(emulation_type & EMULTYPE_NO_DECODE)) {
int cs_db, cs_l;
Expand Down Expand Up @@ -3783,12 +3761,9 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
if (r == 0)
kvm_x86_ops->set_interrupt_shadow(vcpu, shadow_mask);

if (vcpu->arch.pio.string)
return EMULATE_DO_MMIO;

if (vcpu->arch.pio.cur_count && !vcpu->arch.pio.string) {
if (vcpu->arch.pio.count) {
if (!vcpu->arch.pio.in)
vcpu->arch.pio.cur_count = 0;
vcpu->arch.pio.count = 0;
return EMULATE_DO_MMIO;
}

Expand Down Expand Up @@ -3821,158 +3796,12 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
}
EXPORT_SYMBOL_GPL(emulate_instruction);

static int pio_copy_data(struct kvm_vcpu *vcpu)
{
void *p = vcpu->arch.pio_data;
gva_t q = vcpu->arch.pio.guest_gva;
unsigned bytes;
int ret;
u32 error_code;

bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count;
if (vcpu->arch.pio.in)
ret = kvm_write_guest_virt(q, p, bytes, vcpu, &error_code);
else
ret = kvm_read_guest_virt(q, p, bytes, vcpu, &error_code);

if (ret == X86EMUL_PROPAGATE_FAULT)
kvm_inject_page_fault(vcpu, q, error_code);

return ret;
}

int complete_pio(struct kvm_vcpu *vcpu)
{
struct kvm_pio_request *io = &vcpu->arch.pio;
long delta;
int r;
unsigned long val;

if (io->in) {
r = pio_copy_data(vcpu);
if (r)
goto out;
}

delta = 1;
if (io->rep) {
delta *= io->cur_count;
/*
* The size of the register should really depend on
* current address size.
*/
val = kvm_register_read(vcpu, VCPU_REGS_RCX);
val -= delta;
kvm_register_write(vcpu, VCPU_REGS_RCX, val);
}
if (io->down)
delta = -delta;
delta *= io->size;
if (io->in) {
val = kvm_register_read(vcpu, VCPU_REGS_RDI);
val += delta;
kvm_register_write(vcpu, VCPU_REGS_RDI, val);
} else {
val = kvm_register_read(vcpu, VCPU_REGS_RSI);
val += delta;
kvm_register_write(vcpu, VCPU_REGS_RSI, val);
}

out:
io->count -= io->cur_count;
io->cur_count = 0;

return 0;
}

static int pio_string_write(struct kvm_vcpu *vcpu)
{
struct kvm_pio_request *io = &vcpu->arch.pio;
void *pd = vcpu->arch.pio_data;
int i, r = 0;

for (i = 0; i < io->cur_count; i++) {
if (kvm_io_bus_write(vcpu->kvm, KVM_PIO_BUS,
io->port, io->size, pd)) {
r = -EOPNOTSUPP;
break;
}
pd += io->size;
}
return r;
}

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)
{
unsigned now, in_page;
int ret = 0;

trace_kvm_pio(!in, port, size, count);

vcpu->run->exit_reason = KVM_EXIT_IO;
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
vcpu->run->io.size = vcpu->arch.pio.size = size;
vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
vcpu->run->io.count = vcpu->arch.pio.count = vcpu->arch.pio.cur_count = count;
vcpu->run->io.port = vcpu->arch.pio.port = port;
vcpu->arch.pio.in = in;
vcpu->arch.pio.string = 1;
vcpu->arch.pio.down = down;
vcpu->arch.pio.rep = rep;

if (!count) {
kvm_x86_ops->skip_emulated_instruction(vcpu);
return 1;
}

if (!down)
in_page = PAGE_SIZE - offset_in_page(address);
else
in_page = offset_in_page(address) + size;
now = min(count, (unsigned long)in_page / size);
if (!now)
now = 1;
if (down) {
/*
* String I/O in reverse. Yuck. Kill the guest, fix later.
*/
pr_unimpl(vcpu, "guest string pio down\n");
kvm_inject_gp(vcpu, 0);
return 1;
}
vcpu->run->io.count = now;
vcpu->arch.pio.cur_count = now;

if (vcpu->arch.pio.cur_count == vcpu->arch.pio.count)
kvm_x86_ops->skip_emulated_instruction(vcpu);

vcpu->arch.pio.guest_gva = address;

if (!vcpu->arch.pio.in) {
/* string PIO write */
ret = pio_copy_data(vcpu);
if (ret == X86EMUL_PROPAGATE_FAULT)
return 1;
if (ret == 0 && !pio_string_write(vcpu)) {
complete_pio(vcpu);
if (vcpu->arch.pio.count == 0)
ret = 1;
}
}
/* no string PIO read support yet */

return ret;
}
EXPORT_SYMBOL_GPL(kvm_emulate_pio_string);

int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port)
{
unsigned long val = kvm_register_read(vcpu, VCPU_REGS_RAX);
int ret = emulator_pio_out_emulated(size, port, &val, 1, vcpu);
/* do not return to emulator after return from userspace */
vcpu->arch.pio.cur_count = 0;
vcpu->arch.pio.count = 0;
return ret;
}
EXPORT_SYMBOL_GPL(kvm_fast_pio_out);
Expand Down Expand Up @@ -4705,15 +4534,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (!irqchip_in_kernel(vcpu->kvm))
kvm_set_cr8(vcpu, kvm_run->cr8);

if (vcpu->arch.pio.cur_count) {
if (vcpu->arch.pio.count) {
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
if (!vcpu->arch.pio.string)
r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
else
r = complete_pio(vcpu);
r = emulate_instruction(vcpu, 0, 0, EMULTYPE_NO_DECODE);
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
if (r == EMULATE_DO_MMIO)
if (r == EMULATE_DO_MMIO) {
r = 0;
goto out;
}
}
if (vcpu->mmio_needed) {
memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
Expand Down

0 comments on commit f18d06c

Please sign in to comment.