精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

雙核系統調用(ipipe)

Linux閱碼場 ? 來源:Linux閱碼場 ? 作者:順剛 ? 2022-05-06 11:11 ? 次閱讀

雙核系統調用(ipipe)

解析系統調用是了解內核架構最有力的一把鑰匙。

Linux內核基礎上加入xenomai實時系統內核后,在內核空間兩個內核共存,實時任務需要xenomai內核來完成實時的服務,如果實時任務需要用到linux的服務,還可以調用linux內核的系統調用,你可能會好奇xenomai與linux兩個內核共存后系統調用是如何實現的?

e3b36ab8-ccd0-11ec-bce3-dac502259ad0.png

為什么需要系統調用?現代操作系統中,處理器的運行模式一般分為兩個空間:內核空間和用戶空間,大部分應用程序運行在用戶空間,而操作系統內核和設備驅動程序運行在內核空間,如果應用程序需要訪問硬件資源或者需要內核提供服務,該怎么辦?

為了向用戶空間上運行的應用程序提供服務,內核提供了一組接口。透過該接口,應用程序可以訪問硬件設備和其他操作系統資源。這組接口在應用程序和內核之間扮演了使者的角色,應用程序發送各種請求,而內核負責滿足這些請求,這些接口就是系統調用,它是用戶空間和內核空間一個中間層。

系統調用層主要作用有三個:

  • 它為用戶空間提供了一種統一的硬件的抽象接口。比如當需要讀些文件的時候,應用程序就可以不去管磁盤類型和介質,甚至不用去管文件所在的文件系統到底是哪種類型。

  • 系統調用保證了系統的穩定和安全。應用程序要訪問內核就必須通過系統調用層,內核可以在系統調用層對應用程序的訪問權限、用戶類型和其他一些規則進行過濾,這避免了應用不正確地訪問內核,保證了系統和各個應用程序的安全性。

  • 可移植性??梢宰寫贸绦蛟诓恍薷脑创a的情況下,在不同的操作系統或擁有不同硬件架構的系統中重新編譯運行。

回到本文開頭的問題,該問題細分為如下兩個問題:

  1. 雙核共存時,如何區分應用發起的系統調用是xenomai內核調用還是linux內核調用?

  2. 一個xenomai實時任務既可以調用xenomai內核服務,也可以調用linux內核服務,這是如何做到的?

本文通過分析源代碼為你解答問題1,對于問題2,涉及雙核間的調度,本文暫不涉及,后面的文章揭曉答案。

一、32位Linux系統調用

我們先來看沒有ipipe和xenomai內核時的linux系統調用流程是怎樣的。linux操作系統的API通常以C標準庫的方式提供,比如linux中的libc庫。C標準庫中提供了POSIX的絕大部分API實現,glibc為了提高應用程序的性能,還對一些系統調用進行了封裝。此外,由于32位系統系統調用使用軟中斷 int0x80指令實現,應用程序也可以通過匯編直接進行系統調用。軟中斷屬于異常的一種,通過執行該指令陷入(trap)內核,trap在整理的文檔 x86Linux中斷系統有說明。內核初始化過程中,通過函數 tarp_init()設置IDT(Interrupt Descriptor Table 記錄每個中斷異常處理程序的地址的一張表),有關 int0x80的IDT表項如下:

static const __initconst struct idt_data def_idts[] = {  ......  SYSG(IA32_SYSCALL_VECTOR,  entry_INT80_32),  ......};

當產生系統調用時,硬件根據向量號在 IDT 中找到對應的表項,即中斷描述符,進行特權級檢查,發現 DPL = CPL = 3 ,允許調用。然后硬件將切換到內核棧 (tss.ss0 : tss.esp0)。接著根據中斷描述符的 segment selector 在 GDT / LDT 中找到對應的段描述符,從段描述符拿到段的基址,加載到 cs 。將 offset 加載到 eip。最后硬件將 ss / sp / eflags / cs / ip / error code 依次壓到內核棧。于是開始執行 entry_INT80_32函數,該函數在 entry_32.S定義:

