Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: PCI + DMA в WDM драйвере под х64  (Прочитано 11661 раз)
0 Пользователей и 1 Гость смотрят эту тему.
sabbatazh
Помогающий

ua
Offline Offline

« : 31-05-2012 19:05 » 

Здравствуйте Уважаемые Знатоки!
Опять к Вам на поклон с вопросами…

Возник вопрос о переносе драйвера на х64, уже наверняка много писали, но мало ответов я получил из прочитанного!
Научился бороться с установкой и подписью…
Мой софт не может получить данные (х32 программулина)…
И вот первое попробовал сделать драйвер под х64 и размер типа объявленных переменных вырос (например,sizeof() структура вместо 32 стала 48) как такое можно исправить привести типы в соответствие?!
И как правильно настроить адаптер ДМА что бы х32 программа могла прочитать данные???
ДМА настроено:
Код: (C++)
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;      //перавя версия, нулевая исползуется только при IgnoreCounter = FALSE
    DeviceDescription.Master = TRUE;
    DeviceDescription.ScatterGather = FALSE;
    DeviceDescription.DemandMode = TRUE;
    DeviceDescription.AutoInitialize = FALSE;
    DeviceDescription.Dma32BitAddresses = TRUE;
    DeviceDescription.IgnoreCount = FALSE;//TRUE;
    DeviceDescription.Reserved1 = FALSE;
    DeviceDescription.Dma64BitAddresses = FALSE;
    //devDescr.DoNotUse2 = 0; //=devDescr.BusNumber - NotUsed in WDM
    DeviceDescription.DmaChannel = 0; //только для Slave устройств
    DeviceDescription.InterfaceType = PCIBus;
    DeviceDescription.DmaWidth = Width32Bits;   // PCI default width
    DeviceDescription.DmaSpeed = Compatible;//не для мастера? (только если value only if the machine's ACPI BIOS supports it)... ничего не понял
    //devDescr.MaximumLength = ROUND_TO_PAGES(XXXXX/2);    
    DeviceDescription.MaximumLength =  PAGE_SIZE;    //в любом случае они просили округлить до PAGE_SIZE, да на здоровье!
    //devDescr.DmaPort = 0;   //говорят, что это устаревший параметр. но нужен для совместимости... для Legacy...
    // OS will assign map register count
    NumMapRegisters = 0;

    // Allocate a DMA adapter object
        pdx->DMAAdapter = IoGetDmaAdapter(pdx->PhysicalDeviceObject, &DeviceDescription, &NumMapRegisters);

        if (!pdx->DMAAdapter)
                {
                                KdPrint(("ERROR - DMA Adapter allocation failed\n"));
                        return STATUS_INSUFFICIENT_RESOURCES;
                }
думаю так и оставить надо?!

Спасибо!
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 31-05-2012 21:52 » 

неделя суматошная на работе... заранее прошу прощения.
 
поподробнее - пока ничего не понятно) какой такой сайзоф от чего и что в нем смущает.
опишите интерфейсы подробнее(но коротко),  времени совсем нет вспомнить что у вас за задача была)

"как такое можно исправить привести типы в соответствие" - что это "такое", и в "соответствие" к чему?
на x64 - размер всех указателей 8 байт и это правильно. соответственно сайзоф вам не врет)
включите проверку на портируемость в компиляторе студии (ключ /Wp64 - кажется)- проверьте все варнинги.

чтобы передать указатели на память из x64 драйвера в x32 программу надо отмапировать память(на работе надо проверить!!!, уже забыл) в пространство приложения и использовать только младшую часть(4 байта) после маппинга для отдачи в x32 приложение.
структуру с указателями (но ТОЛЬКО ту, которую вы ее отдаете в приложение) вы должны принудительно оформить, используя 4 байтные поля для передачи адреса.
как это генерично делать - я не помню, кажется я добавлял свой 4-байтный тип (но мне нужна была полная портируемость кода драйвера в среде x32/x64/x64{апликуха x32} )

но вообще грамотно оставлять совместимость 64битного драйвера с ч64 и ч32 приложениями.
для этого в драйвере используется функция... Is... забыл имя. вызывается в драйвере в контексте вызывающего процесса и показывает тип вызывающего процесса - 32 или 64. в зависимости от этого выбираете тип формирования указателей 32/64.

то есть, у меня например в IOCTL заполняется структура и отдается обратно приложению.
первым делом я проверяю тип вызывающего процесса - в зависимости от него, у меня определены две похожие структуры одна для х32 вторая для х64. длинна второй - больше (потому что она с указателями на 8 байт). и я их по разному заполняю.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
sabbatazh
Помогающий

