Still struggling with Shared Kernel/User memory

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I'm working on these drivers and all is working well except the chunks
of memory that we allocate between kernel space and userspace for the
"shared" memory.  

When we load the driver at boot, we allocate, map and reserve the
memory:

typedef struct RtcSoftDev_struct {

    struct semaphore sem;
    u_int  Interrupt;
    u_int  context;
    void                *base;
    unsigned long       iobase;
    unsigned long       iosize;
    char                devname[8];
    int                 dev_num;
    struct pci_dev *    pdev;
    int                 rtc_major;
    u8                  myint;
    unsigned long       irq_cnt;


    spinlock_t mutex;           /* linux mutex equivilent */

    RtcShared *         shared_host_mem;
    RtcShared *         shared_host_mem_area;

} RtcSoftDev;
~

typedef struct rtc_shared {
    unsigned long       snap_addrs_loc;
    time_t              ntimestamp;
} RtcShared;

static int
alloc_rtc_usr_shared(RtcSoftDev *rtc_sp) {
    debug_out(("ALLOC_RTC_USR_SHARED\n"));

    unsigned long addr;
    unsigned long bytes = PAGE_SIZE << get_order(RTC_COMMON_SIZE);
    unsigned long sz;

    debug_out(("BYTES: %#lx, ORDER: %#lx, RTC_COMMON_SIZE: %#lx\n",
        bytes, get_order(RTC_COMMON_SIZE), RTC_COMMON_SIZE));

    rtc_sp->shared_host_mem =
        __get_free_pages(GFP_KERNEL, get_order(RTC_COMMON_SIZE));

    if (rtc_sp->shared_host_mem == NULL) {
        debug_out(("alloc_rtc_usr_shared: out of memory.\n"));
        return(0);
    }

    memset((void *)rtc_sp->shared_host_mem, 0, bytes);

    for (addr = rtc_sp->shared_host_mem, sz = bytes;
        sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
            debug_out(("SetPageReserved: virt: %#lx, addr: %#lx\n",
                virt_to_page(addr), addr));

            SetPageReserved(virt_to_page(addr));
    }

    rtc_sp->shared_host_mem->snap_addrs_loc     = 911;
    rtc_sp->shared_host_mem->ntimestamp         = 119;

    debug_out(("rtc_sp->shared_host_mem = %#lx\n",
        rtc_sp->shared_host_mem));

    debug_out(("rtc_sp->shared_host_mem->snap_addrs_loc = %#lx (%d)\n",
        rtc_sp->shared_host_mem->snap_addrs_loc,
        rtc_sp->shared_host_mem->snap_addrs_loc));

    debug_out(("rtc_sp->shared_host_mem->ntimestamp = %#lx (%d)\n",
        rtc_sp->shared_host_mem->ntimestamp,
        rtc_sp->shared_host_mem->ntimestamp));

    debug_out(("ALLOC_RTC_USR_SHARED\n"));
    return(0);
}

And then when we mmap, we do this:

static int
alloc_rtc_usr_shared(RtcSoftDev *rtc_sp) {
    debug_out(("ALLOC_RTC_USR_SHARED\n"));

    unsigned long addr;
    unsigned long bytes = PAGE_SIZE << get_order(RTC_COMMON_SIZE);
    unsigned long sz;

    debug_out(("BYTES: %#lx, ORDER: %#lx, RTC_COMMON_SIZE: %#lx\n",
        bytes, get_order(RTC_COMMON_SIZE), RTC_COMMON_SIZE));

    rtc_sp->shared_host_mem =
        __get_free_pages(GFP_KERNEL, get_order(RTC_COMMON_SIZE));

    if (rtc_sp->shared_host_mem == NULL) {
        debug_out(("alloc_rtc_usr_shared: out of memory.\n"));
        return(0);
    }

    memset((void *)rtc_sp->shared_host_mem, 0, bytes);

    for (addr = rtc_sp->shared_host_mem, sz = bytes;
        sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
            debug_out(("SetPageReserved: virt: %#lx, addr: %#lx\n",
                virt_to_page(addr), addr));

            SetPageReserved(virt_to_page(addr));
    }

    rtc_sp->shared_host_mem->snap_addrs_loc     = 911;
    rtc_sp->shared_host_mem->ntimestamp         = 119;

    debug_out(("rtc_sp->shared_host_mem = %#lx\n",
        rtc_sp->shared_host_mem));

    debug_out(("rtc_sp->shared_host_mem->snap_addrs_loc = %#lx (%d)\n",
        rtc_sp->shared_host_mem->snap_addrs_loc,
        rtc_sp->shared_host_mem->snap_addrs_loc));

    debug_out(("rtc_sp->shared_host_mem->ntimestamp = %#lx (%d)\n",
        rtc_sp->shared_host_mem->ntimestamp,
        rtc_sp->shared_host_mem->ntimestamp));

    debug_out(("ALLOC_RTC_USR_SHARED\n"));
    return(0);
}