ENTRY(entry_INT80_32)  ASM_CLAC  pushl  %eax    /* pt_regs->orig_ax */  SAVE_ALL pt_regs_ax=$-ENOSYS  /* *存儲當前用戶態寄存器,保存在pt_regs結構里*/  /*   * User mode is traced as though IRQs are on, and the interrupt gate   * turned them off.   */  TRACE_IRQS_OFF
  movl  %esp, %eax  call  do_int80_syscall_32.Lsyscall_32_done:  ........Lirq_return:  INTERRUPT_RETURN/*iret 指令將原來用戶態保存的現場恢復回來,包含代碼段、指令指針寄存器等。這時候用戶態進程恢復執行。*/

在內核棧的最高地址端,存放的是結構 ptregs,首先通過 push 和 SAVEALL 將當前用戶態的寄存器,保存在棧中 ptregs 結構里面.保存完畢后,關閉中斷,將當前棧指針保存到 eax,即doint80syscall32的參數1。調用doint80syscall32=>dosyscall32irqs_on。先看看沒有ipipe時Linux實現如下:

__always_inline void do_syscall_32_irqs_on(struct pt_regs *regs){  struct thread_info *ti = pt_regs_to_thread_info(regs);  unsigned int nr = (unsigned int)regs->orig_ax;
  .....  if (likely(nr < IA32_NR_syscalls)) {    nr = array_index_nospec(nr, IA32_NR_syscalls);    regs->ax = ia32_sys_call_table[nr](  /*根據系統調用號索引直接執行*/      (unsigned int)regs->bx, (unsigned int)regs->cx,      (unsigned int)regs->dx, (unsigned int)regs->si,      (unsigned int)regs->di, (unsigned int)regs->bp);  }  syscall_return_slowpath(regs);}

在這里,將系統調用號從pt_reges中eax 里面取出來,然后根據系統調用號,在系統調用表中找到相應的函數進行調用,并將寄存器中保存的參數取出來,作為函數參數。如果仔細比對,就能發現,這些參數所對應的寄存器,和 Linux 的注釋是一樣的。ia32_sys_call_table系統調用表生成后面解析(此圖來源于網絡)。

e3cd33d0-ccd0-11ec-bce3-dac502259ad0.png

相關內核調用執行完后,一直返回到 dosyscall32irqson ,如果系統調用有返回值,會被保存到 regs->ax 中。接著返回 entryINT8032 繼續執行,最后執行 INTERRUPTRETURN 。INTERRUPTRETURN 在 arch/x86/include/asm/irqflags.h 中定義為 iret ,iret 指令將原來用戶態保存的現場恢復回來,包含代碼段、指令指針寄存器等。這時候用戶態進程恢復執行。

系統調用執行完畢。

二、32位實時系統調用

xenomai+linux雙內核架構下,通過I-pipe 攔截系統調用,并將系統調用定向到實現它們的系統。

實時系統調用,除了直接通過匯編系統調用外,xenomai還實現了libcoblat實時庫,相當于glibc,通過libcoblat進行xenomai系統調用,以libcoblat庫函數sem_open為例,libcolat庫中C函數實現如下:

COBALT_IMPL(sem_t *, sem_open, (const char *name, int oflags, ...)){  ......  err = XENOMAI_SYSCALL5(sc_cobalt_sem_open,             &rsem, name, oflags, mode, value);  if (err == 0) {    if (rsem != sem)      free(sem);    return &rsem->native_sem;  }  .......  return SEM_FAILED;}

libcolat庫調用系統調用使用宏 XENOMAI_SYSCALL5,XENOAI_SYSCALL宏在 includeasmxenomaisyscall.h中聲明, XENOMAI_SYSCALL5中的'5'代表'該系統調用有五個參數:

#define XENOMAI_DO_SYSCALL(nr, op, args...)      ({                  unsigned __resultvar;            asm volatile (                LOADARGS_##nr              "movl %1, %%eax
	"            DOSYSCALL              RESTOREARGS_##nr            : "=a" (__resultvar)            : "i" (__xn_syscode(op)) ASMFMT_##nr(args)      : "memory", "cc");          (int) __resultvar;          })
