5.3.3 ipipe_flags之TIP_NOTIFY

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-优快云博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

5.3.3 ipipe_flags之TIP_NOTIFY

TIP_NOTIFY的机制是最复杂的!

(1)Xenomai线程必有TIP_NOTIFY标记

只要是绑定到xenomai core的进程或线程,一定有TIP_NOTIFY标记!除非收到IPIPE_KEVT_CLEANUP,代表任务退出才清除。

引用ipipe.rst中_binding段落中的说明:

The real-time core should inform the kernel about its 
intent to receive notifications about that task, 
by calling :c:func::`ipipe_enable_notifier` when 
such task is current.

include/linux/ipipe.h:
#define ipipe_enable_notifier(p)                    \
    ipipe_set_ti_thread_flag(task_thread_info(p), TIP_NOTIFY)
  • 内核态线程创建,会调用ipipe_enable_notifier设置TIP_NOTIFY
rtdm_task_init // kernel/xenomai/rtdm/drvlib.c
 ->xnthread_init // kernel/xenomai/thread.c
  ->__xnthread_init // kernel/xenomai/thread.c
   ->(如果是内核线程)spawn_kthread // kernel/xenomai/thread.c
    ->kthread_trampoline // kernel/xenomai/thread.c
     ->map_kthread // kernel/xenomai/thread.c
      ->pipeline_enable_kevents //kernel/xenomai/pipeline/kevents.c
       ->ipipe_enable_notifier // include/linux/ipipe.h

 用户态线程创建过程中,也会调用ipipe_enable_notifier设置TIP_NOTIFY

COBALT_SYSCALL(thread_create)
 |->__cobalt_thread_create // kernel/xenomai/posix/thread.c
 | |->pthread_create //kernel/xenomai/posix/thread.c
 |  |->xnthread_init // kernel/xenomai/thread.c
 |   |->__xnthread_init // kernel/xenomai/thread.c
 |->cobalt_map_user // kernel/xenomai/posix/process.c
  |->pipeline_enable_kevents //kernel/xenomai/pipeline/kevents.c
   |->ipipe_enable_notifier // include/linux/ipipe.h
(2)TIP_NOTIFY分3类syscall/trap/kevent

TIP_NOTIFY定义的notifications,在代码中分为三类syscall、trap、kevent,在include/linux/ipipe_domain.h中有如下宏定义。

include/linux/ipipe_domain.h:

#define __IPIPE_SYSCALL_P  0
#define __IPIPE_TRAP_P     1
#define __IPIPE_KEVENT_P   2
#define __IPIPE_SYSCALL_E (1 << __IPIPE_SYSCALL_P)
#define __IPIPE_TRAP_E    (1 << __IPIPE_TRAP_P)
#define __IPIPE_KEVENT_E  (1 << __IPIPE_KEVENT_P)
#define __IPIPE_ALL_E      0x7
#define __IPIPE_SYSCALL_R (8 << __IPIPE_SYSCALL_P)
#define __IPIPE_TRAP_R    (8 << __IPIPE_TRAP_P)
#define __IPIPE_KEVENT_R  (8 << __IPIPE_KEVENT_P)
#define __IPIPE_SHIFT_R    3
#define __IPIPE_ALL_R     (__IPIPE_ALL_E << __IPIPE_SHIFT_R)

/* ipipe_set_hooks(..., enables) */
#define IPIPE_SYSCALL   __IPIPE_SYSCALL_E
#define IPIPE_TRAP  __IPIPE_TRAP_E
#define IPIPE_KEVENT    __IPIPE_KEVENT_E