int
rtc_mmap(struct file *filep, struct vm_area_struct *vma) {
    RtcSoftDev *rtc_sp = filep->private_data;

    unsigned long start = vma->vm_start;
    unsigned long size = vma->vm_end - vma->vm_start;
    unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
    unsigned long page = ((rtc_sp->iobase + offset) >> PAGE_SHIFT);

    if (offset > __pa(high_memory) || (filep->f_flags & O_SYNC)) {
        vma->vm_flags |= VM_IO;
    }

    vma->vm_flags |= VM_RESERVED;

    if ((offset == RTC_SNAP_INTERVAL_OFFSET)
        || (offset == RTC_DIGIO_OFFSET)
        || (offset == RTC_STROBE_TIMER_OFFSET)
        || (offset == RTC_CONTROL_REG_OFFSET)
        || (offset == RTC_ENCODER_CNT_OFFSET)
        || (offset == RTC_GRAPHICS_REG_OFFSET)
        || (offset == RTC_CY545_TRANS_OFFSET)
        || (offset == RTC_CY545_CONTROL_OFFSET)
        || (offset == RTC_GRAPHICS_MEM_OFFSET))
    {
        while (size > 0) {
            if (remap_pfn_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
                return(-EAGAIN);
            }

            start += PAGE_SIZE;
            page += PAGE_SIZE;

            if (size > PAGE_SIZE) {
                size -= PAGE_SIZE;
            } else {
                size = 0;
            }
        }
    }

    else if (offset == RTC_COMMON_VADDR) {
        debug_out(("RTC_COMMON_VADDR\n"));

        debug_out(("RTC: vma = %#lx\n", vma));
        debug_out(("RTC: vma->vm_start = %#lx\n", vma->vm_start));
        debug_out(("RTC: vma->vm_end = %#lx\n", vma->vm_end));
        debug_out(("RTC: vma->vm_pgoff = %#lx\n", vma->vm_pgoff));
        debug_out(("RTC: vma->vm_end - vma->vm_start = %#lx\n", size));
        debug_out(("RTC: rtc_sp->iobase = %#lx\n", rtc_sp->iobase));
        debug_out(("RTC: page = %#lx\n", page));
        debug_out(("RTC: offset = %#lx\n", offset));
        debug_out(("RTC: rtc_sp->shared_host_mem = %#lx\n",
rtc_sp->shared_host_mem));

        if (remap_pfn_range(vma,
            start,
                rtc_sp->shared_host_mem,
                    PAGE_SIZE,
                        PAGE_SHARED))
        {
            return(-EAGAIN);
        }
    }

    else {
        debug_out(("RTC_???_OFFSET --- WE'RE BROKEN --- %x\n", offset));
    }

    return(0);
}

When the driver loads I get this in my kernel log file:

