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