Index: sys/x86/iommu/busdma_dmar.c =================================================================== --- sys/x86/iommu/busdma_dmar.c +++ sys/x86/iommu/busdma_dmar.c @@ -665,8 +665,8 @@ { struct bus_dma_tag_dmar *tag; struct bus_dmamap_dmar *map; - vm_page_t *ma; - vm_paddr_t pstart, pend; + vm_page_t *ma, fma; + vm_paddr_t pstart, pend, paddr; int error, i, ma_cnt, offset; tag = (struct bus_dma_tag_dmar *)dmat; @@ -679,10 +679,36 @@ M_WAITOK : M_NOWAIT); if (ma == NULL) return (ENOMEM); - for (i = 0; i < ma_cnt; i++) - ma[i] = PHYS_TO_VM_PAGE(pstart + i * PAGE_SIZE); + for (i = 0; i < ma_cnt; i++) { + paddr = pstart + i * PAGE_SIZE; + ma[i] = PHYS_TO_VM_PAGE(paddr); + if (ma[i] == NULL || VM_PAGE_TO_PHYS(ma[i]) != paddr) { + /* + * If PHYS_TO_VM_PAGE() returned NULL or the + * vm_page was not initialized bail and go the + * fake page route. + */ + break; + } + } + if (i != ma_cnt) { + fma = malloc(sizeof(struct vm_page) * ma_cnt, M_DEVBUF, + M_ZERO | (map->cansleep ? M_WAITOK : M_NOWAIT)); + if (fma == NULL) { + free(ma, M_DEVBUF); + return (ENOMEM); + } + + for (i = 0; i < ma_cnt; i++) { + vm_page_initfake(&fma[i], pstart + i * PAGE_SIZE, + VM_MEMATTR_DEFAULT); + ma[i] = &fma[i]; + } + } else + fma = NULL; error = dmar_bus_dmamap_load_something(tag, map, ma, offset, buflen, flags, segs, segp); + free(fma, M_DEVBUF); free(ma, M_DEVBUF); return (error); } @@ -708,14 +734,22 @@ M_WAITOK : M_NOWAIT); if (ma == NULL) return (ENOMEM); - if (dumping) { - /* - * If dumping, do not attempt to call - * PHYS_TO_VM_PAGE() at all. It may return non-NULL - * but the vm_page returned might be not initialized, - * e.g. for the kernel itself. - */ - KASSERT(pmap == kernel_pmap, ("non-kernel address write")); + for (i = 0; i < ma_cnt; i++, pstart += PAGE_SIZE) { + if (pmap == kernel_pmap) + paddr = pmap_kextract(pstart); + else + paddr = pmap_extract(pmap, pstart); + ma[i] = PHYS_TO_VM_PAGE(paddr); + if (ma[i] == NULL || VM_PAGE_TO_PHYS(ma[i]) != paddr) { + /* + * If PHYS_TO_VM_PAGE() returned NULL or the + * vm_page was not initialized bail and go the + * fake page route. + */ + break; + } + } + if (i != ma_cnt) { fma = malloc(sizeof(struct vm_page) * ma_cnt, M_DEVBUF, M_ZERO | (map->cansleep ? M_WAITOK : M_NOWAIT)); if (fma == NULL) { @@ -723,24 +757,15 @@ return (ENOMEM); } for (i = 0; i < ma_cnt; i++, pstart += PAGE_SIZE) { - paddr = pmap_kextract(pstart); - vm_page_initfake(&fma[i], paddr, VM_MEMATTR_DEFAULT); - ma[i] = &fma[i]; - } - } else { - fma = NULL; - for (i = 0; i < ma_cnt; i++, pstart += PAGE_SIZE) { if (pmap == kernel_pmap) paddr = pmap_kextract(pstart); else paddr = pmap_extract(pmap, pstart); - ma[i] = PHYS_TO_VM_PAGE(paddr); - KASSERT(VM_PAGE_TO_PHYS(ma[i]) == paddr, - ("PHYS_TO_VM_PAGE failed %jx %jx m %p", - (uintmax_t)paddr, (uintmax_t)VM_PAGE_TO_PHYS(ma[i]), - ma[i])); + vm_page_initfake(&fma[i], paddr, VM_MEMATTR_DEFAULT); + ma[i] = &fma[i]; } - } + } else + fma = NULL; error = dmar_bus_dmamap_load_something(tag, map, ma, offset, buflen, flags, segs, segp); free(ma, M_DEVBUF);