Annotation of qemu/hw/piix_pci.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * QEMU i440FX/PIIX3 PCI Bridge Emulation
                      3:  *
                      4:  * Copyright (c) 2006 Fabrice Bellard
                      5:  * 
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: 
                     25: #include "vl.h"
                     26: typedef uint32_t pci_addr_t;
                     27: #include "pci_host.h"
                     28: 
                     29: typedef PCIHostState I440FXState;
                     30: 
                     31: static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val)
                     32: {
                     33:     I440FXState *s = opaque;
                     34:     s->config_reg = val;
                     35: }
                     36: 
                     37: static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
                     38: {
                     39:     I440FXState *s = opaque;
                     40:     return s->config_reg;
                     41: }
                     42: 
1.1.1.2 ! root       43: static void piix3_set_irq(void *pic, int irq_num, int level);
1.1       root       44: 
1.1.1.2 ! root       45: /* return the global irq number corresponding to a given device irq
        !            46:    pin. We could also use the bus number to have a more precise
        !            47:    mapping. */
        !            48: static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
        !            49: {
        !            50:     int slot_addend;
        !            51:     slot_addend = (pci_dev->devfn >> 3) - 1;
        !            52:     return (irq_num + slot_addend) & 3;
        !            53: }
        !            54: 
        !            55: static uint32_t isa_page_descs[384 / 4];
        !            56: static uint8_t smm_enabled;
        !            57: 
        !            58: static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r)
        !            59: {
        !            60:     uint32_t addr;
        !            61: 
        !            62:     //    printf("ISA mapping %08x-0x%08x: %d\n", start, end, r);
        !            63:     switch(r) {
        !            64:     case 3:
        !            65:         /* RAM */
        !            66:         cpu_register_physical_memory(start, end - start, 
        !            67:                                      start);
        !            68:         break;
        !            69:     case 1:
        !            70:         /* ROM (XXX: not quite correct) */
        !            71:         cpu_register_physical_memory(start, end - start, 
        !            72:                                      start | IO_MEM_ROM);
        !            73:         break;
        !            74:     case 2:
        !            75:     case 0:
        !            76:         /* XXX: should distinguish read/write cases */
        !            77:         for(addr = start; addr < end; addr += 4096) {
        !            78:             cpu_register_physical_memory(addr, 4096, 
        !            79:                                          isa_page_descs[(addr - 0xa0000) >> 12]);
        !            80:         }
        !            81:         break;
        !            82:     }
        !            83: }
        !            84: 
        !            85: static void i440fx_update_memory_mappings(PCIDevice *d)
        !            86: {
        !            87:     int i, r;
        !            88:     uint32_t smram, addr;
        !            89: 
        !            90:     update_pam(d, 0xf0000, 0x100000, (d->config[0x59] >> 4) & 3);
        !            91:     for(i = 0; i < 12; i++) {
        !            92:         r = (d->config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3;
        !            93:         update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r);
        !            94:     }
        !            95:     smram = d->config[0x72];
        !            96:     if ((smm_enabled && (smram & 0x08)) || (smram & 0x40)) {
        !            97:         cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000);
        !            98:     } else {
        !            99:         for(addr = 0xa0000; addr < 0xc0000; addr += 4096) {
        !           100:             cpu_register_physical_memory(addr, 4096, 
        !           101:                                          isa_page_descs[(addr - 0xa0000) >> 12]);
        !           102:         }
        !           103:     }
        !           104: }
        !           105: 
        !           106: void i440fx_set_smm(PCIDevice *d, int val)
        !           107: {
        !           108:     val = (val != 0);
        !           109:     if (smm_enabled != val) {
        !           110:         smm_enabled = val;
        !           111:         i440fx_update_memory_mappings(d);
        !           112:     }
        !           113: }
        !           114: 
        !           115: 
        !           116: /* XXX: suppress when better memory API. We make the assumption that
        !           117:    no device (in particular the VGA) changes the memory mappings in
        !           118:    the 0xa0000-0x100000 range */
        !           119: void i440fx_init_memory_mappings(PCIDevice *d)
        !           120: {
        !           121:     int i;
        !           122:     for(i = 0; i < 96; i++) {
        !           123:         isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000);
        !           124:     }
        !           125: }
        !           126: 
        !           127: static void i440fx_write_config(PCIDevice *d, 
        !           128:                                 uint32_t address, uint32_t val, int len)
        !           129: {
        !           130:     /* XXX: implement SMRAM.D_LOCK */
        !           131:     pci_default_write_config(d, address, val, len);
        !           132:     if ((address >= 0x59 && address <= 0x5f) || address == 0x72)
        !           133:         i440fx_update_memory_mappings(d);
        !           134: }
        !           135: 
        !           136: static void i440fx_save(QEMUFile* f, void *opaque)
        !           137: {
        !           138:     PCIDevice *d = opaque;
        !           139:     pci_device_save(d, f);
        !           140:     qemu_put_8s(f, &smm_enabled);
        !           141: }
        !           142: 
        !           143: static int i440fx_load(QEMUFile* f, void *opaque, int version_id)
        !           144: {
        !           145:     PCIDevice *d = opaque;
        !           146:     int ret;
        !           147: 
        !           148:     if (version_id != 1)
        !           149:         return -EINVAL;
        !           150:     ret = pci_device_load(d, f);
        !           151:     if (ret < 0)
        !           152:         return ret;
        !           153:     i440fx_update_memory_mappings(d);
        !           154:     qemu_get_8s(f, &smm_enabled);
        !           155:     return 0;
        !           156: }
        !           157: 
        !           158: PCIBus *i440fx_init(PCIDevice **pi440fx_state)
