static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, MachineState *machine) { const char *cpu_model = machine->cpu_model; unsigned int i; void *iommu, *espdma, *ledma, *nvram; qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS], espdma_irq, ledma_irq; qemu_irq esp_reset, dma_enable; qemu_irq fdc_tc; qemu_irq *cpu_halt; unsigned long kernel_size; DriveInfo *fd[MAX_FD]; FWCfgState *fw_cfg; unsigned int num_vsimms; /* init CPUs */ if (!cpu_model) cpu_model = hwdef->default_cpu_model; for(i = 0; i < smp_cpus; i++) { cpu_devinit(cpu_model, i, hwdef->slavio_base, &cpu_irqs[i]); } for (i = smp_cpus; i < MAX_CPUS; i++) cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); /* set up devices */ ram_init(0, machine->ram_size, hwdef->max_mem); /* models without ECC don't trap when missing ram is accessed */ if (!hwdef->ecc_base) { empty_slot_init(machine->ram_size, hwdef->max_mem - machine->ram_size); } prom_init(hwdef->slavio_base, bios_name); slavio_intctl = slavio_intctl_init(hwdef->intctl_base, hwdef->intctl_base + 0x10000ULL, cpu_irqs); for (i = 0; i < 32; i++) { slavio_irq[i] = qdev_get_gpio_in(slavio_intctl, i); } for (i = 0; i < MAX_CPUS; i++) { slavio_cpu_irq[i] = qdev_get_gpio_in(slavio_intctl, 32 + i); } if (hwdef->idreg_base) { idreg_init(hwdef->idreg_base); } if (hwdef->afx_base) { afx_init(hwdef->afx_base); } iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version, slavio_irq[30]); if (hwdef->iommu_pad_base) { /* On the real hardware (SS-5, LX) the MMU is not padded, but aliased. Software shouldn't use aliased addresses, neither should it crash when does. Using empty_slot instead of aliasing can help with debugging such accesses */ empty_slot_init(hwdef->iommu_pad_base,hwdef->iommu_pad_len); } espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[18], iommu, &espdma_irq, 0); ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, slavio_irq[16], iommu, &ledma_irq, 1); if (graphic_depth != 8 && graphic_depth != 24) { error_report("Unsupported depth: %d", graphic_depth); exit (1); } num_vsimms = 0; if (num_vsimms == 0) { if (vga_interface_type == VGA_CG3) { if (graphic_depth != 8) { error_report("Unsupported depth: %d", graphic_depth); exit(1); } if (!(graphic_width == 1024 && graphic_height == 768) && !(graphic_width == 1152 && graphic_height == 900)) { error_report("Unsupported resolution: %d x %d", graphic_width, graphic_height); exit(1); } /* sbus irq 5 */ cg3_init(hwdef->tcx_base, slavio_irq[11], 0x00100000, graphic_width, graphic_height, graphic_depth); } else { /* If no display specified, default to TCX */ if (graphic_depth != 8 && graphic_depth != 24) { error_report("Unsupported depth: %d", graphic_depth); exit(1); } if (!(graphic_width == 1024 && graphic_height == 768)) { error_report("Unsupported resolution: %d x %d", graphic_width, graphic_height); exit(1); } tcx_init(hwdef->tcx_base, slavio_irq[11], 0x00100000, graphic_width, graphic_height, graphic_depth); } } for (i = num_vsimms; i < MAX_VSIMMS; i++) { /* vsimm registers probed by OBP */ if (hwdef->vsimm[i].reg_base) { empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000); } } if (hwdef->sx_base) { empty_slot_init(hwdef->sx_base, 0x2000); } lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq); nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 8); slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus); slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[14], display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1); /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */ escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15], serial_hds[0], serial_hds[1], ESCC_CLOCK, 1); cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1); if (hwdef->apc_base) { apc_init(hwdef->apc_base, cpu_halt[0]); } if (hwdef->fd_base) { /* there is zero or one floppy drive */ memset(fd, 0, sizeof(fd)); fd[0] = drive_get(IF_FLOPPY, 0, 0); sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd, &fdc_tc); } else { fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1); } slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base, slavio_irq[30], fdc_tc); if (drive_get_max_bus(IF_SCSI) > 0) { fprintf(stderr, "qemu: too many SCSI bus\n"); exit(1); } esp_init(hwdef->esp_base, 2, espdma_memory_read, espdma_memory_write, espdma, espdma_irq, &esp_reset, &dma_enable); qdev_connect_gpio_out(espdma, 0, esp_reset); qdev_connect_gpio_out(espdma, 1, dma_enable); if (hwdef->cs_base) { sysbus_create_simple("SUNW,CS4231", hwdef->cs_base, slavio_irq[5]); } if (hwdef->dbri_base) { /* ISDN chip with attached CS4215 audio codec */ /* prom space */ empty_slot_init(hwdef->dbri_base+0x1000, 0x30); /* reg space */ empty_slot_init(hwdef->dbri_base+0x10000, 0x100); } if (hwdef->bpp_base) { /* parallel port */ empty_slot_init(hwdef->bpp_base, 0x20); } kernel_size = sun4m_load_kernel(machine->kernel_filename, machine->initrd_filename, machine->ram_size); nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, machine->kernel_cmdline, machine->boot_order, machine->ram_size, kernel_size, graphic_width, graphic_height, graphic_depth, hwdef->nvram_machine_id, "Sun4m"); if (hwdef->ecc_base) ecc_init(hwdef->ecc_base, slavio_irq[28], hwdef->ecc_version); fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); 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, hwdef->machine_id); fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_DEPTH, graphic_depth); fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_WIDTH, graphic_width); fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_HEIGHT, graphic_height); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); if (machine->kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, machine->kernel_cmdline); fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, machine->kernel_cmdline); fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(machine->kernel_cmdline) + 1); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); } fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); }
static void sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { CPUState *env, *envs[MAX_CPUS]; unsigned int i; void *iommu, *espdma, *ledma, *main_esp, *nvram; qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq, *espdma_irq, *ledma_irq; qemu_irq *esp_reset, *le_reset; unsigned long prom_offset, kernel_size; int ret; char buf[1024]; BlockDriverState *fd[MAX_FD]; int index; /* init CPUs */ if (!cpu_model) cpu_model = hwdef->default_cpu_model; for(i = 0; i < smp_cpus; i++) { env = cpu_init(cpu_model); if (!env) { fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n"); exit(1); } cpu_sparc_set_id(env, i); envs[i] = env; if (i == 0) { qemu_register_reset(main_cpu_reset, env); } else { qemu_register_reset(secondary_cpu_reset, env); env->halted = 1; } register_savevm("cpu", i, 3, cpu_save, cpu_load, env); cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS); env->prom_addr = hwdef->slavio_base; } for (i = smp_cpus; i < MAX_CPUS; i++) cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); /* allocate RAM */ if ((uint64_t)RAM_size > hwdef->max_mem) { fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", (unsigned int)RAM_size / (1024 * 1024), (unsigned int)(hwdef->max_mem / (1024 * 1024))); exit(1); } cpu_register_physical_memory(0, RAM_size, 0); /* load boot prom */ prom_offset = RAM_size + hwdef->vram_size; cpu_register_physical_memory(hwdef->slavio_base, (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); if (bios_name == NULL) bios_name = PROM_FILENAME; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL); if (ret < 0 || ret > PROM_SIZE_MAX) ret = load_image(buf, phys_ram_base + prom_offset); if (ret < 0 || ret > PROM_SIZE_MAX) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); exit(1); } prom_offset += (ret + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; /* set up devices */ slavio_intctl = slavio_intctl_init(hwdef->intctl_base, hwdef->intctl_base + 0x10000ULL, &hwdef->intbit_to_level[0], &slavio_irq, &slavio_cpu_irq, cpu_irqs, hwdef->clock_irq); if (hwdef->idreg_base != (target_phys_addr_t)-1) { stl_raw(phys_ram_base + prom_offset, 0xfe810103); cpu_register_physical_memory(hwdef->idreg_base, sizeof(uint32_t), prom_offset | IO_MEM_ROM); } iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version, slavio_irq[hwdef->me_irq]); espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], iommu, &espdma_irq, &esp_reset); ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, slavio_irq[hwdef->le_irq], iommu, &ledma_irq, &le_reset); if (graphic_depth != 8 && graphic_depth != 24) { fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); exit (1); } tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size, hwdef->vram_size, graphic_width, graphic_height, graphic_depth); if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); } else if (strcmp(nd_table[0].model, "?") == 0) { fprintf(stderr, "qemu: Supported NICs: lance\n"); exit (1); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); } nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, hwdef->nvram_size, 8); slavio_timer_init_all(hwdef->counter_base, slavio_irq[hwdef->clock1_irq], slavio_cpu_irq, smp_cpus); slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq], nographic); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], serial_hds[1], serial_hds[0]); if (hwdef->fd_base != (target_phys_addr_t)-1) { /* there is zero or one floppy drive */ fd[1] = fd[0] = NULL; index = drive_get_index(IF_FLOPPY, 0, 0); if (index != -1) fd[0] = drives_table[index].bdrv; sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd); } if (drive_get_max_bus(IF_SCSI) > 0) { fprintf(stderr, "qemu: too many SCSI bus\n"); exit(1); } main_esp = esp_init(hwdef->esp_base, espdma, *espdma_irq, esp_reset); for (i = 0; i < ESP_MAX_DEVS; i++) { index = drive_get_index(IF_SCSI, 0, i); if (index == -1) continue; esp_scsi_attach(main_esp, drives_table[index].bdrv, i); } slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->power_base, slavio_irq[hwdef->me_irq]); if (hwdef->cs_base != (target_phys_addr_t)-1) cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline, initrd_filename); nvram_init((m48t59_t *)nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, RAM_size, kernel_size, graphic_width, graphic_height, graphic_depth, hwdef->machine_id, "Sun4m"); if (hwdef->ecc_base != (target_phys_addr_t)-1) ecc_init(hwdef->ecc_base, hwdef->ecc_version); }