]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/GdbStub/Ia32/Processor.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmbeddedPkg / GdbStub / Ia32 / Processor.c
CommitLineData
1e57a462 1/** @file\r
2 Processor specific parts of the GDB stub\r
3\r
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
3402aac7 5\r
878b807a 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
1e57a462 7\r
8**/\r
9\r
10#include <GdbStubInternal.h>\r
11\r
12//\r
13// Array of exception types that need to be hooked by the debugger\r
14// {EFI mapping, GDB mapping}\r
15//\r
e7108d0e
MK
16EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {\r
17 { EXCEPT_IA32_DIVIDE_ERROR, GDB_SIGFPE },\r
18 { EXCEPT_IA32_DEBUG, GDB_SIGTRAP },\r
19 { EXCEPT_IA32_NMI, GDB_SIGEMT },\r
20 { EXCEPT_IA32_BREAKPOINT, GDB_SIGTRAP },\r
21 { EXCEPT_IA32_OVERFLOW, GDB_SIGSEGV },\r
22 { EXCEPT_IA32_BOUND, GDB_SIGSEGV },\r
23 { EXCEPT_IA32_INVALID_OPCODE, GDB_SIGILL },\r
24 { EXCEPT_IA32_DOUBLE_FAULT, GDB_SIGEMT },\r
25 { EXCEPT_IA32_STACK_FAULT, GDB_SIGSEGV },\r
26 { EXCEPT_IA32_GP_FAULT, GDB_SIGSEGV },\r
27 { EXCEPT_IA32_PAGE_FAULT, GDB_SIGSEGV },\r
28 { EXCEPT_IA32_FP_ERROR, GDB_SIGEMT },\r
29 { EXCEPT_IA32_ALIGNMENT_CHECK, GDB_SIGEMT },\r
30 { EXCEPT_IA32_MACHINE_CHECK, GDB_SIGEMT }\r
1e57a462 31};\r
32\r
1e57a462 33// The offsets of registers SystemContext.\r
34// The fields in the array are in the gdb ordering.\r
35//\r
e7108d0e
MK
36// 16 regs\r
37UINTN gRegisterOffsets[] = {\r
38 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Eax),\r
39 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Ecx),\r
40 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Edx),\r
41 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Ebx),\r
42 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Esp),\r
43 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Ebp),\r
44 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Esi),\r
45 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Edi),\r
46 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Eip),\r
47 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Eflags),\r
48 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Cs),\r
49 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Ss),\r
50 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Ds),\r
51 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Es),\r
52 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Fs),\r
53 OFFSET_OF (EFI_SYSTEM_CONTEXT_IA32, Gs)\r
1e57a462 54};\r
55\r
e7108d0e 56// Debug only..\r
3402aac7 57VOID\r
1e57a462 58PrintReg (\r
e7108d0e 59 IN EFI_SYSTEM_CONTEXT SystemContext\r
1e57a462 60 )\r
61{\r
62 Print ((CHAR16 *)L"EAX: %x ", SystemContext.SystemContextIa32->Eax);\r
63 Print ((CHAR16 *)L"ECX: %x ", SystemContext.SystemContextIa32->Ecx);\r
64 Print ((CHAR16 *)L"EDX: %x ", SystemContext.SystemContextIa32->Edx);\r
65 Print ((CHAR16 *)L"EBX: %x ", SystemContext.SystemContextIa32->Ebx);\r
66 Print ((CHAR16 *)L"ESP: %x ", SystemContext.SystemContextIa32->Esp);\r
67 Print ((CHAR16 *)L"EBP: %x ", SystemContext.SystemContextIa32->Ebp);\r
68 Print ((CHAR16 *)L"ESI: %x ", SystemContext.SystemContextIa32->Esi);\r
69 Print ((CHAR16 *)L"EDI: %x ", SystemContext.SystemContextIa32->Edi);\r
70 Print ((CHAR16 *)L"EIP: %x\n", SystemContext.SystemContextIa32->Eip);\r
71 Print ((CHAR16 *)L"EFlags: %x\n", SystemContext.SystemContextIa32->Eflags);\r
72}\r
73\r
e7108d0e 74// Debug only..\r
3402aac7 75VOID\r
1e57a462 76PrintDRreg (\r
e7108d0e 77 IN EFI_SYSTEM_CONTEXT SystemContext\r
1e57a462 78 )\r
79{\r
80 Print ((CHAR16 *)L"DR0: %x ", SystemContext.SystemContextIa32->Dr0);\r
81 Print ((CHAR16 *)L"DR1: %x ", SystemContext.SystemContextIa32->Dr1);\r
82 Print ((CHAR16 *)L"DR2: %x ", SystemContext.SystemContextIa32->Dr2);\r
83 Print ((CHAR16 *)L"DR3: %x ", SystemContext.SystemContextIa32->Dr3);\r
84 Print ((CHAR16 *)L"DR6: %x ", SystemContext.SystemContextIa32->Dr6);\r
85 Print ((CHAR16 *)L"DR7: %x\n", SystemContext.SystemContextIa32->Dr7);\r
86}\r
87\r
1e57a462 88/**\r
89 Return the number of entries in the gExceptionType[]\r
3402aac7
RC
90\r
91 @retval UINTN, the number of entries in the gExceptionType[] array.\r
1e57a462 92 **/\r
93UINTN\r
94MaxEfiException (\r
95 VOID\r
96 )\r
97{\r
98 return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);\r
99}\r
100\r
1e57a462 101/**\r
102 Return the number of entries in the gRegisters[]\r
3402aac7
RC
103\r
104 @retval UINTN, the number of entries (registers) in the gRegisters[] array.\r
1e57a462 105 **/\r
106UINTN\r
107MaxRegisterCount (\r
108 VOID\r
109 )\r
110{\r
111 return sizeof (gRegisterOffsets)/sizeof (UINTN);\r
112}\r
113\r
1e57a462 114/**\r
3402aac7 115 Check to see if the ISA is supported.\r
1e57a462 116 ISA = Instruction Set Architecture\r
3402aac7 117\r
1e57a462 118 @retval TRUE if Isa is supported,\r
119 FALSE otherwise.\r
120**/\r
121BOOLEAN\r
122CheckIsa (\r
123 IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa\r
124 )\r
125{\r
126 return (BOOLEAN)(Isa == IsaIa32);\r
127}\r
128\r
1e57a462 129/**\r
130 This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering\r
131 It is, by default, set to find the register pointer of the IA32 member\r
132\r
3402aac7 133 @param SystemContext Register content at time of the exception\r
1e57a462 134 @param RegNumber The register to which we want to find a pointer\r
135 @retval the pointer to the RegNumber-th pointer\r
136 **/\r
137UINTN *\r
6f711615 138FindPointerToRegister (\r
1e57a462 139 IN EFI_SYSTEM_CONTEXT SystemContext,\r
3402aac7 140 IN UINTN RegNumber\r
1e57a462 141 )\r
142{\r
e7108d0e
MK
143 UINT8 *TempPtr;\r
144\r
1e57a462 145 TempPtr = ((UINT8 *)SystemContext.SystemContextIa32) + gRegisterOffsets[RegNumber];\r
146 return (UINTN *)TempPtr;\r
147}\r
148\r
1e57a462 149/**\r
150 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr\r
151\r
152 @param SystemContext Register content at time of the exception\r
153 @param RegNumber the number of the register that we want to read\r
154 @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.\r
155 @retval the pointer to the next character of the output buffer that is available to be written on.\r
156 **/\r
157CHAR8 *\r
158BasicReadRegister (\r
e7108d0e
MK
159 IN EFI_SYSTEM_CONTEXT SystemContext,\r
160 IN UINTN RegNumber,\r
161 IN CHAR8 *OutBufPtr\r
1e57a462 162 )\r
163{\r
e7108d0e 164 UINTN RegSize;\r
3402aac7 165\r
1e57a462 166 RegSize = 0;\r
167 while (RegSize < REG_SIZE) {\r
6f711615 168 *OutBufPtr++ = mHexToStr[((*FindPointerToRegister (SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];\r
169 *OutBufPtr++ = mHexToStr[((*FindPointerToRegister (SystemContext, RegNumber) >> RegSize) & 0xf)];\r
e7108d0e 170 RegSize = RegSize + 8;\r
1e57a462 171 }\r
e7108d0e 172\r
1e57a462 173 return OutBufPtr;\r
174}\r
175\r
3402aac7
RC
176/** ‘p n’\r
177 Reads the n-th register's value into an output buffer and sends it as a packet\r
1e57a462 178\r
179 @param SystemContext Register content at time of the exception\r
180 @param InBuffer Pointer to the input buffer received from gdb server\r
181 **/\r
182VOID\r
183EFIAPI\r
184ReadNthRegister (\r
e7108d0e
MK
185 IN EFI_SYSTEM_CONTEXT SystemContext,\r
186 IN CHAR8 *InBuffer\r
1e57a462 187 )\r
188{\r
e7108d0e
MK
189 UINTN RegNumber;\r
190 CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)\r
191 CHAR8 *OutBufPtr; // pointer to the output buffer\r
3402aac7 192\r
1e57a462 193 RegNumber = AsciiStrHexToUintn (&InBuffer[1]);\r
194\r
e7108d0e 195 if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount ())) {\r
1e57a462 196 SendError (GDB_EINVALIDREGNUM);\r
197 return;\r
198 }\r
199\r
200 OutBufPtr = OutBuffer;\r
6f711615 201 OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);\r
1e57a462 202\r
203 *OutBufPtr = '\0'; // the end of the buffer\r
e7108d0e 204 SendPacket (OutBuffer);\r
1e57a462 205}\r
206\r
3402aac7
RC
207/** ‘g’\r
208 Reads the general registers into an output buffer and sends it as a packet\r
1e57a462 209\r
210 @param SystemContext Register content at time of the exception\r
211 **/\r
212VOID\r
213EFIAPI\r
3402aac7 214ReadGeneralRegisters (\r
e7108d0e 215 IN EFI_SYSTEM_CONTEXT SystemContext\r
1e57a462 216 )\r
217{\r
e7108d0e
MK
218 UINTN i;\r
219 CHAR8 OutBuffer[129]; // 16 regs, 8 hex chars each, and the end '\0' (escape seq)\r
220 CHAR8 *OutBufPtr; // pointer to the output buffer\r
1e57a462 221\r
222 OutBufPtr = OutBuffer;\r
e7108d0e
MK
223 for (i = 0; i < MaxRegisterCount (); i++) {\r
224 // there are only 16 registers to read\r
6f711615 225 OutBufPtr = BasicReadRegister (SystemContext, i, OutBufPtr);\r
1e57a462 226 }\r
227\r
228 *OutBufPtr = '\0'; // the end of the buffer\r
e7108d0e 229 SendPacket (OutBuffer);\r
1e57a462 230}\r
231\r
1e57a462 232/**\r
233 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr\r
234\r
235 @param SystemContext Register content at time of the exception\r
236 @param RegNumber the number of the register that we want to write\r
237 @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.\r
238 @retval the pointer to the next character of the input buffer that can be used\r
239 **/\r
240CHAR8 *\r
241BasicWriteRegister (\r
e7108d0e
MK
242 IN EFI_SYSTEM_CONTEXT SystemContext,\r
243 IN UINTN RegNumber,\r
244 IN CHAR8 *InBufPtr\r
1e57a462 245 )\r
246{\r
e7108d0e
MK
247 UINTN RegSize;\r
248 UINTN TempValue; // the value transferred from a hex char\r
249 UINT32 NewValue; // the new value of the RegNumber-th Register\r
3402aac7 250\r
1e57a462 251 NewValue = 0;\r
e7108d0e 252 RegSize = 0;\r
1e57a462 253 while (RegSize < REG_SIZE) {\r
e7108d0e 254 TempValue = HexCharToInt (*InBufPtr++);\r
3402aac7 255\r
e7108d0e 256 if (TempValue < 0) {\r
3402aac7 257 SendError (GDB_EBADMEMDATA);\r
1e57a462 258 return NULL;\r
259 }\r
260\r
261 NewValue += (TempValue << (RegSize+4));\r
e7108d0e 262 TempValue = HexCharToInt (*InBufPtr++);\r
3402aac7 263\r
1e57a462 264 if (TempValue < 0) {\r
3402aac7 265 SendError (GDB_EBADMEMDATA);\r
1e57a462 266 return NULL;\r
267 }\r
3402aac7
RC
268\r
269 NewValue += (TempValue << RegSize);\r
e7108d0e 270 RegSize = RegSize + 8;\r
1e57a462 271 }\r
e7108d0e 272\r
6f711615 273 *(FindPointerToRegister (SystemContext, RegNumber)) = NewValue;\r
1e57a462 274 return InBufPtr;\r
275}\r
276\r
1e57a462 277/** ‘P n...=r...’\r
278 Writes the new value of n-th register received into the input buffer to the n-th register\r
279\r
280 @param SystemContext Register content at time of the exception\r
c6a72cd7 281 @param InBuffer Pointer to the input buffer received from gdb server\r
1e57a462 282 **/\r
283VOID\r
284EFIAPI\r
285WriteNthRegister (\r
e7108d0e
MK
286 IN EFI_SYSTEM_CONTEXT SystemContext,\r
287 IN CHAR8 *InBuffer\r
1e57a462 288 )\r
289{\r
e7108d0e
MK
290 UINTN RegNumber;\r
291 CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array\r
292 CHAR8 *RegNumBufPtr;\r
293 CHAR8 *InBufPtr; // pointer to the input buffer\r
3402aac7 294\r
1e57a462 295 // find the register number to write\r
e7108d0e 296 InBufPtr = &InBuffer[1];\r
1e57a462 297 RegNumBufPtr = RegNumBuffer;\r
298 while (*InBufPtr != '=') {\r
299 *RegNumBufPtr++ = *InBufPtr++;\r
3402aac7 300 }\r
e7108d0e 301\r
1e57a462 302 *RegNumBufPtr = '\0';\r
e7108d0e 303 RegNumber = AsciiStrHexToUintn (RegNumBuffer);\r
1e57a462 304\r
305 // check if this is a valid Register Number\r
e7108d0e 306 if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount ())) {\r
91c38d4e 307 SendError (GDB_EINVALIDREGNUM);\r
1e57a462 308 return;\r
309 }\r
e7108d0e 310\r
1e57a462 311 InBufPtr++; // skips the '=' character\r
312 BasicWriteRegister (SystemContext, RegNumber, InBufPtr);\r
e7108d0e 313 SendSuccess ();\r
1e57a462 314}\r
315\r
1e57a462 316/** ‘G XX...’\r
317 Writes the new values received into the input buffer to the general registers\r
318\r
319 @param SystemContext Register content at time of the exception\r
320 @param InBuffer Pointer to the input buffer received from gdb server\r
321 **/\r
322VOID\r
323EFIAPI\r
324WriteGeneralRegisters (\r
e7108d0e
MK
325 IN EFI_SYSTEM_CONTEXT SystemContext,\r
326 IN CHAR8 *InBuffer\r
1e57a462 327 )\r
328{\r
329 UINTN i;\r
e7108d0e 330 CHAR8 *InBufPtr; /// pointer to the input buffer\r
1e57a462 331\r
3402aac7
RC
332 // check to see if the buffer is the right size which is\r
333 // 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 129\r
e7108d0e
MK
334 if (AsciiStrLen (InBuffer) != 129) {\r
335 // 16 regs, 8 hex chars each, and the end '\0' (escape seq)\r
336 // Bad message. Message is not the right length\r
3402aac7 337 SendError (GDB_EBADBUFSIZE);\r
1e57a462 338 return;\r
339 }\r
340\r
341 InBufPtr = &InBuffer[1];\r
3402aac7 342\r
1e57a462 343 // Read the new values for the registers from the input buffer to an array, NewValueArray.\r
344 // The values in the array are in the gdb ordering\r
e7108d0e
MK
345 for (i = 0; i < MaxRegisterCount (); i++) {\r
346 // there are only 16 registers to write\r
6f711615 347 InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);\r
1e57a462 348 }\r
349\r
e7108d0e 350 SendSuccess ();\r
1e57a462 351}\r
352\r
3402aac7 353/**\r
1e57a462 354 Insert Single Step in the SystemContext\r
3402aac7 355\r
1e57a462 356 @param SystemContext Register content at time of the exception\r
357 **/\r
358VOID\r
359AddSingleStep (\r
360 IN EFI_SYSTEM_CONTEXT SystemContext\r
361 )\r
362{\r
e7108d0e 363 SystemContext.SystemContextIa32->Eflags |= TF_BIT; // Setting the TF bit.\r
1e57a462 364}\r
365\r
3402aac7 366/**\r
1e57a462 367 Remove Single Step in the SystemContext\r
3402aac7 368\r
1e57a462 369 @param SystemContext Register content at time of the exception\r
370 **/\r
371VOID\r
372RemoveSingleStep (\r
373 IN EFI_SYSTEM_CONTEXT SystemContext\r
374 )\r
375{\r
376 SystemContext.SystemContextIa32->Eflags &= ~TF_BIT; // clearing the TF bit.\r
377}\r
378\r
3402aac7
RC
379/** ‘c [addr ]’\r
380 Continue. addr is Address to resume. If addr is omitted, resume at current\r
1e57a462 381 Address.\r
3402aac7
RC
382\r
383 @param SystemContext Register content at time of the exception\r
1e57a462 384 **/\r
385VOID\r
386EFIAPI\r
387ContinueAtAddress (\r
e7108d0e
MK
388 IN EFI_SYSTEM_CONTEXT SystemContext,\r
389 IN CHAR8 *PacketData\r
1e57a462 390 )\r
391{\r
392 if (PacketData[1] != '\0') {\r
393 SystemContext.SystemContextIa32->Eip = AsciiStrHexToUintn (&PacketData[1]);\r
3402aac7 394 }\r
1e57a462 395}\r
396\r
1e57a462 397/** ‘s [addr ]’\r
3402aac7 398 Single step. addr is the Address at which to resume. If addr is omitted, resume\r
1e57a462 399 at same Address.\r
3402aac7
RC
400\r
401 @param SystemContext Register content at time of the exception\r
1e57a462 402 **/\r
403VOID\r
404EFIAPI\r
405SingleStep (\r
e7108d0e
MK
406 IN EFI_SYSTEM_CONTEXT SystemContext,\r
407 IN CHAR8 *PacketData\r
1e57a462 408 )\r
409{\r
410 if (PacketData[1] != '\0') {\r
411 SystemContext.SystemContextIa32->Eip = AsciiStrHexToUintn (&PacketData[1]);\r
412 }\r
3402aac7 413\r
1e57a462 414 AddSingleStep (SystemContext);\r
415}\r
416\r
1e57a462 417/**\r
418 Returns breakpoint data address from DR0-DR3 based on the input breakpoint number\r
419\r
420 @param SystemContext Register content at time of the exception\r
421 @param BreakpointNumber Breakpoint number\r
422\r
423 @retval Address Data address from DR0-DR3 based on the breakpoint number.\r
424\r
425**/\r
426UINTN\r
427GetBreakpointDataAddress (\r
428 IN EFI_SYSTEM_CONTEXT SystemContext,\r
429 IN UINTN BreakpointNumber\r
430 )\r
431{\r
e7108d0e 432 UINTN Address;\r
1e57a462 433\r
434 if (BreakpointNumber == 1) {\r
435 Address = SystemContext.SystemContextIa32->Dr0;\r
436 } else if (BreakpointNumber == 2) {\r
437 Address = SystemContext.SystemContextIa32->Dr1;\r
438 } else if (BreakpointNumber == 3) {\r
439 Address = SystemContext.SystemContextIa32->Dr2;\r
440 } else if (BreakpointNumber == 4) {\r
441 Address = SystemContext.SystemContextIa32->Dr3;\r
442 } else {\r
443 Address = 0;\r
444 }\r
445\r
446 return Address;\r
447}\r
448\r
1e57a462 449/**\r
450 Returns currently detected breakpoint value based on the register DR6 B0-B3 field.\r
451 If no breakpoint is detected then it returns 0.\r
452\r
453 @param SystemContext Register content at time of the exception\r
454\r
3402aac7 455 @retval {1-4} Currently detected breakpoint value\r
1e57a462 456 @retval 0 No breakpoint detected.\r
3402aac7 457\r
1e57a462 458**/\r
459UINTN\r
460GetBreakpointDetected (\r
461 IN EFI_SYSTEM_CONTEXT SystemContext\r
462 )\r
463{\r
e7108d0e
MK
464 IA32_DR6 Dr6;\r
465 UINTN BreakpointNumber;\r
1e57a462 466\r
467 Dr6.UintN = SystemContext.SystemContextIa32->Dr6;\r
468\r
469 if (Dr6.Bits.B0 == 1) {\r
470 BreakpointNumber = 1;\r
471 } else if (Dr6.Bits.B1 == 1) {\r
472 BreakpointNumber = 2;\r
473 } else if (Dr6.Bits.B2 == 1) {\r
474 BreakpointNumber = 3;\r
475 } else if (Dr6.Bits.B3 == 1) {\r
476 BreakpointNumber = 4;\r
477 } else {\r
e7108d0e 478 BreakpointNumber = 0; // No breakpoint detected\r
1e57a462 479 }\r
480\r
481 return BreakpointNumber;\r
482}\r
483\r
1e57a462 484/**\r
485 Returns Breakpoint type (InstructionExecution, DataWrite, DataRead or DataReadWrite)\r
486 based on the Breakpoint number\r
3402aac7 487\r
1e57a462 488 @param SystemContext Register content at time of the exception\r
489 @param BreakpointNumber Breakpoint number\r
3402aac7 490\r
1e57a462 491 @retval BREAK_TYPE Breakpoint type value read from register DR7 RWn field\r
492 For unknown value, it returns NotSupported.\r
3402aac7 493\r
1e57a462 494**/\r
495BREAK_TYPE\r
496GetBreakpointType (\r
497 IN EFI_SYSTEM_CONTEXT SystemContext,\r
498 IN UINTN BreakpointNumber\r
499 )\r
500{\r
e7108d0e
MK
501 IA32_DR7 Dr7;\r
502 BREAK_TYPE Type = NotSupported; // Default is NotSupported type\r
1e57a462 503\r
504 Dr7.UintN = SystemContext.SystemContextIa32->Dr7;\r
505\r
506 if (BreakpointNumber == 1) {\r
e7108d0e 507 Type = (BREAK_TYPE)Dr7.Bits.RW0;\r
1e57a462 508 } else if (BreakpointNumber == 2) {\r
e7108d0e 509 Type = (BREAK_TYPE)Dr7.Bits.RW1;\r
1e57a462 510 } else if (BreakpointNumber == 3) {\r
e7108d0e 511 Type = (BREAK_TYPE)Dr7.Bits.RW2;\r
1e57a462 512 } else if (BreakpointNumber == 4) {\r
e7108d0e 513 Type = (BREAK_TYPE)Dr7.Bits.RW3;\r
1e57a462 514 }\r
515\r
516 return Type;\r
517}\r
518\r
3402aac7 519/**\r
1e57a462 520 Parses Length and returns the length which DR7 LENn field accepts.\r
3402aac7 521 For example: If we receive 1-Byte length then we should return 0.\r
1e57a462 522 Zero gets written to DR7 LENn field.\r
523\r
524 @param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)\r
525\r
526 @retval Length Appropriate converted values which DR7 LENn field accepts.\r
527\r
528**/\r
529UINTN\r
530ConvertLengthData (\r
e7108d0e 531 IN UINTN Length\r
1e57a462 532 )\r
533{\r
e7108d0e
MK
534 if (Length == 1) {\r
535 // 1-Byte length\r
1e57a462 536 return 0;\r
e7108d0e
MK
537 } else if (Length == 2) {\r
538 // 2-Byte length\r
1e57a462 539 return 1;\r
e7108d0e
MK
540 } else if (Length == 4) {\r
541 // 4-Byte length\r
1e57a462 542 return 3;\r
e7108d0e
MK
543 } else {\r
544 // Undefined or 8-byte length\r
1e57a462 545 return 2;\r
546 }\r
547}\r
548\r
1e57a462 549/**\r
3402aac7
RC
550 Finds the next free debug register. If all the registers are occupied then\r
551 EFI_OUT_OF_RESOURCES is returned.\r
1e57a462 552\r
553 @param SystemContext Register content at time of the exception\r
554 @param Register Register value (0 - 3 for the first free debug register)\r
555\r
556 @retval EFI_STATUS Appropriate status value.\r
557\r
558**/\r
559EFI_STATUS\r
560FindNextFreeDebugRegister (\r
561 IN EFI_SYSTEM_CONTEXT SystemContext,\r
562 OUT UINTN *Register\r
563 )\r
564{\r
e7108d0e 565 IA32_DR7 Dr7;\r
1e57a462 566\r
567 Dr7.UintN = SystemContext.SystemContextIa32->Dr7;\r
568\r
569 if (Dr7.Bits.G0 == 0) {\r
570 *Register = 0;\r
571 } else if (Dr7.Bits.G1 == 0) {\r
572 *Register = 1;\r
573 } else if (Dr7.Bits.G2 == 0) {\r
574 *Register = 2;\r
575 } else if (Dr7.Bits.G3 == 0) {\r
576 *Register = 3;\r
577 } else {\r
578 return EFI_OUT_OF_RESOURCES;\r
579 }\r
580\r
581 return EFI_SUCCESS;\r
582}\r
583\r
1e57a462 584/**\r
585 Enables the debug register. Writes Address value to appropriate DR0-3 register.\r
586 Sets LENn, Gn, RWn bits in DR7 register.\r
3402aac7 587\r
1e57a462 588 @param SystemContext Register content at time of the exception\r
3402aac7 589 @param Register Register value (0 - 3)\r
1e57a462 590 @param Address Breakpoint address value\r
3402aac7 591 @param Type Breakpoint type (Instruction, Data write, Data read\r
1e57a462 592 or write etc.)\r
593\r
594 @retval EFI_STATUS Appropriate status value.\r
595\r
596**/\r
597EFI_STATUS\r
598EnableDebugRegister (\r
599 IN EFI_SYSTEM_CONTEXT SystemContext,\r
600 IN UINTN Register,\r
601 IN UINTN Address,\r
602 IN UINTN Length,\r
603 IN UINTN Type\r
604 )\r
605{\r
606 IA32_DR7 Dr7;\r
607\r
e7108d0e 608 // Convert length data\r
1e57a462 609 Length = ConvertLengthData (Length);\r
610\r
e7108d0e
MK
611 // For Instruction execution, length should be 0\r
612 // (Ref. Intel reference manual 18.2.4)\r
1e57a462 613 if ((Type == 0) && (Length != 0)) {\r
614 return EFI_INVALID_PARAMETER;\r
615 }\r
3402aac7 616\r
e7108d0e
MK
617 // Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle\r
618 // software breakpoint. We should send empty packet in both these cases.\r
3402aac7 619 if ((Type == (BREAK_TYPE)DataRead) ||\r
e7108d0e
MK
620 (Type == (BREAK_TYPE)SoftwareBreakpoint))\r
621 {\r
1e57a462 622 return EFI_UNSUPPORTED;\r
623 }\r
624\r
e7108d0e 625 // Read DR7 so appropriate Gn, RWn and LENn bits can be modified.\r
1e57a462 626 Dr7.UintN = SystemContext.SystemContextIa32->Dr7;\r
627\r
628 if (Register == 0) {\r
629 SystemContext.SystemContextIa32->Dr0 = Address;\r
e7108d0e
MK
630 Dr7.Bits.G0 = 1;\r
631 Dr7.Bits.RW0 = Type;\r
632 Dr7.Bits.LEN0 = Length;\r
1e57a462 633 } else if (Register == 1) {\r
634 SystemContext.SystemContextIa32->Dr1 = Address;\r
e7108d0e
MK
635 Dr7.Bits.G1 = 1;\r
636 Dr7.Bits.RW1 = Type;\r
637 Dr7.Bits.LEN1 = Length;\r
1e57a462 638 } else if (Register == 2) {\r
639 SystemContext.SystemContextIa32->Dr2 = Address;\r
e7108d0e
MK
640 Dr7.Bits.G2 = 1;\r
641 Dr7.Bits.RW2 = Type;\r
642 Dr7.Bits.LEN2 = Length;\r
1e57a462 643 } else if (Register == 3) {\r
644 SystemContext.SystemContextIa32->Dr3 = Address;\r
e7108d0e
MK
645 Dr7.Bits.G3 = 1;\r
646 Dr7.Bits.RW3 = Type;\r
647 Dr7.Bits.LEN3 = Length;\r
1e57a462 648 } else {\r
649 return EFI_INVALID_PARAMETER;\r
650 }\r
651\r
e7108d0e 652 // Update Dr7 with appropriate Gn, RWn and LENn bits\r
1e57a462 653 SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;\r
654\r
655 return EFI_SUCCESS;\r
656}\r
657\r
1e57a462 658/**\r
c6a72cd7 659 Returns register number 0 - 3 for the matching debug register.\r
1e57a462 660 This function compares incoming Address, Type, Length and\r
661 if there is a match then it returns the appropriate register number.\r
662 In case of mismatch, function returns EFI_NOT_FOUND message.\r
663\r
664 @param SystemContext Register content at time of the exception\r
665 @param Address Breakpoint address value\r
666 @param Length Breakpoint length value\r
3402aac7 667 @param Type Breakpoint type (Instruction, Data write,\r
1e57a462 668 Data read or write etc.)\r
669 @param Register Register value to be returned\r
670\r
671 @retval EFI_STATUS Appropriate status value.\r
672\r
673**/\r
674EFI_STATUS\r
675FindMatchingDebugRegister (\r
e7108d0e
MK
676 IN EFI_SYSTEM_CONTEXT SystemContext,\r
677 IN UINTN Address,\r
678 IN UINTN Length,\r
679 IN UINTN Type,\r
680 OUT UINTN *Register\r
681 )\r
1e57a462 682{\r
e7108d0e 683 IA32_DR7 Dr7;\r
1e57a462 684\r
e7108d0e
MK
685 // Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle\r
686 // software breakpoint. We should send empty packet in both these cases.\r
3402aac7 687 if ((Type == (BREAK_TYPE)DataRead) ||\r
e7108d0e
MK
688 (Type == (BREAK_TYPE)SoftwareBreakpoint))\r
689 {\r
1e57a462 690 return EFI_UNSUPPORTED;\r
691 }\r
692\r
e7108d0e
MK
693 // Convert length data\r
694 Length = ConvertLengthData (Length);\r
1e57a462 695\r
696 Dr7.UintN = SystemContext.SystemContextIa32->Dr7;\r
697\r
3402aac7 698 if ((Dr7.Bits.G0 == 1) &&\r
1e57a462 699 (Dr7.Bits.LEN0 == Length) &&\r
3402aac7 700 (Dr7.Bits.RW0 == Type) &&\r
e7108d0e
MK
701 (Address == SystemContext.SystemContextIa32->Dr0))\r
702 {\r
1e57a462 703 *Register = 0;\r
3402aac7 704 } else if ((Dr7.Bits.G1 == 1) &&\r
1e57a462 705 (Dr7.Bits.LEN1 == Length) &&\r
3402aac7 706 (Dr7.Bits.RW1 == Type) &&\r
e7108d0e
MK
707 (Address == SystemContext.SystemContextIa32->Dr1))\r
708 {\r
1e57a462 709 *Register = 1;\r
3402aac7 710 } else if ((Dr7.Bits.G2 == 1) &&\r
1e57a462 711 (Dr7.Bits.LEN2 == Length) &&\r
3402aac7 712 (Dr7.Bits.RW2 == Type) &&\r
e7108d0e
MK
713 (Address == SystemContext.SystemContextIa32->Dr2))\r
714 {\r
1e57a462 715 *Register = 2;\r
3402aac7 716 } else if ((Dr7.Bits.G3 == 1) &&\r
1e57a462 717 (Dr7.Bits.LEN3 == Length) &&\r
3402aac7 718 (Dr7.Bits.RW3 == Type) &&\r
e7108d0e
MK
719 (Address == SystemContext.SystemContextIa32->Dr3))\r
720 {\r
1e57a462 721 *Register = 3;\r
722 } else {\r
723 Print ((CHAR16 *)L"No match found..\n");\r
724 return EFI_NOT_FOUND;\r
725 }\r
726\r
727 return EFI_SUCCESS;\r
728}\r
729\r
1e57a462 730/**\r
731 Disables the particular debug register.\r
732\r
733 @param SystemContext Register content at time of the exception\r
734 @param Register Register to be disabled\r
735\r
736 @retval EFI_STATUS Appropriate status value.\r
737\r
738**/\r
739EFI_STATUS\r
740DisableDebugRegister (\r
e7108d0e
MK
741 IN EFI_SYSTEM_CONTEXT SystemContext,\r
742 IN UINTN Register\r
743 )\r
1e57a462 744{\r
745 IA32_DR7 Dr7;\r
e7108d0e 746 UINTN Address = 0;\r
3402aac7 747\r
e7108d0e 748 // Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off.\r
1e57a462 749 Dr7.UintN = SystemContext.SystemContextIa32->Dr7;\r
750\r
751 if (Register == 0) {\r
752 SystemContext.SystemContextIa32->Dr0 = Address;\r
e7108d0e
MK
753 Dr7.Bits.G0 = 0;\r
754 Dr7.Bits.RW0 = 0;\r
755 Dr7.Bits.LEN0 = 0;\r
1e57a462 756 } else if (Register == 1) {\r
757 SystemContext.SystemContextIa32->Dr1 = Address;\r
e7108d0e
MK
758 Dr7.Bits.G1 = 0;\r
759 Dr7.Bits.RW1 = 0;\r
760 Dr7.Bits.LEN1 = 0;\r
1e57a462 761 } else if (Register == 2) {\r
762 SystemContext.SystemContextIa32->Dr2 = Address;\r
e7108d0e
MK
763 Dr7.Bits.G2 = 0;\r
764 Dr7.Bits.RW2 = 0;\r
765 Dr7.Bits.LEN2 = 0;\r
1e57a462 766 } else if (Register == 3) {\r
767 SystemContext.SystemContextIa32->Dr3 = Address;\r
e7108d0e
MK
768 Dr7.Bits.G3 = 0;\r
769 Dr7.Bits.RW3 = 0;\r
770 Dr7.Bits.LEN3 = 0;\r
1e57a462 771 } else {\r
772 return EFI_INVALID_PARAMETER;\r
773 }\r
774\r
e7108d0e 775 // Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off.\r
1e57a462 776 SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;\r
777\r
778 return EFI_SUCCESS;\r
779}\r
780\r
1e57a462 781/**\r
782 ‘Z1, [addr], [length]’\r
783 ‘Z2, [addr], [length]’\r
784 ‘Z3, [addr], [length]’\r
785 ‘Z4, [addr], [length]’\r
786\r
787 Insert hardware breakpoint/watchpoint at address addr of size length\r
788\r
789 @param SystemContext Register content at time of the exception\r
790 @param *PacketData Pointer to the Payload data for the packet\r
791\r
792**/\r
793VOID\r
794EFIAPI\r
795InsertBreakPoint (\r
796 IN EFI_SYSTEM_CONTEXT SystemContext,\r
e7108d0e 797 IN CHAR8 *PacketData\r
1e57a462 798 )\r
799{\r
e7108d0e
MK
800 UINTN Type;\r
801 UINTN Address;\r
802 UINTN Length;\r
803 UINTN Register;\r
804 EFI_STATUS Status;\r
805 BREAK_TYPE BreakType = NotSupported;\r
806 UINTN ErrorCode;\r
1e57a462 807\r
808 ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);\r
809 if (ErrorCode > 0) {\r
810 SendError ((UINT8)ErrorCode);\r
811 return;\r
812 }\r
813\r
814 switch (Type) {\r
e7108d0e 815 case 0: // Software breakpoint\r
1e57a462 816 BreakType = SoftwareBreakpoint;\r
817 break;\r
818\r
e7108d0e 819 case 1: // Hardware breakpoint\r
1e57a462 820 BreakType = InstructionExecution;\r
821 break;\r
822\r
e7108d0e 823 case 2: // Write watchpoint\r
1e57a462 824 BreakType = DataWrite;\r
825 break;\r
826\r
e7108d0e 827 case 3: // Read watchpoint\r
1e57a462 828 BreakType = DataRead;\r
829 break;\r
830\r
e7108d0e 831 case 4: // Access watchpoint\r
1e57a462 832 BreakType = DataReadWrite;\r
833 break;\r
834\r
e7108d0e 835 default:\r
1e57a462 836 Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type);\r
837 SendError (GDB_EINVALIDBRKPOINTTYPE);\r
838 return;\r
839 }\r
840\r
841 // Find next free debug register\r
842 Status = FindNextFreeDebugRegister (SystemContext, &Register);\r
e7108d0e 843 if (EFI_ERROR (Status)) {\r
1e57a462 844 Print ((CHAR16 *)L"No space left on device\n");\r
845 SendError (GDB_ENOSPACE);\r
846 return;\r
847 }\r
848\r
849 // Write Address, length data at particular DR register\r
850 Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType);\r
e7108d0e 851 if (EFI_ERROR (Status)) {\r
1e57a462 852 if (Status == EFI_UNSUPPORTED) {\r
853 Print ((CHAR16 *)L"Not supported\n");\r
6f711615 854 SendNotSupported ();\r
1e57a462 855 return;\r
856 }\r
857\r
858 Print ((CHAR16 *)L"Invalid argument\n");\r
859 SendError (GDB_EINVALIDARG);\r
860 return;\r
861 }\r
862\r
863 SendSuccess ();\r
864}\r
865\r
1e57a462 866/**\r
867 ‘z1, [addr], [length]’\r
868 ‘z2, [addr], [length]’\r
869 ‘z3, [addr], [length]’\r
870 ‘z4, [addr], [length]’\r
871\r
872 Remove hardware breakpoint/watchpoint at address addr of size length\r
873\r
874 @param *PacketData Pointer to the Payload data for the packet\r
875\r
876**/\r
877VOID\r
878EFIAPI\r
879RemoveBreakPoint (\r
880 IN EFI_SYSTEM_CONTEXT SystemContext,\r
881 IN CHAR8 *PacketData\r
882 )\r
883{\r
e7108d0e
MK
884 UINTN Type;\r
885 UINTN Address;\r
886 UINTN Length;\r
887 UINTN Register;\r
888 BREAK_TYPE BreakType = NotSupported;\r
889 EFI_STATUS Status;\r
890 UINTN ErrorCode;\r
891\r
892 // Parse breakpoint packet data\r
1e57a462 893 ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);\r
894 if (ErrorCode > 0) {\r
895 SendError ((UINT8)ErrorCode);\r
896 return;\r
897 }\r
898\r
899 switch (Type) {\r
e7108d0e 900 case 0: // Software breakpoint\r
1e57a462 901 BreakType = SoftwareBreakpoint;\r
902 break;\r
3402aac7 903\r
e7108d0e 904 case 1: // Hardware breakpoint\r
1e57a462 905 BreakType = InstructionExecution;\r
906 break;\r
3402aac7 907\r
e7108d0e 908 case 2: // Write watchpoint\r
1e57a462 909 BreakType = DataWrite;\r
910 break;\r
911\r
e7108d0e 912 case 3: // Read watchpoint\r
1e57a462 913 BreakType = DataRead;\r
914 break;\r
915\r
e7108d0e 916 case 4: // Access watchpoint\r
1e57a462 917 BreakType = DataReadWrite;\r
918 break;\r
919\r
e7108d0e 920 default:\r
1e57a462 921 SendError (GDB_EINVALIDBRKPOINTTYPE);\r
922 return;\r
923 }\r
924\r
e7108d0e 925 // Find matching debug register\r
1e57a462 926 Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register);\r
e7108d0e 927 if (EFI_ERROR (Status)) {\r
1e57a462 928 if (Status == EFI_UNSUPPORTED) {\r
929 Print ((CHAR16 *)L"Not supported.\n");\r
6f711615 930 SendNotSupported ();\r
1e57a462 931 return;\r
932 }\r
933\r
934 Print ((CHAR16 *)L"No matching register found.\n");\r
935 SendError (GDB_ENOSPACE);\r
936 return;\r
937 }\r
938\r
e7108d0e 939 // Remove breakpoint\r
6f711615 940 Status = DisableDebugRegister (SystemContext, Register);\r
e7108d0e 941 if (EFI_ERROR (Status)) {\r
1e57a462 942 Print ((CHAR16 *)L"Invalid argument.\n");\r
943 SendError (GDB_EINVALIDARG);\r
944 return;\r
945 }\r
946\r
947 SendSuccess ();\r
948}\r
949\r
1e57a462 950VOID\r
951InitializeProcessor (\r
952 VOID\r
953 )\r
954{\r
955}\r
956\r
957BOOLEAN\r
958ValidateAddress (\r
959 IN VOID *Address\r
960 )\r
961{\r
962 return TRUE;\r
963}\r
964\r
965BOOLEAN\r
966ValidateException (\r
e7108d0e
MK
967 IN EFI_EXCEPTION_TYPE ExceptionType,\r
968 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
1e57a462 969 )\r
970{\r
971 return TRUE;\r
972}\r