在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

雙核系統(tǒng)調(diào)用(ipipe)

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

雙核系統(tǒng)調(diào)用(ipipe)

解析系統(tǒng)調(diào)用是了解內(nèi)核架構(gòu)最有力的一把鑰匙。

Linux內(nèi)核基礎(chǔ)上加入xenomai實(shí)時系統(tǒng)內(nèi)核后,在內(nèi)核空間兩個內(nèi)核共存,實(shí)時任務(wù)需要xenomai內(nèi)核來完成實(shí)時的服務(wù),如果實(shí)時任務(wù)需要用到linux的服務(wù),還可以調(diào)用linux內(nèi)核的系統(tǒng)調(diào)用,你可能會好奇xenomai與linux兩個內(nèi)核共存后系統(tǒng)調(diào)用是如何實(shí)現(xiàn)的?

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

為什么需要系統(tǒng)調(diào)用?現(xiàn)代操作系統(tǒng)中,處理器的運(yùn)行模式一般分為兩個空間:內(nèi)核空間和用戶空間,大部分應(yīng)用程序運(yùn)行在用戶空間,而操作系統(tǒng)內(nèi)核和設(shè)備驅(qū)動程序運(yùn)行在內(nèi)核空間,如果應(yīng)用程序需要訪問硬件資源或者需要內(nèi)核提供服務(wù),該怎么辦?

為了向用戶空間上運(yùn)行的應(yīng)用程序提供服務(wù),內(nèi)核提供了一組接口。透過該接口,應(yīng)用程序可以訪問硬件設(shè)備和其他操作系統(tǒng)資源。這組接口在應(yīng)用程序和內(nèi)核之間扮演了使者的角色,應(yīng)用程序發(fā)送各種請求,而內(nèi)核負(fù)責(zé)滿足這些請求,這些接口就是系統(tǒng)調(diào)用,它是用戶空間和內(nèi)核空間一個中間層。

系統(tǒng)調(diào)用層主要作用有三個:

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

  • 系統(tǒng)調(diào)用保證了系統(tǒng)的穩(wěn)定和安全。應(yīng)用程序要訪問內(nèi)核就必須通過系統(tǒng)調(diào)用層,內(nèi)核可以在系統(tǒng)調(diào)用層對應(yīng)用程序的訪問權(quán)限、用戶類型和其他一些規(guī)則進(jìn)行過濾,這避免了應(yīng)用不正確地訪問內(nèi)核,保證了系統(tǒng)和各個應(yīng)用程序的安全性。

  • 可移植性。可以讓應(yīng)用程序在不修改源代碼的情況下,在不同的操作系統(tǒng)或擁有不同硬件架構(gòu)的系統(tǒng)中重新編譯運(yùn)行。

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

  1. 雙核共存時,如何區(qū)分應(yīng)用發(fā)起的系統(tǒng)調(diào)用是xenomai內(nèi)核調(diào)用還是linux內(nèi)核調(diào)用?

  2. 一個xenomai實(shí)時任務(wù)既可以調(diào)用xenomai內(nèi)核服務(wù),也可以調(diào)用linux內(nèi)核服務(wù),這是如何做到的?

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

一、32位Linux系統(tǒng)調(diào)用

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

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

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

ENTRY(entry_INT80_32)  ASM_CLAC  pushl  %eax    /* pt_regs->orig_ax */  SAVE_ALL pt_regs_ax=$-ENOSYS  /* *存儲當(dāng)前用戶態(tài)寄存器,保存在pt_regs結(jié)構(gòu)里*/  /*   * 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 指令將原來用戶態(tài)保存的現(xiàn)場恢復(fù)回來,包含代碼段、指令指針寄存器等。這時候用戶態(tài)進(jìn)程恢復(fù)執(zhí)行。*/

在內(nèi)核棧的最高地址端,存放的是結(jié)構(gòu) ptregs,首先通過 push 和 SAVEALL 將當(dāng)前用戶態(tài)的寄存器,保存在棧中 ptregs 結(jié)構(gòu)里面.保存完畢后,關(guān)閉中斷,將當(dāng)前棧指針保存到 eax,即doint80syscall32的參數(shù)1。調(diào)用doint80syscall32=>dosyscall32irqs_on。先看看沒有ipipe時Linux實(shí)現(xiàn)如下:

