summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-12-19 01:51:58 +0100
committerJustus Winter <4winter@informatik.uni-hamburg.de>2015-02-20 19:14:22 +0100
commitd3f20b06cee70fd5afe8aaff31614756a57e6bb6 (patch)
treec48f6c2aefd471dfad91c22396be360bffb604b7
parent5bf4c1cb311ade33ea2c4b3706f7c6a42917b008 (diff)
i386: specialize `copyinmsg' and `copyoutmsg'
Previously, `copyinmsg' was the same function as `copyin'. The former is for messages, and the size of messages is a multiple of four. Likewise for `copyoutmsg'. Provide a specialized version of both functions. This shaves off a couple of instructions and improves our IPC performance. * i386/i386/locore.S (copyinmsg): New function. (copyoutmsg): New function.
-rw-r--r--i386/i386/locore.S83
1 files changed, 79 insertions, 4 deletions
diff --git a/i386/i386/locore.S b/i386/i386/locore.S
index 2e04bb89..cfda86f0 100644
--- a/i386/i386/locore.S
+++ b/i386/i386/locore.S
@@ -1232,13 +1232,12 @@ ENTRY(discover_x86_cpu_type)
*/
/*
- * Copy from user address space.
+ * Copy from user address space - generic version.
* arg0: user address
* arg1: kernel address
* arg2: byte count
*/
ENTRY(copyin)
-Entry(copyinmsg)
pushl %esi
pushl %edi /* save registers */
@@ -1275,13 +1274,48 @@ copyin_fail:
jmp copyin_ret /* pop frame and return */
/*
- * Copy to user address space.
+ * Copy from user address space - version for copying messages.
+ * arg0: user address
+ * arg1: kernel address
+ * arg2: byte count - must be a multiple of four
+ */
+ENTRY(copyinmsg)
+ pushl %esi
+ pushl %edi /* save registers */
+
+ movl 8+S_ARG0,%esi /* get user start address */
+ movl 8+S_ARG1,%edi /* get kernel destination address */
+ movl 8+S_ARG2,%ecx /* get count */
+
+ movl $USER_DS,%eax /* use user data segment for accesses */
+ mov %ax,%ds
+
+ /*cld*/ /* count up: default mode in all GCC code */
+ shrl $2,%ecx
+ RECOVER(copyinmsg_fail)
+ rep
+ movsl /* move longwords */
+ xorl %eax,%eax /* return 0 for success */
+
+copyinmsg_ret:
+ mov %ss,%di /* restore DS to kernel segment */
+ mov %di,%ds
+
+ popl %edi /* restore registers */
+ popl %esi
+ ret /* and return */
+
+copyinmsg_fail:
+ movl $1,%eax /* return 1 for failure */
+ jmp copyinmsg_ret /* pop frame and return */
+
+/*
+ * Copy to user address space - generic version.
* arg0: kernel address
* arg1: user address
* arg2: byte count
*/
ENTRY(copyout)
-Entry(copyoutmsg)
pushl %esi
pushl %edi /* save registers */
@@ -1322,6 +1356,47 @@ copyout_fail:
movl $1,%eax /* return 1 for failure */
jmp copyout_ret /* pop frame and return */
+/*
+ * Copy to user address space - version for copying messages.
+ * arg0: kernel address
+ * arg1: user address
+ * arg2: byte count - must be a multiple of four
+ */
+ENTRY(copyoutmsg)
+ pushl %esi
+ pushl %edi /* save registers */
+
+ movl 8+S_ARG0,%esi /* get kernel start address */
+ movl 8+S_ARG1,%edi /* get user start address */
+ movl 8+S_ARG2,%ecx /* get count */
+
+ movl $USER_DS,%eax /* use user data segment for accesses */
+ mov %ax,%es
+
+#if !defined(MACH_HYP) && !PAE
+ movl 8+S_ARG2,%edx /* copyout_retry expects count here */
+ cmpl $3,machine_slot+SUB_TYPE_CPU_TYPE
+ jbe copyout_retry /* Use slow version on i386 */
+#endif /* !defined(MACH_HYP) && !PAE */
+
+ shrl $2,%ecx /* move by longwords */
+ RECOVER(copyoutmsg_fail)
+ rep
+ movsl
+ xorl %eax,%eax /* return 0 for success */
+
+copyoutmsg_ret:
+ mov %ss,%di /* restore ES to kernel segment */
+ mov %di,%es
+
+ popl %edi /* restore registers */
+ popl %esi
+ ret /* and return */
+
+copyoutmsg_fail:
+ movl $1,%eax /* return 1 for failure */
+ jmp copyoutmsg_ret /* pop frame and return */
+
#if !defined(MACH_HYP) && !PAE
/*
* Check whether user address space is writable