amd64/93961: Problem in bounce buffer handling in sys/amd64/amd64/busdma_machdep.c: _bus_dmamap_load_buffer()

Kaustubh Patil kpatil at vmware.com
Tue Feb 28 17:00:22 PST 2006


>Number:         93961
>Category:       amd64
>Synopsis:       Problem in bounce buffer handling in sys/amd64/amd64/busdma_machdep.c: _bus_dmamap_load_buffer()
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    freebsd-amd64
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Mar 01 01:00:20 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Kaustubh Patil
>Release:        5.3-64
>Organization:
VMware, Inc.
>Environment:
>Description:
A couple of us have observed this problem with 5.3-64 bit version on a high
memmory machine (> 4GiB memory), but a look at the current code indicates
that the bug might be present in recent branches as well.

_bus_dmamap_load_buffer() first calculates the number of pages that need to be
bounced.

vaddr = trunc_page((vm_offset_t)buf);    ---------- (1)
vendaddr = (vm_offset_t)buf + buflen;

while (vaddr < vendaddr) {
   paddr = pmap_kextract(vaddr);         ---------- (2)
   if (run_filter(dmat, paddr) != 0) {   ---------- (3)
      needbounce = 1;
      map->pagesneeded++;                ---------- (4)
   }
   vaddr += PAGE_SIZE;
}

Consider a dma-map that is set up to indicate the need to bounce
o if the address is in high memory or
o if the address is not page-aligned.

(1) The above code uses trunc_page() on the input virtual address.
(2) This page-aligned address is passed to pmap_kextract(), which returns a
    page-aligned paddr ...
(3) ... which is passed to run_filter(). As the paddr is page-aligned,
    run_filter() finds it okay as far as the page-alignment requirement is
    concerned.
(4) The count obtained is stored in "map->pagesneeded".

Later the function starts allocating bounce pages. However unlike the above code
the allocation code does not align virtual addresses, so run_filter() call
catches the input paddr if it is not page-aligned, then a bounce page is
allocated for it using add_bounce_page() and "map->pagesneeded" is decremented.

Thus this code consumes "map->pagesneeded" for a virtual address that
was not initially identified for bouncing. This potentially leads to other needy
pages not being bounced.

In our scenario this bug caused the mpt driver to pass incorrectly truncated
32-bit addresses in the scatter-gather list, because the data buffer in the high
memory (> 4Gib) was not bounced to < 4Gib memory.

-- Vyacheslav Malyugin, Kaustubh Patil
>How-To-Repeat:

>Fix:
The use of trunc_page() in the counting code seems questionable.
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-amd64 mailing list