中级会员
- 积分
- 254
- 金钱
- 254
- 注册时间
- 2020-10-19
- 在线时间
- 54 小时
|
20金钱
求助大佬指点一下,我要做的是基于AMP的linux 服务器与裸核的交互。我现在能够实现的是裸核主动上传数据,然后linux服务器传递到网络上位机。但是它时不时会卡死,SSH无法访问,终端无法键入,ping linux服务器也ping不通。我怀疑是整个系统崩了,但是我还看不到任何的报错信息。个人觉得用户代码不会导致linux系统卡死,除非是内核,所以想请教linux大佬帮忙看看内核驱动是哪里有问题:- /// [url=home.php?mod=space&uid=175224]@file[/url] zynq_amp.c
- /// [url=home.php?mod=space&uid=90321]@Author[/url] LucasYuen (LewinAllen123@gmail.com)
- /// @brief Zynq AMP 驱动,用于双核通信
- /// @version 1.0
- /// @date 2024-10-08
- ///
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <asm/io.h>
- #include <linux/irqchip/arm-gic.h>
- #include <linux/fs.h>
- #include <linux/uaccess.h>
- #include <linux/device.h>
- #include <linux/spinlock.h>
- #include <linux/slab.h>
- #include <linux/delay.h>
- #define DEVICE_NAME "zynq_amp" // 设备名称,用户空间交互时使用
- #define CLASS_NAME "zynq" // 设备类名称
- #define OCM_PHYS_ADDR 0xffff0000 // OCM共享内存物理地址
- #define OCM_PHYS_SIZE 64 * 1024 // OCM共享内存大小
- #define DDR_PHYS_ADDR 0x1FA00000 // DDR共享内存物理地址
- #define DDR_PHYS_SIZE 4 * 1024 * 1024 // DDR共享内存大小
- #define IsPrint 0 // 调试打印标志
- static void __iomem *ocm_phy_addr; // 共享内存OCM的虚拟地址
- static void __iomem *ddr_phy_addr; // 共享内存DDR的虚拟地址
- static int major; // 设备号
- static char kernel_buffer[OCM_PHYS_SIZE]; // 内核缓冲区,用于存储数据
- static struct class *zynq_amp_class = NULL; // 设备类指针
- static struct device *zynq_amp_device = NULL; // 设备指针
- static spinlock_t lock; // 自旋锁,用于保护共享数据
- static uint32_t *g_pu32data; // 全局指针
- static struct fasync_struct *async_queue; // fasync 结构体指针
- /// @brief Linux核SGI中断处理
- static void zynq_irq_handler(void)
- {
- printk(KERN_INFO "KERN_INFO[msg]: Receive Interrupt triggered\r\n");
- g_pu32data = (uint32_t *)ddr_phy_addr; // 指向共享内存
- if (async_queue)
- {
- printk(KERN_INFO "KERN_INFO[msg]:Sending async notification\r\n");
- kill_fasync(&async_queue, SIGIO, POLL_IN); // 发送异步通知
- }
- }
- /// @brief 打开设备
- static int zynq_amp_open(struct inode *inode, struct file *file)
- {
- return 0; // 设备打开成功
- }
- /// @brief 关闭/释放设备
- static int zynq_amp_release(struct inode *inode, struct file *file)
- {
- fasync_helper(-1, file, 0, &async_queue); // 注销fasync
- return 0; // 设备释放成功
- }
- /// @brief 用户空间→内核→OCM
- static ssize_t zynq_amp_write(struct file *file, const char __user *buf, size_t len, loff_t *off)
- {
- size_t to_copy; // 要复制的数据长度
- size_t i; // 循环索引
- if (len > OCM_PHYS_SIZE) // 如果写入长度大于内核缓冲区,则限制为缓冲区大小
- {
- to_copy = OCM_PHYS_SIZE;
- }
- else
- {
- to_copy = len;
- }
- if (copy_from_user(kernel_buffer, buf, to_copy)) // 从用户空间复制数据到内核缓冲区
- {
- return -EFAULT; // 复制失败,返回错误
- }
- // 打印接收到的用户数据
- printk(KERN_INFO "\nKERN_INFO[Copy from UserApp]:");
- for (i = 0; i < to_copy / sizeof(uint32_t); i++)
- {
- printk(KERN_CONT " %08X", ((uint32_t *)kernel_buffer)[i]); // 逐个打印32位整数
- }
- printk(KERN_CONT "\n");
- // 将数据写入共享内存
- spin_lock(&lock); // 加锁,保护共享内存
- memcpy(ocm_phy_addr, kernel_buffer, to_copy); // 复制数据到共享内存
- mb(); // 添加内存屏障,确保写入完成
- spin_unlock(&lock); // 解锁
- memset(kernel_buffer, 0, OCM_PHYS_SIZE); // 清空内核缓存
- gic_raise_softirq(cpumask_of(1), 15); // 发送软中断(中断CPU1)
- return to_copy; // 返回实际写入的字节数
- }
- /// @brief 内核→用户空间
- static ssize_t zynq_amp_read(struct file *file, char __user *buf, size_t len, loff_t *off)
- {
- size_t to_copy; // 要复制的数据长度
- if (len > DDR_PHYS_SIZE) // 访问越界则限制为缓冲区大小
- {
- to_copy = DDR_PHYS_SIZE;
- }
- else
- {
- to_copy = len;
- }
- // 确保读取后有短暂延时
- mdelay(100);
- // 加锁,保护共享内存
- spin_lock(&lock);
- if (copy_to_user(buf, g_pu32data, to_copy)) // 拷贝失败
- {
- printk(KERN_ERR "KERN_INFO[error]: Failed to copy data to user space\r\n");
- spin_unlock(&lock); // 解锁
- return -EFAULT; // 地址无效或不可访问,出错
- }
- // 清空缓冲区并解锁
- memset(g_pu32data, 0, DDR_PHYS_SIZE); // 清空堆
- spin_unlock(&lock); // 解锁
- return to_copy; // 返回实际读取的字节数
- }
- /// @brief fasync 函数
- static int zynq_amp_fasync(int fd, struct file *file, int mode)
- {
- printk(KERN_INFO "zynq_amp_fasync called, mode: %d\n", mode);
- return fasync_helper(fd, file, mode, &async_queue);
- }
- /// @brief 设备操作函数集合
- static struct file_operations fops = {
- .open = zynq_amp_open, // 打开设备
- .release = zynq_amp_release, // 释放设备
- .write = zynq_amp_write, // 写入设备
- .read = zynq_amp_read, // 读取设备
- .fasync = zynq_amp_fasync, // 注册fasync
- };
- /// @brief 设备探测函数
- static int zynq_amp_probe(struct platform_device *pdev)
- {
- // 将共享内存物理地址映射到虚拟地址
- ocm_phy_addr = ioremap(OCM_PHYS_ADDR, OCM_PHYS_SIZE);
- ddr_phy_addr = ioremap(DDR_PHYS_ADDR, DDR_PHYS_SIZE);
- if ((!ocm_phy_addr) || (!ddr_phy_addr))
- {
- printk(KERN_ALERT "Failed to map shared memory\n"); // 映射失败,打印错误信息
- return -ENOMEM; // 返回内存不足错误
- }
- // 注册字符设备
- major = register_chrdev(0, DEVICE_NAME, &fops);
- if (major < 0)
- {
- printk(KERN_ALERT "Registering char device failed with %d\n", major); // 注册失败,打印错误信息
- iounmap(ocm_phy_addr); // 解除映射
- iounmap(ddr_phy_addr);
- return major; // 返回错误代码
- }
- // 创建设备类
- zynq_amp_class = class_create(THIS_MODULE, CLASS_NAME);
- if (IS_ERR(zynq_amp_class))
- {
- unregister_chrdev(major, DEVICE_NAME); // 注销字符设备
- iounmap(ocm_phy_addr); // 解除映射
- iounmap(ddr_phy_addr);
- printk(KERN_ALERT "Failed to create device class\n"); // 创建失败,打印错误信息
- return PTR_ERR(zynq_amp_class); // 返回错误代码
- }
- // 创建设备
- zynq_amp_device = device_create(zynq_amp_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
- if (IS_ERR(zynq_amp_device))
- {
- class_destroy(zynq_amp_class); // 销毁设备类
- unregister_chrdev(major, DEVICE_NAME); // 注销字符设备
- iounmap(ocm_phy_addr); // 解除映射
- iounmap(ddr_phy_addr);
- printk(KERN_ALERT "Failed to create device\n"); // 创建失败,打印错误信息
- return PTR_ERR(zynq_amp_device); // 返回错误代码
- }
- printk(KERN_INFO "KERN_INFO[msg]: Driver /dev/%s registered successfully\n", DEVICE_NAME);
- spin_lock_init(&lock); // 初始化自旋锁
- return set_ipi_handler(14, zynq_irq_handler, "Zynq amp"); // 注册软中断处理函数
- }
- /// @brief 设备删除函数
- static int zynq_amp_remove(struct platform_device *pdev)
- {
- device_destroy(zynq_amp_class, MKDEV(major, 0)); // 删除设备
- class_destroy(zynq_amp_class); // 销毁设备类
- unregister_chrdev(major, DEVICE_NAME); // 注销字符设备
- iounmap(ocm_phy_addr); // 解除映射
- iounmap(ddr_phy_addr);
- return 0; // 返回成功
- }
- /// @brief 设备匹配表
- static const struct of_device_id zynq_amp_of_match[] = {
- {
- .compatible = "xlnx,zynq-amp",
- },
- {/* end of list */},
- };
- MODULE_DEVICE_TABLE(of, zynq_amp_of_match);
- /// @brief 平台驱动结构体
- static struct platform_driver zynq_amp_driver = {
- .probe = zynq_amp_probe, // 设备探测函数
- .remove = zynq_amp_remove, // 设备删除函数
- .driver = {
- .name = DEVICE_NAME, // 驱动名称
- .owner = THIS_MODULE, // 所有者模块
- .of_match_table = zynq_amp_of_match, // 设备匹配表
- },
- };
- /// @brief 模块初始化函数
- static int __init zynq_amp_init(void)
- {
- return platform_driver_register(&zynq_amp_driver); // 注册平台驱动
- }
- /// @brief 模块退出函数
- static void __exit zynq_amp_exit(void)
- {
- platform_driver_unregister(&zynq_amp_driver); // 注销平台驱动
- printk(KERN_INFO "Zynq AMP Driver exited\n"); // 打印退出信息
- }
- module_init(zynq_amp_init); // 初始化模块
- module_exit(zynq_amp_exit); // 退出模块
- MODULE_LICENSE("GPL"); // 许可证
- MODULE_AUTHOR("LucasYuen"); // 作者
- MODULE_DESCRIPTION("Zynq AMP Driver"); // 描述
- MODULE_VERSION("1.0"); // 版本信息
复制代码
|
|