+
+void *
+contigmalloc(size, type, flags, maxpa, alignmask, boundarymask)
+ unsigned long size;
+ int type;
+ int flags;
+ unsigned long maxpa; /* e.g. 16M - 1 for isa dma */
+ unsigned long alignmask; /* e.g. 1M - 1 for M boundary */
+ unsigned long boundarymask; /* e.g. 64K - 1 for 8-bit isa dma */
+{
+ unsigned long skipsize;
+ void *skipva;
+
+ size = round_page(size);
+ if (size == 0 || size > boundarymask + 1)
+ return (NULL);
+
+ /*
+ * Attempt to push the physical address to a suitable boundary by
+ * skipping some memory. We could be cleverer here. E.g., mallocate
+ * lots of single pages and then free the ones that we hope to use.
+ * flags == M_WAIT is likely to hang the system.
+ */
+ for (skipsize = 0, skipva = NULL; ; skipsize += NBPG) {
+ unsigned long off;
+ unsigned long pa;
+ unsigned long prevpa;
+ void *va;
+
+ if (skipsize != 0) {
+ skipva = malloc(skipsize, type, flags);
+ if (skipva == NULL) {
+#ifdef DEBUG
+ printf("contigmalloc: skipva NULL on try %d\n",
+ 1 + skipsize / NBPG);
+#endif
+ return (NULL);
+ }
+ }
+ va = malloc(size, type, flags);
+ if (skipsize != 0)
+ free(skipva, type);
+ if (va == NULL) {
+#ifdef DEBUG
+ printf("contigmalloc: va NULL on try %d\n",
+ 1 + skipsize / NBPG);
+#endif
+ return (NULL);
+ }
+ for (off = 0, prevpa = 0; off < size; off += NBPG, prevpa = pa)
+ {
+ pa = pmap_extract(pmap_kernel(), (vm_offset_t)va + off);
+ if (pa + NBPG - 1 > maxpa
+ || off == 0 && pa & alignmask
+ || off != 0
+ && (pa != prevpa + NBPG
+ || (pa & boundarymask) == 0))
+ goto fail;
+ }
+#ifdef DEBUG
+ printf("contigmalloc: success at va %lx pa %lx on try %d\n",
+ (unsigned long)va,
+ pmap_extract(pmap_kernel(), (unsigned long)va),
+ 1 + skipsize / NBPG);
+#endif
+ return (va);
+fail:
+ free(va, type);
+ }
+}
+
+