diff options
Diffstat (limited to 'kernel6/源码阅读.md')
| -rw-r--r-- | kernel6/源码阅读.md | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/kernel6/源码阅读.md b/kernel6/源码阅读.md new file mode 100644 index 0000000..4f15a58 --- /dev/null +++ b/kernel6/源码阅读.md @@ -0,0 +1,154 @@ +## 应用层接口 + +```c +unsigned int uintr_received; +unsigned int uvec_fd; + +void __attribute__ ((interrupt)) uintr_handler(struct __uintr_frame *ui_frame, + unsigned long long vector) +{ + static const char print[] = "\t-- User Interrupt handler --\n"; + + write(STDOUT_FILENO, print, sizeof(print) - 1); + uintr_received = 1; +} + +void *sender_thread(void *arg) +{ + int uipi_index; + + uipi_index = uintr_register_sender(uvec_fd, 0); + if (uipi_index < 0) { + printf("Sender register error\n"); + exit(EXIT_FAILURE); + } + + printf("Sending IPI from sender thread\n"); + _senduipi(uipi_index); + + uintr_unregister_sender(uipi_index, 0); + + return NULL; +} + +int main(int argc, char *argv[]) +{ + pthread_t pt; + + if (uintr_register_handler(uintr_handler, 0)) { + printf("Interrupt handler register error\n"); + exit(EXIT_FAILURE); + } + + uvec_fd = uintr_vector_fd(0, 0); + if (uvec_fd < 0) { + printf("Interrupt vector registration error\n"); + exit(EXIT_FAILURE); + } + + _stui(); + printf("Receiver enabled interrupts\n"); + + if (pthread_create(&pt, NULL, &sender_thread, NULL)) { + printf("Error creating sender thread\n"); + exit(EXIT_FAILURE); + } + + /* Do some other work */ + while (!uintr_received) + usleep(1); + + pthread_join(pt, NULL); + close(uvec_fd); + uintr_unregister_handler(0); + + printf("Success\n"); + exit(EXIT_SUCCESS); +} +``` + +系统调用列表 + +| 名称 | 功能 | 描述 | +| ------------------------ | ------------------------------ | ------------------------------------ | +| uintr_register_handler | 用户态中断 接收方 注册中断处理函数 | | +| uintr_unregister_handler | 接收方 注销 中断处理函数 | 注销后硬件将不在记录 中断处理函数地址 | +| uintr_vector_fd | 创建 中断向量 `vector` (封装是 文件描述符FD) | 接收方创建,传递给发送方.进入中断处理函数参数带有该值,以区分不同发送方 | +| uintr_register_sender | 发送方 注册 `sender` 文件描述符 | | +| uintr_unregister_sender | 注销用户态中断的发送方 | | +| uintr_wait | | | +| uintr_register_self() | | | +| uintr_alt_stack | | | +| uintr_ipi_fd | | | + +硬件指令 + +- ` _clui() `- Disable user interrupts - clear UIF (User Interrupt Flag). +- `_stui()` - enable user interrupts - set UIF. +- `_testui()` - test current value of UIF. +- `_uiret()` - return from a user interrupt handler. +- `_senduipi` <uipi_index> - send a user IPI to a target task. The + - uipi_index is obtained using uintr_register_sender(2). + +## 追踪 + +### uintr_register_handler(uintr_handler, 0) + +对应到 uintr.c 的 `SYSCALL_DEFINE2(uintr_register_handler, u64 __user *, handler, unsigned int, flags)` + +经历参数校验到了同文件下的 `do_uintr_register_handler` + +#### do_uintr_register_handler + +首先检查当前进程是否已经注册了中断处理程序,如果已经注册,则返回错误码 `-EBUSY`。 + +分配一个 UPID 上下文结构体 `upid_ctx`,并将其保存在当前进程的 `thread` 结构体中。如果之前已经分配了 `upid_ctx`,则直接使用之前的结构体。 + +upid 等等初始化, + +特别的有了 `upid_ctx->waiting_cost` 等待的代价由哪一方承担. + +返回 + +## uintr_vector_fd(0, 0); + +匿名 inode,关联 uintrfd_ctx ,返回 uintrfd + +## uintr_register_sender(uvec_fd, 0); + +### do_uintr_register_sender + +uitt_ctx 被搬到了 mm_context_t 结构中 而不是原来的 thread_struct + +## wait + +uintr 的 wait 流程似乎完全不同了. + +等待list 还是全局的 `uintr_wait_list` + +```c +static DEFINE_SPINLOCK(uintr_wait_lock); +static struct list_head uintr_wait_list = LIST_HEAD_INIT(uintr_wait_list); +``` + +添加到等待列表的地方只有在 `uintr_switch_to_kernel_interrupt` 上级是 `switch_uintr_prepare` --> `arch/x86/kernel/process_64.c`:: `__switch_to` + +数据结构中多了一个 `upid_ctx->waiting_cost` 需要由谁承担.如果是 接收者承担才会执行 `uintr_switch_to_kernel_interrupt` 添加到等待列表. + +`upid_ctx->waiting_cost` 的判断还有一个调用分支, `switch_uintr_finish` 上级是 `__switch_to`::`switch_uintr_finish(next_p);` + +```c +void switch_uintr_finish(struct task_struct *next) +{ + if (IS_ENABLED(CONFIG_X86_UINTR_BLOCKING) && // 如果开启了阻塞模式 + is_uintr_receiver(next) && // 如果是接收者 + is_uintr_waiting(next)) { // 如果正在等待 + if (is_uintr_waiting_cost_sender(next)) //等待成本由发送者承担 + uintr_clear_blocked_bit(next->thread.upid_ctx); // 清除 UINTR_UPID_STATUS_BLKD + else + uintr_remove_task_wait(next); + } +} +``` + +这里牵扯出了 `UINTR_UPID_STATUS_BLKD` 占用了 `nc.status` 的保留位 7. |