#define XENOMAI_SYSCALL0(op)      XENOMAI_DO_SYSCALL(0,op)#define XENOMAI_SYSCALL1(op,a1)      XENOMAI_DO_SYSCALL(1,op,a1)#define XENOMAI_SYSCALL2(op,a1,a2)    XENOMAI_DO_SYSCALL(2,op,a1,a2)#define XENOMAI_SYSCALL3(op,a1,a2,a3)    XENOMAI_DO_SYSCALL(3,op,a1,a2,a3)#define XENOMAI_SYSCALL4(op,a1,a2,a3,a4)  XENOMAI_DO_SYSCALL(4,op,a1,a2,a3,a4)#defineXENOMAI_SYSCALL5(op,a1,a2,a3,a4,a5)XENOMAI_DO_SYSCALL(5,op,a1,a2,a3,a4,a5)

每個宏中,內嵌另一個宏DOSYSCALL,即實現系統調用的int指令:int$0x80

#defineDOSYSCALL"int$0x80
	"

系統調用過程硬件處理及中斷入口上節一致,從 do_syscall_32_irqs_on開始不同,有ipipe后變成下面這樣子:

static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs){  struct thread_info *ti = current_thread_info();  unsigned int nr = (unsigned int)regs->orig_ax;/*取出系統調用號*/  int ret;    ret = pipeline_syscall(ti, nr, regs);/*pipeline 攔截系統調用*/  ......done:  syscall_return_slowpath(regs);}

套路和ipipe接管中斷類似,在關鍵路徑上攔截系統調用,然后調用 ipipe_handle_syscall(ti,nr,regs)讓ipipe來接管處理:

int ipipe_handle_syscall(struct thread_info *ti,       unsigned long nr, struct pt_regs *regs){  unsigned long local_flags = READ_ONCE(ti->ipipe_flags);  int ret;   if (nr >= NR_syscalls && (local_flags & _TIP_HEAD)) {/*運行在head域且者系統調用號超過linux*/    ipipe_fastcall_hook(regs);      /*快速系統調用路徑*/    local_flags = READ_ONCE(ti->ipipe_flags);    if (local_flags & _TIP_HEAD) {      if (local_flags &  _TIP_MAYDAY)        __ipipe_call_mayday(regs);      return 1; /* don't pass down, no tail work. */    } else {      sync_root_irqs();      return -1; /* don't pass down, do tail work. */    }  }
  if ((local_flags & _TIP_NOTIFY) || nr >= NR_syscalls) {    ret =__ipipe_notify_syscall(regs);    local_flags = READ_ONCE(ti->ipipe_flags);    if (local_flags & _TIP_HEAD)      return 1; /* don't pass down, no tail work. */    if (ret)      return -1; /* don't pass down, do tail work. */  }
  return 0; /* pass syscall down to the host. */}

這個函數的處理邏輯是這樣,怎樣區分xenomai系統調用和linux系統調用?每個CPU架構不同linux系統調用總數不同,在x86系統中有300多個,用變量 NR_syscalls表示,系統調用號與系統調用一一對應。首先獲取到的系統調用號 nr>=NR_syscalls,不用多想,那這個系統調用是xenomai內核的系統調用。另外還有個問題,如果是Linux非實時任務觸發的xenomai系統調用,或者xenomai 實時任務要調用linux的服務,這些交叉服務涉及實時任務與非實時任務在兩個內核之間運行,優先級怎么處理等問題。這些涉及 cobalt_sysmodes[].

首先看怎么區分一個任務是realtime還是norealtime。在 task_struct結構的頭有一個成員結構體 thread_info,存儲著當前線程的信息,ipipe在結構體 thread_info中增加了兩個成員變量 ipipe_flagsipipe_data, ipipe_flags用來來標示一個線程是實時還是非實時,TIPHEAD置位表示已經是實時上下文。對于需要切換到xenomai上下文的系統調用TIP_NOTIFY置位。

