exfldio.c revision 138287
1/******************************************************************************
2 *
3 * Module Name: exfldio - Aml Field I/O
4 *              $Revision: 111 $
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 (AcpiGbl_EnableInterpreterSlack)
216        {
217            /*
218             * Slack mode only:  We will go ahead and allow access to this
219             * field if it is within the region length rounded up to the next
220             * access width boundary.
221             */
222            if (ACPI_ROUND_UP (RgnDesc->Region.Length,
223                                ObjDesc->CommonField.AccessByteWidth) >=
224                (ObjDesc->CommonField.BaseByteOffset +
225                 (ACPI_NATIVE_UINT) ObjDesc->CommonField.AccessByteWidth +
226                 FieldDatumByteOffset))
227            {
228                return_ACPI_STATUS (AE_OK);
229            }
230        }
231
232        if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
233        {
234            /*
235             * This is the case where the AccessType (AccWord, etc.) is wider
236             * than the region itself.  For example, a region of length one
237             * byte, and a field with Dword access specified.
238             */
239            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
240                "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
241                AcpiUtGetNodeName (ObjDesc->CommonField.Node),
242                ObjDesc->CommonField.AccessByteWidth,
243                AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length));
244        }
245
246        /*
247         * Offset rounded up to next multiple of field width
248         * exceeds region length, indicate an error
249         */
250        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
251            "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
252            AcpiUtGetNodeName (ObjDesc->CommonField.Node),
253            ObjDesc->CommonField.BaseByteOffset,
254            FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
255            AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length));
256
257        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
258    }
259
260    return_ACPI_STATUS (AE_OK);
261}
262
263
264/*******************************************************************************
265 *
266 * FUNCTION:    AcpiExAccessRegion
267 *
268 * PARAMETERS:  *ObjDesc                - Field to be read
269 *              FieldDatumByteOffset    - Byte offset of this datum within the
270 *                                        parent field
271 *              *Value                  - Where to store value (must at least
272 *                                        the size of ACPI_INTEGER)
273 *              Function                - Read or Write flag plus other region-
274 *                                        dependent flags
275 *
276 * RETURN:      Status
277 *
278 * DESCRIPTION: Read or Write a single field datum to an Operation Region.
279 *
280 ******************************************************************************/
281
282ACPI_STATUS
283AcpiExAccessRegion (
284    ACPI_OPERAND_OBJECT     *ObjDesc,
285    UINT32                  FieldDatumByteOffset,
286    ACPI_INTEGER            *Value,
287    UINT32                  Function)
288{
289    ACPI_STATUS             Status;
290    ACPI_OPERAND_OBJECT     *RgnDesc;
291    ACPI_PHYSICAL_ADDRESS   Address;
292
293
294    ACPI_FUNCTION_TRACE ("ExAccessRegion");
295
296
297    /*
298     * Ensure that the region operands are fully evaluated and verify
299     * the validity of the request
300     */
301    Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
302    if (ACPI_FAILURE (Status))
303    {
304        return_ACPI_STATUS (Status);
305    }
306
307    /*
308     * The physical address of this field datum is:
309     *
310     * 1) The base of the region, plus
311     * 2) The base offset of the field, plus
312     * 3) The current offset into the field
313     */
314    RgnDesc = ObjDesc->CommonField.RegionObj;
315    Address = RgnDesc->Region.Address
316                + ObjDesc->CommonField.BaseByteOffset
317                + FieldDatumByteOffset;
318
319    if ((Function & ACPI_IO_MASK) == ACPI_READ)
320    {
321        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
322    }
323    else
324    {
325        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
326    }
327
328    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
329        " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
330        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
331        RgnDesc->Region.SpaceId,
332        ObjDesc->CommonField.AccessByteWidth,
333        ObjDesc->CommonField.BaseByteOffset,
334        FieldDatumByteOffset,
335        ACPI_FORMAT_UINT64 (Address)));
336
337    /* Invoke the appropriate AddressSpace/OpRegion handler */
338
339    Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function,
340                    Address, ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
341
342    if (ACPI_FAILURE (Status))
343    {
344        if (Status == AE_NOT_IMPLEMENTED)
345        {
346            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
347                "Region %s(%X) not implemented\n",
348                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
349                RgnDesc->Region.SpaceId));
350        }
351        else if (Status == AE_NOT_EXIST)
352        {
353            ACPI_REPORT_ERROR ((
354                "Region %s(%X) has no handler\n",
355                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
356                RgnDesc->Region.SpaceId));
357        }
358    }
359
360    return_ACPI_STATUS (Status);
361}
362
363
364/*******************************************************************************
365 *
366 * FUNCTION:    AcpiExRegisterOverflow
367 *
368 * PARAMETERS:  *ObjDesc                - Register(Field) to be written
369 *              Value                   - Value to be stored
370 *
371 * RETURN:      TRUE if value overflows the field, FALSE otherwise
372 *
373 * DESCRIPTION: Check if a value is out of range of the field being written.
374 *              Used to check if the values written to Index and Bank registers
375 *              are out of range.  Normally, the value is simply truncated
376 *              to fit the field, but this case is most likely a serious
377 *              coding error in the ASL.
378 *
379 ******************************************************************************/
380
381BOOLEAN
382AcpiExRegisterOverflow (
383    ACPI_OPERAND_OBJECT     *ObjDesc,
384    ACPI_INTEGER            Value)
385{
386
387    if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
388    {
389        /*
390         * The field is large enough to hold the maximum integer, so we can
391         * never overflow it.
392         */
393        return (FALSE);
394    }
395
396    if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength))
397    {
398        /*
399         * The Value is larger than the maximum value that can fit into
400         * the register.
401         */
402        return (TRUE);
403    }
404
405    /* The Value will fit into the field with no truncation */
406
407    return (FALSE);
408}
409
410
411/*******************************************************************************
412 *
413 * FUNCTION:    AcpiExFieldDatumIo
414 *
415 * PARAMETERS:  *ObjDesc                - Field to be read
416 *              FieldDatumByteOffset    - Byte offset of this datum within the
417 *                                        parent field
418 *              *Value                  - Where to store value (must be 64 bits)
419 *              ReadWrite               - Read or Write flag
420 *
421 * RETURN:      Status
422 *
423 * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
424 *              demultiplexed here to handle the different types of fields
425 *              (BufferField, RegionField, IndexField, BankField)
426 *
427 ******************************************************************************/
428
429ACPI_STATUS
430AcpiExFieldDatumIo (
431    ACPI_OPERAND_OBJECT     *ObjDesc,
432    UINT32                  FieldDatumByteOffset,
433    ACPI_INTEGER            *Value,
434    UINT32                  ReadWrite)
435{
436    ACPI_STATUS             Status;
437    ACPI_INTEGER            LocalValue;
438
439
440    ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset);
441
442
443    if (ReadWrite == ACPI_READ)
444    {
445        if (!Value)
446        {
447            LocalValue = 0;
448            Value = &LocalValue;  /* To support reads without saving return value */
449        }
450
451        /* Clear the entire return buffer first, [Very Important!] */
452
453        *Value = 0;
454    }
455
456    /*
457     * The four types of fields are:
458     *
459     * BufferField - Read/write from/to a Buffer
460     * RegionField - Read/write from/to a Operation Region.
461     * BankField   - Write to a Bank Register, then read/write from/to an OpRegion
462     * IndexField  - Write to an Index Register, then read/write from/to a Data Register
463     */
464    switch (ACPI_GET_OBJECT_TYPE (ObjDesc))
465    {
466    case ACPI_TYPE_BUFFER_FIELD:
467        /*
468         * If the BufferField arguments have not been previously evaluated,
469         * evaluate them now and save the results.
470         */
471        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
472        {
473            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
474            if (ACPI_FAILURE (Status))
475            {
476                return_ACPI_STATUS (Status);
477            }
478        }
479
480        if (ReadWrite == ACPI_READ)
481        {
482            /*
483             * Copy the data from the source buffer.
484             * Length is the field width in bytes.
485             */
486            ACPI_MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer
487                            + ObjDesc->BufferField.BaseByteOffset
488                            + FieldDatumByteOffset,
489                            ObjDesc->CommonField.AccessByteWidth);
490        }
491        else
492        {
493            /*
494             * Copy the data to the target buffer.
495             * Length is the field width in bytes.
496             */
497            ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer
498                    + ObjDesc->BufferField.BaseByteOffset
499                    + FieldDatumByteOffset,
500                    Value, ObjDesc->CommonField.AccessByteWidth);
501        }
502
503        Status = AE_OK;
504        break;
505
506
507    case ACPI_TYPE_LOCAL_BANK_FIELD:
508
509        /* Ensure that the BankValue is not beyond the capacity of the register */
510
511        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
512                                    (ACPI_INTEGER) ObjDesc->BankField.Value))
513        {
514            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
515        }
516
517        /*
518         * For BankFields, we must write the BankValue to the BankRegister
519         * (itself a RegionField) before we can access the data.
520         */
521        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
522                                &ObjDesc->BankField.Value,
523                                sizeof (ObjDesc->BankField.Value));
524        if (ACPI_FAILURE (Status))
525        {
526            return_ACPI_STATUS (Status);
527        }
528
529        /*
530         * Now that the Bank has been selected, fall through to the
531         * RegionField case and write the datum to the Operation Region
532         */
533
534        /*lint -fallthrough */
535
536
537    case ACPI_TYPE_LOCAL_REGION_FIELD:
538        /*
539         * For simple RegionFields, we just directly access the owning
540         * Operation Region.
541         */
542        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
543                        ReadWrite);
544        break;
545
546
547    case ACPI_TYPE_LOCAL_INDEX_FIELD:
548
549
550        /* Ensure that the IndexValue is not beyond the capacity of the register */
551
552        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
553                                    (ACPI_INTEGER) ObjDesc->IndexField.Value))
554        {
555            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
556        }
557
558        /* Write the index value to the IndexRegister (itself a RegionField) */
559
560        FieldDatumByteOffset += ObjDesc->IndexField.Value;
561
562        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
563                "Write to Index Register: Value %8.8X\n",
564                FieldDatumByteOffset));
565
566        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
567                                &FieldDatumByteOffset,
568                                sizeof (FieldDatumByteOffset));
569        if (ACPI_FAILURE (Status))
570        {
571            return_ACPI_STATUS (Status);
572        }
573
574        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
575                "I/O to Data Register: ValuePtr %p\n",
576                Value));
577
578        if (ReadWrite == ACPI_READ)
579        {
580            /* Read the datum from the DataRegister */
581
582            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
583                            Value, sizeof (ACPI_INTEGER));
584        }
585        else
586        {
587            /* Write the datum to the DataRegister */
588
589            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
590                            Value, sizeof (ACPI_INTEGER));
591        }
592        break;
593
594
595    default:
596
597        ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n",
598            ACPI_GET_OBJECT_TYPE (ObjDesc)));
599        Status = AE_AML_INTERNAL;
600        break;
601    }
602
603    if (ACPI_SUCCESS (Status))
604    {
605        if (ReadWrite == ACPI_READ)
606        {
607            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n",
608                                ACPI_FORMAT_UINT64 (*Value),
609                                ObjDesc->CommonField.AccessByteWidth));
610        }
611        else
612        {
613            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n",
614                                ACPI_FORMAT_UINT64 (*Value),
615                                ObjDesc->CommonField.AccessByteWidth));
616        }
617    }
618
619    return_ACPI_STATUS (Status);
620}
621
622
623/*******************************************************************************
624 *
625 * FUNCTION:    AcpiExWriteWithUpdateRule
626 *
627 * PARAMETERS:  *ObjDesc            - Field to be set
628 *              Value               - Value to store
629 *
630 * RETURN:      Status
631 *
632 * DESCRIPTION: Apply the field update rule to a field write
633 *
634 ******************************************************************************/
635
636ACPI_STATUS
637AcpiExWriteWithUpdateRule (
638    ACPI_OPERAND_OBJECT     *ObjDesc,
639    ACPI_INTEGER            Mask,
640    ACPI_INTEGER            FieldValue,
641    UINT32                  FieldDatumByteOffset)
642{
643    ACPI_STATUS             Status = AE_OK;
644    ACPI_INTEGER            MergedValue;
645    ACPI_INTEGER            CurrentValue;
646
647
648    ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
649
650
651    /* Start with the new bits  */
652
653    MergedValue = FieldValue;
654
655    /* If the mask is all ones, we don't need to worry about the update rule */
656
657    if (Mask != ACPI_INTEGER_MAX)
658    {
659        /* Decode the update rule */
660
661        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
662        {
663        case AML_FIELD_UPDATE_PRESERVE:
664            /*
665             * Check if update rule needs to be applied (not if mask is all
666             * ones)  The left shift drops the bits we want to ignore.
667             */
668            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
669                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
670            {
671                /*
672                 * Read the current contents of the byte/word/dword containing
673                 * the field, and merge with the new field value.
674                 */
675                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
676                                &CurrentValue, ACPI_READ);
677                if (ACPI_FAILURE (Status))
678                {
679                    return_ACPI_STATUS (Status);
680                }
681
682                MergedValue |= (CurrentValue & ~Mask);
683            }
684            break;
685
686        case AML_FIELD_UPDATE_WRITE_AS_ONES:
687
688            /* Set positions outside the field to all ones */
689
690            MergedValue |= ~Mask;
691            break;
692
693        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
694
695            /* Set positions outside the field to all zeros */
696
697            MergedValue &= Mask;
698            break;
699
700        default:
701
702            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
703                "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n",
704                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
705            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
706        }
707    }
708
709    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
710        "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
711        ACPI_FORMAT_UINT64 (Mask),
712        FieldDatumByteOffset,
713        ObjDesc->CommonField.AccessByteWidth,
714        ACPI_FORMAT_UINT64 (FieldValue),
715        ACPI_FORMAT_UINT64 (MergedValue)));
716
717    /* Write the merged value */
718
719    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
720                    &MergedValue, ACPI_WRITE);
721
722    return_ACPI_STATUS (Status);
723}
724
725
726/*******************************************************************************
727 *
728 * FUNCTION:    AcpiExGetBufferDatum
729 *
730 * PARAMETERS:  Datum               - Where the Datum is returned
731 *              Buffer              - Raw field buffer
732 *              BufferLength        - Entire length (used for big-endian only)
733 *              ByteGranularity     - 1/2/4/8 Granularity of the field
734 *                                    (aka Datum Size)
735 *              BufferOffset        - Datum offset into the buffer
736 *
737 * RETURN:      none
738 *
739 * DESCRIPTION: Get a datum from the buffer according to the buffer field
740 *              byte granularity
741 *
742 ******************************************************************************/
743
744void
745AcpiExGetBufferDatum (
746    ACPI_INTEGER            *Datum,
747    void                    *Buffer,
748    UINT32                  BufferLength,
749    UINT32                  ByteGranularity,
750    UINT32                  BufferOffset)
751{
752    UINT32                  Index;
753
754
755    ACPI_FUNCTION_TRACE_U32 ("ExGetBufferDatum", ByteGranularity);
756
757
758    /* Get proper index into buffer (handles big/little endian) */
759
760    Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity);
761
762    /* Move the requested number of bytes */
763
764    switch (ByteGranularity)
765    {
766    case ACPI_FIELD_BYTE_GRANULARITY:
767
768        *Datum = ((UINT8 *) Buffer) [Index];
769        break;
770
771    case ACPI_FIELD_WORD_GRANULARITY:
772
773        ACPI_MOVE_16_TO_64 (Datum, &(((UINT16 *) Buffer) [Index]));
774        break;
775
776    case ACPI_FIELD_DWORD_GRANULARITY:
777
778        ACPI_MOVE_32_TO_64 (Datum, &(((UINT32 *) Buffer) [Index]));
779        break;
780
781    case ACPI_FIELD_QWORD_GRANULARITY:
782
783        ACPI_MOVE_64_TO_64 (Datum, &(((UINT64 *) Buffer) [Index]));
784        break;
785
786    default:
787        /* Should not get here */
788        break;
789    }
790
791    return_VOID;
792}
793
794
795/*******************************************************************************
796 *
797 * FUNCTION:    AcpiExSetBufferDatum
798 *
799 * PARAMETERS:  MergedDatum         - Value to store
800 *              Buffer              - Receiving buffer
801 *              BufferLength        - Entire length (used for big-endian only)
802 *              ByteGranularity     - 1/2/4/8 Granularity of the field
803 *                                    (aka Datum Size)
804 *              BufferOffset        - Datum offset into the buffer
805 *
806 * RETURN:      none
807 *
808 * DESCRIPTION: Store the merged datum to the buffer according to the
809 *              byte granularity
810 *
811 ******************************************************************************/
812
813void
814AcpiExSetBufferDatum (
815    ACPI_INTEGER            MergedDatum,
816    void                    *Buffer,
817    UINT32                  BufferLength,
818    UINT32                  ByteGranularity,
819    UINT32                  BufferOffset)
820{
821    UINT32                  Index;
822
823
824    ACPI_FUNCTION_TRACE_U32 ("ExSetBufferDatum", ByteGranularity);
825
826
827    /* Get proper index into buffer (handles big/little endian) */
828
829    Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity);
830
831    /* Move the requested number of bytes */
832
833    switch (ByteGranularity)
834    {
835    case ACPI_FIELD_BYTE_GRANULARITY:
836
837        ((UINT8 *) Buffer) [Index] = (UINT8) MergedDatum;
838        break;
839
840    case ACPI_FIELD_WORD_GRANULARITY:
841
842        ACPI_MOVE_64_TO_16 (&(((UINT16 *) Buffer)[Index]), &MergedDatum);
843        break;
844
845    case ACPI_FIELD_DWORD_GRANULARITY:
846
847        ACPI_MOVE_64_TO_32 (&(((UINT32 *) Buffer)[Index]), &MergedDatum);
848        break;
849
850    case ACPI_FIELD_QWORD_GRANULARITY:
851
852        ACPI_MOVE_64_TO_64 (&(((UINT64 *) Buffer)[Index]), &MergedDatum);
853        break;
854
855    default:
856        /* Should not get here */
857        break;
858    }
859
860    return_VOID;
861}
862
863
864/*******************************************************************************
865 *
866 * FUNCTION:    AcpiExCommonBufferSetup
867 *
868 * PARAMETERS:  ObjDesc             - Field object
869 *              BufferLength        - Length of caller's buffer
870 *              DatumCount          - Where the DatumCount is returned
871 *
872 * RETURN:      Status, DatumCount
873 *
874 * DESCRIPTION: Common code to validate the incoming buffer size and compute
875 *              the number of field "datums" that must be read or written.
876 *              A "datum" is the smallest unit that can be read or written
877 *              to the field, it is either 1,2,4, or 8 bytes.
878 *
879 ******************************************************************************/
880
881ACPI_STATUS
882AcpiExCommonBufferSetup (
883    ACPI_OPERAND_OBJECT     *ObjDesc,
884    UINT32                  BufferLength,
885    UINT32                  *DatumCount)
886{
887    UINT32                  ByteFieldLength;
888    UINT32                  ActualByteFieldLength;
889
890
891    ACPI_FUNCTION_TRACE ("ExCommonBufferSetup");
892
893
894    /*
895     * Incoming buffer must be at least as long as the field, we do not
896     * allow "partial" field reads/writes.  We do not care if the buffer is
897     * larger than the field, this typically happens when an integer is
898     * read/written to a field that is actually smaller than an integer.
899     */
900    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (
901                            ObjDesc->CommonField.BitLength);
902    if (ByteFieldLength > BufferLength)
903    {
904        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
905            "Field size %X (bytes) is too large for buffer (%X)\n",
906            ByteFieldLength, BufferLength));
907
908        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
909    }
910
911    /*
912     * Create "actual" field byte count (minimum number of bytes that
913     * must be read), then convert to datum count (minimum number
914     * of datum-sized units that must be read)
915     */
916    ActualByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (
917                                ObjDesc->CommonField.StartFieldBitOffset +
918                                ObjDesc->CommonField.BitLength);
919
920
921    *DatumCount = ACPI_ROUND_UP_TO (ActualByteFieldLength,
922                        ObjDesc->CommonField.AccessByteWidth);
923
924    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
925        "BufferBytes %X, ActualBytes %X, Datums %X, ByteGran %X\n",
926        ByteFieldLength, ActualByteFieldLength,
927        *DatumCount, ObjDesc->CommonField.AccessByteWidth));
928
929    return_ACPI_STATUS (AE_OK);
930}
931
932
933/*******************************************************************************
934 *
935 * FUNCTION:    AcpiExExtractFromField
936 *
937 * PARAMETERS:  ObjDesc             - Field to be read
938 *              Buffer              - Where to store the field data
939 *              BufferLength        - Length of Buffer
940 *
941 * RETURN:      Status
942 *
943 * DESCRIPTION: Retrieve the current value of the given field
944 *
945 ******************************************************************************/
946
947ACPI_STATUS
948AcpiExExtractFromField (
949    ACPI_OPERAND_OBJECT     *ObjDesc,
950    void                    *Buffer,
951    UINT32                  BufferLength)
952{
953    ACPI_STATUS             Status;
954    UINT32                  FieldDatumByteOffset;
955    UINT32                  BufferDatumOffset;
956    ACPI_INTEGER            PreviousRawDatum = 0;
957    ACPI_INTEGER            ThisRawDatum = 0;
958    ACPI_INTEGER            MergedDatum = 0;
959    UINT32                  DatumCount;
960    UINT32                  i;
961
962
963    ACPI_FUNCTION_TRACE ("ExExtractFromField");
964
965
966    /* Validate buffer, compute number of datums */
967
968    Status = AcpiExCommonBufferSetup (ObjDesc, BufferLength, &DatumCount);
969    if (ACPI_FAILURE (Status))
970    {
971        return_ACPI_STATUS (Status);
972    }
973
974    /*
975     * Clear the caller's buffer (the whole buffer length as given)
976     * This is very important, especially in the cases where the buffer
977     * is longer than the size of the field.
978     */
979    ACPI_MEMSET (Buffer, 0, BufferLength);
980
981    FieldDatumByteOffset = 0;
982    BufferDatumOffset= 0;
983
984    /* Read the entire field */
985
986    for (i = 0; i < DatumCount; i++)
987    {
988        Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
989                        &ThisRawDatum, ACPI_READ);
990        if (ACPI_FAILURE (Status))
991        {
992            return_ACPI_STATUS (Status);
993        }
994
995        /* We might actually be done if the request fits in one datum */
996
997        if ((DatumCount == 1) &&
998            (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
999        {
1000            /* 1) Shift the valid data bits down to start at bit 0 */
1001
1002            MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1003
1004            /* 2) Mask off any upper unused bits (bits not part of the field) */
1005
1006            if (ObjDesc->CommonField.EndBufferValidBits)
1007            {
1008                MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
1009            }
1010
1011            /* Store the datum to the caller buffer */
1012
1013            AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1014                    ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1015
1016            return_ACPI_STATUS (AE_OK);
1017        }
1018
1019        /* Special handling for the last datum to ignore extra bits */
1020
1021        if ((i >= (DatumCount -1))           &&
1022            (ObjDesc->CommonField.EndFieldValidBits))
1023        {
1024            /*
1025             * This is the last iteration of the loop.  We need to clear
1026             * any unused bits (bits that are not part of this field) before
1027             * we store the final merged datum into the caller buffer.
1028             */
1029            ThisRawDatum &=
1030                ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1031        }
1032
1033        /*
1034         * Create the (possibly) merged datum to be stored to the caller buffer
1035         */
1036        if (ObjDesc->CommonField.StartFieldBitOffset == 0)
1037        {
1038            /* Field is not skewed and we can just copy the datum */
1039
1040            AcpiExSetBufferDatum (ThisRawDatum, Buffer, BufferLength,
1041                    ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1042            BufferDatumOffset++;
1043        }
1044        else
1045        {
1046            /* Not aligned -- on the first iteration, just save the datum */
1047
1048            if (i != 0)
1049            {
1050                /*
1051                 * Put together the appropriate bits of the two raw data to make a
1052                 * single complete field datum
1053                 *
1054                 * 1) Normalize the first datum down to bit 0
1055                 */
1056                MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1057
1058                /* 2) Insert the second datum "above" the first datum */
1059
1060                MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
1061
1062                AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1063                        ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1064                BufferDatumOffset++;
1065            }
1066
1067            /*
1068             * Save the raw datum that was just acquired since it may contain bits
1069             * of the *next* field datum
1070             */
1071            PreviousRawDatum = ThisRawDatum;
1072        }
1073
1074        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1075    }
1076
1077    /* For non-aligned case, there is one last datum to insert */
1078
1079    if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1080    {
1081        MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1082
1083        AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1084                ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1085    }
1086
1087    return_ACPI_STATUS (AE_OK);
1088}
1089
1090
1091/*******************************************************************************
1092 *
1093 * FUNCTION:    AcpiExInsertIntoField
1094 *
1095 * PARAMETERS:  ObjDesc             - Field to be written
1096 *              Buffer              - Data to be written
1097 *              BufferLength        - Length of Buffer
1098 *
1099 * RETURN:      Status
1100 *
1101 * DESCRIPTION: Store the Buffer contents into the given field
1102 *
1103 ******************************************************************************/
1104
1105ACPI_STATUS
1106AcpiExInsertIntoField (
1107    ACPI_OPERAND_OBJECT     *ObjDesc,
1108    void                    *Buffer,
1109    UINT32                  BufferLength)
1110{
1111    ACPI_STATUS             Status;
1112    UINT32                  FieldDatumByteOffset;
1113    UINT32                  DatumOffset;
1114    ACPI_INTEGER            Mask;
1115    ACPI_INTEGER            MergedDatum;
1116    ACPI_INTEGER            PreviousRawDatum;
1117    ACPI_INTEGER            ThisRawDatum;
1118    UINT32                  DatumCount;
1119
1120
1121    ACPI_FUNCTION_TRACE ("ExInsertIntoField");
1122
1123
1124    /* Validate buffer, compute number of datums */
1125
1126    Status = AcpiExCommonBufferSetup (ObjDesc, BufferLength, &DatumCount);
1127    if (ACPI_FAILURE (Status))
1128    {
1129        return_ACPI_STATUS (Status);
1130    }
1131
1132    /*
1133     * Break the request into up to three parts (similar to an I/O request):
1134     * 1) non-aligned part at start
1135     * 2) aligned part in middle
1136     * 3) non-aligned part at the end
1137     */
1138    FieldDatumByteOffset = 0;
1139    DatumOffset= 0;
1140
1141    /* Get a single datum from the caller's buffer */
1142
1143    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer, BufferLength,
1144            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1145
1146    /*
1147     * Part1:
1148     * Write a partial field datum if field does not begin on a datum boundary
1149     * Note: The code in this section also handles the aligned case
1150     *
1151     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
1152     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
1153     *
1154     * Mask off bits that are "below" the field (if any)
1155     */
1156    Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
1157
1158    /* If the field fits in one datum, may need to mask upper bits */
1159
1160    if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
1161         ObjDesc->CommonField.EndFieldValidBits)
1162    {
1163        /* There are bits above the field, mask them off also */
1164
1165        Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1166    }
1167
1168    /* Shift and mask the value into the field position */
1169
1170    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1171    MergedDatum &= Mask;
1172
1173    /* Apply the update rule (if necessary) and write the datum to the field */
1174
1175    Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1176                        FieldDatumByteOffset);
1177    if (ACPI_FAILURE (Status))
1178    {
1179        return_ACPI_STATUS (Status);
1180    }
1181
1182    /* We just wrote the first datum */
1183
1184    DatumOffset++;
1185
1186    /* If the entire field fits within one datum, we are done. */
1187
1188    if ((DatumCount == 1) &&
1189       (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
1190    {
1191        return_ACPI_STATUS (AE_OK);
1192    }
1193
1194    /*
1195     * Part2:
1196     * Write the aligned data.
1197     *
1198     * We don't need to worry about the update rule for these data, because
1199     * all of the bits in each datum are part of the field.
1200     *
1201     * The last datum must be special cased because it might contain bits
1202     * that are not part of the field -- therefore the "update rule" must be
1203     * applied in Part3 below.
1204     */
1205    while (DatumOffset < DatumCount)
1206    {
1207        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1208
1209        /*
1210         * Get the next raw buffer datum.  It may contain bits of the previous
1211         * field datum
1212         */
1213        AcpiExGetBufferDatum (&ThisRawDatum, Buffer, BufferLength,
1214                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1215
1216        /* Create the field datum based on the field alignment */
1217
1218        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1219        {
1220            /*
1221             * Put together appropriate bits of the two raw buffer data to make
1222             * a single complete field datum
1223             */
1224            MergedDatum =
1225                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
1226                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1227        }
1228        else
1229        {
1230            /* Field began aligned on datum boundary */
1231
1232            MergedDatum = ThisRawDatum;
1233        }
1234
1235        /*
1236         * Special handling for the last datum if the field does NOT end on
1237         * a datum boundary.  Update Rule must be applied to the bits outside
1238         * the field.
1239         */
1240        DatumOffset++;
1241        if ((DatumOffset == DatumCount) &&
1242            (ObjDesc->CommonField.EndFieldValidBits))
1243        {
1244            /*
1245             * If there are dangling non-aligned bits, perform one more merged write
1246             * Else - field is aligned at the end, no need for any more writes
1247             */
1248
1249            /*
1250             * Part3:
1251             * This is the last datum and the field does not end on a datum boundary.
1252             * Build the partial datum and write with the update rule.
1253             *
1254             * Mask off the unused bits above (after) the end-of-field
1255             */
1256            Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1257            MergedDatum &= Mask;
1258
1259            /* Write the last datum with the update rule */
1260
1261            Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1262                                FieldDatumByteOffset);
1263            if (ACPI_FAILURE (Status))
1264            {
1265                return_ACPI_STATUS (Status);
1266            }
1267        }
1268        else
1269        {
1270            /* Normal (aligned) case -- write the completed datum */
1271
1272            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
1273                            &MergedDatum, ACPI_WRITE);
1274            if (ACPI_FAILURE (Status))
1275            {
1276                return_ACPI_STATUS (Status);
1277            }
1278        }
1279
1280        /*
1281         * Save the most recent datum since it may contain bits of the *next*
1282         * field datum.  Update current byte offset.
1283         */
1284        PreviousRawDatum = ThisRawDatum;
1285    }
1286
1287    return_ACPI_STATUS (Status);
1288}
1289
1290
1291