Linux內核設計與實現 總結筆記(第五章)系統調用

系統調用

內核提供了用戶進程和內核交互的接口,使得應用程序能夠受限制的訪問硬件設備。linux

提供這些接口主要是爲了保證系統穩定可靠,避免應用程序恣意妄行。redis

 

1、內核通訊

系統調用在用戶空間進程和硬件設備之間添加中間才能。做用有三:編程

  • 爲用戶空間提供一種硬件的抽象接口。無需理會物理結構是怎麼樣的。
  • 系統調用保證了系統的穩定和安全。內核能夠有選擇的對其訪問進行控制。
  • 每一個進程都運行在虛擬系統中,用戶空間和系統的其他部分提供這樣一層公共接口。

 

2、API、POSIX和C庫

API:應用程序不須要訪問內核,編程接口能夠組合成API安全

POSIX:依據大多數Unix系統接口創建的cookie

C庫:提供了Unix主要API,全部C程序均可以使用C庫app

 

3、系統調用

例如,getpid中的系統調用:dom

SYSCALL_DEFINE0(getpid)
{
    return task_tgid_vnr(current);    //returns current->tgid
}

SYSCALL_DEFINE0只是一個宏,它定義一個無參數的系統調用(所以數字0),展開後代碼以下:socket

asmlinkage long sys_getpid(void)

asmlinkage是一個限定詞,是一個編譯指令,通知編譯器僅從棧中提取該函數的參數。async

 

3.1 系統調用號

在Linux中,每一個系統調用被附於一個系統調用號。tcp

系統調用號,一旦分配就不能在更改,不然編譯好的應用程序會崩潰。

Linux中有一個"未實現"系統調用sys_ni_syscall(),會返回-ENOSYS。

內核記錄了系統調用表中全部已註冊過的系統調用的列表,存儲在sys_call_table中。定義於arch/i386/kernel/syscall_64.c

 

3.2 系統調用的性能

Linux系統調用比其餘操做系統執行的要快,上下文切換時間是一個重要的緣由,內核都被優化的簡潔高效。

 

4、系統調用處理程序

通知內核的機制是靠軟中斷實現的:經過引起一個異常來促使系統切換到內核態去執行異常處理程序。

此時的異常處理程序就是系統調用處理程序。程序名字叫system_call(),而且與硬件系統密切相關。

system_call()經過將給定的系統調用號與NR_syscalls做比較來檢查有效性。若是它大於或者等於NR_syscalls,該函數就返回-ENOSYS。不然執行系統調用

call *sys_call_table(, %rax, 8)

 

4.2 參數傳遞

參數依次用ebx、ecx、edx、esi和edi的順序存放前5個參數。

須要六個或六個以上參數的狀況很少見,此時,應該用一個單獨的寄存器存放指向全部這些參數在用戶空間地址的指針。

 

5、系統調用的實現

怎樣設計和實現一個系統調用是難題所在,而把它加到內核裏卻無須太多周折。

 

5.1 實現系統調用

Linux中不提倡採用多用途的系統調用(一個系統調用經過傳遞不一樣的參數值來選擇完成不一樣的工做)。

  • 系統調用的接口應該力求簡介,參數儘量少。而且力求穩定,不作改動。
  • 設計接口的時候要儘可能爲未來多作考慮,系統調用設計的越通用越好。
  • 要時刻注意可移植性和健壯性。

 

5.2 參數驗證

若是用戶將不合法的輸入傳遞給內核,那麼系統的安全和穩定將面臨極大的考驗。

最重要的檢查就是檢查用戶提供的指針是否有效,在接收用戶空間的指針以前,內核必須保證:

  • 指針指向的內存區是用戶空間,進程決不能哄騙內核去讀其餘進程的數據。
  • 指針知悉將發的內存區域在進程的地址空間裏,進程決不能哄騙內核去讀其餘進程的數據。
  • 若是是讀,該內存應被標記爲可讀;若是是寫,該內存應被標記爲可寫;若是可執行,該內存應被標記爲可執行。進程不能繞過內存訪問限制。

