167754Smsmith
267754Smsmith/******************************************************************************
367754Smsmith *
477424Smsmith * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
567754Smsmith *
667754Smsmith *****************************************************************************/
767754Smsmith
8217365Sjkim/*
9217365Sjkim * Copyright (C) 2000 - 2011, Intel Corp.
1070243Smsmith * All rights reserved.
1167754Smsmith *
12217365Sjkim * Redistribution and use in source and binary forms, with or without
13217365Sjkim * modification, are permitted provided that the following conditions
14217365Sjkim * are met:
15217365Sjkim * 1. Redistributions of source code must retain the above copyright
16217365Sjkim *    notice, this list of conditions, and the following disclaimer,
17217365Sjkim *    without modification.
18217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
20217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
21217365Sjkim *    including a substantially similar Disclaimer requirement for further
22217365Sjkim *    binary redistribution.
23217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
24217365Sjkim *    of any contributors may be used to endorse or promote products derived
25217365Sjkim *    from this software without specific prior written permission.
2667754Smsmith *
27217365Sjkim * Alternatively, this software may be distributed under the terms of the
28217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
29217365Sjkim * Software Foundation.
3067754Smsmith *
31217365Sjkim * NO WARRANTY
32217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
43217365Sjkim */
4467754Smsmith
4577424Smsmith#define __EXMISC_C__
4667754Smsmith
47193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
48193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
49193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
50193341Sjkim#include <contrib/dev/acpica/include/amlcode.h>
51193341Sjkim#include <contrib/dev/acpica/include/amlresrc.h>
5267754Smsmith
5367754Smsmith
5477424Smsmith#define _COMPONENT          ACPI_EXECUTER
5591116Smsmith        ACPI_MODULE_NAME    ("exmisc")
5667754Smsmith
5767754Smsmith
5867754Smsmith/*******************************************************************************
5967754Smsmith *
6085756Smsmith * FUNCTION:    AcpiExGetObjectReference
6167754Smsmith *
62100966Siwasaki * PARAMETERS:  ObjDesc             - Create a reference to this object
63100966Siwasaki *              ReturnDesc          - Where to store the reference
64100966Siwasaki *              WalkState           - Current state
6567754Smsmith *
6667754Smsmith * RETURN:      Status
6767754Smsmith *
6885756Smsmith * DESCRIPTION: Obtain and return a "reference" to the target object
6985756Smsmith *              Common code for the RefOfOp and the CondRefOfOp.
7067754Smsmith *
7167754Smsmith ******************************************************************************/
7267754Smsmith
7367754SmsmithACPI_STATUS
7485756SmsmithAcpiExGetObjectReference (
7585756Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
7685756Smsmith    ACPI_OPERAND_OBJECT     **ReturnDesc,
7784491Smsmith    ACPI_WALK_STATE         *WalkState)
7867754Smsmith{
79100966Siwasaki    ACPI_OPERAND_OBJECT     *ReferenceObj;
80100966Siwasaki    ACPI_OPERAND_OBJECT     *ReferencedObj;
8167754Smsmith
8267754Smsmith
83167802Sjkim    ACPI_FUNCTION_TRACE_PTR (ExGetObjectReference, ObjDesc);
8467754Smsmith
8580062Smsmith
86100966Siwasaki    *ReturnDesc = NULL;
87100966Siwasaki
8891116Smsmith    switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))
8985756Smsmith    {
9099679Siwasaki    case ACPI_DESC_TYPE_OPERAND:
9191116Smsmith
92193267Sjkim        if (ObjDesc->Common.Type != ACPI_TYPE_LOCAL_REFERENCE)
9385756Smsmith        {
94100966Siwasaki            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
9585756Smsmith        }
9667754Smsmith
9785756Smsmith        /*
98100966Siwasaki         * Must be a reference to a Local or Arg
9985756Smsmith         */
100193267Sjkim        switch (ObjDesc->Reference.Class)
10185756Smsmith        {
102193267Sjkim        case ACPI_REFCLASS_LOCAL:
103193267Sjkim        case ACPI_REFCLASS_ARG:
104193267Sjkim        case ACPI_REFCLASS_DEBUG:
10567754Smsmith
106100966Siwasaki            /* The referenced object is the pseudo-node for the local/arg */
107100966Siwasaki
108100966Siwasaki            ReferencedObj = ObjDesc->Reference.Object;
10985756Smsmith            break;
11085756Smsmith
11185756Smsmith        default:
11285756Smsmith
113204773Sjkim            ACPI_ERROR ((AE_INFO, "Unknown Reference Class 0x%2.2X",
114193267Sjkim                ObjDesc->Reference.Class));
115100966Siwasaki            return_ACPI_STATUS (AE_AML_INTERNAL);
11685756Smsmith        }
11791116Smsmith        break;
11885756Smsmith
11985756Smsmith
12091116Smsmith    case ACPI_DESC_TYPE_NAMED:
12191116Smsmith
122102550Siwasaki        /*
123100966Siwasaki         * A named reference that has already been resolved to a Node
124100966Siwasaki         */
125100966Siwasaki        ReferencedObj = ObjDesc;
12691116Smsmith        break;
12767754Smsmith
12891116Smsmith
12991116Smsmith    default:
13091116Smsmith
131204773Sjkim        ACPI_ERROR ((AE_INFO, "Invalid descriptor type 0x%X",
132167802Sjkim            ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)));
133100966Siwasaki        return_ACPI_STATUS (AE_TYPE);
13485756Smsmith    }
13567754Smsmith
13667754Smsmith
137100966Siwasaki    /* Create a new reference object */
13880062Smsmith
139107325Siwasaki    ReferenceObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE);
140100966Siwasaki    if (!ReferenceObj)
141100966Siwasaki    {
142100966Siwasaki        return_ACPI_STATUS (AE_NO_MEMORY);
143100966Siwasaki    }
144100966Siwasaki
145193267Sjkim    ReferenceObj->Reference.Class = ACPI_REFCLASS_REFOF;
146100966Siwasaki    ReferenceObj->Reference.Object = ReferencedObj;
147100966Siwasaki    *ReturnDesc = ReferenceObj;
148100966Siwasaki
149151937Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
150151937Sjkim        "Object %p Type [%s], returning Reference %p\n",
151151937Sjkim        ObjDesc, AcpiUtGetObjectTypeName (ObjDesc), *ReturnDesc));
152100966Siwasaki
153100966Siwasaki    return_ACPI_STATUS (AE_OK);
15485756Smsmith}
15580062Smsmith
15680062Smsmith
15785756Smsmith/*******************************************************************************
15885756Smsmith *
15991116Smsmith * FUNCTION:    AcpiExConcatTemplate
16085756Smsmith *
161138287Smarks * PARAMETERS:  Operand0            - First source object
162138287Smarks *              Operand1            - Second source object
163138287Smarks *              ActualReturnDesc    - Where to place the return object
16485756Smsmith *              WalkState           - Current walk state
16585756Smsmith *
16685756Smsmith * RETURN:      Status
16785756Smsmith *
16891116Smsmith * DESCRIPTION: Concatenate two resource templates
16991116Smsmith *
17091116Smsmith ******************************************************************************/
17191116Smsmith
17291116SmsmithACPI_STATUS
17391116SmsmithAcpiExConcatTemplate (
174138287Smarks    ACPI_OPERAND_OBJECT     *Operand0,
175138287Smarks    ACPI_OPERAND_OBJECT     *Operand1,
17691116Smsmith    ACPI_OPERAND_OBJECT     **ActualReturnDesc,
17791116Smsmith    ACPI_WALK_STATE         *WalkState)
17891116Smsmith{
179167802Sjkim    ACPI_STATUS             Status;
18091116Smsmith    ACPI_OPERAND_OBJECT     *ReturnDesc;
181107325Siwasaki    UINT8                   *NewBuf;
182167802Sjkim    UINT8                   *EndTag;
183167802Sjkim    ACPI_SIZE               Length0;
18491116Smsmith    ACPI_SIZE               Length1;
185167802Sjkim    ACPI_SIZE               NewLength;
18691116Smsmith
18791116Smsmith
188167802Sjkim    ACPI_FUNCTION_TRACE (ExConcatTemplate);
18991116Smsmith
19091116Smsmith
191167802Sjkim    /*
192167802Sjkim     * Find the EndTag descriptor in each resource template.
193167802Sjkim     * Note1: returned pointers point TO the EndTag, not past it.
194167802Sjkim     * Note2: zero-length buffers are allowed; treated like one EndTag
195167802Sjkim     */
19691116Smsmith
197167802Sjkim    /* Get the length of the first resource template */
198167802Sjkim
199167802Sjkim    Status = AcpiUtGetResourceEndTag (Operand0, &EndTag);
200167802Sjkim    if (ACPI_FAILURE (Status))
20191116Smsmith    {
202167802Sjkim        return_ACPI_STATUS (Status);
20391116Smsmith    }
20491116Smsmith
205167802Sjkim    Length0 = ACPI_PTR_DIFF (EndTag, Operand0->Buffer.Pointer);
20691116Smsmith
207167802Sjkim    /* Get the length of the second resource template */
20891116Smsmith
209167802Sjkim    Status = AcpiUtGetResourceEndTag (Operand1, &EndTag);
210167802Sjkim    if (ACPI_FAILURE (Status))
211167802Sjkim    {
212167802Sjkim        return_ACPI_STATUS (Status);
213167802Sjkim    }
214107325Siwasaki
215167802Sjkim    Length1 = ACPI_PTR_DIFF (EndTag, Operand1->Buffer.Pointer);
216167802Sjkim
217167802Sjkim    /* Combine both lengths, minimum size will be 2 for EndTag */
218167802Sjkim
219167802Sjkim    NewLength = Length0 + Length1 + sizeof (AML_RESOURCE_END_TAG);
220167802Sjkim
221167802Sjkim    /* Create a new buffer object for the result (with one EndTag) */
222167802Sjkim
223167802Sjkim    ReturnDesc = AcpiUtCreateBufferObject (NewLength);
224107325Siwasaki    if (!ReturnDesc)
22591116Smsmith    {
226107325Siwasaki        return_ACPI_STATUS (AE_NO_MEMORY);
22791116Smsmith    }
22891116Smsmith
229167802Sjkim    /*
230167802Sjkim     * Copy the templates to the new buffer, 0 first, then 1 follows. One
231167802Sjkim     * EndTag descriptor is copied from Operand1.
232167802Sjkim     */
233107325Siwasaki    NewBuf = ReturnDesc->Buffer.Pointer;
234167802Sjkim    ACPI_MEMCPY (NewBuf, Operand0->Buffer.Pointer, Length0);
235167802Sjkim    ACPI_MEMCPY (NewBuf + Length0, Operand1->Buffer.Pointer, Length1);
23691116Smsmith
237167802Sjkim    /* Insert EndTag and set the checksum to zero, means "ignore checksum" */
23891116Smsmith
239167802Sjkim    NewBuf[NewLength - 1] = 0;
240167802Sjkim    NewBuf[NewLength - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
24191116Smsmith
242167802Sjkim    /* Return the completed resource template */
24391116Smsmith
24491116Smsmith    *ActualReturnDesc = ReturnDesc;
24591116Smsmith    return_ACPI_STATUS (AE_OK);
24691116Smsmith}
24791116Smsmith
24891116Smsmith
24991116Smsmith/*******************************************************************************
25091116Smsmith *
25191116Smsmith * FUNCTION:    AcpiExDoConcatenate
25291116Smsmith *
253138287Smarks * PARAMETERS:  Operand0            - First source object
254138287Smarks *              Operand1            - Second source object
25591116Smsmith *              ActualReturnDesc    - Where to place the return object
25691116Smsmith *              WalkState           - Current walk state
25791116Smsmith *
25891116Smsmith * RETURN:      Status
25991116Smsmith *
26085756Smsmith * DESCRIPTION: Concatenate two objects OF THE SAME TYPE.
26185756Smsmith *
26285756Smsmith ******************************************************************************/
26380062Smsmith
26485756SmsmithACPI_STATUS
26585756SmsmithAcpiExDoConcatenate (
266138287Smarks    ACPI_OPERAND_OBJECT     *Operand0,
267138287Smarks    ACPI_OPERAND_OBJECT     *Operand1,
26885756Smsmith    ACPI_OPERAND_OBJECT     **ActualReturnDesc,
26985756Smsmith    ACPI_WALK_STATE         *WalkState)
27085756Smsmith{
271138287Smarks    ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
27285756Smsmith    ACPI_OPERAND_OBJECT     *ReturnDesc;
273114237Snjl    char                    *NewBuf;
274138287Smarks    ACPI_STATUS             Status;
27580062Smsmith
27680062Smsmith
277167802Sjkim    ACPI_FUNCTION_TRACE (ExDoConcatenate);
27880062Smsmith
27980062Smsmith
28085756Smsmith    /*
281138287Smarks     * Convert the second operand if necessary.  The first operand
282138287Smarks     * determines the type of the second operand, (See the Data Types
283138287Smarks     * section of the ACPI specification.)  Both object types are
284138287Smarks     * guaranteed to be either Integer/String/Buffer by the operand
285138287Smarks     * resolution mechanism.
286138287Smarks     */
287193267Sjkim    switch (Operand0->Common.Type)
288138287Smarks    {
289138287Smarks    case ACPI_TYPE_INTEGER:
290138287Smarks        Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16);
291138287Smarks        break;
292138287Smarks
293138287Smarks    case ACPI_TYPE_STRING:
294138287Smarks        Status = AcpiExConvertToString (Operand1, &LocalOperand1,
295138287Smarks                    ACPI_IMPLICIT_CONVERT_HEX);
296138287Smarks        break;
297138287Smarks
298138287Smarks    case ACPI_TYPE_BUFFER:
299138287Smarks        Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
300138287Smarks        break;
301138287Smarks
302138287Smarks    default:
303204773Sjkim        ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
304193267Sjkim            Operand0->Common.Type));
305138287Smarks        Status = AE_AML_INTERNAL;
306138287Smarks    }
307138287Smarks
308138287Smarks    if (ACPI_FAILURE (Status))
309138287Smarks    {
310138287Smarks        goto Cleanup;
311138287Smarks    }
312138287Smarks
313138287Smarks    /*
314138287Smarks     * Both operands are now known to be the same object type
315138287Smarks     * (Both are Integer, String, or Buffer), and we can now perform the
316138287Smarks     * concatenation.
317138287Smarks     */
318138287Smarks
319138287Smarks    /*
32085756Smsmith     * There are three cases to handle:
321102550Siwasaki     *
32299679Siwasaki     * 1) Two Integers concatenated to produce a new Buffer
32399679Siwasaki     * 2) Two Strings concatenated to produce a new String
32499679Siwasaki     * 3) Two Buffers concatenated to produce a new Buffer
32585756Smsmith     */
326193267Sjkim    switch (Operand0->Common.Type)
32785756Smsmith    {
32885756Smsmith    case ACPI_TYPE_INTEGER:
32985756Smsmith
33099679Siwasaki        /* Result of two Integers is a Buffer */
331107325Siwasaki        /* Need enough buffer space for two integers */
33285756Smsmith
333151937Sjkim        ReturnDesc = AcpiUtCreateBufferObject ((ACPI_SIZE)
334138287Smarks                            ACPI_MUL_2 (AcpiGbl_IntegerByteWidth));
33585756Smsmith        if (!ReturnDesc)
33684491Smsmith        {
337138287Smarks            Status = AE_NO_MEMORY;
338138287Smarks            goto Cleanup;
33985756Smsmith        }
34084491Smsmith
341114237Snjl        NewBuf = (char *) ReturnDesc->Buffer.Pointer;
34284491Smsmith
343138287Smarks        /* Copy the first integer, LSB first */
34484491Smsmith
345167802Sjkim        ACPI_MEMCPY (NewBuf, &Operand0->Integer.Value,
346138287Smarks                        AcpiGbl_IntegerByteWidth);
34784491Smsmith
348138287Smarks        /* Copy the second integer (LSB first) after the first */
34984491Smsmith
350138287Smarks        ACPI_MEMCPY (NewBuf + AcpiGbl_IntegerByteWidth,
351138287Smarks                        &LocalOperand1->Integer.Value,
352138287Smarks                        AcpiGbl_IntegerByteWidth);
35380062Smsmith        break;
35480062Smsmith
35585756Smsmith    case ACPI_TYPE_STRING:
35680062Smsmith
35799679Siwasaki        /* Result of two Strings is a String */
35899679Siwasaki
359193267Sjkim        ReturnDesc = AcpiUtCreateStringObject (
360193267Sjkim                        ((ACPI_SIZE) Operand0->String.Length +
361167802Sjkim                        LocalOperand1->String.Length));
362138287Smarks        if (!ReturnDesc)
36380062Smsmith        {
36480062Smsmith            Status = AE_NO_MEMORY;
36567754Smsmith            goto Cleanup;
36667754Smsmith        }
36783174Smsmith
368138287Smarks        NewBuf = ReturnDesc->String.Pointer;
369138287Smarks
37099679Siwasaki        /* Concatenate the strings */
37199679Siwasaki
372167802Sjkim        ACPI_STRCPY (NewBuf, Operand0->String.Pointer);
373138287Smarks        ACPI_STRCPY (NewBuf + Operand0->String.Length,
374138287Smarks                        LocalOperand1->String.Pointer);
37585756Smsmith        break;
37680062Smsmith
37785756Smsmith    case ACPI_TYPE_BUFFER:
37880062Smsmith
37999679Siwasaki        /* Result of two Buffers is a Buffer */
38085756Smsmith
381193267Sjkim        ReturnDesc = AcpiUtCreateBufferObject (
382193267Sjkim                        ((ACPI_SIZE) Operand0->Buffer.Length +
383167802Sjkim                        LocalOperand1->Buffer.Length));
38485756Smsmith        if (!ReturnDesc)
38585756Smsmith        {
386138287Smarks            Status = AE_NO_MEMORY;
387138287Smarks            goto Cleanup;
38867754Smsmith        }
38967754Smsmith
390114237Snjl        NewBuf = (char *) ReturnDesc->Buffer.Pointer;
39167754Smsmith
39299679Siwasaki        /* Concatenate the buffers */
39399679Siwasaki
394167802Sjkim        ACPI_MEMCPY (NewBuf, Operand0->Buffer.Pointer,
395138287Smarks                        Operand0->Buffer.Length);
396138287Smarks        ACPI_MEMCPY (NewBuf + Operand0->Buffer.Length,
397138287Smarks                        LocalOperand1->Buffer.Pointer,
398138287Smarks                        LocalOperand1->Buffer.Length);
39980062Smsmith        break;
40067754Smsmith
40185756Smsmith    default:
40299679Siwasaki
40399679Siwasaki        /* Invalid object type, should not happen here */
40499679Siwasaki
405204773Sjkim        ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
406193267Sjkim            Operand0->Common.Type));
407138287Smarks        Status =AE_AML_INTERNAL;
408138287Smarks        goto Cleanup;
40985756Smsmith    }
41067754Smsmith
41185756Smsmith    *ActualReturnDesc = ReturnDesc;
41267754Smsmith
41385756SmsmithCleanup:
414138287Smarks    if (LocalOperand1 != Operand1)
415138287Smarks    {
416138287Smarks        AcpiUtRemoveReference (LocalOperand1);
417138287Smarks    }
418151937Sjkim    return_ACPI_STATUS (Status);
41967754Smsmith}
42067754Smsmith
42167754Smsmith
42267754Smsmith/*******************************************************************************
42367754Smsmith *
42485756Smsmith * FUNCTION:    AcpiExDoMathOp
42567754Smsmith *
42685756Smsmith * PARAMETERS:  Opcode              - AML opcode
427138287Smarks *              Integer0            - Integer operand #0
428138287Smarks *              Integer1            - Integer operand #1
42967754Smsmith *
43085756Smsmith * RETURN:      Integer result of the operation
43167754Smsmith *
43285756Smsmith * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
43385756Smsmith *              math functions here is to prevent a lot of pointer dereferencing
43485756Smsmith *              to obtain the operands.
43567754Smsmith *
43667754Smsmith ******************************************************************************/
43767754Smsmith
438202771SjkimUINT64
43985756SmsmithAcpiExDoMathOp (
44085756Smsmith    UINT16                  Opcode,
441202771Sjkim    UINT64                  Integer0,
442202771Sjkim    UINT64                  Integer1)
44367754Smsmith{
44467754Smsmith
445138287Smarks    ACPI_FUNCTION_ENTRY ();
44667754Smsmith
447138287Smarks
44885756Smsmith    switch (Opcode)
44967754Smsmith    {
450138287Smarks    case AML_ADD_OP:                /* Add (Integer0, Integer1, Result) */
45167754Smsmith
452138287Smarks        return (Integer0 + Integer1);
45367754Smsmith
45467754Smsmith
455138287Smarks    case AML_BIT_AND_OP:            /* And (Integer0, Integer1, Result) */
45667754Smsmith
457138287Smarks        return (Integer0 & Integer1);
45867754Smsmith
45980062Smsmith
460138287Smarks    case AML_BIT_NAND_OP:           /* NAnd (Integer0, Integer1, Result) */
46167754Smsmith
462138287Smarks        return (~(Integer0 & Integer1));
46367754Smsmith
46467754Smsmith
465138287Smarks    case AML_BIT_OR_OP:             /* Or (Integer0, Integer1, Result) */
46667754Smsmith
467138287Smarks        return (Integer0 | Integer1);
46867754Smsmith
46967754Smsmith
470138287Smarks    case AML_BIT_NOR_OP:            /* NOr (Integer0, Integer1, Result) */
47167754Smsmith
472138287Smarks        return (~(Integer0 | Integer1));
47367754Smsmith
47467754Smsmith
475138287Smarks    case AML_BIT_XOR_OP:            /* XOr (Integer0, Integer1, Result) */
47667754Smsmith
477138287Smarks        return (Integer0 ^ Integer1);
47867754Smsmith
47967754Smsmith
480138287Smarks    case AML_MULTIPLY_OP:           /* Multiply (Integer0, Integer1, Result) */
48167754Smsmith
482138287Smarks        return (Integer0 * Integer1);
48367754Smsmith
48467754Smsmith
485151937Sjkim    case AML_SHIFT_LEFT_OP:         /* ShiftLeft (Operand, ShiftCount, Result)*/
48667754Smsmith
487167802Sjkim        /*
488167802Sjkim         * We need to check if the shiftcount is larger than the integer bit
489167802Sjkim         * width since the behavior of this is not well-defined in the C language.
490167802Sjkim         */
491167802Sjkim        if (Integer1 >= AcpiGbl_IntegerBitWidth)
492167802Sjkim        {
493167802Sjkim            return (0);
494167802Sjkim        }
495138287Smarks        return (Integer0 << Integer1);
49667754Smsmith
49780062Smsmith
49885756Smsmith    case AML_SHIFT_RIGHT_OP:        /* ShiftRight (Operand, ShiftCount, Result) */
49980062Smsmith
500167802Sjkim        /*
501167802Sjkim         * We need to check if the shiftcount is larger than the integer bit
502167802Sjkim         * width since the behavior of this is not well-defined in the C language.
503167802Sjkim         */
504167802Sjkim        if (Integer1 >= AcpiGbl_IntegerBitWidth)
505167802Sjkim        {
506167802Sjkim            return (0);
507167802Sjkim        }
508138287Smarks        return (Integer0 >> Integer1);
50980062Smsmith
51080062Smsmith
511138287Smarks    case AML_SUBTRACT_OP:           /* Subtract (Integer0, Integer1, Result) */
51267754Smsmith
513138287Smarks        return (Integer0 - Integer1);
51467754Smsmith
51585756Smsmith    default:
51667754Smsmith
51785756Smsmith        return (0);
51885756Smsmith    }
51985756Smsmith}
52067754Smsmith
52167754Smsmith
52285756Smsmith/*******************************************************************************
52385756Smsmith *
524138287Smarks * FUNCTION:    AcpiExDoLogicalNumericOp
525138287Smarks *
526138287Smarks * PARAMETERS:  Opcode              - AML opcode
527138287Smarks *              Integer0            - Integer operand #0
528138287Smarks *              Integer1            - Integer operand #1
529138287Smarks *              LogicalResult       - TRUE/FALSE result of the operation
530138287Smarks *
531138287Smarks * RETURN:      Status
532138287Smarks *
533138287Smarks * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
534138287Smarks *              operators (LAnd and LOr), both operands must be integers.
535138287Smarks *
536138287Smarks *              Note: cleanest machine code seems to be produced by the code
537138287Smarks *              below, rather than using statements of the form:
538138287Smarks *                  Result = (Integer0 && Integer1);
539138287Smarks *
540138287Smarks ******************************************************************************/
541138287Smarks
542138287SmarksACPI_STATUS
543138287SmarksAcpiExDoLogicalNumericOp (
544138287Smarks    UINT16                  Opcode,
545202771Sjkim    UINT64                  Integer0,
546202771Sjkim    UINT64                  Integer1,
547138287Smarks    BOOLEAN                 *LogicalResult)
548138287Smarks{
549138287Smarks    ACPI_STATUS             Status = AE_OK;
550138287Smarks    BOOLEAN                 LocalResult = FALSE;
551138287Smarks
552138287Smarks
553167802Sjkim    ACPI_FUNCTION_TRACE (ExDoLogicalNumericOp);
554138287Smarks
555138287Smarks
556138287Smarks    switch (Opcode)
557138287Smarks    {
558138287Smarks    case AML_LAND_OP:               /* LAnd (Integer0, Integer1) */
559138287Smarks
560138287Smarks        if (Integer0 && Integer1)
561138287Smarks        {
562138287Smarks            LocalResult = TRUE;
563138287Smarks        }
564138287Smarks        break;
565138287Smarks
566138287Smarks    case AML_LOR_OP:                /* LOr (Integer0, Integer1) */
567138287Smarks
568138287Smarks        if (Integer0 || Integer1)
569138287Smarks        {
570138287Smarks            LocalResult = TRUE;
571138287Smarks        }
572138287Smarks        break;
573138287Smarks
574138287Smarks    default:
575138287Smarks        Status = AE_AML_INTERNAL;
576138287Smarks        break;
577138287Smarks    }
578138287Smarks
579138287Smarks    /* Return the logical result and status */
580138287Smarks
581138287Smarks    *LogicalResult = LocalResult;
582138287Smarks    return_ACPI_STATUS (Status);
583138287Smarks}
584138287Smarks
585138287Smarks
586138287Smarks/*******************************************************************************
587138287Smarks *
58885756Smsmith * FUNCTION:    AcpiExDoLogicalOp
58985756Smsmith *
59085756Smsmith * PARAMETERS:  Opcode              - AML opcode
591138287Smarks *              Operand0            - operand #0
592138287Smarks *              Operand1            - operand #1
593138287Smarks *              LogicalResult       - TRUE/FALSE result of the operation
59485756Smsmith *
595138287Smarks * RETURN:      Status
59685756Smsmith *
59785756Smsmith * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
59885756Smsmith *              functions here is to prevent a lot of pointer dereferencing
59985756Smsmith *              to obtain the operands and to simplify the generation of the
600138287Smarks *              logical value. For the Numeric operators (LAnd and LOr), both
601138287Smarks *              operands must be integers. For the other logical operators,
602138287Smarks *              operands can be any combination of Integer/String/Buffer. The
603138287Smarks *              first operand determines the type to which the second operand
604138287Smarks *              will be converted.
60585756Smsmith *
60685756Smsmith *              Note: cleanest machine code seems to be produced by the code
60785756Smsmith *              below, rather than using statements of the form:
60885756Smsmith *                  Result = (Operand0 == Operand1);
60985756Smsmith *
61085756Smsmith ******************************************************************************/
61167754Smsmith
612138287SmarksACPI_STATUS
61385756SmsmithAcpiExDoLogicalOp (
61485756Smsmith    UINT16                  Opcode,
615138287Smarks    ACPI_OPERAND_OBJECT     *Operand0,
616138287Smarks    ACPI_OPERAND_OBJECT     *Operand1,
617138287Smarks    BOOLEAN                 *LogicalResult)
61885756Smsmith{
619138287Smarks    ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
620202771Sjkim    UINT64                  Integer0;
621202771Sjkim    UINT64                  Integer1;
622138287Smarks    UINT32                  Length0;
623138287Smarks    UINT32                  Length1;
624138287Smarks    ACPI_STATUS             Status = AE_OK;
625138287Smarks    BOOLEAN                 LocalResult = FALSE;
626138287Smarks    int                     Compare;
62767754Smsmith
62867754Smsmith
629167802Sjkim    ACPI_FUNCTION_TRACE (ExDoLogicalOp);
630138287Smarks
631138287Smarks
632138287Smarks    /*
633138287Smarks     * Convert the second operand if necessary.  The first operand
634138287Smarks     * determines the type of the second operand, (See the Data Types
635138287Smarks     * section of the ACPI 3.0+ specification.)  Both object types are
636138287Smarks     * guaranteed to be either Integer/String/Buffer by the operand
637138287Smarks     * resolution mechanism.
638138287Smarks     */
639193267Sjkim    switch (Operand0->Common.Type)
64085756Smsmith    {
641138287Smarks    case ACPI_TYPE_INTEGER:
642138287Smarks        Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16);
643138287Smarks        break;
64467754Smsmith
645138287Smarks    case ACPI_TYPE_STRING:
646138287Smarks        Status = AcpiExConvertToString (Operand1, &LocalOperand1,
647138287Smarks                    ACPI_IMPLICIT_CONVERT_HEX);
648138287Smarks        break;
64967754Smsmith
650138287Smarks    case ACPI_TYPE_BUFFER:
651138287Smarks        Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
65285756Smsmith        break;
65367754Smsmith
654138287Smarks    default:
655138287Smarks        Status = AE_AML_INTERNAL;
656138287Smarks        break;
657138287Smarks    }
65867754Smsmith
659138287Smarks    if (ACPI_FAILURE (Status))
660138287Smarks    {
661138287Smarks        goto Cleanup;
662138287Smarks    }
66367754Smsmith
664138287Smarks    /*
665138287Smarks     * Two cases: 1) Both Integers, 2) Both Strings or Buffers
666138287Smarks     */
667193267Sjkim    if (Operand0->Common.Type == ACPI_TYPE_INTEGER)
668138287Smarks    {
669138287Smarks        /*
670138287Smarks         * 1) Both operands are of type integer
671138287Smarks         *    Note: LocalOperand1 may have changed above
672138287Smarks         */
673138287Smarks        Integer0 = Operand0->Integer.Value;
674138287Smarks        Integer1 = LocalOperand1->Integer.Value;
675138287Smarks
676138287Smarks        switch (Opcode)
67785756Smsmith        {
678138287Smarks        case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
67967754Smsmith
680138287Smarks            if (Integer0 == Integer1)
681138287Smarks            {
682138287Smarks                LocalResult = TRUE;
683138287Smarks            }
684138287Smarks            break;
68567754Smsmith
686138287Smarks        case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
68767754Smsmith
688138287Smarks            if (Integer0 > Integer1)
689138287Smarks            {
690138287Smarks                LocalResult = TRUE;
691138287Smarks            }
692138287Smarks            break;
693138287Smarks
694138287Smarks        case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
695138287Smarks
696138287Smarks            if (Integer0 < Integer1)
697138287Smarks            {
698138287Smarks                LocalResult = TRUE;
699138287Smarks            }
700138287Smarks            break;
701138287Smarks
702138287Smarks        default:
703138287Smarks            Status = AE_AML_INTERNAL;
704138287Smarks            break;
70585756Smsmith        }
706138287Smarks    }
707138287Smarks    else
708138287Smarks    {
709138287Smarks        /*
710138287Smarks         * 2) Both operands are Strings or both are Buffers
711138287Smarks         *    Note: Code below takes advantage of common Buffer/String
712138287Smarks         *          object fields. LocalOperand1 may have changed above. Use
713138287Smarks         *          memcmp to handle nulls in buffers.
714138287Smarks         */
715138287Smarks        Length0 = Operand0->Buffer.Length;
716138287Smarks        Length1 = LocalOperand1->Buffer.Length;
71767754Smsmith
718138287Smarks        /* Lexicographic compare: compare the data bytes */
71967754Smsmith
720151937Sjkim        Compare = ACPI_MEMCMP (Operand0->Buffer.Pointer,
721151937Sjkim                    LocalOperand1->Buffer.Pointer,
722138287Smarks                    (Length0 > Length1) ? Length1 : Length0);
72367754Smsmith
724138287Smarks        switch (Opcode)
72585756Smsmith        {
726138287Smarks        case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
72767754Smsmith
728138287Smarks            /* Length and all bytes must be equal */
72967754Smsmith
730138287Smarks            if ((Length0 == Length1) &&
731138287Smarks                (Compare == 0))
732138287Smarks            {
733138287Smarks                /* Length and all bytes match ==> TRUE */
73467754Smsmith
735138287Smarks                LocalResult = TRUE;
736138287Smarks            }
737138287Smarks            break;
738138287Smarks
739138287Smarks        case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
740138287Smarks
741138287Smarks            if (Compare > 0)
742138287Smarks            {
743138287Smarks                LocalResult = TRUE;
744138287Smarks                goto Cleanup;   /* TRUE */
745138287Smarks            }
746138287Smarks            if (Compare < 0)
747138287Smarks            {
748138287Smarks                goto Cleanup;   /* FALSE */
749138287Smarks            }
750138287Smarks
751138287Smarks            /* Bytes match (to shortest length), compare lengths */
752138287Smarks
753138287Smarks            if (Length0 > Length1)
754138287Smarks            {
755138287Smarks                LocalResult = TRUE;
756138287Smarks            }
757138287Smarks            break;
758138287Smarks
759138287Smarks        case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
760138287Smarks
761138287Smarks            if (Compare > 0)
762138287Smarks            {
763138287Smarks                goto Cleanup;   /* FALSE */
764138287Smarks            }
765138287Smarks            if (Compare < 0)
766138287Smarks            {
767138287Smarks                LocalResult = TRUE;
768138287Smarks                goto Cleanup;   /* TRUE */
769138287Smarks            }
770138287Smarks
771138287Smarks            /* Bytes match (to shortest length), compare lengths */
772138287Smarks
773138287Smarks            if (Length0 < Length1)
774138287Smarks            {
775138287Smarks                LocalResult = TRUE;
776138287Smarks            }
777138287Smarks            break;
778138287Smarks
779138287Smarks        default:
780138287Smarks            Status = AE_AML_INTERNAL;
781138287Smarks            break;
78267754Smsmith        }
783138287Smarks    }
78499679Siwasaki
785138287SmarksCleanup:
786138287Smarks
787138287Smarks    /* New object was created if implicit conversion performed - delete */
788138287Smarks
789138287Smarks    if (LocalOperand1 != Operand1)
790138287Smarks    {
791138287Smarks        AcpiUtRemoveReference (LocalOperand1);
79267754Smsmith    }
79367754Smsmith
794138287Smarks    /* Return the logical result and status */
795138287Smarks
796138287Smarks    *LogicalResult = LocalResult;
797138287Smarks    return_ACPI_STATUS (Status);
79885756Smsmith}
79967754Smsmith
80067754Smsmith
801