Author: Siro, Mugabi

Category: qemu

Summary:

This entry presents a few examples of using QEMU character devices. [Update Note -- Dec 2016] Original test platform was QEMU v1.0.1 on Ubuntu 12.04 AMD64 (Linux v3.x). Minor revisions in section QEMU Commandline with QEMU v2.7. The old case studies in section Examples may still require tests/updates for QEMU v2.x and Linux v4.x.

Tags: qemu linux virtio debugging/tracing

QEMU Commandline

A QEMU character device or backend implements a framework for data exchange between the host and a QEMU instance, or for user interaction with the VM. Examples of backends include stdio of the QEMU launch terminal, pipes, UNIX domain sockets, UDP and TCP sockets, TTY line disciplines (/dev/tty*), pseudo-terminals (pts(4)), disk files, /dev/null, etc, of the QEMU host machine. See qemu(1) for the full listing.

Typically, a backend is specified for one or more frontends. To support multiple frontends, the backend is used in multiplexing mode. A frontend could refer to a QEMU emulated device or some other facility such as the HMI (or simply monitor).

For QEMU frontend devices, the general format for specifying the backend-frontend pairing is:

  • QEMU command line:

    -chardev BACKEND,OPTS,id=BID
    -device FRONTEND,OPTS,chardev=BID
    
  • HMI commands (hotplugging):

    chardev-add BACKEND,OPTS,id=BID
    device_add FRONTEND,OPTS,id=FID,chardev=BID
    

    and (hot-unplugging):

    device_del FID
    chardev-remove BID
    

where:

  • BID and FID are (arbitrary) identifiers which must start with a letter, and may be followed by a sequence of letters, digits, hyphen, period or underscore. BID is required in order to associate the frontend with the backend. FID is especially useful/convenient for QEMU frontend device hot-unplugging via the HMI.

  • See section Character device options in qemu(1) for the complete list and descriptions of backends and associated options.

  • QEMU frontend devices include "character-like" devices such as the ubiquitous UART and friends (e.g. hw/usb/dev-serial.c), devices under hw/char/, and miscellaneous devices e.g. hw/misc/ivshmem.c. Essentially, these implementations support the "chardev" device property. Different boards/SoCs support different sets of these devices. For example, on x86_64:

    $ qemu-system-x86_64 -device ? 2>&1 | grep -i usb-serial
    name "usb-serial", bus usb-bus
    
    $ qemu-system-x86_64 -device ? |& grep -i ivshmem
    name "ivshmem", bus PCI, desc "Inter-VM shared memory (legacy)"
    name "ivshmem-doorbell", bus PCI, desc "Inter-VM shared memory"
    name "ivshmem-plain", bus PCI, desc "Inter-VM shared memory"
    

    Then to check for the "chardev" device property:

    $ qemu-system-x86_64 -device usb-serial,'?' |& grep chardev
    usb-serial.chardev=str (ID of a chardev to use as a backend)
    
    $ qemu-system-x86_64 -device ivshmem,'?' 2>&1 | grep chardev
    ivshmem.chardev=str (ID of a chardev to use as a backend)
    

Below are a few examples of QEMU character device backend and frontend device command lines:

  • Psuedo-terminal backend with UART device frontend. For example, see Redirecting QEMU Serial Line Terminals:

    -chardev tty,id=pts2,path=/dev/pts/2 \
    -device isa-serial,chardev=pts2
    
  • stdio backend with USB serial device frontend. The "piix3-usb-uhci" device is the USB controller on the PCI bus while "usb-serial" is the actual USB serial dongle to be associated with the stdio backend. See section Guest System Console over USB-serial below:

    -chardev stdio,id=ID \
    -device piix3-usb-uhci \
    -device usb-serial,chardev=ID
    
  • UNIX domain socket backend with the InterVM SHared MEMory (ivshmem) device frontend. See Writing a Linux PCI Device Driver Tutorial:

    -chardev socket,path=/dev/shm/ivshmem,id=ivshmem \
    -device ivshmem,shm=/dev/shm/ivshmem,size=SIZE,chardev=ivshmem
    
  • TCP socket backend with UART device frontend. See Redirecting QEMU Serial Line Terminals:

    -chardev socket,host=192.168.2.1,port=4555,id=gnc0 \
    -device isa-serial,chardev=gnc0
    