struct thread_info {  unsigned long    flags;    /* low level flags */  u32      status;    /* thread synchronous flags */#ifdef CONFIG_IPIPE  unsigned long    ipipe_flags;  struct ipipe_threadinfo ipipe_data;#endif};

ipipe_handle_syscall處理邏輯:1.對于已經在實時上下文的實時任務發起xenomai的系統調用,使用快速調用路徑函數 ipipe_fastcall_hook(regs);2.需要切換到實時上下文或者非實時調用實時的,使用慢速調用路徑:

_ipipenotifysyscall(regs)->ipipesyscallhook(callerdomain, regs)

快速調用 ipipe_fastcall_hook(regs)內直接 handle_head_syscall執行代碼如下:

static int handle_head_syscall(struct ipipe_domain *ipd, struct pt_regs *regs){  ....  code = __xn_syscall(regs);  nr = code & (__NR_COBALT_SYSCALLS - 1);  ......  handler = cobalt_syscalls[code];  sysflags = cobalt_sysmodes[nr];  ........
  ret = handler(__xn_reg_arglist(regs));  .......
  __xn_status_return(regs, ret);
  .......}

這個函數很復雜,涉及xenomai與linux之間很多聯系,代碼是簡化后的,先取出系統調用號,然后從 cobalt_syscalls取出系統調用入口handler,然后執行 handler(__xn_reg_arglist(regs))執行完成后將執行結果放到寄存器 ax,后面的文章會詳細分析ipipe如何處理系統調用。

三、 64位系統調用

我們再來看 64 位的情況,系統調用,不是用中斷了,而是改用 syscall 指令。并且傳遞參數的寄存器也變了。e3f3a1f0-ccd0-11ec-bce3-dac502259ad0.png

#define DO_SYSCALL(name, nr, args...)      ({                unsigned long __resultvar;        LOAD_ARGS_##nr(args)          LOAD_REGS_##nr            asm volatile (              "syscall
	"            : "=a" (__resultvar)          : "0" (name) ASM_ARGS_##nr        : "memory", "cc", "r11", "cx");      (int) __resultvar;        })
#define XENOMAI_DO_SYSCALL(nr, op, args...)   DO_SYSCALL(__xn_syscode(op), nr, args)
#define XENOMAI_SYSBIND(breq) XENOMAI_DO_SYSCALL(1,sc_cobalt_bind,breq)

這里將系統調用號使用 __xn_syscode(op)處理了一下,把最高位置1,表示Cobalt系統調用,然后使用syscall 指令。

#define __COBALT_SYSCALL_BIT  0x10000000#define__xn_syscode(__nr)(__COBALT_SYSCALL_BIT|(__nr))

syscall 指令還使用了一種特殊的寄存器,我們叫特殊模塊寄存器(Model Specific Registers,簡稱 MSR)。這種寄存器是 CPU 為了完成某些特殊控制功能為目的的寄存器,其中就有系統調用。在系統初始化的時候,trapinit 除了初始化上面的中斷模式,這里面還會調用 cpuinit->syscall_init。這里面有這樣的代碼:

wrmsrl(MSR_LSTAR,(unsignedlong)entry_SYSCALL_64);

rdmsr 和 wrmsr 是用來讀寫特殊模塊寄存器的。MSRLSTAR 就是這樣一個特殊的寄存器, 當 syscall 指令調用的時候,會從這個寄存器里面拿出函數地址來調用,也就是調entrySYSCALL64。該函數在'entry64.S'定義:

ENTRY(entry_SYSCALL_64)  UNWIND_HINT_EMPTY  ......  swapgs  /*   * This path is only taken when PAGE_TABLE_ISOLATION is disabled so it   * is not required to switch CR3.   */  movq  %rsp, PER_CPU_VAR(rsp_scratch)  movq  PER_CPU_VAR(cpu_current_top_of_stack), %rsp
  /* Construct struct pt_regs on stack */  pushq  $__USER_DS      /* pt_regs->ss */  pushq  PER_CPU_VAR(rsp_scratch)  /* pt_regs->sp */  pushq  %r11        /* pt_regs->flags */  pushq  $__USER_CS      /* pt_regs->cs */  pushq  %rcx        /* pt_regs->ip *//*保存用戶太指令指針寄存器*/GLOBAL(entry_SYSCALL_64_after_hwframe)  pushq  %rax        /* pt_regs->orig_ax */
  PUSH_AND_CLEAR_REGS rax=$-ENOSYS
  TRACE_IRQS_OFF
  /* IRQs are off. */  movq  %rsp, %rdi  call  do_syscall_64    /* returns with IRQs disabled */
  TRACE_IRQS_IRETQ    /* we're about to change IF */
  /*   * Try to use SYSRET instead of IRET if we're returning to   * a completely clean 64-bit userspace context.  If we're not,   * go to the slow exit path.   */  movq  RCX(%rsp), %rcx  movq  RIP(%rsp), %r11
  cmpq  %rcx, %r11  /* SYSRET requires RCX == RIP */  jne  swapgs_restore_regs_and_return_to_usermode  .......  testq  $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11  jnz  swapgs_restore_regs_and_return_to_usermode
  /* nothing to check for RSP */
  cmpq  $__USER_DS, SS(%rsp)    /* SS must match SYSRET */  jne  swapgs_restore_regs_and_return_to_usermode
  /*   * We win! This label is here just for ease of understanding   * perf profiles. Nothing jumps here.   */syscall_return_via_sysret:  /* rcx and r11 are already restored (see code above) */  UNWIND_HINT_EMPTY  POP_REGS pop_rdi=0 skip_r11rcx=1
  /*   * Now all regs are restored except RSP and RDI.   * Save old stack pointer and switch to trampoline stack.   */  movq  %rsp, %rdi  movq  PER_CPU_VAR(cpu_tss_rw + TSS_sp0), %rsp
  pushq  RSP-RDI(%rdi)  /* RSP */  pushq  (%rdi)    /* RDI */
  /*   * We are on the trampoline stack.  All regs except RDI are live.   * We can do future final exit work right here.   */  SWITCH_TO_USER_CR3_STACK scratch_reg=%rdi
  popq  %rdi  popq  %rsp  USERGS_SYSRET64END(entry_SYSCALL_64)

這里先保存了很多寄存器到 pt_regs 結構里面,例如用戶態的代碼段、數據段、保存參數的寄存器.

e40ad8c0-ccd0-11ec-bce3-dac502259ad0.png

然后調用 entry_SYSCALL64_slow_pat->do_syscall_64。

__visible void do_syscall_64(struct pt_regs *regs){  struct thread_info *ti = current_thread_info();  unsigned long nr = regs->orig_ax;  /*取出系統調用號*/  int ret;
  enter_from_user_mode();  enable_local_irqs();
  ret = ipipe_handle_syscall(ti, nr & __SYSCALL_MASK, regs);  if (ret > 0) {    disable_local_irqs();    return;  }  if (ret < 0)    goto done;  ......  if (likely((nr & __SYSCALL_MASK) < NR_syscalls)) {    nr = array_index_nospec(nr & __SYSCALL_MASK, NR_syscalls);    regs->ax = sys_call_table[nr](      regs->di, regs->si, regs->dx,      regs->r10, regs->r8, regs->r9);  }done:  syscall_return_slowpath(regs);}

與32位一樣,ipipe攔截了系統調用,后面的處理流程類似所以,無論是 32 位,還是 64 位,都會到linux系統調用表 sys_call_table和xenomai系統調用表 cobalt_syscalls[]這里來。

四、 實時系統調用表cobalt_syscalls

xenomai每個系統的系統系統調用號在 cobaltuapisyscall.h中:

#define sc_cobalt_bind        0#define sc_cobalt_thread_create      1#define sc_cobalt_thread_getpid      2  ......#definesc_cobalt_extend96

bind()函數在內核代碼中對應的聲明和實現為:


/*聲明*/#define COBALT_SYSCALL_DECL(__name, __args)    long CoBaLt_ ## __name __argsstatic COBALT_SYSCALL_DECL(bind, lostage,          (struct cobalt_bindreq __user *u_breq));/*實現*/#define COBALT_SYSCALL(__name, __mode, __args)    long CoBaLt_ ## __name __argsstatic COBALT_SYSCALL(bind, lostage,(structcobalt_bindreq__user*u_breq)){......}

其中 __name表示系統調用名對應bind、 __mode表示該系統調用模式對應lostage。 COBALT_SYSCALL展開定義的bind函數后如下:

longCoBaLt_bind(structcobalt_bindreq__user*u_breq){......}

么將 CoBaLt_bind與系統調用號 sc_cobalt_bind聯系起來后放入 cobalt_syscalls[]的呢?在編譯過程中Makefile使用腳本 gen-syscall-entries.sh處理各個 .c文件中的COBALTSYSCALL宏,生成一個頭文件 syscall_entries.h,里面是對每個COBALTSYSCALL宏處理后后的項,以上面 COBALT_SYSCALL(bind,...)為例 syscall_entries.h中會生成如下兩項,第一項為系統調用入口,第二項為系統調用的模式:

#define __COBALT_CALL_ENTRIES __COBALT_CALL_ENTRY(bind)#define__COBALT_CALL_MODES__COBALT_MODE(lostage)

實時系統調用表 cobalt_syscalls[]定義在文件 kernelcobaltposixsyscall.c中:

#define __syshand__(__name)  ((cobalt_syshand)(CoBaLt_ ## __name))
#define __COBALT_NI  __syshand__(ni)
#define __COBALT_CALL_NI          [0 ... __NR_COBALT_SYSCALLS-1] = __COBALT_NI,    __COBALT_CALL32_INITHAND(__COBALT_NI)
#define __COBALT_CALL_NFLAGS          [0 ... __NR_COBALT_SYSCALLS-1] = 0,      __COBALT_CALL32_INITMODE(0)
#define __COBALT_CALL_ENTRY(__name)          [sc_cobalt_ ## __name] = __syshand__(__name),      __COBALT_CALL32_ENTRY(__name, __syshand__(__name))
#define __COBALT_MODE(__name, __mode)    [sc_cobalt_ ## __name] = __xn_exec_##__mode,  #include "syscall_entries.h"    /*該頭文件由腳本生成*/
static const cobalt_syshand cobalt_syscalls[] = {  __COBALT_CALL_NI  __COBALT_CALL_ENTRIES};
static const int cobalt_sysmodes[] = {  __COBALT_CALL_NFLAGS  __COBALT_CALL_MODES};

_COBALTCALLNI宏表示數組空間大小為__NRCOBALTSYSCALLS(128),每一項由COBALTCALL_ENTRIES定義,即腳本頭文件 syscall_entries.h中生成的每一項來填充:

#define __COBALT_CALL_ENTRY(__name)          [sc_cobalt_ ## __name] = __syshand__(__name),    __COBALT_CALL32_ENTRY(__name,__syshand__(__name))

__COBALT_CALL32_ENTRY是定義兼容的系統調用,宏展開如下,相當于在數組的多個位置定義包含了同一項CoBaLt_bind

#define __COBALT_CALL32_ENTRY(__name, __handler)    __COBALT_CALL32x_ENTRY(__name, __handler)    __COBALT_CALL32emu_ENTRY(__name, __handler)
#define __COBALT_CALL32emu_ENTRY(__name, __handler)          [sc_cobalt_ ## __name + 256] = __handler,#define __COBALT_CALL32x_ENTRY(__name, __handler)    [sc_cobalt_##__name+128]=__handler,

最后bind系統調用在cobalt_syscalls[]中如下

static const cobalt_syshand cobalt_syscalls[] = {  [sc_cobalt_bind] = CoBaLt_bind,    [sc_cobalt_bind + 128] = CoBaLt_bind,   /*x32 support */    [sc_cobalt_bind + 256] = CoBaLt_bind,   /*ia32 emulation support*/  .....};

相應的數組cobalt_sysmodes[]中的內容如下:

static const int cobalt_sysmodes[] = {  [sc_cobalt_bind] = __xn_exec_bind,    [sc_cobalt_bind + 256] = __xn_exec_lostage, /*x32 support */    [sc_cobalt_bind + 128] = __xn_exec_lostage, /*ia32 emulation support*/    ......};

五、實時系統調用權限控制cobalt_sysmodes

上面說到,ipipe管理應用的系統調用時需要分清該系統調用是否合法,是否需要域切換等等。cobalt_sysmodes[]就是每個系統調用對應的模式,控制著每個系統調用的調用路徑。系統調用號為下標,值為具體模式。每個系統調用的sysmode如何生成見上一節,還是以實時應用的bind系統調用為例:

static const int cobalt_sysmodes[] = {  [sc_cobalt_bind] = __xn_exec_bind,    [sc_cobalt_bind + 256] = __xn_exec_lostage, /*x32 support */    [sc_cobalt_bind + 128] = __xn_exec_lostage, /*ia32 emulation support*/    ......};

xenomai中所有的系統調用模式定義如下:

/*xenomaiposixsyscall.c*/#define __xn_exec_lostage    0x1  /*必須在linux域運行該系統調用*/  #define __xn_exec_histage    0x2  /*必須在Xenomai域運行該系統調用*/  #define __xn_exec_shadow     0x4    /*影子系統調用:必須映射調用方*/#define __xn_exec_switchback 0x8   /*切換回切換;調用者必須返回其原始模式*/#define __xn_exec_current    0x10    /*在不管域直接執行。*/#define __xn_exec_conforming 0x20    /*在兼容域(Xenomai或Linux)中執行*/#define __xn_exec_adaptive   0x40  /* 先直接執行如果返回-ENOSYS,則嘗試在相反的域中重新執行系統調用 */#define __xn_exec_norestart  0x80  /*收到信號后不要重新啟動syscall*/ /*Shorthand初始化系統調用的簡寫*/#define __xn_exec_init       __xn_exec_lostage /*Xenomai空間中shadow系統調用的簡寫*/#define __xn_exec_primary   (__xn_exec_shadow|__xn_exec_histage) /*Linux空間中shadow系統調用的簡寫*/#define __xn_exec_secondary (__xn_exec_shadow|__xn_exec_lostage)/*Linux空間中syscall的簡寫,如果有shadow則切換回linux*/#define __xn_exec_downup    (__xn_exec_lostage|__xn_exec_switchback)/* 主域系統不可重啟調用的簡寫 */#define __xn_exec_nonrestartable (__xn_exec_primary|__xn_exec_norestart)/*域探測系統調用簡寫*/#define __xn_exec_probing   (__xn_exec_conforming|__xn_exec_adaptive)/*將模式選擇移交給syscall。*/#define__xn_exec_handover(__xn_exec_current|__xn_exec_adaptive)

使用一個無符號32 位數的每一位來表示一種模式,各模式注釋已經很清楚,不在解釋,后面文章解析ipipe是如何根據mode來處理的。

參考

英特爾 64 位和 IA-32 架構軟件開發人員手冊第 3 卷 :系統編程指南極客時間專欄-趣談Linux操作系統《linux內核源代碼情景分析》

審核編輯 :李倩


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    87

