X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/bd4524edb80610a5e5523599aaa81614a512056c..757179038c4884dc43c2ecd0f4da3facb24f262c:/hw/ppc_oldworld.c diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 46d0362559..75a312742e 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -1,3 +1,4 @@ + /* * QEMU OldWorld PowerMac (currently ~G3 Beige) hardware System Emulator * @@ -32,106 +33,53 @@ #include "net.h" #include "isa.h" #include "pci.h" +#include "usb-ohci.h" #include "boards.h" #include "fw_cfg.h" #include "escc.h" +#include "ide.h" +#include "loader.h" +#include "elf.h" +#include "kvm.h" +#include "kvm_ppc.h" +#include "blockdev.h" #define MAX_IDE_BUS 2 -#define VGA_BIOS_SIZE 65536 #define CFG_ADDR 0xf0000510 -/* temporary frame buffer OSI calls for the video.x driver. The right - solution is to modify the driver to use VGA PCI I/Os */ -/* XXX: to be removed. This is no way related to emulation */ -static int vga_osi_call (CPUState *env) +static int fw_cfg_boot_set(void *opaque, const char *boot_device) { - static int vga_vbl_enabled; - int linesize; - - // printf("osi_call R5=" REGX "\n", ppc_dump_gpr(env, 5)); - - /* same handler as PearPC, coming from the original MOL video - driver. */ - switch(env->gpr[5]) { - case 4: - break; - case 28: /* set_vmode */ - if (env->gpr[6] != 1 || env->gpr[7] != 0) - env->gpr[3] = 1; - else - env->gpr[3] = 0; - break; - case 29: /* get_vmode_info */ - if (env->gpr[6] != 0) { - if (env->gpr[6] != 1 || env->gpr[7] != 0) { - env->gpr[3] = 1; - break; - } - } - env->gpr[3] = 0; - env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */ - env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */ - env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */ - env->gpr[7] = 85 << 16; /* refresh rate */ - env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */ - linesize = ((graphic_depth + 7) >> 3) * graphic_width; - linesize = (linesize + 3) & ~3; - env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */ - break; - case 31: /* set_video power */ - env->gpr[3] = 0; - break; - case 39: /* video_ctrl */ - if (env->gpr[6] == 0 || env->gpr[6] == 1) - vga_vbl_enabled = env->gpr[6]; - env->gpr[3] = 0; - break; - case 47: - break; - case 59: /* set_color */ - /* R6 = index, R7 = RGB */ - env->gpr[3] = 0; - break; - case 64: /* get color */ - /* R6 = index */ - env->gpr[3] = 0; - break; - case 116: /* set hwcursor */ - /* R6 = x, R7 = y, R8 = visible, R9 = data */ - break; - default: - fprintf(stderr, "unsupported OSI call R5=" REGX "\n", - ppc_dump_gpr(env, 5)); - break; - } + fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]); + return 0; +} + - return 1; /* osi_call handled */ +static uint64_t translate_kernel_address(void *opaque, uint64_t addr) +{ + return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; } -static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, +static void ppc_heathrow_init (ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - CPUState *env = NULL, *envs[MAX_CPUS]; - char buf[1024]; + CPUState *env = NULL; + char *filename; qemu_irq *pic, **heathrow_irqs; - nvram_t nvram; - m48t59_t *m48t59; int linux_boot, i; - ram_addr_t ram_offset, vga_ram_offset, bios_offset, vga_bios_offset; + ram_addr_t ram_offset, bios_offset; uint32_t kernel_base, initrd_base; int32_t kernel_size, initrd_size; PCIBus *pci_bus; MacIONVRAMState *nvr; - int vga_bios_size, bios_size; + int bios_size; int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index; int escc_mem_index, ide_mem_index[2]; - int ppc_boot_device; - BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - int index; + uint16_t ppc_boot_device; + DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; void *dbdma; @@ -148,9 +96,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, } /* Set time-base frequency to 16.6 Mhz */ cpu_ppc_tb_init(env, 16600000UL); - env->osi_call = vga_osi_call; - qemu_register_reset(&cpu_ppc_reset, env); - envs[i] = env; + qemu_register_reset((QEMUResetHandler*)&cpu_reset, env); } /* allocate RAM */ @@ -161,77 +107,62 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, exit(1); } - ram_offset = qemu_ram_alloc(ram_size); + ram_offset = qemu_ram_alloc(NULL, "ppc_heathrow.ram", ram_size); cpu_register_physical_memory(0, ram_size, ram_offset); - /* allocate VGA RAM */ - vga_ram_offset = qemu_ram_alloc(vga_ram_size); - /* allocate and load BIOS */ - bios_offset = qemu_ram_alloc(BIOS_SIZE); + bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.bios", BIOS_SIZE); if (bios_name == NULL) bios_name = PROM_FILENAME; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); cpu_register_physical_memory(PROM_ADDR, BIOS_SIZE, bios_offset | IO_MEM_ROM); /* Load OpenBIOS (ELF) */ - bios_size = load_elf(buf, 0, NULL, NULL, NULL); + if (filename) { + bios_size = load_elf(filename, 0, NULL, NULL, NULL, NULL, + 1, ELF_MACHINE, 0); + qemu_free(filename); + } else { + bios_size = -1; + } if (bios_size < 0 || bios_size > BIOS_SIZE) { - cpu_abort(env, "qemu: could not load PowerPC bios '%s'\n", buf); + hw_error("qemu: could not load PowerPC bios '%s'\n", bios_name); exit(1); } - /* allocate and load VGA BIOS */ - vga_bios_offset = qemu_ram_alloc(VGA_BIOS_SIZE); - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); - vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8); - if (vga_bios_size < 0) { - /* if no bios is present, we can still work */ - fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf); - vga_bios_size = 0; - } else { - /* set a specific header (XXX: find real Apple format for NDRV - drivers) */ - phys_ram_base[vga_bios_offset] = 'N'; - phys_ram_base[vga_bios_offset + 1] = 'D'; - phys_ram_base[vga_bios_offset + 2] = 'R'; - phys_ram_base[vga_bios_offset + 3] = 'V'; - cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4), - vga_bios_size); - vga_bios_size += 8; - } - if (linux_boot) { uint64_t lowaddr = 0; + int bswap_needed; + +#ifdef BSWAP_NEEDED + bswap_needed = 1; +#else + bswap_needed = 0; +#endif kernel_base = KERNEL_LOAD_ADDR; - /* Now we can load the kernel. The first step tries to load the kernel - supposing PhysAddr = 0x00000000. If that was wrong the kernel is - loaded again, the new PhysAddr being computed from lowaddr. */ - kernel_size = load_elf(kernel_filename, kernel_base, NULL, &lowaddr, NULL); - if (kernel_size > 0 && lowaddr != KERNEL_LOAD_ADDR) { - kernel_size = load_elf(kernel_filename, (2 * kernel_base) - lowaddr, - NULL, 0, NULL); - } + kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, + NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, kernel_base, - ram_size - kernel_base); + ram_size - kernel_base, bswap_needed, + TARGET_PAGE_SIZE); if (kernel_size < 0) kernel_size = load_image_targphys(kernel_filename, kernel_base, ram_size - kernel_base); if (kernel_size < 0) { - cpu_abort(env, "qemu: could not load kernel '%s'\n", + hw_error("qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } /* load initrd */ if (initrd_filename) { initrd_base = INITRD_LOAD_ADDR; - initrd_size = load_image(initrd_filename, - phys_ram_base + initrd_base); + initrd_size = load_image_targphys(initrd_filename, initrd_base, + ram_size - initrd_base); if (initrd_size < 0) { - cpu_abort(env, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); + hw_error("qemu: could not load initial ram disk '%s'\n", + initrd_filename); exit(1); } } else { @@ -286,60 +217,35 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; break; default: - cpu_abort(env, "Bus model not supported on OldWorld Mac machine\n"); - exit(1); + hw_error("Bus model not supported on OldWorld Mac machine\n"); } } /* init basic PC hardware */ if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) { - cpu_abort(env, "Only 6xx bus is supported on heathrow machine\n"); - exit(1); + hw_error("Only 6xx bus is supported on heathrow machine\n"); } pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs); pci_bus = pci_grackle_init(0xfec00000, pic); - pci_vga_init(pci_bus, phys_ram_base + vga_ram_offset, - vga_ram_offset, vga_ram_size, - vga_bios_offset, vga_bios_size); + pci_vga_init(pci_bus); escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); for(i = 0; i < nb_nics; i++) - pci_nic_init(pci_bus, &nd_table[i], -1, "ne2k_pci"); + pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); - if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { - fprintf(stderr, "qemu: too many IDE bus\n"); - exit(1); - } + ide_drive_get(hd, MAX_IDE_BUS); /* First IDE channel is a MAC IDE on the MacIO bus */ - index = drive_get_index(IF_IDE, 0, 0); - if (index == -1) - hd[0] = NULL; - else - hd[0] = drives_table[index].bdrv; - index = drive_get_index(IF_IDE, 0, 1); - if (index == -1) - hd[1] = NULL; - else - hd[1] = drives_table[index].bdrv; dbdma = DBDMA_init(&dbdma_mem_index); ide_mem_index[0] = -1; ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]); /* Second IDE channel is a CMD646 on the PCI bus */ - index = drive_get_index(IF_IDE, 1, 0); - if (index == -1) - hd[0] = NULL; - else - hd[0] = drives_table[index].bdrv; - index = drive_get_index(IF_IDE, 1, 1); - if (index == -1) - hd[1] = NULL; - else - hd[1] = drives_table[index].bdrv; + hd[0] = hd[MAX_IDE_DEVS]; + hd[1] = hd[MAX_IDE_DEVS + 1]; hd[3] = hd[2] = NULL; pci_cmd646_ide_init(pci_bus, hd, 0); @@ -357,35 +263,65 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size, escc_mem_index); if (usb_enabled) { - usb_ohci_init_pci(pci_bus, 3, -1); + usb_ohci_init_pci(pci_bus, -1); } if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) graphic_depth = 15; - m48t59 = m48t59_init(0, 0xFFF04000, 0x0074, NVRAM_SIZE, 59); - nvram.opaque = m48t59; - nvram.read_fn = &m48t59_read; - nvram.write_fn = &m48t59_write; - PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "HEATHROW", ram_size, - ppc_boot_device, kernel_base, kernel_size, - kernel_cmdline, - initrd_base, initrd_size, - /* XXX: need an option to load a NVRAM image */ - 0, - graphic_width, graphic_height, graphic_depth); /* No PCI init: the BIOS will do it */ fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_HEATHROW); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); + if (kernel_cmdline) { + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); + pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); + } + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_base); + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); + fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ppc_boot_device); + + fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_WIDTH, graphic_width); + fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height); + fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth); + + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled()); + if (kvm_enabled()) { +#ifdef CONFIG_KVM + uint8_t *hypercall; + + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq()); + hypercall = qemu_malloc(16); + kvmppc_get_hypercall(env, hypercall, 16); + fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16); + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid()); +#endif + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec()); + } + + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } -QEMUMachine heathrow_machine = { +static QEMUMachine heathrow_machine = { .name = "g3beige", .desc = "Heathrow based PowerMAC", .init = ppc_heathrow_init, - .ram_require = BIOS_SIZE + VGA_BIOS_SIZE + VGA_RAM_SIZE, .max_cpus = MAX_CPUS, +#ifndef TARGET_PPC64 + .is_default = 1, +#endif }; + +static void heathrow_machine_init(void) +{ + qemu_register_machine(&heathrow_machine); +} + +machine_init(heathrow_machine_init);