|
39 | 39 | #include <asm/iommu.h>
|
40 | 40 | #include <asm/switch_to.h>
|
41 | 41 | #include <asm/xive.h>
|
| 42 | +#ifdef CONFIG_PPC_PSERIES |
| 43 | +#include <asm/hvcall.h> |
| 44 | +#include <asm/plpar_wrappers.h> |
| 45 | +#endif |
42 | 46 |
|
43 | 47 | #include "timing.h"
|
44 | 48 | #include "irq.h"
|
@@ -548,6 +552,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
548 | 552 | #ifdef CONFIG_KVM_XICS
|
549 | 553 | case KVM_CAP_IRQ_XICS:
|
550 | 554 | #endif
|
| 555 | + case KVM_CAP_PPC_GET_CPU_CHAR: |
551 | 556 | r = 1;
|
552 | 557 | break;
|
553 | 558 |
|
@@ -1759,6 +1764,124 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
|
1759 | 1764 | return r;
|
1760 | 1765 | }
|
1761 | 1766 |
|
| 1767 | +#ifdef CONFIG_PPC_BOOK3S_64 |
| 1768 | +/* |
| 1769 | + * These functions check whether the underlying hardware is safe |
| 1770 | + * against attacks based on observing the effects of speculatively |
| 1771 | + * executed instructions, and whether it supplies instructions for |
| 1772 | + * use in workarounds. The information comes from firmware, either |
| 1773 | + * via the device tree on powernv platforms or from an hcall on |
| 1774 | + * pseries platforms. |
| 1775 | + */ |
| 1776 | +#ifdef CONFIG_PPC_PSERIES |
| 1777 | +static int pseries_get_cpu_char(struct kvm_ppc_cpu_char *cp) |
| 1778 | +{ |
| 1779 | + struct h_cpu_char_result c; |
| 1780 | + unsigned long rc; |
| 1781 | + |
| 1782 | + if (!machine_is(pseries)) |
| 1783 | + return -ENOTTY; |
| 1784 | + |
| 1785 | + rc = plpar_get_cpu_characteristics(&c); |
| 1786 | + if (rc == H_SUCCESS) { |
| 1787 | + cp->character = c.character; |
| 1788 | + cp->behaviour = c.behaviour; |
| 1789 | + cp->character_mask = KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 | |
| 1790 | + KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED | |
| 1791 | + KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30 | |
| 1792 | + KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2 | |
| 1793 | + KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV | |
| 1794 | + KVM_PPC_CPU_CHAR_BR_HINT_HONOURED | |
| 1795 | + KVM_PPC_CPU_CHAR_MTTRIG_THR_RECONF | |
| 1796 | + KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS; |
| 1797 | + cp->behaviour_mask = KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY | |
| 1798 | + KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR | |
| 1799 | + KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR; |
| 1800 | + } |
| 1801 | + return 0; |
| 1802 | +} |
| 1803 | +#else |
| 1804 | +static int pseries_get_cpu_char(struct kvm_ppc_cpu_char *cp) |
| 1805 | +{ |
| 1806 | + return -ENOTTY; |
| 1807 | +} |
| 1808 | +#endif |
| 1809 | + |
| 1810 | +static inline bool have_fw_feat(struct device_node *fw_features, |
| 1811 | + const char *state, const char *name) |
| 1812 | +{ |
| 1813 | + struct device_node *np; |
| 1814 | + bool r = false; |
| 1815 | + |
| 1816 | + np = of_get_child_by_name(fw_features, name); |
| 1817 | + if (np) { |
| 1818 | + r = of_property_read_bool(np, state); |
| 1819 | + of_node_put(np); |
| 1820 | + } |
| 1821 | + return r; |
| 1822 | +} |
| 1823 | + |
| 1824 | +static int kvmppc_get_cpu_char(struct kvm_ppc_cpu_char *cp) |
| 1825 | +{ |
| 1826 | + struct device_node *np, *fw_features; |
| 1827 | + int r; |
| 1828 | + |
| 1829 | + memset(cp, 0, sizeof(*cp)); |
| 1830 | + r = pseries_get_cpu_char(cp); |
| 1831 | + if (r != -ENOTTY) |
| 1832 | + return r; |
| 1833 | + |
| 1834 | + np = of_find_node_by_name(NULL, "ibm,opal"); |
| 1835 | + if (np) { |
| 1836 | + fw_features = of_get_child_by_name(np, "fw-features"); |
| 1837 | + of_node_put(np); |
| 1838 | + if (!fw_features) |
| 1839 | + return 0; |
| 1840 | + if (have_fw_feat(fw_features, "enabled", |
| 1841 | + "inst-spec-barrier-ori31,31,0")) |
| 1842 | + cp->character |= KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31; |
| 1843 | + if (have_fw_feat(fw_features, "enabled", |
| 1844 | + "fw-bcctrl-serialized")) |
| 1845 | + cp->character |= KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED; |
| 1846 | + if (have_fw_feat(fw_features, "enabled", |
| 1847 | + "inst-l1d-flush-ori30,30,0")) |
| 1848 | + cp->character |= KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30; |
| 1849 | + if (have_fw_feat(fw_features, "enabled", |
| 1850 | + "inst-l1d-flush-trig2")) |
| 1851 | + cp->character |= KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2; |
| 1852 | + if (have_fw_feat(fw_features, "enabled", |
| 1853 | + "fw-l1d-thread-split")) |
| 1854 | + cp->character |= KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV; |
| 1855 | + if (have_fw_feat(fw_features, "enabled", |
| 1856 | + "fw-count-cache-disabled")) |
| 1857 | + cp->character |= KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS; |
| 1858 | + cp->character_mask = KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 | |
| 1859 | + KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED | |
| 1860 | + KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30 | |
| 1861 | + KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2 | |
| 1862 | + KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV | |
| 1863 | + KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS; |
| 1864 | + |
| 1865 | + if (have_fw_feat(fw_features, "enabled", |
| 1866 | + "speculation-policy-favor-security")) |
| 1867 | + cp->behaviour |= KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY; |
| 1868 | + if (!have_fw_feat(fw_features, "disabled", |
| 1869 | + "needs-l1d-flush-msr-pr-0-to-1")) |
| 1870 | + cp->behaviour |= KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR; |
| 1871 | + if (!have_fw_feat(fw_features, "disabled", |
| 1872 | + "needs-spec-barrier-for-bound-checks")) |
| 1873 | + cp->behaviour |= KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR; |
| 1874 | + cp->behaviour_mask = KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY | |
| 1875 | + KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR | |
| 1876 | + KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR; |
| 1877 | + |
| 1878 | + of_node_put(fw_features); |
| 1879 | + } |
| 1880 | + |
| 1881 | + return 0; |
| 1882 | +} |
| 1883 | +#endif |
| 1884 | + |
1762 | 1885 | long kvm_arch_vm_ioctl(struct file *filp,
|
1763 | 1886 | unsigned int ioctl, unsigned long arg)
|
1764 | 1887 | {
|
@@ -1861,6 +1984,14 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
1861 | 1984 | r = -EFAULT;
|
1862 | 1985 | break;
|
1863 | 1986 | }
|
| 1987 | + case KVM_PPC_GET_CPU_CHAR: { |
| 1988 | + struct kvm_ppc_cpu_char cpuchar; |
| 1989 | + |
| 1990 | + r = kvmppc_get_cpu_char(&cpuchar); |
| 1991 | + if (r >= 0 && copy_to_user(argp, &cpuchar, sizeof(cpuchar))) |
| 1992 | + r = -EFAULT; |
| 1993 | + break; |
| 1994 | + } |
1864 | 1995 | default: {
|
1865 | 1996 | struct kvm *kvm = filp->private_data;
|
1866 | 1997 | r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg);
|
|
0 commit comments