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 | }
|
---|