static int __diag_ipl_functions(struct kvm_vcpu *vcpu) { unsigned int reg = vcpu->arch.sie_block->ipa & 0xf; unsigned long subcode = vcpu->arch.guest_gprs[reg] & 0xffff; VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode); switch (subcode) { case 3: vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; break; case 4: vcpu->run->s390_reset_flags = 0; break; default: return -EOPNOTSUPP; } atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM; vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL; vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT; vcpu->run->exit_reason = KVM_EXIT_S390_RESET; VCPU_EVENT(vcpu, 3, "requesting userspace resets %llx", vcpu->run->s390_reset_flags); return -EREMOTE; }
static int __sigp_restart(struct kvm_vcpu *vcpu, u16 cpu_addr) { struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; struct kvm_s390_local_interrupt *li; int rc = SIGP_CC_ORDER_CODE_ACCEPTED; if (cpu_addr >= KVM_MAX_VCPUS) return SIGP_CC_NOT_OPERATIONAL; spin_lock(&fi->lock); li = fi->local_int[cpu_addr]; if (li == NULL) { rc = SIGP_CC_NOT_OPERATIONAL; goto out; } spin_lock_bh(&li->lock); if (li->action_bits & ACTION_STOP_ON_STOP) rc = SIGP_CC_BUSY; else VCPU_EVENT(vcpu, 4, "sigp restart %x to handle userspace", cpu_addr); spin_unlock_bh(&li->lock); out: spin_unlock(&fi->lock); return rc; }
static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg) { int rc; struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; if (cpu_addr >= KVM_MAX_VCPUS) return SIGP_CC_NOT_OPERATIONAL; spin_lock(&fi->lock); if (fi->local_int[cpu_addr] == NULL) rc = SIGP_CC_NOT_OPERATIONAL; else { if (atomic_read(fi->local_int[cpu_addr]->cpuflags) & CPUSTAT_RUNNING) { /* running */ rc = SIGP_CC_ORDER_CODE_ACCEPTED; } else { /* not running */ *reg &= 0xffffffff00000000UL; *reg |= SIGP_STATUS_NOT_RUNNING; rc = SIGP_CC_STATUS_STORED; } } spin_unlock(&fi->lock); VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x", cpu_addr, rc); return rc; }
static int handle_store_prefix(struct kvm_vcpu *vcpu) { u64 operand2; u32 address; vcpu->stat.instruction_stpx++; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); operand2 = kvm_s390_get_base_disp_s(vcpu); /* must be word boundary */ if (operand2 & 3) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); address = vcpu->arch.sie_block->prefix; address = address & 0x7fffe000u; /* get the value */ if (put_guest(vcpu, address, (u32 __user *)operand2)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); VCPU_EVENT(vcpu, 5, "storing prefix to %x", address); trace_kvm_s390_handle_prefix(vcpu, 0, address); return 0; }
static int handle_store_cpu_address(struct kvm_vcpu *vcpu) { int base2 = vcpu->arch.sie_block->ipb >> 28; int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); u64 useraddr; int rc; vcpu->stat.instruction_stap++; useraddr = disp2; if (base2) useraddr += vcpu->arch.guest_gprs[base2]; if (useraddr & 1) { kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); goto out; } rc = put_guest_u16(vcpu, useraddr, vcpu->vcpu_id); if (rc == -EFAULT) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); out: return 0; }
static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, unsigned long *reg) { struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; int rc; if (cpu_addr >= KVM_MAX_VCPUS) return 3; /* not operational */ spin_lock(&fi->lock); if (fi->local_int[cpu_addr] == NULL) rc = 3; /* not operational */ else if (atomic_read(fi->local_int[cpu_addr]->cpuflags) & CPUSTAT_RUNNING) { *reg &= 0xffffffff00000000UL; rc = 1; /* status stored */ } else { *reg &= 0xffffffff00000000UL; *reg |= SIGP_STAT_STOPPED; rc = 1; /* status stored */ } spin_unlock(&fi->lock); VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc); return rc; }
static int handle_skey(struct kvm_vcpu *vcpu) { vcpu->stat.instruction_storage_key++; vcpu->arch.sie_block->gpsw.addr -= 4; VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation"); return 0; }
static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg) { struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; int rc; if (cpu_addr >= KVM_MAX_VCPUS) return SIGP_CC_NOT_OPERATIONAL; spin_lock(&fi->lock); if (fi->local_int[cpu_addr] == NULL) rc = SIGP_CC_NOT_OPERATIONAL; else if (!(atomic_read(fi->local_int[cpu_addr]->cpuflags) & (CPUSTAT_ECALL_PEND | CPUSTAT_STOPPED))) rc = SIGP_CC_ORDER_CODE_ACCEPTED; else { *reg &= 0xffffffff00000000UL; if (atomic_read(fi->local_int[cpu_addr]->cpuflags) & CPUSTAT_ECALL_PEND) *reg |= SIGP_STATUS_EXT_CALL_PENDING; if (atomic_read(fi->local_int[cpu_addr]->cpuflags) & CPUSTAT_STOPPED) *reg |= SIGP_STATUS_STOPPED; rc = SIGP_CC_STATUS_STORED; } spin_unlock(&fi->lock); VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc); return rc; }
static int handle_stidp(struct kvm_vcpu *vcpu) { int base2 = vcpu->arch.sie_block->ipb >> 28; int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); u64 operand2; int rc; vcpu->stat.instruction_stidp++; operand2 = disp2; if (base2) operand2 += vcpu->arch.guest_gprs[base2]; if (operand2 & 7) { kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); goto out; } rc = put_guest_u64(vcpu, operand2, vcpu->arch.stidp_data); if (rc == -EFAULT) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } VCPU_EVENT(vcpu, 5, "%s", "store cpu id"); out: return 0; }
static int handle_set_prefix(struct kvm_vcpu *vcpu) { u64 operand2; u32 address = 0; u8 tmp; vcpu->stat.instruction_spx++; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); operand2 = kvm_s390_get_base_disp_s(vcpu); /* must be word boundary */ if (operand2 & 3) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); /* get the value */ if (get_guest(vcpu, address, (u32 __user *) operand2)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); address = address & 0x7fffe000u; /* make sure that the new value is valid memory */ if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || (copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1))) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); kvm_s390_set_prefix(vcpu, address); VCPU_EVENT(vcpu, 5, "setting prefix to %x", address); trace_kvm_s390_handle_prefix(vcpu, 1, address); return 0; }
static int handle_stsi(struct kvm_vcpu *vcpu) { int fc = (vcpu->arch.guest_gprs[0] & 0xf0000000) >> 28; int sel1 = vcpu->arch.guest_gprs[0] & 0xff; int sel2 = vcpu->arch.guest_gprs[1] & 0xffff; int base2 = vcpu->arch.sie_block->ipb >> 28; int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); u64 operand2; unsigned long mem; vcpu->stat.instruction_stsi++; VCPU_EVENT(vcpu, 4, "stsi: fc: %x sel1: %x sel2: %x", fc, sel1, sel2); operand2 = disp2; if (base2) operand2 += vcpu->arch.guest_gprs[base2]; if (operand2 & 0xfff && fc > 0) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); switch (fc) { case 0: vcpu->arch.guest_gprs[0] = 3 << 28; vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); return 0; case 1: /* same handling for 1 and 2 */ case 2: mem = get_zeroed_page(GFP_KERNEL); if (!mem) goto out_fail; if (stsi((void *) mem, fc, sel1, sel2) == -ENOSYS) goto out_mem; break; case 3: if (sel1 != 2 || sel2 != 2) goto out_fail; mem = get_zeroed_page(GFP_KERNEL); if (!mem) goto out_fail; handle_stsi_3_2_2(vcpu, (void *) mem); break; default: goto out_fail; } if (copy_to_guest_absolute(vcpu, operand2, (void *) mem, PAGE_SIZE)) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out_mem; } free_page(mem); vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); vcpu->arch.guest_gprs[0] = 0; return 0; out_mem: free_page(mem); out_fail: /* condition code 3 */ vcpu->arch.sie_block->gpsw.mask |= 3ul << 44; return 0; }
static int handle_io_inst(struct kvm_vcpu *vcpu) { VCPU_EVENT(vcpu, 4, "%s", "I/O instruction"); if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); if (vcpu->kvm->arch.css_support) { /* * Most I/O instructions will be handled by userspace. * Exceptions are tpi and the interrupt portion of tsch. */ if (vcpu->arch.sie_block->ipa == 0xb236) return handle_tpi(vcpu); if (vcpu->arch.sie_block->ipa == 0xb235) return handle_tsch(vcpu); /* Handle in userspace. */ return -EOPNOTSUPP; } else { /* * Set condition code 3 to stop the guest from issueing channel * I/O instructions. */ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; return 0; } }
static int handle_store_prefix(struct kvm_vcpu *vcpu) { int base2 = vcpu->arch.sie_block->ipb >> 28; int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); u64 operand2; u32 address; vcpu->stat.instruction_stpx++; operand2 = disp2; if (base2) operand2 += vcpu->arch.guest_gprs[base2]; /* must be word boundary */ if (operand2 & 3) { kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); goto out; } address = vcpu->arch.sie_block->prefix; address = address & 0x7fffe000u; /* get the value */ if (put_guest_u32(vcpu, operand2, address)) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } VCPU_EVENT(vcpu, 5, "storing prefix to %x", address); out: return 0; }
static int handle_store_cpu_address(struct kvm_vcpu *vcpu) { u64 useraddr; int rc; vcpu->stat.instruction_stap++; useraddr = kvm_s390_get_base_disp_s(vcpu); if (useraddr & 1) { kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); goto out; } rc = put_guest_u16(vcpu, useraddr, vcpu->vcpu_id); if (rc == -EFAULT) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); trace_kvm_s390_handle_stap(vcpu, useraddr); out: return 0; }
static int handle_store_prefix(struct kvm_vcpu *vcpu) { u64 operand2; u32 address; vcpu->stat.instruction_stpx++; operand2 = kvm_s390_get_base_disp_s(vcpu); /* must be word boundary */ if (operand2 & 3) { kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); goto out; } address = vcpu->arch.sie_block->prefix; address = address & 0x7fffe000u; /* get the value */ if (put_guest_u32(vcpu, operand2, address)) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } VCPU_EVENT(vcpu, 5, "storing prefix to %x", address); trace_kvm_s390_handle_prefix(vcpu, 0, address); out: return 0; }
static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, u64 *reg) { struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; struct kvm_s390_local_interrupt *li = NULL; struct kvm_s390_interrupt_info *inti; int rc; u8 tmp; /* make sure that the new value is valid memory */ address = address & 0x7fffe000u; if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1)) { *reg &= 0xffffffff00000000UL; *reg |= SIGP_STATUS_INVALID_PARAMETER; return SIGP_CC_STATUS_STORED; } inti = kzalloc(sizeof(*inti), GFP_KERNEL); if (!inti) return SIGP_CC_BUSY; spin_lock(&fi->lock); if (cpu_addr < KVM_MAX_VCPUS) li = fi->local_int[cpu_addr]; if (li == NULL) { *reg &= 0xffffffff00000000UL; *reg |= SIGP_STATUS_INCORRECT_STATE; rc = SIGP_CC_STATUS_STORED; kfree(inti); goto out_fi; } spin_lock_bh(&li->lock); /* cpu must be in stopped state */ if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) { *reg &= 0xffffffff00000000UL; *reg |= SIGP_STATUS_INCORRECT_STATE; rc = SIGP_CC_STATUS_STORED; kfree(inti); goto out_li; } inti->type = KVM_S390_SIGP_SET_PREFIX; inti->prefix.address = address; list_add_tail(&inti->list, &li->list); atomic_set(&li->active, 1); if (waitqueue_active(&li->wq)) wake_up_interruptible(&li->wq); rc = SIGP_CC_ORDER_CODE_ACCEPTED; VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address); out_li: spin_unlock_bh(&li->lock); out_fi: spin_unlock(&fi->lock); return rc; }
static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, unsigned long *reg) { struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; struct kvm_s390_local_interrupt *li = NULL; struct kvm_s390_interrupt_info *inti; int rc; u8 tmp; /* make sure that the new value is valid memory */ address = address & 0x7fffe000u; if ((copy_from_guest(vcpu, &tmp, (u64) (address + vcpu->arch.sie_block->gmsor) , 1)) || (copy_from_guest(vcpu, &tmp, (u64) (address + vcpu->arch.sie_block->gmsor + PAGE_SIZE), 1))) { *reg |= SIGP_STAT_INVALID_PARAMETER; return 1; /* invalid parameter */ } inti = kzalloc(sizeof(*inti), GFP_KERNEL); if (!inti) return 2; /* busy */ spin_lock(&fi->lock); if (cpu_addr < KVM_MAX_VCPUS) li = fi->local_int[cpu_addr]; if (li == NULL) { rc = 1; /* incorrect state */ *reg &= SIGP_STAT_INCORRECT_STATE; kfree(inti); goto out_fi; } spin_lock_bh(&li->lock); /* cpu must be in stopped state */ if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) { rc = 1; /* incorrect state */ *reg &= SIGP_STAT_INCORRECT_STATE; kfree(inti); goto out_li; } inti->type = KVM_S390_SIGP_SET_PREFIX; inti->prefix.address = address; list_add_tail(&inti->list, &li->list); atomic_set(&li->active, 1); if (waitqueue_active(&li->wq)) wake_up_interruptible(&li->wq); rc = 0; /* order accepted */ VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address); out_li: spin_unlock_bh(&li->lock); out_fi: spin_unlock(&fi->lock); return rc; }
static int __diag_time_slice_end(struct kvm_vcpu *vcpu) { VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); vcpu->stat.diagnose_44++; vcpu_put(vcpu); yield(); vcpu_load(vcpu); return 0; }
static int handle_chsc(struct kvm_vcpu *vcpu) { vcpu->stat.instruction_chsc++; VCPU_EVENT(vcpu, 4, "%s", "channel subsystem call - CC3"); /* condition code 3 */ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; return 0; }
static int handle_stsch(struct kvm_vcpu *vcpu) { vcpu->stat.instruction_stsch++; VCPU_EVENT(vcpu, 4, "%s", "store subchannel - CC3"); /* condition code 3 */ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; return 0; }
static int handle_skey(struct kvm_vcpu *vcpu) { vcpu->stat.instruction_storage_key++; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); vcpu->arch.sie_block->gpsw.addr = __rewind_psw(vcpu->arch.sie_block->gpsw, 4); VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation"); return 0; }
static int handle_stfl(struct kvm_vcpu *vcpu) { int rc; vcpu->stat.instruction_stfl++; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list), vfacilities, 4); if (rc) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); VCPU_EVENT(vcpu, 5, "store facility list value %x", *(unsigned int *) vfacilities); trace_kvm_s390_handle_stfl(vcpu, *(unsigned int *) vfacilities); return 0; }
static int handle_stfl(struct kvm_vcpu *vcpu) { unsigned int facility_list = stfl(); int rc; vcpu->stat.instruction_stfl++; /* only pass the facility bits, which we can handle */ facility_list &= 0xff00fff3; rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list), &facility_list, sizeof(facility_list)); if (rc == -EFAULT) kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); else VCPU_EVENT(vcpu, 5, "store facility list value %x", facility_list); return 0; }
static int handle_set_prefix(struct kvm_vcpu *vcpu) { int base2 = vcpu->arch.sie_block->ipb >> 28; int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); u64 operand2; u32 address = 0; u8 tmp; vcpu->stat.instruction_spx++; operand2 = disp2; if (base2) operand2 += vcpu->arch.guest_gprs[base2]; /* must be word boundary */ if (operand2 & 3) { kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); goto out; } /* get the value */ if (get_guest_u32(vcpu, operand2, &address)) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } address = address & 0x7fffe000u; /* make sure that the new value is valid memory */ if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || (copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1))) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } vcpu->arch.sie_block->prefix = address; vcpu->arch.sie_block->ihcpu = 0xffff; VCPU_EVENT(vcpu, 5, "setting prefix to %x", address); out: return 0; }
static int handle_stidp(struct kvm_vcpu *vcpu) { u64 operand2; vcpu->stat.instruction_stidp++; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); operand2 = kvm_s390_get_base_disp_s(vcpu); if (operand2 & 7) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); if (put_guest(vcpu, vcpu->arch.stidp_data, (u64 __user *)operand2)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); VCPU_EVENT(vcpu, 5, "%s", "store cpu id"); return 0; }
static int handle_stfl(struct kvm_vcpu *vcpu) { unsigned int facility_list; int rc; vcpu->stat.instruction_stfl++; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); /* only pass the facility bits, which we can handle */ facility_list = S390_lowcore.stfl_fac_list & 0xff82fff3; rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list), &facility_list, sizeof(facility_list)); if (rc) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); VCPU_EVENT(vcpu, 5, "store facility list value %x", facility_list); trace_kvm_s390_handle_stfl(vcpu, facility_list); return 0; }
static int handle_store_cpu_address(struct kvm_vcpu *vcpu) { u64 useraddr; vcpu->stat.instruction_stap++; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); useraddr = kvm_s390_get_base_disp_s(vcpu); if (useraddr & 1) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); if (put_guest(vcpu, vcpu->vcpu_id, (u16 __user *)useraddr)) return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); trace_kvm_s390_handle_stap(vcpu, useraddr); return 0; }
static int handle_lctlg(struct kvm_vcpu *vcpu) { int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; int reg3 = vcpu->arch.sie_block->ipa & 0x000f; int base2 = vcpu->arch.sie_block->ipb >> 28; int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) + ((vcpu->arch.sie_block->ipb & 0xff00) << 4); u64 useraddr; int reg, rc; vcpu->stat.instruction_lctlg++; if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f) return -ENOTSUPP; useraddr = disp2; if (base2) useraddr += vcpu->arch.guest_gprs[base2]; if (useraddr & 7) return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); reg = reg1; VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, disp2); do { rc = get_guest_u64(vcpu, useraddr, &vcpu->arch.sie_block->gcr[reg]); if (rc == -EFAULT) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); break; } useraddr += 8; if (reg == reg3) break; reg = (reg + 1) % 16; } while (1); return 0; }
static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store) { struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; struct kvm_s390_local_interrupt *li; struct kvm_s390_interrupt_info *inti; int rc; if (cpu_addr >= KVM_MAX_VCPUS) return 3; /* not operational */ inti = kzalloc(sizeof(*inti), GFP_KERNEL); if (!inti) return -ENOMEM; inti->type = KVM_S390_SIGP_STOP; spin_lock_bh(&fi->lock); li = fi->local_int[cpu_addr]; if (li == NULL) { rc = 3; /* not operational */ kfree(inti); goto unlock; } spin_lock_bh(&li->lock); list_add_tail(&inti->list, &li->list); atomic_set(&li->active, 1); atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags); if (store) li->action_bits |= ACTION_STORE_ON_STOP; li->action_bits |= ACTION_STOP_ON_STOP; if (waitqueue_active(&li->wq)) wake_up_interruptible(&li->wq); spin_unlock_bh(&li->lock); rc = 0; /* order accepted */ unlock: spin_unlock_bh(&fi->lock); VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr); return rc; }
static int handle_set_prefix(struct kvm_vcpu *vcpu) { u64 operand2; u32 address = 0; u8 tmp; vcpu->stat.instruction_spx++; operand2 = kvm_s390_get_base_disp_s(vcpu); /* must be word boundary */ if (operand2 & 3) { kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); goto out; } /* get the value */ if (get_guest_u32(vcpu, operand2, &address)) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } address = address & 0x7fffe000u; /* make sure that the new value is valid memory */ if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || (copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1))) { kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out; } kvm_s390_set_prefix(vcpu, address); VCPU_EVENT(vcpu, 5, "setting prefix to %x", address); trace_kvm_s390_handle_prefix(vcpu, 1, address); out: return 0; }