關鍵詞:__SYSCALL()、SYSCALL_DEFINEx()、syscall()等等。git
內核和用戶空間數據交換有不少種方式:sysfs、proc、信號等等。api
可是syscall效率要高於這些方式,使用起來也更加簡單。函數
缺點是可移植性差,對於新增的系統調用,須要內核和用戶空間同步。spa
每一個系統調用都有一個系統調用號,這個系統調用號對應sys_call_table[]下標。code
經過sys_call_table[syscallid]就能夠對應到此係統調用的函數。blog
在include/uapi/asm/unistd.h中添加__NR_basetime系統調用號,關聯繫統調用號和系統調用函數。ci
diff --git a/arch/csky/include/uapi/asm/unistd.h b/arch/csky/include/uapi/asm/unistd.h index 98e62b9..a1b6503 100644 --- a/arch/csky/include/uapi/asm/unistd.h +++ b/arch/csky/include/uapi/asm/unistd.h @@ -43,6 +43,11 @@ __SYSCALL(__NR_ugetrlimit, sys_getrlimit) #define __NR_sysfs (__NR_arch_specific_syscall + 5) __SYSCALL(__NR_sysfs, sys_sysfs) +#ifdef CONFIG_PERF_TIMER +#define __NR_basetime (__NR_arch_specific_syscall + 6) +__SYSCALL(__NR_basetime, sys_basetime) +#endif
__SYSCALL()將sys_call_table[]中的系統調用號和系統調用函數關聯起來。get
#undef __SYSCALL #define __SYSCALL(nr, call) [nr] = (call), #define sys_fadvise64_64 sys_csky_fadvise64_64 void * const sys_call_table[__NR_syscalls] __page_aligned_data = { [0 ... __NR_syscalls - 1] = sys_ni_syscall, #include <asm/unistd.h> };
在include/asm/syscalls.h中添加sys_basetime()引用。同步
#ifdef CONFIG_PERF_TIMER long sys_basetime(void); #endif
最後就是sys_basetime()的實現:string
SYSCALL_DEFINE0(basetime) { return perf_timer_read_us(); }
當SYSCALL_DEFINEx()的x爲0時,很簡單就是調用sys_##name()函數。
x爲其餘值時,同時定義了幾個函數,並使用了別名屬性。
#define SYSCALL_DEFINE0(sname) \ SYSCALL_METADATA(_##sname, 0); \ asmlinkage long sys_##sname(void) #define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) #define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) #define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) #define SYSCALL_DEFINEx(x, sname, ...) \ SYSCALL_METADATA(sname, x, __VA_ARGS__) \ __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) #define __PROTECT(...) asmlinkage_protect(__VA_ARGS__) #define __SYSCALL_DEFINEx(x, name, ...) \ asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ __attribute__((alias(__stringify(SyS##name)))); \ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \ long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \ __MAP(x,__SC_TEST,__VA_ARGS__); \ __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ return ret; \ } \ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
用戶空間系統調用的使用經過syscall函數:
#define _GNU_SOURCE /* See feature_test_macros(7) */ #include <unistd.h> #include <sys/syscall.h> /* For SYS_xxx definitions */ long syscall(long number, ...);
第一個參數是系統調用號,後面的參數是內核對應sys_##name()函數一致的。
#include <stdio.h> #include <unistd.h> #define __NR_basetime 250 void main(void) { unsigned int timestamp = 0, i = 0; for(i = 0; i < 100; i++) { timestamp = syscall(__NR_basetime); printf("timestamp=%u\n", timestamp); usleep(1000); } }
用戶空間經過syscall()函數,觸發系統調用,使系統由用戶態陷入到內核態。
在系統個調用異常裏面獲取到系統調用號,以及必須的參數。根據系統調用號和sys_call_table[]找到對應系統調用函數。
以syscall()其他部分參數爲入參,執行相關結果。完成後返還給用戶空間。