exfldio.c revision 126372
1/******************************************************************************
2 *
3 * Module Name: exfldio - Aml Field I/O
4 *              $Revision: 103 $
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_DEBUG_PRINT ((ACPI_DB_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:    AcpiExExtractFromField
850 *
851 * PARAMETERS:  *ObjDesc            - Field to be read
852 *              *Value              - Where to store value
853 *
854 * RETURN:      Status
855 *
856 * DESCRIPTION: Retrieve the value of the given field
857 *
858 ******************************************************************************/
859
860ACPI_STATUS
861AcpiExExtractFromField (
862    ACPI_OPERAND_OBJECT     *ObjDesc,
863    void                    *Buffer,
864    UINT32                  BufferLength)
865{
866    ACPI_STATUS             Status;
867    UINT32                  FieldDatumByteOffset;
868    UINT32                  BufferDatumOffset;
869    ACPI_INTEGER            PreviousRawDatum = 0;
870    ACPI_INTEGER            ThisRawDatum = 0;
871    ACPI_INTEGER            MergedDatum = 0;
872    UINT32                  ByteFieldLength;
873    UINT32                  DatumCount;
874    UINT32                  i;
875
876
877    ACPI_FUNCTION_TRACE ("ExExtractFromField");
878
879
880    /*
881     * The field must fit within the caller's buffer
882     */
883    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
884    if (ByteFieldLength > BufferLength)
885    {
886        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
887            "Field size %X (bytes) too large for buffer (%X)\n",
888            ByteFieldLength, BufferLength));
889
890        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
891    }
892
893    /* Convert field byte count to datum count, round up if necessary */
894
895    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength,
896                              ObjDesc->CommonField.AccessByteWidth);
897
898    /*
899     * If the field is not aligned on a datum boundary and does not
900     * fit within a single datum, we must read an extra datum.
901     *
902     * We could just split the aligned and non-aligned cases since the
903     * aligned case is so very simple, but this would require more code.
904     */
905    if ((ObjDesc->CommonField.EndFieldValidBits != 0)         &&
906        (!(ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM)))
907    {
908        DatumCount++;
909    }
910
911    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
912        "ByteLen %X, DatumLen %X, ByteGran %X\n",
913        ByteFieldLength, DatumCount,ObjDesc->CommonField.AccessByteWidth));
914
915    /*
916     * Clear the caller's buffer (the whole buffer length as given)
917     * This is very important, especially in the cases where the buffer
918     * is longer than the size of the field.
919     */
920    ACPI_MEMSET (Buffer, 0, BufferLength);
921
922    FieldDatumByteOffset = 0;
923    BufferDatumOffset= 0;
924
925    /* Read the entire field */
926
927    for (i = 0; i < DatumCount; i++)
928    {
929        Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
930                        &ThisRawDatum, ACPI_READ);
931        if (ACPI_FAILURE (Status))
932        {
933            return_ACPI_STATUS (Status);
934        }
935
936        /* We might actually be done if the request fits in one datum */
937
938        if ((DatumCount == 1) &&
939            (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
940        {
941            /* 1) Shift the valid data bits down to start at bit 0 */
942
943            MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
944
945            /* 2) Mask off any upper unused bits (bits not part of the field) */
946
947            if (ObjDesc->CommonField.EndBufferValidBits)
948            {
949                MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
950            }
951
952            /* Store the datum to the caller buffer */
953
954            AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
955                    ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
956
957            return_ACPI_STATUS (AE_OK);
958        }
959
960        /* Special handling for the last datum to ignore extra bits */
961
962        if ((i >= (DatumCount -1))           &&
963            (ObjDesc->CommonField.EndFieldValidBits))
964        {
965            /*
966             * This is the last iteration of the loop.  We need to clear
967             * any unused bits (bits that are not part of this field) before
968             * we store the final merged datum into the caller buffer.
969             */
970            ThisRawDatum &=
971                ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
972        }
973
974        /*
975         * Create the (possibly) merged datum to be stored to the caller buffer
976         */
977        if (ObjDesc->CommonField.StartFieldBitOffset == 0)
978        {
979            /* Field is not skewed and we can just copy the datum */
980
981            AcpiExSetBufferDatum (ThisRawDatum, Buffer, BufferLength,
982                    ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
983            BufferDatumOffset++;
984        }
985        else
986        {
987            /* Not aligned -- on the first iteration, just save the datum */
988
989            if (i != 0)
990            {
991                /*
992                 * Put together the appropriate bits of the two raw data to make a
993                 * single complete field datum
994                 *
995                 * 1) Normalize the first datum down to bit 0
996                 */
997                MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
998
999                /* 2) Insert the second datum "above" the first datum */
1000
1001                MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
1002
1003                AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1004                        ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1005                BufferDatumOffset++;
1006            }
1007
1008            /*
1009             * Save the raw datum that was just acquired since it may contain bits
1010             * of the *next* field datum
1011             */
1012            PreviousRawDatum = ThisRawDatum;
1013        }
1014
1015        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1016    }
1017
1018    /* For non-aligned case, there is one last datum to insert */
1019
1020    if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1021    {
1022        MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1023
1024        AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1025                ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1026    }
1027
1028    return_ACPI_STATUS (AE_OK);
1029}
1030
1031
1032/*******************************************************************************
1033 *
1034 * FUNCTION:    AcpiExInsertIntoField
1035 *
1036 * PARAMETERS:  *ObjDesc            - Field to be set
1037 *              Buffer              - Value to store
1038 *
1039 * RETURN:      Status
1040 *
1041 * DESCRIPTION: Store the value into the given field
1042 *
1043 ******************************************************************************/
1044
1045ACPI_STATUS
1046AcpiExInsertIntoField (
1047    ACPI_OPERAND_OBJECT     *ObjDesc,
1048    void                    *Buffer,
1049    UINT32                  BufferLength)
1050{
1051    ACPI_STATUS             Status;
1052    UINT32                  FieldDatumByteOffset;
1053    UINT32                  DatumOffset;
1054    ACPI_INTEGER            Mask;
1055    ACPI_INTEGER            MergedDatum;
1056    ACPI_INTEGER            PreviousRawDatum;
1057    ACPI_INTEGER            ThisRawDatum;
1058    UINT32                  ByteFieldLength;
1059    UINT32                  DatumCount;
1060
1061
1062    ACPI_FUNCTION_TRACE ("ExInsertIntoField");
1063
1064
1065    /*
1066     * Incoming buffer must be at least as long as the field, we do not
1067     * allow "partial" field writes.  We do not care if the buffer is
1068     * larger than the field, this typically happens when an integer is
1069     * written to a field that is actually smaller than an integer.
1070     */
1071    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (
1072                            ObjDesc->CommonField.BitLength);
1073    if (BufferLength < ByteFieldLength)
1074    {
1075        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
1076            "Buffer length %X too small for field %X\n",
1077            BufferLength, ByteFieldLength));
1078
1079        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
1080    }
1081
1082    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (
1083                            ObjDesc->CommonField.StartFieldBitOffset +
1084                            ObjDesc->CommonField.BitLength);
1085
1086    /* Convert byte count to datum count, round up if necessary */
1087
1088    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength,
1089                                   ObjDesc->CommonField.AccessByteWidth);
1090
1091    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
1092        "Bytes %X, Datums %X, ByteGran %X\n",
1093        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessByteWidth));
1094
1095    /*
1096     * Break the request into up to three parts (similar to an I/O request):
1097     * 1) non-aligned part at start
1098     * 2) aligned part in middle
1099     * 3) non-aligned part at the end
1100     */
1101    FieldDatumByteOffset = 0;
1102    DatumOffset= 0;
1103
1104    /* Get a single datum from the caller's buffer */
1105
1106    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer, BufferLength,
1107            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1108
1109    /*
1110     * Part1:
1111     * Write a partial field datum if field does not begin on a datum boundary
1112     * Note: The code in this section also handles the aligned case
1113     *
1114     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
1115     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
1116     *
1117     * Mask off bits that are "below" the field (if any)
1118     */
1119    Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
1120
1121    /* If the field fits in one datum, may need to mask upper bits */
1122
1123    if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
1124         ObjDesc->CommonField.EndFieldValidBits)
1125    {
1126        /* There are bits above the field, mask them off also */
1127
1128        Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1129    }
1130
1131    /* Shift and mask the value into the field position */
1132
1133    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1134    MergedDatum &= Mask;
1135
1136    /* Apply the update rule (if necessary) and write the datum to the field */
1137
1138    Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1139                        FieldDatumByteOffset);
1140    if (ACPI_FAILURE (Status))
1141    {
1142        return_ACPI_STATUS (Status);
1143    }
1144
1145    /* We just wrote the first datum */
1146
1147    DatumOffset++;
1148
1149    /* If the entire field fits within one datum, we are done. */
1150
1151    if ((DatumCount == 1) &&
1152       (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
1153    {
1154        return_ACPI_STATUS (AE_OK);
1155    }
1156
1157    /*
1158     * Part2:
1159     * Write the aligned data.
1160     *
1161     * We don't need to worry about the update rule for these data, because
1162     * all of the bits in each datum are part of the field.
1163     *
1164     * The last datum must be special cased because it might contain bits
1165     * that are not part of the field -- therefore the "update rule" must be
1166     * applied in Part3 below.
1167     */
1168    while (DatumOffset < DatumCount)
1169    {
1170        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1171
1172        /*
1173         * Get the next raw buffer datum.  It may contain bits of the previous
1174         * field datum
1175         */
1176        AcpiExGetBufferDatum (&ThisRawDatum, Buffer, BufferLength,
1177                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1178
1179        /* Create the field datum based on the field alignment */
1180
1181        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1182        {
1183            /*
1184             * Put together appropriate bits of the two raw buffer data to make
1185             * a single complete field datum
1186             */
1187            MergedDatum =
1188                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
1189                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1190        }
1191        else
1192        {
1193            /* Field began aligned on datum boundary */
1194
1195            MergedDatum = ThisRawDatum;
1196        }
1197
1198        /*
1199         * Special handling for the last datum if the field does NOT end on
1200         * a datum boundary.  Update Rule must be applied to the bits outside
1201         * the field.
1202         */
1203        DatumOffset++;
1204        if ((DatumOffset == DatumCount) &&
1205            (ObjDesc->CommonField.EndFieldValidBits))
1206        {
1207            /*
1208             * If there are dangling non-aligned bits, perform one more merged write
1209             * Else - field is aligned at the end, no need for any more writes
1210             */
1211
1212            /*
1213             * Part3:
1214             * This is the last datum and the field does not end on a datum boundary.
1215             * Build the partial datum and write with the update rule.
1216             *
1217             * Mask off the unused bits above (after) the end-of-field
1218             */
1219            Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1220            MergedDatum &= Mask;
1221
1222            /* Write the last datum with the update rule */
1223
1224            Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1225                                FieldDatumByteOffset);
1226            if (ACPI_FAILURE (Status))
1227            {
1228                return_ACPI_STATUS (Status);
1229            }
1230        }
1231        else
1232        {
1233            /* Normal (aligned) case -- write the completed datum */
1234
1235            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
1236                            &MergedDatum, ACPI_WRITE);
1237            if (ACPI_FAILURE (Status))
1238            {
1239                return_ACPI_STATUS (Status);
1240            }
1241        }
1242
1243        /*
1244         * Save the most recent datum since it may contain bits of the *next*
1245         * field datum.  Update current byte offset.
1246         */
1247        PreviousRawDatum = ThisRawDatum;
1248    }
1249
1250    return_ACPI_STATUS (Status);
1251}
1252
1253
1254