diff --git a/.gitignore b/.gitignore index 22565a06b72f..27785526b734 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,7 @@ debian-jessie-initrd.gz external/dump_trace external/mambo/skiboot-boot_test.dump external/mambo/skiboot-hello_world.dump +external/mambo/mambo-socket-proxy external/memboot/memboot hdata/test/hdata_to_dt hdata/test/hdata_to_dt-gcov diff --git a/external/mambo/Makefile b/external/mambo/Makefile new file mode 100644 index 000000000000..fbc696e17fe2 --- /dev/null +++ b/external/mambo/Makefile @@ -0,0 +1,8 @@ +CFLAGS=-O2 -m64 -pthread -Werror -Wall + +CC=$(CROSS)gcc + +all: mambo-socket-proxy + +clean: + rm -rf mambo-socket-proxy diff --git a/external/mambo/mambo-socket-proxy.c b/external/mambo/mambo-socket-proxy.c new file mode 100644 index 000000000000..f3a1a2f086b2 --- /dev/null +++ b/external/mambo/mambo-socket-proxy.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2017 Michael Neuling , IBM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Compile with: + * gcc -static -O2 mambo-socket-proxy.c -o mambo-socket-proxy -pthread + * Run inside the simulator: + * - to forward host ssh connections to sim ssh server + * ./mambo-socket-proxy -h 10022 -s 22 + * Then connect to port 10022 on your host + * ssh -p 10022 localhost + * - to allow http proxy access from inside the sim to local http proxy + * ./mambo-socket-proxy -b proxy.mynetwork -h 3128 -s 3128 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CALL_TCL 86 +#define BOGUS_SOCKET_CONN_PROBE_CODE 224 +#define BOGUS_SOCKET_CONN_SEND_CODE 225 +#define BOGUS_SOCKET_CONN_RECV_CODE 226 + +static inline int callthru2(int command, unsigned long arg1, unsigned long arg2) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2)); + return (c); +} + +static inline int callthru3(int command, unsigned long arg1, unsigned long arg2, + unsigned long arg3) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + register unsigned long a3 asm("r6") = arg3; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2), + "r"(a3)); + return (c); +} + +static inline int callthru4(int command, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + register unsigned long a3 asm("r6") = arg3; + register unsigned long a4 asm("r7") = arg4; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2), + "r"(a3), "r"(a4)); + return (c); +} + +static inline int callthru5(int command, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5) +{ + register int c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + register unsigned long a3 asm("r6") = arg3; + register unsigned long a4 asm("r7") = arg4; + register unsigned long a5 asm("r8") = arg5; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2), + "r"(a3), "r"(a4), "r"(a5)); + return (c); +} + +unsigned long callthru_tcl(const char *str, int strlen) +{ + return callthru2(CALL_TCL, (unsigned long)str, + (unsigned long)strlen); +} + +unsigned long bogus_socket_conn_probe(int dev, void *addr, int conn) +{ + return callthru3(BOGUS_SOCKET_CONN_PROBE_CODE, + (unsigned long)dev, + (unsigned long)addr, + (unsigned long)conn); +} + +unsigned long bogus_socket_conn_recv(int dev, void *addr, int maxlen, int conn) +{ + return callthru4(BOGUS_SOCKET_CONN_RECV_CODE, + (unsigned long)dev, + (unsigned long)addr, + (unsigned long)maxlen, + (unsigned long)conn); +} + +unsigned long bogus_socket_conn_send(int dev, void *addr, int maxlen, int conn) +{ + return callthru5(BOGUS_SOCKET_CONN_SEND_CODE, + (unsigned long)dev, + (unsigned long)addr, + (unsigned long)maxlen, + 0, + (unsigned long)conn); +} + +#define BUF_MAX 1024 + +struct sock_info { + char *host; + int sock; + int dev; + int open; + int conn; +}; + +void *recv_thread(void *ptr) +{ + struct timeval timeout; + struct sock_info *si = ptr; + char buf[BUF_MAX]; + int len; + fd_set set; + + /* 1 sec */ + + + while(1) { + FD_ZERO(&set); + FD_SET(si->sock, &set); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + /* Set timeout to 1 second */ + len = select(si->sock+1, &set, NULL, NULL, &timeout); + if (len <= 0) /* timeout */ + len = -1; + else /* Receive from mambo tcp server */ + len = recv(si->sock, &buf, BUF_MAX, 0); + if (len == 0) { + si->open = 0; + return NULL; /* closed */ + } + if (len != -1) { + bogus_socket_conn_send(si->dev, &buf, len, si->conn); + } + if (!si->open) + return NULL; + } +} + +#define POLL_MAX_NS 10000000 + +void *send_thread(void *ptr) +{ + struct sock_info *si = ptr; + char buf[BUF_MAX]; + int len; + struct timespec t; + int fault_retry = 16; + + t.tv_sec = 0; + t.tv_nsec = POLL_MAX_NS; + + while(1) { + /* Send to mambo tcp server */ + len = bogus_socket_conn_recv(si->dev, &buf, BUF_MAX, si->conn); + if (len == -3 && fault_retry--) { + /* Page fault. Touch the buf and try again */ + memset(buf, 0, BUF_MAX); + continue; + } + fault_retry = 16; + + if (len == -1) /* EAGAIN */ + nanosleep(&t , NULL); + else if (len > 0) + send(si->sock, &buf, len, 0); + else { + si->open = 0; + return NULL; /* closed */ + } + if (!si->open) + return NULL; + } + +} + +void *connect_sockets(void *ptr) +{ + struct sock_info *si = ptr; + pthread_t recv, send; + unsigned long rc = 0; + + if (pthread_create(&recv, NULL, recv_thread, si) || + pthread_create(&send, NULL, send_thread, si)) { + rc = -1; + goto out; + } + + if (pthread_join(recv, NULL) || pthread_join(send, NULL)) { + rc = -1; + goto out; + } + +out: + /* FIXME: Do shutdown better */ + shutdown(si->sock, SHUT_WR); + si->open = 0; + free(si); + return (void *)rc; +} + +void print_usage() { + printf("Usage:\n"); + printf(" mambo-socket-proxy [-b ] -h -s \n"); + printf("\n"); + printf(" -h : Port on the host to forward\n"); + printf(" -s : Port in the sim to forward\n"); + printf(" -b : Connect sim port to host network\n"); + printf("\n"); +} + +int main (int argc, char *argv[]) +{ + char cmd[128]; + struct sockaddr_in ser, client; + pthread_t sockets_thread; + struct sock_info *si; + int sock, conn, rc = 0, option = 0, one_shot = 0, c, sock_desc = 0; + char *host = NULL; + int host_port = -1, sim_port = -1; + int dev = 1; /* backwards starts at 1 so forwards can use 0 */ + + while ((option = getopt(argc, argv,"rb:h:s:")) != -1) { + switch (option) { + case 'b' : + host = optarg; + break; + case 'h' : + host_port = atoi(optarg); + break; + case 's' : + sim_port = atoi(optarg); + break; + default: + print_usage(); + exit(1); + } + } + + if (host_port == -1 || sim_port ==-1) { + print_usage(); + exit(EXIT_FAILURE); + } + + /* + * A host/backwards connection will use dev=0 and conn >= 0. + * The forwards connection will use dev >= 1 and conn=0 + */ + if (host) { + sock_desc = socket(PF_INET, SOCK_STREAM, 0); + ser.sin_family = AF_INET; + ser.sin_addr.s_addr = INADDR_ANY; + ser.sin_port = htons(sim_port); + + if (bind(sock_desc, (struct sockaddr *) &ser, sizeof(ser)) < 0) { + perror("Can't connect to sim port"); + rc = -1; + goto out; + } + + listen(sock_desc, 3); + } else { + /* + * Cleaning up old bogus socket. + */ + sprintf(cmd, "mysim bogus socket cleanup"); + callthru_tcl(cmd, strlen(cmd)); + sleep(1); /* Cleanup takes a while */ + sprintf(cmd, "mysim bogus socket init 0 server " + "127.0.0.1 %i poll 0 nonblock", host_port); + callthru_tcl(cmd, strlen(cmd)); + } + + while (1) { + + if (host) { + sock = accept(sock_desc, (struct sockaddr *)&client, (socklen_t*)&c); + if (sock < 0) { + perror("accept failed"); + rc = -1; + goto out; + } + + sprintf(cmd, "mysim bogus socket init %i client %s %i poll 0", + dev, host, host_port); + callthru_tcl(cmd, strlen(cmd)); + while (bogus_socket_conn_probe(dev, NULL, 0) == -1) + sleep(1); + } else { + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 10000000; + do { + conn = bogus_socket_conn_probe(0, NULL, -1); + nanosleep(&t , NULL); + } while (conn == -1); + + sock = socket(PF_INET, SOCK_STREAM, 0); + ser.sin_family = AF_INET; + ser.sin_port = htons(sim_port); + ser.sin_addr.s_addr = inet_addr("127.0.0.1"); + memset(ser.sin_zero, '\0', sizeof ser.sin_zero); + + if (connect(sock, (struct sockaddr *) &ser, sizeof(ser))) { + perror("Can't connect to sim port"); + rc = -1; + goto out; + } + } + + si = malloc(sizeof(struct sock_info)); + si->host = host; + si->sock = sock; + si->dev = host?dev:0; + si->open = 1; + si->conn = host?0:conn; + + if (pthread_create(&sockets_thread, NULL, connect_sockets, si)) { + rc = -1; + goto out; + } + + if (one_shot) + break; + ++dev; // FIXME: do a real allocator + } +out: + exit(rc); +}