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

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

unix.superglobalmegacorp.com

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