The HMI frontend is somewhat special:

In QEMU graphical mode, the HMI is (by default) available on a QEMU SDL Virtual Console (VC) backend (accessible via CTRL+ALT+N, where N is 2, 3,... depending on the setup). In graphical mode, the legacy command line for redirecting the HMI to stdio or some other host terminal interface backend is:

-monitor BACKEND

where BACKEND is stdio, /dev/pts/N, /dev/ttyN, etc.

The -chardev version is:

-chardev BACKEND,id=ID \
-mon chardev=ID,mode=readline,default

where BACKEND is stdio, tty,path=/dev/pts/N, tty,path=/dev/ttyN, etc.

In QEMU nographic mode, i.e. -nographic, the HMI and the guest's serial port system console are automatically multiplexed on the stdio backend. This is scenario presents an example of multiplexing multiple frontends on a single backend. HMI and guest UART multiplexing is also possible in graphical mode via the legacy mon:stdio. The -chardev command line allows multiplexing the HMI with up to three guest serial terminals on stdio or some other host TTY line discipline. An example is presented in section Multiplexing Mode.

See QEMU Serial Port System Console for details of configuring a Linux guest for serial port system console. See Redirecting QEMU Serial Line Terminals for a discussion of using host terminals with QEMU serial lines.

Examples

Multiplexing Mode

-chardev allows multiplexing up to four frontends on a single backend. Specifying mux=on in -chardev BACKEND,mux=on,id=BID,... enables multiplexing mode. Multiple frontends (including the HMI) can be connected to the backend via their chardev=BID property/option. Note that, by default, multiplexing mode is disabled, i.e. mux=off. In this default mode, the backend can only support one frontend. See qemu(1) for more.

Consider the following QEMU command line which multiplexes the HMI frontend, a UART and a USB-serial device on the stdio backend:

$ qemu-system-x86_64 -enable-kvm ... \
    -append "root=/dev/vda1 rw console=ttyS0" \
    -chardev stdio,mux=on,id=char0 \
    -mon chardev=char0,mode=readline,default \
    -device isa-serial,chardev=char0 \
    -device piix4-usb-uhci \
    -device usb-serial,chardev=char0 \
    -nographic

NOTE: The guest configuration presented below may be incomplete. See section Guest System Console over USB-serial for a detailed discussion of guest configuration for USB serial console. Check QEMU Serial Port System Console for examples of UART configuration. Guest platform was Ubuntu 14.04.2 LTS.

  • To allow login on both the UART (/dev/ttyS0) and USB-serial (/dev/ttyUSB0), the following files were prepared in the guest before booting with the QEMU command line shown above:

    $ cat /etc/init/ttyS0.conf 
    # ttyS0 - getty
    start on stopped rc or RUNLEVEL=[12345]
    stop on runlevel [!12345]
    respawn
    exec /sbin/getty -L 115200 ttyS0 vt102
    
    $ cat /etc/init/ttyUSB0.conf 
    # ttyUSB0 - getty
    start on stopped rc or RUNLEVEL=[12345]
    stop on runlevel [!12345]
    respawn
    exec /sbin/getty -L 115200 ttyUSB0 vt102
    
  • Upon guest boot:

     * Stopping ISC DHCP IPv4 server              [ OK ]
     * Restoring resolver state...                [ OK ]
    
    Ubuntu 14.04.2 LTS user ttyS0
    user login:
    

    the frontend interface for guest /dev/ttyS0 was unresponsive to user input against the login(1) prompt. Switching input focus to the HMI and then back, i.e:

    <CTRL+a c>
    
    QEMU 2.6.94 monitor - type 'help' for more information  
    (qemu)
    
    <CTRL+a c>
    
    Ubuntu 14.04.2 LTS user ttyS0
    user login: user
    Password:
    

    fixed the problem and allowed guest login. The following checks in the guest were performed while switching focus between the multiplexed frontend devices and the HMI:

    ~$ tty
    /dev/ttyS0
    
    ~$ ls /dev/ttyS0
    /dev/ttyS0
    
    ~$ ls /dev/ttyUSB0 
    /dev/ttyUSB0
    
    $ lspci | grep -i usb
    00:05.0 USB controller: Intel Corporation 82371AB/EB/MB PIIX4 USB (rev 01)
    
    <CTRL+a c>
    
    (qemu) info chardev 
    parallel0: filename=null
    char0: filename=mux
    char0-base: filename=stdio
    
    (qemu) info usb
    Device 0.2, Port 1, Speed 12 Mb/s, Product QEMU USB Serial
    
    <CTRL+a c> <RETURN>
    
    ~$ tty
    /dev/ttyS0
    
    <CTRL+a c> <RETURN>
    
    Ubuntu 14.04.2 LTS user ttyUSB0
    user login: user
    Password:
    
    ~$ tty
    /dev/ttyUSB0
    
    <CTRL+a c>
    
    (qemu)
    
    <CTRL+a c> <RETURN>
    
    ~$ tty
    /dev/ttyS0
    