1.1       root      159: {
                    160:     PCIBus *b;
                    161:     PCIDevice *d;
                    162:     I440FXState *s;
                    163: 
                    164:     s = qemu_mallocz(sizeof(I440FXState));
1.1.1.2 ! root      165:     b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0, 4);
1.1       root      166:     s->bus = b;
                    167: 
                    168:     register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
                    169:     register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s);
                    170: 
                    171:     register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
                    172:     register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
                    173:     register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
                    174:     register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
                    175:     register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
                    176:     register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
                    177: 
                    178:     d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0, 
1.1.1.2 ! root      179:                             NULL, i440fx_write_config);
1.1       root      180: 
                    181:     d->config[0x00] = 0x86; // vendor_id
                    182:     d->config[0x01] = 0x80;
                    183:     d->config[0x02] = 0x37; // device_id
                    184:     d->config[0x03] = 0x12;
                    185:     d->config[0x08] = 0x02; // revision
                    186:     d->config[0x0a] = 0x00; // class_sub = host2pci
                    187:     d->config[0x0b] = 0x06; // class_base = PCI_bridge
                    188:     d->config[0x0e] = 0x00; // header_type
1.1.1.2 ! root      189: 
        !           190:     d->config[0x72] = 0x02; /* SMRAM */
        !           191: 
        !           192:     register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d);
        !           193:     *pi440fx_state = d;
1.1       root      194:     return b;
                    195: }
                    196: 
                    197: /* PIIX3 PCI to ISA bridge */
                    198: 
1.1.1.2 ! root      199: PCIDevice *piix3_dev;
        !           200: PCIDevice *piix4_dev;
1.1       root      201: 
                    202: /* just used for simpler irq handling. */
                    203: #define PCI_IRQ_WORDS   ((PCI_DEVICES_MAX + 31) / 32)
                    204: 
1.1.1.2 ! root      205: static int pci_irq_levels[4];
1.1       root      206: 
1.1.1.2 ! root      207: static void piix3_set_irq(void *pic, int irq_num, int level)
1.1       root      208: {
1.1.1.2 ! root      209:     int i, pic_irq, pic_level;
1.1       root      210: 
1.1.1.2 ! root      211:     pci_irq_levels[irq_num] = level;
1.1       root      212: 
                    213:     /* now we change the pic irq level according to the piix irq mappings */
                    214:     /* XXX: optimize */
                    215:     pic_irq = piix3_dev->config[0x60 + irq_num];
                    216:     if (pic_irq < 16) {
1.1.1.2 ! root      217:         /* The pic level is the logical OR of all the PCI irqs mapped
1.1       root      218:            to it */
                    219:         pic_level = 0;
1.1.1.2 ! root      220:         for (i = 0; i < 4; i++) {
        !           221:             if (pic_irq == piix3_dev->config[0x60 + i])
        !           222:                 pic_level |= pci_irq_levels[i];
        !           223:         }
1.1       root      224:         pic_set_irq(pic_irq, pic_level);
                    225:     }
                    226: }
                    227: 
                    228: static void piix3_reset(PCIDevice *d)
                    229: {
                    230:     uint8_t *pci_conf = d->config;
                    231: 
                    232:     pci_conf[0x04] = 0x07; // master, memory and I/O
                    233:     pci_conf[0x05] = 0x00;
                    234:     pci_conf[0x06] = 0x00;
                    235:     pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
                    236:     pci_conf[0x4c] = 0x4d;
                    237:     pci_conf[0x4e] = 0x03;
                    238:     pci_conf[0x4f] = 0x00;
                    239:     pci_conf[0x60] = 0x80;
                    240:     pci_conf[0x69] = 0x02;
                    241:     pci_conf[0x70] = 0x80;
                    242:     pci_conf[0x76] = 0x0c;
                    243:     pci_conf[0x77] = 0x0c;
                    244:     pci_conf[0x78] = 0x02;
                    245:     pci_conf[0x79] = 0x00;
                    246:     pci_conf[0x80] = 0x00;
                    247:     pci_conf[0x82] = 0x00;
                    248:     pci_conf[0xa0] = 0x08;
1.1.1.2 ! root      249:     pci_conf[0xa2] = 0x00;
        !           250:     pci_conf[0xa3] = 0x00;
        !           251:     pci_conf[0xa4] = 0x00;
        !           252:     pci_conf[0xa5] = 0x00;
        !           253:     pci_conf[0xa6] = 0x00;
        !           254:     pci_conf[0xa7] = 0x00;
        !           255:     pci_conf[0xa8] = 0x0f;
        !           256:     pci_conf[0xaa] = 0x00;
        !           257:     pci_conf[0xab] = 0x00;
        !           258:     pci_conf[0xac] = 0x00;
        !           259:     pci_conf[0xae] = 0x00;
        !           260: }
        !           261: 
        !           262: static void piix4_reset(PCIDevice *d)
        !           263: {
        !           264:     uint8_t *pci_conf = d->config;
        !           265: 
        !           266:     pci_conf[0x04] = 0x07; // master, memory and I/O
        !           267:     pci_conf[0x05] = 0x00;
        !           268:     pci_conf[0x06] = 0x00;
        !           269:     pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
        !           270:     pci_conf[0x4c] = 0x4d;
        !           271:     pci_conf[0x4e] = 0x03;
        !           272:     pci_conf[0x4f] = 0x00;
        !           273:     pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10
        !           274:     pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10
        !           275:     pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11
        !           276:     pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11
        !           277:     pci_conf[0x69] = 0x02;
        !           278:     pci_conf[0x70] = 0x80;
        !           279:     pci_conf[0x76] = 0x0c;
        !           280:     pci_conf[0x77] = 0x0c;
        !           281:     pci_conf[0x78] = 0x02;
        !           282:     pci_conf[0x79] = 0x00;
        !           283:     pci_conf[0x80] = 0x00;
        !           284:     pci_conf[0x82] = 0x00;
1.1       root      285:     pci_conf[0xa0] = 0x08;
                    286:     pci_conf[0xa2] = 0x00;
                    287:     pci_conf[0xa3] = 0x00;
                    288:     pci_conf[0xa4] = 0x00;
                    289:     pci_conf[0xa5] = 0x00;
                    290:     pci_conf[0xa6] = 0x00;
                    291:     pci_conf[0xa7] = 0x00;
                    292:     pci_conf[0xa8] = 0x0f;
                    293:     pci_conf[0xaa] = 0x00;
                    294:     pci_conf[0xab] = 0x00;
                    295:     pci_conf[0xac] = 0x00;
                    296:     pci_conf[0xae] = 0x00;
                    297: }
                    298: 
