]> git.saurik.com Git - apple/xnu.git/blame_incremental - osfmk/kdp/kdp_udp.c
xnu-344.12.2.tar.gz
[apple/xnu.git] / osfmk / kdp / kdp_udp.c
... / ...
CommitLineData
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) 1982, 1986, 1993
24 * The Regents of the University of California. All rights reserved.
25 */
26
27/*
28 * Kernel Debugging Protocol UDP implementation.
29 */
30
31#include <mach_kdb.h>
32#include <mach/boolean.h>
33#include <mach/exception_types.h>
34#include <mach/mach_types.h>
35#include <kern/cpu_data.h>
36#include <kern/debug.h>
37
38#include <kdp/kdp_internal.h>
39#include <kdp/kdp_en_debugger.h>
40#include <kdp/kdp_udp.h>
41
42#define DO_ALIGN 1 /* align all packet data accesses */
43
44extern int kdp_getc(void);
45extern int reattach_wait;
46
47static u_short ip_id; /* ip packet ctr, for ids */
48
49/* @(#)udp_usrreq.c 2.2 88/05/23 4.0NFSSRC SMI; from UCB 7.1 6/5/86 */
50
51/*
52 * UDP protocol implementation.
53 * Per RFC 768, August, 1980.
54 */
55#define UDP_TTL 60 /* deflt time to live for UDP packets */
56int udp_ttl=UDP_TTL;
57static unsigned char exception_seq;
58
59static struct {
60 unsigned char data[KDP_MAXPACKET];
61 unsigned int off, len;
62 boolean_t input;
63} pkt, saved_reply;
64
65struct {
66 struct {
67 struct in_addr in;
68 struct ether_addr ea;
69 } loc;
70 struct {
71 struct in_addr in;
72 struct ether_addr ea;
73 } rmt;
74} adr;
75
76static char
77*exception_message[] = {
78 "Unknown",
79 "Memory access", /* EXC_BAD_ACCESS */
80 "Failed instruction", /* EXC_BAD_INSTRUCTION */
81 "Arithmetic", /* EXC_ARITHMETIC */
82 "Emulation", /* EXC_EMULATION */
83 "Software", /* EXC_SOFTWARE */
84 "Breakpoint" /* EXC_BREAKPOINT */
85};
86
87int kdp_flag = 0;
88
89static kdp_send_t kdp_en_send_pkt = 0;
90static kdp_receive_t kdp_en_recv_pkt = 0;
91
92
93static unsigned int kdp_current_ip_address = 0;
94static struct ether_addr kdp_current_mac_address = {{0, 0, 0, 0, 0, 0}};
95static char kdp_arp_init = 0;
96
97static void kdp_handler( void *);
98
99void
100kdp_register_send_receive(
101 kdp_send_t send,
102 kdp_receive_t receive)
103{
104 unsigned int debug;
105
106 kdp_en_send_pkt = send;
107 kdp_en_recv_pkt = receive;
108 debug_log_init();
109 PE_parse_boot_arg("debug", &debug);
110 if (debug & DB_KDP_BP_DIS)
111 kdp_flag |= KDP_BP_DIS;
112
113 kdp_flag |= KDP_READY;
114 if (current_debugger == NO_CUR_DB)
115 current_debugger = KDP_CUR_DB;
116 if (halt_in_debugger) {
117 kdp_call();
118 halt_in_debugger=0;
119 }
120}
121
122void
123kdp_unregister_send_receive(
124 kdp_send_t send,
125 kdp_receive_t receive)
126{
127 if (current_debugger == KDP_CUR_DB)
128 current_debugger = NO_CUR_DB;
129 kdp_flag &= ~KDP_READY;
130 kdp_en_send_pkt = NULL;
131 kdp_en_recv_pkt = NULL;
132}
133
134static void
135enaddr_copy(
136 void *src,
137 void *dst
138)
139{
140 bcopy((char *)src, (char *)dst, sizeof (struct ether_addr));
141}
142
143static unsigned short
144ip_sum(
145 unsigned char *c,
146 unsigned int hlen
147)
148{
149 unsigned int high, low, sum;
150
151 high = low = 0;
152 while (hlen-- > 0) {
153 low += c[1] + c[3];
154 high += c[0] + c[2];
155
156 c += sizeof (int);
157 }
158
159 sum = (high << 8) + low;
160 sum = (sum >> 16) + (sum & 65535);
161
162 return (sum > 65535 ? sum - 65535 : sum);
163}
164
165static void
166kdp_reply(
167 unsigned short reply_port
168)
169{
170 struct udpiphdr aligned_ui, *ui = &aligned_ui;
171 struct ip aligned_ip, *ip = &aligned_ip;
172 struct in_addr tmp_ipaddr;
173 struct ether_addr tmp_enaddr;
174 struct ether_header *eh;
175
176 if (!pkt.input)
177 kdp_panic("kdp_reply");
178
179 pkt.off -= sizeof (struct udpiphdr);
180
181#if DO_ALIGN
182 bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui));
183#else
184 ui = (struct udpiphdr *)&pkt.data[pkt.off];
185#endif
186 ui->ui_next = ui->ui_prev = 0;
187 ui->ui_x1 = 0;
188 ui->ui_pr = IPPROTO_UDP;
189 ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr));
190 tmp_ipaddr = ui->ui_src;
191 ui->ui_src = ui->ui_dst;
192 ui->ui_dst = tmp_ipaddr;
193 ui->ui_sport = htons(KDP_REMOTE_PORT);
194 ui->ui_dport = reply_port;
195 ui->ui_ulen = ui->ui_len;
196 ui->ui_sum = 0;
197#if DO_ALIGN
198 bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui));
199
200 bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip));
201#else
202 ip = (struct ip *)&pkt.data[pkt.off];
203#endif
204 ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len);
205 ip->ip_v = IPVERSION;
206 ip->ip_id = htons(ip_id++);
207 ip->ip_hl = sizeof (struct ip) >> 2;
208 ip->ip_ttl = udp_ttl;
209 ip->ip_sum = 0;
210 ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl));
211#if DO_ALIGN
212 bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip));
213#endif
214
215 pkt.len += sizeof (struct udpiphdr);
216
217 pkt.off -= sizeof (struct ether_header);
218
219 eh = (struct ether_header *)&pkt.data[pkt.off];
220 enaddr_copy(eh->ether_shost, &tmp_enaddr);
221 enaddr_copy(eh->ether_dhost, eh->ether_shost);
222 enaddr_copy(&tmp_enaddr, eh->ether_dhost);
223 eh->ether_type = htons(ETHERTYPE_IP);
224
225 pkt.len += sizeof (struct ether_header);
226
227 // save reply for possible retransmission
228 bcopy((char *)&pkt, (char *)&saved_reply, sizeof(pkt));
229
230 (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len);
231
232 // increment expected sequence number
233 exception_seq++;
234}
235
236static void
237kdp_send(
238 unsigned short remote_port
239)
240{
241 struct udpiphdr aligned_ui, *ui = &aligned_ui;
242 struct ip aligned_ip, *ip = &aligned_ip;
243 struct ether_header *eh;
244
245 if (pkt.input)
246 kdp_panic("kdp_send");
247
248 pkt.off -= sizeof (struct udpiphdr);
249
250#if DO_ALIGN
251 bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui));
252#else
253 ui = (struct udpiphdr *)&pkt.data[pkt.off];
254#endif
255 ui->ui_next = ui->ui_prev = 0;
256 ui->ui_x1 = 0;
257 ui->ui_pr = IPPROTO_UDP;
258 ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr));
259 ui->ui_src = adr.loc.in;
260 ui->ui_dst = adr.rmt.in;
261 ui->ui_sport = htons(KDP_REMOTE_PORT);
262 ui->ui_dport = remote_port;
263 ui->ui_ulen = ui->ui_len;
264 ui->ui_sum = 0;
265#if DO_ALIGN
266 bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui));
267 bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip));
268#else
269 ip = (struct ip *)&pkt.data[pkt.off];
270#endif
271 ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len);
272 ip->ip_v = IPVERSION;
273 ip->ip_id = htons(ip_id++);
274 ip->ip_hl = sizeof (struct ip) >> 2;
275 ip->ip_ttl = udp_ttl;
276 ip->ip_sum = 0;
277 ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl));
278#if DO_ALIGN
279 bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip));
280#endif
281
282 pkt.len += sizeof (struct udpiphdr);
283
284 pkt.off -= sizeof (struct ether_header);
285
286 eh = (struct ether_header *)&pkt.data[pkt.off];
287 enaddr_copy(&adr.loc.ea, eh->ether_shost);
288 enaddr_copy(&adr.rmt.ea, eh->ether_dhost);
289 eh->ether_type = htons(ETHERTYPE_IP);
290
291 pkt.len += sizeof (struct ether_header);
292 (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len);
293}
294
295
296void
297kdp_set_ip_and_mac_addresses(
298 struct in_addr *ipaddr,
299 struct ether_addr *macaddr)
300{
301 unsigned int debug = 0;
302
303 kdp_current_ip_address = ipaddr->s_addr;
304 kdp_current_mac_address = *macaddr;
305
306 /* Get the debug boot-arg to decide if ARP replies are allowed */
307 if (kdp_arp_init == 0) {
308 PE_parse_boot_arg("debug", &debug);
309 if (debug & DB_ARP)
310 kdp_flag |= KDP_ARP;
311 kdp_arp_init = 1;
312 }
313}
314
315struct ether_addr
316kdp_get_mac_addr(void)
317{
318 return kdp_current_mac_address;
319}
320
321unsigned int
322kdp_get_ip_address(void)
323{
324 return kdp_current_ip_address;
325}
326
327/* ARP responses are enabled when the DB_ARP bit of the debug boot arg
328 is set. A workaround if you don't want to reboot is to set
329 kdpDEBUGFlag &= DB_ARP when connected (but that certainly isn't a published
330 interface!)
331*/
332
333static void
334kdp_arp_reply(void)
335{
336 struct ether_header *eh;
337 struct ether_arp aligned_ea, *ea = &aligned_ea;
338
339 struct in_addr isaddr, itaddr, myaddr;
340 struct ether_addr my_enaddr;
341
342 eh = (struct ether_header *)&pkt.data[pkt.off];
343 pkt.off += sizeof(struct ether_header);
344
345 memcpy((void *)ea, (void *)&pkt.data[pkt.off],sizeof(*ea));
346
347 if(ntohs(ea->arp_op) != ARPOP_REQUEST)
348 return;
349
350 myaddr.s_addr = kdp_get_ip_address();
351 my_enaddr = kdp_get_mac_addr();
352
353 if (!(myaddr.s_addr) || !(my_enaddr.ether_addr_octet[1]))
354 return;
355
356 (void)memcpy((void *)&isaddr, (void *)ea->arp_spa, sizeof (isaddr));
357 (void)memcpy((void *)&itaddr, (void *)ea->arp_tpa, sizeof (itaddr));
358
359 if (itaddr.s_addr == myaddr.s_addr) {
360 (void)memcpy((void *)ea->arp_tha, (void *)ea->arp_sha, sizeof(ea->arp_sha));
361 (void)memcpy((void *)ea->arp_sha, (void *)&my_enaddr, sizeof(ea->arp_sha));
362
363 (void)memcpy((void *)ea->arp_tpa, (void *) ea->arp_spa, sizeof(ea->arp_spa));
364 (void)memcpy((void *)ea->arp_spa, (void *) &itaddr, sizeof(ea->arp_spa));
365
366 ea->arp_op = htons(ARPOP_REPLY);
367 ea->arp_pro = htons(ETHERTYPE_IP);
368 (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost));
369 (void)memcpy(eh->ether_shost, &my_enaddr, sizeof(eh->ether_shost));
370 eh->ether_type = htons(ETHERTYPE_ARP);
371 (void)memcpy(&pkt.data[pkt.off], ea, sizeof(*ea));
372 pkt.off -= sizeof (struct ether_header);
373 /* pkt.len is still the length we want, ether_header+ether_arp */
374 (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len);
375 }
376}
377
378static void
379kdp_poll(void)
380{
381 struct ether_header *eh;
382 struct udpiphdr aligned_ui, *ui = &aligned_ui;
383 struct ip aligned_ip, *ip = &aligned_ip;
384 static int msg_printed;
385
386
387 if (pkt.input)
388 kdp_panic("kdp_poll");
389
390 if (!kdp_en_recv_pkt || !kdp_en_send_pkt) {
391 if( msg_printed == 0) {
392 msg_printed = 1;
393 printf("kdp_poll: no debugger device\n");
394 }
395 return;
396 }
397
398 pkt.off = pkt.len = 0;
399 (*kdp_en_recv_pkt)(pkt.data, &pkt.len, 3/* ms */);
400
401 if (pkt.len == 0)
402 return;
403
404 if (pkt.len >= sizeof(struct ether_header))
405 {
406 eh = (struct ether_header *)&pkt.data[pkt.off];
407
408 if (kdp_flag & KDP_ARP)
409 {
410 if (ntohs(eh->ether_type) == ETHERTYPE_ARP)
411 {
412 kdp_arp_reply();
413 return;
414 }
415 }
416 }
417
418 if (pkt.len < (sizeof (struct ether_header) + sizeof (struct udpiphdr)))
419 return;
420
421 pkt.off += sizeof (struct ether_header);
422 if (ntohs(eh->ether_type) != ETHERTYPE_IP) {
423 return;
424 }
425
426#if DO_ALIGN
427 bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui));
428 bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip));
429#else
430 ui = (struct udpiphdr *)&pkt.data[pkt.off];
431 ip = (struct ip *)&pkt.data[pkt.off];
432#endif
433
434 pkt.off += sizeof (struct udpiphdr);
435 if (ui->ui_pr != IPPROTO_UDP) {
436 return;
437 }
438
439 if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
440 return;
441 }
442
443 if (ntohs(ui->ui_dport) != KDP_REMOTE_PORT) {
444 return;
445 }
446
447 if (!kdp.is_conn) {
448 enaddr_copy(eh->ether_dhost, &adr.loc.ea);
449 adr.loc.in = ui->ui_dst;
450
451 enaddr_copy(eh->ether_shost, &adr.rmt.ea);
452 adr.rmt.in = ui->ui_src;
453 }
454
455 /*
456 * Calculate kdp packet length.
457 */
458 pkt.len = ntohs((u_short)ui->ui_ulen) - sizeof (struct udphdr);
459 pkt.input = TRUE;
460
461}
462
463static void
464kdp_handler(
465 void *saved_state
466)
467{
468 unsigned short reply_port;
469 kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr;
470
471
472 kdp.saved_state = saved_state; // see comment in kdp_raise_exception
473
474 do {
475 while (!pkt.input)
476 kdp_poll();
477
478#if DO_ALIGN
479 bcopy((char *)&pkt.data[pkt.off], (char *)hdr, sizeof(*hdr));
480#else
481 hdr = (kdp_hdr_t *)&pkt.data[pkt.off];
482#endif
483
484 // ignore replies -- we're not expecting them anyway.
485 if (hdr->is_reply) {
486 goto again;
487 }
488
489 if (hdr->request == KDP_REATTACH)
490 exception_seq = hdr->seq;
491
492 // check for retransmitted request
493 if (hdr->seq == (exception_seq - 1)) {
494 /* retransmit last reply */
495 (*kdp_en_send_pkt)(&saved_reply.data[saved_reply.off],
496 saved_reply.len);
497 goto again;
498 } else if (hdr->seq != exception_seq) {
499 printf("kdp: bad sequence %d (want %d)\n",
500 hdr->seq, exception_seq);
501 goto again;
502 }
503
504 if (kdp_packet((unsigned char*)&pkt.data[pkt.off],
505 (int *)&pkt.len,
506 (unsigned short *)&reply_port)) {
507 kdp_reply(reply_port);
508 }
509
510again:
511 pkt.input = FALSE;
512 } while (kdp.is_halted);
513}
514
515static void
516kdp_connection_wait(void)
517{
518 unsigned short reply_port;
519 boolean_t kdp_call_kdb();
520 struct ether_addr kdp_mac_addr = kdp_get_mac_addr();
521 unsigned int ip_addr = kdp_get_ip_address();
522
523 printf( "ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
524 kdp_mac_addr.ether_addr_octet[0] & 0xff,
525 kdp_mac_addr.ether_addr_octet[1] & 0xff,
526 kdp_mac_addr.ether_addr_octet[2] & 0xff,
527 kdp_mac_addr.ether_addr_octet[3] & 0xff,
528 kdp_mac_addr.ether_addr_octet[4] & 0xff,
529 kdp_mac_addr.ether_addr_octet[5] & 0xff);
530
531 printf( "ip address: %d.%d.%d.%d\n",
532 (ip_addr & 0xff000000) >> 24,
533 (ip_addr & 0xff0000) >> 16,
534 (ip_addr & 0xff00) >> 8,
535 (ip_addr & 0xff));
536
537 printf("\nWaiting for remote debugger connection.\n");
538
539 if (reattach_wait == 0)
540 {
541#ifdef MACH_PE
542 if( 0 != kdp_getc())
543#endif
544 {
545 printf("Options..... Type\n");
546 printf("------------ ----\n");
547 printf("continue.... 'c'\n");
548 printf("reboot...... 'r'\n");
549#if MACH_KDB
550 printf("enter kdb... 'k'\n");
551#endif
552 }
553 }
554 else
555 reattach_wait = 0;
556
557 exception_seq = 0;
558 do {
559 kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr;
560
561 while (!pkt.input) {
562 int c;
563 c = kdp_getc();
564 switch(c) {
565 case 'c':
566 printf("Continuing...\n");
567 return;
568 case 'r':
569 printf("Rebooting...\n");
570 kdp_reboot();
571 break;
572#if MACH_KDB
573 case 'k':
574 printf("calling kdb...\n");
575 if (kdp_call_kdb())
576 return;
577 else
578 printf("not implemented...\n");
579#endif
580 default:
581 break;
582 }
583 kdp_poll();
584 }
585
586 // check for sequence number of 0
587#if DO_ALIGN
588 bcopy((char *)&pkt.data[pkt.off], (char *)hdr, sizeof(*hdr));
589#else
590 hdr = (kdp_hdr_t *)&pkt.data[pkt.off];
591#endif
592 if (hdr->request == KDP_HOSTREBOOT) {
593 kdp_reboot();
594 /* should not return! */
595 }
596 if (((hdr->request == KDP_CONNECT) || (hdr->request == KDP_REATTACH)) &&
597 !hdr->is_reply && (hdr->seq == exception_seq)) {
598 if (kdp_packet((unsigned char *)&pkt.data[pkt.off],
599 (int *)&pkt.len,
600 (unsigned short *)&reply_port))
601 kdp_reply(reply_port);
602 if (hdr->request == KDP_REATTACH)
603 {
604 reattach_wait = 0;
605 hdr->request=KDP_DISCONNECT;
606 exception_seq = 0;
607 }
608 }
609
610 pkt.input = FALSE;
611 } while (!kdp.is_conn);
612
613 if (current_debugger == KDP_CUR_DB)
614 active_debugger=1;
615 printf("Connected to remote debugger.\n");
616}
617
618static void
619kdp_send_exception(
620 unsigned int exception,
621 unsigned int code,
622 unsigned int subcode
623)
624{
625 unsigned short remote_port;
626 unsigned int timeout_count = 100;
627 unsigned int poll_timeout;
628
629 do {
630 pkt.off = sizeof (struct ether_header) + sizeof (struct udpiphdr);
631 kdp_exception((unsigned char *)&pkt.data[pkt.off],
632 (int *)&pkt.len,
633 (unsigned short *)&remote_port,
634 (unsigned int)exception,
635 (unsigned int)code,
636 (unsigned int)subcode);
637
638 kdp_send(remote_port);
639
640 poll_timeout = 50;
641 while(!pkt.input && poll_timeout)
642 {
643 kdp_poll();
644 poll_timeout--;
645 }
646
647 if (pkt.input) {
648 if (!kdp_exception_ack(&pkt.data[pkt.off], pkt.len)) {
649 pkt.input = FALSE;
650 }
651 }
652
653 pkt.input = FALSE;
654
655 if (kdp.exception_ack_needed)
656 kdp_us_spin(250000);
657
658 } while (kdp.exception_ack_needed && timeout_count--);
659
660 if (kdp.exception_ack_needed) {
661 // give up & disconnect
662 printf("kdp: exception ack timeout\n");
663 if (current_debugger == KDP_CUR_DB)
664 active_debugger=0;
665 kdp_reset();
666 }
667}
668
669void
670kdp_raise_exception(
671 unsigned int exception,
672 unsigned int code,
673 unsigned int subcode,
674 void *saved_state
675)
676{
677 int index;
678
679 disable_preemption();
680
681 if (saved_state == 0)
682 printf("kdp_raise_exception with NULL state\n");
683
684 index = exception;
685 if (exception != EXC_BREAKPOINT) {
686 if (exception > EXC_BREAKPOINT || exception < EXC_BAD_ACCESS) {
687 index = 0;
688 }
689 printf("%s exception (%x,%x,%x)\n",
690 exception_message[index],
691 exception, code, subcode);
692 }
693
694 kdp_sync_cache();
695
696 /* XXX WMG it seems that sometimes it doesn't work to let kdp_handler
697 * do this. I think the client and the host can get out of sync.
698 */
699 kdp.saved_state = saved_state;
700
701 if (pkt.input)
702 kdp_panic("kdp_raise_exception");
703 again:
704 if (!kdp.is_conn)
705 kdp_connection_wait();
706 else
707 {
708 kdp_send_exception(exception, code, subcode);
709 if (kdp.exception_ack_needed)
710 {
711 kdp.exception_ack_needed = FALSE;
712 kdp_remove_all_breakpoints();
713 printf("Remote debugger disconnected.\n");
714 }
715 }
716
717 if (kdp.is_conn) {
718 kdp.is_halted = TRUE; /* XXX */
719 kdp_handler(saved_state);
720 if (!kdp.is_conn)
721 {
722 kdp_remove_all_breakpoints();
723 printf("Remote debugger disconnected.\n");
724 }
725 }
726
727 kdp_sync_cache();
728
729 if (reattach_wait == 1)
730 goto again;
731
732 enable_preemption();
733}
734
735void
736kdp_reset(void)
737{
738 kdp.reply_port = kdp.exception_port = 0;
739 kdp.is_halted = kdp.is_conn = FALSE;
740 kdp.exception_seq = kdp.conn_seq = 0;
741}
742