Help with mmap()

Good day! I'm working with MPC8349 CPU and Linux 2.6.11. I'd like to write a kernel module to map CPU IMMR area to user space to use it in user applications. I've read LLD3 about mmap() and remap_pfn_range(), but I can't understand how can I set a real physical address to these functions?

-- Best regards, Miloserdin Oleg

============================================================ MicroLAB Systems address: 83 Dubninskaya street, #612, 127591 Moscow, Russia phone/fax: +7-(499)-900-6208 e-mail: snipped-for-privacy@mlabsys.com WEB:

formatting link
=============================================

__________ Information from ESET NOD32 Antivirus, version of virus signature database 3941 (20090317) __________

The message was checked by ESET NOD32 Antivirus.

formatting link

Reply to
Miloserdin Oleg
Loading thread data ...

Here you can find an example:

formatting link

-Michael

Reply to
Michael Schnell

You don't need to create a kernel module to do this. Linux already provides the user space mmap() functionality to do this. Here is an userspace example I posted earlier on this group. And it works on the MPC8349 if your bootloader/bios maps the IMMR to 0xE0000000 address area. It is EXTREMELY IMPORTANT to note that which ever registers you are writing to may also be written/read by the kernel device drivers. So make sure you don't load any device driver that undoes what you are trying to do.

Full man can be found at

formatting link

Example: /* * Maps real memory address to a virtual address. The virtual address * then could be used to read/write the real memory as if it was accessed * directly. * Adapted by Janaka Subhawickrama. Copyright 2007. * GPL software. */ #include #include #include #include #include #include #include #include #include #include

//Virtual address that is associated with the physical address static char *regmap_addr = NULL;

//The following is the physical address of memory mapped registers of the CPU #define REGISTRY_MAP_ADDRESS_OFFSET (0xE0000000) #define REGISTRY_MAP_SIZE (0x000FFFFF) #define GPIO2_DATA_DIR_REG_OFFSET (0x00000D00) #define GPIO2_DATA_REG_OFFSET (0x00000D08)

#define GPIO2_DONE_PIN (0x00800000) #define GPIO2_FAULT_PIN (0x00400000) #define GPIO2_PROGB_PIN (0x01000000)

int main(int argc, char *argv[]) { int devmem; // this is the "/dev/mem" descriptor //Registers of the CPU I am using is 32bit volatile unsigned int uiGet; volatile unsigned int *ptmp = NULL;

//On embedded systems you may have to mknod /dev/mem printf("\nOpening /dev/mem"); devmem = open("/dev/mem", O_RDWR | O_SYNC);

if (devmem < 0) { printf("\nOpening of /dev/mem failed with (%d) %s\n", errno, strerror(errno)); return -1; }

printf("\nMapping Memory mapped registers at %08X with size %08X", REGISTRY_MAP_SIZE, REGISTRY_MAP_ADDRESS_OFFSET); regmap_addr = (char *)mmap( 0, REGISTRY_MAP_SIZE, PROT_READ| PROT_WRITE, MAP_SHARED, devmem, REGISTRY_MAP_ADDRESS_OFFSET);

if (regmap_addr == (char *)MAP_FAILED) { printf("\nCould not map registers (%d) %s", errno, strerror(errno)); close(devmem); return -1; }

//Now you can write to CPU registers as if you were from a boot loader

//Setup directions of GPIO pins *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_DIR_REG_OFFSET) = GPIO2_FAULT_PIN | GPIO2_PROGB_PIN; //Turn some GPIO Pins on *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET) = GPIO2_FAULT_PIN | GPIO2_PROGB_PIN; //Get some values of GPIO lines uiGet = *(volatile unsigned int *)(regmap_addr + GPIO2_DATA_REG_OFFSET);

printf("\nGPIO register %08X", uiGet);

//Cleanup munmap((void *)REGISTRY_MAP_ADDRESS_OFFSET, REGISTRY_MAP_SIZE); close(devmem); return 0;

Reply to
Janaka

There is a lot more to this. E.g. Memory that is accessed by some hardware could impose cache issues. Stuff like this should not be handled in user space.

-Michael

Reply to
Michael Schnell

Hmmm. Could you be more specific please. What type of caching issues ? Are you talking about HW cache (in the internal processor system bus) or a SW based cache in a device driver (ie: Device driver think the register state is in sync) ? If there are caching issues, whether its in kernel space or user space you need to handle them.

Reply to
Janaka

Thanks a lot! Everything works fine! But I want to ask you: If is it a correct way to do it (i.e. do all the work from the user space), or it's needed to have a device driver to remap physical memory?

-- Best regards, Miloserd> > You don't need to create a kernel module to do this.

Hmmm. Could you be more specific please. What type of caching issues ? Are you talking about HW cache (in the internal processor system bus) or a SW based cache in a device driver (ie: Device driver think the register state is in sync) ? If there are caching issues, whether its in kernel space or user space you need to handle them.

__________ Information from ESET NOD32 Antivirus, version of virus signature database 3950 (20090320) __________

The message was checked by ESET NOD32 Antivirus.

formatting link

__________ Information from ESET NOD32 Antivirus, version of virus signature database 3950 (20090320) __________

The message was checked by ESET NOD32 Antivirus.

formatting link

Reply to
Miloserdin Oleg

Usually, the hardware cache is between the CPU and the RAM, thus it does not see when the RAM is written by the hardware device and the hardware device does not see data still in the cache.

Of course this can be handle in user space, too, but regarding portability (you _will_ modify your hardware one day), user space software should be as little aware of hardware implementation issues as possible.

-Michael

Reply to
Michael Schnell

For improved portability, user space software should be as little aware of hardware implementation issues as possible.

-Michael

Reply to
Michael Schnell

Hi Michael, The issue that you describe is special case where the "hardware device" has direct access to Ram (eg: DMA engine). However I dont see how that is related to this topic. The issue was about accessing memory area from userspace vs kernel space. Either of these access methods would utilise the CPU. Hence I don't see any HW caching issue (eg: using Userspace doesn't mean you by-pass the CPU; on the contrary!!). Having made that point I do agree that the kernelspace has some nice easy functions to set your caching and MMU settings (eg: passthrough, Write Combining (WC), Write Through (WT), Write Back (WB)). But there is no reason why you cant do this in userspace. So in summary, I would say that If you know what your hardware is doing and how your caching/MMU is setup; there is no reason why you cant use userspace. Cheers Janaka

Reply to
Janaka

e
s
I

Furthermore: One thing I discovered while writing a DMA device driver was that there is a major drawback in using userspace. This is, userspace memory allocations gives us virtual addresses and I could not find any way to get the physical address of these memory blocks in userspace. Most DMA engines only support physical address memory locations. Hence I couldn't write my DMA device controller in Userspace. In kernel space there are functions like "virt_to_phys" to get the physical addresses of allocated memory. So I had to write the DMA device controller as a Linux Device Driver. If you look at the "other side of the coin", userspace gives you nice memory protections where if you go past your allocated memory area then you'll get a segfault and the userspace app will most likely exit. On the flip side you will most likely get a "kernel panic" and require a reboot if this happens in kernel space. But the contradicting factor in using "mmap" in userspace is that you loose this protection (I dont know what will happen if you go past a mmaped region. May be someone can enlighten me on this!!!!). Cheers Janaka

Reply to
Janaka

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.