Friday 13 August 2021

How to acess the physical address from linux kernel space?

 

  1. Get a virtual address mapping setup to the registers in question using ioremap
  2. Use readl/writel to manipulate the physical memory.


examples :

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

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

iounmap(regs);
write examples:
 void __iomem *regs;
 regs = ioremap(0xa90260, 4);
 writel(0x4380f, regs);

Allocation of I/O memory is not the only required step before that memory may be accessed. You must also ensure that this I/O memory has been made accessible to the kernel. So a mapping must be set up first. This is the role of the ioremap function.

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

The function is designed specifically to assign virtual addresses to I/O memory regions.

The proper way of getting at I/O memory is via a set of functions (defined via ) provided for that purpose.

To read from I/O memory, use one of the following:

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

Here, addr should be an address obtained from ioremap and the return value is what was read from the given I/O memory.


There is a similar set of functions for writing to I/O memory:

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

As an example:

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


On the other hand, you can do it in user space on this way:

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;

No comments:

Post a Comment