+ Copy memory from source to destination with specified width.\r
+\r
+ @param[out] Dest A pointer to the destination buffer of the memory copy.\r
+ @param[in] Src A pointer to the source buffer of the memory copy.\r
+ @param[in] Count The number of data with specified width to copy from source to destination.\r
+ @param[in] Width Data width in byte.\r
+\r
+**/\r
+VOID\r
+CopyMemByWidth (\r
+ OUT UINT8 *Dest,\r
+ IN UINT8 *Src,\r
+ IN UINT16 Count,\r
+ IN UINT8 Width\r
+ )\r
+{\r
+ UINT8 *Destination;\r
+ UINT8 *Source;\r
+ INT8 Step;\r
+\r
+ if (Src > Dest) {\r
+ Destination = Dest;\r
+ Source = Src;\r
+ Step = Width;\r
+ } else {\r
+ //\r
+ // Copy memory from tail to avoid memory overlap\r
+ //\r
+ Destination = Dest + (Count - 1) * Width;\r
+ Source = Src + (Count - 1) * Width;\r
+ Step = -Width;\r
+ }\r
+\r
+ while (Count-- != 0) {\r
+ switch (Width) {\r
+ case 1:\r
+ *(UINT8 *) Destination = MmioRead8 ((UINTN) Source);\r
+ break;\r
+ case 2:\r
+ *(UINT16 *) Destination = MmioRead16 ((UINTN) Source);\r
+ break;\r
+ case 4:\r
+ *(UINT32 *) Destination = MmioRead32 ((UINTN) Source);\r
+ break;\r
+ case 8:\r
+ *(UINT64 *) Destination = MmioRead64 ((UINTN) Source);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+ Source += Step;\r
+ Destination += Step;\r
+ }\r
+}\r
+\r
+/**\r
+ Compress the data buffer but do not modify the original buffer.\r
+\r
+ The compressed data is directly send to the debug channel.\r
+ Compressing in place doesn't work because the data may become larger\r
+ during compressing phase. ("3 3 ..." --> "3 3 0 ...")\r
+ The routine is expected to be called three times:\r
+ 1. Compute the length of the compressed data buffer;\r
+ 2. Compute the CRC of the compressed data buffer;\r
+ 3. Compress the data and send to the debug channel.\r
+\r
+ @param[in] Handle The debug channel handle to send the compressed data buffer.\r
+ @param[in] Data The data buffer.\r
+ @param[in] Length The length of the data buffer.\r
+ @param[in] Send TRUE to send the compressed data buffer.\r
+ @param[out] CompressedLength Return the length of the compressed data buffer.\r
+ It may be larger than the Length in some cases.\r
+ @param[out] CompressedCrc Return the CRC of the compressed data buffer.\r
+**/\r
+VOID\r
+CompressData (\r
+ IN DEBUG_PORT_HANDLE Handle,\r
+ IN UINT8 *Data,\r
+ IN UINT8 Length,\r
+ IN BOOLEAN Send,\r
+ OUT UINTN *CompressedLength, OPTIONAL\r
+ OUT UINT16 *CompressedCrc OPTIONAL\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT8 LastChar;\r
+ UINT8 LastCharCount;\r
+ UINT8 CurrentChar;\r
+ UINTN CompressedIndex;\r
+\r
+ ASSERT (Length > 0);\r
+ LastChar = Data[0] + 1; // Just ensure it's different from the first byte.\r
+ LastCharCount = 0;\r
+\r
+ for (Index = 0, CompressedIndex = 0; Index <= Length; Index++) {\r
+ if (Index < Length) {\r
+ CurrentChar = Data[Index];\r
+ } else {\r
+ CurrentChar = (UINT8) LastChar + 1; // just ensure it's different from LastChar\r
+ }\r
+ if (LastChar != CurrentChar) {\r
+ if (LastCharCount == 1) {\r
+ CompressedIndex++;\r
+ if (CompressedCrc != NULL) {\r
+ *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);\r
+ }\r
+ if (Send) {\r
+ DebugPortWriteBuffer (Handle, &LastChar, 1);\r
+ }\r
+ \r
+ } else if (LastCharCount >= 2) {\r
+ CompressedIndex += 3;\r
+ LastCharCount -= 2;\r
+ if (CompressedCrc != NULL) {\r
+ *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);\r
+ *CompressedCrc = CalculateCrc16 (&LastChar, 1, *CompressedCrc);\r
+ *CompressedCrc = CalculateCrc16 (&LastCharCount, 1, *CompressedCrc);\r
+ }\r
+ if (Send) {\r
+ DebugPortWriteBuffer (Handle, &LastChar, 1);\r
+ DebugPortWriteBuffer (Handle, &LastChar, 1);\r
+ DebugPortWriteBuffer (Handle, &LastCharCount, 1);\r
+ }\r
+ }\r
+ LastCharCount = 0;\r
+ }\r
+ LastCharCount++;\r
+ LastChar = CurrentChar;\r
+ }\r
+\r
+ if (CompressedLength != NULL) {\r
+ *CompressedLength = CompressedIndex;\r
+ }\r
+}\r
+\r
+/**\r
+ Read memory with speicifed width and send packet with response data to HOST.\r