xref: /haiku/src/add-ons/kernel/bus_managers/acpi/acpica/components/executer/exfldio.c (revision f2df0cfe93a902842f6f4629ff614f5b3f9bf687)
1 /******************************************************************************
2  *
3  * Module Name: exfldio - Aml Field I/O
4  *
5  *****************************************************************************/
6 
7 /******************************************************************************
8  *
9  * 1. Copyright Notice
10  *
11  * Some or all of this work - Copyright (c) 1999 - 2016, Intel Corp.
12  * All rights reserved.
13  *
14  * 2. License
15  *
16  * 2.1. This is your license from Intel Corp. under its intellectual property
17  * rights. You may have additional license terms from the party that provided
18  * you this software, covering your right to use that party's intellectual
19  * property rights.
20  *
21  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
22  * copy of the source code appearing in this file ("Covered Code") an
23  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
24  * base code distributed originally by Intel ("Original Intel Code") to copy,
25  * make derivatives, distribute, use and display any portion of the Covered
26  * Code in any form, with the right to sublicense such rights; and
27  *
28  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
29  * license (with the right to sublicense), under only those claims of Intel
30  * patents that are infringed by the Original Intel Code, to make, use, sell,
31  * offer to sell, and import the Covered Code and derivative works thereof
32  * solely to the minimum extent necessary to exercise the above copyright
33  * license, and in no event shall the patent license extend to any additions
34  * to or modifications of the Original Intel Code. No other license or right
35  * is granted directly or by implication, estoppel or otherwise;
36  *
37  * The above copyright and patent license is granted only if the following
38  * conditions are met:
39  *
40  * 3. Conditions
41  *
42  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
43  * Redistribution of source code of any substantial portion of the Covered
44  * Code or modification with rights to further distribute source must include
45  * the above Copyright Notice, the above License, this list of Conditions,
46  * and the following Disclaimer and Export Compliance provision. In addition,
47  * Licensee must cause all Covered Code to which Licensee contributes to
48  * contain a file documenting the changes Licensee made to create that Covered
49  * Code and the date of any change. Licensee must include in that file the
50  * documentation of any changes made by any predecessor Licensee. Licensee
51  * must include a prominent statement that the modification is derived,
52  * directly or indirectly, from Original Intel Code.
53  *
54  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55  * Redistribution of source code of any substantial portion of the Covered
56  * Code or modification without rights to further distribute source must
57  * include the following Disclaimer and Export Compliance provision in the
58  * documentation and/or other materials provided with distribution. In
59  * addition, Licensee may not authorize further sublicense of source of any
60  * portion of the Covered Code, and must include terms to the effect that the
61  * license from Licensee to its licensee is limited to the intellectual
62  * property embodied in the software Licensee provides to its licensee, and
63  * not to intellectual property embodied in modifications its licensee may
64  * make.
65  *
66  * 3.3. Redistribution of Executable. Redistribution in executable form of any
67  * substantial portion of the Covered Code or modification must reproduce the
68  * above Copyright Notice, and the following Disclaimer and Export Compliance
69  * provision in the documentation and/or other materials provided with the
70  * distribution.
71  *
72  * 3.4. Intel retains all right, title, and interest in and to the Original
73  * Intel Code.
74  *
75  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
76  * Intel shall be used in advertising or otherwise to promote the sale, use or
77  * other dealings in products derived from or relating to the Covered Code
78  * without prior written authorization from Intel.
79  *
80  * 4. Disclaimer and Export Compliance
81  *
82  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83  * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
84  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
85  * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
86  * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
87  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
88  * PARTICULAR PURPOSE.
89  *
90  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
91  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
92  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
93  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
94  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
95  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
96  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
97  * LIMITED REMEDY.
98  *
99  * 4.3. Licensee shall not export, either directly or indirectly, any of this
100  * software or system incorporating such software without first obtaining any
101  * required license or other approval from the U. S. Department of Commerce or
102  * any other agency or department of the United States Government. In the
103  * event Licensee exports any such software from the United States or
104  * re-exports any such software from a foreign destination, Licensee shall
105  * ensure that the distribution and export/re-export of the software is in
106  * compliance with all laws, regulations, orders, or other restrictions of the
107  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
108  * any of its subsidiaries will export/re-export any technical data, process,
109  * software, or service, directly or indirectly, to any country for which the
110  * United States government or any agency thereof requires an export license,
111  * other governmental approval, or letter of assurance, without first obtaining
112  * such license, approval or letter.
113  *
114  *****************************************************************************/
115 
116 #include "acpi.h"
117 #include "accommon.h"
118 #include "acinterp.h"
119 #include "amlcode.h"
120 #include "acevents.h"
121 #include "acdispat.h"
122 
123 
124 #define _COMPONENT          ACPI_EXECUTER
125         ACPI_MODULE_NAME    ("exfldio")
126 
127 /* Local prototypes */
128 
129 static ACPI_STATUS
130 AcpiExFieldDatumIo (
131     ACPI_OPERAND_OBJECT     *ObjDesc,
132     UINT32                  FieldDatumByteOffset,
133     UINT64                  *Value,
134     UINT32                  ReadWrite);
135 
136 static BOOLEAN
137 AcpiExRegisterOverflow (
138     ACPI_OPERAND_OBJECT     *ObjDesc,
139     UINT64                  Value);
140 
141 static ACPI_STATUS
142 AcpiExSetupRegion (
143     ACPI_OPERAND_OBJECT     *ObjDesc,
144     UINT32                  FieldDatumByteOffset);
145 
146 
147 /*******************************************************************************
148  *
149  * FUNCTION:    AcpiExSetupRegion
150  *
151  * PARAMETERS:  ObjDesc                 - Field to be read or written
152  *              FieldDatumByteOffset    - Byte offset of this datum within the
153  *                                        parent field
154  *
155  * RETURN:      Status
156  *
157  * DESCRIPTION: Common processing for AcpiExExtractFromField and
158  *              AcpiExInsertIntoField. Initialize the Region if necessary and
159  *              validate the request.
160  *
161  ******************************************************************************/
162 
163 static ACPI_STATUS
164 AcpiExSetupRegion (
165     ACPI_OPERAND_OBJECT     *ObjDesc,
166     UINT32                  FieldDatumByteOffset)
167 {
168     ACPI_STATUS             Status = AE_OK;
169     ACPI_OPERAND_OBJECT     *RgnDesc;
170     UINT8                   SpaceId;
171 
172 
173     ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);
174 
175 
176     RgnDesc = ObjDesc->CommonField.RegionObj;
177 
178     /* We must have a valid region */
179 
180     if (RgnDesc->Common.Type != ACPI_TYPE_REGION)
181     {
182         ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
183             RgnDesc->Common.Type,
184             AcpiUtGetObjectTypeName (RgnDesc)));
185 
186         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
187     }
188 
189     SpaceId = RgnDesc->Region.SpaceId;
190 
191     /* Validate the Space ID */
192 
193     if (!AcpiIsValidSpaceId (SpaceId))
194     {
195         ACPI_ERROR ((AE_INFO,
196             "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId));
197         return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
198     }
199 
200     /*
201      * If the Region Address and Length have not been previously evaluated,
202      * evaluate them now and save the results.
203      */
204     if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
205     {
206         Status = AcpiDsGetRegionArguments (RgnDesc);
207         if (ACPI_FAILURE (Status))
208         {
209             return_ACPI_STATUS (Status);
210         }
211     }
212 
213     /*
214      * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
215      * address space and the request cannot be directly validated
216      */
217     if (SpaceId == ACPI_ADR_SPACE_SMBUS ||
218         SpaceId == ACPI_ADR_SPACE_GSBUS ||
219         SpaceId == ACPI_ADR_SPACE_IPMI)
220     {
221         /* SMBus or IPMI has a non-linear address space */
222 
223         return_ACPI_STATUS (AE_OK);
224     }
225 
226 #ifdef ACPI_UNDER_DEVELOPMENT
227     /*
228      * If the Field access is AnyAcc, we can now compute the optimal
229      * access (because we know know the length of the parent region)
230      */
231     if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
232     {
233         if (ACPI_FAILURE (Status))
234         {
235             return_ACPI_STATUS (Status);
236         }
237     }
238 #endif
239 
240     /*
241      * Validate the request. The entire request from the byte offset for a
242      * length of one field datum (access width) must fit within the region.
243      * (Region length is specified in bytes)
244      */
245     if (RgnDesc->Region.Length <
246         (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset +
247         ObjDesc->CommonField.AccessByteWidth))
248     {
249         if (AcpiGbl_EnableInterpreterSlack)
250         {
251             /*
252              * Slack mode only:  We will go ahead and allow access to this
253              * field if it is within the region length rounded up to the next
254              * access width boundary. ACPI_SIZE cast for 64-bit compile.
255              */
256             if (ACPI_ROUND_UP (RgnDesc->Region.Length,
257                     ObjDesc->CommonField.AccessByteWidth) >=
258                 ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +
259                     ObjDesc->CommonField.AccessByteWidth +
260                     FieldDatumByteOffset))
261             {
262                 return_ACPI_STATUS (AE_OK);
263             }
264         }
265 
266         if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
267         {
268             /*
269              * This is the case where the AccessType (AccWord, etc.) is wider
270              * than the region itself. For example, a region of length one
271              * byte, and a field with Dword access specified.
272              */
273             ACPI_ERROR ((AE_INFO,
274                 "Field [%4.4s] access width (%u bytes) "
275                 "too large for region [%4.4s] (length %u)",
276                 AcpiUtGetNodeName (ObjDesc->CommonField.Node),
277                 ObjDesc->CommonField.AccessByteWidth,
278                 AcpiUtGetNodeName (RgnDesc->Region.Node),
279                 RgnDesc->Region.Length));
280         }
281 
282         /*
283          * Offset rounded up to next multiple of field width
284          * exceeds region length, indicate an error
285          */
286         ACPI_ERROR ((AE_INFO,
287             "Field [%4.4s] Base+Offset+Width %u+%u+%u "
288             "is beyond end of region [%4.4s] (length %u)",
289             AcpiUtGetNodeName (ObjDesc->CommonField.Node),
290             ObjDesc->CommonField.BaseByteOffset,
291             FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
292             AcpiUtGetNodeName (RgnDesc->Region.Node),
293             RgnDesc->Region.Length));
294 
295         return_ACPI_STATUS (AE_AML_REGION_LIMIT);
296     }
297 
298     return_ACPI_STATUS (AE_OK);
299 }
300 
301 
302 /*******************************************************************************
303  *
304  * FUNCTION:    AcpiExAccessRegion
305  *
306  * PARAMETERS:  ObjDesc                 - Field to be read
307  *              FieldDatumByteOffset    - Byte offset of this datum within the
308  *                                        parent field
309  *              Value                   - Where to store value (must at least
310  *                                        64 bits)
311  *              Function                - Read or Write flag plus other region-
312  *                                        dependent flags
313  *
314  * RETURN:      Status
315  *
316  * DESCRIPTION: Read or Write a single field datum to an Operation Region.
317  *
318  ******************************************************************************/
319 
320 ACPI_STATUS
321 AcpiExAccessRegion (
322     ACPI_OPERAND_OBJECT     *ObjDesc,
323     UINT32                  FieldDatumByteOffset,
324     UINT64                  *Value,
325     UINT32                  Function)
326 {
327     ACPI_STATUS             Status;
328     ACPI_OPERAND_OBJECT     *RgnDesc;
329     UINT32                  RegionOffset;
330 
331 
332     ACPI_FUNCTION_TRACE (ExAccessRegion);
333 
334 
335     /*
336      * Ensure that the region operands are fully evaluated and verify
337      * the validity of the request
338      */
339     Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
340     if (ACPI_FAILURE (Status))
341     {
342         return_ACPI_STATUS (Status);
343     }
344 
345     /*
346      * The physical address of this field datum is:
347      *
348      * 1) The base of the region, plus
349      * 2) The base offset of the field, plus
350      * 3) The current offset into the field
351      */
352     RgnDesc = ObjDesc->CommonField.RegionObj;
353     RegionOffset =
354         ObjDesc->CommonField.BaseByteOffset +
355         FieldDatumByteOffset;
356 
357     if ((Function & ACPI_IO_MASK) == ACPI_READ)
358     {
359         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
360     }
361     else
362     {
363         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
364     }
365 
366     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
367         " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
368         AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
369         RgnDesc->Region.SpaceId,
370         ObjDesc->CommonField.AccessByteWidth,
371         ObjDesc->CommonField.BaseByteOffset,
372         FieldDatumByteOffset,
373         ACPI_FORMAT_UINT64 (RgnDesc->Region.Address + RegionOffset)));
374 
375     /* Invoke the appropriate AddressSpace/OpRegion handler */
376 
377     Status = AcpiEvAddressSpaceDispatch (RgnDesc, ObjDesc,
378         Function, RegionOffset,
379         ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
380 
381     if (ACPI_FAILURE (Status))
382     {
383         if (Status == AE_NOT_IMPLEMENTED)
384         {
385             ACPI_ERROR ((AE_INFO,
386                 "Region %s (ID=%u) not implemented",
387                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
388                 RgnDesc->Region.SpaceId));
389         }
390         else if (Status == AE_NOT_EXIST)
391         {
392             ACPI_ERROR ((AE_INFO,
393                 "Region %s (ID=%u) has no handler",
394                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
395                 RgnDesc->Region.SpaceId));
396         }
397     }
398 
399     return_ACPI_STATUS (Status);
400 }
401 
402 
403 /*******************************************************************************
404  *
405  * FUNCTION:    AcpiExRegisterOverflow
406  *
407  * PARAMETERS:  ObjDesc                 - Register(Field) to be written
408  *              Value                   - Value to be stored
409  *
410  * RETURN:      TRUE if value overflows the field, FALSE otherwise
411  *
412  * DESCRIPTION: Check if a value is out of range of the field being written.
413  *              Used to check if the values written to Index and Bank registers
414  *              are out of range. Normally, the value is simply truncated
415  *              to fit the field, but this case is most likely a serious
416  *              coding error in the ASL.
417  *
418  ******************************************************************************/
419 
420 static BOOLEAN
421 AcpiExRegisterOverflow (
422     ACPI_OPERAND_OBJECT     *ObjDesc,
423     UINT64                  Value)
424 {
425 
426     if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
427     {
428         /*
429          * The field is large enough to hold the maximum integer, so we can
430          * never overflow it.
431          */
432         return (FALSE);
433     }
434 
435     if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength))
436     {
437         /*
438          * The Value is larger than the maximum value that can fit into
439          * the register.
440          */
441         ACPI_ERROR ((AE_INFO,
442             "Index value 0x%8.8X%8.8X overflows field width 0x%X",
443             ACPI_FORMAT_UINT64 (Value),
444             ObjDesc->CommonField.BitLength));
445 
446         return (TRUE);
447     }
448 
449     /* The Value will fit into the field with no truncation */
450 
451     return (FALSE);
452 }
453 
454 
455 /*******************************************************************************
456  *
457  * FUNCTION:    AcpiExFieldDatumIo
458  *
459  * PARAMETERS:  ObjDesc                 - Field to be read
460  *              FieldDatumByteOffset    - Byte offset of this datum within the
461  *                                        parent field
462  *              Value                   - Where to store value (must be 64 bits)
463  *              ReadWrite               - Read or Write flag
464  *
465  * RETURN:      Status
466  *
467  * DESCRIPTION: Read or Write a single datum of a field. The FieldType is
468  *              demultiplexed here to handle the different types of fields
469  *              (BufferField, RegionField, IndexField, BankField)
470  *
471  ******************************************************************************/
472 
473 static ACPI_STATUS
474 AcpiExFieldDatumIo (
475     ACPI_OPERAND_OBJECT     *ObjDesc,
476     UINT32                  FieldDatumByteOffset,
477     UINT64                  *Value,
478     UINT32                  ReadWrite)
479 {
480     ACPI_STATUS             Status;
481     UINT64                  LocalValue;
482 
483 
484     ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);
485 
486 
487     if (ReadWrite == ACPI_READ)
488     {
489         if (!Value)
490         {
491             LocalValue = 0;
492 
493             /* To support reads without saving return value */
494             Value = &LocalValue;
495         }
496 
497         /* Clear the entire return buffer first, [Very Important!] */
498 
499         *Value = 0;
500     }
501 
502     /*
503      * The four types of fields are:
504      *
505      * BufferField - Read/write from/to a Buffer
506      * RegionField - Read/write from/to a Operation Region.
507      * BankField   - Write to a Bank Register, then read/write from/to an
508      *               OperationRegion
509      * IndexField  - Write to an Index Register, then read/write from/to a
510      *               Data Register
511      */
512     switch (ObjDesc->Common.Type)
513     {
514     case ACPI_TYPE_BUFFER_FIELD:
515         /*
516          * If the BufferField arguments have not been previously evaluated,
517          * evaluate them now and save the results.
518          */
519         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
520         {
521             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
522             if (ACPI_FAILURE (Status))
523             {
524                 return_ACPI_STATUS (Status);
525             }
526         }
527 
528         if (ReadWrite == ACPI_READ)
529         {
530             /*
531              * Copy the data from the source buffer.
532              * Length is the field width in bytes.
533              */
534             memcpy (Value,
535                 (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
536                     ObjDesc->BufferField.BaseByteOffset +
537                     FieldDatumByteOffset,
538                 ObjDesc->CommonField.AccessByteWidth);
539         }
540         else
541         {
542             /*
543              * Copy the data to the target buffer.
544              * Length is the field width in bytes.
545              */
546             memcpy ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
547                 ObjDesc->BufferField.BaseByteOffset +
548                 FieldDatumByteOffset,
549                 Value, ObjDesc->CommonField.AccessByteWidth);
550         }
551 
552         Status = AE_OK;
553         break;
554 
555     case ACPI_TYPE_LOCAL_BANK_FIELD:
556         /*
557          * Ensure that the BankValue is not beyond the capacity of
558          * the register
559          */
560         if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
561                 (UINT64) ObjDesc->BankField.Value))
562         {
563             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
564         }
565 
566         /*
567          * For BankFields, we must write the BankValue to the BankRegister
568          * (itself a RegionField) before we can access the data.
569          */
570         Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
571                     &ObjDesc->BankField.Value,
572                     sizeof (ObjDesc->BankField.Value));
573         if (ACPI_FAILURE (Status))
574         {
575             return_ACPI_STATUS (Status);
576         }
577 
578         /*
579          * Now that the Bank has been selected, fall through to the
580          * RegionField case and write the datum to the Operation Region
581          */
582 
583         /*lint -fallthrough */
584 
585     case ACPI_TYPE_LOCAL_REGION_FIELD:
586         /*
587          * For simple RegionFields, we just directly access the owning
588          * Operation Region.
589          */
590         Status = AcpiExAccessRegion (
591             ObjDesc, FieldDatumByteOffset, Value, ReadWrite);
592         break;
593 
594     case ACPI_TYPE_LOCAL_INDEX_FIELD:
595         /*
596          * Ensure that the IndexValue is not beyond the capacity of
597          * the register
598          */
599         if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
600                 (UINT64) ObjDesc->IndexField.Value))
601         {
602             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
603         }
604 
605         /* Write the index value to the IndexRegister (itself a RegionField) */
606 
607         FieldDatumByteOffset += ObjDesc->IndexField.Value;
608 
609         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
610             "Write to Index Register: Value %8.8X\n",
611             FieldDatumByteOffset));
612 
613         Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
614             &FieldDatumByteOffset, sizeof (FieldDatumByteOffset));
615         if (ACPI_FAILURE (Status))
616         {
617             return_ACPI_STATUS (Status);
618         }
619 
620         if (ReadWrite == ACPI_READ)
621         {
622             /* Read the datum from the DataRegister */
623 
624             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
625                 "Read from Data Register\n"));
626 
627             Status = AcpiExExtractFromField (
628                 ObjDesc->IndexField.DataObj, Value, sizeof (UINT64));
629         }
630         else
631         {
632             /* Write the datum to the DataRegister */
633 
634             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
635                 "Write to Data Register: Value %8.8X%8.8X\n",
636                 ACPI_FORMAT_UINT64 (*Value)));
637 
638             Status = AcpiExInsertIntoField (
639                 ObjDesc->IndexField.DataObj, Value, sizeof (UINT64));
640         }
641         break;
642 
643     default:
644 
645         ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
646             ObjDesc->Common.Type));
647         Status = AE_AML_INTERNAL;
648         break;
649     }
650 
651     if (ACPI_SUCCESS (Status))
652     {
653         if (ReadWrite == ACPI_READ)
654         {
655             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
656                 "Value Read %8.8X%8.8X, Width %u\n",
657                 ACPI_FORMAT_UINT64 (*Value),
658                 ObjDesc->CommonField.AccessByteWidth));
659         }
660         else
661         {
662             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
663                 "Value Written %8.8X%8.8X, Width %u\n",
664                 ACPI_FORMAT_UINT64 (*Value),
665                 ObjDesc->CommonField.AccessByteWidth));
666         }
667     }
668 
669     return_ACPI_STATUS (Status);
670 }
671 
672 
673 /*******************************************************************************
674  *
675  * FUNCTION:    AcpiExWriteWithUpdateRule
676  *
677  * PARAMETERS:  ObjDesc                 - Field to be written
678  *              Mask                    - bitmask within field datum
679  *              FieldValue              - Value to write
680  *              FieldDatumByteOffset    - Offset of datum within field
681  *
682  * RETURN:      Status
683  *
684  * DESCRIPTION: Apply the field update rule to a field write
685  *
686  ******************************************************************************/
687 
688 ACPI_STATUS
689 AcpiExWriteWithUpdateRule (
690     ACPI_OPERAND_OBJECT     *ObjDesc,
691     UINT64                  Mask,
692     UINT64                  FieldValue,
693     UINT32                  FieldDatumByteOffset)
694 {
695     ACPI_STATUS             Status = AE_OK;
696     UINT64                  MergedValue;
697     UINT64                  CurrentValue;
698 
699 
700     ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
701 
702 
703     /* Start with the new bits  */
704 
705     MergedValue = FieldValue;
706 
707     /* If the mask is all ones, we don't need to worry about the update rule */
708 
709     if (Mask != ACPI_UINT64_MAX)
710     {
711         /* Decode the update rule */
712 
713         switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
714         {
715         case AML_FIELD_UPDATE_PRESERVE:
716             /*
717              * Check if update rule needs to be applied (not if mask is all
718              * ones)  The left shift drops the bits we want to ignore.
719              */
720             if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
721                    ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
722             {
723                 /*
724                  * Read the current contents of the byte/word/dword containing
725                  * the field, and merge with the new field value.
726                  */
727                 Status = AcpiExFieldDatumIo (
728                     ObjDesc, FieldDatumByteOffset, &CurrentValue, ACPI_READ);
729                 if (ACPI_FAILURE (Status))
730                 {
731                     return_ACPI_STATUS (Status);
732                 }
733 
734                 MergedValue |= (CurrentValue & ~Mask);
735             }
736             break;
737 
738         case AML_FIELD_UPDATE_WRITE_AS_ONES:
739 
740             /* Set positions outside the field to all ones */
741 
742             MergedValue |= ~Mask;
743             break;
744 
745         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
746 
747             /* Set positions outside the field to all zeros */
748 
749             MergedValue &= Mask;
750             break;
751 
752         default:
753 
754             ACPI_ERROR ((AE_INFO,
755                 "Unknown UpdateRule value: 0x%X",
756                 (ObjDesc->CommonField.FieldFlags &
757                     AML_FIELD_UPDATE_RULE_MASK)));
758             return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
759         }
760     }
761 
762     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
763         "Mask %8.8X%8.8X, DatumOffset %X, Width %X, "
764         "Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
765         ACPI_FORMAT_UINT64 (Mask),
766         FieldDatumByteOffset,
767         ObjDesc->CommonField.AccessByteWidth,
768         ACPI_FORMAT_UINT64 (FieldValue),
769         ACPI_FORMAT_UINT64 (MergedValue)));
770 
771     /* Write the merged value */
772 
773     Status = AcpiExFieldDatumIo (
774         ObjDesc, FieldDatumByteOffset, &MergedValue, ACPI_WRITE);
775 
776     return_ACPI_STATUS (Status);
777 }
778 
779 
780 /*******************************************************************************
781  *
782  * FUNCTION:    AcpiExExtractFromField
783  *
784  * PARAMETERS:  ObjDesc             - Field to be read
785  *              Buffer              - Where to store the field data
786  *              BufferLength        - Length of Buffer
787  *
788  * RETURN:      Status
789  *
790  * DESCRIPTION: Retrieve the current value of the given field
791  *
792  ******************************************************************************/
793 
794 ACPI_STATUS
795 AcpiExExtractFromField (
796     ACPI_OPERAND_OBJECT     *ObjDesc,
797     void                    *Buffer,
798     UINT32                  BufferLength)
799 {
800     ACPI_STATUS             Status;
801     UINT64                  RawDatum;
802     UINT64                  MergedDatum;
803     UINT32                  FieldOffset = 0;
804     UINT32                  BufferOffset = 0;
805     UINT32                  BufferTailBits;
806     UINT32                  DatumCount;
807     UINT32                  FieldDatumCount;
808     UINT32                  AccessBitWidth;
809     UINT32                  i;
810 
811 
812     ACPI_FUNCTION_TRACE (ExExtractFromField);
813 
814 
815     /* Validate target buffer and clear it */
816 
817     if (BufferLength <
818         ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
819     {
820         ACPI_ERROR ((AE_INFO,
821             "Field size %u (bits) is too large for buffer (%u)",
822             ObjDesc->CommonField.BitLength, BufferLength));
823 
824         return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
825     }
826 
827     memset (Buffer, 0, BufferLength);
828     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
829 
830     /* Handle the simple case here */
831 
832     if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
833         (ObjDesc->CommonField.BitLength == AccessBitWidth))
834     {
835         if (BufferLength >= sizeof (UINT64))
836         {
837             Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
838         }
839         else
840         {
841             /* Use RawDatum (UINT64) to handle buffers < 64 bits */
842 
843             Status = AcpiExFieldDatumIo (ObjDesc, 0, &RawDatum, ACPI_READ);
844             memcpy (Buffer, &RawDatum, BufferLength);
845         }
846 
847         return_ACPI_STATUS (Status);
848     }
849 
850 /* TBD: Move to common setup code */
851 
852     /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
853 
854     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
855     {
856         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
857         AccessBitWidth = sizeof (UINT64) * 8;
858     }
859 
860     /* Compute the number of datums (access width data items) */
861 
862     DatumCount = ACPI_ROUND_UP_TO (
863         ObjDesc->CommonField.BitLength, AccessBitWidth);
864 
865     FieldDatumCount = ACPI_ROUND_UP_TO (
866         ObjDesc->CommonField.BitLength +
867         ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);
868 
869     /* Priming read from the field */
870 
871     Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
872     if (ACPI_FAILURE (Status))
873     {
874         return_ACPI_STATUS (Status);
875     }
876     MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
877 
878     /* Read the rest of the field */
879 
880     for (i = 1; i < FieldDatumCount; i++)
881     {
882         /* Get next input datum from the field */
883 
884         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
885         Status = AcpiExFieldDatumIo (
886             ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
887         if (ACPI_FAILURE (Status))
888         {
889             return_ACPI_STATUS (Status);
890         }
891 
892         /*
893          * Merge with previous datum if necessary.
894          *
895          * Note: Before the shift, check if the shift value will be larger than
896          * the integer size. If so, there is no need to perform the operation.
897          * This avoids the differences in behavior between different compilers
898          * concerning shift values larger than the target data width.
899          */
900         if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
901             ACPI_INTEGER_BIT_SIZE)
902         {
903             MergedDatum |= RawDatum <<
904                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
905         }
906 
907         if (i == DatumCount)
908         {
909             break;
910         }
911 
912         /* Write merged datum to target buffer */
913 
914         memcpy (((char *) Buffer) + BufferOffset, &MergedDatum,
915             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
916                 BufferLength - BufferOffset));
917 
918         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
919         MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
920     }
921 
922     /* Mask off any extra bits in the last datum */
923 
924     BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
925     if (BufferTailBits)
926     {
927         MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
928     }
929 
930     /* Write the last datum to the buffer */
931 
932     memcpy (((char *) Buffer) + BufferOffset, &MergedDatum,
933         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
934             BufferLength - BufferOffset));
935 
936     return_ACPI_STATUS (AE_OK);
937 }
938 
939 
940 /*******************************************************************************
941  *
942  * FUNCTION:    AcpiExInsertIntoField
943  *
944  * PARAMETERS:  ObjDesc             - Field to be written
945  *              Buffer              - Data to be written
946  *              BufferLength        - Length of Buffer
947  *
948  * RETURN:      Status
949  *
950  * DESCRIPTION: Store the Buffer contents into the given field
951  *
952  ******************************************************************************/
953 
954 ACPI_STATUS
955 AcpiExInsertIntoField (
956     ACPI_OPERAND_OBJECT     *ObjDesc,
957     void                    *Buffer,
958     UINT32                  BufferLength)
959 {
960     void                    *NewBuffer;
961     ACPI_STATUS             Status;
962     UINT64                  Mask;
963     UINT64                  WidthMask;
964     UINT64                  MergedDatum;
965     UINT64                  RawDatum = 0;
966     UINT32                  FieldOffset = 0;
967     UINT32                  BufferOffset = 0;
968     UINT32                  BufferTailBits;
969     UINT32                  DatumCount;
970     UINT32                  FieldDatumCount;
971     UINT32                  AccessBitWidth;
972     UINT32                  RequiredLength;
973     UINT32                  i;
974 
975 
976     ACPI_FUNCTION_TRACE (ExInsertIntoField);
977 
978 
979     /* Validate input buffer */
980 
981     NewBuffer = NULL;
982     RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
983         ObjDesc->CommonField.BitLength);
984 
985     /*
986      * We must have a buffer that is at least as long as the field
987      * we are writing to. This is because individual fields are
988      * indivisible and partial writes are not supported -- as per
989      * the ACPI specification.
990      */
991     if (BufferLength < RequiredLength)
992     {
993         /* We need to create a new buffer */
994 
995         NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
996         if (!NewBuffer)
997         {
998             return_ACPI_STATUS (AE_NO_MEMORY);
999         }
1000 
1001         /*
1002          * Copy the original data to the new buffer, starting
1003          * at Byte zero. All unused (upper) bytes of the
1004          * buffer will be 0.
1005          */
1006         memcpy ((char *) NewBuffer, (char *) Buffer, BufferLength);
1007         Buffer = NewBuffer;
1008         BufferLength = RequiredLength;
1009     }
1010 
1011 /* TBD: Move to common setup code */
1012 
1013     /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
1014     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
1015     {
1016         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
1017     }
1018 
1019     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
1020 
1021     /*
1022      * Create the bitmasks used for bit insertion.
1023      * Note: This if/else is used to bypass compiler differences with the
1024      * shift operator
1025      */
1026     if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
1027     {
1028         WidthMask = ACPI_UINT64_MAX;
1029     }
1030     else
1031     {
1032         WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth);
1033     }
1034 
1035     Mask = WidthMask &
1036         ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
1037 
1038     /* Compute the number of datums (access width data items) */
1039 
1040     DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
1041         AccessBitWidth);
1042 
1043     FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
1044         ObjDesc->CommonField.StartFieldBitOffset,
1045         AccessBitWidth);
1046 
1047     /* Get initial Datum from the input buffer */
1048 
1049     memcpy (&RawDatum, Buffer,
1050         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
1051             BufferLength - BufferOffset));
1052 
1053     MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
1054 
1055     /* Write the entire field */
1056 
1057     for (i = 1; i < FieldDatumCount; i++)
1058     {
1059         /* Write merged datum to the target field */
1060 
1061         MergedDatum &= Mask;
1062         Status = AcpiExWriteWithUpdateRule (
1063             ObjDesc, Mask, MergedDatum, FieldOffset);
1064         if (ACPI_FAILURE (Status))
1065         {
1066             goto Exit;
1067         }
1068 
1069         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
1070 
1071         /*
1072          * Start new output datum by merging with previous input datum
1073          * if necessary.
1074          *
1075          * Note: Before the shift, check if the shift value will be larger than
1076          * the integer size. If so, there is no need to perform the operation.
1077          * This avoids the differences in behavior between different compilers
1078          * concerning shift values larger than the target data width.
1079          */
1080         if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
1081             ACPI_INTEGER_BIT_SIZE)
1082         {
1083             MergedDatum = RawDatum >>
1084                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
1085         }
1086         else
1087         {
1088             MergedDatum = 0;
1089         }
1090 
1091         Mask = WidthMask;
1092 
1093         if (i == DatumCount)
1094         {
1095             break;
1096         }
1097 
1098         /* Get the next input datum from the buffer */
1099 
1100         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
1101         memcpy (&RawDatum, ((char *) Buffer) + BufferOffset,
1102             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
1103                  BufferLength - BufferOffset));
1104 
1105         MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
1106     }
1107 
1108     /* Mask off any extra bits in the last datum */
1109 
1110     BufferTailBits = (ObjDesc->CommonField.BitLength +
1111         ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;
1112     if (BufferTailBits)
1113     {
1114         Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
1115     }
1116 
1117     /* Write the last datum to the field */
1118 
1119     MergedDatum &= Mask;
1120     Status = AcpiExWriteWithUpdateRule (
1121         ObjDesc, Mask, MergedDatum, FieldOffset);
1122 
1123 Exit:
1124     /* Free temporary buffer if we used one */
1125 
1126     if (NewBuffer)
1127     {
1128         ACPI_FREE (NewBuffer);
1129     }
1130     return_ACPI_STATUS (Status);
1131 }
1132