qemu/hw/ppc_oldworld.c
<<
>>
Prefs
   1
   2/*
   3 * QEMU OldWorld PowerMac (currently ~G3 Beige) hardware System Emulator
   4 *
   5 * Copyright (c) 2004-2007 Fabrice Bellard
   6 * Copyright (c) 2007 Jocelyn Mayer
   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#include "hw.h"
  27#include "ppc.h"
  28#include "ppc_mac.h"
  29#include "mac_dbdma.h"
  30#include "nvram.h"
  31#include "pc.h"
  32#include "sysemu.h"
  33#include "net.h"
  34#include "isa.h"
  35#include "pci.h"
  36#include "usb-ohci.h"
  37#include "boards.h"
  38#include "fw_cfg.h"
  39#include "escc.h"
  40#include "ide.h"
  41#include "loader.h"
  42#include "elf.h"
  43#include "kvm.h"
  44#include "kvm_ppc.h"
  45#include "blockdev.h"
  46
  47#define MAX_IDE_BUS 2
  48#define CFG_ADDR 0xf0000510
  49
  50static int fw_cfg_boot_set(void *opaque, const char *boot_device)
  51{
  52    fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
  53    return 0;
  54}
  55
  56
  57static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
  58{
  59    return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
  60}
  61
  62static target_phys_addr_t round_page(target_phys_addr_t addr)
  63{
  64    return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
  65}
  66
  67static void ppc_heathrow_init (ram_addr_t ram_size,
  68                               const char *boot_device,
  69                               const char *kernel_filename,
  70                               const char *kernel_cmdline,
  71                               const char *initrd_filename,
  72                               const char *cpu_model)
  73{
  74    CPUState *env = NULL;
  75    char *filename;
  76    qemu_irq *pic, **heathrow_irqs;
  77    int linux_boot, i;
  78    ram_addr_t ram_offset, bios_offset;
  79    uint32_t kernel_base, initrd_base, cmdline_base = 0;
  80    int32_t kernel_size, initrd_size;
  81    PCIBus *pci_bus;
  82    MacIONVRAMState *nvr;
  83    int bios_size;
  84    int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index;
  85    int escc_mem_index, ide_mem_index[2];
  86    uint16_t ppc_boot_device;
  87    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
  88    void *fw_cfg;
  89    void *dbdma;
  90
  91    linux_boot = (kernel_filename != NULL);
  92
  93    /* init CPUs */
  94    if (cpu_model == NULL)
  95        cpu_model = "G3";
  96    for (i = 0; i < smp_cpus; i++) {
  97        env = cpu_init(cpu_model);
  98        if (!env) {
  99            fprintf(stderr, "Unable to find PowerPC CPU definition\n");
 100            exit(1);
 101        }
 102        /* Set time-base frequency to 16.6 Mhz */
 103        cpu_ppc_tb_init(env,  16600000UL);
 104        qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
 105    }
 106
 107    /* allocate RAM */
 108    if (ram_size > (2047 << 20)) {
 109        fprintf(stderr,
 110                "qemu: Too much memory for this machine: %d MB, maximum 2047 MB\n",
 111                ((unsigned int)ram_size / (1 << 20)));
 112        exit(1);
 113    }
 114
 115    ram_offset = qemu_ram_alloc(NULL, "ppc_heathrow.ram", ram_size);
 116    cpu_register_physical_memory(0, ram_size, ram_offset);
 117
 118    /* allocate and load BIOS */
 119    bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.bios", BIOS_SIZE);
 120    if (bios_name == NULL)
 121        bios_name = PROM_FILENAME;
 122    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
 123    cpu_register_physical_memory(PROM_ADDR, BIOS_SIZE, bios_offset | IO_MEM_ROM);
 124
 125    /* Load OpenBIOS (ELF) */
 126    if (filename) {
 127        bios_size = load_elf(filename, 0, NULL, NULL, NULL, NULL,
 128                             1, ELF_MACHINE, 0);
 129        qemu_free(filename);
 130    } else {
 131        bios_size = -1;
 132    }
 133    if (bios_size < 0 || bios_size > BIOS_SIZE) {
 134        hw_error("qemu: could not load PowerPC bios '%s'\n", bios_name);
 135        exit(1);
 136    }
 137
 138    if (linux_boot) {
 139        uint64_t lowaddr = 0;
 140        int bswap_needed;
 141
 142#ifdef BSWAP_NEEDED
 143        bswap_needed = 1;
 144#else
 145        bswap_needed = 0;
 146#endif
 147        kernel_base = KERNEL_LOAD_ADDR;
 148        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
 149                               NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
 150        if (kernel_size < 0)
 151            kernel_size = load_aout(kernel_filename, kernel_base,
 152                                    ram_size - kernel_base, bswap_needed,
 153                                    TARGET_PAGE_SIZE);
 154        if (kernel_size < 0)
 155            kernel_size = load_image_targphys(kernel_filename,
 156                                              kernel_base,
 157                                              ram_size - kernel_base);
 158        if (kernel_size < 0) {
 159            hw_error("qemu: could not load kernel '%s'\n",
 160                      kernel_filename);
 161            exit(1);
 162        }
 163        /* load initrd */
 164        if (initrd_filename) {
 165            initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
 166            initrd_size = load_image_targphys(initrd_filename, initrd_base,
 167                                              ram_size - initrd_base);
 168            if (initrd_size < 0) {
 169                hw_error("qemu: could not load initial ram disk '%s'\n",
 170                         initrd_filename);
 171                exit(1);
 172            }
 173            cmdline_base = round_page(initrd_base + initrd_size);
 174        } else {
 175            initrd_base = 0;
 176            initrd_size = 0;
 177            cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
 178        }
 179        ppc_boot_device = 'm';
 180    } else {
 181        kernel_base = 0;
 182        kernel_size = 0;
 183        initrd_base = 0;
 184        initrd_size = 0;
 185        ppc_boot_device = '\0';
 186        for (i = 0; boot_device[i] != '\0'; i++) {
 187            /* TOFIX: for now, the second IDE channel is not properly
 188             *        used by OHW. The Mac floppy disk are not emulated.
 189             *        For now, OHW cannot boot from the network.
 190             */
 191#if 0
 192            if (boot_device[i] >= 'a' && boot_device[i] <= 'f') {
 193                ppc_boot_device = boot_device[i];
 194                break;
 195            }
 196#else
 197            if (boot_device[i] >= 'c' && boot_device[i] <= 'd') {
 198                ppc_boot_device = boot_device[i];
 199                break;
 200            }
 201#endif
 202        }
 203        if (ppc_boot_device == '\0') {
 204            fprintf(stderr, "No valid boot device for G3 Beige machine\n");
 205            exit(1);
 206        }
 207    }
 208
 209    isa_mem_base = 0x80000000;
 210
 211    /* Register 2 MB of ISA IO space */
 212    isa_mmio_init(0xfe000000, 0x00200000);
 213
 214    /* XXX: we register only 1 output pin for heathrow PIC */
 215    heathrow_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
 216    heathrow_irqs[0] =
 217        qemu_mallocz(smp_cpus * sizeof(qemu_irq) * 1);
 218    /* Connect the heathrow PIC outputs to the 6xx bus */
 219    for (i = 0; i < smp_cpus; i++) {
 220        switch (PPC_INPUT(env)) {
 221        case PPC_FLAGS_INPUT_6xx:
 222            heathrow_irqs[i] = heathrow_irqs[0] + (i * 1);
 223            heathrow_irqs[i][0] =
 224                ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
 225            break;
 226        default:
 227            hw_error("Bus model not supported on OldWorld Mac machine\n");
 228        }
 229    }
 230
 231    /* init basic PC hardware */
 232    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
 233        hw_error("Only 6xx bus is supported on heathrow machine\n");
 234    }
 235    pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
 236    pci_bus = pci_grackle_init(0xfec00000, pic);
 237    pci_vga_init(pci_bus);
 238
 239    escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
 240                               serial_hds[1], ESCC_CLOCK, 4);
 241
 242    for(i = 0; i < nb_nics; i++)
 243        pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
 244
 245
 246    ide_drive_get(hd, MAX_IDE_BUS);
 247
 248    /* First IDE channel is a MAC IDE on the MacIO bus */
 249    dbdma = DBDMA_init(&dbdma_mem_index);
 250    ide_mem_index[0] = -1;
 251    ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]);
 252
 253    /* Second IDE channel is a CMD646 on the PCI bus */
 254    hd[0] = hd[MAX_IDE_DEVS];
 255    hd[1] = hd[MAX_IDE_DEVS + 1];
 256    hd[3] = hd[2] = NULL;
 257    pci_cmd646_ide_init(pci_bus, hd, 0);
 258
 259    /* cuda also initialize ADB */
 260    cuda_init(&cuda_mem_index, pic[0x12]);
 261
 262    adb_kbd_init(&adb_bus);
 263    adb_mouse_init(&adb_bus);
 264
 265    nvr = macio_nvram_init(&nvram_mem_index, 0x2000, 4);
 266    pmac_format_nvram_partition(nvr, 0x2000);
 267
 268    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem_index,
 269               dbdma_mem_index, cuda_mem_index, nvr, 2, ide_mem_index,
 270               escc_mem_index);
 271
 272    if (usb_enabled) {
 273        usb_ohci_init_pci(pci_bus, -1);
 274    }
 275
 276    if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
 277        graphic_depth = 15;
 278
 279    /* No PCI init: the BIOS will do it */
 280
 281    fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
 282    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
 283    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
 284    fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_HEATHROW);
 285    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
 286    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
 287    if (kernel_cmdline) {
 288        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
 289        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
 290    } else {
 291        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
 292    }
 293    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_base);
 294    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
 295    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ppc_boot_device);
 296
 297    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_WIDTH, graphic_width);
 298    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
 299    fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
 300
 301    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
 302    if (kvm_enabled()) {
 303#ifdef CONFIG_KVM
 304        uint8_t *hypercall;
 305
 306        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
 307        hypercall = qemu_malloc(16);
 308        kvmppc_get_hypercall(env, hypercall, 16);
 309        fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
 310        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
 311#endif
 312    } else {
 313        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
 314    }
 315
 316    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
 317}
 318
 319static QEMUMachine heathrow_machine = {
 320    .name = "g3beige",
 321    .desc = "Heathrow based PowerMAC",
 322    .init = ppc_heathrow_init,
 323    .max_cpus = MAX_CPUS,
 324#ifndef TARGET_PPC64
 325    .is_default = 1,
 326#endif
 327};
 328
 329static void heathrow_machine_init(void)
 330{
 331    qemu_register_machine(&heathrow_machine);
 332}
 333
 334machine_init(heathrow_machine_init);
 335