]>
Commit | Line | Data |
---|---|---|
117d9ec2 | 1 | //----------------------------------------------------------------------------- |
2 | // Jonathan Westhues, Aug 2005 | |
3 | // Gerhard de Koning Gans, April 2008, May 2011 | |
4 | // | |
5 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, | |
6 | // at your option, any later version. See the LICENSE.txt file for the text of | |
7 | // the license. | |
8 | //----------------------------------------------------------------------------- | |
9 | // BigBuf and functions to allocate/free parts of it. | |
10 | //----------------------------------------------------------------------------- | |
11 | ||
12 | #include <stdint.h> | |
13 | #include "proxmark3.h" | |
14 | #include "apps.h" | |
15 | #include "string.h" | |
b8e461ff | 16 | #include "util.h" |
117d9ec2 | 17 | |
f71f4deb | 18 | // BigBuf is the large multi-purpose buffer, typically used to hold A/D samples or traces. |
19 | // Also used to hold various smaller buffers and the Mifare Emulator Memory. | |
20 | ||
f4329b17 I |
21 | /* BigBuf memory layout: |
22 | Pointer to highest available memory: BigBuf_hi | |
23 | ||
a8561e35 | 24 | high BIGBUF_SIZE |
25 | reserved = BigBuf_malloc() subtracts amount from BigBuf_hi, | |
f4329b17 I |
26 | low 0x00 |
27 | */ | |
28 | ||
f71f4deb | 29 | // declare it as uint32_t to achieve alignment to 4 Byte boundary |
30 | static uint32_t BigBuf[BIGBUF_SIZE/sizeof(uint32_t)]; | |
117d9ec2 | 31 | |
32 | // High memory mark | |
33 | static uint16_t BigBuf_hi = BIGBUF_SIZE; | |
34 | ||
f71f4deb | 35 | // pointer to the emulator memory. |
36 | static uint8_t *emulator_memory = NULL; | |
37 | ||
3000dc4e | 38 | // trace related variables |
d9de20fa | 39 | static uint32_t traceLen = 0; |
40 | static bool tracing = true; | |
117d9ec2 | 41 | |
a8561e35 | 42 | |
117d9ec2 | 43 | // get the address of BigBuf |
44 | uint8_t *BigBuf_get_addr(void) | |
45 | { | |
f71f4deb | 46 | return (uint8_t *)BigBuf; |
47 | } | |
48 | ||
49 | ||
50 | // get the address of the emulator memory. Allocate part of Bigbuf for it, if not yet done | |
51 | uint8_t *BigBuf_get_EM_addr(void) | |
52 | { | |
f4329b17 I |
53 | // not yet allocated |
54 | if (emulator_memory == NULL) { | |
f71f4deb | 55 | emulator_memory = BigBuf_malloc(CARD_MEMORY_SIZE); |
56 | } | |
a8561e35 | 57 | |
f71f4deb | 58 | return emulator_memory; |
117d9ec2 | 59 | } |
60 | ||
61 | ||
62 | // clear ALL of BigBuf | |
63 | void BigBuf_Clear(void) | |
7cfc777b | 64 | { |
65 | BigBuf_Clear_ext(true); | |
66 | } | |
a8561e35 | 67 | |
68 | ||
7cfc777b | 69 | // clear ALL of BigBuf |
70 | void BigBuf_Clear_ext(bool verbose) | |
117d9ec2 | 71 | { |
d9de20fa | 72 | memset(BigBuf, 0, BIGBUF_SIZE); |
a8561e35 | 73 | if (verbose) |
74 | Dbprintf("Buffer cleared (%i bytes)", BIGBUF_SIZE); | |
117d9ec2 | 75 | } |
a8561e35 | 76 | |
77 | ||
f4329b17 I |
78 | void BigBuf_Clear_EM(void){ |
79 | memset(BigBuf_get_EM_addr(), 0, CARD_MEMORY_SIZE); | |
80 | } | |
117d9ec2 | 81 | |
a8561e35 | 82 | |
3cec7061 | 83 | void BigBuf_Clear_keep_EM(void) |
84 | { | |
d9de20fa | 85 | memset(BigBuf, 0, BigBuf_hi); |
3cec7061 | 86 | } |
117d9ec2 | 87 | |
f71f4deb | 88 | // allocate a chunk of memory from BigBuf. We allocate high memory first. The unallocated memory |
89 | // at the beginning of BigBuf is always for traces/samples | |
117d9ec2 | 90 | uint8_t *BigBuf_malloc(uint16_t chunksize) |
91 | { | |
a8561e35 | 92 | if (BigBuf_hi - chunksize < 0) { |
93 | return NULL; // no memory left | |
117d9ec2 | 94 | } else { |
a8561e35 | 95 | chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4 |
96 | BigBuf_hi -= chunksize; // aligned to 4 Byte boundary | |
f71f4deb | 97 | return (uint8_t *)BigBuf + BigBuf_hi; |
117d9ec2 | 98 | } |
99 | } | |
100 | ||
101 | ||
f71f4deb | 102 | // free ALL allocated chunks. The whole BigBuf is available for traces or samples again. |
117d9ec2 | 103 | void BigBuf_free(void) |
104 | { | |
105 | BigBuf_hi = BIGBUF_SIZE; | |
f71f4deb | 106 | emulator_memory = NULL; |
107 | } | |
108 | ||
109 | ||
110 | // free allocated chunks EXCEPT the emulator memory | |
111 | void BigBuf_free_keep_EM(void) | |
112 | { | |
113 | if (emulator_memory != NULL) { | |
114 | BigBuf_hi = emulator_memory - (uint8_t *)BigBuf; | |
115 | } else { | |
116 | BigBuf_hi = BIGBUF_SIZE; | |
117 | } | |
117d9ec2 | 118 | } |
119 | ||
e2012d1b MHS |
120 | void BigBuf_print_status(void) |
121 | { | |
122 | Dbprintf("Memory"); | |
123 | Dbprintf(" BIGBUF_SIZE.............%d", BIGBUF_SIZE); | |
f4329b17 | 124 | Dbprintf(" Available memory........%d", BigBuf_hi); |
e2012d1b MHS |
125 | Dbprintf("Tracing"); |
126 | Dbprintf(" tracing ................%d", tracing); | |
127 | Dbprintf(" traceLen ...............%d", traceLen); | |
128 | } | |
129 | ||
117d9ec2 | 130 | |
131 | // return the maximum trace length (i.e. the unallocated size of BigBuf) | |
f71f4deb | 132 | uint16_t BigBuf_max_traceLen(void) |
117d9ec2 | 133 | { |
134 | return BigBuf_hi; | |
f71f4deb | 135 | } |
3000dc4e | 136 | |
a8561e35 | 137 | |
3000dc4e | 138 | void clear_trace() { |
3000dc4e MHS |
139 | traceLen = 0; |
140 | } | |
141 | ||
a8561e35 | 142 | |
3000dc4e MHS |
143 | void set_tracing(bool enable) { |
144 | tracing = enable; | |
145 | } | |
146 | ||
a8561e35 | 147 | |
6e49717b | 148 | bool get_tracing(void) { |
149 | return tracing; | |
150 | } | |
151 | ||
a8561e35 | 152 | |
3000dc4e MHS |
153 | /** |
154 | * Get the number of bytes traced | |
155 | * @return | |
156 | */ | |
157 | uint16_t BigBuf_get_traceLen(void) | |
158 | { | |
159 | return traceLen; | |
160 | } | |
161 | ||
a8561e35 | 162 | |
3000dc4e MHS |
163 | /** |
164 | This is a function to store traces. All protocols can use this generic tracer-function. | |
165 | The traces produced by calling this function can be fetched on the client-side | |
166 | by 'hf list raw', alternatively 'hf list <proto>' for protocol-specific | |
167 | annotation of commands/responses. | |
168 | ||
169 | **/ | |
170 | bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) | |
171 | { | |
f4329b17 | 172 | if (!tracing) return false; |
3000dc4e MHS |
173 | |
174 | uint8_t *trace = BigBuf_get_addr(); | |
175 | ||
a8561e35 | 176 | uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity |
d9de20fa | 177 | uint32_t duration = timestamp_end - timestamp_start; |
3000dc4e MHS |
178 | |
179 | // Return when trace is full | |
180 | uint16_t max_traceLen = BigBuf_max_traceLen(); | |
181 | ||
182 | if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= max_traceLen) { | |
a8561e35 | 183 | tracing = false; // don't trace any more |
f4329b17 | 184 | return false; |
3000dc4e MHS |
185 | } |
186 | // Traceformat: | |
187 | // 32 bits timestamp (little endian) | |
188 | // 16 bits duration (little endian) | |
189 | // 16 bits data length (little endian, Highest Bit used as readerToTag flag) | |
190 | // y Bytes data | |
191 | // x Bytes parity (one byte per 8 bytes data) | |
192 | ||
193 | // timestamp (start) | |
194 | trace[traceLen++] = ((timestamp_start >> 0) & 0xff); | |
195 | trace[traceLen++] = ((timestamp_start >> 8) & 0xff); | |
196 | trace[traceLen++] = ((timestamp_start >> 16) & 0xff); | |
197 | trace[traceLen++] = ((timestamp_start >> 24) & 0xff); | |
198 | ||
199 | // duration | |
200 | trace[traceLen++] = ((duration >> 0) & 0xff); | |
201 | trace[traceLen++] = ((duration >> 8) & 0xff); | |
202 | ||
203 | // data length | |
204 | trace[traceLen++] = ((iLen >> 0) & 0xff); | |
205 | trace[traceLen++] = ((iLen >> 8) & 0xff); | |
206 | ||
207 | // readerToTag flag | |
208 | if (!readerToTag) { | |
209 | trace[traceLen - 1] |= 0x80; | |
210 | } | |
211 | ||
212 | // data bytes | |
213 | if (btBytes != NULL && iLen != 0) { | |
d9de20fa | 214 | for (int i = 0; i < iLen; i++) { |
215 | trace[traceLen++] = *btBytes++; | |
216 | } | |
3000dc4e | 217 | } |
3000dc4e MHS |
218 | |
219 | // parity bytes | |
c4c3af7c | 220 | if (num_paritybytes != 0) { |
48ece4a7 | 221 | if (parity != NULL) { |
d9de20fa | 222 | for (int i = 0; i < num_paritybytes; i++) { |
223 | trace[traceLen++] = *parity++; | |
224 | } | |
48ece4a7 | 225 | } else { |
d9de20fa | 226 | for (int i = 0; i < num_paritybytes; i++) { |
227 | trace[traceLen++] = 0x00; | |
228 | } | |
48ece4a7 | 229 | } |
3000dc4e | 230 | } |
3000dc4e | 231 | |
f4329b17 | 232 | return true; |
3000dc4e | 233 | } |
09ffd16e | 234 | |
235 | ||
beefe5bc | 236 | int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int readerToTag) |
aabb719d | 237 | { |
beefe5bc MHS |
238 | /** |
239 | Todo, rewrite the logger to use the generic functionality instead. It should be noted, however, | |
240 | that this logger takes number of bits as argument, not number of bytes. | |
241 | **/ | |
aabb719d | 242 | |
f4329b17 | 243 | if (!tracing) return false; |
665775c8 MHS |
244 | |
245 | uint8_t *trace = BigBuf_get_addr(); | |
246 | uint16_t iLen = nbytes(iBits); | |
7b6e3205 | 247 | |
aabb719d | 248 | // Return when trace is full |
7b6e3205 | 249 | if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) { |
250 | return false; | |
a8561e35 | 251 | } |
665775c8 MHS |
252 | |
253 | //Hitag traces appear to use this traceformat: | |
254 | // 32 bits timestamp (little endian,Highest Bit used as readerToTag flag) | |
255 | // 32 bits parity | |
beefe5bc | 256 | // 8 bits size (number of bits in the trace entry, not number of bytes) |
665775c8 | 257 | // y Bytes data |
aabb719d | 258 | |
7b6e3205 | 259 | |
260 | ||
aabb719d MHS |
261 | rsamples += iSamples; |
262 | trace[traceLen++] = ((rsamples >> 0) & 0xff); | |
263 | trace[traceLen++] = ((rsamples >> 8) & 0xff); | |
264 | trace[traceLen++] = ((rsamples >> 16) & 0xff); | |
265 | trace[traceLen++] = ((rsamples >> 24) & 0xff); | |
665775c8 | 266 | |
beefe5bc | 267 | if (!readerToTag) { |
665775c8 | 268 | trace[traceLen - 1] |= 0x80; |
aabb719d | 269 | } |
665775c8 | 270 | |
aabb719d MHS |
271 | trace[traceLen++] = ((dwParity >> 0) & 0xff); |
272 | trace[traceLen++] = ((dwParity >> 8) & 0xff); | |
273 | trace[traceLen++] = ((dwParity >> 16) & 0xff); | |
274 | trace[traceLen++] = ((dwParity >> 24) & 0xff); | |
275 | trace[traceLen++] = iBits; | |
665775c8 | 276 | |
d9de20fa | 277 | for (int i = 0; i < iLen; i++) { |
278 | trace[traceLen++] = *btBytes++; | |
279 | } | |
665775c8 | 280 | |
f4329b17 | 281 | return true; |
aabb719d | 282 | } |
48ece4a7 | 283 | |
284 | ||
e80aeb96 MHS |
285 | // Emulator memory |
286 | uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length){ | |
287 | uint8_t* mem = BigBuf_get_EM_addr(); | |
f4329b17 | 288 | if (offset+length < CARD_MEMORY_SIZE) { |
e80aeb96 MHS |
289 | memcpy(mem+offset, data, length); |
290 | return 0; | |
f4329b17 | 291 | } else { |
e80aeb96 MHS |
292 | Dbprintf("Error, trying to set memory outside of bounds! %d > %d", (offset+length), CARD_MEMORY_SIZE); |
293 | return 1; | |
294 | } | |
295 | } |