领导总是爱提一些奇怪的需求。给到的是使用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");