[NTFS] - Add some fixes and improvements to attribute.c from CR-123:
[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@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
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
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
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
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 */