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 = <&1>; //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");
Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号