ua
Offline Offline

« Ответ #2 : 02-06-2012 17:17 » 

У меня тоже структура с указателем! И в тупике… как скрутить все в куче… ибо 32 разрядная программа вываливает кучу ошибок… разобрался что структура не заполняется!
и я так понял, что настройку ДМА адаптера можно оставить без изменения...Не понял 
Код: (C++)
struct XDSP_DMA_BUFFER_PTRS
{      
        ULONG* DMABufferUserPtr1;
        ULONG* DMABufferUserPtr2;
        ULONG* DMABufferUserPtr3;
        ULONG* DMABufferUserPtr4;

        ULONG  DMABufferPhysPtr1;
        ULONG  DMABufferPhysPtr2;
        ULONG  DMABufferPhysPtr3;
        ULONG  DMABufferPhysPtr4;
};
в дравере заполнение происходит в IOCTL запросе:
Код: (C++)
case MDMAI_DMA_SETUP://:
                {
                        DbgPrint("enter MDMAI_DMA_SETUP:\n");
                        //ResetDevice(pdx);
                        // Verify DMA Adapter was created

                         HANDLE hEvent =  *(HANDLE*)Irp->AssociatedIrp.SystemBuffer;

                                        KdPrint((DRIVERNAME" -  InterruptEventHandle = %0x.\n", hEvent));

                if (pdx->DMAAdapter != NULL)
                        {
                                 if (cbin < sizeof( XDSP_DMA_BUFFER_PTRS*))
                                         {
                                                status = STATUS_INVALID_PARAMETER;
                                                break;
                                         }                                     

                                    XDSP_DMA_BUFFER_PTRS* pBuffer = (XDSP_DMA_BUFFER_PTRS*)ExAllocatePool(NonPagedPool,cbout);
                                                                KdPrint((DRIVERNAME " — Size of XDSP_DMA_BUFFER_PTRS = %d \n", sizeof(XDSP_DMA_BUFFER_PTRS)));

                                        if (pBuffer!=NULL)
                                        {      
                                                if ((uDmaPhysAddr1 != 0)&&(uDmaPhysAddr2 != 0)&&(uDmaPhysAddr3 != 0)&&(uDmaPhysAddr4 != 0))
                                                {                                                      

                                                status = ObReferenceObjectByHandle(        //Create reference to Event Object with Application
                           (HANDLE)hEvent,              //Handle as Event Object
                           EVENT_MODIFY_STATE,   //Can Modify Event Object state
                           *ExEventObjectType,    //Type of event object. if File object - *IofileObjectType
                                                   KernelMode,   //UserMode or KernelMode. If KernelMode - Set Previuos parameter to NULL
                           (PVOID *)&_kEvent,              //Global pointer to Event object
                           NULL);

                                                 if(status != STATUS_SUCCESS)
                                                        {
                                                                KdPrint((DRIVERNAME " — ERROR Event Object \n"));
                                                                status = STATUS_INVALID_PARAMETER;
                                                                break;
                                                        }

                                                if (!_kEvent)
                                                        {
                                                                KdPrint((DRIVERNAME " — ERROR SetKEvent \n"));
                                                                status = STATUS_INVALID_PARAMETER;
                                                                break;
                                                        }                                                              
                                                                KdPrint((DRIVERNAME " — Init Event Object... \n"));
                                                               
                                                        pBuffer->DMABufferPhysPtr1 = uDmaPhysAddr1;
                                                                KdPrint((DRIVERNAME " -  SHOW DMA pBuffer 1 ADDRESS IN START %Xh\n", pBuffer->DMABufferPhysPtr1));
                                                        pBuffer->DMABufferPhysPtr2 = uDmaPhysAddr2;
                                                                KdPrint((DRIVERNAME " -  SHOW DMA pBuffer 2 ADDRESS IN START %Xh\n", pBuffer->DMABufferPhysPtr2));
                                                        pBuffer->DMABufferPhysPtr3 = uDmaPhysAddr3;
                                                                KdPrint((DRIVERNAME " -  SHOW DMA pBuffer 3 ADDRESS IN START %Xh\n", pBuffer->DMABufferPhysPtr3));
                                                        pBuffer->DMABufferPhysPtr4 = uDmaPhysAddr4;
                                                                KdPrint((DRIVERNAME " -  SHOW DMA pBuffer 4 ADDRESS IN START %Xh\n", pBuffer->DMABufferPhysPtr4));
                                                        pBuffer->DMABufferUserPtr1 = (ULONG*) MmMapLockedPagesSpecifyCache(DmaBufferMemory1, UserMode, MmCached, NULL, FALSE, NormalPagePriority);//DmaVirtualAddr1;                                       
                                                                KdPrint((DRIVERNAME " -  SHOW maps the physical pages 1 %Xh\n", (ULONG)pBuffer->DMABufferUserPtr1));
                                                        pBuffer->DMABufferUserPtr2 = (ULONG*) MmMapLockedPagesSpecifyCache(DmaBufferMemory2, UserMode, MmCached, NULL, FALSE, NormalPagePriority);//DmaVirtualAddr2;
                                                                KdPrint((DRIVERNAME " -  SHOW maps the physical pages 2 %Xh\n", (ULONG)pBuffer->DMABufferUserPtr2));
                                                        pBuffer->DMABufferUserPtr3 = (ULONG*) MmMapLockedPagesSpecifyCache(DmaBufferMemory3, UserMode, MmCached, NULL, FALSE, NormalPagePriority);//DmaVirtualAddr3;
                                                                KdPrint((DRIVERNAME " -  SHOW maps the physical pages 3 %Xh\n", (ULONG)pBuffer->DMABufferUserPtr3));
                                                        pBuffer->DMABufferUserPtr4 = (ULONG*) MmMapLockedPagesSpecifyCache(DmaBufferMemory4, UserMode, MmCached, NULL, FALSE, NormalPagePriority);//DmaVirtualAddr4;
                                                                KdPrint((DRIVERNAME " -  SHOW maps the physical pages 4 %Xh\n", (ULONG)pBuffer->DMABufferUserPtr4));

                                                                info = sizeof(XDSP_DMA_BUFFER_PTRS);
                                                                        KdPrint((DRIVERNAME " — Size of DATA = %d \n", info));

                                                                PVOID pInputBuffer  = Irp->AssociatedIrp.SystemBuffer;
                                                                PVOID pOutputBuffer = NULL;
                                               
                                                                        if(Irp->MdlAddress)
                                                                                {
                                                                                        pOutputBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);                                                                     
                                                                                }
                                               
                                                                        if(pInputBuffer && pOutputBuffer)
                                                                                {                                                                      
                                                                                                DbgPrint("%i >= %i", cbout, info);
                                                                                        if(cbout >= info)
                                                                                        {
                                                                                                RtlCopyMemory(pOutputBuffer, pBuffer, info);
                                                                                                //pOutputBuffer = (PVOID) pBuffer;
                                                                                                  status = STATUS_SUCCESS;
                                                                                        }else return STATUS_BUFFER_TOO_SMALL;
                                                                                }

                                                                        ExFreePool(pBuffer);// Free Buffer!

                                                        //удаляем обьект прерывания и порождаем новый?!!!
                                        if (pdx->InterruptObject){
                                                        IoDisconnectInterrupt(pdx->InterruptObject);
                                                                                                  pdx->InterruptObject = NULL;}

                                                status = IoConnectInterrupt( &pdx->InterruptObject, (PKSERVICE_ROUTINE)OnInterrupt,
                                                                        (PVOID)pdx, NULL, pdx->InterruptVector, pdx->InterruptIrql, pdx->InterruptIrql, pdx->InterruptMode, TRUE, pdx->InterruptAffinity, FALSE );
                       
                                                        if( !NT_SUCCESS( status ) )
                                                                {
                                                                                KdPrint( ( "IoConnectInterrupt failed! - %X\n", status ) );
                                                                                status = STATUS_INVALID_PARAMETER;
                                                                                break;
                                                                }else
                                                                {
                                                                                KdPrint( ( "IoConnectInterrupt() Success\n" ) );
                                                                }

                                                IoInitializeDpcRequest(fdo, (PIO_DPC_ROUTINE)DpcForIsr);

                                                        ResetDevice(pdx);
                                                        ULONG offset = 7*4;
                                                       
                                                        WRITE_PORT_BUFFER_ULONG((PULONG)(pdx->portaddr + offset), (PULONG)&uDmaPhysAddr1, 1);                  
                                                               
                                                        DeviceWasSetuped = 1;
                                         status = STATUS_SUCCESS;
                                        }else status = STATUS_INVALID_PARAMETER;                                                                       
                                                 
                                }else status = STATUS_INVALID_PARAMETER;                                       
                        }else
                                {
                                        KdPrint(("ERROR - DMA Adapter allocation failed\n"));
                                        status = STATUS_INVALID_PARAMETER;
                                }
                               
                        break;
                }
