REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4091 Fixes spelling errors in the package so the SpellCheck CI plugin can be enabled. Cc: Hao A Wu <hao.a.wu@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Hao A Wu <hao.a.wu@intel.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
		
			
				
	
	
		
			497 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			497 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Command header of for Debug Agent library instance.
 | 
						|
 | 
						|
  Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#ifndef _DEBUG_AGENT_H_
 | 
						|
#define _DEBUG_AGENT_H_
 | 
						|
 | 
						|
#include <Register/LocalApic.h>
 | 
						|
#include <Guid/DebugAgentGuid.h>
 | 
						|
#include <Guid/VectorHandoffTable.h>
 | 
						|
#include <Ppi/VectorHandoffInfo.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/ResetSystemLib.h>
 | 
						|
#include <Library/IoLib.h>
 | 
						|
#include <Library/HobLib.h>
 | 
						|
#include <Library/DebugCommunicationLib.h>
 | 
						|
#include <Library/DebugAgentLib.h>
 | 
						|
#include <Library/PcdLib.h>
 | 
						|
#include <Library/SynchronizationLib.h>
 | 
						|
#include <Library/LocalApicLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/TimerLib.h>
 | 
						|
#include <Library/PrintLib.h>
 | 
						|
#include <Library/PeCoffGetEntryPointLib.h>
 | 
						|
#include <Library/PeCoffExtraActionLib.h>
 | 
						|
#include <Register/ArchitecturalMsr.h>
 | 
						|
 | 
						|
#include <TransferProtocol.h>
 | 
						|
#include <ImageDebugSupport.h>
 | 
						|
 | 
						|
#include "DebugMp.h"
 | 
						|
#include "DebugTimer.h"
 | 
						|
#include "ArchDebugSupport.h"
 | 
						|
#include "DebugException.h"
 | 
						|
 | 
						|
//
 | 
						|
// These macros may be already defined in DebugAgentLib.h
 | 
						|
//
 | 
						|
#define DEBUG_AGENT_INIT_PEI                  9
 | 
						|
#define DEBUG_AGENT_INIT_DXE_LOAD             10
 | 
						|
#define DEBUG_AGENT_INIT_DXE_UNLOAD           11
 | 
						|
#define DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64  12
 | 
						|
 | 
						|
#define DEBUG_INT1_VECTOR     DEBUG_EXCEPT_DEBUG
 | 
						|
#define DEBUG_INT3_VECTOR     DEBUG_EXCEPT_BREAKPOINT
 | 
						|
#define DEBUG_TIMER_VECTOR    32
 | 
						|
#define DEBUG_MAILBOX_VECTOR  33
 | 
						|
 | 
						|
//
 | 
						|
//  Timeout value for reading packet (unit is microsecond)
 | 
						|
//
 | 
						|
#define READ_PACKET_TIMEOUT   (500 * 1000)
 | 
						|
#define DEBUG_TIMER_INTERVAL  (100 * 1000)
 | 
						|
 | 
						|
#define SOFT_INTERRUPT_SIGNATURE  SIGNATURE_32('S','O','F','T')
 | 
						|
#define SYSTEM_RESET_SIGNATURE    SIGNATURE_32('S','Y','S','R')
 | 
						|
#define MEMORY_READY_SIGNATURE    SIGNATURE_32('M','E','M','R')
 | 
						|
 | 
						|
extern UINTN                    Exception0Handle;
 | 
						|
extern UINTN                    TimerInterruptHandle;
 | 
						|
extern UINT32                   ExceptionStubHeaderSize;
 | 
						|
extern BOOLEAN                  mSkipBreakpoint;
 | 
						|
extern EFI_VECTOR_HANDOFF_INFO  mVectorHandoffInfoDebugAgent[];
 | 
						|
extern UINTN                    mVectorHandoffInfoCount;
 | 
						|
 | 
						|
//
 | 
						|
// CPU exception information issued by debug agent
 | 
						|
//
 | 
						|
