Patch "works": continue vs return stuff
[reactos.git] / reactos / 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 #define _FULL_ 1
12 #define _WORKS_ 0
13 #define _WORKS2_ 0
14
15 /* GLOBALS ********************************************************************/
16
17 ULONG CurrentPacketId = INITIAL_PACKET_ID | SYNC_PACKET_ID;
18 ULONG RemotePacketId = INITIAL_PACKET_ID;
19
20 #if _FULL_
21 ULONG KdCompNumberRetries = 5;
22 ULONG KdCompRetryCount = 5;
23 #endif
24
25 /* PRIVATE FUNCTIONS **********************************************************/
26
27 /******************************************************************************
28 * \name KdpCalculateChecksum
29 * \brief Calculates the checksum for the packet data.
30 * \param Buffer Pointer to the packet data.
31 * \param Length Length of data in bytes.
32 * \return The calculated checksum.
33 * \sa http://www.vista-xp.co.uk/forums/technical-reference-library/2540-basics-debugging.html
34 */
35 ULONG
36 NTAPI
37 KdpCalculateChecksum(
38 IN PVOID Buffer,
39 IN ULONG Length)
40 {
41 ULONG i, Checksum = 0;
42
43 for (i = 0; i < Length; i++)
44 {
45 Checksum += ((PUCHAR)Buffer)[i];
46 }
47
48 return Checksum;
49 }
50
51 VOID
52 NTAPI
53 KdpSendControlPacket(
54 IN USHORT PacketType,
55 IN ULONG PacketId OPTIONAL)
56 {
57 KD_PACKET Packet;
58
59 Packet.PacketLeader = CONTROL_PACKET_LEADER;
60 Packet.PacketId = PacketId;
61 Packet.ByteCount = 0;
62 Packet.Checksum = 0;
63 Packet.PacketType = PacketType;
64
65 KdpSendBuffer(&Packet, sizeof(KD_PACKET));
66 }
67
68
69 /* PUBLIC FUNCTIONS ***********************************************************/
70
71 NTSTATUS
72 NTAPI
73 KdD0Transition(VOID)
74 {
75 return STATUS_SUCCESS;
76 }
77
78 NTSTATUS
79 NTAPI
80 KdD3Transition(VOID)
81 {
82 return STATUS_SUCCESS;
83 }
84
85
86 /******************************************************************************
87 * \name KdDebuggerInitialize1
88 * \brief Phase 1 initialization.
89 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
90 * \return Status
91 */
92 NTSTATUS
93 NTAPI
94 KdDebuggerInitialize1(
95 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
96 {
97 return STATUS_SUCCESS;
98 }
99
100
101 /******************************************************************************
102 * \name KdReceivePacket
103 * \brief Receive a packet from the KD port.
104 * \param [in] PacketType Describes the type of the packet to receive.
105 * This can be one of the PACKET_TYPE_ constants.
106 * \param [out] MessageHeader Pointer to a STRING structure for the header.
107 * \param [out] MessageData Pointer to a STRING structure for the data.
108 * \return KdPacketReceived if successful, KdPacketTimedOut if the receive
109 * timed out, KdPacketNeedsResend to signal that the last packet needs
110 * to be sent again.
111 * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
112 * wait for any data, but returns KdPacketTimedOut instantly if no breakin
113 * packet byte is received.
114 * \sa http://www.nynaeve.net/?p=169
115 */
116 KDP_STATUS
117 NTAPI
118 KdReceivePacket(
119 IN ULONG PacketType,
120 OUT PSTRING MessageHeader,
121 OUT PSTRING MessageData,
122 OUT PULONG DataLength,
123 IN OUT PKD_CONTEXT KdContext)
124 {
125 UCHAR Byte = 0;
126 KDP_STATUS KdStatus;
127 KD_PACKET Packet;
128 ULONG Checksum;
129
130 /* Special handling for breakin packet */
131 if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
132 {
133 return KdpPollBreakIn();
134 }
135
136 for (;;)
137 {
138 #if _FULL_ || _WORKS2_
139 if (KdContext)
140 {
141 KdContext->KdpControlCPending = FALSE;
142 }
143 #endif
144 /* Step 1 - Read PacketLeader */
145 KdStatus = KdpReceivePacketLeader(&Packet.PacketLeader);
146 #if _FULL_
147 if (KdStatus != KDP_PACKET_TIMEOUT)
148 {
149 // KdCompNumberRetries = KdCompRetryCount;
150 }
151 #endif
152 if (KdStatus != KDP_PACKET_RECEIVED)
153 {
154 /* Check if we got a breakin */
155 if (KdStatus == KDP_PACKET_RESEND)
156 {
157 #if _FULL_ || _WORKS2_ || _PATCH_
158 if (KdContext)
159 #endif
160 KdContext->KdpControlCPending = TRUE;
161 }
162 return KdStatus;
163 }
164
165 /* Step 2 - Read PacketType */
166 KdStatus = KdpReceiveBuffer(&Packet.PacketType, sizeof(USHORT));
167 if (KdStatus != KDP_PACKET_RECEIVED)
168 {
169 /* Didn't receive a PacketType. */
170 KDDBGPRINT("KdReceivePacket - Didn't receive a PacketType.\n");
171 #if _WORKS_
172 continue;
173 #else
174 return KdStatus;
175 #endif
176 }
177
178 /* Check if we got a resend packet */
179 if (Packet.PacketLeader == CONTROL_PACKET_LEADER &&
180 Packet.PacketType == PACKET_TYPE_KD_RESEND)
181 {
182 KDDBGPRINT("KdReceivePacket - PACKET_TYPE_KD_RESEND.\n");
183 return KDP_PACKET_RESEND;
184 }
185
186 /* Step 3 - Read ByteCount */
187 KdStatus = KdpReceiveBuffer(&Packet.ByteCount, sizeof(USHORT));
188 #if _WORKS_
189 if (KdStatus != KDP_PACKET_RECEIVED || Packet.ByteCount > PACKET_MAX_SIZE)
190 #else
191 if (KdStatus != KDP_PACKET_RECEIVED)
192 #endif
193 {
194 /* Didn't receive ByteCount _WORKS_: or it's too big. Start over. */
195 KDDBGPRINT("KdReceivePacket - Didn't receive ByteCount.\n");
196 #if _WORKS_
197 continue;
198 #else
199 return KdStatus;
200 #endif
201 }
202
203 /* Step 4 - Read PacketId */
204 KdStatus = KdpReceiveBuffer(&Packet.PacketId, sizeof(ULONG));
205 if (KdStatus != KDP_PACKET_RECEIVED)
206 {
207 /* Didn't receive PacketId. */
208 KDDBGPRINT("KdReceivePacket - Didn't receive PacketId.\n");
209 #if _WORKS_
210 continue;
211 #else
212 return KdStatus;
213 #endif
214 }
215
216 /*
217 if (Packet.PacketId != ExpectedPacketId)
218 {
219 // Ask for a resend!
220 continue;
221 }
222 */
223
224 /* Step 5 - Read Checksum */
225 KdStatus = KdpReceiveBuffer(&Packet.Checksum, sizeof(ULONG));
226 if (KdStatus != KDP_PACKET_RECEIVED)
227 {
228 /* Didn't receive Checksum. */
229 KDDBGPRINT("KdReceivePacket - Didn't receive Checksum.\n");
230 #if _WORKS_
231 continue;
232 #else
233 return KdStatus;
234 #endif
235 }
236
237 /* Step 6 - Handle control packets */
238 if (Packet.PacketLeader == CONTROL_PACKET_LEADER)
239 {
240 switch (Packet.PacketType)
241 {
242 case PACKET_TYPE_KD_ACKNOWLEDGE:
243 /* Are we waiting for an ACK packet? */
244 if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE &&
245 Packet.PacketId == (CurrentPacketId & ~SYNC_PACKET_ID))
246 {
247 /* Remote acknowledges the last packet */
248 CurrentPacketId ^= 1;
249 return KDP_PACKET_RECEIVED;
250 }
251 /* That's not what we were waiting for, start over */
252 continue;
253
254 case PACKET_TYPE_KD_RESET:
255 KDDBGPRINT("KdReceivePacket - got PACKET_TYPE_KD_RESET\n");
256 CurrentPacketId = INITIAL_PACKET_ID;
257 RemotePacketId = INITIAL_PACKET_ID;
258 KdpSendControlPacket(PACKET_TYPE_KD_RESET, 0);
259 /* Fall through */
260
261 case PACKET_TYPE_KD_RESEND:
262 KDDBGPRINT("KdReceivePacket - got PACKET_TYPE_KD_RESEND\n");
263 /* Remote wants us to resend the last packet */
264 return KDP_PACKET_RESEND;
265
266 default:
267 KDDBGPRINT("KdReceivePacket - got unknown control packet\n");
268 #if _FULL_
269 continue;
270 #else
271 return KDP_PACKET_RESEND;
272 #endif
273 }
274 }
275
276 /* Did we wait for an ack packet? */
277 if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE)
278 {
279 /* We received something different */
280 #if _FULL_ || _WORKS2_
281 if (Packet.PacketId != RemotePacketId)
282 {
283 KdpSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE,
284 Packet.PacketId);
285 continue;
286 }
287 #elif _PATCH_
288 DBGKD_MANIPULATE_STATE64 State;
289 KdStatus = KdpReceiveBuffer(&State, sizeof(State));
290 KDDBGPRINT("KdReceivePacket - unxpected Packet.PacketType=0x%x, 0x%x, 0x%x\n",
291 Packet.PacketType, Packet.Checksum, State.ApiNumber);
292 #endif
293 KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
294 CurrentPacketId ^= 1;
295 return KDP_PACKET_RECEIVED;
296 }
297
298 /* Get size of the message header */
299 #if _WORKS_
300 switch (Packet.PacketType)
301 {
302 case PACKET_TYPE_KD_STATE_CHANGE64:
303 MessageHeader->Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
304 break;
305
306 case PACKET_TYPE_KD_STATE_MANIPULATE:
307 MessageHeader->Length = sizeof(DBGKD_MANIPULATE_STATE64);
308 break;
309
310 case PACKET_TYPE_KD_DEBUG_IO:
311 MessageHeader->Length = sizeof(DBGKD_DEBUG_IO);
312 break;
313
314 default:
315 KDDBGPRINT("KdReceivePacket - unknown PacketType\n");
316 return KDP_PACKET_RESEND;
317 }
318
319 //KDDBGPRINT("KdReceivePacket - got normal PacketType\n");
320
321 /* Packet smaller than expected? */
322 if (MessageHeader->Length > Packet.ByteCount)
323 #else
324 MessageHeader->Length = MessageHeader->MaximumLength;
325
326 /* Packet smaller than expected or too big? */
327 if (Packet.ByteCount < MessageHeader->Length ||
328 Packet.ByteCount > PACKET_MAX_SIZE)
329 #endif
330 {
331 KDDBGPRINT("KdReceivePacket - too few data (%d) for type %d\n",
332 Packet.ByteCount, MessageHeader->Length);
333 MessageHeader->Length = Packet.ByteCount;
334 KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
335 continue;
336 }
337
338 //KDDBGPRINT("KdReceivePacket - got normal PacketType, Buffer = %p\n", MessageHeader->Buffer);
339
340 /* Receive the message header data */
341 #if _WORKS2_
342 MessageHeader->Length = MessageHeader->MaximumLength;
343 #endif
344 KdStatus = KdpReceiveBuffer(MessageHeader->Buffer,
345 MessageHeader->Length);
346 if (KdStatus != KDP_PACKET_RECEIVED)
347 {
348 /* Didn't receive data. Packet needs to be resent. */
349 KDDBGPRINT("KdReceivePacket - Didn't receive message header data.\n");
350 KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
351 continue;
352 }
353
354 //KDDBGPRINT("KdReceivePacket - got normal PacketType 3\n");
355
356 /* Calculate checksum for the header data */
357 Checksum = KdpCalculateChecksum(MessageHeader->Buffer,
358 MessageHeader->Length);
359
360 /* Calculate the length of the message data */
361 *DataLength = Packet.ByteCount - MessageHeader->Length;
362
363 /* Shall we receive messsage data? */
364 if (MessageData)
365 {
366 /* Set the length of the message data */
367 MessageData->Length = (USHORT)*DataLength;
368
369 /* Do we have data? */
370 if (MessageData->Length)
371 {
372 KDDBGPRINT("KdReceivePacket - 0x%lx bytes data\n", *DataLength);
373
374 /* Receive the message data */
375 KdStatus = KdpReceiveBuffer(MessageData->Buffer,
376 MessageData->Length);
377 if (KdStatus != KDP_PACKET_RECEIVED)
378 {
379 /* Didn't receive data. Start over. */
380 KDDBGPRINT("KdReceivePacket - Didn't receive message data.\n");
381 KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
382 continue;
383 }
384
385 /* Add cheksum for message data */
386 Checksum += KdpCalculateChecksum(MessageData->Buffer,
387 MessageData->Length);
388 }
389 }
390
391 /* We must receive a PACKET_TRAILING_BYTE now */
392 KdStatus = KdpReceiveBuffer(&Byte, sizeof(UCHAR));
393 if (KdStatus != KDP_PACKET_RECEIVED || Byte != PACKET_TRAILING_BYTE)
394 {
395 KDDBGPRINT("KdReceivePacket - wrong trailing byte (0x%x), status 0x%x\n", Byte, KdStatus);
396 KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
397 continue;
398 }
399
400 /* Compare checksum */
401 if (Packet.Checksum != Checksum)
402 {
403 KDDBGPRINT("KdReceivePacket - wrong cheksum, got %x, calculated %x\n",
404 Packet.Checksum, Checksum);
405 KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
406 continue;
407 }
408
409 #if _FULL_ || _WORKS2_
410 if (Packet.PacketId != INITIAL_PACKET_ID &&
411 Packet.PacketId != (INITIAL_PACKET_ID ^ 1))
412 {
413 KdpSendControlPacket(PACKET_TYPE_KD_RESEND, 0);
414 continue;
415 }
416 #endif
417
418 /* Acknowledge the received packet */
419 KdpSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE, Packet.PacketId);
420
421 /* Check if the received PacketId is ok */
422 if (Packet.PacketId != RemotePacketId)
423 {
424 /* Continue with next packet */
425 KDDBGPRINT("KdReceivePacket - Wrong PacketId.\n");
426 continue;
427 }
428
429 /* Did we get the right packet type? */
430 if (PacketType == Packet.PacketType)
431 {
432 /* Yes, return success */
433 //KDDBGPRINT("KdReceivePacket - all ok\n");
434 RemotePacketId ^= 1;
435 return KDP_PACKET_RECEIVED;
436 }
437
438 /* We received something different, ignore it. */
439 KDDBGPRINT("KdReceivePacket - wrong PacketType\n");
440 }
441
442 return KDP_PACKET_RECEIVED;
443 }
444
445 static
446 BOOLEAN
447 IsQuickTimeoutAllowed(
448 IN ULONG PacketType,
449 IN PSTRING MessageHeader)
450 {
451 PDBGKD_DEBUG_IO DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
452 ULONG ApiNumber = DebugIo->ApiNumber;
453
454 if ( ((PacketType == PACKET_TYPE_KD_DEBUG_IO) &&
455 ((ApiNumber == DbgKdPrintStringApi))) ||
456 ((PacketType == PACKET_TYPE_KD_FILE_IO) &&
457 ((ApiNumber == DbgKdCreateFileApi))) ||
458 ((PacketType == PACKET_TYPE_KD_STATE_CHANGE64) &&
459 ((ApiNumber == DbgKdLoadSymbolsStateChange))) )
460 {
461 return TRUE;
462 }
463
464 return FALSE;
465 }
466
467 VOID
468 NTAPI
469 KdSendPacket(
470 IN ULONG PacketType,
471 IN PSTRING MessageHeader,
472 IN PSTRING MessageData,
473 IN OUT PKD_CONTEXT KdContext)
474 {
475 KD_PACKET Packet;
476 KDP_STATUS KdStatus;
477 ULONG Retries;
478
479 /* Initialize a KD_PACKET */
480 Packet.PacketLeader = PACKET_LEADER;
481 Packet.PacketType = (USHORT)PacketType;
482 Packet.ByteCount = MessageHeader->Length;
483 Packet.Checksum = KdpCalculateChecksum(MessageHeader->Buffer,
484 MessageHeader->Length);
485
486 /* If we have message data, add it to the packet */
487 if (MessageData)
488 {
489 Packet.ByteCount += MessageData->Length;
490 Packet.Checksum += KdpCalculateChecksum(MessageData->Buffer,
491 MessageData->Length);
492 }
493
494 #if _FULL_
495 Retries = KdCompNumberRetries = KdCompRetryCount;
496 #else
497 Retries = KdContext->KdpDefaultRetries;
498 #endif
499
500 for (;;)
501 {
502 /* Set the packet id */
503 Packet.PacketId = CurrentPacketId;
504
505 /* Send the packet header to the KD port */
506 KdpSendBuffer(&Packet, sizeof(KD_PACKET));
507
508 /* Send the message header */
509 KdpSendBuffer(MessageHeader->Buffer, MessageHeader->Length);
510
511 /* If we have message data, also send it */
512 if (MessageData)
513 {
514 KdpSendBuffer(MessageData->Buffer, MessageData->Length);
515 }
516
517 /* Finalize with a trailing byte */
518 KdpSendByte(PACKET_TRAILING_BYTE);
519
520 /* Wait for acknowledge */
521 KdStatus = KdReceivePacket(PACKET_TYPE_KD_ACKNOWLEDGE,
522 NULL,
523 NULL,
524 NULL,
525 KdContext);
526
527 /* Did we succeed? */
528 if (KdStatus == KDP_PACKET_RECEIVED)
529 {
530 /* Packet received, we can quit the loop */
531 CurrentPacketId &= ~SYNC_PACKET_ID;
532 break;
533 }
534
535 if (KdStatus == KDP_PACKET_TIMEOUT)
536 {
537 /* Timeout, decrement the retry count */
538 Retries--;
539
540 /*
541 * If the retry count reaches zero, bail out
542 * for packet types allowed to timeout.
543 */
544 if ((Retries == 0) &&
545 IsQuickTimeoutAllowed(PacketType, MessageHeader))
546 {
547
548 /* Reset debugger state */
549 KD_DEBUGGER_NOT_PRESENT = TRUE;
550 SharedUserData->KdDebuggerEnabled &= ~0x00000002;
551 CurrentPacketId = INITIAL_PACKET_ID | SYNC_PACKET_ID;
552 RemotePacketId = INITIAL_PACKET_ID;
553 return;
554 }
555 }
556
557 /* Packet timed out, send it again */
558 KDDBGPRINT("KdSendPacket got KdStatus 0x%x\n", KdStatus);
559 }
560
561 #if _FULL_
562 KdCompNumberRetries = Retries;
563 #endif // _FULL_
564 }
565