__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](  /*根據(jù)系統(tǒng)調(diào)用號索引直接執(zhí)行*/      (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);}

在這里,將系統(tǒng)調(diào)用號從pt_reges中eax 里面取出來,然后根據(jù)系統(tǒng)調(diào)用號,在系統(tǒng)調(diào)用表中找到相應(yīng)的函數(shù)進(jìn)行調(diào)用,并將寄存器中保存的參數(shù)取出來,作為函數(shù)參數(shù)。如果仔細(xì)比對,就能發(fā)現(xiàn),這些參數(shù)所對應(yīng)的寄存器,和 Linux 的注釋是一樣的。ia32_sys_call_table系統(tǒng)調(diào)用表生成后面解析(此圖來源于網(wǎng)絡(luò))。

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

相關(guān)內(nèi)核調(diào)用執(zhí)行完后,一直返回到 dosyscall32irqson ,如果系統(tǒng)調(diào)用有返回值,會被保存到 regs->ax 中。接著返回 entryINT8032 繼續(xù)執(zhí)行,最后執(zhí)行 INTERRUPTRETURN 。INTERRUPTRETURN 在 arch/x86/include/asm/irqflags.h 中定義為 iret ,iret 指令將原來用戶態(tài)保存的現(xiàn)場恢復(fù)回來,包含代碼段、指令指針寄存器等。這時候用戶態(tài)進(jìn)程恢復(fù)執(zhí)行。

系統(tǒng)調(diào)用執(zhí)行完畢。

二、32位實(shí)時系統(tǒng)調(diào)用

xenomai+linux雙內(nèi)核架構(gòu)下,通過I-pipe 攔截系統(tǒng)調(diào)用,并將系統(tǒng)調(diào)用定向到實(shí)現(xiàn)它們的系統(tǒng)。

實(shí)時系統(tǒng)調(diào)用,除了直接通過匯編系統(tǒng)調(diào)用外,xenomai還實(shí)現(xiàn)了libcoblat實(shí)時庫,相當(dāng)于glibc,通過libcoblat進(jìn)行xenomai系統(tǒng)調(diào)用,以libcoblat庫函數(shù)sem_open為例,libcolat庫中C函數(shù)實(shí)現(xiàn)如下:

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庫調(diào)用系統(tǒng)調(diào)用使用宏 XENOMAI_SYSCALL5XENOAI_SYSCALL宏在 includeasmxenomaisyscall.h中聲明, XENOMAI_SYSCALL5中的'5'代表'該系統(tǒng)調(diào)用有五個參數(shù):

#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)

每個宏中,內(nèi)嵌另一個宏DOSYSCALL,即實(shí)現(xiàn)系統(tǒng)調(diào)用的int指令:int$0x80

#defineDOSYSCALL"int$0x80
	"

系統(tǒng)調(diào)用過程硬件處理及中斷入口上節(jié)一致,從 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;/*取出系統(tǒng)調(diào)用號*/  int ret;    ret = pipeline_syscall(ti, nr, regs);/*pipeline 攔截系統(tǒng)調(diào)用*/  ......done:  syscall_return_slowpath(regs);}

套路和ipipe接管中斷類似,在關(guān)鍵路徑上攔截系統(tǒng)調(diào)用,然后調(diào)用 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)) {/*運(yùn)行在head域且者系統(tǒng)調(diào)用號超過linux*/    ipipe_fastcall_hook(regs);      /*快速系統(tǒng)調(diào)用路徑*/    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. */}

