diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2015-04-08 01:55:22 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2015-04-08 01:55:22 +0000 |
commit | 5f01ba81aefd6e2be3bd010d12a7c207a362bfb4 (patch) | |
tree | 7a8638cf4f1ecc494c7173f4af3f2eca488c980d /sys/x86/iommu/busdma_dmar.c | |
parent | 6554d5b4214de940f874afcfbdee27549047dadb (diff) | |
download | src-5f01ba81aefd6e2be3bd010d12a7c207a362bfb4.tar.gz src-5f01ba81aefd6e2be3bd010d12a7c207a362bfb4.zip |
Account for the offset of the page run when allocating the
dmar_map_entry. Non-zero offset both increases the required mapping
size, which is handled in dmar_bus_dmamap_load_something1(), and makes
it possible that allocated range crosses boundary, which needs a check
in dmar_gas_match_one().
Reported and tested by: jimharris
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Notes
Notes:
svn path=/head/; revision=281254
Diffstat (limited to 'sys/x86/iommu/busdma_dmar.c')
-rw-r--r-- | sys/x86/iommu/busdma_dmar.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/sys/x86/iommu/busdma_dmar.c b/sys/x86/iommu/busdma_dmar.c index 3f86c7844c1f..96b0bcea394f 100644 --- a/sys/x86/iommu/busdma_dmar.c +++ b/sys/x86/iommu/busdma_dmar.c @@ -462,6 +462,7 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag, bus_size_t buflen1; int error, idx, gas_flags, seg; + KASSERT(offset < DMAR_PAGE_SIZE, ("offset %d", offset)); if (segs == NULL) segs = tag->segments; ctx = tag->ctx; @@ -476,7 +477,6 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag, } buflen1 = buflen > tag->common.maxsegsz ? tag->common.maxsegsz : buflen; - buflen -= buflen1; size = round_page(offset + buflen1); /* @@ -487,7 +487,7 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag, if (seg + 1 < tag->common.nsegments) gas_flags |= DMAR_GM_CANSPLIT; - error = dmar_gas_map(ctx, &tag->common, size, + error = dmar_gas_map(ctx, &tag->common, size, offset, DMAR_MAP_ENTRY_READ | DMAR_MAP_ENTRY_WRITE, gas_flags, ma + idx, &entry); if (error != 0) @@ -506,6 +506,10 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag, (uintmax_t)size, (uintmax_t)entry->start, (uintmax_t)entry->end)); } + if (offset + buflen1 > size) + buflen1 = size - offset; + if (buflen1 > tag->common.maxsegsz) + buflen1 = tag->common.maxsegsz; KASSERT(((entry->start + offset) & (tag->common.alignment - 1)) == 0, @@ -519,15 +523,16 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag, (uintmax_t)entry->start, (uintmax_t)entry->end, (uintmax_t)tag->common.lowaddr, (uintmax_t)tag->common.highaddr)); - KASSERT(dmar_test_boundary(entry->start, entry->end - - entry->start, tag->common.boundary), + KASSERT(dmar_test_boundary(entry->start + offset, buflen1, + tag->common.boundary), ("boundary failed: ctx %p start 0x%jx end 0x%jx " "boundary 0x%jx", ctx, (uintmax_t)entry->start, (uintmax_t)entry->end, (uintmax_t)tag->common.boundary)); KASSERT(buflen1 <= tag->common.maxsegsz, ("segment too large: ctx %p start 0x%jx end 0x%jx " - "maxsegsz 0x%jx", ctx, (uintmax_t)entry->start, - (uintmax_t)entry->end, (uintmax_t)tag->common.maxsegsz)); + "buflen1 0x%jx maxsegsz 0x%jx", ctx, + (uintmax_t)entry->start, (uintmax_t)entry->end, + (uintmax_t)buflen1, (uintmax_t)tag->common.maxsegsz)); DMAR_CTX_LOCK(ctx); TAILQ_INSERT_TAIL(&map->map_entries, entry, dmamap_link); @@ -541,6 +546,7 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag, idx += OFF_TO_IDX(trunc_page(offset + buflen1)); offset += buflen1; offset &= DMAR_PAGE_MASK; + buflen -= buflen1; } if (error == 0) *segp = seg; |