а точнее
Код: (C++)
pBuffer->DMABufferPhysPtr1 = uDmaPhysAddr1;
pBuffer->DMABufferPhysPtr2 = uDmaPhysAddr2;
pBuffer->DMABufferPhysPtr3 = uDmaPhysAddr3;
pBuffer->DMABufferPhysPtr4 = uDmaPhysAddr4;

pBuffer->DMABufferUserPtr1 = (ULONG*) MmMapLockedPagesSpecifyCache(DmaBufferMemory1, UserMode, MmCached, NULL, FALSE, NormalPagePriority);//DmaVirtualAddr1;                                       
pBuffer->DMABufferUserPtr2 = (ULONG*) MmMapLockedPagesSpecifyCache(DmaBufferMemory2, UserMode, MmCached, NULL, FALSE, NormalPagePriority);//DmaVirtualAddr2;
pBuffer->DMABufferUserPtr3 = (ULONG*) MmMapLockedPagesSpecifyCache(DmaBufferMemory3, UserMode, MmCached, NULL, FALSE, NormalPagePriority);//DmaVirtualAddr3;
pBuffer->DMABufferUserPtr4 = (ULONG*) MmMapLockedPagesSpecifyCache(DmaBufferMemory4, UserMode, MmCached, NULL, FALSE, NormalPagePriority);//DmaVirtualAddr4;
и дальше отправляем пользователю и запускаем плату на сбор данных, как показано в коде IOCTL запроса...
и получается не соответсвие размеров структур...  Здесь была моя ладья...
и еще Вы мне говорили, что необходимо заменить RtlCopyMemory(pOutputBuffer, pBuffer, info);, я так и не понял на что? А черт его знает...
« Последнее редактирование: 02-06-2012 17:20 от sabbatazh » Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 02-06-2012 20:04 » 

