
Changes in 5.10.219 x86/tsc: Trust initial offset in architectural TSC-adjust MSRs tty: n_gsm: fix possible out-of-bounds in gsm0_receive() speakup: Fix sizeof() vs ARRAY_SIZE() bug ring-buffer: Fix a race between readers and resize checks net: smc91x: Fix m68k kernel compilation for ColdFire CPU nilfs2: fix unexpected freezing of nilfs_segctor_sync() nilfs2: fix potential hang in nilfs_detach_log_writer() ALSA: core: Fix NULL module pointer assignment at card init wifi: cfg80211: fix the order of arguments for trace events of the tx_rx_evt class net: usb: qmi_wwan: add Telit FN920C04 compositions drm/amd/display: Set color_mgmt_changed to true on unsuspend ASoC: rt5645: Fix the electric noise due to the CBJ contacts floating ASoC: dt-bindings: rt5645: add cbj sleeve gpio property regulator: vqmmc-ipq4019: fix module autoloading ASoC: rt715: add vendor clear control register ASoC: da7219-aad: fix usage of device_get_named_child_node() drm/amdkfd: Flush the process wq before creating a kfd_process nvme: find numa distance only if controller has valid numa id openpromfs: finish conversion to the new mount API crypto: bcm - Fix pointer arithmetic firmware: raspberrypi: Use correct device for DMA mappings ecryptfs: Fix buffer size for tag 66 packet nilfs2: fix out-of-range warning parisc: add missing export of __cmpxchg_u8() crypto: ccp - drop platform ifdef checks crypto: x86/nh-avx2 - add missing vzeroupper crypto: x86/sha256-avx2 - add missing vzeroupper s390/cio: fix tracepoint subchannel type field jffs2: prevent xattr node from overflowing the eraseblock soc: mediatek: cmdq: Fix typo of CMDQ_JUMP_RELATIVE null_blk: Fix missing mutex_destroy() at module removal md: fix resync softlockup when bitmap size is less than array size wifi: ath10k: poll service ready message before failing x86/boot: Ignore relocations in .notes sections in walk_relocs() too qed: avoid truncating work queue length scsi: ufs: qcom: Perform read back after writing reset bit scsi: ufs-qcom: Fix ufs RST_n spec violation scsi: ufs: qcom: Perform read back after writing REG_UFS_SYS1CLK_1US scsi: ufs: ufs-qcom: Fix the Qcom register name for offset 0xD0 scsi: ufs: ufs-qcom: Clear qunipro_g4_sel for HW version major 5 scsi: ufs: qcom: Perform read back after writing unipro mode scsi: ufs: qcom: Perform read back after writing CGC enable scsi: ufs: cdns-pltfrm: Perform read back after writing HCLKDIV scsi: ufs: core: Perform read back after disabling interrupts scsi: ufs: core: Perform read back after disabling UIC_COMMAND_COMPL irqchip/alpine-msi: Fix off-by-one in allocation error path irqchip/loongson-pch-msi: Fix off-by-one on allocation error path ACPI: disable -Wstringop-truncation gfs2: Fix "ignore unlock failures after withdraw" selftests/bpf: Fix umount cgroup2 error in test_sockmap cpufreq: Reorganize checks in cpufreq_offline() cpufreq: Split cpufreq_offline() cpufreq: Rearrange locking in cpufreq_remove_dev() cpufreq: exit() callback is optional net: export inet_lookup_reuseport and inet6_lookup_reuseport net: remove duplicate reuseport_lookup functions udp: Avoid call to compute_score on multiple sites scsi: libsas: Fix the failure of adding phy with zero-address to port scsi: hpsa: Fix allocation size for Scsi_Host private data x86/purgatory: Switch to the position-independent small code model wifi: ath10k: Fix an error code problem in ath10k_dbg_sta_write_peer_debug_trigger() wifi: ath10k: populate board data for WCN3990 tcp: avoid premature drops in tcp_add_backlog() net: give more chances to rcu in netdev_wait_allrefs_any() macintosh/via-macii: Fix "BUG: sleeping function called from invalid context" wifi: carl9170: add a proper sanity check for endpoints wifi: ar5523: enable proper endpoint verification sh: kprobes: Merge arch_copy_kprobe() into arch_prepare_kprobe() Revert "sh: Handle calling csum_partial with misaligned data" selftests/binderfs: use the Makefile's rules, not Make's implicit rules HID: intel-ish-hid: ipc: Add check for pci_alloc_irq_vectors scsi: bfa: Ensure the copied buf is NUL terminated scsi: qedf: Ensure the copied buf is NUL terminated wifi: mwl8k: initialize cmd->addr[] properly usb: aqc111: stop lying about skb->truesize net: usb: sr9700: stop lying about skb->truesize m68k: Fix spinlock race in kernel thread creation m68k: mac: Fix reboot hang on Mac IIci net: ipv6: fix wrong start position when receive hop-by-hop fragment eth: sungem: remove .ndo_poll_controller to avoid deadlocks net: ethernet: cortina: Locking fixes af_unix: Fix data races in unix_release_sock/unix_stream_sendmsg net: usb: smsc95xx: stop lying about skb->truesize net: openvswitch: fix overwriting ct original tuple for ICMPv6 ipv6: sr: add missing seg6_local_exit ipv6: sr: fix incorrect unregister order ipv6: sr: fix invalid unregister error path net/mlx5: Discard command completions in internal error drm/amd/display: Fix potential index out of bounds in color transformation function ASoC: soc-acpi: add helper to identify parent driver. ASoC: Intel: Disable route checks for Skylake boards mtd: rawnand: hynix: fixed typo fbdev: shmobile: fix snprintf truncation drm/meson: vclk: fix calculation of 59.94 fractional rates drm/mediatek: Add 0 size check to mtk_drm_gem_obj powerpc/fsl-soc: hide unused const variable fbdev: sisfb: hide unused variables media: ngene: Add dvb_ca_en50221_init return value check media: radio-shark2: Avoid led_names truncations drm: bridge: cdns-mhdp8546: Fix possible null pointer dereference fbdev: sh7760fb: allow modular build media: atomisp: ssh_css: Fix a null-pointer dereference in load_video_binaries drm/arm/malidp: fix a possible null pointer dereference drm: vc4: Fix possible null pointer dereference ASoC: tracing: Export SND_SOC_DAPM_DIR_OUT to its value drm/bridge: lt9611: Don't log an error when DSI host can't be found drm/bridge: tc358775: Don't log an error when DSI host can't be found drm/panel: simple: Add missing Innolux G121X1-L03 format, flags, connector drm/mipi-dsi: use correct return type for the DSC functions RDMA/hns: Refactor the hns_roce_buf allocation flow RDMA/hns: Create QP with selected QPN for bank load balance RDMA/hns: Fix incorrect symbol types RDMA/hns: Fix return value in hns_roce_map_mr_sg RDMA/hns: Use complete parentheses in macros RDMA/hns: Modify the print level of CQE error clk: qcom: mmcc-msm8998: fix venus clock issue x86/insn: Fix PUSH instruction in x86 instruction decoder opcode map ext4: avoid excessive credit estimate in ext4_tmpfile() sunrpc: removed redundant procp check ext4: simplify calculation of blkoff in ext4_mb_new_blocks_simple ext4: fix unit mismatch in ext4_mb_new_blocks_simple ext4: try all groups in ext4_mb_new_blocks_simple ext4: remove unused parameter from ext4_mb_new_blocks_simple() ext4: fix potential unnitialized variable SUNRPC: Fix gss_free_in_token_pages() selftests/kcmp: Make the test output consistent and clear selftests/kcmp: remove unused open mode RDMA/IPoIB: Fix format truncation compilation errors net: qrtr: fix null-ptr-deref in qrtr_ns_remove net: qrtr: ns: Fix module refcnt netrom: fix possible dead-lock in nr_rt_ioctl() af_packet: do not call packet_read_pending() from tpacket_destruct_skb() sched/fair: Allow disabling sched_balance_newidle with sched_relax_domain_level greybus: lights: check return of get_channel_from_mode f2fs: fix to wait on page writeback in __clone_blkaddrs() soundwire: cadence: fix invalid PDI offset dmaengine: idma64: Add check for dma_set_max_seg_size firmware: dmi-id: add a release callback function serial: max3100: Lock port->lock when calling uart_handle_cts_change() serial: max3100: Update uart_driver_registered on driver removal serial: max3100: Fix bitwise types greybus: arche-ctrl: move device table to its right location serial: sc16is7xx: add proper sched.h include for sched_set_fifo() f2fs: compress: support chksum f2fs: add compress_mode mount option f2fs: compress: clean up parameter of __f2fs_cluster_blocks() f2fs: compress: remove unneeded preallocation f2fs: introduce FI_COMPRESS_RELEASED instead of using IMMUTABLE bit f2fs: compress: fix to relocate check condition in f2fs_{release,reserve}_compress_blocks() f2fs: add cp_error check in f2fs_write_compressed_pages f2fs: fix to force keeping write barrier for strict fsync mode f2fs: do not allow partial truncation on pinned file f2fs: fix typos in comments f2fs: fix to relocate check condition in f2fs_fallocate() f2fs: fix to check pinfile flag in f2fs_move_file_range() iio: pressure: dps310: support negative temperature values fpga: region: change FPGA indirect article to an fpga: region: Rename dev to parent for parent device docs: driver-api: fpga: avoid using UTF-8 chars fpga: region: Use standard dev_release for class driver fpga: region: add owner module and take its refcount microblaze: Remove gcc flag for non existing early_printk.c file microblaze: Remove early printk call from cpuinfo-static.c usb: gadget: u_audio: Clear uac pointer when freed. stm class: Fix a double free in stm_register_device() ppdev: Remove usage of the deprecated ida_simple_xx() API ppdev: Add an error check in register_device extcon: max8997: select IRQ_DOMAIN instead of depending on it PCI/EDR: Align EDR_PORT_DPC_ENABLE_DSM with PCI Firmware r3.3 PCI/EDR: Align EDR_PORT_LOCATE_DSM with PCI Firmware r3.3 f2fs: compress: fix to cover {reserve,release}_compress_blocks() w/ cp_rwsem lock f2fs: fix to release node block count in error path of f2fs_new_node_page() f2fs: compress: don't allow unaligned truncation on released compress inode serial: sh-sci: protect invalidating RXDMA on shutdown libsubcmd: Fix parse-options memory leak s390/ipl: Fix incorrect initialization of len fields in nvme reipl block s390/ipl: Fix incorrect initialization of nvme dump block Input: ims-pcu - fix printf string overflow Input: ioc3kbd - convert to platform remove callback returning void Input: ioc3kbd - add device table mmc: sdhci_am654: Add tuning algorithm for delay chain mmc: sdhci_am654: Write ITAPDLY for DDR52 timing mmc: sdhci_am654: Drop lookup for deprecated ti,otap-del-sel mmc: sdhci_am654: Add OTAP/ITAP delay enable mmc: sdhci_am654: Add ITAPDLYSEL in sdhci_j721e_4bit_set_clock mmc: sdhci_am654: Fix ITAPDLY for HS400 timing Input: pm8xxx-vibrator - correct VIB_MAX_LEVELS calculation drm/msm/dpu: Always flush the slave INTF on the CTL um: Fix return value in ubd_init() um: Add winch to winch_handlers before registering winch IRQ um: vector: fix bpfflash parameter evaluation drm/bridge: tc358775: fix support for jeida-18 and jeida-24 media: stk1160: fix bounds checking in stk1160_copy_video() scsi: qla2xxx: Replace all non-returning strlcpy() with strscpy() media: flexcop-usb: clean up endpoint sanity checks media: flexcop-usb: fix sanity check of bNumEndpoints powerpc/pseries: Add failure related checks for h_get_mpp and h_get_ppp um: Fix the -Wmissing-prototypes warning for __switch_mm media: cec: cec-adap: always cancel work in cec_transmit_msg_fh media: cec: cec-api: add locking in cec_release() media: core headers: fix kernel-doc warnings media: cec: fix a deadlock situation media: cec: call enable_adap on s_log_addrs media: cec: abort if the current transmit was canceled media: cec: correctly pass on reply results media: cec: use call_op and check for !unregistered media: cec-adap.c: drop activate_cnt, use state info instead media: cec: core: avoid recursive cec_claim_log_addrs media: cec: core: avoid confusing "transmit timed out" message null_blk: Fix the WARNING: modpost: missing MODULE_DESCRIPTION() regulator: bd71828: Don't overwrite runtime voltages x86/kconfig: Select ARCH_WANT_FRAME_POINTERS again when UNWINDER_FRAME_POINTER=y nfc: nci: Fix uninit-value in nci_rx_work ASoC: tas2552: Add TX path for capturing AUDIO-OUT data sunrpc: fix NFSACL RPC retry on soft mount rpcrdma: fix handling for RDMA_CM_EVENT_DEVICE_REMOVAL ipv6: sr: fix memleak in seg6_hmac_init_algo params: lift param_set_uint_minmax to common code tcp: Fix shift-out-of-bounds in dctcp_update_alpha(). openvswitch: Set the skbuff pkt_type for proper pmtud support. arm64: asm-bug: Add .align 2 to the end of __BUG_ENTRY virtio: delete vq in vp_find_vqs_msix() when request_irq() fails net: fec: avoid lock evasion when reading pps_enable tls: fix missing memory barrier in tls_init nfc: nci: Fix kcov check in nci_rx_work() nfc: nci: Fix handling of zero-length payload packets in nci_rx_work() netfilter: nfnetlink_queue: acquire rcu_read_lock() in instance_destroy_rcu() netfilter: nft_payload: restore vlan q-in-q match support spi: Don't mark message DMA mapped when no transfer in it is nvmet: fix ns enable/disable possible hang net/mlx5e: Use rx_missed_errors instead of rx_dropped for reporting buffer exhaustion dma-buf/sw-sync: don't enable IRQ from sync_print_obj() bpf: Fix potential integer overflow in resolve_btfids enic: Validate length of nl attributes in enic_set_vf_port net: usb: smsc95xx: fix changing LED_SEL bit value updated from EEPROM bpf: Allow delete from sockmap/sockhash only if update is allowed net:fec: Add fec_enet_deinit() netfilter: tproxy: bail out if IP has been disabled on the device kconfig: fix comparison to constant symbols, 'm', 'n' spi: stm32: Don't warn about spurious interrupts ipvlan: Dont Use skb->sk in ipvlan_process_v{4,6}_outbound hwmon: (shtc1) Fix property misspelling ALSA: timer: Set lower bound of start tick time genirq/cpuhotplug, x86/vector: Prevent vector leak during CPU offline media: cec: core: add adap_nb_transmit_canceled() callback SUNRPC: Fix loop termination condition in gss_free_in_token_pages() binder: fix max_thread type inconsistency mmc: core: Do not force a retune before RPMB switch io_uring: fail NOP if non-zero op flags is passed in afs: Don't cross .backup mountpoint from backup volume nilfs2: fix use-after-free of timer for log writer thread vxlan: Fix regression when dropping packets due to invalid src addresses x86/mm: Remove broken vsyscall emulation code from the page fault code netfilter: nf_tables: restrict tunnel object to NFPROTO_NETDEV netfilter: nf_tables: Fix potential data-race in __nft_obj_type_get() f2fs: fix to do sanity check on i_xattr_nid in sanity_check_inode() media: lgdt3306a: Add a check against null-pointer-def drm/amdgpu: add error handle to avoid out-of-bounds ata: pata_legacy: make legacy_exit() work again ACPI: resource: Do IRQ override on TongFang GXxHRXx and GMxHGxx arm64: tegra: Correct Tegra132 I2C alias arm64: dts: qcom: qcs404: fix bluetooth device address md/raid5: fix deadlock that raid5d() wait for itself to clear MD_SB_CHANGE_PENDING wifi: rtl8xxxu: Fix the TX power of RTL8192CU, RTL8723AU wifi: rtlwifi: rtl8192de: Fix low speed with WPA3-SAE wifi: rtlwifi: rtl8192de: Fix endianness issue in RX path arm64: dts: hi3798cv200: fix the size of GICR media: mc: mark the media devnode as registered from the, start media: mxl5xx: Move xpt structures off stack media: v4l2-core: hold videodev_lock until dev reg, finishes mmc: core: Add mmc_gpiod_set_cd_config() function mmc: sdhci-acpi: Sort DMI quirks alphabetically mmc: sdhci-acpi: Fix Lenovo Yoga Tablet 2 Pro 1380 sdcard slot not working mmc: sdhci-acpi: Disable write protect detection on Toshiba WT10-A fbdev: savage: Handle err return when savagefb_check_var failed KVM: arm64: Allow AArch32 PSTATE.M to be restored as System mode crypto: ecrdsa - Fix module auto-load on add_key crypto: qat - Fix ADF_DEV_RESET_SYNC memory leak net/ipv6: Fix route deleting failure when metric equals 0 net/9p: fix uninit-value in p9_client_rpc() intel_th: pci: Add Meteor Lake-S CPU support sparc64: Fix number of online CPUs watchdog: rti_wdt: Set min_hw_heartbeat_ms to accommodate a safety margin kdb: Fix buffer overflow during tab-complete kdb: Use format-strings rather than '\0' injection in kdb_read() kdb: Fix console handling when editing and tab-completing commands kdb: Merge identical case statements in kdb_read() kdb: Use format-specifiers rather than memset() for padding in kdb_read() net: fix __dst_negative_advice() race sparc: move struct termio to asm/termios.h ext4: fix mb_cache_entry's e_refcnt leak in ext4_xattr_block_cache_find() s390/ap: Fix crash in AP internal function modify_bitmap() nfs: fix undefined behavior in nfs_block_bits() NFS: Fix READ_PLUS when server doesn't support OP_READ_PLUS scsi: ufs: ufs-qcom: Clear qunipro_g4_sel for HW major version > 5 f2fs: compress: fix compression chksum RDMA/hns: Use mutex instead of spinlock for ida allocation RDMA/hns: Fix CQ and QP cache affinity Linux 5.10.219 Change-Id: I0e21ff44d28df2a2802a9fb35f0959bb5ab528fc Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
1004 lines
24 KiB
C
1004 lines
24 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2012,2013 - ARM Ltd
|
|
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
|
*
|
|
* Derived from arch/arm/kvm/guest.c:
|
|
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
|
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
|
*/
|
|
|
|
#include <linux/bits.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/err.h>
|
|
#include <linux/nospec.h>
|
|
#include <linux/kvm_host.h>
|
|
#include <linux/module.h>
|
|
#include <linux/stddef.h>
|
|
#include <linux/string.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/fs.h>
|
|
#include <kvm/arm_psci.h>
|
|
#include <asm/cputype.h>
|
|
#include <linux/uaccess.h>
|
|
#include <asm/fpsimd.h>
|
|
#include <asm/kvm.h>
|
|
#include <asm/kvm_emulate.h>
|
|
#include <asm/sigcontext.h>
|
|
|
|
#include "trace.h"
|
|
|
|
struct kvm_stats_debugfs_item debugfs_entries[] = {
|
|
VCPU_STAT("halt_successful_poll", halt_successful_poll),
|
|
VCPU_STAT("halt_attempted_poll", halt_attempted_poll),
|
|
VCPU_STAT("halt_poll_invalid", halt_poll_invalid),
|
|
VCPU_STAT("halt_wakeup", halt_wakeup),
|
|
VCPU_STAT("hvc_exit_stat", hvc_exit_stat),
|
|
VCPU_STAT("wfe_exit_stat", wfe_exit_stat),
|
|
VCPU_STAT("wfi_exit_stat", wfi_exit_stat),
|
|
VCPU_STAT("mmio_exit_user", mmio_exit_user),
|
|
VCPU_STAT("mmio_exit_kernel", mmio_exit_kernel),
|
|
VCPU_STAT("exits", exits),
|
|
VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns),
|
|
VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns),
|
|
{ NULL }
|
|
};
|
|
|
|
static bool core_reg_offset_is_vreg(u64 off)
|
|
{
|
|
return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) &&
|
|
off < KVM_REG_ARM_CORE_REG(fp_regs.fpsr);
|
|
}
|
|
|
|
static u64 core_reg_offset_from_id(u64 id)
|
|
{
|
|
return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
|
|
}
|
|
|
|
static int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off)
|
|
{
|
|
int size;
|
|
|
|
switch (off) {
|
|
case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
|
|
KVM_REG_ARM_CORE_REG(regs.regs[30]):
|
|
case KVM_REG_ARM_CORE_REG(regs.sp):
|
|
case KVM_REG_ARM_CORE_REG(regs.pc):
|
|
case KVM_REG_ARM_CORE_REG(regs.pstate):
|
|
case KVM_REG_ARM_CORE_REG(sp_el1):
|
|
case KVM_REG_ARM_CORE_REG(elr_el1):
|
|
case KVM_REG_ARM_CORE_REG(spsr[0]) ...
|
|
KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]):
|
|
size = sizeof(__u64);
|
|
break;
|
|
|
|
case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ...
|
|
KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]):
|
|
size = sizeof(__uint128_t);
|
|
break;
|
|
|
|
case KVM_REG_ARM_CORE_REG(fp_regs.fpsr):
|
|
case KVM_REG_ARM_CORE_REG(fp_regs.fpcr):
|
|
size = sizeof(__u32);
|
|
break;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!IS_ALIGNED(off, size / sizeof(__u32)))
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* The KVM_REG_ARM64_SVE regs must be used instead of
|
|
* KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
|
|
* SVE-enabled vcpus:
|
|
*/
|
|
if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
|
|
return -EINVAL;
|
|
|
|
return size;
|
|
}
|
|
|
|
static void *core_reg_addr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
u64 off = core_reg_offset_from_id(reg->id);
|
|
int size = core_reg_size_from_offset(vcpu, off);
|
|
|
|
if (size < 0)
|
|
return NULL;
|
|
|
|
if (KVM_REG_SIZE(reg->id) != size)
|
|
return NULL;
|
|
|
|
switch (off) {
|
|
case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
|
|
KVM_REG_ARM_CORE_REG(regs.regs[30]):
|
|
off -= KVM_REG_ARM_CORE_REG(regs.regs[0]);
|
|
off /= 2;
|
|
return &vcpu->arch.ctxt.regs.regs[off];
|
|
|
|
case KVM_REG_ARM_CORE_REG(regs.sp):
|
|
return &vcpu->arch.ctxt.regs.sp;
|
|
|
|
case KVM_REG_ARM_CORE_REG(regs.pc):
|
|
return &vcpu->arch.ctxt.regs.pc;
|
|
|
|
case KVM_REG_ARM_CORE_REG(regs.pstate):
|
|
return &vcpu->arch.ctxt.regs.pstate;
|
|
|
|
case KVM_REG_ARM_CORE_REG(sp_el1):
|
|
return __ctxt_sys_reg(&vcpu->arch.ctxt, SP_EL1);
|
|
|
|
case KVM_REG_ARM_CORE_REG(elr_el1):
|
|
return __ctxt_sys_reg(&vcpu->arch.ctxt, ELR_EL1);
|
|
|
|
case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_EL1]):
|
|
return __ctxt_sys_reg(&vcpu->arch.ctxt, SPSR_EL1);
|
|
|
|
case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_ABT]):
|
|
return &vcpu->arch.ctxt.spsr_abt;
|
|
|
|
case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_UND]):
|
|
return &vcpu->arch.ctxt.spsr_und;
|
|
|
|
case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_IRQ]):
|
|
return &vcpu->arch.ctxt.spsr_irq;
|
|
|
|
case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_FIQ]):
|
|
return &vcpu->arch.ctxt.spsr_fiq;
|
|
|
|
case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ...
|
|
KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]):
|
|
off -= KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]);
|
|
off /= 4;
|
|
return &vcpu->arch.ctxt.fp_regs.vregs[off];
|
|
|
|
case KVM_REG_ARM_CORE_REG(fp_regs.fpsr):
|
|
return &vcpu->arch.ctxt.fp_regs.fpsr;
|
|
|
|
case KVM_REG_ARM_CORE_REG(fp_regs.fpcr):
|
|
return &vcpu->arch.ctxt.fp_regs.fpcr;
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
/*
|
|
* Because the kvm_regs structure is a mix of 32, 64 and
|
|
* 128bit fields, we index it as if it was a 32bit
|
|
* array. Hence below, nr_regs is the number of entries, and
|
|
* off the index in the "array".
|
|
*/
|
|
__u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr;
|
|
int nr_regs = sizeof(struct kvm_regs) / sizeof(__u32);
|
|
void *addr;
|
|
u32 off;
|
|
|
|
/* Our ID is an index into the kvm_regs struct. */
|
|
off = core_reg_offset_from_id(reg->id);
|
|
if (off >= nr_regs ||
|
|
(off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
|
|
return -ENOENT;
|
|
|
|
addr = core_reg_addr(vcpu, reg);
|
|
if (!addr)
|
|
return -EINVAL;
|
|
|
|
if (copy_to_user(uaddr, addr, KVM_REG_SIZE(reg->id)))
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
__u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr;
|
|
int nr_regs = sizeof(struct kvm_regs) / sizeof(__u32);
|
|
__uint128_t tmp;
|
|
void *valp = &tmp, *addr;
|
|
u64 off;
|
|
int err = 0;
|
|
|
|
/* Our ID is an index into the kvm_regs struct. */
|
|
off = core_reg_offset_from_id(reg->id);
|
|
if (off >= nr_regs ||
|
|
(off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
|
|
return -ENOENT;
|
|
|
|
addr = core_reg_addr(vcpu, reg);
|
|
if (!addr)
|
|
return -EINVAL;
|
|
|
|
if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(valp, uaddr, KVM_REG_SIZE(reg->id))) {
|
|
err = -EFAULT;
|
|
goto out;
|
|
}
|
|
|
|
if (off == KVM_REG_ARM_CORE_REG(regs.pstate)) {
|
|
u64 mode = (*(u64 *)valp) & PSR_AA32_MODE_MASK;
|
|
switch (mode) {
|
|
case PSR_AA32_MODE_USR:
|
|
if (!kvm_supports_32bit_el0())
|
|
return -EINVAL;
|
|
break;
|
|
case PSR_AA32_MODE_FIQ:
|
|
case PSR_AA32_MODE_IRQ:
|
|
case PSR_AA32_MODE_SVC:
|
|
case PSR_AA32_MODE_ABT:
|
|
case PSR_AA32_MODE_UND:
|
|
case PSR_AA32_MODE_SYS:
|
|
if (!vcpu_el1_is_32bit(vcpu))
|
|
return -EINVAL;
|
|
break;
|
|
case PSR_MODE_EL0t:
|
|
case PSR_MODE_EL1t:
|
|
case PSR_MODE_EL1h:
|
|
if (vcpu_el1_is_32bit(vcpu))
|
|
return -EINVAL;
|
|
break;
|
|
default:
|
|
err = -EINVAL;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
memcpy(addr, valp, KVM_REG_SIZE(reg->id));
|
|
|
|
if (*vcpu_cpsr(vcpu) & PSR_MODE32_BIT) {
|
|
int i, nr_reg;
|
|
|
|
switch (*vcpu_cpsr(vcpu)) {
|
|
/*
|
|
* Either we are dealing with user mode, and only the
|
|
* first 15 registers (+ PC) must be narrowed to 32bit.
|
|
* AArch32 r0-r14 conveniently map to AArch64 x0-x14.
|
|
*/
|
|
case PSR_AA32_MODE_USR:
|
|
case PSR_AA32_MODE_SYS:
|
|
nr_reg = 15;
|
|
break;
|
|
|
|
/*
|
|
* Otherwide, this is a priviledged mode, and *all* the
|
|
* registers must be narrowed to 32bit.
|
|
*/
|
|
default:
|
|
nr_reg = 31;
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < nr_reg; i++)
|
|
vcpu_set_reg(vcpu, i, (u32)vcpu_get_reg(vcpu, i));
|
|
|
|
*vcpu_pc(vcpu) = (u32)*vcpu_pc(vcpu);
|
|
}
|
|
out:
|
|
return err;
|
|
}
|
|
|
|
#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
|
|
#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
|
|
#define vq_present(vqs, vq) (!!((vqs)[vq_word(vq)] & vq_mask(vq)))
|
|
|
|
static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
unsigned int max_vq, vq;
|
|
u64 vqs[KVM_ARM64_SVE_VLS_WORDS];
|
|
|
|
if (!vcpu_has_sve(vcpu))
|
|
return -ENOENT;
|
|
|
|
if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
|
|
return -EINVAL;
|
|
|
|
memset(vqs, 0, sizeof(vqs));
|
|
|
|
max_vq = vcpu_sve_max_vq(vcpu);
|
|
for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
|
|
if (sve_vq_available(vq))
|
|
vqs[vq_word(vq)] |= vq_mask(vq);
|
|
|
|
if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
unsigned int max_vq, vq;
|
|
u64 vqs[KVM_ARM64_SVE_VLS_WORDS];
|
|
|
|
if (!vcpu_has_sve(vcpu))
|
|
return -ENOENT;
|
|
|
|
if (kvm_arm_vcpu_sve_finalized(vcpu))
|
|
return -EPERM; /* too late! */
|
|
|
|
if (WARN_ON(vcpu->arch.sve_state))
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
|
|
return -EFAULT;
|
|
|
|
max_vq = 0;
|
|
for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
|
|
if (vq_present(vqs, vq))
|
|
max_vq = vq;
|
|
|
|
if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* Vector lengths supported by the host can't currently be
|
|
* hidden from the guest individually: instead we can only set a
|
|
* maximum via ZCR_EL2.LEN. So, make sure the available vector
|
|
* lengths match the set requested exactly up to the requested
|
|
* maximum:
|
|
*/
|
|
for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
|
|
if (vq_present(vqs, vq) != sve_vq_available(vq))
|
|
return -EINVAL;
|
|
|
|
/* Can't run with no vector lengths at all: */
|
|
if (max_vq < SVE_VQ_MIN)
|
|
return -EINVAL;
|
|
|
|
/* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */
|
|
vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define SVE_REG_SLICE_SHIFT 0
|
|
#define SVE_REG_SLICE_BITS 5
|
|
#define SVE_REG_ID_SHIFT (SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
|
|
#define SVE_REG_ID_BITS 5
|
|
|
|
#define SVE_REG_SLICE_MASK \
|
|
GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1, \
|
|
SVE_REG_SLICE_SHIFT)
|
|
#define SVE_REG_ID_MASK \
|
|
GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT)
|
|
|
|
#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
|
|
|
|
#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
|
|
#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
|
|
|
|
/*
|
|
* Number of register slices required to cover each whole SVE register.
|
|
* NOTE: Only the first slice every exists, for now.
|
|
* If you are tempted to modify this, you must also rework sve_reg_to_region()
|
|
* to match:
|
|
*/
|
|
#define vcpu_sve_slices(vcpu) 1
|
|
|
|
/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
|
|
struct sve_state_reg_region {
|
|
unsigned int koffset; /* offset into sve_state in kernel memory */
|
|
unsigned int klen; /* length in kernel memory */
|
|
unsigned int upad; /* extra trailing padding in user memory */
|
|
};
|
|
|
|
/*
|
|
* Validate SVE register ID and get sanitised bounds for user/kernel SVE
|
|
* register copy
|
|
*/
|
|
static int sve_reg_to_region(struct sve_state_reg_region *region,
|
|
struct kvm_vcpu *vcpu,
|
|
const struct kvm_one_reg *reg)
|
|
{
|
|
/* reg ID ranges for Z- registers */
|
|
const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0);
|
|
const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
|
|
SVE_NUM_SLICES - 1);
|
|
|
|
/* reg ID ranges for P- registers and FFR (which are contiguous) */
|
|
const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0);
|
|
const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1);
|
|
|
|
unsigned int vq;
|
|
unsigned int reg_num;
|
|
|
|
unsigned int reqoffset, reqlen; /* User-requested offset and length */
|
|
unsigned int maxlen; /* Maximum permitted length */
|
|
|
|
size_t sve_state_size;
|
|
|
|
const u64 last_preg_id = KVM_REG_ARM64_SVE_PREG(SVE_NUM_PREGS - 1,
|
|
SVE_NUM_SLICES - 1);
|
|
|
|
/* Verify that the P-regs and FFR really do have contiguous IDs: */
|
|
BUILD_BUG_ON(KVM_REG_ARM64_SVE_FFR(0) != last_preg_id + 1);
|
|
|
|
/* Verify that we match the UAPI header: */
|
|
BUILD_BUG_ON(SVE_NUM_SLICES != KVM_ARM64_SVE_MAX_SLICES);
|
|
|
|
reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
|
|
|
|
if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) {
|
|
if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0)
|
|
return -ENOENT;
|
|
|
|
vq = vcpu_sve_max_vq(vcpu);
|
|
|
|
reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
|
|
SVE_SIG_REGS_OFFSET;
|
|
reqlen = KVM_SVE_ZREG_SIZE;
|
|
maxlen = SVE_SIG_ZREG_SIZE(vq);
|
|
} else if (reg->id >= preg_id_min && reg->id <= preg_id_max) {
|
|
if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0)
|
|
return -ENOENT;
|
|
|
|
vq = vcpu_sve_max_vq(vcpu);
|
|
|
|
reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
|
|
SVE_SIG_REGS_OFFSET;
|
|
reqlen = KVM_SVE_PREG_SIZE;
|
|
maxlen = SVE_SIG_PREG_SIZE(vq);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
sve_state_size = vcpu_sve_state_size(vcpu);
|
|
if (WARN_ON(!sve_state_size))
|
|
return -EINVAL;
|
|
|
|
region->koffset = array_index_nospec(reqoffset, sve_state_size);
|
|
region->klen = min(maxlen, reqlen);
|
|
region->upad = reqlen - region->klen;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
int ret;
|
|
struct sve_state_reg_region region;
|
|
char __user *uptr = (char __user *)reg->addr;
|
|
|
|
/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
|
|
if (reg->id == KVM_REG_ARM64_SVE_VLS)
|
|
return get_sve_vls(vcpu, reg);
|
|
|
|
/* Try to interpret reg ID as an architectural SVE register... */
|
|
ret = sve_reg_to_region(®ion, vcpu, reg);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (!kvm_arm_vcpu_sve_finalized(vcpu))
|
|
return -EPERM;
|
|
|
|
if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
|
|
region.klen) ||
|
|
clear_user(uptr + region.klen, region.upad))
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
int ret;
|
|
struct sve_state_reg_region region;
|
|
const char __user *uptr = (const char __user *)reg->addr;
|
|
|
|
/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
|
|
if (reg->id == KVM_REG_ARM64_SVE_VLS)
|
|
return set_sve_vls(vcpu, reg);
|
|
|
|
/* Try to interpret reg ID as an architectural SVE register... */
|
|
ret = sve_reg_to_region(®ion, vcpu, reg);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (!kvm_arm_vcpu_sve_finalized(vcpu))
|
|
return -EPERM;
|
|
|
|
if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
|
|
region.klen))
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,
|
|
u64 __user *uindices)
|
|
{
|
|
unsigned int i;
|
|
int n = 0;
|
|
|
|
for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
|
|
u64 reg = KVM_REG_ARM64 | KVM_REG_ARM_CORE | i;
|
|
int size = core_reg_size_from_offset(vcpu, i);
|
|
|
|
if (size < 0)
|
|
continue;
|
|
|
|
switch (size) {
|
|
case sizeof(__u32):
|
|
reg |= KVM_REG_SIZE_U32;
|
|
break;
|
|
|
|
case sizeof(__u64):
|
|
reg |= KVM_REG_SIZE_U64;
|
|
break;
|
|
|
|
case sizeof(__uint128_t):
|
|
reg |= KVM_REG_SIZE_U128;
|
|
break;
|
|
|
|
default:
|
|
WARN_ON(1);
|
|
continue;
|
|
}
|
|
|
|
if (uindices) {
|
|
if (put_user(reg, uindices))
|
|
return -EFAULT;
|
|
uindices++;
|
|
}
|
|
|
|
n++;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)
|
|
{
|
|
return copy_core_reg_indices(vcpu, NULL);
|
|
}
|
|
|
|
/**
|
|
* ARM64 versions of the TIMER registers, always available on arm64
|
|
*/
|
|
|
|
#define NUM_TIMER_REGS 3
|
|
|
|
static bool is_timer_reg(u64 index)
|
|
{
|
|
switch (index) {
|
|
case KVM_REG_ARM_TIMER_CTL:
|
|
case KVM_REG_ARM_TIMER_CNT:
|
|
case KVM_REG_ARM_TIMER_CVAL:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
|
{
|
|
if (put_user(KVM_REG_ARM_TIMER_CTL, uindices))
|
|
return -EFAULT;
|
|
uindices++;
|
|
if (put_user(KVM_REG_ARM_TIMER_CNT, uindices))
|
|
return -EFAULT;
|
|
uindices++;
|
|
if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices))
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
void __user *uaddr = (void __user *)(long)reg->addr;
|
|
u64 val;
|
|
int ret;
|
|
|
|
ret = copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id));
|
|
if (ret != 0)
|
|
return -EFAULT;
|
|
|
|
return kvm_arm_timer_set_reg(vcpu, reg->id, val);
|
|
}
|
|
|
|
static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
void __user *uaddr = (void __user *)(long)reg->addr;
|
|
u64 val;
|
|
|
|
val = kvm_arm_timer_get_reg(vcpu, reg->id);
|
|
return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
|
|
}
|
|
|
|
static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
|
|
{
|
|
const unsigned int slices = vcpu_sve_slices(vcpu);
|
|
|
|
if (!vcpu_has_sve(vcpu))
|
|
return 0;
|
|
|
|
/* Policed by KVM_GET_REG_LIST: */
|
|
WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
|
|
|
|
return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
|
|
+ 1; /* KVM_REG_ARM64_SVE_VLS */
|
|
}
|
|
|
|
static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
|
|
u64 __user *uindices)
|
|
{
|
|
const unsigned int slices = vcpu_sve_slices(vcpu);
|
|
u64 reg;
|
|
unsigned int i, n;
|
|
int num_regs = 0;
|
|
|
|
if (!vcpu_has_sve(vcpu))
|
|
return 0;
|
|
|
|
/* Policed by KVM_GET_REG_LIST: */
|
|
WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
|
|
|
|
/*
|
|
* Enumerate this first, so that userspace can save/restore in
|
|
* the order reported by KVM_GET_REG_LIST:
|
|
*/
|
|
reg = KVM_REG_ARM64_SVE_VLS;
|
|
if (put_user(reg, uindices++))
|
|
return -EFAULT;
|
|
++num_regs;
|
|
|
|
for (i = 0; i < slices; i++) {
|
|
for (n = 0; n < SVE_NUM_ZREGS; n++) {
|
|
reg = KVM_REG_ARM64_SVE_ZREG(n, i);
|
|
if (put_user(reg, uindices++))
|
|
return -EFAULT;
|
|
num_regs++;
|
|
}
|
|
|
|
for (n = 0; n < SVE_NUM_PREGS; n++) {
|
|
reg = KVM_REG_ARM64_SVE_PREG(n, i);
|
|
if (put_user(reg, uindices++))
|
|
return -EFAULT;
|
|
num_regs++;
|
|
}
|
|
|
|
reg = KVM_REG_ARM64_SVE_FFR(i);
|
|
if (put_user(reg, uindices++))
|
|
return -EFAULT;
|
|
num_regs++;
|
|
}
|
|
|
|
return num_regs;
|
|
}
|
|
|
|
/**
|
|
* kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
|
|
*
|
|
* This is for all registers.
|
|
*/
|
|
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
|
|
{
|
|
unsigned long res = 0;
|
|
|
|
res += num_core_regs(vcpu);
|
|
res += num_sve_regs(vcpu);
|
|
res += kvm_arm_num_sys_reg_descs(vcpu);
|
|
res += kvm_arm_get_fw_num_regs(vcpu);
|
|
res += NUM_TIMER_REGS;
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* kvm_arm_copy_reg_indices - get indices of all registers.
|
|
*
|
|
* We do core registers right here, then we append system regs.
|
|
*/
|
|
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
|
{
|
|
int ret;
|
|
|
|
ret = copy_core_reg_indices(vcpu, uindices);
|
|
if (ret < 0)
|
|
return ret;
|
|
uindices += ret;
|
|
|
|
ret = copy_sve_reg_indices(vcpu, uindices);
|
|
if (ret < 0)
|
|
return ret;
|
|
uindices += ret;
|
|
|
|
ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
|
|
if (ret < 0)
|
|
return ret;
|
|
uindices += kvm_arm_get_fw_num_regs(vcpu);
|
|
|
|
ret = copy_timer_indices(vcpu, uindices);
|
|
if (ret < 0)
|
|
return ret;
|
|
uindices += NUM_TIMER_REGS;
|
|
|
|
return kvm_arm_copy_sys_reg_indices(vcpu, uindices);
|
|
}
|
|
|
|
int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
/* We currently use nothing arch-specific in upper 32 bits */
|
|
if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
|
|
return -EINVAL;
|
|
|
|
switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
|
|
case KVM_REG_ARM_CORE: return get_core_reg(vcpu, reg);
|
|
case KVM_REG_ARM_FW: return kvm_arm_get_fw_reg(vcpu, reg);
|
|
case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg);
|
|
}
|
|
|
|
if (is_timer_reg(reg->id))
|
|
return get_timer_reg(vcpu, reg);
|
|
|
|
return kvm_arm_sys_reg_get_reg(vcpu, reg);
|
|
}
|
|
|
|
int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
|
{
|
|
/* We currently use nothing arch-specific in upper 32 bits */
|
|
if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
|
|
return -EINVAL;
|
|
|
|
switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
|
|
case KVM_REG_ARM_CORE: return set_core_reg(vcpu, reg);
|
|
case KVM_REG_ARM_FW: return kvm_arm_set_fw_reg(vcpu, reg);
|
|
case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg);
|
|
}
|
|
|
|
if (is_timer_reg(reg->id))
|
|
return set_timer_reg(vcpu, reg);
|
|
|
|
return kvm_arm_sys_reg_set_reg(vcpu, reg);
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
|
|
struct kvm_sregs *sregs)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
|
struct kvm_sregs *sregs)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
|
|
struct kvm_vcpu_events *events)
|
|
{
|
|
events->exception.serror_pending = !!(vcpu->arch.hcr_el2 & HCR_VSE);
|
|
events->exception.serror_has_esr = cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
|
|
|
|
if (events->exception.serror_pending && events->exception.serror_has_esr)
|
|
events->exception.serror_esr = vcpu_get_vsesr(vcpu);
|
|
|
|
/*
|
|
* We never return a pending ext_dabt here because we deliver it to
|
|
* the virtual CPU directly when setting the event and it's no longer
|
|
* 'pending' at this point.
|
|
*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
|
|
struct kvm_vcpu_events *events)
|
|
{
|
|
bool serror_pending = events->exception.serror_pending;
|
|
bool has_esr = events->exception.serror_has_esr;
|
|
bool ext_dabt_pending = events->exception.ext_dabt_pending;
|
|
|
|
if (serror_pending && has_esr) {
|
|
if (!cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
|
|
return -EINVAL;
|
|
|
|
if (!((events->exception.serror_esr) & ~ESR_ELx_ISS_MASK))
|
|
kvm_set_sei_esr(vcpu, events->exception.serror_esr);
|
|
else
|
|
return -EINVAL;
|
|
} else if (serror_pending) {
|
|
kvm_inject_vabt(vcpu);
|
|
}
|
|
|
|
if (ext_dabt_pending)
|
|
kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int __attribute_const__ kvm_target_cpu(void)
|
|
{
|
|
unsigned long implementor = read_cpuid_implementor();
|
|
unsigned long part_number = read_cpuid_part_number();
|
|
|
|
switch (implementor) {
|
|
case ARM_CPU_IMP_ARM:
|
|
switch (part_number) {
|
|
case ARM_CPU_PART_AEM_V8:
|
|
return KVM_ARM_TARGET_AEM_V8;
|
|
case ARM_CPU_PART_FOUNDATION:
|
|
return KVM_ARM_TARGET_FOUNDATION_V8;
|
|
case ARM_CPU_PART_CORTEX_A53:
|
|
return KVM_ARM_TARGET_CORTEX_A53;
|
|
case ARM_CPU_PART_CORTEX_A57:
|
|
return KVM_ARM_TARGET_CORTEX_A57;
|
|
}
|
|
break;
|
|
case ARM_CPU_IMP_APM:
|
|
switch (part_number) {
|
|
case APM_CPU_PART_POTENZA:
|
|
return KVM_ARM_TARGET_XGENE_POTENZA;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* Return a default generic target */
|
|
return KVM_ARM_TARGET_GENERIC_V8;
|
|
}
|
|
|
|
int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init)
|
|
{
|
|
int target = kvm_target_cpu();
|
|
|
|
if (target < 0)
|
|
return -ENODEV;
|
|
|
|
memset(init, 0, sizeof(*init));
|
|
|
|
/*
|
|
* For now, we don't return any features.
|
|
* In future, we might use features to return target
|
|
* specific features available for the preferred
|
|
* target type.
|
|
*/
|
|
init->target = (__u32)target;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
|
|
struct kvm_translation *tr)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
|
|
KVM_GUESTDBG_USE_SW_BP | \
|
|
KVM_GUESTDBG_USE_HW | \
|
|
KVM_GUESTDBG_SINGLESTEP)
|
|
|
|
/**
|
|
* kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging
|
|
* @kvm: pointer to the KVM struct
|
|
* @kvm_guest_debug: the ioctl data buffer
|
|
*
|
|
* This sets up and enables the VM for guest debugging. Userspace
|
|
* passes in a control flag to enable different debug types and
|
|
* potentially other architecture specific information in the rest of
|
|
* the structure.
|
|
*/
|
|
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
|
|
struct kvm_guest_debug *dbg)
|
|
{
|
|
int ret = 0;
|
|
|
|
trace_kvm_set_guest_debug(vcpu, dbg->control);
|
|
|
|
if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) {
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
if (dbg->control & KVM_GUESTDBG_ENABLE) {
|
|
vcpu->guest_debug = dbg->control;
|
|
|
|
/* Hardware assisted Break and Watch points */
|
|
if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
|
|
vcpu->arch.external_debug_state = dbg->arch;
|
|
}
|
|
|
|
} else {
|
|
/* If not enabled clear all flags */
|
|
vcpu->guest_debug = 0;
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu,
|
|
struct kvm_device_attr *attr)
|
|
{
|
|
int ret;
|
|
|
|
switch (attr->group) {
|
|
case KVM_ARM_VCPU_PMU_V3_CTRL:
|
|
ret = kvm_arm_pmu_v3_set_attr(vcpu, attr);
|
|
break;
|
|
case KVM_ARM_VCPU_TIMER_CTRL:
|
|
ret = kvm_arm_timer_set_attr(vcpu, attr);
|
|
break;
|
|
case KVM_ARM_VCPU_PVTIME_CTRL:
|
|
ret = kvm_arm_pvtime_set_attr(vcpu, attr);
|
|
break;
|
|
default:
|
|
ret = -ENXIO;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
|
|
struct kvm_device_attr *attr)
|
|
{
|
|
int ret;
|
|
|
|
switch (attr->group) {
|
|
case KVM_ARM_VCPU_PMU_V3_CTRL:
|
|
ret = kvm_arm_pmu_v3_get_attr(vcpu, attr);
|
|
break;
|
|
case KVM_ARM_VCPU_TIMER_CTRL:
|
|
ret = kvm_arm_timer_get_attr(vcpu, attr);
|
|
break;
|
|
case KVM_ARM_VCPU_PVTIME_CTRL:
|
|
ret = kvm_arm_pvtime_get_attr(vcpu, attr);
|
|
break;
|
|
default:
|
|
ret = -ENXIO;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
|
|
struct kvm_device_attr *attr)
|
|
{
|
|
int ret;
|
|
|
|
switch (attr->group) {
|
|
case KVM_ARM_VCPU_PMU_V3_CTRL:
|
|
ret = kvm_arm_pmu_v3_has_attr(vcpu, attr);
|
|
break;
|
|
case KVM_ARM_VCPU_TIMER_CTRL:
|
|
ret = kvm_arm_timer_has_attr(vcpu, attr);
|
|
break;
|
|
case KVM_ARM_VCPU_PVTIME_CTRL:
|
|
ret = kvm_arm_pvtime_has_attr(vcpu, attr);
|
|
break;
|
|
default:
|
|
ret = -ENXIO;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|