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