Annotation of qemu/roms/SLOF/clients/net-snk/app/biosemu/device.c, revision 1.1

1.1     ! root        1: /******************************************************************************
        !             2:  * Copyright (c) 2004, 2008 IBM Corporation
        !             3:  * All rights reserved.
        !             4:  * This program and the accompanying materials
        !             5:  * are made available under the terms of the BSD License
        !             6:  * which accompanies this distribution, and is available at
        !             7:  * http://www.opensource.org/licenses/bsd-license.php
        !             8:  *
        !             9:  * Contributors:
        !            10:  *     IBM Corporation - initial implementation
        !            11:  *****************************************************************************/
        !            12: 
        !            13: 
        !            14: #include "device.h"
        !            15: #include "rtas.h"
        !            16: #include <stdio.h>
        !            17: #include <string.h>
        !            18: #include "debug.h"
        !            19: 
        !            20: typedef struct {
        !            21:        uint8_t info;
        !            22:        uint8_t bus;
        !            23:        uint8_t devfn;
        !            24:        uint8_t cfg_space_offset;
        !            25:        uint64_t address;
        !            26:        uint64_t size;
        !            27: } __attribute__ ((__packed__)) assigned_address_t;
        !            28: 
        !            29: // use translate_address_dev and get_puid from net-snk's net_support.c
        !            30: void translate_address_dev(uint64_t *, phandle_t);
        !            31: uint64_t get_puid(phandle_t node);
        !            32: 
        !            33: 
        !            34: // scan all adresses assigned to the device ("assigned-addresses" and "reg")
        !            35: // store in translate_address_array for faster translation using dev_translate_address
        !            36: void
        !            37: dev_get_addr_info()
        !            38: {
        !            39:        // get bus/dev/fn from assigned-addresses
        !            40:        int32_t len;
        !            41:        //max. 6 BARs and 1 Exp.ROM plus CfgSpace and 3 legacy ranges
        !            42:        assigned_address_t buf[11];
        !            43:        len =
        !            44:            of_getprop(bios_device.phandle, "assigned-addresses", buf,
        !            45:                       sizeof(buf));
        !            46:        bios_device.bus = buf[0].bus;
        !            47:        bios_device.devfn = buf[0].devfn;
        !            48:        DEBUG_PRINTF("bus: %x, devfn: %x\n", bios_device.bus,
        !            49:                     bios_device.devfn);
        !            50:        //store address translations for all assigned-addresses and regs in
        !            51:        //translate_address_array for faster translation later on...
        !            52:        int i = 0;
        !            53:        // index to insert data into translate_address_array
        !            54:        int taa_index = 0;
        !            55:        uint64_t address_offset;
        !            56:        for (i = 0; i < (len / sizeof(assigned_address_t)); i++, taa_index++) {
        !            57:                //copy all info stored in assigned-addresses
        !            58:                translate_address_array[taa_index].info = buf[i].info;
        !            59:                translate_address_array[taa_index].bus = buf[i].bus;
        !            60:                translate_address_array[taa_index].devfn = buf[i].devfn;
        !            61:                translate_address_array[taa_index].cfg_space_offset =
        !            62:                    buf[i].cfg_space_offset;
        !            63:                translate_address_array[taa_index].address = buf[i].address;
        !            64:                translate_address_array[taa_index].size = buf[i].size;
        !            65:                // translate first address and store it as address_offset
        !            66:                address_offset = buf[i].address;
        !            67:                translate_address_dev(&address_offset, bios_device.phandle);
        !            68:                translate_address_array[taa_index].address_offset =
        !            69:                    address_offset - buf[i].address;
        !            70:        }
        !            71:        //get "reg" property
        !            72:        len = of_getprop(bios_device.phandle, "reg", buf, sizeof(buf));
        !            73:        for (i = 0; i < (len / sizeof(assigned_address_t)); i++) {
        !            74:                if ((buf[i].size == 0) || (buf[i].cfg_space_offset != 0)) {
        !            75:                        // we dont care for ranges with size 0 and
        !            76:                        // BARs and Expansion ROM must be in assigned-addresses... so in reg
        !            77:                        // we only look for those without config space offset set...
        !            78:                        // i.e. the legacy ranges
        !            79:                        continue;
        !            80:                }
        !            81:                //copy all info stored in assigned-addresses
        !            82:                translate_address_array[taa_index].info = buf[i].info;
        !            83:                translate_address_array[taa_index].bus = buf[i].bus;
        !            84:                translate_address_array[taa_index].devfn = buf[i].devfn;
        !            85:                translate_address_array[taa_index].cfg_space_offset =
        !            86:                    buf[i].cfg_space_offset;
        !            87:                translate_address_array[taa_index].address = buf[i].address;
        !            88:                translate_address_array[taa_index].size = buf[i].size;
        !            89:                // translate first address and store it as address_offset
        !            90:                address_offset = buf[i].address;
        !            91:                translate_address_dev(&address_offset, bios_device.phandle);
        !            92:                translate_address_array[taa_index].address_offset =
        !            93:                    address_offset - buf[i].address;
        !            94:                taa_index++;
        !            95:        }
        !            96:        // store last entry index of translate_address_array
        !            97:        taa_last_entry = taa_index - 1;
        !            98: #ifdef DEBUG
        !            99:        //dump translate_address_array
        !           100:        printf("translate_address_array: \n");
        !           101:        translate_address_t ta;
        !           102:        for (i = 0; i <= taa_last_entry; i++) {
        !           103:                ta = translate_address_array[i];
        !           104:                printf
        !           105:                    ("%d: %02x%02x%02x%02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
        !           106:                     i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
        !           107:                     ta.address, ta.address_offset, ta.size);
        !           108:        }
        !           109: #endif
        !           110: }
        !           111: 
        !           112: // to simulate accesses to legacy VGA Memory (0xA0000-0xBFFFF)
        !           113: // we look for the first prefetchable memory BAR, if no prefetchable BAR found,
        !           114: // we use the first memory BAR
        !           115: // dev_translate_addr will translate accesses to the legacy VGA Memory into the found vmem BAR
        !           116: void
        !           117: dev_find_vmem_addr()
        !           118: {
        !           119:        int i = 0;
        !           120:        translate_address_t ta;
        !           121:        int8_t tai_np = -1, tai_p = -1; // translate_address_array index for non-prefetchable and prefetchable memory
        !           122:        //search backwards to find first entry
        !           123:        for (i = taa_last_entry; i >= 0; i--) {
        !           124:                ta = translate_address_array[i];
        !           125:                if ((ta.cfg_space_offset >= 0x10)
        !           126:                    && (ta.cfg_space_offset <= 0x24)) {
        !           127:                        //only BARs
        !           128:                        if ((ta.info & 0x03) >= 0x02) {
        !           129:                                //32/64bit memory
        !           130:                                tai_np = i;
        !           131:                                if ((ta.info & 0x40) != 0) {
        !           132:                                        // prefetchable
        !           133:                                        tai_p = i;
        !           134:                                }
        !           135:                        }
        !           136:                }
        !           137:        }
        !           138:        if (tai_p != -1) {
        !           139:                ta = translate_address_array[tai_p];
        !           140:                bios_device.vmem_addr = ta.address;
        !           141:                bios_device.vmem_size = ta.size;
        !           142:                DEBUG_PRINTF
        !           143:                    ("%s: Found prefetchable Virtual Legacy Memory BAR: %llx, size: %llx\n",
        !           144:                     __FUNCTION__, bios_device.vmem_addr,
        !           145:                     bios_device.vmem_size);
        !           146:        } else if (tai_np != -1) {
        !           147:                ta = translate_address_array[tai_np];
        !           148:                bios_device.vmem_addr = ta.address;
        !           149:                bios_device.vmem_size = ta.size;
        !           150:                DEBUG_PRINTF
        !           151:                    ("%s: Found non-prefetchable Virtual Legacy Memory BAR: %llx, size: %llx",
        !           152:                     __FUNCTION__, bios_device.vmem_addr,
        !           153:                     bios_device.vmem_size);
        !           154:        }
        !           155:        // disable vmem
        !           156:        //bios_device.vmem_size = 0;
        !           157: }
        !           158: 
        !           159: void
        !           160: dev_get_puid()
        !           161: {
        !           162:        // get puid
        !           163:        bios_device.puid = get_puid(bios_device.phandle);
        !           164:        DEBUG_PRINTF("puid: 0x%llx\n", bios_device.puid);
        !           165: }
        !           166: 
        !           167: void
        !           168: dev_get_device_vendor_id()
        !           169: {
        !           170:        uint32_t pci_config_0 =
        !           171:            rtas_pci_config_read(bios_device.puid, 4, bios_device.bus,
        !           172:                                 bios_device.devfn, 0x0);
        !           173:        bios_device.pci_device_id =
        !           174:            (uint16_t) ((pci_config_0 & 0xFFFF0000) >> 16);
        !           175:        bios_device.pci_vendor_id = (uint16_t) (pci_config_0 & 0x0000FFFF);
        !           176:        DEBUG_PRINTF("PCI Device ID: %04x, PCI Vendor ID: %x\n",
        !           177:                     bios_device.pci_device_id, bios_device.pci_vendor_id);
        !           178: }
        !           179: 
        !           180: /* check, wether the device has a valid Expansion ROM, also search the PCI Data Structure and
        !           181:  * any Expansion ROM Header (using dev_scan_exp_header()) for needed information */
        !           182: uint8_t
        !           183: dev_check_exprom()
        !           184: {
        !           185:        int i = 0;
        !           186:        translate_address_t ta;
        !           187:        uint64_t rom_base_addr = 0;
        !           188:        uint16_t pci_ds_offset;
        !           189:        pci_data_struct_t pci_ds;
        !           190:        // check for ExpROM Address (Offset 30) in taa
        !           191:        for (i = 0; i <= taa_last_entry; i++) {
        !           192:                ta = translate_address_array[i];
        !           193:                if (ta.cfg_space_offset == 0x30) {
        !           194:                        rom_base_addr = ta.address + ta.address_offset; //translated address
        !           195:                        break;
        !           196:                }
        !           197:        }
        !           198:        // in the ROM there could be multiple Expansion ROM Images... start searching
        !           199:        // them for a x86 image
        !           200:        do {
        !           201:                if (rom_base_addr == 0) {
        !           202:                        printf("Error: no Expansion ROM address found!\n");
        !           203:                        return -1;
        !           204:                }
        !           205:                set_ci();
        !           206:                uint16_t rom_signature = *((uint16_t *) rom_base_addr);
        !           207:                clr_ci();
        !           208:                if (rom_signature != 0x55aa) {
        !           209:                        printf
        !           210:                            ("Error: invalid Expansion ROM signature: %02x!\n",
        !           211:                             *((uint16_t *) rom_base_addr));
        !           212:                        return -1;
        !           213:                }
        !           214:                set_ci();
        !           215:                // at offset 0x18 is the (16bit little-endian) pointer to the PCI Data Structure
        !           216:                pci_ds_offset = in16le((void *) (rom_base_addr + 0x18));
        !           217:                //copy the PCI Data Structure
        !           218:                memcpy(&pci_ds, (void *) (rom_base_addr + pci_ds_offset),
        !           219:                       sizeof(pci_ds));
        !           220:                clr_ci();
        !           221: #ifdef DEBUG
        !           222:                DEBUG_PRINTF("PCI Data Structure @%llx:\n",
        !           223:                             rom_base_addr + pci_ds_offset);
        !           224:                dump((void *) &pci_ds, sizeof(pci_ds));
        !           225: #endif
        !           226:                if (strncmp((const char *) pci_ds.signature, "PCIR", 4) != 0) {
        !           227:                        printf("Invalid PCI Data Structure found!\n");
        !           228:                        break;
        !           229:                }
        !           230:                //little-endian conversion
        !           231:                pci_ds.vendor_id = in16le(&pci_ds.vendor_id);
        !           232:                pci_ds.device_id = in16le(&pci_ds.device_id);
        !           233:                pci_ds.img_length = in16le(&pci_ds.img_length);
        !           234:                pci_ds.pci_ds_length = in16le(&pci_ds.pci_ds_length);
        !           235:                if (pci_ds.vendor_id != bios_device.pci_vendor_id) {
        !           236:                        printf
        !           237:                            ("Image has invalid Vendor ID: %04x, expected: %04x\n",
        !           238:                             pci_ds.vendor_id, bios_device.pci_vendor_id);
        !           239:                        break;
        !           240:                }
        !           241:                if (pci_ds.device_id != bios_device.pci_device_id) {
        !           242:                        printf
        !           243:                            ("Image has invalid Device ID: %04x, expected: %04x\n",
        !           244:                             pci_ds.device_id, bios_device.pci_device_id);
        !           245:                        break;
        !           246:                }
        !           247:                //DEBUG_PRINTF("Image Length: %d\n", pci_ds.img_length * 512);
        !           248:                //DEBUG_PRINTF("Image Code Type: %d\n", pci_ds.code_type);
        !           249:                if (pci_ds.code_type == 0) {
        !           250:                        //x86 image
        !           251:                        //store image address and image length in bios_device struct
        !           252:                        bios_device.img_addr = rom_base_addr;
        !           253:                        bios_device.img_size = pci_ds.img_length * 512;
        !           254:                        // we found the image, exit the loop
        !           255:                        break;
        !           256:                } else {
        !           257:                        // no x86 image, check next image (if any)
        !           258:                        rom_base_addr += pci_ds.img_length * 512;
        !           259:                }
        !           260:                if ((pci_ds.indicator & 0x80) == 0x80) {
        !           261:                        //last image found, exit the loop
        !           262:                        DEBUG_PRINTF("Last PCI Expansion ROM Image found.\n");
        !           263:                        break;
        !           264:                }
        !           265:        }
        !           266:        while (bios_device.img_addr == 0);
        !           267:        // in case we did not find a valid x86 Expansion ROM Image
        !           268:        if (bios_device.img_addr == 0) {
        !           269:                printf("Error: no valid x86 Expansion ROM Image found!\n");
        !           270:                return -1;
        !           271:        }
        !           272:        return 0;
        !           273: }
        !           274: 
        !           275: uint8_t
        !           276: dev_init(char *device_name)
        !           277: {
        !           278:        uint8_t rval = 0;
        !           279:        //init bios_device struct
        !           280:        DEBUG_PRINTF("%s(%s)\n", __FUNCTION__, device_name);
        !           281:        memset(&bios_device, 0, sizeof(bios_device));
        !           282:        bios_device.ihandle = of_open(device_name);
        !           283:        if (bios_device.ihandle == 0) {
        !           284:                DEBUG_PRINTF("%s is no valid device!\n", device_name);
        !           285:                return -1;
        !           286:        }
        !           287:        bios_device.phandle = of_finddevice(device_name);
        !           288:        dev_get_addr_info();
        !           289:        dev_find_vmem_addr();
        !           290:        dev_get_puid();
        !           291:        dev_get_device_vendor_id();
        !           292:        return rval;
        !           293: }
        !           294: 
        !           295: // translate address function using translate_address_array assembled
        !           296: // by dev_get_addr_info... MUCH faster than calling translate_address_dev
        !           297: // and accessing client interface for every translation...
        !           298: // returns: 0 if addr not found in translate_address_array, 1 if found.
        !           299: uint8_t
        !           300: dev_translate_address(uint64_t * addr)
        !           301: {
        !           302:        int i = 0;
        !           303:        translate_address_t ta;
        !           304:        //check if it is an access to legacy VGA Mem... if it is, map the address
        !           305:        //to the vmem BAR and then translate it...
        !           306:        // (translation info provided by Ben Herrenschmidt)
        !           307:        // NOTE: the translation seems to only work for NVIDIA cards... but it is needed
        !           308:        // to make some NVIDIA cards work at all...
        !           309:        if ((bios_device.vmem_size > 0)
        !           310:            && ((*addr >= 0xA0000) && (*addr < 0xB8000))) {
        !           311:                *addr = (*addr - 0xA0000) * 4 + 2 + bios_device.vmem_addr;
        !           312:        }
        !           313:        if ((bios_device.vmem_size > 0)
        !           314:            && ((*addr >= 0xB8000) && (*addr < 0xC0000))) {
        !           315:                uint8_t shift = *addr & 1;
        !           316:                *addr &= 0xfffffffe;
        !           317:                *addr = (*addr - 0xB8000) * 4 + shift + bios_device.vmem_addr;
        !           318:        }
        !           319:        for (i = 0; i <= taa_last_entry; i++) {
        !           320:                ta = translate_address_array[i];
        !           321:                if ((*addr >= ta.address) && (*addr <= (ta.address + ta.size))) {
        !           322:                        *addr += ta.address_offset;
        !           323:                        return 1;
        !           324:                }
        !           325:        }
        !           326:        return 0;
        !           327: }

unix.superglobalmegacorp.com

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