向用戶空間寫入數據,內核提供了copy_to_user(),第一個參數是進程空間中的目的內存地址。第二個參數是內核空間的源地址,最後一個是數據長度。

從用戶空間讀取數據,內核提供了copy_from_user(),把第二個參數拷貝到第一個參數中,第三個參數是數據長度

SYSCALL_DEFINE4(reboot,
                int, magic1,
                int, magic2,
                unsigned int, cmd,
                void __user *, arg)
{
    char buffer[256];

    /* 咱們只信任啓動系統的系統管理員 */
    if(!capable(CAP_SYS_BOOT))
        return -EPERM;

    /* 爲了安全起見,咱們須要"magic"參數 */
    if(magic1 != LINUX_REBOOT_MAGIC1 ||
      (magic2 != LINUX_REBOOT_MAGIC2 &&
        magic2 != LINUX_REBOOT_MAGIC2A &&
        magic2 != LINUX_REBOOT_MAGIC2B &&
        magic2 != LINUX_REBOOT_MAGIC2C))
        return -EINVAL;
    
    /* 當未設置pm_power_off時,請不要試圖讓power_off的代碼看起來像是能夠停機
     * 而應該採用更簡單的方式 */
    if((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
        cmd = LINUX_REBOOT_CMD_HALT;

    lock_kernel();
    switch(cmd) {
    case LINUX_REBOOT_CMD_RESTART:
        kernel_restart(NULL);
        break;

    case LINUX_REBOOT_CMD_CAD_ON:
        C_A_D = 1;
        break;
    
    case LINUX_REBOOT_CMD_CAD_OFF:
        C_A_D = 0;
        break;
    
    case LINUX_REBOOT_CMD_HALT:
        kernel_halt();
        unlock_kernel();
        do_exit(0);
        break;

    case LINUX_REBOOT_CMD_POWER_OFF:
        kernel_power_off();
        unlock_kernel();
        do_exit(0);
        break;

    case LINUX_REBOOT_CMD_RESTART2:
        if(strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
            unlock_kernel();
            return -EFAULT;
        }
        buffer[sizeof(buffer) - 1] = '\0';

        kernel_restart(buffer);
        break;
    
    default:
        unlock_kernel();
        return -EINVAL;
    }
    unlock_kernel();
    return 0;
}
SYSCALL_DEFINE4

具體capable()的權能和其對應的權限列表,能夠在<linux/capability.h>中找到

 

6、系統上下文調用

在進程上下文中,內核能夠休眠(好比系統調用阻塞或顯式調用schedule()的時候),而且能夠搶佔

可以休眠說明系統調用可使用內核提供 ,休眠能力能給編程極大便利。

當系統調用返回的時候,控制權任然在system_call()中,最終會負責切換到用戶空間,而且用戶進程繼續執行下去。

 

6.1 綁定一個系統調用的最後步驟

當編寫完一個系統調用後,把註冊成一個正式的系統調用是件瑣碎的工做:

1)在系統調用表的最後加入一個表項。從0開始算起,系統調用在該表中的位置就是它的系統調用號

2)對於所支持的各類體系結構,系統調用號都必須定義於<asm/unistd.h>中

3)系統調用必須被編譯進內核映象(不能被編譯成模塊)。只要把它放進kernel/下的一個相關的文件中就能夠了,好比sys.c包含了各類各樣的系統調用。

文中說在entry.s中,多是x86結構。然而我看得是4412的內核,在 arch/arm/kernel/call.S :

/*
 *  linux/arch/arm/kernel/calls.S
 *
 *  Copyright (C) 1995-2005 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *  This file is included thrice in entry-common.S
 */
/* 0 */        CALL(sys_restart_syscall)
        CALL(sys_exit)
        CALL(sys_fork_wrapper)
        CALL(sys_read)
        CALL(sys_write)
/* 5 */        CALL(sys_open)
        CALL(sys_close)
        CALL(sys_ni_syscall)        /* was sys_waitpid */
        CALL(sys_creat)
        CALL(sys_link)
/* 10 */    CALL(sys_unlink)
        CALL(sys_execve_wrapper)
        CALL(sys_chdir)
        CALL(OBSOLETE(sys_time))    /* used by libc4 */
        CALL(sys_mknod)
