]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 1993 NeXT Computer, Inc. All rights reserved. | |
24 | * | |
25 | * kdp.c -- Kernel Debugging Protocol. | |
26 | * | |
27 | */ | |
28 | ||
29 | #include <mach/mach_types.h> | |
30 | #include <kern/debug.h> | |
31 | ||
32 | #include <kdp/kdp_internal.h> | |
33 | #include <kdp/kdp_private.h> | |
34 | ||
35 | int kdp_vm_read( caddr_t, caddr_t, unsigned int); | |
36 | int kdp_vm_write( caddr_t, caddr_t, unsigned int); | |
37 | ||
38 | #define DO_ALIGN 1 /* align all packet data accesses */ | |
39 | ||
40 | #define KDP_TEST_HARNESS 0 | |
41 | #if KDP_TEST_HARNESS | |
42 | #define dprintf(x) kprintf x | |
43 | #else | |
44 | #define dprintf(x) | |
45 | #endif | |
46 | ||
47 | static kdp_dispatch_t | |
48 | dispatch_table[KDP_TERMINATION - KDP_CONNECT + 1] = | |
49 | { | |
50 | /* 0 */ kdp_connect, | |
51 | /* 1 */ kdp_disconnect, | |
52 | /* 2 */ kdp_hostinfo, | |
53 | /* 3 */ kdp_regions, | |
54 | /* 4 */ kdp_maxbytes, | |
55 | /* 5 */ kdp_readmem, | |
56 | /* 6 */ kdp_writemem, | |
57 | /* 7 */ kdp_readregs, | |
58 | /* 8 */ kdp_writeregs, | |
59 | /* 9 */ kdp_unknown, | |
60 | /* A */ kdp_unknown, | |
61 | /* B */ kdp_suspend, | |
62 | /* C */ kdp_resumecpus, | |
63 | /* D */ kdp_unknown, | |
64 | /* E */ kdp_unknown, | |
65 | }; | |
66 | ||
67 | kdp_glob_t kdp; | |
68 | int kdp_flag=0; | |
69 | ||
70 | boolean_t | |
71 | kdp_packet( | |
72 | unsigned char *pkt, | |
73 | int *len, | |
74 | unsigned short *reply_port | |
75 | ) | |
76 | { | |
77 | static unsigned aligned_pkt[1538/sizeof(unsigned)+1]; // max ether pkt | |
78 | kdp_pkt_t *rd = (kdp_pkt_t *)&aligned_pkt; | |
79 | int plen = *len; | |
80 | unsigned int req; | |
81 | boolean_t ret; | |
82 | ||
83 | #if DO_ALIGN | |
84 | bcopy((char *)pkt, (char *)rd, sizeof(aligned_pkt)); | |
85 | #else | |
86 | rd = (kdp_pkt_t *)pkt; | |
87 | #endif | |
88 | if (plen < sizeof (rd->hdr) || rd->hdr.len != plen) { | |
89 | printf("kdp_packet bad len pkt %d hdr %d\n", plen, rd->hdr.len); | |
90 | ||
91 | return (FALSE); | |
92 | } | |
93 | ||
94 | if (rd->hdr.is_reply) { | |
95 | printf("kdp_packet reply recvd req %x seq %x\n", | |
96 | rd->hdr.request, rd->hdr.seq); | |
97 | ||
98 | return (FALSE); | |
99 | } | |
100 | ||
101 | req = rd->hdr.request; | |
102 | if (req < KDP_CONNECT || req > KDP_TERMINATION) { | |
103 | printf("kdp_packet bad request %x len %d seq %x key %x\n", | |
104 | rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key); | |
105 | ||
106 | return (FALSE); | |
107 | } | |
108 | ||
109 | ret = ((*dispatch_table[req - KDP_CONNECT])(rd, len, reply_port)); | |
110 | #if DO_ALIGN | |
111 | bcopy((char *)rd, (char *) pkt, *len); | |
112 | #endif | |
113 | return ret; | |
114 | } | |
115 | ||
116 | static boolean_t | |
117 | kdp_unknown( | |
118 | kdp_pkt_t *pkt, | |
119 | int *len, | |
120 | unsigned short *reply_port | |
121 | ) | |
122 | { | |
123 | kdp_pkt_t *rd = (kdp_pkt_t *)pkt; | |
124 | ||
125 | printf("kdp_unknown request %x len %d seq %x key %x\n", | |
126 | rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key); | |
127 | ||
128 | return (FALSE); | |
129 | } | |
130 | ||
131 | static boolean_t | |
132 | kdp_connect( | |
133 | kdp_pkt_t *pkt, | |
134 | int *len, | |
135 | unsigned short *reply_port | |
136 | ) | |
137 | { | |
138 | kdp_connect_req_t *rq = &pkt->connect_req; | |
139 | int plen = *len; | |
140 | kdp_connect_reply_t *rp = &pkt->connect_reply; | |
141 | ||
142 | if (plen < sizeof (*rq)) | |
143 | return (FALSE); | |
144 | ||
145 | dprintf(("kdp_connect seq %x greeting %s\n", rq->hdr.seq, rq->greeting)); | |
146 | ||
147 | if (kdp.is_conn) { | |
148 | if (rq->hdr.seq == kdp.conn_seq) /* duplicate request */ | |
149 | rp->error = KDPERR_NO_ERROR; | |
150 | else | |
151 | rp->error = KDPERR_ALREADY_CONNECTED; | |
152 | } | |
153 | else { | |
154 | kdp.reply_port = rq->req_reply_port; | |
155 | kdp.exception_port = rq->exc_note_port; | |
156 | kdp.is_conn = TRUE; | |
157 | kdp.conn_seq = rq->hdr.seq; | |
158 | ||
159 | rp->error = KDPERR_NO_ERROR; | |
160 | } | |
161 | ||
162 | rp->hdr.is_reply = 1; | |
163 | rp->hdr.len = sizeof (*rp); | |
164 | ||
165 | *reply_port = kdp.reply_port; | |
166 | *len = rp->hdr.len; | |
167 | ||
168 | if (current_debugger == KDP_CUR_DB) | |
169 | active_debugger=1; | |
170 | ||
171 | return (TRUE); | |
172 | } | |
173 | ||
174 | static boolean_t | |
175 | kdp_disconnect( | |
176 | kdp_pkt_t *pkt, | |
177 | int *len, | |
178 | unsigned short *reply_port | |
179 | ) | |
180 | { | |
181 | kdp_disconnect_req_t *rq = &pkt->disconnect_req; | |
182 | int plen = *len; | |
183 | kdp_disconnect_reply_t *rp = &pkt->disconnect_reply; | |
184 | ||
185 | if (plen < sizeof (*rq)) | |
186 | return (FALSE); | |
187 | ||
188 | if (!kdp.is_conn) | |
189 | return (FALSE); | |
190 | ||
191 | dprintf(("kdp_disconnect\n")); | |
192 | ||
193 | *reply_port = kdp.reply_port; | |
194 | ||
195 | kdp.reply_port = kdp.exception_port = 0; | |
196 | kdp.is_halted = kdp.is_conn = FALSE; | |
197 | kdp.exception_seq = kdp.conn_seq = 0; | |
198 | ||
199 | rp->hdr.is_reply = 1; | |
200 | rp->hdr.len = sizeof (*rp); | |
201 | ||
202 | *len = rp->hdr.len; | |
203 | ||
204 | if (current_debugger == KDP_CUR_DB) | |
205 | active_debugger=0; | |
206 | ||
207 | return (TRUE); | |
208 | } | |
209 | ||
210 | static boolean_t | |
211 | kdp_hostinfo( | |
212 | kdp_pkt_t *pkt, | |
213 | int *len, | |
214 | unsigned short *reply_port | |
215 | ) | |
216 | { | |
217 | kdp_hostinfo_req_t *rq = &pkt->hostinfo_req; | |
218 | int plen = *len; | |
219 | kdp_hostinfo_reply_t *rp = &pkt->hostinfo_reply; | |
220 | ||
221 | if (plen < sizeof (*rq)) | |
222 | return (FALSE); | |
223 | ||
224 | rp->hdr.is_reply = 1; | |
225 | rp->hdr.len = sizeof (*rp); | |
226 | ||
227 | kdp_machine_hostinfo(&rp->hostinfo); | |
228 | ||
229 | *reply_port = kdp.reply_port; | |
230 | *len = rp->hdr.len; | |
231 | ||
232 | return (TRUE); | |
233 | } | |
234 | ||
235 | static boolean_t | |
236 | kdp_suspend( | |
237 | kdp_pkt_t *pkt, | |
238 | int *len, | |
239 | unsigned short *reply_port | |
240 | ) | |
241 | { | |
242 | kdp_suspend_req_t *rq = &pkt->suspend_req; | |
243 | int plen = *len; | |
244 | kdp_suspend_reply_t *rp = &pkt->suspend_reply; | |
245 | ||
246 | if (plen < sizeof (*rq)) | |
247 | return (FALSE); | |
248 | ||
249 | rp->hdr.is_reply = 1; | |
250 | rp->hdr.len = sizeof (*rp); | |
251 | ||
252 | dprintf(("kdp_suspend\n")); | |
253 | ||
254 | kdp.is_halted = TRUE; | |
255 | ||
256 | *reply_port = kdp.reply_port; | |
257 | *len = rp->hdr.len; | |
258 | ||
259 | return (TRUE); | |
260 | } | |
261 | ||
262 | static boolean_t | |
263 | kdp_resumecpus( | |
264 | kdp_pkt_t *pkt, | |
265 | int *len, | |
266 | unsigned short *reply_port | |
267 | ) | |
268 | { | |
269 | kdp_resumecpus_req_t *rq = &pkt->resumecpus_req; | |
270 | int plen = *len; | |
271 | kdp_resumecpus_reply_t *rp = &pkt->resumecpus_reply; | |
272 | ||
273 | if (plen < sizeof (*rq)) | |
274 | return (FALSE); | |
275 | ||
276 | rp->hdr.is_reply = 1; | |
277 | rp->hdr.len = sizeof (*rp); | |
278 | ||
279 | dprintf(("kdp_resumecpus %x\n", rq->cpu_mask)); | |
280 | ||
281 | kdp.is_halted = FALSE; | |
282 | ||
283 | *reply_port = kdp.reply_port; | |
284 | *len = rp->hdr.len; | |
285 | ||
286 | return (TRUE); | |
287 | } | |
288 | ||
289 | static boolean_t | |
290 | kdp_writemem( | |
291 | kdp_pkt_t *pkt, | |
292 | int *len, | |
293 | unsigned short *reply_port | |
294 | ) | |
295 | { | |
296 | kdp_writemem_req_t *rq = &pkt->writemem_req; | |
297 | int plen = *len; | |
298 | kdp_writemem_reply_t *rp = &pkt->writemem_reply; | |
299 | int cnt; | |
300 | ||
301 | if (plen < sizeof (*rq)) | |
302 | return (FALSE); | |
303 | ||
304 | if (rq->nbytes > MAX_KDP_DATA_SIZE) | |
305 | rp->error = KDPERR_BAD_NBYTES; | |
306 | else { | |
307 | dprintf(("kdp_writemem addr %x size %d\n", rq->address, rq->nbytes)); | |
308 | ||
309 | cnt = kdp_vm_write((caddr_t)rq->data, (caddr_t)rq->address, rq->nbytes); | |
310 | rp->error = KDPERR_NO_ERROR; | |
311 | } | |
312 | ||
313 | rp->hdr.is_reply = 1; | |
314 | rp->hdr.len = sizeof (*rp); | |
315 | ||
316 | *reply_port = kdp.reply_port; | |
317 | *len = rp->hdr.len; | |
318 | ||
319 | return (TRUE); | |
320 | } | |
321 | ||
322 | static boolean_t | |
323 | kdp_readmem( | |
324 | kdp_pkt_t *pkt, | |
325 | int *len, | |
326 | unsigned short *reply_port | |
327 | ) | |
328 | { | |
329 | kdp_readmem_req_t *rq = &pkt->readmem_req; | |
330 | int plen = *len; | |
331 | kdp_readmem_reply_t *rp = &pkt->readmem_reply; | |
332 | int cnt; | |
333 | ||
334 | if (plen < sizeof (*rq)) | |
335 | return (FALSE); | |
336 | ||
337 | rp->hdr.is_reply = 1; | |
338 | rp->hdr.len = sizeof (*rp); | |
339 | ||
340 | if (rq->nbytes > MAX_KDP_DATA_SIZE) | |
341 | rp->error = KDPERR_BAD_NBYTES; | |
342 | else { | |
343 | unsigned int n = rq->nbytes; | |
344 | ||
345 | dprintf(("kdp_readmem addr %x size %d\n", rq->address, rq->nbytes)); | |
346 | ||
347 | cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)rp->data, rq->nbytes); | |
348 | rp->error = KDPERR_NO_ERROR; | |
349 | ||
350 | rp->hdr.len += cnt; | |
351 | } | |
352 | ||
353 | *reply_port = kdp.reply_port; | |
354 | *len = rp->hdr.len; | |
355 | ||
356 | return (TRUE); | |
357 | } | |
358 | ||
359 | static boolean_t | |
360 | kdp_maxbytes( | |
361 | kdp_pkt_t *pkt, | |
362 | int *len, | |
363 | unsigned short *reply_port | |
364 | ) | |
365 | { | |
366 | kdp_maxbytes_req_t *rq = &pkt->maxbytes_req; | |
367 | int plen = *len; | |
368 | kdp_maxbytes_reply_t *rp = &pkt->maxbytes_reply; | |
369 | ||
370 | if (plen < sizeof (*rq)) | |
371 | return (FALSE); | |
372 | ||
373 | rp->hdr.is_reply = 1; | |
374 | rp->hdr.len = sizeof (*rp); | |
375 | ||
376 | dprintf(("kdp_maxbytes\n")); | |
377 | ||
378 | rp->max_bytes = MAX_KDP_DATA_SIZE; | |
379 | ||
380 | *reply_port = kdp.reply_port; | |
381 | *len = rp->hdr.len; | |
382 | ||
383 | return (TRUE); | |
384 | } | |
385 | ||
386 | static boolean_t | |
387 | kdp_regions( | |
388 | kdp_pkt_t *pkt, | |
389 | int *len, | |
390 | unsigned short *reply_port | |
391 | ) | |
392 | { | |
393 | kdp_regions_req_t *rq = &pkt->regions_req; | |
394 | int plen = *len; | |
395 | kdp_regions_reply_t *rp = &pkt->regions_reply; | |
396 | kdp_region_t *r; | |
397 | ||
398 | if (plen < sizeof (*rq)) | |
399 | return (FALSE); | |
400 | ||
401 | rp->hdr.is_reply = 1; | |
402 | rp->hdr.len = sizeof (*rp); | |
403 | ||
404 | dprintf(("kdp_regions\n")); | |
405 | ||
406 | r = rp->regions; | |
407 | rp->nregions = 0; | |
408 | ||
409 | (vm_offset_t)r->address = 0; | |
410 | r->nbytes = 0xffffffff; | |
411 | ||
412 | r->protection = VM_PROT_ALL; r++; rp->nregions++; | |
413 | ||
414 | rp->hdr.len += rp->nregions * sizeof (kdp_region_t); | |
415 | ||
416 | *reply_port = kdp.reply_port; | |
417 | *len = rp->hdr.len; | |
418 | ||
419 | return (TRUE); | |
420 | } | |
421 | ||
422 | static boolean_t | |
423 | kdp_writeregs( | |
424 | kdp_pkt_t *pkt, | |
425 | int *len, | |
426 | unsigned short *reply_port | |
427 | ) | |
428 | { | |
429 | kdp_writeregs_req_t *rq = &pkt->writeregs_req; | |
430 | int plen = *len; | |
431 | int size; | |
432 | kdp_writeregs_reply_t *rp = &pkt->writeregs_reply; | |
433 | ||
434 | if (plen < sizeof (*rq)) | |
435 | return (FALSE); | |
436 | ||
437 | size = rq->hdr.len - sizeof(kdp_hdr_t) - sizeof(unsigned int); | |
438 | rp->error = kdp_machine_write_regs(rq->cpu, rq->flavor, rq->data, &size); | |
439 | ||
440 | rp->hdr.is_reply = 1; | |
441 | rp->hdr.len = sizeof (*rp); | |
442 | ||
443 | *reply_port = kdp.reply_port; | |
444 | *len = rp->hdr.len; | |
445 | ||
446 | return (TRUE); | |
447 | } | |
448 | ||
449 | static boolean_t | |
450 | kdp_readregs( | |
451 | kdp_pkt_t *pkt, | |
452 | int *len, | |
453 | unsigned short *reply_port | |
454 | ) | |
455 | { | |
456 | kdp_readregs_req_t *rq = &pkt->readregs_req; | |
457 | int plen = *len; | |
458 | kdp_readregs_reply_t *rp = &pkt->readregs_reply; | |
459 | int size; | |
460 | ||
461 | if (plen < sizeof (*rq)) | |
462 | return (FALSE); | |
463 | ||
464 | rp->hdr.is_reply = 1; | |
465 | rp->hdr.len = sizeof (*rp); | |
466 | ||
467 | rp->error = kdp_machine_read_regs(rq->cpu, rq->flavor, rp->data, &size); | |
468 | rp->hdr.len += size; | |
469 | ||
470 | *reply_port = kdp.reply_port; | |
471 | *len = rp->hdr.len; | |
472 | ||
473 | return (TRUE); | |
474 | } |