Date: Sun, 13 Jan 2008 11:45:53 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 133182 for review Message-ID: <200801131145.m0DBjra3077773@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=133182 Change 133182 by hselasky@hselasky_laptop001 on 2008/01/13 11:44:56 OHCI isochronous "off by one" bugfix. When doing isochronous transfers the final physical page was computed like: usbd_get_page(xfer->frbuffers + 0, buf_offset, &buf_res); Instead of: usbd_get_page(xfer->frbuffers + 0, buf_offset-1, &buf_res); This can lead to invalid memory access in some special cases. Non-isochronous transfers are not affected. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/ohci.c#57 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/ohci.c#57 (text+ko) ==== @@ -1907,24 +1907,22 @@ struct ohci_hcca *hcca; uint32_t buf_offset; uint32_t nframes; - uint32_t bp0; - uint32_t end_phy; uint32_t ed_flags; uint32_t *plen; uint16_t itd_offset[OHCI_ITD_NOFFSET]; + uint16_t length; uint8_t ncur; - uint8_t allzero = 1; ohci_itd_t *td; ohci_itd_t *td_last = NULL; ohci_ed_t *ed; - DPRINTFN(5, ("xfer=%p next=%d nframes=%d\n", - xfer, xfer->pipe->isoc_next, xfer->nframes)); - hcca = ohci_get_hcca(sc); nframes = le32toh(hcca->hcca_frame_number); + DPRINTFN(5, ("xfer=%p isoc_next=%u nframes=%u hcca_fn=%u\n", + xfer, xfer->pipe->isoc_next, xfer->nframes, nframes)); + if ((LIST_FIRST(&(xfer->pipe->list_head)) == NULL) || (((nframes - xfer->pipe->isoc_next) & 0xFFFF) < xfer->nframes) || (((xfer->pipe->isoc_next - nframes) & 0xFFFF) >= 128)) { @@ -1955,7 +1953,6 @@ nframes = xfer->nframes; buf_offset = 0; - usbd_get_page(xfer->frbuffers + 0, buf_offset, &buf_res); plen = xfer->frlengths; @@ -1968,32 +1965,24 @@ xfer->td_transfer_first = td; ncur = 0; - - bp0 = OHCI_PAGE(buf_res.physaddr); + length = 0; - end_phy = 0; - while (nframes--) { if (td == NULL) { panic("%s:%d: out of TD's\n", __FUNCTION__, __LINE__); } - itd_offset[ncur] = htole16(OHCI_ITD_MK_OFFS - (buf_res.physaddr - bp0)); - if (*plen) { - allzero = 0; - buf_offset += (*plen) - 1; - usbd_get_page(xfer->frbuffers + 0, buf_offset, &buf_res); - - end_phy = buf_res.physaddr; - buf_offset += 1; - usbd_get_page(xfer->frbuffers + 0, buf_offset, &buf_res); - } + itd_offset[ncur] = length; + buf_offset += *plen; + length += *plen; plen++; ncur++; - if ((ncur == OHCI_ITD_NOFFSET) || - (OHCI_PAGE(buf_res.physaddr) != bp0) || + if (/* check if the ITD is full */ + (ncur == OHCI_ITD_NOFFSET) || + /* check if we have put more than 4K into the ITD */ + (length & 0xF000) || + /* check if it is the last frame */ (nframes == 0)) { /* fill current ITD */ @@ -2003,22 +1992,37 @@ OHCI_ITD_NOINTR | OHCI_ITD_SET_FC(ncur)); - if (allzero) { + td->frames = ncur; + xfer->pipe->isoc_next += ncur; + + if (length == 0) { + /* all zero */ td->itd_bp0 = 0; td->itd_be = ~0; + + while (ncur--) { + td->itd_offset[ncur] = + htole16(OHCI_ITD_MK_OFFS(0)); + } } else { - td->itd_bp0 = htole32(bp0); - td->itd_be = htole32(end_phy); - } - td->frames = ncur; + usbd_get_page(xfer->frbuffers + 0, buf_offset-length, &buf_res); + length = OHCI_PAGE_MASK(buf_res.physaddr); + buf_res.physaddr = + OHCI_PAGE(buf_res.physaddr); + td->itd_bp0 = htole32(buf_res.physaddr); + usbd_get_page(xfer->frbuffers + 0, buf_offset-1, &buf_res); + td->itd_be = htole32(buf_res.physaddr); - xfer->pipe->isoc_next += ncur; - bp0 = OHCI_PAGE(buf_res.physaddr); - while (ncur--) { - td->itd_offset[ncur] = itd_offset[ncur]; + while (ncur--) { + itd_offset[ncur] += length; + itd_offset[ncur] = + OHCI_ITD_MK_OFFS(itd_offset[ncur]); + td->itd_offset[ncur] = + htole16(itd_offset[ncur]); + } } ncur = 0; - allzero = 1; + length = 0; td_last = td; td = td->obj_next;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801131145.m0DBjra3077773>