/* 15 */    CALL(sys_chmod)
        CALL(sys_lchown16)
        CALL(sys_ni_syscall)        /* was sys_break */
        CALL(sys_ni_syscall)        /* was sys_stat */
        CALL(sys_lseek)
/* 20 */    CALL(sys_getpid)
        CALL(sys_mount)
        CALL(OBSOLETE(sys_oldumount))    /* used by libc4 */
        CALL(sys_setuid16)
        CALL(sys_getuid16)
/* 25 */    CALL(OBSOLETE(sys_stime))
        CALL(sys_ptrace)
        CALL(OBSOLETE(sys_alarm))    /* used by libc4 */
        CALL(sys_ni_syscall)        /* was sys_fstat */
        CALL(sys_pause)
/* 30 */    CALL(OBSOLETE(sys_utime))    /* used by libc4 */
        CALL(sys_ni_syscall)        /* was sys_stty */
        CALL(sys_ni_syscall)        /* was sys_getty */
        CALL(sys_access)
        CALL(sys_nice)
/* 35 */    CALL(sys_ni_syscall)        /* was sys_ftime */
        CALL(sys_sync)
        CALL(sys_kill)
        CALL(sys_rename)
        CALL(sys_mkdir)
/* 40 */    CALL(sys_rmdir)
        CALL(sys_dup)
        CALL(sys_pipe)
        CALL(sys_times)
        CALL(sys_ni_syscall)        /* was sys_prof */
/* 45 */    CALL(sys_brk)
        CALL(sys_setgid16)
        CALL(sys_getgid16)
        CALL(sys_ni_syscall)        /* was sys_signal */
        CALL(sys_geteuid16)
/* 50 */    CALL(sys_getegid16)
        CALL(sys_acct)
        CALL(sys_umount)
        CALL(sys_ni_syscall)        /* was sys_lock */
        CALL(sys_ioctl)
/* 55 */    CALL(sys_fcntl)
        CALL(sys_ni_syscall)        /* was sys_mpx */
        CALL(sys_setpgid)
        CALL(sys_ni_syscall)        /* was sys_ulimit */
        CALL(sys_ni_syscall)        /* was sys_olduname */
/* 60 */    CALL(sys_umask)
        CALL(sys_chroot)
        CALL(sys_ustat)
        CALL(sys_dup2)
        CALL(sys_getppid)
/* 65 */    CALL(sys_getpgrp)
        CALL(sys_setsid)
        CALL(sys_sigaction)
        CALL(sys_ni_syscall)        /* was sys_sgetmask */
        CALL(sys_ni_syscall)        /* was sys_ssetmask */
/* 70 */    CALL(sys_setreuid16)
        CALL(sys_setregid16)
        CALL(sys_sigsuspend)
        CALL(sys_sigpending)
        CALL(sys_sethostname)
/* 75 */    CALL(sys_setrlimit)
        CALL(OBSOLETE(sys_old_getrlimit)) /* used by libc4 */
        CALL(sys_getrusage)
        CALL(sys_gettimeofday)
        CALL(sys_settimeofday)
/* 80 */    CALL(sys_getgroups16)
        CALL(sys_setgroups16)
        CALL(OBSOLETE(sys_old_select))    /* used by libc4 */
        CALL(sys_symlink)
        CALL(sys_ni_syscall)        /* was sys_lstat */
/* 85 */    CALL(sys_readlink)
        CALL(sys_uselib)
        CALL(sys_swapon)
        CALL(sys_reboot)
        CALL(OBSOLETE(sys_old_readdir))    /* used by libc4 */
/* 90 */    CALL(OBSOLETE(sys_old_mmap))    /* used by libc4 */
        CALL(sys_munmap)
        CALL(sys_truncate)
        CALL(sys_ftruncate)
        CALL(sys_fchmod)
/* 95 */    CALL(sys_fchown16)
        CALL(sys_getpriority)
        CALL(sys_setpriority)
        CALL(sys_ni_syscall)        /* was sys_profil */
        CALL(sys_statfs)
