Messages in this thread Patch in this message |  | | | Date | Sat, 13 Jun 1998 08:45:56 -0700 (PDT) | | From | <> | | Subject | SYSENTER based syscalls patch, 2.1.105, RFC | |
the attached patch implements SYSENTER/SYSEXIT based system calls for P6
type x86 CPUs that support it. (tested only on PII, - K6, PPro anyone?)
with this patch, null-syscall latency got more than halved on PIIs:
[mingo@hal fastcall]$ ./fastcall
(INT $0x80 based getpid(), got pid 497) latency:282 cycles
(SYSENTER based getpid(), got pid 497) latency:138 cycles
on a 266 MHz PII this is 0.51 usecs for a getpid(). (was 1.06 usecs)
the interface is binary compatible, glibc support with auto-detection is
in the works (being worked on by Richard Hendersson).
At first sight it looks like as if schedule() got slower by loading the
MSR in switch_to(), but actually scheduling times get faster, because no
matter how we get into schedule(), we have done it through some syscall
interface ...
the implementation has a few FIXME's, but is more or less equivalent to
the final version. (performance-wise)
i've attached some small testcode too which demonstrates the new syscall
interface, compile it with:
gcc -fomit-frame-pointer -o fastcall fastcall.c
enjoy, reports/comments/suggestions welcome.
-- mingo
--- ./include/asm-i386/system.h.orig Sat Jun 13 07:53:24 1998
+++ ./include/asm-i386/system.h Sat Jun 13 07:57:00 1998
@@ -52,7 +52,10 @@
* It also reloads the debug regs if necessary..
*/
-
+#define LOAD_FASTSYS \
+ __asm__ __volatile__("wrmsr" : : \
+ "c" (0x175), "a" ((int)(next) + 2*PAGE_SIZE), "d" (0))
+
#ifdef __SMP__
/*
* Keep the lock depth straight. If we switch on an interrupt from
@@ -76,6 +79,7 @@
__asm__ __volatile__("fwait"); \
prev->flags&=~PF_USEDFPU; \
} \
+ LOAD_FASTSYS; \
__asm__("ljmp %0\n\t" \
: /* no output */ \
:"m" (*(((char *)&next->tss.tr)-4)), \
@@ -93,6 +97,7 @@
#else
#define switch_to(prev,next) do { \
+ LOAD_FASTSYS; \
__asm__("ljmp %0\n\t" \
"cmpl %1,"SYMBOL_NAME_STR(last_task_used_math)"\n\t" \
"jne 1f\n\t" \
--- ./arch/i386/kernel/entry.S.orig Tue May 12 13:13:15 1998
+++ ./arch/i386/kernel/entry.S Sat Jun 13 08:40:14 1998
@@ -1,7 +1,7 @@
/*
* linux/arch/i386/entry.S
*
- * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1991, 1992, 1998 Linus Torvalds, Ingo Molnar
*/
/*
@@ -94,7 +94,7 @@
movl %dx,%ds; \
movl %dx,%es;
-#define RESTORE_ALL \
+#define RESTORE_ALL_REGS \
popl %ebx; \
popl %ecx; \
popl %edx; \
@@ -104,9 +104,18 @@
popl %eax; \
popl %ds; \
popl %es; \
- addl $4,%esp; \
+ addl $4,%esp;
+
+#define RESTORE_ALL \
+ RESTORE_ALL_REGS \
iret
+#define RESTORE_ALL_FASTSYS \
+ RESTORE_ALL_REGS \
+ movl %ebp, %ecx; \
+ movl (%ebp), %edx; \
+ .byte 0x0f, 0x35;
+
#define GET_CURRENT(reg) \
movl %esp, reg; \
andl $-8192, reg;
@@ -139,6 +148,92 @@
btrl $0, SYMBOL_NAME(scheduler_lock)
jmp ret_from_sys_call
#endif /* __SMP__ */
+
+ENTRY(fast_system_call)
+
+/*
+ * %ebp has the caller's stack, first entry on the stack is the
+ * return eip ... ugly but we have to do it this way due to
+ * the (only?) 5 parameter system call select()
+ */
+
+ sti # ugh! SYSENTER disables IRQs
+
+ pushl %eax # save orig_eax
+ SAVE_ALL
+
+ #
+ # validate the user provided return stack-pointer and EIP
+ # _before_ we execute the system call.
+ #
+
+ GET_CURRENT(%ebx)
+
+#if 0
+/*
+ * FIXME: user-space access, add exception code
+ */
+ cmpl %ebp, addr_limit(%ebx)
+ jge badfastsys
+ movl (%ebp), %edx;
+ cmpl %edx, addr_limit(%ebx)
+ jge badfastsys
+#endif
+ cmpl $(NR_syscalls),%eax
+ jae badfastsys
+
+ testb $0x20,flags(%ebx) # PF_TRACESYS
+ jne tracefastsys
+ call *SYMBOL_NAME(sys_call_table)(,%eax,4)
+ movl %eax,EAX(%esp) # save the return value
+ ALIGN
+ .globl ret_from_fastsys_call
+ret_from_fastsys_call:
+ movl SYMBOL_NAME(bh_mask),%eax
+ andl SYMBOL_NAME(bh_active),%eax
+ jne handle_bottom_half_fastsys
+ cmpl $0,SYMBOL_NAME(need_resched)
+ jne reschedule_fastsys
+ cmpl $0,sigpending(%ebx)
+ jne signal_return_fastsys
+ RESTORE_ALL_FASTSYS
+ ALIGN
+signal_return_fastsys:
+ testl $(VM_MASK),EFLAGS(%esp)
+ pushl %esp
+ jne v86_signal_return_fastsys
+ pushl $0
+ call SYMBOL_NAME(do_signal)
+ addl $8,%esp
+ RESTORE_ALL_FASTSYS
+ ALIGN
+v86_signal_return_fastsys:
+ call SYMBOL_NAME(save_v86_state)
+ movl %eax,%esp
+ pushl %eax
+ pushl $0
+ call SYMBOL_NAME(do_signal)
+ addl $8,%esp
+ RESTORE_ALL_FASTSYS
+ ALIGN
+tracefastsys:
+ movl $-ENOSYS,EAX(%esp)
+ call SYMBOL_NAME(syscall_trace)
+ movl ORIG_EAX(%esp),%eax
+ call *SYMBOL_NAME(sys_call_table)(,%eax,4)
+ movl %eax,EAX(%esp) # save the return value
+ call SYMBOL_NAME(syscall_trace)
+ jmp ret_from_fastsys_call
+handle_bottom_half_fastsys:
+ pushl $ret_from_fastsys_call
+ jmp SYMBOL_NAME(do_bottom_half)
+ ALIGN
+reschedule_fastsys:
+ pushl $ret_from_fastsys_call
+ jmp SYMBOL_NAME(schedule) # test
+badfastsys:
+ movl $-ENOSYS,EAX(%esp)
+ jmp ret_from_fastsys_call
/*
* Return to user mode is not as complex as all this looks,
--- ./arch/i386/kernel/mtrr.c.orig Tue Jun 9 21:49:19 1998
+++ ./arch/i386/kernel/mtrr.c Sat Jun 13 03:56:26 1998
@@ -1205,6 +1205,13 @@
__initfunc(int mtrr_init(void))
#endif
{
+ extern char fast_system_call;
+
+ printk("fastsys init\n");
+ wrmsr(0x174, 0x10, 0);
+ wrmsr(0x175, 0, 0);
+ wrmsr(0x176, &fast_system_call, 0);
+
if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
# if !defined(__SMP__) || defined(MODULE)
printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sched.h>
unsigned int t1,t2,t3,t4;
unsigned int TIME64 (void)
{
unsigned int dummy,low;
__asm__("rdtsc"
:"=a" (low),
"=d" (dummy));
return low;
}
int main(void)
{
int i, pid;
for (i=0; i<100; i++)
{
t1 = TIME64();
asm volatile ("
movl $20, %%eax
int $0x80
":"=a"(pid)::"memory");
t2 = TIME64();
}
for (i=0; i<100; i++)
{
t3 = TIME64();
t4 = TIME64();
}
printf("(INT $0x80 based getpid(), got pid %d) latency:%u cycles\n",
pid, t2-t1-(t4-t3));
for (i=0; i<100; i++)
{
t1 = TIME64();
asm volatile ("
mov $1f, %%edx;
pushl %%edx
movl %%esp, %%ecx;
movl %%esp, %%ebp
movl $20, %%eax
.byte 0x0f, 0x34;
1:
popl %%edx
":"=a"(pid)::"memory");
t2 = TIME64();
}
printf("(SYSENTER based getpid(), got pid %d) latency:%u cycles\n",
pid, t2-t1-(t4-t3));
return 0;
}
|  |