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