]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/vbus.cc
d8185d67470d70a32bd4086f1aae7d867edd3813
[l4.git] / l4 / pkg / io / server / src / vbus.cc
1 /*
2  * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *          Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #include <l4/re/protocols>
11
12 #include <l4/cxx/ipc_server>
13 #include <l4/cxx/iostream>
14 #include <l4/cxx/l4iostream>
15
16 #include <l4/re/env>
17 #include <l4/re/namespace>
18 #include <l4/re/dataspace-sys.h>
19
20 #include <l4/re/error_helper>
21
22 #include <l4/vbus/vbus_types.h>
23 #include <l4/vbus/vdevice-ops.h>
24
25 #include <cstdio>
26
27 #include "vbus.h"
28 #include "vicu.h"
29 #include "server.h"
30 #include "res.h"
31 #include "cfg.h"
32 #include "vbus_factory.h"
33
34 namespace {
35
36 class Root_irq_rs : public Resource_space
37 {
38 private:
39   Vi::System_bus *_bus;
40   Vi::Sw_icu *_icu;
41
42 public:
43   Root_irq_rs(Vi::System_bus *bus) : Resource_space(), _bus(bus), _icu(0)
44   {}
45
46   bool request(Resource *parent, Device *, Resource *child, Device *)
47   {
48     // printf("VBUS: IRQ resource request: "); child->dump();
49     Adr_resource *r = dynamic_cast<Adr_resource*>(child);
50     if (!r || !parent)
51       return false;
52
53     if (!_icu)
54       {
55         _icu = new Vi::Sw_icu();
56         _bus->add_child(_icu);
57       }
58
59     _icu->add_irqs(r);
60     _bus->resource_set()->insert(r);
61
62     return true;
63   };
64
65   bool alloc(Resource *, Device *, Resource *, Device *, bool)
66   { return false; }
67
68   ~Root_irq_rs() {}
69 };
70
71 class Root_x_rs : public Resource_space
72 {
73 private:
74   Vi::System_bus *_bus;
75
76 public:
77   Root_x_rs(Vi::System_bus *bus) : Resource_space(), _bus(bus)
78   {}
79
80   bool request(Resource *parent, Device *, Resource *child, Device *)
81   {
82     //printf("VBUS: X resource request: "); child->dump();
83     Adr_resource *r = dynamic_cast<Adr_resource*>(child);
84     if (!r || !parent)
85       return false;
86
87
88     _bus->resource_set()->insert(r);
89     return true;
90   }
91
92   bool alloc(Resource *, Device *, Resource *, Device *, bool)
93   { return false; }
94
95   ~Root_x_rs() {}
96 };
97 }
98
99
100
101 namespace Vi {
102
103 bool
104 System_bus::resource_allocated(Resource const *_r) const
105 {
106   Adr_resource const *r = dynamic_cast<Adr_resource const *>(_r);
107   if (!r)
108     return false;
109
110   Resource_set::const_iterator i = _resources.find(const_cast<Adr_resource*>(r));
111   if (i == _resources.end())
112     return false;
113
114   if ((*i)->data().start() <= r->data().start()
115       && (*i)->data().end() >= r->data().end())
116     return true;
117
118   return false;
119 }
120
121
122 System_bus::System_bus()
123 {
124   add_feature(this);
125   add_resource(new Root_resource(Resource::Irq_res, new Root_irq_rs(this)));
126   Resource_space *x = new Root_x_rs(this);
127   add_resource(new Root_resource(Resource::Mmio_res, x));
128   add_resource(new Root_resource(Resource::Mmio_res | Resource::F_prefetchable, x));
129   add_resource(new Root_resource(Resource::Io_res, x));
130 }
131
132 System_bus::~System_bus()
133 {
134   registry->unregister_obj(this);
135   // FIXME: must delete all devices
136 }
137
138
139 void
140 System_bus::dump_resources() const
141 {
142   for (Resource_set::const_iterator i = _resources.begin(); i != _resources.end(); ++i)
143     (*i)->dump();
144 }
145
146 int
147 System_bus::request_resource(L4::Ipc_iostream &ios)
148 {
149   l4vbus_resource_t res;
150   ios.get(res);
151
152   ::Adr_resource ires(res.type, res.start, res.end);
153   if (Io_config::cfg->verbose() > 1)
154     {
155       printf("request resource: ");
156       Adr_resource(ires).dump();
157       puts("");
158     }
159
160   Resource_set::const_iterator i = _resources.find(&ires);
161 #if 0
162   for (Resource_set::Const_iterator m = _resources.begin(); m != _resources.end(); ++m)
163     {
164       m->dump();
165       puts("");
166     }
167 #endif
168
169   if (i == _resources.end() || !(*i)->contains(ires))
170     return -L4_ENOENT;
171
172 #if 0
173   if (Io_config::cfg->verbose() > 1)
174     {
175       printf("  found resource: ");
176       i->dump();
177       puts("");
178     }
179 #endif
180
181   if (res.type == L4VBUS_RESOURCE_PORT)
182     {
183       l4_uint64_t sz = res.end + 1 - res.start;
184
185       int szl2 = 0;
186       while ((1UL << szl2) < sz)
187         ++szl2;
188
189       if ((1UL << szl2) > sz)
190         --szl2;
191
192       ios << L4::Snd_fpage::io(res.start, szl2, L4_FPAGE_RWX);
193       return L4_EOK;
194     }
195
196
197   return -L4_ENOENT;
198 }
199
200 int
201 System_bus::request_iomem(L4::Ipc_iostream &ios)
202 {
203   L4::Opcode op;
204   ios >> op;
205   switch (op)
206     {
207     case L4Re::Dataspace_::Map:
208         {
209           l4_addr_t offset, spot;
210           unsigned long flags;
211           ios >> offset >> spot >> flags;
212
213 //        printf("map iomem: %lx...\n", offset);
214           Adr_resource pivot(L4VBUS_RESOURCE_MEM, offset, offset);
215           Resource_set::iterator r = _resources.find(&pivot);
216
217           if (r == _resources.end())
218             return -L4_ERANGE;
219
220           offset = l4_trunc_page(offset);
221
222           l4_addr_t st = l4_trunc_page((*r)->start());
223           l4_addr_t adr = (*r)->map_iomem();
224
225           if (!adr)
226             return -L4_ENOMEM;
227
228           adr = l4_trunc_page(adr);
229
230           l4_addr_t addr = offset - st + adr;
231           unsigned char order
232             = l4_fpage_max_order(L4_PAGESHIFT,
233                                  addr, addr, addr + (*r)->size(), spot);
234
235           // we also might want to do WB instead of UNCACHED...
236           ios << L4::Snd_fpage::mem(l4_trunc_size(addr, order), order,
237                                     L4_FPAGE_RWX, l4_trunc_page(spot),
238                                     L4::Snd_fpage::Map,
239                                     L4::Snd_fpage::Uncached);
240           return L4_EOK;
241         }
242     }
243   return -L4_ENOSYS;
244 };
245
246 int
247 System_bus::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
248 {
249   l4_msgtag_t tag;
250   ios >> tag;
251
252   if (tag.label() == 0)
253     {
254       l4vbus_device_handle_t devid;
255       l4_uint32_t func;
256       ios >> devid >> func;
257       Device *dev = get_dev_by_id(devid);
258       if (!dev)
259         return -L4_ENODEV;
260       return dev->vdevice_dispatch(obj, func, ios);
261     }
262
263   if (tag.label() == L4Re::Protocol::Dataspace)
264     return request_iomem(ios);
265
266   return -L4_EBADPROTO;
267
268 }
269
270 int
271 System_bus::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios)
272 {
273   switch (func)
274     {
275     case L4vbus_vbus_request_resource:
276       return request_resource(ios);
277     default:
278       return -L4_ENOSYS;
279     }
280 }
281
282
283 static Dev_factory_t<System_bus> __sb_root_factory("System_bus");
284
285 }