lkml.org 
[lkml]   [1998]   [Jun]   [13]   [last100]   RSS Feed
Views: [more markup]  [less markup]  [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
DateSat, 13 Jun 1998 08:45:56 -0700 (PDT)
From<>
SubjectSYSENTER 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;
}

\
 
 \ /
  Last update: 2005-03-22 12:43    [from the cache]
©2003-2008