KGDB/GDB via QEMU Serial Port

This example illustrates usage of QEMU command line for serial port devices with a case study that simulates remote kernel debugging with KGDB via serial port. Note that with this approach, the point at which debugging the Linux boot process may begin is only after the builtin KGDB I/O driver has been initialized1.

Prepare Linux guest kernel images with debugging info, for example:

$ cd /tmp
$ wget -c http://www.kernel.org/pub/linux/kernel/v3.x/linux-3.11.tar.xz  
$ tar Jxf linux-3.11.tar.xz
$ cd linux-3.11
$ make x86_64_defconfig

This should enable core debugging infrastructure such as CONFIG_DEBUG_KENREL. The run make menuconfig to include the following minimal debugging config for KGDB:

CONFIG_DEBUG_INFO=y
CONFIG_KGDB=y 
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_KDB=y
CONFIG_KGDB_LOW_LEVEL_TRAP=y

In addition, enabling CONFIG_FRAME_POINTER is advisable, although not a requirement. This option inserts code to into the compiled executable which saves the frame information in registers or on the stack at different points which will allow GDB to more accurately construct stack back traces while debugging the kernel. On the other hand, consider leaving CONFIG_DEBUG_RODATA disabled. This option will prevent the use of software breakpoints because it marks certain regions of the kernel's memory space as read-only2.

Of course, several other kernel debugging options exist for use with KGDB/KDB. Please check them out.

$ make -jN
[...]
    OBJCOPY arch/x86/boot/vmlinux.bin
    AS      arch/x86/boot/header.o
    LD      arch/x86/boot/setup.elf
    OBJCOPY arch/x86/boot/setup.bin
    BUILD   arch/x86/boot/bzImage
