1/** @file 2Prototypes and defines for the QNC SMM Dispatcher. 3 4Copyright (c) 2013-2015 Intel Corporation. 5 6This program and the accompanying materials 7are licensed and made available under the terms and conditions of the BSD License 8which accompanies this distribution. The full text of the license may be found at 9http://opensource.org/licenses/bsd-license.php 10 11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14**/ 15 16#ifndef QNC_SMM_H 17#define QNC_SMM_H 18 19// 20// Include common header file for this module. 21// 22#include "CommonHeader.h" 23 24#include "QNCSmmRegisters.h" 25 26extern EFI_HANDLE mQNCSmmDispatcherImageHandle; 27 28 29// 30// ///////////////////////////////////////////////////////////////////////////// 31// SUPPORTED PROTOCOLS 32// 33 34// 35// Define an enumeration for all the supported protocols 36// 37typedef enum { 38 // UsbType, DELETE:on QuarkNcSocId, there is no usb smi supported 39 SxType, 40 SwType, 41 GpiType, 42 QNCnType, 43 PowerButtonType, 44 PeriodicTimerType, 45 NUM_PROTOCOLS 46} QNC_SMM_PROTOCOL_TYPE; 47 48// 49// ///////////////////////////////////////////////////////////////////////////// 50// SPECIFYING A REGISTER 51// We want a general way of referring to addresses. For this case, we'll only 52// need addresses in the ACPI table (and the TCO entries within the ACPI table). 53// However, it's interesting to consider what it would take to support other types 54// of addresses. To address Will's concern, I think it prudent to accommodate it 55// early on in the design. 56// 57// Addresses we need to consider: 58// 59// Type: Required: 60// I/O Yes 61// ACPI (special case of I/O) Only if we want to 62// TCO (special case of ACPI) Only if we want to 63// Memory (or Memory Mapped I/O) Only if we want to 64// PCI Yes, for BiosWp 65// 66typedef enum { 67 // 68 // IO_ADDR_TYPE, // unimplemented 69 // 70 ACPI_ADDR_TYPE, 71 GPE_ADDR_TYPE, 72 // 73 // MEMORY_ADDR_TYPE, // unimplemented 74 // 75 MEMORY_MAPPED_IO_ADDRESS_TYPE, 76 PCI_ADDR_TYPE, 77 NUM_ADDR_TYPES, // count of items in this enum 78 QNC_SMM_ADDR_TYPE_NULL = -1 // sentinel to indicate NULL or to signal end of arrays 79} ADDR_TYPE; 80 81// 82// Assumption: 32-bits -- enum's evaluate to integer 83// Assumption: This code will only run on IA-32. Justification: IA-64 doesn't have SMIs. 84// We don't have to worry about 64-bit addresses. 85// Typedef the size of addresses in case the numbers I'm using are wrong or in case 86// this changes. This is a good idea because PCI_ADDR will change, for example, when 87// we add support for PciExpress. 88// 89typedef UINT16 IO_ADDR; 90typedef IO_ADDR ACPI_ADDR; // can omit 91typedef IO_ADDR GPE_ADDR; // can omit 92typedef IO_ADDR TCO_ADDR; // can omit 93typedef VOID *MEM_ADDR; 94typedef MEM_ADDR MEMORY_MAPPED_IO_ADDRESS; 95typedef union { 96 UINT32 Raw; 97 struct { 98 UINT8 Reg; 99 UINT8 Fnc; 100 UINT8 Dev; 101 UINT8 Bus; 102 } Fields; 103} PCI_ADDR; 104 105typedef struct { 106 ADDR_TYPE Type; 107 union { 108 // 109 // used to initialize during declaration/definition 110 // 111 UINTN raw; 112 113 // 114 // used to access useful data 115 // 116 IO_ADDR io; 117 ACPI_ADDR acpi; 118 GPE_ADDR gpe; 119 TCO_ADDR tco; 120 MEM_ADDR mem; 121 MEMORY_MAPPED_IO_ADDRESS Mmio; 122 PCI_ADDR pci; 123 124 } Data; 125 126} QNC_SMM_ADDRESS; 127// 128// Assumption: total size is 64 bits (32 for type and 32 for data) or 8 bytes 129// 130#define EFI_PCI_ADDRESS_PORT 0xcf8 131#define EFI_PCI_DATA_PORT 0xcfc 132 133// 134// ///////////////////////////////////////////////////////////////////////////// 135// SPECIFYING BITS WITHIN A REGISTER 136// Here's a struct that helps us specify a source or enable bit. 137// 138typedef struct { 139 QNC_SMM_ADDRESS Reg; 140 UINT8 SizeInBytes; // of the register 141 UINT8 Bit; 142} QNC_SMM_BIT_DESC; 143 144// 145// Sometimes, we'll have bit descriptions that are unused. It'd be great to have a 146// way to easily identify them: 147// 148#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type == QNC_SMM_ADDR_TYPE_NULL) // "returns" true when BitDesc is NULL 149#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = QNC_SMM_ADDR_TYPE_NULL) // will "return" an integer w/ value of 0 150#define NULL_BIT_DESC_INITIALIZER \ 151 { \ 152 { \ 153 QNC_SMM_ADDR_TYPE_NULL, \ 154 { \ 155 0 \ 156 } \ 157 }, \ 158 0, 0 \ 159 } 160// 161// I'd like a type to specify the callback's Sts & En bits because they'll 162// be commonly used together: 163// 164#define NUM_EN_BITS 2 165#define NUM_STS_BITS 1 166 167// 168// Flags 169// 170typedef UINT8 QNC_SMM_SOURCE_FLAGS; 171 172// 173// Flags required today 174// 175#define QNC_SMM_NO_FLAGS 0 176#define QNC_SMM_SCI_EN_DEPENDENT (BIT0) 177#define QNC_SMM_CLEAR_WITH_ZERO (BIT6) 178 179// 180// Flags that might be required tomorrow 181// #define QNC_SMM_CLEAR_WITH_ONE 2 // may need to support bits that clear by writing 0 182// #define QNC_SMM_MULTIBIT_FIELD 3 // may need to support status/enable fields 2 bits wide 183// 184typedef struct { 185 QNC_SMM_SOURCE_FLAGS Flags; 186 QNC_SMM_BIT_DESC En[NUM_EN_BITS]; 187 QNC_SMM_BIT_DESC Sts[NUM_STS_BITS]; 188} QNC_SMM_SOURCE_DESC; 189// 190// 31 bytes, I think 191// 192#define NULL_SOURCE_DESC_INITIALIZER \ 193 { \ 194 QNC_SMM_NO_FLAGS, \ 195 { \ 196 NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \ 197 }, \ 198 { \ 199 NULL_BIT_DESC_INITIALIZER \ 200 } \ 201 } 202 203// 204// ///////////////////////////////////////////////////////////////////////////// 205// CHILD CONTEXTS 206// To keep consistent w/ the architecture, we'll need to provide the context 207// to the child when we call its callback function. After talking with Will, 208// we agreed that we'll need functions to "dig" the context out of the hardware 209// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those 210// contexts to prevent unnecessary dispatches. I'd like a general type for these 211// "GetContext" functions, so I'll need a union of all the protocol contexts for 212// our internal use: 213// 214typedef union { 215 // 216 // (in no particular order) 217 // 218 EFI_SMM_ICHN_REGISTER_CONTEXT QNCn; 219 EFI_SMM_SX_REGISTER_CONTEXT Sx; 220 EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer; 221 EFI_SMM_SW_REGISTER_CONTEXT Sw; 222 EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton; 223 // EFI_SMM_USB_REGISTER_CONTEXT Usb; DELETE:on QuarkNcSocId, there is no usb smi supported 224 EFI_SMM_GPI_REGISTER_CONTEXT Gpi; 225} QNC_SMM_CONTEXT; 226 227typedef union { 228 // 229 // (in no particular order) 230 // 231 EFI_SMM_SW_CONTEXT Sw; 232 EFI_SMM_PERIODIC_TIMER_CONTEXT PeriodicTimer; 233} QNC_SMM_BUFFER; 234 235// 236// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes 237// 238typedef struct _DATABASE_RECORD DATABASE_RECORD; 239 240typedef 241VOID 242(EFIAPI *GET_CONTEXT) ( 243 IN DATABASE_RECORD * Record, 244 OUT QNC_SMM_CONTEXT * Context 245 ); 246// 247// Assumption: the GET_CONTEXT function will be as small and simple as possible. 248// Assumption: We don't need to pass in an enumeration for the protocol because each 249// GET_CONTEXT function is written for only one protocol. 250// We also need a function to compare contexts to see if the child should be dispatched 251// 252typedef 253BOOLEAN 254(EFIAPI *CMP_CONTEXT) ( 255 IN QNC_SMM_CONTEXT * Context1, 256 IN QNC_SMM_CONTEXT * Context2 257 ); 258 259/* 260 Returns: True when contexts are equivalent; False otherwise 261*/ 262 263// 264// This function is used to get the content of CommBuffer that will be passed 265// to Callback function 266// 267typedef 268VOID 269(EFIAPI *GET_BUFFER) ( 270 IN DATABASE_RECORD * Record 271 ); 272 273// 274// Finally, every protocol will require a "Get Context", "Compare Context" 275// and "Get CommBuffer" call, so we may as well wrap that up in a table, too. 276// 277typedef struct { 278 GET_CONTEXT GetContext; 279 CMP_CONTEXT CmpContext; 280 GET_BUFFER GetBuffer; 281} CONTEXT_FUNCTIONS; 282 283extern CONTEXT_FUNCTIONS ContextFunctions[NUM_PROTOCOLS]; 284 285// 286// ///////////////////////////////////////////////////////////////////////////// 287// MAPPING CONTEXT TO BIT DESCRIPTIONS 288// I'd like to have a general approach to mapping contexts to bit descriptions. 289// Sometimes, we'll find that we can use table lookups or CONSTant assignments; 290// other times, we'll find that we'll need to use a function to perform the mapping. 291// If we define a macro to mask that process, we'll never have to change the code. 292// I don't know if this is desirable or not -- if it isn't, then we can get rid 293// of the macros and just use function calls or variable assignments. Doesn't matter 294// to me. 295// Mapping complex contexts requires a function 296// 297// DELETE:on QuarkNcSocId, there is no usb smi supported 298//EFI_STATUS 299//EFIAPI 300//MapUsbToSrcDesc ( 301// IN QNC_SMM_CONTEXT *RegisterContext, 302// OUT QNC_SMM_SOURCE_DESC *SrcDesc 303// ) 304/*++ 305 306Routine Description: 307 308 GC_TODO: Add function description 309 310Arguments: 311 312 RegisterContext - GC_TODO: add argument description 313 SrcDesc - GC_TODO: add argument description 314 315Returns: 316 317 GC_TODO: add return values 318 319--*/ 320; 321 322EFI_STATUS 323MapPeriodicTimerToSrcDesc ( 324 IN QNC_SMM_CONTEXT *RegisterContext, 325 OUT QNC_SMM_SOURCE_DESC *SrcDesc 326 ) 327/*++ 328 329Routine Description: 330 331 GC_TODO: Add function description 332 333Arguments: 334 335 RegisterContext - GC_TODO: add argument description 336 SrcDesc - GC_TODO: add argument description 337 338Returns: 339 340 GC_TODO: add return values 341 342--*/ 343; 344 345// 346// Mapping simple contexts can be done by assignment or lookup table 347// 348extern CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC; 349extern CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC; 350 351// 352// With the changes we've made to the protocols, we can now use table 353// lookups for the following protocols: 354// 355extern CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC; 356 357extern QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES]; 358 359 360// 361// For QNCx, APMC is UINT8 port, so the MAX SWI Value is 0xFF. 362// 363#define MAXIMUM_SWI_VALUE 0xFF 364 365 366// 367// Open: Need to make sure this kind of type cast will actually work. 368// May need an intermediate form w/ two VOID* arguments. I'll figure 369// that out when I start compiling. 370 371/////////////////////////////////////////////////////////////////////////////// 372// 373typedef 374VOID 375(EFIAPI *QNC_SMM_CLEAR_SOURCE) ( 376 QNC_SMM_SOURCE_DESC * SrcDesc 377 ); 378 379// 380// ///////////////////////////////////////////////////////////////////////////// 381// "DATABASE" RECORD 382// Linked list data structures 383// 384#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C') 385 386struct _DATABASE_RECORD { 387 UINT32 Signature; 388 LIST_ENTRY Link; 389 390 // 391 // Status and Enable bit description 392 // 393 QNC_SMM_SOURCE_DESC SrcDesc; 394 395 // 396 // Callback function 397 // 398 EFI_SMM_HANDLER_ENTRY_POINT2 Callback; 399 QNC_SMM_CONTEXT ChildContext; 400 QNC_SMM_BUFFER CommBuffer; 401 UINTN BufferSize; 402 403 // 404 // Special handling hooks -- init them to NULL if unused/unneeded 405 // 406 QNC_SMM_CLEAR_SOURCE ClearSource; // needed for SWSMI timer 407 // Functions required to make callback code general 408 // 409 CONTEXT_FUNCTIONS ContextFunctions; 410 411 // 412 // The protocol that this record dispatches 413 // 414 QNC_SMM_PROTOCOL_TYPE ProtocolType; 415 416}; 417 418#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE) 419#define DATABASE_RECORD_FROM_CONTEXT(_record) CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE) 420 421// 422// ///////////////////////////////////////////////////////////////////////////// 423// HOOKING INTO THE ARCHITECTURE 424// 425typedef 426EFI_STATUS 427(EFIAPI *QNC_SMM_GENERIC_REGISTER) ( 428 IN VOID **This, 429 IN VOID *DispatchFunction, 430 IN VOID *RegisterContext, 431 OUT EFI_HANDLE * DispatchHandle 432 ); 433typedef 434EFI_STATUS 435(EFIAPI *QNC_SMM_GENERIC_UNREGISTER) ( 436 IN VOID **This, 437 IN EFI_HANDLE DispatchHandle 438 ); 439 440// 441// Define a memory "stamp" equivalent in size and function to most of the protocols 442// 443typedef struct { 444 QNC_SMM_GENERIC_REGISTER Register; 445 QNC_SMM_GENERIC_UNREGISTER Unregister; 446 UINTN Extra1; 447 UINTN Extra2; // may not need this one 448} QNC_SMM_GENERIC_PROTOCOL; 449 450EFI_STATUS 451QNCSmmCoreRegister ( 452 IN QNC_SMM_GENERIC_PROTOCOL *This, 453 IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, 454 IN QNC_SMM_CONTEXT *RegisterContext, 455 OUT EFI_HANDLE *DispatchHandle 456 ) 457/*++ 458 459Routine Description: 460 461 GC_TODO: Add function description 462 463Arguments: 464 465 This - GC_TODO: add argument description 466 DispatchFunction - GC_TODO: add argument description 467 RegisterContext - GC_TODO: add argument description 468 DispatchHandle - GC_TODO: add argument description 469 470Returns: 471 472 GC_TODO: add return values 473 474--*/ 475; 476EFI_STATUS 477QNCSmmCoreUnRegister ( 478 IN QNC_SMM_GENERIC_PROTOCOL *This, 479 IN EFI_HANDLE DispatchHandle 480 ) 481/*++ 482 483Routine Description: 484 485 GC_TODO: Add function description 486 487Arguments: 488 489 This - GC_TODO: add argument description 490 DispatchHandle - GC_TODO: add argument description 491 492Returns: 493 494 GC_TODO: add return values 495 496--*/ 497; 498 499typedef union { 500 QNC_SMM_GENERIC_PROTOCOL Generic; 501 502 // EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; DELETE:on QuarkNcSocId, there is no usb smi supported 503 EFI_SMM_SX_DISPATCH2_PROTOCOL Sx; 504 EFI_SMM_SW_DISPATCH2_PROTOCOL Sw; 505 EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi; 506 EFI_SMM_ICHN_DISPATCH2_PROTOCOL QNCn; 507 EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton; 508 EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer; 509} QNC_SMM_PROTOCOL; 510 511// 512// Define a structure to help us identify the generic protocol 513// 514#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T') 515 516typedef struct { 517 UINTN Signature; 518 519 QNC_SMM_PROTOCOL_TYPE Type; 520 EFI_GUID *Guid; 521 QNC_SMM_PROTOCOL Protocols; 522} QNC_SMM_QUALIFIED_PROTOCOL; 523 524#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \ 525 CR (_generic, \ 526 QNC_SMM_QUALIFIED_PROTOCOL, \ 527 Protocols, \ 528 PROTOCOL_SIGNATURE \ 529 ) 530 531// 532// Create private data for the protocols that we'll publish 533// 534typedef struct { 535 LIST_ENTRY CallbackDataBase; 536 EFI_HANDLE SmiHandle; 537 EFI_HANDLE InstallMultProtHandle; 538 QNC_SMM_QUALIFIED_PROTOCOL Protocols[NUM_PROTOCOLS]; 539} PRIVATE_DATA; 540 541extern PRIVATE_DATA mPrivateData; 542 543// 544// ///////////////////////////////////////////////////////////////////////////// 545// 546VOID 547EFIAPI 548SwGetContext ( 549 IN DATABASE_RECORD *Record, 550 OUT QNC_SMM_CONTEXT *Context 551 ) 552/*++ 553 554Routine Description: 555 556 GC_TODO: Add function description 557 558Arguments: 559 560 Record - GC_TODO: add argument description 561 Context - GC_TODO: add argument description 562 563Returns: 564 565 GC_TODO: add return values 566 567--*/ 568; 569 570BOOLEAN 571EFIAPI 572SwCmpContext ( 573 IN QNC_SMM_CONTEXT *Context1, 574 IN QNC_SMM_CONTEXT *Context2 575 ) 576/*++ 577 578Routine Description: 579 580 GC_TODO: Add function description 581 582Arguments: 583 584 Context1 - GC_TODO: add argument description 585 Context2 - GC_TODO: add argument description 586 587Returns: 588 589 GC_TODO: add return values 590 591--*/ 592; 593 594VOID 595SwGetBuffer ( 596 IN DATABASE_RECORD * Record 597 ) 598/*++ 599 600Routine Description: 601 602 GC_TODO: Add function description 603 604Arguments: 605 606 Record - GC_TODO: add argument description 607 608Returns: 609 610 GC_TODO: add return values 611 612--*/ 613; 614 615VOID 616EFIAPI 617SxGetContext ( 618 IN DATABASE_RECORD *Record, 619 OUT QNC_SMM_CONTEXT *Context 620 ) 621/*++ 622 623Routine Description: 624 625 GC_TODO: Add function description 626 627Arguments: 628 629 Record - GC_TODO: add argument description 630 Context - GC_TODO: add argument description 631 632Returns: 633 634 GC_TODO: add return values 635 636--*/ 637; 638 639BOOLEAN 640EFIAPI 641SxCmpContext ( 642 IN QNC_SMM_CONTEXT *Context1, 643 IN QNC_SMM_CONTEXT *Context2 644 ) 645/*++ 646 647Routine Description: 648 649 GC_TODO: Add function description 650 651Arguments: 652 653 Context1 - GC_TODO: add argument description 654 Context2 - GC_TODO: add argument description 655 656Returns: 657 658 GC_TODO: add return values 659 660--*/ 661; 662 663VOID 664EFIAPI 665PeriodicTimerGetContext ( 666 IN DATABASE_RECORD *Record, 667 OUT QNC_SMM_CONTEXT *Context 668 ) 669/*++ 670 671Routine Description: 672 673 GC_TODO: Add function description 674 675Arguments: 676 677 Record - GC_TODO: add argument description 678 Context - GC_TODO: add argument description 679 680Returns: 681 682 GC_TODO: add return values 683 684--*/ 685; 686 687BOOLEAN 688EFIAPI 689PeriodicTimerCmpContext ( 690 IN QNC_SMM_CONTEXT *Context1, 691 IN QNC_SMM_CONTEXT *Context2 692 ) 693/*++ 694 695Routine Description: 696 697 GC_TODO: Add function description 698 699Arguments: 700 701 Context1 - GC_TODO: add argument description 702 Context2 - GC_TODO: add argument description 703 704Returns: 705 706 GC_TODO: add return values 707 708--*/ 709; 710 711VOID 712PeriodicTimerGetBuffer ( 713 IN DATABASE_RECORD * Record 714 ) 715/*++ 716 717Routine Description: 718 719 GC_TODO: Add function description 720 721Arguments: 722 723 Record - GC_TODO: add argument description 724 725Returns: 726 727 GC_TODO: add return values 728 729--*/ 730; 731 732VOID 733EFIAPI 734PowerButtonGetContext ( 735 IN DATABASE_RECORD *Record, 736 OUT QNC_SMM_CONTEXT *Context 737 ) 738/*++ 739 740Routine Description: 741 742 GC_TODO: Add function description 743 744Arguments: 745 746 Record - GC_TODO: add argument description 747 Context - GC_TODO: add argument description 748 749Returns: 750 751 GC_TODO: add return values 752 753--*/ 754; 755 756BOOLEAN 757EFIAPI 758PowerButtonCmpContext ( 759 IN QNC_SMM_CONTEXT *Context1, 760 IN QNC_SMM_CONTEXT *Context2 761 ) 762/*++ 763 764Routine Description: 765 766 GC_TODO: Add function description 767 768Arguments: 769 770 Context1 - GC_TODO: add argument description 771 Context2 - GC_TODO: add argument description 772 773Returns: 774 775 GC_TODO: add return values 776 777--*/ 778; 779 780// 781// ///////////////////////////////////////////////////////////////////////////// 782// 783VOID 784EFIAPI 785QNCSmmPeriodicTimerClearSource ( 786 QNC_SMM_SOURCE_DESC *SrcDesc 787 ) 788/*++ 789 790Routine Description: 791 792 GC_TODO: Add function description 793 794Arguments: 795 796 SrcDesc - GC_TODO: add argument description 797 798Returns: 799 800 GC_TODO: add return values 801 802--*/ 803; 804 805EFI_STATUS 806QNCSmmPeriodicTimerDispatchGetNextShorterInterval ( 807 IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, 808 IN OUT UINT64 **SmiTickInterval 809 ) 810/*++ 811 812Routine Description: 813 814 GC_TODO: Add function description 815 816Arguments: 817 818 This - GC_TODO: add argument description 819 SmiTickInterval - GC_TODO: add argument description 820 821Returns: 822 823 GC_TODO: add return values 824 825--*/ 826; 827 828VOID 829QNCSmmSxGoToSleep ( 830 VOID 831 ) 832/*++ 833 834Routine Description: 835 836 GC_TODO: Add function description 837 838Arguments: 839 840 None 841 842Returns: 843 844 GC_TODO: add return values 845 846--*/ 847; 848 849VOID 850EFIAPI 851QNCSmmQNCnClearSource ( 852 QNC_SMM_SOURCE_DESC *SrcDesc 853 ) 854/*++ 855 856Routine Description: 857 858 GC_TODO: Add function description 859 860Arguments: 861 862 SrcDesc - GC_TODO: add argument description 863 864Returns: 865 866 GC_TODO: add return values 867 868--*/ 869; 870 871#endif 872