X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/060df5ea7c632b1ac8cc8aac1fb59758165c2084..39236c6e673c41db228275375ab7fdb0f837b292:/osfmk/kdp/kdp_udp.c?ds=sidebyside diff --git a/osfmk/kdp/kdp_udp.c b/osfmk/kdp/kdp_udp.c index 3b298fe6e..e51c48286 100644 --- a/osfmk/kdp/kdp_udp.c +++ b/osfmk/kdp/kdp_udp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2013 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -35,7 +35,6 @@ * Kernel Debugging Protocol UDP implementation. */ -#include #include #include #include @@ -57,19 +56,37 @@ #include /* kernel_map */ #include +#include #include +/* we just want the link status flags, so undef KERNEL_PRIVATE for this + * header file. */ +#undef KERNEL_PRIVATE +#include +#define KERNEL_PRIVATE + #include -#define DO_ALIGN 1 /* align all packet data accesses */ +#include +#include + +extern int inet_aton(const char *, struct kdp_in_addr *); /* in libkern */ +extern char *inet_ntoa_r(struct kdp_in_addr ina, char *buf, + size_t buflen); /* in libkern */ + +#define DO_ALIGN 1 /* align all packet data accesses */ +#define KDP_SERIAL_IPADDR 0xABADBABE /* IP address used for serial KDP */ +#define LINK_UP_STATUS (IFM_AVALID | IFM_ACTIVE) extern int kdp_getc(void); extern int reattach_wait; -extern int serial_getc(void); -extern void serial_putc(char); -extern int serial_init(void); +/* only used by IONetworkingFamily */ +typedef uint32_t (*kdp_link_t)(void); +typedef boolean_t (*kdp_mode_t)(boolean_t); +void kdp_register_link(kdp_link_t link, kdp_mode_t mode); +void kdp_unregister_link(kdp_link_t link, kdp_mode_t mode); static u_short ip_id; /* ip packet ctr, for ids */ @@ -80,9 +97,124 @@ static u_short ip_id; /* ip packet ctr, for ids */ * Per RFC 768, August, 1980. */ #define UDP_TTL 60 /* deflt time to live for UDP packets */ -int udp_ttl = UDP_TTL; +static int udp_ttl = UDP_TTL; static unsigned char exception_seq; +struct kdp_ipovly { + uint32_t ih_next, ih_prev; /* for protocol sequence q's */ + u_char ih_x1; /* (unused) */ + u_char ih_pr; /* protocol */ + short ih_len; /* protocol length */ + struct kdp_in_addr ih_src; /* source internet address */ + struct kdp_in_addr ih_dst; /* destination internet address */ +}; + +struct kdp_udphdr { + u_short uh_sport; /* source port */ + u_short uh_dport; /* destination port */ + short uh_ulen; /* udp length */ + u_short uh_sum; /* udp checksum */ +}; + +struct kdp_udpiphdr { + struct kdp_ipovly ui_i; /* overlaid ip structure */ + struct kdp_udphdr ui_u; /* udp header */ +}; +#define ui_next ui_i.ih_next +#define ui_prev ui_i.ih_prev +#define ui_x1 ui_i.ih_x1 +#define ui_pr ui_i.ih_pr +#define ui_len ui_i.ih_len +#define ui_src ui_i.ih_src +#define ui_dst ui_i.ih_dst +#define ui_sport ui_u.uh_sport +#define ui_dport ui_u.uh_dport +#define ui_ulen ui_u.uh_ulen +#define ui_sum ui_u.uh_sum + +struct kdp_ip { + union { + uint32_t ip_w; + struct { + unsigned int +#ifdef __LITTLE_ENDIAN__ + ip_xhl:4, /* header length */ + ip_xv:4, /* version */ + ip_xtos:8, /* type of service */ + ip_xlen:16; /* total length */ +#endif +#ifdef __BIG_ENDIAN__ + ip_xv:4, /* version */ + ip_xhl:4, /* header length */ + ip_xtos:8, /* type of service */ + ip_xlen:16; /* total length */ +#endif + } ip_x; + } ip_vhltl; + u_short ip_id; /* identification */ + short ip_off; /* fragment offset field */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_char ip_ttl; /* time to live */ + u_char ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + struct kdp_in_addr ip_src,ip_dst; /* source and dest address */ +}; +#define ip_v ip_vhltl.ip_x.ip_xv +#define ip_hl ip_vhltl.ip_x.ip_xhl +#define ip_tos ip_vhltl.ip_x.ip_xtos +#define ip_len ip_vhltl.ip_x.ip_xlen + +#define IPPROTO_UDP 17 +#define IPVERSION 4 + +#define ETHERTYPE_IP 0x0800 /* IP protocol */ + +/* + * Ethernet Address Resolution Protocol. + * + * See RFC 826 for protocol description. Structure below is adapted + * to resolving internet addresses. Field names used correspond to + * RFC 826. + */ + +#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */ + +struct kdp_arphdr { + u_short ar_hrd; /* format of hardware address */ +#define ARPHRD_ETHER 1 /* ethernet hardware format */ +#define ARPHRD_FRELAY 15 /* frame relay hardware format */ + u_short ar_pro; /* format of protocol address */ + u_char ar_hln; /* length of hardware address */ + u_char ar_pln; /* length of protocol address */ + u_short ar_op; /* one of: */ +#define ARPOP_REQUEST 1 /* request to resolve address */ +#define ARPOP_REPLY 2 /* response to previous request */ +#define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ +#define ARPOP_REVREPLY 4 /* response giving protocol address */ +#define ARPOP_INVREQUEST 8 /* request to identify peer */ +#define ARPOP_INVREPLY 9 /* response identifying peer */ +}; + +struct kdp_ether_arp { + struct kdp_arphdr ea_hdr; /* fixed-size header */ + u_char arp_sha[ETHER_ADDR_LEN]; /* sender hardware address */ + u_char arp_spa[4]; /* sender protocol address */ + u_char arp_tha[ETHER_ADDR_LEN]; /* target hardware address */ + u_char arp_tpa[4]; /* target protocol address */ +}; +#define arp_hrd ea_hdr.ar_hrd +#define arp_pro ea_hdr.ar_pro +#define arp_hln ea_hdr.ar_hln +#define arp_pln ea_hdr.ar_pln +#define arp_op ea_hdr.ar_op + +#define ETHERMTU 1500 +#define ETHERHDRSIZE 14 +#define ETHERCRC 4 +#define KDP_MAXPACKET (ETHERHDRSIZE + ETHERMTU + ETHERCRC) + static struct { unsigned char data[KDP_MAXPACKET]; unsigned int off, len; @@ -93,12 +225,12 @@ struct kdp_manual_pkt manual_pkt; struct { struct { - struct in_addr in; - struct ether_addr ea; + struct kdp_in_addr in; + struct kdp_ether_addr ea; } loc; struct { - struct in_addr in; - struct ether_addr ea; + struct kdp_in_addr in; + struct kdp_ether_addr ea; } rmt; } adr; @@ -115,12 +247,20 @@ static const char volatile int kdp_flag = 0; -static kdp_send_t kdp_en_send_pkt; +static kdp_send_t kdp_en_send_pkt; static kdp_receive_t kdp_en_recv_pkt; +static kdp_link_t kdp_en_linkstatus; +static kdp_mode_t kdp_en_setmode; +#if CONFIG_SERIAL_KDP +static void kdp_serial_send(void *rpkt, unsigned int rpkt_len); +#define KDP_SERIAL_ENABLED() (kdp_en_send_pkt == kdp_serial_send) +#else +#define KDP_SERIAL_ENABLED() (0) +#endif static uint32_t kdp_current_ip_address = 0; -static struct ether_addr kdp_current_mac_address = {{0, 0, 0, 0, 0, 0}}; +static struct kdp_ether_addr kdp_current_mac_address = {{0, 0, 0, 0, 0, 0}}; static void *kdp_current_ifp; static void kdp_handler( void *); @@ -130,17 +270,19 @@ static uint32_t parsed_router_ip = 0; static uint32_t router_ip = 0; static uint32_t target_ip = 0; +static boolean_t save_ip_in_nvram = FALSE; + static volatile boolean_t panicd_specified = FALSE; static boolean_t router_specified = FALSE; static boolean_t corename_specified = FALSE; static unsigned int panicd_port = CORE_REMOTE_PORT; -static struct ether_addr etherbroadcastaddr = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; +static struct kdp_ether_addr etherbroadcastaddr = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; -static struct ether_addr router_mac = {{0, 0, 0 , 0, 0, 0}}; -static struct ether_addr destination_mac = {{0, 0, 0 , 0, 0, 0}}; -static struct ether_addr temp_mac = {{0, 0, 0 , 0, 0, 0}}; -static struct ether_addr current_resolved_MAC = {{0, 0, 0 , 0, 0, 0}}; +static struct kdp_ether_addr router_mac = {{0, 0, 0 , 0, 0, 0}}; +static struct kdp_ether_addr destination_mac = {{0, 0, 0 , 0, 0, 0}}; +static struct kdp_ether_addr temp_mac = {{0, 0, 0 , 0, 0, 0}}; +static struct kdp_ether_addr current_resolved_MAC = {{0, 0, 0 , 0, 0, 0}}; static boolean_t flag_panic_dump_in_progress = FALSE; static boolean_t flag_router_mac_initialized = FALSE; @@ -151,8 +293,10 @@ static boolean_t flag_arp_resolved = FALSE; static unsigned int panic_timeout = 100000; static unsigned int last_panic_port = CORE_REMOTE_PORT; -unsigned int SEGSIZE = 512; +#define KDP_THROTTLE_VALUE (10ULL * NSEC_PER_SEC) +uint32_t kdp_crashdump_pkt_size = 512; +#define KDP_LARGE_CRASHDUMP_PKT_SIZE (1440 - 6 - sizeof(struct kdp_udpiphdr)) static char panicd_ip_str[20]; static char router_ip_str[20]; static char corename_str[50]; @@ -170,20 +314,21 @@ extern boolean_t kdp_call_kdb(void); extern int kern_dump(void); void * kdp_get_interface(void); -void kdp_set_gateway_mac(void *); -void kdp_set_ip_and_mac_addresses(struct in_addr *, struct ether_addr *); -void kdp_set_interface(void *); +void kdp_set_gateway_mac(void *gatewaymac); +void kdp_set_ip_and_mac_addresses(struct kdp_in_addr *ipaddr, struct kdp_ether_addr *); +void kdp_set_interface(void *interface, const struct kdp_ether_addr *macaddr); void kdp_disable_arp(void); -static void kdp_arp_reply(struct ether_arp *); -static void kdp_process_arp_reply(struct ether_arp *); -static boolean_t kdp_arp_resolve(uint32_t, struct ether_addr *); +static void kdp_arp_reply(struct kdp_ether_arp *); +static void kdp_process_arp_reply(struct kdp_ether_arp *); +static boolean_t kdp_arp_resolve(uint32_t, struct kdp_ether_addr *); static volatile unsigned kdp_reentry_deadline; -#if defined(__LP64__) -uint32_t kdp_crashdump_feature_mask = KDP_FEATURE_LARGE_CRASHDUMPS; -static uint32_t kdp_feature_large_crashdumps; -#endif + +static uint32_t kdp_crashdump_feature_mask = KDP_FEATURE_LARGE_CRASHDUMPS | KDP_FEATURE_LARGE_PKT_SIZE; +uint32_t kdp_feature_large_crashdumps, kdp_feature_large_pkt_size; + +char kdp_kernelversion_string[256]; static boolean_t gKDPDebug = FALSE; #define KDP_DEBUG(...) if (gKDPDebug) printf(__VA_ARGS__); @@ -200,6 +345,13 @@ static uint32_t stack_snapshot_dispatch_offset; static unsigned int old_debugger; +#define SBLOCKSZ (2048) +uint64_t kdp_dump_start_time = 0; +uint64_t kdp_min_superblock_dump_time = ~1ULL; +uint64_t kdp_max_superblock_dump_time = 0; +uint64_t kdp_superblock_dump_time = 0; +uint64_t kdp_superblock_dump_start_time = 0; + void kdp_snapshot_preflight(int pid, void * tracebuf, uint32_t tracebuf_size, uint32_t flags, uint32_t dispatch_offset); @@ -231,6 +383,52 @@ kdp_timer_callout_init(void) { } +/* only send/receive data if the link is up */ +inline static void wait_for_link(void) +{ + static int first = 0; + + if (!kdp_en_linkstatus) + return; + + while (((*kdp_en_linkstatus)() & LINK_UP_STATUS) != LINK_UP_STATUS) { + if (first) + continue; + + first = 1; + printf("Waiting for link to become available.\n"); + kprintf("Waiting for link to become available.\n"); + } +} + + +inline static void kdp_send_data(void *packet, unsigned int len) +{ + wait_for_link(); + (*kdp_en_send_pkt)(packet, len); +} + + +inline static void kdp_receive_data(void *packet, unsigned int *len, + unsigned int timeout) +{ + wait_for_link(); + (*kdp_en_recv_pkt)(packet, len, timeout); +} + + +void kdp_register_link(kdp_link_t link, kdp_mode_t mode) +{ + kdp_en_linkstatus = link; + kdp_en_setmode = mode; +} + +void kdp_unregister_link(__unused kdp_link_t link, __unused kdp_mode_t mode) +{ + kdp_en_linkstatus = NULL; + kdp_en_setmode = NULL; +} + void kdp_register_send_receive( kdp_send_t send, @@ -238,20 +436,14 @@ kdp_register_send_receive( { unsigned int debug = 0; - debug_log_init(); - - kdp_timer_callout_init(); - PE_parse_boot_argn("debug", &debug, sizeof (debug)); -#if defined(__LP64__) - kdp_crashdump_feature_mask = htonl(kdp_crashdump_feature_mask); -#endif + if (!debug) return; - kdp_en_send_pkt = send; - kdp_en_recv_pkt = receive; + kdp_en_send_pkt = send; + kdp_en_recv_pkt = receive; if (debug & DB_KDP_BP_DIS) kdp_flag |= KDP_BP_DIS; @@ -303,8 +495,8 @@ kdp_unregister_send_receive( if (current_debugger == KDP_CUR_DB) current_debugger = NO_CUR_DB; kdp_flag &= ~KDP_READY; - kdp_en_send_pkt = NULL; - kdp_en_recv_pkt = NULL; + kdp_en_send_pkt = NULL; + kdp_en_recv_pkt = NULL; } /* Cache stack snapshot parameters in preparation for a trace */ @@ -361,7 +553,7 @@ enaddr_copy( void *dst ) { - bcopy((char *)src, (char *)dst, sizeof (struct ether_addr)); + bcopy((char *)src, (char *)dst, sizeof (struct kdp_ether_addr)); } static unsigned short @@ -392,26 +584,26 @@ kdp_reply( const boolean_t sideband ) { - struct udpiphdr aligned_ui, *ui = &aligned_ui; - struct ip aligned_ip, *ip = &aligned_ip; - struct in_addr tmp_ipaddr; - struct ether_addr tmp_enaddr; - struct ether_header *eh = NULL; + struct kdp_udpiphdr aligned_ui, *ui = &aligned_ui; + struct kdp_ip aligned_ip, *ip = &aligned_ip; + struct kdp_in_addr tmp_ipaddr; + struct kdp_ether_addr tmp_enaddr; + struct kdp_ether_header *eh = NULL; if (!pkt.input) kdp_panic("kdp_reply"); - pkt.off -= (unsigned int)sizeof (struct udpiphdr); + pkt.off -= (unsigned int)sizeof (struct kdp_udpiphdr); #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); #else - ui = (struct udpiphdr *)&pkt.data[pkt.off]; + ui = (struct kdp_udpiphdr *)&pkt.data[pkt.off]; #endif ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; - ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr)); + ui->ui_len = htons((u_short)pkt.len + sizeof (struct kdp_udphdr)); tmp_ipaddr = ui->ui_src; ui->ui_src = ui->ui_dst; ui->ui_dst = tmp_ipaddr; @@ -423,12 +615,12 @@ kdp_reply( bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); #else - ip = (struct ip *)&pkt.data[pkt.off]; + ip = (struct kdp_ip *)&pkt.data[pkt.off]; #endif - ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len); + ip->ip_len = htons(sizeof (struct kdp_udpiphdr) + pkt.len); ip->ip_v = IPVERSION; ip->ip_id = htons(ip_id++); - ip->ip_hl = sizeof (struct ip) >> 2; + ip->ip_hl = sizeof (struct kdp_ip) >> 2; ip->ip_ttl = udp_ttl; ip->ip_sum = 0; ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); @@ -436,23 +628,24 @@ kdp_reply( bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); #endif - pkt.len += (unsigned int)sizeof (struct udpiphdr); + pkt.len += (unsigned int)sizeof (struct kdp_udpiphdr); - pkt.off -= (unsigned int)sizeof (struct ether_header); + pkt.off -= (unsigned int)sizeof (struct kdp_ether_header); - eh = (struct ether_header *)&pkt.data[pkt.off]; + eh = (struct kdp_ether_header *)&pkt.data[pkt.off]; enaddr_copy(eh->ether_shost, &tmp_enaddr); enaddr_copy(eh->ether_dhost, eh->ether_shost); enaddr_copy(&tmp_enaddr, eh->ether_dhost); eh->ether_type = htons(ETHERTYPE_IP); - pkt.len += (unsigned int)sizeof (struct ether_header); + pkt.len += (unsigned int)sizeof (struct kdp_ether_header); // save reply for possible retransmission + assert(pkt.len <= KDP_MAXPACKET); if (!sideband) - bcopy((char *)&pkt, (char *)&saved_reply, sizeof(pkt)); + bcopy((char *)&pkt, (char *)&saved_reply, sizeof(saved_reply)); - (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); + kdp_send_data(&pkt.data[pkt.off], pkt.len); // increment expected sequence number if (!sideband) @@ -464,24 +657,24 @@ kdp_send( unsigned short remote_port ) { - struct udpiphdr aligned_ui, *ui = &aligned_ui; - struct ip aligned_ip, *ip = &aligned_ip; - struct ether_header *eh; + struct kdp_udpiphdr aligned_ui, *ui = &aligned_ui; + struct kdp_ip aligned_ip, *ip = &aligned_ip; + struct kdp_ether_header *eh; if (pkt.input) kdp_panic("kdp_send"); - pkt.off -= (unsigned int)sizeof (struct udpiphdr); + pkt.off -= (unsigned int)sizeof (struct kdp_udpiphdr); #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); #else - ui = (struct udpiphdr *)&pkt.data[pkt.off]; + ui = (struct kdp_udpiphdr *)&pkt.data[pkt.off]; #endif ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; - ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr)); + ui->ui_len = htons((u_short)pkt.len + sizeof (struct kdp_udphdr)); ui->ui_src = adr.loc.in; ui->ui_dst = adr.rmt.in; ui->ui_sport = htons(KDP_REMOTE_PORT); @@ -492,12 +685,12 @@ kdp_send( bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); #else - ip = (struct ip *)&pkt.data[pkt.off]; + ip = (struct kdp_ip *)&pkt.data[pkt.off]; #endif - ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len); + ip->ip_len = htons(sizeof (struct kdp_udpiphdr) + pkt.len); ip->ip_v = IPVERSION; ip->ip_id = htons(ip_id++); - ip->ip_hl = sizeof (struct ip) >> 2; + ip->ip_hl = sizeof (struct kdp_ip) >> 2; ip->ip_ttl = udp_ttl; ip->ip_sum = 0; ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); @@ -505,25 +698,76 @@ kdp_send( bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); #endif - pkt.len += (unsigned int)sizeof (struct udpiphdr); + pkt.len += (unsigned int)sizeof (struct kdp_udpiphdr); - pkt.off -= (unsigned int)sizeof (struct ether_header); + pkt.off -= (unsigned int)sizeof (struct kdp_ether_header); - eh = (struct ether_header *)&pkt.data[pkt.off]; + eh = (struct kdp_ether_header *)&pkt.data[pkt.off]; enaddr_copy(&adr.loc.ea, eh->ether_shost); enaddr_copy(&adr.rmt.ea, eh->ether_dhost); eh->ether_type = htons(ETHERTYPE_IP); - pkt.len += (unsigned int)sizeof (struct ether_header); - (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); + pkt.len += (unsigned int)sizeof (struct kdp_ether_header); + kdp_send_data(&pkt.data[pkt.off], pkt.len); } -/* We don't interpret this pointer, we just give it to the -bsd stack so it can decide when to set the MAC and IP info. */ + +inline static void debugger_if_necessary(void) +{ + if ((current_debugger == KDP_CUR_DB) && halt_in_debugger) { + kdp_call(); + halt_in_debugger=0; + } +} + + +/* We don't interpret this pointer, we just give it to the bsd stack + so it can decide when to set the MAC and IP info. We'll + early initialize the MAC/IP info if we can so that we can use + KDP early in boot. These values may subsequently get over-written + when the interface gets initialized for real. +*/ void -kdp_set_interface(void *ifp) +kdp_set_interface(void *ifp, const struct kdp_ether_addr *macaddr) { + char kdpstr[80]; + struct kdp_in_addr addr = { 0 }; + unsigned int len; + kdp_current_ifp = ifp; + + if (PE_parse_boot_argn("kdp_ip_addr", kdpstr, sizeof(kdpstr))) { + /* look for a static ip address */ + if (inet_aton(kdpstr, &addr) == FALSE) + goto done; + + goto config_network; + } + + /* use saved ip address */ + save_ip_in_nvram = TRUE; + + len = sizeof(kdpstr); + if (PEReadNVRAMProperty("_kdp_ipstr", kdpstr, &len) == FALSE) + goto done; + + kdpstr[len < sizeof(kdpstr) ? len : sizeof(kdpstr) - 1] = '\0'; + if (inet_aton(kdpstr, &addr) == FALSE) + goto done; + +config_network: + kdp_current_ip_address = addr.s_addr; + if (macaddr) + kdp_current_mac_address = *macaddr; + + /* we can't drop into the debugger at this point because the + link will likely not be up. when getDebuggerLinkStatus() support gets + added to the appropriate network drivers, adding the + following will enable this capability: + debugger_if_necessary(); + */ +done: + return; } void * @@ -534,25 +778,54 @@ kdp_get_interface(void) void kdp_set_ip_and_mac_addresses( - struct in_addr *ipaddr, - struct ether_addr *macaddr) + struct kdp_in_addr *ipaddr, + struct kdp_ether_addr *macaddr) { - kdp_current_ip_address = ipaddr->s_addr; - kdp_current_mac_address = *macaddr; - if ((current_debugger == KDP_CUR_DB) && halt_in_debugger) { - kdp_call(); - halt_in_debugger=0; - } + static uint64_t last_time = (uint64_t) -1; + static uint64_t throttle_val = 0; + uint64_t cur_time; + char addr[16]; + + if (kdp_current_ip_address == ipaddr->s_addr) + goto done; + + /* don't replace if serial debugging is configured */ + if (!KDP_SERIAL_ENABLED() || + (kdp_current_ip_address != KDP_SERIAL_IPADDR)) { + kdp_current_mac_address = *macaddr; + kdp_current_ip_address = ipaddr->s_addr; + } + + if (save_ip_in_nvram == FALSE) + goto done; + + if (inet_ntoa_r(*ipaddr, addr, sizeof(addr)) == NULL) + goto done; + + /* throttle writes if needed */ + if (!throttle_val) + nanoseconds_to_absolutetime(KDP_THROTTLE_VALUE, &throttle_val); + + cur_time = mach_absolute_time(); + if (last_time == (uint64_t) -1 || + ((cur_time - last_time) > throttle_val)) { + PEWriteNVRAMProperty("_kdp_ipstr", addr, + (const unsigned int) strlen(addr)); + } + last_time = cur_time; + +done: + debugger_if_necessary(); } void kdp_set_gateway_mac(void *gatewaymac) { - router_mac = *(struct ether_addr *)gatewaymac; - flag_router_mac_initialized = TRUE; + router_mac = *(struct kdp_ether_addr *)gatewaymac; + flag_router_mac_initialized = TRUE; } -struct ether_addr +struct kdp_ether_addr kdp_get_mac_addr(void) { return kdp_current_mac_address; @@ -573,10 +846,10 @@ kdp_disable_arp(void) static void kdp_arp_dispatch(void) { - struct ether_arp aligned_ea, *ea = &aligned_ea; + struct kdp_ether_arp aligned_ea, *ea = &aligned_ea; unsigned arp_header_offset; - arp_header_offset = (unsigned)sizeof(struct ether_header) + pkt.off; + arp_header_offset = (unsigned)sizeof(struct kdp_ether_header) + pkt.off; memcpy((void *)ea, (void *)&pkt.data[arp_header_offset], sizeof(*ea)); switch(ntohs(ea->arp_op)) { @@ -592,18 +865,18 @@ kdp_arp_dispatch(void) } static void -kdp_process_arp_reply(struct ether_arp *ea) +kdp_process_arp_reply(struct kdp_ether_arp *ea) { /* Are we interested in ARP replies? */ if (flag_arp_resolved == TRUE) return; /* Did we receive a reply from the right source? */ - if (((struct in_addr *)(ea->arp_spa))->s_addr != target_ip) + if (((struct kdp_in_addr *)(ea->arp_spa))->s_addr != target_ip) return; flag_arp_resolved = TRUE; - current_resolved_MAC = *(struct ether_addr *) (ea->arp_sha); + current_resolved_MAC = *(struct kdp_ether_addr *) (ea->arp_sha); return; } @@ -613,15 +886,15 @@ kdp_process_arp_reply(struct ether_arp *ea) */ static void -kdp_arp_reply(struct ether_arp *ea) +kdp_arp_reply(struct kdp_ether_arp *ea) { - struct ether_header *eh; + struct kdp_ether_header *eh; - struct in_addr isaddr, itaddr, myaddr; - struct ether_addr my_enaddr; + struct kdp_in_addr isaddr, itaddr, myaddr; + struct kdp_ether_addr my_enaddr; - eh = (struct ether_header *)&pkt.data[pkt.off]; - pkt.off += (unsigned int)sizeof(struct ether_header); + eh = (struct kdp_ether_header *)&pkt.data[pkt.off]; + pkt.off += (unsigned int)sizeof(struct kdp_ether_header); if(ntohs(ea->arp_op) != ARPOP_REQUEST) return; @@ -655,18 +928,18 @@ kdp_arp_reply(struct ether_arp *ea) (void)memcpy(eh->ether_shost, &my_enaddr, sizeof(eh->ether_shost)); eh->ether_type = htons(ETHERTYPE_ARP); (void)memcpy(&pkt.data[pkt.off], ea, sizeof(*ea)); - pkt.off -= (unsigned int)sizeof (struct ether_header); + pkt.off -= (unsigned int)sizeof (struct kdp_ether_header); /* pkt.len is still the length we want, ether_header+ether_arp */ - (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); + kdp_send_data(&pkt.data[pkt.off], pkt.len); } } static void kdp_poll(void) { - struct ether_header *eh = NULL; - struct udpiphdr aligned_ui, *ui = &aligned_ui; - struct ip aligned_ip, *ip = &aligned_ip; + struct kdp_ether_header *eh = NULL; + struct kdp_udpiphdr aligned_ui, *ui = &aligned_ui; + struct kdp_ip aligned_ip, *ip = &aligned_ip; static int msg_printed; if (pkt.input) @@ -681,14 +954,14 @@ kdp_poll(void) } pkt.off = pkt.len = 0; - (*kdp_en_recv_pkt)(pkt.data, &pkt.len, 3/* ms */); + kdp_receive_data(pkt.data, &pkt.len, 3/* ms */); if (pkt.len == 0) return; - if (pkt.len >= sizeof(struct ether_header)) + if (pkt.len >= sizeof(struct kdp_ether_header)) { - eh = (struct ether_header *)&pkt.data[pkt.off]; + eh = (struct kdp_ether_header *)&pkt.data[pkt.off]; if (kdp_flag & KDP_ARP) { @@ -700,10 +973,10 @@ kdp_poll(void) } } - if (pkt.len < (sizeof (struct ether_header) + sizeof (struct udpiphdr))) + if (pkt.len < (sizeof (struct kdp_ether_header) + sizeof (struct kdp_udpiphdr))) return; - pkt.off += (unsigned int)sizeof (struct ether_header); + pkt.off += (unsigned int)sizeof (struct kdp_ether_header); if (ntohs(eh->ether_type) != ETHERTYPE_IP) { return; } @@ -712,16 +985,16 @@ kdp_poll(void) bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); #else - ui = (struct udpiphdr *)&pkt.data[pkt.off]; - ip = (struct ip *)&pkt.data[pkt.off]; + ui = (struct kdp_udpiphdr *)&pkt.data[pkt.off]; + ip = (struct kdp_ip *)&pkt.data[pkt.off]; #endif - pkt.off += (unsigned int)sizeof (struct udpiphdr); + pkt.off += (unsigned int)sizeof (struct kdp_udpiphdr); if (ui->ui_pr != IPPROTO_UDP) { return; } - if (ip->ip_hl > (sizeof (struct ip) >> 2)) { + if (ip->ip_hl > (sizeof (struct kdp_ip) >> 2)) { return; } @@ -757,7 +1030,7 @@ kdp_poll(void) /* * Calculate kdp packet length. */ - pkt.len = ntohs((u_short)ui->ui_ulen) - (unsigned int)sizeof (struct udphdr); + pkt.len = ntohs((u_short)ui->ui_ulen) - (unsigned int)sizeof (struct kdp_udphdr); pkt.input = TRUE; } @@ -768,8 +1041,8 @@ kdp_poll(void) static void transmit_ARP_request(uint32_t ip_addr) { - struct ether_header *eh = (struct ether_header *) &pkt.data[0]; - struct ether_arp *ea = (struct ether_arp *) &pkt.data[sizeof(struct ether_header)]; + struct kdp_ether_header *eh = (struct kdp_ether_header *) &pkt.data[0]; + struct kdp_ether_arp *ea = (struct kdp_ether_arp *) &pkt.data[sizeof(struct kdp_ether_header)]; KDP_DEBUG("Transmitting ARP request\n"); /* Populate the ether_header */ @@ -793,13 +1066,13 @@ transmit_ARP_request(uint32_t ip_addr) memcpy(ea->arp_spa, (void *) &kdp_current_ip_address, sizeof(kdp_current_ip_address)); pkt.off = 0; - pkt.len = sizeof(struct ether_header) + sizeof(struct ether_arp); + pkt.len = sizeof(struct kdp_ether_header) + sizeof(struct kdp_ether_arp); /* Transmit */ - (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); + kdp_send_data(&pkt.data[pkt.off], pkt.len); } static boolean_t -kdp_arp_resolve(uint32_t arp_target_ip, struct ether_addr *resolved_MAC) +kdp_arp_resolve(uint32_t arp_target_ip, struct kdp_ether_addr *resolved_MAC) { int poll_count = 256; /* ~770 ms modulo broadcast/delayed traffic? */ char tretries = 0; @@ -878,8 +1151,8 @@ kdp_handler( // check for retransmitted request if (hdr->seq == (exception_seq - 1)) { /* retransmit last reply */ - (*kdp_en_send_pkt)(&saved_reply.data[saved_reply.off], - saved_reply.len); + kdp_send_data(&saved_reply.data[saved_reply.off], + saved_reply.len); goto again; } else if ((hdr->seq != exception_seq) && (hdr->request != KDP_CONNECT)) { @@ -937,7 +1210,7 @@ static void kdp_connection_wait(void) { unsigned short reply_port; - struct ether_addr kdp_mac_addr = kdp_get_mac_addr(); + struct kdp_ether_addr kdp_mac_addr = kdp_get_mac_addr(); unsigned int ip_addr = ntohl(kdp_get_ip_address()); /* @@ -946,35 +1219,41 @@ kdp_connection_wait(void) * the panic.log */ - printf( "ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", - kdp_mac_addr.ether_addr_octet[0] & 0xff, - kdp_mac_addr.ether_addr_octet[1] & 0xff, - kdp_mac_addr.ether_addr_octet[2] & 0xff, - kdp_mac_addr.ether_addr_octet[3] & 0xff, - kdp_mac_addr.ether_addr_octet[4] & 0xff, - kdp_mac_addr.ether_addr_octet[5] & 0xff); + if (KDP_SERIAL_ENABLED()) { + printf("Using serial KDP.\n"); + kprintf("Using serial KDP.\n"); + } else { + printf( "ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", + kdp_mac_addr.ether_addr_octet[0] & 0xff, + kdp_mac_addr.ether_addr_octet[1] & 0xff, + kdp_mac_addr.ether_addr_octet[2] & 0xff, + kdp_mac_addr.ether_addr_octet[3] & 0xff, + kdp_mac_addr.ether_addr_octet[4] & 0xff, + kdp_mac_addr.ether_addr_octet[5] & 0xff); - kprintf( "ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", - kdp_mac_addr.ether_addr_octet[0] & 0xff, - kdp_mac_addr.ether_addr_octet[1] & 0xff, - kdp_mac_addr.ether_addr_octet[2] & 0xff, - kdp_mac_addr.ether_addr_octet[3] & 0xff, - kdp_mac_addr.ether_addr_octet[4] & 0xff, - kdp_mac_addr.ether_addr_octet[5] & 0xff); + kprintf( "ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", + kdp_mac_addr.ether_addr_octet[0] & 0xff, + kdp_mac_addr.ether_addr_octet[1] & 0xff, + kdp_mac_addr.ether_addr_octet[2] & 0xff, + kdp_mac_addr.ether_addr_octet[3] & 0xff, + kdp_mac_addr.ether_addr_octet[4] & 0xff, + kdp_mac_addr.ether_addr_octet[5] & 0xff); - printf( "ip address: %d.%d.%d.%d\n", - (ip_addr & 0xff000000) >> 24, - (ip_addr & 0xff0000) >> 16, - (ip_addr & 0xff00) >> 8, - (ip_addr & 0xff)); + printf( "ip address: %d.%d.%d.%d\n", + (ip_addr & 0xff000000) >> 24, + (ip_addr & 0xff0000) >> 16, + (ip_addr & 0xff00) >> 8, + (ip_addr & 0xff)); - kprintf( "ip address: %d.%d.%d.%d\n", - (ip_addr & 0xff000000) >> 24, - (ip_addr & 0xff0000) >> 16, - (ip_addr & 0xff00) >> 8, - (ip_addr & 0xff)); + kprintf( "ip address: %d.%d.%d.%d\n", + (ip_addr & 0xff000000) >> 24, + (ip_addr & 0xff0000) >> 16, + (ip_addr & 0xff00) >> 8, + (ip_addr & 0xff)); + } printf("\nWaiting for remote debugger connection.\n"); + kprintf("\nWaiting for remote debugger connection.\n"); if (reattach_wait == 0) { @@ -984,9 +1263,6 @@ kdp_connection_wait(void) printf("------------ ----\n"); printf("continue.... 'c'\n"); printf("reboot...... 'r'\n"); -#if MACH_KDB - printf("enter kdb... 'k'\n"); -#endif } } else reattach_wait = 0; @@ -1006,15 +1282,7 @@ kdp_connection_wait(void) printf("Rebooting...\n"); kdp_machine_reboot(); break; -#if MACH_KDB - case 'k': - printf("calling kdb...\n"); - if (kdp_call_kdb()) - return; - else - printf("not implemented...\n"); -#endif - default: + default: break; } } @@ -1049,6 +1317,7 @@ kdp_connection_wait(void) if (current_debugger == KDP_CUR_DB) active_debugger=1; printf("Connected to remote debugger.\n"); + kprintf("Connected to remote debugger.\n"); } static void @@ -1063,7 +1332,7 @@ kdp_send_exception( unsigned int poll_timeout; do { - pkt.off = sizeof (struct ether_header) + sizeof (struct udpiphdr); + pkt.off = sizeof (struct kdp_ether_header) + sizeof (struct kdp_udpiphdr); kdp_exception((unsigned char *)&pkt.data[pkt.off], (int *)&pkt.len, (unsigned short *)&remote_port, @@ -1111,13 +1380,16 @@ kdp_raise_exception( ) { int index; + unsigned int initial_not_in_kdp = not_in_kdp; + not_in_kdp = 0; /* Was a system trace requested ? */ if (kdp_snapshot && (!panic_active()) && (panic_caller == 0)) { stack_snapshot_ret = kdp_stackshot(stack_snapshot_pid, stack_snapshot_buf, stack_snapshot_bufsize, stack_snapshot_flags, stack_snapshot_dispatch_offset, &stack_snapshot_bytes_traced); + not_in_kdp = initial_not_in_kdp; return; } @@ -1145,10 +1417,12 @@ kdp_raise_exception( kdp.kdp_cpu = cpu_number(); kdp.kdp_thread = current_thread(); + if (kdp_en_setmode) + (*kdp_en_setmode)(TRUE); /* enabling link mode */ + if (pkt.input) kdp_panic("kdp_raise_exception"); - if (((kdp_flag & KDP_PANIC_DUMP_ENABLED) || (kdp_flag & PANIC_LOG_DUMP)) && (panicstr != (char *) 0)) { kdp_panic_dump(); @@ -1223,6 +1497,11 @@ kdp_raise_exception( goto again; exit_raise_exception: + if (kdp_en_setmode) + (*kdp_en_setmode)(FALSE); /* link cleanup */ + + not_in_kdp = initial_not_in_kdp; + enable_preemption(); } @@ -1232,37 +1511,37 @@ kdp_reset(void) 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; + kdp.session_key = 0; + pkt.input = manual_pkt.input = FALSE; + pkt.len = pkt.off = manual_pkt.len = 0; } struct corehdr * create_panic_header(unsigned int request, const char *corename, unsigned length, unsigned int block) { - struct udpiphdr aligned_ui, *ui = &aligned_ui; - struct ip aligned_ip, *ip = &aligned_ip; - struct ether_header *eh; + struct kdp_udpiphdr aligned_ui, *ui = &aligned_ui; + struct kdp_ip aligned_ip, *ip = &aligned_ip; + struct kdp_ether_header *eh; struct corehdr *coreh; const char *mode = "octet"; - char modelen = strlen(mode); -#if defined(__LP64__) + char modelen = strlen(mode) + 1; + size_t fmask_size = sizeof(KDP_FEATURE_MASK_STRING) + sizeof(kdp_crashdump_feature_mask); -#else - size_t fmask_size = 0; -#endif - pkt.off = sizeof (struct ether_header); + + pkt.off = sizeof (struct kdp_ether_header); pkt.len = (unsigned int)(length + ((request == KDP_WRQ) ? modelen + fmask_size : 0) + - (corename ? strlen(corename): 0) + sizeof(struct corehdr)); + (corename ? (strlen(corename) + 1 ): 0) + sizeof(struct corehdr)); #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); #else - ui = (struct udpiphdr *)&pkt.data[pkt.off]; + ui = (struct kdp_udpiphdr *)&pkt.data[pkt.off]; #endif ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; - ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr)); + ui->ui_len = htons((u_short)pkt.len + sizeof (struct kdp_udphdr)); ui->ui_src.s_addr = (uint32_t)kdp_current_ip_address; /* Already in network byte order via inet_aton() */ ui->ui_dst.s_addr = panic_server_ip; @@ -1274,12 +1553,12 @@ create_panic_header(unsigned int request, const char *corename, bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); #else - ip = (struct ip *)&pkt.data[pkt.off]; + ip = (struct kdp_ip *)&pkt.data[pkt.off]; #endif - ip->ip_len = htons(sizeof (struct udpiphdr) + pkt.len); + ip->ip_len = htons(sizeof (struct kdp_udpiphdr) + pkt.len); ip->ip_v = IPVERSION; ip->ip_id = htons(ip_id++); - ip->ip_hl = sizeof (struct ip) >> 2; + ip->ip_hl = sizeof (struct kdp_ip) >> 2; ip->ip_ttl = udp_ttl; ip->ip_sum = 0; ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); @@ -1287,9 +1566,9 @@ create_panic_header(unsigned int request, const char *corename, bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); #endif - pkt.len += (unsigned int)sizeof (struct udpiphdr); + pkt.len += (unsigned int)sizeof (struct kdp_udpiphdr); - pkt.off += (unsigned int)sizeof (struct udpiphdr); + pkt.off += (unsigned int)sizeof (struct kdp_udpiphdr); coreh = (struct corehdr *) &pkt.data[pkt.off]; coreh->th_opcode = htons((u_short)request); @@ -1303,26 +1582,28 @@ create_panic_header(unsigned int request, const char *corename, *cp++ = '\0'; cp += strlcpy (cp, mode, KDP_MAXPACKET - strlen(corename)); *cp++ = '\0'; -#if defined(__LP64__) cp += strlcpy(cp, KDP_FEATURE_MASK_STRING, sizeof(KDP_FEATURE_MASK_STRING)); *cp++ = '\0'; /* Redundant */ bcopy(&kdp_crashdump_feature_mask, cp, sizeof(kdp_crashdump_feature_mask)); -#endif + kdp_crashdump_pkt_size = KDP_LARGE_CRASHDUMP_PKT_SIZE; + PE_parse_boot_argn("kdp_crashdump_pkt_size", &kdp_crashdump_pkt_size, sizeof(kdp_crashdump_pkt_size)); + cp += sizeof(kdp_crashdump_feature_mask); + *(uint32_t *)cp = htonl(kdp_crashdump_pkt_size); } else { coreh->th_block = htonl((unsigned int) block); } - pkt.off -= (unsigned int)sizeof (struct udpiphdr); - pkt.off -= (unsigned int)sizeof (struct ether_header); + pkt.off -= (unsigned int)sizeof (struct kdp_udpiphdr); + pkt.off -= (unsigned int)sizeof (struct kdp_ether_header); - eh = (struct ether_header *)&pkt.data[pkt.off]; + eh = (struct kdp_ether_header *)&pkt.data[pkt.off]; enaddr_copy(&kdp_current_mac_address, eh->ether_shost); enaddr_copy(&destination_mac, eh->ether_dhost); eh->ether_type = htons(ETHERTYPE_IP); - pkt.len += (unsigned int)sizeof (struct ether_header); + pkt.len += (unsigned int)sizeof (struct kdp_ether_header); return coreh; } @@ -1330,14 +1611,11 @@ static int kdp_send_crashdump_seek(char *corename, uint64_t seek_off) { int panic_error; -#if defined(__LP64__) if (kdp_feature_large_crashdumps) { panic_error = kdp_send_crashdump_pkt(KDP_SEEK, corename, sizeof(seek_off), &seek_off); - } else -#endif - { + } else { uint32_t off = (uint32_t) seek_off; panic_error = kdp_send_crashdump_pkt(KDP_SEEK, corename, sizeof(off), &off); @@ -1353,40 +1631,44 @@ static int kdp_send_crashdump_seek(char *corename, uint64_t seek_off) } int kdp_send_crashdump_data(unsigned int request, char *corename, - uint64_t length, caddr_t txstart) + int64_t length, caddr_t txstart) { int panic_error = 0; while (length > 0) { - uint64_t chunk = MIN(SEGSIZE, length); - + uint64_t chunk = MIN(kdp_crashdump_pkt_size, length); + panic_error = kdp_send_crashdump_pkt(request, corename, chunk, - (caddr_t) txstart); + txstart); if (panic_error < 0) { printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error); return panic_error; } - if (!(panic_block % 2000)) - kdb_printf_unbuffered("."); - txstart += chunk; length -= chunk; } return 0; } +uint32_t kdp_crashdump_short_pkt; + int kdp_send_crashdump_pkt(unsigned int request, char *corename, uint64_t length, void *panic_data) { + int poll_count; struct corehdr *th = NULL; - int poll_count = 2500; - - char rretries = 0, tretries = 0; + char rretries, tretries; + if (kdp_dump_start_time == 0) { + kdp_dump_start_time = mach_absolute_time(); + kdp_superblock_dump_start_time = kdp_dump_start_time; + } + + tretries = rretries = 0; + poll_count = KDP_CRASHDUMP_POLL_COUNT; pkt.off = pkt.len = 0; - if (request == KDP_WRQ) /* longer timeout for initial request */ poll_count += 1000; @@ -1409,27 +1691,34 @@ TRANSMIT_RETRY: th = create_panic_header(request, corename, (unsigned)length, panic_block); if (request == KDP_DATA) { - /* as all packets are SEGSIZE in length, the last packet + /* as all packets are kdp_crashdump_pkt_size in length, the last packet * may end up with trailing bits. make sure that those * bits aren't confusing. */ - if (length < SEGSIZE) - memset(th->th_data + length, 'X', - SEGSIZE - (uint32_t) length); + if (length < kdp_crashdump_pkt_size) { + kdp_crashdump_short_pkt++; + memset(th->th_data + length, 'Y', + kdp_crashdump_pkt_size - (uint32_t) length); + } - if (!kdp_machine_vm_read((mach_vm_address_t)(intptr_t)panic_data, (caddr_t) th->th_data, length)) { - memset ((caddr_t) th->th_data, 'X', (size_t)length); + if (!kdp_machine_vm_read((mach_vm_address_t)(uintptr_t)panic_data, (caddr_t) th->th_data, length)) { + uintptr_t next_page = round_page((uintptr_t)panic_data); + memset((caddr_t) th->th_data, 'X', (size_t)length); + if ((next_page - ((uintptr_t) panic_data)) < length) { + uint64_t resid = length - (next_page - (intptr_t) panic_data); + if (!kdp_machine_vm_read((mach_vm_address_t)(uintptr_t)next_page, (caddr_t) th->th_data + (length - resid), resid)) { + memset((caddr_t) th->th_data + (length - resid), 'X', (size_t)resid); + } + } } } else if (request == KDP_SEEK) { -#if defined(__LP64__) if (kdp_feature_large_crashdumps) *(uint64_t *) th->th_data = OSSwapHostToBigInt64((*(uint64_t *) panic_data)); else -#endif - *(unsigned int *) th->th_data = htonl(*(unsigned int *) panic_data); + *(unsigned int *) th->th_data = htonl(*(unsigned int *) panic_data); } - (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); + kdp_send_data(&pkt.data[pkt.off], pkt.len); /* Listen for the ACK */ RECEIVE_RETRY: @@ -1443,17 +1732,22 @@ RECEIVE_RETRY: pkt.input = FALSE; th = (struct corehdr *) &pkt.data[pkt.off]; -#if defined(__LP64__) if (request == KDP_WRQ) { uint16_t opcode64 = ntohs(th->th_opcode); uint16_t features64 = (opcode64 & 0xFF00)>>8; if ((opcode64 & 0xFF) == KDP_ACK) { kdp_feature_large_crashdumps = features64 & KDP_FEATURE_LARGE_CRASHDUMPS; + if (features64 & KDP_FEATURE_LARGE_PKT_SIZE) { + kdp_feature_large_pkt_size = 1; + } + else { + kdp_feature_large_pkt_size = 0; + kdp_crashdump_pkt_size = 512; + } printf("Protocol features: 0x%x\n", (uint32_t) features64); th->th_opcode = htons(KDP_ACK); } } -#endif if (ntohs(th->th_opcode) == KDP_ACK && ntohl(th->th_block) == panic_block) { } else @@ -1485,12 +1779,25 @@ RECEIVE_RETRY: kdp_us_spin ((tretries%4) * panic_timeout); /* capped linear backoff */ goto TRANSMIT_RETRY; } - - panic_block++; - - if (request == KDP_EOF) + + if (!(++panic_block % SBLOCKSZ)) { + uint64_t ctime; + kdb_printf_unbuffered("."); + ctime = mach_absolute_time(); + kdp_superblock_dump_time = ctime - kdp_superblock_dump_start_time; + kdp_superblock_dump_start_time = ctime; + if (kdp_superblock_dump_time > kdp_max_superblock_dump_time) + kdp_max_superblock_dump_time = kdp_superblock_dump_time; + if (kdp_superblock_dump_time < kdp_min_superblock_dump_time) + kdp_min_superblock_dump_time = kdp_superblock_dump_time; + } + + if (request == KDP_EOF) { printf("\nTotal number of packets transmitted: %d\n", panic_block); - + printf("Avg. superblock transfer abstime 0x%llx\n", ((mach_absolute_time() - kdp_dump_start_time) / panic_block) * SBLOCKSZ); + printf("Minimum superblock transfer abstime: 0x%llx\n", kdp_min_superblock_dump_time); + printf("Maximum superblock transfer abstime: 0x%llx\n", kdp_max_superblock_dump_time); + } return 1; } @@ -1499,29 +1806,6 @@ isdigit (char c) { return ((c > 47) && (c < 58)); } -/* From user mode Libc - this ought to be in a library */ -static char * -strnstr(char *s, const char *find, size_t slen) -{ - char c, sc; - size_t len; - - if ((c = *find++) != '\0') { - len = strlen(find); - do { - do { - if ((sc = *s++) == '\0' || slen-- < 1) - return (NULL); - } while (sc != c); - if (len > slen) - return (NULL); - } while (strncmp(s, find, len) != 0); - s--; - } - return (s); -} - -extern char version[]; /* Horrid hack to extract xnu version if possible - a much cleaner approach * would be to have the integrator run a script which would copy the @@ -1541,10 +1825,9 @@ kdp_get_xnu_version(char *versionbuf) char *vptr; strlcpy(vstr, "custom", 10); - if (kdp_machine_vm_read((mach_vm_address_t)(uintptr_t)version, versionbuf, 128)) { - versionbuf[127] = '\0'; - versionpos = strnstr(versionbuf, "xnu-", 115); + versionbuf[127] = '\0'; + versionpos = strnstr(versionbuf, "xnu-", 115); if (versionpos) { strncpy(vstr, versionpos, sizeof(vstr)); vstr[sizeof(vstr)-1] = '\0'; @@ -1562,8 +1845,6 @@ kdp_get_xnu_version(char *versionbuf) return retval; } -extern char *inet_aton(const char *cp, struct in_addr *pin); - void kdp_set_dump_info(const uint32_t flags, const char *filename, const char *destipstr, const char *routeripstr, @@ -1685,28 +1966,27 @@ kdp_panic_dump(void) char coreprefix[10]; int panic_error; - uint64_t abstime; + uint64_t abstime; uint32_t current_ip = ntohl((uint32_t)kdp_current_ip_address); if (flag_panic_dump_in_progress) { - printf("System dump aborted.\n"); + kdb_printf("System dump aborted.\n"); goto panic_dump_exit; } printf("Entering system dump routine\n"); if (!kdp_en_recv_pkt || !kdp_en_send_pkt) { - printf("Error: No transport device registered for kernel crashdump\n"); - return; + kdb_printf("Error: No transport device registered for kernel crashdump\n"); + return; } if (!panicd_specified) { - printf("A dump server was not specified in the boot-args, terminating kernel core dump.\n"); + kdb_printf("A dump server was not specified in the boot-args, terminating kernel core dump.\n"); goto panic_dump_exit; } flag_panic_dump_in_progress = TRUE; - not_in_kdp = 0; if (pkt.input) kdp_panic("kdp_panic_dump: unexpected pending input packet"); @@ -1733,28 +2013,28 @@ kdp_panic_dump(void) (unsigned int) (abstime & 0xffffffff)); } - if (0 == inet_aton(panicd_ip_str, (struct in_addr *) &panic_server_ip)) { - printf("inet_aton() failed interpreting %s as a panic server IP\n", panicd_ip_str); + if (0 == inet_aton(panicd_ip_str, (struct kdp_in_addr *) &panic_server_ip)) { + kdb_printf("inet_aton() failed interpreting %s as a panic server IP\n", panicd_ip_str); } else - printf("Attempting connection to panic server configured at IP %s, port %d\n", panicd_ip_str, panicd_port); + kdb_printf("Attempting connection to panic server configured at IP %s, port %d\n", panicd_ip_str, panicd_port); destination_mac = router_mac; if (kdp_arp_resolve(panic_server_ip, &temp_mac)) { - printf("Resolved %s's (or proxy's) link level address\n", panicd_ip_str); + kdb_printf("Resolved %s's (or proxy's) link level address\n", panicd_ip_str); destination_mac = temp_mac; } else { if (!flag_panic_dump_in_progress) goto panic_dump_exit; if (router_specified) { - if (0 == inet_aton(router_ip_str, (struct in_addr *) &parsed_router_ip)) - printf("inet_aton() failed interpreting %s as an IP\n", router_ip_str); + if (0 == inet_aton(router_ip_str, (struct kdp_in_addr *) &parsed_router_ip)) + kdb_printf("inet_aton() failed interpreting %s as an IP\n", router_ip_str); else { router_ip = parsed_router_ip; if (kdp_arp_resolve(router_ip, &temp_mac)) { destination_mac = temp_mac; - printf("Routing through specified router IP %s (%d)\n", router_ip_str, router_ip); + kdb_printf("Routing through specified router IP %s (%d)\n", router_ip_str, router_ip); } } } @@ -1762,7 +2042,7 @@ kdp_panic_dump(void) if (!flag_panic_dump_in_progress) goto panic_dump_exit; - printf("Transmitting packets to link level address: %02x:%02x:%02x:%02x:%02x:%02x\n", + kdb_printf("Transmitting packets to link level address: %02x:%02x:%02x:%02x:%02x:%02x\n", destination_mac.ether_addr_octet[0] & 0xff, destination_mac.ether_addr_octet[1] & 0xff, destination_mac.ether_addr_octet[2] & 0xff, @@ -1770,17 +2050,17 @@ kdp_panic_dump(void) destination_mac.ether_addr_octet[4] & 0xff, destination_mac.ether_addr_octet[5] & 0xff); - printf("Kernel map size is %llu\n", (unsigned long long) get_vmmap_size(kernel_map)); - printf("Sending write request for %s\n", corename_str); + kdb_printf("Kernel map size is %llu\n", (unsigned long long) get_vmmap_size(kernel_map)); + kdb_printf("Sending write request for %s\n", corename_str); if ((panic_error = kdp_send_crashdump_pkt(KDP_WRQ, corename_str, 0 , NULL)) < 0) { - printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error); + kdb_printf ("kdp_send_crashdump_pkt failed with error %d\n", panic_error); goto panic_dump_exit; } /* Just the panic log requested */ if ((panicstr != (char *) 0) && (kdp_flag & PANIC_LOG_DUMP)) { - printf("Transmitting panic log, please wait: "); + kdb_printf_unbuffered("Transmitting panic log, please wait: "); kdp_send_crashdump_data(KDP_DATA, corename_str, debug_buf_ptr - debug_buf, debug_buf); @@ -1794,15 +2074,13 @@ kdp_panic_dump(void) long start_off = msgbufp->msg_bufx; long len; - printf("Transmitting system log, please wait: "); + kdb_printf_unbuffered("Transmitting system log, please wait: "); if (start_off >= msgbufp->msg_bufr) { len = msgbufp->msg_size - start_off; kdp_send_crashdump_data(KDP_DATA, corename_str, len, msgbufp->msg_bufc + start_off); - /* seek to remove trailing bytes */ - if (len & (SEGSIZE - 1)) - kdp_send_crashdump_seek(corename_str, len); + kdp_send_crashdump_seek(corename_str, len); start_off = 0; } @@ -1821,8 +2099,6 @@ kdp_panic_dump(void) panic_dump_exit: abort_panic_transfer(); - pkt.input = FALSE; - pkt.len = 0; kdp_reset(); return; } @@ -1832,7 +2108,6 @@ abort_panic_transfer(void) { flag_panic_dump_in_progress = FALSE; flag_dont_abort_panic_dump = FALSE; - not_in_kdp = 1; panic_block = 0; } @@ -1843,14 +2118,8 @@ static boolean_t needs_serial_init = TRUE; static void kdp_serial_send(void *rpkt, unsigned int rpkt_len) { - if (needs_serial_init) - { - serial_init(); - needs_serial_init = FALSE; - } - // printf("tx\n"); - kdp_serialize_packet((unsigned char *)rpkt, rpkt_len, serial_putc); + kdp_serialize_packet((unsigned char *)rpkt, rpkt_len, pal_serial_putc); } static void @@ -1859,18 +2128,12 @@ kdp_serial_receive(void *rpkt, unsigned int *rpkt_len, unsigned int timeout) int readkar; uint64_t now, deadline; - if (needs_serial_init) - { - serial_init(); - needs_serial_init = FALSE; - } - clock_interval_to_deadline(timeout, 1000 * 1000 /* milliseconds */, &deadline); // printf("rx\n"); for(clock_get_uptime(&now); now < deadline; clock_get_uptime(&now)) { - readkar = serial_getc(); + readkar = pal_serial_getc(); if(readkar >= 0) { unsigned char *packet; @@ -1885,6 +2148,21 @@ kdp_serial_receive(void *rpkt, unsigned int *rpkt_len, unsigned int timeout) *rpkt_len = 0; } +static boolean_t +kdp_serial_setmode(boolean_t active) +{ + if (active == FALSE) /* leaving KDP */ + return TRUE; + + if (!needs_serial_init) + return TRUE; + + pal_serial_init(); + needs_serial_init = FALSE; + return TRUE; +} + + static void kdp_serial_callout(__unused void *arg, kdp_event_t event) { /* When we stop KDP, set the bit to re-initialize the console serial port @@ -1912,25 +2190,53 @@ static void kdp_serial_callout(__unused void *arg, kdp_event_t event) void kdp_init(void) { + strlcpy(kdp_kernelversion_string, version, sizeof(kdp_kernelversion_string)); + + /* Relies on platform layer calling panic_init() before kdp_init() */ + if (kernel_uuid_string[0] != '\0') { + /* + * Update kdp_kernelversion_string with our UUID + * generated at link time. + */ + + strlcat(kdp_kernelversion_string, "; UUID=", sizeof(kdp_kernelversion_string)); + strlcat(kdp_kernelversion_string, kernel_uuid_string, sizeof(kdp_kernelversion_string)); + } + + debug_log_init(); + +#if defined(__x86_64__) || defined(__arm__) + if (vm_kernel_slide) { + char KASLR_stext[19]; + strlcat(kdp_kernelversion_string, "; stext=", sizeof(kdp_kernelversion_string)); + snprintf(KASLR_stext, sizeof(KASLR_stext), "%p", (void *) vm_kernel_stext); + strlcat(kdp_kernelversion_string, KASLR_stext, sizeof(kdp_kernelversion_string)); + } +#endif + + if (debug_boot_arg & DB_REBOOT_POST_CORE) + kdp_flag |= REBOOT_POST_CORE; +#if defined(__x86_64__) + kdp_machine_init(); +#endif + + kdp_timer_callout_init(); + kdp_crashdump_feature_mask = htonl(kdp_crashdump_feature_mask); + #if CONFIG_SERIAL_KDP char kdpname[80]; - struct in_addr ipaddr; - struct ether_addr macaddr; + struct kdp_in_addr ipaddr; + struct kdp_ether_addr macaddr; -#if CONFIG_EMBEDDED - //serial will be the debugger, unless match name is explicitly provided, and it's not "serial" - if(PE_parse_boot_argn("kdp_match_name", kdpname, sizeof(kdpname)) && strncmp(kdpname, "serial", sizeof(kdpname)) != 0) - return; -#else // serial must be explicitly requested if(!PE_parse_boot_argn("kdp_match_name", kdpname, sizeof(kdpname)) || strncmp(kdpname, "serial", sizeof(kdpname)) != 0) return; -#endif - kprintf("Intializing serial KDP\n"); + kprintf("Initializing serial KDP\n"); kdp_register_callout(kdp_serial_callout, NULL); + kdp_register_link(NULL, kdp_serial_setmode); kdp_register_send_receive(kdp_serial_send, kdp_serial_receive); /* fake up an ip and mac for early serial debugging */ @@ -1940,7 +2246,8 @@ kdp_init(void) macaddr.ether_addr_octet[3] = 'i'; macaddr.ether_addr_octet[4] = 'a'; macaddr.ether_addr_octet[5] = 'l'; - ipaddr.s_addr = 0xABADBABE; + ipaddr.s_addr = KDP_SERIAL_IPADDR; kdp_set_ip_and_mac_addresses(&ipaddr, &macaddr); + #endif /* CONFIG_SERIAL_KDP */ }