static unsigned long sun4m_load_kernel(const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename) { int linux_boot; unsigned int i; long initrd_size, kernel_size; linux_boot = (kernel_filename != NULL); kernel_size = 0; if (linux_boot) { kernel_size = load_elf(kernel_filename, -0xf0000000ULL, NULL, NULL, NULL); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } /* load initrd */ initrd_size = 0; if (initrd_filename) { initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } } if (initrd_size > 0) { for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) == 0x48647253) { // HdrS stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); break; } } } } return kernel_size; }
/* coalesce internal state, copy to pci i/o region 0 */ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) { VirtIOBlock *s = to_virtio_blk(vdev); struct virtio_blk_config blkcfg; uint64_t capacity; int blk_size = s->conf->logical_block_size; bdrv_get_geometry(s->bs, &capacity); memset(&blkcfg, 0, sizeof(blkcfg)); stq_raw(&blkcfg.capacity, capacity); stl_raw(&blkcfg.seg_max, 128 - 2); stw_raw(&blkcfg.cylinders, s->conf->cyls); stl_raw(&blkcfg.blk_size, blk_size); stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size); stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size); blkcfg.heads = s->conf->heads; /* * We must ensure that the block device capacity is a multiple of * the logical block size. If that is not the case, lets use * sector_mask to adopt the geometry to have a correct picture. * For those devices where the capacity is ok for the given geometry * we dont touch the sector value of the geometry, since some devices * (like s390 dasd) need a specific value. Here the capacity is already * cyls*heads*secs*blk_size and the sector value is not block size * divided by 512 - instead it is the amount of blk_size blocks * per track (cylinder). */ if (bdrv_getlength(s->bs) / s->conf->heads / s->conf->secs % blk_size) { blkcfg.sectors = s->conf->secs & ~s->sector_mask; } else { blkcfg.sectors = s->conf->secs; } blkcfg.size_max = 0; blkcfg.physical_block_exp = get_physical_block_exp(s->conf); blkcfg.alignment_offset = 0; blkcfg.wce = bdrv_enable_write_cache(s->bs); memcpy(config, &blkcfg, sizeof(struct virtio_blk_config)); }
/* coalesce internal state, copy to pci i/o region 0 */ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) { VirtIOBlock *s = to_virtio_blk(vdev); struct virtio_blk_config blkcfg; uint64_t capacity; int cylinders, heads, secs; int blk_size = s->conf->logical_block_size; bdrv_get_geometry(s->bs, &capacity); bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); memset(&blkcfg, 0, sizeof(blkcfg)); stq_raw(&blkcfg.capacity, capacity); stl_raw(&blkcfg.seg_max, 128 - 2); stw_raw(&blkcfg.cylinders, cylinders); stl_raw(&blkcfg.blk_size, blk_size); stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size); stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size); blkcfg.heads = heads; blkcfg.sectors = secs & ~s->sector_mask; blkcfg.size_max = 0; blkcfg.physical_block_exp = get_physical_block_exp(s->conf); blkcfg.alignment_offset = 0; memcpy(config, &blkcfg, sizeof(struct virtio_blk_config)); }
static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) { VirtIOBlock *s = to_virtio_blk(vdev); struct virtio_blk_config blkcfg; uint64_t capacity; int cylinders, heads, secs; bdrv_get_geometry(s->bs, &capacity); bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); stq_raw(&blkcfg.capacity, capacity); stl_raw(&blkcfg.seg_max, 128 - 2); stw_raw(&blkcfg.cylinders, cylinders); blkcfg.heads = heads; blkcfg.sectors = secs; memcpy(config, &blkcfg, sizeof(blkcfg)); }
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); }