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