Messages in this thread Patch in this message | | | From | "Eric D. Seppanen" <> | Subject | ioremap() bugs + patch | Date | Thu, 18 Feb 1999 17:42:46 -0600 (CST) |
| |
Note: this _has_ been reported before, by David Howells and Molnar Ingo, but no fixes have made it into the kernel, and all of the patches I've seen miss one or two of the problems I describe below.
I was writing a driver here the other day and discovered a bug which prevents attempts to ioremap() the top of physical space on i386. I was able to fix it and I am now able to do things like
ioremap(0xFFF00000,0x100000);
which grabs the top 1MB of physical space. (hint: this is where the bios flash chip might live on a system with an Intel chipset). These accesses fail on both 2.2.1 and 2.0.36 currently due to little bugs in __ioremap().
The problem is that __ioremap() does this:
101 if (phys_addr >= 0xA0000 && (phys_addr+size) <= 0x100000) 102 return phys_to_virt(phys_addr);
and this:
120 if (!size || size > phys_addr + size) 121 return NULL;
Problem #1: You can see that first of all, the first test will (incorrectly) think I'm within the range 0xA0000 - 0x100000 because phys_addr+size will wrap to 0. This should be phys_addr - 1 + size.
Problem #2: The second test will fail because phys_addr+size, again, is 0. This should also be phys_addr - 1 + size to work properly.
Problem #3: (need help here) The test on line 120 (checking for a range that will go past the end of memory) should really be first, as the call
ioremap(0xFFF00000, 0x1B0000)
will be seen not as an illegal request, but as a request for the area between 0xA0000 and 0x100000. I'm thinking that this test should move to the beginning of the function. Are there any reasons why this would be a bad idea? (note I've done it in my patch below)
Thanks...
Eric Seppanen / sepp@primenet.com
PS I'd appreciate a CC if anyone replies. PPS this patch fixes it and I've been running with it for a few days now, no problems.
--- linux-2.2.1/arch/i386/mm/ioremap.c Fri Nov 27 17:03:14 1998 +++ linux/arch/i386/mm/ioremap.c Thu Feb 18 17:01:45 1999 @@ -96,9 +96,15 @@ unsigned long offset; /* + * Don't allow mappings that wrap.. + */ + if (!size || size > phys_addr-1+size) + return NULL; + + /* * Don't remap the low PCI/ISA area, it's always mapped.. */ - if (phys_addr >= 0xA0000 && (phys_addr+size) <= 0x100000) + if (phys_addr >= 0xA0000 && (phys_addr-1+size) <= 0x100000) return phys_to_virt(phys_addr); /* @@ -113,12 +119,6 @@ offset = phys_addr & ~PAGE_MASK; phys_addr &= PAGE_MASK; size = PAGE_ALIGN(size + offset); - - /* - * Don't allow mappings that wrap.. - */ - if (!size || size > phys_addr + size) - return NULL; /* * Ok, go for it..
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |