# Virtual I/Os

Emulated CPUs in Dusk OS have a "hook" indirection that is called at each
instruction ran. This hook is there mostly for Virtual I/Os, which is a
structure that uses memory shared by the host and the guest to allow serial I/O
and mass storage access.

Through this memory area, the guest and the host send commands to each other.
The area is 8b in size and has this structure:

1b index of command coming from the guest
3b argument (little endian)
1b index of command coming from the host
3b argument (little endian)

List of guest command IDs:

1. Serial out              Arg: character
2. Set sector ptr          Arg: guest address where sectors go
3. Set sector size         Arg: size in bytes (default 512)
4. Read a sector           Arg: sector number
5. Write a sector          Arg: sector number
6. Exit :enter             Arg: none

List of host command IDs:

1. Serial in              Arg: character

The role of this unit is to act as an indirection mechanism for those commands
to be fulfilled by plugging adequate IO and File structs in it. It does so
through the VirtIO struct.

The host is able to process commands between each instruction, so from the point
of view of the guest, command processing is instant, no need to implement any
status polling mechanism.

In the other direction, it's another matter. If the host needs to send a command
to the guest but that the command field is nonzero, it will block and run the
CPU until the command is processed by the guest.

Therefore, an important point to remember: if you want to keep a tight control
over how the emulated CPU is ran, be careful of the way you send commands to the
associated VirtIO.

## Serial communication

Outgoing communications are simply funneled to "out :putc".

For incoming communication, just write to the virtio struct which is a stream
[doc/io/stream]. If you try to write more than one byte at once, "writebuf"
will block and cycle the cpu until all bytes are written.

## Sector read and write

Sector seeking is simply done by doing "block number * sector size" and then
read or writing "sector size" bytes into/from guest's pointer.

## Interactive mode

Instead of writing contents to the VirtIO struct, you can enter in interactive
mode with it with "enter". This will loop forever, waiting for input and then
sending it to the VirtIO. Between each character sent, we call "cpu run".

The software you run through this method should be VirtIO aware for "enter" to
work well, that is:

1. When it's waiting for a key, it should halt.
2. When it wants to exit the "enter" loop, it should send a CMD6.

## API

### Struct

extends Stream struct VirtIO
  fields cpu cmdptr out storage secsz secptr shouldexit
endstruct

cpu       A pointer to a CPU (see [doc/emul/cpu]) struct.
cmdptr    A pointer to a *host* address where to check for commands.
out       A pointer to the IO receiving outgoing communications.
storage   A pointer to a File struct that is a src/dst for sectors.
secsz     Sector size, defaults to 512
secptr    A pointer to a *host* address for sector's src/dst.

### Words

cansend? ( virtio -- f )
  Yields whether the host-to-guest command buffer is empty.

process ( virtio -- )
  Process stuff, that is, check if a command has been issued from the guest. If
  yes, process it and set the command field to zero.

newvirtio ( storage out cmd mem -- virtio )
  Allocate a new virtio with specified initial values for fields. It also sets
  the cpu's "hook" value to its process method.
