]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c
This revision can only work with Intel(c) UDK Debugger Tool version 1.3 or greater...
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugAgent / SmmDebugAgent / SmmDebugAgentLib.c
1 /** @file
2 Debug Agent library implementition.
3
4 Copyright (c) 2010 - 2013, 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
17 DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL;
18 DEBUG_AGENT_MAILBOX mLocalMailbox;
19 UINTN mSavedDebugRegisters[6];
20 IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33];
21 BOOLEAN mSkipBreakpoint = FALSE;
22
23 CHAR8 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 **/
32 BOOLEAN
33 MultiProcessorDebugSupport (
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 **/
50 EFI_STATUS
51 DebugReadBreakSymbol (
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 **/
68 DEBUG_AGENT_MAILBOX *
69 GetMailboxFromHob (
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 **/
94 DEBUG_AGENT_MAILBOX *
95 GetMailboxPointer (
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 **/
109 DEBUG_PORT_HANDLE
110 GetDebugPortHandle (
111 VOID
112 )
113 {
114 return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer()->DebugPortHandle);
115 }
116
117 /**
118 Store debug register when SMI exit.
119
120 **/
121 VOID
122 SaveDebugRegister (
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 **/
138 VOID
139 RestoreDebugRegister (
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 **/
174 VOID
175 EFIAPI
176 InitializeDebugAgent (
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
193 switch (InitFlag) {
194 case DEBUG_AGENT_INIT_SMM:
195 //
196 // Check if Debug Agent initialized in DXE phase
197 //
198 Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox);
199 if (Status == EFI_SUCCESS && Mailbox != NULL) {
200 VerifyMailboxChecksum (Mailbox);
201 mMailboxPointer = Mailbox;
202 break;
203 }
204 //
205 // Check if Debug Agent initialized in SEC/PEI phase
206 //
207 Mailbox = GetMailboxFromHob ();
208 if (Mailbox != NULL) {
209 mMailboxPointer = Mailbox;
210 break;
211 }
212 //
213 // Debug Agent was not initialized before, uset the local mailbox.
214 //
215 ZeroMem (&mLocalMailbox, sizeof (DEBUG_AGENT_MAILBOX));
216 Mailbox = &mLocalMailbox;
217 //
218 // Save original IDT entries
219 //
220 AsmReadIdtr (&IdtDescriptor);
221 CopyMem (&IdtEntry, (VOID *)IdtDescriptor.Base, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR));
222 //
223 // Initialized Debug Agent
224 //
225 InitializeDebugIdt ();
226 DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, NULL);
227 UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
228 mMailboxPointer = Mailbox;
229 //
230 // Trigger one software interrupt to inform HOST
231 //
232 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
233
234 SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
235 //
236 // Memory has been ready
237 //
238 if (IsHostAttached ()) {
239 //
240 // Trigger one software interrupt to inform HOST
241 //
242 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
243 }
244 //
245 // Find and report PE/COFF image info to HOST
246 //
247 FindAndReportModuleImageInfo (SIZE_4KB);
248 //
249 // Restore saved IDT entries
250 //
251 CopyMem ((VOID *)IdtDescriptor.Base, &IdtEntry, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR));
252
253 break;
254
255 case DEBUG_AGENT_INIT_ENTER_SMI:
256 SaveDebugRegister ();
257 InitializeDebugIdt ();
258
259 Mailbox = GetMailboxPointer ();
260 if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) {
261 //
262 // If Debug Agent has been communicaton state with HOST, we need skip
263 // any break points set in SMM, set Skip Breakpoint flag
264 //
265 mSkipBreakpoint = TRUE;
266 }
267 if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI) == 1) {
268 if (mSkipBreakpoint) {
269 //
270 // Print warning message if ignore smm entry break
271 //
272 DebugPortWriteBuffer ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle,
273 (UINT8 *)mWarningMsgIgnoreSmmEntryBreak,
274 AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak)
275 );
276 } else {
277 //
278 // If SMM entry break is set, SMM code will be break at here.
279 //
280 CpuBreakpoint ();
281 }
282 }
283 break;
284
285 case DEBUG_AGENT_INIT_EXIT_SMI:
286 Mailbox = GetMailboxPointer ();
287 //
288 // Clear Skip Breakpoint flag
289 //
290 mSkipBreakpoint = FALSE;
291 RestoreDebugRegister ();
292 break;
293
294 case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
295 if (Context == NULL) {
296 DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
297 CpuDeadLoop ();
298 } else {
299 Ia32Idtr = (IA32_DESCRIPTOR *) Context;
300 Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
301 MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
302 (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
303 mMailboxPointer = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
304 VerifyMailboxChecksum (mMailboxPointer);
305 //
306 // Get original IDT address and size.
307 //
308 AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);
309 IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
310 if (IdtEntryCount < 33) {
311 Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
312 Idtr.Base = (UINTN) &mIdtEntryTable;
313 ZeroMem (&mIdtEntryTable, Idtr.Limit + 1);
314 AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr);
315 }
316
317 InitializeDebugIdt ();
318 //
319 // Initialize Debug Timer hardware and enable interrupt.
320 //
321 InitializeDebugTimer ();
322 EnableInterrupts ();
323
324 FindAndReportModuleImageInfo (SIZE_4KB);
325 }
326 break;
327
328 default:
329 //
330 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
331 // Debug Agent library instance.
332 //
333 DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
334 CpuDeadLoop ();
335 break;
336 }
337 }
338