]> mj.ucw.cz Git - pciutils.git/blob - lib/emulated.c
Released as 3.9.0
[pciutils.git] / lib / emulated.c
1 /*
2  *      The PCI Library -- Virtual Emulated Config Space Access Functions
3  *
4  *      Copyright (c) 2022 Pali Rohár
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL.
7  */
8
9 #include "internal.h"
10
11 static u32
12 ioflg_to_pciflg(pciaddr_t ioflg)
13 {
14   u32 flg = 0;
15
16   if ((ioflg & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_IO)
17     flg = PCI_BASE_ADDRESS_SPACE_IO;
18   else if ((ioflg & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_MEM)
19     {
20       flg = PCI_BASE_ADDRESS_SPACE_MEMORY;
21       if (ioflg & PCI_IORESOURCE_MEM_64)
22         flg |= PCI_BASE_ADDRESS_MEM_TYPE_64;
23       else
24         flg |= PCI_BASE_ADDRESS_MEM_TYPE_32;
25       if (ioflg & PCI_IORESOURCE_PREFETCH)
26         flg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
27     }
28
29   return flg;
30 }
31
32 static u32
33 baseres_to_pcires(pciaddr_t addr, pciaddr_t ioflg, int *have_sec, u32 *sec_val)
34 {
35   u32 val = ioflg_to_pciflg(ioflg);
36
37   if (have_sec)
38     *have_sec = 0;
39
40   if ((val & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO && addr <= 0xffffffff)
41     val |= addr & PCI_BASE_ADDRESS_IO_MASK;
42   else if ((val & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY)
43     {
44       val |= addr & PCI_BASE_ADDRESS_MEM_MASK;
45       if ((val & PCI_BASE_ADDRESS_MEM_TYPE_64) && have_sec)
46         {
47           *have_sec = 1;
48           *sec_val = addr >> 32;
49         }
50     }
51
52   return val;
53 }
54
55 static inline u32
56 even_baseres_to_pcires(pciaddr_t addr, pciaddr_t ioflg)
57 {
58   return baseres_to_pcires(addr, ioflg, NULL, NULL);
59 }
60
61 static inline u32
62 odd_baseres_to_pcires(pciaddr_t addr0, pciaddr_t ioflg0, pciaddr_t addr, pciaddr_t ioflg)
63 {
64   int have_sec;
65   u32 val;
66   baseres_to_pcires(addr0, ioflg0, &have_sec, &val);
67   if (!have_sec)
68     val = baseres_to_pcires(addr, ioflg, NULL, NULL);
69   return val;
70 }
71
72 int
73 pci_emulated_read(struct pci_dev *d, int pos, byte *buf, int len)
74 {
75   u32 ht = PCI_HEADER_TYPE_NORMAL;
76   u32 val = 0;
77   int i;
78
79   if (pos >= 64)
80     return 0;
81
82   if (len > 4)
83     return pci_generic_block_read(d, pos, buf, len);
84
85   if (d->device_class == PCI_CLASS_BRIDGE_PCI)
86     ht = PCI_HEADER_TYPE_BRIDGE;
87   else if (d->device_class == PCI_CLASS_BRIDGE_CARDBUS)
88     ht = PCI_HEADER_TYPE_CARDBUS;
89
90   switch (pos & ~3)
91     {
92       case PCI_COMMAND:
93         for (i = 0; i < 6; i++)
94           {
95             if (!d->size[i])
96               continue;
97             if ((d->flags[i] & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_IO)
98               val |= PCI_COMMAND_IO;
99             else if ((d->flags[i] & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_MEM)
100               val |= PCI_COMMAND_MEMORY;
101           }
102         break;
103       case PCI_VENDOR_ID:
104         val = (d->device_id << 16) | d->vendor_id;
105         break;
106       case PCI_CLASS_REVISION:
107         val = (d->device_class << 16) | (d->prog_if << 8) | d->rev_id;
108         break;
109       case PCI_CACHE_LINE_SIZE:
110         val = ht << 16;
111         break;
112       case PCI_BASE_ADDRESS_0:
113         val = even_baseres_to_pcires(d->base_addr[0], d->flags[0]);
114         break;
115       case PCI_INTERRUPT_LINE:
116         val = (d->irq >= 0 && d->irq <= 0xff) ? d->irq : 0;
117         break;
118     }
119
120   if ((pos & ~3) == PCI_BASE_ADDRESS_1 && (ht == PCI_HEADER_TYPE_NORMAL || ht == PCI_HEADER_TYPE_BRIDGE))
121     val = odd_baseres_to_pcires(d->base_addr[0], d->flags[0], d->base_addr[1], d->flags[1]);
122
123   if (ht == PCI_HEADER_TYPE_NORMAL)
124     switch (pos & ~3)
125       {
126         case PCI_BASE_ADDRESS_2:
127           val = even_baseres_to_pcires(d->base_addr[2], d->flags[2]);
128           break;
129         case PCI_BASE_ADDRESS_3:
130           val = odd_baseres_to_pcires(d->base_addr[2], d->flags[2], d->base_addr[3], d->flags[3]);
131           break;
132         case PCI_BASE_ADDRESS_4:
133           val = even_baseres_to_pcires(d->base_addr[4], d->flags[4]);
134           break;
135         case PCI_BASE_ADDRESS_5:
136           val = odd_baseres_to_pcires(d->base_addr[4], d->flags[4], d->base_addr[5], d->flags[5]);
137           break;
138         case PCI_SUBSYSTEM_VENDOR_ID:
139           val = (d->subsys_id << 16) | d->subsys_vendor_id;
140           break;
141         case PCI_ROM_ADDRESS:
142           val = d->rom_base_addr & PCI_ROM_ADDRESS_MASK;
143           if (val)
144             val |= PCI_ROM_ADDRESS_ENABLE;
145           break;
146       }
147   else if (ht == PCI_HEADER_TYPE_BRIDGE)
148     switch (pos & ~3)
149       {
150         case PCI_COMMAND:
151           if (d->bridge_size[0])
152             val |= PCI_COMMAND_IO;
153           if (d->bridge_size[1] || d->bridge_size[2])
154             val |= PCI_COMMAND_MEMORY;
155           break;
156         case PCI_PRIMARY_BUS:
157           val = d->bus;
158           break;
159         case PCI_IO_BASE:
160           if (d->bridge_size[0])
161             {
162               val = (((((d->bridge_base_addr[0] + d->bridge_size[0] - 1) >> 8) & PCI_IO_RANGE_MASK) << 8) & 0xff00) |
163                     (((d->bridge_base_addr[0] >> 8) & PCI_IO_RANGE_MASK) & 0x00ff);
164               if ((d->bridge_flags[0] & PCI_IORESOURCE_IO_16BIT_ADDR) &&
165                   d->bridge_base_addr[0] + d->bridge_size[0] - 1 <= 0xffff)
166                 val |= (PCI_IO_RANGE_TYPE_16 << 8) | PCI_IO_RANGE_TYPE_16;
167               else
168                 val |= (PCI_IO_RANGE_TYPE_32 << 8) | PCI_IO_RANGE_TYPE_32;
169             }
170           else
171             val = 0xff & PCI_IO_RANGE_MASK;
172           break;
173         case PCI_MEMORY_BASE:
174           if (d->bridge_size[1])
175             val = (((((d->bridge_base_addr[1] + d->bridge_size[1] - 1) >> 16) & PCI_MEMORY_RANGE_MASK) << 16) & 0xffff0000) |
176                   (((d->bridge_base_addr[1] >> 16) & PCI_MEMORY_RANGE_MASK) & 0x0000ffff);
177           else
178             val = 0xffff & PCI_MEMORY_RANGE_MASK;
179           break;
180         case PCI_PREF_MEMORY_BASE:
181           if (d->bridge_size[2])
182             {
183               val = (((((d->bridge_base_addr[2] + d->bridge_size[2] - 1) >> 16) & PCI_PREF_RANGE_MASK) << 16) & 0xffff0000) |
184                     (((d->bridge_base_addr[2] >> 16) & PCI_PREF_RANGE_MASK) & 0x0000ffff);
185               if ((d->bridge_flags[2] & PCI_IORESOURCE_MEM_64) ||
186                   d->bridge_base_addr[2] + d->bridge_size[2] - 1 > 0xffffffff)
187                 val |= (PCI_PREF_RANGE_TYPE_64 << 16) | PCI_PREF_RANGE_TYPE_64;
188               else
189                 val |= (PCI_PREF_RANGE_TYPE_32 << 16) | PCI_PREF_RANGE_TYPE_32;
190             }
191           else
192             val = 0xffff & PCI_PREF_RANGE_MASK;
193           break;
194         case PCI_PREF_BASE_UPPER32:
195           if (d->bridge_size[2])
196             val = d->bridge_base_addr[2] >> 32;
197           break;
198         case PCI_PREF_LIMIT_UPPER32:
199           if (d->bridge_size[2])
200             val = (d->bridge_base_addr[2] + d->bridge_size[2] - 1) >> 32;
201           break;
202         case PCI_IO_BASE_UPPER16:
203           if (d->bridge_size[0])
204             val = ((((d->bridge_base_addr[0] + d->bridge_size[0] - 1) >> 16) << 16) & 0xffff0000) |
205                   ((d->bridge_base_addr[0] >> 16) & 0x0000ffff);
206           break;
207         case PCI_ROM_ADDRESS1:
208           val = d->rom_base_addr & PCI_ROM_ADDRESS_MASK;
209           if (val)
210             val |= PCI_ROM_ADDRESS_ENABLE;
211           break;
212       }
213   else if (ht == PCI_HEADER_TYPE_CARDBUS)
214     switch (pos & ~3)
215       {
216         case PCI_COMMAND:
217           if (d->bridge_size[0] || d->bridge_size[1])
218             val |= PCI_COMMAND_MEMORY;
219           if (d->bridge_size[2] || d->bridge_size[3])
220             val |= PCI_COMMAND_IO;
221           break;
222         case PCI_CB_PRIMARY_BUS:
223           val = d->bus;
224           break;
225         case PCI_CB_MEMORY_BASE_0:
226           if (d->bridge_size[0])
227             val = d->bridge_base_addr[0] & ~0xfff;
228           else
229             val = 0xffffffff & ~0xfff;
230           break;
231         case PCI_CB_MEMORY_LIMIT_0:
232           if (d->bridge_size[0])
233             val = (d->bridge_base_addr[0] + d->bridge_size[0] - 1) & ~0xfff;
234           break;
235         case PCI_CB_MEMORY_BASE_1:
236           if (d->bridge_size[1])
237             val = d->bridge_base_addr[1] & ~0xfff;
238           else
239             val = 0xffffffff & ~0xfff;
240           break;
241         case PCI_CB_MEMORY_LIMIT_1:
242           if (d->bridge_size[1])
243             val = (d->bridge_base_addr[1] + d->bridge_size[1] - 1) & ~0xfff;
244           break;
245         case PCI_CB_IO_BASE_0:
246           if (d->bridge_size[2])
247             {
248               val = d->bridge_base_addr[2] & PCI_CB_IO_RANGE_MASK;
249               if ((d->bridge_flags[2] & PCI_IORESOURCE_IO_16BIT_ADDR) ||
250                   d->bridge_base_addr[2] + d->bridge_size[2] - 1 <= 0xffff)
251                 val |= PCI_IO_RANGE_TYPE_16;
252               else
253                 val |= PCI_IO_RANGE_TYPE_32;
254             }
255           else
256             val = 0x0000ffff & PCI_CB_IO_RANGE_MASK;
257           break;
258         case PCI_CB_IO_LIMIT_0:
259           if (d->bridge_size[2])
260             val = (d->bridge_base_addr[2] + d->bridge_size[2] - 1) & PCI_CB_IO_RANGE_MASK;
261           break;
262         case PCI_CB_IO_BASE_1:
263           if (d->bridge_size[3])
264             {
265               val = d->bridge_base_addr[3] & PCI_CB_IO_RANGE_MASK;
266               if ((d->bridge_flags[3] & PCI_IORESOURCE_IO_16BIT_ADDR) ||
267                   d->bridge_base_addr[3] + d->bridge_size[3] - 1 <= 0xffff)
268                 val |= PCI_IO_RANGE_TYPE_16;
269               else
270                 val |= PCI_IO_RANGE_TYPE_32;
271             }
272           else
273             val = 0x0000ffff & PCI_CB_IO_RANGE_MASK;
274           break;
275         case PCI_CB_IO_LIMIT_1:
276           if (d->bridge_size[3])
277             val = (d->bridge_base_addr[3] + d->bridge_size[3] - 1) & PCI_CB_IO_RANGE_MASK;
278           break;
279         case PCI_CB_BRIDGE_CONTROL:
280           if (d->bridge_flags[0] & PCI_IORESOURCE_PREFETCH)
281             val |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
282           if (d->bridge_flags[1] & PCI_IORESOURCE_PREFETCH)
283             val |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
284           break;
285         case PCI_CB_SUBSYSTEM_VENDOR_ID:
286           val = (d->subsys_id << 16) | d->subsys_vendor_id;
287           break;
288       }
289
290   if (len <= 2)
291     val = (val >> (8 * (pos & 3))) & ((1 << (len * 8)) - 1);
292
293   while (len-- > 0)
294     {
295       *(buf++) = val & 0xff;
296       val >>= 8;
297     }
298   return 1;
299 }