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

kar*_*kar 1 linux embedded linux-device-driver linux-kernel embedded-linux

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

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

谢谢

wkz*_*wkz 11

是.

  1. 使用获取虚拟地址映射设置到相关寄存器 ioremap
  2. 使用readl/writel操纵物理内存.

请注意ARM处理器在未对齐访问时会出错.Linux处理得很好,但性能下降.

小小的例子:

void __iomem *regs = ioremap(0xdead0000, 4);

pr_info("0xdead0000: %#x\n", readl(regs));

iounmap(regs);
Run Code Online (Sandbox Code Playgroud)

  • 在MMU系统上,按照设计,您无法直接访问物理地址空间.也就是说,许多架构为SoC中的整个IO空间设置了映射,供早期代码使用.该偏移通常在`arch/arm/mach- $ YOUR_ARCH/include/mach/hardware.h`中定义. (3认同)

omo*_*tto 6

在访问内存之前,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);
Run Code Online (Sandbox Code Playgroud)

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

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

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

unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);
Run Code Online (Sandbox Code Playgroud)

这里,addr应该是从ioremap获得的地址,返回值是从给定的I/O内存中读取的值.

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

void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);
Run Code Online (Sandbox Code Playgroud)

举个例子:

void __iomem *io = ioremap(PHYSICAL_ADDRESS, SZ_4K);
iowrite32(value, io);
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)