[17179664.560000] rtc_probe: RTC 0x000000a2 found @bus 6 dev 3 func 0
[17179664.560000] alloc_rtc_soft_state: return 0 [17179664.560000]
rtc_probe: device 0 [17179664.560000] rtc_probe_module: base start
0xd0000000 size 0x00400000 [17179664.560000] rtc_map_one(0): Successful
map Snap Interval: Phys 0xd0020000 [17179664.560000] rtc_map_one(0):
Successful map Digital I/O: Phys 0xd0040000 [17179664.568000]
rtc_map_one(0): Successful map Strobe Timer: Phys 0xd0060000
[17179664.568000] rtc_map_one(0): Successful map Control Reg: Phys
0xd0080000 [17179664.568000] rtc_map_one(0): Successful map Encoder
Counter: Phys 0xd00a0000 [17179664.584000] rtc_map_one(0): Successful
map Graphics Register: Phys 0xd00c0000 [17179664.584000] rtc_map_one(0):
Successful map CY545 Trans Reg: Phys 0xd00e0000 [17179664.588000]
rtc_map_one(0): Successful map CY545 Control Reg: Phys 0xd00f0000
[17179664.588000] rtc_map_one(0): Successful map Graphics Memory: Phys
0xd0200000 [17179664.588000] ALLOC_RTC_USR_SHARED [17179664.588000]
BYTES: 0x1000, ORDER: 0x0, RTC_COMMON_SIZE: 0x8 [17179664.588000]
rtc_sp->shared_host_mem = 0xd8c37000 [17179664.588000]
rtc_sp->shared_host_mem->snap_addrs_loc = 0x38f (911) [17179664.588000]
rtc_sp->shared_host_mem->ntimestamp = 0x77 (119) [17179664.588000]
ALLOC_RTC_USR_SHARED [17179664.588000] rtc_probe_module: got major 253
[17179664.588000] MVP Real Time Controller Board A: /dev/rtc0, A2.J,
Int: 225 [17179664.588000] driver(0) $Id: mvp_rtc.c,v 1.3 2006/04/18
21:20:36 brian Exp brian $ (c) MVP [17181068.308000] rtc_open: major 253
minor 0 [17181068.308000] find_rtc_soft_state: major 253
[17181068.308000] find_rtc_soft_state: return 0

Which is a good thing (I think).  But then I run my little test program:

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>

#define VADDR                           0x010000
#define SIZE                            0x1000

typedef struct rtc_shared {
    unsigned long       snap_addrs_loc;
    time_t              ntimestamp;
} RtcShared;

RtcShared       *rtc_shared;

static inline void
quick_unmap(int fd, char *pointer, int size) {
    if (pointer != MAP_FAILED) {
        if (munmap(pointer, size) < 0)
            abort();
    }
}

static inline char *
quick_map(int fd, off_t offset, size_t len, const char *name) {
    int prot = (PROT_READ | PROT_WRITE);
    int flags = MAP_SHARED;

    char *addr;
    addr = mmap(0, len, prot, flags, fd, offset);

    if (addr == MAP_FAILED) {
        abort();
    }

    return(addr);
}

int
main(int argc, char *argv[])
{
    int rtc = open("/dev/mvp_rtc", O_RDWR);

    if (!rtc)
        abort();

    rtc_shared = (RtcShared *) quick_map(rtc, VADDR, SIZE, "Common");
    printf("rtc_shared: %#lx\n", rtc_shared);
    printf("rtc_shared->snap_addrs_loc: %#lx\n", *rtc_shared);

#if 0
    rtc_shared->snap_addrs_loc = 0;
#else
    rtc_shared->snap_addrs_loc = 0;
    printf("rtc_shared->snap_addrs_loc: %#lx\n",
rtc_shared->snap_addrs_loc); #endif

    quick_unmap(rtc, (char *) rtc_shared, SIZE);

    close(rtc);
    return(0);
}

And I get:

12_ rtcquicktest
rtc_shared: 0xb7f32000
Segmentation fault
mvp-sw5:~/mvp/work/pcb-linux/misc/dev-drivers/linux/rtc 10:45:39 13_

And this is in my kernel log file:

[17182140.568000] rtc_open: major 253 minor 0 [17182140.568000]
find_rtc_soft_state: major 253 [17182140.568000] find_rtc_soft_state:
return 0 [17182140.568000] rtc opened by rtcquicktest pid 5978 PAGE_SIZE
0x1000 [17182140.568000] RTC_COMMON_VADDR [17182140.568000] RTC: vma =
0xde521184 [17182140.568000] RTC: vma->vm_start = 0xb7f32000
[17182140.568000] RTC: vma->vm_end = 0xb7f33000 [17182140.568000] RTC:
vma->vm_pgoff = 0x10 [17182140.568000] RTC: vma->vm_end - vma->vm_start
= 0x1000 [17182140.568000] RTC: rtc_sp->iobase = 0xd0000000
[17182140.568000] RTC: page = 0xd0010 [17182140.568000] RTC: offset =
0x10000 [17182140.568000] RTC: rtc_sp->shared_host_mem = 0xd8c37000

I'm pretty sure the problem is in my kernel in the remap_pfn_range with
the 'page' variable but I'm not sure what I'm doing wrong ... Anything
you can offer???  Cuz I really don't want to go to jail for homicide
today!!!

???

:b!

Brian D. McGrew { [email protected] || [email protected] }
--
> This is a test.  This is only a test!
  Had this been an actual emergency, you would have been
  told to cancel this test and seek professional assistance!

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux