]> git.proxmox.com Git - mirror_edk2.git/blame - SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c
This revision can only work with Intel(c) UDK Debugger Tool version 1.2 or greater...
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugAgent / SecPeiDebugAgent / SecPeiDebugAgentLib.c
CommitLineData
18b144ea 1/** @file\r
2 SEC Core Debug Agent Library instance implementition.\r
3\r
93c0bdec 4 Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>\r
18b144ea 5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php.\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "SecPeiDebugAgentLib.h"\r
16\r
17CONST BOOLEAN MultiProcessorDebugSupport = FALSE;\r
18\r
93c0bdec 19/**\r
20 Read the Attach/Break-in symbols from the debug port.\r
21\r
22 @param[in] Handle Pointer to Debug Port handle.\r
23 @param[out] BreakSymbol Returned break symbol.\r
24\r
25 @retval EFI_SUCCESS Read the symbol in BreakSymbol.\r
26 @retval EFI_NOT_FOUND No read the break symbol.\r
27\r
28**/\r
29EFI_STATUS\r
30DebugReadBreakSymbol (\r
31 IN DEBUG_PORT_HANDLE Handle,\r
32 OUT UINT8 *BreakSymbol\r
33 )\r
34{\r
35 *BreakSymbol = 0;\r
36 //\r
37 // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer emty.\r
38 //\r
39 while (DebugPortPollBuffer (Handle)) {\r
40 DebugPortReadBuffer (Handle, BreakSymbol, 1, 0);\r
41 if (*BreakSymbol == DEBUG_STARTING_SYMBOL_ATTACH || *BreakSymbol == DEBUG_STARTING_SYMBOL_BREAK) {\r
42 return EFI_SUCCESS;\r
43 }\r
44 }\r
45 \r
46 return EFI_NOT_FOUND;\r
47}\r
48\r
18b144ea 49/**\r
50 Get pointer to Mailbox from IDT entry before memory is ready.\r
51\r
52**/\r
53VOID *\r
54GetMailboxPointerInIdtEntry (\r
55 VOID\r
56 )\r
57{\r
58 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;\r
59 IA32_DESCRIPTOR IdtDescriptor;\r
60 UINTN Mailbox;\r
61\r
62 AsmReadIdtr (&IdtDescriptor);\r
63 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;\r
64\r
65 Mailbox = IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + (IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16);\r
66 return (VOID *) Mailbox;\r
67}\r
68\r
69/**\r
70 Set the pointer of Mailbox into IDT entry before memory is ready.\r
71\r
72 @param[in] Mailbox The pointer of Mailbox.\r
73\r
74**/\r
75VOID\r
76SetMailboxPointerInIdtEntry (\r
77 IN VOID *Mailbox\r
78 )\r
79{\r
80 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;\r
81 IA32_DESCRIPTOR IdtDescriptor;\r
82\r
83 AsmReadIdtr (&IdtDescriptor);\r
84 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;\r
85\r
86 IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)Mailbox;\r
87 IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)Mailbox >> 16);\r
88}\r
89\r
90/**\r
91 Get the pointer to Mailbox from IDT entry and build the Mailbox into GUIDed Hob\r
92 after memory is ready.\r
93\r
94 @return Pointer to Mailbox.\r
95\r
96**/\r
97DEBUG_AGENT_MAILBOX *\r
98BuildMailboxHob (\r
99 VOID\r
100 )\r
101{\r
102 DEBUG_AGENT_MAILBOX *Mailbox;\r
103\r
104 Mailbox = (DEBUG_AGENT_MAILBOX *) GetMailboxPointerInIdtEntry ();\r
105\r
106 return BuildGuidDataHob (\r
107 &gEfiDebugAgentGuid,\r
108 Mailbox,\r
109 sizeof (DEBUG_AGENT_MAILBOX)\r
110 );\r
111}\r
112\r
113/**\r
114 Get Debug Agent Mailbox pointer.\r
115\r
116 @return Mailbox pointer.\r
117\r
118**/\r
119DEBUG_AGENT_MAILBOX *\r
120GetMailboxPointer (\r
121 VOID\r
122 )\r
123{\r
124 return (DEBUG_AGENT_MAILBOX *) GetMailboxPointerInIdtEntry ();\r
125}\r
126\r
127/**\r
128 Get debug port handle.\r
129\r
130 @return Debug port handle.\r
131\r
132**/\r
133DEBUG_PORT_HANDLE\r
134GetDebugPortHandle (\r
135 VOID\r
136 )\r
137{\r
138 DEBUG_AGENT_MAILBOX *DebugAgentMailbox;\r
139 \r
140 DebugAgentMailbox = (DEBUG_AGENT_MAILBOX *)GetMailboxPointerInIdtEntry ();\r
141\r
142 return (DEBUG_PORT_HANDLE) (UINTN)(DebugAgentMailbox->DebugPortHandle);\r
143}\r
144\r
145/**\r
146 Trigger one software interrupt to debug agent to handle it.\r
147\r
148 @param Signature Software interrupt signature.\r
149\r
150**/\r
151VOID\r
152TriggerSoftInterrupt (\r
153 UINT32 Signature\r
154 )\r
155{\r
156 UINTN Dr0;\r
157 UINTN Dr1;\r
158\r
159 //\r
160 // Save Debug Register State\r
161 //\r
162 Dr0 = AsmReadDr0 ();\r
163 Dr1 = AsmReadDr1 ();\r
164\r
165 //\r
166 // DR0 = Signature\r
167 //\r
168 AsmWriteDr0 (SOFT_INTERRUPT_SIGNATURE);\r
169 AsmWriteDr1 (Signature);\r
170\r
171 //\r
172 // Do INT3 to communicate with HOST side\r
173 //\r
174 CpuBreakpoint ();\r
175\r
176 //\r
177 // Restore Debug Register State only when Host didn't change it inside exception handler.\r
178 // Dr registers can only be changed by setting the HW breakpoint.\r
179 //\r
180 AsmWriteDr0 (Dr0);\r
181 AsmWriteDr1 (Dr1);\r
182\r
183}\r
184\r
185/**\r
186 Initialize debug agent.\r
187\r
188 This function is used to set up debug environment for SEC and PEI phase.\r
189\r
190 If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries\r
191 and initialize debug port. It will enable interrupt to support break-in feature.\r
192 It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before\r
193 physical memory is ready.\r
194 If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed\r
195 HOB to copy debug agent Mailbox. It will be called after physical memory is ready.\r
196\r
197 This function is used to set up debug environment to support source level debugging.\r
198 If certain Debug Agent Library instance has to save some private data in the stack,\r
199 this function must work on the mode that doesn't return to the caller, then\r
200 the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one\r
201 function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is\r
202 responsible to invoke the passing-in function at the end of InitializeDebugAgent().\r
203\r
204 If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by\r
205 passing in the Context to be its parameter.\r
206\r
207 If Function() is NULL, Debug Agent Library instance will return after setup debug\r
208 environment.\r
209\r
210 @param[in] InitFlag Init flag is used to decide the initialize process.\r
211 @param[in] Context Context needed according to InitFlag; it was optional.\r
212 @param[in] Function Continue function called by debug agent library; it was\r
213 optional.\r
214\r
215**/\r
216VOID\r
217EFIAPI\r
218InitializeDebugAgent (\r
219 IN UINT32 InitFlag,\r
220 IN VOID *Context, OPTIONAL\r
221 IN DEBUG_AGENT_CONTINUE Function OPTIONAL\r
222 )\r
223{\r
224 DEBUG_AGENT_MAILBOX *Mailbox;\r
225 DEBUG_AGENT_MAILBOX MailboxInStack;\r
226 DEBUG_AGENT_PHASE2_CONTEXT Phase2Context;\r
227 DEBUG_AGENT_CONTEXT_POSTMEM_SEC *DebugAgentContext;\r
228\r
18b144ea 229 DisableInterrupts ();\r
230\r
e2104834 231 switch (InitFlag) {\r
232\r
233 case DEBUG_AGENT_INIT_PREMEM_SEC:\r
234\r
235 InitializeDebugIdt ();\r
236\r
237 Mailbox = &MailboxInStack;\r
238 ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX));\r
239\r
240 //\r
241 // Get and save debug port handle and set the length of memory block.\r
242 //\r
243 SetMailboxPointerInIdtEntry ((VOID *) Mailbox);\r
244\r
245 InitializeDebugTimer ();\r
246\r
247 Phase2Context.Context = Context;\r
248 Phase2Context.Function = Function;\r
249 DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);\r
250\r
251 //\r
252 // If reaches here, it means Debug Port initialization failed.\r
253 //\r
254 DEBUG ((EFI_D_ERROR, "Debug Agent: Debug port initialization failed.\n"));\r
255\r
256 break;\r
257\r
258 case DEBUG_AGENT_INIT_POSTMEM_SEC:\r
18b144ea 259\r
260 //\r
261 // Memory has been ready\r
262 //\r
93c0bdec 263 if (IsHostAttached()) {\r
18b144ea 264 //\r
265 // Trigger one software interrupt to inform HOST\r
266 //\r
267 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);\r
268 }\r
269\r
270 DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context;\r
271\r
272 Mailbox = (DEBUG_AGENT_MAILBOX *) GetMailboxPointerInIdtEntry ();\r
93c0bdec 273 Mailbox->DebugPortHandle = (UINT64)(UINT32)(Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset);\r
274 Mailbox->DebugFlag.MemoryReady = 1;\r
18b144ea 275\r
276 Mailbox = BuildMailboxHob ();\r
277 Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->HeapMigrateOffset);\r
278\r
279 SetMailboxPointerInIdtEntry ((VOID *) Mailbox);\r
280\r
281 EnableInterrupts ();\r
282\r
e2104834 283 break;\r
18b144ea 284\r
e2104834 285 default:\r
18b144ea 286\r
287 //\r
e2104834 288 // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this \r
289 // Debug Agent library instance.\r
18b144ea 290 //\r
e2104834 291 DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));\r
292 CpuDeadLoop ();\r
293 break;\r
18b144ea 294\r
e2104834 295 }\r
18b144ea 296\r
e2104834 297 //\r
298 // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not.\r
299 //\r
300 if (Function != NULL) {\r
301 Function (Context);\r
18b144ea 302 }\r
303}\r
304\r
305/**\r
306 Caller provided function to be invoked at the end of DebugPortInitialize().\r
307\r
308 Refer to the descrption for DebugPortInitialize() for more details.\r
309\r
310 @param[in] Context The first input argument of DebugPortInitialize().\r
311 @param[in] DebugPortHandle Debug port handle created by Debug Communication Libary.\r
312\r
313**/\r
314VOID\r
315EFIAPI\r
316InitializeDebugAgentPhase2 (\r
317 IN VOID *Context,\r
318 IN DEBUG_PORT_HANDLE DebugPortHandle\r
319 )\r
320{\r
321 DEBUG_AGENT_PHASE2_CONTEXT *Phase2Context;\r
322 DEBUG_AGENT_MAILBOX *Mailbox;\r
323 EFI_SEC_PEI_HAND_OFF *SecCoreData;\r
324\r
325 Mailbox = GetMailboxPointerInIdtEntry ();\r
326 Mailbox->DebugPortHandle = (UINT64) (UINTN)DebugPortHandle;\r
327\r
328 //\r
329 // Trigger one software interrupt to inform HOST\r
330 //\r
331 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);\r
332\r
333 //\r
334 // If Temporary RAM region is below 128 MB, then send message to \r
335 // host to disable low memory filtering.\r
336 //\r
337 Phase2Context = (DEBUG_AGENT_PHASE2_CONTEXT *) Context;\r
338 SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Phase2Context->Context;\r
93c0bdec 339 if ((UINTN)SecCoreData->TemporaryRamBase < BASE_128MB && IsHostAttached ()) {\r
18b144ea 340 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);\r
341 }\r
342\r
343 //\r
344 // Enable CPU interrupts so debug timer interrupts can be delivered\r
345 //\r
346 EnableInterrupts ();\r
347\r
348 //\r
e2104834 349 // Call continuation function if it is not NULL.\r
18b144ea 350 //\r
351 if (Phase2Context->Function != NULL) {\r
352 Phase2Context->Function (Phase2Context->Context);\r
353 }\r
354}\r