ranchu: Create console and ADB ports automatically

On startup, start listening on the console and ADB ports automatically,
using the same "start at 5554 and work up until we find a pair of
ports which we can listen on" algorithm as the classic emulator.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/hw/arm/ranchu.c b/hw/arm/ranchu.c
index be2dbfc..a79a69f 100644
--- a/hw/arm/ranchu.c
+++ b/hw/arm/ranchu.c
@@ -35,6 +35,17 @@
 #include "exec/address-spaces.h"
 #include "qemu/bitops.h"
 #include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "sysemu/char.h"
+#include "monitor/monitor.h"
+#include "hw/misc/android_pipe.h"
+
+/* Maximum number of emulators that can run at once (affects how
+ * far through the TCP port space from 5554 we will scan to find
+ * a pair of ports we can listen on)
+ */
+#define MAX_ANDROID_EMULATORS 64
+#define ANDROID_CONSOLE_BASEPORT 5554
 
 #define NUM_VIRTIO_TRANSPORTS 32
 
@@ -392,6 +403,73 @@
     return board->fdt;
 }
 
+static CharDriverState *try_to_create_console_chardev(int portno)
+{
+    /* Try to create the chardev for the Android console on the specified port.
+     * This is equivalent to the command line options
+     *  -chardev socket,id=monitor,host=127.0.0.1,port=NNN,server,nowait,telnet
+
+     *  -mon chardev=monitor,mode=android-console
+     * Return true on success, false on failure (presumably port-in-use).
+     */
+    Error *err = NULL;
+    CharDriverState *chr;
+    QemuOpts *opts;
+    const char *chardev_opts =
+        "socket,id=private-chardev-for-android-monitor,"
+        "host=127.0.0.1,server,nowait,telnet";
+
+    opts = qemu_opts_parse(qemu_find_opts("chardev"), chardev_opts, 1);
+    assert(opts);
+    qemu_opt_set_number(opts, "port", portno);
+    chr = qemu_chr_new_from_opts(opts, NULL, &err);
+    if (err) {
+        /* Assume this was port-in-use */
+        qemu_opts_del(opts);
+        error_free(err);
+        return NULL;
+    }
+
+    qemu_chr_fe_claim_no_fail(chr);
+    return chr;
+}
+
+static void initialize_console_and_adb(void)
+{
+    /* Initialize the console and ADB, which must listen on two
+     * consecutive TCP ports starting from 5555 and working up until
+     * we manage to open both connections.
+     */
+    int baseport = ANDROID_CONSOLE_BASEPORT;
+    int tries = MAX_ANDROID_EMULATORS;
+    CharDriverState *chr;
+
+    for (; tries > 0; tries--, baseport += 2) {
+        chr = try_to_create_console_chardev(baseport);
+        if (!chr) {
+            continue;
+        }
+
+        if (!adb_server_init(baseport + 1)) {
+            qemu_chr_delete(chr);
+            chr = NULL;
+            continue;
+        }
+
+        /* Confirmed we have both ports, now we can create the console itself.
+         * This is equivalent to
+         * "-mon chardev=private-chardev,mode=android-console"
+         */
+        monitor_init(chr, MONITOR_ANDROID_CONSOLE | MONITOR_USE_READLINE);
+
+        printf("console on port %d, ADB on port %d\n", baseport, baseport + 1);
+        return;
+    }
+    error_report("it seems too many emulator instances are running "
+                 "on this machine. Aborting\n");
+    exit(1);
+}
+
 static void ranchu_init(QEMUMachineInitArgs *args)
 {
     qemu_irq pic[NUM_IRQS];
@@ -470,6 +548,11 @@
      */
     create_virtio_devices(vbi, pic);
 
+    /* Initialize the Android console and adb connection
+     * (must be done after the pipe has been realized).
+     */
+    initialize_console_and_adb();
+
     vbi->bootinfo.ram_size = args->ram_size;
     vbi->bootinfo.kernel_filename = args->kernel_filename;
     vbi->bootinfo.kernel_cmdline = args->kernel_cmdline;