如何从内核模块向用户态应用共享64位整数?
内核模块向用户态共享64位整数的实现方案
问题背景
在中断处理流程中,需要将读取到的64位寄存器值传递给用户态进程,尝试使用信号时遇到用户态无法直接访问内核内存的问题。
解决方案:利用实时信号传递拆分后的64位值
实时信号(SIGRTMIN至SIGRTMAX)支持通过siginfo_t结构体携带额外数据,可将64位值拆分为两个32位部分,分别存入该结构体的可访问字段,避免内核内存直接暴露给用户态。
内核端实现代码
#include <linux/signal.h> #include <linux/sched.h> #include <linux/uaccess.h> // 假设在中断处理或内核函数中调用此逻辑 int send_64bit_to_user(struct task_struct *task, uint64_t value_to_send) { struct siginfo info; memset(&info, 0, sizeof(info)); // 初始化结构体,避免未定义行为 info.si_signo = SIGRTMIN; // 使用实时信号 info.si_code = SI_QUEUE; // 标记为队列式信号发送 info.si_pid = current->pid; // 发送进程PID info.si_uid = current_uid().val; // 发送进程UID // 拆分64位值为两个32位部分 info.si_lower = (uint32_t)(value_to_send & 0xFFFFFFFF); // 低32位 info.si_upper = (uint32_t)(value_to_send >> 32); // 高32位 // 发送信号到目标用户态进程 int ret = send_sig_info(SIGRTMIN, &info, task); if (ret < 0) { printk(KERN_ALERT "send_sig_info failed: %d\n", -ret); return ret; } return 0; }
用户态接收代码
用户态需通过sigaction注册带siginfo_t支持的信号处理函数,拼接回64位值:
#include <stdio.h> #include <signal.h> #include <stdint.h> #include <unistd.h> void rt_sig_handler(int signo, siginfo_t *info, void *unused) { if (signo != SIGRTMIN) return; // 拼接32位字段为64位值 uint64_t received_value = ((uint64_t)info->si_upper << 32) | info->si_lower; printf("Received 64-bit value from kernel: 0x%lx\n", received_value); } int main() { struct sigaction sa; sa.sa_sigaction = rt_sig_handler; sa.sa_flags = SA_SIGINFO; // 启用siginfo_t传递 sigemptyset(&sa.sa_mask); if (sigaction(SIGRTMIN, &sa, NULL) == -1) { perror("Failed to set signal handler"); return 1; } printf("Waiting for kernel signal...\n"); while (1) { pause(); // 阻塞等待信号 } return 0; }
关键注意事项
- 实时信号特性:实时信号支持排队,不会像普通信号那样丢失,适合中断这类可能频繁触发的场景。
- 进程指针获取:确保目标进程的
task_struct指针正确,可通过PID查找:struct task_struct *task = pid_task(find_vpid(target_pid), PIDTYPE_PID); - 信号队列限制:内核实时信号队列长度有限(可通过
/proc/sys/kernel/rtsig-max调整),高频中断场景下需注意避免信号溢出。 - 字节序兼容:同一架构下内核与用户态字节序一致,无需额外处理跨字节序问题。
内容的提问来源于stack exchange,提问作者Prashant Raiger
相关产品推荐
相关产品推荐

