-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAlsOO14ACgkQONu9yGCS aT4ulhAAhMVYSRa/cOFm0BHxSL/59WmJTa3Na8TJqkTrJy+LRluBiKCywyiMZknp 4rIffv4jcxcFNCpqYTjNTSStGLWCCkBLNSzxuzFv5M89Jdx4Gz1Ww1hzMESP3gxK puHUewSJQm7qtVOiC2l4YcW3Q6nFK0kqbCWpSkHoGVfZoX9JS2P1V8n+KFZpUH1a UyhVW48ainUpXfhSKJZ5xABiWYM2hcSq52RW1edNZvwuKwulZ+2EME26HgGCK7ff WHzGHECE6Lem+iunR26J/QtbTo8LKEyU0F039X21E7FIxf33S0xyPx+MGjJfWBOo Q6A23mAEWwEhlMomNKzdd/iUzSVlWSzKe8LJa7GI5G6BxftN8Z0TGTnKzIDkw++M T6RfK03CP6c9rQ756d0fTPxdZh6ae9EN8WSot/Sbbc9SvGSfy6o4I8Y/uJygShmF j13JfMweC+t7/6fyUqc5dcgY0Xy7LUFiWqfPxQj6axDiT82Mx2AvQaczrPUAKr1K KQsetmyhHC+Cpy7ILrhUGYjEWlvQm11ZiFoX8BkocFLFWk736QA63iB7mOUpCOQR SKLK00dF163GJdQC6nb4wCtyBxnCg4pSoP/72Z1foPtaSd3ccJ4CLsIE6GY5sP/I sDlPnIlnzEDfDPIxtVfKC8e1JINP6awXwtoJJo6MnuCuP3LDb58= =ogZQ -----END PGP SIGNATURE----- Merge 4.4.134 into android-4.4 Changes in 4.4.134 MIPS: ptrace: Expose FIR register through FP regset MIPS: Fix ptrace(2) PTRACE_PEEKUSR and PTRACE_POKEUSR accesses to o32 FGRs KVM: Fix spelling mistake: "cop_unsuable" -> "cop_unusable" affs_lookup(): close a race with affs_remove_link() aio: fix io_destroy(2) vs. lookup_ioctx() race ALSA: timer: Fix pause event notification mmc: sdhci-iproc: fix 32bit writes for TRANSFER_MODE register libata: Blacklist some Sandisk SSDs for NCQ libata: blacklist Micron 500IT SSD with MU01 firmware xen-swiotlb: fix the check condition for xen_swiotlb_free_coherent Revert "ipc/shm: Fix shmat mmap nil-page protection" ipc/shm: fix shmat() nil address after round-down when remapping kasan: fix memory hotplug during boot kernel/sys.c: fix potential Spectre v1 issue kernel/signal.c: avoid undefined behaviour in kill_something_info xfs: remove racy hasattr check from attr ops do d_instantiate/unlock_new_inode combinations safely firewire-ohci: work around oversized DMA reads on JMicron controllers NFSv4: always set NFS_LOCK_LOST when a lock is lost. ALSA: hda - Use IS_REACHABLE() for dependency on input ASoC: au1x: Fix timeout tests in au1xac97c_ac97_read() kvm: x86: fix KVM_XEN_HVM_CONFIG ioctl tracing/hrtimer: Fix tracing bugs by taking all clock bases and modes into account PCI: Add function 1 DMA alias quirk for Marvell 9128 tools lib traceevent: Simplify pointer print logic and fix %pF perf callchain: Fix attr.sample_max_stack setting tools lib traceevent: Fix get_field_str() for dynamic strings dm thin: fix documentation relative to low water mark threshold nfs: Do not convert nfs_idmap_cache_timeout to jiffies watchdog: sp5100_tco: Fix watchdog disable bit kconfig: Don't leak main menus during parsing kconfig: Fix automatic menu creation mem leak kconfig: Fix expr_free() E_NOT leak mac80211_hwsim: fix possible memory leak in hwsim_new_radio_nl() ipmi/powernv: Fix error return code in ipmi_powernv_probe() Btrfs: set plug for fsync btrfs: Fix out of bounds access in btrfs_search_slot Btrfs: fix scrub to repair raid6 corruption scsi: fas216: fix sense buffer initialization HID: roccat: prevent an out of bounds read in kovaplus_profile_activated() jffs2: Fix use-after-free bug in jffs2_iget()'s error handling path powerpc/numa: Use ibm,max-associativity-domains to discover possible nodes powerpc/numa: Ensure nodes initialized for hotplug RDMA/mlx5: Avoid memory leak in case of XRCD dealloc failure ntb_transport: Fix bug with max_mw_size parameter ocfs2: return -EROFS to mount.ocfs2 if inode block is invalid ocfs2/acl: use 'ip_xattr_sem' to protect getting extended attribute ocfs2: return error when we attempt to access a dirty bh in jbd2 mm/mempolicy: fix the check of nodemask from user mm/mempolicy: add nodes_empty check in SYSC_migrate_pages asm-generic: provide generic_pmdp_establish() mm: pin address_space before dereferencing it while isolating an LRU page IB/ipoib: Fix for potential no-carrier state x86/power: Fix swsusp_arch_resume prototype firmware: dmi_scan: Fix handling of empty DMI strings ACPI: processor_perflib: Do not send _PPC change notification if not ready bpf: fix selftests/bpf test_kmod.sh failure when CONFIG_BPF_JIT_ALWAYS_ON=y MIPS: TXx9: use IS_BUILTIN() for CONFIG_LEDS_CLASS xen-netfront: Fix race between device setup and open xen/grant-table: Use put_page instead of free_page RDS: IB: Fix null pointer issue arm64: spinlock: Fix theoretical trylock() A-B-A with LSE atomics proc: fix /proc/*/map_files lookup cifs: silence compiler warnings showing up with gcc-8.0.0 bcache: properly set task state in bch_writeback_thread() bcache: fix for allocator and register thread race bcache: fix for data collapse after re-attaching an attached device bcache: return attach error when no cache set exist tools/libbpf: handle issues with bpf ELF objects containing .eh_frames locking/qspinlock: Ensure node->count is updated before initialising node irqchip/gic-v3: Change pr_debug message to pr_devel scsi: ufs: Enable quirk to ignore sending WRITE_SAME command scsi: bnx2fc: Fix check in SCSI completion handler for timed out request scsi: sym53c8xx_2: iterator underflow in sym_getsync() scsi: mptfusion: Add bounds check in mptctl_hp_targetinfo() scsi: qla2xxx: Avoid triggering undefined behavior in qla2x00_mbx_completion() ARC: Fix malformed ARC_EMUL_UNALIGNED default usb: gadget: f_uac2: fix bFirstInterface in composite gadget usb: gadget: fsl_udc_core: fix ep valid checks usb: dwc2: Fix dwc2_hsotg_core_init_disconnected() selftests: memfd: add config fragment for fuse scsi: storvsc: Increase cmd_per_lun for higher speed devices scsi: aacraid: fix shutdown crash when init fails scsi: qla4xxx: skip error recovery in case of register disconnect. ARM: OMAP2+: timer: fix a kmemleak caused in omap_get_timer_dt ARM: OMAP3: Fix prm wake interrupt for resume ARM: OMAP1: clock: Fix debugfs_create_*() usage NFC: llcp: Limit size of SDP URI mac80211: round IEEE80211_TX_STATUS_HEADROOM up to multiple of 4 md raid10: fix NULL deference in handle_write_completed() drm/exynos: fix comparison to bitshift when dealing with a mask usb: musb: fix enumeration after resume locking/xchg/alpha: Add unconditional memory barrier to cmpxchg() md: raid5: avoid string overflow warning kernel/relay.c: limit kmalloc size to KMALLOC_MAX_SIZE powerpc/bpf/jit: Fix 32-bit JIT for seccomp_data access s390/cio: fix return code after missing interrupt s390/cio: clear timer when terminating driver I/O ARM: OMAP: Fix dmtimer init for omap1 smsc75xx: fix smsc75xx_set_features() regulatory: add NUL to request alpha2 locking/xchg/alpha: Fix xchg() and cmpxchg() memory ordering bugs x86/topology: Update the 'cpu cores' field in /proc/cpuinfo correctly across CPU hotplug operations media: dmxdev: fix error code for invalid ioctls md/raid1: fix NULL pointer dereference batman-adv: fix packet checksum in receive path batman-adv: invalidate checksum on fragment reassembly netfilter: ebtables: convert BUG_ONs to WARN_ONs nvme-pci: Fix nvme queue cleanup if IRQ setup fails clocksource/drivers/fsl_ftm_timer: Fix error return checking r8152: fix tx packets accounting virtio-gpu: fix ioctl and expose the fixed status to userspace. dmaengine: rcar-dmac: fix max_chunk_size for R-Car Gen3 bcache: fix kcrashes with fio in RAID5 backend dev sit: fix IFLA_MTU ignored on NEWLINK gianfar: Fix Rx byte accounting for ndev stats net/tcp/illinois: replace broken algorithm reference link xen/pirq: fix error path cleanup when binding MSIs Btrfs: send, fix issuing write op when processing hole in no data mode selftests/powerpc: Skip the subpage_prot tests if the syscall is unavailable KVM: PPC: Book3S HV: Fix VRMA initialization with 2MB or 1GB memory backing watchdog: f71808e_wdt: Fix magic close handling e1000e: Fix check_for_link return value with autoneg off e1000e: allocate ring descriptors with dma_zalloc_coherent usb: musb: call pm_runtime_{get,put}_sync before reading vbus registers scsi: mpt3sas: Do not mark fw_event workqueue as WQ_MEM_RECLAIM scsi: sd: Keep disk read-only when re-reading partition fbdev: Fixing arbitrary kernel leak in case FBIOGETCMAP_SPARC in sbusfb_ioctl_helper(). xen: xenbus: use put_device() instead of kfree() USB: OHCI: Fix NULL dereference in HCDs using HCD_LOCAL_MEM netfilter: ebtables: fix erroneous reject of last rule bnxt_en: Check valid VNIC ID in bnxt_hwrm_vnic_set_tpa(). workqueue: use put_device() instead of kfree() ipv4: lock mtu in fnhe when received PMTU < net.ipv4.route.min_pmtu sunvnet: does not support GSO for sctp net: Fix vlan untag for bridge and vlan_dev with reorder_hdr off batman-adv: fix header size check in batadv_dbg_arp() vti4: Don't count header length twice on tunnel setup vti4: Don't override MTU passed on link creation via IFLA_MTU perf/cgroup: Fix child event counting bug RDMA/ucma: Correct option size check using optlen mm/mempolicy.c: avoid use uninitialized preferred_node selftests: ftrace: Add probe event argument syntax testcase selftests: ftrace: Add a testcase for string type with kprobe_event selftests: ftrace: Add a testcase for probepoint batman-adv: fix multicast-via-unicast transmission with AP isolation batman-adv: fix packet loss for broadcasted DHCP packets to a server ARM: 8748/1: mm: Define vdso_start, vdso_end as array net: qmi_wwan: add BroadMobi BM806U 2020:2033 net/usb/qmi_wwan.c: Add USB id for lt4120 modem net-usb: add qmi_wwan if on lte modem wistron neweb d18q1 llc: properly handle dev_queue_xmit() return value mm/kmemleak.c: wait for scan completion before disabling free net: Fix untag for vlan packets without ethernet header net: mvneta: fix enable of all initialized RXQs sh: fix debug trap failure to process signals before return to user x86/pgtable: Don't set huge PUD/PMD on non-leaf entries fs/proc/proc_sysctl.c: fix potential page fault while unregistering sysctl table swap: divide-by-zero when zero length swap file on ssd sr: get/drop reference to device in revalidate and check_events Force log to disk before reading the AGF during a fstrim cpufreq: CPPC: Initialize shared perf capabilities of CPUs scsi: aacraid: Insure command thread is not recursively stopped dp83640: Ensure against premature access to PHY registers after reset mm/ksm: fix interaction with THP mm: fix races between address_space dereference and free in page_evicatable Btrfs: bail out on error during replay_dir_deletes Btrfs: fix NULL pointer dereference in log_dir_items btrfs: Fix possible softlock on single core machines ocfs2/dlm: don't handle migrate lockres if already in shutdown sched/rt: Fix rq->clock_update_flags < RQCF_ACT_SKIP warning KVM: VMX: raise internal error for exception during invalid protected mode state fscache: Fix hanging wait on page discarded by writeback sparc64: Make atomic_xchg() an inline function rather than a macro. rtc: snvs: Fix usage of snvs_rtc_enable net: bgmac: Fix endian access in bgmac_dma_tx_ring_free() Bluetooth: btusb: Add USB ID 7392:a611 for Edimax EW-7611ULB btrfs: tests/qgroup: Fix wrong tree backref level Btrfs: fix copy_items() return value when logging an inode btrfs: fix lockdep splat in btrfs_alloc_subvolume_writers xen/acpi: off by one in read_acpi_id() ACPI: acpi_pad: Fix memory leak in power saving threads powerpc/mpic: Check if cpu_possible() in mpic_physmask() m68k: set dma and coherent masks for platform FEC ethernets parisc/pci: Switch LBA PCI bus from Hard Fail to Soft Fail mode hwmon: (nct6775) Fix writing pwmX_mode rtc: hctosys: Ensure system time doesn't overflow time_t powerpc/perf: Prevent kernel address leak to userspace via BHRB buffer powerpc/perf: Fix kernel address leak via sampling registers tools/thermal: tmon: fix for segfault selftests: Print the test we're running to /dev/kmsg net/mlx5: Protect from command bit overflow ath10k: Fix kernel panic while using worker (ath10k_sta_rc_update_wk) ima: Fix Kconfig to select TPM 2.0 CRB interface ima: Fallback to the builtin hash algorithm virtio-net: Fix operstate for virtio when no VIRTIO_NET_F_STATUS arm: dts: socfpga: fix GIC PPI warning usb: dwc3: Update DWC_usb31 GTXFIFOSIZ reg fields cpufreq: cppc_cpufreq: Fix cppc_cpufreq_init() failure path clk: Don't show the incorrect clock phase zorro: Set up z->dev.dma_mask for the DMA API bcache: quit dc->writeback_thread when BCACHE_DEV_DETACHING is set ACPICA: Events: add a return on failure from acpi_hw_register_read ACPICA: acpi: acpica: fix acpi operand cache leak in nseval.c i2c: mv64xxx: Apply errata delay only in standard mode KVM: lapic: stop advertising DIRECTED_EOI when in-kernel IOAPIC is in use xhci: zero usb device slot_id member when disabling and freeing a xhci slot MIPS: ath79: Fix AR724X_PLL_REG_PCIE_CONFIG offset PCI: Restore config space on runtime resume despite being unbound ipmi_ssif: Fix kernel panic at msg_done_handler usb: dwc2: Fix interval type issue usb: gadget: ffs: Let setup() return USB_GADGET_DELAYED_STATUS usb: gadget: ffs: Execute copy_to_user() with USER_DS set powerpc: Add missing prototype for arch_irq_work_raise() ASoC: topology: create TLV data for dapm widgets perf/core: Fix perf_output_read_group() hwmon: (pmbus/max8688) Accept negative page register values hwmon: (pmbus/adm1275) Accept negative page register values cdrom: do not call check_disk_change() inside cdrom_open() gfs2: Fix fallocate chunk size usb: gadget: udc: change comparison to bitshift when dealing with a mask usb: gadget: composite: fix incorrect handling of OS desc requests x86/devicetree: Initialize device tree before using it x86/devicetree: Fix device IRQ settings in DT ALSA: vmaster: Propagate slave error media: cx23885: Override 888 ImpactVCBe crystal frequency media: cx23885: Set subdev host data to clk_freq pointer media: s3c-camif: fix out-of-bounds array access dmaengine: pl330: fix a race condition in case of threaded irqs media: em28xx: USB bulk packet size fix clk: rockchip: Prevent calculating mmc phase if clock rate is zero enic: enable rq before updating rq descriptors hwrng: stm32 - add reset during probe staging: rtl8192u: return -ENOMEM on failed allocation of priv->oldaddr rtc: tx4939: avoid unintended sign extension on a 24 bit shift serial: xuartps: Fix out-of-bounds access through DT alias serial: samsung: Fix out-of-bounds access through serial port index serial: mxs-auart: Fix out-of-bounds access through serial port index serial: imx: Fix out-of-bounds access through serial port index serial: fsl_lpuart: Fix out-of-bounds access through DT alias serial: arc_uart: Fix out-of-bounds access through DT alias PCI: Add function 1 DMA alias quirk for Marvell 88SE9220 udf: Provide saner default for invalid uid / gid media: cx25821: prevent out-of-bounds read on array card clk: samsung: s3c2410: Fix PLL rates clk: samsung: exynos5260: Fix PLL rates clk: samsung: exynos5433: Fix PLL rates clk: samsung: exynos5250: Fix PLL rates clk: samsung: exynos3250: Fix PLL rates crypto: sunxi-ss - Add MODULE_ALIAS to sun4i-ss audit: return on memory error to avoid null pointer dereference MIPS: Octeon: Fix logging messages with spurious periods after newlines drm/rockchip: Respect page offset for PRIME mmap calls x86/apic: Set up through-local-APIC mode on the boot CPU if 'noapic' specified perf tests: Use arch__compare_symbol_names to compare symbols perf report: Fix memory corruption in --branch-history mode --branch-history selftests/net: fixes psock_fanout eBPF test case netlabel: If PF_INET6, check sk_buff ip header version scsi: lpfc: Fix issue_lip if link is disabled scsi: lpfc: Fix soft lockup in lpfc worker thread during LIP testing scsi: lpfc: Fix frequency of Release WQE CQEs regulator: of: Add a missing 'of_node_put()' in an error handling path of 'of_regulator_match()' ASoC: samsung: i2s: Ensure the RCLK rate is properly determined Bluetooth: btusb: Add device ID for RTL8822BE kdb: make "mdr" command repeat s390/ftrace: use expoline for indirect branches Linux 4.4.134 Change-Id: Iababaf9b89bc8d0437b95e1368d8b0a9126a178c Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
1063 lines
26 KiB
C
1063 lines
26 KiB
C
/*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*
|
|
* Copyright (C) 1992 Ross Biro
|
|
* Copyright (C) Linus Torvalds
|
|
* Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
|
|
* Copyright (C) 1996 David S. Miller
|
|
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
|
|
* Copyright (C) 1999 MIPS Technologies, Inc.
|
|
* Copyright (C) 2000 Ulf Carlsson
|
|
*
|
|
* At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
|
|
* binaries.
|
|
*/
|
|
#include <linux/compiler.h>
|
|
#include <linux/context_tracking.h>
|
|
#include <linux/elf.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/regset.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/security.h>
|
|
#include <linux/stddef.h>
|
|
#include <linux/tracehook.h>
|
|
#include <linux/audit.h>
|
|
#include <linux/seccomp.h>
|
|
#include <linux/ftrace.h>
|
|
|
|
#include <asm/byteorder.h>
|
|
#include <asm/cpu.h>
|
|
#include <asm/cpu-info.h>
|
|
#include <asm/dsp.h>
|
|
#include <asm/fpu.h>
|
|
#include <asm/mipsregs.h>
|
|
#include <asm/mipsmtregs.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/page.h>
|
|
#include <asm/syscall.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/bootinfo.h>
|
|
#include <asm/reg.h>
|
|
|
|
#define CREATE_TRACE_POINTS
|
|
#include <trace/events/syscalls.h>
|
|
|
|
static void init_fp_ctx(struct task_struct *target)
|
|
{
|
|
/* If FP has been used then the target already has context */
|
|
if (tsk_used_math(target))
|
|
return;
|
|
|
|
/* Begin with data registers set to all 1s... */
|
|
memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr));
|
|
|
|
/* FCSR has been preset by `mips_set_personality_nan'. */
|
|
|
|
/*
|
|
* Record that the target has "used" math, such that the context
|
|
* just initialised, and any modifications made by the caller,
|
|
* aren't discarded.
|
|
*/
|
|
set_stopped_child_used_math(target);
|
|
}
|
|
|
|
/*
|
|
* Called by kernel/ptrace.c when detaching..
|
|
*
|
|
* Make sure single step bits etc are not set.
|
|
*/
|
|
void ptrace_disable(struct task_struct *child)
|
|
{
|
|
/* Don't load the watchpoint registers for the ex-child. */
|
|
clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
|
|
}
|
|
|
|
/*
|
|
* Poke at FCSR according to its mask. Set the Cause bits even
|
|
* if a corresponding Enable bit is set. This will be noticed at
|
|
* the time the thread is switched to and SIGFPE thrown accordingly.
|
|
*/
|
|
static void ptrace_setfcr31(struct task_struct *child, u32 value)
|
|
{
|
|
u32 fcr31;
|
|
u32 mask;
|
|
|
|
fcr31 = child->thread.fpu.fcr31;
|
|
mask = boot_cpu_data.fpu_msk31;
|
|
child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
|
|
}
|
|
|
|
/*
|
|
* Read a general register set. We always use the 64-bit format, even
|
|
* for 32-bit kernels and for 32-bit processes on a 64-bit kernel.
|
|
* Registers are sign extended to fill the available space.
|
|
*/
|
|
int ptrace_getregs(struct task_struct *child, struct user_pt_regs __user *data)
|
|
{
|
|
struct pt_regs *regs;
|
|
int i;
|
|
|
|
if (!access_ok(VERIFY_WRITE, data, 38 * 8))
|
|
return -EIO;
|
|
|
|
regs = task_pt_regs(child);
|
|
|
|
for (i = 0; i < 32; i++)
|
|
__put_user((long)regs->regs[i], (__s64 __user *)&data->regs[i]);
|
|
__put_user((long)regs->lo, (__s64 __user *)&data->lo);
|
|
__put_user((long)regs->hi, (__s64 __user *)&data->hi);
|
|
__put_user((long)regs->cp0_epc, (__s64 __user *)&data->cp0_epc);
|
|
__put_user((long)regs->cp0_badvaddr, (__s64 __user *)&data->cp0_badvaddr);
|
|
__put_user((long)regs->cp0_status, (__s64 __user *)&data->cp0_status);
|
|
__put_user((long)regs->cp0_cause, (__s64 __user *)&data->cp0_cause);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a general register set. As for PTRACE_GETREGS, we always use
|
|
* the 64-bit format. On a 32-bit kernel only the lower order half
|
|
* (according to endianness) will be used.
|
|
*/
|
|
int ptrace_setregs(struct task_struct *child, struct user_pt_regs __user *data)
|
|
{
|
|
struct pt_regs *regs;
|
|
int i;
|
|
|
|
if (!access_ok(VERIFY_READ, data, 38 * 8))
|
|
return -EIO;
|
|
|
|
regs = task_pt_regs(child);
|
|
|
|
for (i = 0; i < 32; i++)
|
|
__get_user(regs->regs[i], (__s64 __user *)&data->regs[i]);
|
|
__get_user(regs->lo, (__s64 __user *)&data->lo);
|
|
__get_user(regs->hi, (__s64 __user *)&data->hi);
|
|
__get_user(regs->cp0_epc, (__s64 __user *)&data->cp0_epc);
|
|
|
|
/* badvaddr, status, and cause may not be written. */
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
|
|
{
|
|
int i;
|
|
|
|
if (!access_ok(VERIFY_WRITE, data, 33 * 8))
|
|
return -EIO;
|
|
|
|
if (tsk_used_math(child)) {
|
|
union fpureg *fregs = get_fpu_regs(child);
|
|
for (i = 0; i < 32; i++)
|
|
__put_user(get_fpr64(&fregs[i], 0),
|
|
i + (__u64 __user *)data);
|
|
} else {
|
|
for (i = 0; i < 32; i++)
|
|
__put_user((__u64) -1, i + (__u64 __user *) data);
|
|
}
|
|
|
|
__put_user(child->thread.fpu.fcr31, data + 64);
|
|
__put_user(boot_cpu_data.fpu_id, data + 65);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
|
|
{
|
|
union fpureg *fregs;
|
|
u64 fpr_val;
|
|
u32 value;
|
|
int i;
|
|
|
|
if (!access_ok(VERIFY_READ, data, 33 * 8))
|
|
return -EIO;
|
|
|
|
init_fp_ctx(child);
|
|
fregs = get_fpu_regs(child);
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
__get_user(fpr_val, i + (__u64 __user *)data);
|
|
set_fpr64(&fregs[i], 0, fpr_val);
|
|
}
|
|
|
|
__get_user(value, data + 64);
|
|
ptrace_setfcr31(child, value);
|
|
|
|
/* FIR may not be written. */
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ptrace_get_watch_regs(struct task_struct *child,
|
|
struct pt_watch_regs __user *addr)
|
|
{
|
|
enum pt_watch_style style;
|
|
int i;
|
|
|
|
if (!cpu_has_watch || boot_cpu_data.watch_reg_use_cnt == 0)
|
|
return -EIO;
|
|
if (!access_ok(VERIFY_WRITE, addr, sizeof(struct pt_watch_regs)))
|
|
return -EIO;
|
|
|
|
#ifdef CONFIG_32BIT
|
|
style = pt_watch_style_mips32;
|
|
#define WATCH_STYLE mips32
|
|
#else
|
|
style = pt_watch_style_mips64;
|
|
#define WATCH_STYLE mips64
|
|
#endif
|
|
|
|
__put_user(style, &addr->style);
|
|
__put_user(boot_cpu_data.watch_reg_use_cnt,
|
|
&addr->WATCH_STYLE.num_valid);
|
|
for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
|
|
__put_user(child->thread.watch.mips3264.watchlo[i],
|
|
&addr->WATCH_STYLE.watchlo[i]);
|
|
__put_user(child->thread.watch.mips3264.watchhi[i] & 0xfff,
|
|
&addr->WATCH_STYLE.watchhi[i]);
|
|
__put_user(boot_cpu_data.watch_reg_masks[i],
|
|
&addr->WATCH_STYLE.watch_masks[i]);
|
|
}
|
|
for (; i < 8; i++) {
|
|
__put_user(0, &addr->WATCH_STYLE.watchlo[i]);
|
|
__put_user(0, &addr->WATCH_STYLE.watchhi[i]);
|
|
__put_user(0, &addr->WATCH_STYLE.watch_masks[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ptrace_set_watch_regs(struct task_struct *child,
|
|
struct pt_watch_regs __user *addr)
|
|
{
|
|
int i;
|
|
int watch_active = 0;
|
|
unsigned long lt[NUM_WATCH_REGS];
|
|
u16 ht[NUM_WATCH_REGS];
|
|
|
|
if (!cpu_has_watch || boot_cpu_data.watch_reg_use_cnt == 0)
|
|
return -EIO;
|
|
if (!access_ok(VERIFY_READ, addr, sizeof(struct pt_watch_regs)))
|
|
return -EIO;
|
|
/* Check the values. */
|
|
for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
|
|
__get_user(lt[i], &addr->WATCH_STYLE.watchlo[i]);
|
|
#ifdef CONFIG_32BIT
|
|
if (lt[i] & __UA_LIMIT)
|
|
return -EINVAL;
|
|
#else
|
|
if (test_tsk_thread_flag(child, TIF_32BIT_ADDR)) {
|
|
if (lt[i] & 0xffffffff80000000UL)
|
|
return -EINVAL;
|
|
} else {
|
|
if (lt[i] & __UA_LIMIT)
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
__get_user(ht[i], &addr->WATCH_STYLE.watchhi[i]);
|
|
if (ht[i] & ~0xff8)
|
|
return -EINVAL;
|
|
}
|
|
/* Install them. */
|
|
for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) {
|
|
if (lt[i] & 7)
|
|
watch_active = 1;
|
|
child->thread.watch.mips3264.watchlo[i] = lt[i];
|
|
/* Set the G bit. */
|
|
child->thread.watch.mips3264.watchhi[i] = ht[i];
|
|
}
|
|
|
|
if (watch_active)
|
|
set_tsk_thread_flag(child, TIF_LOAD_WATCH);
|
|
else
|
|
clear_tsk_thread_flag(child, TIF_LOAD_WATCH);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* regset get/set implementations */
|
|
|
|
#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
|
|
|
|
static int gpr32_get(struct task_struct *target,
|
|
const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
void *kbuf, void __user *ubuf)
|
|
{
|
|
struct pt_regs *regs = task_pt_regs(target);
|
|
u32 uregs[ELF_NGREG] = {};
|
|
unsigned i;
|
|
|
|
for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) {
|
|
/* k0/k1 are copied as zero. */
|
|
if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27)
|
|
continue;
|
|
|
|
uregs[i] = regs->regs[i - MIPS32_EF_R0];
|
|
}
|
|
|
|
uregs[MIPS32_EF_LO] = regs->lo;
|
|
uregs[MIPS32_EF_HI] = regs->hi;
|
|
uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc;
|
|
uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
|
|
uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status;
|
|
uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause;
|
|
|
|
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
|
|
sizeof(uregs));
|
|
}
|
|
|
|
static int gpr32_set(struct task_struct *target,
|
|
const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf)
|
|
{
|
|
struct pt_regs *regs = task_pt_regs(target);
|
|
u32 uregs[ELF_NGREG];
|
|
unsigned start, num_regs, i;
|
|
int err;
|
|
|
|
start = pos / sizeof(u32);
|
|
num_regs = count / sizeof(u32);
|
|
|
|
if (start + num_regs > ELF_NGREG)
|
|
return -EIO;
|
|
|
|
err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
|
|
sizeof(uregs));
|
|
if (err)
|
|
return err;
|
|
|
|
for (i = start; i < num_regs; i++) {
|
|
/*
|
|
* Cast all values to signed here so that if this is a 64-bit
|
|
* kernel, the supplied 32-bit values will be sign extended.
|
|
*/
|
|
switch (i) {
|
|
case MIPS32_EF_R1 ... MIPS32_EF_R25:
|
|
/* k0/k1 are ignored. */
|
|
case MIPS32_EF_R28 ... MIPS32_EF_R31:
|
|
regs->regs[i - MIPS32_EF_R0] = (s32)uregs[i];
|
|
break;
|
|
case MIPS32_EF_LO:
|
|
regs->lo = (s32)uregs[i];
|
|
break;
|
|
case MIPS32_EF_HI:
|
|
regs->hi = (s32)uregs[i];
|
|
break;
|
|
case MIPS32_EF_CP0_EPC:
|
|
regs->cp0_epc = (s32)uregs[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
|
|
|
|
#ifdef CONFIG_64BIT
|
|
|
|
static int gpr64_get(struct task_struct *target,
|
|
const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
void *kbuf, void __user *ubuf)
|
|
{
|
|
struct pt_regs *regs = task_pt_regs(target);
|
|
u64 uregs[ELF_NGREG] = {};
|
|
unsigned i;
|
|
|
|
for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) {
|
|
/* k0/k1 are copied as zero. */
|
|
if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27)
|
|
continue;
|
|
|
|
uregs[i] = regs->regs[i - MIPS64_EF_R0];
|
|
}
|
|
|
|
uregs[MIPS64_EF_LO] = regs->lo;
|
|
uregs[MIPS64_EF_HI] = regs->hi;
|
|
uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc;
|
|
uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
|
|
uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status;
|
|
uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause;
|
|
|
|
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
|
|
sizeof(uregs));
|
|
}
|
|
|
|
static int gpr64_set(struct task_struct *target,
|
|
const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf)
|
|
{
|
|
struct pt_regs *regs = task_pt_regs(target);
|
|
u64 uregs[ELF_NGREG];
|
|
unsigned start, num_regs, i;
|
|
int err;
|
|
|
|
start = pos / sizeof(u64);
|
|
num_regs = count / sizeof(u64);
|
|
|
|
if (start + num_regs > ELF_NGREG)
|
|
return -EIO;
|
|
|
|
err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
|
|
sizeof(uregs));
|
|
if (err)
|
|
return err;
|
|
|
|
for (i = start; i < num_regs; i++) {
|
|
switch (i) {
|
|
case MIPS64_EF_R1 ... MIPS64_EF_R25:
|
|
/* k0/k1 are ignored. */
|
|
case MIPS64_EF_R28 ... MIPS64_EF_R31:
|
|
regs->regs[i - MIPS64_EF_R0] = uregs[i];
|
|
break;
|
|
case MIPS64_EF_LO:
|
|
regs->lo = uregs[i];
|
|
break;
|
|
case MIPS64_EF_HI:
|
|
regs->hi = uregs[i];
|
|
break;
|
|
case MIPS64_EF_CP0_EPC:
|
|
regs->cp0_epc = uregs[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* CONFIG_64BIT */
|
|
|
|
/*
|
|
* Copy the floating-point context to the supplied NT_PRFPREG buffer,
|
|
* !CONFIG_CPU_HAS_MSA variant. FP context's general register slots
|
|
* correspond 1:1 to buffer slots. Only general registers are copied.
|
|
*/
|
|
static int fpr_get_fpa(struct task_struct *target,
|
|
unsigned int *pos, unsigned int *count,
|
|
void **kbuf, void __user **ubuf)
|
|
{
|
|
return user_regset_copyout(pos, count, kbuf, ubuf,
|
|
&target->thread.fpu,
|
|
0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
|
|
}
|
|
|
|
/*
|
|
* Copy the floating-point context to the supplied NT_PRFPREG buffer,
|
|
* CONFIG_CPU_HAS_MSA variant. Only lower 64 bits of FP context's
|
|
* general register slots are copied to buffer slots. Only general
|
|
* registers are copied.
|
|
*/
|
|
static int fpr_get_msa(struct task_struct *target,
|
|
unsigned int *pos, unsigned int *count,
|
|
void **kbuf, void __user **ubuf)
|
|
{
|
|
unsigned int i;
|
|
u64 fpr_val;
|
|
int err;
|
|
|
|
BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
|
|
for (i = 0; i < NUM_FPU_REGS; i++) {
|
|
fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
|
|
err = user_regset_copyout(pos, count, kbuf, ubuf,
|
|
&fpr_val, i * sizeof(elf_fpreg_t),
|
|
(i + 1) * sizeof(elf_fpreg_t));
|
|
if (err)
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Copy the floating-point context to the supplied NT_PRFPREG buffer.
|
|
* Choose the appropriate helper for general registers, and then copy
|
|
* the FCSR and FIR registers separately.
|
|
*/
|
|
static int fpr_get(struct task_struct *target,
|
|
const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
void *kbuf, void __user *ubuf)
|
|
{
|
|
const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
|
|
const int fir_pos = fcr31_pos + sizeof(u32);
|
|
int err;
|
|
|
|
if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
|
|
err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf);
|
|
else
|
|
err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf);
|
|
if (err)
|
|
return err;
|
|
|
|
err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
|
&target->thread.fpu.fcr31,
|
|
fcr31_pos, fcr31_pos + sizeof(u32));
|
|
if (err)
|
|
return err;
|
|
|
|
err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
|
&boot_cpu_data.fpu_id,
|
|
fir_pos, fir_pos + sizeof(u32));
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Copy the supplied NT_PRFPREG buffer to the floating-point context,
|
|
* !CONFIG_CPU_HAS_MSA variant. Buffer slots correspond 1:1 to FP
|
|
* context's general register slots. Only general registers are copied.
|
|
*/
|
|
static int fpr_set_fpa(struct task_struct *target,
|
|
unsigned int *pos, unsigned int *count,
|
|
const void **kbuf, const void __user **ubuf)
|
|
{
|
|
return user_regset_copyin(pos, count, kbuf, ubuf,
|
|
&target->thread.fpu,
|
|
0, NUM_FPU_REGS * sizeof(elf_fpreg_t));
|
|
}
|
|
|
|
/*
|
|
* Copy the supplied NT_PRFPREG buffer to the floating-point context,
|
|
* CONFIG_CPU_HAS_MSA variant. Buffer slots are copied to lower 64
|
|
* bits only of FP context's general register slots. Only general
|
|
* registers are copied.
|
|
*/
|
|
static int fpr_set_msa(struct task_struct *target,
|
|
unsigned int *pos, unsigned int *count,
|
|
const void **kbuf, const void __user **ubuf)
|
|
{
|
|
unsigned int i;
|
|
u64 fpr_val;
|
|
int err;
|
|
|
|
BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t));
|
|
for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) {
|
|
err = user_regset_copyin(pos, count, kbuf, ubuf,
|
|
&fpr_val, i * sizeof(elf_fpreg_t),
|
|
(i + 1) * sizeof(elf_fpreg_t));
|
|
if (err)
|
|
return err;
|
|
set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Copy the supplied NT_PRFPREG buffer to the floating-point context.
|
|
* Choose the appropriate helper for general registers, and then copy
|
|
* the FCSR register separately. Ignore the incoming FIR register
|
|
* contents though, as the register is read-only.
|
|
*
|
|
* We optimize for the case where `count % sizeof(elf_fpreg_t) == 0',
|
|
* which is supposed to have been guaranteed by the kernel before
|
|
* calling us, e.g. in `ptrace_regset'. We enforce that requirement,
|
|
* so that we can safely avoid preinitializing temporaries for
|
|
* partial register writes.
|
|
*/
|
|
static int fpr_set(struct task_struct *target,
|
|
const struct user_regset *regset,
|
|
unsigned int pos, unsigned int count,
|
|
const void *kbuf, const void __user *ubuf)
|
|
{
|
|
const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);
|
|
const int fir_pos = fcr31_pos + sizeof(u32);
|
|
u32 fcr31;
|
|
int err;
|
|
|
|
BUG_ON(count % sizeof(elf_fpreg_t));
|
|
|
|
if (pos + count > sizeof(elf_fpregset_t))
|
|
return -EIO;
|
|
|
|
init_fp_ctx(target);
|
|
|
|
if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t))
|
|
err = fpr_set_fpa(target, &pos, &count, &kbuf, &ubuf);
|
|
else
|
|
err = fpr_set_msa(target, &pos, &count, &kbuf, &ubuf);
|
|
if (err)
|
|
return err;
|
|
|
|
if (count > 0) {
|
|
err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
|
&fcr31,
|
|
fcr31_pos, fcr31_pos + sizeof(u32));
|
|
if (err)
|
|
return err;
|
|
|
|
ptrace_setfcr31(target, fcr31);
|
|
}
|
|
|
|
if (count > 0)
|
|
err = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
|
fir_pos,
|
|
fir_pos + sizeof(u32));
|
|
|
|
return err;
|
|
}
|
|
|
|
enum mips_regset {
|
|
REGSET_GPR,
|
|
REGSET_FPR,
|
|
};
|
|
|
|
struct pt_regs_offset {
|
|
const char *name;
|
|
int offset;
|
|
};
|
|
|
|
#define REG_OFFSET_NAME(reg, r) { \
|
|
.name = #reg, \
|
|
.offset = offsetof(struct pt_regs, r) \
|
|
}
|
|
|
|
#define REG_OFFSET_END { \
|
|
.name = NULL, \
|
|
.offset = 0 \
|
|
}
|
|
|
|
static const struct pt_regs_offset regoffset_table[] = {
|
|
REG_OFFSET_NAME(r0, regs[0]),
|
|
REG_OFFSET_NAME(r1, regs[1]),
|
|
REG_OFFSET_NAME(r2, regs[2]),
|
|
REG_OFFSET_NAME(r3, regs[3]),
|
|
REG_OFFSET_NAME(r4, regs[4]),
|
|
REG_OFFSET_NAME(r5, regs[5]),
|
|
REG_OFFSET_NAME(r6, regs[6]),
|
|
REG_OFFSET_NAME(r7, regs[7]),
|
|
REG_OFFSET_NAME(r8, regs[8]),
|
|
REG_OFFSET_NAME(r9, regs[9]),
|
|
REG_OFFSET_NAME(r10, regs[10]),
|
|
REG_OFFSET_NAME(r11, regs[11]),
|
|
REG_OFFSET_NAME(r12, regs[12]),
|
|
REG_OFFSET_NAME(r13, regs[13]),
|
|
REG_OFFSET_NAME(r14, regs[14]),
|
|
REG_OFFSET_NAME(r15, regs[15]),
|
|
REG_OFFSET_NAME(r16, regs[16]),
|
|
REG_OFFSET_NAME(r17, regs[17]),
|
|
REG_OFFSET_NAME(r18, regs[18]),
|
|
REG_OFFSET_NAME(r19, regs[19]),
|
|
REG_OFFSET_NAME(r20, regs[20]),
|
|
REG_OFFSET_NAME(r21, regs[21]),
|
|
REG_OFFSET_NAME(r22, regs[22]),
|
|
REG_OFFSET_NAME(r23, regs[23]),
|
|
REG_OFFSET_NAME(r24, regs[24]),
|
|
REG_OFFSET_NAME(r25, regs[25]),
|
|
REG_OFFSET_NAME(r26, regs[26]),
|
|
REG_OFFSET_NAME(r27, regs[27]),
|
|
REG_OFFSET_NAME(r28, regs[28]),
|
|
REG_OFFSET_NAME(r29, regs[29]),
|
|
REG_OFFSET_NAME(r30, regs[30]),
|
|
REG_OFFSET_NAME(r31, regs[31]),
|
|
REG_OFFSET_NAME(c0_status, cp0_status),
|
|
REG_OFFSET_NAME(hi, hi),
|
|
REG_OFFSET_NAME(lo, lo),
|
|
#ifdef CONFIG_CPU_HAS_SMARTMIPS
|
|
REG_OFFSET_NAME(acx, acx),
|
|
#endif
|
|
REG_OFFSET_NAME(c0_badvaddr, cp0_badvaddr),
|
|
REG_OFFSET_NAME(c0_cause, cp0_cause),
|
|
REG_OFFSET_NAME(c0_epc, cp0_epc),
|
|
#ifdef CONFIG_MIPS_MT_SMTC
|
|
REG_OFFSET_NAME(c0_tcstatus, cp0_tcstatus),
|
|
#endif
|
|
#ifdef CONFIG_CPU_CAVIUM_OCTEON
|
|
REG_OFFSET_NAME(mpl0, mpl[0]),
|
|
REG_OFFSET_NAME(mpl1, mpl[1]),
|
|
REG_OFFSET_NAME(mpl2, mpl[2]),
|
|
REG_OFFSET_NAME(mtp0, mtp[0]),
|
|
REG_OFFSET_NAME(mtp1, mtp[1]),
|
|
REG_OFFSET_NAME(mtp2, mtp[2]),
|
|
#endif
|
|
REG_OFFSET_END,
|
|
};
|
|
|
|
/**
|
|
* regs_query_register_offset() - query register offset from its name
|
|
* @name: the name of a register
|
|
*
|
|
* regs_query_register_offset() returns the offset of a register in struct
|
|
* pt_regs from its name. If the name is invalid, this returns -EINVAL;
|
|
*/
|
|
int regs_query_register_offset(const char *name)
|
|
{
|
|
const struct pt_regs_offset *roff;
|
|
for (roff = regoffset_table; roff->name != NULL; roff++)
|
|
if (!strcmp(roff->name, name))
|
|
return roff->offset;
|
|
return -EINVAL;
|
|
}
|
|
|
|
#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
|
|
|
|
static const struct user_regset mips_regsets[] = {
|
|
[REGSET_GPR] = {
|
|
.core_note_type = NT_PRSTATUS,
|
|
.n = ELF_NGREG,
|
|
.size = sizeof(unsigned int),
|
|
.align = sizeof(unsigned int),
|
|
.get = gpr32_get,
|
|
.set = gpr32_set,
|
|
},
|
|
[REGSET_FPR] = {
|
|
.core_note_type = NT_PRFPREG,
|
|
.n = ELF_NFPREG,
|
|
.size = sizeof(elf_fpreg_t),
|
|
.align = sizeof(elf_fpreg_t),
|
|
.get = fpr_get,
|
|
.set = fpr_set,
|
|
},
|
|
};
|
|
|
|
static const struct user_regset_view user_mips_view = {
|
|
.name = "mips",
|
|
.e_machine = ELF_ARCH,
|
|
.ei_osabi = ELF_OSABI,
|
|
.regsets = mips_regsets,
|
|
.n = ARRAY_SIZE(mips_regsets),
|
|
};
|
|
|
|
#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
|
|
|
|
#ifdef CONFIG_64BIT
|
|
|
|
static const struct user_regset mips64_regsets[] = {
|
|
[REGSET_GPR] = {
|
|
.core_note_type = NT_PRSTATUS,
|
|
.n = ELF_NGREG,
|
|
.size = sizeof(unsigned long),
|
|
.align = sizeof(unsigned long),
|
|
.get = gpr64_get,
|
|
.set = gpr64_set,
|
|
},
|
|
[REGSET_FPR] = {
|
|
.core_note_type = NT_PRFPREG,
|
|
.n = ELF_NFPREG,
|
|
.size = sizeof(elf_fpreg_t),
|
|
.align = sizeof(elf_fpreg_t),
|
|
.get = fpr_get,
|
|
.set = fpr_set,
|
|
},
|
|
};
|
|
|
|
static const struct user_regset_view user_mips64_view = {
|
|
.name = "mips64",
|
|
.e_machine = ELF_ARCH,
|
|
.ei_osabi = ELF_OSABI,
|
|
.regsets = mips64_regsets,
|
|
.n = ARRAY_SIZE(mips64_regsets),
|
|
};
|
|
|
|
#ifdef CONFIG_MIPS32_N32
|
|
|
|
static const struct user_regset_view user_mipsn32_view = {
|
|
.name = "mipsn32",
|
|
.e_flags = EF_MIPS_ABI2,
|
|
.e_machine = ELF_ARCH,
|
|
.ei_osabi = ELF_OSABI,
|
|
.regsets = mips64_regsets,
|
|
.n = ARRAY_SIZE(mips64_regsets),
|
|
};
|
|
|
|
#endif /* CONFIG_MIPS32_N32 */
|
|
|
|
#endif /* CONFIG_64BIT */
|
|
|
|
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
|
{
|
|
#ifdef CONFIG_32BIT
|
|
return &user_mips_view;
|
|
#else
|
|
#ifdef CONFIG_MIPS32_O32
|
|
if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
|
|
return &user_mips_view;
|
|
#endif
|
|
#ifdef CONFIG_MIPS32_N32
|
|
if (test_tsk_thread_flag(task, TIF_32BIT_ADDR))
|
|
return &user_mipsn32_view;
|
|
#endif
|
|
return &user_mips64_view;
|
|
#endif
|
|
}
|
|
|
|
long arch_ptrace(struct task_struct *child, long request,
|
|
unsigned long addr, unsigned long data)
|
|
{
|
|
int ret;
|
|
void __user *addrp = (void __user *) addr;
|
|
void __user *datavp = (void __user *) data;
|
|
unsigned long __user *datalp = (void __user *) data;
|
|
|
|
switch (request) {
|
|
/* when I and D space are separate, these will need to be fixed. */
|
|
case PTRACE_PEEKTEXT: /* read word at location addr. */
|
|
case PTRACE_PEEKDATA:
|
|
ret = generic_ptrace_peekdata(child, addr, data);
|
|
break;
|
|
|
|
/* Read the word at location addr in the USER area. */
|
|
case PTRACE_PEEKUSR: {
|
|
struct pt_regs *regs;
|
|
union fpureg *fregs;
|
|
unsigned long tmp = 0;
|
|
|
|
regs = task_pt_regs(child);
|
|
ret = 0; /* Default return value. */
|
|
|
|
switch (addr) {
|
|
case 0 ... 31:
|
|
tmp = regs->regs[addr];
|
|
break;
|
|
case FPR_BASE ... FPR_BASE + 31:
|
|
if (!tsk_used_math(child)) {
|
|
/* FP not yet used */
|
|
tmp = -1;
|
|
break;
|
|
}
|
|
fregs = get_fpu_regs(child);
|
|
|
|
#ifdef CONFIG_32BIT
|
|
if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
|
|
/*
|
|
* The odd registers are actually the high
|
|
* order bits of the values stored in the even
|
|
* registers - unless we're using r2k_switch.S.
|
|
*/
|
|
tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
|
|
addr & 1);
|
|
break;
|
|
}
|
|
#endif
|
|
tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
|
|
break;
|
|
case PC:
|
|
tmp = regs->cp0_epc;
|
|
break;
|
|
case CAUSE:
|
|
tmp = regs->cp0_cause;
|
|
break;
|
|
case BADVADDR:
|
|
tmp = regs->cp0_badvaddr;
|
|
break;
|
|
case MMHI:
|
|
tmp = regs->hi;
|
|
break;
|
|
case MMLO:
|
|
tmp = regs->lo;
|
|
break;
|
|
#ifdef CONFIG_CPU_HAS_SMARTMIPS
|
|
case ACX:
|
|
tmp = regs->acx;
|
|
break;
|
|
#endif
|
|
case FPC_CSR:
|
|
tmp = child->thread.fpu.fcr31;
|
|
break;
|
|
case FPC_EIR:
|
|
/* implementation / version register */
|
|
tmp = boot_cpu_data.fpu_id;
|
|
break;
|
|
case DSP_BASE ... DSP_BASE + 5: {
|
|
dspreg_t *dregs;
|
|
|
|
if (!cpu_has_dsp) {
|
|
tmp = 0;
|
|
ret = -EIO;
|
|
goto out;
|
|
}
|
|
dregs = __get_dsp_regs(child);
|
|
tmp = (unsigned long) (dregs[addr - DSP_BASE]);
|
|
break;
|
|
}
|
|
case DSP_CONTROL:
|
|
if (!cpu_has_dsp) {
|
|
tmp = 0;
|
|
ret = -EIO;
|
|
goto out;
|
|
}
|
|
tmp = child->thread.dsp.dspcontrol;
|
|
break;
|
|
default:
|
|
tmp = 0;
|
|
ret = -EIO;
|
|
goto out;
|
|
}
|
|
ret = put_user(tmp, datalp);
|
|
break;
|
|
}
|
|
|
|
/* when I and D space are separate, this will have to be fixed. */
|
|
case PTRACE_POKETEXT: /* write the word at location addr. */
|
|
case PTRACE_POKEDATA:
|
|
ret = generic_ptrace_pokedata(child, addr, data);
|
|
break;
|
|
|
|
case PTRACE_POKEUSR: {
|
|
struct pt_regs *regs;
|
|
ret = 0;
|
|
regs = task_pt_regs(child);
|
|
|
|
switch (addr) {
|
|
case 0 ... 31:
|
|
regs->regs[addr] = data;
|
|
break;
|
|
case FPR_BASE ... FPR_BASE + 31: {
|
|
union fpureg *fregs = get_fpu_regs(child);
|
|
|
|
init_fp_ctx(child);
|
|
#ifdef CONFIG_32BIT
|
|
if (test_tsk_thread_flag(child, TIF_32BIT_FPREGS)) {
|
|
/*
|
|
* The odd registers are actually the high
|
|
* order bits of the values stored in the even
|
|
* registers - unless we're using r2k_switch.S.
|
|
*/
|
|
set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
|
|
addr & 1, data);
|
|
break;
|
|
}
|
|
#endif
|
|
set_fpr64(&fregs[addr - FPR_BASE], 0, data);
|
|
break;
|
|
}
|
|
case PC:
|
|
regs->cp0_epc = data;
|
|
break;
|
|
case MMHI:
|
|
regs->hi = data;
|
|
break;
|
|
case MMLO:
|
|
regs->lo = data;
|
|
break;
|
|
#ifdef CONFIG_CPU_HAS_SMARTMIPS
|
|
case ACX:
|
|
regs->acx = data;
|
|
break;
|
|
#endif
|
|
case FPC_CSR:
|
|
ptrace_setfcr31(child, data);
|
|
break;
|
|
case DSP_BASE ... DSP_BASE + 5: {
|
|
dspreg_t *dregs;
|
|
|
|
if (!cpu_has_dsp) {
|
|
ret = -EIO;
|
|
break;
|
|
}
|
|
|
|
dregs = __get_dsp_regs(child);
|
|
dregs[addr - DSP_BASE] = data;
|
|
break;
|
|
}
|
|
case DSP_CONTROL:
|
|
if (!cpu_has_dsp) {
|
|
ret = -EIO;
|
|
break;
|
|
}
|
|
child->thread.dsp.dspcontrol = data;
|
|
break;
|
|
default:
|
|
/* The rest are not allowed. */
|
|
ret = -EIO;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case PTRACE_GETREGS:
|
|
ret = ptrace_getregs(child, datavp);
|
|
break;
|
|
|
|
case PTRACE_SETREGS:
|
|
ret = ptrace_setregs(child, datavp);
|
|
break;
|
|
|
|
case PTRACE_GETFPREGS:
|
|
ret = ptrace_getfpregs(child, datavp);
|
|
break;
|
|
|
|
case PTRACE_SETFPREGS:
|
|
ret = ptrace_setfpregs(child, datavp);
|
|
break;
|
|
|
|
case PTRACE_GET_THREAD_AREA:
|
|
ret = put_user(task_thread_info(child)->tp_value, datalp);
|
|
break;
|
|
|
|
case PTRACE_GET_WATCH_REGS:
|
|
ret = ptrace_get_watch_regs(child, addrp);
|
|
break;
|
|
|
|
case PTRACE_SET_WATCH_REGS:
|
|
ret = ptrace_set_watch_regs(child, addrp);
|
|
break;
|
|
|
|
default:
|
|
ret = ptrace_request(child, request, addr, data);
|
|
break;
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Notification of system call entry/exit
|
|
* - triggered by current->work.syscall_trace
|
|
*/
|
|
asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
|
|
{
|
|
long ret = 0;
|
|
user_exit();
|
|
|
|
current_thread_info()->syscall = syscall;
|
|
|
|
if (secure_computing() == -1)
|
|
return -1;
|
|
|
|
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
|
|
tracehook_report_syscall_entry(regs))
|
|
ret = -1;
|
|
|
|
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
|
|
trace_sys_enter(regs, regs->regs[2]);
|
|
|
|
audit_syscall_entry(syscall, regs->regs[4], regs->regs[5],
|
|
regs->regs[6], regs->regs[7]);
|
|
return syscall;
|
|
}
|
|
|
|
/*
|
|
* Notification of system call entry/exit
|
|
* - triggered by current->work.syscall_trace
|
|
*/
|
|
asmlinkage void syscall_trace_leave(struct pt_regs *regs)
|
|
{
|
|
/*
|
|
* We may come here right after calling schedule_user()
|
|
* or do_notify_resume(), in which case we can be in RCU
|
|
* user mode.
|
|
*/
|
|
user_exit();
|
|
|
|
audit_syscall_exit(regs);
|
|
|
|
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
|
|
trace_sys_exit(regs, regs_return_value(regs));
|
|
|
|
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
|
tracehook_report_syscall_exit(regs, 0);
|
|
|
|
user_enter();
|
|
}
|