xref: /xnu-10002.41.9/osfmk/kdp/kdp_serial.c (revision 699cd48037512bf4380799317ca44ca453c82f57)
1 /*
2  * Copyright (c) 2008 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 #include "kdp_serial.h"
29 #include <libkern/zlib.h>
30 #include <stdint.h>
31 #include <stdbool.h>
32 
33 #define SKDP_START_CHAR 0xFA
34 #define SKDP_END_CHAR 0xFB
35 #define SKDP_ESC_CHAR 0xFE
36 
37 static enum {DS_WAITSTART, DS_READING, DS_ESCAPED} dsState;
38 static unsigned char dsBuffer[1518];
39 static int dsPos;
40 static uint32_t dsCRC;
41 static bool dsHaveCRC;
42 
43 
44 static void
kdp_serial_out(unsigned char byte,void (* outFunc)(char))45 kdp_serial_out(unsigned char byte, void (*outFunc)(char))
46 {
47 	//need to escape '\n' because the kernel serial output turns it into a cr/lf
48 	if (byte == SKDP_START_CHAR || byte == SKDP_END_CHAR || byte == SKDP_ESC_CHAR || byte == '\n') {
49 		outFunc(SKDP_ESC_CHAR);
50 		byte = ~byte;
51 	}
52 	outFunc((char)byte);
53 }
54 
55 void
kdp_serialize_packet(unsigned char * packet,unsigned int len,void (* outFunc)(char))56 kdp_serialize_packet(unsigned char *packet, unsigned int len, void (*outFunc)(char))
57 {
58 	unsigned int  index;
59 	unsigned char byte;
60 	uint32_t      crc;
61 
62 	// insert the CRC between back to back STARTs which is compatible with old clients
63 	crc = (uint32_t) z_crc32(0, packet, len);
64 	outFunc(SKDP_START_CHAR);
65 	kdp_serial_out((unsigned char)(crc >> 0), outFunc);
66 	kdp_serial_out((unsigned char)(crc >> 8), outFunc);
67 	kdp_serial_out((unsigned char)(crc >> 16), outFunc);
68 	kdp_serial_out((unsigned char)(crc >> 24), outFunc);
69 
70 	outFunc(SKDP_START_CHAR);
71 	for (index = 0; index < len; index++) {
72 		byte = *packet++;
73 		kdp_serial_out(byte, outFunc);
74 	}
75 	outFunc(SKDP_END_CHAR);
76 }
77 
78 unsigned char *
kdp_unserialize_packet(unsigned char byte,unsigned int * len)79 kdp_unserialize_packet(unsigned char byte, unsigned int *len)
80 {
81 	uint32_t crc;
82 
83 	switch (dsState) {
84 	case DS_WAITSTART:
85 		if (byte == SKDP_START_CHAR) {
86 //				printf("got start char\n");
87 			dsState = DS_READING;
88 			dsPos = 0;
89 			*len = SERIALIZE_READING;
90 			dsHaveCRC = false;
91 			return 0;
92 		}
93 		*len = SERIALIZE_WAIT_START;
94 		break;
95 	case DS_READING:
96 		if (byte == SKDP_ESC_CHAR) {
97 			dsState = DS_ESCAPED;
98 			*len = SERIALIZE_READING;
99 			return 0;
100 		}
101 		if (byte == SKDP_START_CHAR) {
102 			if (dsPos >= 4) {
103 				dsHaveCRC = true;
104 				dsCRC = dsBuffer[0] | (dsBuffer[1] << 8) | (dsBuffer[2] << 16) | (dsBuffer[3] << 24);
105 			}
106 			//else				printf("unexpected start char, resetting\n");
107 			dsPos = 0;
108 			*len = SERIALIZE_READING;
109 			return 0;
110 		}
111 		if (byte == SKDP_END_CHAR) {
112 			dsState = DS_WAITSTART;
113 			if (dsHaveCRC) {
114 				crc = (uint32_t) z_crc32(0, &dsBuffer[0], dsPos);
115 				if (crc != dsCRC) {
116 //						printf("bad packet crc 0x%x != 0x%x\n", crc, dsCRC);
117 					dsPos = 0;
118 					*len = SERIALIZE_WAIT_START;
119 					return 0;
120 				}
121 			}
122 			*len = dsPos;
123 			dsPos = 0;
124 			return dsBuffer;
125 		}
126 		dsBuffer[dsPos++] = byte;
127 		break;
128 	case DS_ESCAPED:
129 //			printf("unescaping %02x to %02x\n", byte, ~byte);
130 		dsBuffer[dsPos++] = ~byte;
131 		dsState = DS_READING;
132 		*len = SERIALIZE_READING;
133 		break;
134 	}
135 	if (dsPos == sizeof(dsBuffer)) { //too much data...forget this packet
136 		dsState = DS_WAITSTART;
137 		dsPos = 0;
138 		*len = SERIALIZE_WAIT_START;
139 	}
140 
141 	return 0;
142 }
143