[Top] [All Lists]

CVS linux

Subject: CVS linux
Date: Wed, 25 Feb 2004 22:09:23 +0000
CVSROOT:        /home/cvs
Module name:    linux
Changes by: 04/02/25 22:09:23

Modified files:
        arch/mips/mm   : Tag: linux_2_4 ioremap.c 

Log message:
        Fix for off by one bug from OSDL's buzilla:
        Summary: __ioremap does not map entirely the size specified (if
        size = 1 + multiple of PAGE_SIZE)
        Kernel Version: 2.6.x , 2.4.x
        Status: NEW
        Severity: normal
        Distribution: redHat , snapgear
        Hardware Environment:
        Software Environment: linux2.6.x linux2.4.x linux2.2.x
        Problem Description:__ioremap does remap properly if the size specified 
is a
        (mulptiple of PAGE_SIZE) + 1 and if the physical address passed happens 
to be
        already page aligned. In this particular case, the last byte is not 
covered and
        an access to it will create a Segmentation Fault.
        Steps to reproduce: ioremap  a piece of PCI memory of size PAGE_SIZE + 
1 and
        write to the last byte : Segmentation Fault occurs.
        I checked in several architectures (ARM, x86 ) and different kernel 
        2.4.x, 2.6.x, the __ioremap implementations are similar and contain the 
        The bug is quite simple to fix :
        For example, in snpagear distribution for ARM architecture
        void * __ioremap(unsigned long phys_addr, size_t size, unsigned long 
        void * addr;
        struct vm_struct * area;
        unsigned long offset, last_addr;
        /* Don't allow wraparound or zero size */
        last_addr = phys_addr + size - 1;   <----- last address is inside
        if (!size || last_addr < phys_addr)
        return NULL;
        * Mappings have to be page-aligned
        offset = phys_addr & ~PAGE_MASK;
        phys_addr &= PAGE_MASK;
        //size = PAGE_ALIGN(last_addr ) - phys_addr;
        size = PAGE_ALIGN(last_addr + 1) - phys_addr;  <--- THE FIX
        * Ok, go for it..
        area = get_vm_area(size, VM_IOREMAP);
        if (!area)
        return NULL;
        addr = area->addr;
        if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr >> PAGE_SHIFT, 
size, flags)) {
        return NULL;
        return (void *) (offset + (char *)addr);

<Prev in Thread] Current Thread [Next in Thread>