]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/dev/acpica/executer/exfldio.c
Merge ACPICA 20111123.
[FreeBSD/FreeBSD.git] / sys / contrib / dev / acpica / executer / exfldio.c
1 /******************************************************************************
2  *
3  * Module Name: exfldio - Aml Field I/O
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2011, 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 <contrib/dev/acpica/include/acpi.h>
48 #include <contrib/dev/acpica/include/accommon.h>
49 #include <contrib/dev/acpica/include/acinterp.h>
50 #include <contrib/dev/acpica/include/amlcode.h>
51 #include <contrib/dev/acpica/include/acevents.h>
52 #include <contrib/dev/acpica/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     ACPI_FUNCTION_NAME (ExRegisterOverflow);
354
355
356     if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
357     {
358         /*
359          * The field is large enough to hold the maximum integer, so we can
360          * never overflow it.
361          */
362         return (FALSE);
363     }
364
365     if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength))
366     {
367         /*
368          * The Value is larger than the maximum value that can fit into
369          * the register.
370          */
371         ACPI_ERROR ((AE_INFO,
372             "Index value 0x%8.8X%8.8X overflows field width 0x%X",
373             ACPI_FORMAT_UINT64 (Value),
374             ObjDesc->CommonField.BitLength));
375
376         return (TRUE);
377     }
378
379     /* The Value will fit into the field with no truncation */
380
381     return (FALSE);
382 }
383
384
385 /*******************************************************************************
386  *
387  * FUNCTION:    AcpiExFieldDatumIo
388  *
389  * PARAMETERS:  ObjDesc                 - Field to be read
390  *              FieldDatumByteOffset    - Byte offset of this datum within the
391  *                                        parent field
392  *              Value                   - Where to store value (must be 64 bits)
393  *              ReadWrite               - Read or Write flag
394  *
395  * RETURN:      Status
396  *
397  * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
398  *              demultiplexed here to handle the different types of fields
399  *              (BufferField, RegionField, IndexField, BankField)
400  *
401  ******************************************************************************/
402
403 static ACPI_STATUS
404 AcpiExFieldDatumIo (
405     ACPI_OPERAND_OBJECT     *ObjDesc,
406     UINT32                  FieldDatumByteOffset,
407     UINT64                  *Value,
408     UINT32                  ReadWrite)
409 {
410     ACPI_STATUS             Status;
411     UINT64                  LocalValue;
412
413
414     ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);
415
416
417     if (ReadWrite == ACPI_READ)
418     {
419         if (!Value)
420         {
421             LocalValue = 0;
422
423             /* To support reads without saving return value */
424             Value = &LocalValue;
425         }
426
427         /* Clear the entire return buffer first, [Very Important!] */
428
429         *Value = 0;
430     }
431
432     /*
433      * The four types of fields are:
434      *
435      * BufferField - Read/write from/to a Buffer
436      * RegionField - Read/write from/to a Operation Region.
437      * BankField   - Write to a Bank Register, then read/write from/to an
438      *               OperationRegion
439      * IndexField  - Write to an Index Register, then read/write from/to a
440      *               Data Register
441      */
442     switch (ObjDesc->Common.Type)
443     {
444     case ACPI_TYPE_BUFFER_FIELD:
445         /*
446          * If the BufferField arguments have not been previously evaluated,
447          * evaluate them now and save the results.
448          */
449         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
450         {
451             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
452             if (ACPI_FAILURE (Status))
453             {
454                 return_ACPI_STATUS (Status);
455             }
456         }
457
458         if (ReadWrite == ACPI_READ)
459         {
460             /*
461              * Copy the data from the source buffer.
462              * Length is the field width in bytes.
463              */
464             ACPI_MEMCPY (Value,
465                 (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
466                     ObjDesc->BufferField.BaseByteOffset +
467                     FieldDatumByteOffset,
468                 ObjDesc->CommonField.AccessByteWidth);
469         }
470         else
471         {
472             /*
473              * Copy the data to the target buffer.
474              * Length is the field width in bytes.
475              */
476             ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
477                 ObjDesc->BufferField.BaseByteOffset +
478                 FieldDatumByteOffset,
479                 Value, ObjDesc->CommonField.AccessByteWidth);
480         }
481
482         Status = AE_OK;
483         break;
484
485
486     case ACPI_TYPE_LOCAL_BANK_FIELD:
487
488         /*
489          * Ensure that the BankValue is not beyond the capacity of
490          * the register
491          */
492         if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
493                 (UINT64) ObjDesc->BankField.Value))
494         {
495             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
496         }
497
498         /*
499          * For BankFields, we must write the BankValue to the BankRegister
500          * (itself a RegionField) before we can access the data.
501          */
502         Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
503                     &ObjDesc->BankField.Value,
504                     sizeof (ObjDesc->BankField.Value));
505         if (ACPI_FAILURE (Status))
506         {
507             return_ACPI_STATUS (Status);
508         }
509
510         /*
511          * Now that the Bank has been selected, fall through to the
512          * RegionField case and write the datum to the Operation Region
513          */
514
515         /*lint -fallthrough */
516
517
518     case ACPI_TYPE_LOCAL_REGION_FIELD:
519         /*
520          * For simple RegionFields, we just directly access the owning
521          * Operation Region.
522          */
523         Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
524                     ReadWrite);
525         break;
526
527
528     case ACPI_TYPE_LOCAL_INDEX_FIELD:
529
530
531         /*
532          * Ensure that the IndexValue is not beyond the capacity of
533          * the register
534          */
535         if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
536                 (UINT64) ObjDesc->IndexField.Value))
537         {
538             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
539         }
540
541         /* Write the index value to the IndexRegister (itself a RegionField) */
542
543         FieldDatumByteOffset += ObjDesc->IndexField.Value;
544
545         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
546             "Write to Index Register: Value %8.8X\n",
547             FieldDatumByteOffset));
548
549         Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
550                     &FieldDatumByteOffset,
551                     sizeof (FieldDatumByteOffset));
552         if (ACPI_FAILURE (Status))
553         {
554             return_ACPI_STATUS (Status);
555         }
556
557         if (ReadWrite == ACPI_READ)
558         {
559             /* Read the datum from the DataRegister */
560
561             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
562                 "Read from Data Register\n"));
563
564             Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
565                         Value, sizeof (UINT64));
566         }
567         else
568         {
569             /* Write the datum to the DataRegister */
570
571             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
572                 "Write to Data Register: Value %8.8X%8.8X\n",
573                 ACPI_FORMAT_UINT64 (*Value)));
574
575             Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
576                         Value, sizeof (UINT64));
577         }
578         break;
579
580
581     default:
582
583         ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
584             ObjDesc->Common.Type));
585         Status = AE_AML_INTERNAL;
586         break;
587     }
588
589     if (ACPI_SUCCESS (Status))
590     {
591         if (ReadWrite == ACPI_READ)
592         {
593             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
594                 "Value Read %8.8X%8.8X, Width %u\n",
595                 ACPI_FORMAT_UINT64 (*Value),
596                 ObjDesc->CommonField.AccessByteWidth));
597         }
598         else
599         {
600             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
601                 "Value Written %8.8X%8.8X, Width %u\n",
602                 ACPI_FORMAT_UINT64 (*Value),
603                 ObjDesc->CommonField.AccessByteWidth));
604         }
605     }
606
607     return_ACPI_STATUS (Status);
608 }
609
610
611 /*******************************************************************************
612  *
613  * FUNCTION:    AcpiExWriteWithUpdateRule
614  *
615  * PARAMETERS:  ObjDesc                 - Field to be written
616  *              Mask                    - bitmask within field datum
617  *              FieldValue              - Value to write
618  *              FieldDatumByteOffset    - Offset of datum within field
619  *
620  * RETURN:      Status
621  *
622  * DESCRIPTION: Apply the field update rule to a field write
623  *
624  ******************************************************************************/
625
626 ACPI_STATUS
627 AcpiExWriteWithUpdateRule (
628     ACPI_OPERAND_OBJECT     *ObjDesc,
629     UINT64                  Mask,
630     UINT64                  FieldValue,
631     UINT32                  FieldDatumByteOffset)
632 {
633     ACPI_STATUS             Status = AE_OK;
634     UINT64                  MergedValue;
635     UINT64                  CurrentValue;
636
637
638     ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
639
640
641     /* Start with the new bits  */
642
643     MergedValue = FieldValue;
644
645     /* If the mask is all ones, we don't need to worry about the update rule */
646
647     if (Mask != ACPI_UINT64_MAX)
648     {
649         /* Decode the update rule */
650
651         switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
652         {
653         case AML_FIELD_UPDATE_PRESERVE:
654             /*
655              * Check if update rule needs to be applied (not if mask is all
656              * ones)  The left shift drops the bits we want to ignore.
657              */
658             if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
659                            ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
660             {
661                 /*
662                  * Read the current contents of the byte/word/dword containing
663                  * the field, and merge with the new field value.
664                  */
665                 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
666                             &CurrentValue, ACPI_READ);
667                 if (ACPI_FAILURE (Status))
668                 {
669                     return_ACPI_STATUS (Status);
670                 }
671
672                 MergedValue |= (CurrentValue & ~Mask);
673             }
674             break;
675
676         case AML_FIELD_UPDATE_WRITE_AS_ONES:
677
678             /* Set positions outside the field to all ones */
679
680             MergedValue |= ~Mask;
681             break;
682
683         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
684
685             /* Set positions outside the field to all zeros */
686
687             MergedValue &= Mask;
688             break;
689
690         default:
691
692             ACPI_ERROR ((AE_INFO,
693                 "Unknown UpdateRule value: 0x%X",
694                 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
695             return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
696         }
697     }
698
699     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
700         "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
701         ACPI_FORMAT_UINT64 (Mask),
702         FieldDatumByteOffset,
703         ObjDesc->CommonField.AccessByteWidth,
704         ACPI_FORMAT_UINT64 (FieldValue),
705         ACPI_FORMAT_UINT64 (MergedValue)));
706
707     /* Write the merged value */
708
709     Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
710                 &MergedValue, ACPI_WRITE);
711
712     return_ACPI_STATUS (Status);
713 }
714
715
716 /*******************************************************************************
717  *
718  * FUNCTION:    AcpiExExtractFromField
719  *
720  * PARAMETERS:  ObjDesc             - Field to be read
721  *              Buffer              - Where to store the field data
722  *              BufferLength        - Length of Buffer
723  *
724  * RETURN:      Status
725  *
726  * DESCRIPTION: Retrieve the current value of the given field
727  *
728  ******************************************************************************/
729
730 ACPI_STATUS
731 AcpiExExtractFromField (
732     ACPI_OPERAND_OBJECT     *ObjDesc,
733     void                    *Buffer,
734     UINT32                  BufferLength)
735 {
736     ACPI_STATUS             Status;
737     UINT64                  RawDatum;
738     UINT64                  MergedDatum;
739     UINT32                  FieldOffset = 0;
740     UINT32                  BufferOffset = 0;
741     UINT32                  BufferTailBits;
742     UINT32                  DatumCount;
743     UINT32                  FieldDatumCount;
744     UINT32                  AccessBitWidth;
745     UINT32                  i;
746
747
748     ACPI_FUNCTION_TRACE (ExExtractFromField);
749
750
751     /* Validate target buffer and clear it */
752
753     if (BufferLength <
754         ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
755     {
756         ACPI_ERROR ((AE_INFO,
757             "Field size %u (bits) is too large for buffer (%u)",
758             ObjDesc->CommonField.BitLength, BufferLength));
759
760         return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
761     }
762
763     ACPI_MEMSET (Buffer, 0, BufferLength);
764     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
765
766     /* Handle the simple case here */
767
768     if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
769         (ObjDesc->CommonField.BitLength == AccessBitWidth))
770     {
771         Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
772         return_ACPI_STATUS (Status);
773     }
774
775 /* TBD: Move to common setup code */
776
777     /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
778
779     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
780     {
781         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
782         AccessBitWidth = sizeof (UINT64) * 8;
783     }
784
785     /* Compute the number of datums (access width data items) */
786
787     DatumCount = ACPI_ROUND_UP_TO (
788         ObjDesc->CommonField.BitLength, AccessBitWidth);
789
790     FieldDatumCount = ACPI_ROUND_UP_TO (
791         ObjDesc->CommonField.BitLength +
792         ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);
793
794     /* Priming read from the field */
795
796     Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
797     if (ACPI_FAILURE (Status))
798     {
799         return_ACPI_STATUS (Status);
800     }
801     MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
802
803     /* Read the rest of the field */
804
805     for (i = 1; i < FieldDatumCount; i++)
806     {
807         /* Get next input datum from the field */
808
809         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
810         Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
811                     &RawDatum, ACPI_READ);
812         if (ACPI_FAILURE (Status))
813         {
814             return_ACPI_STATUS (Status);
815         }
816
817         /*
818          * Merge with previous datum if necessary.
819          *
820          * Note: Before the shift, check if the shift value will be larger than
821          * the integer size. If so, there is no need to perform the operation.
822          * This avoids the differences in behavior between different compilers
823          * concerning shift values larger than the target data width.
824          */
825         if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
826             ACPI_INTEGER_BIT_SIZE)
827         {
828             MergedDatum |= RawDatum <<
829                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
830         }
831
832         if (i == DatumCount)
833         {
834             break;
835         }
836
837         /* Write merged datum to target buffer */
838
839         ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
840             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
841                 BufferLength - BufferOffset));
842
843         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
844         MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
845     }
846
847     /* Mask off any extra bits in the last datum */
848
849     BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
850     if (BufferTailBits)
851     {
852         MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
853     }
854
855     /* Write the last datum to the buffer */
856
857     ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
858         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
859             BufferLength - BufferOffset));
860
861     return_ACPI_STATUS (AE_OK);
862 }
863
864
865 /*******************************************************************************
866  *
867  * FUNCTION:    AcpiExInsertIntoField
868  *
869  * PARAMETERS:  ObjDesc             - Field to be written
870  *              Buffer              - Data to be written
871  *              BufferLength        - Length of Buffer
872  *
873  * RETURN:      Status
874  *
875  * DESCRIPTION: Store the Buffer contents into the given field
876  *
877  ******************************************************************************/
878
879 ACPI_STATUS
880 AcpiExInsertIntoField (
881     ACPI_OPERAND_OBJECT     *ObjDesc,
882     void                    *Buffer,
883     UINT32                  BufferLength)
884 {
885     void                    *NewBuffer;
886     ACPI_STATUS             Status;
887     UINT64                  Mask;
888     UINT64                  WidthMask;
889     UINT64                  MergedDatum;
890     UINT64                  RawDatum = 0;
891     UINT32                  FieldOffset = 0;
892     UINT32                  BufferOffset = 0;
893     UINT32                  BufferTailBits;
894     UINT32                  DatumCount;
895     UINT32                  FieldDatumCount;
896     UINT32                  AccessBitWidth;
897     UINT32                  RequiredLength;
898     UINT32                  i;
899
900
901     ACPI_FUNCTION_TRACE (ExInsertIntoField);
902
903
904     /* Validate input buffer */
905
906     NewBuffer = NULL;
907     RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
908                         ObjDesc->CommonField.BitLength);
909     /*
910      * We must have a buffer that is at least as long as the field
911      * we are writing to.  This is because individual fields are
912      * indivisible and partial writes are not supported -- as per
913      * the ACPI specification.
914      */
915     if (BufferLength < RequiredLength)
916     {
917         /* We need to create a new buffer */
918
919         NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
920         if (!NewBuffer)
921         {
922             return_ACPI_STATUS (AE_NO_MEMORY);
923         }
924
925         /*
926          * Copy the original data to the new buffer, starting
927          * at Byte zero.  All unused (upper) bytes of the
928          * buffer will be 0.
929          */
930         ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength);
931         Buffer = NewBuffer;
932         BufferLength = RequiredLength;
933     }
934
935 /* TBD: Move to common setup code */
936
937     /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
938     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
939     {
940         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
941     }
942
943     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
944
945     /*
946      * Create the bitmasks used for bit insertion.
947      * Note: This if/else is used to bypass compiler differences with the
948      * shift operator
949      */
950     if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
951     {
952         WidthMask = ACPI_UINT64_MAX;
953     }
954     else
955     {
956         WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth);
957     }
958
959     Mask = WidthMask &
960         ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
961
962     /* Compute the number of datums (access width data items) */
963
964     DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
965         AccessBitWidth);
966
967     FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
968         ObjDesc->CommonField.StartFieldBitOffset,
969         AccessBitWidth);
970
971     /* Get initial Datum from the input buffer */
972
973     ACPI_MEMCPY (&RawDatum, Buffer,
974         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
975             BufferLength - BufferOffset));
976
977     MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
978
979     /* Write the entire field */
980
981     for (i = 1; i < FieldDatumCount; i++)
982     {
983         /* Write merged datum to the target field */
984
985         MergedDatum &= Mask;
986         Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
987                     MergedDatum, FieldOffset);
988         if (ACPI_FAILURE (Status))
989         {
990             goto Exit;
991         }
992
993         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
994
995         /*
996          * Start new output datum by merging with previous input datum
997          * if necessary.
998          *
999          * Note: Before the shift, check if the shift value will be larger than
1000          * the integer size. If so, there is no need to perform the operation.
1001          * This avoids the differences in behavior between different compilers
1002          * concerning shift values larger than the target data width.
1003          */
1004         if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
1005             ACPI_INTEGER_BIT_SIZE)
1006         {
1007             MergedDatum = RawDatum >>
1008                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
1009         }
1010         else
1011         {
1012             MergedDatum = 0;
1013         }
1014
1015         Mask = WidthMask;
1016
1017         if (i == DatumCount)
1018         {
1019             break;
1020         }
1021
1022         /* Get the next input datum from the buffer */
1023
1024         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
1025         ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset,
1026             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
1027                  BufferLength - BufferOffset));
1028
1029         MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
1030     }
1031
1032     /* Mask off any extra bits in the last datum */
1033
1034     BufferTailBits = (ObjDesc->CommonField.BitLength +
1035         ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;
1036     if (BufferTailBits)
1037     {
1038         Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
1039     }
1040
1041     /* Write the last datum to the field */
1042
1043     MergedDatum &= Mask;
1044     Status = AcpiExWriteWithUpdateRule (ObjDesc,
1045                 Mask, MergedDatum, FieldOffset);
1046
1047 Exit:
1048     /* Free temporary buffer if we used one */
1049
1050     if (NewBuffer)
1051     {
1052         ACPI_FREE (NewBuffer);
1053     }
1054     return_ACPI_STATUS (Status);
1055 }
1056
1057