xref: /freebsd/sys/contrib/dev/acpica/components/executer/exmisc.c (revision c6ec7d31830ab1c80edae95ad5e4b9dba10c47ac)
1 /******************************************************************************
2  *
3  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2012, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #define __EXMISC_C__
45 
46 #include <contrib/dev/acpica/include/acpi.h>
47 #include <contrib/dev/acpica/include/accommon.h>
48 #include <contrib/dev/acpica/include/acinterp.h>
49 #include <contrib/dev/acpica/include/amlcode.h>
50 #include <contrib/dev/acpica/include/amlresrc.h>
51 
52 
53 #define _COMPONENT          ACPI_EXECUTER
54         ACPI_MODULE_NAME    ("exmisc")
55 
56 
57 /*******************************************************************************
58  *
59  * FUNCTION:    AcpiExGetObjectReference
60  *
61  * PARAMETERS:  ObjDesc             - Create a reference to this object
62  *              ReturnDesc          - Where to store the reference
63  *              WalkState           - Current state
64  *
65  * RETURN:      Status
66  *
67  * DESCRIPTION: Obtain and return a "reference" to the target object
68  *              Common code for the RefOfOp and the CondRefOfOp.
69  *
70  ******************************************************************************/
71 
72 ACPI_STATUS
73 AcpiExGetObjectReference (
74     ACPI_OPERAND_OBJECT     *ObjDesc,
75     ACPI_OPERAND_OBJECT     **ReturnDesc,
76     ACPI_WALK_STATE         *WalkState)
77 {
78     ACPI_OPERAND_OBJECT     *ReferenceObj;
79     ACPI_OPERAND_OBJECT     *ReferencedObj;
80 
81 
82     ACPI_FUNCTION_TRACE_PTR (ExGetObjectReference, ObjDesc);
83 
84 
85     *ReturnDesc = NULL;
86 
87     switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))
88     {
89     case ACPI_DESC_TYPE_OPERAND:
90 
91         if (ObjDesc->Common.Type != ACPI_TYPE_LOCAL_REFERENCE)
92         {
93             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
94         }
95 
96         /*
97          * Must be a reference to a Local or Arg
98          */
99         switch (ObjDesc->Reference.Class)
100         {
101         case ACPI_REFCLASS_LOCAL:
102         case ACPI_REFCLASS_ARG:
103         case ACPI_REFCLASS_DEBUG:
104 
105             /* The referenced object is the pseudo-node for the local/arg */
106 
107             ReferencedObj = ObjDesc->Reference.Object;
108             break;
109 
110         default:
111 
112             ACPI_ERROR ((AE_INFO, "Unknown Reference Class 0x%2.2X",
113                 ObjDesc->Reference.Class));
114             return_ACPI_STATUS (AE_AML_INTERNAL);
115         }
116         break;
117 
118 
119     case ACPI_DESC_TYPE_NAMED:
120 
121         /*
122          * A named reference that has already been resolved to a Node
123          */
124         ReferencedObj = ObjDesc;
125         break;
126 
127 
128     default:
129 
130         ACPI_ERROR ((AE_INFO, "Invalid descriptor type 0x%X",
131             ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)));
132         return_ACPI_STATUS (AE_TYPE);
133     }
134 
135 
136     /* Create a new reference object */
137 
138     ReferenceObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE);
139     if (!ReferenceObj)
140     {
141         return_ACPI_STATUS (AE_NO_MEMORY);
142     }
143 
144     ReferenceObj->Reference.Class = ACPI_REFCLASS_REFOF;
145     ReferenceObj->Reference.Object = ReferencedObj;
146     *ReturnDesc = ReferenceObj;
147 
148     ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
149         "Object %p Type [%s], returning Reference %p\n",
150         ObjDesc, AcpiUtGetObjectTypeName (ObjDesc), *ReturnDesc));
151 
152     return_ACPI_STATUS (AE_OK);
153 }
154 
155 
156 /*******************************************************************************
157  *
158  * FUNCTION:    AcpiExConcatTemplate
159  *
160  * PARAMETERS:  Operand0            - First source object
161  *              Operand1            - Second source object
162  *              ActualReturnDesc    - Where to place the return object
163  *              WalkState           - Current walk state
164  *
165  * RETURN:      Status
166  *
167  * DESCRIPTION: Concatenate two resource templates
168  *
169  ******************************************************************************/
170 
171 ACPI_STATUS
172 AcpiExConcatTemplate (
173     ACPI_OPERAND_OBJECT     *Operand0,
174     ACPI_OPERAND_OBJECT     *Operand1,
175     ACPI_OPERAND_OBJECT     **ActualReturnDesc,
176     ACPI_WALK_STATE         *WalkState)
177 {
178     ACPI_STATUS             Status;
179     ACPI_OPERAND_OBJECT     *ReturnDesc;
180     UINT8                   *NewBuf;
181     UINT8                   *EndTag;
182     ACPI_SIZE               Length0;
183     ACPI_SIZE               Length1;
184     ACPI_SIZE               NewLength;
185 
186 
187     ACPI_FUNCTION_TRACE (ExConcatTemplate);
188 
189 
190     /*
191      * Find the EndTag descriptor in each resource template.
192      * Note1: returned pointers point TO the EndTag, not past it.
193      * Note2: zero-length buffers are allowed; treated like one EndTag
194      */
195 
196     /* Get the length of the first resource template */
197 
198     Status = AcpiUtGetResourceEndTag (Operand0, &EndTag);
199     if (ACPI_FAILURE (Status))
200     {
201         return_ACPI_STATUS (Status);
202     }
203 
204     Length0 = ACPI_PTR_DIFF (EndTag, Operand0->Buffer.Pointer);
205 
206     /* Get the length of the second resource template */
207 
208     Status = AcpiUtGetResourceEndTag (Operand1, &EndTag);
209     if (ACPI_FAILURE (Status))
210     {
211         return_ACPI_STATUS (Status);
212     }
213 
214     Length1 = ACPI_PTR_DIFF (EndTag, Operand1->Buffer.Pointer);
215 
216     /* Combine both lengths, minimum size will be 2 for EndTag */
217 
218     NewLength = Length0 + Length1 + sizeof (AML_RESOURCE_END_TAG);
219 
220     /* Create a new buffer object for the result (with one EndTag) */
221 
222     ReturnDesc = AcpiUtCreateBufferObject (NewLength);
223     if (!ReturnDesc)
224     {
225         return_ACPI_STATUS (AE_NO_MEMORY);
226     }
227 
228     /*
229      * Copy the templates to the new buffer, 0 first, then 1 follows. One
230      * EndTag descriptor is copied from Operand1.
231      */
232     NewBuf = ReturnDesc->Buffer.Pointer;
233     ACPI_MEMCPY (NewBuf, Operand0->Buffer.Pointer, Length0);
234     ACPI_MEMCPY (NewBuf + Length0, Operand1->Buffer.Pointer, Length1);
235 
236     /* Insert EndTag and set the checksum to zero, means "ignore checksum" */
237 
238     NewBuf[NewLength - 1] = 0;
239     NewBuf[NewLength - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
240 
241     /* Return the completed resource template */
242 
243     *ActualReturnDesc = ReturnDesc;
244     return_ACPI_STATUS (AE_OK);
245 }
246 
247 
248 /*******************************************************************************
249  *
250  * FUNCTION:    AcpiExDoConcatenate
251  *
252  * PARAMETERS:  Operand0            - First source object
253  *              Operand1            - Second source object
254  *              ActualReturnDesc    - Where to place the return object
255  *              WalkState           - Current walk state
256  *
257  * RETURN:      Status
258  *
259  * DESCRIPTION: Concatenate two objects OF THE SAME TYPE.
260  *
261  ******************************************************************************/
262 
263 ACPI_STATUS
264 AcpiExDoConcatenate (
265     ACPI_OPERAND_OBJECT     *Operand0,
266     ACPI_OPERAND_OBJECT     *Operand1,
267     ACPI_OPERAND_OBJECT     **ActualReturnDesc,
268     ACPI_WALK_STATE         *WalkState)
269 {
270     ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
271     ACPI_OPERAND_OBJECT     *ReturnDesc;
272     char                    *NewBuf;
273     ACPI_STATUS             Status;
274 
275 
276     ACPI_FUNCTION_TRACE (ExDoConcatenate);
277 
278 
279     /*
280      * Convert the second operand if necessary. The first operand
281      * determines the type of the second operand, (See the Data Types
282      * section of the ACPI specification.)  Both object types are
283      * guaranteed to be either Integer/String/Buffer by the operand
284      * resolution mechanism.
285      */
286     switch (Operand0->Common.Type)
287     {
288     case ACPI_TYPE_INTEGER:
289         Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16);
290         break;
291 
292     case ACPI_TYPE_STRING:
293         Status = AcpiExConvertToString (Operand1, &LocalOperand1,
294                     ACPI_IMPLICIT_CONVERT_HEX);
295         break;
296 
297     case ACPI_TYPE_BUFFER:
298         Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
299         break;
300 
301     default:
302         ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
303             Operand0->Common.Type));
304         Status = AE_AML_INTERNAL;
305     }
306 
307     if (ACPI_FAILURE (Status))
308     {
309         goto Cleanup;
310     }
311 
312     /*
313      * Both operands are now known to be the same object type
314      * (Both are Integer, String, or Buffer), and we can now perform the
315      * concatenation.
316      */
317 
318     /*
319      * There are three cases to handle:
320      *
321      * 1) Two Integers concatenated to produce a new Buffer
322      * 2) Two Strings concatenated to produce a new String
323      * 3) Two Buffers concatenated to produce a new Buffer
324      */
325     switch (Operand0->Common.Type)
326     {
327     case ACPI_TYPE_INTEGER:
328 
329         /* Result of two Integers is a Buffer */
330         /* Need enough buffer space for two integers */
331 
332         ReturnDesc = AcpiUtCreateBufferObject ((ACPI_SIZE)
333                             ACPI_MUL_2 (AcpiGbl_IntegerByteWidth));
334         if (!ReturnDesc)
335         {
336             Status = AE_NO_MEMORY;
337             goto Cleanup;
338         }
339 
340         NewBuf = (char *) ReturnDesc->Buffer.Pointer;
341 
342         /* Copy the first integer, LSB first */
343 
344         ACPI_MEMCPY (NewBuf, &Operand0->Integer.Value,
345                         AcpiGbl_IntegerByteWidth);
346 
347         /* Copy the second integer (LSB first) after the first */
348 
349         ACPI_MEMCPY (NewBuf + AcpiGbl_IntegerByteWidth,
350                         &LocalOperand1->Integer.Value,
351                         AcpiGbl_IntegerByteWidth);
352         break;
353 
354     case ACPI_TYPE_STRING:
355 
356         /* Result of two Strings is a String */
357 
358         ReturnDesc = AcpiUtCreateStringObject (
359                         ((ACPI_SIZE) Operand0->String.Length +
360                         LocalOperand1->String.Length));
361         if (!ReturnDesc)
362         {
363             Status = AE_NO_MEMORY;
364             goto Cleanup;
365         }
366 
367         NewBuf = ReturnDesc->String.Pointer;
368 
369         /* Concatenate the strings */
370 
371         ACPI_STRCPY (NewBuf, Operand0->String.Pointer);
372         ACPI_STRCPY (NewBuf + Operand0->String.Length,
373                         LocalOperand1->String.Pointer);
374         break;
375 
376     case ACPI_TYPE_BUFFER:
377 
378         /* Result of two Buffers is a Buffer */
379 
380         ReturnDesc = AcpiUtCreateBufferObject (
381                         ((ACPI_SIZE) Operand0->Buffer.Length +
382                         LocalOperand1->Buffer.Length));
383         if (!ReturnDesc)
384         {
385             Status = AE_NO_MEMORY;
386             goto Cleanup;
387         }
388 
389         NewBuf = (char *) ReturnDesc->Buffer.Pointer;
390 
391         /* Concatenate the buffers */
392 
393         ACPI_MEMCPY (NewBuf, Operand0->Buffer.Pointer,
394                         Operand0->Buffer.Length);
395         ACPI_MEMCPY (NewBuf + Operand0->Buffer.Length,
396                         LocalOperand1->Buffer.Pointer,
397                         LocalOperand1->Buffer.Length);
398         break;
399 
400     default:
401 
402         /* Invalid object type, should not happen here */
403 
404         ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
405             Operand0->Common.Type));
406         Status =AE_AML_INTERNAL;
407         goto Cleanup;
408     }
409 
410     *ActualReturnDesc = ReturnDesc;
411 
412 Cleanup:
413     if (LocalOperand1 != Operand1)
414     {
415         AcpiUtRemoveReference (LocalOperand1);
416     }
417     return_ACPI_STATUS (Status);
418 }
419 
420 
421 /*******************************************************************************
422  *
423  * FUNCTION:    AcpiExDoMathOp
424  *
425  * PARAMETERS:  Opcode              - AML opcode
426  *              Integer0            - Integer operand #0
427  *              Integer1            - Integer operand #1
428  *
429  * RETURN:      Integer result of the operation
430  *
431  * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
432  *              math functions here is to prevent a lot of pointer dereferencing
433  *              to obtain the operands.
434  *
435  ******************************************************************************/
436 
437 UINT64
438 AcpiExDoMathOp (
439     UINT16                  Opcode,
440     UINT64                  Integer0,
441     UINT64                  Integer1)
442 {
443 
444     ACPI_FUNCTION_ENTRY ();
445 
446 
447     switch (Opcode)
448     {
449     case AML_ADD_OP:                /* Add (Integer0, Integer1, Result) */
450 
451         return (Integer0 + Integer1);
452 
453 
454     case AML_BIT_AND_OP:            /* And (Integer0, Integer1, Result) */
455 
456         return (Integer0 & Integer1);
457 
458 
459     case AML_BIT_NAND_OP:           /* NAnd (Integer0, Integer1, Result) */
460 
461         return (~(Integer0 & Integer1));
462 
463 
464     case AML_BIT_OR_OP:             /* Or (Integer0, Integer1, Result) */
465 
466         return (Integer0 | Integer1);
467 
468 
469     case AML_BIT_NOR_OP:            /* NOr (Integer0, Integer1, Result) */
470 
471         return (~(Integer0 | Integer1));
472 
473 
474     case AML_BIT_XOR_OP:            /* XOr (Integer0, Integer1, Result) */
475 
476         return (Integer0 ^ Integer1);
477 
478 
479     case AML_MULTIPLY_OP:           /* Multiply (Integer0, Integer1, Result) */
480 
481         return (Integer0 * Integer1);
482 
483 
484     case AML_SHIFT_LEFT_OP:         /* ShiftLeft (Operand, ShiftCount, Result)*/
485 
486         /*
487          * We need to check if the shiftcount is larger than the integer bit
488          * width since the behavior of this is not well-defined in the C language.
489          */
490         if (Integer1 >= AcpiGbl_IntegerBitWidth)
491         {
492             return (0);
493         }
494         return (Integer0 << Integer1);
495 
496 
497     case AML_SHIFT_RIGHT_OP:        /* ShiftRight (Operand, ShiftCount, Result) */
498 
499         /*
500          * We need to check if the shiftcount is larger than the integer bit
501          * width since the behavior of this is not well-defined in the C language.
502          */
503         if (Integer1 >= AcpiGbl_IntegerBitWidth)
504         {
505             return (0);
506         }
507         return (Integer0 >> Integer1);
508 
509 
510     case AML_SUBTRACT_OP:           /* Subtract (Integer0, Integer1, Result) */
511 
512         return (Integer0 - Integer1);
513 
514     default:
515 
516         return (0);
517     }
518 }
519 
520 
521 /*******************************************************************************
522  *
523  * FUNCTION:    AcpiExDoLogicalNumericOp
524  *
525  * PARAMETERS:  Opcode              - AML opcode
526  *              Integer0            - Integer operand #0
527  *              Integer1            - Integer operand #1
528  *              LogicalResult       - TRUE/FALSE result of the operation
529  *
530  * RETURN:      Status
531  *
532  * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
533  *              operators (LAnd and LOr), both operands must be integers.
534  *
535  *              Note: cleanest machine code seems to be produced by the code
536  *              below, rather than using statements of the form:
537  *                  Result = (Integer0 && Integer1);
538  *
539  ******************************************************************************/
540 
541 ACPI_STATUS
542 AcpiExDoLogicalNumericOp (
543     UINT16                  Opcode,
544     UINT64                  Integer0,
545     UINT64                  Integer1,
546     BOOLEAN                 *LogicalResult)
547 {
548     ACPI_STATUS             Status = AE_OK;
549     BOOLEAN                 LocalResult = FALSE;
550 
551 
552     ACPI_FUNCTION_TRACE (ExDoLogicalNumericOp);
553 
554 
555     switch (Opcode)
556     {
557     case AML_LAND_OP:               /* LAnd (Integer0, Integer1) */
558 
559         if (Integer0 && Integer1)
560         {
561             LocalResult = TRUE;
562         }
563         break;
564 
565     case AML_LOR_OP:                /* LOr (Integer0, Integer1) */
566 
567         if (Integer0 || Integer1)
568         {
569             LocalResult = TRUE;
570         }
571         break;
572 
573     default:
574         Status = AE_AML_INTERNAL;
575         break;
576     }
577 
578     /* Return the logical result and status */
579 
580     *LogicalResult = LocalResult;
581     return_ACPI_STATUS (Status);
582 }
583 
584 
585 /*******************************************************************************
586  *
587  * FUNCTION:    AcpiExDoLogicalOp
588  *
589  * PARAMETERS:  Opcode              - AML opcode
590  *              Operand0            - operand #0
591  *              Operand1            - operand #1
592  *              LogicalResult       - TRUE/FALSE result of the operation
593  *
594  * RETURN:      Status
595  *
596  * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
597  *              functions here is to prevent a lot of pointer dereferencing
598  *              to obtain the operands and to simplify the generation of the
599  *              logical value. For the Numeric operators (LAnd and LOr), both
600  *              operands must be integers. For the other logical operators,
601  *              operands can be any combination of Integer/String/Buffer. The
602  *              first operand determines the type to which the second operand
603  *              will be converted.
604  *
605  *              Note: cleanest machine code seems to be produced by the code
606  *              below, rather than using statements of the form:
607  *                  Result = (Operand0 == Operand1);
608  *
609  ******************************************************************************/
610 
611 ACPI_STATUS
612 AcpiExDoLogicalOp (
613     UINT16                  Opcode,
614     ACPI_OPERAND_OBJECT     *Operand0,
615     ACPI_OPERAND_OBJECT     *Operand1,
616     BOOLEAN                 *LogicalResult)
617 {
618     ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
619     UINT64                  Integer0;
620     UINT64                  Integer1;
621     UINT32                  Length0;
622     UINT32                  Length1;
623     ACPI_STATUS             Status = AE_OK;
624     BOOLEAN                 LocalResult = FALSE;
625     int                     Compare;
626 
627 
628     ACPI_FUNCTION_TRACE (ExDoLogicalOp);
629 
630 
631     /*
632      * Convert the second operand if necessary. The first operand
633      * determines the type of the second operand, (See the Data Types
634      * section of the ACPI 3.0+ specification.)  Both object types are
635      * guaranteed to be either Integer/String/Buffer by the operand
636      * resolution mechanism.
637      */
638     switch (Operand0->Common.Type)
639     {
640     case ACPI_TYPE_INTEGER:
641         Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16);
642         break;
643 
644     case ACPI_TYPE_STRING:
645         Status = AcpiExConvertToString (Operand1, &LocalOperand1,
646                     ACPI_IMPLICIT_CONVERT_HEX);
647         break;
648 
649     case ACPI_TYPE_BUFFER:
650         Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
651         break;
652 
653     default:
654         Status = AE_AML_INTERNAL;
655         break;
656     }
657 
658     if (ACPI_FAILURE (Status))
659     {
660         goto Cleanup;
661     }
662 
663     /*
664      * Two cases: 1) Both Integers, 2) Both Strings or Buffers
665      */
666     if (Operand0->Common.Type == ACPI_TYPE_INTEGER)
667     {
668         /*
669          * 1) Both operands are of type integer
670          *    Note: LocalOperand1 may have changed above
671          */
672         Integer0 = Operand0->Integer.Value;
673         Integer1 = LocalOperand1->Integer.Value;
674 
675         switch (Opcode)
676         {
677         case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
678 
679             if (Integer0 == Integer1)
680             {
681                 LocalResult = TRUE;
682             }
683             break;
684 
685         case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
686 
687             if (Integer0 > Integer1)
688             {
689                 LocalResult = TRUE;
690             }
691             break;
692 
693         case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
694 
695             if (Integer0 < Integer1)
696             {
697                 LocalResult = TRUE;
698             }
699             break;
700 
701         default:
702             Status = AE_AML_INTERNAL;
703             break;
704         }
705     }
706     else
707     {
708         /*
709          * 2) Both operands are Strings or both are Buffers
710          *    Note: Code below takes advantage of common Buffer/String
711          *          object fields. LocalOperand1 may have changed above. Use
712          *          memcmp to handle nulls in buffers.
713          */
714         Length0 = Operand0->Buffer.Length;
715         Length1 = LocalOperand1->Buffer.Length;
716 
717         /* Lexicographic compare: compare the data bytes */
718 
719         Compare = ACPI_MEMCMP (Operand0->Buffer.Pointer,
720                     LocalOperand1->Buffer.Pointer,
721                     (Length0 > Length1) ? Length1 : Length0);
722 
723         switch (Opcode)
724         {
725         case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
726 
727             /* Length and all bytes must be equal */
728 
729             if ((Length0 == Length1) &&
730                 (Compare == 0))
731             {
732                 /* Length and all bytes match ==> TRUE */
733 
734                 LocalResult = TRUE;
735             }
736             break;
737 
738         case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
739 
740             if (Compare > 0)
741             {
742                 LocalResult = TRUE;
743                 goto Cleanup;   /* TRUE */
744             }
745             if (Compare < 0)
746             {
747                 goto Cleanup;   /* FALSE */
748             }
749 
750             /* Bytes match (to shortest length), compare lengths */
751 
752             if (Length0 > Length1)
753             {
754                 LocalResult = TRUE;
755             }
756             break;
757 
758         case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
759 
760             if (Compare > 0)
761             {
762                 goto Cleanup;   /* FALSE */
763             }
764             if (Compare < 0)
765             {
766                 LocalResult = TRUE;
767                 goto Cleanup;   /* TRUE */
768             }
769 
770             /* Bytes match (to shortest length), compare lengths */
771 
772             if (Length0 < Length1)
773             {
774                 LocalResult = TRUE;
775             }
776             break;
777 
778         default:
779             Status = AE_AML_INTERNAL;
780             break;
781         }
782     }
783 
784 Cleanup:
785 
786     /* New object was created if implicit conversion performed - delete */
787 
788     if (LocalOperand1 != Operand1)
789     {
790         AcpiUtRemoveReference (LocalOperand1);
791     }
792 
793     /* Return the logical result and status */
794 
795     *LogicalResult = LocalResult;
796     return_ACPI_STATUS (Status);
797 }
798