/* 100 */    CALL(sys_fstatfs)
        CALL(sys_ni_syscall)        /* sys_ioperm */
        CALL(OBSOLETE(ABI(sys_socketcall, sys_oabi_socketcall)))
        CALL(sys_syslog)
        CALL(sys_setitimer)
/* 105 */    CALL(sys_getitimer)
        CALL(sys_newstat)
        CALL(sys_newlstat)
        CALL(sys_newfstat)
        CALL(sys_ni_syscall)        /* was sys_uname */
/* 110 */    CALL(sys_ni_syscall)        /* was sys_iopl */
        CALL(sys_vhangup)
        CALL(sys_ni_syscall)
        CALL(OBSOLETE(sys_syscall))    /* call a syscall */
        CALL(sys_wait4)
/* 115 */    CALL(sys_swapoff)
        CALL(sys_sysinfo)
        CALL(OBSOLETE(ABI(sys_ipc, sys_oabi_ipc)))
        CALL(sys_fsync)
        CALL(sys_sigreturn_wrapper)
/* 120 */    CALL(sys_clone_wrapper)
        CALL(sys_setdomainname)
        CALL(sys_newuname)
        CALL(sys_ni_syscall)        /* modify_ldt */
        CALL(sys_adjtimex)
/* 125 */    CALL(sys_mprotect)
        CALL(sys_sigprocmask)
        CALL(sys_ni_syscall)        /* was sys_create_module */
        CALL(sys_init_module)
        CALL(sys_delete_module)
/* 130 */    CALL(sys_ni_syscall)        /* was sys_get_kernel_syms */
        CALL(sys_quotactl)
        CALL(sys_getpgid)
        CALL(sys_fchdir)
        CALL(sys_bdflush)
/* 135 */    CALL(sys_sysfs)
        CALL(sys_personality)
        CALL(sys_ni_syscall)        /* reserved for afs_syscall */
        CALL(sys_setfsuid16)
        CALL(sys_setfsgid16)
/* 140 */    CALL(sys_llseek)
        CALL(sys_getdents)
        CALL(sys_select)
        CALL(sys_flock)
        CALL(sys_msync)
/* 145 */    CALL(sys_readv)
        CALL(sys_writev)
        CALL(sys_getsid)
        CALL(sys_fdatasync)
        CALL(sys_sysctl)
/* 150 */    CALL(sys_mlock)
        CALL(sys_munlock)
        CALL(sys_mlockall)
        CALL(sys_munlockall)
        CALL(sys_sched_setparam)
/* 155 */    CALL(sys_sched_getparam)
        CALL(sys_sched_setscheduler)
        CALL(sys_sched_getscheduler)
        CALL(sys_sched_yield)
        CALL(sys_sched_get_priority_max)
/* 160 */    CALL(sys_sched_get_priority_min)
        CALL(sys_sched_rr_get_interval)
        CALL(sys_nanosleep)
        CALL(sys_mremap)
        CALL(sys_setresuid16)
/* 165 */    CALL(sys_getresuid16)
        CALL(sys_ni_syscall)        /* vm86 */
        CALL(sys_ni_syscall)        /* was sys_query_module */
        CALL(sys_poll)
        CALL(sys_nfsservctl)
/* 170 */    CALL(sys_setresgid16)
        CALL(sys_getresgid16)
        CALL(sys_prctl)
        CALL(sys_rt_sigreturn_wrapper)
        CALL(sys_rt_sigaction)
/* 175 */    CALL(sys_rt_sigprocmask)
        CALL(sys_rt_sigpending)
        CALL(sys_rt_sigtimedwait)
        CALL(sys_rt_sigqueueinfo)
        CALL(sys_rt_sigsuspend)
/* 180 */    CALL(ABI(sys_pread64, sys_oabi_pread64))
        CALL(ABI(sys_pwrite64, sys_oabi_pwrite64))
        CALL(sys_chown16)
        CALL(sys_getcwd)
        CALL(sys_capget)
/* 185 */    CALL(sys_capset)
        CALL(sys_sigaltstack_wrapper)
        CALL(sys_sendfile)
        CALL(sys_ni_syscall)        /* getpmsg */
        CALL(sys_ni_syscall)        /* putpmsg */
