target/hppa: Enhancements and fixes

Some enhancements and fixes for the hppa target.
 
 The major change is, that this patchset adds a new SeaBIOS-hppa firmware
 which is built as 32- and 64-bit firmware.
 The new 64-bit firmware is necessary to fully support 64-bit operating systems
 (HP-UX, Linux, NetBSD,...).
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCZcquAQAKCRD3ErUQojoP
 X9pjAQCVsWyuYlGCW2paIGVWKV0vsOpwetUrbhRtFUZGqZxb4AD9FbMsXRcCN/oq
 CotBPY/a8MEzIQcwYl5QbcI5nNW4ygs=
 =RA0B
 -----END PGP SIGNATURE-----

Merge tag 'hppa64-pull-request' of https://github.com/hdeller/qemu-hppa into staging

target/hppa: Enhancements and fixes

Some enhancements and fixes for the hppa target.

The major change is, that this patchset adds a new SeaBIOS-hppa firmware
which is built as 32- and 64-bit firmware.
The new 64-bit firmware is necessary to fully support 64-bit operating systems
(HP-UX, Linux, NetBSD,...).

# -----BEGIN PGP SIGNATURE-----
#
# iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCZcquAQAKCRD3ErUQojoP
# X9pjAQCVsWyuYlGCW2paIGVWKV0vsOpwetUrbhRtFUZGqZxb4AD9FbMsXRcCN/oq
# CotBPY/a8MEzIQcwYl5QbcI5nNW4ygs=
# =RA0B
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 12 Feb 2024 23:47:13 GMT
# gpg:                using EDDSA key BCE9123E1AD29F07C049BBDEF712B510A23A0F5F
# gpg: Good signature from "Helge Deller <deller@gmx.de>" [unknown]
# gpg:                 aka "Helge Deller <deller@kernel.org>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 4544 8228 2CD9 10DB EF3D  25F8 3E5F 3D04 A7A2 4603
#      Subkey fingerprint: BCE9 123E 1AD2 9F07 C049  BBDE F712 B510 A23A 0F5F

* tag 'hppa64-pull-request' of https://github.com/hdeller/qemu-hppa:
  hw/hppa/machine: Load 64-bit firmware on 64-bit machines
  target/hppa: Update SeaBIOS-hppa to version 16
  hw/net/tulip: add chip status register values
  target/hppa: PDC_BTLB_INFO uses 32-bit ints
  target/hppa: Allow read-access to PSW with rsm 0,reg instruction
  lasi: Add reset I/O ports for LASI audio and FDC
  target/hppa: Implement do_transaction_failed handler for I/O errors
  lasi: allow access to LAN MAC address registers
  hw/pci-host/astro: Implement Hard Fail and Soft Fail mode
  hw/pci-host/astro: Avoid aborting on access failure
  target/hppa: Add "diag 0x101" for console output support
  disas/hppa: Add disassembly for qemu specific instructions

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-02-13 13:56:46 +00:00
commit bc2e8b18fb
16 changed files with 150 additions and 43 deletions

View File

@ -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]))

View File

@ -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",

View File

@ -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;

View File

@ -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,
};

View File

@ -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 = {

View File

@ -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 */

View File

@ -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 {

BIN
pc-bios/hppa-firmware.img Normal file → Executable file

Binary file not shown.

BIN
pc-bios/hppa-firmware64.img Executable file

Binary file not shown.

@ -1 +1 @@
Subproject commit e4eac85880e8677f96d8b9e94de9f2eec9c0751f
Subproject commit 03774edaad3bfae090ac96ca5450353c641637d1

View File

@ -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 */
};

View File

@ -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 *);

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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;