之前感觉都是在做应用层的分析,今天来个驱动层面的吧
前两篇都是应用层分析,今天分析驱动层面的,首先加载开机打印项
[ 7.488846] xilinx-vcu-core a0140000.vcu: No reset gpio info from dts for vcu. This may lead to incorrect functionality if VCU isolation is removed post initialization.
[ 7.821372] xilinx-vcu xilinx-vcu: Could not get core_enc clock
[ 7.829821] VCU PLL: enable
[ 7.833245] xilinx-vcu xilinx-vcu: xvcu_probe: Probed successfully
[ 7.833737] allegro: loading out-of-tree module taints kernel.
[ 7.833739] allegro: loading out-of-tree module taints kernel.
[ 7.867802] al5e a0100000.al5e: l2 prefetch size:0 (bits), l2 color bitdepth:10
[ 7.885599] al5d a0120000.al5d: l2 prefetch size:0 (bits), l2 color bitdepth:10
可以看出,首先加载的是vcu_core驱动,然后是vcu_clk驱动,最后是vcu驱动,所以这里直接吧他们顺序读完之后直接看他们都操作了啥寄存器,然后在用户空间读出来,在逆向写入我们的硬件寄存器就好了,这波操作我真的服我自己,哈哈哈。
先来vcu_core的probe代码:
static int xvcu_core_probe(struct platform_device *pdev)
{
struct xvcu_device *xvcu;
struct resource *res;
int ret;
xvcu = devm_kzalloc(&pdev->dev, sizeof(*xvcu), GFP_KERNEL);
if (!xvcu)
return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vcu_slcr");
if (!res) {
dev_err(&pdev->dev, "get vcu_slcr memory resource failed.\n");
return -ENODEV;
}//获取资源
xvcu->vcu_slcr_ba = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));//映射物理地址
if (!xvcu->vcu_slcr_ba) {
dev_err(&pdev->dev, "vcu_slcr register mapping failed.\n");
return -ENOMEM;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "logicore");
if (!res) {
dev_err(&pdev->dev, "get logicore memory resource failed.\n");
return -ENODEV;
}//获取资源
xvcu->logicore_reg_ba = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));//映射
if (!xvcu->logicore_reg_ba) {
dev_err(&pdev->dev, "logicore register mapping failed.\n");
return -ENOMEM;
}
dev_set_drvdata(&pdev->dev, xvcu);//设置数据
xvcu->aclk = devm_clk_get(&pdev->dev, "aclk");
if (IS_ERR(xvcu->aclk)) {
dev_err(&pdev->dev, "Could not get aclk clock\n");
return PTR_ERR(xvcu->aclk);
}
//第一件事,使能时钟
ret = clk_prepare_enable(xvcu->aclk);//使用时钟
if (ret) {
dev_err(&pdev->dev, "aclk clock enable failed\n");
return ret;
}
/*
* Do the Gasket isolation and put the VCU out of reset
* Bit 0 : Gasket isolation
* Bit 1 : put VCU out of reset
*/
xvcu->reset_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(xvcu->reset_gpio)) {
ret = PTR_ERR(xvcu->reset_gpio);
dev_err(&pdev->dev, "failed to get reset gpio for vcu.\n");
return ret;
}
if (xvcu->reset_gpio) {//这里没有走
gpiod_set_value(xvcu->reset_gpio, 0);
/* min 2 clock cycle of vcu pll_ref, slowest freq is 33.33KHz */
usleep_range(60, 120);
gpiod_set_value(xvcu->reset_gpio, 1);
usleep_range(60, 120);
} else {
dev_warn(&pdev->dev, "No reset gpio info from dts for vcu. This may lead to incorrect functionality if VCU isolation is removed post initialization.\n");
}
//第二件事写寄存器
iowrite32(VCU_GASKET_VALUE, xvcu->logicore_reg_ba + VCU_GASKET_INIT);
ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, xvcu_devs,
ARRAY_SIZE(xvcu_devs), NULL, 0, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to add MFD devices %d\n", ret);
goto err_mfd_add_devices;
}
dev_dbg(&pdev->dev, "Successfully added MFD devices\n");
return 0;
err_mfd_add_devices:
/* Add the the Gasket isolation and put the VCU in reset. */
iowrite32(0, xvcu->logicore_reg_ba + VCU_GASKET_INIT);
clk_disable_unprepare(xvcu->aclk);
return ret;
}
其中驱动做的事情已经在注释中写好,所以这里也直接写寄存axi的时钟以及vcu_gate使能
其次vcu probe如下:就是使能各项时钟,自己看吧~
static int xvcu_set_vcu_pll(struct xvcu_priv *xvcu)
{
u32 refclk, coreclk, mcuclk, inte, deci;
int ret;
inte = xvcu_read(xvcu->logicore_reg_ba, VCU_PLL_CLK);
deci = xvcu_read(xvcu->logicore_reg_ba, VCU_PLL_CLK_DEC);
coreclk = xvcu_read(xvcu->logicore_reg_ba, VCU_CORE_CLK) * MHZ;
mcuclk = xvcu_read(xvcu->logicore_reg_ba, VCU_MCU_CLK) * MHZ;
if (!mcuclk || !coreclk) {
dev_err(xvcu->dev, "Invalid mcu and core clock data\n");
return -EINVAL;
}
refclk = (inte * MHZ) + (deci * (MHZ / FRAC));
dev_dbg(xvcu->dev, "Ref clock from logicoreIP is %uHz\n", refclk);
dev_dbg(xvcu->dev, "Core clock from logicoreIP is %uHz\n", coreclk);
dev_dbg(xvcu->dev, "Mcu clock from logicoreIP is %uHz\n", mcuclk);
ret = clk_set_rate(xvcu->pll_ref, refclk);
if (ret)
dev_warn(xvcu->dev, "failed to set logicoreIP refclk rate %d\n"
, ret);
ret = clk_prepare_enable(xvcu->pll_ref);
if (ret) {
dev_err(xvcu->dev, "failed to enable pll_ref clock source %d\n",
ret);
return ret;
}
ret = clk_set_rate(xvcu->mcu_enc, mcuclk);
if (ret)
dev_warn(xvcu->dev, "failed to set logicoreIP mcu clk rate %d\n",
ret);
ret = clk_prepare_enable(xvcu->mcu_enc);
if (ret) {
dev_err(xvcu->dev, "failed to enable mcu_enc %d\n", ret);
goto error_mcu_enc;
}
ret = clk_set_rate(xvcu->mcu_dec, mcuclk);
if (ret)
dev_warn(xvcu->dev, "failed to set logicoreIP mcu clk rate %d\n",
ret);
ret = clk_prepare_enable(xvcu->mcu_dec);
if (ret) {
dev_err(xvcu->dev, "failed to enable mcu_dec %d\n", ret);
goto error_mcu_dec;
}
ret = clk_set_rate(xvcu->core_enc, coreclk);
if (ret)
dev_warn(xvcu->dev, "failed to set logicoreIP core clk rate %d\n",
ret);
ret = clk_prepare_enable(xvcu->core_enc);
if (ret) {
dev_err(xvcu->dev, "failed to enable core_enc %d\n", ret);
goto error_core_enc;
}
ret = clk_set_rate(xvcu->core_dec, coreclk);
if (ret)
dev_warn(xvcu->dev, "failed to set logicoreIP core clk rate %d\n",
ret);
ret = clk_prepare_enable(xvcu->core_dec);
if (ret) {
dev_err(xvcu->dev, "failed to enable core_dec %d\n", ret);
goto error_core_dec;
}
return 0;
error_core_dec:
clk_disable_unprepare(xvcu->core_enc);
error_core_enc:
clk_disable_unprepare(xvcu->mcu_dec);
error_mcu_dec:
clk_disable_unprepare(xvcu->mcu_enc);
error_mcu_enc:
clk_disable_unprepare(xvcu->pll_ref);
return ret;
}
首先把开机用到的寄存器全部读出来,这里给一个用户空间读取的程序,参考的网上的,如下:
int Xil_In32(uint64_t phyaddr)
{
int fd;
uint32_t val;
volatile uint8_t *map_base;
uint64_t base = phyaddr & PAGE_MASK;
uint64_t pgoffset = phyaddr & (~PAGE_MASK);
//open /dev/mem
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
{
perror("open /dev/mem:");
}
//mmap
map_base = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, base);
if(map_base == MAP_FAILED)
{
perror("mmap:");
}
val = *(volatile uint32_t *)(map_base + pgoffset);
close(fd);
munmap((void *)map_base, PAGE_SIZE);
return val;
}
然后编译的话参考我之前在win10下用cmake编译的,效果如下:
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa0140024
Input data 0xa0140024
Addr Val : 0x15000
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa0140028
Input data 0xa0140028
Addr Val : 0x7e4b0c62
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa0140000
Input data 0xa0140000
Addr Val : 0x0
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa0140020
Input data 0xa0140020
Addr Val : 0x0
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa0140030
Input data 0xa0140030
Addr Val : 0x1021
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa0140034
Input data 0xa0140034
Addr Val : 0x1031
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa0140040
Input data 0xa0140040
Addr Val : 0xf000
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa0140060
Input data 0xa0140060
Addr Val : 0x9
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa0140078
Input data 0xa0140078
Addr Val : 0x0
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa014007c
Input data 0xa014007c
Addr Val : 0x0
root@jokerVCU19:/mnt/cmake_gcc# ./Joker_zynqmp_readmen 0xa0140020
Input data 0xa0140020
Addr Val : 0x0
就是读取了所有的硬件寄存器,然后这里最好用nfs挂载,这样主机编译就可以直接nfs用app了,注意挂载时加上-o nolock,这里给出:
mount -t nfs 192.168.1.2:/home/jodon/nfs_root/rootfs /mnt -o nolock
然后逆向写入,代码如下:
static int xvcu_set_vcu_pll(struct xvcu_priv *xvcu)
{
u32 refclk, coreclk, mcuclk, inte, deci;
int ret;
xil_printf("VCU CLK : start read %x\r\n", (u32)(xvcu->logicore_reg_ba));
//sleep(1000);
inte = xvcu_read(xvcu->logicore_reg_ba, VCU_PLL_CLK);
//xil_printf("VCU CLK : pll %d\r\n", inte);
deci = xvcu_read(xvcu->logicore_reg_ba, VCU_PLL_CLK_DEC);
coreclk = xvcu_read(xvcu->logicore_reg_ba, VCU_CORE_CLK) * MHZ;
mcuclk = xvcu_read(xvcu->logicore_reg_ba, VCU_MCU_CLK) * MHZ;
if (!mcuclk || !coreclk) {
xil_printf("VCU CLK : Invalid mcu and core clock data\r\n");
return -1;
}
refclk = (inte * MHZ) + (deci * (MHZ / FRAC));
xil_printf("vcu clk :Ref clock from logicoreIP is %uHz\r\n", refclk);
xil_printf("vcu clk :Core clock from logicoreIP is %uHz\r\n", coreclk);
xil_printf("vcu clk :Mcu clock from logicoreIP is %uHz\r\n", mcuclk);
xvcu_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0x00);
sleep(1);
xvcu_write(xvcu->logicore_reg_ba, VCU_GASKET_INIT, 0x03);
sleep(1);
xil_printf("vcu pll set start\r\n");
//set pll reg
/*read from linux kernel*/
xvcu_write(xvcu->vcu_slcr_ba, VCU_PLL_CTRL, 0x15000);
xvcu_write(xvcu->vcu_slcr_ba, VCU_PLL_CFG, 0x7e4b0c62);
xvcu_write(xvcu->vcu_slcr_ba, VCU_ENC_CORE_CTRL, 0x1021);
xvcu_write(xvcu->vcu_slcr_ba, VCU_ENC_MCU_CTRL, 0x1031);
xvcu_write(xvcu->vcu_slcr_ba, VCU_AXI_CTRL, 0xf000);
xil_printf("vcu pll set ok\r\n");
}
此时vcu的寄存器已经可用,不然没法读取寄存器值
xil_printf("Version : %d\r\n", xvcu_get_version());
待续