导航

    全志在线开发者论坛

    • 注册
    • 登录
    • 搜索
    • 版块
    • 话题
    • 在线文档
    • 社区主页
    1. 主页
    2. eechino
    3. 帖子
    • 资料
    • 关注 0
    • 粉丝 0
    • 我的积分 157
    • 主题 1
    • 帖子 1
    • 最佳 1
    • 群组 0

    eechino 发布的帖子

    • T153 msgbox+共享内存进行通讯(U盘代理)

      领导总是爱提一些奇怪的需求。给到的是使用T153跑裸机程序,然后还要能进行U盘的读写,但是全志的HAL_V2库里没有相关的接口,所以我只能退而求其次,使用CPU0 CPU1跑linux 留出CPU2给跑老板的裸机程序,这里使用remoteproc框架让cpu2加载裸机程序,然后通过msgbox+共享内存实现linux U盘代理。
      首先是设置共享内存区:

      	arm_bare_vdev0buffer: vdev0buffer@0x44300000 {
      		compatible = "shared-dma-pool";
      		reg = <0x0 0x44300000 0x0 0x00200000>;
      		no-map;
      	};
      
      	arm_baremetal_rproc: arm_baremetal_rproc@0 {
      		compatible = "allwinner,arm-barematal-rproc";
      		/* core2 chn0 */
      		mboxes = <&msgbox_core0 5>;
      		mbox-names = "arm-kick";
      		memory-region = <&arm_bare_vdev0buffer>,
      				<&arm_baremetal_reserved>;
      		memory-mappings =
      		/* DDR front 1GB */
      		< 0x40000000    0x40000000      0x40000000 >;
      
      		fw-region = <&arm_baremetal_mem_fw>;
      		firmware-name = "amp_arm_bare.bin";
      		boot-amp = <&amp1>;
      		//auto-boot;
      		/* only boot on remote baremetal core without
      			rsc table */
      		//only-boot;
      		share-irq = "arm-baremetal";
      		status = "okay";
      	};
      

      共享内存这里遇到一个小坑,但是没找到真正原因,在逻辑端我使用u8 *p去读取内存有时候读出来全是0,换成u32 *p就不会有这个问题了,怀疑是缓存RMW的问题,但是后面不知道为什么就复现不了,这里建议大家还是使用U32 *p去读写32位内存地址,然后记得缓存的失效与同步。
      然后就是配置msgbox 在设备树中添加节点

      nina_msgbox_test: nina_msg@0 {
      compatible = "eechino,msgbox-file-proxy";
      mboxes = <&msgbox_core0 7>; // 7-4=3 ch3 这里一定要注意了,我踩了坑, 这里写7实际上对于通道3,在裸机端要把通道配置成3.
      mbox-names = "nina-kick";
      status = "okay";
      };
      

      然后添加驱动程序用于U盘的代理读写

      // SPDX-License-Identifier: GPL-2.0-or-later
      #include <linux/debugfs.h>
      #include <linux/err.h>
      #include <linux/fs.h>
      #include <linux/io.h>
      #include <linux/kernel.h>
      #include <linux/mailbox_client.h>
      #include <linux/module.h>
      #include <linux/of.h>
      #include <linux/platform_device.h>
      #include <linux/slab.h>
      #include <linux/uaccess.h>
      #include <linux/file.h>
      #include <linux/workqueue.h>
      
      /* ---------- 共享内存物理地址 ---------- */
      #define SHM_PHYS_BASE   0x44300000UL
      #define SHM_SIZE        0x200000        // 2MB
      #define DATA_OFFSET     0x10000         // DATA_BUF 偏移
      #define MAX_PATH_LEN    255
      #define MAX_HANDLES     16              // 最多同时打开 16 个文件
      
      #define MAGIC           0x45454348UL
      #define CMD_OPEN        1
      #define CMD_READ        2
      #define CMD_WRITE       3
      #define CMD_CLOSE       4
      #define CMD_REPLY       5
      
      typedef struct {
          volatile uint32_t magic;
          volatile uint32_t cmd;
          volatile uint32_t seq;
          volatile uint32_t arg1;
          volatile uint32_t arg2;
          volatile uint32_t ret;
          volatile uint32_t err;
      } file_cmd_t;
      
      /* ---------- 句柄映射表 ---------- */
      static struct file *handle_table[MAX_HANDLES];
      static uint32_t next_handle_id = 1000;  // 从 1000 开始,避免冲突
      
      static uint32_t alloc_handle(struct file *filp)
      {
          uint32_t id = ++next_handle_id;
          handle_table[id % MAX_HANDLES] = filp;
          return id;
      }
      
      static struct file *get_handle(uint32_t id)
      {
          if (id <= 1000) return ERR_PTR(-EBADF);
          return handle_table[id % MAX_HANDLES];
      }
      
      static void free_handle(uint32_t id)
      {
          if (id > 1000)
              handle_table[id % MAX_HANDLES] = NULL;
      }
      
      /* ---------- 驱动结构体 ---------- */
      struct msgbox_file_dev {
          struct device *dev;
          struct mbox_chan *chan;
          struct dentry *dbg_dir;
          struct workqueue_struct *wq;
          struct work_struct work;
          void __iomem *shm_base;
          file_cmd_t *cmd_buf;
          uint8_t *data_buf;
      };
      
      /* ---------- work 函数 ---------- */
      static void file_proxy_work(struct work_struct *work)
      {
          struct msgbox_file_dev *tdev = container_of(work, struct msgbox_file_dev, work);
          file_cmd_t *c = tdev->cmd_buf;
          char full_path[512];
          char filename[MAX_PATH_LEN + 1];
          struct file *filp = NULL;
          loff_t pos;
          ssize_t ret;
          uint32_t handle_id;
          if (!c || c->magic != MAGIC) {
              return;
          }
      
          dev_info(tdev->dev, "cmd=%d seq=%u\n", c->cmd, c->seq);
      
          switch (c->cmd) {
          case CMD_OPEN: {
              uint32_t path_len = c->arg2;
      
              if (path_len == 0 || path_len > MAX_PATH_LEN) {
                  c->ret = -1; c->err = -EINVAL;
                  dev_warn(tdev->dev, "invalid path len: %u\n", path_len);
                  goto reply;
              }
      
              memcpy(filename, tdev->data_buf, path_len);
              filename[path_len] = '\0';
      
              if (strstr(filename, "..") || strchr(filename, '/') || strchr(filename, '\\')) {
                  c->ret = -1; c->err = -EPERM;
                  dev_warn(tdev->dev, "path traversal: %s\n", filename);
                  goto reply;
              }
      
              snprintf(full_path, sizeof(full_path), "/mnt/usb/sda1/%s", filename);
              dev_info(tdev->dev, "打开: %s\n", full_path);
      
              filp = filp_open(full_path, O_RDWR | O_CREAT, 0644);
              if (IS_ERR(filp)) {
                  c->ret = -1;
                  c->err = PTR_ERR(filp);
                  dev_err(tdev->dev, "打开失败: %ld\n", PTR_ERR(filp));
                  goto reply;
              }
      
              handle_id = alloc_handle(filp);
              c->ret = handle_id;
              c->err = 0;
              dev_info(tdev->dev, "打开成功 handle=%u\n", handle_id);
              goto reply;
          }
      
          case CMD_READ: {
              filp = get_handle(c->arg1);
              if (IS_ERR(filp)) {
                  c->err = PTR_ERR(filp);
                  goto reply;
              }
              pos = 0;
              ret = kernel_read(filp, tdev->data_buf, c->arg2, &pos);
              c->ret = (ret < 0) ? 0 : ret;
              c->err = (ret < 0) ? ret : 0;
              goto reply;
          }
      
          case CMD_WRITE: {
              filp = get_handle(c->arg1);
              if (IS_ERR(filp)) {
                  c->err = PTR_ERR(filp);
                  goto reply;
              }
              pos = 0;
              ret = kernel_write(filp, tdev->data_buf, c->arg2, &pos);
              c->ret = (ret < 0) ? 0 : ret;
              c->err = (ret < 0) ? ret : 0;
              goto reply;
          }
      
          case CMD_CLOSE: {
              filp = get_handle(c->arg1);
              if (!IS_ERR(filp)) {
                  filp_close(filp, NULL);
              }
              free_handle(c->arg1);
              c->ret = 0; c->err = 0;
              goto reply;
          }
      
          default:
              goto reply;
          }
      
      reply:
          c->cmd = CMD_REPLY;
      }
      
      /* ---------- 中断回调 ---------- */
      static void file_proxy_handler(struct mbox_client *cl, void *msg)
      {
          struct msgbox_file_dev *tdev = dev_get_drvdata(cl->dev);
          queue_work(tdev->wq, &tdev->work);
      }
      
      /* ---------- probe ---------- */
      static int msgbox_file_probe(struct platform_device *pdev)
      {
          struct msgbox_file_dev *tdev;
          struct mbox_client *cl;
          struct mbox_chan *chan;
          int i;
      
          tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
          if (!tdev) return -ENOMEM;
      
          tdev->shm_base = ioremap(SHM_PHYS_BASE, SHM_SIZE);
          if (!tdev->shm_base) {
              dev_err(&pdev->dev, "ioremap failed\n");
              goto err_free_tdev;
          }
          tdev->cmd_buf  = (file_cmd_t *)tdev->shm_base;
          tdev->data_buf = (uint8_t *)(tdev->shm_base + DATA_OFFSET);
      
          /* 初始化句柄表 */
          for (i = 0; i < MAX_HANDLES; i++) {
              handle_table[i] = NULL;
          }
      
          cl = devm_kzalloc(&pdev->dev, sizeof(*cl), GFP_KERNEL);
          if (!cl) goto err_unmap;
      
          cl->dev = &pdev->dev;
          cl->rx_callback = file_proxy_handler;
          cl->tx_block = false;
          cl->knows_txdone = false;
          cl->tx_tout = 500;
      
          chan = mbox_request_channel_byname(cl, "nina-kick");
          if (IS_ERR(chan)) {
              dev_warn(&pdev->dev, "no nina-kick channel\n");
              goto err_unmap;
          }
          tdev->chan = chan;
      
          tdev->wq = alloc_workqueue("msgbox_file_wq", WQ_HIGHPRI | WQ_UNBOUND, 1);
          if (!tdev->wq) goto err_free_chan;
      
          INIT_WORK(&tdev->work, file_proxy_work);
          tdev->dev = &pdev->dev;
          platform_set_drvdata(pdev, tdev);
      
          dev_info(&pdev->dev, "就绪: shm=0x%lx -> virt=%px\n", SHM_PHYS_BASE, tdev->shm_base);
          return 0;
      
      err_free_chan:
          mbox_free_channel(tdev->chan);
      err_unmap:
          iounmap(tdev->shm_base);
      err_free_tdev:
          kfree(tdev);
          return -ENOMEM;
      }
      
      static int msgbox_file_remove(struct platform_device *pdev)
      {
          struct msgbox_file_dev *tdev = platform_get_drvdata(pdev);
          int i;
      
          if (tdev->wq) {
              destroy_workqueue(tdev->wq);
          }
          if (tdev->chan) mbox_free_channel(tdev->chan);
          if (tdev->shm_base) iounmap(tdev->shm_base);
      
          /* 清理句柄表 */
          for (i = 0; i < MAX_HANDLES; i++) {
              if (handle_table[i]) {
                  filp_close(handle_table[i], NULL);
                  handle_table[i] = NULL;
              }
          }
      
          return 0;
      }
      
      /* ---------- 设备树匹配 ---------- */
      static const struct of_device_id msgbox_file_match[] = {
          { .compatible = "eechino,msgbox-file-proxy" },
          { },
      };
      MODULE_DEVICE_TABLE(of, msgbox_file_match);
      
      static struct platform_driver msgbox_file_driver = {
          .probe  = msgbox_file_probe,
          .remove = msgbox_file_remove,
          .driver = {
              .name           = "msgbox_file_proxy",
              .of_match_table = msgbox_file_match,
          },
      };
      module_platform_driver(msgbox_file_driver);
      
      MODULE_DESCRIPTION("T153 Msgbox U盘代理");
      MODULE_LICENSE("GPL");
      

      裸机端测试程序如下:

      /home/eechino/tina5.0-t153/rtos/lichee/baremetal/drivers/hal_v2/include/hal/hal_msgbox.h
      /* according by dts msgbox_core phandle*/
      #define MSGBOX_READ_CH    3
      #define MSGBOX_WRITE_CH   3
      
      
      // components/FS/msgbox_file.h
      #ifndef __MSGBOX_FILE_H__
      #define __MSGBOX_FILE_H__
      
      #include <stdint.h>
      #include <string.h>
      
      // 共享内存地址(和 Linux 驱动完全一致)
      #define SHM_BASE        0x44300000UL
      #define CMD_BUF         ((volatile struct file_cmd *)SHM_BASE)
      #define DATA_BUF        ((uint8_t *)(SHM_BASE + 0x10000))
      
      #define MAGIC           0x45454348UL    // "EECH"
      
      #define CMD_OPEN        1
      #define CMD_READ        2
      #define CMD_WRITE       3
      #define CMD_CLOSE       4
      #define CMD_REPLY       5
      
      struct file_cmd {
          volatile uint32_t magic;
          volatile uint32_t cmd;
          volatile uint32_t seq;
          volatile uint32_t arg1;
          volatile uint32_t arg2;
          volatile uint32_t ret;
          volatile uint32_t err;
      };
      
      /* API */
      uint32_t file_open(const char* path);
      uint32_t file_read(uint32_t fd, void* buf, uint32_t len);
      void file_write(uint32_t fd, const void* buf, uint32_t len);
      void file_close(uint32_t fd);
      void test_file_proxy(void);
      
      #endif
      
      // components/FS/msgbox_file.c
      #include "msgbox_file.h"
      #include <hal_time.h>
      #include "shell.h"
      #include <stdio.h>
      static const uint32_t kick_magic = 0xEE;  // 或者 0xDEADBEEF
      // 新增:获取官方 edp 的函数
      extern struct msg_endpoint *get_msgbox_edp(void);
      extern int msgbox_baremetal_alloc_msgbox(int argc, char **argv);
      extern int  hal_msgbox_channel_send(struct msg_endpoint *edp, uint8_t *bf,
      							 unsigned int len);
      static uint32_t seq = 0;
      static int inited = 0;
      
      static void msgbox_init(void)
      {
          if (inited) return;
          char *argv[] = { "msgbox_baremetal_alloc_msgbox", NULL };
          msgbox_baremetal_alloc_msgbox(1, argv);
          inited = 1;
      }
      
      static void wait_reply(uint32_t my_seq)
      {
          while (CMD_BUF->seq != my_seq || CMD_BUF->cmd != CMD_REPLY) {
              hal_udelay(500);
          }
      }
      
      uint32_t file_open(const char* path)
      {
          struct msg_endpoint *edp = get_msgbox_edp();
          msgbox_init();
      
          // 1. 把文件名复制到约定好的 DATA_BUF
          strcpy((char*)DATA_BUF, path);
      
          seq++;
          CMD_BUF->magic = MAGIC;
          CMD_BUF->cmd   = CMD_OPEN;
          CMD_BUF->seq   = seq;
          CMD_BUF->arg1  = 0;                    // 不传地址!Linux 知道去 DATA_BUF 读
          CMD_BUF->arg2  = strlen(path) + 1;     // 只传长度!
      
          hal_msgbox_channel_send(edp, (uint8_t *)&kick_magic, 4);
          wait_reply(seq);
          return CMD_BUF->ret;
      }
      
      uint32_t file_read(uint32_t fd, void* buf, uint32_t len)
      {
          struct msg_endpoint *edp = get_msgbox_edp();
          seq++;
          CMD_BUF->cmd   = CMD_READ;
          CMD_BUF->seq   = seq;
          CMD_BUF->arg1  = fd;
          CMD_BUF->arg2  = len;
      
          hal_msgbox_channel_send(edp, (uint8_t *)&kick_magic, sizeof(kick_magic));;
          wait_reply(seq);
      
          if (CMD_BUF->err == 0) {
              memcpy(buf, (void*)DATA_BUF, len);
              return len;
          }
          return 0;
      }
      
      void file_write(uint32_t fd, const void* buf, uint32_t len)
      {
          struct msg_endpoint *edp = get_msgbox_edp();
          memcpy((void*)DATA_BUF, buf, len);
          seq++;
          CMD_BUF->cmd   = CMD_WRITE;
          CMD_BUF->seq   = seq;
          CMD_BUF->arg1  = fd;
          CMD_BUF->arg2  = len;
      
          hal_msgbox_channel_send(edp, (uint8_t *)&kick_magic, sizeof(kick_magic));;
          wait_reply(seq);
      }
      
      void file_close(uint32_t fd)
      {
          struct msg_endpoint *edp = get_msgbox_edp();
          seq++;
          CMD_BUF->cmd   = CMD_CLOSE;
          CMD_BUF->seq   = seq;
          CMD_BUF->arg1  = fd;
      
          hal_msgbox_channel_send(edp, (uint8_t *)&kick_magic, sizeof(kick_magic));;
          wait_reply(seq);
      }
      
      void test_file_proxy(void)
      {
          char wbuf[] = "裸机写U盘成功!2025-11-11 Singapore\n";
          char rbuf[256];
          uint32_t fd, len;
      
          printf("\n=== U盘文件代理测试 (Singapore 09:53 AM) ===\n");
      
          fd = file_open("sg_test.txt");
          if (fd == (uint32_t)-1) {
              printf("打开失败 err=%d\n", CMD_BUF->err);
              return;
          }
          printf("打开成功 fd=%u\n", fd);
      
          file_write(fd, wbuf, sizeof(wbuf)-1);
          printf("写入: %s", wbuf);
      
          file_close(fd);
      
          fd = file_open("sg_test.txt");
          len = file_read(fd, rbuf, 200);
          rbuf[len] = '\0';
          printf("读取: %s\n", rbuf);
      
          file_close(fd);
          printf("=== 测试完成 ===\n");
          printf("Linux 执行: cat /mnt/udisk/sg_test.txt\n\n");
      }
      
      /* shell 命令 */
      SHELL_EXPORT_CMD(
          SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
          test_file_proxy, test_file_proxy, "test msgbox file proxy");
      
      发布在 T Series
      eechino
      eechino
    • 1 / 1