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