這個函數(shù)的處理邏輯是這樣,怎樣區(qū)分xenomai系統(tǒng)調(diào)用和linux系統(tǒng)調(diào)用?每個CPU架構(gòu)不同linux系統(tǒng)調(diào)用總數(shù)不同,在x86系統(tǒng)中有300多個,用變量 NR_syscalls表示,系統(tǒng)調(diào)用號與系統(tǒng)調(diào)用一一對應(yīng)。首先獲取到的系統(tǒng)調(diào)用號 nr>=NR_syscalls,不用多想,那這個系統(tǒng)調(diào)用是xenomai內(nèi)核的系統(tǒng)調(diào)用。另外還有個問題,如果是Linux非實(shí)時任務(wù)觸發(fā)的xenomai系統(tǒng)調(diào)用,或者xenomai 實(shí)時任務(wù)要調(diào)用linux的服務(wù),這些交叉服務(wù)涉及實(shí)時任務(wù)與非實(shí)時任務(wù)在兩個內(nèi)核之間運(yùn)行,優(yōu)先級怎么處理等問題。這些涉及 cobalt_sysmodes[].

首先看怎么區(qū)分一個任務(wù)是realtime還是norealtime。在 task_struct結(jié)構(gòu)的頭有一個成員結(jié)構(gòu)體 thread_info,存儲著當(dāng)前線程的信息,ipipe在結(jié)構(gòu)體 thread_info中增加了兩個成員變量 ipipe_flagsipipe_data, ipipe_flags用來來標(biāo)示一個線程是實(shí)時還是非實(shí)時,TIPHEAD置位表示已經(jīng)是實(shí)時上下文。對于需要切換到xenomai上下文的系統(tǒng)調(diào)用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.對于已經(jīng)在實(shí)時上下文的實(shí)時任務(wù)發(fā)起xenomai的系統(tǒng)調(diào)用,使用快速調(diào)用路徑函數(shù) ipipe_fastcall_hook(regs);2.需要切換到實(shí)時上下文或者非實(shí)時調(diào)用實(shí)時的,使用慢速調(diào)用路徑:

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

快速調(diào)用 ipipe_fastcall_hook(regs)內(nèi)直接 handle_head_syscall執(zhí)行代碼如下:

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);
  .......}

這個函數(shù)很復(fù)雜,涉及xenomai與linux之間很多聯(lián)系,代碼是簡化后的,先取出系統(tǒng)調(diào)用號,然后從 cobalt_syscalls取出系統(tǒng)調(diào)用入口handler,然后執(zhí)行 handler(__xn_reg_arglist(regs))執(zhí)行完成后將執(zhí)行結(jié)果放到寄存器 ax,后面的文章會詳細(xì)分析ipipe如何處理系統(tǒng)調(diào)用。

三、 64位系統(tǒng)調(diào)用

我們再來看 64 位的情況,系統(tǒng)調(diào)用,不是用中斷了,而是改用 syscall 指令。并且傳遞參數(shù)的寄存器也變了。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)

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

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

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

wrmsrl(MSR_LSTAR,(unsignedlong)entry_SYSCALL_64);

rdmsr 和 wrmsr 是用來讀寫特殊模塊寄存器的。MSRLSTAR 就是這樣一個特殊的寄存器, 當(dāng) syscall 指令調(diào)用的時候,會從這個寄存器里面拿出函數(shù)地址來調(diào)用,也就是調(diào)entrySYSCALL64。該函數(shù)在'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 結(jié)構(gòu)里面,例如用戶態(tài)的代碼段、數(shù)據(jù)段、保存參數(shù)的寄存器.

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

然后調(diào)用 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;  /*取出系統(tǒng)調(diào)用號*/  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攔截了系統(tǒng)調(diào)用,后面的處理流程類似所以,無論是 32 位,還是 64 位,都會到linux系統(tǒng)調(diào)用表 sys_call_table和xenomai系統(tǒng)調(diào)用表 cobalt_syscalls[]這里來。

四、 實(shí)時系統(tǒng)調(diào)用表cobalt_syscalls

xenomai每個系統(tǒng)的系統(tǒng)系統(tǒng)調(diào)用號在 cobaltuapisyscall.h中:

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

bind()函數(shù)在內(nèi)核代碼中對應(yīng)的聲明和實(shí)現(xiàn)為:


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

其中 __name表示系統(tǒng)調(diào)用名對應(yīng)bind、 __mode表示該系統(tǒng)調(diào)用模式對應(yīng)lostage。 COBALT_SYSCALL展開定義的bind函數(shù)后如下:

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

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

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