typedef struct {
 | 
						|
  //
 | 
						|
  // This field is used to save CPU content before executing HOST command
 | 
						|
  //
 | 
						|
  BASE_LIBRARY_JUMP_BUFFER             JumpBuffer;
 | 
						|
  //
 | 
						|
  // This field returns the exception information issued by the HOST command
 | 
						|
  //
 | 
						|
  DEBUG_DATA_RESPONSE_GET_EXCEPTION    ExceptionContent;
 | 
						|
} DEBUG_AGENT_EXCEPTION_BUFFER;
 | 
						|
 | 
						|
#define DEBUG_AGENT_FLAG_HOST_ATTACHED         BIT0
 | 
						|
#define DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS     BIT1
 | 
						|
#define DEBUG_AGENT_FLAG_MEMORY_READY          BIT2
 | 
						|
#define DEBUG_AGENT_FLAG_STEPPING              BIT3
 | 
						|
#define DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB  BIT4
 | 
						|
#define DEBUG_AGENT_FLAG_INIT_ARCH             BIT5|BIT6
 | 
						|
#define DEBUG_AGENT_FLAG_INTERRUPT_FLAG        BIT7
 | 
						|
#define DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI     BIT32
 | 
						|
#define DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL     (BIT33|BIT34|BIT35|BIT36)
 | 
						|
#define DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT     BIT37
 | 
						|
 | 
						|
#define DEBUG_MAILBOX_DEBUG_FLAG_INDEX                1
 | 
						|
#define DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX         2
 | 
						|
#define DEBUG_MAILBOX_EXCEPTION_BUFFER_POINTER_INDEX  3
 | 
						|
#define DEBUG_MAILBOX_LAST_ACK                        4
 | 
						|
#define DEBUG_MAILBOX_SEQUENCE_NO_INDEX               5
 | 
						|
#define DEBUG_MAILBOX_HOST_SEQUENCE_NO_INDEX          6
 | 
						|
#define DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY           7
 | 
						|
 | 
						|
#pragma pack(1)
 | 
						|
typedef union {
 | 
						|
  struct {
 | 
						|
    //
 | 
						|
    // Lower 32 bits to store the status of DebugAgent
 | 
						|
    //
 | 
						|
    UINT32    HostAttached      : 1; // 1: HOST is attached
 | 
						|
    UINT32    AgentInProgress   : 1; // 1: Debug Agent is communicating with HOST
 | 
						|
    UINT32    MemoryReady       : 1; // 1: Memory is ready
 | 
						|
    UINT32    SteppingFlag      : 1; // 1: Agent is running stepping command
 | 
						|
    UINT32    CheckMailboxInHob : 1; // 1: Need to check mailbox saved in HOB
 | 
						|
    UINT32    InitArch          : 2; // value of DEBUG_DATA_RESPONSE_ARCH_MODE
 | 
						|
    UINT32    InterruptFlag     : 1; // 1: EFLAGS.IF is set
 | 
						|
    UINT32    Reserved1         : 24;
 | 
						|
    //
 | 
						|
    // Higher 32bits to control the behavior of DebugAgent
 | 
						|
    //
 | 
						|
    UINT32    BreakOnNextSmi    : 1; // 1: Break on next SMI
 | 
						|
    UINT32    PrintErrorLevel   : 4; // Bitmask of print error level for debug message
 | 
						|
    UINT32    BreakOnBootScript : 1; // 1: Break before executing boot script
 | 
						|
    UINT32    Reserved2         : 26;
 | 
						|
  } Bits;
 | 
						|
  UINT64    Uint64;
 | 
						|
} DEBUG_AGENT_FLAG;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  DEBUG_AGENT_FLAG    DebugFlag;
 | 
						|
  UINT64              DebugPortHandle;
 | 
						|
  //
 | 
						|
  // Pointer to DEBUG_AGENT_EXCEPTION_BUFFER
 | 
						|
  //
 | 
						|
  UINT64              ExceptionBufferPointer;
 | 
						|
  UINT8               LastAck;             // The last ack packet type
 | 
						|
  UINT8               SequenceNo;
 | 
						|
  UINT8               HostSequenceNo;
 | 
						|
  UINT32              DebugTimerFrequency;
 | 
						|
  UINT8               CheckSum;            // Mailbox checksum
 | 
						|
  UINT8               ToBeCheckSum;        // To be Mailbox checksum at the next
 | 
						|
} DEBUG_AGENT_MAILBOX;
 | 
						|
