diff options
57 files changed, 669 insertions, 243 deletions
diff --git a/.gitmodules b/.gitmodules index 49e9c2e3f4..d108478e0a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "roms/vgabios"] - path = roms/vgabios - url = git://git.qemu-project.org/vgabios.git/ [submodule "roms/seabios"] path = roms/seabios url = git://git.qemu-project.org/seabios.git/ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index eebe97dabb..20c147d655 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -235,20 +235,30 @@ void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *src_cpu, async_safe_run_on_cpu(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); } +static inline bool tlb_hit_page_anyprot(CPUTLBEntry *tlb_entry, + target_ulong page) +{ + return tlb_hit_page(tlb_entry->addr_read, page) || + tlb_hit_page(tlb_entry->addr_write, page) || + tlb_hit_page(tlb_entry->addr_code, page); +} - -static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) +static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong page) { - if (addr == (tlb_entry->addr_read & - (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || - addr == (tlb_entry->addr_write & - (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || - addr == (tlb_entry->addr_code & - (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (tlb_hit_page_anyprot(tlb_entry, page)) { memset(tlb_entry, -1, sizeof(*tlb_entry)); } } +static inline void tlb_flush_vtlb_page(CPUArchState *env, int mmu_idx, + target_ulong page) +{ + int k; + for (k = 0; k < CPU_VTLB_SIZE; k++) { + tlb_flush_entry(&env->tlb_v_table[mmu_idx][k], page); + } +} + static void tlb_flush_page_async_work(CPUState *cpu, run_on_cpu_data data) { CPUArchState *env = cpu->env_ptr; @@ -274,14 +284,7 @@ static void tlb_flush_page_async_work(CPUState *cpu, run_on_cpu_data data) i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr); - } - - /* check whether there are entries that need to be flushed in the vtlb */ - for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { - int k; - for (k = 0; k < CPU_VTLB_SIZE; k++) { - tlb_flush_entry(&env->tlb_v_table[mmu_idx][k], addr); - } + tlb_flush_vtlb_page(env, mmu_idx, addr); } tb_flush_jmp_cache(cpu, addr); @@ -313,7 +316,6 @@ static void tlb_flush_page_by_mmuidx_async_work(CPUState *cpu, unsigned long mmu_idx_bitmap = addr_and_mmuidx & ALL_MMUIDX_BITS; int page = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); int mmu_idx; - int i; assert_cpu_is_self(cpu); @@ -323,11 +325,7 @@ static void tlb_flush_page_by_mmuidx_async_work(CPUState *cpu, for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { if (test_bit(mmu_idx, &mmu_idx_bitmap)) { tlb_flush_entry(&env->tlb_table[mmu_idx][page], addr); - - /* check whether there are vltb entries that need to be flushed */ - for (i = 0; i < CPU_VTLB_SIZE; i++) { - tlb_flush_entry(&env->tlb_v_table[mmu_idx][i], addr); - } + tlb_flush_vtlb_page(env, mmu_idx, addr); } } @@ -612,10 +610,9 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, target_ulong address; target_ulong code_address; uintptr_t addend; - CPUTLBEntry *te, *tv, tn; + CPUTLBEntry *te, tn; hwaddr iotlb, xlat, sz, paddr_page; target_ulong vaddr_page; - unsigned vidx = env->vtlb_index++ % CPU_VTLB_SIZE; int asidx = cpu_asidx_from_attrs(cpu, attrs); assert_cpu_is_self(cpu); @@ -657,19 +654,28 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, addend = (uintptr_t)memory_region_get_ram_ptr(section->mr) + xlat; } + /* Make sure there's no cached translation for the new page. */ + tlb_flush_vtlb_page(env, mmu_idx, vaddr_page); + code_address = address; iotlb = memory_region_section_get_iotlb(cpu, section, vaddr_page, paddr_page, xlat, prot, &address); index = (vaddr_page >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); te = &env->tlb_table[mmu_idx][index]; - /* do not discard the translation in te, evict it into a victim tlb */ - tv = &env->tlb_v_table[mmu_idx][vidx]; - /* addr_write can race with tlb_reset_dirty_range */ - copy_tlb_helper(tv, te, true); + /* + * Only evict the old entry to the victim tlb if it's for a + * different page; otherwise just overwrite the stale data. + */ + if (!tlb_hit_page_anyprot(te, vaddr_page)) { + unsigned vidx = env->vtlb_index++ % CPU_VTLB_SIZE; + CPUTLBEntry *tv = &env->tlb_v_table[mmu_idx][vidx]; - env->iotlb_v[mmu_idx][vidx] = env->iotlb[mmu_idx][index]; + /* Evict the old entry into the victim tlb. */ + copy_tlb_helper(tv, te, true); + env->iotlb_v[mmu_idx][vidx] = env->iotlb[mmu_idx][index]; + } /* refill the tlb */ /* @@ -960,14 +966,14 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr) index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); mmu_idx = cpu_mmu_index(env, true); - if (unlikely(env->tlb_table[mmu_idx][index].addr_code != - (addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)))) { + if (unlikely(!tlb_hit(env->tlb_table[mmu_idx][index].addr_code, addr))) { if (!VICTIM_TLB_HIT(addr_read, addr)) { tlb_fill(ENV_GET_CPU(env), addr, 0, MMU_INST_FETCH, mmu_idx, 0); } } - if (unlikely(env->tlb_table[mmu_idx][index].addr_code & TLB_RECHECK)) { + if (unlikely((env->tlb_table[mmu_idx][index].addr_code & + (TLB_RECHECK | TLB_INVALID_MASK)) == TLB_RECHECK)) { /* * This is a TLB_RECHECK access, where the MMU protection * covers a smaller range than a target page, and we must @@ -1046,8 +1052,7 @@ void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx, int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write; - if ((addr & TARGET_PAGE_MASK) - != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (!tlb_hit(tlb_addr, addr)) { /* TLB entry is for a different page */ if (!VICTIM_TLB_HIT(addr_write, addr)) { tlb_fill(ENV_GET_CPU(env), addr, size, MMU_DATA_STORE, @@ -1091,8 +1096,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, } /* Check TLB entry and enforce page permissions. */ - if ((addr & TARGET_PAGE_MASK) - != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (!tlb_hit(tlb_addr, addr)) { if (!VICTIM_TLB_HIT(addr_write, addr)) { tlb_fill(ENV_GET_CPU(env), addr, 1 << s_bits, MMU_DATA_STORE, mmu_idx, retaddr); diff --git a/accel/tcg/softmmu_template.h b/accel/tcg/softmmu_template.h index c47591c970..badbf14880 100644 --- a/accel/tcg/softmmu_template.h +++ b/accel/tcg/softmmu_template.h @@ -123,8 +123,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, } /* If the TLB entry is for a different page, reload and try again. */ - if ((addr & TARGET_PAGE_MASK) - != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (!tlb_hit(tlb_addr, addr)) { if (!VICTIM_TLB_HIT(ADDR_READ, addr)) { tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, READ_ACCESS_TYPE, mmu_idx, retaddr); @@ -191,8 +190,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, } /* If the TLB entry is for a different page, reload and try again. */ - if ((addr & TARGET_PAGE_MASK) - != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (!tlb_hit(tlb_addr, addr)) { if (!VICTIM_TLB_HIT(ADDR_READ, addr)) { tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, READ_ACCESS_TYPE, mmu_idx, retaddr); @@ -286,8 +284,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } /* If the TLB entry is for a different page, reload and try again. */ - if ((addr & TARGET_PAGE_MASK) - != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (!tlb_hit(tlb_addr, addr)) { if (!VICTIM_TLB_HIT(addr_write, addr)) { tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, MMU_DATA_STORE, mmu_idx, retaddr); @@ -322,7 +319,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, page2 = (addr + DATA_SIZE) & TARGET_PAGE_MASK; index2 = (page2 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); tlb_addr2 = env->tlb_table[mmu_idx][index2].addr_write; - if (page2 != (tlb_addr2 & (TARGET_PAGE_MASK | TLB_INVALID_MASK)) + if (!tlb_hit_page(tlb_addr2, page2) && !VICTIM_TLB_HIT(addr_write, page2)) { tlb_fill(ENV_GET_CPU(env), page2, DATA_SIZE, MMU_DATA_STORE, mmu_idx, retaddr); @@ -364,8 +361,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } /* If the TLB entry is for a different page, reload and try again. */ - if ((addr & TARGET_PAGE_MASK) - != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (!tlb_hit(tlb_addr, addr)) { if (!VICTIM_TLB_HIT(addr_write, addr)) { tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, MMU_DATA_STORE, mmu_idx, retaddr); @@ -400,7 +396,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, page2 = (addr + DATA_SIZE) & TARGET_PAGE_MASK; index2 = (page2 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); tlb_addr2 = env->tlb_table[mmu_idx][index2].addr_write; - if (page2 != (tlb_addr2 & (TARGET_PAGE_MASK | TLB_INVALID_MASK)) + if (!tlb_hit_page(tlb_addr2, page2) && !VICTIM_TLB_HIT(addr_write, page2)) { tlb_fill(ENV_GET_CPU(env), page2, DATA_SIZE, MMU_DATA_STORE, mmu_idx, retaddr); diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index e8228bf3e6..170b95793f 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -669,9 +669,15 @@ static inline void page_lock_tb(const TranslationBlock *tb) static inline void page_unlock_tb(const TranslationBlock *tb) { - page_unlock(page_find(tb->page_addr[0] >> TARGET_PAGE_BITS)); + PageDesc *p1 = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); + + page_unlock(p1); if (unlikely(tb->page_addr[1] != -1)) { - page_unlock(page_find(tb->page_addr[1] >> TARGET_PAGE_BITS)); + PageDesc *p2 = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); + + if (p2 != p1) { + page_unlock(p2); + } } } @@ -850,22 +856,34 @@ static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1, PageDesc **ret_p2, tb_page_addr_t phys2, int alloc) { PageDesc *p1, *p2; + tb_page_addr_t page1; + tb_page_addr_t page2; assert_memory_lock(); - g_assert(phys1 != -1 && phys1 != phys2); - p1 = page_find_alloc(phys1 >> TARGET_PAGE_BITS, alloc); + g_assert(phys1 != -1); + + page1 = phys1 >> TARGET_PAGE_BITS; + page2 = phys2 >> TARGET_PAGE_BITS; + + p1 = page_find_alloc(page1, alloc); if (ret_p1) { *ret_p1 = p1; } if (likely(phys2 == -1)) { page_lock(p1); return; + } else if (page1 == page2) { + page_lock(p1); + if (ret_p2) { + *ret_p2 = p1; + } + return; } - p2 = page_find_alloc(phys2 >> TARGET_PAGE_BITS, alloc); + p2 = page_find_alloc(page2, alloc); if (ret_p2) { *ret_p2 = p2; } - if (phys1 < phys2) { + if (page1 < page2) { page_lock(p1); page_lock(p2); } else { @@ -1623,7 +1641,7 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, tb = existing_tb; } - if (p2) { + if (p2 && p2 != p) { page_unlock(p2); } page_unlock(p); diff --git a/disas/m68k.c b/disas/m68k.c index 61b689ef3e..a687df437c 100644 --- a/disas/m68k.c +++ b/disas/m68k.c @@ -2017,6 +2017,20 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info) } } + /* Don't match FPU insns with non-default coprocessor ID. */ + if (*d == '\0') + { + for (d = opc->args; *d; d += 2) + { + if (d[0] == 'I') + { + val = fetch_arg (buffer, 'd', 3, info); + if (val != 1) + break; + } + } + } + if (*d == '\0') if ((val = match_insn_m68k (memaddr, info, opc, & priv))) return val; diff --git a/hw/core/loader.c b/hw/core/loader.c index 06bdbca537..bbb6e65bb5 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -191,7 +191,7 @@ void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size, rom_add_blob_fixed(name, source, (nulp - source) + 1, dest); } else { rom_add_blob_fixed(name, source, buf_size, dest); - ptr = rom_ptr(dest + buf_size - 1); + ptr = rom_ptr(dest + buf_size - 1, sizeof(*ptr)); *ptr = 0; } } @@ -1165,7 +1165,7 @@ void rom_reset_order_override(void) fw_cfg_reset_order_override(fw_cfg); } -static Rom *find_rom(hwaddr addr) +static Rom *find_rom(hwaddr addr, size_t size) { Rom *rom; @@ -1179,7 +1179,7 @@ static Rom *find_rom(hwaddr addr) if (rom->addr > addr) { continue; } - if (rom->addr + rom->romsize < addr) { + if (rom->addr + rom->romsize < addr + size) { continue; } return rom; @@ -1249,11 +1249,11 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) return (d + l) - dest; } -void *rom_ptr(hwaddr addr) +void *rom_ptr(hwaddr addr, size_t size) { Rom *rom; - rom = find_rom(addr); + rom = find_rom(addr, size); if (!rom || !rom->data) return NULL; return rom->data + (addr - rom->addr); diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c index 5e0c1f1914..09d8944a1b 100644 --- a/hw/display/bochs-display.c +++ b/hw/display/bochs-display.c @@ -338,6 +338,7 @@ static void bochs_display_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_QEMU_VGA; k->realize = bochs_display_realize; + k->romfile = "vgabios-bochs-display.bin"; k->exit = bochs_display_exit; dc->vmsd = &vmstate_bochs_display; dc->props = bochs_display_properties; diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c index 30f5c8da20..25c8ad7c25 100644 --- a/hw/display/ramfb.c +++ b/hw/display/ramfb.c @@ -88,6 +88,7 @@ RAMFBState *ramfb_setup(Error **errp) s = g_new0(RAMFBState, 1); + rom_add_vga("vgabios-ramfb.bin"); fw_cfg_add_file_callback(fw_cfg, "etc/ramfb", NULL, ramfb_fw_cfg_write, s, &s->cfg, sizeof(s->cfg), false); diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 1603f9a762..3467451482 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -1136,11 +1136,13 @@ void mips_malta_init(MachineState *machine) a neat trick which allows bi-endian firmware. */ #ifndef TARGET_WORDS_BIGENDIAN { - uint32_t *end, *addr = rom_ptr(FLASH_ADDRESS); + uint32_t *end, *addr; + const size_t swapsize = MIN(bios_size, 0x3e0000); + addr = rom_ptr(FLASH_ADDRESS, swapsize); if (!addr) { addr = memory_region_get_ram_ptr(bios); } - end = (void *)addr + MIN(bios_size, 0x3e0000); + end = (void *)addr + swapsize; while (addr < end) { bswap32s(addr); addr++; diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index dc704b57d6..93282f7c59 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -14,6 +14,9 @@ obj-$(CONFIG_PCI) += s390-pci-bus.o s390-pci-inst.o obj-$(call lnot,$(CONFIG_PCI)) += s390-pci-stub.o obj-y += s390-skeys.o obj-y += s390-stattrib.o +obj-y += tod.o +obj-$(CONFIG_KVM) += tod-kvm.o +obj-$(CONFIG_TCG) += tod-qemu.o obj-$(CONFIG_KVM) += s390-skeys-kvm.o obj-$(CONFIG_KVM) += s390-stattrib-kvm.o obj-y += s390-ccw.o diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 0d67349004..21f64ad26a 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -33,7 +33,6 @@ #define KERN_PARM_AREA 0x010480UL #define INITRD_START 0x800000UL #define INITRD_PARM_START 0x010408UL -#define INITRD_PARM_SIZE 0x010410UL #define PARMFILE_START 0x001000UL #define ZIPL_IMAGE_START 0x009000UL #define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64) @@ -165,12 +164,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) goto error; } /* if this is Linux use KERN_IMAGE_START */ - magic = rom_ptr(LINUX_MAGIC_ADDR); + magic = rom_ptr(LINUX_MAGIC_ADDR, 6); if (magic && !memcmp(magic, "S390EP", 6)) { pentry = KERN_IMAGE_START; } else { /* if not Linux load the address of the (short) IPL PSW */ - ipl_psw = rom_ptr(4); + ipl_psw = rom_ptr(4, 4); if (ipl_psw) { pentry = be32_to_cpu(*ipl_psw) & 0x7fffffffUL; } else { @@ -186,9 +185,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) * loader) and it won't work. For this case we force it to 0x10000, too. */ if (pentry == KERN_IMAGE_START || pentry == 0x800) { + char *parm_area = rom_ptr(KERN_PARM_AREA, strlen(ipl->cmdline) + 1); ipl->start_addr = KERN_IMAGE_START; /* Overwrite parameters in the kernel image, which are "rom" */ - strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline); + if (parm_area) { + strcpy(parm_area, ipl->cmdline); + } } else { ipl->start_addr = pentry; } @@ -196,6 +198,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) if (ipl->initrd) { ram_addr_t initrd_offset; int initrd_size; + uint64_t *romptr; initrd_offset = INITRD_START; while (kernel_size + 0x100000 > initrd_offset) { @@ -212,8 +215,11 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) * we have to overwrite values in the kernel image, * which are "rom" */ - stq_p(rom_ptr(INITRD_PARM_START), initrd_offset); - stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size); + romptr = rom_ptr(INITRD_PARM_START, 16); + if (romptr) { + stq_p(romptr, initrd_offset); + stq_p(romptr + 1, initrd_size); + } } } /* @@ -535,7 +541,13 @@ void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type) ipl->iplb_valid = s390_gen_initial_iplb(ipl); } } - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + if (reset_type == S390_RESET_MODIFIED_CLEAR || + reset_type == S390_RESET_LOAD_NORMAL) { + /* ignore -no-reboot, send no event */ + qemu_system_reset_request(SHUTDOWN_CAUSE_SUBSYSTEM_RESET); + } else { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } /* as this is triggered by a CPU, make sure to exit the loop */ if (tcg_enabled()) { cpu_loop_exit(cs); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 7ae5fb38dd..7983185d04 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -35,6 +35,7 @@ #include "migration/register.h" #include "cpu_models.h" #include "hw/nmi.h" +#include "hw/s390x/tod.h" S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) { @@ -187,58 +188,6 @@ static void s390_memory_init(ram_addr_t mem_size) s390_stattrib_init(); } -#define S390_TOD_CLOCK_VALUE_MISSING 0x00 -#define S390_TOD_CLOCK_VALUE_PRESENT 0x01 - -static void gtod_save(QEMUFile *f, void *opaque) -{ - uint64_t tod_low; - uint8_t tod_high; - int r; - - r = s390_get_clock(&tod_high, &tod_low); - if (r) { - warn_report("Unable to get guest clock for migration: %s", - strerror(-r)); - error_printf("Guest clock will not be migrated " - "which could cause the guest to hang."); - qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING); - return; - } - - qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT); - qemu_put_byte(f, tod_high); - qemu_put_be64(f, tod_low); -} - -static int gtod_load(QEMUFile *f, void *opaque, int version_id) -{ - uint64_t tod_low; - uint8_t tod_high; - int r; - - if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) { - warn_report("Guest clock was not migrated. This could " - "cause the guest to hang."); - return 0; - } - - tod_high = qemu_get_byte(f); - tod_low = qemu_get_be64(f); - - r = s390_set_clock(&tod_high, &tod_low); - if (r) { - error_report("Unable to set KVM guest TOD clock: %s", strerror(-r)); - } - - return r; -} - -static SaveVMHandlers savevm_gtod = { - .save_state = gtod_save, - .load_state = gtod_load, -}; - static void s390_init_ipl_dev(const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *firmware, @@ -363,8 +312,8 @@ static void ccw_init(MachineState *machine) s390_create_sclpconsole("sclplmconsole", serial_hd(1)); } - /* Register savevm handler for guest TOD clock */ - register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, NULL); + /* init the TOD clock */ + s390_init_tod(); } static void s390_cpu_plug(HotplugHandler *hotplug_dev, @@ -824,6 +773,8 @@ DEFINE_CCW_MACHINE(3_0, "3.0", true); static void ccw_machine_2_12_instance_options(MachineState *machine) { ccw_machine_3_0_instance_options(machine); + s390_cpudef_featoff_greater(11, 1, S390_FEAT_PPA15); + s390_cpudef_featoff_greater(11, 1, S390_FEAT_BPB); } static void ccw_machine_2_12_class_options(MachineClass *mc) diff --git a/hw/s390x/tod-kvm.c b/hw/s390x/tod-kvm.c new file mode 100644 index 0000000000..df564ab89c --- /dev/null +++ b/hw/s390x/tod-kvm.c @@ -0,0 +1,64 @@ +/* + * TOD (Time Of Day) clock - KVM implementation + * + * Copyright 2018 Red Hat, Inc. + * Author(s): David Hildenbrand <david@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/s390x/tod.h" +#include "kvm_s390x.h" + +static void kvm_s390_tod_get(const S390TODState *td, S390TOD *tod, Error **errp) +{ + int r; + + r = kvm_s390_get_clock_ext(&tod->high, &tod->low); + if (r == -ENXIO) { + r = kvm_s390_get_clock(&tod->high, &tod->low); + } + if (r) { + error_setg(errp, "Unable to get KVM guest TOD clock: %s", + strerror(-r)); + } +} + +static void kvm_s390_tod_set(S390TODState *td, const S390TOD *tod, Error **errp) +{ + int r; + + r = kvm_s390_set_clock_ext(tod->high, tod->low); + if (r == -ENXIO) { + r = kvm_s390_set_clock(tod->high, tod->low); + } + if (r) { + error_setg(errp, "Unable to set KVM guest TOD clock: %s", + strerror(-r)); + } +} + +static void kvm_s390_tod_class_init(ObjectClass *oc, void *data) +{ + S390TODClass *tdc = S390_TOD_CLASS(oc); + + tdc->get = kvm_s390_tod_get; + tdc->set = kvm_s390_tod_set; +} + +static TypeInfo kvm_s390_tod_info = { + .name = TYPE_KVM_S390_TOD, + .parent = TYPE_S390_TOD, + .instance_size = sizeof(S390TODState), + .class_init = kvm_s390_tod_class_init, + .class_size = sizeof(S390TODClass), +}; + +static void register_types(void) +{ + type_register_static(&kvm_s390_tod_info); +} +type_init(register_types); diff --git a/hw/s390x/tod-qemu.c b/hw/s390x/tod-qemu.c new file mode 100644 index 0000000000..59c015c69d --- /dev/null +++ b/hw/s390x/tod-qemu.c @@ -0,0 +1,87 @@ +/* + * TOD (Time Of Day) clock - QEMU implementation + * + * Copyright 2018 Red Hat, Inc. + * Author(s): David Hildenbrand <david@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/s390x/tod.h" +#include "qemu/timer.h" +#include "qemu/cutils.h" +#include "cpu.h" +#include "tcg_s390x.h" + +static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod, + Error **errp) +{ + *tod = td->base; + + tod->low += time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + if (tod->low < td->base.low) { + tod->high++; + } +} + +static void qemu_s390_tod_set(S390TODState *td, const S390TOD *tod, + Error **errp) +{ + CPUState *cpu; + + td->base = *tod; + + td->base.low -= time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + if (td->base.low > tod->low) { + td->base.high--; + } + + /* + * The TOD has been changed and we have to recalculate the CKC values + * for all CPUs. We do this asynchronously, as "SET CLOCK should be + * issued only while all other activity on all CPUs .. has been + * suspended". + */ + CPU_FOREACH(cpu) { + async_run_on_cpu(cpu, tcg_s390_tod_updated, RUN_ON_CPU_NULL); + } +} + +static void qemu_s390_tod_class_init(ObjectClass *oc, void *data) +{ + S390TODClass *tdc = S390_TOD_CLASS(oc); + + tdc->get = qemu_s390_tod_get; + tdc->set = qemu_s390_tod_set; +} + +static void qemu_s390_tod_init(Object *obj) +{ + S390TODState *td = S390_TOD(obj); + struct tm tm; + + qemu_get_timedate(&tm, 0); + td->base.high = 0; + td->base.low = TOD_UNIX_EPOCH + (time2tod(mktimegm(&tm)) * 1000000000ULL); + if (td->base.low < TOD_UNIX_EPOCH) { + td->base.high += 1; + } +} + +static TypeInfo qemu_s390_tod_info = { + .name = TYPE_QEMU_S390_TOD, + .parent = TYPE_S390_TOD, + .instance_size = sizeof(S390TODState), + .instance_init = qemu_s390_tod_init, + .class_init = qemu_s390_tod_class_init, + .class_size = sizeof(S390TODClass), +}; + +static void register_types(void) +{ + type_register_static(&qemu_s390_tod_info); +} +type_init(register_types); diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c new file mode 100644 index 0000000000..1c63f411e6 --- /dev/null +++ b/hw/s390x/tod.c @@ -0,0 +1,130 @@ +/* + * TOD (Time Of Day) clock + * + * Copyright 2018 Red Hat, Inc. + * Author(s): David Hildenbrand <david@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/s390x/tod.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "sysemu/kvm.h" +#include "migration/register.h" + +void s390_init_tod(void) +{ + Object *obj; + + if (kvm_enabled()) { + obj = object_new(TYPE_KVM_S390_TOD); + } else { + obj = object_new(TYPE_QEMU_S390_TOD); + } + object_property_add_child(qdev_get_machine(), TYPE_S390_TOD, obj, NULL); + object_unref(obj); + + qdev_init_nofail(DEVICE(obj)); +} + +S390TODState *s390_get_todstate(void) +{ + static S390TODState *ts; + + if (!ts) { + ts = S390_TOD(object_resolve_path_type("", TYPE_S390_TOD, NULL)); + } + + return ts; +} + +#define S390_TOD_CLOCK_VALUE_MISSING 0x00 +#define S390_TOD_CLOCK_VALUE_PRESENT 0x01 + +static void s390_tod_save(QEMUFile *f, void *opaque) +{ + S390TODState *td = opaque; + S390TODClass *tdc = S390_TOD_GET_CLASS(td); + Error *err = NULL; + S390TOD tod; + + tdc->get(td, &tod, &err); + if (err) { + warn_report_err(err); + error_printf("Guest clock will not be migrated " + "which could cause the guest to hang."); + qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING); + return; + } + + qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT); + qemu_put_byte(f, tod.high); + qemu_put_be64(f, tod.low); +} + +static int s390_tod_load(QEMUFile *f, void *opaque, int version_id) +{ + S390TODState *td = opaque; + S390TODClass *tdc = S390_TOD_GET_CLASS(td); + Error *err = NULL; + S390TOD tod; + + if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) { + warn_report("Guest clock was not migrated. This could " + "cause the guest to hang."); + return 0; + } + + tod.high = qemu_get_byte(f); + tod.low = qemu_get_be64(f); + + tdc->set(td, &tod, &err); + if (err) { + error_report_err(err); + return -1; + } + return 0; +} + +static SaveVMHandlers savevm_tod = { + .save_state = s390_tod_save, + .load_state = s390_tod_load, +}; + +static void s390_tod_realize(DeviceState *dev, Error **errp) +{ + S390TODState *td = S390_TOD(dev); + + /* Legacy migration interface */ + register_savevm_live(NULL, "todclock", 0, 1, &savevm_tod, td); +} + +static void s390_tod_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->desc = "TOD (Time Of Day) Clock"; + dc->realize = s390_tod_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + /* We only have one TOD clock in the system attached to the machine */ + dc->user_creatable = false; +} + +static TypeInfo s390_tod_info = { + .name = TYPE_S390_TOD, + .parent = TYPE_DEVICE, + .instance_size = sizeof(S390TODState), + .class_init = s390_tod_class_init, + .class_size = sizeof(S390TODClass), + .abstract = true, +}; + +static void register_types(void) +{ + type_register_static(&s390_tod_info); +} +type_init(register_types); diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index a9d477572e..d981de1841 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -272,8 +272,8 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename, } if (initrd_size > 0) { for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - ptr = rom_ptr(KERNEL_LOAD_ADDR + i); - if (ldl_p(ptr) == 0x48647253) { // HdrS + ptr = rom_ptr(KERNEL_LOAD_ADDR + i, 24); + if (ptr && ldl_p(ptr) == 0x48647253) { /* HdrS */ stl_p(ptr + 16, INITRD_LOAD_ADDR); stl_p(ptr + 20, initrd_size); break; diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 97d1269346..74b748497e 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -186,8 +186,8 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename, } if (*initrd_size > 0) { for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - ptr = rom_ptr(*kernel_addr + i); - if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */ + ptr = rom_ptr(*kernel_addr + i, 32); + if (ptr && ldl_p(ptr + 8) == 0x48647253) { /* HdrS */ stl_p(ptr + 24, *initrd_addr + *kernel_addr); stl_p(ptr + 28, *initrd_size); break; diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 7338f57062..117d2fbbca 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -339,6 +339,29 @@ CPUArchState *cpu_copy(CPUArchState *env); #define TLB_FLAGS_MASK (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \ | TLB_RECHECK) +/** + * tlb_hit_page: return true if page aligned @addr is a hit against the + * TLB entry @tlb_addr + * + * @addr: virtual address to test (must be page aligned) + * @tlb_addr: TLB entry address (a CPUTLBEntry addr_read/write/code value) + */ +static inline bool tlb_hit_page(target_ulong tlb_addr, target_ulong addr) +{ + return addr == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); +} + +/** + * tlb_hit: return true if @addr is a hit against the TLB entry @tlb_addr + * + * @addr: virtual address to test (need not be page aligned) + * @tlb_addr: TLB entry address (a CPUTLBEntry addr_read/write/code value) + */ +static inline bool tlb_hit(target_ulong tlb_addr, target_ulong addr) +{ + return tlb_hit_page(tlb_addr, addr & TARGET_PAGE_MASK); +} + void dump_exec_info(FILE *f, fprintf_function cpu_fprintf); void dump_opcount_info(FILE *f, fprintf_function cpu_fprintf); #endif /* !CONFIG_USER_ONLY */ diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 5de8c8a5af..0f2cb717b1 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -422,8 +422,7 @@ static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr, g_assert_not_reached(); } - if ((addr & TARGET_PAGE_MASK) - != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + if (!tlb_hit(tlb_addr, addr)) { /* TLB entry is for a different page */ return NULL; } diff --git a/include/hw/loader.h b/include/hw/loader.h index 5ed3fd8ae6..e98b84b8f9 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -226,7 +226,7 @@ void rom_set_fw(FWCfgState *f); void rom_set_order_override(int order); void rom_reset_order_override(void); int rom_copy(uint8_t *dest, hwaddr addr, size_t size); -void *rom_ptr(hwaddr addr); +void *rom_ptr(hwaddr addr, size_t size); void hmp_info_roms(Monitor *mon, const QDict *qdict); #define rom_add_file_fixed(_f, _a, _i) \ diff --git a/include/hw/s390x/tod.h b/include/hw/s390x/tod.h new file mode 100644 index 0000000000..413c0d7c02 --- /dev/null +++ b/include/hw/s390x/tod.h @@ -0,0 +1,65 @@ +/* + * TOD (Time Of Day) clock + * + * Copyright 2018 Red Hat, Inc. + * Author(s): David Hildenbrand <david@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HW_S390_TOD_H +#define HW_S390_TOD_H + +#include "hw/qdev.h" + +typedef struct S390TOD { + uint8_t high; + uint64_t low; +} S390TOD; + +#define TYPE_S390_TOD "s390-tod" +#define S390_TOD(obj) OBJECT_CHECK(S390TODState, (obj), TYPE_S390_TOD) +#define S390_TOD_CLASS(oc) OBJECT_CLASS_CHECK(S390TODClass, (oc), \ + TYPE_S390_TOD) +#define S390_TOD_GET_CLASS(obj) OBJECT_GET_CLASS(S390TODClass, (obj), \ + TYPE_S390_TOD) +#define TYPE_KVM_S390_TOD TYPE_S390_TOD "-kvm" +#define TYPE_QEMU_S390_TOD TYPE_S390_TOD "-qemu" + +typedef struct S390TODState { + /* private */ + DeviceState parent_obj; + + /* unused by KVM implementation */ + S390TOD base; +} S390TODState; + +typedef struct S390TODClass { + /* private */ + DeviceClass parent_class; + + /* public */ + void (*get)(const S390TODState *td, S390TOD *tod, Error **errp); + void (*set)(S390TODState *td, const S390TOD *tod, Error **errp); +} S390TODClass; + +/* The value of the TOD clock for 1.1.1970. */ +#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL + +/* Converts ns to s390's clock format */ +static inline uint64_t time2tod(uint64_t ns) +{ + return (ns << 9) / 125 + (((ns & 0xff10000000000000ull) / 125) << 9); +} + +/* Converts s390's clock format to ns */ +static inline uint64_t tod2time(uint64_t t) +{ + return ((t >> 9) * 125) + (((t & 0x1ff) * 125) >> 9); +} + +void s390_init_tod(void); +S390TODState *s390_get_todstate(void); + +#endif diff --git a/include/qom/cpu.h b/include/qom/cpu.h index cce2fd6acc..bd796579ee 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -620,11 +620,13 @@ static inline hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr) static inline int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs) { CPUClass *cc = CPU_GET_CLASS(cpu); + int ret = 0; if (cc->asidx_from_attrs) { - return cc->asidx_from_attrs(cpu, attrs); + ret = cc->asidx_from_attrs(cpu, attrs); + assert(ret < cpu->num_ases && ret >= 0); } - return 0; + return ret; } #endif diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index b921c6f3b7..76ef6196a7 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -44,6 +44,10 @@ typedef enum ShutdownCause { turns that into a shutdown */ SHUTDOWN_CAUSE_GUEST_PANIC, /* Guest panicked, and command line turns that into a shutdown */ + SHUTDOWN_CAUSE_SUBSYSTEM_RESET,/* Partial guest reset that does not trigger + QMP events and ignores --no-reboot. This + is useful for sanitize hypercalls on s390 + that are used during kexec/kdump/boot */ SHUTDOWN_CAUSE__MAX, } ShutdownCause; diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin Binary files differindex 0061dc9928..6ffa6ec524 100644 --- a/pc-bios/bios-256k.bin +++ b/pc-bios/bios-256k.bin diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin Binary files differindex 69bb8635ae..afa450c4a0 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/pc-bios/vgabios-bochs-display.bin b/pc-bios/vgabios-bochs-display.bin Binary files differnew file mode 100644 index 0000000000..6021d9b199 --- /dev/null +++ b/pc-bios/vgabios-bochs-display.bin diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin Binary files differindex cec498d59e..c1ec6b6298 100644 --- a/pc-bios/vgabios-cirrus.bin +++ b/pc-bios/vgabios-cirrus.bin diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin Binary files differindex 82c9970df7..2529ac954d 100644 --- a/pc-bios/vgabios-qxl.bin +++ b/pc-bios/vgabios-qxl.bin diff --git a/pc-bios/vgabios-ramfb.bin b/pc-bios/vgabios-ramfb.bin Binary files differnew file mode 100644 index 0000000000..30a124538f --- /dev/null +++ b/pc-bios/vgabios-ramfb.bin diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin Binary files differindex 8029c2ae12..2d868321c7 100644 --- a/pc-bios/vgabios-stdvga.bin +++ b/pc-bios/vgabios-stdvga.bin diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin Binary files differindex 79333575e0..8188eabb18 100644 --- a/pc-bios/vgabios-virtio.bin +++ b/pc-bios/vgabios-virtio.bin diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin Binary files differindex ba1718c784..58afa79d2f 100644 --- a/pc-bios/vgabios-vmware.bin +++ b/pc-bios/vgabios-vmware.bin diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin Binary files differindex b624014bb9..136c94520c 100644 --- a/pc-bios/vgabios.bin +++ b/pc-bios/vgabios.bin diff --git a/roms/Makefile b/roms/Makefile index 02b69fbac8..f1ac85ae9b 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -1,5 +1,5 @@ -vgabios_variants := stdvga cirrus vmware qxl isavga virtio +vgabios_variants := stdvga cirrus vmware qxl isavga virtio bochs-display ramfb vgabios_targets := $(subst -isavga,,$(patsubst %,vgabios-%.bin,$(vgabios_variants))) pxerom_variants := e1000 e1000e eepro100 ne2k_pci pcnet rtl8139 virtio vmxnet3 pxerom_targets := 8086100e 808610d3 80861209 10500940 10222000 10ec8139 1af41000 15ad07b0 @@ -56,8 +56,7 @@ default: @echo "nothing is build by default" @echo "available build targets:" @echo " bios -- update bios.bin (seabios)" - @echo " seavgabios -- update vgabios binaries (seabios)" - @echo " lgplvgabios -- update vgabios binaries (lgpl)" + @echo " vgabios -- update vgabios binaries (seabios)" @echo " sgabios -- update sgabios binaries" @echo " pxerom -- update nic roms (bios only)" @echo " efirom -- update nic roms (bios+efi, this needs" @@ -71,7 +70,7 @@ bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin cp seabios/builds/seabios-256k/bios.bin ../pc-bios/bios-256k.bin -seavgabios: $(patsubst %,seavgabios-%,$(vgabios_variants)) +vgabios seavgabios: $(patsubst %,seavgabios-%,$(vgabios_variants)) seavgabios-isavga: build-seabios-config-vga-isavga cp seabios/builds/vga-isavga/vgabios.bin ../pc-bios/vgabios.bin @@ -94,17 +93,6 @@ build-seabios-config-%: config.% OUT=$(CURDIR)/seabios/builds/$*/ all -lgplvgabios: $(patsubst %,lgplvgabios-%,$(vgabios_variants)) - -lgplvgabios-isavga: build-lgplvgabios - cp vgabios/VGABIOS-lgpl-latest.bin ../pc-bios/vgabios.bin -lgplvgabios-%: build-lgplvgabios - cp vgabios/VGABIOS-lgpl-latest.$*.bin ../pc-bios/vgabios-$*.bin - -build-lgplvgabios: - $(MAKE) -C vgabios $(vgabios_targets) - - .PHONY: sgabios skiboot sgabios: $(MAKE) -C sgabios @@ -159,8 +147,6 @@ skiboot: clean: rm -rf seabios/.config seabios/out seabios/builds - $(MAKE) -C vgabios clean - rm -f vgabios/VGABIOS-lgpl-latest* $(MAKE) -C sgabios clean rm -f sgabios/.depend $(MAKE) -C ipxe/src veryclean diff --git a/roms/config.seabios-128k b/roms/config.seabios-128k index 486ef0e132..35b5a07d8f 100644 --- a/roms/config.seabios-128k +++ b/roms/config.seabios-128k @@ -2,6 +2,7 @@ # need to turn off features (xhci,uas) to make it fit into 128k CONFIG_QEMU=y CONFIG_ROM_SIZE=128 +CONFIG_ATA_DMA=y CONFIG_BOOTSPLASH=n CONFIG_XEN=n CONFIG_USB_OHCI=n diff --git a/roms/config.seabios-256k b/roms/config.seabios-256k index 65e5015c2f..b14b614fcc 100644 --- a/roms/config.seabios-256k +++ b/roms/config.seabios-256k @@ -1,3 +1,4 @@ # for qemu machine types 2.0 + newer CONFIG_QEMU=y CONFIG_ROM_SIZE=256 +CONFIG_ATA_DMA=y diff --git a/roms/config.vga-bochs-display b/roms/config.vga-bochs-display new file mode 100644 index 0000000000..d2adaaef66 --- /dev/null +++ b/roms/config.vga-bochs-display @@ -0,0 +1,3 @@ +CONFIG_BUILD_VGABIOS=y +CONFIG_DISPLAY_BOCHS=y +CONFIG_VGA_PCI=y diff --git a/roms/config.vga-ramfb b/roms/config.vga-ramfb new file mode 100644 index 0000000000..c809c799b9 --- /dev/null +++ b/roms/config.vga-ramfb @@ -0,0 +1,3 @@ +CONFIG_BUILD_VGABIOS=y +CONFIG_VGA_RAMFB=y +CONFIG_VGA_PCI=n diff --git a/roms/seabios b/roms/seabios -Subproject 0551a4be2ce599fb60e478b4c15e06ab6587822 +Subproject f9626ccb91e771f990fbb2da92e427a399d7d91 diff --git a/roms/vgabios b/roms/vgabios deleted file mode 160000 -Subproject 19ea12c230ded95928ecaef0db47a82231c2e48 diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 82ff450f9a..64a8005a4b 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -239,7 +239,7 @@ static void arm_cpu_reset(CPUState *s) /* Load the initial SP and PC from offset 0 and 4 in the vector table */ vecbase = env->v7m.vecbase[env->v7m.secure]; - rom = rom_ptr(vecbase); + rom = rom_ptr(vecbase, 8); if (rom) { /* Address zero is covered by ROM which hasn't yet been * copied into physical memory. diff --git a/target/s390x/Makefile.objs b/target/s390x/Makefile.objs index 31932de9cf..22a9a9927a 100644 --- a/target/s390x/Makefile.objs +++ b/target/s390x/Makefile.objs @@ -5,6 +5,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o arch_dump.o mmu_helper.o diag.o obj-$(CONFIG_SOFTMMU) += sigp.o obj-$(CONFIG_KVM) += kvm.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o +obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o # build and run feature list generator feat-src = $(SRC_PATH)/target/$(TARGET_BASE_ARCH)/ diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index c268065887..271c5ce652 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -30,7 +30,6 @@ #include "kvm_s390x.h" #include "sysemu/kvm.h" #include "qemu-common.h" -#include "qemu/cutils.h" #include "qemu/timer.h" #include "qemu/error-report.h" #include "trace.h" @@ -219,11 +218,18 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) #endif s390_cpu_gdb_init(cs); qemu_init_vcpu(cs); -#if !defined(CONFIG_USER_ONLY) - run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); -#else - cpu_reset(cs); -#endif + + /* + * KVM requires the initial CPU reset ioctl to be executed on the target + * CPU thread. CPU hotplug under single-threaded TCG will not work with + * run_on_cpu(), as run_on_cpu() will not work properly if called while + * the main thread is already running but the CPU hasn't been realized. + */ + if (kvm_enabled()) { + run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); + } else { + cpu_reset(cs); + } scc->parent_realize(dev, &err); out: @@ -275,9 +281,6 @@ static void s390_cpu_initfn(Object *obj) CPUState *cs = CPU(obj); S390CPU *cpu = S390_CPU(obj); CPUS390XState *env = &cpu->env; -#if !defined(CONFIG_USER_ONLY) - struct tm tm; -#endif cs->env_ptr = env; cs->halted = 1; @@ -286,10 +289,6 @@ static void s390_cpu_initfn(Object *obj) s390_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL); s390_cpu_model_register_props(obj); #if !defined(CONFIG_USER_ONLY) - qemu_get_timedate(&tm, 0); - env->tod_offset = TOD_UNIX_EPOCH + - (time2tod(mktimegm(&tm)) * 1000000000ULL); - env->tod_basetime = 0; env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu); env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu); s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); @@ -390,38 +389,6 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) return s390_count_running_cpus(); } -int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low) -{ - int r = 0; - - if (kvm_enabled()) { - r = kvm_s390_get_clock_ext(tod_high, tod_low); - if (r == -ENXIO) { - return kvm_s390_get_clock(tod_high, tod_low); - } - } else { - /* Fixme TCG */ - *tod_high = 0; - *tod_low = 0; - } - - return r; -} - -int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) -{ - int r = 0; - - if (kvm_enabled()) { - r = kvm_s390_set_clock_ext(tod_high, tod_low); - if (r == -ENXIO) { - return kvm_s390_set_clock(tod_high, tod_low); - } - } - /* Fixme TCG */ - return r; -} - int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) { if (kvm_enabled()) { diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 6629a533f3..2c3dd2d189 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -130,8 +130,6 @@ struct CPUS390XState { uint64_t cpuid; #endif - uint64_t tod_offset; - uint64_t tod_basetime; QEMUTimer *tod_timer; QEMUTimer *cpu_timer; @@ -714,8 +712,6 @@ static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg) /* cpu.c */ -int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low); -int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low); void s390_crypto_reset(void); bool s390_get_squash_mcss(void); int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit); diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index 0cdbc15378..6626b6f565 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -512,6 +512,8 @@ static uint16_t default_GEN11_GA1[] = { S390_FEAT_IPTE_RANGE, S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION, S390_FEAT_GROUP_MSA_EXT_4, + S390_FEAT_PPA15, + S390_FEAT_BPB, }; #define default_GEN11_GA2 EmptyFeat diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 59cba86a27..97c60ca7bc 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -127,6 +127,7 @@ DEF_HELPER_4(diag, void, env, i32, i32, i32) DEF_HELPER_3(load_psw, noreturn, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) +DEF_HELPER_FLAGS_2(sck, TCG_CALL_NO_RWG, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(sckpf, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 157619403d..5c6f33ed9c 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -997,8 +997,7 @@ /* SET ADDRESS SPACE CONTROL FAST */ C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0) /* SET CLOCK */ - /* ??? Not implemented - is it necessary? */ - C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) + C(0xb204, SCK, S, Z, la2, 0, 0, 0, sck, 0) /* SET CLOCK COMPARATOR */ C(0xb206, SCKC, S, Z, 0, m2_64a, 0, 0, sckc, 0) /* SET CLOCK PROGRAMMABLE FIELD */ diff --git a/target/s390x/internal.h b/target/s390x/internal.h index e392a02d12..f2a771e2b4 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -237,21 +237,6 @@ enum cc_op { CC_OP_MAX }; -/* The value of the TOD clock for 1.1.1970. */ -#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL - -/* Converts ns to s390's clock format */ -static inline uint64_t time2tod(uint64_t ns) -{ - return (ns << 9) / 125; -} - -/* Converts s390's clock format to ns */ -static inline uint64_t tod2time(uint64_t t) -{ - return (t * 125) >> 9; -} - static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb, uint8_t *ar) { diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c index 29b10542cc..bf7795e47a 100644 --- a/target/s390x/kvm-stub.c +++ b/target/s390x/kvm-stub.c @@ -60,12 +60,12 @@ int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low) return -ENOSYS; } -int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) +int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low) { return -ENOSYS; } -int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_low) +int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low) { return -ENOSYS; } diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index ac370da281..d923cf4240 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -666,13 +666,13 @@ int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low) return r; } -int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) +int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low) { int r; struct kvm_device_attr attr = { .group = KVM_S390_VM_TOD, .attr = KVM_S390_VM_TOD_LOW, - .addr = (uint64_t)tod_low, + .addr = (uint64_t)&tod_low, }; r = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); @@ -681,15 +681,15 @@ int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) } attr.attr = KVM_S390_VM_TOD_HIGH; - attr.addr = (uint64_t)tod_high; + attr.addr = (uint64_t)&tod_high; return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); } -int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_low) +int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low) { struct kvm_s390_vm_tod_clock gtod = { - .epoch_idx = *tod_high, - .tod = *tod_low, + .epoch_idx = tod_high, + .tod = tod_low, }; struct kvm_device_attr attr = { .group = KVM_S390_VM_TOD, @@ -752,12 +752,23 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, */ static void *legacy_s390_alloc(size_t size, uint64_t *align, bool shared) { - void *mem; + static void *mem; + + if (mem) { + /* we only support one allocation, which is enough for initial ram */ + return NULL; + } mem = mmap((void *) 0x800000000ULL, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0); - return mem == MAP_FAILED ? NULL : mem; + if (mem == MAP_FAILED) { + mem = NULL; + } + if (mem && align) { + *align = QEMU_VMALLOC_ALIGN; + } + return mem; } static uint8_t const *sw_bp_inst; diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h index c383bf4ee9..6e52287da3 100644 --- a/target/s390x/kvm_s390x.h +++ b/target/s390x/kvm_s390x.h @@ -10,6 +10,8 @@ #ifndef KVM_S390X_H #define KVM_S390X_H +#include "cpu-qom.h" + struct kvm_s390_irq; void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq); @@ -25,8 +27,8 @@ int kvm_s390_get_ri(void); int kvm_s390_get_gs(void); int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock); int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock); -int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_clock); -int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_clock); +int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_clock); +int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_clock); void kvm_s390_enable_css_support(S390CPU *cpu); int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, int vq, bool assign); diff --git a/target/s390x/machine.c b/target/s390x/machine.c index 84b4928755..bd3230d027 100644 --- a/target/s390x/machine.c +++ b/target/s390x/machine.c @@ -19,6 +19,7 @@ #include "cpu.h" #include "internal.h" #include "kvm_s390x.h" +#include "tcg_s390x.h" #include "sysemu/kvm.h" static int cpu_post_load(void *opaque, int version_id) @@ -34,6 +35,11 @@ static int cpu_post_load(void *opaque, int version_id) return kvm_s390_vcpu_interrupt_post_load(cpu); } + if (tcg_enabled()) { + /* Rearm the CKC timer if necessary */ + tcg_s390_tod_updated(CPU(cpu), RUN_ON_CPU_NULL); + } + return 0; } diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index de1ced2082..3f91579570 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -28,6 +28,8 @@ #include "qemu/timer.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" +#include "qapi/error.h" +#include "tcg_s390x.h" #if !defined(CONFIG_USER_ONLY) #include "sysemu/cpus.h" @@ -39,6 +41,7 @@ #include "hw/s390x/ioinst.h" #include "hw/s390x/s390-pci-inst.h" #include "hw/boards.h" +#include "hw/s390x/tod.h" #endif /* #define DEBUG_HELPER */ @@ -138,30 +141,69 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1) /* Store Clock */ uint64_t HELPER(stck)(CPUS390XState *env) { - uint64_t time; - - time = env->tod_offset + - time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime); + S390TODState *td = s390_get_todstate(); + S390TODClass *tdc = S390_TOD_GET_CLASS(td); + S390TOD tod; - return time; + tdc->get(td, &tod, &error_abort); + return tod.low; } -/* Set Clock Comparator */ -void HELPER(sckc)(CPUS390XState *env, uint64_t time) +static void update_ckc_timer(CPUS390XState *env) { - if (time == -1ULL) { + S390TODState *td = s390_get_todstate(); + uint64_t time; + + /* stop the timer and remove pending CKC IRQs */ + timer_del(env->tod_timer); + g_assert(qemu_mutex_iothread_locked()); + env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR; + + /* the tod has to exceed the ckc, this can never happen if ckc is all 1's */ + if (env->ckc == -1ULL) { return; } - env->ckc = time; - /* difference between origins */ - time -= env->tod_offset; + time = env->ckc - td->base.low; /* nanoseconds */ time = tod2time(time); - timer_mod(env->tod_timer, env->tod_basetime + time); + timer_mod(env->tod_timer, time); +} + +/* Set Clock Comparator */ +void HELPER(sckc)(CPUS390XState *env, uint64_t ckc) +{ + env->ckc = ckc; + + qemu_mutex_lock_iothread(); + update_ckc_timer(env); + qemu_mutex_unlock_iothread(); +} + +void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque) +{ + S390CPU *cpu = S390_CPU(cs); + + update_ckc_timer(&cpu->env); +} + +/* Set Clock */ +uint32_t HELPER(sck)(CPUS390XState *env, uint64_t tod_low) +{ + S390TODState *td = s390_get_todstate(); + S390TODClass *tdc = S390_TOD_GET_CLASS(td); + S390TOD tod = { + .high = 0, + .low = tod_low, + }; + + qemu_mutex_lock_iothread(); + tdc->set(td, &tod, &error_abort); + qemu_mutex_unlock_iothread(); + return 0; } /* Set Tod Programmable Field */ diff --git a/target/s390x/tcg-stub.c b/target/s390x/tcg-stub.c new file mode 100644 index 0000000000..c93501db0b --- /dev/null +++ b/target/s390x/tcg-stub.c @@ -0,0 +1,20 @@ +/* + * QEMU TCG support -- s390x specific function stubs. + * + * Copyright (C) 2018 Red Hat Inc + * + * Authors: + * David Hildenbrand <david@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "cpu.h" +#include "tcg_s390x.h" + +void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque) +{ +} diff --git a/target/s390x/tcg_s390x.h b/target/s390x/tcg_s390x.h new file mode 100644 index 0000000000..4e308aa0ce --- /dev/null +++ b/target/s390x/tcg_s390x.h @@ -0,0 +1,18 @@ +/* + * QEMU TCG support -- s390x specific functions. + * + * Copyright 2018 Red Hat, Inc. + * + * Authors: + * David Hildenbrand <david@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef TCG_S390X_H +#define TCG_S390X_H + +void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque); + +#endif /* TCG_S390X_H */ diff --git a/target/s390x/translate.c b/target/s390x/translate.c index fdfec7feba..57c03cbf58 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4016,6 +4016,15 @@ static DisasJumpType op_stcke(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_sck(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_qemu_ld_i64(o->in1, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN); + gen_helper_sck(cc_op, cpu_env, o->in1); + set_cc_static(s); + return DISAS_NEXT; +} + static DisasJumpType op_sckc(DisasContext *s, DisasOps *o) { check_privileged(s); @@ -1646,7 +1646,7 @@ void qemu_system_reset(ShutdownCause reason) } else { qemu_devices_reset(); } - if (reason) { + if (reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) { qapi_event_send_reset(shutdown_caused_by_guest(reason), &error_abort); } @@ -1692,7 +1692,7 @@ void qemu_system_guest_panicked(GuestPanicInformation *info) void qemu_system_reset_request(ShutdownCause reason) { - if (no_reboot) { + if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) { shutdown_requested = reason; } else { reset_requested = reason; |