如何从linux内核空间访问物理地址?

时间:2014-03-20 09:48:40

标签: linux linux-kernel embedded linux-device-driver embedded-linux

我正在研究rasberry pi board。是否可以直接访问GPIO物理地址 从Linux内核空间使用inb(),outb()......?如果是的话怎么样?。

GPIO寄存器地址链接 第90页 http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf

谢谢

2 个答案:

答案 0 :(得分:10)

  1. 使用ioremap
  2. 获取相关寄存器的虚拟地址映射设置
  3. 使用readl/writel来操纵物理内存。
  4. 请注意ARM处理器在未对齐访问时会出错。 Linux处理得很好,但性能下降。

    微小的例子:

    void __iomem *regs = ioremap(0xdead0000, 4);
    
    pr_info("0xdead0000: %#x\n", readl(regs));
    
    iounmap(regs);
    

答案 1 :(得分:5)

在访问内存之前,I / O内存的分配不是唯一必需的步骤。您还必须确保内核可以访问此I / O内存。因此必须首先设置映射。这是ioremap功能的作用。

void *ioremap(unsigned long phys_addr, unsigned long size);
void *ioremap_nocache(unsigned long phys_addr, unsigned long size);
void iounmap(void * addr);

该功能专门用于为I / O存储区分配虚拟地址。

获取I / O存储器的正确方法是通过为此目的提供的一组功能(定义为通道)。

要从I / O内存中读取数据,请使用以下方法之一:

unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);

此处, addr 应该是从ioremap获取的地址,返回值是从给定的I / O内存中读取的内容。

写入I / O存储器有一组类似的功能:

void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);

举个例子:

void __iomem *io = ioremap(PHYSICAL_ADDRESS, SZ_4K);
iowrite32(value, io);

另一方面,您可以通过以下方式在用户空间中执行此操作:

static volatile uint32_t *gpio = NULL;
int   fd;

if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) return -1; 
gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);
if ((int32_t)gpio == -1) return -1; 

*(gpio + n) = value;