提交 90785be3 编写于 作者: L Linus Torvalds

Merge branch 'alpha' (alpha architecture patches)

Merge alpha architecture update from Michael Cree:
 "The Alpha Maintainer, Matt Turner, is currently unavailable, so I have
  collected up patches that have been posted to the linux-alpha mailing
  list over the last couple of months, and are forwarding them to you in
  the hope that you are prepared to accept them via me.

  The patches by Al Viro and myself I have been running against kernels
  for two months now so have had quite a bit of testing.  All except one
  patch were intended for the 3.5 kernel but because of Matt's
  unavailability never got forwarded to you."

* emailed patches from Michael Cree <mcree@orcon.net.nz>: (9 commits)
  alpha: Fix fall-out from disintegrating asm/system.h
  Redefine ATOMIC_INIT and ATOMIC64_INIT to drop the casts
  alpha: fix fpu.h usage in userspace
  alpha/mm/fault.c: Port OOM changes to do_page_fault
  alpha: take kernel_execve() out of entry.S
  alpha: take a bunch of syscalls into osf_sys.c
  alpha: Use new generic strncpy_from_user() and strnlen_user()
  alpha: Wire up cross memory attach syscalls
  alpha: Don't export SOCK_NONBLOCK to user space.
......@@ -18,6 +18,8 @@ config ALPHA
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_SMP_IDLE_THREAD
select GENERIC_CMOS_UPDATE
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
help
The Alpha is a 64-bit general-purpose processor designed and
marketed by the Digital Equipment Corporation of blessed memory,
......
......@@ -14,8 +14,8 @@
*/
#define ATOMIC_INIT(i) ( (atomic_t) { (i) } )
#define ATOMIC64_INIT(i) ( (atomic64_t) { (i) } )
#define ATOMIC_INIT(i) { (i) }
#define ATOMIC64_INIT(i) { (i) }
#define atomic_read(v) (*(volatile int *)&(v)->counter)
#define atomic64_read(v) (*(volatile long *)&(v)->counter)
......
#ifndef __ASM_ALPHA_FPU_H
#define __ASM_ALPHA_FPU_H
#ifdef __KERNEL__
#include <asm/special_insns.h>
#endif
/*
* Alpha floating-point control register defines:
......
......@@ -76,7 +76,10 @@ struct switch_stack {
#define task_pt_regs(task) \
((struct pt_regs *) (task_stack_page(task) + 2*PAGE_SIZE) - 1)
#define force_successful_syscall_return() (task_pt_regs(current)->r0 = 0)
#define current_pt_regs() \
((struct pt_regs *) ((char *)current_thread_info() + 2*PAGE_SIZE) - 1)
#define force_successful_syscall_return() (current_pt_regs()->r0 = 0)
#endif
......
......@@ -76,9 +76,11 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
#ifdef __KERNEL__
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
*/
#define SOCK_NONBLOCK 0x40000000
#endif /* __KERNEL__ */
#endif /* _ASM_SOCKET_H */
......@@ -433,36 +433,12 @@ clear_user(void __user *to, long len)
#undef __module_address
#undef __module_call
/* Returns: -EFAULT if exception before terminator, N if the entire
buffer filled, else strlen. */
#define user_addr_max() \
(segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL)
extern long __strncpy_from_user(char *__to, const char __user *__from, long __to_len);
extern inline long
strncpy_from_user(char *to, const char __user *from, long n)
{
long ret = -EFAULT;
if (__access_ok((unsigned long)from, 0, get_fs()))
ret = __strncpy_from_user(to, from, n);
return ret;
}
/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
extern long __strlen_user(const char __user *);
extern inline long strlen_user(const char __user *str)
{
return access_ok(VERIFY_READ,str,0) ? __strlen_user(str) : 0;
}
/* Returns: 0 if exception before NUL or reaching the supplied limit (N),
* a value greater than N if the limit would be exceeded, else strlen. */
extern long __strnlen_user(const char __user *, long);
extern inline long strnlen_user(const char __user *str, long n)
{
return access_ok(VERIFY_READ,str,0) ? __strnlen_user(str, n) : 0;
}
extern long strncpy_from_user(char *dest, const char __user *src, long count);
extern __must_check long strlen_user(const char __user *str);
extern __must_check long strnlen_user(const char __user *str, long n);
/*
* About the exception table:
......
......@@ -465,10 +465,12 @@
#define __NR_setns 501
#define __NR_accept4 502
#define __NR_sendmmsg 503
#define __NR_process_vm_readv 504
#define __NR_process_vm_writev 505
#ifdef __KERNEL__
#define NR_SYSCALLS 504
#define NR_SYSCALLS 506
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_STAT64
......
#ifndef _ASM_WORD_AT_A_TIME_H
#define _ASM_WORD_AT_A_TIME_H
#include <asm/compiler.h>
/*
* word-at-a-time interface for Alpha.
*/
/*
* We do not use the word_at_a_time struct on Alpha, but it needs to be
* implemented to humour the generic code.
*/
struct word_at_a_time {
const unsigned long unused;
};
#define WORD_AT_A_TIME_CONSTANTS { 0 }
/* Return nonzero if val has a zero */
static inline unsigned long has_zero(unsigned long val, unsigned long *bits, const struct word_at_a_time *c)
{
unsigned long zero_locations = __kernel_cmpbge(0, val);
*bits = zero_locations;
return zero_locations;
}
static inline unsigned long prep_zero_mask(unsigned long val, unsigned long bits, const struct word_at_a_time *c)
{
return bits;
}
#define create_zero_mask(bits) (bits)
static inline unsigned long find_zero(unsigned long bits)
{
#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
/* Simple if have CIX instructions */
return __kernel_cttz(bits);
#else
unsigned long t1, t2, t3;
/* Retain lowest set bit only */
bits &= -bits;
/* Binary search for lowest set bit */
t1 = bits & 0xf0;
t2 = bits & 0xcc;
t3 = bits & 0xaa;
if (t1) t1 = 4;
if (t2) t2 = 2;
if (t3) t3 = 1;
return t1 + t2 + t3;
#endif
}
#endif /* _ASM_WORD_AT_A_TIME_H */
......@@ -52,7 +52,6 @@ EXPORT_SYMBOL(alpha_write_fp_reg_s);
/* entry.S */
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(kernel_execve);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_tcpudp_magic);
......@@ -74,8 +73,6 @@ EXPORT_SYMBOL(alpha_fp_emul);
*/
EXPORT_SYMBOL(__copy_user);
EXPORT_SYMBOL(__do_clear_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__strnlen_user);
/*
* SMP-specific symbols.
......
......@@ -663,58 +663,6 @@ kernel_thread:
br ret_to_kernel
.end kernel_thread
/*
* kernel_execve(path, argv, envp)
*/
.align 4
.globl kernel_execve
.ent kernel_execve
kernel_execve:
/* We can be called from a module. */
ldgp $gp, 0($27)
lda $sp, -(32+SIZEOF_PT_REGS+8)($sp)
.frame $sp, 32+SIZEOF_PT_REGS+8, $26, 0
stq $26, 0($sp)
stq $16, 8($sp)
stq $17, 16($sp)
stq $18, 24($sp)
.prologue 1
lda $16, 32($sp)
lda $17, 0
lda $18, SIZEOF_PT_REGS
bsr $26, memset !samegp
/* Avoid the HAE being gratuitously wrong, which would cause us
to do the whole turn off interrupts thing and restore it. */
ldq $2, alpha_mv+HAE_CACHE
stq $2, 152+32($sp)
ldq $16, 8($sp)
ldq $17, 16($sp)
ldq $18, 24($sp)
lda $19, 32($sp)
bsr $26, do_execve !samegp
ldq $26, 0($sp)
bne $0, 1f /* error! */
/* Move the temporary pt_regs struct from its current location
to the top of the kernel stack frame. See copy_thread for
details for a normal process. */
lda $16, 0x4000 - SIZEOF_PT_REGS($8)
lda $17, 32($sp)
lda $18, SIZEOF_PT_REGS
bsr $26, memmove !samegp
/* Take that over as our new stack frame and visit userland! */
lda $sp, 0x4000 - SIZEOF_PT_REGS($8)
br $31, ret_from_sys_call
1: lda $sp, 32+SIZEOF_PT_REGS+8($sp)
ret
.end kernel_execve
/*
* Special system calls. Most of these are special in that they either
......@@ -796,115 +744,6 @@ sys_rt_sigreturn:
br ret_from_sys_call
.end sys_rt_sigreturn
.align 4
.globl sys_sethae
.ent sys_sethae
sys_sethae:
.prologue 0
stq $16, 152($sp)
ret
.end sys_sethae
.align 4
.globl osf_getpriority
.ent osf_getpriority
osf_getpriority:
lda $sp, -16($sp)
stq $26, 0($sp)
.prologue 0
jsr $26, sys_getpriority
ldq $26, 0($sp)
blt $0, 1f
/* Return value is the unbiased priority, i.e. 20 - prio.
This does result in negative return values, so signal
no error by writing into the R0 slot. */
lda $1, 20
stq $31, 16($sp)
subl $1, $0, $0
unop
1: lda $sp, 16($sp)
ret
.end osf_getpriority
.align 4
.globl sys_getxuid
.ent sys_getxuid
sys_getxuid:
.prologue 0
ldq $2, TI_TASK($8)
ldq $3, TASK_CRED($2)
ldl $0, CRED_UID($3)
ldl $1, CRED_EUID($3)
stq $1, 80($sp)
ret
.end sys_getxuid
.align 4
.globl sys_getxgid
.ent sys_getxgid
sys_getxgid:
.prologue 0
ldq $2, TI_TASK($8)
ldq $3, TASK_CRED($2)
ldl $0, CRED_GID($3)
ldl $1, CRED_EGID($3)
stq $1, 80($sp)
ret
.end sys_getxgid
.align 4
.globl sys_getxpid
.ent sys_getxpid
sys_getxpid:
.prologue 0
ldq $2, TI_TASK($8)
/* See linux/kernel/timer.c sys_getppid for discussion
about this loop. */
ldq $3, TASK_GROUP_LEADER($2)
ldq $4, TASK_REAL_PARENT($3)
ldl $0, TASK_TGID($2)
1: ldl $1, TASK_TGID($4)
#ifdef CONFIG_SMP
mov $4, $5
mb
ldq $3, TASK_GROUP_LEADER($2)
ldq $4, TASK_REAL_PARENT($3)
cmpeq $4, $5, $5
beq $5, 1b
#endif
stq $1, 80($sp)
ret
.end sys_getxpid
.align 4
.globl sys_alpha_pipe
.ent sys_alpha_pipe
sys_alpha_pipe:
lda $sp, -16($sp)
stq $26, 0($sp)
.prologue 0
mov $31, $17
lda $16, 8($sp)
jsr $26, do_pipe_flags
ldq $26, 0($sp)
bne $0, 1f
/* The return values are in $0 and $20. */
ldl $1, 12($sp)
ldl $0, 8($sp)
stq $1, 80+16($sp)
1: lda $sp, 16($sp)
ret
.end sys_alpha_pipe
.align 4
.globl sys_execve
.ent sys_execve
......
......@@ -1404,3 +1404,52 @@ SYSCALL_DEFINE3(osf_writev, unsigned long, fd,
}
#endif
SYSCALL_DEFINE2(osf_getpriority, int, which, int, who)
{
int prio = sys_getpriority(which, who);
if (prio >= 0) {
/* Return value is the unbiased priority, i.e. 20 - prio.
This does result in negative return values, so signal
no error */
force_successful_syscall_return();
prio = 20 - prio;
}
return prio;
}
SYSCALL_DEFINE0(getxuid)
{
current_pt_regs()->r20 = sys_geteuid();
return sys_getuid();
}
SYSCALL_DEFINE0(getxgid)
{
current_pt_regs()->r20 = sys_getegid();
return sys_getgid();
}
SYSCALL_DEFINE0(getxpid)
{
current_pt_regs()->r20 = sys_getppid();
return sys_getpid();
}
SYSCALL_DEFINE0(alpha_pipe)
{
int fd[2];
int res = do_pipe_flags(fd, 0);
if (!res) {
/* The return values are in $0 and $20. */
current_pt_regs()->r20 = fd[1];
res = fd[0];
}
return res;
}
SYSCALL_DEFINE1(sethae, unsigned long, val)
{
current_pt_regs()->hae = val;
return 0;
}
......@@ -455,3 +455,22 @@ get_wchan(struct task_struct *p)
}
return pc;
}
int kernel_execve(const char *path, const char *const argv[], const char *const envp[])
{
/* Avoid the HAE being gratuitously wrong, which would cause us
to do the whole turn off interrupts thing and restore it. */
struct pt_regs regs = {.hae = alpha_mv.hae_cache};
int err = do_execve(path, argv, envp, &regs);
if (!err) {
struct pt_regs *p = current_pt_regs();
/* copy regs to normal position and off to userland we go... */
*p = regs;
__asm__ __volatile__ (
"mov %0, $sp;"
"br $31, ret_from_sys_call"
: : "r"(p));
}
return err;
}
EXPORT_SYMBOL(kernel_execve);
......@@ -111,7 +111,7 @@ sys_call_table:
.quad sys_socket
.quad sys_connect
.quad sys_accept
.quad osf_getpriority /* 100 */
.quad sys_osf_getpriority /* 100 */
.quad sys_send
.quad sys_recv
.quad sys_sigreturn
......@@ -522,6 +522,8 @@ sys_call_table:
.quad sys_setns
.quad sys_accept4
.quad sys_sendmmsg
.quad sys_process_vm_readv
.quad sys_process_vm_writev /* 505 */
.size sys_call_table, . - sys_call_table
.type sys_call_table, @object
......
......@@ -31,8 +31,6 @@ lib-y = __divqu.o __remqu.o __divlu.o __remlu.o \
$(ev6-y)memchr.o \
$(ev6-y)copy_user.o \
$(ev6-y)clear_user.o \
$(ev6-y)strncpy_from_user.o \
$(ev67-y)strlen_user.o \
$(ev6-y)csum_ipv6_magic.o \
$(ev6-y)clear_page.o \
$(ev6-y)copy_page.o \
......
/*
* arch/alpha/lib/ev6-strncpy_from_user.S
* 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
*
* Just like strncpy except in the return value:
*
* -EFAULT if an exception occurs before the terminator is copied.
* N if the buffer filled.
*
* Otherwise the length of the string is returned.
*
* Much of the information about 21264 scheduling/coding comes from:
* Compiler Writer's Guide for the Alpha 21264
* abbreviated as 'CWG' in other comments here
* ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
* Scheduling notation:
* E - either cluster
* U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
* L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
* A bunch of instructions got moved and temp registers were changed
* to aid in scheduling. Control flow was also re-arranged to eliminate
* branches, and to provide longer code sequences to enable better scheduling.
* A total rewrite (using byte load/stores for start & tail sequences)
* is desirable, but very difficult to do without a from-scratch rewrite.
* Save that for the future.
*/
#include <asm/errno.h>
#include <asm/regdef.h>
/* Allow an exception for an insn; exit if we get one. */
#define EX(x,y...) \
99: x,##y; \
.section __ex_table,"a"; \
.long 99b - .; \
lda $31, $exception-99b($0); \
.previous
.set noat
.set noreorder
.text
.globl __strncpy_from_user
.ent __strncpy_from_user
.frame $30, 0, $26
.prologue 0
.align 4
__strncpy_from_user:
and a0, 7, t3 # E : find dest misalignment
beq a2, $zerolength # U :
/* Are source and destination co-aligned? */
mov a0, v0 # E : save the string start
xor a0, a1, t4 # E :
EX( ldq_u t1, 0(a1) ) # L : Latency=3 load first quadword
ldq_u t0, 0(a0) # L : load first (partial) aligned dest quadword
addq a2, t3, a2 # E : bias count by dest misalignment
subq a2, 1, a3 # E :
addq zero, 1, t10 # E :
and t4, 7, t4 # E : misalignment between the two
and a3, 7, t6 # E : number of tail bytes
sll t10, t6, t10 # E : t10 = bitmask of last count byte
bne t4, $unaligned # U :
lda t2, -1 # E : build a mask against false zero
/*
* We are co-aligned; take care of a partial first word.
* On entry to this basic block:
* t0 == the first destination word for masking back in
* t1 == the first source word.
*/
srl a3, 3, a2 # E : a2 = loop counter = (count - 1)/8
addq a1, 8, a1 # E :
mskqh t2, a1, t2 # U : detection in the src word
nop
/* Create the 1st output word and detect 0's in the 1st input word. */
mskqh t1, a1, t3 # U :
mskql t0, a1, t0 # U : assemble the first output word
ornot t1, t2, t2 # E :
nop
cmpbge zero, t2, t8 # E : bits set iff null found
or t0, t3, t0 # E :
beq a2, $a_eoc # U :
bne t8, $a_eos # U : 2nd branch in a quad. Bad.
/* On entry to this basic block:
* t0 == a source quad not containing a null.
* a0 - current aligned destination address
* a1 - current aligned source address
* a2 - count of quadwords to move.
* NOTE: Loop improvement - unrolling this is going to be
* a huge win, since we're going to stall otherwise.
* Fix this later. For _really_ large copies, look
* at using wh64 on a look-ahead basis. See the code
* in clear_user.S and copy_user.S.
* Presumably, since (a0) and (a1) do not overlap (by C definition)
* Lots of nops here:
* - Separate loads from stores
* - Keep it to 1 branch/quadpack so the branch predictor
* can train.
*/
$a_loop:
stq_u t0, 0(a0) # L :
addq a0, 8, a0 # E :
nop
subq a2, 1, a2 # E :
EX( ldq_u t0, 0(a1) ) # L :
addq a1, 8, a1 # E :
cmpbge zero, t0, t8 # E : Stall 2 cycles on t0
beq a2, $a_eoc # U :
beq t8, $a_loop # U :
nop
nop
nop
/* Take care of the final (partial) word store. At this point
* the end-of-count bit is set in t8 iff it applies.
*
* On entry to this basic block we have:
* t0 == the source word containing the null
* t8 == the cmpbge mask that found it.
*/
$a_eos:
negq t8, t12 # E : find low bit set
and t8, t12, t12 # E :
/* We're doing a partial word store and so need to combine
our source and original destination words. */
ldq_u t1, 0(a0) # L :
subq t12, 1, t6 # E :
or t12, t6, t8 # E :
zapnot t0, t8, t0 # U : clear src bytes > null
zap t1, t8, t1 # U : clear dst bytes <= null
or t0, t1, t0 # E :
stq_u t0, 0(a0) # L :
br $finish_up # L0 :
nop
nop
/* Add the end-of-count bit to the eos detection bitmask. */
.align 4
$a_eoc:
or t10, t8, t8
br $a_eos
nop
nop
/* The source and destination are not co-aligned. Align the destination
and cope. We have to be very careful about not reading too much and
causing a SEGV. */
.align 4
$u_head:
/* We know just enough now to be able to assemble the first
full source word. We can still find a zero at the end of it
that prevents us from outputting the whole thing.
On entry to this basic block:
t0 == the first dest word, unmasked
t1 == the shifted low bits of the first source word
t6 == bytemask that is -1 in dest word bytes */
EX( ldq_u t2, 8(a1) ) # L : load second src word
addq a1, 8, a1 # E :
mskql t0, a0, t0 # U : mask trailing garbage in dst
extqh t2, a1, t4 # U :
or t1, t4, t1 # E : first aligned src word complete
mskqh t1, a0, t1 # U : mask leading garbage in src
or t0, t1, t0 # E : first output word complete
or t0, t6, t6 # E : mask original data for zero test
cmpbge zero, t6, t8 # E :
beq a2, $u_eocfin # U :
bne t8, $u_final # U : bad news - 2nd branch in a quad
lda t6, -1 # E : mask out the bits we have
mskql t6, a1, t6 # U : already seen
stq_u t0, 0(a0) # L : store first output word
or t6, t2, t2 # E :
cmpbge zero, t2, t8 # E : find nulls in second partial
addq a0, 8, a0 # E :
subq a2, 1, a2 # E :
bne t8, $u_late_head_exit # U :
nop
/* Finally, we've got all the stupid leading edge cases taken care
of and we can set up to enter the main loop. */
extql t2, a1, t1 # U : position hi-bits of lo word
EX( ldq_u t2, 8(a1) ) # L : read next high-order source word
addq a1, 8, a1 # E :
cmpbge zero, t2, t8 # E :
beq a2, $u_eoc # U :
bne t8, $u_eos # U :
nop
nop
/* Unaligned copy main loop. In order to avoid reading too much,
the loop is structured to detect zeros in aligned source words.
This has, unfortunately, effectively pulled half of a loop
iteration out into the head and half into the tail, but it does
prevent nastiness from accumulating in the very thing we want
to run as fast as possible.
On entry to this basic block:
t1 == the shifted high-order bits from the previous source word
t2 == the unshifted current source word
We further know that t2 does not contain a null terminator. */
/*
* Extra nops here:
* separate load quads from store quads
* only one branch/quad to permit predictor training
*/
.align 4
$u_loop:
extqh t2, a1, t0 # U : extract high bits for current word
addq a1, 8, a1 # E :
extql t2, a1, t3 # U : extract low bits for next time
addq a0, 8, a0 # E :
or t0, t1, t0 # E : current dst word now complete
EX( ldq_u t2, 0(a1) ) # L : load high word for next time
subq a2, 1, a2 # E :
nop
stq_u t0, -8(a0) # L : save the current word
mov t3, t1 # E :
cmpbge zero, t2, t8 # E : test new word for eos
beq a2, $u_eoc # U :
beq t8, $u_loop # U :
nop
nop
nop
/* We've found a zero somewhere in the source word we just read.
If it resides in the lower half, we have one (probably partial)
word to write out, and if it resides in the upper half, we
have one full and one partial word left to write out.
On entry to this basic block:
t1 == the shifted high-order bits from the previous source word
t2 == the unshifted current source word. */
.align 4
$u_eos:
extqh t2, a1, t0 # U :
or t0, t1, t0 # E : first (partial) source word complete
cmpbge zero, t0, t8 # E : is the null in this first bit?
nop
bne t8, $u_final # U :
stq_u t0, 0(a0) # L : the null was in the high-order bits
addq a0, 8, a0 # E :
subq a2, 1, a2 # E :
.align 4
$u_late_head_exit:
extql t2, a1, t0 # U :
cmpbge zero, t0, t8 # E :
or t8, t10, t6 # E :
cmoveq a2, t6, t8 # E :
/* Take care of a final (probably partial) result word.
On entry to this basic block:
t0 == assembled source word
t8 == cmpbge mask that found the null. */
.align 4
$u_final:
negq t8, t6 # E : isolate low bit set
and t6, t8, t12 # E :
ldq_u t1, 0(a0) # L :
subq t12, 1, t6 # E :
or t6, t12, t8 # E :
zapnot t0, t8, t0 # U : kill source bytes > null
zap t1, t8, t1 # U : kill dest bytes <= null
or t0, t1, t0 # E :
stq_u t0, 0(a0) # E :
br $finish_up # U :
nop
nop
.align 4
$u_eoc: # end-of-count
extqh t2, a1, t0 # U :
or t0, t1, t0 # E :
cmpbge zero, t0, t8 # E :
nop
.align 4
$u_eocfin: # end-of-count, final word
or t10, t8, t8 # E :
br $u_final # U :
nop
nop
/* Unaligned copy entry point. */
.align 4
$unaligned:
srl a3, 3, a2 # U : a2 = loop counter = (count - 1)/8
and a0, 7, t4 # E : find dest misalignment
and a1, 7, t5 # E : find src misalignment
mov zero, t0 # E :
/* Conditionally load the first destination word and a bytemask
with 0xff indicating that the destination byte is sacrosanct. */
mov zero, t6 # E :
beq t4, 1f # U :
ldq_u t0, 0(a0) # L :
lda t6, -1 # E :
mskql t6, a0, t6 # E :
nop
nop
nop
.align 4
1:
subq a1, t4, a1 # E : sub dest misalignment from src addr
/* If source misalignment is larger than dest misalignment, we need
extra startup checks to avoid SEGV. */
cmplt t4, t5, t12 # E :
extql t1, a1, t1 # U : shift src into place
lda t2, -1 # E : for creating masks later
beq t12, $u_head # U :
mskqh t2, t5, t2 # U : begin src byte validity mask
cmpbge zero, t1, t8 # E : is there a zero?
nop
extql t2, a1, t2 # U :
or t8, t10, t5 # E : test for end-of-count too
cmpbge zero, t2, t3 # E :
cmoveq a2, t5, t8 # E : Latency=2, extra map slot
nop # E : goes with cmov
andnot t8, t3, t8 # E :
beq t8, $u_head # U :
nop
/* At this point we've found a zero in the first partial word of
the source. We need to isolate the valid source data and mask
it into the original destination data. (Incidentally, we know
that we'll need at least one byte of that original dest word.) */
ldq_u t0, 0(a0) # L :
negq t8, t6 # E : build bitmask of bytes <= zero
mskqh t1, t4, t1 # U :
and t6, t8, t12 # E :
subq t12, 1, t6 # E :
or t6, t12, t8 # E :
zapnot t2, t8, t2 # U : prepare source word; mirror changes
zapnot t1, t8, t1 # U : to source validity mask
andnot t0, t2, t0 # E : zero place for source to reside
or t0, t1, t0 # E : and put it there
stq_u t0, 0(a0) # L :
nop
.align 4
$finish_up:
zapnot t0, t12, t4 # U : was last byte written null?
and t12, 0xf0, t3 # E : binary search for the address of the
cmovne t4, 1, t4 # E : Latency=2, extra map slot
nop # E : with cmovne
and t12, 0xcc, t2 # E : last byte written
and t12, 0xaa, t1 # E :
cmovne t3, 4, t3 # E : Latency=2, extra map slot
nop # E : with cmovne
bic a0, 7, t0
cmovne t2, 2, t2 # E : Latency=2, extra map slot
nop # E : with cmovne
nop
cmovne t1, 1, t1 # E : Latency=2, extra map slot
nop # E : with cmovne
addq t0, t3, t0 # E :
addq t1, t2, t1 # E :
addq t0, t1, t0 # E :
addq t0, t4, t0 # add one if we filled the buffer
subq t0, v0, v0 # find string length
ret # L0 :
.align 4
$zerolength:
nop
nop
nop
clr v0
$exception:
nop
nop
nop
ret
.end __strncpy_from_user
/*
* arch/alpha/lib/ev67-strlen_user.S
* 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com>
*
* Return the length of the string including the NULL terminator
* (strlen+1) or zero if an error occurred.
*
* In places where it is critical to limit the processing time,
* and the data is not trusted, strnlen_user() should be used.
* It will return a value greater than its second argument if
* that limit would be exceeded. This implementation is allowed
* to access memory beyond the limit, but will not cross a page
* boundary when doing so.
*
* Much of the information about 21264 scheduling/coding comes from:
* Compiler Writer's Guide for the Alpha 21264
* abbreviated as 'CWG' in other comments here
* ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
* Scheduling notation:
* E - either cluster
* U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
* L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
* Try not to change the actual algorithm if possible for consistency.
*/
#include <asm/regdef.h>
/* Allow an exception for an insn; exit if we get one. */
#define EX(x,y...) \
99: x,##y; \
.section __ex_table,"a"; \
.long 99b - .; \
lda v0, $exception-99b(zero); \
.previous
.set noreorder
.set noat
.text
.globl __strlen_user
.ent __strlen_user
.frame sp, 0, ra
.align 4
__strlen_user:
ldah a1, 32767(zero) # do not use plain strlen_user() for strings
# that might be almost 2 GB long; you should
# be using strnlen_user() instead
nop
nop
nop
.globl __strnlen_user
.align 4
__strnlen_user:
.prologue 0
EX( ldq_u t0, 0(a0) ) # L : load first quadword (a0 may be misaligned)
lda t1, -1(zero) # E :
insqh t1, a0, t1 # U :
andnot a0, 7, v0 # E :
or t1, t0, t0 # E :
subq a0, 1, a0 # E : get our +1 for the return
cmpbge zero, t0, t1 # E : t1 <- bitmask: bit i == 1 <==> i-th byte == 0
subq a1, 7, t2 # E :
subq a0, v0, t0 # E :
bne t1, $found # U :
addq t2, t0, t2 # E :
addq a1, 1, a1 # E :
nop # E :
nop # E :
.align 4
$loop: ble t2, $limit # U :
EX( ldq t0, 8(v0) ) # L :
nop # E :
nop # E :
cmpbge zero, t0, t1 # E :
subq t2, 8, t2 # E :
addq v0, 8, v0 # E : addr += 8
beq t1, $loop # U :
$found: cttz t1, t2 # U0 :
addq v0, t2, v0 # E :
subq v0, a0, v0 # E :
ret # L0 :
$exception:
nop
nop
nop
ret
.align 4 # currently redundant
$limit:
nop
nop
subq a1, t2, v0
ret
.end __strlen_user
/*
* arch/alpha/lib/strlen_user.S
*
* Return the length of the string including the NUL terminator
* (strlen+1) or zero if an error occurred.
*
* In places where it is critical to limit the processing time,
* and the data is not trusted, strnlen_user() should be used.
* It will return a value greater than its second argument if
* that limit would be exceeded. This implementation is allowed
* to access memory beyond the limit, but will not cross a page
* boundary when doing so.
*/
#include <asm/regdef.h>
/* Allow an exception for an insn; exit if we get one. */
#define EX(x,y...) \
99: x,##y; \
.section __ex_table,"a"; \
.long 99b - .; \
lda v0, $exception-99b(zero); \
.previous
.set noreorder
.set noat
.text
.globl __strlen_user
.ent __strlen_user
.frame sp, 0, ra
.align 3
__strlen_user:
ldah a1, 32767(zero) # do not use plain strlen_user() for strings
# that might be almost 2 GB long; you should
# be using strnlen_user() instead
.globl __strnlen_user
.align 3
__strnlen_user:
.prologue 0
EX( ldq_u t0, 0(a0) ) # load first quadword (a0 may be misaligned)
lda t1, -1(zero)
insqh t1, a0, t1
andnot a0, 7, v0
or t1, t0, t0
subq a0, 1, a0 # get our +1 for the return
cmpbge zero, t0, t1 # t1 <- bitmask: bit i == 1 <==> i-th byte == 0
subq a1, 7, t2
subq a0, v0, t0
bne t1, $found
addq t2, t0, t2
addq a1, 1, a1
.align 3
$loop: ble t2, $limit
EX( ldq t0, 8(v0) )
subq t2, 8, t2
addq v0, 8, v0 # addr += 8
cmpbge zero, t0, t1
beq t1, $loop
$found: negq t1, t2 # clear all but least set bit
and t1, t2, t1
and t1, 0xf0, t2 # binary search for that set bit
and t1, 0xcc, t3
and t1, 0xaa, t4
cmovne t2, 4, t2
cmovne t3, 2, t3
cmovne t4, 1, t4
addq t2, t3, t2
addq v0, t4, v0
addq v0, t2, v0
nop # dual issue next two on ev4 and ev5
subq v0, a0, v0
$exception:
ret
.align 3 # currently redundant
$limit:
subq a1, t2, v0
ret
.end __strlen_user
/*
* arch/alpha/lib/strncpy_from_user.S
* Contributed by Richard Henderson (rth@tamu.edu)
*
* Just like strncpy except in the return value:
*
* -EFAULT if an exception occurs before the terminator is copied.
* N if the buffer filled.
*
* Otherwise the length of the string is returned.
*/
#include <asm/errno.h>
#include <asm/regdef.h>
/* Allow an exception for an insn; exit if we get one. */
#define EX(x,y...) \
99: x,##y; \
.section __ex_table,"a"; \
.long 99b - .; \
lda $31, $exception-99b($0); \
.previous
.set noat
.set noreorder
.text
.globl __strncpy_from_user
.ent __strncpy_from_user
.frame $30, 0, $26
.prologue 0
.align 3
$aligned:
/* On entry to this basic block:
t0 == the first destination word for masking back in
t1 == the first source word. */
/* Create the 1st output word and detect 0's in the 1st input word. */
lda t2, -1 # e1 : build a mask against false zero
mskqh t2, a1, t2 # e0 : detection in the src word
mskqh t1, a1, t3 # e0 :
ornot t1, t2, t2 # .. e1 :
mskql t0, a1, t0 # e0 : assemble the first output word
cmpbge zero, t2, t8 # .. e1 : bits set iff null found
or t0, t3, t0 # e0 :
beq a2, $a_eoc # .. e1 :
bne t8, $a_eos # .. e1 :
/* On entry to this basic block:
t0 == a source word not containing a null. */
$a_loop:
stq_u t0, 0(a0) # e0 :
addq a0, 8, a0 # .. e1 :
EX( ldq_u t0, 0(a1) ) # e0 :
addq a1, 8, a1 # .. e1 :
subq a2, 1, a2 # e0 :
cmpbge zero, t0, t8 # .. e1 (stall)
beq a2, $a_eoc # e1 :
beq t8, $a_loop # e1 :
/* Take care of the final (partial) word store. At this point
the end-of-count bit is set in t8 iff it applies.
On entry to this basic block we have:
t0 == the source word containing the null
t8 == the cmpbge mask that found it. */
$a_eos:
negq t8, t12 # e0 : find low bit set
and t8, t12, t12 # e1 (stall)
/* For the sake of the cache, don't read a destination word
if we're not going to need it. */
and t12, 0x80, t6 # e0 :
bne t6, 1f # .. e1 (zdb)
/* We're doing a partial word store and so need to combine
our source and original destination words. */
ldq_u t1, 0(a0) # e0 :
subq t12, 1, t6 # .. e1 :
or t12, t6, t8 # e0 :
unop #
zapnot t0, t8, t0 # e0 : clear src bytes > null
zap t1, t8, t1 # .. e1 : clear dst bytes <= null
or t0, t1, t0 # e1 :
1: stq_u t0, 0(a0)
br $finish_up
/* Add the end-of-count bit to the eos detection bitmask. */
$a_eoc:
or t10, t8, t8
br $a_eos
/*** The Function Entry Point ***/
.align 3
__strncpy_from_user:
mov a0, v0 # save the string start
beq a2, $zerolength
/* Are source and destination co-aligned? */
xor a0, a1, t1 # e0 :
and a0, 7, t0 # .. e1 : find dest misalignment
and t1, 7, t1 # e0 :
addq a2, t0, a2 # .. e1 : bias count by dest misalignment
subq a2, 1, a2 # e0 :
and a2, 7, t2 # e1 :
srl a2, 3, a2 # e0 : a2 = loop counter = (count - 1)/8
addq zero, 1, t10 # .. e1 :
sll t10, t2, t10 # e0 : t10 = bitmask of last count byte
bne t1, $unaligned # .. e1 :
/* We are co-aligned; take care of a partial first word. */
EX( ldq_u t1, 0(a1) ) # e0 : load first src word
addq a1, 8, a1 # .. e1 :
beq t0, $aligned # avoid loading dest word if not needed
ldq_u t0, 0(a0) # e0 :
br $aligned # .. e1 :
/* The source and destination are not co-aligned. Align the destination
and cope. We have to be very careful about not reading too much and
causing a SEGV. */
.align 3
$u_head:
/* We know just enough now to be able to assemble the first
full source word. We can still find a zero at the end of it
that prevents us from outputting the whole thing.
On entry to this basic block:
t0 == the first dest word, unmasked
t1 == the shifted low bits of the first source word
t6 == bytemask that is -1 in dest word bytes */
EX( ldq_u t2, 8(a1) ) # e0 : load second src word
addq a1, 8, a1 # .. e1 :
mskql t0, a0, t0 # e0 : mask trailing garbage in dst
extqh t2, a1, t4 # e0 :
or t1, t4, t1 # e1 : first aligned src word complete
mskqh t1, a0, t1 # e0 : mask leading garbage in src
or t0, t1, t0 # e0 : first output word complete
or t0, t6, t6 # e1 : mask original data for zero test
cmpbge zero, t6, t8 # e0 :
beq a2, $u_eocfin # .. e1 :
bne t8, $u_final # e1 :
lda t6, -1 # e1 : mask out the bits we have
mskql t6, a1, t6 # e0 : already seen
stq_u t0, 0(a0) # e0 : store first output word
or t6, t2, t2 # .. e1 :
cmpbge zero, t2, t8 # e0 : find nulls in second partial
addq a0, 8, a0 # .. e1 :
subq a2, 1, a2 # e0 :
bne t8, $u_late_head_exit # .. e1 :
/* Finally, we've got all the stupid leading edge cases taken care
of and we can set up to enter the main loop. */
extql t2, a1, t1 # e0 : position hi-bits of lo word
EX( ldq_u t2, 8(a1) ) # .. e1 : read next high-order source word
addq a1, 8, a1 # e0 :
cmpbge zero, t2, t8 # e1 (stall)
beq a2, $u_eoc # e1 :
bne t8, $u_eos # e1 :
/* Unaligned copy main loop. In order to avoid reading too much,
the loop is structured to detect zeros in aligned source words.
This has, unfortunately, effectively pulled half of a loop
iteration out into the head and half into the tail, but it does
prevent nastiness from accumulating in the very thing we want
to run as fast as possible.
On entry to this basic block:
t1 == the shifted high-order bits from the previous source word
t2 == the unshifted current source word
We further know that t2 does not contain a null terminator. */
.align 3
$u_loop:
extqh t2, a1, t0 # e0 : extract high bits for current word
addq a1, 8, a1 # .. e1 :
extql t2, a1, t3 # e0 : extract low bits for next time
addq a0, 8, a0 # .. e1 :
or t0, t1, t0 # e0 : current dst word now complete
EX( ldq_u t2, 0(a1) ) # .. e1 : load high word for next time
stq_u t0, -8(a0) # e0 : save the current word
mov t3, t1 # .. e1 :
subq a2, 1, a2 # e0 :
cmpbge zero, t2, t8 # .. e1 : test new word for eos
beq a2, $u_eoc # e1 :
beq t8, $u_loop # e1 :
/* We've found a zero somewhere in the source word we just read.
If it resides in the lower half, we have one (probably partial)
word to write out, and if it resides in the upper half, we
have one full and one partial word left to write out.
On entry to this basic block:
t1 == the shifted high-order bits from the previous source word
t2 == the unshifted current source word. */
$u_eos:
extqh t2, a1, t0 # e0 :
or t0, t1, t0 # e1 : first (partial) source word complete
cmpbge zero, t0, t8 # e0 : is the null in this first bit?
bne t8, $u_final # .. e1 (zdb)
stq_u t0, 0(a0) # e0 : the null was in the high-order bits
addq a0, 8, a0 # .. e1 :
subq a2, 1, a2 # e1 :
$u_late_head_exit:
extql t2, a1, t0 # .. e0 :
cmpbge zero, t0, t8 # e0 :
or t8, t10, t6 # e1 :
cmoveq a2, t6, t8 # e0 :
nop # .. e1 :
/* Take care of a final (probably partial) result word.
On entry to this basic block:
t0 == assembled source word
t8 == cmpbge mask that found the null. */
$u_final:
negq t8, t6 # e0 : isolate low bit set
and t6, t8, t12 # e1 :
and t12, 0x80, t6 # e0 : avoid dest word load if we can
bne t6, 1f # .. e1 (zdb)
ldq_u t1, 0(a0) # e0 :
subq t12, 1, t6 # .. e1 :
or t6, t12, t8 # e0 :
zapnot t0, t8, t0 # .. e1 : kill source bytes > null
zap t1, t8, t1 # e0 : kill dest bytes <= null
or t0, t1, t0 # e1 :
1: stq_u t0, 0(a0) # e0 :
br $finish_up
$u_eoc: # end-of-count
extqh t2, a1, t0
or t0, t1, t0
cmpbge zero, t0, t8
$u_eocfin: # end-of-count, final word
or t10, t8, t8
br $u_final
/* Unaligned copy entry point. */
.align 3
$unaligned:
EX( ldq_u t1, 0(a1) ) # e0 : load first source word
and a0, 7, t4 # .. e1 : find dest misalignment
and a1, 7, t5 # e0 : find src misalignment
/* Conditionally load the first destination word and a bytemask
with 0xff indicating that the destination byte is sacrosanct. */
mov zero, t0 # .. e1 :
mov zero, t6 # e0 :
beq t4, 1f # .. e1 :
ldq_u t0, 0(a0) # e0 :
lda t6, -1 # .. e1 :
mskql t6, a0, t6 # e0 :
1:
subq a1, t4, a1 # .. e1 : sub dest misalignment from src addr
/* If source misalignment is larger than dest misalignment, we need
extra startup checks to avoid SEGV. */
cmplt t4, t5, t12 # e1 :
extql t1, a1, t1 # .. e0 : shift src into place
lda t2, -1 # e0 : for creating masks later
beq t12, $u_head # e1 :
mskqh t2, t5, t2 # e0 : begin src byte validity mask
cmpbge zero, t1, t8 # .. e1 : is there a zero?
extql t2, a1, t2 # e0 :
or t8, t10, t5 # .. e1 : test for end-of-count too
cmpbge zero, t2, t3 # e0 :
cmoveq a2, t5, t8 # .. e1 :
andnot t8, t3, t8 # e0 :
beq t8, $u_head # .. e1 (zdb)
/* At this point we've found a zero in the first partial word of
the source. We need to isolate the valid source data and mask
it into the original destination data. (Incidentally, we know
that we'll need at least one byte of that original dest word.) */
ldq_u t0, 0(a0) # e0 :
negq t8, t6 # .. e1 : build bitmask of bytes <= zero
mskqh t1, t4, t1 # e0 :
and t6, t8, t12 # .. e1 :
subq t12, 1, t6 # e0 :
or t6, t12, t8 # e1 :
zapnot t2, t8, t2 # e0 : prepare source word; mirror changes
zapnot t1, t8, t1 # .. e1 : to source validity mask
andnot t0, t2, t0 # e0 : zero place for source to reside
or t0, t1, t0 # e1 : and put it there
stq_u t0, 0(a0) # e0 :
$finish_up:
zapnot t0, t12, t4 # was last byte written null?
cmovne t4, 1, t4
and t12, 0xf0, t3 # binary search for the address of the
and t12, 0xcc, t2 # last byte written
and t12, 0xaa, t1
bic a0, 7, t0
cmovne t3, 4, t3
cmovne t2, 2, t2
cmovne t1, 1, t1
addq t0, t3, t0
addq t1, t2, t1
addq t0, t1, t0
addq t0, t4, t0 # add one if we filled the buffer
subq t0, v0, v0 # find string length
ret
$zerolength:
clr v0
$exception:
ret
.end __strncpy_from_user
......@@ -89,6 +89,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
const struct exception_table_entry *fixup;
int fault, si_code = SEGV_MAPERR;
siginfo_t info;
unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
(cause > 0 ? FAULT_FLAG_WRITE : 0));
/* As of EV6, a load into $31/$f31 is a prefetch, and never faults
(or is suppressed by the PALcode). Support that for older CPUs
......@@ -114,6 +116,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
goto vmalloc_fault;
#endif
retry:
down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
if (!vma)
......@@ -144,8 +147,11 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
/* If for any reason at all we couldn't handle the fault,
make sure we exit gracefully rather than endlessly redo
the fault. */
fault = handle_mm_fault(mm, vma, address, cause > 0 ? FAULT_FLAG_WRITE : 0);
up_read(&mm->mmap_sem);
fault = handle_mm_fault(mm, vma, address, flags);
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
return;
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
......@@ -153,10 +159,26 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
goto do_sigbus;
BUG();
}
if (fault & VM_FAULT_MAJOR)
current->maj_flt++;
else
current->min_flt++;
if (flags & FAULT_FLAG_ALLOW_RETRY) {
if (fault & VM_FAULT_MAJOR)
current->maj_flt++;
else
current->min_flt++;
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
/* No need to up_read(&mm->mmap_sem) as we would
* have already released it in __lock_page_or_retry
* in mm/filemap.c.
*/
goto retry;
}
}
up_read(&mm->mmap_sem);
return;
/* Something tried to access memory that isn't in our memory map.
......@@ -186,12 +208,14 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
/* We ran out of memory, or some other thing happened to us that
made us unable to handle the page fault gracefully. */
out_of_memory:
up_read(&mm->mmap_sem);
if (!user_mode(regs))
goto no_context;
pagefault_out_of_memory();
return;
do_sigbus:
up_read(&mm->mmap_sem);
/* Send a sigbus, regardless of whether we were in kernel
or user mode. */
info.si_signo = SIGBUS;
......
......@@ -12,6 +12,7 @@
#include <linux/smp.h>
#include <linux/errno.h>
#include <asm/ptrace.h>
#include <asm/special_insns.h>
#include "op_impl.h"
......
......@@ -1407,13 +1407,6 @@ SYSCALL_DEFINE1(alarm, unsigned int, seconds)
#endif
#ifndef __alpha__
/*
* The Alpha uses getxpid, getxuid, and getxgid instead. Maybe this
* should be moved into arch/i386 instead?
*/
/**
* sys_getpid - return the thread group id of the current process
*
......@@ -1469,8 +1462,6 @@ SYSCALL_DEFINE0(getegid)
return from_kgid_munged(current_user_ns(), current_egid());
}
#endif
static void process_timeout(unsigned long __data)
{
wake_up_process((struct task_struct *)__data);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册