Zynq-Linux移植学习笔记之15-用户APP直接访问PL物理地址

 

Zynq-Linux移植学习笔记之15-用户APP直接访问PL物理地址


参考网址:http://blog.csdn.net/zhaoxinfan/article/details/73351247


1、  背景介绍

在zynq中,由于有PL部分的存在,操作系统需要对PL部分的物理地址进行操作,也就是对操作相关IP核的寄存器。除了在驱动中进行映射外(参看前一篇文章点击打开链接),也可以直接在用户态进行地址映射访问。

 

2、  IO接口头文件

如果做过裸奔的应用程序,可以看到用户app最终调用的接口无非是下面以下这一类函数:

[cpp]  view plain  copy
 print ?
  1. u8 Xil_In8(INTPTR Addr);  
  2. u16 Xil_In16(INTPTR Addr);  
  3. u32 Xil_In32(INTPTR Addr);  
  4. void Xil_Out8(INTPTR Addr, u8 Value);  
  5. void Xil_Out16(INTPTR Addr, u16 Value);  
  6. void Xil_Out32(INTPTR Addr, u32 Value);  
  7. u16 Xil_In16BE(INTPTR Addr);  
  8. u32 Xil_In32BE(INTPTR Addr);  
  9. void Xil_Out16BE(INTPTR Addr, u16 Value);  
  10. void Xil_Out32BE(INTPTR Addr, u32 Value);  


在访问物理地址方面,没有比这一类函数更底层的了。当在Linux下对这一类函数加以实现,用户app便可直接访问PL部分物理地址。实现这一类函数需要进行物理映射,不过由于不是驱动,这种映射可以直接放在应用层实现。

下面是xil_in32()和xil_out32()的具体实现,映射时只需要对/dev/mem映射即可。

[cpp]  view plain  copy
 print ?
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <stdint.h>  
  4. #include <string.h>  
  5. #include <sys/types.h>  
  6. #include <sys/stat.h>  
  7. #include <sys/mman.h>  
  8.   
  9. #include <unistd.h>  
  10. #include <fcntl.h>  
  11.   
  12. #define PAGE_SIZE  ((size_t)getpagesize())  
  13. #define PAGE_MASK ((uint64_t) (long)~(PAGE_SIZE - 1))  
  14.   
  15. void Xil_Out32(uint64_t phyaddr, uint32_t val)  
  16. {  
  17.     int fd;  
  18.     volatile uint8_t *map_base;  
  19.     uint64_t base = phyaddr & PAGE_MASK;  
  20.     uint64_t pgoffset = phyaddr & (~PAGE_MASK);  
  21.   
  22.     if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)  
  23.     {  
  24.         perror("open /dev/mem:");  
  25.     }  
  26.   
  27.     map_base = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,  
  28.             fd, base);  
  29.     if(map_base == MAP_FAILED)  
  30.     {  
  31.         perror("mmap:");  
  32.     }  
  33.     *(volatile uint32_t *)(map_base + pgoffset) = val;   
  34.     close(fd);  
  35.     munmap((void *)map_base, PAGE_SIZE);  
  36. }  
  37.   
  38. int Xil_In32(uint64_t phyaddr)  
  39. {  
  40.     int fd;  
  41.     uint32_t val;  
  42.     volatile uint8_t *map_base;  
  43.     uint64_t base = phyaddr & PAGE_MASK;  
  44.     uint64_t pgoffset = phyaddr & (~PAGE_MASK);  
  45.     //open /dev/mem  
  46.     if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)  
  47.     {  
  48.         perror("open /dev/mem:");  
  49.     }  
  50.     //mmap  
  51.     map_base = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,  
  52.             fd, base);  
  53.     if(map_base == MAP_FAILED)  
  54.     {  
  55.         perror("mmap:");  
  56.     }  
  57.     val = *(volatile uint32_t *)(map_base + pgoffset);  
  58.     close(fd);  
  59.     munmap((void *)map_base, PAGE_SIZE);  
  60.   
  61.     return val;  
  62. }  


 

 

3、  应用层实现

应用层中只需要指定起始物理地址,然后调用xil_in32()和xil_out32()进行操作,为了调用方便,可以封装一层。

 

