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