]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/components/executer/exfldio.c
Import ACPICA 20120215.
[FreeBSD/FreeBSD.git] / source / components / executer / exfldio.c
1 /******************************************************************************
2  *
3  * Module Name: exfldio - Aml Field I/O
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2012, 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
45 #define __EXFLDIO_C__
46
47 #include "acpi.h"
48 #include "accommon.h"
49 #include "acinterp.h"
50 #include "amlcode.h"
51 #include "acevents.h"
52 #include "acdispat.h"
53
54
55 #define _COMPONENT          ACPI_EXECUTER
56         ACPI_MODULE_NAME    ("exfldio")
57
58 /* Local prototypes */
59
60 static ACPI_STATUS
61 AcpiExFieldDatumIo (
62     ACPI_OPERAND_OBJECT     *ObjDesc,
63     UINT32                  FieldDatumByteOffset,
64     UINT64                  *Value,
65     UINT32                  ReadWrite);
66
67 static BOOLEAN
68 AcpiExRegisterOverflow (
69     ACPI_OPERAND_OBJECT     *ObjDesc,
70     UINT64                  Value);
71
72 static ACPI_STATUS
73 AcpiExSetupRegion (
74     ACPI_OPERAND_OBJECT     *ObjDesc,
75     UINT32                  FieldDatumByteOffset);
76
77
78 /*******************************************************************************
79  *
80  * FUNCTION:    AcpiExSetupRegion
81  *
82  * PARAMETERS:  ObjDesc                 - Field to be read or written
83  *              FieldDatumByteOffset    - Byte offset of this datum within the
84  *                                        parent field
85  *
86  * RETURN:      Status
87  *
88  * DESCRIPTION: Common processing for AcpiExExtractFromField and
89  *              AcpiExInsertIntoField.  Initialize the Region if necessary and
90  *              validate the request.
91  *
92  ******************************************************************************/
93
94 static ACPI_STATUS
95 AcpiExSetupRegion (
96     ACPI_OPERAND_OBJECT     *ObjDesc,
97     UINT32                  FieldDatumByteOffset)
98 {
99     ACPI_STATUS             Status = AE_OK;
100     ACPI_OPERAND_OBJECT     *RgnDesc;
101     UINT8                   SpaceId;
102
103
104     ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);
105
106
107     RgnDesc = ObjDesc->CommonField.RegionObj;
108
109     /* We must have a valid region */
110
111     if (RgnDesc->Common.Type != ACPI_TYPE_REGION)
112     {
113         ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
114             RgnDesc->Common.Type,
115             AcpiUtGetObjectTypeName (RgnDesc)));
116
117         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
118     }
119
120     SpaceId = RgnDesc->Region.SpaceId;
121
122     /* Validate the Space ID */
123
124     if (!AcpiIsValidSpaceId (SpaceId))
125     {
126         ACPI_ERROR ((AE_INFO, "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId));
127         return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
128     }
129
130     /*
131      * If the Region Address and Length have not been previously evaluated,
132      * evaluate them now and save the results.
133      */
134     if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
135     {
136         Status = AcpiDsGetRegionArguments (RgnDesc);
137         if (ACPI_FAILURE (Status))
138         {
139             return_ACPI_STATUS (Status);
140         }
141     }
142
143     /*
144      * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
145      * address space and the request cannot be directly validated
146      */
147     if (SpaceId == ACPI_ADR_SPACE_SMBUS ||
148         SpaceId == ACPI_ADR_SPACE_GSBUS ||
149         SpaceId == ACPI_ADR_SPACE_IPMI)
150     {
151         /* SMBus or IPMI has a non-linear address space */
152
153         return_ACPI_STATUS (AE_OK);
154     }
155
156 #ifdef ACPI_UNDER_DEVELOPMENT
157     /*
158      * If the Field access is AnyAcc, we can now compute the optimal
159      * access (because we know know the length of the parent region)
160      */
161     if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
162     {
163         if (ACPI_FAILURE (Status))
164         {
165             return_ACPI_STATUS (Status);
166         }
167     }
168 #endif
169
170     /*
171      * Validate the request.  The entire request from the byte offset for a
172      * length of one field datum (access width) must fit within the region.
173      * (Region length is specified in bytes)
174      */
175     if (RgnDesc->Region.Length <
176             (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset +
177             ObjDesc->CommonField.AccessByteWidth))
178     {
179         if (AcpiGbl_EnableInterpreterSlack)
180         {
181             /*
182              * Slack mode only:  We will go ahead and allow access to this
183              * field if it is within the region length rounded up to the next
184              * access width boundary. ACPI_SIZE cast for 64-bit compile.
185              */
186             if (ACPI_ROUND_UP (RgnDesc->Region.Length,
187                     ObjDesc->CommonField.AccessByteWidth) >=
188                 ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +
189                     ObjDesc->CommonField.AccessByteWidth +
190                     FieldDatumByteOffset))
191             {
192                 return_ACPI_STATUS (AE_OK);
193             }
194         }
195
196         if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
197         {
198             /*
199              * This is the case where the AccessType (AccWord, etc.) is wider
200              * than the region itself.  For example, a region of length one
201              * byte, and a field with Dword access specified.
202              */
203             ACPI_ERROR ((AE_INFO,
204                 "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)",
205                 AcpiUtGetNodeName (ObjDesc->CommonField.Node),
206                 ObjDesc->CommonField.AccessByteWidth,
207                 AcpiUtGetNodeName (RgnDesc->Region.Node),
208                 RgnDesc->Region.Length));
209         }
210
211         /*
212          * Offset rounded up to next multiple of field width
213          * exceeds region length, indicate an error
214          */
215         ACPI_ERROR ((AE_INFO,
216             "Field [%4.4s] Base+Offset+Width %u+%u+%u 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
248 ACPI_STATUS
249 AcpiExAccessRegion (
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 %p\n",
296         AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
297         RgnDesc->Region.SpaceId,
298         ObjDesc->CommonField.AccessByteWidth,
299         ObjDesc->CommonField.BaseByteOffset,
300         FieldDatumByteOffset,
301         ACPI_CAST_PTR (void, (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
348 static BOOLEAN
349 AcpiExRegisterOverflow (
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
401 static ACPI_STATUS
402 AcpiExFieldDatumIo (
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             ACPI_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             ACPI_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
484     case ACPI_TYPE_LOCAL_BANK_FIELD:
485
486         /*
487          * Ensure that the BankValue is not beyond the capacity of
488          * the register
489          */
490         if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
491                 (UINT64) ObjDesc->BankField.Value))
492         {
493             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
494         }
495
496         /*
497          * For BankFields, we must write the BankValue to the BankRegister
498          * (itself a RegionField) before we can access the data.
499          */
500         Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
501                     &ObjDesc->BankField.Value,
502                     sizeof (ObjDesc->BankField.Value));
503         if (ACPI_FAILURE (Status))
504         {
505             return_ACPI_STATUS (Status);
506         }
507
508         /*
509          * Now that the Bank has been selected, fall through to the
510          * RegionField case and write the datum to the Operation Region
511          */
512
513         /*lint -fallthrough */
514
515
516     case ACPI_TYPE_LOCAL_REGION_FIELD:
517         /*
518          * For simple RegionFields, we just directly access the owning
519          * Operation Region.
520          */
521         Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
522                     ReadWrite);
523         break;
524
525
526     case ACPI_TYPE_LOCAL_INDEX_FIELD:
527
528
529         /*
530          * Ensure that the IndexValue is not beyond the capacity of
531          * the register
532          */
533         if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
534                 (UINT64) ObjDesc->IndexField.Value))
535         {
536             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
537         }
538
539         /* Write the index value to the IndexRegister (itself a RegionField) */
540
541         FieldDatumByteOffset += ObjDesc->IndexField.Value;
542
543         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
544             "Write to Index Register: Value %8.8X\n",
545             FieldDatumByteOffset));
546
547         Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
548                     &FieldDatumByteOffset,
549                     sizeof (FieldDatumByteOffset));
550         if (ACPI_FAILURE (Status))
551         {
552             return_ACPI_STATUS (Status);
553         }
554
555         if (ReadWrite == ACPI_READ)
556         {
557             /* Read the datum from the DataRegister */
558
559             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
560                 "Read from Data Register\n"));
561
562             Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
563                         Value, sizeof (UINT64));
564         }
565         else
566         {
567             /* Write the datum to the DataRegister */
568
569             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
570                 "Write to Data Register: Value %8.8X%8.8X\n",
571                 ACPI_FORMAT_UINT64 (*Value)));
572
573             Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
574                         Value, sizeof (UINT64));
575         }
576         break;
577
578
579     default:
580
581         ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
582             ObjDesc->Common.Type));
583         Status = AE_AML_INTERNAL;
584         break;
585     }
586
587     if (ACPI_SUCCESS (Status))
588     {
589         if (ReadWrite == ACPI_READ)
590         {
591             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
592                 "Value Read %8.8X%8.8X, Width %u\n",
593                 ACPI_FORMAT_UINT64 (*Value),
594                 ObjDesc->CommonField.AccessByteWidth));
595         }
596         else
597         {
598             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
599                 "Value Written %8.8X%8.8X, Width %u\n",
600                 ACPI_FORMAT_UINT64 (*Value),
601                 ObjDesc->CommonField.AccessByteWidth));
602         }
603     }
604
605     return_ACPI_STATUS (Status);
606 }
607
608
609 /*******************************************************************************
610  *
611  * FUNCTION:    AcpiExWriteWithUpdateRule
612  *
613  * PARAMETERS:  ObjDesc                 - Field to be written
614  *              Mask                    - bitmask within field datum
615  *              FieldValue              - Value to write
616  *              FieldDatumByteOffset    - Offset of datum within field
617  *
618  * RETURN:      Status
619  *
620  * DESCRIPTION: Apply the field update rule to a field write
621  *
622  ******************************************************************************/
623
624 ACPI_STATUS
625 AcpiExWriteWithUpdateRule (
626     ACPI_OPERAND_OBJECT     *ObjDesc,
627     UINT64                  Mask,
628     UINT64                  FieldValue,
629     UINT32                  FieldDatumByteOffset)
630 {
631     ACPI_STATUS             Status = AE_OK;
632     UINT64                  MergedValue;
633     UINT64                  CurrentValue;
634
635
636     ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
637
638
639     /* Start with the new bits  */
640
641     MergedValue = FieldValue;
642
643     /* If the mask is all ones, we don't need to worry about the update rule */
644
645     if (Mask != ACPI_UINT64_MAX)
646     {
647         /* Decode the update rule */
648
649         switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
650         {
651         case AML_FIELD_UPDATE_PRESERVE:
652             /*
653              * Check if update rule needs to be applied (not if mask is all
654              * ones)  The left shift drops the bits we want to ignore.
655              */
656             if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
657                            ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
658             {
659                 /*
660                  * Read the current contents of the byte/word/dword containing
661                  * the field, and merge with the new field value.
662                  */
663                 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
664                             &CurrentValue, ACPI_READ);
665                 if (ACPI_FAILURE (Status))
666                 {
667                     return_ACPI_STATUS (Status);
668                 }
669
670                 MergedValue |= (CurrentValue & ~Mask);
671             }
672             break;
673
674         case AML_FIELD_UPDATE_WRITE_AS_ONES:
675
676             /* Set positions outside the field to all ones */
677
678             MergedValue |= ~Mask;
679             break;
680
681         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
682
683             /* Set positions outside the field to all zeros */
684
685             MergedValue &= Mask;
686             break;
687
688         default:
689
690             ACPI_ERROR ((AE_INFO,
691                 "Unknown UpdateRule value: 0x%X",
692                 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
693             return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
694         }
695     }
696
697     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
698         "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
699         ACPI_FORMAT_UINT64 (Mask),
700         FieldDatumByteOffset,
701         ObjDesc->CommonField.AccessByteWidth,
702         ACPI_FORMAT_UINT64 (FieldValue),
703         ACPI_FORMAT_UINT64 (MergedValue)));
704
705     /* Write the merged value */
706
707     Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
708                 &MergedValue, ACPI_WRITE);
709
710     return_ACPI_STATUS (Status);
711 }
712
713
714 /*******************************************************************************
715  *
716  * FUNCTION:    AcpiExExtractFromField
717  *
718  * PARAMETERS:  ObjDesc             - Field to be read
719  *              Buffer              - Where to store the field data
720  *              BufferLength        - Length of Buffer
721  *
722  * RETURN:      Status
723  *
724  * DESCRIPTION: Retrieve the current value of the given field
725  *
726  ******************************************************************************/
727
728 ACPI_STATUS
729 AcpiExExtractFromField (
730     ACPI_OPERAND_OBJECT     *ObjDesc,
731     void                    *Buffer,
732     UINT32                  BufferLength)
733 {
734     ACPI_STATUS             Status;
735     UINT64                  RawDatum;
736     UINT64                  MergedDatum;
737     UINT32                  FieldOffset = 0;
738     UINT32                  BufferOffset = 0;
739     UINT32                  BufferTailBits;
740     UINT32                  DatumCount;
741     UINT32                  FieldDatumCount;
742     UINT32                  AccessBitWidth;
743     UINT32                  i;
744
745
746     ACPI_FUNCTION_TRACE (ExExtractFromField);
747
748
749     /* Validate target buffer and clear it */
750
751     if (BufferLength <
752         ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
753     {
754         ACPI_ERROR ((AE_INFO,
755             "Field size %u (bits) is too large for buffer (%u)",
756             ObjDesc->CommonField.BitLength, BufferLength));
757
758         return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
759     }
760
761     ACPI_MEMSET (Buffer, 0, BufferLength);
762     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
763
764     /* Handle the simple case here */
765
766     if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
767         (ObjDesc->CommonField.BitLength == AccessBitWidth))
768     {
769         Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
770         return_ACPI_STATUS (Status);
771     }
772
773 /* TBD: Move to common setup code */
774
775     /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
776
777     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
778     {
779         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
780         AccessBitWidth = sizeof (UINT64) * 8;
781     }
782
783     /* Compute the number of datums (access width data items) */
784
785     DatumCount = ACPI_ROUND_UP_TO (
786         ObjDesc->CommonField.BitLength, AccessBitWidth);
787
788     FieldDatumCount = ACPI_ROUND_UP_TO (
789         ObjDesc->CommonField.BitLength +
790         ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);
791
792     /* Priming read from the field */
793
794     Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
795     if (ACPI_FAILURE (Status))
796     {
797         return_ACPI_STATUS (Status);
798     }
799     MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
800
801     /* Read the rest of the field */
802
803     for (i = 1; i < FieldDatumCount; i++)
804     {
805         /* Get next input datum from the field */
806
807         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
808         Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
809                     &RawDatum, ACPI_READ);
810         if (ACPI_FAILURE (Status))
811         {
812             return_ACPI_STATUS (Status);
813         }
814
815         /*
816          * Merge with previous datum if necessary.
817          *
818          * Note: Before the shift, check if the shift value will be larger than
819          * the integer size. If so, there is no need to perform the operation.
820          * This avoids the differences in behavior between different compilers
821          * concerning shift values larger than the target data width.
822          */
823         if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
824             ACPI_INTEGER_BIT_SIZE)
825         {
826             MergedDatum |= RawDatum <<
827                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
828         }
829
830         if (i == DatumCount)
831         {
832             break;
833         }
834
835         /* Write merged datum to target buffer */
836
837         ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
838             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
839                 BufferLength - BufferOffset));
840
841         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
842         MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
843     }
844
845     /* Mask off any extra bits in the last datum */
846
847     BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
848     if (BufferTailBits)
849     {
850         MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
851     }
852
853     /* Write the last datum to the buffer */
854
855     ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
856         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
857             BufferLength - BufferOffset));
858
859     return_ACPI_STATUS (AE_OK);
860 }
861
862
863 /*******************************************************************************
864  *
865  * FUNCTION:    AcpiExInsertIntoField
866  *
867  * PARAMETERS:  ObjDesc             - Field to be written
868  *              Buffer              - Data to be written
869  *              BufferLength        - Length of Buffer
870  *
871  * RETURN:      Status
872  *
873  * DESCRIPTION: Store the Buffer contents into the given field
874  *
875  ******************************************************************************/
876
877 ACPI_STATUS
878 AcpiExInsertIntoField (
879     ACPI_OPERAND_OBJECT     *ObjDesc,
880     void                    *Buffer,
881     UINT32                  BufferLength)
882 {
883     void                    *NewBuffer;
884     ACPI_STATUS             Status;
885     UINT64                  Mask;
886     UINT64                  WidthMask;
887     UINT64                  MergedDatum;
888     UINT64                  RawDatum = 0;
889     UINT32                  FieldOffset = 0;
890     UINT32                  BufferOffset = 0;
891     UINT32                  BufferTailBits;
892     UINT32                  DatumCount;
893     UINT32                  FieldDatumCount;
894     UINT32                  AccessBitWidth;
895     UINT32                  RequiredLength;
896     UINT32                  i;
897
898
899     ACPI_FUNCTION_TRACE (ExInsertIntoField);
900
901
902     /* Validate input buffer */
903
904     NewBuffer = NULL;
905     RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
906                         ObjDesc->CommonField.BitLength);
907     /*
908      * We must have a buffer that is at least as long as the field
909      * we are writing to.  This is because individual fields are
910      * indivisible and partial writes are not supported -- as per
911      * the ACPI specification.
912      */
913     if (BufferLength < RequiredLength)
914     {
915         /* We need to create a new buffer */
916
917         NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
918         if (!NewBuffer)
919         {
920             return_ACPI_STATUS (AE_NO_MEMORY);
921         }
922
923         /*
924          * Copy the original data to the new buffer, starting
925          * at Byte zero.  All unused (upper) bytes of the
926          * buffer will be 0.
927          */
928         ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength);
929         Buffer = NewBuffer;
930         BufferLength = RequiredLength;
931     }
932
933 /* TBD: Move to common setup code */
934
935     /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
936     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
937     {
938         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
939     }
940
941     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
942
943     /*
944      * Create the bitmasks used for bit insertion.
945      * Note: This if/else is used to bypass compiler differences with the
946      * shift operator
947      */
948     if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
949     {
950         WidthMask = ACPI_UINT64_MAX;
951     }
952     else
953     {
954         WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth);
955     }
956
957     Mask = WidthMask &
958         ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
959
960     /* Compute the number of datums (access width data items) */
961
962     DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
963         AccessBitWidth);
964
965     FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
966         ObjDesc->CommonField.StartFieldBitOffset,
967         AccessBitWidth);
968
969     /* Get initial Datum from the input buffer */
970
971     ACPI_MEMCPY (&RawDatum, Buffer,
972         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
973             BufferLength - BufferOffset));
974
975     MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
976
977     /* Write the entire field */
978
979     for (i = 1; i < FieldDatumCount; i++)
980     {
981         /* Write merged datum to the target field */
982
983         MergedDatum &= Mask;
984         Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
985                     MergedDatum, FieldOffset);
986         if (ACPI_FAILURE (Status))
987         {
988             goto Exit;
989         }
990
991         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
992
993         /*
994          * Start new output datum by merging with previous input datum
995          * if necessary.
996          *
997          * Note: Before the shift, check if the shift value will be larger than
998          * the integer size. If so, there is no need to perform the operation.
999          * This avoids the differences in behavior between different compilers
1000          * concerning shift values larger than the target data width.
1001          */
1002         if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
1003             ACPI_INTEGER_BIT_SIZE)
1004         {
1005             MergedDatum = RawDatum >>
1006                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
1007         }
1008         else
1009         {
1010             MergedDatum = 0;
1011         }
1012
1013         Mask = WidthMask;
1014
1015         if (i == DatumCount)
1016         {
1017             break;
1018         }
1019
1020         /* Get the next input datum from the buffer */
1021
1022         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
1023         ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset,
1024             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
1025                  BufferLength - BufferOffset));
1026
1027         MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
1028     }
1029
1030     /* Mask off any extra bits in the last datum */
1031
1032     BufferTailBits = (ObjDesc->CommonField.BitLength +
1033         ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;
1034     if (BufferTailBits)
1035     {
1036         Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
1037     }
1038
1039     /* Write the last datum to the field */
1040
1041     MergedDatum &= Mask;
1042     Status = AcpiExWriteWithUpdateRule (ObjDesc,
1043                 Mask, MergedDatum, FieldOffset);
1044
1045 Exit:
1046     /* Free temporary buffer if we used one */
1047
1048     if (NewBuffer)
1049     {
1050         ACPI_FREE (NewBuffer);
1051     }
1052     return_ACPI_STATUS (Status);
1053 }
1054
1055