在这段宏定义中,后缀 P、E 和 R 分别代表不同的含义:

  • P 代表 "Position",即位置。在 __IPIPE_SYSCALL_P、__IPIPE_TRAP_P 和 __IPIPE_KEVENT_P 中,P 表示这些事件在某个优先级或位掩码中的位置。
  • E 代表 "Enable",即启用。在 __IPIPE_SYSCALL_E、__IPIPE_TRAP_E 和 __IPIPE_KEVENT_E 中,E 表示相应事件的启用标志。这些标志是通过将 1 左移相应的位置(由 P 定义)来设置的。
  • R 代表 "Response" 或 "Result",即响应或结果。在 __IPIPE_SYSCALL_R、__IPIPE_TRAP_R 和 __IPIPE_KEVENT_R 中,R 表示相应事件的响应或结果。这些值是通过将 8 左移相应的位置(由 P 定义)来设置的。- 我觉的是response的可能性比较大,估计是表达正在处理中的意思。

上述三类notifications,应用在不同的场景,来看一下ipipe_set_hooks。

xenomai_init // kernel/xenomai/init.c
->cobalt_init // kernel/xenomai/posix/process.c
->pipeline_trap_kevents // kernel/xenomai/pipeline/kevents.c

int pipeline_trap_kevents(void)
{
    init_hostrt();
    ipipe_set_hooks(ipipe_root_domain, IPIPE_SYSCALL|IPIPE_KEVENT);
    ipipe_set_hooks(&xnsched_primary_domain, IPIPE_SYSCALL|IPIPE_TRAP);
    return 0;
}

ipipe_set_hooks 的函数,它用于设置root domain和head domain所对应的 ipipe_percpu_domain_data 结构体中的 coflags 字段,以反映新的钩子启用或禁用状态。为啥不把coflags直接定义在root domain和head domain数据结构中的呢?暂时不清楚。

不过,root domain和head domain的coflags是不同的哦!

对于root domain,设置coflags为IPIPE_SYSCALL|IPIPE_KEVENT,代表当实时进程运行在root domain,则可以调用__ipipe_notify_syscall 、 __ipipe_notify_trap告知xenomai处理此两类信号。

对于head domain,设置coflags为IPIPE_SYSCALL|IPIPE_TRAP,代表当实时进程运行在head domain,则可以调用__ipipe_notify_syscall 、 __ipipe_notify_kevent告知xenomai处理此两类信号。

其中,系统调用syscall是共同的,trap是root domain独有的,kevent是head domain独有的。

(3)TIP_NOTIFY需要hook钩子函数来响应

从上面的分析可知,notification是由IPIPE在不同场景,调用__ipipe_notify_syscall、__ipipe_notify_trap、__ipipe_notify_kevent三个接口发送出去的,那么谁是接收者?

Xenomai是接收者,它需要实现一系列hook函数,来完成notifications的处理。

第一,__ipipe_notify_syscall对应的钩子函数
kernel/xenomai/pipeline/syscall.c:

int ipipe_syscall_hook(struct ipipe_domain *ipd, struct pt_regs *regs)

int ipipe_fastcall_hook(struct pt_regs *regs) 

系统调用syscall对应两个hook。

ipipe_fastcall_hook是系统调用快速处理通路,专门用于处理Xenomai实时线程运行在Head域时触发的Xenomai系统调用!

ipipe_syscall_hook是系统调用慢速处理通路,一般需要先把Xenomai实时线程从root domain切换到head domain之后,再处理系统调用。

ipipe_syscall_hook 这个函数的命名很有意思。

ipipe: 表明这是ipipe所需的函数

syscall:表明这是TIP_NOTIFY中的syscall notification

hook:这是一个预埋的钩子函数,需要co-kernel去实现!

第二,__ipipe_notify_trap对应的钩子函数
kernel/xenomai/pipeline/kevents.c:

int ipipe_trap_hook(struct ipipe_trap_data *data)

什么是TRAP?看起来是IPIPE自己创造的软件层面的概念。

arch/arm64/include/asm/ipipe_base.h:

/* ARM64 traps */
#define IPIPE_TRAP_MAYDAY        0	/* Internal recovery trap */
#define IPIPE_TRAP_ACCESS	 1	/* Data or instruction access exception */
#define IPIPE_TRAP_SECTION	 2	/* Section fault */
#define IPIPE_TRAP_DABT		 3	/* Generic data abort */
#define IPIPE_TRAP_UNKNOWN	 4	/* Unknown exception */
#define IPIPE_TRAP_BREAK	 5	/* Instruction breakpoint */
#define IPIPE_TRAP_FPU_ACC	 6	/* Floating point access */
#define IPIPE_TRAP_FPU_EXC	 7	/* Floating point exception */
#define IPIPE_TRAP_UNDEFINSTR	 8	/* Undefined instruction */
#define IPIPE_TRAP_ALIGNMENT	 9	/* Unaligned access exception */
#define IPIPE_NR_FAULTS         10

