Patrick Rudolph (siro@das-labor.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14512
-gerrit
commit 37bf6de3a26fa15303152d0e744847bc59fc1462 Author: Patrick Rudolph siro@das-labor.org Date: Mon Apr 25 12:26:12 2016 +0200
qemu-0.15.x/serialice-com: Implement TCP serialice connection
Add support for TCP connections. Useful to connect to BeagleBone Black in EHCI Debug mode using ser2net daemon. Pass tcp:hostname:port instead of tty device path. Example: ./qemu -M serialice -serialice tcp:10.0.0.1:8888
The windows version hasn't been tested yet.
Change-Id: Iee264dfd11375e11c02ea25b6887d32f3db887c5 Signed-off-by: Patrick Rudolph siro@das-labor.org --- SerialICE/README.QEMU | 7 ++ qemu-0.15.x/serialice-com.c | 177 ++++++++++++++++++++++++++++++++------------ 2 files changed, 138 insertions(+), 46 deletions(-)
diff --git a/SerialICE/README.QEMU b/SerialICE/README.QEMU index 3af8c36..b9d2a96 100644 --- a/SerialICE/README.QEMU +++ b/SerialICE/README.QEMU @@ -47,6 +47,13 @@ $ i386-softmmu/qemu -M serialice -serialice \ The device /dev/ttyS0 is the name of the serial device connected to your target machine running the SerialICE shell.
+Instead of a local serial device you can connect over TCP to a BeagleBone Black +running a ser2tcp server. +The command to connect to a remote host at 10.0.0.1 port 8080 is: + +$ i386-softmmu/qemu -M serialice -serialice \ + tcp:10.0.0.1:8080 -hda /dev/zero -L ./bios + For debugging hints see the file README.GDB
ADAPTING THE CODE diff --git a/qemu-0.15.x/serialice-com.c b/qemu-0.15.x/serialice-com.c index 9211b6f..85172d0 100644 --- a/qemu-0.15.x/serialice-com.c +++ b/qemu-0.15.x/serialice-com.c @@ -34,6 +34,9 @@ #include <fcntl.h> #include <termios.h> #include <sys/ioctl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> #endif
#include <serialice.h> @@ -47,6 +50,7 @@ typedef struct { #else int fd; #endif + int tcp; char *buffer; char *command; } SerialICEState; @@ -114,6 +118,7 @@ static int serialice_write(SerialICEState * state, const void *buf, char *buffer = (char *)buf; char c; int i; + int err;
for (i = 0; i < (int)nbyte; i++) { c = 0; @@ -207,6 +212,10 @@ static int serialice_wait_prompt(void)
const SerialICE_target *serialice_serial_init(void) { + int len = 0; + int port = 0; + char *hostname = NULL; + s = mallocz(sizeof(SerialICEState));
if (!s) { @@ -217,69 +226,145 @@ const SerialICE_target *serialice_serial_init(void) printf("You need to specify a serial device to use SerialICE.\n"); exit(1); } + len = strlen(serialice_device); + if (len > 5) { + char *tmp = strstr(serialice_device, "tcp:"); + if (tmp && tmp == serialice_device) { + hostname = mallocz(len - 4 + 1); + /* copy hostname and port */ + memcpy(hostname, tmp + 4, len - 4); + /* search for port */ + tmp = strstr(hostname, ":"); + if (tmp) { + /* cut of port from hostname string */ + *tmp = 0; + /* read port */ + port = atoi(tmp + 1); + s->tcp = !!port; + } + } + } #ifdef WIN32 - s->fd = CreateFile(serialice_device, GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL); + if (s->tcp) { + int ret; + WSADATA wsaData = {0}; + ret = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (ret) { + perror("WSAStartup failed: %d\n", ret); + exit(1); + }
- if (s->fd == INVALID_HANDLE_VALUE) { - perror("SerialICE: Could not connect to target TTY"); - exit(1); - } + s->fd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); + if (s->fd == INVALID_SOCKET) { + perror("SerialICE: Could not create a TCP socket"); + exit(1); + } + } else { + s->fd = CreateFile(serialice_device, GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (s->fd == INVALID_HANDLE_VALUE) { + perror("SerialICE: Could not connect to target TTY"); + exit(1); + }
- DCB dcb; - if (!GetCommState(s->fd, &dcb)) { - perror("SerialICE: Could not load config for target TTY"); - exit(1); - } + DCB dcb; + if (!GetCommState(s->fd, &dcb)) { + perror("SerialICE: Could not load config for target TTY"); + exit(1); + }
- dcb.BaudRate = CBR_115200; - dcb.ByteSize = 8; - dcb.Parity = NOPARITY; - dcb.StopBits = ONESTOPBIT; + dcb.BaudRate = CBR_115200; + dcb.ByteSize = 8; + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT;
- if (!SetCommState(s->fd, &dcb)) { - perror("SerialICE: Could not store config for target TTY"); - exit(1); + if (!SetCommState(s->fd, &dcb)) { + perror("SerialICE: Could not store config for target TTY"); + exit(1); + } } #else - s->fd = open(serialice_device, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (s->tcp) { + struct timeval tv; + s->fd = socket(AF_INET, SOCK_STREAM, 0); + if (s->fd == -1) { + perror("SerialICE: Could not create a TCP socket"); + exit(1); + }
- if (s->fd == -1) { - perror("SerialICE: Could not connect to target TTY"); - exit(1); - } + if (fcntl(s->fd, F_SETFL, 0) == -1) { + perror("SerialICE: Could not switch to blocking I/O"); + exit(1); + }
- if (ioctl(s->fd, TIOCEXCL) == -1) { - perror("SerialICE: TTY not exclusively available"); - exit(1); - } + tv.tv_sec = 1; /* 1 second timeout */ + tv.tv_usec = 0; + setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); + } else { + s->fd = open(serialice_device, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (s->fd == -1) { + perror("SerialICE: Could not connect to target TTY"); + exit(1); + }
- if (fcntl(s->fd, F_SETFL, 0) == -1) { - perror("SerialICE: Could not switch to blocking I/O"); - exit(1); - } + if (ioctl(s->fd, TIOCEXCL) == -1) { + perror("SerialICE: TTY not exclusively available"); + exit(1); + }
- if (tcgetattr(s->fd, &options) == -1) { - perror("SerialICE: Could not get TTY attributes"); - exit(1); - } + if (fcntl(s->fd, F_SETFL, 0) == -1) { + perror("SerialICE: Could not switch to blocking I/O"); + exit(1); + }
- cfsetispeed(&options, B115200); - cfsetospeed(&options, B115200); + if (tcgetattr(s->fd, &options) == -1) { + perror("SerialICE: Could not get TTY attributes"); + exit(1); + } + + cfsetispeed(&options, B115200); + cfsetospeed(&options, B115200);
- /* set raw input, 1 second timeout */ - options.c_cflag |= (CLOCAL | CREAD); - options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - options.c_oflag &= ~OPOST; - options.c_iflag |= IGNCR; - options.c_cc[VMIN] = 0; - options.c_cc[VTIME] = 100; + /* set raw input, 1 second timeout */ + options.c_cflag |= (CLOCAL | CREAD); + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + options.c_oflag &= ~OPOST; + options.c_iflag |= IGNCR; + options.c_cc[VMIN] = 0; + options.c_cc[VTIME] = 100;
- tcsetattr(s->fd, TCSANOW, &options); + tcsetattr(s->fd, TCSANOW, &options);
- tcflush(s->fd, TCIOFLUSH); + tcflush(s->fd, TCIOFLUSH); + } #endif
+ if (s->tcp) { + struct hostent *server; + struct sockaddr_in serv_addr; + + server = gethostbyname(hostname); + if (server == NULL) { + perror("No such host.\n"); + exit(1); + } + + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + bcopy((char *)server->h_addr, + (char *)&serv_addr.sin_addr.s_addr, + server->h_length); + serv_addr.sin_port = htons(port); + + printf("Connecting to tcp://%s:%d ...\n", hostname, port); + + if (connect(s->fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + perror("ERROR connecting"); + exit(1); + } + printf("Connected to tcp://%s:%d .\n", hostname, port); + } + s->buffer = mallocz(BUFFER_SIZE); s->command = mallocz(BUFFER_SIZE); if (!s->buffer || !s->command) {