Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

775 lines
22 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. translate.c
  5. Abstract:
  6. This file implements translator interfaces for busses
  7. enumerated by ACPI.
  8. The actual translation information about this bus is
  9. gotten from the _CRS associated with the bus. We put
  10. the data into an IO_RESOURCE_REQUIREMENTS_LIST as
  11. device private data of the following form:
  12. DevicePrivate.Data[0]: child's CM_RESOURCE_TYPE
  13. DevicePrivate.Data[1]: child's start address [31:0]
  14. DevicePrivate.Data[2]: child's start address [63:32]
  15. The descriptor that describes child-side translation
  16. immediately follows the one that describes the
  17. parent-side resources.
  18. The Flags field of the IO_RESOURCE_REQUIREMENTS_LIST may have the
  19. TRANSLATION_RANGE_SPARSE bit set.
  20. Author:
  21. Jake Oshins 7-Nov-97
  22. Environment:
  23. NT Kernel Model Driver only
  24. --*/
  25. #include "pch.h"
  26. NTSTATUS
  27. FindTranslationRange(
  28. IN PHYSICAL_ADDRESS Start,
  29. IN LONGLONG Length,
  30. IN PBRIDGE_TRANSLATOR Translator,
  31. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  32. IN UCHAR ResType,
  33. OUT PBRIDGE_WINDOW *Window
  34. );
  35. NTSTATUS
  36. TranslateBridgeResources(
  37. IN PVOID Context,
  38. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  39. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  40. IN ULONG AlternativesCount, OPTIONAL
  41. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  42. IN PDEVICE_OBJECT PhysicalDeviceObject,
  43. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  44. );
  45. NTSTATUS
  46. TranslateBridgeRequirements(
  47. IN PVOID Context,
  48. IN PIO_RESOURCE_DESCRIPTOR Source,
  49. IN PDEVICE_OBJECT PhysicalDeviceObject,
  50. OUT PULONG TargetCount,
  51. OUT PIO_RESOURCE_DESCRIPTOR *Target
  52. );
  53. NTSTATUS
  54. BuildTranslatorRanges(
  55. IN PBRIDGE_TRANSLATOR Translator,
  56. OUT ULONG *BridgeWindowCount,
  57. OUT PBRIDGE_WINDOW *Window
  58. );
  59. #define MAX(a, b) \
  60. ((a) > (b) ? (a) : (b))
  61. #define MIN(a, b) \
  62. ((a) < (b) ? (a) : (b))
  63. HAL_PORT_RANGE_INTERFACE HalPortRangeInterface;
  64. #ifdef ALLOC_PRAGMA
  65. #pragma alloc_text(PAGE, TranslateEjectInterface)
  66. #pragma alloc_text(PAGE, TranslateBridgeResources)
  67. #pragma alloc_text(PAGE, TranslateBridgeRequirements)
  68. #pragma alloc_text(PAGE, FindTranslationRange)
  69. #pragma alloc_text(PAGE, AcpiNullReference)
  70. #pragma alloc_text(PAGE, BuildTranslatorRanges)
  71. #endif
  72. NTSTATUS
  73. TranslateEjectInterface(
  74. PDEVICE_OBJECT DeviceObject,
  75. PIRP Irp
  76. )
  77. {
  78. PIO_RESOURCE_REQUIREMENTS_LIST ioList = NULL;
  79. PIO_RESOURCE_DESCRIPTOR transDesc;
  80. PIO_RESOURCE_DESCRIPTOR parentDesc;
  81. PTRANSLATOR_INTERFACE transInterface;
  82. PBRIDGE_TRANSLATOR bridgeTrans = NULL;
  83. PIO_STACK_LOCATION irpSp;
  84. PDEVICE_EXTENSION devExtension;
  85. BOOLEAN foundTranslations = FALSE;
  86. NTSTATUS status;
  87. PUCHAR crsBuf = NULL;
  88. ULONG descCount;
  89. ULONG parentResType;
  90. ULONG childResType;
  91. ULONG crsBufSize;
  92. PHYSICAL_ADDRESS parentStart;
  93. PHYSICAL_ADDRESS childStart;
  94. PAGED_CODE();
  95. devExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  96. ASSERT(devExtension);
  97. ASSERT(devExtension->AcpiObject);
  98. irpSp = IoGetCurrentIrpStackLocation(Irp);
  99. ASSERT(irpSp->Parameters.QueryInterface.Size >= sizeof(TRANSLATOR_INTERFACE));
  100. transInterface = (PTRANSLATOR_INTERFACE)irpSp->Parameters.QueryInterface.Interface;
  101. ASSERT(transInterface);
  102. //
  103. // Get the resources for this bus.
  104. //
  105. status = ACPIGetBufferSync(
  106. devExtension,
  107. PACKED_CRS,
  108. &crsBuf,
  109. &crsBufSize
  110. );
  111. if (!NT_SUCCESS(status)) {
  112. //
  113. // This bus has no _CRS. So it doesn't need a translator.
  114. //
  115. status = Irp->IoStatus.Status;
  116. goto TranslateEjectInterfaceExit;
  117. }
  118. //
  119. // Turn it into something meaningful.
  120. //
  121. status = PnpBiosResourcesToNtResources(
  122. crsBuf,
  123. PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES,
  124. &ioList
  125. );
  126. if (!NT_SUCCESS(status)) {
  127. goto TranslateEjectInterfaceExit;
  128. }
  129. //
  130. // This was a leagal _CRS but it contained no resources that are useful to the OS.
  131. //
  132. if (!ioList) {
  133. status = Irp->IoStatus.Status;
  134. goto TranslateEjectInterfaceExit;
  135. }
  136. //
  137. // Cycle through the descriptors looking for device private data
  138. // that contains translation information.
  139. //
  140. for (descCount = 0; descCount < ioList->List[0].Count; descCount++) {
  141. transDesc = &ioList->List[0].Descriptors[descCount];
  142. if (transDesc->Type == CmResourceTypeDevicePrivate) {
  143. //
  144. // Translation information is contained in
  145. // a device private resource that has
  146. // TRANSLATION_DATA_PARENT_ADDRESS in the
  147. // flags field.
  148. //
  149. if (transDesc->Flags & TRANSLATION_DATA_PARENT_ADDRESS) {
  150. // The first descriptor cannot be a translation descriptor
  151. ASSERT(descCount != 0);
  152. //
  153. // The translation descriptor should follow the descriptor
  154. // that it is trying to modify. The first, normal,
  155. // descriptor is for the child-relative resources. The
  156. // second, device private, descriptor is modifies the
  157. // child-relative resources to generate the parent-relative
  158. // resources.
  159. //
  160. parentResType = transDesc->u.DevicePrivate.Data[0];
  161. parentStart.LowPart = transDesc->u.DevicePrivate.Data[1];
  162. parentStart.HighPart = transDesc->u.DevicePrivate.Data[2];
  163. childResType = ioList->List[0].Descriptors[descCount - 1].Type;
  164. childStart.QuadPart = (transDesc - 1)->u.Generic.MinimumAddress.QuadPart;
  165. if ((parentResType != childResType) ||
  166. (parentStart.QuadPart != childStart.QuadPart)) {
  167. foundTranslations = TRUE;
  168. break;
  169. }
  170. }
  171. }
  172. }
  173. if (!foundTranslations) {
  174. //
  175. // Didn't find any translation information for this bus.
  176. //
  177. status = Irp->IoStatus.Status;
  178. goto TranslateEjectInterfaceExit;
  179. }
  180. //
  181. // Build a translator interface.
  182. //
  183. bridgeTrans = ExAllocatePoolWithTag(
  184. PagedPool,
  185. sizeof (BRIDGE_TRANSLATOR),
  186. ACPI_TRANSLATE_POOLTAG
  187. );
  188. if (!bridgeTrans) {
  189. status = STATUS_INSUFFICIENT_RESOURCES;
  190. goto TranslateEjectInterfaceExit;
  191. }
  192. bridgeTrans->AcpiObject = devExtension->AcpiObject;
  193. bridgeTrans->IoList = ioList;
  194. //
  195. // Build the array of bridge windows.
  196. //
  197. status = BuildTranslatorRanges(
  198. bridgeTrans,
  199. &bridgeTrans->RangeCount,
  200. &bridgeTrans->Ranges
  201. );
  202. if (!NT_SUCCESS(status)) {
  203. goto TranslateEjectInterfaceExit;
  204. }
  205. transInterface->Size = sizeof(TRANSLATOR_INTERFACE);
  206. transInterface->Version = 1;
  207. transInterface->Context = (PVOID)bridgeTrans;
  208. transInterface->InterfaceReference = AcpiNullReference;
  209. transInterface->InterfaceDereference = AcpiNullReference;
  210. transInterface->TranslateResources = TranslateBridgeResources;
  211. transInterface->TranslateResourceRequirements = TranslateBridgeRequirements;
  212. status = STATUS_SUCCESS;
  213. TranslateEjectInterfaceExit:
  214. if (!NT_SUCCESS(status) && bridgeTrans){
  215. ExFreePool(bridgeTrans);
  216. }
  217. if(crsBuf){
  218. ExFreePool(crsBuf);
  219. }
  220. if(ioList){
  221. ExFreePool(ioList);
  222. }
  223. return status;
  224. }
  225. NTSTATUS
  226. FindTranslationRange(
  227. IN PHYSICAL_ADDRESS Start,
  228. IN LONGLONG Length,
  229. IN PBRIDGE_TRANSLATOR Translator,
  230. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  231. IN UCHAR ResType,
  232. OUT PBRIDGE_WINDOW *Window
  233. )
  234. {
  235. LONGLONG beginning, end;
  236. ULONG i;
  237. UCHAR rangeType;
  238. PAGED_CODE();
  239. for (i = 0; i < Translator->RangeCount; i++) {
  240. if (Direction == TranslateParentToChild) {
  241. beginning = Translator->Ranges[i].ParentAddress.QuadPart;
  242. rangeType = Translator->Ranges[i].ParentType;
  243. } else {
  244. beginning = Translator->Ranges[i].ChildAddress.QuadPart;
  245. rangeType = Translator->Ranges[i].ChildType;
  246. }
  247. end = beginning + Translator->Ranges[i].Length;
  248. if ((rangeType == ResType) &&
  249. (!((Start.QuadPart < beginning) ||
  250. (Start.QuadPart + Length > end)))) {
  251. //
  252. // The range lies within this bridge window
  253. // and the resource types match.
  254. //
  255. *Window = &Translator->Ranges[i];
  256. return STATUS_SUCCESS;
  257. }
  258. }
  259. return STATUS_NOT_FOUND;
  260. }
  261. NTSTATUS
  262. TranslateBridgeResources(
  263. IN PVOID Context,
  264. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  265. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  266. IN ULONG AlternativesCount, OPTIONAL
  267. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  268. IN PDEVICE_OBJECT PhysicalDeviceObject,
  269. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  270. )
  271. /*++
  272. Routine Description:
  273. This function takes a set of resources that are
  274. passed through a bridge and does any translation
  275. that is necessary when changing from a parent-
  276. relative viewpoint to a child-relative one or
  277. back again.
  278. In this function, we have the notion of a "window,"
  279. which is an aperature within the bridge. Bridges
  280. often have multiple windows, each with distinct
  281. translations.
  282. This function should never fail, as any resource
  283. range that will fail translation should have already
  284. been stripped out by TranslateBridgeRequirements.
  285. Arguments:
  286. Context - pointer to the translation data
  287. Source - resource list to be translated
  288. Direction - TranslateChildToParent or
  289. TranslateParentToChild
  290. AlternativesCount - not used
  291. Alternatives - not used
  292. PhysicalDeviceObject - not used
  293. Target - translated resource list
  294. Return Value:
  295. Status
  296. --*/
  297. {
  298. PBRIDGE_TRANSLATOR translator;
  299. PBRIDGE_WINDOW window;
  300. NTSTATUS status;
  301. PAGED_CODE();
  302. ASSERT(Context);
  303. ASSERT((Source->Type == CmResourceTypePort) ||
  304. (Source->Type == CmResourceTypeMemory));
  305. translator = (PBRIDGE_TRANSLATOR)Context;
  306. ASSERT(translator->RangeCount > 0);
  307. //
  308. // Find the window that this translation occurs
  309. // within.
  310. //
  311. status = FindTranslationRange(Source->u.Generic.Start,
  312. Source->u.Generic.Length,
  313. translator,
  314. Direction,
  315. Source->Type,
  316. &window);
  317. if (!NT_SUCCESS(status)) {
  318. //
  319. // We should never get here. This fucntion
  320. // should only be called for ranges that
  321. // are valid. TranslateBridgeRequirements should
  322. // weed out all the invalid ranges.
  323. return status;
  324. }
  325. //
  326. // Copy everything
  327. //
  328. *Target = *Source;
  329. switch (Direction) {
  330. case TranslateChildToParent:
  331. //
  332. // Target inherits the parent's resource type.
  333. //
  334. Target->Type = window->ParentType;
  335. //
  336. // Calculate the target's parent-relative start
  337. // address.
  338. //
  339. Target->u.Generic.Start.QuadPart =
  340. Source->u.Generic.Start.QuadPart +
  341. window->ParentAddress.QuadPart -
  342. window->ChildAddress.QuadPart;
  343. //
  344. // Make sure the length is still in bounds.
  345. //
  346. ASSERT(Target->u.Generic.Length <= (ULONG)(window->Length -
  347. (Target->u.Generic.Start.QuadPart -
  348. window->ParentAddress.QuadPart)));
  349. status = STATUS_TRANSLATION_COMPLETE;
  350. break;
  351. case TranslateParentToChild:
  352. //
  353. // Target inherits the child's resource type.
  354. //
  355. Target->Type = window->ChildType;
  356. //
  357. // Calculate the target's child-relative start
  358. // address.
  359. //
  360. Target->u.Generic.Start.QuadPart =
  361. Source->u.Generic.Start.QuadPart +
  362. window->ChildAddress.QuadPart -
  363. window->ParentAddress.QuadPart;
  364. //
  365. // Make sure the length is still in bounds.
  366. //
  367. ASSERT(Target->u.Generic.Length <= (ULONG)(window->Length -
  368. (Target->u.Generic.Start.QuadPart -
  369. window->ChildAddress.QuadPart)));
  370. status = STATUS_SUCCESS;
  371. break;
  372. default:
  373. status = STATUS_INVALID_PARAMETER;
  374. }
  375. #if 0
  376. if (Target->Type == CmResourceTypePort) {
  377. DbgPrint("XXX: %s[%d]=0x%I64x -> %s[%d]=0x%I64x\n",
  378. (Direction == TranslateChildToParent) ? "child" : "parent",
  379. Source->Type,
  380. Source->u.Generic.Start.QuadPart,
  381. (Direction == TranslateChildToParent) ? "parent" : "child",
  382. Target->Type,
  383. Target->u.Generic.Start.QuadPart);
  384. }
  385. #endif
  386. return status;
  387. }
  388. NTSTATUS
  389. TranslateBridgeRequirements(
  390. IN PVOID Context,
  391. IN PIO_RESOURCE_DESCRIPTOR Source,
  392. IN PDEVICE_OBJECT PhysicalDeviceObject,
  393. OUT PULONG TargetCount,
  394. OUT PIO_RESOURCE_DESCRIPTOR *Target
  395. )
  396. /*++
  397. Routine Description:
  398. This function takes a resource requirements list for
  399. resources on the child side of the bridge and
  400. translates them into resource requirements on the
  401. parent side of the bridge. This may involve clipping
  402. and there may be multiple target ranges.
  403. Arguments:
  404. Context - pointer to the translation data
  405. Source - resource list to be translated
  406. PhysicalDeviceObject - not used
  407. TargetCount - number of resources in the target list
  408. Target - translated resource requirements list
  409. Return Value:
  410. Status
  411. --*/
  412. {
  413. PBRIDGE_TRANSLATOR translator;
  414. PBRIDGE_WINDOW window;
  415. NTSTATUS status;
  416. LONGLONG rangeStart, rangeEnd, windowStart, windowEnd;
  417. ULONG i;
  418. PAGED_CODE();
  419. ASSERT(Context);
  420. ASSERT((Source->Type == CmResourceTypePort) ||
  421. (Source->Type == CmResourceTypeMemory));
  422. translator = (PBRIDGE_TRANSLATOR)Context;
  423. //
  424. // Allocate memory for the target range.
  425. //
  426. *Target = ExAllocatePoolWithTag(PagedPool,
  427. sizeof(IO_RESOURCE_DESCRIPTOR),
  428. ACPI_RESOURCE_POOLTAG);
  429. if (!*Target) {
  430. status = STATUS_INSUFFICIENT_RESOURCES;
  431. goto cleanup;
  432. }
  433. //
  434. // Look at all the aperatures in the bridge to see which
  435. // ones of them could possibly provide translations for
  436. // this resource.
  437. //
  438. rangeStart = Source->u.Generic.MinimumAddress.QuadPart;
  439. rangeEnd = Source->u.Generic.MaximumAddress.QuadPart;
  440. for (i = 0; i < translator->RangeCount; i++) {
  441. window = &translator->Ranges[i];
  442. if (window->ChildType != Source->Type) {
  443. //
  444. // This window describes the wrong
  445. // type of resource.
  446. //
  447. continue;
  448. }
  449. if (Source->u.Generic.Length > window->Length) {
  450. //
  451. // This resource won't fit in this aperature.
  452. //
  453. continue;
  454. }
  455. windowStart = window->ChildAddress.QuadPart;
  456. windowEnd = window->ChildAddress.QuadPart + (LONGLONG)window->Length;
  457. if (!(((rangeStart < windowStart) && (rangeEnd < windowStart)) ||
  458. ((rangeStart > windowEnd) && (rangeEnd > windowEnd)))) {
  459. //
  460. // The range and the window do intersect. So create
  461. // a resource that clips the range to the window.
  462. //
  463. **Target = *Source;
  464. *TargetCount = 1;
  465. (*Target)->Type = window->ParentType;
  466. (*Target)->u.Generic.MinimumAddress.QuadPart =
  467. rangeStart + (window->ParentAddress.QuadPart - windowStart);
  468. (*Target)->u.Generic.MaximumAddress.QuadPart =
  469. rangeEnd + (window->ParentAddress.QuadPart - windowStart);
  470. break;
  471. }
  472. }
  473. if (i < translator->RangeCount) {
  474. return STATUS_TRANSLATION_COMPLETE;
  475. } else {
  476. *TargetCount = 0;
  477. status = STATUS_PNP_TRANSLATION_FAILED;
  478. }
  479. cleanup:
  480. if (*Target) {
  481. ExFreePool(*Target);
  482. }
  483. return status;
  484. }
  485. NTSTATUS
  486. BuildTranslatorRanges(
  487. IN PBRIDGE_TRANSLATOR Translator,
  488. OUT ULONG *BridgeWindowCount,
  489. OUT PBRIDGE_WINDOW *Window
  490. )
  491. {
  492. PIO_RESOURCE_REQUIREMENTS_LIST ioList;
  493. PIO_RESOURCE_DESCRIPTOR transDesc, resDesc;
  494. ULONG descCount, windowCount, maxWindows;
  495. PAGED_CODE();
  496. ioList = Translator->IoList;
  497. //
  498. // Make an array of windows for holding the translation information.
  499. //
  500. maxWindows = ioList->List[0].Count / 2;
  501. *Window = ExAllocatePoolWithTag(PagedPool,
  502. maxWindows * sizeof(BRIDGE_WINDOW),
  503. ACPI_TRANSLATE_POOLTAG);
  504. if (!*Window) {
  505. return STATUS_INSUFFICIENT_RESOURCES;
  506. }
  507. //
  508. // Fill in the array with translations.
  509. //
  510. windowCount = 0;
  511. for (descCount = 0; descCount < ioList->List[0].Count; descCount++) {
  512. transDesc = &ioList->List[0].Descriptors[descCount];
  513. if (transDesc->Type == CmResourceTypeDevicePrivate) {
  514. //
  515. // Translation information is contained in
  516. // a device private resource that has
  517. // TRANSLATION_DATA_PARENT_ADDRESS in the
  518. // flags field.
  519. //
  520. if (transDesc->Flags & TRANSLATION_DATA_PARENT_ADDRESS) {
  521. ASSERT(windowCount <= maxWindows);
  522. //
  523. // The translation descriptor is supposed to follow
  524. // the resource that it is providing information about.
  525. //
  526. resDesc = &ioList->List[0].Descriptors[descCount - 1];
  527. (*Window)[windowCount].ParentType =
  528. (UCHAR)transDesc->u.DevicePrivate.Data[0];
  529. (*Window)[windowCount].ChildType = resDesc->Type;
  530. (*Window)[windowCount].ParentAddress.LowPart =
  531. transDesc->u.DevicePrivate.Data[1];
  532. (*Window)[windowCount].ParentAddress.HighPart =
  533. transDesc->u.DevicePrivate.Data[2];
  534. (*Window)[windowCount].ChildAddress.QuadPart =
  535. resDesc->u.Generic.MinimumAddress.QuadPart;
  536. (*Window)[windowCount].Length =
  537. resDesc->u.Generic.Length;
  538. //
  539. // If the HAL has provided underlying sparse port translation
  540. // services, allow for that.
  541. //
  542. if ((HalPortRangeInterface.QueryAllocateRange != NULL) &&
  543. (resDesc->Type == CmResourceTypePort)) {
  544. USHORT rangeId;
  545. UCHAR parentType = (UCHAR)transDesc->u.DevicePrivate.Data[0];
  546. BOOLEAN isSparse = transDesc->Flags & TRANSLATION_RANGE_SPARSE;
  547. ULONG parentLength = resDesc->u.Generic.Length;
  548. PHYSICAL_ADDRESS parentAddress;
  549. NTSTATUS status;
  550. PHYSICAL_ADDRESS rangeZeroBase;
  551. parentAddress.LowPart = transDesc->u.DevicePrivate.Data[1];
  552. parentAddress.HighPart = transDesc->u.DevicePrivate.Data[2];
  553. rangeZeroBase.QuadPart = parentAddress.QuadPart - resDesc->u.Generic.MinimumAddress.QuadPart;
  554. if (isSparse) {
  555. parentLength = (parentLength + resDesc->u.Generic.MinimumAddress.LowPart) << 10;
  556. }
  557. status = HalPortRangeInterface.QueryAllocateRange(
  558. isSparse,
  559. parentType == CmResourceTypeMemory,
  560. NULL,
  561. rangeZeroBase,
  562. parentLength,
  563. &rangeId
  564. );
  565. if (NT_SUCCESS(status)) {
  566. (*Window)[windowCount].ParentType = CmResourceTypePort;
  567. (*Window)[windowCount].ParentAddress.QuadPart =
  568. ((ULONGLONG)rangeId << 16) |
  569. ((*Window)[windowCount].ChildAddress.QuadPart & 0xffff);
  570. }
  571. }
  572. windowCount++;
  573. }
  574. }
  575. }
  576. *BridgeWindowCount = windowCount;
  577. return STATUS_SUCCESS;
  578. }