diff --git a/disas/hppa.c b/disas/hppa.c index cce4f4aa37..22dce9b41b 100644 --- a/disas/hppa.c +++ b/disas/hppa.c @@ -1609,6 +1609,10 @@ static const struct pa_opcode pa_opcodes[] = { "call", 0xe800a000, 0xffe0e000, "nW", pa10, FLAG_STRICT}, { "ret", 0xe840d000, 0xfffffffd, "n", pa20, FLAG_STRICT}, +/* Opcodes assigned to QEMU, used by SeaBIOS firmware and Linux kernel */ +{ "HALT QEMU", 0xfffdead0, 0xfffffffd, "n", pa10, FLAG_STRICT}, +{ "RESET QEMU", 0xfffdead1, 0xfffffffd, "n", pa10, FLAG_STRICT}, +{ "RESTORE SHR",0xfffdead2, 0xfffffffd, "n", pa10, FLAG_STRICT}, }; #define NUMOPCODES ((sizeof pa_opcodes)/(sizeof pa_opcodes[0])) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index eb78c46ff1..5fcaf5884b 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -13,6 +13,7 @@ #include "qemu/error-report.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" +#include "sysemu/qtest.h" #include "sysemu/runstate.h" #include "hw/rtc/mc146818rtc.h" #include "hw/timer/i8254.h" @@ -333,6 +334,7 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus, const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; + const char *firmware = machine->firmware; MachineClass *mc = MACHINE_GET_CLASS(machine); DeviceState *dev; PCIDevice *pci_dev; @@ -408,31 +410,37 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus, /* Load firmware. Given that this is not "real" firmware, but one explicitly written for the emulation, we might as - well load it directly from an ELF image. */ - firmware_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, - machine->firmware ?: "hppa-firmware.img"); - if (firmware_filename == NULL) { - error_report("no firmware provided"); - exit(1); - } + well load it directly from an ELF image. Load the 64-bit + firmware on 64-bit machines by default if not specified + on command line. */ + if (!qtest_enabled()) { + if (!firmware) { + firmware = lasi_dev ? "hppa-firmware.img" : "hppa-firmware64.img"; + } + firmware_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware); + if (firmware_filename == NULL) { + error_report("no firmware provided"); + exit(1); + } - size = load_elf(firmware_filename, NULL, translate, NULL, - &firmware_entry, &firmware_low, &firmware_high, NULL, - true, EM_PARISC, 0, 0); + size = load_elf(firmware_filename, NULL, translate, NULL, + &firmware_entry, &firmware_low, &firmware_high, NULL, + true, EM_PARISC, 0, 0); - if (size < 0) { - error_report("could not load firmware '%s'", firmware_filename); - exit(1); + if (size < 0) { + error_report("could not load firmware '%s'", firmware_filename); + exit(1); + } + qemu_log_mask(CPU_LOG_PAGE, "Firmware loaded at 0x%08" PRIx64 + "-0x%08" PRIx64 ", entry at 0x%08" PRIx64 ".\n", + firmware_low, firmware_high, firmware_entry); + if (firmware_low < translate(NULL, FIRMWARE_START) || + firmware_high >= translate(NULL, FIRMWARE_END)) { + error_report("Firmware overlaps with memory or IO space"); + exit(1); + } + g_free(firmware_filename); } - qemu_log_mask(CPU_LOG_PAGE, "Firmware loaded at 0x%08" PRIx64 - "-0x%08" PRIx64 ", entry at 0x%08" PRIx64 ".\n", - firmware_low, firmware_high, firmware_entry); - if (firmware_low < translate(NULL, FIRMWARE_START) || - firmware_high >= translate(NULL, FIRMWARE_END)) { - error_report("Firmware overlaps with memory or IO space"); - exit(1); - } - g_free(firmware_filename); rom_region = g_new(MemoryRegion, 1); memory_region_init_ram(rom_region, NULL, "firmware", diff --git a/hw/misc/lasi.c b/hw/misc/lasi.c index 003f5b5ed8..970fc98b5c 100644 --- a/hw/misc/lasi.c +++ b/hw/misc/lasi.c @@ -36,9 +36,13 @@ static bool lasi_chip_mem_valid(void *opaque, hwaddr addr, case LASI_IAR: case LASI_LPT: + case LASI_AUDIO: + case LASI_AUDIO + 4: case LASI_UART: case LASI_LAN: + case LASI_LAN + 12: /* LASI LAN MAC */ case LASI_RTC: + case LASI_FDC: case LASI_PCR ... LASI_AMR: ret = true; @@ -78,6 +82,8 @@ static MemTxResult lasi_chip_read_with_attrs(void *opaque, hwaddr addr, case LASI_LPT: case LASI_UART: case LASI_LAN: + case LASI_LAN + 12: + case LASI_FDC: val = 0; break; case LASI_RTC: @@ -143,12 +149,19 @@ static MemTxResult lasi_chip_write_with_attrs(void *opaque, hwaddr addr, case LASI_LPT: /* XXX: reset parallel port */ break; + case LASI_AUDIO: + case LASI_AUDIO + 4: + /* XXX: reset audio port */ + break; case LASI_UART: /* XXX: reset serial port */ break; case LASI_LAN: /* XXX: reset LAN card */ break; + case LASI_FDC: + /* XXX: reset Floppy controller */ + break; case LASI_RTC: s->rtc_ref = val - time(NULL); break; diff --git a/hw/net/tulip.c b/hw/net/tulip.c index 6d4fb06dad..1f2ef20977 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -421,7 +421,7 @@ static uint16_t tulip_mdi_default[] = { /* MDI Registers 8 - 15 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* MDI Registers 16 - 31 */ - 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0003, 0x0000, 0x0001, 0x0000, 0x3b40, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; @@ -429,7 +429,7 @@ static uint16_t tulip_mdi_default[] = { static const uint16_t tulip_mdi_mask[] = { 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0x0fff, 0x0000, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c index 37d271118c..e3e589ceac 100644 --- a/hw/pci-host/astro.c +++ b/hw/pci-host/astro.c @@ -122,10 +122,6 @@ static MemTxResult elroy_chip_read_with_attrs(void *opaque, hwaddr addr, case 0x0800: /* IOSAPIC_REG_SELECT */ val = s->iosapic_reg_select; break; - case 0x0808: - val = UINT64_MAX; /* XXX: tbc. */ - g_assert_not_reached(); - break; case 0x0810: /* IOSAPIC_REG_WINDOW */ switch (s->iosapic_reg_select) { case 0x01: /* IOSAPIC_REG_VERSION */ @@ -135,15 +131,21 @@ static MemTxResult elroy_chip_read_with_attrs(void *opaque, hwaddr addr, if (s->iosapic_reg_select < ARRAY_SIZE(s->iosapic_reg)) { val = s->iosapic_reg[s->iosapic_reg_select]; } else { - trace_iosapic_reg_read(s->iosapic_reg_select, size, val); - g_assert_not_reached(); + goto check_hf; } } trace_iosapic_reg_read(s->iosapic_reg_select, size, val); break; default: - trace_elroy_read(addr, size, val); - g_assert_not_reached(); + check_hf: + if (s->status_control & HF_ENABLE) { + val = 0; + ret = MEMTX_DECODE_ERROR; + } else { + /* return -1ULL if HardFail is disabled */ + val = ~0; + ret = MEMTX_OK; + } } trace_elroy_read(addr, size, val); @@ -191,7 +193,7 @@ static MemTxResult elroy_chip_write_with_attrs(void *opaque, hwaddr addr, if (s->iosapic_reg_select < ARRAY_SIZE(s->iosapic_reg)) { s->iosapic_reg[s->iosapic_reg_select] = val; } else { - g_assert_not_reached(); + goto check_hf; } break; case 0x0840: /* IOSAPIC_REG_EOI */ @@ -204,7 +206,10 @@ static MemTxResult elroy_chip_write_with_attrs(void *opaque, hwaddr addr, } break; default: - g_assert_not_reached(); + check_hf: + if (s->status_control & HF_ENABLE) { + return MEMTX_DECODE_ERROR; + } } return MEMTX_OK; } @@ -594,8 +599,8 @@ static MemTxResult astro_chip_read_with_attrs(void *opaque, hwaddr addr, #undef EMPTY_PORT default: - trace_astro_chip_read(addr, size, val); - g_assert_not_reached(); + val = 0; + ret = MEMTX_DECODE_ERROR; } /* for 32-bit accesses mask return value */ @@ -610,6 +615,7 @@ static MemTxResult astro_chip_write_with_attrs(void *opaque, hwaddr addr, uint64_t val, unsigned size, MemTxAttrs attrs) { + MemTxResult ret = MEMTX_OK; AstroState *s = opaque; trace_astro_chip_write(addr, size, val); @@ -686,11 +692,9 @@ static MemTxResult astro_chip_write_with_attrs(void *opaque, hwaddr addr, #undef EMPTY_PORT default: - /* Controlled by astro_chip_mem_valid above. */ - trace_astro_chip_write(addr, size, val); - g_assert_not_reached(); + ret = MEMTX_DECODE_ERROR; } - return MEMTX_OK; + return ret; } static const MemoryRegionOps astro_chip_ops = { diff --git a/include/hw/misc/lasi.h b/include/hw/misc/lasi.h index 0a8c7352be..f01c0f680a 100644 --- a/include/hw/misc/lasi.h +++ b/include/hw/misc/lasi.h @@ -26,9 +26,11 @@ OBJECT_DECLARE_SIMPLE_TYPE(LasiState, LASI_CHIP) #define LASI_IAR 0x10 #define LASI_LPT 0x02000 +#define LASI_AUDIO 0x04000 #define LASI_UART 0x05000 #define LASI_LAN 0x07000 #define LASI_RTC 0x09000 +#define LASI_FDC 0x0A000 #define LASI_PCR 0x0C000 /* LASI Power Control register */ #define LASI_ERRLOG 0x0C004 /* LASI Error Logging register */ diff --git a/include/hw/pci-host/astro.h b/include/hw/pci-host/astro.h index f63fd220f3..e2966917cd 100644 --- a/include/hw/pci-host/astro.h +++ b/include/hw/pci-host/astro.h @@ -27,6 +27,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(ElroyState, ELROY_PCI_HOST_BRIDGE) #define IOS_DIST_BASE_ADDR 0xfffee00000ULL #define IOS_DIST_BASE_SIZE 0x10000ULL +#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */ + struct AstroState; struct ElroyState { diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img old mode 100644 new mode 100755 index 1b3a841825..e065e48ded Binary files a/pc-bios/hppa-firmware.img and b/pc-bios/hppa-firmware.img differ diff --git a/pc-bios/hppa-firmware64.img b/pc-bios/hppa-firmware64.img new file mode 100755 index 0000000000..7f6d837f0d Binary files /dev/null and b/pc-bios/hppa-firmware64.img differ diff --git a/roms/seabios-hppa b/roms/seabios-hppa index e4eac85880..03774edaad 160000 --- a/roms/seabios-hppa +++ b/roms/seabios-hppa @@ -1 +1 @@ -Subproject commit e4eac85880e8677f96d8b9e94de9f2eec9c0751f +Subproject commit 03774edaad3bfae090ac96ca5450353c641637d1 diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 5f87c1b12a..afe73d4474 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -191,6 +191,7 @@ static const TCGCPUOps hppa_tcg_ops = { .cpu_exec_interrupt = hppa_cpu_exec_interrupt, .do_interrupt = hppa_cpu_do_interrupt, .do_unaligned_access = hppa_cpu_do_unaligned_access, + .do_transaction_failed = hppa_cpu_do_transaction_failed, #endif /* !CONFIG_USER_ONLY */ }; diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 7a181e8f33..a92dc352cb 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -381,6 +381,11 @@ bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req); int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, int type, hwaddr *pphys, int *pprot, HPPATLBEntry **tlb_entry); +void hppa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + vaddr addr, unsigned size, + MMUAccessType access_type, + int mmu_idx, MemTxAttrs attrs, + MemTxResult response, uintptr_t retaddr); extern const MemoryRegionOps hppa_io_eir_ops; extern const VMStateDescription vmstate_hppa_cpu; void hppa_cpu_alarm_timer(void *); diff --git a/target/hppa/helper.h b/target/hppa/helper.h index 20698f68ed..1bdbcd8f98 100644 --- a/target/hppa/helper.h +++ b/target/hppa/helper.h @@ -103,4 +103,5 @@ DEF_HELPER_FLAGS_1(ptlbe, TCG_CALL_NO_RWG, void, env) DEF_HELPER_FLAGS_2(lpa, TCG_CALL_NO_WG, tl, env, tl) DEF_HELPER_FLAGS_1(change_prot_id, TCG_CALL_NO_RWG, void, env) DEF_HELPER_1(diag_btlb, void, env) +DEF_HELPER_1(diag_console_output, void, env) #endif diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index 629a9d90ef..66b8fa7d72 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -353,6 +353,25 @@ raise_exception_with_ior(CPUHPPAState *env, int excp, uintptr_t retaddr, cpu_loop_exit_restore(cs, retaddr); } +void hppa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + vaddr addr, unsigned size, + MMUAccessType access_type, + int mmu_idx, MemTxAttrs attrs, + MemTxResult response, uintptr_t retaddr) +{ + CPUHPPAState *env = cpu_env(cs); + + qemu_log_mask(LOG_GUEST_ERROR, "HPMC at " TARGET_FMT_lx ":" TARGET_FMT_lx + " while accessing I/O at %#08" HWADDR_PRIx "\n", + env->iasq_f, env->iaoq_f, physaddr); + + /* FIXME: Enable HPMC exceptions when firmware has clean device probing */ + if (0) { + raise_exception_with_ior(env, EXCP_HPMC, retaddr, addr, + MMU_IDX_MMU_DISABLED(mmu_idx)); + } +} + bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, MMUAccessType type, int mmu_idx, bool probe, uintptr_t retaddr) @@ -665,7 +684,7 @@ void HELPER(diag_btlb)(CPUHPPAState *env) case 0: /* return BTLB parameters */ qemu_log_mask(CPU_LOG_MMU, "PDC_BLOCK_TLB: PDC_BTLB_INFO\n"); - vaddr = probe_access(env, env->gr[24], 4 * sizeof(target_ulong), + vaddr = probe_access(env, env->gr[24], 4 * sizeof(uint32_t), MMU_DATA_STORE, mmu_idx, ra); if (vaddr == NULL) { env->gr[28] = -10; /* invalid argument */ diff --git a/target/hppa/sys_helper.c b/target/hppa/sys_helper.c index a59245eed3..4a31748342 100644 --- a/target/hppa/sys_helper.c +++ b/target/hppa/sys_helper.c @@ -23,6 +23,8 @@ #include "exec/helper-proto.h" #include "qemu/timer.h" #include "sysemu/runstate.h" +#include "sysemu/sysemu.h" +#include "chardev/char-fe.h" void HELPER(write_interval_timer)(CPUHPPAState *env, target_ulong val) { @@ -109,3 +111,37 @@ void HELPER(rfi_r)(CPUHPPAState *env) helper_getshadowregs(env); helper_rfi(env); } + +#ifndef CONFIG_USER_ONLY +/* + * diag_console_output() is a helper function used during the initial bootup + * process of the SeaBIOS-hppa firmware. During the bootup phase, addresses of + * serial ports on e.g. PCI busses are unknown and most other devices haven't + * been initialized and configured yet. With help of a simple "diag" assembler + * instruction and an ASCII character code in register %r26 firmware can easily + * print debug output without any dependencies to the first serial port and use + * that as serial console. + */ +void HELPER(diag_console_output)(CPUHPPAState *env) +{ + CharBackend *serial_backend; + Chardev *serial_port; + unsigned char c; + + /* find first serial port */ + serial_port = serial_hd(0); + if (!serial_port) { + return; + } + + /* get serial_backend for the serial port */ + serial_backend = serial_port->be; + if (!serial_backend || + !qemu_chr_fe_backend_connected(serial_backend)) { + return; + } + + c = (unsigned char)env->gr[26]; + qemu_chr_fe_write(serial_backend, &c, sizeof(c)); +} +#endif diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 08d09d50d7..01f3188656 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -2156,10 +2156,16 @@ static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) static bool trans_rsm(DisasContext *ctx, arg_rsm *a) { +#ifdef CONFIG_USER_ONLY CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); -#ifndef CONFIG_USER_ONLY +#else TCGv_i64 tmp; + /* HP-UX 11i and HP ODE use rsm for read-access to PSW */ + if (a->i) { + CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); + } + nullify_over(ctx); tmp = tcg_temp_new_i64(); @@ -4411,6 +4417,12 @@ static bool trans_diag(DisasContext *ctx, arg_diag *a) gen_helper_diag_btlb(tcg_env); return nullify_end(ctx); } + if (a->i == 0x101) { + /* print char in %r26 to first serial console, used by SeaBIOS-hppa */ + nullify_over(ctx); + gen_helper_diag_console_output(tcg_env); + return nullify_end(ctx); + } #endif qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); return true;