Files
Greg Kroah-Hartman 8fc3f01965 Merge 4.4.167 into android-4.4-p
Changes in 4.4.167
	media: em28xx: Fix use-after-free when disconnecting
	Revert "wlcore: Add missing PM call for wlcore_cmd_wait_for_event_or_timeout()"
	rapidio/rionet: do not free skb before reading its length
	s390/qeth: fix length check in SNMP processing
	usbnet: ipheth: fix potential recvmsg bug and recvmsg bug 2
	kvm: mmu: Fix race in emulated page table writes
	xtensa: enable coprocessors that are being flushed
	xtensa: fix coprocessor context offset definitions
	Btrfs: ensure path name is null terminated at btrfs_control_ioctl
	ALSA: wss: Fix invalid snd_free_pages() at error path
	ALSA: ac97: Fix incorrect bit shift at AC97-SPSA control write
	ALSA: control: Fix race between adding and removing a user element
	ALSA: sparc: Fix invalid snd_free_pages() at error path
	ext2: fix potential use after free
	dmaengine: at_hdmac: fix memory leak in at_dma_xlate()
	dmaengine: at_hdmac: fix module unloading
	btrfs: release metadata before running delayed refs
	USB: usb-storage: Add new IDs to ums-realtek
	usb: core: quirks: add RESET_RESUME quirk for Cherry G230 Stream series
	misc: mic/scif: fix copy-paste error in scif_create_remote_lookup
	Kbuild: suppress packed-not-aligned warning for default setting only
	exec: avoid gcc-8 warning for get_task_comm
	disable stringop truncation warnings for now
	kobject: Replace strncpy with memcpy
	unifdef: use memcpy instead of strncpy
	kernfs: Replace strncpy with memcpy
	ip_tunnel: Fix name string concatenate in __ip_tunnel_create()
	drm: gma500: fix logic error
	scsi: bfa: convert to strlcpy/strlcat
	staging: rts5208: fix gcc-8 logic error warning
	kdb: use memmove instead of overlapping memcpy
	iser: set sector for ambiguous mr status errors
	uprobes: Fix handle_swbp() vs. unregister() + register() race once more
	MIPS: ralink: Fix mt7620 nd_sd pinmux
	mips: fix mips_get_syscall_arg o32 check
	drm/ast: Fix incorrect free on ioregs
	scsi: scsi_devinfo: cleanly zero-pad devinfo strings
	ALSA: trident: Suppress gcc string warning
	scsi: csiostor: Avoid content leaks and casts
	kgdboc: Fix restrict error
	kgdboc: Fix warning with module build
	leds: call led_pwm_set() in leds-pwm to enforce default LED_OFF
	leds: turn off the LED and wait for completion on unregistering LED class device
	leds: leds-gpio: Fix return value check in create_gpio_led()
	Input: xpad - quirk all PDP Xbox One gamepads
	Input: matrix_keypad - check for errors from of_get_named_gpio()
	Input: elan_i2c - add ELAN0620 to the ACPI table
	Input: elan_i2c - add ACPI ID for Lenovo IdeaPad 330-15ARR
	Input: elan_i2c - add support for ELAN0621 touchpad
	btrfs: Always try all copies when reading extent buffers
	Btrfs: fix use-after-free when dumping free space
	ARC: change defconfig defaults to ARCv2
	arc: [devboards] Add support of NFSv3 ACL
	mm: cleancache: fix corruption on missed inode invalidation
	mm: mlock: avoid increase mm->locked_vm on mlock() when already mlock2(,MLOCK_ONFAULT)
	usb: gadget: dummy: fix nonsensical comparisons
	iommu/vt-d: Fix NULL pointer dereference in prq_event_thread()
	iommu/ipmmu-vmsa: Fix crash on early domain free
	can: rcar_can: Fix erroneous registration
	batman-adv: Expand merged fragment buffer for full packet
	bnx2x: Assign unique DMAE channel number for FW DMAE transactions.
	qed: Fix PTT leak in qed_drain()
	qed: Fix reading wrong value in loop condition
	net/mlx4_core: Zero out lkey field in SW2HW_MPT fw command
	net/mlx4_core: Fix uninitialized variable compilation warning
	net/mlx4: Fix UBSAN warning of signed integer overflow
	net: faraday: ftmac100: remove netif_running(netdev) check before disabling interrupts
	iommu/vt-d: Use memunmap to free memremap
	net: amd: add missing of_node_put()
	usb: quirk: add no-LPM quirk on SanDisk Ultra Flair device
	usb: appledisplay: Add 27" Apple Cinema Display
	USB: check usb_get_extra_descriptor for proper size
	ALSA: usb-audio: Fix UAF decrement if card has no live interfaces in card.c
	ALSA: hda: Add support for AMD Stoney Ridge
	ALSA: pcm: Fix starvation on down_write_nonblock()
	ALSA: pcm: Call snd_pcm_unlink() conditionally at closing
	ALSA: pcm: Fix interval evaluation with openmin/max
	virtio/s390: avoid race on vcdev->config
	virtio/s390: fix race in ccw_io_helper()
	SUNRPC: Fix leak of krb5p encode pages
	xhci: Prevent U1/U2 link pm states if exit latency is too long
	Staging: lustre: remove two build warnings
	cifs: Fix separator when building path from dentry
	tty: serial: 8250_mtk: always resume the device in probe.
	kgdboc: fix KASAN global-out-of-bounds bug in param_set_kgdboc_var()
	mac80211_hwsim: Timer should be initialized before device registered
	mac80211: Clear beacon_int in ieee80211_do_stop
	mac80211: ignore tx status for PS stations in ieee80211_tx_status_ext
	mac80211: fix reordering of buffered broadcast packets
	mac80211: ignore NullFunc frames in the duplicate detection
	Linux 4.4.167

