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