X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6601e61aa18bf4f09af135ff61fc7f4771d23b06..813fb2f63a553c957e917ede5f119b021d6ce391:/osfmk/kdp/kdp.c diff --git a/osfmk/kdp/kdp.c b/osfmk/kdp/kdp.c index 695b356c6..ee2e9f8d8 100644 --- a/osfmk/kdp/kdp.c +++ b/osfmk/kdp/kdp.c @@ -1,37 +1,54 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2012 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include +#include +#include #include +#include #include #include +#include #include +#include #include /* bcopy */ -int kdp_vm_read( caddr_t, caddr_t, unsigned int); -int kdp_vm_write( caddr_t, caddr_t, unsigned int); +#include +#include +#include +#include +#include +#include +#include +#include #define DO_ALIGN 1 /* align all packet data accesses */ @@ -43,7 +60,7 @@ int kdp_vm_write( caddr_t, caddr_t, unsigned int); #endif static kdp_dispatch_t - dispatch_table[KDP_HOSTREBOOT - KDP_CONNECT +1] = + dispatch_table[KDP_INVALID_REQUEST-KDP_CONNECT] = { /* 0 */ kdp_connect, /* 1 */ kdp_disconnect, @@ -64,23 +81,37 @@ static kdp_dispatch_t /*10 */ kdp_breakpoint_remove, /*11 */ kdp_regions, /*12 */ kdp_reattach, -/*13 */ kdp_reboot +/*13 */ kdp_reboot, +/*14 */ kdp_readmem64, +/*15 */ kdp_writemem64, +/*16 */ kdp_breakpoint64_set, +/*17 */ kdp_breakpoint64_remove, +/*18 */ kdp_kernelversion, +/*19 */ kdp_readphysmem64, +/*1A */ kdp_writephysmem64, +/*1B */ kdp_readioport, +/*1C */ kdp_writeioport, +/*1D */ kdp_readmsr64, +/*1E */ kdp_writemsr64, +/*1F */ kdp_dumpinfo, }; kdp_glob_t kdp; - #define MAX_BREAKPOINTS 100 -#define KDP_MAX_BREAKPOINTS 100 - -#define BREAKPOINT_NOT_FOUND 101 -#define BREAKPOINT_ALREADY_SET 102 -#define KDP_VERSION 10 +/* + * Version 11 of the KDP Protocol adds support for 64-bit wide memory + * addresses (read/write and breakpoints) as well as a dedicated + * kernelversion request. Version 12 adds read/writing of physical + * memory with 64-bit wide memory addresses. + */ +#define KDP_VERSION 12 typedef struct{ - unsigned int address; - unsigned int old_instruction; + mach_vm_address_t address; + uint32_t bytesused; + uint8_t oldbytes[MAX_BREAKINSN_BYTES]; } kdp_breakpoint_record_t; static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS]; @@ -88,6 +119,17 @@ static unsigned int breakpoints_initialized = 0; int reattach_wait = 0; int noresume_on_disconnect = 0; +extern unsigned int return_on_panic; + +kdp_error_t +kdp_set_breakpoint_internal( + mach_vm_address_t address + ); + +kdp_error_t +kdp_remove_breakpoint_internal( + mach_vm_address_t address + ); boolean_t kdp_packet( @@ -98,17 +140,21 @@ kdp_packet( { static unsigned aligned_pkt[1538/sizeof(unsigned)+1]; // max ether pkt kdp_pkt_t *rd = (kdp_pkt_t *)&aligned_pkt; - int plen = *len; - unsigned int req; + size_t plen = *len; + kdp_req_t req; boolean_t ret; - + #if DO_ALIGN - bcopy((char *)pkt, (char *)rd, sizeof(aligned_pkt)); + if (plen > sizeof(aligned_pkt)) { + printf("kdp_packet bad len %lu\n", plen); + return FALSE; + } + bcopy((char *)pkt, (char *)rd, plen); #else rd = (kdp_pkt_t *)pkt; #endif if (plen < sizeof (rd->hdr) || rd->hdr.len != plen) { - printf("kdp_packet bad len pkt %d hdr %d\n", plen, rd->hdr.len); + printf("kdp_packet bad len pkt %lu hdr %d\n", plen, rd->hdr.len); return (FALSE); } @@ -121,7 +167,7 @@ kdp_packet( } req = rd->hdr.request; - if ((req < KDP_CONNECT) || (req > KDP_HOSTREBOOT)) { + if (req >= KDP_INVALID_REQUEST) { printf("kdp_packet bad request %x len %d seq %x key %x\n", rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key); @@ -138,8 +184,8 @@ kdp_packet( static boolean_t kdp_unknown( kdp_pkt_t *pkt, - int *len, - unsigned short *reply_port + __unused int *len, + __unused unsigned short *reply_port ) { kdp_pkt_t *rd = (kdp_pkt_t *)pkt; @@ -158,33 +204,44 @@ kdp_connect( ) { kdp_connect_req_t *rq = &pkt->connect_req; - int plen = *len; + size_t plen = *len; kdp_connect_reply_t *rp = &pkt->connect_reply; + uint16_t rport, eport; + uint32_t key; + uint8_t seq; if (plen < sizeof (*rq)) return (FALSE); dprintf(("kdp_connect seq %x greeting %s\n", rq->hdr.seq, rq->greeting)); + rport = rq->req_reply_port; + eport = rq->exc_note_port; + key = rq->hdr.key; + seq = rq->hdr.seq; if (kdp.is_conn) { - if (rq->hdr.seq == kdp.conn_seq) /* duplicate request */ + if ((seq == kdp.conn_seq) && /* duplicate request */ + (rport == kdp.reply_port) && + (eport == kdp.exception_port) && + (key == kdp.session_key)) rp->error = KDPERR_NO_ERROR; - else + else rp->error = KDPERR_ALREADY_CONNECTED; } else { - kdp.reply_port = rq->req_reply_port; - kdp.exception_port = rq->exc_note_port; - kdp.is_conn = TRUE; - kdp.conn_seq = rq->hdr.seq; - + kdp.reply_port = rport; + kdp.exception_port = eport; + kdp.is_conn = TRUE; + kdp.conn_seq = seq; + kdp.session_key = key; + rp->error = KDPERR_NO_ERROR; } rp->hdr.is_reply = 1; rp->hdr.len = sizeof (*rp); - *reply_port = kdp.reply_port; + *reply_port = rport; *len = rp->hdr.len; if (current_debugger == KDP_CUR_DB) @@ -201,7 +258,7 @@ kdp_disconnect( ) { kdp_disconnect_req_t *rq = &pkt->disconnect_req; - int plen = *len; + size_t plen = *len; kdp_disconnect_reply_t *rp = &pkt->disconnect_reply; if (plen < sizeof (*rq)) @@ -217,6 +274,10 @@ kdp_disconnect( kdp.reply_port = kdp.exception_port = 0; kdp.is_halted = kdp.is_conn = FALSE; kdp.exception_seq = kdp.conn_seq = 0; + kdp.session_key = 0; + + if ((panicstr != NULL) && (return_on_panic == 0)) + reattach_wait = 1; if (noresume_on_disconnect == 1) { reattach_wait = 1; @@ -241,14 +302,13 @@ kdp_reattach( unsigned short *reply_port ) { - kdp_reattach_req_t *rq = &pkt->reattach_req; - kdp_disconnect_reply_t *rp = &pkt->disconnect_reply; + kdp_reattach_req_t *rq = &pkt->reattach_req; - kdp.is_conn = TRUE; - kdp_disconnect(pkt, len, reply_port); - *reply_port = rq->req_reply_port; - reattach_wait = 1; - return (TRUE); + kdp.is_conn = TRUE; + kdp_disconnect(pkt, len, reply_port); + *reply_port = rq->req_reply_port; + reattach_wait = 1; + return (TRUE); } static boolean_t @@ -259,12 +319,14 @@ kdp_hostinfo( ) { kdp_hostinfo_req_t *rq = &pkt->hostinfo_req; - int plen = *len; + size_t plen = *len; kdp_hostinfo_reply_t *rp = &pkt->hostinfo_reply; if (plen < sizeof (*rq)) return (FALSE); + dprintf(("kdp_hostinfo\n")); + rp->hdr.is_reply = 1; rp->hdr.len = sizeof (*rp); @@ -276,6 +338,35 @@ kdp_hostinfo( return (TRUE); } +static boolean_t +kdp_kernelversion( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_kernelversion_req_t *rq = &pkt->kernelversion_req; + size_t plen = *len; + kdp_kernelversion_reply_t *rp = &pkt->kernelversion_reply; + size_t slen; + + if (plen < sizeof (*rq)) + return (FALSE); + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + dprintf(("kdp_kernelversion\n")); + slen = strlcpy(rp->version, kdp_kernelversion_string, MAX_KDP_DATA_SIZE); + + rp->hdr.len += slen + 1; /* strlcpy returns the amount copied with NUL */ + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} + static boolean_t kdp_suspend( kdp_pkt_t *pkt, @@ -284,7 +375,7 @@ kdp_suspend( ) { kdp_suspend_req_t *rq = &pkt->suspend_req; - int plen = *len; + size_t plen = *len; kdp_suspend_reply_t *rp = &pkt->suspend_reply; if (plen < sizeof (*rq)) @@ -311,7 +402,7 @@ kdp_resumecpus( ) { kdp_resumecpus_req_t *rq = &pkt->resumecpus_req; - int plen = *len; + size_t plen = *len; kdp_resumecpus_reply_t *rp = &pkt->resumecpus_reply; if (plen < sizeof (*rq)) @@ -338,9 +429,9 @@ kdp_writemem( ) { kdp_writemem_req_t *rq = &pkt->writemem_req; - int plen = *len; + size_t plen = *len; kdp_writemem_reply_t *rp = &pkt->writemem_reply; - int cnt; + mach_vm_size_t cnt; if (plen < sizeof (*rq)) return (FALSE); @@ -349,9 +440,9 @@ kdp_writemem( rp->error = KDPERR_BAD_NBYTES; else { dprintf(("kdp_writemem addr %x size %d\n", rq->address, rq->nbytes)); - - cnt = kdp_vm_write((caddr_t)rq->data, (caddr_t)rq->address, rq->nbytes); - rp->error = KDPERR_NO_ERROR; + cnt = kdp_machine_vm_write((caddr_t)rq->data, (mach_vm_address_t)rq->address, rq->nbytes); + rp->error = KDPERR_ACCESS(rq->nbytes, cnt); + dprintf((" cnt %lld error %d\n", cnt, rp->error)); } rp->hdr.is_reply = 1; @@ -363,6 +454,74 @@ kdp_writemem( return (TRUE); } +static boolean_t +kdp_writemem64( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_writemem64_req_t *rq = &pkt->writemem64_req; + size_t plen = *len; + kdp_writemem64_reply_t *rp = &pkt->writemem64_reply; + mach_vm_size_t cnt; + + if (plen < sizeof (*rq)) + return (FALSE); + + if (rq->nbytes > MAX_KDP_DATA_SIZE) + rp->error = KDPERR_BAD_NBYTES; + else { + dprintf(("kdp_writemem64 addr %llx size %d\n", rq->address, rq->nbytes)); + cnt = kdp_machine_vm_write((caddr_t)rq->data, (mach_vm_address_t)rq->address, (mach_vm_size_t)rq->nbytes); + rp->error = KDPERR_ACCESS(rq->nbytes, cnt); + dprintf((" cnt %lld error %d\n", cnt, rp->error)); + } + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} + +static boolean_t +kdp_writephysmem64( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_writephysmem64_req_t *rq = &pkt->writephysmem64_req; + size_t plen = *len; + kdp_writephysmem64_reply_t *rp = &pkt->writephysmem64_reply; + mach_vm_size_t cnt; + unsigned int size; + + if (plen < sizeof (*rq)) + return (FALSE); + + size = rq->nbytes; + if (size > MAX_KDP_DATA_SIZE) + rp->error = KDPERR_BAD_NBYTES; + else { + dprintf(("kdp_writephysmem64 addr %llx size %d\n", rq->address, size)); + cnt = kdp_machine_phys_write(rq, rq->data, rq->lcpu); + rp->error = KDPERR_ACCESS(size, cnt); + dprintf((" cnt %lld error %d\n", cnt, rp->error)); + } + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} + static boolean_t kdp_readmem( kdp_pkt_t *pkt, @@ -371,9 +530,10 @@ kdp_readmem( ) { kdp_readmem_req_t *rq = &pkt->readmem_req; - int plen = *len; + size_t plen = *len; kdp_readmem_reply_t *rp = &pkt->readmem_reply; - int cnt; + mach_vm_size_t cnt; + unsigned int size; if (plen < sizeof (*rq)) return (FALSE); @@ -381,19 +541,92 @@ kdp_readmem( rp->hdr.is_reply = 1; rp->hdr.len = sizeof (*rp); - if (rq->nbytes > MAX_KDP_DATA_SIZE) + size = rq->nbytes; + if (size > MAX_KDP_DATA_SIZE) rp->error = KDPERR_BAD_NBYTES; else { - unsigned int n = rq->nbytes; + dprintf(("kdp_readmem addr %x size %d\n", rq->address, size)); + cnt = kdp_machine_vm_read((mach_vm_address_t)rq->address, (caddr_t)rp->data, rq->nbytes); + rp->error = KDPERR_ACCESS(size, cnt); + dprintf((" cnt %lld error %d\n", cnt, rp->error)); - dprintf(("kdp_readmem addr %x size %d\n", rq->address, rq->nbytes)); + rp->hdr.len += cnt; + } - cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)rp->data, rq->nbytes); - rp->error = KDPERR_NO_ERROR; + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} + +static boolean_t +kdp_readmem64( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_readmem64_req_t *rq = &pkt->readmem64_req; + size_t plen = *len; + kdp_readmem64_reply_t *rp = &pkt->readmem64_reply; + mach_vm_size_t cnt; + unsigned int size; + if (plen < sizeof (*rq)) + return (FALSE); + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + size = rq->nbytes; + if (size > MAX_KDP_DATA_SIZE) + rp->error = KDPERR_BAD_NBYTES; + else { + dprintf(("kdp_readmem64 addr %llx size %d\n", rq->address, size)); + cnt = kdp_machine_vm_read((mach_vm_address_t)rq->address, (caddr_t)rp->data, rq->nbytes); + rp->error = KDPERR_ACCESS(size, cnt); + dprintf((" cnt %lld error %d\n", cnt, rp->error)); + rp->hdr.len += cnt; } + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} + +static boolean_t +kdp_readphysmem64( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_readphysmem64_req_t *rq = &pkt->readphysmem64_req; + size_t plen = *len; + kdp_readphysmem64_reply_t *rp = &pkt->readphysmem64_reply; + mach_vm_size_t cnt; + unsigned int size; + if (plen < sizeof (*rq)) + return (FALSE); + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + size = rq->nbytes; + if (size > MAX_KDP_DATA_SIZE) + rp->error = KDPERR_BAD_NBYTES; + else { + dprintf(("kdp_readphysmem64 addr %llx size %d\n", rq->address, size)); + cnt = kdp_machine_phys_read(rq, rp->data, rq->lcpu); + rp->error = KDPERR_ACCESS(size, cnt); + dprintf((" cnt %lld error %d\n", cnt, rp->error)); + + rp->hdr.len += cnt; + } + *reply_port = kdp.reply_port; *len = rp->hdr.len; @@ -408,7 +641,7 @@ kdp_maxbytes( ) { kdp_maxbytes_req_t *rq = &pkt->maxbytes_req; - int plen = *len; + size_t plen = *len; kdp_maxbytes_reply_t *rp = &pkt->maxbytes_reply; if (plen < sizeof (*rq)) @@ -435,9 +668,8 @@ kdp_version( ) { kdp_version_req_t *rq = &pkt->version_req; - int plen = *len; + size_t plen = *len; kdp_version_reply_t *rp = &pkt->version_reply; - kdp_region_t *r; if (plen < sizeof (*rq)) return (FALSE); @@ -448,15 +680,11 @@ kdp_version( dprintf(("kdp_version\n")); rp->version = KDP_VERSION; -#ifdef __ppc__ if (!(kdp_flag & KDP_BP_DIS)) rp->feature = KDP_FEATURE_BP; else rp->feature = 0; -#else - rp->feature = 0; -#endif - + *reply_port = kdp.reply_port; *len = rp->hdr.len; @@ -471,7 +699,7 @@ kdp_regions( ) { kdp_regions_req_t *rq = &pkt->regions_req; - int plen = *len; + size_t plen = *len; kdp_regions_reply_t *rp = &pkt->regions_reply; kdp_region_t *r; @@ -486,7 +714,7 @@ kdp_regions( r = rp->regions; rp->nregions = 0; - (vm_offset_t)r->address = 0; + r->address = 0; r->nbytes = 0xffffffff; r->protection = VM_PROT_ALL; r++; rp->nregions++; @@ -507,14 +735,14 @@ kdp_writeregs( ) { kdp_writeregs_req_t *rq = &pkt->writeregs_req; - int plen = *len; + size_t plen = *len; int size; kdp_writeregs_reply_t *rp = &pkt->writeregs_reply; if (plen < sizeof (*rq)) return (FALSE); - size = rq->hdr.len - sizeof(kdp_hdr_t) - sizeof(unsigned int); + size = rq->hdr.len - (unsigned)sizeof(kdp_hdr_t) - (unsigned)sizeof(unsigned int); rp->error = kdp_machine_write_regs(rq->cpu, rq->flavor, rq->data, &size); rp->hdr.is_reply = 1; @@ -534,7 +762,7 @@ kdp_readregs( ) { kdp_readregs_req_t *rq = &pkt->readregs_req; - int plen = *len; + size_t plen = *len; kdp_readregs_reply_t *rp = &pkt->readregs_reply; int size; @@ -553,126 +781,376 @@ kdp_readregs( return (TRUE); } -static boolean_t + +boolean_t kdp_breakpoint_set( kdp_pkt_t *pkt, int *len, unsigned short *reply_port ) { - kdp_breakpoint_req_t *rq = &pkt->breakpoint_req; - kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply; - int plen = *len; - int cnt, i; - unsigned int old_instruction = 0; - unsigned int breakinstr = kdp_ml_get_breakinsn(); + kdp_breakpoint_req_t *rq = &pkt->breakpoint_req; + kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply; + size_t plen = *len; + kdp_error_t kerr; + + if (plen < sizeof (*rq)) + return (FALSE); + + dprintf(("kdp_breakpoint_set %x\n", rq->address)); - if(breakpoints_initialized == 0) - { - for(i=0;(i < MAX_BREAKPOINTS); breakpoint_list[i].address=0, i++); - breakpoints_initialized++; - } - if (plen < sizeof (*rq)) - return (FALSE); - cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)(&old_instruction), sizeof(int)); + kerr = kdp_set_breakpoint_internal((mach_vm_address_t)rq->address); + + rp->error = kerr; + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} - if (old_instruction==breakinstr) - { - printf("A trap was already set at that address, not setting new breakpoint\n"); - rp->error = BREAKPOINT_ALREADY_SET; - - rp->hdr.is_reply = 1; - rp->hdr.len = sizeof (*rp); - *reply_port = kdp.reply_port; - *len = rp->hdr.len; - - return (TRUE); - } +boolean_t +kdp_breakpoint64_set( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_breakpoint64_req_t *rq = &pkt->breakpoint64_req; + kdp_breakpoint64_reply_t *rp = &pkt->breakpoint64_reply; + size_t plen = *len; + kdp_error_t kerr; + + if (plen < sizeof (*rq)) + return (FALSE); + + dprintf(("kdp_breakpoint64_set %llx\n", rq->address)); - for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != 0); i++); + kerr = kdp_set_breakpoint_internal((mach_vm_address_t)rq->address); + + rp->error = kerr; + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} - if (i == MAX_BREAKPOINTS) +boolean_t +kdp_breakpoint_remove( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_breakpoint_req_t *rq = &pkt->breakpoint_req; + kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply; + size_t plen = *len; + kdp_error_t kerr; + if (plen < sizeof (*rq)) + return (FALSE); + + dprintf(("kdp_breakpoint_remove %x\n", rq->address)); + + kerr = kdp_remove_breakpoint_internal((mach_vm_address_t)rq->address); + + rp->error = kerr; + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} + +boolean_t +kdp_breakpoint64_remove( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_breakpoint64_req_t *rq = &pkt->breakpoint64_req; + kdp_breakpoint64_reply_t *rp = &pkt->breakpoint64_reply; + size_t plen = *len; + kdp_error_t kerr; + + if (plen < sizeof (*rq)) + return (FALSE); + + dprintf(("kdp_breakpoint64_remove %llx\n", rq->address)); + + kerr = kdp_remove_breakpoint_internal((mach_vm_address_t)rq->address); + + rp->error = kerr; + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} + + +kdp_error_t +kdp_set_breakpoint_internal( + mach_vm_address_t address +) +{ + + uint8_t breakinstr[MAX_BREAKINSN_BYTES], oldinstr[MAX_BREAKINSN_BYTES]; + uint32_t breakinstrsize = sizeof(breakinstr); + mach_vm_size_t cnt; + int i; + + kdp_machine_get_breakinsn(breakinstr, &breakinstrsize); + + if(breakpoints_initialized == 0) { - rp->error = KDP_MAX_BREAKPOINTS; - - rp->hdr.is_reply = 1; - rp->hdr.len = sizeof (*rp); - *reply_port = kdp.reply_port; - *len = rp->hdr.len; - - return (TRUE); + for(i=0;(i < MAX_BREAKPOINTS); breakpoint_list[i].address=0, i++); + breakpoints_initialized++; } - breakpoint_list[i].address = rq->address; - breakpoint_list[i].old_instruction = old_instruction; + + cnt = kdp_machine_vm_read(address, (caddr_t)&oldinstr, (mach_vm_size_t)breakinstrsize); + + if (0 == memcmp(oldinstr, breakinstr, breakinstrsize)) { + printf("A trap was already set at that address, not setting new breakpoint\n"); + + return KDPERR_BREAKPOINT_ALREADY_SET; + } + + for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != 0); i++); + + if (i == MAX_BREAKPOINTS) { + return KDPERR_MAX_BREAKPOINTS; + } + + breakpoint_list[i].address = address; + memcpy(breakpoint_list[i].oldbytes, oldinstr, breakinstrsize); + breakpoint_list[i].bytesused = breakinstrsize; + + cnt = kdp_machine_vm_write((caddr_t)&breakinstr, address, breakinstrsize); + + return KDPERR_NO_ERROR; +} - cnt = kdp_vm_write((caddr_t)&breakinstr, (caddr_t)rq->address, sizeof(&breakinstr)); +kdp_error_t +kdp_remove_breakpoint_internal( + mach_vm_address_t address +) +{ + mach_vm_size_t cnt; + int i; + + for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != address); i++); + + if (i == MAX_BREAKPOINTS) + { + return KDPERR_BREAKPOINT_NOT_FOUND; + } + + breakpoint_list[i].address = 0; + cnt = kdp_machine_vm_write((caddr_t)&breakpoint_list[i].oldbytes, address, breakpoint_list[i].bytesused); + + return KDPERR_NO_ERROR; +} - rp->error = KDPERR_NO_ERROR; - rp->hdr.is_reply = 1; - rp->hdr.len = sizeof (*rp); - *reply_port = kdp.reply_port; - *len = rp->hdr.len; +boolean_t +kdp_remove_all_breakpoints(void) +{ + int i; + boolean_t breakpoint_found = FALSE; + + if (breakpoints_initialized) + { + for(i=0;i < MAX_BREAKPOINTS; i++) + { + if (breakpoint_list[i].address) + { + 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); + breakpoint_found = TRUE; + breakpoint_list[i].address = 0; + } + } + + if (breakpoint_found) + printf("kdp_remove_all_breakpoints: found extant breakpoints, removing them.\n"); + } + return breakpoint_found; +} + +boolean_t +kdp_reboot( + __unused kdp_pkt_t *pkt, + __unused int *len, + __unused unsigned short *reply_port +) +{ + dprintf(("kdp_reboot\n")); - return (TRUE); + kdp_machine_reboot(); + + return (TRUE); // no, not really, we won't return } static boolean_t -kdp_breakpoint_remove( +kdp_readioport( kdp_pkt_t *pkt, int *len, unsigned short *reply_port -) + ) { - kdp_breakpoint_req_t *rq = &pkt->breakpoint_req; - kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply; - int plen = *len; - int cnt,i; + kdp_readioport_req_t *rq = &pkt->readioport_req; + kdp_readioport_reply_t *rp = &pkt->readioport_reply; + size_t plen = *len; - if (plen < sizeof (*rq)) - return (FALSE); + if (plen < sizeof (*rq)) + return (FALSE); + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + if (rq->nbytes > MAX_KDP_DATA_SIZE) + rp->error = KDPERR_BAD_NBYTES; + else { +#if KDP_TEST_HARNESS + uint16_t addr = rq->address; +#endif + uint16_t size = rq->nbytes; + dprintf(("kdp_readioport addr %x size %d\n", addr, size)); - for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != rq->address); i++); - if (i == MAX_BREAKPOINTS) - { - rp->error = BREAKPOINT_NOT_FOUND; - rp->hdr.is_reply = 1; - rp->hdr.len = sizeof (*rp); - *reply_port = kdp.reply_port; - *len = rp->hdr.len; + rp->error = kdp_machine_ioport_read(rq, rp->data, rq->lcpu); + if (rp->error == KDPERR_NO_ERROR) + rp->hdr.len += size; + } + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} - return (TRUE); /* Check if it needs to be FALSE in case of error */ - } +static boolean_t +kdp_writeioport( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port + ) +{ + kdp_writeioport_req_t *rq = &pkt->writeioport_req; + kdp_writeioport_reply_t *rp = &pkt->writeioport_reply; + size_t plen = *len; + + if (plen < sizeof (*rq)) + return (FALSE); + + if (rq->nbytes > MAX_KDP_DATA_SIZE) + rp->error = KDPERR_BAD_NBYTES; + else { + dprintf(("kdp_writeioport addr %x size %d\n", rq->address, + rq->nbytes)); + + rp->error = kdp_machine_ioport_write(rq, rq->data, rq->lcpu); + } + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} - breakpoint_list[i].address = 0; - cnt = kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)rq->address, sizeof(int)); - rp->error = KDPERR_NO_ERROR; - rp->hdr.is_reply = 1; - rp->hdr.len = sizeof (*rp); - *reply_port = kdp.reply_port; - *len = rp->hdr.len; +static boolean_t +kdp_readmsr64( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port +) +{ + kdp_readmsr64_req_t *rq = &pkt->readmsr64_req; + kdp_readmsr64_reply_t *rp = &pkt->readmsr64_reply; + size_t plen = *len; - return (TRUE); + if (plen < sizeof (*rq)) + return (FALSE); + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + dprintf(("kdp_readmsr64 lcpu %x addr %x\n", rq->lcpu, rq->address)); + rp->error = kdp_machine_msr64_read(rq, rp->data, rq->lcpu); + if (rp->error == KDPERR_NO_ERROR) + rp->hdr.len += sizeof(uint64_t); + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); } -boolean_t -kdp_remove_all_breakpoints() +static boolean_t +kdp_writemsr64( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port + ) { - int i; - boolean_t breakpoint_found = FALSE; - - if (breakpoints_initialized) - { - for(i=0;i < MAX_BREAKPOINTS; i++) - { - if (breakpoint_list[i].address) - { - kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)breakpoint_list[i].address, sizeof(int)); - breakpoint_found = TRUE; - breakpoint_list[i].address = 0; - } - } - if (breakpoint_found) - printf("kdp_remove_all_breakpoints: found extant breakpoints, removing them.\n"); - } - return breakpoint_found; + kdp_writemsr64_req_t *rq = &pkt->writemsr64_req; + kdp_writemsr64_reply_t *rp = &pkt->writemsr64_reply; + size_t plen = *len; + + if (plen < sizeof (*rq)) + return (FALSE); + + dprintf(("kdp_writemsr64 lcpu %x addr %x\n", rq->lcpu, rq->address)); + rp->error = kdp_machine_msr64_write(rq, rq->data, rq->lcpu); + + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); } + +static boolean_t +kdp_dumpinfo( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port + ) +{ + kdp_dumpinfo_req_t *rq = &pkt->dumpinfo_req; + kdp_dumpinfo_reply_t *rp = &pkt->dumpinfo_reply; + size_t plen = *len; + + if (plen < sizeof (*rq)) + return (FALSE); + + dprintf(("kdp_dumpinfo file=%s destip=%s routerip=%s\n", rq->name, rq->destip, rq->routerip)); + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + if ((rq->type & KDP_DUMPINFO_MASK) != KDP_DUMPINFO_GETINFO) { + kdp_set_dump_info(rq->type, rq->name, rq->destip, rq->routerip, + rq->port); + } + + /* gather some stats for reply */ + kdp_get_dump_info(rp); + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +} +