Subject: kern/6669: pcic_chip_mem_alloc() can't handle large requests
To: None <gnats-bugs@gnats.netbsd.org>
From: None <eramer@era-t.ericsson.se>
List: netbsd-bugs
Date: 12/28/1998 17:34:09
>Number:         6669
>Category:       kern
>Synopsis:       pcic_chip_mem_alloc() can't handle large requests
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Dec 28 08:35:01 1998
>Last-Modified:
>Originator:     Michael Eriksson
>Organization:
Michael Eriksson <eramer@era-t.ericsson.se>
>Release:        981130
>Environment:
System: NetBSD burken 1.3I NetBSD 1.3I (HEMPC) #0: Fri Dec 4 22:36:15 CET 1998 eramer@burken:/usr/src/sys-981130/arch/i386/compile/HEMPC i386


>Description:

The pcic_chip_mem_alloc() function has some problems:

1. It hangs (for as long as it takes to count to ~2^31) if the
   requested size is larger than (PCIC_MEM_PAGES + 1) pages, since the
   loop condition is bogus.
2. Even if the loop condition was correct, it's still can't handle
   larger I/O ranges than PCIC_MEM_PAGES (PCIC_MEM_PAGES is only the
   default, and it's possible to request larger iosize in the kernel
   config file).
3. The "region found" check of the loop variable is bogus (the loop
   variable is compared to a bogus expresion).

>How-To-Repeat:

Try to use a PCMCIA card which needs 32 k of memory space.

>Fix:

--- dev/ic/i82365.c.orig	Sat Nov 28 13:13:17 1998
+++ dev/ic/i82365.c	Fri Dec 25 13:59:25 1998
@@ -700,13 +700,15 @@
 
 	/* convert size to PCIC pages */
 	sizepg = (size + (PCIC_MEM_ALIGN - 1)) / PCIC_MEM_ALIGN;
+	if (sizepg > PCIC_MAX_MEM_PAGES)
+		return (1);
 
 	mask = (1 << sizepg) - 1;
 
 	addr = 0;		/* XXX gcc -Wuninitialized */
 	mhandle = 0;		/* XXX gcc -Wuninitialized */
 
-	for (i = 0; i < (PCIC_MEM_PAGES + 1 - sizepg); i++) {
+	for (i = 0; i <= PCIC_MAX_MEM_PAGES - sizepg; i++) {
 		if ((h->sc->subregionmask & (mask << i)) == (mask << i)) {
 			if (bus_space_subregion(h->sc->memt, h->sc->memh,
 			    i * PCIC_MEM_PAGESIZE,
@@ -715,24 +717,17 @@
 			mhandle = mask << i;
 			addr = h->sc->membase + (i * PCIC_MEM_PAGESIZE);
 			h->sc->subregionmask &= ~(mhandle);
-			break;
+			pcmhp->memt = h->sc->memt;
+			pcmhp->memh = memh;
+			pcmhp->addr = addr;
+			pcmhp->size = size;
+			pcmhp->mhandle = mhandle;
+			pcmhp->realsize = sizepg * PCIC_MEM_PAGESIZE;
+			return (0);
 		}
 	}
 
-	if (i == (PCIC_MEM_PAGES + 1 - size))
-		return (1);
-
-	DPRINTF(("pcic_chip_mem_alloc bus addr 0x%lx+0x%lx\n", (u_long) addr,
-		 (u_long) size));
-
-	pcmhp->memt = h->sc->memt;
-	pcmhp->memh = memh;
-	pcmhp->addr = addr;
-	pcmhp->size = size;
-	pcmhp->mhandle = mhandle;
-	pcmhp->realsize = sizepg * PCIC_MEM_PAGESIZE;
-
-	return (0);
+	return (1);
 }
 
 void 
--- dev/ic/i82365var.h.orig	Tue Nov 17 13:14:33 1998
+++ dev/ic/i82365var.h	Wed Dec 23 13:46:52 1998
@@ -106,6 +106,7 @@
 
 	/* this needs to be large enough to hold PCIC_MEM_PAGES bits */
 	int	subregionmask;
+#define PCIC_MAX_MEM_PAGES	(8 * sizeof(int))
 
 	/* used by memory window mapping functions */
 	bus_addr_t membase;
>Audit-Trail:
>Unformatted: