xref: /pciutils/lib/emulated.c (revision 61829219)
108609192SPali Rohár /*
208609192SPali Rohár  *	The PCI Library -- Virtual Emulated Config Space Access Functions
308609192SPali Rohár  *
408609192SPali Rohár  *	Copyright (c) 2022 Pali Rohár
508609192SPali Rohár  *
6*61829219SMartin Mares  *	Can be freely distributed and used under the terms of the GNU GPL v2+.
7*61829219SMartin Mares  *
8*61829219SMartin Mares  *	SPDX-License-Identifier: GPL-2.0-or-later
908609192SPali Rohár  */
1008609192SPali Rohár 
1108609192SPali Rohár #include "internal.h"
1208609192SPali Rohár 
1308609192SPali Rohár static u32
ioflg_to_pciflg(pciaddr_t ioflg)1408609192SPali Rohár ioflg_to_pciflg(pciaddr_t ioflg)
1508609192SPali Rohár {
1608609192SPali Rohár   u32 flg = 0;
1708609192SPali Rohár 
1808609192SPali Rohár   if ((ioflg & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_IO)
1908609192SPali Rohár     flg = PCI_BASE_ADDRESS_SPACE_IO;
2008609192SPali Rohár   else if ((ioflg & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_MEM)
2108609192SPali Rohár     {
2208609192SPali Rohár       flg = PCI_BASE_ADDRESS_SPACE_MEMORY;
2308609192SPali Rohár       if (ioflg & PCI_IORESOURCE_MEM_64)
2408609192SPali Rohár         flg |= PCI_BASE_ADDRESS_MEM_TYPE_64;
2508609192SPali Rohár       else
2608609192SPali Rohár         flg |= PCI_BASE_ADDRESS_MEM_TYPE_32;
2708609192SPali Rohár       if (ioflg & PCI_IORESOURCE_PREFETCH)
2808609192SPali Rohár         flg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
2908609192SPali Rohár     }
3008609192SPali Rohár 
3108609192SPali Rohár   return flg;
3208609192SPali Rohár }
3308609192SPali Rohár 
3408609192SPali Rohár static u32
baseres_to_pcires(pciaddr_t addr,pciaddr_t ioflg,int * have_sec,u32 * sec_val)3508609192SPali Rohár baseres_to_pcires(pciaddr_t addr, pciaddr_t ioflg, int *have_sec, u32 *sec_val)
3608609192SPali Rohár {
3708609192SPali Rohár   u32 val = ioflg_to_pciflg(ioflg);
3808609192SPali Rohár 
3908609192SPali Rohár   if (have_sec)
4008609192SPali Rohár     *have_sec = 0;
4108609192SPali Rohár 
4208609192SPali Rohár   if ((val & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO && addr <= 0xffffffff)
4308609192SPali Rohár     val |= addr & PCI_BASE_ADDRESS_IO_MASK;
4408609192SPali Rohár   else if ((val & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY)
4508609192SPali Rohár     {
4608609192SPali Rohár       val |= addr & PCI_BASE_ADDRESS_MEM_MASK;
4708609192SPali Rohár       if ((val & PCI_BASE_ADDRESS_MEM_TYPE_64) && have_sec)
4808609192SPali Rohár         {
4908609192SPali Rohár           *have_sec = 1;
5008609192SPali Rohár           *sec_val = addr >> 32;
5108609192SPali Rohár         }
5208609192SPali Rohár     }
5308609192SPali Rohár 
5408609192SPali Rohár   return val;
5508609192SPali Rohár }
5608609192SPali Rohár 
5708609192SPali Rohár static inline u32
even_baseres_to_pcires(pciaddr_t addr,pciaddr_t ioflg)5808609192SPali Rohár even_baseres_to_pcires(pciaddr_t addr, pciaddr_t ioflg)
5908609192SPali Rohár {
6008609192SPali Rohár   return baseres_to_pcires(addr, ioflg, NULL, NULL);
6108609192SPali Rohár }
6208609192SPali Rohár 
6308609192SPali Rohár static inline u32
odd_baseres_to_pcires(pciaddr_t addr0,pciaddr_t ioflg0,pciaddr_t addr,pciaddr_t ioflg)6408609192SPali Rohár odd_baseres_to_pcires(pciaddr_t addr0, pciaddr_t ioflg0, pciaddr_t addr, pciaddr_t ioflg)
6508609192SPali Rohár {
6608609192SPali Rohár   int have_sec;
6708609192SPali Rohár   u32 val;
6808609192SPali Rohár   baseres_to_pcires(addr0, ioflg0, &have_sec, &val);
6908609192SPali Rohár   if (!have_sec)
7008609192SPali Rohár     val = baseres_to_pcires(addr, ioflg, NULL, NULL);
7108609192SPali Rohár   return val;
7208609192SPali Rohár }
7308609192SPali Rohár 
7408609192SPali Rohár int
pci_emulated_read(struct pci_dev * d,int pos,byte * buf,int len)7508609192SPali Rohár pci_emulated_read(struct pci_dev *d, int pos, byte *buf, int len)
7608609192SPali Rohár {
7708609192SPali Rohár   u32 ht = PCI_HEADER_TYPE_NORMAL;
7808609192SPali Rohár   u32 val = 0;
7908609192SPali Rohár   int i;
8008609192SPali Rohár 
8108609192SPali Rohár   if (pos >= 64)
8208609192SPali Rohár     return 0;
8308609192SPali Rohár 
8408609192SPali Rohár   if (len > 4)
8508609192SPali Rohár     return pci_generic_block_read(d, pos, buf, len);
8608609192SPali Rohár 
8708609192SPali Rohár   if (d->device_class == PCI_CLASS_BRIDGE_PCI)
8808609192SPali Rohár     ht = PCI_HEADER_TYPE_BRIDGE;
8908609192SPali Rohár   else if (d->device_class == PCI_CLASS_BRIDGE_CARDBUS)
9008609192SPali Rohár     ht = PCI_HEADER_TYPE_CARDBUS;
9108609192SPali Rohár 
9208609192SPali Rohár   switch (pos & ~3)
9308609192SPali Rohár     {
9408609192SPali Rohár       case PCI_COMMAND:
9508609192SPali Rohár         for (i = 0; i < 6; i++)
9608609192SPali Rohár           {
9708609192SPali Rohár             if (!d->size[i])
9808609192SPali Rohár               continue;
9908609192SPali Rohár             if ((d->flags[i] & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_IO)
10008609192SPali Rohár               val |= PCI_COMMAND_IO;
10108609192SPali Rohár             else if ((d->flags[i] & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_MEM)
10208609192SPali Rohár               val |= PCI_COMMAND_MEMORY;
10308609192SPali Rohár           }
10408609192SPali Rohár         break;
10508609192SPali Rohár       case PCI_VENDOR_ID:
10608609192SPali Rohár         val = (d->device_id << 16) | d->vendor_id;
10708609192SPali Rohár         break;
10808609192SPali Rohár       case PCI_CLASS_REVISION:
10908609192SPali Rohár         val = (d->device_class << 16) | (d->prog_if << 8) | d->rev_id;
11008609192SPali Rohár         break;
11108609192SPali Rohár       case PCI_CACHE_LINE_SIZE:
11208609192SPali Rohár         val = ht << 16;
11308609192SPali Rohár         break;
11408609192SPali Rohár       case PCI_BASE_ADDRESS_0:
11508609192SPali Rohár         val = even_baseres_to_pcires(d->base_addr[0], d->flags[0]);
11608609192SPali Rohár         break;
11708609192SPali Rohár       case PCI_INTERRUPT_LINE:
11808609192SPali Rohár         val = (d->irq >= 0 && d->irq <= 0xff) ? d->irq : 0;
11908609192SPali Rohár         break;
12008609192SPali Rohár     }
12108609192SPali Rohár 
12208609192SPali Rohár   if ((pos & ~3) == PCI_BASE_ADDRESS_1 && (ht == PCI_HEADER_TYPE_NORMAL || ht == PCI_HEADER_TYPE_BRIDGE))
12308609192SPali Rohár     val = odd_baseres_to_pcires(d->base_addr[0], d->flags[0], d->base_addr[1], d->flags[1]);
12408609192SPali Rohár 
12508609192SPali Rohár   if (ht == PCI_HEADER_TYPE_NORMAL)
12608609192SPali Rohár     switch (pos & ~3)
12708609192SPali Rohár       {
12808609192SPali Rohár         case PCI_BASE_ADDRESS_2:
12908609192SPali Rohár           val = even_baseres_to_pcires(d->base_addr[2], d->flags[2]);
13008609192SPali Rohár           break;
13108609192SPali Rohár         case PCI_BASE_ADDRESS_3:
13208609192SPali Rohár           val = odd_baseres_to_pcires(d->base_addr[2], d->flags[2], d->base_addr[3], d->flags[3]);
13308609192SPali Rohár           break;
13408609192SPali Rohár         case PCI_BASE_ADDRESS_4:
13508609192SPali Rohár           val = even_baseres_to_pcires(d->base_addr[4], d->flags[4]);
13608609192SPali Rohár           break;
13708609192SPali Rohár         case PCI_BASE_ADDRESS_5:
13808609192SPali Rohár           val = odd_baseres_to_pcires(d->base_addr[4], d->flags[4], d->base_addr[5], d->flags[5]);
13908609192SPali Rohár           break;
14008609192SPali Rohár         case PCI_SUBSYSTEM_VENDOR_ID:
14108609192SPali Rohár           val = (d->subsys_id << 16) | d->subsys_vendor_id;
14208609192SPali Rohár           break;
14308609192SPali Rohár         case PCI_ROM_ADDRESS:
14408609192SPali Rohár           val = d->rom_base_addr & PCI_ROM_ADDRESS_MASK;
14508609192SPali Rohár           if (val)
14608609192SPali Rohár             val |= PCI_ROM_ADDRESS_ENABLE;
14708609192SPali Rohár           break;
14808609192SPali Rohár       }
14908609192SPali Rohár   else if (ht == PCI_HEADER_TYPE_BRIDGE)
15008609192SPali Rohár     switch (pos & ~3)
15108609192SPali Rohár       {
15208609192SPali Rohár         case PCI_COMMAND:
15308609192SPali Rohár           if (d->bridge_size[0])
15408609192SPali Rohár             val |= PCI_COMMAND_IO;
15508609192SPali Rohár           if (d->bridge_size[1] || d->bridge_size[2])
15608609192SPali Rohár             val |= PCI_COMMAND_MEMORY;
15708609192SPali Rohár           break;
15808609192SPali Rohár         case PCI_PRIMARY_BUS:
15908609192SPali Rohár           val = d->bus;
16008609192SPali Rohár           break;
16108609192SPali Rohár         case PCI_IO_BASE:
16208609192SPali Rohár           if (d->bridge_size[0])
16308609192SPali Rohár             {
16408609192SPali Rohár               val = (((((d->bridge_base_addr[0] + d->bridge_size[0] - 1) >> 8) & PCI_IO_RANGE_MASK) << 8) & 0xff00) |
16508609192SPali Rohár                     (((d->bridge_base_addr[0] >> 8) & PCI_IO_RANGE_MASK) & 0x00ff);
16608609192SPali Rohár               if ((d->bridge_flags[0] & PCI_IORESOURCE_IO_16BIT_ADDR) &&
16708609192SPali Rohár                   d->bridge_base_addr[0] + d->bridge_size[0] - 1 <= 0xffff)
16808609192SPali Rohár                 val |= (PCI_IO_RANGE_TYPE_16 << 8) | PCI_IO_RANGE_TYPE_16;
16908609192SPali Rohár               else
17008609192SPali Rohár                 val |= (PCI_IO_RANGE_TYPE_32 << 8) | PCI_IO_RANGE_TYPE_32;
17108609192SPali Rohár             }
17208609192SPali Rohár           else
17308609192SPali Rohár             val = 0xff & PCI_IO_RANGE_MASK;
17408609192SPali Rohár           break;
17508609192SPali Rohár         case PCI_MEMORY_BASE:
17608609192SPali Rohár           if (d->bridge_size[1])
17708609192SPali Rohár             val = (((((d->bridge_base_addr[1] + d->bridge_size[1] - 1) >> 16) & PCI_MEMORY_RANGE_MASK) << 16) & 0xffff0000) |
17808609192SPali Rohár                   (((d->bridge_base_addr[1] >> 16) & PCI_MEMORY_RANGE_MASK) & 0x0000ffff);
17908609192SPali Rohár           else
18008609192SPali Rohár             val = 0xffff & PCI_MEMORY_RANGE_MASK;
18108609192SPali Rohár           break;
18208609192SPali Rohár         case PCI_PREF_MEMORY_BASE:
18308609192SPali Rohár           if (d->bridge_size[2])
18408609192SPali Rohár             {
18508609192SPali Rohár               val = (((((d->bridge_base_addr[2] + d->bridge_size[2] - 1) >> 16) & PCI_PREF_RANGE_MASK) << 16) & 0xffff0000) |
18608609192SPali Rohár                     (((d->bridge_base_addr[2] >> 16) & PCI_PREF_RANGE_MASK) & 0x0000ffff);
18708609192SPali Rohár               if ((d->bridge_flags[2] & PCI_IORESOURCE_MEM_64) ||
18808609192SPali Rohár                   d->bridge_base_addr[2] + d->bridge_size[2] - 1 > 0xffffffff)
18908609192SPali Rohár                 val |= (PCI_PREF_RANGE_TYPE_64 << 16) | PCI_PREF_RANGE_TYPE_64;
19008609192SPali Rohár               else
19108609192SPali Rohár                 val |= (PCI_PREF_RANGE_TYPE_32 << 16) | PCI_PREF_RANGE_TYPE_32;
19208609192SPali Rohár             }
19308609192SPali Rohár           else
19408609192SPali Rohár             val = 0xffff & PCI_PREF_RANGE_MASK;
19508609192SPali Rohár           break;
19608609192SPali Rohár         case PCI_PREF_BASE_UPPER32:
19708609192SPali Rohár           if (d->bridge_size[2])
19808609192SPali Rohár             val = d->bridge_base_addr[2] >> 32;
19908609192SPali Rohár           break;
20008609192SPali Rohár         case PCI_PREF_LIMIT_UPPER32:
20108609192SPali Rohár           if (d->bridge_size[2])
20208609192SPali Rohár             val = (d->bridge_base_addr[2] + d->bridge_size[2] - 1) >> 32;
20308609192SPali Rohár           break;
20408609192SPali Rohár         case PCI_IO_BASE_UPPER16:
20508609192SPali Rohár           if (d->bridge_size[0])
20608609192SPali Rohár             val = ((((d->bridge_base_addr[0] + d->bridge_size[0] - 1) >> 16) << 16) & 0xffff0000) |
20708609192SPali Rohár                   ((d->bridge_base_addr[0] >> 16) & 0x0000ffff);
20808609192SPali Rohár           break;
20908609192SPali Rohár         case PCI_ROM_ADDRESS1:
21008609192SPali Rohár           val = d->rom_base_addr & PCI_ROM_ADDRESS_MASK;
21108609192SPali Rohár           if (val)
21208609192SPali Rohár             val |= PCI_ROM_ADDRESS_ENABLE;
21308609192SPali Rohár           break;
21408609192SPali Rohár       }
21508609192SPali Rohár   else if (ht == PCI_HEADER_TYPE_CARDBUS)
21608609192SPali Rohár     switch (pos & ~3)
21708609192SPali Rohár       {
21808609192SPali Rohár         case PCI_COMMAND:
21908609192SPali Rohár           if (d->bridge_size[0] || d->bridge_size[1])
22008609192SPali Rohár             val |= PCI_COMMAND_MEMORY;
22108609192SPali Rohár           if (d->bridge_size[2] || d->bridge_size[3])
22208609192SPali Rohár             val |= PCI_COMMAND_IO;
22308609192SPali Rohár           break;
22408609192SPali Rohár         case PCI_CB_PRIMARY_BUS:
22508609192SPali Rohár           val = d->bus;
22608609192SPali Rohár           break;
22708609192SPali Rohár         case PCI_CB_MEMORY_BASE_0:
22808609192SPali Rohár           if (d->bridge_size[0])
22908609192SPali Rohár             val = d->bridge_base_addr[0] & ~0xfff;
23008609192SPali Rohár           else
23108609192SPali Rohár             val = 0xffffffff & ~0xfff;
23208609192SPali Rohár           break;
23308609192SPali Rohár         case PCI_CB_MEMORY_LIMIT_0:
23408609192SPali Rohár           if (d->bridge_size[0])
23508609192SPali Rohár             val = (d->bridge_base_addr[0] + d->bridge_size[0] - 1) & ~0xfff;
23608609192SPali Rohár           break;
23708609192SPali Rohár         case PCI_CB_MEMORY_BASE_1:
23808609192SPali Rohár           if (d->bridge_size[1])
23908609192SPali Rohár             val = d->bridge_base_addr[1] & ~0xfff;
24008609192SPali Rohár           else
24108609192SPali Rohár             val = 0xffffffff & ~0xfff;
24208609192SPali Rohár           break;
24308609192SPali Rohár         case PCI_CB_MEMORY_LIMIT_1:
24408609192SPali Rohár           if (d->bridge_size[1])
24508609192SPali Rohár             val = (d->bridge_base_addr[1] + d->bridge_size[1] - 1) & ~0xfff;
24608609192SPali Rohár           break;
24708609192SPali Rohár         case PCI_CB_IO_BASE_0:
24808609192SPali Rohár           if (d->bridge_size[2])
24908609192SPali Rohár             {
25008609192SPali Rohár               val = d->bridge_base_addr[2] & PCI_CB_IO_RANGE_MASK;
25108609192SPali Rohár               if ((d->bridge_flags[2] & PCI_IORESOURCE_IO_16BIT_ADDR) ||
25208609192SPali Rohár                   d->bridge_base_addr[2] + d->bridge_size[2] - 1 <= 0xffff)
25308609192SPali Rohár                 val |= PCI_IO_RANGE_TYPE_16;
25408609192SPali Rohár               else
25508609192SPali Rohár                 val |= PCI_IO_RANGE_TYPE_32;
25608609192SPali Rohár             }
25708609192SPali Rohár           else
25808609192SPali Rohár             val = 0x0000ffff & PCI_CB_IO_RANGE_MASK;
25908609192SPali Rohár           break;
26008609192SPali Rohár         case PCI_CB_IO_LIMIT_0:
26108609192SPali Rohár           if (d->bridge_size[2])
26208609192SPali Rohár             val = (d->bridge_base_addr[2] + d->bridge_size[2] - 1) & PCI_CB_IO_RANGE_MASK;
26308609192SPali Rohár           break;
26408609192SPali Rohár         case PCI_CB_IO_BASE_1:
26508609192SPali Rohár           if (d->bridge_size[3])
26608609192SPali Rohár             {
26708609192SPali Rohár               val = d->bridge_base_addr[3] & PCI_CB_IO_RANGE_MASK;
26808609192SPali Rohár               if ((d->bridge_flags[3] & PCI_IORESOURCE_IO_16BIT_ADDR) ||
26908609192SPali Rohár                   d->bridge_base_addr[3] + d->bridge_size[3] - 1 <= 0xffff)
27008609192SPali Rohár                 val |= PCI_IO_RANGE_TYPE_16;
27108609192SPali Rohár               else
27208609192SPali Rohár                 val |= PCI_IO_RANGE_TYPE_32;
27308609192SPali Rohár             }
27408609192SPali Rohár           else
27508609192SPali Rohár             val = 0x0000ffff & PCI_CB_IO_RANGE_MASK;
27608609192SPali Rohár           break;
27708609192SPali Rohár         case PCI_CB_IO_LIMIT_1:
27808609192SPali Rohár           if (d->bridge_size[3])
27908609192SPali Rohár             val = (d->bridge_base_addr[3] + d->bridge_size[3] - 1) & PCI_CB_IO_RANGE_MASK;
28008609192SPali Rohár           break;
28108609192SPali Rohár         case PCI_CB_BRIDGE_CONTROL:
28208609192SPali Rohár           if (d->bridge_flags[0] & PCI_IORESOURCE_PREFETCH)
28308609192SPali Rohár             val |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
28408609192SPali Rohár           if (d->bridge_flags[1] & PCI_IORESOURCE_PREFETCH)
28508609192SPali Rohár             val |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
28608609192SPali Rohár           break;
28708609192SPali Rohár         case PCI_CB_SUBSYSTEM_VENDOR_ID:
28808609192SPali Rohár           val = (d->subsys_id << 16) | d->subsys_vendor_id;
28908609192SPali Rohár           break;
29008609192SPali Rohár       }
29108609192SPali Rohár 
29208609192SPali Rohár   if (len <= 2)
29308609192SPali Rohár     val = (val >> (8 * (pos & 3))) & ((1 << (len * 8)) - 1);
29408609192SPali Rohár 
29508609192SPali Rohár   while (len-- > 0)
29608609192SPali Rohár     {
29708609192SPali Rohár       *(buf++) = val & 0xff;
29808609192SPali Rohár       val >>= 8;
29908609192SPali Rohár     }
30008609192SPali Rohár   return 1;
30108609192SPali Rohár }
302