/* 190 */    CALL(sys_vfork_wrapper)
        CALL(sys_getrlimit)
        CALL(sys_mmap2)
        CALL(ABI(sys_truncate64, sys_oabi_truncate64))
        CALL(ABI(sys_ftruncate64, sys_oabi_ftruncate64))
/* 195 */    CALL(ABI(sys_stat64, sys_oabi_stat64))
        CALL(ABI(sys_lstat64, sys_oabi_lstat64))
        CALL(ABI(sys_fstat64, sys_oabi_fstat64))
        CALL(sys_lchown)
        CALL(sys_getuid)
/* 200 */    CALL(sys_getgid)
        CALL(sys_geteuid)
        CALL(sys_getegid)
        CALL(sys_setreuid)
        CALL(sys_setregid)
/* 205 */    CALL(sys_getgroups)
        CALL(sys_setgroups)
        CALL(sys_fchown)
        CALL(sys_setresuid)
        CALL(sys_getresuid)
/* 210 */    CALL(sys_setresgid)
        CALL(sys_getresgid)
        CALL(sys_chown)
        CALL(sys_setuid)
        CALL(sys_setgid)
/* 215 */    CALL(sys_setfsuid)
        CALL(sys_setfsgid)
        CALL(sys_getdents64)
        CALL(sys_pivot_root)
        CALL(sys_mincore)
/* 220 */    CALL(sys_madvise)
        CALL(ABI(sys_fcntl64, sys_oabi_fcntl64))
        CALL(sys_ni_syscall) /* TUX */
        CALL(sys_ni_syscall)
        CALL(sys_gettid)
/* 225 */    CALL(ABI(sys_readahead, sys_oabi_readahead))
        CALL(sys_setxattr)
        CALL(sys_lsetxattr)
        CALL(sys_fsetxattr)
        CALL(sys_getxattr)
/* 230 */    CALL(sys_lgetxattr)
        CALL(sys_fgetxattr)
        CALL(sys_listxattr)
        CALL(sys_llistxattr)
        CALL(sys_flistxattr)
/* 235 */    CALL(sys_removexattr)
        CALL(sys_lremovexattr)
        CALL(sys_fremovexattr)
        CALL(sys_tkill)
        CALL(sys_sendfile64)
/* 240 */    CALL(sys_futex)
        CALL(sys_sched_setaffinity)
        CALL(sys_sched_getaffinity)
        CALL(sys_io_setup)
        CALL(sys_io_destroy)
/* 245 */    CALL(sys_io_getevents)
        CALL(sys_io_submit)
        CALL(sys_io_cancel)
        CALL(sys_exit_group)
        CALL(sys_lookup_dcookie)
/* 250 */    CALL(sys_epoll_create)
        CALL(ABI(sys_epoll_ctl, sys_oabi_epoll_ctl))
        CALL(ABI(sys_epoll_wait, sys_oabi_epoll_wait))
        CALL(sys_remap_file_pages)
        CALL(sys_ni_syscall)    /* sys_set_thread_area */
/* 255 */    CALL(sys_ni_syscall)    /* sys_get_thread_area */
        CALL(sys_set_tid_address)
        CALL(sys_timer_create)
        CALL(sys_timer_settime)
        CALL(sys_timer_gettime)
/* 260 */    CALL(sys_timer_getoverrun)
        CALL(sys_timer_delete)
        CALL(sys_clock_settime)
        CALL(sys_clock_gettime)
        CALL(sys_clock_getres)
/* 265 */    CALL(sys_clock_nanosleep)
        CALL(sys_statfs64_wrapper)
        CALL(sys_fstatfs64_wrapper)
        CALL(sys_tgkill)
        CALL(sys_utimes)
/* 270 */    CALL(sys_arm_fadvise64_64)
        CALL(sys_pciconfig_iobase)
        CALL(sys_pciconfig_read)
        CALL(sys_pciconfig_write)
        CALL(sys_mq_open)
/* 275 */    CALL(sys_mq_unlink)
        CALL(sys_mq_timedsend)
        CALL(sys_mq_timedreceive)
        CALL(sys_mq_notify)
        CALL(sys_mq_getsetattr)
