Sync with trunk for console graphics palettes.
[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 /* 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 PUCHAR ByteBuffer = Buffer;
35 ULONG Checksum = 0;
36
37 while (Length-- > 0)
38 {
39 Checksum += (ULONG)*ByteBuffer++;
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 /******************************************************************************
65 * \name KdReceivePacket
66 * \brief Receive a packet from the KD port.
67 * \param [in] PacketType Describes the type of the packet to receive.
68 * This can be one of the PACKET_TYPE_ constants.
69 * \param [out] MessageHeader Pointer to a STRING structure for the header.
70 * \param [out] MessageData Pointer to a STRING structure for the data.
71 * \return KdPacketReceived if successful, KdPacketTimedOut if the receive
72 * timed out, KdPacketNeedsResend to signal that the last packet needs
73 * to be sent again.
74 * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
75 * wait for any data, but returns KdPacketTimedOut instantly if no breakin
76 * packet byte is received.
77 * \sa http://www.nynaeve.net/?p=169
78 */
79 KDP_STATUS
80 NTAPI
81 KdReceivePacket(
82 IN ULONG PacketType,
83 OUT PSTRING MessageHeader,
84 OUT PSTRING MessageData,
85 OUT PULONG DataLength,
86 IN OUT PKD_CONTEXT KdContext)
87 {
88 UCHAR Byte = 0;
89 KDP_STATUS KdStatus;
90 KD_PACKET Packet;
91 ULONG Checksum;
92
93 /* Special handling for breakin packet */
94 if(PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
95 {
96 return KdpPollBreakIn();
97 }
98
99 for (;;)
100 {
101 /* Step 1 - Read PacketLeader */
102 KdStatus = KdpReceivePacketLeader(&Packet.PacketLeader);
103 if (KdStatus != KDP_PACKET_RECEIVED)
104 {
105 /* Check if we got a breakin */
106 if (KdStatus == KDP_PACKET_RESEND)
107 {
108 KdContext->KdpControlCPending = TRUE;
109 }
110 return KdStatus;
111 }
112
113 /* Step 2 - Read PacketType */
114 KdStatus = KdpReceiveBuffer(&Packet.PacketType, sizeof(USHORT));
115 if (KdStatus != KDP_PACKET_RECEIVED)
116 {
117 /* Didn't receive a PacketType. */
118 return KdStatus;
119 }
120
121 /* Check if we got a resend packet */
122 if (Packet.PacketLeader == CONTROL_PACKET_LEADER &&
123 Packet.PacketType == PACKET_TYPE_KD_RESEND)
124 {
125 return KDP_PACKET_RESEND;
126 }
127
128 /* Step 3 - Read ByteCount */
129 KdStatus = KdpReceiveBuffer(&Packet.ByteCount, sizeof(USHORT));
130 if (KdStatus != KDP_PACKET_RECEIVED)
131 {
132 /* Didn't receive ByteCount. */
133 return KdStatus;
134 }
135
136 /* Step 4 - Read PacketId */
137 KdStatus = KdpReceiveBuffer(&Packet.PacketId, sizeof(ULONG));
138 if (KdStatus != KDP_PACKET_RECEIVED)
139 {
140 /* Didn't receive PacketId. */
141 return KdStatus;
142 }
143
144 /*
145 if (Packet.PacketId != ExpectedPacketId)
146 {
147 // Ask for a resend!
148 continue;
149 }
150 */
151
152 /* Step 5 - Read Checksum */
153 KdStatus = KdpReceiveBuffer(&Packet.Checksum, sizeof(ULONG));
154 if (KdStatus != KDP_PACKET_RECEIVED)
155 {
156 /* Didn't receive Checksum. */
157 return KdStatus;
158 }
159
160 /* Step 6 - Handle control packets */
161 if (Packet.PacketLeader == CONTROL_PACKET_LEADER)
162 {
163 switch (Packet.PacketType)
164 {
165 case PACKET_TYPE_KD_ACKNOWLEDGE:
166 /* Are we waiting for an ACK packet? */
167 if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE &&
168 Packet.PacketId == (CurrentPacketId & ~SYNC_PACKET_ID))
169 {
170 /* Remote acknowledges the last packet */
171 CurrentPacketId ^= 1;
172 return KDP_PACKET_RECEIVED;
173 }
174 /* That's not what we were waiting for, start over. */
175 continue;
176
177 case PACKET_TYPE_KD_RESET:
178 KDDBGPRINT("KdReceivePacket - got a reset packet\n");
179 KdpSendControlPacket(PACKET_TYPE_KD_RESET, 0);
180 CurrentPacketId = INITIAL_PACKET_ID;
181 RemotePacketId = INITIAL_PACKET_ID;
182 /* Fall through */
183
184 case PACKET_TYPE_KD_RESEND:
185 KDDBGPRINT("KdReceivePacket - got PACKET_TYPE_KD_RESEND\n");
186 /* Remote wants us to resend the last packet */
187 return KDP_PACKET_RESEND;
188
189 default:
190 KDDBGPRINT("KdReceivePacket - got unknown control packet\n");
191 return KDP_PACKET_RESEND;
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 messsage 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 meesage 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 break;
374 }
375 else if (KdStatus == KDP_PACKET_TIMEOUT)
376 {
377 /* Timeout, decrement the retry count */
378 if (Retries > 0)
379 Retries--;
380
381 /*
382 * If the retry count reaches zero, bail out
383 * for packet types allowed to timeout.
384 */
385 if (Retries == 0)
386 {
387 if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
388 {
389 return;
390 }
391 }
392 }
393 // else (KdStatus == KDP_PACKET_RESEND) /* Resend the packet */
394
395 /* Packet timed out, send it again */
396 KDDBGPRINT("KdSendPacket got KdStatus 0x%x\n", KdStatus);
397 }
398 }
399
400 /* EOF */