]> git.proxmox.com Git - mirror_edk2.git/blob - SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c
Import SourceLevelDebugPkg.
[mirror_edk2.git] / SourceLevelDebugPkg / Library / DebugAgent / SecPeiDebugAgent / SecPeiDebugAgentLib.c
1 /** @file
2 SEC Core Debug Agent Library instance implementition.
3
4 Copyright (c) 2010, 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 "SecPeiDebugAgentLib.h"
16
17 CONST BOOLEAN MultiProcessorDebugSupport = FALSE;
18
19 /**
20 Get pointer to Mailbox from IDT entry before memory is ready.
21
22 **/
23 VOID *
24 GetMailboxPointerInIdtEntry (
25 VOID
26 )
27 {
28 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
29 IA32_DESCRIPTOR IdtDescriptor;
30 UINTN Mailbox;
31
32 AsmReadIdtr (&IdtDescriptor);
33 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
34
35 Mailbox = IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + (IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16);
36 return (VOID *) Mailbox;
37 }
38
39 /**
40 Set the pointer of Mailbox into IDT entry before memory is ready.
41
42 @param[in] Mailbox The pointer of Mailbox.
43
44 **/
45 VOID
46 SetMailboxPointerInIdtEntry (
47 IN VOID *Mailbox
48 )
49 {
50 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
51 IA32_DESCRIPTOR IdtDescriptor;
52
53 AsmReadIdtr (&IdtDescriptor);
54 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
55
56 IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)Mailbox;
57 IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)Mailbox >> 16);
58 }
59
60 /**
61 Get the pointer to Mailbox from IDT entry and build the Mailbox into GUIDed Hob
62 after memory is ready.
63
64 @return Pointer to Mailbox.
65
66 **/
67 DEBUG_AGENT_MAILBOX *
68 BuildMailboxHob (
69 VOID
70 )
71 {
72 DEBUG_AGENT_MAILBOX *Mailbox;
73
74 Mailbox = (DEBUG_AGENT_MAILBOX *) GetMailboxPointerInIdtEntry ();
75
76 return BuildGuidDataHob (
77 &gEfiDebugAgentGuid,
78 Mailbox,
79 sizeof (DEBUG_AGENT_MAILBOX)
80 );
81 }
82
83 /**
84 Get Debug Agent Mailbox pointer.
85
86 @return Mailbox pointer.
87
88 **/
89 DEBUG_AGENT_MAILBOX *
90 GetMailboxPointer (
91 VOID
92 )
93 {
94 return (DEBUG_AGENT_MAILBOX *) GetMailboxPointerInIdtEntry ();
95 }
96
97 /**
98 Get debug port handle.
99
100 @return Debug port handle.
101
102 **/
103 DEBUG_PORT_HANDLE
104 GetDebugPortHandle (
105 VOID
106 )
107 {
108 DEBUG_AGENT_MAILBOX *DebugAgentMailbox;
109
110 DebugAgentMailbox = (DEBUG_AGENT_MAILBOX *)GetMailboxPointerInIdtEntry ();
111
112 return (DEBUG_PORT_HANDLE) (UINTN)(DebugAgentMailbox->DebugPortHandle);
113 }
114
115 /**
116 Trigger one software interrupt to debug agent to handle it.
117
118 @param Signature Software interrupt signature.
119
120 **/
121 VOID
122 TriggerSoftInterrupt (
123 UINT32 Signature
124 )
125 {
126 UINTN Dr0;
127 UINTN Dr1;
128
129 //
130 // Save Debug Register State
131 //
132 Dr0 = AsmReadDr0 ();
133 Dr1 = AsmReadDr1 ();
134
135 //
136 // DR0 = Signature
137 //
138 AsmWriteDr0 (SOFT_INTERRUPT_SIGNATURE);
139 AsmWriteDr1 (Signature);
140
141 //
142 // Do INT3 to communicate with HOST side
143 //
144 CpuBreakpoint ();
145
146 //
147 // Restore Debug Register State only when Host didn't change it inside exception handler.
148 // Dr registers can only be changed by setting the HW breakpoint.
149 //
150 AsmWriteDr0 (Dr0);
151 AsmWriteDr1 (Dr1);
152
153 }
154
155 /**
156 Initialize debug agent.
157
158 This function is used to set up debug environment for SEC and PEI phase.
159
160 If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries
161 and initialize debug port. It will enable interrupt to support break-in feature.
162 It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
163 physical memory is ready.
164 If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
165 HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
166
167 This function is used to set up debug environment to support source level debugging.
168 If certain Debug Agent Library instance has to save some private data in the stack,
169 this function must work on the mode that doesn't return to the caller, then
170 the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
171 function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
172 responsible to invoke the passing-in function at the end of InitializeDebugAgent().
173
174 If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
175 passing in the Context to be its parameter.
176
177 If Function() is NULL, Debug Agent Library instance will return after setup debug
178 environment.
179
180 @param[in] InitFlag Init flag is used to decide the initialize process.
181 @param[in] Context Context needed according to InitFlag; it was optional.
182 @param[in] Function Continue function called by debug agent library; it was
183 optional.
184
185 **/
186 VOID
187 EFIAPI
188 InitializeDebugAgent (
189 IN UINT32 InitFlag,
190 IN VOID *Context, OPTIONAL
191 IN DEBUG_AGENT_CONTINUE Function OPTIONAL
192 )
193 {
194 DEBUG_AGENT_MAILBOX *Mailbox;
195 DEBUG_AGENT_MAILBOX MailboxInStack;
196 DEBUG_AGENT_PHASE2_CONTEXT Phase2Context;
197 DEBUG_AGENT_CONTEXT_POSTMEM_SEC *DebugAgentContext;
198
199 if (InitFlag != DEBUG_AGENT_INIT_PREMEM_SEC &&
200 InitFlag != DEBUG_AGENT_INIT_POSTMEM_SEC) {
201 return;
202 }
203
204 DisableInterrupts ();
205
206 if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) {
207
208 //
209 // Memory has been ready
210 //
211 if (IsHostConnected()) {
212 //
213 // Trigger one software interrupt to inform HOST
214 //
215 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
216 }
217
218 DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context;
219
220 Mailbox = (DEBUG_AGENT_MAILBOX *) GetMailboxPointerInIdtEntry ();
221 Mailbox->DebugPortHandle = Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset;
222
223 Mailbox = BuildMailboxHob ();
224 Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->HeapMigrateOffset);
225
226 SetMailboxPointerInIdtEntry ((VOID *) Mailbox);
227
228 EnableInterrupts ();
229
230 if (Function != NULL) {
231 Function (Context);
232 }
233
234 return;
235
236 } else {
237
238 InitializeDebugIdt ();
239
240 Mailbox = &MailboxInStack;
241 ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
242
243 //
244 // Get and save debug port handle and set the length of memory block.
245 //
246 SetMailboxPointerInIdtEntry ((VOID *) Mailbox);
247
248 InitializeDebugTimer ();
249
250 Phase2Context.Context = Context;
251 Phase2Context.Function = Function;
252 DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
253
254 return;
255 }
256 }
257
258 /**
259 Caller provided function to be invoked at the end of DebugPortInitialize().
260
261 Refer to the descrption for DebugPortInitialize() for more details.
262
263 @param[in] Context The first input argument of DebugPortInitialize().
264 @param[in] DebugPortHandle Debug port handle created by Debug Communication Libary.
265
266 **/
267 VOID
268 EFIAPI
269 InitializeDebugAgentPhase2 (
270 IN VOID *Context,
271 IN DEBUG_PORT_HANDLE DebugPortHandle
272 )
273 {
274 DEBUG_AGENT_PHASE2_CONTEXT *Phase2Context;
275 DEBUG_AGENT_MAILBOX *Mailbox;
276 EFI_SEC_PEI_HAND_OFF *SecCoreData;
277
278 Mailbox = GetMailboxPointerInIdtEntry ();
279 Mailbox->DebugPortHandle = (UINT64) (UINTN)DebugPortHandle;
280
281 //
282 // Trigger one software interrupt to inform HOST
283 //
284 TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
285
286 //
287 // If Temporary RAM region is below 128 MB, then send message to
288 // host to disable low memory filtering.
289 //
290 Phase2Context = (DEBUG_AGENT_PHASE2_CONTEXT *) Context;
291 SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Phase2Context->Context;
292 if ((UINTN)SecCoreData->TemporaryRamBase < BASE_128MB) {
293 TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
294 }
295
296 //
297 // Enable CPU interrupts so debug timer interrupts can be delivered
298 //
299 EnableInterrupts ();
300
301 //
302 // Call continuation function is it is not NULL.
303 //
304 if (Phase2Context->Function != NULL) {
305 Phase2Context->Function (Phase2Context->Context);
306 }
307 }