1149703c7Sjruoho /******************************************************************************
2149703c7Sjruoho  *
3149703c7Sjruoho  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
4149703c7Sjruoho  *
5149703c7Sjruoho  *****************************************************************************/
6149703c7Sjruoho 
768471b32Sjruoho /*
8*73d4e80bSchristos  * Copyright (C) 2000 - 2013, Intel Corp.
9149703c7Sjruoho  * All rights reserved.
10149703c7Sjruoho  *
1168471b32Sjruoho  * Redistribution and use in source and binary forms, with or without
1268471b32Sjruoho  * modification, are permitted provided that the following conditions
1368471b32Sjruoho  * are met:
1468471b32Sjruoho  * 1. Redistributions of source code must retain the above copyright
1568471b32Sjruoho  *    notice, this list of conditions, and the following disclaimer,
1668471b32Sjruoho  *    without modification.
1768471b32Sjruoho  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1868471b32Sjruoho  *    substantially similar to the "NO WARRANTY" disclaimer below
1968471b32Sjruoho  *    ("Disclaimer") and any redistribution must be conditioned upon
2068471b32Sjruoho  *    including a substantially similar Disclaimer requirement for further
2168471b32Sjruoho  *    binary redistribution.
2268471b32Sjruoho  * 3. Neither the names of the above-listed copyright holders nor the names
2368471b32Sjruoho  *    of any contributors may be used to endorse or promote products derived
2468471b32Sjruoho  *    from this software without specific prior written permission.
25149703c7Sjruoho  *
2668471b32Sjruoho  * Alternatively, this software may be distributed under the terms of the
2768471b32Sjruoho  * GNU General Public License ("GPL") version 2 as published by the Free
2868471b32Sjruoho  * Software Foundation.
29149703c7Sjruoho  *
3068471b32Sjruoho  * NO WARRANTY
3168471b32Sjruoho  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3268471b32Sjruoho  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3368471b32Sjruoho  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3468471b32Sjruoho  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3568471b32Sjruoho  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3668471b32Sjruoho  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3768471b32Sjruoho  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3868471b32Sjruoho  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3968471b32Sjruoho  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4068471b32Sjruoho  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4168471b32Sjruoho  * POSSIBILITY OF SUCH DAMAGES.
4268471b32Sjruoho  */
43149703c7Sjruoho 
44149703c7Sjruoho #define __EXMISC_C__
45149703c7Sjruoho 
46149703c7Sjruoho #include "acpi.h"
47149703c7Sjruoho #include "accommon.h"
48149703c7Sjruoho #include "acinterp.h"
49149703c7Sjruoho #include "amlcode.h"
50149703c7Sjruoho #include "amlresrc.h"
51149703c7Sjruoho 
52149703c7Sjruoho 
53149703c7Sjruoho #define _COMPONENT          ACPI_EXECUTER
54149703c7Sjruoho         ACPI_MODULE_NAME    ("exmisc")
55149703c7Sjruoho 
56149703c7Sjruoho 
57149703c7Sjruoho /*******************************************************************************
58149703c7Sjruoho  *
59149703c7Sjruoho  * FUNCTION:    AcpiExGetObjectReference
60149703c7Sjruoho  *
61149703c7Sjruoho  * PARAMETERS:  ObjDesc             - Create a reference to this object
62149703c7Sjruoho  *              ReturnDesc          - Where to store the reference
63149703c7Sjruoho  *              WalkState           - Current state
64149703c7Sjruoho  *
65149703c7Sjruoho  * RETURN:      Status
66149703c7Sjruoho  *
67149703c7Sjruoho  * DESCRIPTION: Obtain and return a "reference" to the target object
68149703c7Sjruoho  *              Common code for the RefOfOp and the CondRefOfOp.
69149703c7Sjruoho  *
70149703c7Sjruoho  ******************************************************************************/
71149703c7Sjruoho 
72149703c7Sjruoho ACPI_STATUS
73149703c7Sjruoho AcpiExGetObjectReference (
74149703c7Sjruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
75149703c7Sjruoho     ACPI_OPERAND_OBJECT     **ReturnDesc,
76149703c7Sjruoho     ACPI_WALK_STATE         *WalkState)
77149703c7Sjruoho {
78149703c7Sjruoho     ACPI_OPERAND_OBJECT     *ReferenceObj;
79149703c7Sjruoho     ACPI_OPERAND_OBJECT     *ReferencedObj;
80149703c7Sjruoho 
81149703c7Sjruoho 
82149703c7Sjruoho     ACPI_FUNCTION_TRACE_PTR (ExGetObjectReference, ObjDesc);
83149703c7Sjruoho 
84149703c7Sjruoho 
85149703c7Sjruoho     *ReturnDesc = NULL;
86149703c7Sjruoho 
87149703c7Sjruoho     switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))
88149703c7Sjruoho     {
89149703c7Sjruoho     case ACPI_DESC_TYPE_OPERAND:
90149703c7Sjruoho 
91149703c7Sjruoho         if (ObjDesc->Common.Type != ACPI_TYPE_LOCAL_REFERENCE)
92149703c7Sjruoho         {
93149703c7Sjruoho             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
94149703c7Sjruoho         }
95149703c7Sjruoho 
96149703c7Sjruoho         /*
97149703c7Sjruoho          * Must be a reference to a Local or Arg
98149703c7Sjruoho          */
99149703c7Sjruoho         switch (ObjDesc->Reference.Class)
100149703c7Sjruoho         {
101149703c7Sjruoho         case ACPI_REFCLASS_LOCAL:
102149703c7Sjruoho         case ACPI_REFCLASS_ARG:
103149703c7Sjruoho         case ACPI_REFCLASS_DEBUG:
104149703c7Sjruoho 
105149703c7Sjruoho             /* The referenced object is the pseudo-node for the local/arg */
106149703c7Sjruoho 
107149703c7Sjruoho             ReferencedObj = ObjDesc->Reference.Object;
108149703c7Sjruoho             break;
109149703c7Sjruoho 
110149703c7Sjruoho         default:
111149703c7Sjruoho 
112149703c7Sjruoho             ACPI_ERROR ((AE_INFO, "Unknown Reference Class 0x%2.2X",
113149703c7Sjruoho                 ObjDesc->Reference.Class));
114149703c7Sjruoho             return_ACPI_STATUS (AE_AML_INTERNAL);
115149703c7Sjruoho         }
116149703c7Sjruoho         break;
117149703c7Sjruoho 
118149703c7Sjruoho     case ACPI_DESC_TYPE_NAMED:
119149703c7Sjruoho         /*
120149703c7Sjruoho          * A named reference that has already been resolved to a Node
121149703c7Sjruoho          */
122149703c7Sjruoho         ReferencedObj = ObjDesc;
123149703c7Sjruoho         break;
124149703c7Sjruoho 
125149703c7Sjruoho     default:
126149703c7Sjruoho 
127149703c7Sjruoho         ACPI_ERROR ((AE_INFO, "Invalid descriptor type 0x%X",
128149703c7Sjruoho             ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)));
129149703c7Sjruoho         return_ACPI_STATUS (AE_TYPE);
130149703c7Sjruoho     }
131149703c7Sjruoho 
132149703c7Sjruoho 
133149703c7Sjruoho     /* Create a new reference object */
134149703c7Sjruoho 
135149703c7Sjruoho     ReferenceObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE);
136149703c7Sjruoho     if (!ReferenceObj)
137149703c7Sjruoho     {
138149703c7Sjruoho         return_ACPI_STATUS (AE_NO_MEMORY);
139149703c7Sjruoho     }
140149703c7Sjruoho 
141149703c7Sjruoho     ReferenceObj->Reference.Class = ACPI_REFCLASS_REFOF;
142149703c7Sjruoho     ReferenceObj->Reference.Object = ReferencedObj;
143149703c7Sjruoho     *ReturnDesc = ReferenceObj;
144149703c7Sjruoho 
145149703c7Sjruoho     ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
146149703c7Sjruoho         "Object %p Type [%s], returning Reference %p\n",
147149703c7Sjruoho         ObjDesc, AcpiUtGetObjectTypeName (ObjDesc), *ReturnDesc));
148149703c7Sjruoho 
149149703c7Sjruoho     return_ACPI_STATUS (AE_OK);
150149703c7Sjruoho }
151149703c7Sjruoho 
152149703c7Sjruoho 
153149703c7Sjruoho /*******************************************************************************
154149703c7Sjruoho  *
155149703c7Sjruoho  * FUNCTION:    AcpiExConcatTemplate
156149703c7Sjruoho  *
157149703c7Sjruoho  * PARAMETERS:  Operand0            - First source object
158149703c7Sjruoho  *              Operand1            - Second source object
159149703c7Sjruoho  *              ActualReturnDesc    - Where to place the return object
160149703c7Sjruoho  *              WalkState           - Current walk state
161149703c7Sjruoho  *
162149703c7Sjruoho  * RETURN:      Status
163149703c7Sjruoho  *
164149703c7Sjruoho  * DESCRIPTION: Concatenate two resource templates
165149703c7Sjruoho  *
166149703c7Sjruoho  ******************************************************************************/
167149703c7Sjruoho 
168149703c7Sjruoho ACPI_STATUS
169149703c7Sjruoho AcpiExConcatTemplate (
170149703c7Sjruoho     ACPI_OPERAND_OBJECT     *Operand0,
171149703c7Sjruoho     ACPI_OPERAND_OBJECT     *Operand1,
172149703c7Sjruoho     ACPI_OPERAND_OBJECT     **ActualReturnDesc,
173149703c7Sjruoho     ACPI_WALK_STATE         *WalkState)
174149703c7Sjruoho {
175149703c7Sjruoho     ACPI_STATUS             Status;
176149703c7Sjruoho     ACPI_OPERAND_OBJECT     *ReturnDesc;
177149703c7Sjruoho     UINT8                   *NewBuf;
178149703c7Sjruoho     UINT8                   *EndTag;
179149703c7Sjruoho     ACPI_SIZE               Length0;
180149703c7Sjruoho     ACPI_SIZE               Length1;
181149703c7Sjruoho     ACPI_SIZE               NewLength;
182149703c7Sjruoho 
183149703c7Sjruoho 
184149703c7Sjruoho     ACPI_FUNCTION_TRACE (ExConcatTemplate);
185149703c7Sjruoho 
186149703c7Sjruoho 
187149703c7Sjruoho     /*
188149703c7Sjruoho      * Find the EndTag descriptor in each resource template.
189149703c7Sjruoho      * Note1: returned pointers point TO the EndTag, not past it.
190149703c7Sjruoho      * Note2: zero-length buffers are allowed; treated like one EndTag
191149703c7Sjruoho      */
192149703c7Sjruoho 
193149703c7Sjruoho     /* Get the length of the first resource template */
194149703c7Sjruoho 
195149703c7Sjruoho     Status = AcpiUtGetResourceEndTag (Operand0, &EndTag);
196149703c7Sjruoho     if (ACPI_FAILURE (Status))
197149703c7Sjruoho     {
198149703c7Sjruoho         return_ACPI_STATUS (Status);
199149703c7Sjruoho     }
200149703c7Sjruoho 
201149703c7Sjruoho     Length0 = ACPI_PTR_DIFF (EndTag, Operand0->Buffer.Pointer);
202149703c7Sjruoho 
203149703c7Sjruoho     /* Get the length of the second resource template */
204149703c7Sjruoho 
205149703c7Sjruoho     Status = AcpiUtGetResourceEndTag (Operand1, &EndTag);
206149703c7Sjruoho     if (ACPI_FAILURE (Status))
207149703c7Sjruoho     {
208149703c7Sjruoho         return_ACPI_STATUS (Status);
209149703c7Sjruoho     }
210149703c7Sjruoho 
211149703c7Sjruoho     Length1 = ACPI_PTR_DIFF (EndTag, Operand1->Buffer.Pointer);
212149703c7Sjruoho 
213149703c7Sjruoho     /* Combine both lengths, minimum size will be 2 for EndTag */
214149703c7Sjruoho 
215149703c7Sjruoho     NewLength = Length0 + Length1 + sizeof (AML_RESOURCE_END_TAG);
216149703c7Sjruoho 
217149703c7Sjruoho     /* Create a new buffer object for the result (with one EndTag) */
218149703c7Sjruoho 
219149703c7Sjruoho     ReturnDesc = AcpiUtCreateBufferObject (NewLength);
220149703c7Sjruoho     if (!ReturnDesc)
221149703c7Sjruoho     {
222149703c7Sjruoho         return_ACPI_STATUS (AE_NO_MEMORY);
223149703c7Sjruoho     }
224149703c7Sjruoho 
225149703c7Sjruoho     /*
226149703c7Sjruoho      * Copy the templates to the new buffer, 0 first, then 1 follows. One
227149703c7Sjruoho      * EndTag descriptor is copied from Operand1.
228149703c7Sjruoho      */
229149703c7Sjruoho     NewBuf = ReturnDesc->Buffer.Pointer;
230149703c7Sjruoho     ACPI_MEMCPY (NewBuf, Operand0->Buffer.Pointer, Length0);
231149703c7Sjruoho     ACPI_MEMCPY (NewBuf + Length0, Operand1->Buffer.Pointer, Length1);
232149703c7Sjruoho 
233149703c7Sjruoho     /* Insert EndTag and set the checksum to zero, means "ignore checksum" */
234149703c7Sjruoho 
235149703c7Sjruoho     NewBuf[NewLength - 1] = 0;
236149703c7Sjruoho     NewBuf[NewLength - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
237149703c7Sjruoho 
238149703c7Sjruoho     /* Return the completed resource template */
239149703c7Sjruoho 
240149703c7Sjruoho     *ActualReturnDesc = ReturnDesc;
241149703c7Sjruoho     return_ACPI_STATUS (AE_OK);
242149703c7Sjruoho }
243149703c7Sjruoho 
244149703c7Sjruoho 
245149703c7Sjruoho /*******************************************************************************
246149703c7Sjruoho  *
247149703c7Sjruoho  * FUNCTION:    AcpiExDoConcatenate
248149703c7Sjruoho  *
249149703c7Sjruoho  * PARAMETERS:  Operand0            - First source object
250149703c7Sjruoho  *              Operand1            - Second source object
251149703c7Sjruoho  *              ActualReturnDesc    - Where to place the return object
252149703c7Sjruoho  *              WalkState           - Current walk state
253149703c7Sjruoho  *
254149703c7Sjruoho  * RETURN:      Status
255149703c7Sjruoho  *
256149703c7Sjruoho  * DESCRIPTION: Concatenate two objects OF THE SAME TYPE.
257149703c7Sjruoho  *
258149703c7Sjruoho  ******************************************************************************/
259149703c7Sjruoho 
260149703c7Sjruoho ACPI_STATUS
261149703c7Sjruoho AcpiExDoConcatenate (
262149703c7Sjruoho     ACPI_OPERAND_OBJECT     *Operand0,
263149703c7Sjruoho     ACPI_OPERAND_OBJECT     *Operand1,
264149703c7Sjruoho     ACPI_OPERAND_OBJECT     **ActualReturnDesc,
265149703c7Sjruoho     ACPI_WALK_STATE         *WalkState)
266149703c7Sjruoho {
267149703c7Sjruoho     ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
268149703c7Sjruoho     ACPI_OPERAND_OBJECT     *ReturnDesc;
269149703c7Sjruoho     char                    *NewBuf;
270149703c7Sjruoho     ACPI_STATUS             Status;
271149703c7Sjruoho 
272149703c7Sjruoho 
273149703c7Sjruoho     ACPI_FUNCTION_TRACE (ExDoConcatenate);
274149703c7Sjruoho 
275149703c7Sjruoho 
276149703c7Sjruoho     /*
277149703c7Sjruoho      * Convert the second operand if necessary. The first operand
278149703c7Sjruoho      * determines the type of the second operand, (See the Data Types
279149703c7Sjruoho      * section of the ACPI specification.)  Both object types are
280149703c7Sjruoho      * guaranteed to be either Integer/String/Buffer by the operand
281149703c7Sjruoho      * resolution mechanism.
282149703c7Sjruoho      */
283149703c7Sjruoho     switch (Operand0->Common.Type)
284149703c7Sjruoho     {
285149703c7Sjruoho     case ACPI_TYPE_INTEGER:
286*73d4e80bSchristos 
287149703c7Sjruoho         Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16);
288149703c7Sjruoho         break;
289149703c7Sjruoho 
290149703c7Sjruoho     case ACPI_TYPE_STRING:
291*73d4e80bSchristos 
292149703c7Sjruoho         Status = AcpiExConvertToString (Operand1, &LocalOperand1,
293149703c7Sjruoho                     ACPI_IMPLICIT_CONVERT_HEX);
294149703c7Sjruoho         break;
295149703c7Sjruoho 
296149703c7Sjruoho     case ACPI_TYPE_BUFFER:
297*73d4e80bSchristos 
298149703c7Sjruoho         Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
299149703c7Sjruoho         break;
300149703c7Sjruoho 
301149703c7Sjruoho     default:
302*73d4e80bSchristos 
303149703c7Sjruoho         ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
304149703c7Sjruoho             Operand0->Common.Type));
305149703c7Sjruoho         Status = AE_AML_INTERNAL;
306149703c7Sjruoho     }
307149703c7Sjruoho 
308149703c7Sjruoho     if (ACPI_FAILURE (Status))
309149703c7Sjruoho     {
310149703c7Sjruoho         goto Cleanup;
311149703c7Sjruoho     }
312149703c7Sjruoho 
313149703c7Sjruoho     /*
314149703c7Sjruoho      * Both operands are now known to be the same object type
315149703c7Sjruoho      * (Both are Integer, String, or Buffer), and we can now perform the
316149703c7Sjruoho      * concatenation.
317149703c7Sjruoho      */
318149703c7Sjruoho 
319149703c7Sjruoho     /*
320149703c7Sjruoho      * There are three cases to handle:
321149703c7Sjruoho      *
322149703c7Sjruoho      * 1) Two Integers concatenated to produce a new Buffer
323149703c7Sjruoho      * 2) Two Strings concatenated to produce a new String
324149703c7Sjruoho      * 3) Two Buffers concatenated to produce a new Buffer
325149703c7Sjruoho      */
326149703c7Sjruoho     switch (Operand0->Common.Type)
327149703c7Sjruoho     {
328149703c7Sjruoho     case ACPI_TYPE_INTEGER:
329149703c7Sjruoho 
330149703c7Sjruoho         /* Result of two Integers is a Buffer */
331149703c7Sjruoho         /* Need enough buffer space for two integers */
332149703c7Sjruoho 
333149703c7Sjruoho         ReturnDesc = AcpiUtCreateBufferObject ((ACPI_SIZE)
334149703c7Sjruoho                             ACPI_MUL_2 (AcpiGbl_IntegerByteWidth));
335149703c7Sjruoho         if (!ReturnDesc)
336149703c7Sjruoho         {
337149703c7Sjruoho             Status = AE_NO_MEMORY;
338149703c7Sjruoho             goto Cleanup;
339149703c7Sjruoho         }
340149703c7Sjruoho 
341149703c7Sjruoho         NewBuf = (char *) ReturnDesc->Buffer.Pointer;
342149703c7Sjruoho 
343149703c7Sjruoho         /* Copy the first integer, LSB first */
344149703c7Sjruoho 
345149703c7Sjruoho         ACPI_MEMCPY (NewBuf, &Operand0->Integer.Value,
346149703c7Sjruoho                         AcpiGbl_IntegerByteWidth);
347149703c7Sjruoho 
348149703c7Sjruoho         /* Copy the second integer (LSB first) after the first */
349149703c7Sjruoho 
350149703c7Sjruoho         ACPI_MEMCPY (NewBuf + AcpiGbl_IntegerByteWidth,
351149703c7Sjruoho                         &LocalOperand1->Integer.Value,
352149703c7Sjruoho                         AcpiGbl_IntegerByteWidth);
353149703c7Sjruoho         break;
354149703c7Sjruoho 
355149703c7Sjruoho     case ACPI_TYPE_STRING:
356149703c7Sjruoho 
357149703c7Sjruoho         /* Result of two Strings is a String */
358149703c7Sjruoho 
359149703c7Sjruoho         ReturnDesc = AcpiUtCreateStringObject (
360149703c7Sjruoho                         ((ACPI_SIZE) Operand0->String.Length +
361149703c7Sjruoho                         LocalOperand1->String.Length));
362149703c7Sjruoho         if (!ReturnDesc)
363149703c7Sjruoho         {
364149703c7Sjruoho             Status = AE_NO_MEMORY;
365149703c7Sjruoho             goto Cleanup;
366149703c7Sjruoho         }
367149703c7Sjruoho 
368149703c7Sjruoho         NewBuf = ReturnDesc->String.Pointer;
369149703c7Sjruoho 
370149703c7Sjruoho         /* Concatenate the strings */
371149703c7Sjruoho 
372149703c7Sjruoho         ACPI_STRCPY (NewBuf, Operand0->String.Pointer);
373149703c7Sjruoho         ACPI_STRCPY (NewBuf + Operand0->String.Length,
374149703c7Sjruoho                         LocalOperand1->String.Pointer);
375149703c7Sjruoho         break;
376149703c7Sjruoho 
377149703c7Sjruoho     case ACPI_TYPE_BUFFER:
378149703c7Sjruoho 
379149703c7Sjruoho         /* Result of two Buffers is a Buffer */
380149703c7Sjruoho 
381149703c7Sjruoho         ReturnDesc = AcpiUtCreateBufferObject (
382149703c7Sjruoho                         ((ACPI_SIZE) Operand0->Buffer.Length +
383149703c7Sjruoho                         LocalOperand1->Buffer.Length));
384149703c7Sjruoho         if (!ReturnDesc)
385149703c7Sjruoho         {
386149703c7Sjruoho             Status = AE_NO_MEMORY;
387149703c7Sjruoho             goto Cleanup;
388149703c7Sjruoho         }
389149703c7Sjruoho 
390149703c7Sjruoho         NewBuf = (char *) ReturnDesc->Buffer.Pointer;
391149703c7Sjruoho 
392149703c7Sjruoho         /* Concatenate the buffers */
393149703c7Sjruoho 
394149703c7Sjruoho         ACPI_MEMCPY (NewBuf, Operand0->Buffer.Pointer,
395149703c7Sjruoho                         Operand0->Buffer.Length);
396149703c7Sjruoho         ACPI_MEMCPY (NewBuf + Operand0->Buffer.Length,
397149703c7Sjruoho                         LocalOperand1->Buffer.Pointer,
398149703c7Sjruoho                         LocalOperand1->Buffer.Length);
399149703c7Sjruoho         break;
400149703c7Sjruoho 
401149703c7Sjruoho     default:
402149703c7Sjruoho 
403149703c7Sjruoho         /* Invalid object type, should not happen here */
404149703c7Sjruoho 
405149703c7Sjruoho         ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
406149703c7Sjruoho             Operand0->Common.Type));
407149703c7Sjruoho         Status =AE_AML_INTERNAL;
408149703c7Sjruoho         goto Cleanup;
409149703c7Sjruoho     }
410149703c7Sjruoho 
411149703c7Sjruoho     *ActualReturnDesc = ReturnDesc;
412149703c7Sjruoho 
413149703c7Sjruoho Cleanup:
414149703c7Sjruoho     if (LocalOperand1 != Operand1)
415149703c7Sjruoho     {
416149703c7Sjruoho         AcpiUtRemoveReference (LocalOperand1);
417149703c7Sjruoho     }
418149703c7Sjruoho     return_ACPI_STATUS (Status);
419149703c7Sjruoho }
420149703c7Sjruoho 
421149703c7Sjruoho 
422149703c7Sjruoho /*******************************************************************************
423149703c7Sjruoho  *
424149703c7Sjruoho  * FUNCTION:    AcpiExDoMathOp
425149703c7Sjruoho  *
426149703c7Sjruoho  * PARAMETERS:  Opcode              - AML opcode
427149703c7Sjruoho  *              Integer0            - Integer operand #0
428149703c7Sjruoho  *              Integer1            - Integer operand #1
429149703c7Sjruoho  *
430149703c7Sjruoho  * RETURN:      Integer result of the operation
431149703c7Sjruoho  *
432149703c7Sjruoho  * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
433149703c7Sjruoho  *              math functions here is to prevent a lot of pointer dereferencing
434149703c7Sjruoho  *              to obtain the operands.
435149703c7Sjruoho  *
436149703c7Sjruoho  ******************************************************************************/
437149703c7Sjruoho 
438149703c7Sjruoho UINT64
439149703c7Sjruoho AcpiExDoMathOp (
440149703c7Sjruoho     UINT16                  Opcode,
441149703c7Sjruoho     UINT64                  Integer0,
442149703c7Sjruoho     UINT64                  Integer1)
443149703c7Sjruoho {
444149703c7Sjruoho 
445149703c7Sjruoho     ACPI_FUNCTION_ENTRY ();
446149703c7Sjruoho 
447149703c7Sjruoho 
448149703c7Sjruoho     switch (Opcode)
449149703c7Sjruoho     {
450149703c7Sjruoho     case AML_ADD_OP:                /* Add (Integer0, Integer1, Result) */
451149703c7Sjruoho 
452149703c7Sjruoho         return (Integer0 + Integer1);
453149703c7Sjruoho 
454149703c7Sjruoho     case AML_BIT_AND_OP:            /* And (Integer0, Integer1, Result) */
455149703c7Sjruoho 
456149703c7Sjruoho         return (Integer0 & Integer1);
457149703c7Sjruoho 
458149703c7Sjruoho     case AML_BIT_NAND_OP:           /* NAnd (Integer0, Integer1, Result) */
459149703c7Sjruoho 
460149703c7Sjruoho         return (~(Integer0 & Integer1));
461149703c7Sjruoho 
462149703c7Sjruoho     case AML_BIT_OR_OP:             /* Or (Integer0, Integer1, Result) */
463149703c7Sjruoho 
464149703c7Sjruoho         return (Integer0 | Integer1);
465149703c7Sjruoho 
466149703c7Sjruoho     case AML_BIT_NOR_OP:            /* NOr (Integer0, Integer1, Result) */
467149703c7Sjruoho 
468149703c7Sjruoho         return (~(Integer0 | Integer1));
469149703c7Sjruoho 
470149703c7Sjruoho     case AML_BIT_XOR_OP:            /* XOr (Integer0, Integer1, Result) */
471149703c7Sjruoho 
472149703c7Sjruoho         return (Integer0 ^ Integer1);
473149703c7Sjruoho 
474149703c7Sjruoho     case AML_MULTIPLY_OP:           /* Multiply (Integer0, Integer1, Result) */
475149703c7Sjruoho 
476149703c7Sjruoho         return (Integer0 * Integer1);
477149703c7Sjruoho 
478149703c7Sjruoho     case AML_SHIFT_LEFT_OP:         /* ShiftLeft (Operand, ShiftCount, Result)*/
479149703c7Sjruoho 
480149703c7Sjruoho         /*
481149703c7Sjruoho          * We need to check if the shiftcount is larger than the integer bit
482149703c7Sjruoho          * width since the behavior of this is not well-defined in the C language.
483149703c7Sjruoho          */
484149703c7Sjruoho         if (Integer1 >= AcpiGbl_IntegerBitWidth)
485149703c7Sjruoho         {
486149703c7Sjruoho             return (0);
487149703c7Sjruoho         }
488149703c7Sjruoho         return (Integer0 << Integer1);
489149703c7Sjruoho 
490149703c7Sjruoho     case AML_SHIFT_RIGHT_OP:        /* ShiftRight (Operand, ShiftCount, Result) */
491149703c7Sjruoho 
492149703c7Sjruoho         /*
493149703c7Sjruoho          * We need to check if the shiftcount is larger than the integer bit
494149703c7Sjruoho          * width since the behavior of this is not well-defined in the C language.
495149703c7Sjruoho          */
496149703c7Sjruoho         if (Integer1 >= AcpiGbl_IntegerBitWidth)
497149703c7Sjruoho         {
498149703c7Sjruoho             return (0);
499149703c7Sjruoho         }
500149703c7Sjruoho         return (Integer0 >> Integer1);
501149703c7Sjruoho 
502149703c7Sjruoho     case AML_SUBTRACT_OP:           /* Subtract (Integer0, Integer1, Result) */
503149703c7Sjruoho 
504149703c7Sjruoho         return (Integer0 - Integer1);
505149703c7Sjruoho 
506149703c7Sjruoho     default:
507149703c7Sjruoho 
508149703c7Sjruoho         return (0);
509149703c7Sjruoho     }
510149703c7Sjruoho }
511149703c7Sjruoho 
512149703c7Sjruoho 
513149703c7Sjruoho /*******************************************************************************
514149703c7Sjruoho  *
515149703c7Sjruoho  * FUNCTION:    AcpiExDoLogicalNumericOp
516149703c7Sjruoho  *
517149703c7Sjruoho  * PARAMETERS:  Opcode              - AML opcode
518149703c7Sjruoho  *              Integer0            - Integer operand #0
519149703c7Sjruoho  *              Integer1            - Integer operand #1
520149703c7Sjruoho  *              LogicalResult       - TRUE/FALSE result of the operation
521149703c7Sjruoho  *
522149703c7Sjruoho  * RETURN:      Status
523149703c7Sjruoho  *
524149703c7Sjruoho  * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
525149703c7Sjruoho  *              operators (LAnd and LOr), both operands must be integers.
526149703c7Sjruoho  *
527149703c7Sjruoho  *              Note: cleanest machine code seems to be produced by the code
528149703c7Sjruoho  *              below, rather than using statements of the form:
529149703c7Sjruoho  *                  Result = (Integer0 && Integer1);
530149703c7Sjruoho  *
531149703c7Sjruoho  ******************************************************************************/
532149703c7Sjruoho 
533149703c7Sjruoho ACPI_STATUS
534149703c7Sjruoho AcpiExDoLogicalNumericOp (
535149703c7Sjruoho     UINT16                  Opcode,
536149703c7Sjruoho     UINT64                  Integer0,
537149703c7Sjruoho     UINT64                  Integer1,
538149703c7Sjruoho     BOOLEAN                 *LogicalResult)
539149703c7Sjruoho {
540149703c7Sjruoho     ACPI_STATUS             Status = AE_OK;
541149703c7Sjruoho     BOOLEAN                 LocalResult = FALSE;
542149703c7Sjruoho 
543149703c7Sjruoho 
544149703c7Sjruoho     ACPI_FUNCTION_TRACE (ExDoLogicalNumericOp);
545149703c7Sjruoho 
546149703c7Sjruoho 
547149703c7Sjruoho     switch (Opcode)
548149703c7Sjruoho     {
549149703c7Sjruoho     case AML_LAND_OP:               /* LAnd (Integer0, Integer1) */
550149703c7Sjruoho 
551149703c7Sjruoho         if (Integer0 && Integer1)
552149703c7Sjruoho         {
553149703c7Sjruoho             LocalResult = TRUE;
554149703c7Sjruoho         }
555149703c7Sjruoho         break;
556149703c7Sjruoho 
557149703c7Sjruoho     case AML_LOR_OP:                /* LOr (Integer0, Integer1) */
558149703c7Sjruoho 
559149703c7Sjruoho         if (Integer0 || Integer1)
560149703c7Sjruoho         {
561149703c7Sjruoho             LocalResult = TRUE;
562149703c7Sjruoho         }
563149703c7Sjruoho         break;
564149703c7Sjruoho 
565149703c7Sjruoho     default:
566*73d4e80bSchristos 
567149703c7Sjruoho         Status = AE_AML_INTERNAL;
568149703c7Sjruoho         break;
569149703c7Sjruoho     }
570149703c7Sjruoho 
571149703c7Sjruoho     /* Return the logical result and status */
572149703c7Sjruoho 
573149703c7Sjruoho     *LogicalResult = LocalResult;
574149703c7Sjruoho     return_ACPI_STATUS (Status);
575149703c7Sjruoho }
576149703c7Sjruoho 
577149703c7Sjruoho 
578149703c7Sjruoho /*******************************************************************************
579149703c7Sjruoho  *
580149703c7Sjruoho  * FUNCTION:    AcpiExDoLogicalOp
581149703c7Sjruoho  *
582149703c7Sjruoho  * PARAMETERS:  Opcode              - AML opcode
583149703c7Sjruoho  *              Operand0            - operand #0
584149703c7Sjruoho  *              Operand1            - operand #1
585149703c7Sjruoho  *              LogicalResult       - TRUE/FALSE result of the operation
586149703c7Sjruoho  *
587149703c7Sjruoho  * RETURN:      Status
588149703c7Sjruoho  *
589149703c7Sjruoho  * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
590149703c7Sjruoho  *              functions here is to prevent a lot of pointer dereferencing
591149703c7Sjruoho  *              to obtain the operands and to simplify the generation of the
592149703c7Sjruoho  *              logical value. For the Numeric operators (LAnd and LOr), both
593149703c7Sjruoho  *              operands must be integers. For the other logical operators,
594149703c7Sjruoho  *              operands can be any combination of Integer/String/Buffer. The
595149703c7Sjruoho  *              first operand determines the type to which the second operand
596149703c7Sjruoho  *              will be converted.
597149703c7Sjruoho  *
598149703c7Sjruoho  *              Note: cleanest machine code seems to be produced by the code
599149703c7Sjruoho  *              below, rather than using statements of the form:
600149703c7Sjruoho  *                  Result = (Operand0 == Operand1);
601149703c7Sjruoho  *
602149703c7Sjruoho  ******************************************************************************/
603149703c7Sjruoho 
604149703c7Sjruoho ACPI_STATUS
605149703c7Sjruoho AcpiExDoLogicalOp (
606149703c7Sjruoho     UINT16                  Opcode,
607149703c7Sjruoho     ACPI_OPERAND_OBJECT     *Operand0,
608149703c7Sjruoho     ACPI_OPERAND_OBJECT     *Operand1,
609149703c7Sjruoho     BOOLEAN                 *LogicalResult)
610149703c7Sjruoho {
611149703c7Sjruoho     ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
612149703c7Sjruoho     UINT64                  Integer0;
613149703c7Sjruoho     UINT64                  Integer1;
614149703c7Sjruoho     UINT32                  Length0;
615149703c7Sjruoho     UINT32                  Length1;
616149703c7Sjruoho     ACPI_STATUS             Status = AE_OK;
617149703c7Sjruoho     BOOLEAN                 LocalResult = FALSE;
618149703c7Sjruoho     int                     Compare;
619149703c7Sjruoho 
620149703c7Sjruoho 
621149703c7Sjruoho     ACPI_FUNCTION_TRACE (ExDoLogicalOp);
622149703c7Sjruoho 
623149703c7Sjruoho 
624149703c7Sjruoho     /*
625149703c7Sjruoho      * Convert the second operand if necessary. The first operand
626149703c7Sjruoho      * determines the type of the second operand, (See the Data Types
627149703c7Sjruoho      * section of the ACPI 3.0+ specification.)  Both object types are
628149703c7Sjruoho      * guaranteed to be either Integer/String/Buffer by the operand
629149703c7Sjruoho      * resolution mechanism.
630149703c7Sjruoho      */
631149703c7Sjruoho     switch (Operand0->Common.Type)
632149703c7Sjruoho     {
633149703c7Sjruoho     case ACPI_TYPE_INTEGER:
634*73d4e80bSchristos 
635149703c7Sjruoho         Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16);
636149703c7Sjruoho         break;
637149703c7Sjruoho 
638149703c7Sjruoho     case ACPI_TYPE_STRING:
639*73d4e80bSchristos 
640149703c7Sjruoho         Status = AcpiExConvertToString (Operand1, &LocalOperand1,
641149703c7Sjruoho                     ACPI_IMPLICIT_CONVERT_HEX);
642149703c7Sjruoho         break;
643149703c7Sjruoho 
644149703c7Sjruoho     case ACPI_TYPE_BUFFER:
645*73d4e80bSchristos 
646149703c7Sjruoho         Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
647149703c7Sjruoho         break;
648149703c7Sjruoho 
649149703c7Sjruoho     default:
650*73d4e80bSchristos 
651149703c7Sjruoho         Status = AE_AML_INTERNAL;
652149703c7Sjruoho         break;
653149703c7Sjruoho     }
654149703c7Sjruoho 
655149703c7Sjruoho     if (ACPI_FAILURE (Status))
656149703c7Sjruoho     {
657149703c7Sjruoho         goto Cleanup;
658149703c7Sjruoho     }
659149703c7Sjruoho 
660149703c7Sjruoho     /*
661149703c7Sjruoho      * Two cases: 1) Both Integers, 2) Both Strings or Buffers
662149703c7Sjruoho      */
663149703c7Sjruoho     if (Operand0->Common.Type == ACPI_TYPE_INTEGER)
664149703c7Sjruoho     {
665149703c7Sjruoho         /*
666149703c7Sjruoho          * 1) Both operands are of type integer
667149703c7Sjruoho          *    Note: LocalOperand1 may have changed above
668149703c7Sjruoho          */
669149703c7Sjruoho         Integer0 = Operand0->Integer.Value;
670149703c7Sjruoho         Integer1 = LocalOperand1->Integer.Value;
671149703c7Sjruoho 
672149703c7Sjruoho         switch (Opcode)
673149703c7Sjruoho         {
674149703c7Sjruoho         case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
675149703c7Sjruoho 
676149703c7Sjruoho             if (Integer0 == Integer1)
677149703c7Sjruoho             {
678149703c7Sjruoho                 LocalResult = TRUE;
679149703c7Sjruoho             }
680149703c7Sjruoho             break;
681149703c7Sjruoho 
682149703c7Sjruoho         case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
683149703c7Sjruoho 
684149703c7Sjruoho             if (Integer0 > Integer1)
685149703c7Sjruoho             {
686149703c7Sjruoho                 LocalResult = TRUE;
687149703c7Sjruoho             }
688149703c7Sjruoho             break;
689149703c7Sjruoho 
690149703c7Sjruoho         case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
691149703c7Sjruoho 
692149703c7Sjruoho             if (Integer0 < Integer1)
693149703c7Sjruoho             {
694149703c7Sjruoho                 LocalResult = TRUE;
695149703c7Sjruoho             }
696149703c7Sjruoho             break;
697149703c7Sjruoho 
698149703c7Sjruoho         default:
699*73d4e80bSchristos 
700149703c7Sjruoho             Status = AE_AML_INTERNAL;
701149703c7Sjruoho             break;
702149703c7Sjruoho         }
703149703c7Sjruoho     }
704149703c7Sjruoho     else
705149703c7Sjruoho     {
706149703c7Sjruoho         /*
707149703c7Sjruoho          * 2) Both operands are Strings or both are Buffers
708149703c7Sjruoho          *    Note: Code below takes advantage of common Buffer/String
709149703c7Sjruoho          *          object fields. LocalOperand1 may have changed above. Use
710149703c7Sjruoho          *          memcmp to handle nulls in buffers.
711149703c7Sjruoho          */
712149703c7Sjruoho         Length0 = Operand0->Buffer.Length;
713149703c7Sjruoho         Length1 = LocalOperand1->Buffer.Length;
714149703c7Sjruoho 
715149703c7Sjruoho         /* Lexicographic compare: compare the data bytes */
716149703c7Sjruoho 
717149703c7Sjruoho         Compare = ACPI_MEMCMP (Operand0->Buffer.Pointer,
718149703c7Sjruoho                     LocalOperand1->Buffer.Pointer,
719149703c7Sjruoho                     (Length0 > Length1) ? Length1 : Length0);
720149703c7Sjruoho 
721149703c7Sjruoho         switch (Opcode)
722149703c7Sjruoho         {
723149703c7Sjruoho         case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
724149703c7Sjruoho 
725149703c7Sjruoho             /* Length and all bytes must be equal */
726149703c7Sjruoho 
727149703c7Sjruoho             if ((Length0 == Length1) &&
728149703c7Sjruoho                 (Compare == 0))
729149703c7Sjruoho             {
730149703c7Sjruoho                 /* Length and all bytes match ==> TRUE */
731149703c7Sjruoho 
732149703c7Sjruoho                 LocalResult = TRUE;
733149703c7Sjruoho             }
734149703c7Sjruoho             break;
735149703c7Sjruoho 
736149703c7Sjruoho         case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
737149703c7Sjruoho 
738149703c7Sjruoho             if (Compare > 0)
739149703c7Sjruoho             {
740149703c7Sjruoho                 LocalResult = TRUE;
741149703c7Sjruoho                 goto Cleanup;   /* TRUE */
742149703c7Sjruoho             }
743149703c7Sjruoho             if (Compare < 0)
744149703c7Sjruoho             {
745149703c7Sjruoho                 goto Cleanup;   /* FALSE */
746149703c7Sjruoho             }
747149703c7Sjruoho 
748149703c7Sjruoho             /* Bytes match (to shortest length), compare lengths */
749149703c7Sjruoho 
750149703c7Sjruoho             if (Length0 > Length1)
751149703c7Sjruoho             {
752149703c7Sjruoho                 LocalResult = TRUE;
753149703c7Sjruoho             }
754149703c7Sjruoho             break;
755149703c7Sjruoho 
756149703c7Sjruoho         case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
757149703c7Sjruoho 
758149703c7Sjruoho             if (Compare > 0)
759149703c7Sjruoho             {
760149703c7Sjruoho                 goto Cleanup;   /* FALSE */
761149703c7Sjruoho             }
762149703c7Sjruoho             if (Compare < 0)
763149703c7Sjruoho             {
764149703c7Sjruoho                 LocalResult = TRUE;
765149703c7Sjruoho                 goto Cleanup;   /* TRUE */
766149703c7Sjruoho             }
767149703c7Sjruoho 
768149703c7Sjruoho             /* Bytes match (to shortest length), compare lengths */
769149703c7Sjruoho 
770149703c7Sjruoho             if (Length0 < Length1)
771149703c7Sjruoho             {
772149703c7Sjruoho                 LocalResult = TRUE;
773149703c7Sjruoho             }
774149703c7Sjruoho             break;
775149703c7Sjruoho 
776149703c7Sjruoho         default:
777*73d4e80bSchristos 
778149703c7Sjruoho             Status = AE_AML_INTERNAL;
779149703c7Sjruoho             break;
780149703c7Sjruoho         }
781149703c7Sjruoho     }
782149703c7Sjruoho 
783149703c7Sjruoho Cleanup:
784149703c7Sjruoho 
785149703c7Sjruoho     /* New object was created if implicit conversion performed - delete */
786149703c7Sjruoho 
787149703c7Sjruoho     if (LocalOperand1 != Operand1)
788149703c7Sjruoho     {
789149703c7Sjruoho         AcpiUtRemoveReference (LocalOperand1);
790149703c7Sjruoho     }
791149703c7Sjruoho 
792149703c7Sjruoho     /* Return the logical result and status */
793149703c7Sjruoho 
794149703c7Sjruoho     *LogicalResult = LocalResult;
795149703c7Sjruoho     return_ACPI_STATUS (Status);
796149703c7Sjruoho }
797