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