OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 197|回复: 2

Linux设备文件读写内核代码(求指点)

[复制链接]

30

主题

71

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
254
金钱
254
注册时间
2020-10-19
在线时间
54 小时
发表于 2024-10-28 20:34:20 | 显示全部楼层 |阅读模式
20金钱
求助大佬指点一下,我要做的是基于AMP的linux 服务器与裸核的交互。我现在能够实现的是裸核主动上传数据,然后linux服务器传递到网络上位机。但是它时不时会卡死,SSH无法访问,终端无法键入,ping linux服务器也ping不通。我怀疑是整个系统崩了,但是我还看不到任何的报错信息。个人觉得用户代码不会导致linux系统卡死,除非是内核,所以想请教linux大佬帮忙看看内核驱动是哪里有问题:
  1. /// [url=home.php?mod=space&uid=175224]@file[/url] zynq_amp.c
  2. /// [url=home.php?mod=space&uid=90321]@Author[/url] LucasYuen (LewinAllen123@gmail.com)
  3. /// @brief Zynq AMP 驱动,用于双核通信
  4. /// @version 1.0
  5. /// @date 2024-10-08
  6. ///

  7. #include <linux/module.h>
  8. #include <linux/platform_device.h>
  9. #include <asm/io.h>
  10. #include <linux/irqchip/arm-gic.h>
  11. #include <linux/fs.h>
  12. #include <linux/uaccess.h>
  13. #include <linux/device.h>
  14. #include <linux/spinlock.h>
  15. #include <linux/slab.h>
  16. #include <linux/delay.h>

  17. #define DEVICE_NAME "zynq_amp"        // 设备名称,用户空间交互时使用
  18. #define CLASS_NAME "zynq"             // 设备类名称
  19. #define OCM_PHYS_ADDR 0xffff0000      // OCM共享内存物理地址
  20. #define OCM_PHYS_SIZE 64 * 1024       // OCM共享内存大小
  21. #define DDR_PHYS_ADDR 0x1FA00000      // DDR共享内存物理地址
  22. #define DDR_PHYS_SIZE 4 * 1024 * 1024 // DDR共享内存大小
  23. #define IsPrint 0                     // 调试打印标志

  24. static void __iomem *ocm_phy_addr;            // 共享内存OCM的虚拟地址
  25. static void __iomem *ddr_phy_addr;            // 共享内存DDR的虚拟地址
  26. static int major;                             // 设备号
  27. static char kernel_buffer[OCM_PHYS_SIZE];     // 内核缓冲区,用于存储数据
  28. static struct class *zynq_amp_class = NULL;   // 设备类指针
  29. static struct device *zynq_amp_device = NULL; // 设备指针
  30. static spinlock_t lock;                       // 自旋锁,用于保护共享数据
  31. static uint32_t *g_pu32data;                  // 全局指针
  32. static struct fasync_struct *async_queue;     // fasync 结构体指针

  33. /// @brief Linux核SGI中断处理
  34. static void zynq_irq_handler(void)
  35. {
  36.   printk(KERN_INFO "KERN_INFO[msg]: Receive Interrupt triggered\r\n");
  37.   g_pu32data = (uint32_t *)ddr_phy_addr; // 指向共享内存
  38.   if (async_queue)
  39.   {
  40.     printk(KERN_INFO "KERN_INFO[msg]:Sending async notification\r\n");
  41.     kill_fasync(&async_queue, SIGIO, POLL_IN); // 发送异步通知
  42.   }
  43. }

  44. /// @brief 打开设备
  45. static int zynq_amp_open(struct inode *inode, struct file *file)
  46. {
  47.   return 0; // 设备打开成功
  48. }

  49. /// @brief 关闭/释放设备
  50. static int zynq_amp_release(struct inode *inode, struct file *file)
  51. {
  52.   fasync_helper(-1, file, 0, &async_queue); // 注销fasync
  53.   return 0;                                 // 设备释放成功
  54. }

  55. /// @brief 用户空间→内核→OCM
  56. static ssize_t zynq_amp_write(struct file *file, const char __user *buf, size_t len, loff_t *off)
  57. {
  58.   size_t to_copy;          // 要复制的数据长度
  59.   size_t i;                // 循环索引
  60.   if (len > OCM_PHYS_SIZE) // 如果写入长度大于内核缓冲区,则限制为缓冲区大小
  61.   {
  62.     to_copy = OCM_PHYS_SIZE;
  63.   }
  64.   else
  65.   {
  66.     to_copy = len;
  67.   }
  68.   if (copy_from_user(kernel_buffer, buf, to_copy)) // 从用户空间复制数据到内核缓冲区
  69.   {
  70.     return -EFAULT; // 复制失败,返回错误
  71.   }

  72.   // 打印接收到的用户数据
  73.   printk(KERN_INFO "\nKERN_INFO[Copy from UserApp]:");
  74.   for (i = 0; i < to_copy / sizeof(uint32_t); i++)
  75.   {
  76.     printk(KERN_CONT " %08X", ((uint32_t *)kernel_buffer)[i]); // 逐个打印32位整数
  77.   }
  78.   printk(KERN_CONT "\n");

  79.   // 将数据写入共享内存
  80.   spin_lock(&lock);                             // 加锁,保护共享内存
  81.   memcpy(ocm_phy_addr, kernel_buffer, to_copy); // 复制数据到共享内存
  82.   mb();                                         // 添加内存屏障,确保写入完成
  83.   spin_unlock(&lock);                           // 解锁
  84.   memset(kernel_buffer, 0, OCM_PHYS_SIZE);      // 清空内核缓存
  85.   gic_raise_softirq(cpumask_of(1), 15);         // 发送软中断(中断CPU1)
  86.   return to_copy;                               // 返回实际写入的字节数
  87. }

  88. /// @brief 内核→用户空间
  89. static ssize_t zynq_amp_read(struct file *file, char __user *buf, size_t len, loff_t *off)
  90. {
  91.   size_t to_copy;          // 要复制的数据长度
  92.   if (len > DDR_PHYS_SIZE) // 访问越界则限制为缓冲区大小
  93.   {
  94.     to_copy = DDR_PHYS_SIZE;
  95.   }
  96.   else
  97.   {
  98.     to_copy = len;
  99.   }

  100.   // 确保读取后有短暂延时
  101.   mdelay(100);

  102.   // 加锁,保护共享内存
  103.   spin_lock(&lock);

  104.   if (copy_to_user(buf, g_pu32data, to_copy)) // 拷贝失败
  105.   {
  106.     printk(KERN_ERR "KERN_INFO[error]: Failed to copy data to user space\r\n");
  107.     spin_unlock(&lock); // 解锁
  108.     return -EFAULT;     // 地址无效或不可访问,出错
  109.   }

  110.   // 清空缓冲区并解锁
  111.   memset(g_pu32data, 0, DDR_PHYS_SIZE); // 清空堆
  112.   spin_unlock(&lock);                   // 解锁
  113.   return to_copy;                       // 返回实际读取的字节数
  114. }

  115. /// @brief fasync 函数
  116. static int zynq_amp_fasync(int fd, struct file *file, int mode)
  117. {
  118.   printk(KERN_INFO "zynq_amp_fasync called, mode: %d\n", mode);
  119.   return fasync_helper(fd, file, mode, &async_queue);
  120. }

  121. /// @brief 设备操作函数集合
  122. static struct file_operations fops = {
  123.     .open = zynq_amp_open,       // 打开设备
  124.     .release = zynq_amp_release, // 释放设备
  125.     .write = zynq_amp_write,     // 写入设备
  126.     .read = zynq_amp_read,       // 读取设备
  127.     .fasync = zynq_amp_fasync,   // 注册fasync
  128. };

  129. /// @brief 设备探测函数
  130. static int zynq_amp_probe(struct platform_device *pdev)
  131. {
  132.   // 将共享内存物理地址映射到虚拟地址
  133.   ocm_phy_addr = ioremap(OCM_PHYS_ADDR, OCM_PHYS_SIZE);
  134.   ddr_phy_addr = ioremap(DDR_PHYS_ADDR, DDR_PHYS_SIZE);
  135.   if ((!ocm_phy_addr) || (!ddr_phy_addr))
  136.   {
  137.     printk(KERN_ALERT "Failed to map shared memory\n"); // 映射失败,打印错误信息
  138.     return -ENOMEM;                                     // 返回内存不足错误
  139.   }

  140.   // 注册字符设备
  141.   major = register_chrdev(0, DEVICE_NAME, &fops);
  142.   if (major < 0)
  143.   {
  144.     printk(KERN_ALERT "Registering char device failed with %d\n", major); // 注册失败,打印错误信息
  145.     iounmap(ocm_phy_addr);                                                // 解除映射
  146.     iounmap(ddr_phy_addr);
  147.     return major; // 返回错误代码
  148.   }

  149.   // 创建设备类
  150.   zynq_amp_class = class_create(THIS_MODULE, CLASS_NAME);
  151.   if (IS_ERR(zynq_amp_class))
  152.   {
  153.     unregister_chrdev(major, DEVICE_NAME); // 注销字符设备
  154.     iounmap(ocm_phy_addr);                 // 解除映射
  155.     iounmap(ddr_phy_addr);
  156.     printk(KERN_ALERT "Failed to create device class\n"); // 创建失败,打印错误信息
  157.     return PTR_ERR(zynq_amp_class);                       // 返回错误代码
  158.   }

  159.   // 创建设备
  160.   zynq_amp_device = device_create(zynq_amp_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
  161.   if (IS_ERR(zynq_amp_device))
  162.   {
  163.     class_destroy(zynq_amp_class);         // 销毁设备类
  164.     unregister_chrdev(major, DEVICE_NAME); // 注销字符设备
  165.     iounmap(ocm_phy_addr);                 // 解除映射
  166.     iounmap(ddr_phy_addr);
  167.     printk(KERN_ALERT "Failed to create device\n"); // 创建失败,打印错误信息
  168.     return PTR_ERR(zynq_amp_device);                // 返回错误代码
  169.   }
  170.   printk(KERN_INFO "KERN_INFO[msg]: Driver /dev/%s registered successfully\n", DEVICE_NAME);
  171.   spin_lock_init(&lock);                                    // 初始化自旋锁
  172.   return set_ipi_handler(14, zynq_irq_handler, "Zynq amp"); // 注册软中断处理函数
  173. }

  174. /// @brief 设备删除函数
  175. static int zynq_amp_remove(struct platform_device *pdev)
  176. {
  177.   device_destroy(zynq_amp_class, MKDEV(major, 0)); // 删除设备
  178.   class_destroy(zynq_amp_class);                   // 销毁设备类
  179.   unregister_chrdev(major, DEVICE_NAME);           // 注销字符设备
  180.   iounmap(ocm_phy_addr);                           // 解除映射
  181.   iounmap(ddr_phy_addr);
  182.   return 0; // 返回成功
  183. }

  184. /// @brief 设备匹配表
  185. static const struct of_device_id zynq_amp_of_match[] = {
  186.     {
  187.         .compatible = "xlnx,zynq-amp",
  188.     },
  189.     {/* end of list */},
  190. };
  191. MODULE_DEVICE_TABLE(of, zynq_amp_of_match);

  192. /// @brief 平台驱动结构体
  193. static struct platform_driver zynq_amp_driver = {
  194.     .probe = zynq_amp_probe,   // 设备探测函数
  195.     .remove = zynq_amp_remove, // 设备删除函数
  196.     .driver = {
  197.         .name = DEVICE_NAME,                 // 驱动名称
  198.         .owner = THIS_MODULE,                // 所有者模块
  199.         .of_match_table = zynq_amp_of_match, // 设备匹配表
  200.     },
  201. };

  202. /// @brief 模块初始化函数
  203. static int __init zynq_amp_init(void)
  204. {
  205.   return platform_driver_register(&zynq_amp_driver); // 注册平台驱动
  206. }

  207. /// @brief 模块退出函数
  208. static void __exit zynq_amp_exit(void)
  209. {
  210.   platform_driver_unregister(&zynq_amp_driver); // 注销平台驱动
  211.   printk(KERN_INFO "Zynq AMP Driver exited\n"); // 打印退出信息
  212. }

  213. module_init(zynq_amp_init); // 初始化模块
  214. module_exit(zynq_amp_exit); // 退出模块

  215. MODULE_LICENSE("GPL");                 // 许可证
  216. MODULE_AUTHOR("LucasYuen");            // 作者
  217. MODULE_DESCRIPTION("Zynq AMP Driver"); // 描述
  218. MODULE_VERSION("1.0");                 // 版本信息
复制代码

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2024-10-29 00:55:25 | 显示全部楼层
回复

使用道具 举报

0

主题

32

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
213
金钱
213
注册时间
2024-3-19
在线时间
105 小时
发表于 2024-10-30 09:25:57 | 显示全部楼层
最好是想办法把报错信息弄出来,光看驱动很难看出问题,要有实际调试信息
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 06:21

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表