[PATCH/RFC 5/9] s390 virtual console for guests

Carsten Otte
2007-05-11T17:36:00Z

From: Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>

This driver provides a simple virtualized console. Userspace can
use read/write to its console to pass the data to the host.

Signed-off-by: Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>

---
drivers/s390/Kconfig | 5 +
drivers/s390/guest/Makefile | 1
drivers/s390/guest/guest_console.c | 72 +++++++++++++++++
drivers/s390/guest/guest_console.h | 47 +++++++++++
drivers/s390/guest/guest_tty.c | 153 +++++++++++++++++++++++++++++++++++++
5 files changed, 278 insertions(+)

Index: linux-2.6.21/drivers/s390/guest/guest_console.c
===================================================================
--- /dev/null
+++ linux-2.6.21/drivers/s390/guest/guest_console.c
@@ -0,0 +1,72 @@
+/*
+ * guest console device driver
+ * Copyright IBM Corp. 2007
+ * Author: Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
+ */
+
+#include "linux/kernel.h"
+#include "linux/types.h"
+#include "linux/console.h"
+#include "linux/string.h"
+#include "linux/init.h"
+#include "linux/errno.h"
+#include "guest_console.h"
+
+#define guest_console_major 4 /* TTYAUX_MAJOR */
+#define guest_console_minor 65
+#define guest_console_name "ttyS"
+
+static void guest_console_write(struct console *console, const char *string,
+ unsigned len)
+{
+ int ret;
+ size_t pos;
+
+ for(pos=0; pos < strlen(string); pos += ret) {
+ ret = diag_write(1, string + pos, len - pos);
+ if (ret <= 0)
+ break;
+ }
+}
+
+static struct tty_driver *
+guest_console_device(struct console *c, int *index)
+{
+ *index = c->index;
+ return guest_tty_driver;
+}
+
+static void
+guest_console_unblank(void)
+{
+ return;
+}
+
+static struct console guest_console =
+{
+ .name = guest_console_name,
+ .write = guest_console_write,
+ .device = guest_console_device,
+ .unblank = guest_console_unblank,
+ .flags = CON_PRINTBUFFER,
+ .index = 0 /* ttyS0 */
+};
+
+/*
+ * called by console_init() in drivers/char/tty_io.c at boot-time.
+ */
+static int __init
+guest_console_init(void)
+{
+ if (!MACHINE_IS_GUEST)
+ return 0;
+
+ printk (KERN_INFO "z/Live console initialized\n");
+
+ /* enable printk-access to this driver */
+ register_console(&guest_console);
+ return 0;
+}
+
+console_initcall(guest_console_init);
+
Index: linux-2.6.21/drivers/s390/guest/guest_console.h
===================================================================
--- /dev/null
+++ linux-2.6.21/drivers/s390/guest/guest_console.h
@@ -0,0 +1,47 @@
+/*
+ * guest console device driver
+ * Copyright IBM Corp. 2007
+ * Author: Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
+ */
+
+
+#ifndef __GCONSOLE_H
+#define __GCONSOLE_H
+extern struct tty_driver *guest_tty_driver;
+static inline int diag_write(int fd, const void *buffer, size_t count)
+{
+ register long __arg1 asm("2") = fd;
+ register const void * __arg2 asm("3") = buffer;
+ register size_t __arg3 asm("4") = count;
+ register long __svcres asm("2");
+ long __res;
+ asm volatile (
+ "diag 0,0,2"
+ : "=d" (__svcres)
+ : "0" (__arg1),
+ "d" (__arg2),
+ "d" (__arg3)
+ : "cc", "memory");
+ __res = __svcres;
+ return __res;
+}
+
+static inline int diag_read(int fd, const void *buffer, size_t count)
+{
+ register long __arg1 asm("2") = fd;
+ register const void * __arg2 asm("3") = buffer;
+ register size_t __arg3 asm("4") = count;
+ register long __svcres asm("2");
+ long __res;
+ asm volatile (
+ "diag 0,0,1"
+ : "=d" (__svcres)
+ : "0" (__arg1),
+ "d" (__arg2),
+ "d" (__arg3)
+ : "cc", "memory");
+ __res = __svcres;
+ return __res;
+}
+#endif
+
Index: linux-2.6.21/drivers/s390/guest/guest_tty.c
===================================================================
--- /dev/null
+++ linux-2.6.21/drivers/s390/guest/guest_tty.c
@@ -0,0 +1,153 @@
+/*
+ * guest console tty device driver
+ * Copyright IBM Corp. 2007
+ * Author: Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>
+ */
+
+#include <linux/fs.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <asm/s390_ext.h>
+#include "guest_console.h"
+
+struct tty_driver *guest_tty_driver;
+static struct tty_struct *guest_tty;
+
+MODULE_DESCRIPTION("Guest console for linux guests");
+MODULE_AUTHOR("Carsten Otte <cotte-tA70FqPdS9bQT0dZR+AlfA@public.gmane.org>");
+MODULE_LICENSE("GPL");
+
+static int
+guest_tty_open(struct tty_struct *tty, struct file *filp)
+{
+ guest_tty = tty;
+ tty->driver_data = NULL;
+ return 0;
+}
+
+static void
+guest_tty_close(struct tty_struct *tty, struct file *filp)
+{
+ if (tty->count > 1)
+ return;
+ guest_tty = NULL;
+}
+
+static int
+guest_tty_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+static int
+guest_tty_write(struct tty_struct *tty, const unsigned char *str, int count)
+{
+ int ret;
+ size_t pos;
+
+ for(pos=0; pos < count; pos += ret) {
+ ret = diag_write(1, str + pos, count - pos);
+ if (ret <= 0)
+ break;
+ }
+ return pos;
+}
+
+static void
+guest_tty_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ guest_tty_write (tty, &ch, 1);
+}
+
+static void
+guest_tty_flush_chars(struct tty_struct *tty)
+{
+ int nop;
+ nop=0; // :)
+}
+
+static int
+guest_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ return 0;
+}
+
+static void
+guest_tty_flush_buffer(struct tty_struct *tty)
+{
+ guest_tty_flush_chars(tty); // :)
+}
+
+static int
+guest_tty_write_room (struct tty_struct *tty)
+{
+ return 65536;
+}
+
+static struct tty_operations guest_ops = {
+ .open = guest_tty_open,
+ .close = guest_tty_close,
+ .write = guest_tty_write,
+ .put_char = guest_tty_put_char,
+ .flush_chars = guest_tty_flush_chars,
+ .write_room = guest_tty_write_room,
+ .chars_in_buffer = guest_tty_chars_in_buffer,
+ .flush_buffer = guest_tty_flush_buffer,
+ .ioctl = guest_tty_ioctl,
+};
+
+static void
+guest_tty_ext_handler(__u16 code)
+{
+ char buffer[256];
+ int count;
+
+ count = diag_read(0, buffer, 256);
+ if (count <= 0)
+ return;
+
+ if (!guest_tty)
+ return;
+ tty_insert_flip_string(guest_tty, buffer, count);
+ tty_flip_buffer_push(guest_tty);
+}
+
+int __init
+guest_tty_init(void)
+{
+ struct tty_driver *driver;
+ int rc;
+
+ if (!MACHINE_IS_GUEST)
+ return 0;
+ register_external_interrupt(0x1234, guest_tty_ext_handler);
+ driver = alloc_tty_driver(1);
+ if (!driver)
+ return -ENOMEM;
+ guest_tty = NULL;
+ driver->owner = THIS_MODULE;
+ driver->driver_name = "guest_line";
+ driver->name = "guest_line";
+ driver->major = TTY_MAJOR;
+ driver->minor_start = 65;
+ driver->type = TTY_DRIVER_TYPE_SYSTEM;
+ driver->subtype = SYSTEM_TYPE_TTY;
+ driver->init_termios = tty_std_termios;
+ driver->init_termios.c_iflag = IGNBRK | IGNPAR;
+ driver->init_termios.c_oflag = ONLCR | XTABS;
+ driver->init_termios.c_lflag = ISIG | ECHO;
+ driver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(driver, &guest_ops);
+ rc = tty_register_driver(driver);
+ if (rc) {
+ printk(KERN_ERR "guest tty driver: could not register tty - "
+ "tty_register_driver returned %d\n", rc);
+ put_tty_driver(driver);
+ return rc;
+ }
+ guest_tty_driver = driver;
+ return 0;
+}
+module_init(guest_tty_init);
Index: linux-2.6.21/drivers/s390/Kconfig
===================================================================
--- linux-2.6.21.orig/drivers/s390/Kconfig
+++ linux-2.6.21/drivers/s390/Kconfig
@@ -211,6 +211,11 @@ config MONWRITER
help
Character device driver for writing z/VM monitor service records

+config GUEST_CONSOLE
+ bool "Guest console support"
+ depends on S390_GUEST
+ help
+ Select this option if you want to run as an s390 guest
endmenu

menu "Cryptographic devices"
Index: linux-2.6.21/drivers/s390/guest/Makefile
===================================================================
--- linux-2.6.21.orig/drivers/s390/guest/Makefile
+++ linux-2.6.21/drivers/s390/guest/Makefile
@@ -2,5 +2,6 @@
# s390 Linux virtual environment
#

+obj-$(CONFIG_GUEST_CONSOLE) += guest_console.o guest_tty.o
obj-$(CONFIG_S390_GUEST) += vdev.o vdev_device.o