SmmDebugAgentLib.c revision edbb27132d4737be1fa54ea9f6e7657daa2bb72a
1/** @file 2 Debug Agent library implementition. 3 4 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php. 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13**/ 14 15#include "SmmDebugAgentLib.h" 16 17DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL; 18DEBUG_AGENT_MAILBOX mLocalMailbox; 19UINTN mSavedDebugRegisters[6]; 20IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33]; 21BOOLEAN mSkipBreakpoint = FALSE; 22 23CHAR8 mWarningMsgIgnoreSmmEntryBreak[] = "Ignore smmentrybreak setting for SMI issued during DXE debugging!\r\n"; 24 25/** 26 Check if debug agent support multi-processor. 27 28 @retval TRUE Multi-processor is supported. 29 @retval FALSE Multi-processor is not supported. 30 31**/ 32BOOLEAN 33MultiProcessorDebugSupport ( 34 VOID 35 ) 36{ 37 return FALSE; 38} 39 40/** 41 Read the Attach/Break-in symbols from the debug port. 42 43 @param[in] Handle Pointer to Debug Port handle. 44 @param[out] BreakSymbol Returned break symbol. 45 46 @retval EFI_SUCCESS Read the symbol in BreakSymbol. 47 @retval EFI_NOT_FOUND No read the break symbol. 48 49**/ 50EFI_STATUS 51DebugReadBreakSymbol ( 52 IN DEBUG_PORT_HANDLE Handle, 53 OUT UINT8 *BreakSymbol 54 ) 55{ 56 // 57 // Smm instance has no debug timer to poll break symbol. 58 // 59 return EFI_NOT_FOUND; 60} 61 62/** 63 Get the pointer to Mailbox from the GUIDed HOB. 64 65 @return Pointer to Mailbox. 66 67**/ 68DEBUG_AGENT_MAILBOX * 69GetMailboxFromHob ( 70 VOID 71 ) 72{ 73 EFI_HOB_GUID_TYPE *GuidHob; 74 UINT64 *MailboxLocation; 75 DEBUG_AGENT_MAILBOX *Mailbox; 76 77 GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid); 78 if (GuidHob == NULL) { 79 return NULL; 80 } 81 MailboxLocation = (UINT64 *) (GET_GUID_HOB_DATA(GuidHob)); 82 Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); 83 VerifyMailboxChecksum (Mailbox); 84 85 return Mailbox; 86} 87 88/** 89 Get Debug Agent Mailbox pointer. 90 91 @return Mailbox pointer. 92 93**/ 94DEBUG_AGENT_MAILBOX * 95GetMailboxPointer ( 96 VOID 97 ) 98{ 99 VerifyMailboxChecksum (mMailboxPointer); 100 return mMailboxPointer; 101} 102 103/** 104 Get debug port handle. 105 106 @return Debug port handle. 107 108**/ 109DEBUG_PORT_HANDLE 110GetDebugPortHandle ( 111 VOID 112 ) 113{ 114 return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer()->DebugPortHandle); 115} 116 117/** 118 Store debug register when SMI exit. 119 120**/ 121VOID 122SaveDebugRegister ( 123 VOID 124 ) 125{ 126 mSavedDebugRegisters[0] = AsmReadDr0 (); 127 mSavedDebugRegisters[1] = AsmReadDr1 (); 128 mSavedDebugRegisters[2] = AsmReadDr2 (); 129 mSavedDebugRegisters[3] = AsmReadDr3 (); 130 mSavedDebugRegisters[4] = AsmReadDr6 (); 131 mSavedDebugRegisters[5] = AsmReadDr7 (); 132} 133 134/** 135 Restore debug register when SMI exit. 136 137**/ 138VOID 139RestoreDebugRegister ( 140 VOID 141 ) 142{ 143 AsmWriteDr7 (0); 144 AsmWriteDr0 (mSavedDebugRegisters[0]); 145 AsmWriteDr1 (mSavedDebugRegisters[1]); 146 AsmWriteDr2 (mSavedDebugRegisters[2]); 147 AsmWriteDr3 (mSavedDebugRegisters[3]); 148 AsmWriteDr6 (mSavedDebugRegisters[4]); 149 AsmWriteDr7 (mSavedDebugRegisters[5]); 150} 151 152/** 153 Initialize debug agent. 154 155 This function is used to set up debug enviroment for source level debug 156 in SMM code. 157 158 If InitFlag is DEBUG_AGENT_INIT_SMM, it will overirde IDT table entries 159 and initialize debug port. It will get debug agent Mailbox from GUIDed HOB, 160 it it exists, debug agent wiil copied it into the local Mailbox in SMM space. 161 it will overirde IDT table entries and initialize debug port. Context will be 162 NULL. 163 If InitFlag is DEBUG_AGENT_INIT_ENTER_SMI, debug agent will save Debug 164 Registers and get local Mailbox in SMM space. Context will be NULL. 165 If InitFlag is DEBUG_AGENT_INIT_EXIT_SMI, debug agent will restore Debug 166 Registers. Context will be NULL. 167 168 @param[in] InitFlag Init flag is used to decide initialize process. 169 @param[in] Context Context needed according to InitFlag. 170 @param[in] Function Continue function called by debug agent library; it was 171 optional. 172 173**/ 174VOID 175EFIAPI 176InitializeDebugAgent ( 177 IN UINT32 InitFlag, 178 IN VOID *Context, OPTIONAL 179 IN DEBUG_AGENT_CONTINUE Function OPTIONAL 180 ) 181{ 182 EFI_STATUS Status; 183 UINT64 DebugPortHandle; 184 IA32_IDT_GATE_DESCRIPTOR IdtEntry[33]; 185 IA32_DESCRIPTOR IdtDescriptor; 186 IA32_DESCRIPTOR *Ia32Idtr; 187 IA32_IDT_ENTRY *Ia32IdtEntry; 188 IA32_DESCRIPTOR Idtr; 189 UINT16 IdtEntryCount; 190 DEBUG_AGENT_MAILBOX *Mailbox; 191 UINT64 *MailboxLocation; 192 UINT32 DebugTimerFrequency; 193 BOOLEAN PeriodicMode; 194 UINTN TimerCycle; 195 196 switch (InitFlag) { 197 case DEBUG_AGENT_INIT_SMM: 198 // 199 // Install configuration table for persisted vector handoff info 200 // 201 Status = gSmst->SmmInstallConfigurationTable ( 202 gSmst, 203 &gEfiVectorHandoffTableGuid, 204 (VOID *) &mVectorHandoffInfoDebugAgent[0], 205 sizeof (EFI_VECTOR_HANDOFF_INFO) * mVectorHandoffInfoCount 206 ); 207 if (EFI_ERROR (Status)) { 208 DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n")); 209 CpuDeadLoop (); 210 } 211 // 212 // Check if Debug Agent initialized in DXE phase 213 // 214 Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox); 215 if (Status == EFI_SUCCESS && Mailbox != NULL) { 216 VerifyMailboxChecksum (Mailbox); 217 mMailboxPointer = Mailbox; 218 break; 219 } 220 // 221 // Check if Debug Agent initialized in SEC/PEI phase 222 // 223 Mailbox = GetMailboxFromHob (); 224 if (Mailbox != NULL) { 225 mMailboxPointer = Mailbox; 226 break; 227 } 228 // 229 // Debug Agent was not initialized before, use the local mailbox. 230 // 231 ZeroMem (&mLocalMailbox, sizeof (DEBUG_AGENT_MAILBOX)); 232 Mailbox = &mLocalMailbox; 233 // 234 // Save original IDT entries 235 // 236 AsmReadIdtr (&IdtDescriptor); 237 CopyMem (&IdtEntry, (VOID *)IdtDescriptor.Base, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR)); 238 // 239 // Initialized Debug Agent 240 // 241 InitializeDebugIdt (); 242 // 243 // Initialize Debug Timer hardware and save its frequency 244 // 245 InitializeDebugTimer (&DebugTimerFrequency); 246 UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); 247 248 DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, NULL); 249 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); 250 mMailboxPointer = Mailbox; 251 // 252 // Trigger one software interrupt to inform HOST 253 // 254 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE); 255 256 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1); 257 // 258 // Memory has been ready 259 // 260 if (IsHostAttached ()) { 261 // 262 // Trigger one software interrupt to inform HOST 263 // 264 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); 265 } 266 // 267 // Find and report PE/COFF image info to HOST 268 // 269 FindAndReportModuleImageInfo (SIZE_4KB); 270 // 271 // Restore saved IDT entries 272 // 273 CopyMem ((VOID *)IdtDescriptor.Base, &IdtEntry, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR)); 274 275 break; 276 277 case DEBUG_AGENT_INIT_ENTER_SMI: 278 SaveDebugRegister (); 279 InitializeDebugIdt (); 280 // 281 // Check if CPU APIC Timer is working, otherwise initialize it. 282 // 283 GetApicTimerState (NULL, &PeriodicMode, NULL); 284 TimerCycle = GetApicTimerInitCount (); 285 if (PeriodicMode != TRUE || TimerCycle == 0) { 286 InitializeDebugTimer (NULL); 287 DisableApicTimerInterrupt (); 288 } 289 Mailbox = GetMailboxPointer (); 290 if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) { 291 // 292 // If Debug Agent has been communicaton state with HOST, we need skip 293 // any break points set in SMM, set Skip Breakpoint flag 294 // 295 mSkipBreakpoint = TRUE; 296 } 297 if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI) == 1) { 298 if (mSkipBreakpoint) { 299 // 300 // Print warning message if ignore smm entry break 301 // 302 DebugPortWriteBuffer ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, 303 (UINT8 *)mWarningMsgIgnoreSmmEntryBreak, 304 AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak) 305 ); 306 } else { 307 // 308 // If SMM entry break is set, SMM code will be break at here. 309 // 310 CpuBreakpoint (); 311 } 312 } 313 break; 314 315 case DEBUG_AGENT_INIT_EXIT_SMI: 316 Mailbox = GetMailboxPointer (); 317 // 318 // Clear Skip Breakpoint flag 319 // 320 mSkipBreakpoint = FALSE; 321 RestoreDebugRegister (); 322 break; 323 324 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64: 325 if (Context == NULL) { 326 DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n")); 327 CpuDeadLoop (); 328 } else { 329 Ia32Idtr = (IA32_DESCRIPTOR *) Context; 330 Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base); 331 MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + 332 (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16)); 333 mMailboxPointer = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); 334 VerifyMailboxChecksum (mMailboxPointer); 335 // 336 // Get original IDT address and size. 337 // 338 AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr); 339 IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)); 340 if (IdtEntryCount < 33) { 341 Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1); 342 Idtr.Base = (UINTN) &mIdtEntryTable; 343 ZeroMem (&mIdtEntryTable, Idtr.Limit + 1); 344 AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr); 345 } 346 347 InitializeDebugIdt (); 348 // 349 // Initialize Debug Timer hardware and save its frequency 350 // 351 InitializeDebugTimer (&DebugTimerFrequency); 352 UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); 353 EnableInterrupts (); 354 355 FindAndReportModuleImageInfo (SIZE_4KB); 356 } 357 break; 358 359 default: 360 // 361 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this 362 // Debug Agent library instance. 363 // 364 DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); 365 CpuDeadLoop (); 366 break; 367 } 368} 369 370