oprgn.c 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. oprgn.c
  5. Abstract:
  6. This module implements support for ACPI Operation Regions.
  7. Author:
  8. Evan Green 17-Nov-2012
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/driver.h>
  16. #include "acpiobj.h"
  17. #include "amlos.h"
  18. #include "namespce.h"
  19. #include "oprgn.h"
  20. #include "fixedreg.h"
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // ------------------------------------------------------ Data Type Definitions
  26. //
  27. //
  28. // ----------------------------------------------- Internal Function Prototypes
  29. //
  30. VOID
  31. AcpipShiftBufferIntoFieldPosition (
  32. PVOID Buffer,
  33. ULONGLONG BitOffset,
  34. ULONGLONG BitLength,
  35. ULONG AccessSize
  36. );
  37. VOID
  38. AcpipWriteFieldBitsIntoBuffer (
  39. PVOID FieldBuffer,
  40. ULONGLONG BitOffset,
  41. ULONGLONG BitLength,
  42. ULONG AccessSize,
  43. PVOID ResultBuffer,
  44. ULONGLONG ResultBufferSize
  45. );
  46. //
  47. // -------------------------------------------------------------------- Globals
  48. //
  49. //
  50. // ------------------------------------------------------------------ Functions
  51. //
  52. KSTATUS
  53. AcpipCreateOperationRegion (
  54. PAML_EXECUTION_CONTEXT Context,
  55. PSTR Name,
  56. ACPI_OPERATION_REGION_SPACE Space,
  57. ULONGLONG Offset,
  58. ULONGLONG Length
  59. )
  60. /*++
  61. Routine Description:
  62. This routine creates an ACPI Operation Region object.
  63. Arguments:
  64. Context - Supplies a pointer to the AML execution context.
  65. Name - Supplies a pointer to the name of the Operation Region object.
  66. Space - Supplies the address space type of the region.
  67. Offset - Supplies the byte offset into the address space of the beginning
  68. of the Operation Region.
  69. Length - Supplies the byte length of the Operation Region.
  70. Return Value:
  71. Status code.
  72. --*/
  73. {
  74. PACPI_OPERATION_REGION_FUNCTION_TABLE FunctionTable;
  75. PACPI_OBJECT Object;
  76. PVOID OsContext;
  77. PVOID OsMutex;
  78. KSTATUS Status;
  79. FunctionTable = NULL;
  80. Object = NULL;
  81. OsContext = NULL;
  82. OsMutex = NULL;
  83. //
  84. // Get a pointer to the operation region function table.
  85. //
  86. if (Space >= OperationRegionCount) {
  87. Status = STATUS_INVALID_PARAMETER;
  88. goto CreateOperationRegionEnd;
  89. }
  90. //
  91. // Create the namespace object.
  92. //
  93. Object = AcpipCreateNamespaceObject(Context,
  94. AcpiObjectOperationRegion,
  95. Name,
  96. NULL,
  97. 0);
  98. if (Object == NULL) {
  99. Status = STATUS_UNSUCCESSFUL;
  100. goto CreateOperationRegionEnd;
  101. }
  102. AcpipObjectReleaseReference(Object);
  103. //
  104. // Create the mutex.
  105. //
  106. OsMutex = AcpipCreateMutex(0);
  107. if (OsMutex == NULL) {
  108. Status = STATUS_UNSUCCESSFUL;
  109. goto CreateOperationRegionEnd;
  110. }
  111. FunctionTable = AcpiOperationRegionFunctionTable[Space];
  112. //
  113. // Create the operation region with the OS.
  114. //
  115. Status = FunctionTable->Create(Object, Offset, Length, &OsContext);
  116. if (!KSUCCESS(Status)) {
  117. goto CreateOperationRegionEnd;
  118. }
  119. //
  120. // Initialize and return the operation region.
  121. //
  122. Object->U.OperationRegion.Space = Space;
  123. Object->U.OperationRegion.OsContext = OsContext;
  124. Object->U.OperationRegion.Offset = Offset;
  125. Object->U.OperationRegion.Length = Length;
  126. Object->U.OperationRegion.FunctionTable = FunctionTable;
  127. Object->U.OperationRegion.OsMutex = OsMutex;
  128. Status = STATUS_SUCCESS;
  129. CreateOperationRegionEnd:
  130. if (!KSUCCESS(Status)) {
  131. //
  132. // Destroy the operation region if created.
  133. //
  134. if (OsContext != NULL) {
  135. FunctionTable->Destroy(OsContext);
  136. }
  137. //
  138. // Destroy the mutex.
  139. //
  140. if (OsMutex != NULL) {
  141. AcpipDestroyMutex(OsMutex);
  142. }
  143. if (Object != NULL) {
  144. AcpipObjectReleaseReference(Object);
  145. }
  146. }
  147. return Status;
  148. }
  149. VOID
  150. AcpipDestroyOperationRegion (
  151. PACPI_OBJECT Object
  152. )
  153. /*++
  154. Routine Description:
  155. This routine destroys an ACPI Operation Region object. This routine should
  156. not be called directly, but will be called from the namespace object
  157. destruction routine.
  158. Arguments:
  159. Object - Supplies a pointer to the operation region to destroy.
  160. Return Value:
  161. None.
  162. --*/
  163. {
  164. PACPI_OPERATION_REGION_FUNCTION_TABLE FunctionTable;
  165. ASSERT(Object->Type == AcpiObjectOperationRegion);
  166. if (Object->U.OperationRegion.OsContext != NULL) {
  167. FunctionTable = Object->U.OperationRegion.FunctionTable;
  168. ASSERT(FunctionTable != NULL);
  169. FunctionTable->Destroy(Object->U.OperationRegion.OsContext);
  170. Object->U.OperationRegion.OsContext = NULL;
  171. }
  172. if (Object->U.OperationRegion.OsMutex != NULL) {
  173. AcpipDestroyMutex(Object->U.OperationRegion.OsMutex);
  174. Object->U.OperationRegion.OsMutex = NULL;
  175. }
  176. Object->U.OperationRegion.FunctionTable = NULL;
  177. return;
  178. }
  179. KSTATUS
  180. AcpipReadFromField (
  181. PAML_EXECUTION_CONTEXT Context,
  182. PACPI_OBJECT FieldObject,
  183. PACPI_OBJECT *ResultObject
  184. )
  185. /*++
  186. Routine Description:
  187. This routine reads from an Operation Region field.
  188. Arguments:
  189. Context - Supplies a pointer to the AML execution context.
  190. FieldObject - Supplies a pointer to the field object to read from.
  191. ResultObject - Supplies a pointer where a pointer to the result object will
  192. be returned. The caller is responsible for freeing this memory.
  193. Return Value:
  194. STATUS_SUCCESS on success.
  195. Error codes on failure.
  196. --*/
  197. {
  198. ULONG AccessSize;
  199. PACPI_OBJECT AlternateOperationRegion;
  200. BOOL AlternateOperationRegionMutexAcquired;
  201. PACPI_OBJECT BankRegister;
  202. ULONGLONG BufferSize;
  203. PUCHAR CurrentBuffer;
  204. ULONGLONG CurrentOffset;
  205. PACPI_OBJECT DataRegister;
  206. PACPI_OBJECT DataResult;
  207. ULONGLONG EndBitOffset;
  208. ULONGLONG EndByteOffset;
  209. PACPI_FIELD_UNIT_OBJECT FieldUnit;
  210. BOOL GlobalLockAcquired;
  211. PACPI_OBJECT IndexRegister;
  212. PACPI_OBJECT IndexValue;
  213. BOOL IntegerWidthIs32;
  214. PACPI_OPERATION_REGION_OBJECT OperationRegion;
  215. BOOL OperationRegionMutexHeld;
  216. PACPI_OBJECT OperationRegionObject;
  217. PACPI_OBJECT Result;
  218. PUCHAR ResultBuffer;
  219. ULONGLONG StartBitOffset;
  220. ULONGLONG StartByteOffset;
  221. KSTATUS Status;
  222. *ResultObject = NULL;
  223. AlternateOperationRegion = NULL;
  224. AlternateOperationRegionMutexAcquired = FALSE;
  225. BankRegister = NULL;
  226. GlobalLockAcquired = FALSE;
  227. IndexValue = NULL;
  228. OperationRegion = NULL;
  229. OperationRegionMutexHeld = FALSE;
  230. Result = NULL;
  231. FieldUnit = &(FieldObject->U.FieldUnit);
  232. ASSERT(FieldObject->Type == AcpiObjectFieldUnit);
  233. OperationRegionObject = FieldUnit->OperationRegion;
  234. if (OperationRegionObject != NULL) {
  235. ASSERT(OperationRegionObject->Type == AcpiObjectOperationRegion);
  236. OperationRegion = &(OperationRegionObject->U.OperationRegion);
  237. }
  238. switch (FieldUnit->Access) {
  239. case AcpiFieldAccessAny:
  240. case AcpiFieldAccessBuffer:
  241. case AcpiFieldAccessByte:
  242. AccessSize = BITS_PER_BYTE;
  243. break;
  244. case AcpiFieldAccessWord:
  245. AccessSize = 2 * BITS_PER_BYTE;
  246. break;
  247. case AcpiFieldAccessDoubleWord:
  248. AccessSize = 4 * BITS_PER_BYTE;
  249. break;
  250. case AcpiFieldAccessQuadWord:
  251. AccessSize = 8 * BITS_PER_BYTE;
  252. break;
  253. default:
  254. ASSERT(FALSE);
  255. Status = STATUS_INVALID_PARAMETER;
  256. goto ReadFromFieldEnd;
  257. }
  258. //
  259. // Calculate the size of the buffer needed by rounding the offset down
  260. // to the access size, and the length up.
  261. //
  262. StartBitOffset = ALIGN_RANGE_DOWN(FieldUnit->BitOffset, AccessSize);
  263. EndBitOffset = ALIGN_RANGE_UP(FieldUnit->BitOffset + FieldUnit->BitLength,
  264. AccessSize);
  265. BufferSize = (EndBitOffset - StartBitOffset) / BITS_PER_BYTE;
  266. StartByteOffset = StartBitOffset / BITS_PER_BYTE;
  267. EndByteOffset = EndBitOffset / BITS_PER_BYTE;
  268. //
  269. // Allocate the result buffer. Use an integer if the result is small
  270. // enough to fit in one, or create a buffer if not.
  271. //
  272. IntegerWidthIs32 = FALSE;
  273. if (Context->CurrentMethod != NULL) {
  274. IntegerWidthIs32 = Context->CurrentMethod->IntegerWidthIs32;
  275. }
  276. if ((BufferSize <= sizeof(ULONG)) ||
  277. ((IntegerWidthIs32 == FALSE) && (BufferSize <= sizeof(ULONGLONG)))) {
  278. Result = AcpipCreateNamespaceObject(Context,
  279. AcpiObjectInteger,
  280. NULL,
  281. NULL,
  282. 0);
  283. if (Result == NULL) {
  284. Status = STATUS_UNSUCCESSFUL;
  285. goto ReadFromFieldEnd;
  286. }
  287. Result->U.Integer.Value = 0;
  288. ResultBuffer = (PUCHAR)&(Result->U.Integer.Value);
  289. } else {
  290. Result = AcpipCreateNamespaceObject(Context,
  291. AcpiObjectBuffer,
  292. NULL,
  293. NULL,
  294. BufferSize);
  295. if (Result == NULL) {
  296. Status = STATUS_UNSUCCESSFUL;
  297. goto ReadFromFieldEnd;
  298. }
  299. ResultBuffer = Result->U.Buffer.Buffer;
  300. RtlZeroMemory(ResultBuffer, BufferSize);
  301. }
  302. //
  303. // Validate that the reads are safe.
  304. //
  305. if (OperationRegion != NULL) {
  306. if ((StartByteOffset > OperationRegion->Length) ||
  307. (EndByteOffset > OperationRegion->Length) ||
  308. (EndByteOffset <= StartByteOffset)) {
  309. Status = STATUS_INVALID_PARAMETER;
  310. goto ReadFromFieldEnd;
  311. }
  312. }
  313. //
  314. // If the field is banked, acquire the mutex for the Operation Region that
  315. // the bank register points at, and write the bank value to the bank
  316. // register.
  317. //
  318. BankRegister = FieldUnit->BankRegister;
  319. IndexRegister = FieldUnit->IndexRegister;
  320. DataRegister = FieldUnit->DataRegister;
  321. if (BankRegister != NULL) {
  322. ASSERT(BankRegister->Type == AcpiObjectFieldUnit);
  323. AlternateOperationRegion = BankRegister->U.FieldUnit.OperationRegion;
  324. ASSERT(AlternateOperationRegion->Type == AcpiObjectOperationRegion);
  325. AcpipAcquireMutex(Context,
  326. AlternateOperationRegion->U.OperationRegion.OsMutex,
  327. ACPI_MUTEX_WAIT_INDEFINITELY);
  328. AlternateOperationRegionMutexAcquired = TRUE;
  329. //
  330. // Store the bank value into the bank register.
  331. //
  332. Status = AcpipPerformStoreOperation(Context,
  333. FieldUnit->BankValue,
  334. BankRegister);
  335. if (!KSUCCESS(Status)) {
  336. goto ReadFromFieldEnd;
  337. }
  338. //
  339. // If the field is Indexed, acquire the mutex for the Operation Region
  340. // that the Index register points at.
  341. //
  342. } else if (IndexRegister != NULL) {
  343. ASSERT(IndexRegister->Type == AcpiObjectFieldUnit);
  344. AlternateOperationRegion = IndexRegister->U.FieldUnit.OperationRegion;
  345. ASSERT(AlternateOperationRegion->Type == AcpiObjectOperationRegion);
  346. AcpipAcquireMutex(Context,
  347. AlternateOperationRegion->U.OperationRegion.OsMutex,
  348. ACPI_MUTEX_WAIT_INDEFINITELY);
  349. AlternateOperationRegionMutexAcquired = TRUE;
  350. //
  351. // Also create the index value variable at this time.
  352. //
  353. IndexValue = AcpipCreateNamespaceObject(Context,
  354. AcpiObjectInteger,
  355. NULL,
  356. NULL,
  357. 0);
  358. if (IndexValue == NULL) {
  359. Status = STATUS_UNSUCCESSFUL;
  360. goto ReadFromFieldEnd;
  361. }
  362. }
  363. //
  364. // Acquire the mutex and global lock if needed.
  365. //
  366. if (OperationRegion != NULL) {
  367. AcpipAcquireMutex(Context,
  368. OperationRegion->OsMutex,
  369. ACPI_MUTEX_WAIT_INDEFINITELY);
  370. OperationRegionMutexHeld = TRUE;
  371. }
  372. if (FieldUnit->AcquireGlobalLock != FALSE) {
  373. AcpipAcquireGlobalLock();
  374. GlobalLockAcquired = TRUE;
  375. }
  376. //
  377. // Perform the reads.
  378. //
  379. Status = STATUS_SUCCESS;
  380. CurrentBuffer = ResultBuffer;
  381. for (CurrentOffset = StartByteOffset;
  382. CurrentOffset < EndByteOffset;
  383. CurrentOffset += (AccessSize / BITS_PER_BYTE)) {
  384. //
  385. // For indexed fields, write the index value, then read from the data
  386. // register.
  387. //
  388. if (IndexRegister != NULL) {
  389. IndexValue->U.Integer.Value = CurrentOffset;
  390. Status = AcpipWriteToField(Context, IndexRegister, IndexValue);
  391. if (!KSUCCESS(Status)) {
  392. break;
  393. }
  394. Status = AcpipReadFromField(Context, DataRegister, &DataResult);
  395. if (!KSUCCESS(Status)) {
  396. break;
  397. }
  398. //
  399. // Copy the result from the read into the destination buffer.
  400. //
  401. if (DataResult->Type == AcpiObjectInteger) {
  402. RtlCopyMemory(CurrentBuffer,
  403. &(DataResult->U.Integer.Value),
  404. AccessSize);
  405. } else if (DataResult->Type == AcpiObjectBuffer) {
  406. RtlCopyMemory(CurrentBuffer,
  407. DataResult->U.Buffer.Buffer,
  408. AccessSize);
  409. } else {
  410. AcpipObjectReleaseReference(DataResult);
  411. Status = STATUS_INVALID_PARAMETER;
  412. goto ReadFromFieldEnd;
  413. }
  414. AcpipObjectReleaseReference(DataResult);
  415. //
  416. // Perform a normal region read.
  417. //
  418. } else {
  419. Status = OperationRegion->FunctionTable->Read(
  420. OperationRegion->OsContext,
  421. CurrentOffset,
  422. AccessSize,
  423. CurrentBuffer);
  424. if (!KSUCCESS(Status)) {
  425. //
  426. // Allow region access that occur before they're supposed to.
  427. //
  428. if (Status == STATUS_TOO_EARLY) {
  429. RtlZeroMemory(CurrentBuffer, AccessSize / BITS_PER_BYTE);
  430. Status = STATUS_SUCCESS;
  431. } else {
  432. break;
  433. }
  434. }
  435. }
  436. CurrentBuffer += AccessSize / BITS_PER_BYTE;
  437. }
  438. if (GlobalLockAcquired != FALSE) {
  439. AcpipReleaseGlobalLock();
  440. GlobalLockAcquired = FALSE;
  441. }
  442. if (OperationRegionMutexHeld != FALSE) {
  443. AcpipReleaseMutex(Context, OperationRegion->OsMutex);
  444. OperationRegionMutexHeld = FALSE;
  445. }
  446. //
  447. // If something in the loop failed, bail now.
  448. //
  449. if (!KSUCCESS(Status)) {
  450. goto ReadFromFieldEnd;
  451. }
  452. //
  453. // Shift the buffer, which was read naturally aligned, into the position
  454. // dictated by the field.
  455. //
  456. AcpipShiftBufferIntoFieldPosition(ResultBuffer,
  457. FieldUnit->BitOffset,
  458. FieldUnit->BitLength,
  459. AccessSize);
  460. ReadFromFieldEnd:
  461. if (GlobalLockAcquired != FALSE) {
  462. AcpipReleaseGlobalLock();
  463. }
  464. if (OperationRegionMutexHeld != FALSE) {
  465. AcpipReleaseMutex(Context, OperationRegion->OsMutex);
  466. }
  467. //
  468. // Release the alternate mutex if acquired.
  469. //
  470. if (AlternateOperationRegionMutexAcquired != FALSE) {
  471. AcpipReleaseMutex(Context,
  472. AlternateOperationRegion->U.OperationRegion.OsMutex);
  473. }
  474. if (IndexValue != NULL) {
  475. AcpipObjectReleaseReference(IndexValue);
  476. }
  477. if (!KSUCCESS(Status)) {
  478. if (Result != NULL) {
  479. AcpipObjectReleaseReference(Result);
  480. Result = NULL;
  481. }
  482. }
  483. *ResultObject = Result;
  484. return Status;
  485. }
  486. KSTATUS
  487. AcpipWriteToField (
  488. PAML_EXECUTION_CONTEXT Context,
  489. PACPI_OBJECT FieldObject,
  490. PACPI_OBJECT ValueToWrite
  491. )
  492. /*++
  493. Routine Description:
  494. This routine writes to an Operation Region field.
  495. Arguments:
  496. Context - Supplies a pointer to the AML execution context.
  497. FieldObject - Supplies a pointer to the field object to write to.
  498. ValueToWrite - Supplies a pointer to an Integer or Buffer object containing
  499. the value to write into the field.
  500. Return Value:
  501. STATUS_SUCCESS on success.
  502. Error codes on failure.
  503. --*/
  504. {
  505. ULONG AccessSize;
  506. PACPI_OBJECT AlternateOperationRegion;
  507. BOOL AlternateOperationRegionMutexAcquired;
  508. PACPI_OBJECT BankRegister;
  509. ULONGLONG BufferSize;
  510. PUCHAR CurrentBuffer;
  511. ULONGLONG CurrentOffset;
  512. PACPI_OBJECT DataRegister;
  513. PACPI_OBJECT DataResult;
  514. ULONGLONG EndBitOffset;
  515. ULONGLONG EndByteOffset;
  516. ULONGLONG FieldByteLength;
  517. PACPI_FIELD_UNIT_OBJECT FieldUnit;
  518. PACPI_OBJECT IndexRegister;
  519. PACPI_OBJECT IndexValue;
  520. BOOL IntegerWidthIs32;
  521. BOOL LocksHeld;
  522. PACPI_OPERATION_REGION_OBJECT OperationRegion;
  523. PACPI_OBJECT OperationRegionObject;
  524. PACPI_OBJECT Result;
  525. PUCHAR ResultBuffer;
  526. PUCHAR SourceBuffer;
  527. ULONGLONG SourceBufferSize;
  528. ULONGLONG StartBitOffset;
  529. ULONGLONG StartByteOffset;
  530. KSTATUS Status;
  531. AlternateOperationRegion = NULL;
  532. AlternateOperationRegionMutexAcquired = FALSE;
  533. BankRegister = NULL;
  534. DataRegister = NULL;
  535. DataResult = NULL;
  536. IndexRegister = NULL;
  537. IndexValue = NULL;
  538. LocksHeld = FALSE;
  539. OperationRegion = NULL;
  540. Result = NULL;
  541. FieldUnit = &(FieldObject->U.FieldUnit);
  542. ASSERT(FieldObject->Type == AcpiObjectFieldUnit);
  543. OperationRegionObject = FieldUnit->OperationRegion;
  544. if (OperationRegionObject != NULL) {
  545. ASSERT(OperationRegionObject->Type == AcpiObjectOperationRegion);
  546. OperationRegion = &(OperationRegionObject->U.OperationRegion);
  547. }
  548. switch (FieldUnit->Access) {
  549. case AcpiFieldAccessAny:
  550. case AcpiFieldAccessBuffer:
  551. case AcpiFieldAccessByte:
  552. AccessSize = BITS_PER_BYTE;
  553. break;
  554. case AcpiFieldAccessWord:
  555. AccessSize = 2 * BITS_PER_BYTE;
  556. break;
  557. case AcpiFieldAccessDoubleWord:
  558. AccessSize = 4 * BITS_PER_BYTE;
  559. break;
  560. case AcpiFieldAccessQuadWord:
  561. AccessSize = 8 * BITS_PER_BYTE;
  562. break;
  563. default:
  564. ASSERT(FALSE);
  565. Status = STATUS_INVALID_PARAMETER;
  566. goto WriteToFieldEnd;
  567. }
  568. //
  569. // Calculate the size of the buffer needed by rounding the offset down
  570. // to the access size, and the length up.
  571. //
  572. StartBitOffset = ALIGN_RANGE_DOWN(FieldUnit->BitOffset, AccessSize);
  573. EndBitOffset = ALIGN_RANGE_UP(FieldUnit->BitOffset + FieldUnit->BitLength,
  574. AccessSize);
  575. BufferSize = (EndBitOffset - StartBitOffset) / BITS_PER_BYTE;
  576. StartByteOffset = StartBitOffset / BITS_PER_BYTE;
  577. EndByteOffset = EndBitOffset / BITS_PER_BYTE;
  578. //
  579. // Allocate the result buffer. Use an integer if the result is small
  580. // enough to fit in one, or create a buffer if not.
  581. //
  582. IntegerWidthIs32 = FALSE;
  583. if (Context->CurrentMethod != NULL) {
  584. IntegerWidthIs32 = Context->CurrentMethod->IntegerWidthIs32;
  585. }
  586. if ((BufferSize <= sizeof(ULONG)) ||
  587. ((IntegerWidthIs32 == FALSE) && (BufferSize <= sizeof(ULONGLONG)))) {
  588. Result = AcpipCreateNamespaceObject(Context,
  589. AcpiObjectInteger,
  590. NULL,
  591. NULL,
  592. 0);
  593. if (Result == NULL) {
  594. Status = STATUS_UNSUCCESSFUL;
  595. goto WriteToFieldEnd;
  596. }
  597. ResultBuffer = (PUCHAR)&(Result->U.Integer.Value);
  598. } else {
  599. Result = AcpipCreateNamespaceObject(Context,
  600. AcpiObjectBuffer,
  601. NULL,
  602. NULL,
  603. BufferSize);
  604. if (Result == NULL) {
  605. Status = STATUS_UNSUCCESSFUL;
  606. goto WriteToFieldEnd;
  607. }
  608. ResultBuffer = Result->U.Buffer.Buffer;
  609. }
  610. //
  611. // Validate that the accesses are safe.
  612. //
  613. if (OperationRegion != NULL) {
  614. if ((StartByteOffset >= OperationRegion->Length) ||
  615. (EndByteOffset > OperationRegion->Length) ||
  616. (EndByteOffset <= StartByteOffset)) {
  617. Status = STATUS_INVALID_PARAMETER;
  618. goto WriteToFieldEnd;
  619. }
  620. }
  621. //
  622. // Determine the source buffer based on the source object.
  623. //
  624. if (ValueToWrite->Type == AcpiObjectInteger) {
  625. SourceBuffer = (PUCHAR)&(ValueToWrite->U.Integer.Value);
  626. SourceBufferSize = sizeof(ULONGLONG);
  627. if (IntegerWidthIs32 != FALSE) {
  628. SourceBufferSize = sizeof(ULONG);
  629. }
  630. } else if (ValueToWrite->Type == AcpiObjectBuffer) {
  631. SourceBuffer = ValueToWrite->U.Buffer.Buffer;
  632. SourceBufferSize = ValueToWrite->U.Buffer.Length;
  633. } else {
  634. Status = STATUS_NOT_SUPPORTED;
  635. goto WriteToFieldEnd;
  636. }
  637. //
  638. // The source buffer needs to be at least the size of the field.
  639. //
  640. FieldByteLength = ALIGN_RANGE_UP(FieldUnit->BitLength, BITS_PER_BYTE) /
  641. BITS_PER_BYTE;
  642. if (SourceBufferSize < FieldByteLength) {
  643. Status = STATUS_BUFFER_OVERRUN;
  644. goto WriteToFieldEnd;
  645. }
  646. //
  647. // If the field is banked, acquire the mutex for the Operation Region that
  648. // the bank register points at, and write the bank value to the bank
  649. // register.
  650. //
  651. BankRegister = FieldUnit->BankRegister;
  652. IndexRegister = FieldUnit->IndexRegister;
  653. DataRegister = FieldUnit->DataRegister;
  654. if (BankRegister != NULL) {
  655. ASSERT(BankRegister->Type == AcpiObjectFieldUnit);
  656. AlternateOperationRegion = BankRegister->U.FieldUnit.OperationRegion;
  657. ASSERT(AlternateOperationRegion->Type == AcpiObjectOperationRegion);
  658. AcpipAcquireMutex(Context,
  659. AlternateOperationRegion->U.OperationRegion.OsMutex,
  660. ACPI_MUTEX_WAIT_INDEFINITELY);
  661. AlternateOperationRegionMutexAcquired = TRUE;
  662. //
  663. // Store the bank value into the bank register.
  664. //
  665. Status = AcpipPerformStoreOperation(Context,
  666. FieldUnit->BankValue,
  667. BankRegister);
  668. if (!KSUCCESS(Status)) {
  669. goto WriteToFieldEnd;
  670. }
  671. //
  672. // If the field is Indexed, acquire the mutex for the Operation Region
  673. // that the Index register points at.
  674. //
  675. } else if (IndexRegister != NULL) {
  676. ASSERT(IndexRegister->Type == AcpiObjectFieldUnit);
  677. AlternateOperationRegion = IndexRegister->U.FieldUnit.OperationRegion;
  678. ASSERT(AlternateOperationRegion->Type == AcpiObjectOperationRegion);
  679. AcpipAcquireMutex(Context,
  680. AlternateOperationRegion->U.OperationRegion.OsMutex,
  681. ACPI_MUTEX_WAIT_INDEFINITELY);
  682. AlternateOperationRegionMutexAcquired = TRUE;
  683. //
  684. // Also create the index value variable at this time.
  685. //
  686. IndexValue = AcpipCreateNamespaceObject(Context,
  687. AcpiObjectInteger,
  688. NULL,
  689. NULL,
  690. 0);
  691. if (IndexValue == NULL) {
  692. Status = STATUS_UNSUCCESSFUL;
  693. goto WriteToFieldEnd;
  694. }
  695. }
  696. //
  697. // Acquire the mutex and global lock if needed. Do this now because if the
  698. // rule is preserve, then the register should be read/modified/written
  699. // atomically.
  700. //
  701. if (OperationRegion != NULL) {
  702. AcpipAcquireMutex(Context,
  703. OperationRegion->OsMutex,
  704. ACPI_MUTEX_WAIT_INDEFINITELY);
  705. }
  706. if (FieldUnit->AcquireGlobalLock != FALSE) {
  707. AcpipAcquireGlobalLock();
  708. }
  709. LocksHeld = TRUE;
  710. //
  711. // Fill up the buffer with an initial value depending on the update rule.
  712. // If the field is already aligned, then there's no need for the read
  713. // (and it can in fact be harmful if it has side effects).
  714. //
  715. if ((StartBitOffset != FieldUnit->BitOffset) ||
  716. (EndBitOffset != FieldUnit->BitOffset + FieldUnit->BitLength)) {
  717. CurrentBuffer = ResultBuffer;
  718. if (FieldUnit->UpdateRule == AcpiFieldUpdatePreserve) {
  719. for (CurrentOffset = StartByteOffset;
  720. CurrentOffset < EndByteOffset;
  721. CurrentOffset += (AccessSize / BITS_PER_BYTE)) {
  722. //
  723. // For indexed fields, write the index value, then read from
  724. // the data register.
  725. //
  726. if (IndexRegister != NULL) {
  727. IndexValue->U.Integer.Value = CurrentOffset;
  728. Status = AcpipWriteToField(Context,
  729. IndexRegister,
  730. IndexValue);
  731. if (!KSUCCESS(Status)) {
  732. goto WriteToFieldEnd;
  733. }
  734. Status = AcpipReadFromField(Context,
  735. DataRegister,
  736. &DataResult);
  737. if (!KSUCCESS(Status)) {
  738. goto WriteToFieldEnd;
  739. }
  740. //
  741. // Copy the result from the read into the destination
  742. // buffer.
  743. //
  744. if (DataResult->Type == AcpiObjectInteger) {
  745. RtlCopyMemory(CurrentBuffer,
  746. &(DataResult->U.Integer.Value),
  747. AccessSize);
  748. } else if (DataResult->Type == AcpiObjectBuffer) {
  749. RtlCopyMemory(CurrentBuffer,
  750. DataResult->U.Buffer.Buffer,
  751. AccessSize);
  752. } else {
  753. Status = STATUS_INVALID_PARAMETER;
  754. goto WriteToFieldEnd;
  755. }
  756. AcpipObjectReleaseReference(DataResult);
  757. DataResult = NULL;
  758. //
  759. // Perform a normal region read.
  760. //
  761. } else {
  762. Status = OperationRegion->FunctionTable->Read(
  763. OperationRegion->OsContext,
  764. CurrentOffset,
  765. AccessSize,
  766. CurrentBuffer);
  767. if (!KSUCCESS(Status)) {
  768. break;
  769. }
  770. }
  771. CurrentBuffer += AccessSize / BITS_PER_BYTE;
  772. }
  773. } else if (FieldUnit->UpdateRule == AcpiFieldUpdateWriteAsOnes) {
  774. for (CurrentOffset = StartByteOffset;
  775. CurrentOffset < EndByteOffset;
  776. CurrentOffset += (AccessSize / BITS_PER_BYTE)) {
  777. *CurrentBuffer = 0xFF;
  778. CurrentBuffer += 1;
  779. }
  780. } else {
  781. RtlZeroMemory(CurrentBuffer, EndByteOffset - StartByteOffset);
  782. }
  783. }
  784. //
  785. // Modify the result buffer to include the bits being set in the field.
  786. //
  787. AcpipWriteFieldBitsIntoBuffer(SourceBuffer,
  788. FieldUnit->BitOffset,
  789. FieldUnit->BitLength,
  790. AccessSize,
  791. ResultBuffer,
  792. BufferSize);
  793. //
  794. // If it's an Index/Data style write, create an index data value now.
  795. //
  796. if (IndexRegister != NULL) {
  797. DataResult = AcpipCreateNamespaceObject(Context,
  798. AcpiObjectInteger,
  799. NULL,
  800. NULL,
  801. 0);
  802. if (DataResult == NULL) {
  803. Status = STATUS_UNSUCCESSFUL;
  804. goto WriteToFieldEnd;
  805. }
  806. }
  807. //
  808. // Perform the writes.
  809. //
  810. CurrentBuffer = ResultBuffer;
  811. for (CurrentOffset = StartByteOffset;
  812. CurrentOffset < EndByteOffset;
  813. CurrentOffset += (AccessSize / BITS_PER_BYTE)) {
  814. //
  815. // For indexed fields, write the index value, then read from the data
  816. // register.
  817. //
  818. if (IndexRegister != NULL) {
  819. IndexValue->U.Integer.Value = CurrentOffset;
  820. Status = AcpipWriteToField(Context, IndexRegister, IndexValue);
  821. if (!KSUCCESS(Status)) {
  822. goto WriteToFieldEnd;
  823. }
  824. DataResult->U.Integer.Value = 0;
  825. RtlCopyMemory(&(DataResult->U.Integer.Value),
  826. CurrentBuffer,
  827. AccessSize);
  828. Status = AcpipWriteToField(Context, DataRegister, DataResult);
  829. if (!KSUCCESS(Status)) {
  830. goto WriteToFieldEnd;
  831. }
  832. //
  833. // Perform a normal region write.
  834. //
  835. } else {
  836. Status = OperationRegion->FunctionTable->Write(
  837. OperationRegion->OsContext,
  838. CurrentOffset,
  839. AccessSize,
  840. CurrentBuffer);
  841. if (!KSUCCESS(Status)) {
  842. goto WriteToFieldEnd;
  843. }
  844. }
  845. CurrentBuffer += AccessSize / BITS_PER_BYTE;
  846. }
  847. Status = STATUS_SUCCESS;
  848. WriteToFieldEnd:
  849. if (LocksHeld != FALSE) {
  850. if (FieldUnit->AcquireGlobalLock != FALSE) {
  851. AcpipReleaseGlobalLock();
  852. }
  853. if (OperationRegion != NULL) {
  854. AcpipReleaseMutex(Context, OperationRegion->OsMutex);
  855. }
  856. }
  857. //
  858. // Release the alternate mutex if acquired.
  859. //
  860. if (AlternateOperationRegionMutexAcquired != FALSE) {
  861. AcpipReleaseMutex(Context,
  862. AlternateOperationRegion->U.OperationRegion.OsMutex);
  863. }
  864. if (IndexValue != NULL) {
  865. AcpipObjectReleaseReference(IndexValue);
  866. }
  867. if (DataResult != NULL) {
  868. AcpipObjectReleaseReference(DataResult);
  869. }
  870. if (Result != NULL) {
  871. AcpipObjectReleaseReference(Result);
  872. Result = NULL;
  873. }
  874. return Status;
  875. }
  876. KSTATUS
  877. AcpipReadFromBufferField (
  878. PAML_EXECUTION_CONTEXT Context,
  879. PACPI_OBJECT BufferField,
  880. PACPI_OBJECT *ResultObject
  881. )
  882. /*++
  883. Routine Description:
  884. This routine reads from a Buffer Field.
  885. Arguments:
  886. Context - Supplies a pointer to the AML execution context.
  887. BufferField - Supplies a pointer to the field object to read from.
  888. ResultObject - Supplies a pointer where a pointer to the result object will
  889. be returned. The caller is responsible for freeing this memory.
  890. Return Value:
  891. STATUS_SUCCESS on success.
  892. Error codes on failure.
  893. --*/
  894. {
  895. ULONGLONG BaseBufferSize;
  896. PVOID BasePointer;
  897. PACPI_OBJECT BufferObject;
  898. ULONGLONG EndBitOffset;
  899. ULONGLONG EndByteOffset;
  900. BOOL IntegerWidthIs32;
  901. PACPI_OBJECT Result;
  902. PVOID ResultBuffer;
  903. ULONGLONG ResultBufferSize;
  904. ULONGLONG StartBitOffset;
  905. ULONGLONG StartByteOffset;
  906. KSTATUS Status;
  907. ASSERT(BufferField->Type == AcpiObjectBufferField);
  908. Result = NULL;
  909. //
  910. // Find the buffer this field points to.
  911. //
  912. BufferObject = BufferField->U.BufferField.DestinationObject;
  913. switch (BufferObject->Type) {
  914. case AcpiObjectInteger:
  915. BasePointer = &(BufferObject->U.Integer.Value);
  916. BaseBufferSize = sizeof(ULONGLONG);
  917. break;
  918. case AcpiObjectString:
  919. BasePointer = &(BufferObject->U.String.String);
  920. if (BasePointer == NULL) {
  921. Status = STATUS_BUFFER_TOO_SMALL;
  922. goto ReadFromBufferFieldEnd;
  923. }
  924. BaseBufferSize = RtlStringLength(BasePointer) + 1;
  925. break;
  926. case AcpiObjectBuffer:
  927. BasePointer = BufferObject->U.Buffer.Buffer;
  928. BaseBufferSize = BufferObject->U.Buffer.Length;
  929. if (BaseBufferSize == 0) {
  930. Status = STATUS_BUFFER_TOO_SMALL;
  931. goto ReadFromBufferFieldEnd;
  932. }
  933. break;
  934. default:
  935. ASSERT(FALSE);
  936. Status = STATUS_NOT_SUPPORTED;
  937. goto ReadFromBufferFieldEnd;
  938. }
  939. //
  940. // Perform access checks on the field.
  941. //
  942. StartBitOffset = ALIGN_RANGE_DOWN(BufferField->U.BufferField.BitOffset,
  943. BITS_PER_BYTE);
  944. StartByteOffset = StartBitOffset / BITS_PER_BYTE;
  945. EndBitOffset = BufferField->U.BufferField.BitOffset +
  946. BufferField->U.BufferField.BitLength;
  947. EndBitOffset = ALIGN_RANGE_UP(EndBitOffset, BITS_PER_BYTE);
  948. EndByteOffset = EndBitOffset / BITS_PER_BYTE;
  949. ResultBufferSize = EndByteOffset - StartByteOffset;
  950. if ((StartByteOffset > BaseBufferSize) ||
  951. (EndByteOffset > BaseBufferSize) ||
  952. (EndByteOffset <= StartByteOffset)) {
  953. Status = STATUS_INVALID_PARAMETER;
  954. goto ReadFromBufferFieldEnd;
  955. }
  956. //
  957. // Allocate the result buffer.
  958. //
  959. IntegerWidthIs32 = FALSE;
  960. if (Context->CurrentMethod != NULL) {
  961. IntegerWidthIs32 = Context->CurrentMethod->IntegerWidthIs32;
  962. }
  963. if ((ResultBufferSize <= sizeof(ULONG)) ||
  964. ((ResultBufferSize <= sizeof(ULONGLONG)) &&
  965. (IntegerWidthIs32 != FALSE))) {
  966. Result = AcpipCreateNamespaceObject(Context,
  967. AcpiObjectInteger,
  968. NULL,
  969. NULL,
  970. 0);
  971. if (Result == NULL) {
  972. Status = STATUS_UNSUCCESSFUL;
  973. goto ReadFromBufferFieldEnd;
  974. }
  975. Result->U.Integer.Value = 0;
  976. ResultBuffer = &(Result->U.Integer.Value);
  977. } else {
  978. Result = AcpipCreateNamespaceObject(Context,
  979. AcpiObjectBuffer,
  980. NULL,
  981. NULL,
  982. ResultBufferSize);
  983. if (Result == NULL) {
  984. Status = STATUS_UNSUCCESSFUL;
  985. goto ReadFromBufferFieldEnd;
  986. }
  987. ResultBuffer = Result->U.Buffer.Buffer;
  988. }
  989. //
  990. // Copy the naturally aligned memory to the destination.
  991. //
  992. RtlCopyMemory(ResultBuffer,
  993. BasePointer + StartByteOffset,
  994. EndByteOffset - StartByteOffset);
  995. //
  996. // Shift the memory into place.
  997. //
  998. AcpipShiftBufferIntoFieldPosition(ResultBuffer,
  999. BufferField->U.BufferField.BitOffset,
  1000. BufferField->U.BufferField.BitLength,
  1001. BITS_PER_BYTE);
  1002. Status = STATUS_SUCCESS;
  1003. ReadFromBufferFieldEnd:
  1004. if (!KSUCCESS(Status)) {
  1005. if (Result != NULL) {
  1006. AcpipObjectReleaseReference(Result);
  1007. Result = NULL;
  1008. }
  1009. }
  1010. *ResultObject = Result;
  1011. return Status;
  1012. }
  1013. KSTATUS
  1014. AcpipWriteToBufferField (
  1015. PAML_EXECUTION_CONTEXT Context,
  1016. PACPI_OBJECT BufferField,
  1017. PACPI_OBJECT ValueToWrite
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. This routine reads from a Buffer Field.
  1022. Arguments:
  1023. Context - Supplies a pointer to the AML execution context.
  1024. BufferField - Supplies a pointer to the field object to read from.
  1025. ValueToWrite - Supplies a pointer to the value to write to the buffer field.
  1026. Return Value:
  1027. STATUS_SUCCESS on success.
  1028. Error codes on failure.
  1029. --*/
  1030. {
  1031. PACPI_OBJECT BufferObject;
  1032. PVOID DestinationBuffer;
  1033. ULONGLONG DestinationBufferSize;
  1034. ULONGLONG EndBitOffset;
  1035. ULONGLONG EndByteOffset;
  1036. PVOID FieldBuffer;
  1037. ULONGLONG FieldBufferSize;
  1038. ULONGLONG StartBitOffset;
  1039. ULONGLONG StartByteOffset;
  1040. KSTATUS Status;
  1041. ASSERT(BufferField->Type == AcpiObjectBufferField);
  1042. //
  1043. // Find the buffer this field points to.
  1044. //
  1045. BufferObject = BufferField->U.BufferField.DestinationObject;
  1046. switch (BufferObject->Type) {
  1047. case AcpiObjectInteger:
  1048. DestinationBuffer = &(BufferObject->U.Integer.Value);
  1049. DestinationBufferSize = sizeof(ULONGLONG);
  1050. break;
  1051. case AcpiObjectString:
  1052. DestinationBuffer = &(BufferObject->U.String.String);
  1053. if (DestinationBuffer == NULL) {
  1054. Status = STATUS_BUFFER_TOO_SMALL;
  1055. goto WriteToBufferFieldEnd;
  1056. }
  1057. DestinationBufferSize = RtlStringLength(DestinationBuffer) + 1;
  1058. break;
  1059. case AcpiObjectBuffer:
  1060. DestinationBuffer = BufferObject->U.Buffer.Buffer;
  1061. DestinationBufferSize = BufferObject->U.Buffer.Length;
  1062. if (DestinationBufferSize == 0) {
  1063. Status = STATUS_BUFFER_TOO_SMALL;
  1064. goto WriteToBufferFieldEnd;
  1065. }
  1066. break;
  1067. default:
  1068. ASSERT(FALSE);
  1069. Status = STATUS_NOT_SUPPORTED;
  1070. goto WriteToBufferFieldEnd;
  1071. }
  1072. //
  1073. // Find the buffer pointer of the value to write.
  1074. //
  1075. switch (ValueToWrite->Type) {
  1076. case AcpiObjectInteger:
  1077. FieldBuffer = &(ValueToWrite->U.Integer.Value);
  1078. FieldBufferSize = sizeof(ULONGLONG);
  1079. break;
  1080. case AcpiObjectString:
  1081. FieldBuffer = &(ValueToWrite->U.String.String);
  1082. if (FieldBuffer == NULL) {
  1083. Status = STATUS_BUFFER_TOO_SMALL;
  1084. goto WriteToBufferFieldEnd;
  1085. }
  1086. FieldBufferSize = RtlStringLength(FieldBuffer) + 1;
  1087. break;
  1088. case AcpiObjectBuffer:
  1089. FieldBuffer = ValueToWrite->U.Buffer.Buffer;
  1090. FieldBufferSize = ValueToWrite->U.Buffer.Length;
  1091. if (FieldBufferSize == 0) {
  1092. Status = STATUS_BUFFER_TOO_SMALL;
  1093. goto WriteToBufferFieldEnd;
  1094. }
  1095. break;
  1096. default:
  1097. ASSERT(FALSE);
  1098. Status = STATUS_NOT_SUPPORTED;
  1099. goto WriteToBufferFieldEnd;
  1100. }
  1101. //
  1102. // Perform access checks on the field.
  1103. //
  1104. StartBitOffset = ALIGN_RANGE_DOWN(BufferField->U.BufferField.BitOffset,
  1105. BITS_PER_BYTE);
  1106. StartByteOffset = StartBitOffset / BITS_PER_BYTE;
  1107. EndBitOffset = BufferField->U.BufferField.BitOffset +
  1108. BufferField->U.BufferField.BitLength;
  1109. EndBitOffset = ALIGN_RANGE_UP(EndBitOffset, BITS_PER_BYTE);
  1110. EndByteOffset = EndBitOffset / BITS_PER_BYTE;
  1111. if ((StartByteOffset > DestinationBufferSize) ||
  1112. (EndByteOffset > DestinationBufferSize) ||
  1113. (EndByteOffset <= StartByteOffset)) {
  1114. Status = STATUS_INVALID_PARAMETER;
  1115. goto WriteToBufferFieldEnd;
  1116. }
  1117. if (EndByteOffset - StartByteOffset > FieldBufferSize) {
  1118. Status = STATUS_BUFFER_TOO_SMALL;
  1119. goto WriteToBufferFieldEnd;
  1120. }
  1121. //
  1122. // Write the field's bits into the destination buffer.
  1123. //
  1124. AcpipWriteFieldBitsIntoBuffer(FieldBuffer,
  1125. BufferField->U.BufferField.BitOffset,
  1126. BufferField->U.BufferField.BitLength,
  1127. BITS_PER_BYTE,
  1128. DestinationBuffer + StartByteOffset,
  1129. DestinationBufferSize - StartByteOffset);
  1130. Status = STATUS_SUCCESS;
  1131. WriteToBufferFieldEnd:
  1132. return Status;
  1133. }
  1134. VOID
  1135. AcpipPrintOperationRegion (
  1136. PACPI_OBJECT OperationRegion
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. This routine prints a description of the given Operation Region to the
  1141. debugger.
  1142. Arguments:
  1143. OperationRegion - Supplies a pointer to the Operation Region to print.
  1144. Return Value:
  1145. None.
  1146. --*/
  1147. {
  1148. PSTR Name;
  1149. PSTR Space;
  1150. ASSERT(OperationRegion->Type == AcpiObjectOperationRegion);
  1151. Space = "UnknownSpace";
  1152. switch (OperationRegion->U.OperationRegion.Space) {
  1153. case OperationRegionSystemMemory:
  1154. Space = "SystemMemory";
  1155. break;
  1156. case OperationRegionSystemIo:
  1157. Space = "SystemIO";
  1158. break;
  1159. case OperationRegionPciConfig:
  1160. Space = "PCIConfig";
  1161. break;
  1162. case OperationRegionEmbeddedController:
  1163. Space = "EmbeddedController";
  1164. break;
  1165. case OperationRegionSmBus:
  1166. Space = "SMBus";
  1167. break;
  1168. case OperationRegionCmos:
  1169. Space = "CMOS";
  1170. break;
  1171. case OperationRegionPciBarTarget:
  1172. Space = "PCIBarTarget";
  1173. break;
  1174. case OperationRegionIpmi:
  1175. Space = "IPMI";
  1176. break;
  1177. default:
  1178. break;
  1179. }
  1180. Name = (PSTR)&(OperationRegion->Name);
  1181. RtlDebugPrint("OperationRegion (%c%c%c%c, %s, 0x%I64x, 0x%I64x)",
  1182. Name[0],
  1183. Name[1],
  1184. Name[2],
  1185. Name[3],
  1186. Space,
  1187. OperationRegion->U.OperationRegion.Offset,
  1188. OperationRegion->U.OperationRegion.Length);
  1189. return;
  1190. }
  1191. VOID
  1192. AcpipPrintFieldUnit (
  1193. PACPI_OBJECT FieldUnit
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. This routine prints a description of the given Field Unit to the
  1198. debugger.
  1199. Arguments:
  1200. FieldUnit - Supplies a pointer to the Field Unit to print.
  1201. Return Value:
  1202. None.
  1203. --*/
  1204. {
  1205. PSTR FieldUnitType;
  1206. PSTR Name;
  1207. FieldUnitType = "FieldUnit";
  1208. if (FieldUnit->U.FieldUnit.BankRegister != NULL) {
  1209. FieldUnitType = "BankField";
  1210. }
  1211. if (FieldUnit->U.FieldUnit.IndexRegister != NULL) {
  1212. FieldUnitType = "IndexField";
  1213. }
  1214. Name = (PSTR)&(FieldUnit->Name);
  1215. RtlDebugPrint("%s (%c%c%c%c, ",
  1216. FieldUnitType,
  1217. Name[0],
  1218. Name[1],
  1219. Name[2],
  1220. Name[3]);
  1221. switch (FieldUnit->U.FieldUnit.Access) {
  1222. case AcpiFieldAccessAny:
  1223. RtlDebugPrint("AccessAny, ");
  1224. break;
  1225. case AcpiFieldAccessByte:
  1226. RtlDebugPrint("AccessByte, ");
  1227. break;
  1228. case AcpiFieldAccessWord:
  1229. RtlDebugPrint("AccessWord, ");
  1230. break;
  1231. case AcpiFieldAccessDoubleWord:
  1232. RtlDebugPrint("AccessDWord, ");
  1233. break;
  1234. case AcpiFieldAccessQuadWord:
  1235. RtlDebugPrint("AccessQWord, ");
  1236. break;
  1237. case AcpiFieldAccessBuffer:
  1238. RtlDebugPrint("AccessBuffer, ");
  1239. break;
  1240. default:
  1241. RtlDebugPrint("INVALIDACCESS %d, ", FieldUnit->U.FieldUnit.Access);
  1242. break;
  1243. }
  1244. if (FieldUnit->U.FieldUnit.AcquireGlobalLock == FALSE) {
  1245. RtlDebugPrint("No");
  1246. }
  1247. RtlDebugPrint("Lock, ");
  1248. switch (FieldUnit->U.FieldUnit.UpdateRule) {
  1249. case AcpiFieldUpdatePreserve:
  1250. RtlDebugPrint("Preserve, ");
  1251. break;
  1252. case AcpiFieldUpdateWriteAsOnes:
  1253. RtlDebugPrint("WriteAsOnes, ");
  1254. break;
  1255. case AcpiFieldUpdateWriteAsZeros:
  1256. RtlDebugPrint("WriteAsZeros, ");
  1257. break;
  1258. default:
  1259. RtlDebugPrint("INVALIDUPDATERULE %d",
  1260. FieldUnit->U.FieldUnit.UpdateRule);
  1261. break;
  1262. }
  1263. RtlDebugPrint("%I64d)", FieldUnit->U.FieldUnit.BitLength);
  1264. return;
  1265. }
  1266. VOID
  1267. AcpipPrintBufferField (
  1268. PACPI_OBJECT BufferField
  1269. )
  1270. /*++
  1271. Routine Description:
  1272. This routine prints a description of the given Buffer Field to the
  1273. debugger.
  1274. Arguments:
  1275. BufferField - Supplies a pointer to the Buffer Field to print.
  1276. Return Value:
  1277. None.
  1278. --*/
  1279. {
  1280. PSTR Name;
  1281. Name = (PSTR)&(BufferField->Name);
  1282. RtlDebugPrint("BufferField (%c%c%c%c, %I64x, %I64x, 0x%08x)",
  1283. Name[0],
  1284. Name[1],
  1285. Name[2],
  1286. Name[3],
  1287. BufferField->U.BufferField.BitOffset,
  1288. BufferField->U.BufferField.BitLength,
  1289. BufferField->U.BufferField.DestinationObject);
  1290. return;
  1291. }
  1292. //
  1293. // --------------------------------------------------------- Internal Functions
  1294. //
  1295. VOID
  1296. AcpipShiftBufferIntoFieldPosition (
  1297. PVOID Buffer,
  1298. ULONGLONG BitOffset,
  1299. ULONGLONG BitLength,
  1300. ULONG AccessSize
  1301. )
  1302. /*++
  1303. Routine Description:
  1304. This routine shifts a naturally aligned buffer into a field result buffer.
  1305. Arguments:
  1306. Buffer - Supplies a pointer to the source (and destination buffer) to
  1307. shift right.
  1308. BitOffset - Supplies the bit offset of the field. The entire buffer will
  1309. be shifted this many bits right.
  1310. BitLength - Supplies the bit length of the field. Bits after this length
  1311. will be cleared.
  1312. AccessSize - Supplies the access size of the field in bits.
  1313. Return Value:
  1314. None.
  1315. --*/
  1316. {
  1317. ULONGLONG BufferSize;
  1318. PUCHAR CurrentBuffer;
  1319. ULONGLONG CurrentOffset;
  1320. ULONGLONG EndBitOffset;
  1321. ULONGLONG EndByteOffset;
  1322. ULONG Mask;
  1323. ULONG SaveBits;
  1324. ULONG ShiftAmount;
  1325. ULONGLONG StartBitOffset;
  1326. ULONGLONG StartByteOffset;
  1327. ULONG TotalShiftAmount;
  1328. //
  1329. // Shift the results into place if the field is not aligned to the access
  1330. // size.
  1331. //
  1332. StartBitOffset = ALIGN_RANGE_DOWN(BitOffset, AccessSize);
  1333. EndBitOffset = ALIGN_RANGE_UP(BitOffset + BitLength, AccessSize);
  1334. StartByteOffset = StartBitOffset / BITS_PER_BYTE;
  1335. EndByteOffset = EndBitOffset / BITS_PER_BYTE;
  1336. BufferSize = (EndBitOffset - StartBitOffset) / BITS_PER_BYTE;
  1337. TotalShiftAmount = BitOffset - StartBitOffset;
  1338. while (TotalShiftAmount != 0) {
  1339. //
  1340. // Since the shift algorithm deals in byte pointers (so as not to
  1341. // overstep the array), the max that can be shifted in one iteration is
  1342. // an entire byte.
  1343. //
  1344. if (TotalShiftAmount > BITS_PER_BYTE) {
  1345. ShiftAmount = BITS_PER_BYTE;
  1346. } else {
  1347. ShiftAmount = TotalShiftAmount;
  1348. }
  1349. TotalShiftAmount -= ShiftAmount;
  1350. CurrentBuffer = Buffer;
  1351. for (CurrentOffset = 0;
  1352. CurrentOffset < BufferSize - 1;
  1353. CurrentOffset += 1) {
  1354. *CurrentBuffer = (*CurrentBuffer >> ShiftAmount) |
  1355. (*(CurrentBuffer + 1) << (BITS_PER_BYTE - ShiftAmount));
  1356. CurrentBuffer += 1;
  1357. }
  1358. //
  1359. // Do the last one, filled with zeroes.
  1360. //
  1361. *CurrentBuffer = *CurrentBuffer >> ShiftAmount;
  1362. }
  1363. //
  1364. // Clip the unwanted portion on the end of the buffer. Remember that the
  1365. // buffer has already been shifted down by the unaligned bit offset. For
  1366. // example, if the bit field started at bit 1 with a length of 1, then
  1367. // after the right shift of one that has already occurred, 1 bit needs to
  1368. // be saved (and 7 zeroed).
  1369. //
  1370. SaveBits = BitLength & (AccessSize - 1);
  1371. if (SaveBits != 0) {
  1372. CurrentBuffer = Buffer +
  1373. (EndByteOffset - StartByteOffset) -
  1374. (AccessSize / BITS_PER_BYTE);
  1375. for (CurrentOffset = 0;
  1376. CurrentOffset < (AccessSize / BITS_PER_BYTE);
  1377. CurrentOffset += 1) {
  1378. if (SaveBits > BITS_PER_BYTE) {
  1379. SaveBits -= BITS_PER_BYTE;
  1380. } else {
  1381. //
  1382. // Create a mask that has ones for each bit to save, and zeroes
  1383. // for the more significant parts.
  1384. //
  1385. Mask = (1 << SaveBits) - 1;
  1386. *CurrentBuffer &= Mask;
  1387. SaveBits = 0;
  1388. }
  1389. CurrentBuffer += 1;
  1390. }
  1391. }
  1392. return;
  1393. }
  1394. VOID
  1395. AcpipWriteFieldBitsIntoBuffer (
  1396. PVOID FieldBuffer,
  1397. ULONGLONG BitOffset,
  1398. ULONGLONG BitLength,
  1399. ULONG AccessSize,
  1400. PVOID ResultBuffer,
  1401. ULONGLONG ResultBufferSize
  1402. )
  1403. /*++
  1404. Routine Description:
  1405. This routine modifies a result buffer to write the bits from a field into
  1406. it.
  1407. Arguments:
  1408. FieldBuffer - Supplies a pointer to the bit-aligned field buffer.
  1409. BitOffset - Supplies the bit offset from the start of the region
  1410. where this field refers to.
  1411. BitLength - Supplies the size, in bits, of this field. It is assumed that
  1412. the buffer is at least as big as the number of bits in the field
  1413. rounded up to the nearest byte.
  1414. AccessSize - Supplies the access granularity of the result buffer. The
  1415. bit offset rounded down to the access size determines the start bit
  1416. offset of the result buffer (which is assumed to not be the entire
  1417. region).
  1418. ResultBuffer - Supplies a pointer to the buffer, which is assumed to begin
  1419. at the bit offset of the field, rounded down to the nearest access size.
  1420. ResultBufferSize - Supplies the size of the result buffer, in bytes.
  1421. Return Value:
  1422. None.
  1423. --*/
  1424. {
  1425. ULONG AccessSizeRemainder;
  1426. ULONG ByteBitOffset;
  1427. UCHAR CurrentByte;
  1428. UCHAR Data;
  1429. PUCHAR DestinationBuffer;
  1430. ULONGLONG DestinationOffset;
  1431. BOOL ExtraByte;
  1432. UCHAR Mask;
  1433. UCHAR PreviousByteLeftovers;
  1434. ULONG SaveBits;
  1435. PUCHAR SourceBuffer;
  1436. ULONGLONG SourceBufferSize;
  1437. ULONGLONG SourceIndex;
  1438. ULONGLONG StartBitOffset;
  1439. SourceBuffer = FieldBuffer;
  1440. DestinationBuffer = ResultBuffer;
  1441. StartBitOffset = ALIGN_RANGE_DOWN(BitOffset, AccessSize);
  1442. AccessSizeRemainder = (BitOffset - StartBitOffset) / BITS_PER_BYTE;
  1443. ByteBitOffset = (BitOffset - StartBitOffset) & (BITS_PER_BYTE - 1);
  1444. //
  1445. // Align the source buffer size up to the nearest byte of the field.
  1446. //
  1447. SourceBufferSize = ALIGN_RANGE_UP(BitLength, BITS_PER_BYTE) / BITS_PER_BYTE;
  1448. //
  1449. // Determine if there are more destination bytes to write than source bytes
  1450. // provided due to the shifting of the source bits.
  1451. //
  1452. ExtraByte = FALSE;
  1453. if ((ByteBitOffset != 0) &&
  1454. (ALIGN_RANGE_UP(BitLength, BITS_PER_BYTE) <
  1455. ALIGN_RANGE_UP(BitLength + ByteBitOffset, BITS_PER_BYTE))) {
  1456. ExtraByte = TRUE;
  1457. }
  1458. //
  1459. // Read the bits out of the value to write and put them in the result
  1460. // buffer.
  1461. //
  1462. PreviousByteLeftovers = 0;
  1463. for (SourceIndex = 0; SourceIndex < SourceBufferSize; SourceIndex += 1) {
  1464. Data = SourceBuffer[SourceIndex];
  1465. Mask = 0xFF;
  1466. //
  1467. // If the byte's bit offset is not zero, then extra logic needs to
  1468. // apply to include the bits that may get left shifted away.
  1469. //
  1470. if (ByteBitOffset != 0) {
  1471. CurrentByte = Data;
  1472. Data <<= ByteBitOffset;
  1473. //
  1474. // If this is the first byte in the source, there is no previous
  1475. // data to OR into it. Start the mask at the byte's bit offset.
  1476. //
  1477. if (SourceIndex == 0) {
  1478. Mask <<= ByteBitOffset;
  1479. //
  1480. // Otherwise, OR in the bits taken from the previous byte in the
  1481. // source buffer. The mask should be the full byte, unless this is
  1482. // the last byte to write (handled below).
  1483. //
  1484. } else {
  1485. Data |= PreviousByteLeftovers;
  1486. }
  1487. //
  1488. // Some of the bits may have been shifted out of this round. Save
  1489. // the leftovers.
  1490. //
  1491. PreviousByteLeftovers = CurrentByte >>
  1492. (BITS_PER_BYTE - ByteBitOffset);
  1493. }
  1494. //
  1495. // If this is the last byte in the source buffer, potentially clip the
  1496. // mask.
  1497. //
  1498. if ((ExtraByte == FALSE) &&
  1499. (((SourceIndex + 1) * BITS_PER_BYTE) > BitLength)) {
  1500. SaveBits = (BitOffset + BitLength) & (BITS_PER_BYTE - 1);
  1501. Mask &= (1 << SaveBits) - 1;
  1502. }
  1503. //
  1504. // Mask in the appropriate bits to the result buffer.
  1505. //
  1506. DestinationOffset = SourceIndex + AccessSizeRemainder;
  1507. ASSERT(DestinationOffset < ResultBufferSize);
  1508. DestinationBuffer[DestinationOffset] =
  1509. (DestinationBuffer[DestinationOffset] & (~Mask)) | (Data & Mask);
  1510. }
  1511. //
  1512. // Write the extra byte if necessary. The bits are stored in the previous
  1513. // byte's leftovers.
  1514. //
  1515. if (ExtraByte != FALSE) {
  1516. Data = PreviousByteLeftovers;
  1517. SaveBits = (BitOffset + BitLength) & (BITS_PER_BYTE - 1);
  1518. ASSERT(SaveBits != 0);
  1519. Mask = 0xFF & ((1 << SaveBits) - 1);
  1520. DestinationOffset = SourceBufferSize + AccessSizeRemainder;
  1521. ASSERT(DestinationOffset < ResultBufferSize);
  1522. DestinationBuffer[DestinationOffset] =
  1523. (DestinationBuffer[DestinationOffset] & (~Mask)) | (Data & Mask);
  1524. }
  1525. return;
  1526. }