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