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