    文章

    11227

    瀏覽量

    208922
  • 操作系統
    +關注

    關注

    37

    文章

    6738

    瀏覽量

    123190
  • 雙核
    +關注

    關注

    0

    文章

    37

    瀏覽量

    15179

原文標題:雙核系統調用(ipipe)

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    全志T113異構處理器的使用基于Tina Linux5.0——異構通信驗證

    6、通信驗證 6.1、C906小創建通訊節點 在C906小串口終端建立兩個通訊節點用于監聽數據,輸入eptdev_bind test 2 cpu0 >eptdev_bin
    發表于 11-20 09:47

    Vivado中FFT IP的使用教程

    本文介紹了Vidado中FFT IP的使用,具體內容為:調用IP>>配置界面介紹>>IP端口介紹>>MATLAB生成測試數據>>測試verilogHDL>>TestBench仿真
    的頭像 發表于 11-06 09:51 ?366次閱讀
    Vivado中FFT IP<b class='flag-5'>核</b>的使用教程

    cpu和單核cpu的區別

    CPU與單核CPU在多個方面存在顯著差異,這些差異主要體現在處理能力、性能、運行效率、功耗以及適用場景等方面。 一、概念與結構 CPU :指在一個處理器上集成兩個運算核心,通過
    的頭像 發表于 09-24 16:17 ?1938次閱讀

