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