/** * Read a single character from any console. * * @v None - * @ret character Character read from a console. * @err None - * * A character will be read from the first enabled console device that * has input available using that console's console_driver::getchar() * method. If no console has input available to be read, this method * will block. To perform a non-blocking read, use something like * * @code * * int key = iskey() ? getchar() : -1; * * @endcode * * The character read will not be echoed back to any console. * */ int getchar ( void ) { struct console_driver *console; int character; while ( 1 ) { console = has_input(); if ( console && console->getchar ) { character = console->getchar (); break; } /* Doze for a while (until the next interrupt). This works * fine, because the keyboard is interrupt-driven, and the * timer interrupt (approx. every 50msec) takes care of the * serial port, which is read by polling. This reduces the * power dissipation of a modern CPU considerably, and also * makes Etherboot waiting for user interaction waste a lot * less CPU time in a VMware session. */ cpu_nap(); /* Keep processing background tasks while we wait for * input. */ step(); } /* CR -> LF translation */ if ( character == '\r' ) character = '\n'; return character; }
/** * Receive XenStore response raw data * * @v xen Xen hypervisor * @v data Data buffer, or NULL to discard data * @v len Length of data */ static void xenstore_recv ( struct xen_hypervisor *xen, void *data, size_t len ) { struct xenstore_domain_interface *intf = xen->store.intf; XENSTORE_RING_IDX cons = readl ( &intf->rsp_cons ); XENSTORE_RING_IDX prod; XENSTORE_RING_IDX idx; char *bytes = data; size_t offset = 0; size_t fill; DBGCP ( intf, "XENSTORE raw response:\n" ); /* Read one byte at a time */ while ( offset < len ) { /* Wait for data to be ready */ while ( 1 ) { prod = readl ( &intf->rsp_prod ); fill = ( prod - cons ); if ( fill > 0 ) break; DBGC2 ( xen, "." ); cpu_nap(); rmb(); } /* Read byte */ idx = MASK_XENSTORE_IDX ( cons++ ); if ( data ) bytes[offset++] = readb ( &intf->rsp[idx] ); } if ( data ) DBGCP_HDA ( intf, MASK_XENSTORE_IDX ( cons - len ), data, len ); /* Update consumer counter */ writel ( cons, &intf->rsp_cons ); wmb(); }
/** * Send XenStore request raw data * * @v xen Xen hypervisor * @v data Data buffer * @v len Length of data */ static void xenstore_send ( struct xen_hypervisor *xen, const void *data, size_t len ) { struct xenstore_domain_interface *intf = xen->store.intf; XENSTORE_RING_IDX prod = readl ( &intf->req_prod ); XENSTORE_RING_IDX cons; XENSTORE_RING_IDX idx; const char *bytes = data; size_t offset = 0; size_t fill; DBGCP ( intf, "XENSTORE raw request:\n" ); DBGCP_HDA ( intf, MASK_XENSTORE_IDX ( prod ), data, len ); /* Write one byte at a time */ while ( offset < len ) { /* Wait for space to become available */ while ( 1 ) { cons = readl ( &intf->req_cons ); fill = ( prod - cons ); if ( fill < XENSTORE_RING_SIZE ) break; DBGC2 ( xen, "." ); cpu_nap(); rmb(); } /* Write byte */ idx = MASK_XENSTORE_IDX ( prod++ ); writeb ( bytes[offset++], &intf->req[idx] ); } /* Update producer counter */ wmb(); writel ( prod, &intf->req_prod ); wmb(); }
static size_t gdbudp_recv ( char *buf, size_t len ) { struct io_buffer *iob; struct ethhdr *ethhdr; struct arphdr *arphdr; struct iphdr *iphdr; struct udp_header *udphdr; size_t payload_len; gdbudp_ensure_netdev_open ( netdev ); for ( ; ; ) { netdev_poll ( netdev ); while ( ( iob = netdev_rx_dequeue ( netdev ) ) != NULL ) { /* Ethernet header */ if ( iob_len ( iob ) < sizeof ( *ethhdr ) ) { goto bad_packet; } ethhdr = iob->data; iob_pull ( iob, sizeof ( *ethhdr ) ); /* Handle ARP requests so the client can find our MAC */ if ( ethhdr->h_protocol == htons ( ETH_P_ARP ) ) { arphdr = iob->data; if ( iob_len ( iob ) < sizeof ( *arphdr ) + 2 * ( ETH_ALEN + sizeof ( struct in_addr ) ) || arphdr->ar_hrd != htons ( ARPHRD_ETHER ) || arphdr->ar_pro != htons ( ETH_P_IP ) || arphdr->ar_hln != ETH_ALEN || arphdr->ar_pln != sizeof ( struct in_addr ) || arphdr->ar_op != htons ( ARPOP_REQUEST ) || * ( uint32_t * ) arp_target_pa ( arphdr ) != source_addr.sin_addr.s_addr ) { goto bad_packet; } /* Generate an ARP reply */ arphdr->ar_op = htons ( ARPOP_REPLY ); memswap ( arp_sender_pa ( arphdr ), arp_target_pa ( arphdr ), sizeof ( struct in_addr ) ); memcpy ( arp_target_ha ( arphdr ), arp_sender_ha ( arphdr ), ETH_ALEN ); memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, ETH_ALEN ); /* Fix up ethernet header */ ethhdr = iob_push ( iob, sizeof ( *ethhdr ) ); memcpy ( ethhdr->h_dest, ethhdr->h_source, ETH_ALEN ); memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN ); netdev_tx ( netdev, iob ); continue; /* no need to free iob */ } if ( ethhdr->h_protocol != htons ( ETH_P_IP ) ) { goto bad_packet; } /* IP header */ if ( iob_len ( iob ) < sizeof ( *iphdr ) ) { goto bad_packet; } iphdr = iob->data; iob_pull ( iob, sizeof ( *iphdr ) ); if ( iphdr->protocol != IP_UDP || iphdr->dest.s_addr != source_addr.sin_addr.s_addr ) { goto bad_packet; } /* UDP header */ if ( iob_len ( iob ) < sizeof ( *udphdr ) ) { goto bad_packet; } udphdr = iob->data; if ( udphdr->dest != source_addr.sin_port ) { goto bad_packet; } /* Learn the remote connection details */ memcpy ( dest_eth, ethhdr->h_source, ETH_ALEN ); dest_addr.sin_addr.s_addr = iphdr->src.s_addr; dest_addr.sin_port = udphdr->src; /* Payload */ payload_len = ntohs ( udphdr->len ); if ( payload_len < sizeof ( *udphdr ) || payload_len > iob_len ( iob ) ) { goto bad_packet; } payload_len -= sizeof ( *udphdr ); iob_pull ( iob, sizeof ( *udphdr ) ); if ( payload_len > len ) { goto bad_packet; } memcpy ( buf, iob->data, payload_len ); free_iob ( iob ); return payload_len; bad_packet: free_iob ( iob ); } cpu_nap(); } }