實(shí)時系統(tǒng)調(diào)用表 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宏表示數(shù)組空間大小為__NRCOBALTSYSCALLS(128),每一項(xiàng)由COBALTCALL_ENTRIES定義,即腳本頭文件 syscall_entries.h中生成的每一項(xiàng)來填充:

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

__COBALT_CALL32_ENTRY是定義兼容的系統(tǒng)調(diào)用,宏展開如下,相當(dāng)于在數(shù)組的多個位置定義包含了同一項(xiàng)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系統(tǒng)調(diào)用在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*/  .....};

相應(yīng)的數(shù)組cobalt_sysmodes[]中的內(nèi)容如下:

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*/    ......};

五、實(shí)時系統(tǒng)調(diào)用權(quán)限控制cobalt_sysmodes

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

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中所有的系統(tǒng)調(diào)用模式定義如下:

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

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

參考

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

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11432

    瀏覽量

    212446
  • 操作系統(tǒng)
    +關(guān)注

    關(guān)注

    37

    文章

    7033

    瀏覽量

    124784
  • 雙核
    +關(guān)注

    關(guān)注

    0

    文章

    37

    瀏覽量

    15372

原文標(biāo)題:雙核系統(tǒng)調(diào)用(ipipe)

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

收藏 人收藏

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    請問canmv-k230支持嗎?如何調(diào)用另一個核心工作?

    系統(tǒng)使用的是Canmv-K230-micropython-V1.2.2版本. K230是芯片,在使用canmv-k230上沒找到關(guān)于另一個核心的調(diào)用方法。 請問如何
    發(fā)表于 04-23 06:35

    RZT2H CR52BOOT流程和例程代碼分析

    RZT2H是多核處理器,啟動時,需要一個“主”先啟動,然后主根據(jù)規(guī)則,加載和啟動其他內(nèi)核。本文以T2H內(nèi)部的CR52為例,說明T2H多核啟動流程。
    的頭像 發(fā)表于 04-03 17:14 ?2098次閱讀
    RZT2H CR52<b class='flag-5'>雙</b><b class='flag-5'>核</b>BOOT流程和例程代碼分析

    適用于單核、和四應(yīng)用處理器的PMIC DA9063L-A數(shù)據(jù)手冊

    DA9063L-A 是一款功能強(qiáng)大的系統(tǒng)電源管理集成電路(PMIC),適用于單核、和四應(yīng)用處理器,例如那些基于 ARM? Cortex?-A9和 Cortex-A15 架構(gòu)的處理
    的頭像 發(fā)表于 04-01 18:19 ?292次閱讀
    適用于單核、<b class='flag-5'>雙</b><b class='flag-5'>核</b>和四<b class='flag-5'>核</b>應(yīng)用處理器的PMIC DA9063L-A數(shù)據(jù)手冊

    HOLTEK發(fā)布HT32F67595低功耗藍(lán)牙單片機(jī)

    Holtek新推出HT32F67595(Arm Cortex-M33/M0+)低功耗藍(lán)牙單片機(jī),通過藍(lán)牙SIG BT5.3認(rèn)證。
    的頭像 發(fā)表于 03-26 17:11 ?538次閱讀

    STM32H7間如何通信?

    STM32H7間通信的方法,主要是CM7和CM4之間如何進(jìn)行數(shù)據(jù)傳遞
    發(fā)表于 03-12 07:34

    STM32H745的FreeRTOS是單核工作還是工作?

    在STM32CubeMX 中配置的時候,F(xiàn)REERTOS分為_M4和_M7,應(yīng)該是分布對應(yīng)Cortex_M4和Cortex_M7的。 那實(shí)機(jī)運(yùn)行RTOS的時候,運(yùn)行的是單核還是? 這個是根據(jù)
    發(fā)表于 03-07 13:36

    AIGC系統(tǒng)中多個模型的切換調(diào)用方案探索

    作者:京東科技 賈玉龍 1 背景 1.1 現(xiàn)狀 AIGC系統(tǒng)中多個模型的切換調(diào)用通常指的是在同一個AIGC系統(tǒng)或應(yīng)用中,可以根據(jù)不同的輸入條件或任務(wù)需求,動態(tài)地選擇并調(diào)用不同的機(jī)器學(xué)習(xí)
    的頭像 發(fā)表于 11-27 11:43 ?417次閱讀
    AIGC<b class='flag-5'>系統(tǒng)</b>中多個模型的切換<b class='flag-5'>調(diào)用</b>方案探索

    全志T113異構(gòu)處理器的使用基于Tina Linux5.0——異構(gòu)通信驗(yàn)證

    6、通信驗(yàn)證 6.1、C906小創(chuàng)建通訊節(jié)點(diǎn) 在C906小串口終端建立兩個通訊節(jié)點(diǎn)用于監(jiān)聽數(shù)據(jù),輸入eptdev_bind test 2 cpu0 >eptdev_bin
    發(fā)表于 11-20 09:47

    Vivado中FFT IP的使用教程

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

    cpu和單核cpu的區(qū)別

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

    dsp和單核dsp的區(qū)別

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

    TMS320F2837xD微控制器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《TMS320F2837xD微控制器數(shù)據(jù)表.pdf》資料免費(fèi)下載
    發(fā)表于 08-01 12:59 ?7次下載
    TMS320F2837xD<b class='flag-5'>雙</b><b class='flag-5'>核</b>微控制器數(shù)據(jù)表

    OMAP5910處理器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《OMAP5910處理器數(shù)據(jù)表.pdf》資料免費(fèi)下載
    發(fā)表于 08-01 11:48 ?0次下載
    OMAP5910<b class='flag-5'>雙</b><b class='flag-5'>核</b>處理器數(shù)據(jù)表

    FPGA的IP軟使用技巧

    的工作原理、使用方法和限制條件。 參數(shù)化配置 : 如果IP軟提供了參數(shù)化配置選項(xiàng),可以根據(jù)項(xiàng)目需求進(jìn)行配置。例如,對于RAM IP軟,可以選擇單端口RAM、簡單端口RAM或真正
    發(fā)表于 05-27 16:13

    使用STM32CUBEMX生成 H745代碼,利用cubeide debug時發(fā)現(xiàn)M7阻塞進(jìn)入error_handler是為什么?

    使用STM32CUBEMX 生成 H745代碼,利用cubeide debug時發(fā)現(xiàn)M7因?yàn)橐韵麓a阻塞進(jìn)入error_handler, 請問是為什么? /* USER CODE BEGIN
    發(fā)表于 05-20 07:16
    主站蜘蛛池模板: 色女孩网站 | 最新亚洲人成网站在线影院 | 免费抓胸吻胸激烈视频网站 | 久久婷婷国产精品香蕉 | 看全色黄大色大片免费久久 | 日日夜夜天天操 | 天天爽夜夜爽精品视频一 | 好深好爽视频 | 欧美日韩a级a | 欧洲妇女成人淫片aaa视频 | 九九51精品国产免费看 | 五月天婷婷丁香花 | 色综合中文字幕 | 乱说欲小说又粗又长 | 免费看美女禁处爆涌视频 | 久久久久国产精品免费免费不卡 | 丁香色综合| 亚洲成在人 | 久久亚洲国产午夜精品理论片 | 香蕉视频黄色片 | 午夜不卡影院 | 日本一区视频 | 亚洲香蕉毛片久久网站老妇人 | 久久人人做人人玩人精品 | 日本一区免费在线观看 | 亚洲人成影网站~色 | 欧美视频一区在线观看 | 噜噜色网 | 日本h片在线观看 | 精品三级三级三级三级三级 | 色综合综合网 | 大又大粗又爽又黄少妇毛片 | 久久亚洲国产视频 | 操操插插| 桃花岛亚洲精品tv自拍网站 | 天堂在线视频精品 | 天天综合天天色 | 一级日本大片免费观看视频 | 七月婷婷精品视频在线观看 | 免费澳门一级毛片 | sihu免费观看在线高清 |