Help with mmap()

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
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

We've slightly trimmed the long signature. Click to see the full one.
Re: Help with mmap()
Quoted text here. Click to load it

Here you can find an example:

http://www.nioswiki.com/Accessing_hardware_registers_from_user_space_programs

-Michael

Re: Help with mmap()
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
http://linux.die.net/man/3/mmap

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 <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

//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;


Re: Help with mmap()
Quoted text here. Click to load it

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

Re: Help with mmap()
On Mar 21, 7:13A0%pm, Michael Schnell
Quoted text here. Click to load it

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.

Re: Help with mmap()
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,
Miloserdin Oleg

We've slightly trimmed the long signature. Click to see the full one.
Re: Help with mmap()
For improved portability, user space software should be as little aware
of hardware implementation issues as possible.

-Michael

Re: Help with mmap()
Quoted text here. Click to load it

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

Re: Help with mmap()
On Mar 26, 7:12A0%am, Michael Schnell
Quoted text here. Click to load it

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

Re: Help with mmap()
Quoted text here. Click to load it

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

Site Timeline