/* 280 */    CALL(sys_waitid)
        CALL(sys_socket)
        CALL(ABI(sys_bind, sys_oabi_bind))
        CALL(ABI(sys_connect, sys_oabi_connect))
        CALL(sys_listen)
/* 285 */    CALL(sys_accept)
        CALL(sys_getsockname)
        CALL(sys_getpeername)
        CALL(sys_socketpair)
        CALL(sys_send)
/* 290 */    CALL(ABI(sys_sendto, sys_oabi_sendto))
        CALL(sys_recv)
        CALL(sys_recvfrom)
        CALL(sys_shutdown)
        CALL(sys_setsockopt)
/* 295 */    CALL(sys_getsockopt)
        CALL(ABI(sys_sendmsg, sys_oabi_sendmsg))
        CALL(sys_recvmsg)
        CALL(ABI(sys_semop, sys_oabi_semop))
        CALL(sys_semget)
/* 300 */    CALL(sys_semctl)
        CALL(sys_msgsnd)
        CALL(sys_msgrcv)
        CALL(sys_msgget)
        CALL(sys_msgctl)
/* 305 */    CALL(sys_shmat)
        CALL(sys_shmdt)
        CALL(sys_shmget)
        CALL(sys_shmctl)
        CALL(sys_add_key)
/* 310 */    CALL(sys_request_key)
        CALL(sys_keyctl)
        CALL(ABI(sys_semtimedop, sys_oabi_semtimedop))
/* vserver */    CALL(sys_ni_syscall)
        CALL(sys_ioprio_set)
/* 315 */    CALL(sys_ioprio_get)
        CALL(sys_inotify_init)
        CALL(sys_inotify_add_watch)
        CALL(sys_inotify_rm_watch)
        CALL(sys_mbind)
/* 320 */    CALL(sys_get_mempolicy)
        CALL(sys_set_mempolicy)
        CALL(sys_openat)
        CALL(sys_mkdirat)
        CALL(sys_mknodat)
/* 325 */    CALL(sys_fchownat)
        CALL(sys_futimesat)
        CALL(ABI(sys_fstatat64,  sys_oabi_fstatat64))
        CALL(sys_unlinkat)
        CALL(sys_renameat)
/* 330 */    CALL(sys_linkat)
        CALL(sys_symlinkat)
        CALL(sys_readlinkat)
        CALL(sys_fchmodat)
        CALL(sys_faccessat)
/* 335 */    CALL(sys_pselect6)
        CALL(sys_ppoll)
        CALL(sys_unshare)
        CALL(sys_set_robust_list)
        CALL(sys_get_robust_list)
/* 340 */    CALL(sys_splice)
        CALL(sys_sync_file_range2)
        CALL(sys_tee)
        CALL(sys_vmsplice)
        CALL(sys_move_pages)
/* 345 */    CALL(sys_getcpu)
        CALL(sys_epoll_pwait)
        CALL(sys_kexec_load)
        CALL(sys_utimensat)
        CALL(sys_signalfd)
/* 350 */    CALL(sys_timerfd_create)
        CALL(sys_eventfd)
        CALL(sys_fallocate)
        CALL(sys_timerfd_settime)
        CALL(sys_timerfd_gettime)
/* 355 */    CALL(sys_signalfd4)
        CALL(sys_eventfd2)
        CALL(sys_epoll_create1)
        CALL(sys_dup3)
        CALL(sys_pipe2)
/* 360 */    CALL(sys_inotify_init1)
        CALL(sys_preadv)
        CALL(sys_pwritev)
        CALL(sys_rt_tgsigqueueinfo)
        CALL(sys_perf_event_open)
/* 365 */    CALL(sys_recvmmsg)
        CALL(sys_accept4)
        CALL(sys_fanotify_init)
        CALL(sys_fanotify_mark)
        CALL(sys_prlimit64)
/* 370 */    CALL(sys_name_to_handle_at)
        CALL(sys_open_by_handle_at)
        CALL(sys_clock_adjtime)
        CALL(sys_syncfs)
        CALL(sys_sendmmsg)
/* 375 */    CALL(sys_setns)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
#endif
.rept syscalls_padding
        CALL(sys_ni_syscall)