[cpp]  view plain  copy
 print ?
  1. #ifndef SMARTCARMOVE_H  
  2. #define SMARTCARMOVE_H  
  3.   
  4. #include <stdio.h>  
  5. #include <fcntl.h>  
  6. #include <unistd.h>  
  7. #include <string.h>  
  8. #include <sys/time.h>  
  9. #include <sys/stat.h>  
  10. #include <sys/types.h>  
  11. #include <syslog.h>  
  12. #include <memory.h>  
  13. #include "move.h"  
  14.   
  15. static int fd;  
  16.   
  17. #define MODE (O_WRONLY | O_TRUNC)  
  18.   
  19. /* 
  20.  
  21. static char *gpio_addr[] = { 
  22.     "/sys/class/gpio/export", 
  23.     "/sys/class/gpio/gpio61/direction/","/sys/class/gpio/gpio61/value/", 
  24.     "/sys/class/gpio/gpio62/direction/","/sys/class/gpio/gpio62/value/", 
  25.     "/sys/class/gpio/gpio63/direction/","/sys/class/gpio/gpio63/value/", 
  26.     "/sys/class/gpio/gpio64/direction/","/sys/class/gpio/gpio64/value/" 
  27. }; 
  28.  
  29. */  
  30.   
  31.   
  32. extern void rio_setreg32(unsigned int addrBase,unsigned int addrOffset,unsigned int value);  
  33. extern int rio_getreg32(unsigned int addrBase,unsigned int addrOffset);  
  34. extern int hlMaintWrite(unsigned int dstId,unsigned short hopcount, unsigned int offset, unsigned int writedata);  
  35. extern int hlMaintRead(unsigned int dstId,unsigned short hopcount, unsigned int offset, int mrdataAdr);  
  36.   
  37.   
  38. #endif  

 

[cpp]  view plain  copy
 print ?
  1. #include "xil_io.h"  
  2. #include "move.h"  
  3.   
  4. #define AXI_RIO_BASEADDR 0x40000000  
  5. #define AXI_RIO_NODE_BASEADDR   0x10100  
  6. #define AXI_RIO_MAX_HOPCOUNT    13  
  7.   
  8. /** 
  9. read and write phy mem 
  10.  * */  
  11. void rio_setreg32(unsigned int addrBase,unsigned int addrOffset,unsigned int value)  
  12. {  
  13.     Xil_Out32(addrBase+addrOffset, value);  
  14. }  
  15.   
  16. int rio_getreg32(unsigned int addrBase,unsigned int addrOffset)  
  17. {  
  18.     int ans=0;  
  19.     ans=Xil_In32(addrBase+addrOffset);  
  20.     return ans;  
  21. }  
  22.   
  23. int hlMaintWrite(unsigned int dstId,unsigned short hopcount, unsigned int offset, unsigned int writedata)  
  24. {  
  25.     unsigned int reg_addr;  
  26.     if( hopcount > AXI_RIO_MAX_HOPCOUNT )  
  27.     {  
  28.         printf("!!!error, hopcount = %d,  > %d\n",hopcount,AXI_RIO_MAX_HOPCOUNT);  
  29.         return -1;  
  30.     }  
  31.       
  32.     rio_setreg32(AXI_RIO_BASEADDR,AXI_RIO_NODE_BASEADDR,dstId);   
  33.     reg_addr = (((hopcount+1)<<24)|offset);  
  34.     rio_setreg32(AXI_RIO_BASEADDR,reg_addr,writedata);        
  35.     return 0;    
  36. }  
  37.   
  38. int hlMaintRead(unsigned int dstId,unsigned short hopcount, unsigned int offset, int mrdataAdr)  
  39. {     
  40.     unsigned int reg_addr;  
  41.     if( hopcount > AXI_RIO_MAX_HOPCOUNT )  
  42.     {  
  43.         printf("!!!error, hopcount = %d,  > %d\n",hopcount,AXI_RIO_MAX_HOPCOUNT);  
  44.         return -1;  
  45.     }  
  46.       
  47.     rio_setreg32(AXI_RIO_BASEADDR,AXI_RIO_NODE_BASEADDR,dstId);   
  48.     reg_addr = (((hopcount+1)<<24)|offset);  
  49.     mrdataAdr = rio_getreg32(AXI_RIO_BASEADDR,reg_addr);  
  50.     printf("M_SRIO_MAINT_REG_READ: hopcount = %d, offset = 0x%x, value = 0x%x\n",hopcount,offset,mrdataAdr);  
  51.     return 0;    
  52. }  
  53.   
  54.   
  55. int main(int argc, char *argv[])  
  56. {     
  57.   
  58.     int mtRdata=0;  
  59.   
  60.     printf("get 1848 device id through rio\n");  
  61.       
  62.     hlMaintRead(0xFF,0, 0, mtRdata);  
  63.       
  64.     printf("ok\n");   
  65.   
  66.     return 0;  
  67. }  


运行结果如下,可以看到和在驱动中实现一样


4、  总结

出于安全考虑,在用户态中直接访问物理地址,这种做法在linux中不常见,不过对于zynq来说这种方法要比实现驱动后再通过app调用驱动接口间接明了的多。也可以这样说,是把驱动移植到了用户态中,在用户态下实现地址映射。考虑到这一点,上面给出的例子可以作为用户态中提供给更上一层app的接口,这样就能避免真正的用户直接接触物理地址。



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

a746742897

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值