Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenldevobj.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS Win32k subsystem 00004 * PURPOSE: Support for logical devices 00005 * FILE: subsystems/win32/win32k/eng/ldevobj.c 00006 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org) 00007 */ 00008 00009 #include <win32k.h> 00010 #define NDEBUG 00011 #include <debug.h> 00012 00013 #ifndef RVA_TO_ADDR 00014 #define RVA_TO_ADDR(Base,Rva) ((PVOID)(((ULONG_PTR)(Base)) + (Rva))) 00015 #endif 00016 00019 HSEMAPHORE ghsemLDEVList; 00020 LDEVOBJ *gpldevHead = NULL; 00021 LDEVOBJ *gpldevWin32k = NULL; 00022 00023 00026 INIT_FUNCTION 00027 NTSTATUS 00028 NTAPI 00029 InitLDEVImpl() 00030 { 00031 ULONG cbSize; 00032 00033 /* Initialize the loader lock */ 00034 ghsemLDEVList = EngCreateSemaphore(); 00035 if (!ghsemLDEVList) 00036 { 00037 return STATUS_INSUFFICIENT_RESOURCES; 00038 } 00039 00040 /* Allocate a LDEVOBJ for win32k */ 00041 gpldevWin32k = ExAllocatePoolWithTag(PagedPool, 00042 sizeof(LDEVOBJ) + 00043 sizeof(SYSTEM_GDI_DRIVER_INFORMATION), 00044 GDITAG_LDEV); 00045 if (!gpldevWin32k) 00046 { 00047 return STATUS_NO_MEMORY; 00048 } 00049 00050 /* Initialize the LDEVOBJ for win32k */ 00051 gpldevWin32k->pldevNext = NULL; 00052 gpldevWin32k->pldevPrev = NULL; 00053 gpldevWin32k->ldevtype = LDEV_DEVICE_DISPLAY; 00054 gpldevWin32k->cRefs = 1; 00055 gpldevWin32k->ulDriverVersion = GDI_ENGINE_VERSION; 00056 gpldevWin32k->pGdiDriverInfo = (PVOID)(gpldevWin32k + 1); 00057 RtlInitUnicodeString(&gpldevWin32k->pGdiDriverInfo->DriverName, 00058 L"\\SystemRoot\\System32\\win32k.sys"); 00059 gpldevWin32k->pGdiDriverInfo->ImageAddress = &__ImageBase; 00060 gpldevWin32k->pGdiDriverInfo->SectionPointer = NULL; 00061 gpldevWin32k->pGdiDriverInfo->EntryPoint = (PVOID)DriverEntry; 00062 gpldevWin32k->pGdiDriverInfo->ExportSectionPointer = 00063 RtlImageDirectoryEntryToData(&__ImageBase, 00064 TRUE, 00065 IMAGE_DIRECTORY_ENTRY_EXPORT, 00066 &cbSize); 00067 gpldevWin32k->pGdiDriverInfo->ImageLength = 0; // FIXME 00068 00069 return STATUS_SUCCESS; 00070 } 00071 00072 PLDEVOBJ 00073 NTAPI 00074 LDEVOBJ_AllocLDEV(LDEVTYPE ldevtype) 00075 { 00076 PLDEVOBJ pldev; 00077 00078 /* Allocate the structure from paged pool */ 00079 pldev = ExAllocatePoolWithTag(PagedPool, sizeof(LDEVOBJ), GDITAG_LDEV); 00080 if (!pldev) 00081 { 00082 DPRINT1("Failed to allocate LDEVOBJ.\n"); 00083 return NULL; 00084 } 00085 00086 /* Zero out the structure */ 00087 RtlZeroMemory(pldev, sizeof(LDEVOBJ)); 00088 00089 /* Set the ldevtype */ 00090 pldev->ldevtype = ldevtype; 00091 00092 return pldev; 00093 } 00094 00095 VOID 00096 NTAPI 00097 LDEVOBJ_vFreeLDEV(PLDEVOBJ pldev) 00098 { 00099 /* Make sure we don't have a driver loaded */ 00100 ASSERT(pldev && pldev->pGdiDriverInfo == NULL); 00101 ASSERT(pldev->cRefs == 0); 00102 00103 /* Free the memory */ 00104 ExFreePoolWithTag(pldev, GDITAG_LDEV); 00105 } 00106 00107 PDEVMODEINFO 00108 NTAPI 00109 LDEVOBJ_pdmiGetModes( 00110 PLDEVOBJ pldev, 00111 HANDLE hDriver) 00112 { 00113 ULONG cbSize, cbFull; 00114 PDEVMODEINFO pdminfo; 00115 00116 DPRINT("LDEVOBJ_pdmiGetModes(%p, %p)\n", pldev, hDriver); 00117 00118 /* Call the driver to get the required size */ 00119 cbSize = pldev->pfn.GetModes(hDriver, 0, NULL); 00120 if (!cbSize) 00121 { 00122 DPRINT1("DrvGetModes returned 0\n"); 00123 return NULL; 00124 } 00125 00126 /* Add space for the header */ 00127 cbFull = cbSize + FIELD_OFFSET(DEVMODEINFO, adevmode); 00128 00129 /* Allocate a buffer for the DEVMODE array */ 00130 pdminfo = ExAllocatePoolWithTag(PagedPool, cbFull, GDITAG_DEVMODE); 00131 if (!pdminfo) 00132 { 00133 DPRINT1("Could not allocate devmodeinfo\n"); 00134 return NULL; 00135 } 00136 00137 pdminfo->pldev = pldev; 00138 pdminfo->cbdevmode = cbSize; 00139 00140 /* Call the driver again to fill the buffer */ 00141 cbSize = pldev->pfn.GetModes(hDriver, cbSize, pdminfo->adevmode); 00142 if (!cbSize) 00143 { 00144 /* Could not get modes */ 00145 DPRINT1("returned size %ld(%ld)\n", cbSize, pdminfo->cbdevmode); 00146 ExFreePoolWithTag(pdminfo, GDITAG_DEVMODE); 00147 pdminfo = NULL; 00148 } 00149 00150 return pdminfo; 00151 } 00152 00153 00154 BOOL 00155 NTAPI 00156 LDEVOBJ_bLoadImage( 00157 IN PLDEVOBJ pldev, 00158 PUNICODE_STRING pstrPathName) 00159 { 00160 PSYSTEM_GDI_DRIVER_INFORMATION pDriverInfo; 00161 NTSTATUS Status; 00162 ULONG cbSize; 00163 00164 /* Make sure no image is loaded yet */ 00165 ASSERT(pldev && pldev->pGdiDriverInfo == NULL); 00166 00167 /* Allocate a SYSTEM_GDI_DRIVER_INFORMATION structure */ 00168 cbSize = sizeof(SYSTEM_GDI_DRIVER_INFORMATION) + pstrPathName->Length; 00169 pDriverInfo = ExAllocatePoolWithTag(PagedPool, cbSize, GDITAG_LDEV); 00170 if (!pDriverInfo) 00171 { 00172 DPRINT1("Failed to allocate SYSTEM_GDI_DRIVER_INFORMATION\n"); 00173 return FALSE; 00174 } 00175 00176 /* Initialize the UNICODE_STRING and copy the driver name */ 00177 RtlInitEmptyUnicodeString(&pDriverInfo->DriverName, 00178 (PWSTR)(pDriverInfo + 1), 00179 pstrPathName->Length); 00180 RtlCopyUnicodeString(&pDriverInfo->DriverName, pstrPathName); 00181 00182 /* Try to load the driver */ 00183 Status = ZwSetSystemInformation(SystemLoadGdiDriverInformation, 00184 pDriverInfo, 00185 sizeof(SYSTEM_GDI_DRIVER_INFORMATION)); 00186 00187 if (!NT_SUCCESS(Status)) 00188 { 00189 DPRINT1("Failed to load a GDI driver: '%S', Status = 0x%lx\n", 00190 pstrPathName->Buffer, Status); 00191 00192 /* Free the allocated memory */ 00193 ExFreePoolWithTag(pDriverInfo, GDITAG_LDEV); 00194 return FALSE; 00195 } 00196 00197 /* Set the driver info */ 00198 pldev->pGdiDriverInfo = pDriverInfo; 00199 00200 /* Return success. */ 00201 return TRUE; 00202 } 00203 00204 VOID 00205 NTAPI 00206 LDEVOBJ_vUnloadImage( 00207 IN PLDEVOBJ pldev) 00208 { 00209 NTSTATUS Status; 00210 00211 /* Make sure we have a driver info */ 00212 ASSERT(pldev && pldev->pGdiDriverInfo != NULL); 00213 00214 /* Check if we have loaded a driver */ 00215 if (pldev->pfn.DisableDriver) 00216 { 00217 /* Call the unload function */ 00218 pldev->pfn.DisableDriver(); 00219 } 00220 00221 /* Unload the driver */ 00222 Status = ZwSetSystemInformation(SystemUnloadGdiDriverInformation, 00223 &pldev->pGdiDriverInfo->ImageAddress, 00224 sizeof(HANDLE)); 00225 if (!NT_SUCCESS(Status)) 00226 { 00227 DPRINT1("Failed to unload the driver, this is bad.\n"); 00228 } 00229 00230 /* Free the driver info structure */ 00231 ExFreePoolWithTag(pldev->pGdiDriverInfo, GDITAG_LDEV); 00232 pldev->pGdiDriverInfo = NULL; 00233 } 00234 00235 BOOL 00236 NTAPI 00237 LDEVOBJ_bLoadDriver( 00238 IN PLDEVOBJ pldev) 00239 { 00240 PFN_DrvEnableDriver pfnEnableDriver; 00241 DRVENABLEDATA ded; 00242 ULONG i; 00243 00244 /* Make sure we have a driver info */ 00245 ASSERT(pldev && pldev->pGdiDriverInfo != NULL); 00246 00247 /* Call the drivers DrvEnableDriver function */ 00248 RtlZeroMemory(&ded, sizeof(ded)); 00249 pfnEnableDriver = pldev->pGdiDriverInfo->EntryPoint; 00250 if (!pfnEnableDriver(GDI_ENGINE_VERSION, sizeof(ded), &ded)) 00251 { 00252 DPRINT1("DrvEnableDriver failed\n"); 00253 00254 /* Unload the image. */ 00255 LDEVOBJ_vUnloadImage(pldev); 00256 return FALSE; 00257 } 00258 00259 /* Copy the returned driver version */ 00260 pldev->ulDriverVersion = ded.iDriverVersion; 00261 00262 /* Fill the driver function array */ 00263 for (i = 0; i < ded.c; i++) 00264 { 00265 pldev->apfn[ded.pdrvfn[i].iFunc] = ded.pdrvfn[i].pfn; 00266 } 00267 00268 /* Return success. */ 00269 return TRUE; 00270 } 00271 00272 00273 PVOID 00274 NTAPI 00275 LDEVOBJ_pvFindImageProcAddress( 00276 IN PLDEVOBJ pldev, 00277 IN LPSTR pszProcName) 00278 { 00279 PVOID pvImageBase; 00280 PIMAGE_EXPORT_DIRECTORY pExportDir; 00281 PVOID pvProcAdress = NULL; 00282 PUSHORT pOrdinals; 00283 PULONG pNames, pAddresses; 00284 ULONG i; 00285 00286 /* Make sure we have a driver info */ 00287 ASSERT(pldev && pldev->pGdiDriverInfo != NULL); 00288 00289 /* Get the pointer to the export directory */ 00290 pvImageBase = pldev->pGdiDriverInfo->ImageAddress; 00291 pExportDir = pldev->pGdiDriverInfo->ExportSectionPointer; 00292 if (!pExportDir) 00293 { 00294 return NULL; 00295 } 00296 00297 /* Get pointers to some tables */ 00298 pNames = RVA_TO_ADDR(pvImageBase, pExportDir->AddressOfNames); 00299 pOrdinals = RVA_TO_ADDR(pvImageBase, pExportDir->AddressOfNameOrdinals); 00300 pAddresses = RVA_TO_ADDR(pvImageBase, pExportDir->AddressOfFunctions); 00301 00302 /* Loop the export table */ 00303 for (i = 0; i < pExportDir->NumberOfNames; i++) 00304 { 00305 /* Compare the name */ 00306 if (_stricmp(pszProcName, RVA_TO_ADDR(pvImageBase, pNames[i])) == 0) 00307 { 00308 /* Found! Calculate the procedure address */ 00309 pvProcAdress = RVA_TO_ADDR(pvImageBase, pAddresses[pOrdinals[i]]); 00310 break; 00311 } 00312 } 00313 00314 /* Return the address */ 00315 return pvProcAdress; 00316 } 00317 00318 PLDEVOBJ 00319 NTAPI 00320 EngLoadImageEx( 00321 LPWSTR pwszDriverName, 00322 ULONG ldevtype) 00323 { 00324 WCHAR acwBuffer[MAX_PATH]; 00325 PLDEVOBJ pldev; 00326 UNICODE_STRING strDriverName; 00327 ULONG cwcLength; 00328 LPWSTR pwsz; 00329 00330 DPRINT("EngLoadImageEx(%ls, %ld)\n", pwszDriverName, ldevtype); 00331 ASSERT(pwszDriverName); 00332 00333 /* Initialize buffer for the the driver name */ 00334 RtlInitEmptyUnicodeString(&strDriverName, acwBuffer, sizeof(acwBuffer)); 00335 00336 /* Start path with systemroot */ 00337 RtlAppendUnicodeToString(&strDriverName, L"\\SystemRoot\\System32\\"); 00338 00339 /* Get Length of given string */ 00340 cwcLength = wcslen(pwszDriverName); 00341 00342 /* Check if we have a system32 path given */ 00343 pwsz = pwszDriverName + cwcLength; 00344 while (pwsz > pwszDriverName) 00345 { 00346 if (_wcsnicmp(pwsz, L"\\system32\\", 10) == 0) 00347 { 00348 /* Driver name starts after system32 */ 00349 pwsz += 10; 00350 break; 00351 } 00352 pwsz--; 00353 } 00354 00355 /* Append the driver name */ 00356 RtlAppendUnicodeToString(&strDriverName, pwsz); 00357 00358 /* MSDN says "The driver must include this suffix in the pwszDriver string." 00359 But in fact it's optional. 00360 00361 ms win32k EngLoadImageEx loading .sys file without append .dll 00362 */ 00363 if ( (_wcsnicmp(pwszDriverName + cwcLength - 4, L".dll", 4) != 0) && 00364 (_wcsnicmp(pwszDriverName + cwcLength - 4, L".sys", 4) != 0) ) 00365 { 00366 /* Append the .dll suffix */ 00367 RtlAppendUnicodeToString(&strDriverName, L".dll"); 00368 } 00369 00370 /* Lock loader */ 00371 EngAcquireSemaphore(ghsemLDEVList); 00372 00373 /* Search the List of LDEVS for the driver name */ 00374 for (pldev = gpldevHead; pldev != NULL; pldev = pldev->pldevNext) 00375 { 00376 /* Check if the ldev is associated with a file */ 00377 if (pldev->pGdiDriverInfo) 00378 { 00379 /* Check for match (case insensative) */ 00380 if (RtlEqualUnicodeString(&pldev->pGdiDriverInfo->DriverName, &strDriverName, 1)) 00381 { 00382 /* Image found in LDEV list */ 00383 break; 00384 } 00385 } 00386 } 00387 00388 /* Did we find one? */ 00389 if (!pldev) 00390 { 00391 /* No, allocate a new LDEVOBJ */ 00392 pldev = LDEVOBJ_AllocLDEV(ldevtype); 00393 if (!pldev) 00394 { 00395 DPRINT1("Could not allocate LDEV\n"); 00396 goto leave; 00397 } 00398 00399 /* Load the image */ 00400 if (!LDEVOBJ_bLoadImage(pldev, &strDriverName)) 00401 { 00402 LDEVOBJ_vFreeLDEV(pldev); 00403 pldev = NULL; 00404 DPRINT1("LDEVOBJ_bLoadImage failed\n"); 00405 goto leave; 00406 } 00407 00408 /* Shall we load a driver? */ 00409 if (ldevtype != LDEV_IMAGE) 00410 { 00411 /* Load the driver */ 00412 if (!LDEVOBJ_bLoadDriver(pldev)) 00413 { 00414 DPRINT1("LDEVOBJ_bLoadDriver failed\n"); 00415 LDEVOBJ_vFreeLDEV(pldev); 00416 pldev = NULL; 00417 goto leave; 00418 } 00419 } 00420 00421 /* Insert the LDEV into the global list */ 00422 pldev->pldevPrev = NULL; 00423 pldev->pldevNext = gpldevHead; 00424 gpldevHead = pldev; 00425 } 00426 00427 /* Increase ref count */ 00428 pldev->cRefs++; 00429 00430 leave: 00431 /* Unlock loader */ 00432 EngReleaseSemaphore(ghsemLDEVList); 00433 00434 DPRINT("EngLoadImageEx returning %p\n", pldev); 00435 00436 return pldev; 00437 } 00438 00439 00442 HANDLE 00443 APIENTRY 00444 EngLoadImage( 00445 LPWSTR pwszDriverName) 00446 { 00447 return (HANDLE)EngLoadImageEx(pwszDriverName, LDEV_IMAGE); 00448 } 00449 00450 00451 VOID 00452 APIENTRY 00453 EngUnloadImage( 00454 IN HANDLE hModule) 00455 { 00456 PLDEVOBJ pldev = (PLDEVOBJ)hModule; 00457 00458 /* Make sure the LDEV is in the list */ 00459 ASSERT(pldev->pldevPrev || pldev->pldevNext); 00460 00461 /* Lock loader */ 00462 EngAcquireSemaphore(ghsemLDEVList); 00463 00464 /* Decrement reference count */ 00465 pldev->cRefs--; 00466 00467 /* No more references left? */ 00468 if (pldev->cRefs == 0) 00469 { 00470 /* Remove ldev from the list */ 00471 if (pldev->pldevPrev) 00472 pldev->pldevPrev->pldevNext = pldev->pldevNext; 00473 if (pldev->pldevNext) 00474 pldev->pldevNext->pldevPrev = pldev->pldevPrev; 00475 00476 /* Unload the image and free the LDEV */ 00477 LDEVOBJ_vUnloadImage(pldev); 00478 LDEVOBJ_vFreeLDEV(pldev); 00479 } 00480 00481 /* Unlock loader */ 00482 EngReleaseSemaphore(ghsemLDEVList); 00483 } 00484 00485 00486 PVOID 00487 APIENTRY 00488 EngFindImageProcAddress( 00489 IN HANDLE hModule, 00490 IN LPSTR lpProcName) 00491 { 00492 PLDEVOBJ pldev = (PLDEVOBJ)hModule; 00493 00494 ASSERT(gpldevWin32k != NULL); 00495 00496 /* Check if win32k is requested */ 00497 if (!pldev) 00498 { 00499 pldev = gpldevWin32k; 00500 } 00501 00502 /* Check if the drivers entry point is requested */ 00503 if (_strnicmp(lpProcName, "DrvEnableDriver", 15) == 0) 00504 { 00505 return pldev->pGdiDriverInfo->EntryPoint; 00506 } 00507 00508 /* Try to find the address */ 00509 return LDEVOBJ_pvFindImageProcAddress(pldev, lpProcName); 00510 } 00511 00512 /* EOF */ Generated on Sat May 26 2012 04:37:08 for ReactOS by
1.7.6.1
|