宏定义的值(如IPIPE_TRAP_ACCESS、IPIPE_TRAP_SECTION、IPIPE_TRAP_DABT等)是用于标识不同类型的异常或陷阱(trap),这些值与ARM64架构的异常类型有一定的对应关系,但并不完全一致。这些宏定义的值是为了在软件层面上区分和处理不同类型的异常,而不是直接对应于硬件错误码。

例如,IPIPE_TRAP_ACCESS可能对应于ARM64架构中的数据访问异常,而IPIPE_TRAP_DABT可能对应于数据中止异常。这些宏定义的值是为了在软件层面上提供一个统一的接口,以便处理不同类型的异常,而不是直接与硬件错误码对应。

在实际的异常处理程序中,这些宏定义的值会被用来索引到相应的处理代码,以便对不同类型的异常进行处理。因此,虽然这些宏定义的值与ARM64 CPU的硬件错误码不完全一致,但它们在软件层面上是用于处理和区分不同类型的异常的关键。

举一个具体的例子,在entry.S中,同步异常el0_fpsimd_acc跳转到do_fpsimd_acc函数,IPIPE在其中插入了__ipipe_report_trap-> __ipipe_notify_trap调用。

do_fpsimd_acc会检查__ipipe_report_trap的返回值,如果返回1则直接return,代表Xenomai已经处理完毕了,不在需要Linux处理。如果返回0,代表继续向下执行原来Linux的处理逻辑。

紧接着,__ipipe_notify_trap如果发现此时在root domain,直接返回,并不需要xenomai处理trap。如果此时在head domain,则调用ipipe_trap_hook继续处理!

紧接着,调用ipipe_trap_hook,这是由xenomai来实现的,专门处理trap。

ipipe_trap_hook具体的实现就不展开了,发现它的返回值非常有意思:

#define KEVENT_PROPAGATE   0

#define KEVENT_STOP        1

再回到do_fpsimd_acc的逻辑,如果返回1则直接return,代表Xenomai已经处理完毕了,不在需要Linux处理。如果返回0,代表继续向下执行原来Linux的处理逻辑。

第三,__ipipe_notify_kevent对应的钩子函数
kernel/xenomai/pipeline/kevents.c:

int ipipe_kevent_hook(int kevent, void *data)

kevent是指一些纯的内核事件(似乎与硬件无关),可能会影响Xenomai的任务管理,所以需要通知Xenomai进行处理。

以下事件在(include/linux/ipipe_domain.h)中定义:

#define IPIPE_KEVT_SCHEDULE 0
#define IPIPE_KEVT_SIGWAKE  1
#define IPIPE_KEVT_SETSCHED 2 //已被废弃,不应该使用
#define IPIPE_KEVT_SETAFFINITY  3
#define IPIPE_KEVT_EXIT     4
#define IPIPE_KEVT_CLEANUP  5
#define IPIPE_KEVT_HOSTRT   6
#define IPIPE_KEVT_CLOCKFREQ    7
#define IPIPE_KEVT_USERINTRET   8
#define IPIPE_KEVT_PTRESUME 9

以IPIPE_KEVT_EXIT来举一个实际的例子。

-> do_exit // kernel/exit.c
 -> __ipipe_report_exit(tsk); // include/linux/ipipe.h
  ->__ipipe_notify_kevent(IPIPE_KEVT_EXIT, p); //kernel/ipipe/core.c

__ipipe_notify_kevent会调用ipipe_root_only()确保当前运行在root域。

Xenomai实现的ipipe_kevent_hook,通过switch case语句根据不同的kevent,调用不同的函数处理。

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-优快云博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值