Support multiple ways of driving hftests, add UART

Move logic that gets the boot arguments of hftest to a separate build
target and implement the same interface for communicating over UART.

Add SerialDriver to hftest.py that drives the communication with a
device over serial port.

The UART backend for hftest depends on an implementation of
'hftest_device' interface to reboot the board when the test has
finished.

Change-Id: Idfcb2c6e9af9cd283e360993fa2580d4fea49594
diff --git a/test/hftest/ctrl_uart.c b/test/hftest/ctrl_uart.c
new file mode 100644
index 0000000..da4d0d6
--- /dev/null
+++ b/test/hftest/ctrl_uart.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 The Hafnium Authors.
+ *
+ * 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
+ *
+ *     https://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.
+ */
+
+#include "hf/plat/console.h"
+
+#include "test/hftest.h"
+
+/* clang-format off */
+#define CMD_GET_COMMAND_LINE	"[hftest_ctrl:get_command_line]\n"
+#define CMD_FINISHED		"[hftest_ctrl:finished]\n"
+/* clang-format on */
+
+static char command_line[128];
+
+static void write(const char *str)
+{
+	while (*str != '\0') {
+		plat_console_putchar(*str);
+		str++;
+	}
+}
+
+static bool read(char *buf, size_t max_len, struct memiter *str)
+{
+	char c;
+	size_t len = 0;
+
+	while (true) {
+		c = plat_console_getchar();
+		if (c == '\r' || c == '\n') {
+			memiter_init(str, buf, len);
+			return true;
+		}
+
+		if (len < max_len) {
+			buf[len++] = c;
+		} else {
+			return false;
+		}
+	}
+}
+
+bool hftest_ctrl_start(const struct fdt_header *fdt, struct memiter *cmd)
+{
+	(void)fdt;
+
+	/* Initialize the console */
+	plat_console_init();
+
+	/* Inform the host that we are ready to receive the command line. */
+	write(CMD_GET_COMMAND_LINE);
+
+	/* Read command line from the console. */
+	read(command_line, ARRAY_SIZE(command_line), cmd);
+
+	return true;
+}
+
+void hftest_ctrl_finish(void)
+{
+	/*
+	 * Inform the host that this test has finished running and all
+	 * subsequent logs belong to the next run.
+	 */
+	write(CMD_FINISHED);
+
+	/* Reboot the device. */
+	hftest_device_reboot();
+}