静态映射和动态映射

xiaoxiao2021-02-28  55

在linux中去操作系统寄存器时必须经过映射,即 1,静态映射IO__ADDRESS();//这只是一个工具,使用前必须先初始化静态映射表 2,动态映射ioremap(); 无论静态映射还是动态映射目的都是将外设地址映射到虚拟地址的空间(3G-4G)中分配给用作外设映射的虚拟地址空间(开启mmu后cpu看到的都是虚拟地址,访问外设时同样需要映射到虚拟地址空间) 一般写寄存器读寄存器时:

#define __REG32_DEV(x) (*((volatile unsigned long *)((x) - REGS_PHYS_BASE + REGS_VIRT_BASE))) chip_id_reg = __REG32_DEV(0X18000000);

我们在使用 (*((volatile unsigned long *) ((addr))这样获取系统寄存器的值时,其中的addr必须是经过映射的虚拟地址,而不能直接使用裸的物理地址,这样我们就要使用IO_ADDRESS来进行映射。 上面的__REG32_DEV(x) 是我们自己定义的,我们来看看内核中原生的读写接口:

readl(addr);wrtel(b,addr); #define readl(addr) (*(volatile unsigned int *)(addr)) #define writel(b,addr) (*(volatile unsigned int *)(addr)) = (b)

再看看他们的使用: readl(IO_ADDRESS(offset));看到其中的addr也是必须要使用IO__ADDRESS()来进行地址映射的。 writel也是一样的道理。 但是再回头看看上面的定义:

#define __REG32_DEV(x) (*((volatile unsigned long *)((x) - REGS_PHYS_BASE + \ REGS_VIRT_BASE)))

好像没有调用IO_ADDRESS()来进行映射,那我们分析下这里(x) - REGS_PHYS_BASE + \ REGS_VIRT_BASE 看下(x) - REGS_PHYS_BASE + REGS_VIRT_BASE是不是和IO_ADDRESS(x)是一样的效果 看下IO_ADDRESS(X)实现: #define IO_ADDRESS(x) (((x) & 0x000fffff) | (((x) >> 4) & 0x0ff00000) | IO_BASE) 好像和(x) - REGS_PHYS_BASE + REGS_VIRT_BASE是不是有点类似? 其实是一样的,(x) - REGS_PHYS_BASE + REGS_VIRT_BASE表示: 裸地址 - 系统IO基地址 + 虚拟地址基地址。 所以我们的 (x) - REGS_PHYS_BASE + REGS_VIRT_BASE和IO_ADDRESS(x)的效果是一样的, 完全可以: #define IO_ADDRESS(x) (x) - REGS_PHYS_BASE + REGS_VIRT_BASE和IO_ADDRESS(x)

总结一下: 总之要在带mmu的系统中操作寄存器值就必须进行地址映射 无论使用radl(addr),还是writrl(b,addr),或者自己实现一个宏: #define __REG32_DEV(addr) (*((volatile unsigned long *)(addr)来进行寄存器的操作 其中的addr都必须经过地址映射到虚拟地址空间 映射的方法有: IO_ADDRESS()使用该宏时,必须先在内核中实现一个映射表才可以使用该宏或者使用自己的宏 ioremap() 或者直接自己实现上述函数:addr = (addr) - REGS_PHYS_BASE + REGS_VIRT_BASE)))

转载请注明原文地址: https://www.6miu.com/read-2630275.html

最新回复(0)