/* * kvm guest debug support * * Copyright IBM Corp. 2014 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License (version 2 only) * as published by the Free Software Foundation. * * Author(s): David Hildenbrand */ #include #include #include "kvm-s390.h" #include "gaccess.h" /* * Extends the address range given by *start and *stop to include the address * range starting with estart and the length len. Takes care of overflowing * intervals and tries to minimize the overall intervall size. */ static void extend_address_range(u64 *start, u64 *stop, u64 estart, int len) { u64 estop; if (len > 0) len--; else len = 0; estop = estart + len; /* 0-0 range represents "not set" */ if ((*start == 0) && (*stop == 0)) { *start = estart; *stop = estop; } else if (*start <= *stop) { /* increase the existing range */ if (estart < *start) *start = estart; if (estop > *stop) *stop = estop; } else { /* "overflowing" interval, whereby *stop > *start */ if (estart <= *stop) { if (estop > *stop) *stop = estop; } else if (estop > *start) { if (estart < *start) *start = estart; } /* minimize the range */ else if ((estop - *stop) < (*start - estart)) *stop = estop; else *start = estart; } } #define MAX_INST_SIZE 6 static void enable_all_hw_bp(struct kvm_vcpu *vcpu) { unsigned long start, len; u64 *cr9 = &vcpu->arch.sie_block->gcr[9]; u64 *cr10 = &vcpu->arch.sie_block->gcr[10]; u64 *cr11 = &vcpu->arch.sie_block->gcr[11]; int i; if (vcpu->arch.guestdbg.nr_hw_bp <= 0 || vcpu->arch.guestdbg.hw_bp_info == NULL) return; /* * If the guest is not interrested in branching events, we can savely * limit them to the PER address range. */ if (!(*cr9 & PER_EVENT_BRANCH)) *cr9 |= PER_CONTROL_BRANCH_ADDRESS; *cr9 |= PER_EVENT_IFETCH | PER_EVENT_BRANCH; for (i = 0; i < vcpu->arch.guestdbg.nr_hw_bp; i++) { start = vcpu->arch.guestdbg.hw_bp_info[i].addr; len = vcpu->arch.guestdbg.hw_bp_info[i].len; /* * The instruction in front of the desired bp has to * report instruction-fetching events */ if (start < MAX_INST_SIZE) { len += start; start = 0; } else { start -= MAX_INST_SIZE; len += MAX_INST_SIZE; } extend_address_range(cr10, cr11, start, len); } } static void enable_all_hw_wp(struct kvm_vcpu *vcpu) { unsigned long start, len; u64 *cr9 = &vcpu->arch.sie_block->gcr[9]; u64 *cr10 = &vcpu->arch.sie_block->gcr[10]; u64 *cr11 = &vcpu->arch.sie_block->gcr[11]; int i; if (vcpu->arch.guestdbg.nr_hw_wp <= 0 || vcpu->arch.guestdbg.hw_wp_info == NULL) return; /* if host uses storage alternation for special address * spaces, enable all events and give all to the guest */ if (*cr9 & PER_EVENT_STORE && *cr9 & PER_CONTROL_ALTERATION) { *cr9 &= ~PER_CONTROL_ALTERATION; *cr10 = 0; *cr11 = PSW_ADDR_INSN; } else { *cr9 &= ~PER_CONTROL_ALTERATION; *cr9 |= PER_EVENT_STORE; for (i = 0; i < vcpu->arch.guestdbg.nr_hw_wp; i++) { start = vcpu->arch.guestdbg.hw_wp_info[i].addr; len = vcpu->arch.guestdbg.hw_wp_info[i].len; extend_address_range(cr10, cr11, start, len); } } } void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu) { vcpu->arch.guestdbg.cr0 = vcpu->arch.sie_block->gcr[0]; vcpu->arch.guestdbg.cr9 = vcpu->arch.sie_block->gcr[9]; vcpu->arch.guestdbg.cr10 = vcpu->arch.sie_block->gcr[10]; vcpu->arch.guestdbg.cr11 = vcpu->arch.sie_block->gcr[11]; } void kvm_s390_restore_guest_per_regs(struct kvm_vcpu *vcpu) { vcpu->arch.sie_block->gcr[0] = vcpu->arch.guestdbg.cr0; vcpu->arch.sie_block->gcr[9] = vcpu->arch.guestdbg.cr9; vcpu->arch.sie_block->gcr[10] = vcpu->arch.guestdbg.cr10; vcpu->arch.sie_block->gcr[11] = vcpu->arch.guestdbg.cr11; } void kvm_s390_patch_guest_per_regs(struct kvm_vcpu *vcpu) { /* * TODO: if guest psw has per enabled, otherwise 0s! * This reduces the amount of reported events. * Need to intercept all psw changes! */ if (guestdbg_sstep_enabled(vcpu)) { /* disable timer (clock-comparator) interrupts */ vcpu->arch.sie_block->gcr[0] &= ~0x800ul; vcpu->arch.sie_block->gcr[9] |= PER_EVENT_IFETCH; vcpu->arch.sie_block->gcr[10] = 0; vcpu->arch.sie_block->gcr[11] = PSW_ADDR_INSN; } if (guestdbg_hw_bp_enabled(vcpu)) { enable_all_hw_bp(vcpu); enable_all_hw_wp(vcpu); } /* TODO: Instruction-fetching-nullification not allowed for now */ if (vcpu->arch.sie_block->gcr[9] & PER_EVENT_NULLIFICATION) vcpu->arch.sie_block->gcr[9] &= ~PER_EVENT_NULLIFICATION; } #define MAX_WP_SIZE 100 static int __import_wp_info(struct kvm_vcpu *vcpu, struct kvm_hw_breakpoint *bp_data, struct kvm_hw_wp_info_arch *wp_info) { int ret = 0; wp_info->len = bp_data->len; wp_info->addr = bp_data->addr; wp_info->phys_addr = bp_data->phys_addr; wp_info->old_data = NULL; if (wp_info->len < 0 || wp_info->len > MAX_WP_SIZE) return -EINVAL; wp_info->old_data = kmalloc(bp_data->len, GFP_KERNEL); if (!wp_info->old_data) return -ENOMEM; /* try to backup the original value */ ret = read_guest_abs(vcpu, wp_info->phys_addr, wp_info->old_data, wp_info->len); if (ret) { kfree(wp_info->old_data); wp_info->old_data = NULL; } return ret; } #define MAX_BP_COUNT 50 int kvm_s390_import_bp_data(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) { int ret = 0, nr_wp = 0, nr_bp = 0, i, size; struct kvm_hw_breakpoint *bp_data = NULL; struct kvm_hw_wp_info_arch *wp_info = NULL; struct kvm_hw_bp_info_arch *bp_info = NULL; if (dbg->arch.nr_hw_bp <= 0 || !dbg->arch.hw_bp) retur
/*
 * Per-device information from the pin control system.
 * This is the stuff that get included into the device
 * core.
 *
 * Copyright (C) 2012 ST-Ericsson SA
 * Written on behalf of Linaro for ST-Ericsson
 * This interface is used in the core to keep track of pins.
 *
 * Author: Linus Walleij <linus.walleij@linaro.org>
 *
 * License terms: GNU General Public License (GPL) version 2
 */

#ifndef PINCTRL_DEVINFO_H
#define PINCTRL_DEVINFO_H

#ifdef CONFIG_PINCTRL

/* The device core acts as a consumer toward pinctrl */
#include <linux/pinctrl/consumer.h>

/**
 * struct dev_pin_info - pin state container for devices
 * @p: pinctrl handle for the containing device
 * @default_state: the default state for the handle, if found
 * @init_state: the state at probe time, if found
 * @sleep_state: the state at suspend time, if found
 * @idle_state: the state at idle (runtime suspend) time, if found
 */
struct dev_pin_info {
	struct pinctrl *p;
	struct pinctrl_state *default_state;
	struct pinctrl_state *init_state;
#ifdef CONFIG_PM
	struct pinctrl_state *sleep_state;
	struct pinctrl_state *idle_state;
#endif
};

extern int pinctrl_bind_pins(struct device *dev);
extern int pinctrl_init_done(struct device *dev);

#else