kdcom: initial implementation of KdSendPacket() and KdReceivePacket(). Based on info...
[reactos.git] / reactos / drivers / base / kdcom / i386 / kdbg.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/base/kdcom/kdbg.c
5 * PURPOSE: Serial i/o functions for the kernel debugger.
6 * PROGRAMMER: Alex Ionescu
7 * Hervé Poussineau
8 * Timo Kreuzer
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #define NOEXTAPI
14 #include <ntddk.h>
15 #define NDEBUG
16 #include <halfuncs.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <debug.h>
20 #include "arc/arc.h"
21 #include "windbgkd.h"
22 #include <kddll.h>
23 #include <ioaccess.h> /* port intrinsics */
24
25 typedef struct _KD_PORT_INFORMATION
26 {
27 ULONG ComPort;
28 ULONG BaudRate;
29 ULONG_PTR BaseAddress;
30 } KD_PORT_INFORMATION, *PKD_PORT_INFORMATION;
31
32 BOOLEAN
33 NTAPI
34 KdPortInitializeEx(
35 IN PKD_PORT_INFORMATION PortInformation,
36 IN ULONG Unknown1,
37 IN ULONG Unknown2);
38
39 BOOLEAN
40 NTAPI
41 KdPortGetByteEx(
42 IN PKD_PORT_INFORMATION PortInformation,
43 OUT PUCHAR ByteReceived);
44
45 BOOLEAN
46 NTAPI
47 KdPortPollByteEx(
48 IN PKD_PORT_INFORMATION PortInformation,
49 OUT PUCHAR ByteReceived);
50
51 VOID
52 NTAPI
53 KdPortPutByteEx(
54 IN PKD_PORT_INFORMATION PortInformation,
55 IN UCHAR ByteToSend);
56
57 /* serial debug connection */
58 #define DEFAULT_DEBUG_PORT 2 /* COM2 */
59 #define DEFAULT_DEBUG_COM1_IRQ 4 /* COM1 IRQ */
60 #define DEFAULT_DEBUG_COM2_IRQ 3 /* COM2 IRQ */
61 #define DEFAULT_DEBUG_BAUD_RATE 115200 /* 115200 Baud */
62
63 #define DEFAULT_BAUD_RATE 19200
64
65 #ifdef _M_IX86
66 const ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
67 #elif defined(_M_PPC)
68 const ULONG BaseArray[2] = {0, 0x800003f8};
69 #elif defined(_M_MIPS)
70 const ULONG BaseArray[3] = {0, 0x80006000, 0x80007000};
71 #elif defined(_M_ARM)
72 const ULONG BaseArray[2] = {0, 0xF1012000};
73 #elif defined(_M_AMD64)
74 const ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
75 #else
76 #error Unknown architecture
77 #endif
78
79 /* MACROS *******************************************************************/
80
81 #define SER_RBR(x) ((PUCHAR)(x)+0)
82 #define SER_THR(x) ((PUCHAR)(x)+0)
83 #define SER_DLL(x) ((PUCHAR)(x)+0)
84 #define SER_IER(x) ((PUCHAR)(x)+1)
85 #define SR_IER_ERDA 0x01
86 #define SR_IER_ETHRE 0x02
87 #define SR_IER_ERLSI 0x04
88 #define SR_IER_EMS 0x08
89 #define SR_IER_ALL 0x0F
90 #define SER_DLM(x) ((PUCHAR)(x)+1)
91 #define SER_IIR(x) ((PUCHAR)(x)+2)
92 #define SER_FCR(x) ((PUCHAR)(x)+2)
93 #define SR_FCR_ENABLE_FIFO 0x01
94 #define SR_FCR_CLEAR_RCVR 0x02
95 #define SR_FCR_CLEAR_XMIT 0x04
96 #define SER_LCR(x) ((PUCHAR)(x)+3)
97 #define SR_LCR_CS5 0x00
98 #define SR_LCR_CS6 0x01
99 #define SR_LCR_CS7 0x02
100 #define SR_LCR_CS8 0x03
101 #define SR_LCR_ST1 0x00
102 #define SR_LCR_ST2 0x04
103 #define SR_LCR_PNO 0x00
104 #define SR_LCR_POD 0x08
105 #define SR_LCR_PEV 0x18
106 #define SR_LCR_PMK 0x28
107 #define SR_LCR_PSP 0x38
108 #define SR_LCR_BRK 0x40
109 #define SR_LCR_DLAB 0x80
110 #define SER_MCR(x) ((PUCHAR)(x)+4)
111 #define SR_MCR_DTR 0x01
112 #define SR_MCR_RTS 0x02
113 #define SR_MCR_OUT1 0x04
114 #define SR_MCR_OUT2 0x08
115 #define SR_MCR_LOOP 0x10
116 #define SER_LSR(x) ((PUCHAR)(x)+5)
117 #define SR_LSR_DR 0x01
118 #define SR_LSR_TBE 0x20
119 #define SER_MSR(x) ((PUCHAR)(x)+6)
120 #define SR_MSR_CTS 0x10
121 #define SR_MSR_DSR 0x20
122 #define SER_SCR(x) ((PUCHAR)(x)+7)
123
124
125 /* GLOBAL VARIABLES *********************************************************/
126
127 ULONG CurrentPacketId = INITIAL_PACKET_ID;
128
129 /* STATIC VARIABLES *********************************************************/
130
131 static KD_PORT_INFORMATION DefaultPort = { 0, 0, 0 };
132
133 /* The com port must only be initialized once! */
134 static BOOLEAN PortInitialized = FALSE;
135
136 ULONG KdpPort;
137 ULONG KdpPortIrq;
138
139 // HACK!!!
140 typedef ULONG (*DBGRNT)(const char *Format, ...);
141 DBGRNT FrLdrDbgPrint = 0;
142
143 /* STATIC FUNCTIONS *********************************************************/
144
145 static BOOLEAN
146 KdpDoesComPortExist(
147 IN ULONG_PTR BaseAddress)
148 {
149 BOOLEAN found;
150 UCHAR mcr;
151 UCHAR msr;
152
153 found = FALSE;
154
155 /* save Modem Control Register (MCR) */
156 mcr = READ_PORT_UCHAR(SER_MCR(BaseAddress));
157
158 /* enable loop mode (set Bit 4 of the MCR) */
159 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_LOOP);
160
161 /* clear all modem output bits */
162 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_LOOP);
163
164 /* read the Modem Status Register */
165 msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
166
167 /*
168 * the upper nibble of the MSR (modem output bits) must be
169 * equal to the lower nibble of the MCR (modem input bits)
170 */
171 if ((msr & 0xF0) == 0x00)
172 {
173 /* set all modem output bits */
174 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_DTR | SR_MCR_RTS | SR_MCR_OUT1 | SR_MCR_OUT2 | SR_MCR_LOOP);
175
176 /* read the Modem Status Register */
177 msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
178
179 /*
180 * the upper nibble of the MSR (modem output bits) must be
181 * equal to the lower nibble of the MCR (modem input bits)
182 */
183 if ((msr & 0xF0) == 0xF0)
184 {
185 /*
186 * setup a resonable state for the port:
187 * enable fifo and clear recieve/transmit buffers
188 */
189 WRITE_PORT_UCHAR(SER_FCR(BaseAddress),
190 (SR_FCR_ENABLE_FIFO | SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT));
191 WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0);
192 READ_PORT_UCHAR(SER_RBR(BaseAddress));
193 WRITE_PORT_UCHAR(SER_IER(BaseAddress), 0);
194 found = TRUE;
195 }
196 }
197
198 /* restore MCR */
199 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), mcr);
200
201 return found;
202 }
203
204
205 /* FUNCTIONS ****************************************************************/
206
207 NTSTATUS
208 DriverEntry(
209 IN PDRIVER_OBJECT DriverObject,
210 IN PUNICODE_STRING RegistryPath)
211 {
212 return STATUS_SUCCESS;
213 }
214
215 /* HAL.KdPortInitialize */
216 BOOLEAN
217 NTAPI
218 KdPortInitialize(
219 IN PKD_PORT_INFORMATION PortInformation,
220 IN ULONG Unknown1,
221 IN ULONG Unknown2)
222 {
223 SIZE_T i;
224 CHAR buffer[80];
225
226 if (!PortInitialized)
227 {
228 DefaultPort.BaudRate = PortInformation->BaudRate;
229
230 if (PortInformation->ComPort == 0)
231 {
232 for (i = sizeof(BaseArray) / sizeof(BaseArray[0]) - 1; i > 0; i--)
233 {
234 if (KdpDoesComPortExist(BaseArray[i]))
235 {
236 DefaultPort.BaseAddress = BaseArray[i];
237 DefaultPort.ComPort = i;
238 PortInformation->BaseAddress = DefaultPort.BaseAddress;
239 PortInformation->ComPort = DefaultPort.ComPort;
240 break;
241 }
242 }
243 if (i == 0)
244 {
245 sprintf(buffer,
246 "\nKernel Debugger: No COM port found!\n\n");
247 HalDisplayString(buffer);
248 return FALSE;
249 }
250 }
251
252 PortInitialized = TRUE;
253 }
254
255 /* initialize port */
256 if (!KdPortInitializeEx(&DefaultPort, Unknown1, Unknown2))
257 return FALSE;
258
259 /* set global info */
260 *KdComPortInUse = (PUCHAR)DefaultPort.BaseAddress;
261
262 return TRUE;
263 }
264
265
266 /* HAL.KdPortInitializeEx */
267 BOOLEAN
268 NTAPI
269 KdPortInitializeEx(
270 IN PKD_PORT_INFORMATION PortInformation,
271 IN ULONG Unknown1,
272 IN ULONG Unknown2)
273 {
274 ULONG_PTR ComPortBase;
275 CHAR buffer[80];
276 ULONG divisor;
277 UCHAR lcr;
278
279 #ifdef _ARM_
280 UNIMPLEMENTED;
281 return FALSE;
282 #endif
283
284 if (PortInformation->BaudRate == 0)
285 PortInformation->BaudRate = DEFAULT_BAUD_RATE;
286
287 if (PortInformation->ComPort == 0)
288 return FALSE;
289
290 if (!KdpDoesComPortExist(BaseArray[PortInformation->ComPort]))
291 {
292 sprintf(buffer,
293 "\nKernel Debugger: Serial port not found!\n\n");
294 HalDisplayString(buffer);
295 return FALSE;
296 }
297
298 ComPortBase = BaseArray[PortInformation->ComPort];
299 PortInformation->BaseAddress = ComPortBase;
300 #ifndef NDEBUG
301 sprintf(buffer,
302 "\nSerial port COM%ld found at 0x%lx\n",
303 PortInformation->ComPort,
304 ComPortBase);
305 HalDisplayString(buffer);
306 #endif /* NDEBUG */
307
308 /* set baud rate and data format (8N1) */
309
310 /* turn on DTR and RTS */
311 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), SR_MCR_DTR | SR_MCR_RTS);
312
313 /* set DLAB */
314 lcr = READ_PORT_UCHAR(SER_LCR(ComPortBase)) | SR_LCR_DLAB;
315 WRITE_PORT_UCHAR(SER_LCR(ComPortBase), lcr);
316
317 /* set baud rate */
318 divisor = 115200 / PortInformation->BaudRate;
319 WRITE_PORT_UCHAR(SER_DLL(ComPortBase), (UCHAR)(divisor & 0xff));
320 WRITE_PORT_UCHAR(SER_DLM(ComPortBase), (UCHAR)((divisor >> 8) & 0xff));
321
322 /* reset DLAB and set 8N1 format */
323 WRITE_PORT_UCHAR(SER_LCR(ComPortBase),
324 SR_LCR_CS8 | SR_LCR_ST1 | SR_LCR_PNO);
325
326 /* read junk out of the RBR */
327 lcr = READ_PORT_UCHAR(SER_RBR(ComPortBase));
328
329 #ifndef NDEBUG
330 /* print message to blue screen */
331 sprintf(buffer,
332 "\nKernel Debugger: COM%ld (Port 0x%lx) BaudRate %ld\n\n",
333 PortInformation->ComPort,
334 ComPortBase,
335 PortInformation->BaudRate);
336
337 HalDisplayString(buffer);
338 #endif /* NDEBUG */
339
340 return TRUE;
341 }
342
343
344 /* HAL.KdPortGetByte */
345 BOOLEAN
346 NTAPI
347 KdPortGetByte(
348 OUT PUCHAR ByteReceived)
349 {
350 if (!PortInitialized)
351 return FALSE;
352 return KdPortGetByteEx(&DefaultPort, ByteReceived);
353 }
354
355
356 /* HAL.KdPortGetByteEx */
357 BOOLEAN
358 NTAPI
359 KdPortGetByteEx(
360 IN PKD_PORT_INFORMATION PortInformation,
361 OUT PUCHAR ByteReceived)
362 {
363 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
364
365 if ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR))
366 {
367 *ByteReceived = READ_PORT_UCHAR(SER_RBR(ComPortBase));
368 return TRUE;
369 }
370
371 return FALSE;
372 }
373
374
375 /* HAL.KdPortPollByte */
376 BOOLEAN
377 NTAPI
378 KdPortPollByte(
379 OUT PUCHAR ByteReceived)
380 {
381 if (!PortInitialized)
382 return FALSE;
383 return KdPortPollByteEx(&DefaultPort, ByteReceived);
384 }
385
386
387 /* HAL.KdPortPollByteEx */
388 BOOLEAN
389 NTAPI
390 KdPortPollByteEx(
391 IN PKD_PORT_INFORMATION PortInformation,
392 OUT PUCHAR ByteReceived)
393 {
394 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
395
396 while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR) == 0)
397 ;
398
399 *ByteReceived = READ_PORT_UCHAR(SER_RBR(ComPortBase));
400
401 return TRUE;
402 }
403
404
405 /* HAL.KdPortPutByte */
406 VOID
407 NTAPI
408 KdPortPutByte(
409 IN UCHAR ByteToSend)
410 {
411 if (!PortInitialized)
412 return;
413 KdPortPutByteEx(&DefaultPort, ByteToSend);
414 }
415
416 /* HAL.KdPortPutByteEx */
417 VOID
418 NTAPI
419 KdPortPutByteEx(
420 IN PKD_PORT_INFORMATION PortInformation,
421 IN UCHAR ByteToSend)
422 {
423 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
424
425 while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_TBE) == 0)
426 ;
427
428 WRITE_PORT_UCHAR(SER_THR(ComPortBase), ByteToSend);
429 }
430
431
432 /* HAL.KdPortRestore */
433 VOID
434 NTAPI
435 KdPortRestore(VOID)
436 {
437 UNIMPLEMENTED;
438 }
439
440
441 /* HAL.KdPortSave */
442 VOID
443 NTAPI
444 KdPortSave(VOID)
445 {
446 UNIMPLEMENTED;
447 }
448
449
450 /* HAL.KdPortDisableInterrupts */
451 BOOLEAN
452 NTAPI
453 KdPortDisableInterrupts(VOID)
454 {
455 UCHAR ch;
456
457 if (!PortInitialized)
458 return FALSE;
459
460 ch = READ_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress));
461 ch &= (~(SR_MCR_OUT1 | SR_MCR_OUT2));
462 WRITE_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress), ch);
463
464 ch = READ_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress));
465 ch &= (~SR_IER_ALL);
466 WRITE_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress), ch);
467
468 return TRUE;
469 }
470
471
472 /* HAL.KdPortEnableInterrupts */
473 BOOLEAN
474 NTAPI
475 KdPortEnableInterrupts(VOID)
476 {
477 UCHAR ch;
478
479 if (PortInitialized == FALSE)
480 return FALSE;
481
482 ch = READ_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress));
483 ch &= (~SR_IER_ALL);
484 ch |= SR_IER_ERDA;
485 WRITE_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress), ch);
486
487 ch = READ_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress));
488 ch &= (~SR_MCR_LOOP);
489 ch |= (SR_MCR_OUT1 | SR_MCR_OUT2);
490 WRITE_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress), ch);
491
492 return TRUE;
493 }
494
495 /* NEW INTERNAL FUNCTIONS ****************************************************/
496
497 /******************************************************************************
498 * \name KdpCalculateChecksum
499 * \brief Calculates the checksum for the packet data.
500 * \param Buffer Pointer to the packet data.
501 * \param Length Length of data in bytes.
502 * \return The calculated checksum.
503 * \sa http://www.vista-xp.co.uk/forums/technical-reference-library/2540-basics-debugging.html
504 */
505 ULONG
506 NTAPI
507 KdpCalculateChecksum(
508 IN PVOID Buffer,
509 IN ULONG Length)
510 {
511 ULONG i, Checksum = 0;
512
513 for (i = 0; i < Length; i++)
514 {
515 Checksum += ((PUCHAR)Buffer)[i];
516 }
517 return Checksum;
518 }
519
520 /******************************************************************************
521 * \name KdpSendBuffer
522 * \brief Sends a buffer of data to the KD port.
523 * \param Buffer Pointer to the data.
524 * \param Size Size of data in bytes.
525 */
526 VOID
527 NTAPI
528 KdpSendBuffer(
529 IN PVOID Buffer,
530 IN ULONG Size)
531 {
532 INT i;
533 for (i = 0; i < Size; i++)
534 {
535 KdPortPutByteEx(&DefaultPort, ((PUCHAR)Buffer)[i]);
536 }
537 }
538
539
540 /******************************************************************************
541 * \name KdpReceiveBuffer
542 * \brief Recieves data from the KD port and fills a buffer.
543 * \param Buffer Pointer to a buffer that receives the data.
544 * \param Size Size of data to receive in bytes.
545 * \return KdPacketReceived if successful.
546 * KdPacketTimedOut if the receice timed out (10 seconds).
547 * \todo Handle timeout.
548 */
549 KDSTATUS
550 NTAPI
551 KdpReceiveBuffer(
552 OUT PVOID Buffer,
553 IN ULONG Size)
554 {
555 ULONG i;
556 PUCHAR ByteBuffer = Buffer;
557 BOOLEAN Ret, TimeOut;
558
559 for (i = 0; i < Size; i++)
560 {
561 do
562 {
563 Ret = KdPortGetByteEx(&DefaultPort, &ByteBuffer[i]);
564 TimeOut = FALSE; // FIXME timeout after 10 Sec
565 }
566 while (!Ret | TimeOut);
567
568 if (TimeOut)
569 {
570 return KdPacketTimedOut;
571 }
572 FrLdrDbgPrint("Received byte: %x\n", ByteBuffer[i]);
573 }
574
575 return KdPacketReceived;
576 }
577
578 /* NEW PUBLIC FUNCTIONS ******************************************************/
579
580 /******************************************************************************
581 * \name KdDebuggerInitialize0
582 * \brief Phase 0 initialization.
583 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
584 * \return Status
585 */
586 NTSTATUS
587 NTAPI
588 KdDebuggerInitialize0(
589 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
590 {
591 ULONG Value;
592 PCHAR CommandLine, Port, BaudRate, Irq;
593
594 /* Apply default values */
595 KdpPortIrq = 0;
596 DefaultPort.ComPort = DEFAULT_DEBUG_PORT;
597 DefaultPort.BaudRate = DEFAULT_DEBUG_BAUD_RATE;
598
599 /* Check if e have a LoaderBlock */
600 if (LoaderBlock)
601 {
602 /* Get the Command Line */
603 CommandLine = LoaderBlock->LoadOptions;
604
605 /* Upcase it */
606 _strupr(CommandLine);
607
608 /* Get the port and baud rate */
609 Port = strstr(CommandLine, "DEBUGPORT");
610 BaudRate = strstr(CommandLine, "BAUDRATE");
611 Irq = strstr(CommandLine, "IRQ");
612
613 /* Check if we got the /DEBUGPORT parameter */
614 if (Port)
615 {
616 /* Move past the actual string, to reach the port*/
617 Port += strlen("DEBUGPORT");
618
619 /* Now get past any spaces and skip the equal sign */
620 while (*Port == ' ') Port++;
621 Port++;
622
623 /* Do we have a serial port? */
624 if (strncmp(Port, "COM", 3) != 0)
625 {
626 return STATUS_INVALID_PARAMETER;
627 }
628
629 /* Gheck for a valid Serial Port */
630 Port += 3;
631 Value = atol(Port);
632 if (Value > 4)
633 {
634 return STATUS_INVALID_PARAMETER;
635 }
636
637 /* Set the port to use */
638 DefaultPort.ComPort = Value;
639 }
640
641 /* Check if we got a baud rate */
642 if (BaudRate)
643 {
644 /* Move past the actual string, to reach the rate */
645 BaudRate += strlen("BAUDRATE");
646
647 /* Now get past any spaces */
648 while (*BaudRate == ' ') BaudRate++;
649
650 /* And make sure we have a rate */
651 if (*BaudRate)
652 {
653 /* Read and set it */
654 Value = atol(BaudRate + 1);
655 if (Value) DefaultPort.BaudRate = Value;
656 }
657 }
658
659 /* Check Serial Port Settings [IRQ] */
660 if (Irq)
661 {
662 /* Move past the actual string, to reach the rate */
663 Irq += strlen("IRQ");
664
665 /* Now get past any spaces */
666 while (*Irq == ' ') Irq++;
667
668 /* And make sure we have an IRQ */
669 if (*Irq)
670 {
671 /* Read and set it */
672 Value = atol(Irq + 1);
673 if (Value) KdpPortIrq = Value;
674 }
675 }
676 }
677
678 // HACK use com1 for FrLdrDbg, com2 for WinDbg
679 DefaultPort.ComPort = 2;
680
681 /* Get base address */
682 DefaultPort.BaseAddress = BaseArray[DefaultPort.ComPort];
683
684 /* Check if the COM port does exist */
685 if (!KdpDoesComPortExist(DefaultPort.BaseAddress))
686 {
687 return STATUS_INVALID_PARAMETER;
688 }
689
690 /* Initialize the port */
691 KdPortInitializeEx(&DefaultPort, 0, 0);
692 PortInitialized = TRUE;
693
694 return STATUS_SUCCESS;
695 }
696
697 /******************************************************************************
698 * \name KdDebuggerInitialize0
699 * \brief Phase 0 initialization.
700 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
701 * \return Status
702 */
703 NTSTATUS
704 NTAPI
705 KdDebuggerInitialize1(
706 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
707 {
708 // HACK: misuse this function to get a pointer to FrLdrDbgPrint
709 FrLdrDbgPrint = (PVOID)LoaderBlock;
710 return STATUS_NOT_IMPLEMENTED;
711 }
712
713 /*
714 * @implemented
715 */
716 NTSTATUS
717 NTAPI
718 KdSave(
719 IN BOOLEAN SleepTransition)
720 {
721 /* Nothing to do on COM ports */
722 return STATUS_SUCCESS;
723 }
724
725 /*
726 * @implemented
727 */
728 NTSTATUS
729 NTAPI
730 KdRestore(
731 IN BOOLEAN SleepTransition)
732 {
733 /* Nothing to do on COM ports */
734 return STATUS_SUCCESS;
735 }
736
737 /*
738 * @unimplemented
739 */
740 VOID
741 NTAPI
742 KdSendPacket(
743 IN ULONG PacketType,
744 IN PSTRING MessageHeader,
745 IN PSTRING MessageData,
746 IN OUT PKD_CONTEXT Context)
747 {
748 KD_PACKET Packet;
749 KDSTATUS RcvCode;
750
751 for (;;)
752 {
753 /* Initialize a KD_PACKET */
754 Packet.PacketLeader = PACKET_LEADER;
755 Packet.PacketType = PacketType;
756 Packet.ByteCount = MessageHeader->Length;
757 Packet.Checksum = KdpCalculateChecksum(MessageHeader->Buffer,
758 MessageHeader->Length);
759
760 /* If we have message data, add it to the packet */
761 if (MessageData)
762 {
763 Packet.ByteCount += MessageData->Length;
764 Packet.Checksum += KdpCalculateChecksum(MessageData->Buffer,
765 MessageData->Length);
766 }
767
768 /* Set the packet id */
769 Packet.PacketId = CurrentPacketId;
770
771 /* Send the packet header to the KD port */
772 KdpSendBuffer(&Packet, sizeof(KD_PACKET));
773
774 /* Send the message header */
775 KdpSendBuffer(MessageHeader->Buffer, MessageHeader->Length);
776
777 /* If we have meesage data, also send it */
778 if (MessageData)
779 {
780 KdpSendBuffer(MessageData->Buffer, MessageData->Length);
781 }
782
783 /* Finalize with a trailing byte */
784 KdPortPutByte(PACKET_TRAILING_BYTE);
785
786 /* Wait for acknowledge */
787 RcvCode = KdReceivePacket(PACKET_TYPE_KD_ACKNOWLEDGE,
788 NULL,
789 NULL,
790 0,
791 NULL);
792
793 /* Did we succeed? */
794 if (RcvCode == KdPacketReceived)
795 {
796 break;
797 }
798
799 /* PACKET_TYPE_KD_DEBUG_IO is allowed to instantly timeout */
800 if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
801 {
802 /* No response, silently fail. */
803 return;
804 }
805
806 /* Packet timed out, send it again */
807 }
808
809 return;
810 }
811
812
813 /******************************************************************************
814 * \name KdReceivePacket
815 * \brief Receive a packet from the KD port.
816 * \param [in] PacketType Describes the type of the packet to receive.
817 * This can be one of the PACKET_TYPE_ constants.
818 * \param [out] MessageHeader Pointer to a STRING structure for the header.
819 * \param [out] MessageData Pointer to a STRING structure for the data.
820 * \return KdPacketReceived if successful, KdPacketTimedOut if the receive
821 * timed out, KdPacketNeedsResend to signal that the last packet needs
822 * to be sent again.
823 * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
824 * wait for any data, but returns KdPacketTimedOut instantly if no breakin
825 * packet byte is received.
826 * \sa http://www.nynaeve.net/?p=169
827 */
828 KDSTATUS
829 NTAPI
830 KdReceivePacket(
831 IN ULONG PacketType,
832 OUT PSTRING MessageHeader,
833 OUT PSTRING MessageData,
834 OUT PULONG DataLength,
835 IN OUT PKD_CONTEXT Context)
836 {
837 UCHAR BreakIn = 0;
838 KDSTATUS RcvCode;
839 KD_PACKET Packet;
840
841 /* Special handling for breakin packet */
842 if(PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
843 {
844 if (KdPortGetByteEx(&DefaultPort, &BreakIn))
845 {
846 if (BreakIn == BREAKIN_PACKET_BYTE)
847 {
848 return KdPacketReceived;
849 }
850 }
851 return KdPacketTimedOut;
852 }
853
854 for (;;)
855 {
856 /* Step 1 - Read PacketLeader */
857 RcvCode = KdpReceiveBuffer(&Packet.PacketLeader, sizeof(ULONG));
858 if ( (RcvCode != KdPacketReceived) ||
859 ((Packet.PacketLeader != BREAKIN_PACKET) &&
860 (Packet.PacketLeader != PACKET_LEADER) &&
861 (Packet.PacketLeader != CONTROL_PACKET_LEADER)) )
862 {
863 /* Couldn't read a correct packet leader. Start over. */
864 continue;
865 }
866
867 FrLdrDbgPrint("KdReceivePacket 1, PacketLeader == 0x%x\n", Packet.PacketLeader);
868
869 /* Step 2 - Read PacketType */
870 RcvCode = KdpReceiveBuffer(&Packet.PacketType, sizeof(USHORT));
871 if (RcvCode != KdPacketReceived) // FIXME: check PacketType
872 {
873 /* Didn't receive a PacketType or PacketType is bad. Start over. */
874 continue;
875 }
876
877 FrLdrDbgPrint("KdReceivePacket 2, PacketType == 0x%x\n", Packet.PacketType);
878
879 /* Step 3 - Read ByteCount */
880 RcvCode = KdpReceiveBuffer(&Packet.ByteCount, sizeof(USHORT));
881 if (RcvCode != KdPacketReceived)
882 {
883 /* Didn't receive ByteCount. Start over. */
884 continue;
885 }
886
887 FrLdrDbgPrint("KdReceivePacket 3, ByteCount == 0x%x\n", Packet.ByteCount);
888
889 /* Step 4 - Read PacketId */
890 RcvCode = KdpReceiveBuffer(&Packet.PacketId, sizeof(ULONG));
891 if (RcvCode != KdPacketReceived)
892 {
893 /* Didn't receive PacketId. Start over. */
894 continue;
895 }
896
897 FrLdrDbgPrint("KdReceivePacket 4, PacketId == 0x%x\n", Packet.PacketId);
898 /*
899 if (Packet.PacketId != ExpectedPacketId)
900 {
901 // Ask for a resend!
902 continue;
903 }
904 */
905
906 /* Step 5 - Read Checksum */
907 RcvCode = KdpReceiveBuffer(&Packet.Checksum, sizeof(ULONG));
908 if (RcvCode != KdPacketReceived)
909 {
910 /* Didn't receive Checksum. Start over. */
911 continue;
912 }
913
914 FrLdrDbgPrint("KdReceivePacket 5, Checksum == 0x%x\n", Packet.Checksum);
915
916
917
918 }
919
920 return KdPacketReceived;
921 }
922
923 /* EOF */