Annotation of qemu/hw/spapr.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
                      3:  *
                      4:  * Copyright (c) 2004-2007 Fabrice Bellard
                      5:  * Copyright (c) 2007 Jocelyn Mayer
                      6:  * Copyright (c) 2010 David Gibson, IBM Corporation.
                      7:  *
                      8:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      9:  * of this software and associated documentation files (the "Software"), to deal
                     10:  * in the Software without restriction, including without limitation the rights
                     11:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     12:  * copies of the Software, and to permit persons to whom the Software is
                     13:  * furnished to do so, subject to the following conditions:
                     14:  *
                     15:  * The above copyright notice and this permission notice shall be included in
                     16:  * all copies or substantial portions of the Software.
                     17:  *
                     18:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     19:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     20:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     21:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     22:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     23:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     24:  * THE SOFTWARE.
                     25:  *
                     26:  */
                     27: #include "sysemu.h"
                     28: #include "hw.h"
                     29: #include "elf.h"
                     30: #include "net.h"
                     31: #include "blockdev.h"
                     32: 
                     33: #include "hw/boards.h"
                     34: #include "hw/ppc.h"
                     35: #include "hw/loader.h"
                     36: 
                     37: #include "hw/spapr.h"
                     38: #include "hw/spapr_vio.h"
                     39: #include "hw/xics.h"
                     40: 
                     41: #include <libfdt.h>
                     42: 
                     43: #define KERNEL_LOAD_ADDR        0x00000000
                     44: #define INITRD_LOAD_ADDR        0x02800000
                     45: #define FDT_MAX_SIZE            0x10000
                     46: #define RTAS_MAX_SIZE           0x10000
                     47: #define FW_MAX_SIZE             0x400000
                     48: #define FW_FILE_NAME            "slof.bin"
                     49: 
                     50: #define MIN_RAM_SLOF           512UL
                     51: 
                     52: #define TIMEBASE_FREQ           512000000ULL
                     53: 
                     54: #define MAX_CPUS                256
                     55: #define XICS_IRQS              1024
                     56: 
                     57: sPAPREnvironment *spapr;
                     58: 
                     59: static void *spapr_create_fdt_skel(const char *cpu_model,
                     60:                                    target_phys_addr_t initrd_base,
                     61:                                    target_phys_addr_t initrd_size,
                     62:                                    const char *boot_device,
                     63:                                    const char *kernel_cmdline,
                     64:                                    long hash_shift)
                     65: {
                     66:     void *fdt;
                     67:     CPUState *env;
                     68:     uint64_t mem_reg_property[] = { 0, cpu_to_be64(ram_size) };
                     69:     uint32_t start_prop = cpu_to_be32(initrd_base);
                     70:     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
                     71:     uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
                     72:     char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
                     73:         "\0hcall-tce\0hcall-vio\0hcall-splpar";
                     74:     uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
                     75:     int i;
                     76:     char *modelname;
                     77: 
                     78: #define _FDT(exp) \
                     79:     do { \
                     80:         int ret = (exp);                                           \
                     81:         if (ret < 0) {                                             \
                     82:             fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
                     83:                     #exp, fdt_strerror(ret));                      \
                     84:             exit(1);                                               \
                     85:         }                                                          \
                     86:     } while (0)
                     87: 
                     88:     fdt = qemu_mallocz(FDT_MAX_SIZE);
                     89:     _FDT((fdt_create(fdt, FDT_MAX_SIZE)));
                     90: 
                     91:     _FDT((fdt_finish_reservemap(fdt)));
                     92: 
                     93:     /* Root node */
                     94:     _FDT((fdt_begin_node(fdt, "")));
                     95:     _FDT((fdt_property_string(fdt, "device_type", "chrp")));
                     96:     _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)")));
                     97: 
                     98:     _FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
                     99:     _FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
                    100: 
                    101:     /* /chosen */
                    102:     _FDT((fdt_begin_node(fdt, "chosen")));
                    103: 
                    104:     _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
                    105:     _FDT((fdt_property(fdt, "linux,initrd-start",
                    106:                        &start_prop, sizeof(start_prop))));
                    107:     _FDT((fdt_property(fdt, "linux,initrd-end",
                    108:                        &end_prop, sizeof(end_prop))));
                    109:     _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
                    110: 
                    111:     _FDT((fdt_end_node(fdt)));
                    112: 
                    113:     /* memory node */
                    114:     _FDT((fdt_begin_node(fdt, "memory@0")));
                    115: 
                    116:     _FDT((fdt_property_string(fdt, "device_type", "memory")));
                    117:     _FDT((fdt_property(fdt, "reg",
                    118:                        mem_reg_property, sizeof(mem_reg_property))));
                    119: 
                    120:     _FDT((fdt_end_node(fdt)));
                    121: 
                    122:     /* cpus */
                    123:     _FDT((fdt_begin_node(fdt, "cpus")));
                    124: 
                    125:     _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
                    126:     _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
                    127: 
                    128:     modelname = qemu_strdup(cpu_model);
                    129: 
                    130:     for (i = 0; i < strlen(modelname); i++) {
                    131:         modelname[i] = toupper(modelname[i]);
                    132:     }
                    133: 
                    134:     for (env = first_cpu; env != NULL; env = env->next_cpu) {
                    135:         int index = env->cpu_index;
                    136:         uint32_t gserver_prop[] = {cpu_to_be32(index), 0}; /* HACK! */
                    137:         char *nodename;
                    138:         uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
                    139:                            0xffffffff, 0xffffffff};
                    140: 
                    141:         if (asprintf(&nodename, "%s@%x", modelname, index) < 0) {
                    142:             fprintf(stderr, "Allocation failure\n");
                    143:             exit(1);
                    144:         }
                    145: 
                    146:         _FDT((fdt_begin_node(fdt, nodename)));
                    147: 
                    148:         free(nodename);
                    149: 
                    150:         _FDT((fdt_property_cell(fdt, "reg", index)));
                    151:         _FDT((fdt_property_string(fdt, "device_type", "cpu")));
                    152: 
                    153:         _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR])));
                    154:         _FDT((fdt_property_cell(fdt, "dcache-block-size",
                    155:                                 env->dcache_line_size)));
                    156:         _FDT((fdt_property_cell(fdt, "icache-block-size",
                    157:                                 env->icache_line_size)));
                    158:         _FDT((fdt_property_cell(fdt, "timebase-frequency", TIMEBASE_FREQ)));
                    159:         /* Hardcode CPU frequency for now.  It's kind of arbitrary on
                    160:          * full emu, for kvm we should copy it from the host */
                    161:         _FDT((fdt_property_cell(fdt, "clock-frequency", 1000000000)));
                    162:         _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
                    163:         _FDT((fdt_property(fdt, "ibm,pft-size",
                    164:                            pft_size_prop, sizeof(pft_size_prop))));
                    165:         _FDT((fdt_property_string(fdt, "status", "okay")));
                    166:         _FDT((fdt_property(fdt, "64-bit", NULL, 0)));
                    167:         _FDT((fdt_property_cell(fdt, "ibm,ppc-interrupt-server#s", index)));
                    168:         _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
                    169:                            gserver_prop, sizeof(gserver_prop))));
                    170: 
                    171:         if (env->mmu_model & POWERPC_MMU_1TSEG) {
                    172:             _FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
                    173:                                segs, sizeof(segs))));
                    174:         }
                    175: 
                    176:         _FDT((fdt_end_node(fdt)));
                    177:     }
                    178: 
                    179:     qemu_free(modelname);
                    180: 
                    181:     _FDT((fdt_end_node(fdt)));
                    182: 
                    183:     /* RTAS */
                    184:     _FDT((fdt_begin_node(fdt, "rtas")));
                    185: 
                    186:     _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
                    187:                        sizeof(hypertas_prop))));
                    188: 
                    189:     _FDT((fdt_end_node(fdt)));
                    190: 
                    191:     /* interrupt controller */
                    192:     _FDT((fdt_begin_node(fdt, "interrupt-controller@0")));
                    193: 
                    194:     _FDT((fdt_property_string(fdt, "device_type",
                    195:                               "PowerPC-External-Interrupt-Presentation")));
                    196:     _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
                    197:     _FDT((fdt_property_cell(fdt, "reg", 0)));
                    198:     _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
                    199:     _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
                    200:                        interrupt_server_ranges_prop,
                    201:                        sizeof(interrupt_server_ranges_prop))));
                    202: 
                    203:     _FDT((fdt_end_node(fdt)));
                    204: 
                    205:     /* vdevice */
                    206:     _FDT((fdt_begin_node(fdt, "vdevice")));
                    207: 
                    208:     _FDT((fdt_property_string(fdt, "device_type", "vdevice")));
                    209:     _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
                    210:     _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
                    211:     _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
                    212:     _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2)));
                    213:     _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
                    214: 
                    215:     _FDT((fdt_end_node(fdt)));
                    216: 
                    217:     _FDT((fdt_end_node(fdt))); /* close root node */
                    218:     _FDT((fdt_finish(fdt)));
                    219: 
                    220:     return fdt;
                    221: }
                    222: 
                    223: static void spapr_finalize_fdt(sPAPREnvironment *spapr,
                    224:                                target_phys_addr_t fdt_addr,
                    225:                                target_phys_addr_t rtas_addr,
                    226:                                target_phys_addr_t rtas_size)
                    227: {
                    228:     int ret;
                    229:     void *fdt;
                    230: 
                    231:     fdt = qemu_malloc(FDT_MAX_SIZE);
                    232: 
                    233:     /* open out the base tree into a temp buffer for the final tweaks */
                    234:     _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE)));
                    235: 
                    236:     ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
                    237:     if (ret < 0) {
                    238:         fprintf(stderr, "couldn't setup vio devices in fdt\n");
                    239:         exit(1);
                    240:     }
                    241: 
                    242:     /* RTAS */
                    243:     ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
                    244:     if (ret < 0) {
                    245:         fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
                    246:     }
                    247: 
                    248:     _FDT((fdt_pack(fdt)));
                    249: 
                    250:     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
                    251: 
                    252:     qemu_free(fdt);
                    253: }
                    254: 
                    255: static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
                    256: {
                    257:     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
                    258: }
                    259: 
                    260: static void emulate_spapr_hypercall(CPUState *env)
                    261: {
                    262:     env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]);
                    263: }
                    264: 
                    265: static void spapr_reset(void *opaque)
                    266: {
                    267:     sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
                    268: 
                    269:     fprintf(stderr, "sPAPR reset\n");
                    270: 
                    271:     /* flush out the hash table */
                    272:     memset(spapr->htab, 0, spapr->htab_size);
                    273: 
                    274:     /* Load the fdt */
                    275:     spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr,
                    276:                        spapr->rtas_size);
                    277: 
                    278:     /* Set up the entry state */
                    279:     first_cpu->gpr[3] = spapr->fdt_addr;
                    280:     first_cpu->gpr[5] = 0;
                    281:     first_cpu->halted = 0;
                    282:     first_cpu->nip = spapr->entry_point;
                    283: 
                    284: }
                    285: 
                    286: /* pSeries LPAR / sPAPR hardware init */
                    287: static void ppc_spapr_init(ram_addr_t ram_size,
                    288:                            const char *boot_device,
                    289:                            const char *kernel_filename,
                    290:                            const char *kernel_cmdline,
                    291:                            const char *initrd_filename,
                    292:                            const char *cpu_model)
                    293: {
                    294:     CPUState *env;
                    295:     int i;
                    296:     ram_addr_t ram_offset;
                    297:     uint32_t initrd_base;
                    298:     long kernel_size, initrd_size, fw_size;
                    299:     long pteg_shift = 17;
                    300:     char *filename;
                    301:     int irq = 16;
                    302: 
                    303:     spapr = qemu_malloc(sizeof(*spapr));
                    304:     cpu_ppc_hypercall = emulate_spapr_hypercall;
                    305: 
                    306:     /* We place the device tree just below either the top of RAM, or
                    307:      * 2GB, so that it can be processed with 32-bit code if
                    308:      * necessary */
                    309:     spapr->fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE;
                    310:     spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE;
                    311: 
                    312:     /* init CPUs */
                    313:     if (cpu_model == NULL) {
                    314:         cpu_model = "POWER7";
                    315:     }
                    316:     for (i = 0; i < smp_cpus; i++) {
                    317:         env = cpu_init(cpu_model);
                    318: 
                    319:         if (!env) {
                    320:             fprintf(stderr, "Unable to find PowerPC CPU definition\n");
                    321:             exit(1);
                    322:         }
                    323:         /* Set time-base frequency to 512 MHz */
                    324:         cpu_ppc_tb_init(env, TIMEBASE_FREQ);
                    325:         qemu_register_reset((QEMUResetHandler *)&cpu_reset, env);
                    326: 
                    327:         env->hreset_vector = 0x60;
                    328:         env->hreset_excp_prefix = 0;
                    329:         env->gpr[3] = env->cpu_index;
                    330:     }
                    331: 
                    332:     /* allocate RAM */
                    333:     ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size);
                    334:     cpu_register_physical_memory(0, ram_size, ram_offset);
                    335: 
                    336:     /* allocate hash page table.  For now we always make this 16mb,
                    337:      * later we should probably make it scale to the size of guest
                    338:      * RAM */
                    339:     spapr->htab_size = 1ULL << (pteg_shift + 7);
                    340:     spapr->htab = qemu_malloc(spapr->htab_size);
                    341: 
                    342:     for (env = first_cpu; env != NULL; env = env->next_cpu) {
                    343:         env->external_htab = spapr->htab;
                    344:         env->htab_base = -1;
                    345:         env->htab_mask = spapr->htab_size - 1;
                    346:     }
                    347: 
                    348:     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
                    349:     spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,
                    350:                                            ram_size - spapr->rtas_addr);
                    351:     if (spapr->rtas_size < 0) {
                    352:         hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
                    353:         exit(1);
                    354:     }
                    355:     qemu_free(filename);
                    356: 
                    357:     /* Set up Interrupt Controller */
                    358:     spapr->icp = xics_system_init(XICS_IRQS);
                    359: 
                    360:     /* Set up VIO bus */
                    361:     spapr->vio_bus = spapr_vio_bus_init();
                    362: 
                    363:     for (i = 0; i < MAX_SERIAL_PORTS; i++, irq++) {
                    364:         if (serial_hds[i]) {
                    365:             spapr_vty_create(spapr->vio_bus, SPAPR_VTY_BASE_ADDRESS + i,
                    366:                              serial_hds[i], xics_find_qirq(spapr->icp, irq),
                    367:                              irq);
                    368:         }
                    369:     }
                    370: 
                    371:     for (i = 0; i < nb_nics; i++, irq++) {
                    372:         NICInfo *nd = &nd_table[i];
                    373: 
                    374:         if (!nd->model) {
                    375:             nd->model = qemu_strdup("ibmveth");
                    376:         }
                    377: 
                    378:         if (strcmp(nd->model, "ibmveth") == 0) {
                    379:             spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd,
                    380:                               xics_find_qirq(spapr->icp, irq), irq);
                    381:         } else {
                    382:             fprintf(stderr, "pSeries (sPAPR) platform does not support "
                    383:                     "NIC model '%s' (only ibmveth is supported)\n",
                    384:                     nd->model);
                    385:             exit(1);
                    386:         }
                    387:     }
                    388: 
                    389:     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
                    390:         spapr_vscsi_create(spapr->vio_bus, 0x2000 + i,
                    391:                            xics_find_qirq(spapr->icp, irq), irq);
                    392:         irq++;
                    393:     }
                    394: 
                    395:     if (kernel_filename) {
                    396:         uint64_t lowaddr = 0;
                    397: 
                    398:         kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
                    399:                                NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
                    400:         if (kernel_size < 0) {
                    401:             kernel_size = load_image_targphys(kernel_filename,
                    402:                                               KERNEL_LOAD_ADDR,
                    403:                                               ram_size - KERNEL_LOAD_ADDR);
                    404:         }
                    405:         if (kernel_size < 0) {
                    406:             fprintf(stderr, "qemu: could not load kernel '%s'\n",
                    407:                     kernel_filename);
                    408:             exit(1);
                    409:         }
                    410: 
                    411:         /* load initrd */
                    412:         if (initrd_filename) {
                    413:             initrd_base = INITRD_LOAD_ADDR;
                    414:             initrd_size = load_image_targphys(initrd_filename, initrd_base,
                    415:                                               ram_size - initrd_base);
                    416:             if (initrd_size < 0) {
                    417:                 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
                    418:                         initrd_filename);
                    419:                 exit(1);
                    420:             }
                    421:         } else {
                    422:             initrd_base = 0;
                    423:             initrd_size = 0;
                    424:         }
                    425: 
                    426:         spapr->entry_point = KERNEL_LOAD_ADDR;
                    427:     } else {
                    428:         if (ram_size < (MIN_RAM_SLOF << 20)) {
                    429:             fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
                    430:                     "%ldM guest RAM\n", MIN_RAM_SLOF);
                    431:             exit(1);
                    432:         }
                    433:         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "slof.bin");
                    434:         fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
                    435:         if (fw_size < 0) {
                    436:             hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
                    437:             exit(1);
                    438:         }
                    439:         qemu_free(filename);
                    440:         spapr->entry_point = 0x100;
                    441:         initrd_base = 0;
                    442:         initrd_size = 0;
                    443: 
                    444:         /* SLOF will startup the secondary CPUs using RTAS,
                    445:            rather than expecting a kexec() style entry */
                    446:         for (env = first_cpu; env != NULL; env = env->next_cpu) {
                    447:             env->halted = 1;
                    448:         }
                    449:     }
                    450: 
                    451:     /* Prepare the device tree */
                    452:     spapr->fdt_skel = spapr_create_fdt_skel(cpu_model,
                    453:                                             initrd_base, initrd_size,
                    454:                                             boot_device, kernel_cmdline,
                    455:                                             pteg_shift + 7);
                    456:     assert(spapr->fdt_skel != NULL);
                    457: 
                    458:     qemu_register_reset(spapr_reset, spapr);
                    459: }
                    460: 
                    461: static QEMUMachine spapr_machine = {
                    462:     .name = "pseries",
                    463:     .desc = "pSeries Logical Partition (PAPR compliant)",
                    464:     .init = ppc_spapr_init,
                    465:     .max_cpus = MAX_CPUS,
                    466:     .no_vga = 1,
                    467:     .no_parallel = 1,
                    468:     .use_scsi = 1,
                    469: };
                    470: 
                    471: static void spapr_machine_init(void)
                    472: {
                    473:     qemu_register_machine(&spapr_machine);
                    474: }
                    475: 
                    476: machine_init(spapr_machine_init);

unix.superglobalmegacorp.com