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