еще раз.
смотрите. драйвер работает в среде x64. то есть все указатели стали 64 бита. размер всех структур вырос. пока драйвер работает с ними никому не передавая - все в порядке.
однако приложение - 32разрядное, оно про указатели 64 бита даже не догадывается что такие на свете существуют.

поэтому:
1. именно драйвер должен разделить запросы от 32 битных приложений, и от 64 битных. функция IoIs32bitProcess()
если запрос от 64 битного приложения - он должен отдавать 64битные указатели.
если от 32-битного - отдавать приложению 32 бита.

2. приложение никода не получает указатели которые использует драйвер. почему? - да потому что указатели на память драйвера для приложения не имеют смысла. приложение к этой памяти напрямую обратится не может (как правило).
каждому приложению - драйвер формирует свои указатели путем мапирования (MmMapLockedPages) выделенной дравером памяти в адресное пространство приложения.

когда драйвер мапирует (MmMapLockedPages)  выделенную в драйвере память в 64 битное приложение - получается 64 битный указатель. он целиком предается приложению. приложение тоже работает в 64 битах.

когда драйвер мапирует (MmMapLockedPages)  выделенную в драйвере память в 32 битное приложение - ВСЕ РАВНО получается 64 битный указатель, но значимая часть адреса для приложения - находится в младших 32 битах!!! именно эти биты надо передать приложению в качестве указателя. (старшие 4 байта 64-битного указателя будут нулевыми)

3. для структур, содержащих указатели и отдаваемых 64 битному приложению - надо объявить структуры обычным образом:
Код: (C)
typedef struct _name {
   PVOID       lp_mem1;
   PDWORD   lp_mem2;
} STRUCT_NAME;
для структур передаваемых из 64 битного драйвера - 32-битному приложению - В ДРАЙВЕРЕ надо объявить альтернативную версию (для того, чтобы при компиляции драйвера x64 компилятором, она была идентична по адресам полей исполняемой среды приложения - x32):
Код: (C)
typedef struct _name_x32 {
   DWORD    lp_mem1_x32;  // или используя тип VOID*POINTER_32
   DWORD    lp_mem2_x32;  //как предлагает нам Microsoft
} STRUCT_NAME_X32;
(а вот в приложении можно оставить первый вариант объявления, потому что он будет компилироваться 32битным компилятором. главное об этом помнить. STRUCT_NAME в скомпилированная 32 битном приложении, должна быть идентична по адрсации структуре STRUCT_NAME_X32)