.endr
syscall表

要把新的系統調用加到這個表的末尾。

接下來咱們要把系統調用號加入到<asm/unistd.h>中,它的格式以下:

/*
 * This file contains the system call numbers.
 */

#define __NR_restart_syscall        (__NR_SYSCALL_BASE+  0)
#define __NR_exit            (__NR_SYSCALL_BASE+  1)
#define __NR_fork            (__NR_SYSCALL_BASE+  2)
#define __NR_read            (__NR_SYSCALL_BASE+  3)
#define __NR_write            (__NR_SYSCALL_BASE+  4)
#define __NR_open            (__NR_SYSCALL_BASE+  5)
#define __NR_close            (__NR_SYSCALL_BASE+  6)

#define __NR_name_to_handle_at        (__NR_SYSCALL_BASE+370)
#define __NR_open_by_handle_at        (__NR_SYSCALL_BASE+371)
#define __NR_clock_adjtime        (__NR_SYSCALL_BASE+372)
#define __NR_syncfs            (__NR_SYSCALL_BASE+373)
#define __NR_sendmmsg            (__NR_SYSCALL_BASE+374)
#define __NR_setns            (__NR_SYSCALL_BASE+375)
asm/unistd.h

加入一項好比:#define __NR_foo 338

 

4)而後它是實現函數,能夠放在最緊密關聯的代碼中去。好比功能和調度相關,能夠放在sched.c中

#include <asm/page.h>
/*
 * sys_foo - 每一個人喜歡的系統調用
 */
asmlinkage long sys_foo(void)
{
    return THREAD_SIZE;
}
sys_foo

 

6.2 用戶空間訪問系統調用

一般,系統調用靠C庫支持。用戶程序經過包含標準頭文件並和C庫連接,就可使用系統調用。

Linux自己提供共了一組宏,用於直接對系統調用進行訪問。它會設置好寄存器並調用陷入指令。這些宏是_syscalln(),其中n範圍是0到6,表明須要傳遞給系統調用的參數個數。

long open(const char *filename, int flags, int mode)
/* 而不靠庫支持,直接調用今後系統調用的宏形式爲 */
#define NR_open 5
_syscall3(long, open, const char *, filename, int, flags, int, mode)
/* 這樣應用程序就能夠直接使用open */
open系統調用例子

對於每一個宏來講,都有2+2xn個參數。第一個參數對應着系統調用的返回值類型。第二個參數是系統調用的名稱。再之後是按照系統調用參數的順序排列的每一個參數的類型和名稱。

 

而後是foo()調用的測試代碼:

#define __NR_foo 283
__syscall0(long, foo)

int main()
{
    long stack_size;

    stack_size = foo();
    printf("The kernel stack size is %ld\n", stack_size);

    return 0;   
}
__NR_foo

 

6.3 爲何不經過系統調用的方式實現

儘管創建一個新的系統調用很是容易,但不提倡這麼作。一般都會有更好的辦法用來代替新建一個系統調用以做實現。

創建一個新的系統調用的好處:

  • 系統調用建立容易且使用方便。
  • Linux系統調用的高性能顯而易見。

 

問題是:

  • 你須要一個系統調用號,而這個須要一個內核在處於開發版本的時候由官方分配給你
  • 系統調用被加入穩定內核後就被固化了,爲了不應用程序的崩潰,它的接口不容許作改動
  • 須要將系統調用分別註冊到每一個須要支持的體系結構中去
  • 在腳本中不容易條用系統調用,也不能從文件系統直接訪問系統調用
  • 因爲你須要系統調用號,所以在主內核樹以外是很難維護和使用系統調用的
  • 若是僅僅進行簡單的信息交換,系統調用就大材小用了

 

替代方法:

  • 實現一個設備節點,並對此實現read()和write()。使用ioctl()對特定的設置進行操做或者對特定的信息進行檢索。
  • 像信號量這樣的某些接口,能夠用文件描述符來表示,所以就能夠按上述方式對其進行操做。
  • 把增長的信息做爲一個文件放在sysfs的合適位置。
相關文章
相關標籤/搜索