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