Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

551 lines
14 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. xxkdsup.c
  5. Abstract:
  6. Com support. Code to init a com port, store port state, map
  7. portable procedures to x86 procedures.
  8. Author:
  9. Bryan M. Willman (bryanwi) 24-Sep-90
  10. Revision History:
  11. Shielin Tzong (shielint) 10-Apr-91
  12. Add packet control protocol.
  13. John Vert (jvert) 11-Jul-1991
  14. Moved from KD/i386 to HAL
  15. Eric Nelson (enelson) 1-Jan-00
  16. Move from HAL into DLL
  17. --*/
  18. #include "kdcomp.h"
  19. #include "kdcom.h"
  20. #include "stdio.h"
  21. #include "acpitabl.h"
  22. #if DBG && IA64
  23. CHAR KdProtocolTraceIn[4096];
  24. ULONG KdProtocolIndexIn;
  25. CHAR KdProtocolTraceOut[4096];
  26. ULONG KdProtocolIndexOut;
  27. #endif
  28. PDEBUG_PORT_TABLE HalpDebugPortTable;
  29. //
  30. // This MUST be initialized to zero so we know not to do anything when
  31. // CpGetByte is called when the kernel debugger is disabled.
  32. //
  33. CPPORT Port = {NULL, 0, PORT_DEFAULTRATE };
  34. //
  35. // Remember the debugger port information
  36. //
  37. CPPORT PortInformation = {NULL, 0, PORT_DEFAULTRATE};
  38. ULONG ComPort = 0;
  39. PHYSICAL_ADDRESS DbgpKdComPhysicalAddress; // ACPI DBGP KdCom physical address.
  40. //
  41. // Default debugger port in IO space.
  42. //
  43. UCHAR KdComAddressID = 1; // port debugger ident. : MMIO or IO space. Def:IO.
  44. pKWriteUchar KdWriteUchar = CpWritePortUchar; // stub to real function: MMIO or IO space. Def:IO.
  45. pKReadUchar KdReadUchar = CpReadPortUchar; // stub to real function: MMIO or IO space. Def:IO.
  46. //
  47. // We need this so the serial driver knows that the kernel debugger
  48. // is using a particular port. The serial driver then knows not to
  49. // touch this port. KdInitCom fills this in with the number of the
  50. // COM port it is using (1 or 2)
  51. //
  52. // This will go in the registry as soon as the registry is working.
  53. //
  54. extern PUCHAR *KdComPortInUse;
  55. BOOLEAN HalpGetInfoFromACPI = FALSE;
  56. NTSTATUS
  57. KdCompInitialize(
  58. PDEBUG_PARAMETERS DebugParameters,
  59. PLOADER_PARAMETER_BLOCK LoaderBlock
  60. )
  61. /*++
  62. Routine Description:
  63. This procedure checks for which COM port should be used by kernel
  64. debugger. If DebugParameter specifies a COM port, we will use it
  65. even if we can not find it (we trust user). Otherwise, if COM2
  66. is present and there is no mouse attaching to it, we use COM2.
  67. If COM2 is not availabe, we check COM1. If both COM1 and COM2 are
  68. not present, we give up and return false.
  69. Arguments:
  70. DebugParameters - Supplies a pointer a structure which optionally
  71. sepcified the debugging port information.
  72. LoaderBlock - supplies a pointer to the loader parameter block.
  73. Returned Value:
  74. TRUE - If a debug port is found.
  75. --*/
  76. {
  77. PCONFIGURATION_COMPONENT_DATA ConfigurationEntry, ChildEntry;
  78. PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
  79. PCM_PARTIAL_RESOURCE_LIST List;
  80. ULONG MatchKey, i;
  81. ULONG BaudRate = BD_19200;
  82. PUCHAR PortAddress = NULL;
  83. UCHAR Irq = 0;
  84. ULONG Com = 0;
  85. if (LoaderBlock && KdGetAcpiTablePhase0) {
  86. HalpDebugPortTable =
  87. KdGetAcpiTablePhase0(LoaderBlock, DBGP_SIGNATURE);
  88. }
  89. if (HalpDebugPortTable) {
  90. KdComAddressID = HalpDebugPortTable->BaseAddress.AddressSpaceID;
  91. //
  92. // Debug ports are supported in memory and IO space only.
  93. //
  94. if ((KdComAddressID == 0) ||
  95. (KdComAddressID == 1)) {
  96. DbgpKdComPhysicalAddress = HalpDebugPortTable->BaseAddress.Address;
  97. if(KdComAddressID == 0) {
  98. //
  99. // The address is memory, map it.
  100. //
  101. if (KdMapPhysicalMemory64) {
  102. PortInformation.Address =
  103. KdMapPhysicalMemory64(DbgpKdComPhysicalAddress, 1);
  104. }
  105. } else {
  106. //
  107. // The address is in IO space.
  108. //
  109. PortInformation.Address = (PUCHAR)UlongToPtr(DbgpKdComPhysicalAddress.LowPart);
  110. }
  111. Port.Flags &= ~(PORT_MODEMCONTROL | PORT_DEFAULTRATE);
  112. HalpGetInfoFromACPI = TRUE;
  113. if (HalpDebugPortTable->InterfaceType == 0) {
  114. //
  115. // This is actually a 16550. So pay attention
  116. // to the baud rate requested by the user.
  117. //
  118. if(DebugParameters->BaudRate != 0){
  119. // Baud rate set by user so use it
  120. PortInformation.Baud = DebugParameters->BaudRate;
  121. } else if(HalpDebugPortTable->BaudRate != 0){
  122. // not specified by user so get it out of the debug table
  123. PortInformation.Baud = KdCompGetDebugTblBaudRate(HalpDebugPortTable->BaudRate);
  124. } else {
  125. // No debug table information available so use default
  126. PortInformation.Baud = BD_57600;
  127. }
  128. } else {
  129. //
  130. // This is not a 16550. So we must use
  131. // the fixed baud rate of 57600.
  132. //
  133. PortInformation.Baud = BD_57600;
  134. }
  135. }
  136. }
  137. //
  138. // Check if Port and baudrate have been determined.
  139. //
  140. if ((PortInformation.Address == NULL) && !HalpGetInfoFromACPI) {
  141. //
  142. // First see if the DebugParameters contains debugging port info.
  143. //
  144. if (DebugParameters->BaudRate != 0) {
  145. BaudRate = DebugParameters->BaudRate;
  146. Port.Flags &= ~PORT_DEFAULTRATE;
  147. }
  148. if (DebugParameters->CommunicationPort != 0) {
  149. //
  150. // Find the configuration information of the specified serial port.
  151. //
  152. Com = DebugParameters->CommunicationPort;
  153. MatchKey = Com - 1;
  154. if (LoaderBlock != NULL) {
  155. ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
  156. ControllerClass,
  157. SerialController,
  158. &MatchKey);
  159. } else {
  160. ConfigurationEntry = NULL;
  161. }
  162. } else {
  163. //
  164. // Check if COM2 is present and make sure no mouse attaches to it.
  165. //
  166. MatchKey = 1;
  167. if (LoaderBlock != NULL) {
  168. ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
  169. ControllerClass,
  170. SerialController,
  171. &MatchKey);
  172. } else {
  173. ConfigurationEntry = NULL;
  174. }
  175. if (ConfigurationEntry != NULL) {
  176. ChildEntry = ConfigurationEntry->Child;
  177. if ((ChildEntry != NULL) &&
  178. (ChildEntry->ComponentEntry.Type == PointerPeripheral)) {
  179. ConfigurationEntry = NULL;
  180. }
  181. }
  182. //
  183. // If COM2 does not exist or a serial mouse attaches to it, try
  184. // COM1. If COM1 exists, we will use it no matter what is on
  185. // it.
  186. //
  187. if (ConfigurationEntry == NULL) {
  188. MatchKey = 0;
  189. if (LoaderBlock != NULL) {
  190. ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
  191. ControllerClass,
  192. SerialController,
  193. &MatchKey);
  194. } else {
  195. ConfigurationEntry = NULL;
  196. }
  197. if (ConfigurationEntry != NULL) {
  198. Com = 1;
  199. } else if (CpDoesPortExist((PUCHAR)COM2_PORT)) {
  200. PortAddress = (PUCHAR)COM2_PORT;
  201. Com = 2;
  202. } else if (CpDoesPortExist((PUCHAR)COM1_PORT)) {
  203. PortAddress = (PUCHAR)COM1_PORT;
  204. Com = 1;
  205. } else {
  206. return STATUS_NOT_FOUND;
  207. }
  208. } else {
  209. Com = 2;
  210. }
  211. }
  212. //
  213. // Get Comport address from the component configuration data.
  214. // (If we find the ComponentEntry associated with the com port)
  215. //
  216. if (ConfigurationEntry) {
  217. List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData;
  218. for (i = 0; i < List->Count ; i++ ) {
  219. Descriptor = &List->PartialDescriptors[i];
  220. if (Descriptor->Type == CmResourceTypePort) {
  221. PortAddress = (PUCHAR)UlongToPtr(Descriptor->u.Port.Start.LowPart);
  222. }
  223. }
  224. }
  225. //
  226. // If we can not find the port address for the comport, simply use
  227. // default value.
  228. //
  229. if (PortAddress == NULL) {
  230. switch (Com) {
  231. case 1:
  232. PortAddress = (PUCHAR)COM1_PORT;
  233. break;
  234. case 2:
  235. PortAddress = (PUCHAR)COM2_PORT;
  236. break;
  237. case 3:
  238. PortAddress = (PUCHAR)COM3_PORT;
  239. break;
  240. case 4:
  241. PortAddress = (PUCHAR)COM4_PORT;
  242. }
  243. }
  244. //
  245. // Initialize the port structure.
  246. //
  247. ComPort = Com;
  248. PortInformation.Address = PortAddress;
  249. PortInformation.Baud = BaudRate;
  250. }
  251. if (KdComAddressID == 0) { // MMIO
  252. KdWriteUchar = CpWriteRegisterUchar;
  253. KdReadUchar = CpReadRegisterUchar;
  254. }
  255. CpInitialize(&Port,
  256. PortInformation.Address,
  257. PortInformation.Baud
  258. );
  259. //
  260. // The following should be reworked in conjunction with the serial
  261. // driver. The serial driver doesn't understand the concept of
  262. // ports being memory so we need to have it believe we are using
  263. // the IO port even though we are using a memory mapped equivalent.
  264. //
  265. if (HalpDebugPortTable && (KdComAddressID == 0)) {
  266. *KdComPortInUse = (UCHAR *)((ULONG_PTR)(*KdComPortInUse) & (PAGE_SIZE-1));
  267. }
  268. else {
  269. *KdComPortInUse = PortInformation.Address;
  270. }
  271. return STATUS_SUCCESS;
  272. }
  273. ULONG
  274. KdCompGetByte(
  275. OUT PUCHAR Input
  276. )
  277. /*++
  278. Routine Description:
  279. Fetch a byte from the debug port and return it.
  280. N.B. It is assumed that the IRQL has been raised to the highest level, and
  281. necessary multiprocessor synchronization has been performed before this
  282. routine is called.
  283. Arguments:
  284. Input - Returns the data byte.
  285. Return Value:
  286. CP_GET_SUCCESS is returned if a byte is successfully read from the
  287. kernel debugger line.
  288. CP_GET_ERROR is returned if error encountered during reading.
  289. CP_GET_NODATA is returned if timeout.
  290. --*/
  291. {
  292. ULONG status = CpGetByte(&Port, Input, TRUE);
  293. #if DBG && IA64
  294. KdProtocolTraceIn[KdProtocolIndexIn++%4096]=*Input;
  295. #endif
  296. return status;
  297. }
  298. ULONG
  299. KdCompPollByte(
  300. OUT PUCHAR Input
  301. )
  302. /*++
  303. Routine Description:
  304. Fetch a byte from the debug port and return it if one is available.
  305. N.B. It is assumed that the IRQL has been raised to the highest level, and
  306. necessary multiprocessor synchronization has been performed before this
  307. routine is called.
  308. Arguments:
  309. Input - Returns the data byte.
  310. Return Value:
  311. CP_GET_SUCCESS is returned if a byte is successfully read from the
  312. kernel debugger line.
  313. CP_GET_ERROR is returned if error encountered during reading.
  314. CP_GET_NODATA is returned if timeout.
  315. --*/
  316. {
  317. ULONG status = CpGetByte(&Port, Input, FALSE);
  318. #if DBG && IA64
  319. KdProtocolTraceIn[KdProtocolIndexIn++%4096]=*Input;
  320. #endif
  321. return status;
  322. }
  323. VOID
  324. KdCompPutByte(
  325. IN UCHAR Output
  326. )
  327. /*++
  328. Routine Description:
  329. Write a byte to the debug port.
  330. N.B. It is assumed that the IRQL has been raised to the highest level, and
  331. necessary multiprocessor synchronization has been performed before this
  332. routine is called.
  333. Arguments:
  334. Output - Supplies the output data byte.
  335. Return Value:
  336. None.
  337. --*/
  338. {
  339. #if DBG && IA64
  340. KdProtocolTraceOut[KdProtocolIndexOut++%4096]=Output;
  341. #endif
  342. CpPutByte(&Port, Output);
  343. }
  344. VOID
  345. KdCompRestore(
  346. VOID
  347. )
  348. /*++
  349. Routine Description:
  350. This routine does NOTHING on the x86.
  351. N.B. It is assumed that the IRQL has been raised to the highest level, and
  352. necessary multiprocessor synchronization has been performed before this
  353. routine is called.
  354. Arguments:
  355. None.
  356. Return Value:
  357. None.
  358. --*/
  359. {
  360. Port.Flags &= ~PORT_SAVED;
  361. }
  362. VOID
  363. KdCompSave(
  364. VOID
  365. )
  366. /*++
  367. Routine Description:
  368. This routine does NOTHING on the x86.
  369. N.B. It is assumed that the IRQL has been raised to the highest level, and
  370. necessary multiprocessor synchronization has been performed before this
  371. routine is called.
  372. Arguments:
  373. None.
  374. Return Value:
  375. None.
  376. --*/
  377. {
  378. Port.Flags |= PORT_SAVED;
  379. }
  380. VOID
  381. KdCompInitialize1(
  382. VOID
  383. )
  384. {
  385. if(KdComAddressID == 0) { // MMIO
  386. Port.Address = (PUCHAR)MmMapIoSpace(DbgpKdComPhysicalAddress,8,MmNonCached);
  387. *KdComPortInUse = Port.Address;
  388. }
  389. } // KdCompInitialize1()
  390. ULONG
  391. KdCompGetDebugTblBaudRate(
  392. UCHAR BaudRateFlag
  393. )
  394. {
  395. ULONG Rate = BD_57600; // default.
  396. switch(BaudRateFlag) {
  397. case 3:
  398. Rate = BD_9600;
  399. break;
  400. case 4:
  401. Rate = BD_19200;
  402. break;
  403. case 7:
  404. Rate = BD_115200;
  405. break;
  406. }
  407. return Rate;
  408. }