Change-Id: I67673edf3244cb17523bfb13f256d5b3ddd1bcba
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
2018-12-13 09:44:10 +01:00

360 lines
9.7 KiB
C

/*
* arch/xtensa/kernel/process.c
*
* Xtensa Processor version.
*
* 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) 2001 - 2005 Tensilica Inc.
*
* Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
* Chris Zankel <chris@zankel.net>
* Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
* Kevin Chea
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/elf.h>
#include <linux/init.h>
#include <linux/prctl.h>
#include <linux/init_task.h>
#include <linux/module.h>
#include <linux/mqueue.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/rcupdate.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/platform.h>
#include <asm/mmu.h>
#include <asm/irq.h>
#include <linux/atomic.h>
#include <asm/asm-offsets.h>
#include <asm/regs.h>
extern void ret_from_fork(void);
extern void ret_from_kernel_thread(void);
struct task_struct *current_set[NR_CPUS] = {&init_task, };
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
#if XTENSA_HAVE_COPROCESSORS
void coprocessor_release_all(struct thread_info *ti)
{
unsigned long cpenable;
int i;
/* Make sure we don't switch tasks during this operation. */
preempt_disable();
/* Walk through all cp owners and release it for the requested one. */
cpenable = ti->cpenable;
for (i = 0; i < XCHAL_CP_MAX; i++) {
if (coprocessor_owner[i] == ti) {
coprocessor_owner[i] = 0;
cpenable &= ~(1 << i);
}
}
ti->cpenable = cpenable;
coprocessor_clear_cpenable();
preempt_enable();
}
void coprocessor_flush_all(struct thread_info *ti)
{
unsigned long cpenable, old_cpenable;
int i;
preempt_disable();
RSR_CPENABLE(old_cpenable);
cpenable = ti->cpenable;
WSR_CPENABLE(cpenable);
for (i = 0; i < XCHAL_CP_MAX; i++) {
if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti)
coprocessor_flush(ti, i);
cpenable >>= 1;
}
WSR_CPENABLE(old_cpenable);
preempt_enable();
}
#endif
/*
* Powermanagement idle function, if any is provided by the platform.
*/
void arch_cpu_idle(void)
{
platform_idle();
}
/*
* This is called when the thread calls exit().
*/
void exit_thread(struct task_struct *tsk)
{
#if XTENSA_HAVE_COPROCESSORS
coprocessor_release_all(task_thread_info(tsk));
#endif
}
/*
* Flush thread state. This is called when a thread does an execve()
* Note that we flush coprocessor registers for the case execve fails.
*/
void flush_thread(void)
{
#if XTENSA_HAVE_COPROCESSORS
struct thread_info *ti = current_thread_info();
coprocessor_flush_all(ti);
coprocessor_release_all(ti);
#endif
}
/*
* this gets called so that we can store coprocessor state into memory and
* copy the current task into the new thread.
*/
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
#if XTENSA_HAVE_COPROCESSORS
coprocessor_flush_all(task_thread_info(src));
#endif
*dst = *src;
return 0;
}
/*
* Copy thread.
*
* There are two modes in which this function is called:
* 1) Userspace thread creation,
* regs != NULL, usp_thread_fn is userspace stack pointer.
* It is expected to copy parent regs (in case CLONE_VM is not set
* in the clone_flags) and set up passed usp in the childregs.
* 2) Kernel thread creation,
* regs == NULL, usp_thread_fn is the function to run in the new thread
* and thread_fn_arg is its parameter.
* childregs are not used for the kernel threads.
*
* The stack layout for the new thread looks like this:
*
* +------------------------+
* | childregs |
* +------------------------+ <- thread.sp = sp in dummy-frame
* | dummy-frame | (saved in dummy-frame spill-area)
* +------------------------+
*
* We create a dummy frame to return to either ret_from_fork or
* ret_from_kernel_thread:
* a0 points to ret_from_fork/ret_from_kernel_thread (simulating a call4)
* sp points to itself (thread.sp)
* a2, a3 are unused for userspace threads,
* a2 points to thread_fn, a3 holds thread_fn arg for kernel threads.
*
* Note: This is a pristine frame, so we don't need any spill region on top of
* childregs.
*
* The fun part: if we're keeping the same VM (i.e. cloning a thread,
* not an entire process), we're normally given a new usp, and we CANNOT share
* any live address register windows. If we just copy those live frames over,
* the two threads (parent and child) will overflow the same frames onto the
* parent stack at different times, likely corrupting the parent stack (esp.
* if the parent returns from functions that called clone() and calls new
* ones, before the child overflows its now old copies of its parent windows).
* One solution is to spill windows to the parent stack, but that's fairly
* involved. Much simpler to just not copy those live frames across.
*/
int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
unsigned long thread_fn_arg, struct task_struct *p)
{
struct pt_regs *childregs = task_pt_regs(p);
#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
struct thread_info *ti;
#endif
/* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
*((int*)childregs - 3) = (unsigned long)childregs;
*((int*)childregs - 4) = 0;
p->thread.sp = (unsigned long)childregs;
if (!(p->flags & PF_KTHREAD)) {
struct pt_regs *regs = current_pt_regs();
unsigned long usp = usp_thread_fn ?
usp_thread_fn : regs->areg[1];
p->thread.ra = MAKE_RA_FOR_CALL(
(unsigned long)ret_from_fork, 0x1);
/* This does not copy all the regs.
* In a bout of brilliance or madness,
* ARs beyond a0-a15 exist past the end of the struct.
*/
*childregs = *regs;
childregs->areg[1] = usp;
childregs->areg[2] = 0;
/* When sharing memory with the parent thread, the child
usually starts on a pristine stack, so we have to reset
windowbase, windowstart and wmask.
(Note that such a new thread is required to always create
an initial call4 frame)
The exception is vfork, where the new thread continues to
run on the parent's stack until it calls execve. This could
be a call8 or call12, which requires a legal stack frame
of the previous caller for the overflow handlers to work.
(Note that it's always legal to overflow live registers).
In this case, ensure to spill at least the stack pointer
of that frame. */
if (clone_flags & CLONE_VM) {
/* check that caller window is live and same stack */
int len = childregs->wmask & ~0xf;
if (regs->areg[1] == usp && len != 0) {
int callinc = (regs->areg[0] >> 30) & 3;
int caller_ars = XCHAL_NUM_AREGS - callinc * 4;
put_user(regs->areg[caller_ars+1],
(unsigned __user*)(usp - 12));
}
childregs->wmask = 1;
childregs->windowstart = 1;
childregs->windowbase = 0;
} else {
int len = childregs->wmask & ~0xf;
memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
&regs->areg[XCHAL_NUM_AREGS - len/4], len);
}
/* The thread pointer is passed in the '4th argument' (= a5) */
if (clone_flags & CLONE_SETTLS)
childregs->threadptr = childregs->areg[5];
} else {
p->thread.ra = MAKE_RA_FOR_CALL(
(unsigned long)ret_from_kernel_thread, 1);
/* pass parameters to ret_from_kernel_thread:
* a2 = thread_fn, a3 = thread_fn arg
*/
*((int *)childregs - 1) = thread_fn_arg;
*((int *)childregs - 2) = usp_thread_fn;
/* Childregs are only used when we're going to userspace
* in which case start_thread will set them up.
*/
}
#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
ti = task_thread_info(p);
ti->cpenable = 0;
#endif
return 0;
}
/*
* These bracket the sleeping functions..
*/
unsigned long get_wchan(struct task_struct *p)
{
unsigned long sp, pc;
unsigned long stack_page = (unsigned long) task_stack_page(p);
int count = 0;
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
sp = p->thread.sp;
pc = MAKE_PC_FROM_RA(p->thread.ra, p->thread.sp);
do {
if (sp < stack_page + sizeof(struct task_struct) ||
sp >= (stack_page + THREAD_SIZE) ||
pc == 0)
return 0;
if (!in_sched_functions(pc))
return pc;
/* Stack layout: sp-4: ra, sp-3: sp' */
pc = MAKE_PC_FROM_RA(*(unsigned long*)sp - 4, sp);
sp = *(unsigned long *)sp - 3;
} while (count++ < 16);
return 0;
}
/*
* xtensa_gregset_t and 'struct pt_regs' are vastly different formats
* of processor registers. Besides different ordering,
* xtensa_gregset_t contains non-live register information that
* 'struct pt_regs' does not. Exception handling (primarily) uses
* 'struct pt_regs'. Core files and ptrace use xtensa_gregset_t.
*
*/
void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs)
{
unsigned long wb, ws, wm;
int live, last;
wb = regs->windowbase;
ws = regs->windowstart;
wm = regs->wmask;
ws = ((ws >> wb) | (ws << (WSBITS - wb))) & ((1 << WSBITS) - 1);
/* Don't leak any random bits. */
memset(elfregs, 0, sizeof(*elfregs));
/* Note: PS.EXCM is not set while user task is running; its
* being set in regs->ps is for exception handling convenience.
*/
elfregs->pc = regs->pc;
elfregs->ps = (regs->ps & ~(1 << PS_EXCM_BIT));
elfregs->lbeg = regs->lbeg;
elfregs->lend = regs->lend;
elfregs->lcount = regs->lcount;
elfregs->sar = regs->sar;
elfregs->windowstart = ws;
live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
last = XCHAL_NUM_AREGS - (wm >> 4) * 4;
memcpy(elfregs->a, regs->areg, live * 4);
memcpy(elfregs->a + last, regs->areg + last, (wm >> 4) * 16);
}
int dump_fpu(void)
{
return 0;
}