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