1.1.1.2 ! root      299: static void piix_save(QEMUFile* f, void *opaque)
        !           300: {
        !           301:     PCIDevice *d = opaque;
        !           302:     pci_device_save(d, f);
        !           303: }
        !           304: 
        !           305: static int piix_load(QEMUFile* f, void *opaque, int version_id)
        !           306: {
        !           307:     PCIDevice *d = opaque;
        !           308:     if (version_id != 2)
        !           309:         return -EINVAL;
        !           310:     return pci_device_load(d, f);
        !           311: }
        !           312: 
        !           313: int piix_init(PCIBus *bus, int devfn)
1.1       root      314: {
                    315:     PCIDevice *d;
                    316:     uint8_t *pci_conf;
                    317: 
1.1.1.2 ! root      318:     d = pci_register_device(bus, "PIIX", sizeof(PCIDevice),
        !           319:                                     devfn, NULL, NULL);
        !           320:     register_savevm("PIIX", 0, 2, piix_save, piix_load, d);
1.1       root      321: 
                    322:     piix3_dev = d;
                    323:     pci_conf = d->config;
                    324: 
                    325:     pci_conf[0x00] = 0x86; // Intel
                    326:     pci_conf[0x01] = 0x80;
1.1.1.2 ! root      327:     pci_conf[0x02] = 0x2E; // 82371FB PIIX PCI-to-ISA bridge
        !           328:     pci_conf[0x03] = 0x12;
        !           329:     pci_conf[0x08] = 0x02; // Step A1
1.1       root      330:     pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
                    331:     pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
                    332:     pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
                    333: 
                    334:     piix3_reset(d);
                    335:     return d->devfn;
                    336: }
                    337: 
1.1.1.2 ! root      338: int piix3_init(PCIBus *bus, int devfn)
1.1       root      339: {
1.1.1.2 ! root      340:     PCIDevice *d;
        !           341:     uint8_t *pci_conf;
1.1       root      342: 
1.1.1.2 ! root      343:     d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
        !           344:                                     devfn, NULL, NULL);
        !           345:     register_savevm("PIIX3", 0, 2, piix_save, piix_load, d);
1.1       root      346: 
1.1.1.2 ! root      347:     piix3_dev = d;
        !           348:     pci_conf = d->config;
1.1       root      349: 
1.1.1.2 ! root      350:     pci_conf[0x00] = 0x86; // Intel
        !           351:     pci_conf[0x01] = 0x80;
        !           352:     pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
        !           353:     pci_conf[0x03] = 0x70;
        !           354:     pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
        !           355:     pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
        !           356:     pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
1.1       root      357: 
1.1.1.2 ! root      358:     piix3_reset(d);
        !           359:     return d->devfn;
1.1       root      360: }
                    361: 
1.1.1.2 ! root      362: int piix4_init(PCIBus *bus, int devfn)
1.1       root      363: {
1.1.1.2 ! root      364:     PCIDevice *d;
        !           365:     uint8_t *pci_conf;
1.1       root      366: 
1.1.1.2 ! root      367:     d = pci_register_device(bus, "PIIX4", sizeof(PCIDevice),
        !           368:                                     devfn, NULL, NULL);
        !           369:     register_savevm("PIIX4", 0, 2, piix_save, piix_load, d);
1.1       root      370: 
1.1.1.2 ! root      371:     piix4_dev = d;
        !           372:     pci_conf = d->config;
1.1       root      373: 
1.1.1.2 ! root      374:     pci_conf[0x00] = 0x86; // Intel
        !           375:     pci_conf[0x01] = 0x80;
        !           376:     pci_conf[0x02] = 0x10; // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
        !           377:     pci_conf[0x03] = 0x71;
        !           378:     pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
        !           379:     pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
        !           380:     pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
1.1       root      381: 
1.1.1.2 ! root      382:     piix4_reset(d);
        !           383:     return d->devfn;
1.1       root      384: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.