]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kdp/kdp.c
e5c58b9c49cd9018f89645467818a9ce785db7a7
[apple/xnu.git] / osfmk / kdp / kdp.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30
31 #include <mach/mach_types.h>
32 #include <kern/debug.h>
33
34 #include <kdp/kdp_internal.h>
35 #include <kdp/kdp_private.h>
36
37 #include <libsa/types.h>
38
39 #include <string.h> /* bcopy */
40
41 int kdp_vm_read( caddr_t, caddr_t, unsigned int);
42 int kdp_vm_write( caddr_t, caddr_t, unsigned int);
43
44 #define DO_ALIGN 1 /* align all packet data accesses */
45
46 #define KDP_TEST_HARNESS 0
47 #if KDP_TEST_HARNESS
48 #define dprintf(x) kprintf x
49 #else
50 #define dprintf(x)
51 #endif
52
53 static kdp_dispatch_t
54 dispatch_table[KDP_HOSTREBOOT - KDP_CONNECT +1] =
55 {
56 /* 0 */ kdp_connect,
57 /* 1 */ kdp_disconnect,
58 /* 2 */ kdp_hostinfo,
59 /* 3 */ kdp_version,
60 /* 4 */ kdp_maxbytes,
61 /* 5 */ kdp_readmem,
62 /* 6 */ kdp_writemem,
63 /* 7 */ kdp_readregs,
64 /* 8 */ kdp_writeregs,
65 /* 9 */ kdp_unknown,
66 /* A */ kdp_unknown,
67 /* B */ kdp_suspend,
68 /* C */ kdp_resumecpus,
69 /* D */ kdp_unknown,
70 /* E */ kdp_unknown,
71 /* F */ kdp_breakpoint_set,
72 /*10 */ kdp_breakpoint_remove,
73 /*11 */ kdp_regions,
74 /*12 */ kdp_reattach,
75 /*13 */ kdp_reboot
76 };
77
78 kdp_glob_t kdp;
79
80
81 #define MAX_BREAKPOINTS 100
82 #define KDP_MAX_BREAKPOINTS 100
83
84 #define BREAKPOINT_NOT_FOUND 101
85 #define BREAKPOINT_ALREADY_SET 102
86
87 #define KDP_VERSION 10
88
89 typedef struct{
90 unsigned int address;
91 unsigned int old_instruction;
92 } kdp_breakpoint_record_t;
93
94 static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS];
95 static unsigned int breakpoints_initialized = 0;
96
97 int reattach_wait = 0;
98 int noresume_on_disconnect = 0;
99
100 boolean_t
101 kdp_packet(
102 unsigned char *pkt,
103 int *len,
104 unsigned short *reply_port
105 )
106 {
107 static unsigned aligned_pkt[1538/sizeof(unsigned)+1]; // max ether pkt
108 kdp_pkt_t *rd = (kdp_pkt_t *)&aligned_pkt;
109 int plen = *len;
110 unsigned int req;
111 boolean_t ret;
112
113 #if DO_ALIGN
114 bcopy((char *)pkt, (char *)rd, sizeof(aligned_pkt));
115 #else
116 rd = (kdp_pkt_t *)pkt;
117 #endif
118 if (plen < sizeof (rd->hdr) || rd->hdr.len != plen) {
119 printf("kdp_packet bad len pkt %d hdr %d\n", plen, rd->hdr.len);
120
121 return (FALSE);
122 }
123
124 if (rd->hdr.is_reply) {
125 printf("kdp_packet reply recvd req %x seq %x\n",
126 rd->hdr.request, rd->hdr.seq);
127
128 return (FALSE);
129 }
130
131 req = rd->hdr.request;
132 if ((req < KDP_CONNECT) || (req > KDP_HOSTREBOOT)) {
133 printf("kdp_packet bad request %x len %d seq %x key %x\n",
134 rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
135
136 return (FALSE);
137 }
138
139 ret = ((*dispatch_table[req - KDP_CONNECT])(rd, len, reply_port));
140 #if DO_ALIGN
141 bcopy((char *)rd, (char *) pkt, *len);
142 #endif
143 return ret;
144 }
145
146 static boolean_t
147 kdp_unknown(
148 kdp_pkt_t *pkt,
149 int *len,
150 unsigned short *reply_port
151 )
152 {
153 kdp_pkt_t *rd = (kdp_pkt_t *)pkt;
154
155 printf("kdp_unknown request %x len %d seq %x key %x\n",
156 rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
157
158 return (FALSE);
159 }
160
161 static boolean_t
162 kdp_connect(
163 kdp_pkt_t *pkt,
164 int *len,
165 unsigned short *reply_port
166 )
167 {
168 kdp_connect_req_t *rq = &pkt->connect_req;
169 int plen = *len;
170 kdp_connect_reply_t *rp = &pkt->connect_reply;
171
172 if (plen < sizeof (*rq))
173 return (FALSE);
174
175 dprintf(("kdp_connect seq %x greeting %s\n", rq->hdr.seq, rq->greeting));
176
177 if (kdp.is_conn) {
178 if (rq->hdr.seq == kdp.conn_seq) /* duplicate request */
179 rp->error = KDPERR_NO_ERROR;
180 else
181 rp->error = KDPERR_ALREADY_CONNECTED;
182 }
183 else {
184 kdp.reply_port = rq->req_reply_port;
185 kdp.exception_port = rq->exc_note_port;
186 kdp.is_conn = TRUE;
187 kdp.conn_seq = rq->hdr.seq;
188
189 rp->error = KDPERR_NO_ERROR;
190 }
191
192 rp->hdr.is_reply = 1;
193 rp->hdr.len = sizeof (*rp);
194
195 *reply_port = kdp.reply_port;
196 *len = rp->hdr.len;
197
198 if (current_debugger == KDP_CUR_DB)
199 active_debugger=1;
200
201 return (TRUE);
202 }
203
204 static boolean_t
205 kdp_disconnect(
206 kdp_pkt_t *pkt,
207 int *len,
208 unsigned short *reply_port
209 )
210 {
211 kdp_disconnect_req_t *rq = &pkt->disconnect_req;
212 int plen = *len;
213 kdp_disconnect_reply_t *rp = &pkt->disconnect_reply;
214
215 if (plen < sizeof (*rq))
216 return (FALSE);
217
218 if (!kdp.is_conn)
219 return (FALSE);
220
221 dprintf(("kdp_disconnect\n"));
222
223 *reply_port = kdp.reply_port;
224
225 kdp.reply_port = kdp.exception_port = 0;
226 kdp.is_halted = kdp.is_conn = FALSE;
227 kdp.exception_seq = kdp.conn_seq = 0;
228
229 if (noresume_on_disconnect == 1) {
230 reattach_wait = 1;
231 noresume_on_disconnect = 0;
232 }
233
234 rp->hdr.is_reply = 1;
235 rp->hdr.len = sizeof (*rp);
236
237 *len = rp->hdr.len;
238
239 if (current_debugger == KDP_CUR_DB)
240 active_debugger=0;
241
242 return (TRUE);
243 }
244
245 static boolean_t
246 kdp_reattach(
247 kdp_pkt_t *pkt,
248 int *len,
249 unsigned short *reply_port
250 )
251 {
252 kdp_reattach_req_t *rq = &pkt->reattach_req;
253 kdp_disconnect_reply_t *rp = &pkt->disconnect_reply;
254
255 kdp.is_conn = TRUE;
256 kdp_disconnect(pkt, len, reply_port);
257 *reply_port = rq->req_reply_port;
258 reattach_wait = 1;
259 return (TRUE);
260 }
261
262 static boolean_t
263 kdp_hostinfo(
264 kdp_pkt_t *pkt,
265 int *len,
266 unsigned short *reply_port
267 )
268 {
269 kdp_hostinfo_req_t *rq = &pkt->hostinfo_req;
270 int plen = *len;
271 kdp_hostinfo_reply_t *rp = &pkt->hostinfo_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 kdp_machine_hostinfo(&rp->hostinfo);
280
281 *reply_port = kdp.reply_port;
282 *len = rp->hdr.len;
283
284 return (TRUE);
285 }
286
287 static boolean_t
288 kdp_suspend(
289 kdp_pkt_t *pkt,
290 int *len,
291 unsigned short *reply_port
292 )
293 {
294 kdp_suspend_req_t *rq = &pkt->suspend_req;
295 int plen = *len;
296 kdp_suspend_reply_t *rp = &pkt->suspend_reply;
297
298 if (plen < sizeof (*rq))
299 return (FALSE);
300
301 rp->hdr.is_reply = 1;
302 rp->hdr.len = sizeof (*rp);
303
304 dprintf(("kdp_suspend\n"));
305
306 kdp.is_halted = TRUE;
307
308 *reply_port = kdp.reply_port;
309 *len = rp->hdr.len;
310
311 return (TRUE);
312 }
313
314 static boolean_t
315 kdp_resumecpus(
316 kdp_pkt_t *pkt,
317 int *len,
318 unsigned short *reply_port
319 )
320 {
321 kdp_resumecpus_req_t *rq = &pkt->resumecpus_req;
322 int plen = *len;
323 kdp_resumecpus_reply_t *rp = &pkt->resumecpus_reply;
324
325 if (plen < sizeof (*rq))
326 return (FALSE);
327
328 rp->hdr.is_reply = 1;
329 rp->hdr.len = sizeof (*rp);
330
331 dprintf(("kdp_resumecpus %x\n", rq->cpu_mask));
332
333 kdp.is_halted = FALSE;
334
335 *reply_port = kdp.reply_port;
336 *len = rp->hdr.len;
337
338 return (TRUE);
339 }
340
341 static boolean_t
342 kdp_writemem(
343 kdp_pkt_t *pkt,
344 int *len,
345 unsigned short *reply_port
346 )
347 {
348 kdp_writemem_req_t *rq = &pkt->writemem_req;
349 int plen = *len;
350 kdp_writemem_reply_t *rp = &pkt->writemem_reply;
351 int cnt;
352
353 if (plen < sizeof (*rq))
354 return (FALSE);
355
356 if (rq->nbytes > MAX_KDP_DATA_SIZE)
357 rp->error = KDPERR_BAD_NBYTES;
358 else {
359 dprintf(("kdp_writemem addr %x size %d\n", rq->address, rq->nbytes));
360
361 cnt = kdp_vm_write((caddr_t)rq->data, (caddr_t)rq->address, rq->nbytes);
362 rp->error = KDPERR_NO_ERROR;
363 }
364
365 rp->hdr.is_reply = 1;
366 rp->hdr.len = sizeof (*rp);
367
368 *reply_port = kdp.reply_port;
369 *len = rp->hdr.len;
370
371 return (TRUE);
372 }
373
374 static boolean_t
375 kdp_readmem(
376 kdp_pkt_t *pkt,
377 int *len,
378 unsigned short *reply_port
379 )
380 {
381 kdp_readmem_req_t *rq = &pkt->readmem_req;
382 int plen = *len;
383 kdp_readmem_reply_t *rp = &pkt->readmem_reply;
384 int cnt;
385
386 if (plen < sizeof (*rq))
387 return (FALSE);
388
389 rp->hdr.is_reply = 1;
390 rp->hdr.len = sizeof (*rp);
391
392 if (rq->nbytes > MAX_KDP_DATA_SIZE)
393 rp->error = KDPERR_BAD_NBYTES;
394 else {
395 unsigned int n = rq->nbytes;
396
397 dprintf(("kdp_readmem addr %x size %d\n", rq->address, rq->nbytes));
398
399 cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)rp->data, rq->nbytes);
400 rp->error = KDPERR_NO_ERROR;
401
402 rp->hdr.len += cnt;
403 }
404
405 *reply_port = kdp.reply_port;
406 *len = rp->hdr.len;
407
408 return (TRUE);
409 }
410
411 static boolean_t
412 kdp_maxbytes(
413 kdp_pkt_t *pkt,
414 int *len,
415 unsigned short *reply_port
416 )
417 {
418 kdp_maxbytes_req_t *rq = &pkt->maxbytes_req;
419 int plen = *len;
420 kdp_maxbytes_reply_t *rp = &pkt->maxbytes_reply;
421
422 if (plen < sizeof (*rq))
423 return (FALSE);
424
425 rp->hdr.is_reply = 1;
426 rp->hdr.len = sizeof (*rp);
427
428 dprintf(("kdp_maxbytes\n"));
429
430 rp->max_bytes = MAX_KDP_DATA_SIZE;
431
432 *reply_port = kdp.reply_port;
433 *len = rp->hdr.len;
434
435 return (TRUE);
436 }
437
438 static boolean_t
439 kdp_version(
440 kdp_pkt_t *pkt,
441 int *len,
442 unsigned short *reply_port
443 )
444 {
445 kdp_version_req_t *rq = &pkt->version_req;
446 int plen = *len;
447 kdp_version_reply_t *rp = &pkt->version_reply;
448 kdp_region_t *r;
449
450 if (plen < sizeof (*rq))
451 return (FALSE);
452
453 rp->hdr.is_reply = 1;
454 rp->hdr.len = sizeof (*rp);
455
456 dprintf(("kdp_version\n"));
457
458 rp->version = KDP_VERSION;
459 #ifdef __ppc__
460 if (!(kdp_flag & KDP_BP_DIS))
461 rp->feature = KDP_FEATURE_BP;
462 else
463 rp->feature = 0;
464 #else
465 rp->feature = 0;
466 #endif
467
468 *reply_port = kdp.reply_port;
469 *len = rp->hdr.len;
470
471 return (TRUE);
472 }
473
474 static boolean_t
475 kdp_regions(
476 kdp_pkt_t *pkt,
477 int *len,
478 unsigned short *reply_port
479 )
480 {
481 kdp_regions_req_t *rq = &pkt->regions_req;
482 int plen = *len;
483 kdp_regions_reply_t *rp = &pkt->regions_reply;
484 kdp_region_t *r;
485
486 if (plen < sizeof (*rq))
487 return (FALSE);
488
489 rp->hdr.is_reply = 1;
490 rp->hdr.len = sizeof (*rp);
491
492 dprintf(("kdp_regions\n"));
493
494 r = rp->regions;
495 rp->nregions = 0;
496
497 (vm_offset_t)r->address = 0;
498 r->nbytes = 0xffffffff;
499
500 r->protection = VM_PROT_ALL; r++; rp->nregions++;
501
502 rp->hdr.len += rp->nregions * sizeof (kdp_region_t);
503
504 *reply_port = kdp.reply_port;
505 *len = rp->hdr.len;
506
507 return (TRUE);
508 }
509
510 static boolean_t
511 kdp_writeregs(
512 kdp_pkt_t *pkt,
513 int *len,
514 unsigned short *reply_port
515 )
516 {
517 kdp_writeregs_req_t *rq = &pkt->writeregs_req;
518 int plen = *len;
519 int size;
520 kdp_writeregs_reply_t *rp = &pkt->writeregs_reply;
521
522 if (plen < sizeof (*rq))
523 return (FALSE);
524
525 size = rq->hdr.len - sizeof(kdp_hdr_t) - sizeof(unsigned int);
526 rp->error = kdp_machine_write_regs(rq->cpu, rq->flavor, rq->data, &size);
527
528 rp->hdr.is_reply = 1;
529 rp->hdr.len = sizeof (*rp);
530
531 *reply_port = kdp.reply_port;
532 *len = rp->hdr.len;
533
534 return (TRUE);
535 }
536
537 static boolean_t
538 kdp_readregs(
539 kdp_pkt_t *pkt,
540 int *len,
541 unsigned short *reply_port
542 )
543 {
544 kdp_readregs_req_t *rq = &pkt->readregs_req;
545 int plen = *len;
546 kdp_readregs_reply_t *rp = &pkt->readregs_reply;
547 int size;
548
549 if (plen < sizeof (*rq))
550 return (FALSE);
551
552 rp->hdr.is_reply = 1;
553 rp->hdr.len = sizeof (*rp);
554
555 rp->error = kdp_machine_read_regs(rq->cpu, rq->flavor, rp->data, &size);
556 rp->hdr.len += size;
557
558 *reply_port = kdp.reply_port;
559 *len = rp->hdr.len;
560
561 return (TRUE);
562 }
563
564 static boolean_t
565 kdp_breakpoint_set(
566 kdp_pkt_t *pkt,
567 int *len,
568 unsigned short *reply_port
569 )
570 {
571 kdp_breakpoint_req_t *rq = &pkt->breakpoint_req;
572 kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
573 int plen = *len;
574 int cnt, i;
575 unsigned int old_instruction = 0;
576 unsigned int breakinstr = kdp_ml_get_breakinsn();
577
578 if(breakpoints_initialized == 0)
579 {
580 for(i=0;(i < MAX_BREAKPOINTS); breakpoint_list[i].address=0, i++);
581 breakpoints_initialized++;
582 }
583 if (plen < sizeof (*rq))
584 return (FALSE);
585 cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)(&old_instruction), sizeof(int));
586
587 if (old_instruction==breakinstr)
588 {
589 printf("A trap was already set at that address, not setting new breakpoint\n");
590 rp->error = BREAKPOINT_ALREADY_SET;
591
592 rp->hdr.is_reply = 1;
593 rp->hdr.len = sizeof (*rp);
594 *reply_port = kdp.reply_port;
595 *len = rp->hdr.len;
596
597 return (TRUE);
598 }
599
600 for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != 0); i++);
601
602 if (i == MAX_BREAKPOINTS)
603 {
604 rp->error = KDP_MAX_BREAKPOINTS;
605
606 rp->hdr.is_reply = 1;
607 rp->hdr.len = sizeof (*rp);
608 *reply_port = kdp.reply_port;
609 *len = rp->hdr.len;
610
611 return (TRUE);
612 }
613 breakpoint_list[i].address = rq->address;
614 breakpoint_list[i].old_instruction = old_instruction;
615
616 cnt = kdp_vm_write((caddr_t)&breakinstr, (caddr_t)rq->address, sizeof(&breakinstr));
617
618 rp->error = KDPERR_NO_ERROR;
619 rp->hdr.is_reply = 1;
620 rp->hdr.len = sizeof (*rp);
621 *reply_port = kdp.reply_port;
622 *len = rp->hdr.len;
623
624 return (TRUE);
625 }
626
627 static boolean_t
628 kdp_breakpoint_remove(
629 kdp_pkt_t *pkt,
630 int *len,
631 unsigned short *reply_port
632 )
633 {
634 kdp_breakpoint_req_t *rq = &pkt->breakpoint_req;
635 kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
636 int plen = *len;
637 int cnt,i;
638
639 if (plen < sizeof (*rq))
640 return (FALSE);
641
642 for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != rq->address); i++);
643 if (i == MAX_BREAKPOINTS)
644 {
645 rp->error = BREAKPOINT_NOT_FOUND;
646 rp->hdr.is_reply = 1;
647 rp->hdr.len = sizeof (*rp);
648 *reply_port = kdp.reply_port;
649 *len = rp->hdr.len;
650
651 return (TRUE); /* Check if it needs to be FALSE in case of error */
652 }
653
654 breakpoint_list[i].address = 0;
655 cnt = kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)rq->address, sizeof(int));
656 rp->error = KDPERR_NO_ERROR;
657 rp->hdr.is_reply = 1;
658 rp->hdr.len = sizeof (*rp);
659 *reply_port = kdp.reply_port;
660 *len = rp->hdr.len;
661
662 return (TRUE);
663 }
664
665 boolean_t
666 kdp_remove_all_breakpoints()
667 {
668 int i;
669 boolean_t breakpoint_found = FALSE;
670
671 if (breakpoints_initialized)
672 {
673 for(i=0;i < MAX_BREAKPOINTS; i++)
674 {
675 if (breakpoint_list[i].address)
676 {
677 kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)breakpoint_list[i].address, sizeof(int));
678 breakpoint_found = TRUE;
679 breakpoint_list[i].address = 0;
680 }
681 }
682 if (breakpoint_found)
683 printf("kdp_remove_all_breakpoints: found extant breakpoints, removing them.\n");
684 }
685 return breakpoint_found;
686 }