[SLOF] [PATCH v1 3/3] Add virtio-serial device support
Nikunj A Dadhania
nikunj at linux.vnet.ibm.com
Mon Oct 10 22:17:06 AEDT 2016
Add support for virtio serial device to be used as a console device.
Currently, SLOF only supports spapr-vty device. With this addition
virtio console can be used during boot.
Signed-off-by: Nikunj A Dadhania <nikunj at linux.vnet.ibm.com>
---
board-qemu/slof/Makefile | 3 +
board-qemu/slof/OF.fs | 24 +++-
board-qemu/slof/pci-device_1af4_1003.fs | 25 ++++
board-qemu/slof/pci-device_1af4_1043.fs | 15 +++
board-qemu/slof/virtio-serial.fs | 94 +++++++++++++++
lib/libvirtio/Makefile | 2 +-
lib/libvirtio/virtio-serial.c | 202 ++++++++++++++++++++++++++++++++
lib/libvirtio/virtio-serial.h | 27 +++++
lib/libvirtio/virtio.code | 33 ++++++
lib/libvirtio/virtio.in | 6 +
10 files changed, 424 insertions(+), 7 deletions(-)
create mode 100644 board-qemu/slof/pci-device_1af4_1003.fs
create mode 100644 board-qemu/slof/pci-device_1af4_1043.fs
create mode 100644 board-qemu/slof/virtio-serial.fs
create mode 100644 lib/libvirtio/virtio-serial.c
create mode 100644 lib/libvirtio/virtio-serial.h
diff --git a/board-qemu/slof/Makefile b/board-qemu/slof/Makefile
index 940a15a..cf57f16 100644
--- a/board-qemu/slof/Makefile
+++ b/board-qemu/slof/Makefile
@@ -69,6 +69,8 @@ VIO_FFS_FILES = \
$(SLOFBRDDIR)/pci-device_1af4_1041.fs \
$(SLOFBRDDIR)/pci-device_1af4_1001.fs \
$(SLOFBRDDIR)/pci-device_1af4_1042.fs \
+ $(SLOFBRDDIR)/pci-device_1af4_1003.fs \
+ $(SLOFBRDDIR)/pci-device_1af4_1043.fs \
$(SLOFBRDDIR)/pci-device_1af4_1004.fs \
$(SLOFBRDDIR)/pci-device_1af4_1048.fs \
$(SLOFBRDDIR)/pci-device_1af4_1009.fs \
@@ -79,6 +81,7 @@ VIO_FFS_FILES = \
$(SLOFBRDDIR)/vio-veth.fs \
$(SLOFBRDDIR)/rtas-nvram.fs \
$(SLOFBRDDIR)/virtio-net.fs \
+ $(SLOFBRDDIR)/virtio-serial.fs \
$(SLOFBRDDIR)/virtio-block.fs \
$(SLOFBRDDIR)/virtio-fs.fs \
$(SLOFBRDDIR)/dev-null.fs \
diff --git a/board-qemu/slof/OF.fs b/board-qemu/slof/OF.fs
index 206800c..1406506 100644
--- a/board-qemu/slof/OF.fs
+++ b/board-qemu/slof/OF.fs
@@ -162,6 +162,10 @@ CREATE version-str 10 ALLOT
: dump-display-write
s" screen" find-alias IF
drop terminal-write drop
+ ELSE
+ s" vsterm" find-alias IF
+ drop type
+ THEN
THEN
;
@@ -236,12 +240,20 @@ romfs-base 400000 0 ' claim CATCH IF ." claim failed!" cr 2drop THEN drop
." using hvterm" cr
" hvterm" io
ELSE
- " /openprom" find-node ?dup IF
- set-node
- ." and no default found, creating dev-null" cr
- " dev-null.fs" included
- " devnull-console" io
- 0 set-node
+ " vsterm" find-alias IF
+ drop
+ ." using vsterm" cr
+ " vsterm" io
+ false to store-prevga?
+ dump-display-buffer
+ ELSE
+ " /openprom" find-node ?dup IF
+ set-node
+ ." and no default found, creating dev-null" cr
+ " dev-null.fs" included
+ " devnull-console" io
+ 0 set-node
+ THEN
THEN
THEN
THEN
diff --git a/board-qemu/slof/pci-device_1af4_1003.fs b/board-qemu/slof/pci-device_1af4_1003.fs
new file mode 100644
index 0000000..a7cd53b
--- /dev/null
+++ b/board-qemu/slof/pci-device_1af4_1003.fs
@@ -0,0 +1,25 @@
+\ *****************************************************************************
+\ * Copyright (c) 2016 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ Handle virtio-serial device
+
+s" virtio [ serial ]" type cr
+
+my-space pci-device-generic-setup
+
+pci-master-enable
+pci-mem-enable
+pci-io-enable
+
+s" virtio-serial.fs" included
+
+pci-device-disable
diff --git a/board-qemu/slof/pci-device_1af4_1043.fs b/board-qemu/slof/pci-device_1af4_1043.fs
new file mode 100644
index 0000000..f044450
--- /dev/null
+++ b/board-qemu/slof/pci-device_1af4_1043.fs
@@ -0,0 +1,15 @@
+\ *****************************************************************************
+\ * Copyright (c) 2016 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ Device ID 1044 is for virtio-serial non-transitional device.
+\ Include the driver for virtio-serial
+s" pci-device_1af4_1003.fs" included
diff --git a/board-qemu/slof/virtio-serial.fs b/board-qemu/slof/virtio-serial.fs
new file mode 100644
index 0000000..42ab3e2
--- /dev/null
+++ b/board-qemu/slof/virtio-serial.fs
@@ -0,0 +1,94 @@
+\ *****************************************************************************
+\ * Copyright (c) 2016 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+s" serial" device-type
+
+FALSE VALUE initialized?
+
+virtio-setup-vd VALUE virtiodev
+
+\ Quiescence the virtqueue of this device so that no more background
+\ transactions can be pending.
+: shutdown ( -- )
+ initialized? IF
+ my-phandle node>path open-dev ?dup IF
+ virtiodev virtio-serial-shutdown
+ close-dev
+ THEN
+ FALSE to initialized?
+ THEN
+;
+
+: virtio-serial-term-emit
+ virtiodev SWAP virtio-serial-putchar
+;
+
+: virtio-serial-term-key? virtiodev virtio-serial-haschar ;
+: virtio-serial-term-key BEGIN virtio-serial-term-key? UNTIL virtiodev virtio-serial-getchar ;
+
+\ Basic device initialization - which has only to be done once
+: init ( -- )
+virtiodev virtio-serial-init drop
+ TRUE to initialized?
+ ['] virtio-serial-term-emit to emit
+ ['] virtio-serial-term-key to key
+ ['] virtio-serial-term-key? to key?
+ ['] shutdown add-quiesce-xt
+;
+
+0 VALUE open-count
+
+\ Standard node "open" function
+: open ( -- okay? )
+ open-count 0= IF
+ open IF initialized? 0= IF init THEN
+ true
+ ELSE false exit
+ THEN
+ ELSE true THEN
+ open-count 1 + to open-count
+;
+
+: close
+ open-count 0> IF
+ open-count 1 - dup to open-count
+ 0= IF close THEN
+ THEN
+ close
+;
+
+: write ( addr len -- actual )
+ tuck
+ 0 ?DO
+ dup c@ virtiodev SWAP virtio-serial-putchar
+ 1 +
+ LOOP
+ drop
+;
+
+: read ( addr len -- actual )
+ 0= IF drop 0 EXIT THEN
+ virtiodev virtio-serial-haschar 0= IF 0 swap c! -2 EXIT THEN
+ virtiodev virtio-serial-getchar swap c! 1
+;
+
+: setup-alias
+ " vsterm" find-alias 0= IF
+ " vsterm" get-node node>path set-alias
+ ELSE drop THEN
+;
+setup-alias
+
+\ Override serial methods to make term-io.fs happy
+: serial-emit virtio-serial-term-emit ;
+: serial-key? virtio-serial-term-key? ;
+: serial-key virtio-serial-term-key ;
diff --git a/lib/libvirtio/Makefile b/lib/libvirtio/Makefile
index bd6a1fa..87d9513 100644
--- a/lib/libvirtio/Makefile
+++ b/lib/libvirtio/Makefile
@@ -24,7 +24,7 @@ TARGET = ../libvirtio.a
all: $(TARGET)
-SRCS = virtio.c virtio-blk.c p9.c virtio-9p.c virtio-scsi.c virtio-net.c
+SRCS = virtio.c virtio-blk.c p9.c virtio-9p.c virtio-scsi.c virtio-net.c virtio-serial.c
OBJS = $(SRCS:%.c=%.o)
diff --git a/lib/libvirtio/virtio-serial.c b/lib/libvirtio/virtio-serial.c
new file mode 100644
index 0000000..6234346
--- /dev/null
+++ b/lib/libvirtio/virtio-serial.c
@@ -0,0 +1,202 @@
+/******************************************************************************
+ * Copyright (c) 2016 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * Virtio serial device definitions.
+ * See Virtio 1.0 - 5.3 Console Device, for details
+ */
+#include <stdio.h>
+#include <string.h>
+#include <cpu.h>
+#include <helpers.h>
+#include <byteorder.h>
+#include "virtio.h"
+#include "virtio-serial.h"
+#include "virtio-internal.h"
+
+#define DRIVER_FEATURE_SUPPORT VIRTIO_F_VERSION_1
+#define RX_ELEM_SIZE 4
+#define RX_NUM_ELEMS 128
+
+#define RX_Q 0
+#define TX_Q 1
+
+static struct vqs vq_rx;
+static struct vqs vq_tx;
+static uint16_t last_rx_idx; /* Last index in RX "used" ring */
+
+int virtio_serial_init(struct virtio_device *dev)
+{
+ struct vring_avail *vq_avail;
+ int status = VIRTIO_STAT_ACKNOWLEDGE;
+
+ /* Reset device */
+ virtio_reset_device(dev);
+
+ /* Acknowledge device. */
+ virtio_set_status(dev, status);
+
+ /* Tell HV that we know how to drive the device. */
+ status |= VIRTIO_STAT_DRIVER;
+ virtio_set_status(dev, status);
+
+ if (dev->is_modern) {
+ /* Negotiate features and sets FEATURES_OK if successful */
+ if (virtio_negotiate_guest_features(dev, DRIVER_FEATURE_SUPPORT))
+ goto dev_error;
+
+ virtio_get_status(dev, &status);
+ }
+
+ if (virtio_queue_init_vq(dev, &vq_rx, RX_Q))
+ goto dev_error;
+
+ /* Allocate memory for multiple receive buffers */
+ vq_rx.buf_mem = SLOF_alloc_mem(RX_ELEM_SIZE * RX_NUM_ELEMS);
+ if (!vq_rx.buf_mem) {
+ printf("virtio-serial: Failed to allocate buffers!\n");
+ goto dev_error;
+ }
+
+ /* Prepare receive buffer queue */
+ for (int i = 0; i < RX_NUM_ELEMS; i++) {
+ uint64_t addr = (uint64_t)vq_rx.buf_mem + i * RX_ELEM_SIZE;
+
+ /* Descriptor for data: */
+ virtio_fill_desc(&vq_rx.desc[i], dev->is_modern, addr, 1, VRING_DESC_F_WRITE, 0);
+ vq_rx.avail->ring[i] = virtio_cpu_to_modern16(dev, i);
+ }
+ vq_rx.avail->flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
+ vq_rx.avail->idx = virtio_cpu_to_modern16(dev, RX_NUM_ELEMS);
+ sync();
+
+ last_rx_idx = virtio_modern16_to_cpu(dev, vq_rx.used->idx);
+
+ if (virtio_queue_init_vq(dev, &vq_tx, TX_Q))
+ goto dev_error;
+
+ vq_avail = virtio_get_vring_avail(dev, TX_Q);
+ vq_avail->flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
+ vq_avail->idx = 0;
+
+ /* Tell HV that setup succeeded */
+ status |= VIRTIO_STAT_DRIVER_OK;
+ virtio_set_status(dev, status);
+
+ return 1;
+ dev_error:
+ printf("%s: failed\n", __func__);
+ status |= VIRTIO_STAT_FAILED;
+ virtio_set_status(dev, status);
+ return 0;
+}
+
+void virtio_serial_shutdown(struct virtio_device *dev)
+{
+ /* Quiesce device */
+ virtio_set_status(dev, VIRTIO_STAT_FAILED);
+
+ /* Reset device */
+ virtio_reset_device(dev);
+}
+
+int virtio_serial_putchar(struct virtio_device *dev, char c)
+{
+ struct vring_desc *desc;
+ int id;
+ uint32_t vq_size, time;
+ struct vring_desc *vq_desc;
+ struct vring_avail *vq_avail;
+ struct vring_used *vq_used;
+ volatile uint16_t *current_used_idx;
+ uint16_t last_used_idx, avail_idx;
+
+ vq_size = virtio_get_qsize(dev, TX_Q);
+ vq_desc = virtio_get_vring_desc(dev, TX_Q);
+ vq_avail = virtio_get_vring_avail(dev, TX_Q);
+ vq_used = virtio_get_vring_used(dev, TX_Q);
+
+ avail_idx = virtio_modern16_to_cpu(dev, vq_avail->idx);
+
+ last_used_idx = vq_used->idx;
+ current_used_idx = &vq_used->idx;
+
+ /* Determine descriptor index */
+ id = avail_idx % vq_size;
+
+ /* Set up virtqueue descriptor for header */
+ desc = &vq_desc[id];
+ virtio_fill_desc(desc, dev->is_modern, (uint64_t)&c, 1, 0, 0);
+
+ vq_avail->ring[avail_idx % vq_size] = virtio_cpu_to_modern16 (dev, id);
+ mb();
+ vq_avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1);
+
+ /* Tell HV that the queue is ready */
+ virtio_queue_notify(dev, TX_Q);
+
+ /* Wait for host to consume the descriptor */
+ time = SLOF_GetTimer() + VIRTIO_TIMEOUT;
+ while (*current_used_idx == last_used_idx) {
+ // do something better
+ mb();
+ if (time < SLOF_GetTimer()) {
+ printf("virtio_serial_putchar failed! \n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static uint16_t last_rx_idx; /* Last index in RX "used" ring */
+
+char virtio_serial_getchar(struct virtio_device *dev)
+{
+ int id, idx;
+ char buf[RX_NUM_ELEMS] = {0};
+ uint16_t avail_idx;
+
+ idx = virtio_modern16_to_cpu(dev, vq_rx.used->idx);
+ if (last_rx_idx == idx) {
+ /* Nothing received yet */
+ return 0;
+ }
+
+ id = (virtio_modern32_to_cpu(dev, vq_rx.used->ring[last_rx_idx % vq_rx.size].id) + 1)
+ % vq_rx.size;
+
+ /* Copy data to destination buffer */
+ memcpy(buf, (void *)virtio_modern64_to_cpu(dev, vq_rx.desc[id - 1].addr), RX_ELEM_SIZE);
+
+ /* Move indices to next entries */
+ last_rx_idx = last_rx_idx + 1;
+
+ avail_idx = virtio_modern16_to_cpu(dev, vq_rx.avail->idx);
+ vq_rx.avail->ring[avail_idx % vq_rx.size] = virtio_cpu_to_modern16(dev, id - 1);
+ sync();
+ vq_rx.avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1);
+ sync();
+
+ /* Tell HV that RX queue entry is ready */
+ virtio_queue_notify(dev, RX_Q);
+
+ return buf[0];
+}
+
+int virtio_serial_haschar(struct virtio_device *dev)
+{
+ if (last_rx_idx == virtio_modern16_to_cpu(dev, vq_rx.used->idx))
+ return 0;
+ else
+ return 1;
+}
diff --git a/lib/libvirtio/virtio-serial.h b/lib/libvirtio/virtio-serial.h
new file mode 100644
index 0000000..68af46d
--- /dev/null
+++ b/lib/libvirtio/virtio-serial.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * Copyright (c) 2016 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * Virtio serial device definitions.
+ * See Virtio 1.0 - 5.3 Console Device, for details
+ */
+
+#ifndef _VIRTIO_SERIAL_H
+#define _VIRTIO_SERIAL_H
+
+extern int virtio_serial_init(struct virtio_device *dev);
+extern void virtio_serial_shutdown(struct virtio_device *dev);
+extern int virtio_serial_putchar(struct virtio_device *dev, char c);
+extern char virtio_serial_getchar(struct virtio_device *dev);
+extern int virtio_serial_haschar(struct virtio_device *dev);
+
+#endif /* _VIRTIO_SERIAL_H */
diff --git a/lib/libvirtio/virtio.code b/lib/libvirtio/virtio.code
index 8eec8f0..5cfffcc 100644
--- a/lib/libvirtio/virtio.code
+++ b/lib/libvirtio/virtio.code
@@ -15,6 +15,7 @@
#include <virtio-9p.h>
#include <virtio-scsi.h>
#include <virtio-net.h>
+#include <virtio-serial.h>
/******** core virtio ********/
@@ -165,3 +166,35 @@ PRIM(virtio_X2d_net_X2d_write)
TOS.n = virtionet_write(TOS.a, len);
}
MIRP
+
+/*********** virtio-serial ***********/
+// : virtio-serial-init ( dev -- false | true)
+PRIM(virtio_X2d_serial_X2d_init)
+ void *dev = TOS.a;
+ TOS.u = virtio_serial_init(dev);
+MIRP
+
+// : virtio-serial-shutdown ( dev -- )
+PRIM(virtio_X2d_serial_X2d_shutdown)
+ void *dev = TOS.a; POP;
+ virtio_serial_shutdown(dev);
+MIRP
+
+// : virtio-serial-putchar ( dev char -- )
+PRIM(virtio_X2d_serial_X2d_putchar)
+ unsigned long c = TOS.n; POP;
+ void *dev = TOS.a; POP;
+ virtio_serial_putchar(dev, c);
+MIRP
+
+// : virtio-serial-getchar ( dev -- char)
+PRIM(virtio_X2d_serial_X2d_getchar)
+ void *dev = TOS.a;
+ TOS.n = virtio_serial_getchar(dev);
+MIRP
+
+// : virtio-serial-haschar ( dev -- true | false)
+PRIM(virtio_X2d_serial_X2d_haschar)
+ void *dev = TOS.a;
+ TOS.n = virtio_serial_haschar(dev);
+MIRP
diff --git a/lib/libvirtio/virtio.in b/lib/libvirtio/virtio.in
index 195840e..d2b1641 100644
--- a/lib/libvirtio/virtio.in
+++ b/lib/libvirtio/virtio.in
@@ -33,3 +33,9 @@ cod(virtio-net-open)
cod(virtio-net-close)
cod(virtio-net-read)
cod(virtio-net-write)
+
+cod(virtio-serial-init)
+cod(virtio-serial-shutdown)
+cod(virtio-serial-putchar)
+cod(virtio-serial-getchar)
+cod(virtio-serial-haschar)
--
2.7.4
More information about the SLOF
mailing list