xref: /reactos/drivers/base/kdcom/kddll.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       GPL, see COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            drivers/base/kddll/kddll.c
5  * PURPOSE:         Base functions for the kernel debugger.
6  * PROGRAMMER:      Timo Kreuzer (timo.kreuzer@reactos.org)
7  */
8 
9 #include "kddll.h"
10 
11 /* GLOBALS ********************************************************************/
12 
13 ULONG CurrentPacketId = INITIAL_PACKET_ID | SYNC_PACKET_ID;
14 ULONG RemotePacketId  = INITIAL_PACKET_ID;
15 
16 
17 /* PRIVATE FUNCTIONS **********************************************************/
18 
19 /******************************************************************************
20  * \name KdpCalculateChecksum
21  * \brief Calculates the checksum for the packet data.
22  * \param Buffer Pointer to the packet data.
23  * \param Length Length of data in bytes.
24  * \return The calculated checksum.
25  * \sa http://www.vista-xp.co.uk/forums/technical-reference-library/2540-basics-debugging.html
26  */
27 ULONG
28 NTAPI
KdpCalculateChecksum(IN PVOID Buffer,IN ULONG Length)29 KdpCalculateChecksum(
30     IN PVOID Buffer,
31     IN ULONG Length)
32 {
33     PUCHAR ByteBuffer = Buffer;
34     ULONG Checksum = 0;
35 
36     while (Length-- > 0)
37     {
38         Checksum += (ULONG)*ByteBuffer++;
39     }
40     return Checksum;
41 }
42 
43 VOID
44 NTAPI
KdpSendControlPacket(IN USHORT PacketType,IN ULONG PacketId OPTIONAL)45 KdpSendControlPacket(
46     IN USHORT PacketType,
47     IN ULONG PacketId OPTIONAL)
48 {
49     KD_PACKET Packet;
50 
51     Packet.PacketLeader = CONTROL_PACKET_LEADER;
52     Packet.PacketId = PacketId;
53     Packet.ByteCount = 0;
54     Packet.Checksum = 0;
55     Packet.PacketType = PacketType;
56 
57     KdpSendBuffer(&Packet, sizeof(KD_PACKET));
58 }
59 
60 
61 /* PUBLIC FUNCTIONS ***********************************************************/
62 
63 /******************************************************************************
64  * \name KdReceivePacket
65  * \brief Receive a packet from the KD port.
66  * \param [in] PacketType Describes the type of the packet to receive.
67  *        This can be one of the PACKET_TYPE_ constants.
68  * \param [out] MessageHeader Pointer to a STRING structure for the header.
69  * \param [out] MessageData Pointer to a STRING structure for the data.
70  * \return KdPacketReceived if successful, KdPacketTimedOut if the receive
71  *         timed out, KdPacketNeedsResend to signal that the last packet needs
72  *         to be sent again.
73  * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
74  *       wait for any data, but returns KdPacketTimedOut instantly if no breakin
75  *       packet byte is received.
76  * \sa http://www.nynaeve.net/?p=169
77  */
78 KDP_STATUS
79 NTAPI
KdReceivePacket(IN ULONG PacketType,OUT PSTRING MessageHeader,OUT PSTRING MessageData,OUT PULONG DataLength,IN OUT PKD_CONTEXT KdContext)80 KdReceivePacket(
81     IN ULONG PacketType,
82     OUT PSTRING MessageHeader,
83     OUT PSTRING MessageData,
84     OUT PULONG DataLength,
85     IN OUT PKD_CONTEXT KdContext)
86 {
87     UCHAR Byte = 0;
88     KDP_STATUS KdStatus;
89     KD_PACKET Packet;
90     ULONG Checksum;
91 
92     /* Special handling for breakin packet */
93     if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
94     {
95         return KdpPollBreakIn();
96     }
97 
98     for (;;)
99     {
100         /* Step 1 - Read PacketLeader */
101         KdStatus = KdpReceivePacketLeader(&Packet.PacketLeader);
102         if (KdStatus != KDP_PACKET_RECEIVED)
103         {
104             /* Check if we got a breakin  */
105             if (KdStatus == KDP_PACKET_RESEND)
106             {
107                 KdContext->KdpControlCPending = TRUE;
108             }
109             return KdStatus;
110         }
111 
112         /* Step 2 - Read PacketType */
113         KdStatus = KdpReceiveBuffer(&Packet.PacketType, sizeof(USHORT));
114         if (KdStatus != KDP_PACKET_RECEIVED)
115         {
116             /* Didn't receive a PacketType. */
117             return KdStatus;
118         }
119 
120         /* Check if we got a resend packet */
121         if (Packet.PacketLeader == CONTROL_PACKET_LEADER &&
122             Packet.PacketType == PACKET_TYPE_KD_RESEND)
123         {
124             return KDP_PACKET_RESEND;
125         }
126 
127         /* Step 3 - Read ByteCount */
128         KdStatus = KdpReceiveBuffer(&Packet.ByteCount, sizeof(USHORT));
129         if (KdStatus != KDP_PACKET_RECEIVED)
130         {
131             /* Didn't receive ByteCount. */
132             return KdStatus;
133         }
134 
135         /* Step 4 - Read PacketId */
136         KdStatus = KdpReceiveBuffer(&Packet.PacketId, sizeof(ULONG));
137         if (KdStatus != KDP_PACKET_RECEIVED)
138         {
139             /* Didn't receive PacketId. */
140             return KdStatus;
141         }
142 
143 /*
144         if (Packet.PacketId != ExpectedPacketId)
145         {
146             // Ask for a resend!
147             continue;
148         }
149 */
150 
151         /* Step 5 - Read Checksum */
152         KdStatus = KdpReceiveBuffer(&Packet.Checksum, sizeof(ULONG));
153         if (KdStatus != KDP_PACKET_RECEIVED)
154         {
155             /* Didn't receive Checksum. */
156             return KdStatus;
157         }
158 
159         /* Step 6 - Handle control packets */
160         if (Packet.PacketLeader == CONTROL_PACKET_LEADER)
161         {
162             switch (Packet.PacketType)
163             {
164                 case PACKET_TYPE_KD_ACKNOWLEDGE:
165                     /* Are we waiting for an ACK packet? */
166                     if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE &&
167                         Packet.PacketId == (CurrentPacketId & ~SYNC_PACKET_ID))
168                     {
169                         /* Remote acknowledges the last packet */
170                         CurrentPacketId ^= 1;
171                         return KDP_PACKET_RECEIVED;
172                     }
173                     /* That's not what we were waiting for, start over */
174                     continue;
175 
176                 case PACKET_TYPE_KD_RESET:
177                     KDDBGPRINT("KdReceivePacket - got PACKET_TYPE_KD_RESET\n");
178                     CurrentPacketId = INITIAL_PACKET_ID;
179                     RemotePacketId  = INITIAL_PACKET_ID;
180                     KdpSendControlPacket(PACKET_TYPE_KD_RESET, 0);
181                     /* Fall through */
182 
183                 case PACKET_TYPE_KD_RESEND:
184                     KDDBGPRINT("KdReceivePacket - got PACKET_TYPE_KD_RESEND\n");
185                     /* Remote wants us to resend the last packet */
186                     return KDP_PACKET_RESEND;
187 
188                 default:
189                     KDDBGPRINT("KdReceivePacket - got unknown control packet\n");
190                     /* We got an invalid packet, ignore it and start over */
191                     continue;
192             }
193         }
194 
195         /* Did we wait for an ack packet? */
196         if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE)
197         {
198             /* We received something different */
199             KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
200             CurrentPacketId ^= 1;
201             return KDP_PACKET_RECEIVED;
202         }
203 
204         /* Get size of the message header */
205         MessageHeader->Length = MessageHeader->MaximumLength;
206 
207         /* Packet smaller than expected or too big? */
208         if (Packet.ByteCount < MessageHeader->Length ||
209             Packet.ByteCount > PACKET_MAX_SIZE)
210         {
211             KDDBGPRINT("KdReceivePacket - too few data (%d) for type %d\n",
212                           Packet.ByteCount, MessageHeader->Length);
213             MessageHeader->Length = Packet.ByteCount;
214             KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
215             continue;
216         }
217 
218         //KDDBGPRINT("KdReceivePacket - got normal PacketType, Buffer = %p\n", MessageHeader->Buffer);
219 
220         /* Receive the message header data */
221         KdStatus = KdpReceiveBuffer(MessageHeader->Buffer,
222                                     MessageHeader->Length);
223         if (KdStatus != KDP_PACKET_RECEIVED)
224         {
225             /* Didn't receive data. Packet needs to be resent. */
226             KDDBGPRINT("KdReceivePacket - Didn't receive message header data.\n");
227             KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
228             continue;
229         }
230 
231         //KDDBGPRINT("KdReceivePacket - got normal PacketType 3\n");
232 
233         /* Calculate checksum for the header data */
234         Checksum = KdpCalculateChecksum(MessageHeader->Buffer,
235                                         MessageHeader->Length);
236 
237         /* Calculate the length of the message data */
238         *DataLength = Packet.ByteCount - MessageHeader->Length;
239 
240         /* Shall we receive message data? */
241         if (MessageData)
242         {
243             /* Set the length of the message data */
244             MessageData->Length = (USHORT)*DataLength;
245 
246             /* Do we have data? */
247             if (MessageData->Length)
248             {
249                 KDDBGPRINT("KdReceivePacket - got data\n");
250 
251                 /* Receive the message data */
252                 KdStatus = KdpReceiveBuffer(MessageData->Buffer,
253                                            MessageData->Length);
254                 if (KdStatus != KDP_PACKET_RECEIVED)
255                 {
256                     /* Didn't receive data. Start over. */
257                     KDDBGPRINT("KdReceivePacket - Didn't receive message data.\n");
258                     KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
259                     continue;
260                 }
261 
262                 /* Add cheksum for message data */
263                 Checksum += KdpCalculateChecksum(MessageData->Buffer,
264                                                  MessageData->Length);
265             }
266         }
267 
268         /* We must receive a PACKET_TRAILING_BYTE now */
269         KdStatus = KdpReceiveBuffer(&Byte, sizeof(UCHAR));
270         if (KdStatus != KDP_PACKET_RECEIVED || Byte != PACKET_TRAILING_BYTE)
271         {
272             KDDBGPRINT("KdReceivePacket - wrong trailing byte (0x%x), status 0x%x\n", Byte, KdStatus);
273             KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
274             continue;
275         }
276 
277         /* Compare checksum */
278         if (Packet.Checksum != Checksum)
279         {
280             KDDBGPRINT("KdReceivePacket - wrong cheksum, got %x, calculated %x\n",
281                        Packet.Checksum, Checksum);
282             KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
283             continue;
284         }
285 
286         /* Acknowledge the received packet */
287         KdpSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE, Packet.PacketId);
288 
289         /* Check if the received PacketId is ok */
290         if (Packet.PacketId != RemotePacketId)
291         {
292             /* Continue with next packet */
293             continue;
294         }
295 
296         /* Did we get the right packet type? */
297         if (PacketType == Packet.PacketType)
298         {
299             /* Yes, return success */
300             //KDDBGPRINT("KdReceivePacket - all ok\n");
301             RemotePacketId ^= 1;
302             return KDP_PACKET_RECEIVED;
303         }
304 
305         /* We received something different, ignore it. */
306         KDDBGPRINT("KdReceivePacket - wrong PacketType\n");
307     }
308 
309     return KDP_PACKET_RECEIVED;
310 }
311 
312 VOID
313 NTAPI
KdSendPacket(IN ULONG PacketType,IN PSTRING MessageHeader,IN PSTRING MessageData,IN OUT PKD_CONTEXT KdContext)314 KdSendPacket(
315     IN ULONG PacketType,
316     IN PSTRING MessageHeader,
317     IN PSTRING MessageData,
318     IN OUT PKD_CONTEXT KdContext)
319 {
320     KD_PACKET Packet;
321     KDP_STATUS KdStatus;
322     ULONG Retries;
323 
324     /* Initialize a KD_PACKET */
325     Packet.PacketLeader = PACKET_LEADER;
326     Packet.PacketType = (USHORT)PacketType;
327     Packet.ByteCount = MessageHeader->Length;
328     Packet.Checksum = KdpCalculateChecksum(MessageHeader->Buffer,
329                                            MessageHeader->Length);
330 
331     /* If we have message data, add it to the packet */
332     if (MessageData)
333     {
334         Packet.ByteCount += MessageData->Length;
335         Packet.Checksum += KdpCalculateChecksum(MessageData->Buffer,
336                                                 MessageData->Length);
337     }
338 
339     Retries = KdContext->KdpDefaultRetries;
340 
341     for (;;)
342     {
343         /* Set the packet id */
344         Packet.PacketId = CurrentPacketId;
345 
346         /* Send the packet header to the KD port */
347         KdpSendBuffer(&Packet, sizeof(KD_PACKET));
348 
349         /* Send the message header */
350         KdpSendBuffer(MessageHeader->Buffer, MessageHeader->Length);
351 
352         /* If we have message data, also send it */
353         if (MessageData)
354         {
355             KdpSendBuffer(MessageData->Buffer, MessageData->Length);
356         }
357 
358         /* Finalize with a trailing byte */
359         KdpSendByte(PACKET_TRAILING_BYTE);
360 
361         /* Wait for acknowledge */
362         KdStatus = KdReceivePacket(PACKET_TYPE_KD_ACKNOWLEDGE,
363                                    NULL,
364                                    NULL,
365                                    NULL,
366                                    KdContext);
367 
368         /* Did we succeed? */
369         if (KdStatus == KDP_PACKET_RECEIVED)
370         {
371             /* Packet received, we can quit the loop */
372             CurrentPacketId &= ~SYNC_PACKET_ID;
373             Retries = KdContext->KdpDefaultRetries;
374             break;
375         }
376         else if (KdStatus == KDP_PACKET_TIMEOUT)
377         {
378             /* Timeout, decrement the retry count */
379             if (Retries > 0)
380                 Retries--;
381 
382             /*
383              * If the retry count reaches zero, bail out
384              * for packet types allowed to timeout.
385              */
386             if (Retries == 0)
387             {
388                 ULONG MessageId = *(PULONG)MessageHeader->Buffer;
389                 switch (PacketType)
390                 {
391                     case PACKET_TYPE_KD_DEBUG_IO:
392                     {
393                         if (MessageId != DbgKdPrintStringApi) continue;
394                         break;
395                     }
396 
397                     case PACKET_TYPE_KD_STATE_CHANGE32:
398                     case PACKET_TYPE_KD_STATE_CHANGE64:
399                     {
400                         if (MessageId != DbgKdLoadSymbolsStateChange) continue;
401                         break;
402                     }
403 
404                     case PACKET_TYPE_KD_FILE_IO:
405                     {
406                         if (MessageId != DbgKdCreateFileApi) continue;
407                         break;
408                     }
409                 }
410 
411                 /* Reset debugger state */
412                 KD_DEBUGGER_NOT_PRESENT = TRUE;
413                 SharedUserData->KdDebuggerEnabled &= ~0x00000002;
414                 CurrentPacketId = INITIAL_PACKET_ID | SYNC_PACKET_ID;
415                 RemotePacketId  = INITIAL_PACKET_ID;
416 
417                 return;
418             }
419         }
420         // else (KdStatus == KDP_PACKET_RESEND) /* Resend the packet */
421 
422         /* Packet timed out, send it again */
423         KDDBGPRINT("KdSendPacket got KdStatus 0x%x\n", KdStatus);
424     }
425 }
426 
427 /* EOF */
428