[virtio]: Fake virtio backend

virtio uses a 'backend' abstration to separate device driver
interactions with hardware and interactions with the DDK core.

Introduce a minimal fake backend to allow writing tests of device
drivers. Tests are expected to subclass the Fake backend to intercept
device interactions and provide expected responses to device drivers.

Tested: N/A

Change-Id: I17be1cacca8fd103fbfdbbbec4de9163f0edc727
diff --git a/system/dev/bus/virtio/backends/fake.h b/system/dev/bus/virtio/backends/fake.h
new file mode 100644
index 0000000..01eec43
--- /dev/null
+++ b/system/dev/bus/virtio/backends/fake.h
@@ -0,0 +1,119 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <assert.h>
+#include <initializer_list>
+#include <map>
+#include <set>
+#include <utility>
+#include <unittest/unittest.h>
+#include "backend.h"
+
+namespace virtio {
+
+// FakeBackend allows writing tests of virtio device drivers.
+//
+// Tests may subclass FakeBackend and override certain functions to check device/driver
+// interactions. FakeBackend also provides a small amount of helper functionality itself - it
+// checks the device initialization state machine, tracks valid queues/sizes, and valid config
+// registers.
+class FakeBackend : public Backend {
+  public:
+    ~FakeBackend() override = default;
+
+    zx_status_t Bind() override { return ZX_OK; }
+    void Unbind() override {}
+    bool ReadFeature(uint32_t bit) override { return false; }
+    void SetFeature(uint32_t bit) override { EXPECT_NE(state_, State::DRIVER_OK); }
+    zx_status_t ConfirmFeatures() override { return ZX_OK; }
+    void DriverStatusOk() override {
+        EXPECT_EQ(state_, State::DEVICE_STATUS_ACK);
+        state_ = State::DRIVER_OK;
+    }
+    void DriverStatusAck() override {
+        EXPECT_EQ(state_, State::DEVICE_RESET);
+        state_ = State::DEVICE_STATUS_ACK;
+    }
+    void DeviceReset() override {
+        EXPECT_EQ(state_, State::DEVICE_VOID);
+        state_ = State::DEVICE_RESET;
+    }
+    void DeviceConfigRead(uint16_t offset, uint8_t* value) override {
+        EXPECT_GT(registers8_.count(offset), 0);
+        *value = registers8_[offset];
+    }
+    void DeviceConfigRead(uint16_t offset, uint16_t* value) override {
+        EXPECT_GT(registers16_.count(offset), 0);
+        *value = registers16_[offset];
+    }
+    void DeviceConfigRead(uint16_t offset, uint32_t* value) override {
+        EXPECT_GT(registers32_.count(offset), 0);
+        *value = registers32_[offset];
+    }
+    void DeviceConfigRead(uint16_t offset, uint64_t* value) override {
+        EXPECT_TRUE(0);  // Not Implemented.
+    }
+    void DeviceConfigWrite(uint16_t offset, uint8_t value) override {
+        registers8_[offset] = value;
+    }
+    void DeviceConfigWrite(uint16_t offset, uint16_t value) override {
+        registers16_[offset] = value;
+    }
+    void DeviceConfigWrite(uint16_t offset, uint32_t value) override {
+        registers32_[offset] = value;
+    }
+    void DeviceConfigWrite(uint16_t offset, uint64_t value) override {
+        EXPECT_TRUE(0);  // Not Implemented.
+    }
+    uint16_t GetRingSize(uint16_t index) override {
+        EXPECT_GT(queue_sizes_.count(index), 0);
+        return queue_sizes_[index];
+    }
+    void SetRing(uint16_t index, uint16_t count, zx_paddr_t pa_desc, zx_paddr_t pa_avail,
+                 zx_paddr_t pa_used) override {}
+    void RingKick(uint16_t ring_index) override {
+        EXPECT_EQ(state_, State::DRIVER_OK);
+        EXPECT_GT(queue_sizes_.count(ring_index), 0);
+        kicked_queues_.insert(ring_index);
+    }
+    uint32_t IsrStatus() override { return 0; }
+    zx_status_t InterruptValid() override { return ZX_OK; }
+    zx_status_t WaitForInterrupt() override { return ZX_OK; }
+
+  protected:
+    FakeBackend(std::initializer_list<std::pair<const uint16_t, uint8_t>> registers8,
+                std::initializer_list<std::pair<const uint16_t, uint16_t>> registers16,
+                std::initializer_list<std::pair<const uint16_t, uint32_t>> registers32,
+                std::initializer_list<std::pair<const uint16_t, uint16_t>> queue_sizes):
+        registers8_(registers8), registers16_(registers16), registers32_(registers32),
+        queue_sizes_(queue_sizes) {}
+
+   // Returns true if a queue has been kicked (notified) and clears the notified bit.
+   bool QueueKicked(uint16_t queue_index) {
+     bool is_queue_kicked = (kicked_queues_.count(queue_index));
+     if (is_queue_kicked) {
+       kicked_queues_.erase(queue_index);
+     }
+     return is_queue_kicked;
+   }
+
+  private:
+    enum class State {
+        DEVICE_VOID,
+        DEVICE_RESET,
+        DEVICE_STATUS_ACK,
+        DRIVER_OK,
+    };
+
+    State state_ = State::DEVICE_VOID;
+    std::map<uint16_t, uint8_t> registers8_;
+    std::map<uint16_t, uint16_t> registers16_;
+    std::map<uint16_t, uint32_t> registers32_;
+    std::map<uint16_t, uint16_t> queue_sizes_;
+    std::set<uint16_t> kicked_queues_;
+};
+
+} // namespace virtio