@@ -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
@@ -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
@@ -4411,6 +4411,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;