win-pvdrivers

changeset 600:bfcba5547b8e

Added support for the case where a ScatterGather list is requested with a non-zero offset into the MDL buffer. This fixes a crash when trying to scan a file in Sophos.
author James Harper <james.harper@bendigoit.com.au>
date Thu Jul 02 21:17:37 2009 +1000 (2009-07-02)
parents f118fcbe5ca8
children 2d022b487c64
files xenpci/xenpci_pdo.c
line diff
     1.1 --- a/xenpci/xenpci_pdo.c	Thu Jul 02 21:12:33 2009 +1000
     1.2 +++ b/xenpci/xenpci_pdo.c	Thu Jul 02 21:17:37 2009 +1000
     1.3 @@ -31,8 +31,9 @@ Foundation, Inc., 51 Franklin Street, Fi
     1.4  typedef struct {
     1.5    ULONG map_type;
     1.6    PVOID aligned_buffer;
     1.7 -  PVOID unaligned_buffer;
     1.8    ULONG copy_length;
     1.9 +  PMDL mdl;
    1.10 +  PVOID currentva;
    1.11    BOOLEAN allocated_by_me;
    1.12  } sg_extra_t;
    1.13  
    1.14 @@ -114,10 +115,8 @@ XenPci_DOP_AllocateCommonBuffer(
    1.15  
    1.16    pfn = (PFN_NUMBER)(MmGetPhysicalAddress(buffer).QuadPart >> PAGE_SHIFT);
    1.17    ASSERT(pfn); /* lazy */
    1.18 -  //KdPrint((__DRIVER_NAME "     A Requesting Grant Ref\n"));
    1.19    gref = (grant_ref_t)GntTbl_GrantAccess(xpdd, 0, (ULONG)pfn, FALSE, INVALID_GRANT_REF);
    1.20 -  //KdPrint((__DRIVER_NAME "     A Got Grant Ref %d\n", gref));
    1.21 -  ASSERT(gref); /* lazy */
    1.22 +  ASSERT(gref != INVALID_GRANT_REF); /* lazy */
    1.23    LogicalAddress->QuadPart = (gref << PAGE_SHIFT) | (PtrToUlong(buffer) & (PAGE_SIZE - 1));
    1.24    
    1.25    //FUNCTION_EXIT();
    1.26 @@ -449,12 +448,16 @@ XenPci_DOP_PutScatterGatherList(
    1.27    PXENPCI_DEVICE_DATA xpdd;
    1.28    ULONG i;
    1.29    sg_extra_t *sg_extra;
    1.30 +  PMDL curr_mdl;
    1.31 +  ULONG offset;
    1.32 +  BOOLEAN active;
    1.33  
    1.34    UNREFERENCED_PARAMETER(WriteToDevice);
    1.35    
    1.36    //FUNCTION_ENTER();
    1.37  
    1.38    xen_dma_adapter = (xen_dma_adapter_t *)DmaAdapter;
    1.39 +  ASSERT(xen_dma_adapter);
    1.40    xpdd = GetXpdd(xen_dma_adapter->xppdd->wdf_device_bus_fdo);
    1.41    
    1.42    sg_extra = (sg_extra_t *)((PUCHAR)sg_list + FIELD_OFFSET(SCATTER_GATHER_LIST, Elements) +
    1.43 @@ -470,8 +473,31 @@ XenPci_DOP_PutScatterGatherList(
    1.44        GntTbl_EndAccess(xpdd, gref, FALSE);
    1.45        sg_list->Elements[i].Address.QuadPart = -1;
    1.46      }
    1.47 +    ASSERT(sg_extra->mdl);
    1.48      if (!WriteToDevice)
    1.49 -      memcpy(sg_extra->unaligned_buffer, sg_extra->aligned_buffer, sg_extra->copy_length);
    1.50 +    {
    1.51 +      for (curr_mdl = sg_extra->mdl, offset = 0, active = FALSE; curr_mdl; curr_mdl = curr_mdl->Next)
    1.52 +      {
    1.53 +        PVOID mdl_start_va = MmGetMdlVirtualAddress(curr_mdl);
    1.54 +        ULONG mdl_byte_count = MmGetMdlByteCount(curr_mdl);
    1.55 +        ULONG mdl_offset = 0;
    1.56 +        if ((ULONGLONG)sg_extra->currentva >= (ULONGLONG)mdl_start_va && (ULONGLONG)sg_extra->currentva < (ULONGLONG)mdl_start_va + mdl_byte_count)
    1.57 +        {
    1.58 +          active = TRUE;
    1.59 +          mdl_byte_count -= (ULONG)((ULONGLONG)sg_extra->currentva - (ULONGLONG)mdl_start_va);
    1.60 +          mdl_offset = (ULONG)((ULONGLONG)sg_extra->currentva - (ULONGLONG)mdl_start_va);
    1.61 +          mdl_start_va = sg_extra->currentva;
    1.62 +        }
    1.63 +        if (active)
    1.64 +        {
    1.65 +          PVOID unaligned_buffer;
    1.66 +          unaligned_buffer = MmGetSystemAddressForMdlSafe(curr_mdl, NormalPagePriority);
    1.67 +          ASSERT(unaligned_buffer); /* lazy */
    1.68 +          memcpy((PUCHAR)unaligned_buffer + mdl_offset, (PUCHAR)sg_extra->aligned_buffer + offset, mdl_byte_count);
    1.69 +          offset += mdl_byte_count;
    1.70 +        }
    1.71 +      }
    1.72 +    }
    1.73      ExFreePoolWithTag(sg_extra->aligned_buffer, XENPCI_POOL_TAG);
    1.74      break;
    1.75    case MAP_TYPE_MDL:
    1.76 @@ -581,7 +607,11 @@ XenPci_DOP_BuildScatterGatherListButDont
    1.77    ULONG offset;
    1.78    PFN_NUMBER pfn;
    1.79    grant_ref_t gref;
    1.80 -  //PUCHAR StartVa;
    1.81 +  BOOLEAN active;
    1.82 +  PVOID mdl_start_va;
    1.83 +  ULONG mdl_byte_count;
    1.84 +  ULONG mdl_offset;
    1.85 +  ULONG remapped_bytes = 0;
    1.86    
    1.87    //FUNCTION_ENTER();
    1.88    
    1.89 @@ -590,7 +620,10 @@ XenPci_DOP_BuildScatterGatherListButDont
    1.90      KdPrint((__DRIVER_NAME "     NULL ScatterGatherBuffer\n"));
    1.91      return STATUS_INVALID_PARAMETER;
    1.92    }
    1.93 -  ASSERT(MmGetMdlVirtualAddress(Mdl) == CurrentVa);
    1.94 +  if (MmGetMdlVirtualAddress(Mdl) != CurrentVa)
    1.95 +  {
    1.96 +    KdPrint((__DRIVER_NAME "     MmGetMdlVirtualAddress = %p, CurrentVa = %p, Length = %d\n", MmGetMdlVirtualAddress(Mdl), CurrentVa, Length));
    1.97 +  }
    1.98  
    1.99    xen_dma_adapter = (xen_dma_adapter_t *)DmaAdapter;
   1.100    xpdd = GetXpdd(xen_dma_adapter->xppdd->wdf_device_bus_fdo);
   1.101 @@ -602,6 +635,7 @@ XenPci_DOP_BuildScatterGatherListButDont
   1.102      if (xen_dma_adapter->dma_extension->need_virtual_address && xen_dma_adapter->dma_extension->need_virtual_address(DeviceObject->CurrentIrp))
   1.103      {
   1.104        ASSERT(!Mdl->Next); /* can only virtual a single buffer */
   1.105 +      ASSERT(MmGetMdlVirtualAddress(Mdl) == CurrentVa);
   1.106        map_type = MAP_TYPE_VIRTUAL;
   1.107        sglist->NumberOfElements = 1;
   1.108      }
   1.109 @@ -610,16 +644,27 @@ XenPci_DOP_BuildScatterGatherListButDont
   1.110        if (xen_dma_adapter->dma_extension->get_alignment)
   1.111        {
   1.112          ULONG alignment = xen_dma_adapter->dma_extension->get_alignment(DeviceObject->CurrentIrp);
   1.113 -        if ((MmGetMdlByteOffset(Mdl) & (alignment - 1)) || (MmGetMdlByteCount(Mdl) & (alignment - 1)))
   1.114 +
   1.115 +        map_type = MAP_TYPE_MDL;
   1.116 +        sglist->NumberOfElements = 0;
   1.117 +        for (curr_mdl = Mdl, remapped_bytes = 0, active = FALSE; curr_mdl; curr_mdl = curr_mdl->Next)
   1.118          {
   1.119 -          ASSERT(!Mdl->Next); /* can only remap a single buffer for now - will need to check all Mdl's in the future */
   1.120 -          map_type = MAP_TYPE_REMAPPED;
   1.121 -          sglist->NumberOfElements = ADDRESS_AND_SIZE_TO_SPAN_PAGES(NULL, Length);
   1.122 +          mdl_start_va = MmGetMdlVirtualAddress(curr_mdl);
   1.123 +          mdl_byte_count = MmGetMdlByteCount(curr_mdl);
   1.124 +          if ((ULONGLONG)CurrentVa >= (ULONGLONG)mdl_start_va && (ULONGLONG)CurrentVa < (ULONGLONG)mdl_start_va + mdl_byte_count)
   1.125 +          {
   1.126 +            active = TRUE;
   1.127 +            mdl_byte_count -= (ULONG)((ULONGLONG)CurrentVa - (ULONGLONG)mdl_start_va);
   1.128 +            mdl_start_va = CurrentVa;
   1.129 +          }
   1.130 +          if (active)
   1.131 +          {
   1.132 +            if (((ULONGLONG)mdl_start_va & (alignment - 1)) || (mdl_byte_count & (alignment - 1)))
   1.133 +              map_type = MAP_TYPE_REMAPPED;
   1.134 +            remapped_bytes += mdl_byte_count;
   1.135 +          }
   1.136          }
   1.137 -        else
   1.138 -        {
   1.139 -          map_type = MAP_TYPE_MDL;
   1.140 -        }
   1.141 +        sglist->NumberOfElements += ADDRESS_AND_SIZE_TO_SPAN_PAGES(NULL, remapped_bytes);
   1.142        }
   1.143        else
   1.144        {
   1.145 @@ -633,9 +678,22 @@ XenPci_DOP_BuildScatterGatherListButDont
   1.146    }
   1.147    if (map_type == MAP_TYPE_MDL)
   1.148    {
   1.149 -    for (curr_mdl = Mdl, sglist->NumberOfElements = 0; curr_mdl; curr_mdl = curr_mdl->Next)
   1.150 -      sglist->NumberOfElements += ADDRESS_AND_SIZE_TO_SPAN_PAGES(
   1.151 -        MmGetMdlVirtualAddress(curr_mdl), MmGetMdlByteCount(curr_mdl));
   1.152 +    for (curr_mdl = Mdl, sglist->NumberOfElements = 0, active = FALSE; curr_mdl; curr_mdl = curr_mdl->Next)
   1.153 +    {
   1.154 +      mdl_start_va = MmGetMdlVirtualAddress(curr_mdl);
   1.155 +      mdl_byte_count = MmGetMdlByteCount(curr_mdl);
   1.156 +      if ((ULONGLONG)CurrentVa >= (ULONGLONG)mdl_start_va && (ULONGLONG)CurrentVa < (ULONGLONG)mdl_start_va + mdl_byte_count)
   1.157 +      {
   1.158 +        active = TRUE;
   1.159 +        mdl_byte_count -= (ULONG)((ULONGLONG)CurrentVa - (ULONGLONG)mdl_start_va);
   1.160 +        mdl_start_va = CurrentVa;
   1.161 +      }
   1.162 +      if (active)
   1.163 +      {
   1.164 +        sglist->NumberOfElements += ADDRESS_AND_SIZE_TO_SPAN_PAGES(
   1.165 +          MmGetMdlVirtualAddress(curr_mdl), MmGetMdlByteCount(curr_mdl));
   1.166 +      }
   1.167 +    }
   1.168    }
   1.169    if (ScatterGatherBufferLength < FIELD_OFFSET(SCATTER_GATHER_LIST, Elements) +
   1.170      sizeof(SCATTER_GATHER_ELEMENT) * sglist->NumberOfElements + sizeof(sg_extra_t))
   1.171 @@ -656,51 +714,81 @@ XenPci_DOP_BuildScatterGatherListButDont
   1.172    case MAP_TYPE_MDL:
   1.173      //KdPrint((__DRIVER_NAME "     MAP_TYPE_MDL - %p\n", MmGetMdlVirtualAddress(Mdl)));
   1.174      total_remaining = Length;
   1.175 -    for (sg_element = 0, curr_mdl = Mdl; curr_mdl; curr_mdl = curr_mdl->Next)
   1.176 +    for (sg_element = 0, curr_mdl = Mdl, active = FALSE; curr_mdl; curr_mdl = curr_mdl->Next)
   1.177      {
   1.178 -      remaining = MmGetMdlByteCount(curr_mdl);
   1.179 -      offset = MmGetMdlByteOffset(curr_mdl);
   1.180 -      if (!remaining)
   1.181 -      {
   1.182 -        KdPrint((__DRIVER_NAME "     zero length MDL\n"));
   1.183 -      }
   1.184 -      for (i = 0; i < ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(curr_mdl), MmGetMdlByteCount(curr_mdl)); i++)
   1.185 +      mdl_start_va = MmGetMdlVirtualAddress(curr_mdl);
   1.186 +      mdl_byte_count = MmGetMdlByteCount(curr_mdl);
   1.187 +      if ((ULONGLONG)CurrentVa >= (ULONGLONG)mdl_start_va && (ULONGLONG)CurrentVa < (ULONGLONG)mdl_start_va + mdl_byte_count)
   1.188        {
   1.189 -//KdPrint((__DRIVER_NAME "     element = %d\n", sg_element));
   1.190 -//KdPrint((__DRIVER_NAME "     remaining = %d\n", remaining));
   1.191 -        pfn = MmGetMdlPfnArray(curr_mdl)[i];
   1.192 -        ASSERT(pfn);
   1.193 -        gref = (grant_ref_t)GntTbl_GrantAccess(xpdd, 0, (ULONG)pfn, FALSE, INVALID_GRANT_REF);
   1.194 -        ASSERT(gref != INVALID_GRANT_REF);
   1.195 -        sglist->Elements[sg_element].Address.QuadPart = (LONGLONG)(gref << PAGE_SHIFT) | offset;
   1.196 -        sglist->Elements[sg_element].Length = min(min(PAGE_SIZE - offset, remaining), total_remaining);
   1.197 -        total_remaining -= sglist->Elements[sg_element].Length;
   1.198 -        remaining -= sglist->Elements[sg_element].Length;
   1.199 -        offset = 0;
   1.200 -        sg_element++;
   1.201 +        active = TRUE;
   1.202 +        mdl_byte_count -= (ULONG)((ULONGLONG)CurrentVa - (ULONGLONG)mdl_start_va);
   1.203 +        mdl_start_va = CurrentVa;
   1.204 +      }
   1.205 +      if (active)
   1.206 +      {
   1.207 +        ULONG pfn_offset;
   1.208 +        remaining = mdl_byte_count;
   1.209 +        offset = (ULONG)((ULONGLONG)mdl_start_va & (PAGE_SIZE - 1));
   1.210 +        pfn_offset = (ULONG)(((ULONGLONG)mdl_start_va >> PAGE_SHIFT) - ((ULONGLONG)MmGetMdlVirtualAddress(curr_mdl) >> PAGE_SHIFT));
   1.211 +        for (i = 0; i < ADDRESS_AND_SIZE_TO_SPAN_PAGES(mdl_start_va, mdl_byte_count); i++)
   1.212 +        {
   1.213 +          pfn = MmGetMdlPfnArray(curr_mdl)[pfn_offset + i];
   1.214 +          ASSERT(pfn);
   1.215 +          gref = (grant_ref_t)GntTbl_GrantAccess(xpdd, 0, (ULONG)pfn, FALSE, INVALID_GRANT_REF);
   1.216 +          ASSERT(gref != INVALID_GRANT_REF);
   1.217 +          sglist->Elements[sg_element].Address.QuadPart = (LONGLONG)(gref << PAGE_SHIFT) | offset;
   1.218 +          sglist->Elements[sg_element].Length = min(min(PAGE_SIZE - offset, remaining), total_remaining);
   1.219 +          total_remaining -= sglist->Elements[sg_element].Length;
   1.220 +          remaining -= sglist->Elements[sg_element].Length;
   1.221 +          offset = 0;
   1.222 +          sg_element++;
   1.223 +        }
   1.224        }
   1.225      }
   1.226      break;
   1.227    case MAP_TYPE_REMAPPED:
   1.228 -    sg_extra->aligned_buffer = ExAllocatePoolWithTag(NonPagedPool, max(Length, PAGE_SIZE), XENPCI_POOL_TAG);
   1.229 +    sg_extra->aligned_buffer = ExAllocatePoolWithTag(NonPagedPool, max(remapped_bytes, PAGE_SIZE), XENPCI_POOL_TAG);
   1.230      if (!sg_extra->aligned_buffer)
   1.231      {
   1.232 -      KdPrint((__DRIVER_NAME "     MAP_TYPE_REMAPPED buffer allocation failed - requested va = %p, length = %d\n", MmGetMdlVirtualAddress(Mdl), Length));
   1.233 +      KdPrint((__DRIVER_NAME "     MAP_TYPE_REMAPPED buffer allocation failed - requested va = %p, length = %d\n", MmGetMdlVirtualAddress(Mdl), remapped_bytes));
   1.234        return STATUS_INSUFFICIENT_RESOURCES;
   1.235      }
   1.236      //KdPrint((__DRIVER_NAME "     MAP_TYPE_REMAPPED - %p -> %p\n", MmGetMdlVirtualAddress(Mdl), sg_extra->aligned_buffer));
   1.237 -    sg_extra->unaligned_buffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
   1.238 -    ASSERT(sg_extra->unaligned_buffer); /* lazy */
   1.239 -    sg_extra->copy_length = Length;
   1.240 +    sg_extra->mdl = Mdl;
   1.241 +    sg_extra->currentva = CurrentVa;
   1.242 +    sg_extra->copy_length = remapped_bytes;
   1.243 +
   1.244      if (WriteToDevice)
   1.245 -      memcpy(sg_extra->aligned_buffer, sg_extra->unaligned_buffer, sg_extra->copy_length);
   1.246 -    for (sg_element = 0, remaining = Length; 
   1.247 -      sg_element < ADDRESS_AND_SIZE_TO_SPAN_PAGES(sg_extra->aligned_buffer, Length); sg_element++)
   1.248 +    {
   1.249 +      for (curr_mdl = Mdl, offset = 0, active = FALSE; curr_mdl; curr_mdl = curr_mdl->Next)
   1.250 +      {
   1.251 +        mdl_start_va = MmGetMdlVirtualAddress(curr_mdl);
   1.252 +        mdl_byte_count = MmGetMdlByteCount(curr_mdl);
   1.253 +        mdl_offset = 0;
   1.254 +        if ((ULONGLONG)CurrentVa >= (ULONGLONG)mdl_start_va && (ULONGLONG)CurrentVa < (ULONGLONG)mdl_start_va + mdl_byte_count)
   1.255 +        {
   1.256 +          active = TRUE;
   1.257 +          mdl_byte_count -= (ULONG)((ULONGLONG)CurrentVa - (ULONGLONG)mdl_start_va);
   1.258 +          mdl_offset = (ULONG)((ULONGLONG)CurrentVa - (ULONGLONG)mdl_start_va);
   1.259 +          mdl_start_va = CurrentVa;
   1.260 +        }
   1.261 +        if (active)
   1.262 +        {
   1.263 +          PVOID unaligned_buffer;
   1.264 +          unaligned_buffer = (PUCHAR)MmGetSystemAddressForMdlSafe(curr_mdl, NormalPagePriority);
   1.265 +          ASSERT(unaligned_buffer); /* lazy */
   1.266 +          memcpy((PUCHAR)sg_extra->aligned_buffer + offset, (PUCHAR)unaligned_buffer + mdl_offset, mdl_byte_count);
   1.267 +          offset += mdl_byte_count;
   1.268 +        }
   1.269 +      }
   1.270 +    }
   1.271 +    for (sg_element = 0, remaining = remapped_bytes; 
   1.272 +      sg_element < ADDRESS_AND_SIZE_TO_SPAN_PAGES(sg_extra->aligned_buffer, remapped_bytes); sg_element++)
   1.273      {
   1.274        pfn = (PFN_NUMBER)(MmGetPhysicalAddress((PUCHAR)sg_extra->aligned_buffer + (sg_element << PAGE_SHIFT)).QuadPart >> PAGE_SHIFT);
   1.275        ASSERT(pfn);
   1.276        gref = (grant_ref_t)GntTbl_GrantAccess(xpdd, 0, (ULONG)pfn, FALSE, INVALID_GRANT_REF);
   1.277 -      ASSERT(gref);
   1.278 +      ASSERT(gref != INVALID_GRANT_REF);
   1.279        sglist->Elements[sg_element].Address.QuadPart = (ULONGLONG)gref << PAGE_SHIFT;
   1.280        sglist->Elements[sg_element].Length = min(PAGE_SIZE, remaining);
   1.281        remaining -= sglist->Elements[sg_element].Length;
   1.282 @@ -717,6 +805,7 @@ XenPci_DOP_BuildScatterGatherListButDont
   1.283      KdPrint((__DRIVER_NAME "     map_type = %d\n", map_type));
   1.284      break;
   1.285    }
   1.286 +  //FUNCTION_EXIT();
   1.287    return STATUS_SUCCESS;
   1.288  }
   1.289