    dsp和單核dsp的區別

    DSP(Digital Signal Processor,數字信號處理器)與單核DSP在多個方面存在顯著差異,這些差異主要體現在處理能力、任務分配、資源利用以及適用場景等方面。 一、處理能力
    的頭像 發表于 09-24 16:14 ?558次閱讀

    TMS320F2837xD微控制器數據表

    電子發燒友網站提供《TMS320F2837xD微控制器數據表.pdf》資料免費下載
    發表于 08-01 12:59 ?0次下載
    TMS320F2837xD<b class='flag-5'>雙</b><b class='flag-5'>核</b>微控制器數據表

    使用STM32CUBEMX生成 H745代碼,利用cubeide debug時發現M7阻塞進入error_handler是為什么?

    使用STM32CUBEMX 生成 H745代碼,利用cubeide debug時發現M7因為以下代碼阻塞進入error_handler, 請問是為什么? /* USER CODE BEGIN
    發表于 05-20 07:16

    關于FPGA IP

    對于深入學習使用FPGA的小伙伴們,特別是一些復雜的、大規模的設計應用,適宜的IP核對開發能起到事半功倍的作用。IP的概念與我們sdk里庫的概念相似。IP即電路功能模塊,用戶可以直接調用這些模塊
    發表于 04-29 21:01

    STM32H745ZGTx芯片使用內部FLASH,掛載FATFS為什么打不開文件?

    STM32H745ZGTx芯片使用內部FLASH,掛載FATFS為何打不開文件?
    發表于 04-07 07:11

    STM32H747如何用JLINK調試?

    1.我之前是在STM32H747的官方開發板discover上進行調試,板子上自帶了STlink調試器,按照官方文檔配置可以進行調試 2.目前自己設計的板子上是調試接口是SWD接口,手上只有
    發表于 03-28 08:58

    stm32H747的IAP升級要怎么做?

    H747我看有2個Hex文件,生成的Bin文件也有2個。Bootloader要怎么處理呢?也是2個Bootloader程序嗎?那我要IAP升級程序的話要怎么處理了?
    發表于 03-28 08:50

    PSoC架構中都可以訪問全部外設嗎?

    你好!如標題:PSoC 架構中兩個內核對芯片的全部外設都有直接訪問能力嘛?如果都可以直接訪問,那IPC模塊的主要應用場景是哪些呢?
    發表于 02-02 11:44

    Linux內核中信號相關的系統調用

    正如我們所知,運行在用戶態下的程序可以發送和接收信號。這意味著必須定義一組系統調用來允許這類操作。不幸的是,由于歷史原因,有些系統調用可能功能相同。 因此,其中一些
    的頭像 發表于 01-20 09:34 ?651次閱讀

    請問ADSP BF609的運行同時跑兩個系統,需要如何設置,要注意哪些問題?

    請問ADSP BF609的運行同時跑兩個系統,需要如何設置,要注意哪些問題?另外對另一個運行的實時性處理要求的高一些,尤其是系統啟動時
    發表于 01-12 08:08

    linux內核系統調用之參數傳遞

    與普通函數一樣,系統調用通常需要一些輸入/輸出參數,這些參數可能包括實際值(即數字)、用戶模式進程地址空間中的變量地址,甚至包括指向用戶模式函數指針的數據結構的地址(參見第11章“信號相關的系統
    的頭像 發表于 12-20 09:32 ?1442次閱讀

    Linux系統調用腳本的常見方法

    在linux系統中有多種方法可以在系統啟動后調用腳本,接下來介紹幾種常見的方法
    的頭像 發表于 12-13 18:16 ?999次閱讀