diff options
Diffstat (limited to 'arch/parisc/kernel/syscall.S')
| -rw-r--r-- | arch/parisc/kernel/syscall.S | 68 | 
1 files changed, 50 insertions, 18 deletions
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 68e75ce838d..83878601103 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -1,12 +1,35 @@  /*    * Linux/PA-RISC Project (http://www.parisc-linux.org/)   *  - * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai> + * System call entry code / Linux gateway page + * Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai>   * Licensed under the GNU GPL.   * thanks to Philipp Rumpf, Mike Shaver and various others   * sorry about the wall, puffin..   */ +/* +How does the Linux gateway page on PA-RISC work? +------------------------------------------------ +The Linux gateway page on PA-RISC is "special". +It actually has PAGE_GATEWAY bits set (this is linux terminology; in parisc +terminology it's Execute, promote to PL0) in the page map.  So anything +executing on this page executes with kernel level privilege (there's more to it +than that: to have this happen, you also have to use a branch with a ,gate +completer to activate the privilege promotion).  The upshot is that everything +that runs on the gateway page runs at kernel privilege but with the current +user process address space (although you have access to kernel space via %sr2). +For the 0x100 syscall entry, we redo the space registers to point to the kernel +address space (preserving the user address space in %sr3), move to wide mode if +required, save the user registers and branch into the kernel syscall entry +point.  For all the other functions, we execute at kernel privilege but don't +flip address spaces. The basic upshot of this is that these code snippets are +executed atomically (because the kernel can't be pre-empted) and they may +perform architecturally forbidden (to PL3) operations (like setting control +registers). +*/ + +  #include <asm/asm-offsets.h>  #include <asm/unistd.h>  #include <asm/errno.h> @@ -15,6 +38,7 @@  #include <asm/thread_info.h>  #include <asm/assembly.h>  #include <asm/processor.h> +#include <asm/cache.h>  #include <linux/linkage.h> @@ -156,7 +180,7 @@ linux_gateway_entry:  	STREG	%r26, TASK_PT_GR26(%r1)	 	/* 1st argument */  	STREG	%r27, TASK_PT_GR27(%r1)		/* user dp */  	STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */ -	STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */ +	STREG   %r0, TASK_PT_ORIG_R28(%r1)      /* don't prohibit restarts */  	STREG	%r29, TASK_PT_GR29(%r1)		/* return value 1 */  	STREG	%r31, TASK_PT_GR31(%r1)		/* preserve syscall return ptr */ @@ -180,9 +204,10 @@ linux_gateway_entry:  	/* Are we being ptraced? */  	mfctl	%cr30, %r1 -	LDREG	TI_TASK(%r1),%r1 -	ldw	TASK_PTRACE(%r1), %r1 -	bb,<,n	%r1,31,.Ltracesys +	LDREG	TI_FLAGS(%r1),%r1 +	ldi	_TIF_SYSCALL_TRACE_MASK, %r19 +	and,COND(=) %r1, %r19, %r0 +	b,n	.Ltracesys  	/* Note!  We cannot use the syscall table that is mapped  	nearby since the gateway page is mapped execute-only. */ @@ -308,10 +333,13 @@ tracesys_next:  	LDREG   TASK_PT_GR25(%r1), %r25  	LDREG   TASK_PT_GR24(%r1), %r24  	LDREG   TASK_PT_GR23(%r1), %r23 -#ifdef CONFIG_64BIT  	LDREG   TASK_PT_GR22(%r1), %r22  	LDREG   TASK_PT_GR21(%r1), %r21 +#ifdef CONFIG_64BIT  	ldo	-16(%r30),%r29			/* Reference param save area */ +#else +	stw     %r22, -52(%r30)                 /* 5th argument */ +	stw     %r21, -56(%r30)                 /* 6th argument */  #endif  	comiclr,>>=	__NR_Linux_syscalls, %r20, %r0 @@ -561,10 +589,13 @@ cas_nocontend:  # endif  /* ENABLE_LWS_DEBUG */ +	rsm	PSW_SM_I, %r0				/* Disable interrupts */ +	/* COW breaks can cause contention on UP systems */  	LDCW	0(%sr2,%r20), %r28			/* Try to acquire the lock */  	cmpb,<>,n	%r0, %r28, cas_action		/* Did we get it? */  cas_wouldblock:  	ldo	2(%r0), %r28				/* 2nd case */ +	ssm	PSW_SM_I, %r0  	b	lws_exit				/* Contended... */  	ldo	-EAGAIN(%r0), %r21			/* Spin in userspace */ @@ -591,26 +622,29 @@ cas_action:  	stw	%r1, 4(%sr2,%r20)  #endif  	/* The load and store could fail */ -1:	ldw	0(%sr3,%r26), %r28 +1:	ldw,ma	0(%sr3,%r26), %r28  	sub,<>	%r28, %r25, %r0 -2:	stw	%r24, 0(%sr3,%r26) +2:	stw,ma	%r24, 0(%sr3,%r26)  	/* Free lock */ -	stw	%r20, 0(%sr2,%r20) +	stw,ma	%r20, 0(%sr2,%r20)  #if ENABLE_LWS_DEBUG  	/* Clear thread register indicator */  	stw	%r0, 4(%sr2,%r20)  #endif +	/* Enable interrupts */ +	ssm	PSW_SM_I, %r0  	/* Return to userspace, set no error */  	b	lws_exit  	copy	%r0, %r21  3:		 -	/* Error occured on load or store */ +	/* Error occurred on load or store */  	/* Free lock */  	stw	%r20, 0(%sr2,%r20)  #if ENABLE_LWS_DEBUG  	stw	%r0, 4(%sr2,%r20)  #endif +	ssm	PSW_SM_I, %r0  	b	lws_exit  	ldo	-EFAULT(%r0),%r21	/* set errno */  	nop @@ -621,10 +655,8 @@ cas_action:  	/* Two exception table entries, one for the load,  	   the other for the store. Either return -EFAULT.  	   Each of the entries must be relocated. */ -	.section __ex_table,"aw" -	ASM_ULONG_INSN (1b - linux_gateway_page), (3b - linux_gateway_page) -	ASM_ULONG_INSN (2b - linux_gateway_page), (3b - linux_gateway_page) -	.previous +	ASM_EXCEPTIONTABLE_ENTRY(1b-linux_gateway_page, 3b-linux_gateway_page) +	ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 3b-linux_gateway_page)  	/* Make sure nothing else is placed on this page */ @@ -639,7 +671,7 @@ ENTRY(end_linux_gateway_page)  	.section .rodata,"a" -	.align PAGE_SIZE +	.align 8  	/* Light-weight-syscall table */  	/* Start of lws table. */  ENTRY(lws_table) @@ -648,13 +680,13 @@ ENTRY(lws_table)  END(lws_table)  	/* End of lws table */ -	.align PAGE_SIZE +	.align 8  ENTRY(sys_call_table)  #include "syscall_table.S"  END(sys_call_table)  #ifdef CONFIG_64BIT -	.align PAGE_SIZE +	.align 8  ENTRY(sys_call_table64)  #define SYSCALL_TABLE_64BIT  #include "syscall_table.S" @@ -670,7 +702,7 @@ END(sys_call_table64)  		with ldcw.  	*/  	.section .data -	.align	PAGE_SIZE +	.align	L1_CACHE_BYTES  ENTRY(lws_lock_start)  	/* lws locks */  	.rept 16  | 
