1 /****************************************************************************** 2 * 3 * Module Name: aslprepkg - support for ACPI predefined name package objects 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, 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 #include "aslcompiler.h" 45 #include "aslcompiler.y.h" 46 #include "acpredef.h" 47 48 49 #define _COMPONENT ACPI_COMPILER 50 ACPI_MODULE_NAME ("aslprepkg") 51 52 53 /* Local prototypes */ 54 55 static void 56 ApCheckPackageElements ( 57 const char *PredefinedName, 58 ACPI_PARSE_OBJECT *Op, 59 UINT8 Type1, 60 UINT32 Count1, 61 UINT8 Type2, 62 UINT32 Count2); 63 64 static void 65 ApCheckPackageList ( 66 const char *PredefinedName, 67 ACPI_PARSE_OBJECT *ParentOp, 68 const ACPI_PREDEFINED_INFO *Package, 69 UINT32 StartIndex, 70 UINT32 Count); 71 72 static void 73 ApPackageTooSmall ( 74 const char *PredefinedName, 75 ACPI_PARSE_OBJECT *Op, 76 UINT32 Count, 77 UINT32 ExpectedCount); 78 79 static void 80 ApZeroLengthPackage ( 81 const char *PredefinedName, 82 ACPI_PARSE_OBJECT *Op); 83 84 static void 85 ApPackageTooLarge ( 86 const char *PredefinedName, 87 ACPI_PARSE_OBJECT *Op, 88 UINT32 Count, 89 UINT32 ExpectedCount); 90 91 92 /******************************************************************************* 93 * 94 * FUNCTION: ApCheckPackage 95 * 96 * PARAMETERS: ParentOp - Parser op for the package 97 * Predefined - Pointer to package-specific info for 98 * the method 99 * 100 * RETURN: None 101 * 102 * DESCRIPTION: Top-level validation for predefined name return package 103 * objects. 104 * 105 ******************************************************************************/ 106 107 void 108 ApCheckPackage ( 109 ACPI_PARSE_OBJECT *ParentOp, 110 const ACPI_PREDEFINED_INFO *Predefined) 111 { 112 ACPI_PARSE_OBJECT *Op; 113 const ACPI_PREDEFINED_INFO *Package; 114 ACPI_STATUS Status; 115 UINT32 ExpectedCount; 116 UINT32 Count; 117 UINT32 i; 118 119 120 /* The package info for this name is in the next table entry */ 121 122 Package = Predefined + 1; 123 124 /* First child is the package length */ 125 126 Op = ParentOp->Asl.Child; 127 Count = (UINT32) Op->Asl.Value.Integer; 128 129 /* 130 * Many of the variable-length top-level packages are allowed to simply 131 * have zero elements. This allows the BIOS to tell the host that even 132 * though the predefined name/method exists, the feature is not supported. 133 * Other package types require one or more elements. In any case, there 134 * is no need to continue validation. 135 */ 136 if (!Count) 137 { 138 switch (Package->RetInfo.Type) 139 { 140 case ACPI_PTYPE1_FIXED: 141 case ACPI_PTYPE1_OPTION: 142 case ACPI_PTYPE2_PKG_COUNT: 143 case ACPI_PTYPE2_REV_FIXED: 144 145 ApZeroLengthPackage (Predefined->Info.Name, ParentOp); 146 break; 147 148 case ACPI_PTYPE1_VAR: 149 case ACPI_PTYPE2: 150 case ACPI_PTYPE2_COUNT: 151 case ACPI_PTYPE2_FIXED: 152 case ACPI_PTYPE2_MIN: 153 case ACPI_PTYPE2_FIX_VAR: 154 case ACPI_PTYPE2_VAR_VAR: 155 default: 156 157 break; 158 } 159 160 return; 161 } 162 163 /* Get the first element of the package */ 164 165 Op = Op->Asl.Next; 166 167 /* Decode the package type */ 168 169 switch (Package->RetInfo.Type) 170 { 171 case ACPI_PTYPE1_FIXED: 172 /* 173 * The package count is fixed and there are no subpackages 174 * 175 * If package is too small, exit. 176 * If package is larger than expected, issue warning but continue 177 */ 178 ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2; 179 if (Count < ExpectedCount) 180 { 181 goto PackageTooSmall; 182 } 183 else if (Count > ExpectedCount) 184 { 185 ApPackageTooLarge (Predefined->Info.Name, ParentOp, 186 Count, ExpectedCount); 187 } 188 189 /* Validate all elements of the package */ 190 191 ApCheckPackageElements (Predefined->Info.Name, Op, 192 Package->RetInfo.ObjectType1, Package->RetInfo.Count1, 193 Package->RetInfo.ObjectType2, Package->RetInfo.Count2); 194 break; 195 196 case ACPI_PTYPE1_VAR: 197 /* 198 * The package count is variable, there are no subpackages, 199 * and all elements must be of the same type 200 */ 201 for (i = 0; i < Count; i++) 202 { 203 ApCheckObjectType (Predefined->Info.Name, Op, 204 Package->RetInfo.ObjectType1, i); 205 Op = Op->Asl.Next; 206 } 207 break; 208 209 case ACPI_PTYPE1_OPTION: 210 /* 211 * The package count is variable, there are no subpackages. 212 * There are a fixed number of required elements, and a variable 213 * number of optional elements. 214 * 215 * Check if package is at least as large as the minimum required 216 */ 217 ExpectedCount = Package->RetInfo3.Count; 218 if (Count < ExpectedCount) 219 { 220 goto PackageTooSmall; 221 } 222 223 /* Variable number of sub-objects */ 224 225 for (i = 0; i < Count; i++) 226 { 227 if (i < Package->RetInfo3.Count) 228 { 229 /* These are the required package elements (0, 1, or 2) */ 230 231 ApCheckObjectType (Predefined->Info.Name, Op, 232 Package->RetInfo3.ObjectType[i], i); 233 } 234 else 235 { 236 /* These are the optional package elements */ 237 238 ApCheckObjectType (Predefined->Info.Name, Op, 239 Package->RetInfo3.TailObjectType, i); 240 } 241 242 Op = Op->Asl.Next; 243 } 244 break; 245 246 case ACPI_PTYPE2_REV_FIXED: 247 248 /* First element is the (Integer) revision */ 249 250 ApCheckObjectType (Predefined->Info.Name, Op, 251 ACPI_RTYPE_INTEGER, 0); 252 253 Op = Op->Asl.Next; 254 Count--; 255 256 /* Examine the subpackages */ 257 258 ApCheckPackageList (Predefined->Info.Name, Op, 259 Package, 1, Count); 260 break; 261 262 case ACPI_PTYPE2_PKG_COUNT: 263 264 /* First element is the (Integer) count of subpackages to follow */ 265 266 Status = ApCheckObjectType (Predefined->Info.Name, Op, 267 ACPI_RTYPE_INTEGER, 0); 268 269 /* We must have an integer count from above (otherwise, use Count) */ 270 271 if (ACPI_SUCCESS (Status)) 272 { 273 /* 274 * Count cannot be larger than the parent package length, but 275 * allow it to be smaller. The >= accounts for the Integer above. 276 */ 277 ExpectedCount = (UINT32) Op->Asl.Value.Integer; 278 if (ExpectedCount >= Count) 279 { 280 goto PackageTooSmall; 281 } 282 283 Count = ExpectedCount; 284 } 285 286 Op = Op->Asl.Next; 287 288 /* Examine the subpackages */ 289 290 ApCheckPackageList (Predefined->Info.Name, Op, 291 Package, 1, Count); 292 break; 293 294 case ACPI_PTYPE2_UUID_PAIR: 295 296 /* The package contains a variable list of UUID Buffer/Package pairs */ 297 298 /* The length of the package must be even */ 299 300 if (Count & 1) 301 { 302 sprintf (MsgBuffer, "%4.4s: Package length, %d, must be even.", 303 Predefined->Info.Name, Count); 304 305 AslError (ASL_ERROR, ASL_MSG_RESERVED_PACKAGE_LENGTH, 306 ParentOp->Asl.Child, MsgBuffer); 307 } 308 309 /* Validate the alternating types */ 310 311 for (i = 0; i < Count; ++i) 312 { 313 if (i & 1) 314 { 315 ApCheckObjectType (Predefined->Info.Name, Op, 316 Package->RetInfo.ObjectType2, i); 317 } 318 else 319 { 320 ApCheckObjectType (Predefined->Info.Name, Op, 321 Package->RetInfo.ObjectType1, i); 322 } 323 324 Op = Op->Asl.Next; 325 } 326 327 break; 328 329 case ACPI_PTYPE2_VAR_VAR: 330 331 /* Check for minimum size (ints at beginning + 1 subpackage) */ 332 333 ExpectedCount = Package->RetInfo4.Count1 + 1; 334 if (Count < ExpectedCount) 335 { 336 goto PackageTooSmall; 337 } 338 339 /* Check the non-package elements at beginning of main package */ 340 341 for (i = 0; i < Package->RetInfo4.Count1; ++i) 342 { 343 Status = ApCheckObjectType (Predefined->Info.Name, Op, 344 Package->RetInfo4.ObjectType1, i); 345 Op = Op->Asl.Next; 346 } 347 348 /* Examine the variable-length list of subpackages */ 349 350 ApCheckPackageList (Predefined->Info.Name, Op, 351 Package, Package->RetInfo4.Count1, Count); 352 353 break; 354 355 case ACPI_PTYPE2: 356 case ACPI_PTYPE2_FIXED: 357 case ACPI_PTYPE2_MIN: 358 case ACPI_PTYPE2_COUNT: 359 case ACPI_PTYPE2_FIX_VAR: 360 /* 361 * These types all return a single Package that consists of a 362 * variable number of subpackages. 363 */ 364 365 /* Examine the subpackages */ 366 367 ApCheckPackageList (Predefined->Info.Name, Op, 368 Package, 0, Count); 369 break; 370 371 default: 372 return; 373 } 374 375 return; 376 377 PackageTooSmall: 378 ApPackageTooSmall (Predefined->Info.Name, ParentOp, 379 Count, ExpectedCount); 380 } 381 382 383 /******************************************************************************* 384 * 385 * FUNCTION: ApCheckPackageElements 386 * 387 * PARAMETERS: PredefinedName - Name of the predefined object 388 * Op - Parser op for the package 389 * Type1 - Object type for first group 390 * Count1 - Count for first group 391 * Type2 - Object type for second group 392 * Count2 - Count for second group 393 * 394 * RETURN: None 395 * 396 * DESCRIPTION: Validate all elements of a package. Works with packages that 397 * are defined to contain up to two groups of different object 398 * types. 399 * 400 ******************************************************************************/ 401 402 static void 403 ApCheckPackageElements ( 404 const char *PredefinedName, 405 ACPI_PARSE_OBJECT *Op, 406 UINT8 Type1, 407 UINT32 Count1, 408 UINT8 Type2, 409 UINT32 Count2) 410 { 411 UINT32 i; 412 413 414 /* 415 * Up to two groups of package elements are supported by the data 416 * structure. All elements in each group must be of the same type. 417 * The second group can have a count of zero. 418 * 419 * Aborts check upon a NULL package element, as this means (at compile 420 * time) that the remainder of the package elements are also NULL 421 * (This is the only way to create NULL package elements.) 422 */ 423 for (i = 0; (i < Count1) && Op; i++) 424 { 425 ApCheckObjectType (PredefinedName, Op, Type1, i); 426 Op = Op->Asl.Next; 427 } 428 429 for (i = 0; (i < Count2) && Op; i++) 430 { 431 ApCheckObjectType (PredefinedName, Op, Type2, (i + Count1)); 432 Op = Op->Asl.Next; 433 } 434 } 435 436 437 /******************************************************************************* 438 * 439 * FUNCTION: ApCheckPackageList 440 * 441 * PARAMETERS: PredefinedName - Name of the predefined object 442 * ParentOp - Parser op of the parent package 443 * Package - Package info for this predefined name 444 * StartIndex - Index in parent package where list begins 445 * ParentCount - Element count of parent package 446 * 447 * RETURN: None 448 * 449 * DESCRIPTION: Validate the individual package elements for a predefined name. 450 * Handles the cases where the predefined name is defined as a 451 * Package of Packages (subpackages). These are the types: 452 * 453 * ACPI_PTYPE2 454 * ACPI_PTYPE2_FIXED 455 * ACPI_PTYPE2_MIN 456 * ACPI_PTYPE2_COUNT 457 * ACPI_PTYPE2_FIX_VAR 458 * ACPI_PTYPE2_VAR_VAR 459 * 460 ******************************************************************************/ 461 462 static void 463 ApCheckPackageList ( 464 const char *PredefinedName, 465 ACPI_PARSE_OBJECT *ParentOp, 466 const ACPI_PREDEFINED_INFO *Package, 467 UINT32 StartIndex, 468 UINT32 ParentCount) 469 { 470 ACPI_PARSE_OBJECT *SubPackageOp = ParentOp; 471 ACPI_PARSE_OBJECT *Op; 472 ACPI_STATUS Status; 473 UINT32 Count; 474 UINT32 ExpectedCount; 475 UINT32 i; 476 UINT32 j; 477 478 479 /* 480 * Validate each subpackage in the parent Package 481 * 482 * Note: We ignore NULL package elements on the assumption that 483 * they will be initialized by the BIOS or other ASL code. 484 */ 485 for (i = 0; (i < ParentCount) && SubPackageOp; i++) 486 { 487 /* Each object in the list must be of type Package */ 488 489 Status = ApCheckObjectType (PredefinedName, SubPackageOp, 490 ACPI_RTYPE_PACKAGE, i + StartIndex); 491 if (ACPI_FAILURE (Status)) 492 { 493 goto NextSubpackage; 494 } 495 496 /* Examine the different types of expected subpackages */ 497 498 Op = SubPackageOp->Asl.Child; 499 500 /* First child is the package length */ 501 502 Count = (UINT32) Op->Asl.Value.Integer; 503 Op = Op->Asl.Next; 504 505 /* 506 * Most subpackage must have at least one element, with 507 * only rare exceptions. (_RDI) 508 */ 509 if (!Count && 510 (Package->RetInfo.Type != ACPI_PTYPE2_VAR_VAR)) 511 { 512 ApZeroLengthPackage (PredefinedName, SubPackageOp); 513 goto NextSubpackage; 514 } 515 516 /* 517 * Decode the package type. 518 * PTYPE2 indicates that a "package of packages" is expected for 519 * this name. The various flavors of PTYPE2 indicate the number 520 * and format of the subpackages. 521 */ 522 switch (Package->RetInfo.Type) 523 { 524 case ACPI_PTYPE2: 525 case ACPI_PTYPE2_PKG_COUNT: 526 case ACPI_PTYPE2_REV_FIXED: 527 528 /* Each subpackage has a fixed number of elements */ 529 530 ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2; 531 if (Count < ExpectedCount) 532 { 533 ApPackageTooSmall (PredefinedName, SubPackageOp, 534 Count, ExpectedCount); 535 break; 536 } 537 if (Count > ExpectedCount) 538 { 539 ApPackageTooLarge (PredefinedName, SubPackageOp, 540 Count, ExpectedCount); 541 break; 542 } 543 544 ApCheckPackageElements (PredefinedName, Op, 545 Package->RetInfo.ObjectType1, Package->RetInfo.Count1, 546 Package->RetInfo.ObjectType2, Package->RetInfo.Count2); 547 break; 548 549 case ACPI_PTYPE2_FIX_VAR: 550 /* 551 * Each subpackage has a fixed number of elements and an 552 * optional element 553 */ 554 ExpectedCount = Package->RetInfo.Count1 + Package->RetInfo.Count2; 555 if (Count < ExpectedCount) 556 { 557 ApPackageTooSmall (PredefinedName, SubPackageOp, 558 Count, ExpectedCount); 559 break; 560 } 561 562 ApCheckPackageElements (PredefinedName, Op, 563 Package->RetInfo.ObjectType1, Package->RetInfo.Count1, 564 Package->RetInfo.ObjectType2, 565 Count - Package->RetInfo.Count1); 566 break; 567 568 case ACPI_PTYPE2_VAR_VAR: 569 /* 570 * Must have at least the minimum number elements. 571 * A zero PkgCount means the number of elements is variable. 572 */ 573 ExpectedCount = Package->RetInfo4.PkgCount; 574 if (ExpectedCount && (Count < ExpectedCount)) 575 { 576 ApPackageTooSmall (PredefinedName, SubPackageOp, 577 Count, 1); 578 break; 579 } 580 581 ApCheckPackageElements (PredefinedName, Op, 582 Package->RetInfo4.SubObjectTypes, 583 Package->RetInfo4.PkgCount, 584 0, 0); 585 break; 586 587 case ACPI_PTYPE2_FIXED: 588 589 /* Each subpackage has a fixed length */ 590 591 ExpectedCount = Package->RetInfo2.Count; 592 if (Count < ExpectedCount) 593 { 594 ApPackageTooSmall (PredefinedName, SubPackageOp, 595 Count, ExpectedCount); 596 break; 597 } 598 if (Count > ExpectedCount) 599 { 600 ApPackageTooLarge (PredefinedName, SubPackageOp, 601 Count, ExpectedCount); 602 break; 603 } 604 605 /* Check each object/type combination */ 606 607 for (j = 0; j < ExpectedCount; j++) 608 { 609 ApCheckObjectType (PredefinedName, Op, 610 Package->RetInfo2.ObjectType[j], j); 611 612 Op = Op->Asl.Next; 613 } 614 break; 615 616 case ACPI_PTYPE2_MIN: 617 618 /* Each subpackage has a variable but minimum length */ 619 620 ExpectedCount = Package->RetInfo.Count1; 621 if (Count < ExpectedCount) 622 { 623 ApPackageTooSmall (PredefinedName, SubPackageOp, 624 Count, ExpectedCount); 625 break; 626 } 627 628 /* Check the type of each subpackage element */ 629 630 ApCheckPackageElements (PredefinedName, Op, 631 Package->RetInfo.ObjectType1, Count, 0, 0); 632 break; 633 634 case ACPI_PTYPE2_COUNT: 635 /* 636 * First element is the (Integer) count of elements, including 637 * the count field (the ACPI name is NumElements) 638 */ 639 Status = ApCheckObjectType (PredefinedName, Op, 640 ACPI_RTYPE_INTEGER, 0); 641 642 /* We must have an integer count from above (otherwise, use Count) */ 643 644 if (ACPI_SUCCESS (Status)) 645 { 646 /* 647 * Make sure package is large enough for the Count and is 648 * is as large as the minimum size 649 */ 650 ExpectedCount = (UINT32) Op->Asl.Value.Integer; 651 652 if (Count < ExpectedCount) 653 { 654 ApPackageTooSmall (PredefinedName, SubPackageOp, 655 Count, ExpectedCount); 656 break; 657 } 658 else if (Count > ExpectedCount) 659 { 660 ApPackageTooLarge (PredefinedName, SubPackageOp, 661 Count, ExpectedCount); 662 } 663 664 /* Some names of this type have a minimum length */ 665 666 if (Count < Package->RetInfo.Count1) 667 { 668 ExpectedCount = Package->RetInfo.Count1; 669 ApPackageTooSmall (PredefinedName, SubPackageOp, 670 Count, ExpectedCount); 671 break; 672 } 673 674 Count = ExpectedCount; 675 } 676 677 /* Check the type of each subpackage element */ 678 679 Op = Op->Asl.Next; 680 ApCheckPackageElements (PredefinedName, Op, 681 Package->RetInfo.ObjectType1, (Count - 1), 0, 0); 682 break; 683 684 default: 685 break; 686 } 687 688 NextSubpackage: 689 SubPackageOp = SubPackageOp->Asl.Next; 690 } 691 } 692 693 694 /******************************************************************************* 695 * 696 * FUNCTION: ApPackageTooSmall 697 * 698 * PARAMETERS: PredefinedName - Name of the predefined object 699 * Op - Current parser op 700 * Count - Actual package element count 701 * ExpectedCount - Expected package element count 702 * 703 * RETURN: None 704 * 705 * DESCRIPTION: Issue error message for a package that is smaller than 706 * required. 707 * 708 ******************************************************************************/ 709 710 static void 711 ApPackageTooSmall ( 712 const char *PredefinedName, 713 ACPI_PARSE_OBJECT *Op, 714 UINT32 Count, 715 UINT32 ExpectedCount) 716 { 717 718 sprintf (MsgBuffer, "%s: length %u, required minimum is %u", 719 PredefinedName, Count, ExpectedCount); 720 721 AslError (ASL_ERROR, ASL_MSG_RESERVED_PACKAGE_LENGTH, Op, MsgBuffer); 722 } 723 724 725 /******************************************************************************* 726 * 727 * FUNCTION: ApZeroLengthPackage 728 * 729 * PARAMETERS: PredefinedName - Name of the predefined object 730 * Op - Current parser op 731 * 732 * RETURN: None 733 * 734 * DESCRIPTION: Issue error message for a zero-length package (a package that 735 * is required to have a non-zero length). Variable length 736 * packages seem to be allowed to have zero length, however. 737 * Even if not allowed, BIOS code does it. 738 * 739 ******************************************************************************/ 740 741 static void 742 ApZeroLengthPackage ( 743 const char *PredefinedName, 744 ACPI_PARSE_OBJECT *Op) 745 { 746 747 sprintf (MsgBuffer, "%s: length is zero", PredefinedName); 748 749 AslError (ASL_ERROR, ASL_MSG_RESERVED_PACKAGE_LENGTH, Op, MsgBuffer); 750 } 751 752 753 /******************************************************************************* 754 * 755 * FUNCTION: ApPackageTooLarge 756 * 757 * PARAMETERS: PredefinedName - Name of the predefined object 758 * Op - Current parser op 759 * Count - Actual package element count 760 * ExpectedCount - Expected package element count 761 * 762 * RETURN: None 763 * 764 * DESCRIPTION: Issue a remark for a package that is larger than expected. 765 * 766 ******************************************************************************/ 767 768 static void 769 ApPackageTooLarge ( 770 const char *PredefinedName, 771 ACPI_PARSE_OBJECT *Op, 772 UINT32 Count, 773 UINT32 ExpectedCount) 774 { 775 776 sprintf (MsgBuffer, "%s: length is %u, only %u required", 777 PredefinedName, Count, ExpectedCount); 778 779 AslError (ASL_REMARK, ASL_MSG_RESERVED_PACKAGE_LENGTH, Op, MsgBuffer); 780 } 781