Setup is 15548 bytes (padded to 15872 bytes).
System is 5311 kB
CRC b17b5d48
Kernel: arch/x86/boot/bzImage is ready  (#1)

Now, consider the following QEMU command line:

$ qemu-system-x86_64 -enable-kvm \
    -kernel /tmp/linux-3.11/arch/x86/boot/bzImage \
    -append "console=tty0 kgdboc=ttyS0,115200 kgdbwait" \
    -chardev pty,id=pty -device isa-serial,chardev=pty

where:

  • console=tty0 results in kernel boot messages appearing on the QEMU SDL VGA display.

  • kgdboc=ttyS0,115200 are the serial port settings for the KGBD I/O driver - in this case, drivers/tty/serial/kgdboc.c. This is the driver enabled when CONFIG_KGDB_SERIAL_CONSOLE was selected. Here, kgdboc uses the first UART specified on QEMU's command line. Its baudrate is set to 115.2 kbps. Check out Documentation/kernel-parameters.txt for more elaborate settings.

  • kgdbwait makes KGDB wait for a debugger connection during booting of a kernel. This option will only be effective if a KGDB I/O driver was builtin the kernel. According to Documentation/DocBook/kgdb.tmpl, this option should follow the kgdboc param - but this restriction has seemingly been fixed.

  • -chardev pty,id=pty tells QEMU that the backend to use is a /dev/pts/N device on the VM host computer. The host will dynamically create a new pseudoterminal slave device. The value against id= is arbitrary.

  • -device isa-serial,chardev=pty tells QEMU that the virtual UART is associated with /dev/pts/N on the host.

Note that upon starting QEMU with the command line above, it quite graciously prints out something like:

char device redirected to /dev/pts/5

to inform the user of the pseudoterminal slave device (pts(4)) in use.

The boot process proceeds until finally stopping at the,

[   0.308102] kgdb: Registered I/O driver kgdboc.
[   0.308512] kgdb: Waiting for connection from remote gdb...

Entering kdb (current=0xffff880016d20000, pid 1) on processor 0 due to Keyboard Entry
[0]kdb>

prompt.

At this point, gdb(1) was then started with:

$ gdb -q /tmp/linux-3.11/vmlinux
Reading symbols from /media/kazi/wdir/linux/kgdb/linux-3.11/vmlinux...done.
(gdb) target remote /dev/pts/5
Remote debugging using /dev/pts/5
kgdb_breakpoint () at kernel/debug/debug_core.c:1014
1014        wmb(); /* Sync point after breakpoint */
(gdb) break do_one_initcall
Breakpoint 1 at 0xffffffff810001f0: file init/main.c, line 679.
(gdb) c
Continuing.

In this instance, stepping was performed against the do_one_initcall function pointer call mechanism as shown below:

KGDB-QEMU-serial

At this stage of boot, do_one_initcall was iterating over a table of function pointers to invoke entry points for builtin drivers i.e. modules whose module_init(x) was registered at compile time as an __initcall(x) (see include/linux/init.h)3.

For example, as soon as the (fn=0xffffffff81d15df4 <mod_init>) function completed, the line "Non-volatile memory driver v1.3" appeared on the QEMU SDL window, and the "Linux agpgart interface v0.103" line got printed out right after execution of (fn=0xffffffff81d15e8d <agp_init>), etc.

Also see QEMU serial port system console for information on configuring a QEMU/Linux guest for system console on serial port. Check out QEMU/GDB and Linux Boot for a discussion on debugging the Linux boot process with QEMU and GDB (and without KGDB).

Guest System Console over USB-serial

This example illustrates usage of standard command line syntax for QEMU USB-serial. A case study on Linux guest system console over USB-to-serial is presented.

Linux Guest Support

  • QEMU includes emulation support for the FTDI FT232BM USB-to-UART device. So, select the following kernel options to enable a login terminal via system console on /dev/ttyUSBN. These options may be built as modules:

    CONFIG_USB_SERIAL
    CONFIG_USB_SERIAL_FTDI_SIO
    

    However, in order to receive Linux boot messages, then the options above, in addition to the one below, will have to be statically builtin:

    CONFIG_USB_SERIAL_CONSOLE=y
    
  • Configure getty(8):

    • SysV init(8) example:

      [root@buildroot ~]# cat /etc/inittab
      [...]
      USB0:1:respawn:/sbin/getty -L 115200 ttyUSB0 vt102
      [...]
      
    • Upstart init(5) example:

      $ cat /etc/init/ttyUSB0.conf 
      # ttyUSB0 - getty
      #
      # This service maintains a getty on ttyUSB0 from the point the system is
      # started until it is shut down again.
      
      start on stopped rc or RUNLEVEL=[12345]
      stop on runlevel [!12345]
      
      respawn
      exec /sbin/getty -L 115200 ttyUSB0 vt102
      
  • The device files also need be present in the guest e.g:

    $ ls -l /dev/ttyUSB0 
    crw------- 1 lumumba tty 188, 0 /dev/ttyUSB0
    
  • Also note that the /etc/securetty file may have to be updated to include ttyUSB0, ttyUSB1, etc, to let SELinux permit login via /dev/ttyUSBN. For example:

    $ cat /etc/securetty | grep -i usb
    # USB dongles
    ttyUSB0
    ttyUSB1
    ttyUSB2
    

QEMU Command Line

$ qemu-system-x86_64 (...) -append "root=/dev/vda1 rw console=ttyUSB0" \
    -chardev stdio,id=ID \
    -device piix3-usb-uhci -device usb-serial,chardev=ID

where the console=ttyUSB0 parameter will result in Linux boot messages getting displayed on USB-serial console on the stdio backend. The "piix3-usb-uhci" device is the USB controller on the PCI bus while "usb-serial" is the actual USB serial dongle to be associated with the stdio backend. Also see Linux Guest System Console on QEMU Serial Port for tips on using different host backends (replacing ttySN in the examples with ttyUSBN).

Guest I/O via Virtio-Serial

This section presents an example that makes use of virtio-serial command line. This case study involves data transfer between guest and host.

Virtio-Serial

Virtio-serial provides an alternative serial port I/O transport protocol for the QEMU/Linux guest. The framework comprises of two parts:

  • A QEMU device that presents a virtio-pci device to the guest

  • The paravirtualized Linux virtio serial device driver enabled when CONFIG_VIRTIO_CONSOLE is selected. This option also serves as a general-purpose serial driver for data transfer between guest and host. Check out QEMU-Virtio for an introduction to Linux guest virtio configuration options.

    Character devices at /dev/vportNpn will be created when the corresponding ports are found, where N is the device number and n is the port number within that device. If specified by the host, a sysfs attributed called name will be populated with a name for the port which can be used by udev(7) scripts to create a symlink to the device.

At the cost of I/O paravirtualization, use of virtio-serial presents some advantages over UART emulation including higher bandwidth and scalability (standard UART emulation limited to 4 ports per guest; virtio-serial can provide 31). It also introduces a number of exotic use cases4.

The virtio-serial device supports the virtconsole and virtserialport device options. virtconsole is used to provide a guest console/terminal while virtserialport may be used for other I/O operations such as file transfer and sending/receiving control messages to/from the guest. The following case study illustrates guest-host data transfer via virtserialport. For an example of using virtconsole, see QEMU Virtio.

Case Study

The example presented here is based on code for virtio-serial tests by Amit Shah (check out git://fedorapeople.org/home/fedora/amitshah/public_git/test-virtserial.git). This demo implements skeleton versions of the auto-virtserial.c and auto-virtserial-guest.c files in that repository.

The virtserial-host.c (skeleton version of auto-virtserial.c) and virtserial-guest.c (skeleton version of auto-virtserial-guest.c) sources can be found here. The virtserial-host.c program is meant for execution within the host environment while the virtserial-guest.c program will run in the guest.

The gist of virtserial-host.c are the file transfer operations by the following two functions:

  • test_host_file_send

    Computes the sha1sum(1) message digest of /tmp/virtserial/host-big-file and stores it in /tmp/virtserial/host-csumfile. It then sends these files to the guest via /tmp/virtserial/test2. The virtserial-guest program receives these files via /dev/virtio-ports/test2, performs a sha1sum(1) against host-big-file and compares it against the contents of host-csumfile to verify the integrity of the data transfer. It then notifies test_host_file_send of the result.

  • test_guest_file_send

    Requests virtserial-guest to send a file named guest-big-file and the file's sha1sum message digest in guest-csumfile. It then verifies the file's integrity by running sha1sum(1) against /tmp/virtserial/guest-big-file and comparing the value against the message digest in /tmp/virtserial/guest-csumfile.

In addition, virtserial-host.c (if compiled with with -DGUEST_SHUTDOWN) includes the guest_shutdown function which sends a shutdown(8) command to the guest.

For the first round of tests, build with:

$ gcc -Wall -O2 -Wno-unused-result virtserial-host.c -o virtserial-host

$ gcc -Wall -O2 -Wno-unused-result virtserial-guest.c -o virtserial-guest

Note that the QEMU host (and development) platform, and Linux guest used to perform the tests presented here were both Ubuntu 12.04 AMD64. Otherwise, the usual (cross-platform) guest runtime considerations (particularly, machine architecture and C library) should be observed5.

First create the /tmp/virtserial directory where the UNIX domain socket QEMU backends will be located, then fire up a QEMU instance with the following virtio-serial options:

$ mkdir /tmp/virtserial

$ qemu-system-x86_64 (...) \
-chardev socket,path=/tmp/virtserial/test0,server,nowait,id=test0 \
-chardev socket,path=/tmp/virtserial/test1,server,nowait,id=test1 \
-chardev socket,path=/tmp/virtserial/test2,server,nowait,id=test2 \
-device virtio-serial \
-device virtconsole,chardev=test0,name=console.0 \
-device virtserialport,chardev=test1,name=test1 \
-device virtserialport,chardev=test2,name=test2

where:

  • test1 and test2 under /tmp/virtserial are the UNIX domain sockets to be used for virtserialport I/O. The test0 socket is not used in this example and is meant for operations on virtconsole.

  • The server option specifies that the socket shall be a listening socket and nowait instructs QEMU that it should not block waiting for a client to connect to the listening socket.

  • The name options against -device virtserialport resulted in:

    lumumba@vm:~$ cat /sys/class/virtio-ports/vport1p0/name 
    console.0
    lumumba@vm:~$ cat /sys/class/virtio-ports/vport1p1/name 
    test1
    lumumba@vm:~$ cat /sys/class/virtio-ports/vport1p2/name 
    test2
    

    upon guest boot. udev(7) then created the following:

    lumumba@vm:~$ ls -l /dev/vport1p*
    crw------- 1 root root 250, 0 /dev/vport1p0
    crw------- 1 root root 250, 1 /dev/vport1p1
    crw------- 1 root root 250, 2 /dev/vport1p2
    
    lumumba@vm:~$ ls -l /dev/virtio-ports/*
    lrwxrwxrwx 1 root root /dev/virtio-ports/console.0 -> ../vport1p0
    lrwxrwxrwx 1 root root /dev/virtio-ports/test1 -> ../vport1p1
    lrwxrwxrwx 1 root root /dev/virtio-ports/test2 -> ../vport1p2
    

    Notice that programs should (probably) rely on opening the symlink files under /dev/virtio-ports/ (whose names correspond to the -device virtserialport,name= values) rather than on the N numbering scheme of /dev/vportNp* which seemingly depends on whether other virtio device options (virt-block, virtio-net, etc) were specified on the QEMU command line. Also recall that /dev/virtio-ports/console.0 (or /dev/vportNp0) remains unused in this demo.

Other checks that may be performed in the guest environment:

lumumba@vm:~$ lspci | grep console
00:05.0 Communication controller: Red Hat, Inc Virtio console

lumumba@vm:~$ basename `readlink /sys/bus/pci/devices/0000\:00\:05.0/virtio1/driver`
virtio_console

lumumba@vm:~$ cat /proc/devices | grep -i virtio
250 virtio-portsdev

## QEMU monitor console
(qemu) info chardev 
parallel0: filename=null
serial0: filename=stdio
serial0-base: filename=stdio
test2: filename=unix:/tmp/virtserial/test2,server
test1: filename=unix:/tmp/virtserial/test1,server
test0: filename=unix:/tmp/virtserial/test0,server

Create /tmp/virtserial/guest-big-file before firing up a virtserial-guest instance. This file will be transfered to the host via /dev/virtio-ports/test2.

lumumba@vm:~$ mkdir /tmp/virtserial

lumumba@vm:~$ dd if=/dev/random of=/tmp/virtserial/guest-big-file bs=100 count=1
0+1 records in
0+1 records out
30 bytes (30 B) copied, 0.000117943 s, 254 kB/s

lumumba@vm:~$ hd /tmp/virtserial/guest-big-file 
00000000  9e 7a 4b ec 3f 30 22 a5  b4 cd 74 00 9e 53 3d 3a  |.zK.?0"...t..S=:|
00000010  e3 e7 00 37 11 bb ee cc  6f 4c e2 57 06 58        |...7....oL.W.X|
0000001e

lumumba@vm:~$ sha1sum /tmp/virtserial/guest-big-file 
8c4712a1ce467dda70285f7a56c3c657d80080ea  /tmp/virtserial/guest-big-file

lumumba@vm:~$ sudo ./virtserial-guest

Then, on the host:

$ ls /tmp/virtserial/
test0  test1  test2

$ dd if=/dev/random of=/tmp/virtserial/host-big-file bs=100 count=1
1+0 records in
1+0 records out
100 bytes (100 B) copied, 0.0170329 s, 5.9 kB/s

$ hd /tmp/virtserial/host-big-file 
00000000  c9 4f 79 d3 41 d3 75 df  d5 73 d6 4d 6c de f5 c5  |.Oy.A.u..s.Ml...|
00000010  cc ab 9f f4 14 bb e9 dc  f7 bc 53 c0 46 42 50 02  |..........S.FBP.|
00000020  b2 a3 0d 7e 08 18 15 cd  80 61 49 9e d0 a2 49 0b  |...~.....aI...I.|
00000030  21 ab c5 72 fb d6 f4 73  00 fa 12 64 7a c9 8c e8  |!..r...s...dz...|
00000040  d6 7f 4f 4e 22 43 21 42  2b f2 77 dc b7 b9 c7 8c  |..ON"C!B+.w.....|
00000050  34 82 52 de 7c 27 75 a4  7c b8 6d b5 da bd f6 18  |4.R.|'u.|.m.....|
00000060  a9 43 5b ee                                       |.C[.|
00000064

$ sudo sha1sum /tmp/virtserial/host-big-file 
8bb40aba0c58b40ebd150c2797fa4af6ae4278d1  /tmp/virtserial/host-big-file

$ sudo ./virtserial-host
Guest is up 1
          test_host_file_send -  enabled (      csum): PASS
         test_guest_file_send -  enabled (      csum): PASS

$ ls /tmp/virtserial/
guest-big-file  host-big-file  test0  test2
guest-csumfile  host-csumfile  test1

$ sudo cat /tmp/virtserial/guest-csumfile 
8c4712a1ce467dda70285f7a56c3c657d80080ea  /tmp/virtserial/guest-big-file

$ sudo hd /tmp/virtserial/guest-big-file 
00000000  9e 7a 4b ec 3f 30 22 a5  b4 cd 74 00 9e 53 3d 3a  |.zK.?0"...t..S=:|
00000010  e3 e7 00 37 11 bb ee cc  6f 4c e2 57 06 58        |...7....oL.W.X|
0000001e

Back on the guest, from a separate terminal or, alternatively, killing the virtserial-guest instance (which is still polling on /dev/virtio-ports/test1 for commands from the host) in order to get back the command prompt:

lumumba@vm:~$ ls /tmp/virtserial/
guest-big-file  guest-csumfile  host-big-file  host-csumfile

lumumba@vm:~$ cat /tmp/virtserial/host-csumfile 
8bb40aba0c58b40ebd150c2797fa4af6ae4278d1  /tmp/virtserial/host-big-file

lumumba@vm:~$ sudo hd /tmp/virtserial/host-big-file 
00000000  c9 4f 79 d3 41 d3 75 df  d5 73 d6 4d 6c de f5 c5  |.Oy.A.u..s.Ml...|
00000010  cc ab 9f f4 14 bb e9 dc  f7 bc 53 c0 46 42 50 02  |..........S.FBP.|
00000020  b2 a3 0d 7e 08 18 15 cd  80 61 49 9e d0 a2 49 0b  |...~.....aI...I.|
00000030  21 ab c5 72 fb d6 f4 73  00 fa 12 64 7a c9 8c e8  |!..r...s...dz...|
00000040  d6 7f 4f 4e 22 43 21 42  2b f2 77 dc b7 b9 c7 8c  |..ON"C!B+.w.....|
00000050  34 82 52 de 7c 27 75 a4  7c b8 6d b5 da bd f6 18  |4.R.|'u.|.m.....|
00000060  a9 43 5b ee                                       |.C[.|
00000064

For the second round of tests, recompile virtserial-host.c on the host with:

$ gcc -Wall -O2 -Wno-unused-result virtserial-host.c -o virtserial-host -DGUEST_SHUTDOWN

Then, make sure that virtserial-guest is running on the guest before executing:

$ sudo ./virtserial-host 
Guest is up 1
          test_host_file_send -  enabled (      csum): PASS
         test_guest_file_send -  enabled (      csum): PASS

This time, after file transfer, the virtserial-host process will send the (priviledged) execution instance of virtserial-guest a shutdown -h now command which will cause the QEMU/Linux VM instance to halt and exit.

More

Virtio-serial includes support for several more features e.g. setting number of ports, using MSI interrupts, etc. For example, see http://fedoraproject.org/wiki/Features/VirtioSerial#How_To_Test

Resources

  • qemu(1)
  • docs/qdev-device-use.txt
  • git://fedorapeople.org/home/fedora/amitshah/public_git/test-virtserial.git

Footnotes

1. There exist several other ways of debugging the Linux kernel with QEMU (and without KGDB) e.g. link. This example is included for illustrating serial port command line usage. [go back]

2. See Documentation/DocBook/kgdb.tmpl for more info on configuring and using KGDB. [go back]

3. See Trevor Woerner's Understanding The Linux Kernel Initcall Mechanism guide (available online). Also check out Placing Functions or Data in Arbitrary Sections for a summary of Trevor's guide. [go back]

4. For example, see link. [go back]

5. For a discussion on cross-platform build issues, you may check out the entries in the GNU/Linux Toolchain page. [go back]