2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Optimized memory copy routines.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2004 Randolph Chung <tausq@debian.org>
|
2017-03-30 03:41:05 +08:00
|
|
|
* Copyright (C) 2013-2017 Helge Deller <deller@gmx.de>
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*
|
|
|
|
* Portions derived from the GNU C Library
|
|
|
|
* Copyright (C) 1991, 1997, 2003 Free Software Foundation, Inc.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/compiler.h>
|
2013-10-10 05:47:03 +08:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2017-03-21 09:08:07 +08:00
|
|
|
#define get_user_space() (uaccess_kernel() ? 0 : mfsp(3))
|
2005-04-17 06:20:36 +08:00
|
|
|
#define get_kernel_space() (0)
|
|
|
|
|
parisc: Fix gcc miscompilation in pa_memcpy()
When running the LTP testsuite one may hit this kernel BUG() with the
write06 testcase:
kernel BUG at mm/filemap.c:2023!
CPU: 1 PID: 8614 Comm: writev01 Not tainted 3.10.0-rc7-64bit-c3000+ #6
IASQ: 0000000000000000 0000000000000000 IAOQ: 00000000401e6e84 00000000401e6e88
IIR: 03ffe01f ISR: 0000000010340000 IOR: 000001fbe0380820
CPU: 1 CR30: 00000000bef80000 CR31: ffffffffffffffff
ORIG_R28: 00000000bdc192c0
IAOQ[0]: iov_iter_advance+0x3c/0xc0
IAOQ[1]: iov_iter_advance+0x40/0xc0
RP(r2): generic_file_buffered_write+0x204/0x3f0
Backtrace:
[<00000000401e764c>] generic_file_buffered_write+0x204/0x3f0
[<00000000401eab24>] __generic_file_aio_write+0x244/0x448
[<00000000401eadc0>] generic_file_aio_write+0x98/0x150
[<000000004024f460>] do_sync_readv_writev+0xc0/0x130
[<000000004025037c>] compat_do_readv_writev+0x12c/0x340
[<00000000402505f8>] compat_writev+0x68/0xa0
[<0000000040251d88>] compat_SyS_writev+0x98/0xf8
Reason for this crash is a gcc miscompilation in the fault handlers of
pa_memcpy() which return the fault address instead of the copied bytes.
Since this seems to be a generic problem with gcc-4.7.x (and below), it's
better to simplify the fault handlers in pa_memcpy to avoid this problem.
Here is a simple reproducer for the problem:
int main(int argc, char **argv)
{
int fd, nbytes;
struct iovec wr_iovec[] = {
{ "TEST STRING ",32},
{ (char*)0x40005000,32} }; // random memory.
fd = open(DATA_FILE, O_RDWR | O_CREAT, 0666);
nbytes = writev(fd, wr_iovec, 2);
printf("return value = %d, errno %d (%s)\n",
nbytes, errno, strerror(errno));
return 0;
}
In addition, John David Anglin wrote:
There is no gcc PR as pa_memcpy is not legitimate C code. There is an
implicit assumption that certain variables will contain correct values
when an exception occurs and the code randomly jumps to one of the
exception blocks. There is no guarantee of this. If a PR was filed, it
would likely be marked as invalid.
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: John David Anglin <dave.anglin@bell.net>
Cc: <stable@vger.kernel.org> # 3.8+
Signed-off-by: Helge Deller <deller@gmx.de>
2013-07-05 04:34:11 +08:00
|
|
|
/* Returns 0 for success, otherwise, returns number of bytes not transferred. */
|
2017-03-30 03:41:05 +08:00
|
|
|
extern unsigned long pa_memcpy(void *dst, const void *src,
|
|
|
|
unsigned long len);
|
parisc: Fix gcc miscompilation in pa_memcpy()
When running the LTP testsuite one may hit this kernel BUG() with the
write06 testcase:
kernel BUG at mm/filemap.c:2023!
CPU: 1 PID: 8614 Comm: writev01 Not tainted 3.10.0-rc7-64bit-c3000+ #6
IASQ: 0000000000000000 0000000000000000 IAOQ: 00000000401e6e84 00000000401e6e88
IIR: 03ffe01f ISR: 0000000010340000 IOR: 000001fbe0380820
CPU: 1 CR30: 00000000bef80000 CR31: ffffffffffffffff
ORIG_R28: 00000000bdc192c0
IAOQ[0]: iov_iter_advance+0x3c/0xc0
IAOQ[1]: iov_iter_advance+0x40/0xc0
RP(r2): generic_file_buffered_write+0x204/0x3f0
Backtrace:
[<00000000401e764c>] generic_file_buffered_write+0x204/0x3f0
[<00000000401eab24>] __generic_file_aio_write+0x244/0x448
[<00000000401eadc0>] generic_file_aio_write+0x98/0x150
[<000000004024f460>] do_sync_readv_writev+0xc0/0x130
[<000000004025037c>] compat_do_readv_writev+0x12c/0x340
[<00000000402505f8>] compat_writev+0x68/0xa0
[<0000000040251d88>] compat_SyS_writev+0x98/0xf8
Reason for this crash is a gcc miscompilation in the fault handlers of
pa_memcpy() which return the fault address instead of the copied bytes.
Since this seems to be a generic problem with gcc-4.7.x (and below), it's
better to simplify the fault handlers in pa_memcpy to avoid this problem.
Here is a simple reproducer for the problem:
int main(int argc, char **argv)
{
int fd, nbytes;
struct iovec wr_iovec[] = {
{ "TEST STRING ",32},
{ (char*)0x40005000,32} }; // random memory.
fd = open(DATA_FILE, O_RDWR | O_CREAT, 0666);
nbytes = writev(fd, wr_iovec, 2);
printf("return value = %d, errno %d (%s)\n",
nbytes, errno, strerror(errno));
return 0;
}
In addition, John David Anglin wrote:
There is no gcc PR as pa_memcpy is not legitimate C code. There is an
implicit assumption that certain variables will contain correct values
when an exception occurs and the code randomly jumps to one of the
exception blocks. There is no guarantee of this. If a PR was filed, it
would likely be marked as invalid.
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: John David Anglin <dave.anglin@bell.net>
Cc: <stable@vger.kernel.org> # 3.8+
Signed-off-by: Helge Deller <deller@gmx.de>
2013-07-05 04:34:11 +08:00
|
|
|
|
2017-03-25 11:11:26 +08:00
|
|
|
unsigned long raw_copy_to_user(void __user *dst, const void *src,
|
|
|
|
unsigned long len)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
mtsp(get_kernel_space(), 1);
|
|
|
|
mtsp(get_user_space(), 2);
|
|
|
|
return pa_memcpy((void __force *)dst, src, len);
|
|
|
|
}
|
2017-03-25 11:11:26 +08:00
|
|
|
EXPORT_SYMBOL(raw_copy_to_user);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2017-03-25 11:11:26 +08:00
|
|
|
unsigned long raw_copy_from_user(void *dst, const void __user *src,
|
2016-10-06 15:07:30 +08:00
|
|
|
unsigned long len)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
mtsp(get_user_space(), 1);
|
|
|
|
mtsp(get_kernel_space(), 2);
|
|
|
|
return pa_memcpy(dst, (void __force *)src, len);
|
|
|
|
}
|
2017-03-25 11:11:26 +08:00
|
|
|
EXPORT_SYMBOL(raw_copy_from_user);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2017-03-25 11:11:26 +08:00
|
|
|
unsigned long raw_copy_in_user(void __user *dst, const void __user *src, unsigned long len)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
mtsp(get_user_space(), 1);
|
|
|
|
mtsp(get_user_space(), 2);
|
|
|
|
return pa_memcpy((void __force *)dst, (void __force *)src, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void * memcpy(void * dst,const void *src, size_t count)
|
|
|
|
{
|
|
|
|
mtsp(get_kernel_space(), 1);
|
|
|
|
mtsp(get_kernel_space(), 2);
|
|
|
|
pa_memcpy(dst, src, count);
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2017-03-25 11:11:26 +08:00
|
|
|
EXPORT_SYMBOL(raw_copy_in_user);
|
2005-04-17 06:20:36 +08:00
|
|
|
EXPORT_SYMBOL(memcpy);
|
2013-10-10 05:47:03 +08:00
|
|
|
|
|
|
|
long probe_kernel_read(void *dst, const void *src, size_t size)
|
|
|
|
{
|
|
|
|
unsigned long addr = (unsigned long)src;
|
|
|
|
|
2013-11-13 04:01:24 +08:00
|
|
|
if (addr < PAGE_SIZE)
|
2013-10-10 05:47:03 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
/* check for I/O space F_EXTEND(0xfff00000) access as well? */
|
|
|
|
|
|
|
|
return __probe_kernel_read(dst, src, size);
|
|
|
|
}
|