#pragma pack()
 | 
						|
 | 
						|
///
 | 
						|
/// Byte packed structure for an IA-32 Interrupt Gate Descriptor.
 | 
						|
///
 | 
						|
typedef union {
 | 
						|
  struct {
 | 
						|
    UINT32    OffsetLow  : 16; ///< Offset bits 15..0.
 | 
						|
    UINT32    Selector   : 16; ///< Selector.
 | 
						|
    UINT32    Reserved_0 : 8;  ///< Reserved.
 | 
						|
    UINT32    GateType   : 8;  ///< Gate Type.  See #defines above.
 | 
						|
    UINT32    OffsetHigh : 16; ///< Offset bits 31..16.
 | 
						|
  } Bits;
 | 
						|
  UINT64    Uint64;
 | 
						|
} IA32_IDT_ENTRY;
 | 
						|
 | 
						|
typedef union {
 | 
						|
  struct {
 | 
						|
    UINT32    LimitLow    : 16;
 | 
						|
    UINT32    BaseLow     : 16;
 | 
						|
    UINT32    BaseMid     : 8;
 | 
						|
    UINT32    Type        : 4;
 | 
						|
    UINT32    System      : 1;
 | 
						|
    UINT32    Dpl         : 2;
 | 
						|
    UINT32    Present     : 1;
 | 
						|
    UINT32    LimitHigh   : 4;
 | 
						|
    UINT32    Software    : 1;
 | 
						|
    UINT32    Reserved    : 1;
 | 
						|
    UINT32    DefaultSize : 1;
 | 
						|
    UINT32    Granularity : 1;
 | 
						|
    UINT32    BaseHigh    : 8;
 | 
						|
  } Bits;
 | 
						|
  UINT64    Uint64;
 | 
						|
} IA32_GDT;
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize IDT entries to support source level debug.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
InitializeDebugIdt (
 | 
						|
  VOID
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Read register value from saved CPU context.
 | 
						|
 | 
						|
  @param[in] CpuContext         Pointer to saved CPU context.
 | 
						|
  @param[in] Index              Register index value.
 | 
						|
  @param[in] Width              Data width to read.
 | 
						|
 | 
						|
  @return The address of register value.
 | 
						|
 | 
						|
**/
 | 
						|
UINT8 *
 | 
						|
ArchReadRegisterBuffer (
 | 
						|
  IN DEBUG_CPU_CONTEXT  *CpuContext,
 | 
						|
  IN UINT8              Index,
 | 
						|
  IN UINT8              *Width
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Send packet with response data to HOST.
 | 
						|
 | 
						|
  @param[in]      Data        Pointer to response data buffer.
 | 
						|
  @param[in]      DataSize    Size of response data in byte.
 | 
						|
  @param[in, out] DebugHeader Pointer to a buffer for creating response packet and receiving ACK packet,
 | 
						|
                              to minimize the stack usage.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS      Response data was sent successfully.
 | 
						|
  @retval RETURN_DEVICE_ERROR Cannot receive DEBUG_COMMAND_OK from HOST.
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
SendDataResponsePacket (
 | 
						|
  IN UINT8                    *Data,
 | 
						|
  IN UINT16                   DataSize,
 | 
						|
  IN OUT DEBUG_PACKET_HEADER  *DebugHeader
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Check if HOST is attached based on Mailbox.
 | 
						|
 | 
						|
  @retval TRUE        HOST is attached.
 | 
						|
  @retval FALSE       HOST is not attached.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsHostAttached (
 | 
						|
  VOID
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Get Debug Agent Mailbox pointer.
 | 
						|
 | 
						|
  @return Mailbox pointer.
 | 
						|
 | 
						|
**/
 | 
						|
DEBUG_AGENT_MAILBOX *
 | 
						|
GetMailboxPointer (
 | 
						|
  VOID
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Get debug port handle.
 | 
						|
 | 
						|
  @return Debug port handle.
 | 
						|
 | 
						|
**/
 | 
						|
DEBUG_PORT_HANDLE
 | 
						|
GetDebugPortHandle (
 | 
						|
  VOID
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Read the Attach/Break-in symbols from the debug port.
 | 
						|
 | 
						|
  @param[in]  Handle         Pointer to Debug Port handle.
 | 
						|
  @param[out] BreakSymbol    Returned break symbol.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        Read the symbol in BreakSymbol.
 | 
						|
  @retval EFI_NOT_FOUND      No read the break symbol.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DebugReadBreakSymbol (
 | 
						|
  IN  DEBUG_PORT_HANDLE  Handle,
 | 
						|
  OUT UINT8              *BreakSymbol
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Prints a debug message to the debug port if the specified error level is enabled.
 | 
						|
 | 
						|
  If any bit in ErrorLevel is also set in Mainbox, then print the message specified
 | 
						|
  by Format and the associated variable argument list to the debug port.
 | 
						|
 | 
						|
  @param[in] ErrorLevel  The error level of the debug message.
 | 
						|
  @param[in] Format      Format string for the debug message to print.
 | 
						|
  @param[in] ...         Variable argument list whose contents are accessed
 | 
						|
                         based on the format string specified by Format.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
DebugAgentMsgPrint (
 | 
						|
  IN UINT8  ErrorLevel,
 | 
						|
  IN CHAR8  *Format,
 | 
						|
  ...
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Trigger one software interrupt to debug agent to handle it.
 | 
						|
 | 
						|
  @param[in] Signature       Software interrupt signature.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TriggerSoftInterrupt (
 | 
						|
  IN UINT32  Signature
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Check if debug agent support multi-processor.
 | 
						|
 | 
						|
  @retval TRUE    Multi-processor is supported.
 | 
						|
  @retval FALSE   Multi-processor is not supported.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
MultiProcessorDebugSupport (
 | 
						|
  VOID
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Find and report module image info to HOST.
 | 
						|
 | 
						|
  @param[in] AlignSize      Image aligned size.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
FindAndReportModuleImageInfo (
 | 
						|
  IN UINTN  AlignSize
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Read IDT entry to check if IDT entries are setup by Debug Agent.
 | 
						|
 | 
						|
  @retval  TRUE     IDT entries were setup by Debug Agent.
 | 
						|
  @retval  FALSE    IDT entries were not setup by Debug Agent.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsDebugAgentInitialzed (
 | 
						|
  VOID
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Calculate Mailbox checksum and update the checksum field.
 | 
						|
 | 
						|
  @param[in]  Mailbox  Debug Agent Mailbox pointer.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UpdateMailboxChecksum (
 | 
						|
  IN DEBUG_AGENT_MAILBOX  *Mailbox
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Verify Mailbox checksum.
 | 
						|
 | 
						|
  If checksum error, print debug message and run init dead loop.
 | 
						|
 | 
						|
  @param[in]  Mailbox  Debug Agent Mailbox pointer.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
VerifyMailboxChecksum (
 | 
						|
  IN DEBUG_AGENT_MAILBOX  *Mailbox
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Set debug flag in mailbox.
 | 
						|
 | 
						|
  @param[in]  FlagMask      Debug flag mask value.
 | 
						|
  @param[in]  FlagValue     Debug flag value.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SetDebugFlag (
 | 
						|
  IN UINT64  FlagMask,
 | 
						|
  IN UINT32  FlagValue
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Get debug flag in mailbox.
 | 
						|
 | 
						|
  @param[in]  FlagMask      Debug flag mask value.
 | 
						|
 | 
						|
  @return Debug flag value.
 | 
						|
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
GetDebugFlag (
 | 
						|
  IN UINT64  FlagMask
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Update Mailbox content by index.
 | 
						|
 | 
						|
  @param[in]  Mailbox  Debug Agent Mailbox pointer.
 | 
						|
  @param[in]  Index    Mailbox content index.
 | 
						|
  @param[in]  Value    Value to be set into mail box.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
UpdateMailboxContent (
 | 
						|
  IN DEBUG_AGENT_MAILBOX  *Mailbox,
 | 
						|
  IN UINTN                Index,
 | 
						|
  IN UINT64               Value
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve exception handler from IDT table by ExceptionNum.
 | 
						|
 | 
						|
  @param[in]  ExceptionNum    Exception number
 | 
						|
 | 
						|
  @return Exception handler
 | 
						|
 | 
						|
**/
 | 
						|
VOID *
 | 
						|
GetExceptionHandlerInIdtEntry (
 | 
						|
  IN UINTN  ExceptionNum
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Set exception handler in IDT table by ExceptionNum.
 | 
						|
 | 
						|
  @param[in]  ExceptionNum      Exception number
 | 
						|
  @param[in]  ExceptionHandler  Exception Handler to be set
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SetExceptionHandlerInIdtEntry (
 | 
						|
  IN UINTN  ExceptionNum,
 | 
						|
  IN VOID   *ExceptionHandler
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Prints a debug message to the debug output device if the specified error level is enabled.
 | 
						|
 | 
						|
  If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
 | 
						|
  GetDebugPrintErrorLevel (), then print the message specified by Format and the
 | 
						|
  associated variable argument list to the debug output device.
 | 
						|
 | 
						|
  If Format is NULL, then ASSERT().
 | 
						|
 | 
						|
  @param[in] ErrorLevel  The error level of the debug message.
 | 
						|
  @param[in] IsSend      Flag of debug message to declare that the data is being sent or being received.
 | 
						|
  @param[in] Data        Variable argument list whose contents are accessed
 | 
						|
  @param[in] Length      based on the format string specified by Format.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
DebugAgentDataMsgPrint (
 | 
						|
  IN UINT8    ErrorLevel,
 | 
						|
  IN BOOLEAN  IsSend,
 | 
						|
  IN UINT8    *Data,
 | 
						|
  IN UINT8    Length
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Read remaining debug packet except for the start symbol
 | 
						|
 | 
						|
  @param[in]      Handle        Pointer to Debug Port handle.
 | 
						|
  @param[in, out] DebugHeader   Debug header buffer including start symbol.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        Read the symbol in BreakSymbol.
 | 
						|
  @retval EFI_CRC_ERROR      CRC check fail.
 | 
						|
  @retval EFI_TIMEOUT        Timeout occurs when reading debug packet.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadRemainingBreakPacket (
 | 
						|
  IN     DEBUG_PORT_HANDLE    Handle,
 | 
						|
  IN OUT DEBUG_PACKET_HEADER  *DebugHeader
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Read data from debug channel and save the data in buffer.
 | 
						|
 | 
						|
  Reads NumberOfBytes data bytes from a debug device into the buffer
 | 
						|
  specified by Buffer. The number of bytes actually read is returned.
 | 
						|
  If the return value is less than NumberOfBytes, then the rest operation failed.
 | 
						|
  If NumberOfBytes is zero, then return 0.
 | 
						|
 | 
						|
  @param  Handle           Debug port handle.
 | 
						|
  @param  Buffer           Pointer to the data buffer to store the data read from the debug device.
 | 
						|
  @param  NumberOfBytes    Number of bytes which will be read.
 | 
						|
  @param  Timeout          Timeout value for reading from debug device. It unit is Microsecond.
 | 
						|
 | 
						|
  @retval 0                Read data failed, no data is to be read.
 | 
						|
  @retval >0               Actual number of bytes read from debug device.
 | 
						|
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
DebugAgentReadBuffer (
 | 
						|
  IN     DEBUG_PORT_HANDLE  Handle,
 | 
						|
  IN OUT UINT8              *Buffer,
 | 
						|
  IN     UINTN              NumberOfBytes,
 | 
						|
  IN     UINTN              Timeout
 | 
						|
  );
 | 
						|
 | 
						|
#endif
 |