]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/vmm/server/src/virtio_dev.h
Update
[l4.git] / l4 / pkg / vmm / server / src / virtio_dev.h
1 /*
2  * (c) 2013-2014 Alexander Warg <warg@os.inf.tu-dresden.de>
3  *     economic rights: Technische Universität Dresden (Germany)
4  *
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU General Public License 2.
7  * Please see the COPYING-GPL-2 file for details.
8  */
9 /*
10  * Copyright (C) 2015 Kernkonzept GmbH.
11  * Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com>
12  *
13  * This file is distributed under the terms of the GNU General Public
14  * License, version 2.  Please see the COPYING-GPL-2 file for details.
15  */
16 #pragma once
17
18 #include <l4/l4virtio/virtio.h>
19 #include <l4/l4virtio/server/virtio>
20
21 #include "vm_ram.h"
22
23 namespace Virtio {
24
25 class Virtqueue : public L4virtio::Svr::Virtqueue
26 {
27 public:
28   typedef l4virtio_config_queue_t Queue_config;
29
30   Queue_config config;
31
32   void init_queue(void *base)
33   { setup(config.num, config.align, base); }
34
35 };
36
37
38 class Dev
39 {
40 public:
41   typedef L4virtio::Svr::Dev_status Status;
42   typedef L4virtio::Svr::Dev_features Features;
43
44 protected:
45   l4_uint32_t _vendor;
46   l4_uint32_t _device;
47   l4_uint32_t _irq_status;
48   Status _status;
49   l4_uint32_t _guest_features[8];
50
51   Vmm::Vm_ram *_iommu;
52
53 public:
54   Dev(Vmm::Vm_ram *iommu, l4_uint32_t vendor, l4_uint32_t device)
55   : _vendor(vendor), _device(device), _irq_status(0), _status(0),
56     _iommu(iommu)
57   {
58     memset(_guest_features, 0, sizeof(_guest_features));
59   }
60
61   virtual l4_uint32_t read_config(unsigned /*reg*/) { return 0; }
62   virtual void write_config(unsigned /*reg*/, l4_uint32_t /*value*/) {}
63   virtual void kick() = 0;
64   virtual l4_uint32_t host_feature(unsigned /*id*/) { return 0; }
65   virtual Virtqueue *queue(unsigned idx) = 0;
66   virtual void reset() {}
67
68   l4_uint32_t vendor() const noexcept
69   { return _vendor; }
70
71   l4_uint32_t device() const noexcept
72   { return _device; }
73
74   l4_uint32_t irq_status()
75   {
76     // hack: we have always a queue IRQ
77     return 1;
78     if (0)
79       {
80         l4_uint32_t tmp = _irq_status;
81         _irq_status = 0;
82         return tmp;
83       }
84   }
85
86   Status dev_status() const noexcept
87   { return _status; }
88
89   void set_dev_status(l4_uint32_t status)
90   {
91     _status.raw = status;
92     if (status == 0)
93       reset();
94   }
95
96   l4_uint32_t guest_feature(unsigned idx) noexcept
97   { return (idx < 8) ? _guest_features[idx] : 0; }
98
99   void set_guest_feature(unsigned idx, l4_uint32_t value) noexcept
100   {
101     if (idx < 8)
102       _guest_features[idx] = value;
103   }
104
105   template<typename T>
106   T *devaddr_to_virt(l4_addr_t devaddr) const
107   { return _iommu->access(L4virtio::Ptr<T>(devaddr)); }
108 };
109
110
111 template<typename DEV>
112 class Mmio_connector
113 {
114 public:
115   l4_uint32_t read(unsigned reg, char /*size*/, unsigned)
116   {
117     if (reg >= 0x100)
118       return dev()->read_config(reg - 0x100);
119
120     switch (reg >> 2)
121       {
122       case 0: return *reinterpret_cast<l4_uint32_t const *>("virt");
123       case 1: return 1;
124       case 2: return dev()->device();
125       case 3: return dev()->vendor();
126       case 4: return dev()->host_feature(_current_host_feat);
127       case 13: return _current_q ? _current_q->config.num_max : 0;
128       case 16: return _current_q ? _current_q->config.pfn : 0;
129       case 24: return dev()->irq_status();
130       case 28: return dev()->dev_status().raw;
131       }
132     return ~0U;
133   }
134
135   void write(unsigned reg, char /*size*/, l4_uint32_t value, unsigned)
136   {
137     if (reg >= 0x100)
138       {
139         dev()->write_config(reg - 0x100, value);
140         return;
141       }
142
143     switch (reg >> 2)
144       {
145       case 5:
146         _current_host_feat = value;
147         break;
148
149       case 8:
150         dev()->set_guest_feature(_current_guest_feat, value);
151         break;
152
153       case 9:
154         _current_guest_feat = value;
155         break;
156
157       case 10:
158         _page_size = value;
159         break;
160
161       case 12:
162         _current_q = dev()->queue(value);
163         break;
164
165       case 14:
166         if (_current_q)
167           _current_q->config.num = _current_q->config.num_max >= value
168                                     ? value
169                                     : _current_q->config.num_max;
170         break;
171
172       case 15:
173         if (_current_q)
174           _current_q->config.align = value;
175         break;
176
177       case 16:
178         if (_current_q)
179           {
180             _current_q->config.pfn = value;
181             _current_q->init_queue(dev()->template devaddr_to_virt<void>(value * _page_size));
182           }
183         break;
184
185       case 20:
186         dev()->kick();
187         break;
188
189       case 25:
190         break;
191
192       case 28:
193         dev()->set_dev_status(value);
194         break;
195       }
196   }
197
198 private:
199   DEV *dev()
200   { return static_cast<DEV *>(this); }
201
202   Virtqueue *_current_q = 0;
203   unsigned _current_host_feat = 0;
204   unsigned _current_guest_feat = 0;
205   l4_uint32_t _page_size = 1 << 12;
206 };
207
208 }