]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/GdbStub/SerialIo.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmbeddedPkg / GdbStub / SerialIo.c
1 /** @file
2 Serial IO Abstraction for GDB stub. This allows an EFI consoles that shows up on the system
3 running GDB. One console for error information and another console for user input/output.
4
5 Basic packet format is $packet-data#checksum. So every command has 4 bytes of overhead: $,
6 #, 0, 0. The 0 and 0 are the ascii characters for the checksum.
7
8
9 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
10
11 SPDX-License-Identifier: BSD-2-Clause-Patent
12
13 **/
14
15 #include <GdbStubInternal.h>
16
17 //
18 // Set TRUE if F Reply package signals a ctrl-c. We can not process the Ctrl-c
19 // here we need to wait for the periodic callback to do this.
20 //
21 BOOLEAN gCtrlCBreakFlag = FALSE;
22
23 //
24 // If the periodic callback is called while we are processing an F packet we need
25 // to let the callback know to not read from the serial stream as it could steal
26 // characters from the F response packet
27 //
28 BOOLEAN gProcessingFPacket = FALSE;
29
30 /**
31 Process a control-C break message.
32
33 Currently a place holder, remove the ASSERT when it gets implemented.
34
35 @param ErrNo Error information from the F reply packet or other source
36
37 **/
38 VOID
39 GdbCtrlCBreakMessage (
40 IN UINTN ErrNo
41 )
42 {
43 // See D.10.5 of gdb.pdf
44 // This should look like a break message. Should look like SIGINT
45
46 /* TODO: Make sure if we should do anything with ErrNo */
47 // Turn on the global Ctrl-C flag.
48 gCtrlCBreakFlag = TRUE;
49 }
50
51 /**
52 Parse the F reply packet and extract the return value and an ErrNo if it exists.
53
54 @param Packet Packet to parse like an F reply packet
55 @param ErrNo Buffer to hold Count bytes that were read
56
57 @retval -1 Error, not a valid F reply packet
58 @retval other Return the return code from the F reply packet
59
60 **/
61 INTN
62 GdbParseFReplyPacket (
63 IN CHAR8 *Packet,
64 OUT UINTN *ErrNo
65 )
66 {
67 INTN RetCode;
68
69 if (Packet[0] != 'F') {
70 // A valid response would be an F packet
71 return -1;
72 }
73
74 RetCode = AsciiStrHexToUintn (&Packet[1]);
75
76 // Find 1st comma
77 for ( ; *Packet != '\0' && *Packet != ','; Packet++) {
78 }
79
80 if (*Packet == '\0') {
81 *ErrNo = 0;
82 return RetCode;
83 }
84
85 *ErrNo = AsciiStrHexToUintn (++Packet);
86
87 // Find 2nd comma
88 for ( ; *Packet != '\0' && *Packet != ','; Packet++) {
89 }
90
91 if (*Packet == '\0') {
92 return RetCode;
93 }
94
95 if (*(++Packet) == 'C') {
96 GdbCtrlCBreakMessage (*ErrNo);
97 }
98
99 return RetCode;
100 }
101
102 /**
103 Read data from a FileDescriptor. On success number of bytes read is returned. Zero indicates
104 the end of a file. On error -1 is returned. If count is zero, GdbRead returns zero.
105
106 @param FileDescriptor Device to talk to.
107 @param Buffer Buffer to hold Count bytes that were read
108 @param Count Number of bytes to transfer.
109
110 @retval -1 Error
111 @retval {other} Number of bytes read.
112
113 **/
114 INTN
115 GdbRead (
116 IN INTN FileDescriptor,
117 OUT VOID *Buffer,
118 IN UINTN Count
119 )
120 {
121 CHAR8 Packet[128];
122 UINTN Size;
123 INTN RetCode;
124 UINTN ErrNo;
125 BOOLEAN ReceiveDone = FALSE;
126
127 // Send:
128 // "Fread,XX,YYYYYYYY,XX
129 //
130 // XX - FileDescriptor in ASCII
131 // YYYYYYYY - Buffer address in ASCII
132 // XX - Count in ASCII
133 // SS - check sum
134 //
135 Size = AsciiSPrint (Packet, sizeof (Packet), "Fread,%x,%x,%x", FileDescriptor, Buffer, Count);
136 // Packet array is too small if you got this ASSERT
137 ASSERT (Size < sizeof (Packet));
138
139 gProcessingFPacket = TRUE;
140 SendPacket (Packet);
141 Print ((CHAR16 *)L"Packet sent..\n");
142
143 do {
144 // Reply:
145 ReceivePacket (Packet, sizeof (Packet));
146 Print ((CHAR16 *)L"Command received..%c\n", Packet[0]);
147
148 // Process GDB commands
149 switch (Packet[0]) {
150 // Write memory command.
151 // M addr,length:XX...
152 case 'M':
153 WriteToMemory (Packet);
154 break;
155
156 // Fretcode, errno, Ctrl-C flag
157 // retcode - Count read
158 case 'F':
159 // Once target receives F reply packet that means the previous
160 // transactions are finished.
161 ReceiveDone = TRUE;
162 break;
163
164 // Send empty buffer
165 default:
166 SendNotSupported ();
167 break;
168 }
169 } while (ReceiveDone == FALSE);
170
171 RetCode = GdbParseFReplyPacket (Packet, &ErrNo);
172 Print ((CHAR16 *)L"RetCode: %x..ErrNo: %x..\n", RetCode, ErrNo);
173
174 if (ErrNo > 0) {
175 // Send error to the host if there is any.
176 SendError ((UINT8)ErrNo);
177 }
178
179 gProcessingFPacket = FALSE;
180
181 return RetCode;
182 }
183
184 /**
185 Write data to a FileDescriptor. On success number of bytes written is returned. Zero indicates
186 nothing was written. On error -1 is returned.
187
188 @param FileDescriptor Device to talk to.
189 @param Buffer Buffer to hold Count bytes that are to be written
190 @param Count Number of bytes to transfer.
191
192 @retval -1 Error
193 @retval {other} Number of bytes written.
194
195 **/
196 INTN
197 GdbWrite (
198 IN INTN FileDescriptor,
199 OUT CONST VOID *Buffer,
200 IN UINTN Count
201 )
202 {
203 CHAR8 Packet[128];
204 UINTN Size;
205 INTN RetCode;
206 UINTN ErrNo;
207 BOOLEAN ReceiveDone = FALSE;
208
209 // Send:
210 // #Fwrite,XX,YYYYYYYY,XX$SS
211 //
212 // XX - FileDescriptor in ASCII
213 // YYYYYYYY - Buffer address in ASCII
214 // XX - Count in ASCII
215 // SS - check sum
216 //
217 Size = AsciiSPrint (Packet, sizeof (Packet), "Fwrite,%x,%x,%x", FileDescriptor, Buffer, Count);
218 // Packet array is too small if you got this ASSERT
219 ASSERT (Size < sizeof (Packet));
220
221 SendPacket (Packet);
222 Print ((CHAR16 *)L"Packet sent..\n");
223
224 do {
225 // Reply:
226 ReceivePacket (Packet, sizeof (Packet));
227 Print ((CHAR16 *)L"Command received..%c\n", Packet[0]);
228
229 // Process GDB commands
230 switch (Packet[0]) {
231 // Read memory command.
232 // m addr,length.
233 case 'm':
234 ReadFromMemory (Packet);
235 break;
236
237 // Fretcode, errno, Ctrl-C flag
238 // retcode - Count read
239 case 'F':
240 // Once target receives F reply packet that means the previous
241 // transactions are finished.
242 ReceiveDone = TRUE;
243 break;
244
245 // Send empty buffer
246 default:
247 SendNotSupported ();
248 break;
249 }
250 } while (ReceiveDone == FALSE);
251
252 RetCode = GdbParseFReplyPacket (Packet, &ErrNo);
253 Print ((CHAR16 *)L"RetCode: %x..ErrNo: %x..\n", RetCode, ErrNo);
254
255 // Send error to the host if there is any.
256 if (ErrNo > 0) {
257 SendError ((UINT8)ErrNo);
258 }
259
260 return RetCode;
261 }
262
263 /**
264 Reset the serial device.
265
266 @param This Protocol instance pointer.
267
268 @retval EFI_SUCCESS The device was reset.
269 @retval EFI_DEVICE_ERROR The serial device could not be reset.
270
271 **/
272 EFI_STATUS
273 EFIAPI
274 GdbSerialReset (
275 IN EFI_SERIAL_IO_PROTOCOL *This
276 )
277 {
278 return EFI_SUCCESS;
279 }
280
281 /**
282 Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
283 data buts, and stop bits on a serial device.
284
285 @param This Protocol instance pointer.
286 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the
287 device's default interface speed.
288 @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the
289 serial interface. A ReceiveFifoDepth value of 0 will use
290 the device's default FIFO depth.
291 @param Timeout The requested time out for a single character in microseconds.
292 This timeout applies to both the transmit and receive side of the
293 interface. A Timeout value of 0 will use the device's default time
294 out value.
295 @param Parity The type of parity to use on this serial device. A Parity value of
296 DefaultParity will use the device's default parity value.
297 @param DataBits The number of data bits to use on the serial device. A DataBits
298 value of 0 will use the device's default data bit setting.
299 @param StopBits The number of stop bits to use on this serial device. A StopBits
300 value of DefaultStopBits will use the device's default number of
301 stop bits.
302
303 @retval EFI_SUCCESS The device was reset.
304 @retval EFI_DEVICE_ERROR The serial device could not be reset.
305
306 **/
307 EFI_STATUS
308 EFIAPI
309 GdbSerialSetAttributes (
310 IN EFI_SERIAL_IO_PROTOCOL *This,
311 IN UINT64 BaudRate,
312 IN UINT32 ReceiveFifoDepth,
313 IN UINT32 Timeout,
314 IN EFI_PARITY_TYPE Parity,
315 IN UINT8 DataBits,
316 IN EFI_STOP_BITS_TYPE StopBits
317 )
318 {
319 return EFI_UNSUPPORTED;
320 }
321
322 /**
323 Set the control bits on a serial device
324
325 @param This Protocol instance pointer.
326 @param Control Set the bits of Control that are settable.
327
328 @retval EFI_SUCCESS The new control bits were set on the serial device.
329 @retval EFI_UNSUPPORTED The serial device does not support this operation.
330 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
331
332 **/
333 EFI_STATUS
334 EFIAPI
335 GdbSerialSetControl (
336 IN EFI_SERIAL_IO_PROTOCOL *This,
337 IN UINT32 Control
338 )
339 {
340 return EFI_UNSUPPORTED;
341 }
342
343 /**
344 Retrieves the status of the control bits on a serial device
345
346 @param This Protocol instance pointer.
347 @param Control A pointer to return the current Control signals from the serial device.
348
349 @retval EFI_SUCCESS The control bits were read from the serial device.
350 @retval EFI_DEVICE_ERROR The serial device is not functioning correctly.
351
352 **/
353 EFI_STATUS
354 EFIAPI
355 GdbSerialGetControl (
356 IN EFI_SERIAL_IO_PROTOCOL *This,
357 OUT UINT32 *Control
358 )
359 {
360 return EFI_UNSUPPORTED;
361 }
362
363 /**
364 Writes data to a serial device.
365
366 @param This Protocol instance pointer.
367 @param BufferSize On input, the size of the Buffer. On output, the amount of
368 data actually written.
369 @param Buffer The buffer of data to write
370
371 @retval EFI_SUCCESS The data was written.
372 @retval EFI_DEVICE_ERROR The device reported an error.
373 @retval EFI_TIMEOUT The data write was stopped due to a timeout.
374
375 **/
376 EFI_STATUS
377 EFIAPI
378 GdbSerialWrite (
379 IN EFI_SERIAL_IO_PROTOCOL *This,
380 IN OUT UINTN *BufferSize,
381 IN VOID *Buffer
382 )
383 {
384 GDB_SERIAL_DEV *SerialDev;
385 UINTN Return;
386
387 SerialDev = GDB_SERIAL_DEV_FROM_THIS (This);
388
389 Return = GdbWrite (SerialDev->OutFileDescriptor, Buffer, *BufferSize);
390 if (Return == (UINTN)-1) {
391 return EFI_DEVICE_ERROR;
392 }
393
394 if (Return != *BufferSize) {
395 *BufferSize = Return;
396 }
397
398 return EFI_SUCCESS;
399 }
400
401 /**
402 Writes data to a serial device.
403
404 @param This Protocol instance pointer.
405 @param BufferSize On input, the size of the Buffer. On output, the amount of
406 data returned in Buffer.
407 @param Buffer The buffer to return the data into.
408
409 @retval EFI_SUCCESS The data was read.
410 @retval EFI_DEVICE_ERROR The device reported an error.
411 @retval EFI_TIMEOUT The data write was stopped due to a timeout.
412
413 **/
414 EFI_STATUS
415 EFIAPI
416 GdbSerialRead (
417 IN EFI_SERIAL_IO_PROTOCOL *This,
418 IN OUT UINTN *BufferSize,
419 OUT VOID *Buffer
420 )
421 {
422 GDB_SERIAL_DEV *SerialDev;
423 UINTN Return;
424
425 SerialDev = GDB_SERIAL_DEV_FROM_THIS (This);
426
427 Return = GdbRead (SerialDev->InFileDescriptor, Buffer, *BufferSize);
428 if (Return == (UINTN)-1) {
429 return EFI_DEVICE_ERROR;
430 }
431
432 if (Return != *BufferSize) {
433 *BufferSize = Return;
434 }
435
436 return EFI_SUCCESS;
437 }
438
439 //
440 // Template used to initialize the GDB Serial IO protocols
441 //
442 GDB_SERIAL_DEV gdbSerialDevTemplate = {
443 GDB_SERIAL_DEV_SIGNATURE,
444 NULL,
445
446 { // SerialIo
447 SERIAL_IO_INTERFACE_REVISION,
448 GdbSerialReset,
449 GdbSerialSetAttributes,
450 GdbSerialSetControl,
451 GdbSerialGetControl,
452 GdbSerialWrite,
453 GdbSerialRead,
454 NULL
455 },
456 { // SerialMode
457 0, // ControlMask
458 0, // Timeout
459 0, // BaudRate
460 1, // RceiveFifoDepth
461 0, // DataBits
462 0, // Parity
463 0 // StopBits
464 },
465 {
466 {
467 {
468 HARDWARE_DEVICE_PATH,
469 HW_VENDOR_DP,
470 {
471 (UINT8)(sizeof (VENDOR_DEVICE_PATH) + sizeof (UINT32)),
472 (UINT8)((sizeof (VENDOR_DEVICE_PATH) + sizeof (UINT32)) >> 8)
473 },
474 },
475 EFI_SERIAL_IO_PROTOCOL_GUID
476 },
477 0,
478 {
479 END_DEVICE_PATH_TYPE,
480 END_ENTIRE_DEVICE_PATH_SUBTYPE,
481 {
482 (UINT8)(sizeof (EFI_DEVICE_PATH_PROTOCOL)),
483 (UINT8)(sizeof (EFI_DEVICE_PATH_PROTOCOL) >> 8)
484 }
485 },
486 },
487 GDB_STDIN,
488 GDB_STDOUT
489 };
490
491 /**
492 Make two serial consoles: 1) StdIn and StdOut via GDB. 2) StdErr via GDB.
493
494 These console show up on the remote system running GDB
495
496 **/
497 VOID
498 GdbInitializeSerialConsole (
499 VOID
500 )
501 {
502 EFI_STATUS Status;
503 GDB_SERIAL_DEV *StdOutSerialDev;
504 GDB_SERIAL_DEV *StdErrSerialDev;
505
506 // Use the template to make a copy of the Serial Console private data structure.
507 StdOutSerialDev = AllocateCopyPool (sizeof (GDB_SERIAL_DEV), &gdbSerialDevTemplate);
508 ASSERT (StdOutSerialDev != NULL);
509
510 // Fixup pointer after the copy
511 StdOutSerialDev->SerialIo.Mode = &StdOutSerialDev->SerialMode;
512
513 StdErrSerialDev = AllocateCopyPool (sizeof (GDB_SERIAL_DEV), &gdbSerialDevTemplate);
514 ASSERT (StdErrSerialDev != NULL);
515
516 // Fixup pointer and modify stuff that is different for StdError
517 StdErrSerialDev->SerialIo.Mode = &StdErrSerialDev->SerialMode;
518 StdErrSerialDev->DevicePath.Index = 1;
519 StdErrSerialDev->OutFileDescriptor = GDB_STDERR;
520
521 // Make a new handle with Serial IO protocol and its device path on it.
522 Status = gBS->InstallMultipleProtocolInterfaces (
523 &StdOutSerialDev->Handle,
524 &gEfiSerialIoProtocolGuid,
525 &StdOutSerialDev->SerialIo,
526 &gEfiDevicePathProtocolGuid,
527 &StdOutSerialDev->DevicePath,
528 NULL
529 );
530 ASSERT_EFI_ERROR (Status);
531
532 // Make a new handle with Serial IO protocol and its device path on it.
533 Status = gBS->InstallMultipleProtocolInterfaces (
534 &StdErrSerialDev->Handle,
535 &gEfiSerialIoProtocolGuid,
536 &StdErrSerialDev->SerialIo,
537 &gEfiDevicePathProtocolGuid,
538 &StdErrSerialDev->DevicePath,
539 NULL
540 );
541 ASSERT_EFI_ERROR (Status);
542 }