/* * Copyright (c) 2014, ETH Zurich. All rights reserved. * * This file is distributed under the terms in the attached LICENSE file. * If you do not find this file, copies can be found by writing to: * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. */ /* * virtio_mmio.dev * * Virtio over Memory Mapped IO * * From the Virtio Specification, Section 4.2 * */ device virtio_mmio lsbfirst ( addr base ) "Virtio MMIO Transport Specification" { constants virtio_magic width(4) "Little Endian equivalent of the 'virt' string" { magic_value = 0x74726976 "Little Endian equivalent of the 'virt' string"; }; register magic_value addr(base, 0x000) "Magic value for identifying the Virtio device" { val 32 "Has to be 0x74726976"; }; constants virtio_version width(32) "Virtio MMIO Device Versions" { version_invalid = 0x0 "Invalid Version."; version_legacy = 0x1 "The legacy interface is used."; version_virtio10 = 0x2 "Virtio Version 1.0"; }; register version addr(base, 0x004) "Device Version Number" { version 8 "Virtio device interface version"; _ 24 "Reserved"; }; constants virtio_deviceid width(32) "Virtio Device IDs" { reserved = 0x0 "Invalid Device ID"; network_card = 0x1 "Network Interface Device"; block_device = 0x2 "Block Device"; console = 0x3 "Serial Console Device"; entropy_source = 0x4 "Entorpy Source Device (Randomness)"; legacy_balloon = 0x5 "Memory Ballooning Device (legacy)"; io_memory = 0x6 "IO Memory Device"; rpmsg = 0x7 "RPMSG Device"; scsi_host = 0x8 "SCSI Host Device"; transport_9p = 0x9 "9P Transport Device"; mac80211_wlan = 0xA "MAC 802.11 WLAN Device"; rproc_serial = 0xB "RPROC Serial Device"; virtio_caif = 0xC "Virtio CAIF Device"; memory_balloon = 0xD "Memory Ballooning Device"; gpu_device = 0xE "GPU Device"; timer_device = 0xF "Clock / Timer Device"; }; /* * See 5 Device Types for possible values. Value zero (0x0) is used to de- * fine a system memory map with placeholder devices at static, well known * addresses, assigning functions to them depending on user's needs. */ register deviceid addr(base, 0x008) "Virtio Subsystem Device ID" { id 8 "Device ID"; _ 24 "Reserved"; }; register vendorid addr(base, 0x00C) "Virtio Subsystem Vendor ID" { id 32 "Vendor ID"; }; /* * Reading from this register returns 32 consecutive flag bits, first bit * depending on the last value written to DeviceFeaturesSel. Access to this * register returns bits DeviceFeaturesSel * 32 to * (DeviceFeaturesSel * 32) + 31, eg. feature bits 0 to 31 if * DeviceFeaturesSel is set to 0 and features bits 32 to 63 if * DeviceFeaturesSel is set to 1. Also see 2.2 Feature Bits. * * Note: The representation of the actual feature bits depend on the device */ register dev_features addr(base, 0x010) "Flags representing features the device supports" { features 32 "Virtio Features Bits"; }; /* * Writing to this register selects a set of 32 device feature bits accessible * by reading from DeviceFeatures. */ register dev_features_sel addr(base, 0x014) "Device (host) features word selection." { ready 1 "The host has loaded the dev_features register"; _ 30 "Reserved"; selector 1 "Virtio Feature Selector"; }; /* * Writing to this register sets 32 consecutive flag bits, first bit depending * on the last value written to DriverFeaturesSel. Access to this register sets * bits DriverFeaturesSel * 32 to (DriverFeaturesSel * 32) + 31, eg. feature * bits 0 to 31 if DriverFeaturesSel is set to 0 and features bits 32 to 63 * if DriverFeaturesSel is set to 1. Also see 2.2 Feature Bits. * * Note: The representation of the actual feature bits depend on the device */ register driv_features addr(base, 0x020) "Flags representing device features understood and activated by the driver" { features 32 "Virtio Features Bits"; }; register driv_features_sel addr(base, 0x024) "Activated (guest) features word selection" { selector 1 "Virtio Feature Selector"; _ 29 "Reserved"; ready 1 "signal the host that the values are ready"; ack 1 "the host has stored the values"; }; /* * Writing to this register selects the virtual queue that the following * operations on QueueNumMax, QueueNum, QueueReady, QueueDescLow, * QueueDescHigh, QueueAvailLow, QueueAvailHigh, QueueUsedLow and * QueueUsedHigh apply to. The index number of the first queue is zero (0x0). */ register queue_sel addr(base, 0x030) "Virtual queue index" { selector 31 "Virtio Queue Selector"; ready 1 "the host has loaded the registers witht the values"; }; /* * Reading from the register returns the maximum size (number of elements) * of the queue the device is ready to process or zero (0x0) if the queue is * not available. This applies to the queue selected by writing to QueueSel. */ register queue_max addr(base, 0x34) "Maximum virtual queue size" { size 16 "Number ready to process"; }; /* * Queue size is the number of elements in the queue, therefore size of the * Descriptor Table and both Available and Used rings. Writing to this * register notifies the device what size of the queue the driver will use. * This applies to the queue selected by writing to QueueSel. */ register queue_num addr(base, 0x038) "Virtual queue size" { size 16 "Number of elements in queue"; }; /* * Writing one (0x1) to this register notifies the device that the virtual * queue is ready to be used. Reading from this register returns the last * value written to it. Both read and write accesses apply to the queue * selected by writing to QueueSel. */ register queue_ready addr(base, 0x044) "Virtual queue ready bit" { ready 1 "Queue ready bit"; _ 30 "Reserved"; signal 1 "signal the host that something has changed"; }; constants queue width(1) "Queue Ready Bit Values" { ready = 0x1 "The queue is ready to use"; notready = 0x0 "The queue is not ready"; }; /* * Writing a queue index to this register notifies the device that there are * new buffers to process in the queue. */ register queue_notify addr(base, 0x050) "Queue notifier" { index 32 "The queue index with new buffers"; }; /* * Reading from this register returns a bit mask of events that caused the * device interrupt to be asserted. The following events are possible: * * Used Ring Update - bit 0 - the interrupt was asserted because the device * has updated the Used Ring in at least one of the active virtual queues. * * Configuration Change - bit 1 - the interrupt was asserted because the * configuration of the device has changed. */ register interrupt_status addr(base, 0x060) "Interrupt status" { ring_update 1 "The device has updated the used ring"; config_change 1 "The configuration of the device has changed"; _ 30 ""; }; /* * Writing to this register notifies the device that the interrupt has been * handled, as per values for InterruptStatus. * */ register interrupt_ack addr(base, 0x064) "Interrupt acknowledge" { ring_update 1 "The device has updated the used ring"; config_change 1 "The configuration of the device has changed"; _ 30 ""; }; constants device_status width(8) "Reset value" { device_reset = 0x0 "Reset the device"; }; /* * Reading from this register returns the current device status flags. * Writing non-zero values to this register sets the status flags, indicating * the driver progress. Writing zero (0x0) to this register triggers a * device reset. */ register status addr(base, 0x70) { acknowledge 1 "Guest has found the device"; driver 1 "Guest knows how to drive the device"; driver_ok 1 "Driver setup and ready to drive the device"; features_ok 1 "Driver has acknowledged all the features it understands"; _ 3 "Reserved"; failed 1 "Something went wrong"; _ 24 "Reserved"; }; register reset also addr(base, 0x70) { reset 8 "Reset the device"; _ 24 "Reserved"; }; /* * Writing to these two registers (lower 32 bits of the address to QueueDescLow, * higher 32 bits to QueueDescHigh) notifies the device about location of * the Descriptor Table of the queue selected by writing to QueueSel register. */ register queue_desc_lo addr(base, 0x080) "Virtual queue Descriptor Table 64 bit long physical address" { addr 32 "Address of Queue Descriptor Table"; }; register queue_desc_hi addr(base, 0x084) "Virtual queue Descriptor Table 64 bit long physical address" { addr 32 "Address of Queue Descriptor Table"; }; /* * Writing to these two registers (lower 32 bits of the address to * QueueAvailLow, higher 32 bits to QueueAvailHigh) notifies the device * about location of the Available Ring of the queue selected by writing to QueueSel. */ register queue_avail_lo addr(base, 0x090) "Virtual queue Available Ring 64 bit long physical address" { addr 32 "Address of available ring"; }; register queue_avail_hi addr(base, 0x094) "Virtual queue Available Ring 64 bit long physical address" { addr 32 "Address of available ring"; }; /* * Writing to these two registers (lower 32 bits of the address to * QueueUsedLow, higher 32 bits to QueueUsedHigh) notifies the device about * locationof the Used Ring of the queue selected by writing to QueueSel. */ register queue_used_lo addr(base, 0x0a0) "Virtual queue Used Ring 64 bit long physical address" { addr 32 "Address of used ring"; }; register queue_used_hi addr(base, 0x0a4) "Virtual queue Used Ring 64 bit long physical address" { addr 32 "Address of used ring"; }; /* * Changes every time the configuration noticeably changes */ register config_gen addr(base, 0x0fc) "Configuration atomicity value" { value 32 "Value"; }; constants config_offset width(8) "Reset value" { config_offset = 0x100 "Offset of the configuration space"; }; };