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