1/*
2 * Copyright (c) 2000-2012 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
29#include <mach/mach_types.h>
30#include <mach/vm_param.h>
31#include <sys/appleapiopts.h>
32#include <kern/debug.h>
33#include <uuid/uuid.h>
34
35#include <kdp/kdp_internal.h>
36#include <kdp/kdp_private.h>
37#include <kdp/kdp_core.h>
38
39#include <libsa/types.h>
40#include <libkern/version.h>
41
42#include <string.h> /* bcopy */
43
44#include <kern/processor.h>
45#include <kern/thread.h>
46#include <kern/clock.h>
47#include <vm/vm_map.h>
48#include <vm/vm_kern.h>
49#include <vm/vm_pageout.h>
50#include <vm/vm_shared_region.h>
51#include <libkern/OSKextLibPrivate.h>
52
53#define DO_ALIGN	1	/* align all packet data accesses */
54
55#define KDP_TEST_HARNESS 0
56#if KDP_TEST_HARNESS
57#define dprintf(x) kprintf x
58#else
59#define dprintf(x)
60#endif
61
62static kdp_dispatch_t
63    dispatch_table[KDP_INVALID_REQUEST-KDP_CONNECT] =
64    {
65/* 0 */	kdp_connect,
66/* 1 */	kdp_disconnect,
67/* 2 */	kdp_hostinfo,
68/* 3 */	kdp_version,
69/* 4 */	kdp_maxbytes,
70/* 5 */	kdp_readmem,
71/* 6 */	kdp_writemem,
72/* 7 */	kdp_readregs,
73/* 8 */	kdp_writeregs,
74/* 9 */ kdp_unknown,
75/* A */ kdp_unknown,
76/* B */	kdp_suspend,
77/* C */	kdp_resumecpus,
78/* D */	kdp_unknown,
79/* E */ kdp_unknown,
80/* F */ kdp_breakpoint_set,
81/*10 */ kdp_breakpoint_remove,
82/*11 */	kdp_regions,
83/*12 */ kdp_reattach,
84/*13 */ kdp_reboot,
85/*14 */ kdp_readmem64,
86/*15 */ kdp_writemem64,
87/*16 */ kdp_breakpoint64_set,
88/*17 */ kdp_breakpoint64_remove,
89/*18 */ kdp_kernelversion,
90/*19 */ kdp_readphysmem64,
91/*1A */ kdp_writephysmem64,
92/*1B */ kdp_readioport,
93/*1C */ kdp_writeioport,
94/*1D */ kdp_readmsr64,
95/*1E */ kdp_writemsr64,
96/*1F */ kdp_dumpinfo,
97    };
98
99kdp_glob_t	kdp;
100
101#define MAX_BREAKPOINTS 100
102
103/*
104 * Version 11 of the KDP Protocol adds support for 64-bit wide memory
105 * addresses (read/write and breakpoints) as well as a dedicated
106 * kernelversion request. Version 12 adds read/writing of physical
107 * memory with 64-bit wide memory addresses.
108 */
109#define KDP_VERSION 12
110
111typedef struct{
112	mach_vm_address_t	address;
113	uint32_t	bytesused;
114	uint8_t		oldbytes[MAX_BREAKINSN_BYTES];
115} kdp_breakpoint_record_t;
116
117static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS];
118static unsigned int breakpoints_initialized = 0;
119
120int reattach_wait = 0;
121int noresume_on_disconnect = 0;
122extern unsigned int return_on_panic;
123
124kdp_error_t
125kdp_set_breakpoint_internal(
126							   mach_vm_address_t	address
127							   );
128
129kdp_error_t
130kdp_remove_breakpoint_internal(
131							   mach_vm_address_t	address
132							   );
133
134boolean_t
135kdp_packet(
136    unsigned char	*pkt,
137    int			*len,
138    unsigned short	*reply_port
139)
140{
141    static unsigned	aligned_pkt[1538/sizeof(unsigned)+1]; // max ether pkt
142    kdp_pkt_t		*rd = (kdp_pkt_t *)&aligned_pkt;
143    size_t		plen = *len;
144    kdp_req_t		req;
145    boolean_t		ret;
146
147#if DO_ALIGN
148    bcopy((char *)pkt, (char *)rd, sizeof(aligned_pkt));
149#else
150    rd = (kdp_pkt_t *)pkt;
151#endif
152    if (plen < sizeof (rd->hdr) || rd->hdr.len != plen) {
153	printf("kdp_packet bad len pkt %lu hdr %d\n", plen, rd->hdr.len);
154
155	return (FALSE);
156    }
157
158    if (rd->hdr.is_reply) {
159	printf("kdp_packet reply recvd req %x seq %x\n",
160	    rd->hdr.request, rd->hdr.seq);
161
162	return (FALSE);
163    }
164
165    req = rd->hdr.request;
166    if (req >= KDP_INVALID_REQUEST) {
167	printf("kdp_packet bad request %x len %d seq %x key %x\n",
168	    rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
169
170	return (FALSE);
171    }
172
173    ret = ((*dispatch_table[req - KDP_CONNECT])(rd, len, reply_port));
174#if DO_ALIGN
175    bcopy((char *)rd, (char *) pkt, *len);
176#endif
177    return ret;
178}
179
180static boolean_t
181kdp_unknown(
182    kdp_pkt_t		*pkt,
183    __unused int	*len,
184    __unused unsigned short	*reply_port
185)
186{
187    kdp_pkt_t		*rd = (kdp_pkt_t *)pkt;
188
189    printf("kdp_unknown request %x len %d seq %x key %x\n",
190	rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
191
192    return (FALSE);
193}
194
195static boolean_t
196kdp_connect(
197    kdp_pkt_t		*pkt,
198    int			*len,
199    unsigned short	*reply_port
200)
201{
202    kdp_connect_req_t	*rq = &pkt->connect_req;
203    size_t		plen = *len;
204    kdp_connect_reply_t	*rp = &pkt->connect_reply;
205    uint16_t            rport, eport;
206    uint32_t            key;
207    uint8_t             seq;
208
209    if (plen < sizeof (*rq))
210	return (FALSE);
211
212    dprintf(("kdp_connect seq %x greeting %s\n", rq->hdr.seq, rq->greeting));
213
214    rport = rq->req_reply_port;
215    eport = rq->exc_note_port;
216    key   = rq->hdr.key;
217    seq   = rq->hdr.seq;
218    if (kdp.is_conn) {
219	if ((seq == kdp.conn_seq) &&	/* duplicate request */
220            (rport == kdp.reply_port) &&
221            (eport == kdp.exception_port) &&
222            (key == kdp.session_key))
223	    rp->error = KDPERR_NO_ERROR;
224	else
225	    rp->error = KDPERR_ALREADY_CONNECTED;
226    }
227    else {
228	kdp.reply_port     = rport;
229	kdp.exception_port = eport;
230	kdp.is_conn        = TRUE;
231	kdp.conn_seq       = seq;
232        kdp.session_key    = key;
233
234	rp->error = KDPERR_NO_ERROR;
235    }
236
237    rp->hdr.is_reply = 1;
238    rp->hdr.len = sizeof (*rp);
239
240    *reply_port = rport;
241    *len = rp->hdr.len;
242
243    if (current_debugger == KDP_CUR_DB)
244    	active_debugger=1;
245
246    return (TRUE);
247}
248
249static boolean_t
250kdp_disconnect(
251    kdp_pkt_t		*pkt,
252    int			*len,
253    unsigned short	*reply_port
254)
255{
256    kdp_disconnect_req_t	*rq = &pkt->disconnect_req;
257    size_t			plen = *len;
258    kdp_disconnect_reply_t	*rp = &pkt->disconnect_reply;
259
260    if (plen < sizeof (*rq))
261	return (FALSE);
262
263    if (!kdp.is_conn)
264	return (FALSE);
265
266    dprintf(("kdp_disconnect\n"));
267
268    *reply_port = kdp.reply_port;
269
270    kdp.reply_port = kdp.exception_port = 0;
271    kdp.is_halted = kdp.is_conn = FALSE;
272    kdp.exception_seq = kdp.conn_seq = 0;
273    kdp.session_key = 0;
274
275    if ((panicstr != NULL) && (return_on_panic == 0))
276	reattach_wait = 1;
277
278    if (noresume_on_disconnect == 1) {
279	reattach_wait = 1;
280	noresume_on_disconnect = 0;
281    }
282
283    rp->hdr.is_reply = 1;
284    rp->hdr.len = sizeof (*rp);
285
286    *len = rp->hdr.len;
287
288    if (current_debugger == KDP_CUR_DB)
289    	active_debugger=0;
290
291    return (TRUE);
292}
293
294static boolean_t
295kdp_reattach(
296    kdp_pkt_t		*pkt,
297    int			*len,
298    unsigned short	*reply_port
299)
300{
301    kdp_reattach_req_t            *rq = &pkt->reattach_req;
302
303    kdp.is_conn = TRUE;
304    kdp_disconnect(pkt, len, reply_port);
305    *reply_port = rq->req_reply_port;
306    reattach_wait = 1;
307    return (TRUE);
308}
309
310static boolean_t
311kdp_hostinfo(
312    kdp_pkt_t		*pkt,
313    int			*len,
314    unsigned short	*reply_port
315)
316{
317    kdp_hostinfo_req_t	*rq = &pkt->hostinfo_req;
318    size_t		plen = *len;
319    kdp_hostinfo_reply_t *rp = &pkt->hostinfo_reply;
320
321    if (plen < sizeof (*rq))
322	return (FALSE);
323
324    dprintf(("kdp_hostinfo\n"));
325
326    rp->hdr.is_reply = 1;
327    rp->hdr.len = sizeof (*rp);
328
329    kdp_machine_hostinfo(&rp->hostinfo);
330
331    *reply_port = kdp.reply_port;
332    *len = rp->hdr.len;
333
334    return (TRUE);
335}
336
337static boolean_t
338kdp_kernelversion(
339    kdp_pkt_t		*pkt,
340    int			*len,
341    unsigned short	*reply_port
342)
343{
344    kdp_kernelversion_req_t	*rq = &pkt->kernelversion_req;
345    size_t		plen = *len;
346    kdp_kernelversion_reply_t *rp = &pkt->kernelversion_reply;
347	size_t		slen;
348
349    if (plen < sizeof (*rq))
350		return (FALSE);
351
352    rp->hdr.is_reply = 1;
353    rp->hdr.len = sizeof (*rp);
354
355    dprintf(("kdp_kernelversion\n"));
356    slen = strlcpy(rp->version, kdp_kernelversion_string, MAX_KDP_DATA_SIZE);
357
358    rp->hdr.len += slen + 1; /* strlcpy returns the amount copied with NUL */
359
360    *reply_port = kdp.reply_port;
361    *len = rp->hdr.len;
362
363    return (TRUE);
364}
365
366static boolean_t
367kdp_suspend(
368    kdp_pkt_t		*pkt,
369    int			*len,
370    unsigned short	*reply_port
371)
372{
373    kdp_suspend_req_t	*rq = &pkt->suspend_req;
374    size_t		plen = *len;
375    kdp_suspend_reply_t *rp = &pkt->suspend_reply;
376
377    if (plen < sizeof (*rq))
378	return (FALSE);
379
380    rp->hdr.is_reply = 1;
381    rp->hdr.len = sizeof (*rp);
382
383    dprintf(("kdp_suspend\n"));
384
385    kdp.is_halted = TRUE;
386
387    *reply_port = kdp.reply_port;
388    *len = rp->hdr.len;
389
390    return (TRUE);
391}
392
393static boolean_t
394kdp_resumecpus(
395    kdp_pkt_t		*pkt,
396    int			*len,
397    unsigned short	*reply_port
398)
399{
400    kdp_resumecpus_req_t	*rq = &pkt->resumecpus_req;
401    size_t			plen = *len;
402    kdp_resumecpus_reply_t 	*rp = &pkt->resumecpus_reply;
403
404    if (plen < sizeof (*rq))
405	return (FALSE);
406
407    rp->hdr.is_reply = 1;
408    rp->hdr.len = sizeof (*rp);
409
410    dprintf(("kdp_resumecpus %x\n", rq->cpu_mask));
411
412    kdp.is_halted = FALSE;
413
414    *reply_port = kdp.reply_port;
415    *len = rp->hdr.len;
416
417    return (TRUE);
418}
419
420static boolean_t
421kdp_writemem(
422    kdp_pkt_t		*pkt,
423    int			*len,
424    unsigned short	*reply_port
425)
426{
427    kdp_writemem_req_t	*rq = &pkt->writemem_req;
428    size_t		plen = *len;
429    kdp_writemem_reply_t *rp = &pkt->writemem_reply;
430    mach_vm_size_t 	cnt;
431
432    if (plen < sizeof (*rq))
433	return (FALSE);
434
435    if (rq->nbytes > MAX_KDP_DATA_SIZE)
436	rp->error = KDPERR_BAD_NBYTES;
437    else {
438	dprintf(("kdp_writemem addr %x size %d\n", rq->address, rq->nbytes));
439	cnt = kdp_machine_vm_write((caddr_t)rq->data, (mach_vm_address_t)rq->address, rq->nbytes);
440	rp->error = KDPERR_ACCESS(rq->nbytes, cnt);
441	dprintf(("  cnt %lld error %d\n", cnt, rp->error));
442    }
443
444    rp->hdr.is_reply = 1;
445    rp->hdr.len = sizeof (*rp);
446
447    *reply_port = kdp.reply_port;
448    *len = rp->hdr.len;
449
450    return (TRUE);
451}
452
453static boolean_t
454kdp_writemem64(
455    kdp_pkt_t		*pkt,
456    int			*len,
457    unsigned short	*reply_port
458)
459{
460    kdp_writemem64_req_t	*rq = &pkt->writemem64_req;
461    size_t		plen = *len;
462    kdp_writemem64_reply_t *rp = &pkt->writemem64_reply;
463    mach_vm_size_t 		cnt;
464
465    if (plen < sizeof (*rq))
466		return (FALSE);
467
468    if (rq->nbytes > MAX_KDP_DATA_SIZE)
469	rp->error = KDPERR_BAD_NBYTES;
470    else {
471	dprintf(("kdp_writemem64 addr %llx size %d\n", rq->address, rq->nbytes));
472	cnt = kdp_machine_vm_write((caddr_t)rq->data, (mach_vm_address_t)rq->address, (mach_vm_size_t)rq->nbytes);
473	rp->error = KDPERR_ACCESS(rq->nbytes, cnt);
474	dprintf(("  cnt %lld error %d\n", cnt, rp->error));
475    }
476
477    rp->hdr.is_reply = 1;
478    rp->hdr.len = sizeof (*rp);
479
480    *reply_port = kdp.reply_port;
481    *len = rp->hdr.len;
482
483    return (TRUE);
484}
485
486static boolean_t
487kdp_writephysmem64(
488    kdp_pkt_t		*pkt,
489    int			*len,
490    unsigned short	*reply_port
491)
492{
493    kdp_writephysmem64_req_t	*rq = &pkt->writephysmem64_req;
494    size_t		plen = *len;
495    kdp_writephysmem64_reply_t *rp = &pkt->writephysmem64_reply;
496    mach_vm_size_t 		cnt;
497    unsigned int		size;
498
499    if (plen < sizeof (*rq))
500	return (FALSE);
501
502    size = rq->nbytes;
503    if (size > MAX_KDP_DATA_SIZE)
504	rp->error = KDPERR_BAD_NBYTES;
505    else {
506	dprintf(("kdp_writephysmem64 addr %llx size %d\n", rq->address, size));
507	cnt = kdp_machine_phys_write(rq, rq->data, rq->lcpu);
508	rp->error = KDPERR_ACCESS(size, cnt);
509	dprintf(("  cnt %lld error %d\n", cnt, rp->error));
510    }
511
512    rp->hdr.is_reply = 1;
513    rp->hdr.len = sizeof (*rp);
514
515    *reply_port = kdp.reply_port;
516    *len = rp->hdr.len;
517
518    return (TRUE);
519}
520
521static boolean_t
522kdp_readmem(
523    kdp_pkt_t		*pkt,
524    int			*len,
525    unsigned short	*reply_port
526)
527{
528    kdp_readmem_req_t	*rq = &pkt->readmem_req;
529    size_t		plen = *len;
530    kdp_readmem_reply_t *rp = &pkt->readmem_reply;
531    mach_vm_size_t	cnt;
532    unsigned int	size;
533
534    if (plen < sizeof (*rq))
535	return (FALSE);
536
537    rp->hdr.is_reply = 1;
538    rp->hdr.len = sizeof (*rp);
539
540    size = rq->nbytes;
541    if (size > MAX_KDP_DATA_SIZE)
542	rp->error = KDPERR_BAD_NBYTES;
543    else {
544	dprintf(("kdp_readmem addr %x size %d\n", rq->address, size));
545	cnt = kdp_machine_vm_read((mach_vm_address_t)rq->address, (caddr_t)rp->data, rq->nbytes);
546	rp->error = KDPERR_ACCESS(size, cnt);
547	dprintf(("  cnt %lld error %d\n", cnt, rp->error));
548
549	rp->hdr.len += cnt;
550    }
551
552    *reply_port = kdp.reply_port;
553    *len = rp->hdr.len;
554
555    return (TRUE);
556}
557
558static boolean_t
559kdp_readmem64(
560    kdp_pkt_t		*pkt,
561    int			*len,
562    unsigned short	*reply_port
563)
564{
565    kdp_readmem64_req_t	*rq = &pkt->readmem64_req;
566    size_t		plen = *len;
567    kdp_readmem64_reply_t *rp = &pkt->readmem64_reply;
568    mach_vm_size_t	cnt;
569    unsigned int	size;
570
571    if (plen < sizeof (*rq))
572		return (FALSE);
573
574    rp->hdr.is_reply = 1;
575    rp->hdr.len = sizeof (*rp);
576
577    size = rq->nbytes;
578    if (size > MAX_KDP_DATA_SIZE)
579	rp->error = KDPERR_BAD_NBYTES;
580    else {
581	dprintf(("kdp_readmem64 addr %llx size %d\n", rq->address, size));
582	cnt = kdp_machine_vm_read((mach_vm_address_t)rq->address, (caddr_t)rp->data, rq->nbytes);
583	rp->error = KDPERR_ACCESS(size, cnt);
584	dprintf(("  cnt %lld error %d\n", cnt, rp->error));
585
586	rp->hdr.len += cnt;
587    }
588
589    *reply_port = kdp.reply_port;
590    *len = rp->hdr.len;
591
592    return (TRUE);
593}
594
595static boolean_t
596kdp_readphysmem64(
597    kdp_pkt_t		*pkt,
598    int			*len,
599    unsigned short	*reply_port
600)
601{
602    kdp_readphysmem64_req_t	*rq = &pkt->readphysmem64_req;
603    size_t		plen = *len;
604    kdp_readphysmem64_reply_t *rp = &pkt->readphysmem64_reply;
605    mach_vm_size_t	cnt;
606    unsigned int	size;
607
608    if (plen < sizeof (*rq))
609	return (FALSE);
610
611    rp->hdr.is_reply = 1;
612    rp->hdr.len = sizeof (*rp);
613
614    size = rq->nbytes;
615    if (size > MAX_KDP_DATA_SIZE)
616	rp->error = KDPERR_BAD_NBYTES;
617    else {
618	dprintf(("kdp_readphysmem64 addr %llx size %d\n", rq->address, size));
619	cnt = kdp_machine_phys_read(rq, rp->data, rq->lcpu);
620	rp->error = KDPERR_ACCESS(size, cnt);
621	dprintf(("  cnt %lld error %d\n", cnt, rp->error));
622
623	rp->hdr.len += cnt;
624    }
625
626    *reply_port = kdp.reply_port;
627    *len = rp->hdr.len;
628
629    return (TRUE);
630}
631
632static boolean_t
633kdp_maxbytes(
634    kdp_pkt_t		*pkt,
635    int			*len,
636    unsigned short	*reply_port
637)
638{
639    kdp_maxbytes_req_t	*rq = &pkt->maxbytes_req;
640    size_t		plen = *len;
641    kdp_maxbytes_reply_t *rp = &pkt->maxbytes_reply;
642
643    if (plen < sizeof (*rq))
644	return (FALSE);
645
646    rp->hdr.is_reply = 1;
647    rp->hdr.len = sizeof (*rp);
648
649    dprintf(("kdp_maxbytes\n"));
650
651    rp->max_bytes = MAX_KDP_DATA_SIZE;
652
653    *reply_port = kdp.reply_port;
654    *len = rp->hdr.len;
655
656    return (TRUE);
657}
658
659static boolean_t
660kdp_version(
661    kdp_pkt_t		*pkt,
662    int			*len,
663    unsigned short	*reply_port
664)
665{
666    kdp_version_req_t	*rq = &pkt->version_req;
667    size_t		plen = *len;
668    kdp_version_reply_t *rp = &pkt->version_reply;
669
670    if (plen < sizeof (*rq))
671	return (FALSE);
672
673    rp->hdr.is_reply = 1;
674    rp->hdr.len = sizeof (*rp);
675
676    dprintf(("kdp_version\n"));
677
678    rp->version = KDP_VERSION;
679    if (!(kdp_flag & KDP_BP_DIS))
680      rp->feature = KDP_FEATURE_BP;
681    else
682      rp->feature = 0;
683
684    *reply_port = kdp.reply_port;
685    *len = rp->hdr.len;
686
687    return (TRUE);
688}
689
690static boolean_t
691kdp_regions(
692    kdp_pkt_t		*pkt,
693    int			*len,
694    unsigned short	*reply_port
695)
696{
697    kdp_regions_req_t	*rq = &pkt->regions_req;
698    size_t		plen = *len;
699    kdp_regions_reply_t *rp = &pkt->regions_reply;
700    kdp_region_t	*r;
701
702    if (plen < sizeof (*rq))
703	return (FALSE);
704
705    rp->hdr.is_reply = 1;
706    rp->hdr.len = sizeof (*rp);
707
708    dprintf(("kdp_regions\n"));
709
710    r = rp->regions;
711    rp->nregions = 0;
712
713    r->address = 0;
714    r->nbytes = 0xffffffff;
715
716    r->protection = VM_PROT_ALL; r++; rp->nregions++;
717
718    rp->hdr.len += rp->nregions * sizeof (kdp_region_t);
719
720    *reply_port = kdp.reply_port;
721    *len = rp->hdr.len;
722
723    return (TRUE);
724}
725
726static boolean_t
727kdp_writeregs(
728    kdp_pkt_t		*pkt,
729    int			*len,
730    unsigned short	*reply_port
731)
732{
733    kdp_writeregs_req_t	*rq = &pkt->writeregs_req;
734    size_t		plen = *len;
735    int			size;
736    kdp_writeregs_reply_t *rp = &pkt->writeregs_reply;
737
738    if (plen < sizeof (*rq))
739	return (FALSE);
740
741    size = rq->hdr.len - (unsigned)sizeof(kdp_hdr_t) - (unsigned)sizeof(unsigned int);
742    rp->error = kdp_machine_write_regs(rq->cpu, rq->flavor, rq->data, &size);
743
744    rp->hdr.is_reply = 1;
745    rp->hdr.len = sizeof (*rp);
746
747    *reply_port = kdp.reply_port;
748    *len = rp->hdr.len;
749
750    return (TRUE);
751}
752
753static boolean_t
754kdp_readregs(
755    kdp_pkt_t		*pkt,
756    int			*len,
757    unsigned short	*reply_port
758)
759{
760    kdp_readregs_req_t	*rq = &pkt->readregs_req;
761    size_t		plen = *len;
762    kdp_readregs_reply_t *rp = &pkt->readregs_reply;
763    int			size;
764
765    if (plen < sizeof (*rq))
766	return (FALSE);
767
768    rp->hdr.is_reply = 1;
769    rp->hdr.len = sizeof (*rp);
770
771    rp->error = kdp_machine_read_regs(rq->cpu, rq->flavor, rp->data, &size);
772    rp->hdr.len += size;
773
774    *reply_port = kdp.reply_port;
775    *len = rp->hdr.len;
776
777    return (TRUE);
778}
779
780
781boolean_t
782kdp_breakpoint_set(
783    kdp_pkt_t		*pkt,
784    int			*len,
785    unsigned short	*reply_port
786)
787{
788	kdp_breakpoint_req_t	*rq = &pkt->breakpoint_req;
789	kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
790	size_t		plen = *len;
791	kdp_error_t	kerr;
792
793	if (plen < sizeof (*rq))
794		return (FALSE);
795
796	dprintf(("kdp_breakpoint_set %x\n", rq->address));
797
798	kerr = kdp_set_breakpoint_internal((mach_vm_address_t)rq->address);
799
800	rp->error = kerr;
801
802	rp->hdr.is_reply = 1;
803	rp->hdr.len = sizeof (*rp);
804	*reply_port = kdp.reply_port;
805	*len = rp->hdr.len;
806
807	return (TRUE);
808}
809
810boolean_t
811kdp_breakpoint64_set(
812    kdp_pkt_t		*pkt,
813    int			*len,
814    unsigned short	*reply_port
815)
816{
817	kdp_breakpoint64_req_t	*rq = &pkt->breakpoint64_req;
818	kdp_breakpoint64_reply_t *rp = &pkt->breakpoint64_reply;
819	size_t		plen = *len;
820	kdp_error_t	kerr;
821
822	if (plen < sizeof (*rq))
823		return (FALSE);
824
825	dprintf(("kdp_breakpoint64_set %llx\n", rq->address));
826
827	kerr = kdp_set_breakpoint_internal((mach_vm_address_t)rq->address);
828
829	rp->error = kerr;
830
831	rp->hdr.is_reply = 1;
832	rp->hdr.len = sizeof (*rp);
833	*reply_port = kdp.reply_port;
834	*len = rp->hdr.len;
835
836	return (TRUE);
837}
838
839boolean_t
840kdp_breakpoint_remove(
841    kdp_pkt_t		*pkt,
842    int			*len,
843    unsigned short	*reply_port
844)
845{
846	kdp_breakpoint_req_t	*rq = &pkt->breakpoint_req;
847	kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
848	size_t		plen = *len;
849	kdp_error_t	kerr;
850	if (plen < sizeof (*rq))
851		return (FALSE);
852
853	dprintf(("kdp_breakpoint_remove %x\n", rq->address));
854
855	kerr = kdp_remove_breakpoint_internal((mach_vm_address_t)rq->address);
856
857	rp->error = kerr;
858
859	rp->hdr.is_reply = 1;
860	rp->hdr.len = sizeof (*rp);
861	*reply_port = kdp.reply_port;
862	*len = rp->hdr.len;
863
864	return (TRUE);
865}
866
867boolean_t
868kdp_breakpoint64_remove(
869    kdp_pkt_t		*pkt,
870    int			*len,
871    unsigned short	*reply_port
872)
873{
874	kdp_breakpoint64_req_t	*rq = &pkt->breakpoint64_req;
875	kdp_breakpoint64_reply_t *rp = &pkt->breakpoint64_reply;
876	size_t		plen = *len;
877	kdp_error_t	kerr;
878
879	if (plen < sizeof (*rq))
880		return (FALSE);
881
882	dprintf(("kdp_breakpoint64_remove %llx\n", rq->address));
883
884	kerr = kdp_remove_breakpoint_internal((mach_vm_address_t)rq->address);
885
886	rp->error = kerr;
887
888	rp->hdr.is_reply = 1;
889	rp->hdr.len = sizeof (*rp);
890	*reply_port = kdp.reply_port;
891	*len = rp->hdr.len;
892
893	return (TRUE);
894}
895
896
897kdp_error_t
898kdp_set_breakpoint_internal(
899    mach_vm_address_t	address
900)
901{
902
903	uint8_t		breakinstr[MAX_BREAKINSN_BYTES], oldinstr[MAX_BREAKINSN_BYTES];
904	uint32_t	breakinstrsize = sizeof(breakinstr);
905	mach_vm_size_t	cnt;
906	int			i;
907
908	kdp_machine_get_breakinsn(breakinstr, &breakinstrsize);
909
910	if(breakpoints_initialized == 0)
911    {
912		for(i=0;(i < MAX_BREAKPOINTS); breakpoint_list[i].address=0, i++);
913		breakpoints_initialized++;
914    }
915
916	cnt = kdp_machine_vm_read(address, (caddr_t)&oldinstr, (mach_vm_size_t)breakinstrsize);
917
918	if (0 == memcmp(oldinstr, breakinstr, breakinstrsize)) {
919		printf("A trap was already set at that address, not setting new breakpoint\n");
920
921		return KDPERR_BREAKPOINT_ALREADY_SET;
922	}
923
924	for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != 0); i++);
925
926	if (i == MAX_BREAKPOINTS) {
927		return KDPERR_MAX_BREAKPOINTS;
928	}
929
930	breakpoint_list[i].address =  address;
931	memcpy(breakpoint_list[i].oldbytes, oldinstr, breakinstrsize);
932	breakpoint_list[i].bytesused =  breakinstrsize;
933
934	cnt = kdp_machine_vm_write((caddr_t)&breakinstr, address, breakinstrsize);
935
936	return KDPERR_NO_ERROR;
937}
938
939kdp_error_t
940kdp_remove_breakpoint_internal(
941    mach_vm_address_t	address
942)
943{
944	mach_vm_size_t	cnt;
945	int		i;
946
947	for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != address); i++);
948
949	if (i == MAX_BREAKPOINTS)
950	{
951		return KDPERR_BREAKPOINT_NOT_FOUND;
952	}
953
954	breakpoint_list[i].address = 0;
955	cnt = kdp_machine_vm_write((caddr_t)&breakpoint_list[i].oldbytes, address, breakpoint_list[i].bytesused);
956
957	return KDPERR_NO_ERROR;
958}
959
960boolean_t
961kdp_remove_all_breakpoints(void)
962{
963	int i;
964	boolean_t breakpoint_found = FALSE;
965
966	if (breakpoints_initialized)
967	{
968		for(i=0;i < MAX_BREAKPOINTS; i++)
969		{
970			if (breakpoint_list[i].address)
971			{
972				kdp_machine_vm_write((caddr_t)&(breakpoint_list[i].oldbytes), (mach_vm_address_t)breakpoint_list[i].address, (mach_vm_size_t)breakpoint_list[i].bytesused);
973				breakpoint_found = TRUE;
974				breakpoint_list[i].address = 0;
975			}
976		}
977
978		if (breakpoint_found)
979			printf("kdp_remove_all_breakpoints: found extant breakpoints, removing them.\n");
980	}
981	return breakpoint_found;
982}
983
984boolean_t
985kdp_reboot(
986	__unused kdp_pkt_t *pkt,
987	__unused int	*len,
988	__unused unsigned short *reply_port
989)
990{
991	dprintf(("kdp_reboot\n"));
992
993	kdp_machine_reboot();
994
995	return (TRUE); // no, not really, we won't return
996}
997
998static boolean_t
999kdp_readioport(
1000    kdp_pkt_t		*pkt,
1001    int			*len,
1002    unsigned short	*reply_port
1003	       )
1004{
1005	kdp_readioport_req_t   *rq = &pkt->readioport_req;
1006	kdp_readioport_reply_t *rp = &pkt->readioport_reply;
1007	size_t plen = *len;
1008
1009	if (plen < sizeof (*rq))
1010		return (FALSE);
1011
1012	rp->hdr.is_reply = 1;
1013	rp->hdr.len = sizeof (*rp);
1014
1015	if (rq->nbytes > MAX_KDP_DATA_SIZE)
1016		rp->error = KDPERR_BAD_NBYTES;
1017	else {
1018#if KDP_TEST_HARNESS
1019                uint16_t addr = rq->address;
1020#endif
1021		uint16_t size = rq->nbytes;
1022		dprintf(("kdp_readioport addr %x size %d\n", addr, size));
1023
1024		rp->error = kdp_machine_ioport_read(rq, rp->data, rq->lcpu);
1025		if (rp->error == KDPERR_NO_ERROR)
1026			rp->hdr.len += size;
1027	}
1028
1029	*reply_port = kdp.reply_port;
1030	*len = rp->hdr.len;
1031
1032	return (TRUE);
1033}
1034
1035static boolean_t
1036kdp_writeioport(
1037	kdp_pkt_t	*pkt,
1038	int		*len,
1039	unsigned short	*reply_port
1040                )
1041{
1042	kdp_writeioport_req_t   *rq = &pkt->writeioport_req;
1043	kdp_writeioport_reply_t *rp = &pkt->writeioport_reply;
1044	size_t	plen = *len;
1045
1046	if (plen < sizeof (*rq))
1047		return (FALSE);
1048
1049	if (rq->nbytes > MAX_KDP_DATA_SIZE)
1050		rp->error = KDPERR_BAD_NBYTES;
1051	else {
1052		dprintf(("kdp_writeioport addr %x size %d\n", rq->address,
1053			rq->nbytes));
1054
1055		rp->error = kdp_machine_ioport_write(rq, rq->data, rq->lcpu);
1056	}
1057
1058	rp->hdr.is_reply = 1;
1059	rp->hdr.len = sizeof (*rp);
1060
1061	*reply_port = kdp.reply_port;
1062	*len = rp->hdr.len;
1063
1064	return (TRUE);
1065}
1066
1067static boolean_t
1068kdp_readmsr64(
1069	kdp_pkt_t		*pkt,
1070	int			*len,
1071	unsigned short	*reply_port
1072)
1073{
1074	kdp_readmsr64_req_t   *rq = &pkt->readmsr64_req;
1075	kdp_readmsr64_reply_t *rp = &pkt->readmsr64_reply;
1076	size_t plen = *len;
1077
1078	if (plen < sizeof (*rq))
1079		return (FALSE);
1080
1081	rp->hdr.is_reply = 1;
1082	rp->hdr.len = sizeof (*rp);
1083
1084	dprintf(("kdp_readmsr64 lcpu %x addr %x\n", rq->lcpu, rq->address));
1085	rp->error = kdp_machine_msr64_read(rq, rp->data, rq->lcpu);
1086	if (rp->error == KDPERR_NO_ERROR)
1087		rp->hdr.len += sizeof(uint64_t);
1088
1089	*reply_port = kdp.reply_port;
1090	*len = rp->hdr.len;
1091
1092	return (TRUE);
1093}
1094
1095static boolean_t
1096kdp_writemsr64(
1097	kdp_pkt_t	*pkt,
1098	int		*len,
1099	unsigned short	*reply_port
1100	       )
1101{
1102	kdp_writemsr64_req_t   *rq = &pkt->writemsr64_req;
1103	kdp_writemsr64_reply_t *rp = &pkt->writemsr64_reply;
1104	size_t	plen = *len;
1105
1106	if (plen < sizeof (*rq))
1107		return (FALSE);
1108
1109	dprintf(("kdp_writemsr64 lcpu %x addr %x\n", rq->lcpu, rq->address));
1110	rp->error = kdp_machine_msr64_write(rq, rq->data, rq->lcpu);
1111
1112	rp->hdr.is_reply = 1;
1113	rp->hdr.len = sizeof (*rp);
1114
1115	*reply_port = kdp.reply_port;
1116	*len = rp->hdr.len;
1117
1118	return (TRUE);
1119}
1120
1121static boolean_t
1122kdp_dumpinfo(
1123	kdp_pkt_t	*pkt,
1124	int		*len,
1125	unsigned short	*reply_port
1126	       )
1127{
1128	kdp_dumpinfo_req_t   *rq = &pkt->dumpinfo_req;
1129	kdp_dumpinfo_reply_t *rp = &pkt->dumpinfo_reply;
1130	size_t	plen = *len;
1131
1132	if (plen < sizeof (*rq))
1133		return (FALSE);
1134
1135	dprintf(("kdp_dumpinfo file=%s destip=%s routerip=%s\n", rq->name, rq->destip, rq->routerip));
1136	rp->hdr.is_reply = 1;
1137	rp->hdr.len = sizeof (*rp);
1138
1139        if ((rq->type & KDP_DUMPINFO_MASK) != KDP_DUMPINFO_GETINFO) {
1140            kdp_set_dump_info(rq->type, rq->name, rq->destip, rq->routerip,
1141                                rq->port);
1142        }
1143
1144        /* gather some stats for reply */
1145        kdp_get_dump_info(&rp->type, rp->name, rp->destip, rp->routerip,
1146                          &rp->port);
1147
1148	*reply_port = kdp.reply_port;
1149	*len = rp->hdr.len;
1150
1151	return (TRUE);
1152}
1153
1154