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