Leaked source code of windows server 2003
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.

536 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. #if 0
  122. //
  123. // There's no 'BaudRate' field specified in the _DEBUG_PORT_TABLE
  124. // structure, so don't use it.
  125. // matth (1/2002)
  126. } else if(HalpDebugPortTable->BaudRate != 0){
  127. // not specified by user so get it out of the debug table
  128. PortInformation.Baud = KdCompGetDebugTblBaudRate(HalpDebugPortTable->BaudRate);
  129. #endif
  130. } else {
  131. // No debug table information available so use default
  132. PortInformation.Baud = BD_57600;
  133. }
  134. } else {
  135. //
  136. // This is not a 16550. So we must use
  137. // the fixed baud rate of 57600.
  138. //
  139. PortInformation.Baud = BD_57600;
  140. }
  141. }
  142. }
  143. //
  144. // Check if Port and baudrate have been determined.
  145. //
  146. if ((PortInformation.Address == NULL) && !HalpGetInfoFromACPI) {
  147. //
  148. // First see if the DebugParameters contains debugging port info.
  149. //
  150. if (DebugParameters->BaudRate != 0) {
  151. BaudRate = DebugParameters->BaudRate;
  152. Port.Flags &= ~PORT_DEFAULTRATE;
  153. }
  154. if (DebugParameters->CommunicationPort != 0) {
  155. //
  156. // Find the configuration information of the specified serial port.
  157. //
  158. Com = DebugParameters->CommunicationPort;
  159. MatchKey = Com - 1;
  160. if (LoaderBlock != NULL) {
  161. ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
  162. ControllerClass,
  163. SerialController,
  164. &MatchKey);
  165. } else {
  166. ConfigurationEntry = NULL;
  167. }
  168. } else {
  169. //
  170. // Check if COM2 is present and make sure no mouse attaches to it.
  171. //
  172. MatchKey = 1;
  173. if (LoaderBlock != NULL) {
  174. ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
  175. ControllerClass,
  176. SerialController,
  177. &MatchKey);
  178. } else {
  179. ConfigurationEntry = NULL;
  180. }
  181. if (ConfigurationEntry != NULL) {
  182. ChildEntry = ConfigurationEntry->Child;
  183. if ((ChildEntry != NULL) &&
  184. (ChildEntry->ComponentEntry.Type == PointerPeripheral)) {
  185. ConfigurationEntry = NULL;
  186. }
  187. }
  188. //
  189. // If COM2 does not exist or a serial mouse attaches to it, try
  190. // COM1. If COM1 exists, we will use it no matter what is on
  191. // it.
  192. //
  193. if (ConfigurationEntry == NULL) {
  194. MatchKey = 0;
  195. if (LoaderBlock != NULL) {
  196. ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
  197. ControllerClass,
  198. SerialController,
  199. &MatchKey);
  200. } else {
  201. ConfigurationEntry = NULL;
  202. }
  203. if (ConfigurationEntry != NULL) {
  204. Com = 1;
  205. } else if (CpDoesPortExist((PUCHAR)COM2_PORT)) {
  206. PortAddress = (PUCHAR)COM2_PORT;
  207. Com = 2;
  208. } else if (CpDoesPortExist((PUCHAR)COM1_PORT)) {
  209. PortAddress = (PUCHAR)COM1_PORT;
  210. Com = 1;
  211. } else {
  212. return STATUS_NOT_FOUND;
  213. }
  214. } else {
  215. Com = 2;
  216. }
  217. }
  218. //
  219. // Get Comport address from the component configuration data.
  220. // (If we find the ComponentEntry associated with the com port)
  221. //
  222. if (ConfigurationEntry) {
  223. List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData;
  224. for (i = 0; i < List->Count ; i++ ) {
  225. Descriptor = &List->PartialDescriptors[i];
  226. if (Descriptor->Type == CmResourceTypePort) {
  227. PortAddress = (PUCHAR)UlongToPtr(Descriptor->u.Port.Start.LowPart);
  228. }
  229. }
  230. }
  231. //
  232. // If we can not find the port address for the comport, simply use
  233. // default value.
  234. //
  235. if (PortAddress == NULL) {
  236. switch (Com) {
  237. case 1:
  238. PortAddress = (PUCHAR)COM1_PORT;
  239. break;
  240. case 2:
  241. PortAddress = (PUCHAR)COM2_PORT;
  242. break;
  243. case 3:
  244. PortAddress = (PUCHAR)COM3_PORT;
  245. break;
  246. case 4:
  247. PortAddress = (PUCHAR)COM4_PORT;
  248. }
  249. }
  250. //
  251. // Initialize the port structure.
  252. //
  253. ComPort = Com;
  254. PortInformation.Address = PortAddress;
  255. PortInformation.Baud = BaudRate;
  256. }
  257. if (KdComAddressID == 0) { // MMIO
  258. KdWriteUchar = CpWriteRegisterUchar;
  259. KdReadUchar = CpReadRegisterUchar;
  260. }
  261. CpInitialize(&Port,
  262. PortInformation.Address,
  263. PortInformation.Baud
  264. );
  265. //
  266. // The following should be reworked in conjunction with the serial
  267. // driver. The serial driver doesn't understand the concept of
  268. // ports being memory so we need to have it believe we are using
  269. // the IO port even though we are using a memory mapped equivalent.
  270. //
  271. if (HalpDebugPortTable && (KdComAddressID == 0)) {
  272. *KdComPortInUse = (UCHAR *)((ULONG_PTR)(*KdComPortInUse) & (PAGE_SIZE-1));
  273. }
  274. else {
  275. *KdComPortInUse = PortInformation.Address;
  276. }
  277. return STATUS_SUCCESS;
  278. }
  279. ULONG
  280. KdCompGetByte(
  281. OUT PUCHAR Input
  282. )
  283. /*++
  284. Routine Description:
  285. Fetch a byte from the debug port and return it.
  286. N.B. It is assumed that the IRQL has been raised to the highest level, and
  287. necessary multiprocessor synchronization has been performed before this
  288. routine is called.
  289. Arguments:
  290. Input - Returns the data byte.
  291. Return Value:
  292. CP_GET_SUCCESS is returned if a byte is successfully read from the
  293. kernel debugger line.
  294. CP_GET_ERROR is returned if error encountered during reading.
  295. CP_GET_NODATA is returned if timeout.
  296. --*/
  297. {
  298. ULONG status = CpGetByte(&Port, Input, TRUE);
  299. #if DBG && IA64
  300. KdProtocolTraceIn[KdProtocolIndexIn++%4096]=*Input;
  301. #endif
  302. return status;
  303. }
  304. ULONG
  305. KdCompPollByte(
  306. OUT PUCHAR Input
  307. )
  308. /*++
  309. Routine Description:
  310. Fetch a byte from the debug port and return it if one is available.
  311. N.B. It is assumed that the IRQL has been raised to the highest level, and
  312. necessary multiprocessor synchronization has been performed before this
  313. routine is called.
  314. Arguments:
  315. Input - Returns the data byte.
  316. Return Value:
  317. CP_GET_SUCCESS is returned if a byte is successfully read from the
  318. kernel debugger line.
  319. CP_GET_ERROR is returned if error encountered during reading.
  320. CP_GET_NODATA is returned if timeout.
  321. --*/
  322. {
  323. ULONG status = CpGetByte(&Port, Input, FALSE);
  324. #if DBG && IA64
  325. KdProtocolTraceIn[KdProtocolIndexIn++%4096]=*Input;
  326. #endif
  327. return status;
  328. }
  329. VOID
  330. KdCompPutByte(
  331. IN UCHAR Output
  332. )
  333. /*++
  334. Routine Description:
  335. Write a byte to the debug port.
  336. N.B. It is assumed that the IRQL has been raised to the highest level, and
  337. necessary multiprocessor synchronization has been performed before this
  338. routine is called.
  339. Arguments:
  340. Output - Supplies the output data byte.
  341. Return Value:
  342. None.
  343. --*/
  344. {
  345. #if DBG && IA64
  346. KdProtocolTraceOut[KdProtocolIndexOut++%4096]=Output;
  347. #endif
  348. CpPutByte(&Port, Output);
  349. }
  350. VOID
  351. KdCompRestore(
  352. VOID
  353. )
  354. /*++
  355. Routine Description:
  356. This routine does NOTHING on the x86.
  357. N.B. It is assumed that the IRQL has been raised to the highest level, and
  358. necessary multiprocessor synchronization has been performed before this
  359. routine is called.
  360. Arguments:
  361. None.
  362. Return Value:
  363. None.
  364. --*/
  365. {
  366. Port.Flags &= ~PORT_SAVED;
  367. }
  368. VOID
  369. KdCompSave(
  370. VOID
  371. )
  372. /*++
  373. Routine Description:
  374. This routine does NOTHING on the x86.
  375. N.B. It is assumed that the IRQL has been raised to the highest level, and
  376. necessary multiprocessor synchronization has been performed before this
  377. routine is called.
  378. Arguments:
  379. None.
  380. Return Value:
  381. None.
  382. --*/
  383. {
  384. Port.Flags |= PORT_SAVED;
  385. }
  386. VOID
  387. KdCompInitialize1(
  388. VOID
  389. )
  390. {
  391. if(KdComAddressID == 0) { // MMIO
  392. Port.Address = (PUCHAR)MmMapIoSpace(DbgpKdComPhysicalAddress,8,MmNonCached);
  393. *KdComPortInUse = Port.Address;
  394. }
  395. } // KdCompInitialize1()