f81bcc6994573027b97850311f03cdae971e8ffe
[reactos.git] / reactos / drivers / base / kdcom / i386 / kdbg.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/base/kdcom/kdbg.c
5 * PURPOSE: Serial i/o functions for the kernel debugger.
6 * PROGRAMMER: Alex Ionescu
7 * Hervé Poussineau
8 * Timo Kreuzer
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #define NOEXTAPI
14 #include <ntddk.h>
15 #define NDEBUG
16 #include <halfuncs.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <debug.h>
20 #include "arc/arc.h"
21 #include "windbgkd.h"
22 #include <kddll.h>
23 #include <ioaccess.h> /* port intrinsics */
24
25 typedef struct _KD_PORT_INFORMATION
26 {
27 ULONG ComPort;
28 ULONG BaudRate;
29 ULONG_PTR BaseAddress;
30 } KD_PORT_INFORMATION, *PKD_PORT_INFORMATION;
31
32 BOOLEAN
33 NTAPI
34 KdPortInitializeEx(
35 IN PKD_PORT_INFORMATION PortInformation,
36 IN ULONG Unknown1,
37 IN ULONG Unknown2);
38
39 BOOLEAN
40 NTAPI
41 KdPortGetByteEx(
42 IN PKD_PORT_INFORMATION PortInformation,
43 OUT PUCHAR ByteReceived);
44
45 BOOLEAN
46 NTAPI
47 KdPortPollByteEx(
48 IN PKD_PORT_INFORMATION PortInformation,
49 OUT PUCHAR ByteReceived);
50
51 VOID
52 NTAPI
53 KdPortPutByteEx(
54 IN PKD_PORT_INFORMATION PortInformation,
55 IN UCHAR ByteToSend);
56
57 /* serial debug connection */
58 #define DEFAULT_DEBUG_PORT 2 /* COM2 */
59 #define DEFAULT_DEBUG_COM1_IRQ 4 /* COM1 IRQ */
60 #define DEFAULT_DEBUG_COM2_IRQ 3 /* COM2 IRQ */
61 #define DEFAULT_DEBUG_BAUD_RATE 115200 /* 115200 Baud */
62
63 #define DEFAULT_BAUD_RATE 19200
64
65 #ifdef _M_IX86
66 const ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
67 #elif defined(_M_PPC)
68 const ULONG BaseArray[2] = {0, 0x800003f8};
69 #elif defined(_M_MIPS)
70 const ULONG BaseArray[3] = {0, 0x80006000, 0x80007000};
71 #elif defined(_M_ARM)
72 const ULONG BaseArray[2] = {0, 0xF1012000};
73 #elif defined(_M_AMD64)
74 const ULONG BaseArray[5] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
75 #else
76 #error Unknown architecture
77 #endif
78
79 /* MACROS *******************************************************************/
80
81 #define SER_RBR(x) ((PUCHAR)(x)+0)
82 #define SER_THR(x) ((PUCHAR)(x)+0)
83 #define SER_DLL(x) ((PUCHAR)(x)+0)
84 #define SER_IER(x) ((PUCHAR)(x)+1)
85 #define SR_IER_ERDA 0x01
86 #define SR_IER_ETHRE 0x02
87 #define SR_IER_ERLSI 0x04
88 #define SR_IER_EMS 0x08
89 #define SR_IER_ALL 0x0F
90 #define SER_DLM(x) ((PUCHAR)(x)+1)
91 #define SER_IIR(x) ((PUCHAR)(x)+2)
92 #define SER_FCR(x) ((PUCHAR)(x)+2)
93 #define SR_FCR_ENABLE_FIFO 0x01
94 #define SR_FCR_CLEAR_RCVR 0x02
95 #define SR_FCR_CLEAR_XMIT 0x04
96 #define SER_LCR(x) ((PUCHAR)(x)+3)
97 #define SR_LCR_CS5 0x00
98 #define SR_LCR_CS6 0x01
99 #define SR_LCR_CS7 0x02
100 #define SR_LCR_CS8 0x03
101 #define SR_LCR_ST1 0x00
102 #define SR_LCR_ST2 0x04
103 #define SR_LCR_PNO 0x00
104 #define SR_LCR_POD 0x08
105 #define SR_LCR_PEV 0x18
106 #define SR_LCR_PMK 0x28
107 #define SR_LCR_PSP 0x38
108 #define SR_LCR_BRK 0x40
109 #define SR_LCR_DLAB 0x80
110 #define SER_MCR(x) ((PUCHAR)(x)+4)
111 #define SR_MCR_DTR 0x01
112 #define SR_MCR_RTS 0x02
113 #define SR_MCR_OUT1 0x04
114 #define SR_MCR_OUT2 0x08
115 #define SR_MCR_LOOP 0x10
116 #define SER_LSR(x) ((PUCHAR)(x)+5)
117 #define SR_LSR_DR 0x01
118 #define SR_LSR_TBE 0x20
119 #define SER_MSR(x) ((PUCHAR)(x)+6)
120 #define SR_MSR_CTS 0x10
121 #define SR_MSR_DSR 0x20
122 #define SER_SCR(x) ((PUCHAR)(x)+7)
123
124
125 /* GLOBAL VARIABLES *********************************************************/
126
127 ULONG CurrentPacketId = INITIAL_PACKET_ID;
128
129 /* STATIC VARIABLES *********************************************************/
130
131 static KD_PORT_INFORMATION DefaultPort = { 0, 0, 0 };
132
133 /* The com port must only be initialized once! */
134 static BOOLEAN PortInitialized = FALSE;
135
136 ULONG KdpPort;
137 ULONG KdpPortIrq;
138
139 // HACK!!!
140 typedef ULONG (*DBGRNT)(const char *Format, ...);
141 DBGRNT FrLdrDbgPrint = 0;
142
143 /* STATIC FUNCTIONS *********************************************************/
144
145 static BOOLEAN
146 KdpDoesComPortExist(
147 IN ULONG_PTR BaseAddress)
148 {
149 BOOLEAN found;
150 UCHAR mcr;
151 UCHAR msr;
152
153 found = FALSE;
154
155 /* save Modem Control Register (MCR) */
156 mcr = READ_PORT_UCHAR(SER_MCR(BaseAddress));
157
158 /* enable loop mode (set Bit 4 of the MCR) */
159 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_LOOP);
160
161 /* clear all modem output bits */
162 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_LOOP);
163
164 /* read the Modem Status Register */
165 msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
166
167 /*
168 * the upper nibble of the MSR (modem output bits) must be
169 * equal to the lower nibble of the MCR (modem input bits)
170 */
171 if ((msr & 0xF0) == 0x00)
172 {
173 /* set all modem output bits */
174 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), SR_MCR_DTR | SR_MCR_RTS | SR_MCR_OUT1 | SR_MCR_OUT2 | SR_MCR_LOOP);
175
176 /* read the Modem Status Register */
177 msr = READ_PORT_UCHAR(SER_MSR(BaseAddress));
178
179 /*
180 * the upper nibble of the MSR (modem output bits) must be
181 * equal to the lower nibble of the MCR (modem input bits)
182 */
183 if ((msr & 0xF0) == 0xF0)
184 {
185 /*
186 * setup a resonable state for the port:
187 * enable fifo and clear recieve/transmit buffers
188 */
189 WRITE_PORT_UCHAR(SER_FCR(BaseAddress),
190 (SR_FCR_ENABLE_FIFO | SR_FCR_CLEAR_RCVR | SR_FCR_CLEAR_XMIT));
191 WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0);
192 READ_PORT_UCHAR(SER_RBR(BaseAddress));
193 WRITE_PORT_UCHAR(SER_IER(BaseAddress), 0);
194 found = TRUE;
195 }
196 }
197
198 /* restore MCR */
199 WRITE_PORT_UCHAR(SER_MCR(BaseAddress), mcr);
200
201 return found;
202 }
203
204
205 /* FUNCTIONS ****************************************************************/
206
207 NTSTATUS
208 DriverEntry(
209 IN PDRIVER_OBJECT DriverObject,
210 IN PUNICODE_STRING RegistryPath)
211 {
212 return STATUS_SUCCESS;
213 }
214
215 /* HAL.KdPortInitialize */
216 BOOLEAN
217 NTAPI
218 KdPortInitialize(
219 IN PKD_PORT_INFORMATION PortInformation,
220 IN ULONG Unknown1,
221 IN ULONG Unknown2)
222 {
223 SIZE_T i;
224 CHAR buffer[80];
225
226 if (!PortInitialized)
227 {
228 DefaultPort.BaudRate = PortInformation->BaudRate;
229
230 if (PortInformation->ComPort == 0)
231 {
232 for (i = sizeof(BaseArray) / sizeof(BaseArray[0]) - 1; i > 0; i--)
233 {
234 if (KdpDoesComPortExist(BaseArray[i]))
235 {
236 DefaultPort.BaseAddress = BaseArray[i];
237 DefaultPort.ComPort = i;
238 PortInformation->BaseAddress = DefaultPort.BaseAddress;
239 PortInformation->ComPort = DefaultPort.ComPort;
240 break;
241 }
242 }
243 if (i == 0)
244 {
245 sprintf(buffer,
246 "\nKernel Debugger: No COM port found!\n\n");
247 HalDisplayString(buffer);
248 return FALSE;
249 }
250 }
251
252 PortInitialized = TRUE;
253 }
254
255 /* initialize port */
256 if (!KdPortInitializeEx(&DefaultPort, Unknown1, Unknown2))
257 return FALSE;
258
259 /* set global info */
260 KdComPortInUse = (PUCHAR)DefaultPort.BaseAddress;
261
262 return TRUE;
263 }
264
265
266 /* HAL.KdPortInitializeEx */
267 BOOLEAN
268 NTAPI
269 KdPortInitializeEx(
270 IN PKD_PORT_INFORMATION PortInformation,
271 IN ULONG Unknown1,
272 IN ULONG Unknown2)
273 {
274 ULONG_PTR ComPortBase;
275 CHAR buffer[80];
276 ULONG divisor;
277 UCHAR lcr;
278
279 #ifdef _ARM_
280 UNIMPLEMENTED;
281 return FALSE;
282 #endif
283
284 if (PortInformation->BaudRate == 0)
285 PortInformation->BaudRate = DEFAULT_BAUD_RATE;
286
287 if (PortInformation->ComPort == 0)
288 return FALSE;
289
290 if (!KdpDoesComPortExist(BaseArray[PortInformation->ComPort]))
291 {
292 sprintf(buffer,
293 "\nKernel Debugger: Serial port not found!\n\n");
294 HalDisplayString(buffer);
295 return FALSE;
296 }
297
298 ComPortBase = BaseArray[PortInformation->ComPort];
299 PortInformation->BaseAddress = ComPortBase;
300 #ifndef NDEBUG
301 sprintf(buffer,
302 "\nSerial port COM%ld found at 0x%lx\n",
303 PortInformation->ComPort,
304 ComPortBase);
305 HalDisplayString(buffer);
306 #endif /* NDEBUG */
307
308 /* set baud rate and data format (8N1) */
309
310 /* turn on DTR and RTS */
311 WRITE_PORT_UCHAR(SER_MCR(ComPortBase), SR_MCR_DTR | SR_MCR_RTS);
312
313 /* set DLAB */
314 lcr = READ_PORT_UCHAR(SER_LCR(ComPortBase)) | SR_LCR_DLAB;
315 WRITE_PORT_UCHAR(SER_LCR(ComPortBase), lcr);
316
317 /* set baud rate */
318 divisor = 115200 / PortInformation->BaudRate;
319 WRITE_PORT_UCHAR(SER_DLL(ComPortBase), (UCHAR)(divisor & 0xff));
320 WRITE_PORT_UCHAR(SER_DLM(ComPortBase), (UCHAR)((divisor >> 8) & 0xff));
321
322 /* reset DLAB and set 8N1 format */
323 WRITE_PORT_UCHAR(SER_LCR(ComPortBase),
324 SR_LCR_CS8 | SR_LCR_ST1 | SR_LCR_PNO);
325
326 /* read junk out of the RBR */
327 lcr = READ_PORT_UCHAR(SER_RBR(ComPortBase));
328
329 #ifndef NDEBUG
330 /* print message to blue screen */
331 sprintf(buffer,
332 "\nKernel Debugger: COM%ld (Port 0x%lx) BaudRate %ld\n\n",
333 PortInformation->ComPort,
334 ComPortBase,
335 PortInformation->BaudRate);
336
337 HalDisplayString(buffer);
338 #endif /* NDEBUG */
339
340 return TRUE;
341 }
342
343
344 /* HAL.KdPortGetByte */
345 BOOLEAN
346 NTAPI
347 KdPortGetByte(
348 OUT PUCHAR ByteReceived)
349 {
350 if (!PortInitialized)
351 return FALSE;
352 return KdPortGetByteEx(&DefaultPort, ByteReceived);
353 }
354
355
356 /* HAL.KdPortGetByteEx */
357 BOOLEAN
358 NTAPI
359 KdPortGetByteEx(
360 IN PKD_PORT_INFORMATION PortInformation,
361 OUT PUCHAR ByteReceived)
362 {
363 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
364
365 if ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR))
366 {
367 *ByteReceived = READ_PORT_UCHAR(SER_RBR(ComPortBase));
368 return TRUE;
369 }
370
371 return FALSE;
372 }
373
374
375 /* HAL.KdPortPollByte */
376 BOOLEAN
377 NTAPI
378 KdPortPollByte(
379 OUT PUCHAR ByteReceived)
380 {
381 if (!PortInitialized)
382 return FALSE;
383 return KdPortPollByteEx(&DefaultPort, ByteReceived);
384 }
385
386
387 /* HAL.KdPortPollByteEx */
388 BOOLEAN
389 NTAPI
390 KdPortPollByteEx(
391 IN PKD_PORT_INFORMATION PortInformation,
392 OUT PUCHAR ByteReceived)
393 {
394 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
395
396 while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DR) == 0)
397 ;
398
399 *ByteReceived = READ_PORT_UCHAR(SER_RBR(ComPortBase));
400
401 return TRUE;
402 }
403
404
405 /* HAL.KdPortPutByte */
406 VOID
407 NTAPI
408 KdPortPutByte(
409 IN UCHAR ByteToSend)
410 {
411 if (!PortInitialized)
412 return;
413 KdPortPutByteEx(&DefaultPort, ByteToSend);
414 }
415
416 /* HAL.KdPortPutByteEx */
417 VOID
418 NTAPI
419 KdPortPutByteEx(
420 IN PKD_PORT_INFORMATION PortInformation,
421 IN UCHAR ByteToSend)
422 {
423 PUCHAR ComPortBase = (PUCHAR)PortInformation->BaseAddress;
424
425 while ((READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_TBE) == 0)
426 ;
427
428 WRITE_PORT_UCHAR(SER_THR(ComPortBase), ByteToSend);
429 }
430
431
432 /* HAL.KdPortRestore */
433 VOID
434 NTAPI
435 KdPortRestore(VOID)
436 {
437 UNIMPLEMENTED;
438 }
439
440
441 /* HAL.KdPortSave */
442 VOID
443 NTAPI
444 KdPortSave(VOID)
445 {
446 UNIMPLEMENTED;
447 }
448
449
450 /* HAL.KdPortDisableInterrupts */
451 BOOLEAN
452 NTAPI
453 KdPortDisableInterrupts(VOID)
454 {
455 UCHAR ch;
456
457 if (!PortInitialized)
458 return FALSE;
459
460 ch = READ_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress));
461 ch &= (~(SR_MCR_OUT1 | SR_MCR_OUT2));
462 WRITE_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress), ch);
463
464 ch = READ_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress));
465 ch &= (~SR_IER_ALL);
466 WRITE_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress), ch);
467
468 return TRUE;
469 }
470
471
472 /* HAL.KdPortEnableInterrupts */
473 BOOLEAN
474 NTAPI
475 KdPortEnableInterrupts(VOID)
476 {
477 UCHAR ch;
478
479 if (PortInitialized == FALSE)
480 return FALSE;
481
482 ch = READ_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress));
483 ch &= (~SR_IER_ALL);
484 ch |= SR_IER_ERDA;
485 WRITE_PORT_UCHAR(SER_IER(DefaultPort.BaseAddress), ch);
486
487 ch = READ_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress));
488 ch &= (~SR_MCR_LOOP);
489 ch |= (SR_MCR_OUT1 | SR_MCR_OUT2);
490 WRITE_PORT_UCHAR(SER_MCR(DefaultPort.BaseAddress), ch);
491
492 return TRUE;
493 }
494
495 /* NEW INTERNAL FUNCTIONS ****************************************************/
496
497 /******************************************************************************
498 * \name KdpCalculateChecksum
499 * \brief Calculates the checksum for the packet data.
500 * \param Buffer Pointer to the packet data.
501 * \param Length Length of data in bytes.
502 * \return The calculated checksum.
503 * \sa http://www.vista-xp.co.uk/forums/technical-reference-library/2540-basics-debugging.html
504 */
505 ULONG
506 NTAPI
507 KdpCalculateChecksum(
508 IN PVOID Buffer,
509 IN ULONG Length)
510 {
511 ULONG i, Checksum = 0;
512
513 for (i = 0; i < Length; i++)
514 {
515 Checksum += ((PUCHAR)Buffer)[i];
516 }
517 return Checksum;
518 }
519
520 /******************************************************************************
521 * \name KdpSendBuffer
522 * \brief Sends a buffer of data to the KD port.
523 * \param Buffer Pointer to the data.
524 * \param Size Size of data in bytes.
525 */
526 VOID
527 NTAPI
528 KdpSendBuffer(
529 IN PVOID Buffer,
530 IN ULONG Size)
531 {
532 INT i;
533 for (i = 0; i < Size; i++)
534 {
535 KdPortPutByteEx(&DefaultPort, ((PUCHAR)Buffer)[i]);
536 }
537 }
538
539
540 /******************************************************************************
541 * \name KdpReceiveBuffer
542 * \brief Recieves data from the KD port and fills a buffer.
543 * \param Buffer Pointer to a buffer that receives the data.
544 * \param Size Size of data to receive in bytes.
545 * \return KdPacketReceived if successful.
546 * KdPacketTimedOut if the receice timed out (10 seconds).
547 * \todo Handle timeout.
548 */
549 KDSTATUS
550 NTAPI
551 KdpReceiveBuffer(
552 OUT PVOID Buffer,
553 IN ULONG Size)
554 {
555 ULONG i;
556 PUCHAR ByteBuffer = Buffer;
557 BOOLEAN Ret, TimeOut;
558
559 for (i = 0; i < Size; i++)
560 {
561 do
562 {
563 Ret = KdPortGetByteEx(&DefaultPort, &ByteBuffer[i]);
564 TimeOut = FALSE; // FIXME timeout after 10 Sec
565 }
566 while (!Ret || TimeOut);
567
568 if (TimeOut)
569 {
570 return KdPacketTimedOut;
571 }
572 // FrLdrDbgPrint("Received byte: %x\n", ByteBuffer[i]);
573 }
574
575 return KdPacketReceived;
576 }
577
578 KDSTATUS
579 NTAPI
580 KdpReceivePacketLeader(
581 OUT PULONG PacketLeader)
582 {
583 UCHAR Byte, PrevByte;
584 ULONG i, Temp;
585 KDSTATUS RcvCode;
586
587 Temp = 0;
588 PrevByte = 0;
589 for (i = 0; i < 4; i++)
590 {
591 RcvCode = KdpReceiveBuffer(&Byte, sizeof(UCHAR));
592 Temp = (Temp << 8) | Byte;
593 if ( (RcvCode != KdPacketReceived) ||
594 ((Byte != PACKET_LEADER_BYTE) &&
595 (Byte != CONTROL_PACKET_LEADER_BYTE)) ||
596 (PrevByte != 0 && Byte != PrevByte) )
597 {
598 return KdPacketNeedsResend;
599 }
600 PrevByte = Byte;
601 }
602
603 *PacketLeader = Temp;
604
605 return KdPacketReceived;
606 }
607
608
609 VOID
610 NTAPI
611 KdpSendControlPacket(
612 IN USHORT PacketType,
613 IN ULONG PacketId OPTIONAL)
614 {
615 KD_PACKET Packet;
616
617 Packet.PacketLeader = CONTROL_PACKET_LEADER;
618 Packet.PacketId = PacketId;
619 Packet.ByteCount = 0;
620 Packet.Checksum = 0;
621 Packet.PacketType = PacketType;
622
623 KdpSendBuffer(&Packet, sizeof(KD_PACKET));
624 }
625
626
627 /* NEW PUBLIC FUNCTIONS ******************************************************/
628
629 /******************************************************************************
630 * \name KdDebuggerInitialize0
631 * \brief Phase 0 initialization.
632 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
633 * \return Status
634 */
635 NTSTATUS
636 NTAPI
637 KdDebuggerInitialize0(
638 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
639 {
640 ULONG Value;
641 PCHAR CommandLine, Port, BaudRate, Irq;
642
643 /* Apply default values */
644 KdpPortIrq = 0;
645 DefaultPort.ComPort = DEFAULT_DEBUG_PORT;
646 DefaultPort.BaudRate = DEFAULT_DEBUG_BAUD_RATE;
647
648 /* Check if e have a LoaderBlock */
649 if (LoaderBlock)
650 {
651 /* Get the Command Line */
652 CommandLine = LoaderBlock->LoadOptions;
653
654 /* Upcase it */
655 _strupr(CommandLine);
656
657 /* Get the port and baud rate */
658 Port = strstr(CommandLine, "DEBUGPORT");
659 BaudRate = strstr(CommandLine, "BAUDRATE");
660 Irq = strstr(CommandLine, "IRQ");
661
662 /* Check if we got the /DEBUGPORT parameter */
663 if (Port)
664 {
665 /* Move past the actual string, to reach the port*/
666 Port += strlen("DEBUGPORT");
667
668 /* Now get past any spaces and skip the equal sign */
669 while (*Port == ' ') Port++;
670 Port++;
671
672 /* Do we have a serial port? */
673 if (strncmp(Port, "COM", 3) != 0)
674 {
675 return STATUS_INVALID_PARAMETER;
676 }
677
678 /* Gheck for a valid Serial Port */
679 Port += 3;
680 Value = atol(Port);
681 if (Value > 4)
682 {
683 return STATUS_INVALID_PARAMETER;
684 }
685
686 /* Set the port to use */
687 DefaultPort.ComPort = Value;
688 }
689
690 /* Check if we got a baud rate */
691 if (BaudRate)
692 {
693 /* Move past the actual string, to reach the rate */
694 BaudRate += strlen("BAUDRATE");
695
696 /* Now get past any spaces */
697 while (*BaudRate == ' ') BaudRate++;
698
699 /* And make sure we have a rate */
700 if (*BaudRate)
701 {
702 /* Read and set it */
703 Value = atol(BaudRate + 1);
704 if (Value) DefaultPort.BaudRate = Value;
705 }
706 }
707
708 /* Check Serial Port Settings [IRQ] */
709 if (Irq)
710 {
711 /* Move past the actual string, to reach the rate */
712 Irq += strlen("IRQ");
713
714 /* Now get past any spaces */
715 while (*Irq == ' ') Irq++;
716
717 /* And make sure we have an IRQ */
718 if (*Irq)
719 {
720 /* Read and set it */
721 Value = atol(Irq + 1);
722 if (Value) KdpPortIrq = Value;
723 }
724 }
725 }
726
727 // HACK use com1 for FrLdrDbg, com2 for WinDbg
728 DefaultPort.ComPort = 2;
729
730 /* Get base address */
731 DefaultPort.BaseAddress = BaseArray[DefaultPort.ComPort];
732
733 /* Check if the COM port does exist */
734 if (!KdpDoesComPortExist(DefaultPort.BaseAddress))
735 {
736 return STATUS_INVALID_PARAMETER;
737 }
738
739 /* Initialize the port */
740 KdPortInitializeEx(&DefaultPort, 0, 0);
741 PortInitialized = TRUE;
742
743 return STATUS_SUCCESS;
744 }
745
746 /******************************************************************************
747 * \name KdDebuggerInitialize1
748 * \brief Phase 1 initialization.
749 * \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
750 * \return Status
751 */
752 NTSTATUS
753 NTAPI
754 KdDebuggerInitialize1(
755 IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
756 {
757 // HACK: misuse this function to get a pointer to FrLdrDbgPrint
758 FrLdrDbgPrint = (PVOID)LoaderBlock;
759 return STATUS_NOT_IMPLEMENTED;
760 }
761
762 /*
763 * @implemented
764 */
765 NTSTATUS
766 NTAPI
767 KdSave(
768 IN BOOLEAN SleepTransition)
769 {
770 /* Nothing to do on COM ports */
771 return STATUS_SUCCESS;
772 }
773
774 /*
775 * @implemented
776 */
777 NTSTATUS
778 NTAPI
779 KdRestore(
780 IN BOOLEAN SleepTransition)
781 {
782 /* Nothing to do on COM ports */
783 return STATUS_SUCCESS;
784 }
785
786 /*
787 * @unimplemented
788 */
789 VOID
790 NTAPI
791 KdSendPacket(
792 IN ULONG PacketType,
793 IN PSTRING MessageHeader,
794 IN PSTRING MessageData,
795 IN OUT PKD_CONTEXT Context)
796 {
797 KD_PACKET Packet;
798 KDSTATUS RcvCode;
799
800 for (;;)
801 {
802 /* Initialize a KD_PACKET */
803 Packet.PacketLeader = PACKET_LEADER;
804 Packet.PacketType = PacketType;
805 Packet.ByteCount = MessageHeader->Length;
806 Packet.Checksum = KdpCalculateChecksum(MessageHeader->Buffer,
807 MessageHeader->Length);
808
809 /* If we have message data, add it to the packet */
810 if (MessageData)
811 {
812 Packet.ByteCount += MessageData->Length;
813 Packet.Checksum += KdpCalculateChecksum(MessageData->Buffer,
814 MessageData->Length);
815 }
816
817 /* Set the packet id */
818 Packet.PacketId = CurrentPacketId;
819
820 /* Send the packet header to the KD port */
821 KdpSendBuffer(&Packet, sizeof(KD_PACKET));
822
823 /* Send the message header */
824 KdpSendBuffer(MessageHeader->Buffer, MessageHeader->Length);
825
826 /* If we have meesage data, also send it */
827 if (MessageData)
828 {
829 KdpSendBuffer(MessageData->Buffer, MessageData->Length);
830 }
831
832 /* Finalize with a trailing byte */
833 KdPortPutByte(PACKET_TRAILING_BYTE);
834
835 /* Wait for acknowledge */
836 RcvCode = KdReceivePacket(PACKET_TYPE_KD_ACKNOWLEDGE,
837 NULL,
838 NULL,
839 0,
840 NULL);
841
842 /* Did we succeed? */
843 if (RcvCode == KdPacketReceived)
844 {
845 CurrentPacketId &= ~SYNC_PACKET_ID;
846 break;
847 }
848
849 /* PACKET_TYPE_KD_DEBUG_IO is allowed to instantly timeout */
850 if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
851 {
852 /* No response, silently fail. */
853 // return;
854 }
855
856 /* Packet timed out, send it again */
857 }
858
859 return;
860 }
861
862
863 /******************************************************************************
864 * \name KdReceivePacket
865 * \brief Receive a packet from the KD port.
866 * \param [in] PacketType Describes the type of the packet to receive.
867 * This can be one of the PACKET_TYPE_ constants.
868 * \param [out] MessageHeader Pointer to a STRING structure for the header.
869 * \param [out] MessageData Pointer to a STRING structure for the data.
870 * \return KdPacketReceived if successful, KdPacketTimedOut if the receive
871 * timed out, KdPacketNeedsResend to signal that the last packet needs
872 * to be sent again.
873 * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
874 * wait for any data, but returns KdPacketTimedOut instantly if no breakin
875 * packet byte is received.
876 * \sa http://www.nynaeve.net/?p=169
877 */
878 KDSTATUS
879 NTAPI
880 KdReceivePacket(
881 IN ULONG PacketType,
882 OUT PSTRING MessageHeader,
883 OUT PSTRING MessageData,
884 OUT PULONG DataLength,
885 IN OUT PKD_CONTEXT Context)
886 {
887 UCHAR Byte = 0;
888 KDSTATUS RcvCode;
889 KD_PACKET Packet;
890 ULONG Checksum;
891
892 /* Special handling for breakin packet */
893 if(PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
894 {
895 if (KdPortGetByteEx(&DefaultPort, &Byte))
896 {
897 if (Byte == BREAKIN_PACKET_BYTE)
898 {
899 return KdPacketReceived;
900 }
901 }
902 return KdPacketTimedOut;
903 }
904
905 for (;;)
906 {
907 /* Step 1 - Read PacketLeader */
908 RcvCode = KdpReceivePacketLeader(&Packet.PacketLeader);
909 if (RcvCode != KdPacketReceived)
910 {
911 /* Couldn't read a correct packet leader. Start over. */
912 continue;
913 }
914
915 /* Step 2 - Read PacketType */
916 RcvCode = KdpReceiveBuffer(&Packet.PacketType, sizeof(USHORT));
917 if (RcvCode != KdPacketReceived)
918 {
919 /* Didn't receive a PacketType or PacketType is bad. Start over. */
920 continue;
921 }
922
923 /* Step 3 - Read ByteCount */
924 RcvCode = KdpReceiveBuffer(&Packet.ByteCount, sizeof(USHORT));
925 if (RcvCode != KdPacketReceived || Packet.ByteCount > PACKET_MAX_SIZE)
926 {
927 /* Didn't receive ByteCount or it's too big. Start over. */
928 continue;
929 }
930
931 /* Step 4 - Read PacketId */
932 RcvCode = KdpReceiveBuffer(&Packet.PacketId, sizeof(ULONG));
933 if (RcvCode != KdPacketReceived)
934 {
935 /* Didn't receive PacketId. Start over. */
936 continue;
937 }
938
939 /*
940 if (Packet.PacketId != ExpectedPacketId)
941 {
942 // Ask for a resend!
943 continue;
944 }
945 */
946
947 /* Step 5 - Read Checksum */
948 RcvCode = KdpReceiveBuffer(&Packet.Checksum, sizeof(ULONG));
949 if (RcvCode != KdPacketReceived)
950 {
951 /* Didn't receive Checksum. Start over. */
952 continue;
953 }
954
955 /* Step 6 - Handle control packets */
956 if (Packet.PacketLeader == CONTROL_PACKET_LEADER)
957 {
958 switch (Packet.PacketType)
959 {
960 case PACKET_TYPE_KD_ACKNOWLEDGE:
961 if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE)
962 {
963 /* Remote acknowledges the last packet */
964 CurrentPacketId ^= 1;
965 return KdPacketReceived;
966 }
967 /* That's not what we were waiting for, start over. */
968 continue;
969
970 case PACKET_TYPE_KD_RESET:
971 FrLdrDbgPrint("KdReceivePacket - got a reset packet\n");
972 KdpSendControlPacket(PACKET_TYPE_KD_RESET, 0);
973 CurrentPacketId = INITIAL_PACKET_ID;
974 /* Fall through */
975
976 case PACKET_TYPE_KD_RESEND:
977 /* Remote wants us to resend the last packet */
978 return KdPacketNeedsResend;
979
980 default:
981 FrLdrDbgPrint("KdReceivePacket - got unknown control packet\n");
982 return KdPacketNeedsResend;
983 }
984 }
985
986 /* Did we wait for an ack packet? */
987 if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE)
988 {
989 /* We received something different, start over */
990 continue;
991 }
992
993 /* Did we get the right packet type? */
994 if (PacketType != Packet.PacketType)
995 {
996 /* We received something different, start over */
997 continue;
998 }
999
1000 /* Get size of the message header */
1001 switch (Packet.PacketType)
1002 {
1003 case PACKET_TYPE_KD_STATE_CHANGE64:
1004 MessageHeader->Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
1005 break;
1006
1007 case PACKET_TYPE_KD_STATE_MANIPULATE:
1008 MessageHeader->Length = sizeof(DBGKD_MANIPULATE_STATE64);
1009 break;
1010
1011 case PACKET_TYPE_KD_DEBUG_IO:
1012 MessageHeader->Length = sizeof(DBGKD_DEBUG_IO);
1013 break;
1014
1015 default:
1016 FrLdrDbgPrint("KdReceivePacket - unknown PacketType\n");
1017 return KdPacketNeedsResend;
1018 }
1019
1020 //FrLdrDbgPrint("KdReceivePacket - got normal PacketType\n");
1021
1022 /* Packet smaller than expected? */
1023 if (MessageHeader->Length > Packet.ByteCount)
1024 {
1025 FrLdrDbgPrint("KdReceivePacket - too few data (%d) for type %d\n",
1026 Packet.ByteCount, MessageHeader->Length);
1027 MessageHeader->Length = Packet.ByteCount;
1028 }
1029
1030 //FrLdrDbgPrint("KdReceivePacket - got normal PacketType, Buffer = %p\n", MessageHeader->Buffer);
1031
1032 /* Receive the message header data */
1033 RcvCode = KdpReceiveBuffer(MessageHeader->Buffer,
1034 MessageHeader->Length);
1035 if (RcvCode != KdPacketReceived)
1036 {
1037 /* Didn't receive data. Start over. */
1038 FrLdrDbgPrint("KdReceivePacket - Didn't receive message header data. Start over\n");
1039 continue;
1040 }
1041
1042 //FrLdrDbgPrint("KdReceivePacket - got normal PacketType 3\n");
1043
1044 /* Calculate checksum for the header data */
1045 Checksum = KdpCalculateChecksum(MessageHeader->Buffer,
1046 MessageHeader->Length);
1047
1048 /* Shall we receive messsage data? */
1049 if (MessageData)
1050 {
1051 /* Calculate the length of the message data */
1052 MessageData->Length = Packet.ByteCount - MessageHeader->Length;
1053
1054 /* Do we have data? */
1055 if (MessageData->Length)
1056 {
1057 FrLdrDbgPrint("KdReceivePacket - got data\n");
1058
1059 /* Receive the message data */
1060 RcvCode = KdpReceiveBuffer(MessageData->Buffer,
1061 MessageData->Length);
1062 if (RcvCode != KdPacketReceived)
1063 {
1064 /* Didn't receive data. Start over. */
1065 FrLdrDbgPrint("KdReceivePacket - Didn't receive message data. Start over\n");
1066 continue;
1067 }
1068
1069 /* Add cheksum for message data */
1070 Checksum += KdpCalculateChecksum(MessageData->Buffer,
1071 MessageData->Length);
1072 }
1073 }
1074
1075 /* Compare checksum */
1076 if (Packet.Checksum != Checksum)
1077 {
1078 KdpSendControlPacket(PACKET_TYPE_KD_RESEND, CurrentPacketId);
1079 FrLdrDbgPrint("KdReceivePacket - wrong cheksum, got %x, calculated %x\n",
1080 Packet.Checksum, Checksum);
1081 continue;
1082 }
1083
1084 /* We must receive a PACKET_TRAILING_BYTE now */
1085 RcvCode = KdpReceiveBuffer(&Byte, sizeof(UCHAR));
1086
1087 /* Acknowledge the received packet */
1088 KdpSendControlPacket(PACKET_TYPE_KD_ACKNOWLEDGE, Packet.PacketId);
1089
1090 //FrLdrDbgPrint("KdReceivePacket - all ok\n");
1091
1092 return KdPacketReceived;
1093 }
1094
1095 return KdPacketReceived;
1096 }
1097
1098 /* EOF */