при этом, в 64битном приложении:
sizeof(STRUCT_NAME)        == 16 byte!
sizeof(STRUCT_NAME_X32) == 8 byte!

а в 32 битном приложении:
sizeof(STRUCT_NAME)        == 8 byte!
sizeof(STRUCT_NAME_X32) == 8 byte!

в драйвере для 32битного приложения - поле "lp_mem1_x32" заполняете младшими 4 байтами от полученого 8 байтового  указателя. (кстати в DDK есть специальные макросы, типа PtrToUlong() и подобные. рекомендую использовать их.

теперь ссылка))))) жаль раньше не набрел.
Programming Issues for 64-Bit Drivers

PS msdn предлагает объявлять указатели для x32 не как "DWORD" а как "VOID*POINTER_32"... возможно это более правильный подход. жаль я на этот пример только сейчас набрел.
Technique 2: Using IoIs32bitProcess
Код: (C)
typedef struct _IOCTL_PARAMETERS
{
    PVOID   Addr;
    SIZE_T  Length;
    HANDLE  Handle;
} IOCTL_PARAMETERS, *PIOCTL_PARAMETERS;

typedef struct _IOCTL_PARAMETERS_32
{
    VOID*POINTER_32  Addr;
    INT32            Length;
    VOID*POINTER_32  Handle;
} IOCTL_PARAMETERS_32, *PIOCTL_PARAMETERS_32;

...

if (IoIs32bitProcess(Irp))
{ /* 32-bit process IOCTL */
  params32 = (PIOCTL_PARAMETERS_32)(Irp->AssociatedIrp.SystemBuffer);
  if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(IOCTL_PARAMETERS_32))
  {
    status = STATUS_INVALID_PARAMETER;
  }
  else
  {
    LocalParam.Addr = params32->Addr;
    LocalParam.Handle = params32->Handle;
    LocalParam.Length = params32->Length;
    /* Handle the IOCTL here */
    status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;
  }
}
else
{  /* 64-bit process IOCTL */
  params = (PIOCTL_PARAMETERS)(Irp->AssociatedIrp.SystemBuffer);
  if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(IOCTL_PARAMETERS))
  {
    status = STATUS_INVALID_PARAMETER;
  }
  else
  {
    RtlCopyMemory(&LocalParam,
                  params,
                  sizeof(IOCTL_PARAMETERS));
     /* Handle the ioctl here */
     status = STATUS_SUCCESS;
  }
  Irp->IoStatus.Information = 0;
}
« Последнее редактирование: 02-06-2012 20:11 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
sabbatazh
Помогающий

ua
Offline Offline

« Ответ #4 : 04-06-2012 17:21 » 

Ochkarik, Спасибо!!! БУду разбираться!
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 12-02-2013 12:15 » 

До кучи закину еще одну ссылку по поводу формирования кода IOCTL в x64 приложении/драйвере.
оказывается их надо тоже по разному объявлять дополнительным битом CLIENT_64BIT .... *а мужики то не знают!*
примерно вот так:
Код: (C)
#define REGISTER_FUNCTION 0     // Define the IOCTL function code

#ifdef  _WIN64
#define CLIENT_64BIT   0x800
#define REGISTER_FUNCTION 0
#define IOCTL_REGISTER   CTL_CODE(FILE_DEVICE_UNKNOWN, \
                                  CLIENT_64BIT | REGISTER_FUNCTION, \
                                  METHOD_BUFFERED, \
                                  FILE_ANY_ACCESS)

#else
#define IOCTL_REGISTER   CTL_CODE(FILE_DEVICE_UNKNOWN, \
                                  REGISTER_FUNCTION, \
                                  METHOD_BUFFERED, \
                                  FILE_ANY_ACCESS)

#endif
Technique 1: Defining a "64Bit" Field - определение IOCTL кодов для приложения скомпилированного для x64.
Extended Example: Defining a "64Bit" Field (Windows Drivers) - пример использования.
« Последнее редактирование: 13-02-2013 20:43 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
sabbatazh
Помогающий

ua
Offline Offline

« Ответ #6 : 14-02-2013 11:30 » 

Ochkarik, Спасибо!!! только эта статья появилась, раньше не встречал?!  Очень интересно...
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 14-02-2013 15:37 » new

sabbatazh, да я по вопросу из соседней ветки вспоминал что к чему - случайно наткнулся на раздел. раньше статья была, просто не обращал внимания. лично пока только 32битное приложение с x64 драйвером сопрягал. поэтому не интересовался подробно.
просто кинул в эту тему чтоб было в одном месте)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines