xref: /freebsd/sys/contrib/dev/acpica/components/executer/exmisc.c (revision 3b8f08459569bf0faa21473e5cec2491e95c9349)
1 /******************************************************************************
2  *
3  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2013, 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     case ACPI_DESC_TYPE_NAMED:
119         /*
120          * A named reference that has already been resolved to a Node
121          */
122         ReferencedObj = ObjDesc;
123         break;
124 
125     default:
126 
127         ACPI_ERROR ((AE_INFO, "Invalid descriptor type 0x%X",
128             ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)));
129         return_ACPI_STATUS (AE_TYPE);
130     }
131 
132 
133     /* Create a new reference object */
134 
135     ReferenceObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE);
136     if (!ReferenceObj)
137     {
138         return_ACPI_STATUS (AE_NO_MEMORY);
139     }
140 
141     ReferenceObj->Reference.Class = ACPI_REFCLASS_REFOF;
142     ReferenceObj->Reference.Object = ReferencedObj;
143     *ReturnDesc = ReferenceObj;
144 
145     ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
146         "Object %p Type [%s], returning Reference %p\n",
147         ObjDesc, AcpiUtGetObjectTypeName (ObjDesc), *ReturnDesc));
148 
149     return_ACPI_STATUS (AE_OK);
150 }
151 
152 
153 /*******************************************************************************
154  *
155  * FUNCTION:    AcpiExConcatTemplate
156  *
157  * PARAMETERS:  Operand0            - First source object
158  *              Operand1            - Second source object
159  *              ActualReturnDesc    - Where to place the return object
160  *              WalkState           - Current walk state
161  *
162  * RETURN:      Status
163  *
164  * DESCRIPTION: Concatenate two resource templates
165  *
166  ******************************************************************************/
167 
168 ACPI_STATUS
169 AcpiExConcatTemplate (
170     ACPI_OPERAND_OBJECT     *Operand0,
171     ACPI_OPERAND_OBJECT     *Operand1,
172     ACPI_OPERAND_OBJECT     **ActualReturnDesc,
173     ACPI_WALK_STATE         *WalkState)
174 {
175     ACPI_STATUS             Status;
176     ACPI_OPERAND_OBJECT     *ReturnDesc;
177     UINT8                   *NewBuf;
178     UINT8                   *EndTag;
179     ACPI_SIZE               Length0;
180     ACPI_SIZE               Length1;
181     ACPI_SIZE               NewLength;
182 
183 
184     ACPI_FUNCTION_TRACE (ExConcatTemplate);
185 
186 
187     /*
188      * Find the EndTag descriptor in each resource template.
189      * Note1: returned pointers point TO the EndTag, not past it.
190      * Note2: zero-length buffers are allowed; treated like one EndTag
191      */
192 
193     /* Get the length of the first resource template */
194 
195     Status = AcpiUtGetResourceEndTag (Operand0, &EndTag);
196     if (ACPI_FAILURE (Status))
197     {
198         return_ACPI_STATUS (Status);
199     }
200 
201     Length0 = ACPI_PTR_DIFF (EndTag, Operand0->Buffer.Pointer);
202 
203     /* Get the length of the second resource template */
204 
205     Status = AcpiUtGetResourceEndTag (Operand1, &EndTag);
206     if (ACPI_FAILURE (Status))
207     {
208         return_ACPI_STATUS (Status);
209     }
210 
211     Length1 = ACPI_PTR_DIFF (EndTag, Operand1->Buffer.Pointer);
212 
213     /* Combine both lengths, minimum size will be 2 for EndTag */
214 
215     NewLength = Length0 + Length1 + sizeof (AML_RESOURCE_END_TAG);
216 
217     /* Create a new buffer object for the result (with one EndTag) */
218 
219     ReturnDesc = AcpiUtCreateBufferObject (NewLength);
220     if (!ReturnDesc)
221     {
222         return_ACPI_STATUS (AE_NO_MEMORY);
223     }
224 
225     /*
226      * Copy the templates to the new buffer, 0 first, then 1 follows. One
227      * EndTag descriptor is copied from Operand1.
228      */
229     NewBuf = ReturnDesc->Buffer.Pointer;
230     ACPI_MEMCPY (NewBuf, Operand0->Buffer.Pointer, Length0);
231     ACPI_MEMCPY (NewBuf + Length0, Operand1->Buffer.Pointer, Length1);
232 
233     /* Insert EndTag and set the checksum to zero, means "ignore checksum" */
234 
235     NewBuf[NewLength - 1] = 0;
236     NewBuf[NewLength - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
237 
238     /* Return the completed resource template */
239 
240     *ActualReturnDesc = ReturnDesc;
241     return_ACPI_STATUS (AE_OK);
242 }
243 
244 
245 /*******************************************************************************
246  *
247  * FUNCTION:    AcpiExDoConcatenate
248  *
249  * PARAMETERS:  Operand0            - First source object
250  *              Operand1            - Second source object
251  *              ActualReturnDesc    - Where to place the return object
252  *              WalkState           - Current walk state
253  *
254  * RETURN:      Status
255  *
256  * DESCRIPTION: Concatenate two objects OF THE SAME TYPE.
257  *
258  ******************************************************************************/
259 
260 ACPI_STATUS
261 AcpiExDoConcatenate (
262     ACPI_OPERAND_OBJECT     *Operand0,
263     ACPI_OPERAND_OBJECT     *Operand1,
264     ACPI_OPERAND_OBJECT     **ActualReturnDesc,
265     ACPI_WALK_STATE         *WalkState)
266 {
267     ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
268     ACPI_OPERAND_OBJECT     *ReturnDesc;
269     char                    *NewBuf;
270     ACPI_STATUS             Status;
271 
272 
273     ACPI_FUNCTION_TRACE (ExDoConcatenate);
274 
275 
276     /*
277      * Convert the second operand if necessary. The first operand
278      * determines the type of the second operand, (See the Data Types
279      * section of the ACPI specification.)  Both object types are
280      * guaranteed to be either Integer/String/Buffer by the operand
281      * resolution mechanism.
282      */
283     switch (Operand0->Common.Type)
284     {
285     case ACPI_TYPE_INTEGER:
286 
287         Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16);
288         break;
289 
290     case ACPI_TYPE_STRING:
291 
292         Status = AcpiExConvertToString (Operand1, &LocalOperand1,
293                     ACPI_IMPLICIT_CONVERT_HEX);
294         break;
295 
296     case ACPI_TYPE_BUFFER:
297 
298         Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
299         break;
300 
301     default:
302 
303         ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
304             Operand0->Common.Type));
305         Status = AE_AML_INTERNAL;
306     }
307 
308     if (ACPI_FAILURE (Status))
309     {
310         goto Cleanup;
311     }
312 
313     /*
314      * Both operands are now known to be the same object type
315      * (Both are Integer, String, or Buffer), and we can now perform the
316      * concatenation.
317      */
318 
319     /*
320      * There are three cases to handle:
321      *
322      * 1) Two Integers concatenated to produce a new Buffer
323      * 2) Two Strings concatenated to produce a new String
324      * 3) Two Buffers concatenated to produce a new Buffer
325      */
326     switch (Operand0->Common.Type)
327     {
328     case ACPI_TYPE_INTEGER:
329 
330         /* Result of two Integers is a Buffer */
331         /* Need enough buffer space for two integers */
332 
333         ReturnDesc = AcpiUtCreateBufferObject ((ACPI_SIZE)
334                             ACPI_MUL_2 (AcpiGbl_IntegerByteWidth));
335         if (!ReturnDesc)
336         {
337             Status = AE_NO_MEMORY;
338             goto Cleanup;
339         }
340 
341         NewBuf = (char *) ReturnDesc->Buffer.Pointer;
342 
343         /* Copy the first integer, LSB first */
344 
345         ACPI_MEMCPY (NewBuf, &Operand0->Integer.Value,
346                         AcpiGbl_IntegerByteWidth);
347 
348         /* Copy the second integer (LSB first) after the first */
349 
350         ACPI_MEMCPY (NewBuf + AcpiGbl_IntegerByteWidth,
351                         &LocalOperand1->Integer.Value,
352                         AcpiGbl_IntegerByteWidth);
353         break;
354 
355     case ACPI_TYPE_STRING:
356 
357         /* Result of two Strings is a String */
358 
359         ReturnDesc = AcpiUtCreateStringObject (
360                         ((ACPI_SIZE) Operand0->String.Length +
361                         LocalOperand1->String.Length));
362         if (!ReturnDesc)
363         {
364             Status = AE_NO_MEMORY;
365             goto Cleanup;
366         }
367 
368         NewBuf = ReturnDesc->String.Pointer;
369 
370         /* Concatenate the strings */
371 
372         ACPI_STRCPY (NewBuf, Operand0->String.Pointer);
373         ACPI_STRCPY (NewBuf + Operand0->String.Length,
374                         LocalOperand1->String.Pointer);
375         break;
376 
377     case ACPI_TYPE_BUFFER:
378 
379         /* Result of two Buffers is a Buffer */
380 
381         ReturnDesc = AcpiUtCreateBufferObject (
382                         ((ACPI_SIZE) Operand0->Buffer.Length +
383                         LocalOperand1->Buffer.Length));
384         if (!ReturnDesc)
385         {
386             Status = AE_NO_MEMORY;
387             goto Cleanup;
388         }
389 
390         NewBuf = (char *) ReturnDesc->Buffer.Pointer;
391 
392         /* Concatenate the buffers */
393 
394         ACPI_MEMCPY (NewBuf, Operand0->Buffer.Pointer,
395                         Operand0->Buffer.Length);
396         ACPI_MEMCPY (NewBuf + Operand0->Buffer.Length,
397                         LocalOperand1->Buffer.Pointer,
398                         LocalOperand1->Buffer.Length);
399         break;
400 
401     default:
402 
403         /* Invalid object type, should not happen here */
404 
405         ACPI_ERROR ((AE_INFO, "Invalid object type: 0x%X",
406             Operand0->Common.Type));
407         Status =AE_AML_INTERNAL;
408         goto Cleanup;
409     }
410 
411     *ActualReturnDesc = ReturnDesc;
412 
413 Cleanup:
414     if (LocalOperand1 != Operand1)
415     {
416         AcpiUtRemoveReference (LocalOperand1);
417     }
418     return_ACPI_STATUS (Status);
419 }
420 
421 
422 /*******************************************************************************
423  *
424  * FUNCTION:    AcpiExDoMathOp
425  *
426  * PARAMETERS:  Opcode              - AML opcode
427  *              Integer0            - Integer operand #0
428  *              Integer1            - Integer operand #1
429  *
430  * RETURN:      Integer result of the operation
431  *
432  * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
433  *              math functions here is to prevent a lot of pointer dereferencing
434  *              to obtain the operands.
435  *
436  ******************************************************************************/
437 
438 UINT64
439 AcpiExDoMathOp (
440     UINT16                  Opcode,
441     UINT64                  Integer0,
442     UINT64                  Integer1)
443 {
444 
445     ACPI_FUNCTION_ENTRY ();
446 
447 
448     switch (Opcode)
449     {
450     case AML_ADD_OP:                /* Add (Integer0, Integer1, Result) */
451 
452         return (Integer0 + Integer1);
453 
454     case AML_BIT_AND_OP:            /* And (Integer0, Integer1, Result) */
455 
456         return (Integer0 & Integer1);
457 
458     case AML_BIT_NAND_OP:           /* NAnd (Integer0, Integer1, Result) */
459 
460         return (~(Integer0 & Integer1));
461 
462     case AML_BIT_OR_OP:             /* Or (Integer0, Integer1, Result) */
463 
464         return (Integer0 | Integer1);
465 
466     case AML_BIT_NOR_OP:            /* NOr (Integer0, Integer1, Result) */
467 
468         return (~(Integer0 | Integer1));
469 
470     case AML_BIT_XOR_OP:            /* XOr (Integer0, Integer1, Result) */
471 
472         return (Integer0 ^ Integer1);
473 
474     case AML_MULTIPLY_OP:           /* Multiply (Integer0, Integer1, Result) */
475 
476         return (Integer0 * Integer1);
477 
478     case AML_SHIFT_LEFT_OP:         /* ShiftLeft (Operand, ShiftCount, Result)*/
479 
480         /*
481          * We need to check if the shiftcount is larger than the integer bit
482          * width since the behavior of this is not well-defined in the C language.
483          */
484         if (Integer1 >= AcpiGbl_IntegerBitWidth)
485         {
486             return (0);
487         }
488         return (Integer0 << Integer1);
489 
490     case AML_SHIFT_RIGHT_OP:        /* ShiftRight (Operand, ShiftCount, Result) */
491 
492         /*
493          * We need to check if the shiftcount is larger than the integer bit
494          * width since the behavior of this is not well-defined in the C language.
495          */
496         if (Integer1 >= AcpiGbl_IntegerBitWidth)
497         {
498             return (0);
499         }
500         return (Integer0 >> Integer1);
501 
502     case AML_SUBTRACT_OP:           /* Subtract (Integer0, Integer1, Result) */
503 
504         return (Integer0 - Integer1);
505 
506     default:
507 
508         return (0);
509     }
510 }
511 
512 
513 /*******************************************************************************
514  *
515  * FUNCTION:    AcpiExDoLogicalNumericOp
516  *
517  * PARAMETERS:  Opcode              - AML opcode
518  *              Integer0            - Integer operand #0
519  *              Integer1            - Integer operand #1
520  *              LogicalResult       - TRUE/FALSE result of the operation
521  *
522  * RETURN:      Status
523  *
524  * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
525  *              operators (LAnd and LOr), both operands must be integers.
526  *
527  *              Note: cleanest machine code seems to be produced by the code
528  *              below, rather than using statements of the form:
529  *                  Result = (Integer0 && Integer1);
530  *
531  ******************************************************************************/
532 
533 ACPI_STATUS
534 AcpiExDoLogicalNumericOp (
535     UINT16                  Opcode,
536     UINT64                  Integer0,
537     UINT64                  Integer1,
538     BOOLEAN                 *LogicalResult)
539 {
540     ACPI_STATUS             Status = AE_OK;
541     BOOLEAN                 LocalResult = FALSE;
542 
543 
544     ACPI_FUNCTION_TRACE (ExDoLogicalNumericOp);
545 
546 
547     switch (Opcode)
548     {
549     case AML_LAND_OP:               /* LAnd (Integer0, Integer1) */
550 
551         if (Integer0 && Integer1)
552         {
553             LocalResult = TRUE;
554         }
555         break;
556 
557     case AML_LOR_OP:                /* LOr (Integer0, Integer1) */
558 
559         if (Integer0 || Integer1)
560         {
561             LocalResult = TRUE;
562         }
563         break;
564 
565     default:
566 
567         Status = AE_AML_INTERNAL;
568         break;
569     }
570 
571     /* Return the logical result and status */
572 
573     *LogicalResult = LocalResult;
574     return_ACPI_STATUS (Status);
575 }
576 
577 
578 /*******************************************************************************
579  *
580  * FUNCTION:    AcpiExDoLogicalOp
581  *
582  * PARAMETERS:  Opcode              - AML opcode
583  *              Operand0            - operand #0
584  *              Operand1            - operand #1
585  *              LogicalResult       - TRUE/FALSE result of the operation
586  *
587  * RETURN:      Status
588  *
589  * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
590  *              functions here is to prevent a lot of pointer dereferencing
591  *              to obtain the operands and to simplify the generation of the
592  *              logical value. For the Numeric operators (LAnd and LOr), both
593  *              operands must be integers. For the other logical operators,
594  *              operands can be any combination of Integer/String/Buffer. The
595  *              first operand determines the type to which the second operand
596  *              will be converted.
597  *
598  *              Note: cleanest machine code seems to be produced by the code
599  *              below, rather than using statements of the form:
600  *                  Result = (Operand0 == Operand1);
601  *
602  ******************************************************************************/
603 
604 ACPI_STATUS
605 AcpiExDoLogicalOp (
606     UINT16                  Opcode,
607     ACPI_OPERAND_OBJECT     *Operand0,
608     ACPI_OPERAND_OBJECT     *Operand1,
609     BOOLEAN                 *LogicalResult)
610 {
611     ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
612     UINT64                  Integer0;
613     UINT64                  Integer1;
614     UINT32                  Length0;
615     UINT32                  Length1;
616     ACPI_STATUS             Status = AE_OK;
617     BOOLEAN                 LocalResult = FALSE;
618     int                     Compare;
619 
620 
621     ACPI_FUNCTION_TRACE (ExDoLogicalOp);
622 
623 
624     /*
625      * Convert the second operand if necessary. The first operand
626      * determines the type of the second operand, (See the Data Types
627      * section of the ACPI 3.0+ specification.)  Both object types are
628      * guaranteed to be either Integer/String/Buffer by the operand
629      * resolution mechanism.
630      */
631     switch (Operand0->Common.Type)
632     {
633     case ACPI_TYPE_INTEGER:
634 
635         Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16);
636         break;
637 
638     case ACPI_TYPE_STRING:
639 
640         Status = AcpiExConvertToString (Operand1, &LocalOperand1,
641                     ACPI_IMPLICIT_CONVERT_HEX);
642         break;
643 
644     case ACPI_TYPE_BUFFER:
645 
646         Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
647         break;
648 
649     default:
650 
651         Status = AE_AML_INTERNAL;
652         break;
653     }
654 
655     if (ACPI_FAILURE (Status))
656     {
657         goto Cleanup;
658     }
659 
660     /*
661      * Two cases: 1) Both Integers, 2) Both Strings or Buffers
662      */
663     if (Operand0->Common.Type == ACPI_TYPE_INTEGER)
664     {
665         /*
666          * 1) Both operands are of type integer
667          *    Note: LocalOperand1 may have changed above
668          */
669         Integer0 = Operand0->Integer.Value;
670         Integer1 = LocalOperand1->Integer.Value;
671 
672         switch (Opcode)
673         {
674         case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
675 
676             if (Integer0 == Integer1)
677             {
678                 LocalResult = TRUE;
679             }
680             break;
681 
682         case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
683 
684             if (Integer0 > Integer1)
685             {
686                 LocalResult = TRUE;
687             }
688             break;
689 
690         case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
691 
692             if (Integer0 < Integer1)
693             {
694                 LocalResult = TRUE;
695             }
696             break;
697 
698         default:
699 
700             Status = AE_AML_INTERNAL;
701             break;
702         }
703     }
704     else
705     {
706         /*
707          * 2) Both operands are Strings or both are Buffers
708          *    Note: Code below takes advantage of common Buffer/String
709          *          object fields. LocalOperand1 may have changed above. Use
710          *          memcmp to handle nulls in buffers.
711          */
712         Length0 = Operand0->Buffer.Length;
713         Length1 = LocalOperand1->Buffer.Length;
714 
715         /* Lexicographic compare: compare the data bytes */
716 
717         Compare = ACPI_MEMCMP (Operand0->Buffer.Pointer,
718                     LocalOperand1->Buffer.Pointer,
719                     (Length0 > Length1) ? Length1 : Length0);
720 
721         switch (Opcode)
722         {
723         case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
724 
725             /* Length and all bytes must be equal */
726 
727             if ((Length0 == Length1) &&
728                 (Compare == 0))
729             {
730                 /* Length and all bytes match ==> TRUE */
731 
732                 LocalResult = TRUE;
733             }
734             break;
735 
736         case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
737 
738             if (Compare > 0)
739             {
740                 LocalResult = TRUE;
741                 goto Cleanup;   /* TRUE */
742             }
743             if (Compare < 0)
744             {
745                 goto Cleanup;   /* FALSE */
746             }
747 
748             /* Bytes match (to shortest length), compare lengths */
749 
750             if (Length0 > Length1)
751             {
752                 LocalResult = TRUE;
753             }
754             break;
755 
756         case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
757 
758             if (Compare > 0)
759             {
760                 goto Cleanup;   /* FALSE */
761             }
762             if (Compare < 0)
763             {
764                 LocalResult = TRUE;
765                 goto Cleanup;   /* TRUE */
766             }
767 
768             /* Bytes match (to shortest length), compare lengths */
769 
770             if (Length0 < Length1)
771             {
772                 LocalResult = TRUE;
773             }
774             break;
775 
776         default:
777 
778             Status = AE_AML_INTERNAL;
779             break;
780         }
781     }
782 
783 Cleanup:
784 
785     /* New object was created if implicit conversion performed - delete */
786 
787     if (LocalOperand1 != Operand1)
788     {
789         AcpiUtRemoveReference (LocalOperand1);
790     }
791 
792     /* Return the logical result and status */
793 
794     *LogicalResult = LocalResult;
795     return_ACPI_STATUS (Status);
796 }
797