From patchwork Sun Apr 17 16:14:36 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 91566 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 46540B6EEA for ; Mon, 18 Apr 2011 02:16:59 +1000 (EST) Received: from localhost ([::1]:35832 helo=lists2.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QBUee-0000Y0-Kr for incoming@patchwork.ozlabs.org; Sun, 17 Apr 2011 12:16:56 -0400 Received: from eggs.gnu.org ([140.186.70.92]:48389) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QBUcv-0006ZL-53 for qemu-devel@nongnu.org; Sun, 17 Apr 2011 12:15:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QBUcl-0007Ek-Bj for qemu-devel@nongnu.org; Sun, 17 Apr 2011 12:15:09 -0400 Received: from mail-pw0-f45.google.com ([209.85.160.45]:40877) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QBUck-0007Ec-F2 for qemu-devel@nongnu.org; Sun, 17 Apr 2011 12:14:59 -0400 Received: by pwj6 with SMTP id 6so2410466pwj.4 for ; Sun, 17 Apr 2011 09:14:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:from:to:subject:date:message-id:x-mailer :in-reply-to:references; bh=4gwnlpCKMWy7owlS1kE6uB8LtVlC+l3pCqlPx8nW4SQ=; b=MyYUJSMzV6PnvEm4MUuoHTowJyZ9C6vbIQxoJPN6CgDC/RQj4Ns5cca25Q9txUxiGm LbYzPnVnDi38qfNpYQukeH+ohjB3d3joJRDKrXzoeJ9lcjQv1bwxjHUEWay2FcfFWLPz SdkvUviW6m11dcaUxQ/dEw4BwF8oQ9+1UzLGM= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:subject:date:message-id:x-mailer:in-reply-to :references; b=DePM1EWKvdkA+wgf20tKU74Goobg5D+s6zuuxuyCIl/MEm18uzTcO73lTiFfjFltlq aO6ORxBVRPlik5Kks0qGiF+B7N50nmVOs6/nmEmh2+Y2GwxsXrof1N1uchr48YG02U8U XOF1NX9YQ3L+dN5nu1Dae2iyvr3Pc665zWyUk= Received: by 10.68.30.137 with SMTP id s9mr5039997pbh.146.1303056897611; Sun, 17 Apr 2011 09:14:57 -0700 (PDT) Received: from localhost.localdomain (are.twiddle.net [75.101.38.216]) by mx.google.com with ESMTPS id t7sm1733194pbh.30.2011.04.17.09.14.53 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 17 Apr 2011 09:14:55 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Sun, 17 Apr 2011 09:14:36 -0700 Message-Id: <1303056876-14320-6-git-send-email-rth@twiddle.net> X-Mailer: git-send-email 1.7.4.2 In-Reply-To: <1303056876-14320-1-git-send-email-rth@twiddle.net> References: <1303056876-14320-1-git-send-email-rth@twiddle.net> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.160.45 Subject: [Qemu-devel] [PATCH 5/5] target-alpha: Emulate Alpha SX164. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Delete the old partial support for alpha-softmmu, which kind-of tried to emulate real HW and its PALcode. Instead, use a custom HW interface for a custom PALcode. Wire up as much of the device emulation as is available. This is enough to boot the Linux kernel until it starts scheduling. Signed-off-by: Richard Henderson --- Makefile.target | 4 +- configure | 1 + cpu-exec.c | 16 +- default-configs/alpha-softmmu.mak | 9 + hw/alpha_palcode.c | 1048 ------------------------------------ hw/alpha_pci.c | 327 ++++++++++++ hw/alpha_pyxis.c | 1057 +++++++++++++++++++++++++++++++++++++ hw/alpha_sx164.c | 195 +++++++ hw/alpha_sys.h | 41 ++ linux-user/main.c | 39 +- pc-bios/palcode-sx164 | Bin 0 -> 107781 bytes target-alpha/cpu.h | 337 +++++------- target-alpha/exec.h | 7 +- target-alpha/helper.c | 630 ++++++++++------------ target-alpha/helper.h | 34 +- target-alpha/machine.c | 84 +++ target-alpha/op_helper.c | 249 ++++------ target-alpha/translate.c | 422 +++++++++------- 18 files changed, 2521 insertions(+), 1979 deletions(-) create mode 100644 default-configs/alpha-softmmu.mak delete mode 100644 hw/alpha_palcode.c create mode 100644 hw/alpha_pci.c create mode 100644 hw/alpha_pyxis.c create mode 100644 hw/alpha_sx164.c create mode 100644 hw/alpha_sys.h create mode 100644 pc-bios/palcode-sx164 create mode 100644 target-alpha/machine.c diff --git a/Makefile.target b/Makefile.target index d5761b7..f702780 100644 --- a/Makefile.target +++ b/Makefile.target @@ -362,7 +362,9 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o obj-s390x-y = s390-virtio-bus.o s390-virtio.o -obj-alpha-y = alpha_palcode.o +obj-alpha-y += i8259.o mc146818rtc.o +obj-alpha-y += vga.o cirrus_vga.o +obj-alpha-y += alpha_pci.o alpha_sx164.o alpha_pyxis.o main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) diff --git a/configure b/configure index 4a93972..872747f 100755 --- a/configure +++ b/configure @@ -1011,6 +1011,7 @@ if test -z "$target_list" ; then target_list="\ i386-softmmu \ x86_64-softmmu \ +alpha-softmmu \ arm-softmmu \ cris-softmmu \ lm32-softmmu \ diff --git a/cpu-exec.c b/cpu-exec.c index 5d6c9a8..854cfe5 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -529,9 +529,19 @@ int cpu_exec(CPUState *env1) next_tb = 0; } #elif defined(TARGET_ALPHA) - if (interrupt_request & CPU_INTERRUPT_HARD) { - do_interrupt(env); - next_tb = 0; + if (env->pal_mode == 0 && (env->ps & 7) == 0) { + int idx = -1; + if (interrupt_request & CPU_INTERRUPT_HARD) { + idx = EXCP_DEV_INTERRUPT; + } + if (interrupt_request & CPU_INTERRUPT_TIMER) { + idx = EXCP_CLK_INTERRUPT; + } + if (idx >= 0) { + env->exception_index = idx; + do_interrupt(env); + next_tb = 0; + } } #elif defined(TARGET_CRIS) if (interrupt_request & CPU_INTERRUPT_HARD diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak new file mode 100644 index 0000000..abadcff --- /dev/null +++ b/default-configs/alpha-softmmu.mak @@ -0,0 +1,9 @@ +# Default configuration for alpha-softmmu + +include pci.mak +CONFIG_SERIAL=y +CONFIG_I8254=y +CONFIG_VGA_PCI=y +CONFIG_IDE_CORE=y +CONFIG_IDE_QDEV=y +CONFIG_VMWARE_VGA=y diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c deleted file mode 100644 index 033b542..0000000 --- a/hw/alpha_palcode.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* - * Alpha emulation - PALcode emulation for qemu. - * - * Copyright (c) 2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include -#include -#include - -#include "cpu.h" -#include "exec-all.h" - -/* Shared handlers */ -static void pal_reset (CPUState *env); -/* Console handlers */ -static void pal_console_call (CPUState *env, uint32_t palcode); -/* OpenVMS handlers */ -static void pal_openvms_call (CPUState *env, uint32_t palcode); -/* UNIX / Linux handlers */ -static void pal_unix_call (CPUState *env, uint32_t palcode); - -pal_handler_t pal_handlers[] = { - /* Console handler */ - { - .reset = &pal_reset, - .call_pal = &pal_console_call, - }, - /* OpenVMS handler */ - { - .reset = &pal_reset, - .call_pal = &pal_openvms_call, - }, - /* UNIX / Linux handler */ - { - .reset = &pal_reset, - .call_pal = &pal_unix_call, - }, -}; - -#if 0 -/* One must explicitly check that the TB is valid and the FOE bit is reset */ -static void update_itb (void) -{ - /* This writes into a temp register, not the actual one */ - mtpr(TB_TAG); - mtpr(TB_CTL); - /* This commits the TB update */ - mtpr(ITB_PTE); -} - -static void update_dtb (void); -{ - mtpr(TB_CTL); - /* This write into a temp register, not the actual one */ - mtpr(TB_TAG); - /* This commits the TB update */ - mtpr(DTB_PTE); -} -#endif - -static void pal_reset (CPUState *env) -{ -} - -static void do_swappal (CPUState *env, uint64_t palid) -{ - pal_handler_t *pal_handler; - - switch (palid) { - case 0 ... 2: - pal_handler = &pal_handlers[palid]; - env->pal_handler = pal_handler; - env->ipr[IPR_PAL_BASE] = -1ULL; - (*pal_handler->reset)(env); - break; - case 3 ... 255: - /* Unknown identifier */ - env->ir[0] = 1; - return; - default: - /* We were given the entry point address */ - env->pal_handler = NULL; - env->ipr[IPR_PAL_BASE] = palid; - env->pc = env->ipr[IPR_PAL_BASE]; - cpu_loop_exit(); - } -} - -static void pal_console_call (CPUState *env, uint32_t palcode) -{ - uint64_t palid; - - if (palcode < 0x00000080) { - /* Privileged palcodes */ - if (!(env->ps >> 3)) { - /* TODO: generate privilege exception */ - } - } - switch (palcode) { - case 0x00000000: - /* HALT */ - /* REQUIRED */ - break; - case 0x00000001: - /* CFLUSH */ - break; - case 0x00000002: - /* DRAINA */ - /* REQUIRED */ - /* Implemented as no-op */ - break; - case 0x00000009: - /* CSERVE */ - /* REQUIRED */ - break; - case 0x0000000A: - /* SWPPAL */ - /* REQUIRED */ - palid = env->ir[16]; - do_swappal(env, palid); - break; - case 0x00000080: - /* BPT */ - /* REQUIRED */ - break; - case 0x00000081: - /* BUGCHK */ - /* REQUIRED */ - break; - case 0x00000086: - /* IMB */ - /* REQUIRED */ - /* Implemented as no-op */ - break; - case 0x0000009E: - /* RDUNIQUE */ - /* REQUIRED */ - break; - case 0x0000009F: - /* WRUNIQUE */ - /* REQUIRED */ - break; - case 0x000000AA: - /* GENTRAP */ - /* REQUIRED */ - break; - default: - break; - } -} - -static void pal_openvms_call (CPUState *env, uint32_t palcode) -{ - uint64_t palid, val, oldval; - - if (palcode < 0x00000080) { - /* Privileged palcodes */ - if (!(env->ps >> 3)) { - /* TODO: generate privilege exception */ - } - } - switch (palcode) { - case 0x00000000: - /* HALT */ - /* REQUIRED */ - break; - case 0x00000001: - /* CFLUSH */ - break; - case 0x00000002: - /* DRAINA */ - /* REQUIRED */ - /* Implemented as no-op */ - break; - case 0x00000003: - /* LDQP */ - break; - case 0x00000004: - /* STQP */ - break; - case 0x00000005: - /* SWPCTX */ - break; - case 0x00000006: - /* MFPR_ASN */ - if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0) - env->ir[0] = val; - break; - case 0x00000007: - /* MTPR_ASTEN */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000008: - /* MTPR_ASTSR */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000009: - /* CSERVE */ - /* REQUIRED */ - break; - case 0x0000000A: - /* SWPPAL */ - /* REQUIRED */ - palid = env->ir[16]; - do_swappal(env, palid); - break; - case 0x0000000B: - /* MFPR_FEN */ - if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0) - env->ir[0] = val; - break; - case 0x0000000C: - /* MTPR_FEN */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000000D: - /* MTPR_IPIR */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000000E: - /* MFPR_IPL */ - if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0) - env->ir[0] = val; - break; - case 0x0000000F: - /* MTPR_IPL */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000010: - /* MFPR_MCES */ - if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0) - env->ir[0] = val; - break; - case 0x00000011: - /* MTPR_MCES */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000012: - /* MFPR_PCBB */ - if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0) - env->ir[0] = val; - break; - case 0x00000013: - /* MFPR_PRBR */ - if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0) - env->ir[0] = val; - break; - case 0x00000014: - /* MTPR_PRBR */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000015: - /* MFPR_PTBR */ - if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0) - env->ir[0] = val; - break; - case 0x00000016: - /* MFPR_SCBB */ - if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0) - env->ir[0] = val; - break; - case 0x00000017: - /* MTPR_SCBB */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000018: - /* MTPR_SIRR */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000019: - /* MFPR_SISR */ - if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0) - env->ir[0] = val; - break; - case 0x0000001A: - /* MFPR_TBCHK */ - if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0) - env->ir[0] = val; - break; - case 0x0000001B: - /* MTPR_TBIA */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000001C: - /* MTPR_TBIAP */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000001D: - /* MTPR_TBIS */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000001E: - /* MFPR_ESP */ - if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0) - env->ir[0] = val; - break; - case 0x0000001F: - /* MTPR_ESP */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000020: - /* MFPR_SSP */ - if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0) - env->ir[0] = val; - break; - case 0x00000021: - /* MTPR_SSP */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000022: - /* MFPR_USP */ - if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0) - env->ir[0] = val; - break; - case 0x00000023: - /* MTPR_USP */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000024: - /* MTPR_TBISD */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000025: - /* MTPR_TBISI */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000026: - /* MFPR_ASTEN */ - if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0) - env->ir[0] = val; - break; - case 0x00000027: - /* MFPR_ASTSR */ - if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0) - env->ir[0] = val; - break; - case 0x00000029: - /* MFPR_VPTB */ - if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0) - env->ir[0] = val; - break; - case 0x0000002A: - /* MTPR_VPTB */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000002B: - /* MTPR_PERFMON */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000002E: - /* MTPR_DATFX */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000003E: - /* WTINT */ - break; - case 0x0000003F: - /* MFPR_WHAMI */ - if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0) - env->ir[0] = val; - break; - case 0x00000080: - /* BPT */ - /* REQUIRED */ - break; - case 0x00000081: - /* BUGCHK */ - /* REQUIRED */ - break; - case 0x00000082: - /* CHME */ - break; - case 0x00000083: - /* CHMK */ - break; - case 0x00000084: - /* CHMS */ - break; - case 0x00000085: - /* CHMU */ - break; - case 0x00000086: - /* IMB */ - /* REQUIRED */ - /* Implemented as no-op */ - break; - case 0x00000087: - /* INSQHIL */ - break; - case 0x00000088: - /* INSQTIL */ - break; - case 0x00000089: - /* INSQHIQ */ - break; - case 0x0000008A: - /* INSQTIQ */ - break; - case 0x0000008B: - /* INSQUEL */ - break; - case 0x0000008C: - /* INSQUEQ */ - break; - case 0x0000008D: - /* INSQUEL/D */ - break; - case 0x0000008E: - /* INSQUEQ/D */ - break; - case 0x0000008F: - /* PROBER */ - break; - case 0x00000090: - /* PROBEW */ - break; - case 0x00000091: - /* RD_PS */ - break; - case 0x00000092: - /* REI */ - break; - case 0x00000093: - /* REMQHIL */ - break; - case 0x00000094: - /* REMQTIL */ - break; - case 0x00000095: - /* REMQHIQ */ - break; - case 0x00000096: - /* REMQTIQ */ - break; - case 0x00000097: - /* REMQUEL */ - break; - case 0x00000098: - /* REMQUEQ */ - break; - case 0x00000099: - /* REMQUEL/D */ - break; - case 0x0000009A: - /* REMQUEQ/D */ - break; - case 0x0000009B: - /* SWASTEN */ - break; - case 0x0000009C: - /* WR_PS_SW */ - break; - case 0x0000009D: - /* RSCC */ - break; - case 0x0000009E: - /* READ_UNQ */ - /* REQUIRED */ - break; - case 0x0000009F: - /* WRITE_UNQ */ - /* REQUIRED */ - break; - case 0x000000A0: - /* AMOVRR */ - break; - case 0x000000A1: - /* AMOVRM */ - break; - case 0x000000A2: - /* INSQHILR */ - break; - case 0x000000A3: - /* INSQTILR */ - break; - case 0x000000A4: - /* INSQHIQR */ - break; - case 0x000000A5: - /* INSQTIQR */ - break; - case 0x000000A6: - /* REMQHILR */ - break; - case 0x000000A7: - /* REMQTILR */ - break; - case 0x000000A8: - /* REMQHIQR */ - break; - case 0x000000A9: - /* REMQTIQR */ - break; - case 0x000000AA: - /* GENTRAP */ - /* REQUIRED */ - break; - case 0x000000AE: - /* CLRFEN */ - break; - default: - break; - } -} - -static void pal_unix_call (CPUState *env, uint32_t palcode) -{ - uint64_t palid, val, oldval; - - if (palcode < 0x00000080) { - /* Privileged palcodes */ - if (!(env->ps >> 3)) { - /* TODO: generate privilege exception */ - } - } - switch (palcode) { - case 0x00000000: - /* HALT */ - /* REQUIRED */ - break; - case 0x00000001: - /* CFLUSH */ - break; - case 0x00000002: - /* DRAINA */ - /* REQUIRED */ - /* Implemented as no-op */ - break; - case 0x00000009: - /* CSERVE */ - /* REQUIRED */ - break; - case 0x0000000A: - /* SWPPAL */ - /* REQUIRED */ - palid = env->ir[16]; - do_swappal(env, palid); - break; - case 0x0000000D: - /* WRIPIR */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000010: - /* RDMCES */ - if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0) - env->ir[0] = val; - break; - case 0x00000011: - /* WRMCES */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000002B: - /* WRFEN */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000002D: - /* WRVPTPTR */ - break; - case 0x00000030: - /* SWPCTX */ - break; - case 0x00000031: - /* WRVAL */ - break; - case 0x00000032: - /* RDVAL */ - break; - case 0x00000033: - /* TBI */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000034: - /* WRENT */ - break; - case 0x00000035: - /* SWPIPL */ - break; - case 0x00000036: - /* RDPS */ - break; - case 0x00000037: - /* WRKGP */ - break; - case 0x00000038: - /* WRUSP */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x00000039: - /* WRPERFMON */ - val = env->ir[16]; - if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1) - env->ir[0] = val; - break; - case 0x0000003A: - /* RDUSP */ - if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0) - env->ir[0] = val; - break; - case 0x0000003C: - /* WHAMI */ - if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0) - env->ir[0] = val; - break; - case 0x0000003D: - /* RETSYS */ - break; - case 0x0000003E: - /* WTINT */ - break; - case 0x0000003F: - /* RTI */ - if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0) - env->ir[0] = val; - break; - case 0x00000080: - /* BPT */ - /* REQUIRED */ - break; - case 0x00000081: - /* BUGCHK */ - /* REQUIRED */ - break; - case 0x00000083: - /* CALLSYS */ - break; - case 0x00000086: - /* IMB */ - /* REQUIRED */ - /* Implemented as no-op */ - break; - case 0x00000092: - /* URTI */ - break; - case 0x0000009E: - /* RDUNIQUE */ - /* REQUIRED */ - break; - case 0x0000009F: - /* WRUNIQUE */ - /* REQUIRED */ - break; - case 0x000000AA: - /* GENTRAP */ - /* REQUIRED */ - break; - case 0x000000AE: - /* CLRFEN */ - break; - default: - break; - } -} - -void call_pal (CPUState *env) -{ - pal_handler_t *pal_handler = env->pal_handler; - - switch (env->exception_index) { - case EXCP_RESET: - (*pal_handler->reset)(env); - break; - case EXCP_MCHK: - (*pal_handler->machine_check)(env); - break; - case EXCP_ARITH: - (*pal_handler->arithmetic)(env); - break; - case EXCP_INTERRUPT: - (*pal_handler->interrupt)(env); - break; - case EXCP_DFAULT: - (*pal_handler->dfault)(env); - break; - case EXCP_DTB_MISS_PAL: - (*pal_handler->dtb_miss_pal)(env); - break; - case EXCP_DTB_MISS_NATIVE: - (*pal_handler->dtb_miss_native)(env); - break; - case EXCP_UNALIGN: - (*pal_handler->unalign)(env); - break; - case EXCP_ITB_MISS: - (*pal_handler->itb_miss)(env); - break; - case EXCP_ITB_ACV: - (*pal_handler->itb_acv)(env); - break; - case EXCP_OPCDEC: - (*pal_handler->opcdec)(env); - break; - case EXCP_FEN: - (*pal_handler->fen)(env); - break; - default: - if (env->exception_index >= EXCP_CALL_PAL && - env->exception_index < EXCP_CALL_PALP) { - /* Unprivileged PAL call */ - (*pal_handler->call_pal) - (env, (env->exception_index - EXCP_CALL_PAL) >> 6); - } else if (env->exception_index >= EXCP_CALL_PALP && - env->exception_index < EXCP_CALL_PALE) { - /* Privileged PAL call */ - (*pal_handler->call_pal) - (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80); - } else { - /* Should never happen */ - } - break; - } - env->ipr[IPR_EXC_ADDR] &= ~1; -} - -void pal_init (CPUState *env) -{ - do_swappal(env, 0); -} - -#if 0 -static uint64_t get_ptebase (CPUState *env, uint64_t vaddr) -{ - uint64_t virbnd, ptbr; - - if ((env->features & FEATURE_VIRBND)) { - cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd); - if (vaddr >= virbnd) - cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr); - else - cpu_alpha_mfpr(env, IPR_PTBR, &ptbr); - } else { - cpu_alpha_mfpr(env, IPR_PTBR, &ptbr); - } - - return ptbr; -} - -static int get_page_bits (CPUState *env) -{ - /* XXX */ - return 13; -} - -static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp, - uint64_t ptebase, int page_bits, uint64_t level, - int mmu_idx, int rw) -{ - uint64_t pteaddr, pte, pfn; - uint8_t gh; - int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user; - - /* XXX: TOFIX */ - is_user = mmu_idx == MMU_USER_IDX; - pteaddr = (ptebase << page_bits) + (8 * level); - pte = ldq_raw(pteaddr); - /* Decode all interresting PTE fields */ - pfn = pte >> 32; - uwe = (pte >> 13) & 1; - kwe = (pte >> 12) & 1; - ure = (pte >> 9) & 1; - kre = (pte >> 8) & 1; - gh = (pte >> 5) & 3; - foE = (pte >> 3) & 1; - foW = (pte >> 2) & 1; - foR = (pte >> 1) & 1; - v = pte & 1; - ret = 0; - if (!v) - ret = 0x1; - /* Check access rights */ - ar = 0; - if (is_user) { - if (ure) - ar |= PAGE_READ; - if (uwe) - ar |= PAGE_WRITE; - if (rw == 1 && !uwe) - ret |= 0x2; - if (rw != 1 && !ure) - ret |= 0x2; - } else { - if (kre) - ar |= PAGE_READ; - if (kwe) - ar |= PAGE_WRITE; - if (rw == 1 && !kwe) - ret |= 0x2; - if (rw != 1 && !kre) - ret |= 0x2; - } - if (rw == 0 && foR) - ret |= 0x4; - if (rw == 2 && foE) - ret |= 0x8; - if (rw == 1 && foW) - ret |= 0xC; - *pfnp = pfn; - if (zbitsp != NULL) - *zbitsp = page_bits + (3 * gh); - if (protp != NULL) - *protp = ar; - - return ret; -} - -static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot, - uint64_t ptebase, int page_bits, - uint64_t vaddr, int mmu_idx, int rw) -{ - uint64_t pfn, page_mask, lvl_mask, level1, level2, level3; - int lvl_bits, ret; - - page_mask = (1ULL << page_bits) - 1ULL; - lvl_bits = page_bits - 3; - lvl_mask = (1ULL << lvl_bits) - 1ULL; - level3 = (vaddr >> page_bits) & lvl_mask; - level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask; - level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask; - /* Level 1 PTE */ - ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0); - switch (ret) { - case 3: - /* Access violation */ - return 2; - case 2: - /* translation not valid */ - return 1; - default: - /* OK */ - break; - } - /* Level 2 PTE */ - ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0); - switch (ret) { - case 3: - /* Access violation */ - return 2; - case 2: - /* translation not valid */ - return 1; - default: - /* OK */ - break; - } - /* Level 3 PTE */ - ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw); - if (ret & 0x1) { - /* Translation not valid */ - ret = 1; - } else if (ret & 2) { - /* Access violation */ - ret = 2; - } else { - switch (ret & 0xC) { - case 0: - /* OK */ - ret = 0; - break; - case 0x4: - /* Fault on read */ - ret = 3; - break; - case 0x8: - /* Fault on execute */ - ret = 4; - break; - case 0xC: - /* Fault on write */ - ret = 5; - break; - } - } - *paddr = (pfn << page_bits) | (vaddr & page_mask); - - return 0; -} - -static int virtual_to_physical (CPUState *env, uint64_t *physp, - int *zbitsp, int *protp, - uint64_t virtual, int mmu_idx, int rw) -{ - uint64_t sva, ptebase; - int seg, page_bits, ret; - - sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS); - if (sva != virtual) - seg = -1; - else - seg = sva >> (VA_BITS - 2); - virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43)); - ptebase = get_ptebase(env, virtual); - page_bits = get_page_bits(env); - ret = 0; - switch (seg) { - case 0: - /* seg1: 3 levels of PTE */ - ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, - virtual, mmu_idx, rw); - break; - case 1: - /* seg1: 2 levels of PTE */ - ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, - virtual, mmu_idx, rw); - break; - case 2: - /* kernel segment */ - if (mmu_idx != 0) { - ret = 2; - } else { - *physp = virtual; - } - break; - case 3: - /* seg1: TB mapped */ - ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, - virtual, mmu_idx, rw); - break; - default: - ret = 1; - break; - } - - return ret; -} - -/* XXX: code provision */ -int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, - int mmu_idx, int is_softmmu) -{ - uint64_t physical, page_size, end; - int prot, zbits, ret; - - ret = virtual_to_physical(env, &physical, &zbits, &prot, - address, mmu_idx, rw); - - switch (ret) { - case 0: - /* No fault */ - page_size = 1ULL << zbits; - address &= ~(page_size - 1); - /* FIXME: page_size should probably be passed to tlb_set_page, - and this loop removed. */ - for (end = physical + page_size; physical < end; physical += 0x1000) { - tlb_set_page(env, address, physical, prot, mmu_idx, - TARGET_PAGE_SIZE); - address += 0x1000; - } - ret = 0; - break; -#if 0 - case 1: - env->exception_index = EXCP_DFAULT; - env->ipr[IPR_EXC_ADDR] = address; - ret = 1; - break; - case 2: - env->exception_index = EXCP_ACCESS_VIOLATION; - env->ipr[IPR_EXC_ADDR] = address; - ret = 1; - break; - case 3: - env->exception_index = EXCP_FAULT_ON_READ; - env->ipr[IPR_EXC_ADDR] = address; - ret = 1; - break; - case 4: - env->exception_index = EXCP_FAULT_ON_EXECUTE; - env->ipr[IPR_EXC_ADDR] = address; - ret = 1; - case 5: - env->exception_index = EXCP_FAULT_ON_WRITE; - env->ipr[IPR_EXC_ADDR] = address; - ret = 1; -#endif - default: - /* Should never happen */ - env->exception_index = EXCP_MCHK; - env->ipr[IPR_EXC_ADDR] = address; - ret = 1; - break; - } - - return ret; -} -#endif diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c new file mode 100644 index 0000000..744b68b --- /dev/null +++ b/hw/alpha_pci.c @@ -0,0 +1,327 @@ +/* There's nothing in here that's Alpha specific, really. */ + +#include "config.h" +#include "alpha_sys.h" +#include "qemu-log.h" + + +/* PCI IO reads, to byte-word addressable memory. */ +/* ??? Doesn't handle multiple PCI busses. */ + +static uint32_t bw_io_readb(void *opaque, target_phys_addr_t addr) +{ + return cpu_inb(addr); +} + +static uint32_t bw_io_readw(void *opaque, target_phys_addr_t addr) +{ + return cpu_inw(addr); +} + +static uint32_t bw_io_readl(void *opaque, target_phys_addr_t addr) +{ + return cpu_inl(addr); +} + +/* PCI IO writes, to byte-word addressable memory. */ +/* ??? Doesn't handle multiple PCI busses. */ + +static void bw_io_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + cpu_outb(addr, val); +} + +static void bw_io_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + cpu_outw(addr, val); +} + +static void bw_io_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + cpu_outl(addr, val); +} + +CPUReadMemoryFunc * const alpha_pci_bw_io_reads[] = { + bw_io_readb, + bw_io_readw, + bw_io_readl, +}; + +CPUWriteMemoryFunc * const alpha_pci_bw_io_writes[] = { + bw_io_writeb, + bw_io_writew, + bw_io_writel, +}; + +/* PCI config space reads, to byte-word addressable memory. */ +static uint32_t bw_conf1_readb(void *opaque, target_phys_addr_t addr) +{ + PCIHostState *s = opaque; + return pci_data_read(s->bus, addr, 1); +} + +static uint32_t bw_conf1_readw(void *opaque, target_phys_addr_t addr) +{ + PCIHostState *s = opaque; + return pci_data_read(s->bus, addr, 2); +} + +static uint32_t bw_conf1_readl(void *opaque, target_phys_addr_t addr) +{ + PCIHostState *s = opaque; + return pci_data_read(s->bus, addr, 4); +} + +/* PCI config space writes, to byte-word addressable memory. */ +static void bw_conf1_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCIHostState *s = opaque; + pci_data_write(s->bus, addr, val, 1); +} + +static void bw_conf1_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCIHostState *s = opaque; + pci_data_write(s->bus, addr, val, 2); +} + +static void bw_conf1_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCIHostState *s = opaque; + pci_data_write(s->bus, addr, val, 4); +} + +CPUReadMemoryFunc * const alpha_pci_bw_conf1_reads[] = { + bw_conf1_readb, + bw_conf1_readw, + bw_conf1_readl, +}; + +CPUWriteMemoryFunc * const alpha_pci_bw_conf1_writes[] = { + bw_conf1_writeb, + bw_conf1_writew, + bw_conf1_writel, +}; + +/* PCI MEM access to dense (but not byte-word addressable) memory. */ +static uint32_t dense_mem_readl(void *opaque, target_phys_addr_t addr) +{ + PCIBus *b = opaque; + return ldl_phys(pci_to_cpu_addr(b, addr)); +} + +static void dense_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t v) +{ + PCIBus *b = opaque; + stl_phys(pci_to_cpu_addr(b, addr), v); +} + +CPUReadMemoryFunc * const alpha_pci_dense_mem_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + dense_mem_readl, +}; + +CPUWriteMemoryFunc * const alpha_pci_dense_mem_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + dense_mem_writel, +}; + +/* PCI IO to sparse memory. These are helper routines, which expect that the + relevant HAE has already been prepended to ADDR by the core-specific + routine that is actually registered with the memory region. */ + +uint32_t alpha_sparse_io_read(target_phys_addr_t addr) +{ + int size = (addr >> 3) & 3; + uint32_t val; + + addr >>= 5; + switch (size) { + case 0: + /* byte access */ + val = cpu_inb(addr); + break; + case 1: + /* word access */ + val = cpu_inw(addr); + break; + case 2: + /* tri-byte access; apparently possible with real pci lines. */ + qemu_log("pci: tri-byte io read"); + return ~0u; + default: + /* long access */ + return cpu_inl(addr); + } + + val <<= (addr & 3) * 8; + return val; +} + +void alpha_sparse_io_write(target_phys_addr_t addr, uint32_t val) +{ + int size = (addr >> 3) & 3; + + addr >>= 5; + switch (size) { + case 0: + /* byte access */ + val >>= (addr & 3) * 8; + cpu_outb(addr, val); + break; + case 1: + /* word access */ + val >>= (addr & 3) * 8; + cpu_outw(addr, val); + break; + case 2: + /* tri-byte access; apparently possible with real pci lines. */ + qemu_log("pci: tri-byte io write"); + break; + default: + /* long access */ + cpu_outl(addr, val); + break; + } +} + +uint32_t alpha_sparse_mem_read(PCIBus *b, target_phys_addr_t addr) +{ + int size = (addr >> 3) & 3; + uint32_t val; + + addr = pci_to_cpu_addr(b, addr >> 5); + switch (size) { + case 0: + /* byte access */ + val = ldub_phys(addr); + break; + case 1: + /* word access */ + val = lduw_phys(addr); + break; + case 2: + /* tri-byte access; apparently possible with real pci lines. */ + qemu_log("pci: tri-byte mem read"); + return ~0u; + default: + /* long access */ + return ldl_phys(addr); + } + + val <<= (addr & 3) * 8; + return val; +} + +void alpha_sparse_mem_write(PCIBus *b, target_phys_addr_t addr, uint32_t val) +{ + int size = (addr >> 3) & 3; + + addr = pci_to_cpu_addr(b, addr >> 5); + switch (size) { + case 0: + /* byte access */ + val >>= (addr & 3) * 8; + stb_phys(addr, val); + break; + case 1: + /* word access */ + val >>= (addr & 3) * 8; + stw_phys(addr, val); + break; + case 2: + /* tri-byte access; apparently possible with real pci lines. */ + qemu_log("pci: tri-byte mem write"); + break; + default: + /* long access */ + stl_phys(addr, val); + break; + } +} + +uint32_t alpha_sparse_conf1_read(PCIBus *b, target_phys_addr_t addr) +{ + int size = ((addr >> 3) & 3) + 1; + uint32_t val; + + if (size == 3) { + qemu_log("pci: tri-byte configuration read"); + return ~0u; + } + + addr >>= 5; + val = pci_data_read(b, addr, size); + val <<= (addr & 3) * 8; + + return val; +} + +void alpha_sparse_conf1_write(PCIBus *b, target_phys_addr_t addr, uint32_t val) +{ + int size = ((addr >> 3) & 3) + 1; + + if (size == 3) { + qemu_log("pci: tri-byte configuration write"); + return; + } + + addr >>= 5; + val >>= (addr & 3) * 8; + pci_data_write(b, addr, val, size); +} + +/* Configuration space accesses do not normall use an HAE. */ +static uint32_t sparse_conf1_readl(void *opaque, target_phys_addr_t addr) +{ + PCIBus *b = opaque; + return alpha_sparse_conf1_read(b, addr); +} + +static void sparse_conf1_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBus *b = opaque; + alpha_sparse_conf1_write(b, addr, val); +} + +CPUReadMemoryFunc * const alpha_pci_sparse_conf1_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + sparse_conf1_readl, +}; + +CPUWriteMemoryFunc * const alpha_pci_sparse_conf1_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + sparse_conf1_writel, +}; + +/* PCI/EISA Interrupt Acknowledge Cycle. */ + +static uint32_t iack_readl(void *opaque, target_phys_addr_t addr) +{ + if (addr & 15) { + return unassigned_mem_readl(opaque, addr); + } + return pic_read_irq(isa_pic); +} + +static void special_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + qemu_log("pci: special write cycle %08x", val); +} + +CPUReadMemoryFunc * const alpha_pci_iack_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + iack_readl, +}; + +CPUWriteMemoryFunc * const alpha_pci_special_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + special_writel, +}; diff --git a/hw/alpha_pyxis.c b/hw/alpha_pyxis.c new file mode 100644 index 0000000..0f4c038 --- /dev/null +++ b/hw/alpha_pyxis.c @@ -0,0 +1,1057 @@ +/* + * Qemu 21174 (PYXIS) chipset emulation. + * + * Written by Richard Henderson. + * + * This work is licensed under the GNU GPL license version 2 or later. + */ + +#include "cpu.h" +#include "exec-all.h" +#include "hw.h" +#include "devices.h" +#include "sysemu.h" +#include "alpha_sys.h" + +/* TODO: + ERR_MASK MEM_NEM controls do_unassigned_access behavior. + + RT_COUNT is a 33Mhz free-running counter. + INT_TIME should generate interrupt on RT_COUNT match. +*/ + +typedef struct PyxisState { + PCIHostState host; + /* General registers. */ + uint32_t pyxis_rev; + uint32_t pci_lat; + uint32_t pyxis_ctrl; + uint32_t pyxis_ctrl1; + uint32_t flash_ctrl; + uint32_t hae_mem; + uint32_t hae_io; + uint32_t cfg; + /* Diagnostic registers. */ + uint32_t pyxis_diag; + uint32_t diag_check; + /* Performance monitor registers. */ + uint32_t perf_monitor; + uint32_t perf_control; + /* Error registers. */ + uint32_t pyxis_err; + uint32_t pyxis_stat; + uint32_t err_mask; + uint32_t pyxis_syn; + uint32_t pyxis_err_data; + uint32_t mear; + uint32_t mesr; + uint32_t pci_err0; + uint32_t pci_err1; + uint32_t pci_err2; + /* Memory controler registers. */ + uint32_t mcr; + uint32_t mcmr; + uint32_t gtr; + uint32_t rtr; + uint32_t rhpr; + uint32_t mdr[2]; + uint32_t bbar[8]; + uint32_t bcr[8]; + uint32_t btr[8]; + uint32_t cvm; + /* PCI window control registers. */ + uint32_t tbia; + uint32_t wbase[4]; + uint32_t wmask[4]; + uint32_t tbase[4]; + uint32_t w_dac; + /* Scatter-gather address translation registers. */ + uint32_t tb_tag[8]; + uint32_t tb_page[8][4]; + /* Misc registers. */ + uint32_t ccr; + uint32_t clk_stat; + uint32_t reset; + /* Interrupt control registers. */ + uint64_t int_req; + uint64_t int_mask; + uint32_t int_hilo; + uint32_t int_route; + uint64_t gpo; + uint64_t int_time; + uint32_t iic_ctrl; + uint32_t int_cnfg; + /* QEMU emulation state. */ + uint32_t latch_tmp; + uint64_t ram_size; + /* Items with which to raise interrupts. */ + qemu_irq *irqs; +} PyxisState; + +/* Called when one of INT_REQ or INT_MASK changes, + adjust the signalled state of the cpu. */ +static void pyxis_irq_change(PyxisState *s) +{ + CPUState *env = first_cpu; + uint64_t req; + + req = s->int_req & s->int_mask; + + /* If there are any non-masked interrupts, tell the cpu. */ + if (req) { + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +static void invalidate_tag(PyxisState *s, int i) +{ + s->tb_tag[i] = 0; + memset(s->tb_page[i], 0, sizeof(s->tb_page[i])); +} + +static uint32_t dummy_read(void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static CPUReadMemoryFunc * const dummy_reads[] = { + dummy_read, + dummy_read, + dummy_read, +}; + +static CPUWriteMemoryFunc * const dummy_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + unassigned_mem_writel, +}; + +static uint32_t sparse0_readl(void *opaque, target_phys_addr_t addr) +{ + PyxisState *s = opaque; + target_phys_addr_t hae; + + hae = (s->hae_mem & 0xe0000000ull) << 5; + return alpha_sparse_mem_read(s->host.bus, hae + addr); +} + +static void sparse0_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PyxisState *s = opaque; + target_phys_addr_t hae; + + hae = (s->hae_mem & 0xe0000000ull) << 5; + alpha_sparse_mem_write(s->host.bus, hae + addr, val); +} + +static uint32_t sparse1_readl(void *opaque, target_phys_addr_t addr) +{ + PyxisState *s = opaque; + target_phys_addr_t hae; + + hae = ((s->hae_mem >> 11) & 0x1full) << (27 + 5); + return alpha_sparse_mem_read(s->host.bus, hae + addr); +} + +static void sparse1_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PyxisState *s = opaque; + target_phys_addr_t hae; + + hae = ((s->hae_mem >> 11) & 0x1full) << (27 + 5); + alpha_sparse_mem_write(s->host.bus, hae + addr, val); +} + +static uint32_t sparse2_readl(void *opaque, target_phys_addr_t addr) +{ + PyxisState *s = opaque; + target_phys_addr_t hae; + + hae = ((s->hae_mem >> 2) & 0x3full) << (26 + 5); + return alpha_sparse_mem_read(s->host.bus, hae + addr); +} + +static void sparse2_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PyxisState *s = opaque; + target_phys_addr_t hae; + + hae = ((s->hae_mem >> 2) & 0x3full) << (26 + 5); + alpha_sparse_mem_write(s->host.bus, hae + addr, val); +} + +static uint32_t sparseA_inl(void *opaque, target_phys_addr_t addr) +{ + /* Region A is fixed at the lower 32MB of I/O space. */ + return alpha_sparse_io_read(addr); +} + +static void sparseA_outl(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + /* Region A is fixed at the lower 32MB of I/O space. */ + alpha_sparse_io_write(addr, val); +} + +static uint32_t sparseB_inl(void *opaque, target_phys_addr_t addr) +{ + PyxisState *s = opaque; + target_phys_addr_t hae; + + hae = (s->hae_io & 0xfe000000ull) << 5; + return alpha_sparse_io_read(hae + addr); +} + +static void sparseB_outl(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PyxisState *s = opaque; + target_phys_addr_t hae; + + hae = (s->hae_io & 0xfe000000ull) << 5; + alpha_sparse_io_write(hae + addr, val); +} + +static uint32_t csr_874_readl(void *opaque, target_phys_addr_t addr) +{ + PyxisState *s = opaque; + + switch (addr) { + /* General Registers. */ + case 0x0080: return s->pyxis_rev; + case 0x00c0: return s->pci_lat; + case 0x0100: return s->pyxis_ctrl; + case 0x0140: return s->pyxis_ctrl1; + case 0x0200: return s->flash_ctrl; + case 0x0400: return s->hae_mem; + case 0x0440: return s->hae_io; + case 0x0480: return s->cfg; + + /* Diagnostic Registers. */ + case 0x2000: return s->pyxis_diag; + case 0x3000: return s->diag_check; + + /* Performance Monitor Registers. */ + case 0x4000: return s->perf_monitor; + case 0x4040: return s->perf_control; + + /* Error Registers. */ + case 0x8200: return s->pyxis_err; + case 0x8240: return s->pyxis_stat; + case 0x8280: return s->err_mask; + case 0x8300: return s->pyxis_syn; + case 0x8308: return s->pyxis_err_data; + case 0x8400: return s->mear; + case 0x8440: return s->mesr; + case 0x8800: return s->pci_err0; + case 0x8840: return s->pci_err1; + case 0x8880: return s->pci_err2; + + default: + do_unassigned_access(addr + 0x8740000000ull, 0, 0, 0, 4); + return -1; + } +} + +static uint32_t csr_875_readl(void *opaque, target_phys_addr_t addr) +{ + PyxisState *s = opaque; + + switch (addr) { + /* Memory Controller Registers. */ + case 0x0000: return s->mcr; + case 0x0040: return s->mcmr; + case 0x0200: return s->gtr; + case 0x0300: return s->rtr; + case 0x0400: return s->rhpr; + case 0x0500: return s->mdr[0]; + case 0x0540: return s->mdr[1]; + + case 0x0600: + case 0x0640: + case 0x0680: + case 0x06c0: + case 0x0700: + case 0x0740: + case 0x0780: + case 0x07c0: + return s->bbar[(addr - 0x0600) / 0x40]; + + case 0x0800: + case 0x0840: + case 0x0880: + case 0x08c0: + case 0x0900: + case 0x0940: + case 0x0980: + case 0x09c0: + return s->bcr[(addr - 0x0800) / 0x40]; + + case 0x0a00: + case 0x0a40: + case 0x0a80: + case 0x0ac0: + case 0x0b00: + case 0x0b40: + case 0x0b80: + case 0x0bc0: + return s->btr[(addr - 0x0a00) / 0x40]; + + case 0x0c00: return s->cvm; + + default: + do_unassigned_access(addr + 0x8750000000ull, 0, 0, 0, 4); + return -1; + } +} + +static uint32_t csr_876_readl(void *opaque, target_phys_addr_t addr) +{ + PyxisState *s = opaque; + + switch (addr) { + /* PCI Window Control Registers. */ + case 0x0100: return s->tbia; + + case 0x0400: + case 0x0500: + case 0x0600: + case 0x0700: + return s->wbase[(addr - 0x0400) / 0x0100]; + + case 0x0440: + case 0x0540: + case 0x0640: + case 0x0740: + return s->wmask[(addr - 0x0440) / 0x0100]; + + case 0x0480: + case 0x0580: + case 0x0680: + case 0x0780: + return s->tbase[(addr - 0x0480) / 0x0100]; + + case 0x07c0: return s->w_dac; + + /* Scatter-gather Address Translation Registers. */ + case 0x0800: + case 0x0840: + case 0x0880: + case 0x08c0: + case 0x0900: + case 0x0940: + case 0x0980: + case 0x09c0: + return s->tb_tag[(addr - 0x0800) / 0x40]; + + case 0x1000: case 0x1040: case 0x1080: case 0x10c0: + case 0x1100: case 0x1140: case 0x1180: case 0x11c0: + case 0x1200: case 0x1240: case 0x1280: case 0x12c0: + case 0x1300: case 0x1340: case 0x1380: case 0x13c0: + case 0x1400: case 0x1440: case 0x1480: case 0x14c0: + case 0x1500: case 0x1540: case 0x1580: case 0x15c0: + case 0x1600: case 0x1640: case 0x1680: case 0x16c0: + case 0x1700: case 0x1740: case 0x1780: case 0x17c0: + return *(&s->tb_page[0][0] + ((addr - 0x1000) / 0x40)); + + default: + do_unassigned_access(addr + 0x8760000000ull, 0, 0, 0, 4); + return -1; + } +} + +static uint32_t csr_878_readl(void *opaque, target_phys_addr_t addr) +{ + PyxisState *s = opaque; + + switch (addr) { + /* Miscellaneous Registers. */ + case 0x0000: return s->ccr; + case 0x0100: return s->clk_stat; + case 0x0900: return s->reset; + + default: + do_unassigned_access(addr + 0x8780000000ull, 0, 0, 0, 4); + return -1; + } +} + +static uint32_t csr_87a_readl(void *opaque, target_phys_addr_t addr) +{ + PyxisState *s = opaque; + uint64_t ret; + + switch (addr) { + /* Interrupt Control Registers. */ + case 0x0000: + ret = s->int_req; + break; + case 0x0040: + ret = s->int_mask; + break; + case 0x00c0: + ret = s->int_hilo; + break; + case 0x0140: + ret = s->int_route; + break; + case 0x0180: + ret = s->gpo; + break; + case 0x01c0: return s->int_cnfg; + case 0x0200: + /* The RT_COUNT clock runs at 66.66MHz. */ + ret = qemu_get_clock_ns(vm_clock) / 15; + break; + case 0x0240: + ret = s->int_time; + break; + case 0x02c0: + return s->iic_ctrl; + + case 0x0004: + case 0x0044: + case 0x00c4: + case 0x0144: + case 0x0184: + case 0x0204: + case 0x0244: + return s->latch_tmp; + + default: + do_unassigned_access(addr + 0x87a0000000ull, 0, 0, 0, 4); + return -1; + } + + s->latch_tmp = ret >> 32; + return ret; +} + +static void csr_874_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PyxisState *s = opaque; + + switch (addr) { + /* General Registers. */ + case 0x0080: + /* pyxis_rev: RO */ + break; + case 0x00c0: + s->pci_lat = val & 0xffff; + break; + case 0x0100: + s->pyxis_ctrl = val & 0x77703ffd; + break; + case 0x0140: + s->pyxis_ctrl1 = val & 0xffffff11; + break; + case 0x0200: + s->flash_ctrl = val & 0x3fff; + break; + case 0x0400: + s->hae_mem = val & 0xe000f8fc; + break; + case 0x0440: + s->hae_io = val & 0xfe000000; + break; + case 0x0480: + s->cfg = val & 3; + break; + + /* Diagnostic Registers. */ + case 0x2000: + s->pyxis_diag = val & 0xb0000003; + break; + case 0x3000: + s->diag_check = val & 0xff; + break; + + /* Performance Monitor Registers. */ + case 0x4000: + /* perf_monitor: RO */ + break; + case 0x4040: + /* perf_control: */ + /* If LOW_COUNT_CLR set, zero the low counter. */ + if (val & (1 << 13)) { + s->perf_monitor &= 0xffff0000; + } + /* If HIGH_COUNT_CLR set, zero the high counter. */ + if (val & (1 << 29)) { + s->perf_monitor &= 0x0000ffff; + } + s->perf_control = val & 0xd007d007; + break; + + /* Error Registers. */ + case 0x8200: + /* pyxis_err */ + /* Zap the RW1C fields; the rest are RO. */ + s->pyxis_err &= ~(val & 0xbff); + break; + + case 0x8240: + /* pyxis_stat: RO */ + break; + case 0x8280: + s->err_mask = val & 0x5ff; + break; + case 0x8300: + /* pyxis_syn: RO */ + break; + case 0x8308: + /* pyxis_err_data: RO */ + break; + case 0x8400: + /* mear: RO */ + break; + case 0x8440: + /* mesr: */ + /* There are a bunch of RO fields in here; preserve them. */ + s->mesr = (s->mesr & ~0xfe000000) | (val & 0xfe000000); + break; + case 0x8800: + /* pci_err0: RO */ + break; + case 0x8840: + /* pci_err1: RO */ + break; + case 0x8880: + /* pci_err2: RO */ + break; + + default: + do_unassigned_access(addr + 0x8740000000ull, 1, 0, 0, 4); + return; + } +} + +static void csr_875_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PyxisState *s = opaque; + + switch (addr) { + /* Memory Controller Registers. */ + case 0x0000: /* mcr: */ + /* The SERVER_MODE and BCACHE_TYPE fields are RO. */ + s->mcr = (s->mcr & 0x300) | (val & 0x3ffffc01); + break; + case 0x0040: + s->mcmr = val & 0xffff; + break; + case 0x0200: + s->gtr = val & 0x0737; + break; + case 0x0300: + s->rtr = val & 0x9ff0; + break; + case 0x0400: + s->rhpr = val & 0xffff; + break; + case 0x0500: + s->mdr[0] = val & 0xbf3f3f3f; + break; + case 0x0540: + s->mdr[1] = val & 0xbf3f3f3f; + break; + + case 0x0600: case 0x0640: case 0x0680: case 0x06c0: + case 0x0700: case 0x0740: case 0x0780: case 0x07c0: + s->bbar[(addr - 0x0600) / 0x40] = val & 0xffc0; + break; + + case 0x0800: case 0x0840: case 0x0880: case 0x08c0: + case 0x0900: case 0x0940: case 0x0980: case 0x09c0: + s->bcr[(addr - 0x0800) / 0x40] = val & 0xff; + break; + + case 0x0a00: case 0x0a40: case 0x0a80: case 0x0ac0: + case 0x0b00: case 0x0b40: case 0x0b80: case 0x0bc0: + s->btr[(addr - 0x0a00) / 0x40] = val & 0x23; + break; + + case 0x0c00: /* cvm: */ + /* All bits are RW1C. */ + s->cvm &= ~val; + break; + + default: + do_unassigned_access(addr + 0x8750000000ull, 1, 0, 0, 4); + return; + } +} + +static void csr_876_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PyxisState *s = opaque; + int i; + + switch (addr) { + /* PCI Window Control Registers. */ + case 0x0100: + switch (val & 3) { + case 0: /* No operation. */ + break; + case 1: /* Invalidate and unlock TLB tags that are locked. */ + for (i = 0; i < 4; ++i) { + if (s->tb_tag[i] & 2) { + invalidate_tag(s, i); + } + } + break; + case 2: /* Invalidate and unlock TLB tags that are unlocked. */ + for (i = 0; i < 4; ++i) { + if ((s->tb_tag[i] & 2) == 0) { + invalidate_tag(s, i); + } + } + break; + case 3: /* Invalidate and unlock all TLB tag entries. */ + memset(s->tb_tag, 0, sizeof(s->tb_tag)); + memset(s->tb_page, 0, sizeof(s->tb_page)); + break; + } + break; + + case 0x0400: case 0x0500: case 0x0600: case 0x0700: + s->wbase[(addr - 0x0400) / 0x0100] = val & 0xfff0000f; + break; + + case 0x0440: case 0x0540: case 0x0640: case 0x0740: + s->wmask[(addr - 0x0440) / 0x0100] = val & 0xfff00000; + break; + + case 0x0480: case 0x0580: case 0x0680: case 0x0780: + s->tbase[(addr - 0x0480) / 0x0100] = val & 0xffffff00; + break; + + case 0x07c0: + s->w_dac = val & 0xffffff00; + break; + + /* Scatter-gather Address Translation Registers. */ + case 0x0800: case 0x0840: case 0x0880: case 0x08c0: /* lockable */ + s->tb_tag[(addr - 0x0800) / 0x40] = val & 0xffff8007; + break; + case 0x0900: case 0x0940: case 0x0980: case 0x09c0: /* not lockable */ + s->tb_tag[(addr - 0x0800) / 0x40] = val & 0xffff8005; + break; + + case 0x1000: case 0x1040: case 0x1080: case 0x10c0: + case 0x1100: case 0x1140: case 0x1180: case 0x11c0: + case 0x1200: case 0x1240: case 0x1280: case 0x12c0: + case 0x1300: case 0x1340: case 0x1380: case 0x13c0: + case 0x1400: case 0x1440: case 0x1480: case 0x14c0: + case 0x1500: case 0x1540: case 0x1580: case 0x15c0: + case 0x1600: case 0x1640: case 0x1680: case 0x16c0: + case 0x1700: case 0x1740: case 0x1780: case 0x17c0: + *(&s->tb_page[0][0] + ((addr - 0x1000) / 0x40)) = val & 0x003fffff; + break; + + default: + do_unassigned_access(addr + 0x8760000000ull, 1, 0, 0, 4); + return; + } +} + +static void csr_878_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PyxisState *s = opaque; + + switch (addr) { + /* Miscellaneous Registers. */ + case 0x0000: + s->ccr = val & 0xff071773; + break; + case 0x0100: + /* clk_stat: RO */ + break; + case 0x0900: + /* reset: */ + /* Yes, the value is architected. Jokers... */ + if (val == 0x0000dead) { + /* ??? This should be reset, but shutdown makes for easier + debugging for the moment. */ + qemu_system_shutdown_request(); + } + break; + + default: + do_unassigned_access(addr + 0x8780000000ull, 1, 0, 0, 4); + return; + } +} + +/* ??? We should probably not accept partial writes to the 64-bit registers. + In particular, INT_MASK, RT_COUNT and INT_TIME are likely to do the wrong + thing with partial writes. */ + +static void csr_87a_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PyxisState *s = opaque; + uint64_t val64 = ((uint64_t)val << 32) | s->latch_tmp; + + switch (addr) { + /* Interrupt Control Registers. */ + case 0x0000: + s->latch_tmp = val; + break; + case 0x0004: + s->int_req &= ~(val64 & 0x7ffffffffffffffful); + pyxis_irq_change(s); + break; + case 0x0040: + s->latch_tmp = val; + break; + case 0x0044: + s->int_mask = val64; + pyxis_irq_change(s); + break; + case 0x00c0: + s->int_hilo = val & 0x7f; + break; + case 0x00c4: + /* int_hilo highpart all 0 */ + break; + case 0x0140: + s->int_route = val & 0x7f; + break; + case 0x0144: + /* int_route highpart all 0 */ + break; + case 0x0180: + s->latch_tmp = val; + break; + case 0x0184: + s->gpo = val64; + break; + case 0x01c0: + s->int_cnfg = val; + break; + case 0x0200: + /* rt_count low */ + break; + case 0x0204: + /* rt_count high */ + break; + case 0x0240: + s->latch_tmp = val; + break; + case 0x0244: + s->int_time = val64; + break; + case 0x02c0: + s->iic_ctrl = val; + break; + + default: + do_unassigned_access(addr + 0x87a0000000ull, 1, 0, 0, 4); + return; + } +} + +static CPUReadMemoryFunc * const sparse0_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + sparse0_readl +}; + +static CPUWriteMemoryFunc * const sparse0_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + sparse0_writel +}; + +static CPUReadMemoryFunc * const sparse1_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + sparse1_readl +}; + +static CPUWriteMemoryFunc * const sparse1_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + sparse1_writel +}; + +static CPUReadMemoryFunc * const sparse2_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + sparse2_readl +}; + +static CPUWriteMemoryFunc * const sparse2_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + sparse2_writel +}; + +static CPUReadMemoryFunc * const sparseA_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + sparseA_inl +}; + +static CPUWriteMemoryFunc * const sparseA_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + sparseA_outl +}; + +static CPUReadMemoryFunc * const sparseB_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + sparseB_inl +}; + +static CPUWriteMemoryFunc * const sparseB_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + sparseB_outl +}; + +static CPUReadMemoryFunc * const csr_874_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + csr_874_readl +}; + +static CPUWriteMemoryFunc * const csr_874_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + csr_874_writel +}; + +static CPUReadMemoryFunc * const csr_875_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + csr_875_readl +}; + +static CPUWriteMemoryFunc * const csr_875_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + csr_875_writel +}; + +static CPUReadMemoryFunc * const csr_876_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + csr_876_readl +}; + +static CPUWriteMemoryFunc * const csr_876_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + csr_876_writel +}; + +static CPUReadMemoryFunc * const csr_878_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + csr_878_readl +}; + +static CPUWriteMemoryFunc * const csr_878_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + csr_878_writel +}; + +static CPUReadMemoryFunc * const csr_87a_reads[] = { + unassigned_mem_readb, + unassigned_mem_readw, + csr_87a_readl +}; + +static CPUWriteMemoryFunc * const csr_87a_writes[] = { + unassigned_mem_writeb, + unassigned_mem_writew, + csr_87a_writel +}; + + +static void pyxis_line_change(void *opaque, int irq, int level) +{ + PyxisState *s = opaque; + uint64_t req; + + /* Set/Reset the bit in INT_REQ based on IRQ+LEVEL. */ + req = s->int_req; + if (level) { + req |= 1ull << irq; + } else { + req &= ~(1ull << irq); + } + s->int_req = req; + + pyxis_irq_change(s); +} + +static void pyxis_pci_set_irq(void *opaque, int irq_num, int level) +{ + qemu_irq *irqs = opaque; + qemu_set_irq(irqs[irq_num], level); +} + +static int pyxis_pci_map_irq(PCIDevice *d, int irq_num) +{ + int slot = (d->devfn >> 3) & 3; + + assert(irq_num >= 0 && irq_num <= 3); + + return irq_num * 4 + (11 - slot); +} + +PCIBus *pyxis_init(uint64_t ram_size, qemu_irq *p_isa_irq) +{ + const uint64_t GB = 1024 * 1024 * 1024; + DeviceState *dev; + PCIHostState *p; + PyxisState *s; + PCIBus *b; + int region; + + dev = qdev_create(NULL, "pyxis-pcihost"); + p = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev)); + s = container_of(p, PyxisState, host); + + s->irqs = qemu_allocate_irqs(pyxis_line_change, s, 64); + *p_isa_irq = s->irqs[7]; + + b = pci_register_bus(&s->host.busdev.qdev, "pci", pyxis_pci_set_irq, + pyxis_pci_map_irq, s->irqs, 0, 32); + s->host.bus = b; + + qdev_init_nofail(dev); + + /* Main memory region, 0x00.0000.0000, 8GB. */ + + /* Dummy memory region, 0x0e.0000.0000, 4GB. */ + region = cpu_register_io_memory(dummy_reads, dummy_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0xe00000000ull, 4*GB, region); + + /* PCI Sparse memory region 0, 0x80.0000.0000, 16GB (covers 512MB). */ + region = cpu_register_io_memory(sparse0_reads, sparse0_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8000000000ull, 16*GB, region); + + /* PCI Sparse memory region 1, 0x84.0000.0000, 4GB (covers 128MB). */ + region = cpu_register_io_memory(sparse1_reads, sparse1_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8400000000ull, 4*GB, region); + + /* PCI Sparse memory region 2, 0x85.0000.0000, 2GB (covers 64MB). */ + region = cpu_register_io_memory(sparse2_reads, sparse2_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8500000000ull, 2*GB, region); + + /* PCI Sparse I/O region A, 0x85.8000.0000, 1GB (covers 32MB). */ + region = cpu_register_io_memory(sparseA_reads, sparseA_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8580000000ull, 1*GB, region); + + /* PCI Sparse I/O region B, 0x85.C000.0000, 1GB (covers 32MB). */ + region = cpu_register_io_memory(sparseB_reads, sparseB_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x85c0000000ull, 1*GB, region); + + /* PCI Dense memory, 0x86.0000.0000, 4GB. */ + region = cpu_register_io_memory(alpha_pci_dense_mem_reads, + alpha_pci_dense_mem_writes, b, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8600000000ull, 4*GB, region); + + /* Sparse configuration space, 0x87.0000.0000, 512MB. */ + /* ??? Best I can tell, type 0 and type 1 accesses really only differ + when it comes to the actual bits placed on the PCI bus lines. + Which does not matter inside QEMU. Which means that the contents + of the CFG register doesn't really matter. */ + region = cpu_register_io_memory(alpha_pci_sparse_conf1_reads, + alpha_pci_sparse_conf1_writes, b, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8700000000ull, GB/2, region); + + /* PCI special/interrupt acknowledge 0x87.2000.0000, 512MB. */ + region = cpu_register_io_memory(alpha_pci_iack_reads, + alpha_pci_special_writes, b, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8720000000ull, GB/2, region); + + /* PYXIS Main CSRs, 0x87.4000.0000, 128MB. */ + region = cpu_register_io_memory(csr_874_reads, csr_874_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8740000000ull, GB/4, region); + + /* PYXIS Memory Control CSRs, 0x87.5000.0000, 128MB. */ + region = cpu_register_io_memory(csr_875_reads, csr_875_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8750000000ull, GB/4, region); + + /* PYXIS Address Translation CSRs, 0x87.6000.0000, 128MB. */ + region = cpu_register_io_memory(csr_876_reads, csr_876_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8760000000ull, GB/4, region); + + /* PYXIS Miscellaneous CSRs, 0x87.8000.0000, 128MB. */ + region = cpu_register_io_memory(csr_878_reads, csr_878_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8780000000ull, GB/4, region); + + /* ??? PYXIS Power Management CSRs, 0x87.9000.0000, 128MB. */ + + /* PYXIS Interrupt Control CSRs, 0x87.a000.0000, 128MB. */ + region = cpu_register_io_memory(csr_87a_reads, csr_87a_writes, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x87a0000000ull, GB/4, region); + + /* ??? Flash ROM read/write space, 0x87.c000.0000, 1GB. */ + + /* PCI BW memory, 0x88.0000.0000, 4GB. */ + pci_bus_set_mem_base(b, 0x8800000000ull); + + /* PCI BW I/O, 0x89.0000.0000, 4GB. */ + region = cpu_register_io_memory(alpha_pci_bw_io_reads, + alpha_pci_bw_io_writes, b, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8900000000ull, 4*GB, region); + + /* PCI configuration space type 0, 0x8a.0000.0000, 4GB. */ + /* ??? Best I can tell, type 0 and type 1 accesses really only differ + when it comes to the actual bits placed on the PCI bus lines. + Which does not matter inside QEMU. */ + region = cpu_register_io_memory(alpha_pci_bw_conf1_reads, + alpha_pci_bw_conf1_writes, b, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8a00000000ull, 4*GB, region); + + /* PCI configuration space type 1, 0x8b.0000.0000, 4GB. */ + region = cpu_register_io_memory(alpha_pci_bw_conf1_reads, + alpha_pci_bw_conf1_writes, b, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0x8b00000000ull, 4*GB, region); + + s->ram_size = ram_size; + /* Call reset function. */ + + return b; +} + +static int pyxis_pcihost_init(SysBusDevice *dev) +{ + return 0; +} + +static SysBusDeviceInfo pyxis_pcihost_info = { + .init = pyxis_pcihost_init, + .qdev.name = "pyxis-pcihost", + .qdev.size = sizeof(PyxisState), + .qdev.no_user = 1 +}; + +static void pyxis_register(void) +{ + sysbus_register_withprop(&pyxis_pcihost_info); +} +device_init(pyxis_register); diff --git a/hw/alpha_sx164.c b/hw/alpha_sx164.c new file mode 100644 index 0000000..c2adc90 --- /dev/null +++ b/hw/alpha_sx164.c @@ -0,0 +1,195 @@ +/* + * QEMU Alpha SX164 hardware system emulator. + */ + +#include "hw.h" +#include "elf.h" +#include "loader.h" +#include "boards.h" +#include "alpha_sys.h" +#include "sysemu.h" +#include "mc146818rtc.h" + + +#define MAX_IDE_BUS 2 + + +static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr) +{ + if (((addr >> 41) & 3) == 2) { + addr &= 0xffffffffffull; + } + return addr; +} + +static void rtc_set_irq(void *opaque, int irq_num, int level) +{ + CPUState *env = first_cpu; + if (level) { + cpu_interrupt(env, CPU_INTERRUPT_TIMER); + } else { + cpu_reset_interrupt(env, CPU_INTERRUPT_TIMER); + } +} + +static void sx164_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + CPUState *env = NULL; + ram_addr_t ram_offset; + PCIBus *pci_bus; + ISABus *isa_bus; + qemu_irq isa_pci_irq, *rtc_irqs, *isa_irqs; + long size, i; + const char *palcode_filename; + uint64_t palcode_entry, palcode_low, palcode_high; + uint64_t kernel_entry, kernel_low, kernel_high; + + env = cpu_init(cpu_model ? cpu_model : "pca56"); + + env->trap_arg0 = ram_size; + env->trap_arg1 = 0; + env->trap_arg2 = 0; + + ram_offset = qemu_ram_alloc(NULL, "ram", ram_size); + cpu_register_physical_memory(0, ram_size, ram_offset); + + /* Init pyxis. */ + pci_bus = pyxis_init(ram_size, &isa_pci_irq); + + /* ??? There should be a Cypress CY82C693U SuperIO chip here + providing the PCI-to-ISA bridge. But the generic ISA support + doesn't expect a bridge, so we sort-of hard-code things in. + Ideally, the SuperIO device would capture all unhandled accesses + within the PCI space and then forward to the ISA bus. If the + access is unhandled within the ISA bus only then report to the + CPU via machine check. */ + isa_bus = isa_bus_new(NULL); + isa_mem_base = 0x8800000000ull; + + isa_irqs = i8259_init(isa_pci_irq); + isa_bus_irqs(isa_irqs); + + /* ??? This isn't 100% correct, but should be Good Enough given that + we hide most of the actual details inside our custom PALcode. + The real HW somehow routes the TOY clock to cpu_int<2> (Int22). + How this relates to either the i8259 or the 21174 interrupt masks + is not documented. */ + rtc_irqs = qemu_allocate_irqs(rtc_set_irq, NULL, 1); + rtc_init(1980, rtc_irqs[0]); + + pit_init(0x40, 0); + + /* VGA setup. Don't bother loading the bios. */ + pci_vga_init(pci_bus); + + for (i = 0; i < MAX_SERIAL_PORTS; ++i) { + if (serial_hds[i]) { + serial_isa_init(i, serial_hds[i]); + } + } + +#if 0 + /* IDE setup. */ + /* ??? Real SX164 actually has a Cypress CY82C693U. */ + { + DriveInfo * hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { + hw_error("qemu: too many IDE buses\n"); + exit(1); + } + + for (i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { + hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); + } + pci_cmd646_ide_init(pci_bus, hd, 0); + } +#endif + +#if 0 + /* USB setup. The Cypress chip is OHCI compliant; this ought not + be too far off Really Correct. */ + usb_ohci_init_pci(pci_bus, -1); +#endif + + /* Network setup. NE2K is good enough, failing Tulip support. */ + for (i = 0; i < nb_nics; i++) { + pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); + } + + /* Load PALcode. Given that this is not "real" cpu palcode, + but one explicitly written for the emulation, we might as + well load it directly from and ELF image. */ + palcode_filename = (bios_name ? bios_name : "palcode-sx164"); + palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename); + if (palcode_filename == NULL) { + hw_error("qemu: no palcode provided\n"); + exit(1); + } + size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys, + NULL, &palcode_entry, &palcode_low, &palcode_high, + 0, EM_ALPHA, 0); + if (size < 0) { + hw_error("qemu: could not load palcode '%s'\n", palcode_filename); + exit(1); + } + env->pc = palcode_entry; + env->pal_unix.palbr = palcode_entry; + + /* Load a kernel. */ + if (kernel_filename) { + uint64_t param_offset; + + size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys, + NULL, &kernel_entry, &kernel_low, &kernel_high, + 0, EM_ALPHA, 0); + if (size < 0) { + hw_error("qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + + env->trap_arg1 = kernel_entry; + + param_offset = kernel_low - 0x6000; + + if (kernel_cmdline) { + pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline); + } + + if (initrd_filename) { + long initrd_base, initrd_size; + + initrd_base = (kernel_high | TARGET_PAGE_SIZE) + 1; + initrd_size = load_image_targphys(initrd_filename, initrd_base, + ram_size - initrd_base); + if (initrd_size < 0) { + hw_error("qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + + stq_phys(param_offset + 0x100, initrd_base); + stq_phys(param_offset + 0x108, initrd_size); + } + } +} + +static QEMUMachine sx164_machine = { + .name = "sx164", + .desc = "Alpha SX164", + .init = sx164_init, + .max_cpus = 1, + .is_default = 1, +}; + +static void sx164_machine_init(void) +{ + qemu_register_machine(&sx164_machine); +} + +machine_init(sx164_machine_init); diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h new file mode 100644 index 0000000..43e9892 --- /dev/null +++ b/hw/alpha_sys.h @@ -0,0 +1,41 @@ +/* Alpha cores and system support chips. */ + +#ifndef HW_ALPHA_H +#define HW_ALPHA_H 1 + +#include "pci.h" +#include "pci_host.h" +#include "ide.h" +#include "net.h" +#include "pc.h" +#include "usb-ohci.h" +#include "irq.h" + + +extern PCIBus *pyxis_init(uint64_t, qemu_irq *); + +/* alpha_pci.c. */ +extern CPUReadMemoryFunc * const alpha_pci_bw_io_reads[]; +extern CPUWriteMemoryFunc * const alpha_pci_bw_io_writes[]; +extern CPUReadMemoryFunc * const alpha_pci_bw_conf1_reads[]; +extern CPUWriteMemoryFunc * const alpha_pci_bw_conf1_writes[]; + +extern CPUReadMemoryFunc * const alpha_pci_dense_mem_reads[]; +extern CPUWriteMemoryFunc * const alpha_pci_dense_mem_writes[]; + +extern CPUReadMemoryFunc * const alpha_pci_sparse_conf1_reads[]; +extern CPUWriteMemoryFunc * const alpha_pci_sparse_conf1_writes[]; + +extern CPUReadMemoryFunc * const alpha_pci_iack_reads[]; +extern CPUWriteMemoryFunc * const alpha_pci_special_writes[]; + +extern uint32_t alpha_sparse_io_read(target_phys_addr_t); +extern void alpha_sparse_io_write(target_phys_addr_t, uint32_t); + +extern uint32_t alpha_sparse_mem_read(PCIBus *, target_phys_addr_t); +extern void alpha_sparse_mem_write(PCIBus *, target_phys_addr_t, uint32_t); + +extern uint32_t alpha_sparse_conf1_read(PCIBus *, target_phys_addr_t); +extern void alpha_sparse_conf1_write(PCIBus *, target_phys_addr_t, uint32_t); + +#endif diff --git a/linux-user/main.c b/linux-user/main.c index a1e37e4..4c0a55a 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2526,6 +2526,11 @@ void cpu_loop (CPUState *env) fprintf(stderr, "Machine check exception. Exit\n"); exit(1); break; + case EXCP_CLK_INTERRUPT: + case EXCP_DEV_INTERRUPT: + fprintf(stderr, "External interrupt. Exit\n"); + exit(1); + break; case EXCP_ARITH: env->lock_addr = -1; info.si_signo = TARGET_SIGFPE; @@ -2534,41 +2539,21 @@ void cpu_loop (CPUState *env) info._sifields._sigfault._addr = env->pc; queue_signal(env, info.si_signo, &info); break; - case EXCP_HW_INTERRUPT: - fprintf(stderr, "External interrupt. Exit\n"); - exit(1); - break; - case EXCP_DFAULT: + case EXCP_MMFAULT: env->lock_addr = -1; info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; - info.si_code = (page_get_flags(env->ipr[IPR_EXC_ADDR]) & PAGE_VALID + info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR); - info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR]; + info._sifields._sigfault._addr = env->trap_arg0; queue_signal(env, info.si_signo, &info); break; - case EXCP_DTB_MISS_PAL: - fprintf(stderr, "MMU data TLB miss in PALcode\n"); - exit(1); - break; - case EXCP_ITB_MISS: - fprintf(stderr, "MMU instruction TLB miss\n"); - exit(1); - break; - case EXCP_ITB_ACV: - fprintf(stderr, "MMU instruction access violation\n"); - exit(1); - break; - case EXCP_DTB_MISS_NATIVE: - fprintf(stderr, "MMU data TLB miss\n"); - exit(1); - break; case EXCP_UNALIGN: env->lock_addr = -1; info.si_signo = TARGET_SIGBUS; info.si_errno = 0; info.si_code = TARGET_BUS_ADRALN; - info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR]; + info._sifields._sigfault._addr = env->trap_arg0; queue_signal(env, info.si_signo, &info); break; case EXCP_OPCDEC: @@ -2583,9 +2568,9 @@ void cpu_loop (CPUState *env) case EXCP_FEN: /* No-op. Linux simply re-enables the FPU. */ break; - case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1): + case EXCP_CALL_PAL: env->lock_addr = -1; - switch ((trapnr >> 6) | 0x80) { + switch (env->error_code) { case 0x80: /* BPT */ info.si_signo = TARGET_SIGTRAP; @@ -2676,8 +2661,6 @@ void cpu_loop (CPUState *env) goto do_sigill; } break; - case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1): - goto do_sigill; case EXCP_DEBUG: info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP); if (info.si_signo) { diff --git a/pc-bios/palcode-sx164 b/pc-bios/palcode-sx164 new file mode 100644 index 0000000000000000000000000000000000000000..986fea9a5d6440269c1ec2297ed0e7d892319867 GIT binary patch literal 107781 zcmeHwdwf*Yx%S$#C&T1I7)ZFuC3_|T!Y!Eulz>1c373GV5wPHm$s`$)96~ZqCIq}C z-YT|Uu=PSceg+gQwYJh0FSS+j9X+k>p_Nw8DV|zI#ge%TJN*o_g(LL*1Oi;vuAebTDoeP!!VdU9Bk^2xb$g%e?T;>?~0==z{;2d z@1xiVM(8kGC(+JeXG17=E#wZ$uHz-MEf_oRjaY+ALSLYCe*qn>q8ZQ(Xa+O`ngPv# zWGy|Fe&46Y=GoTsJ3}^;41DXNNfM!55pc&8% zXa+O`ngPv#WGy|Fe&46Y=GoTsJ3}^;41DXNN zfM!55pc&8%Xa+O`ngPv#WGy|Fe&46Y=GoTsJ z3}^;41DXNNfM!55pc&8%Xa+O`ngPv#WGy|Fe z&46Y=GoTsJ3}^;41DXNNfM!55pc&8%Xa+O`ngPv#WGy|Fe&46Y=GoTsJ3}^;41DXNNfM!55pc&8%Xa+O`ngPv#WGy|Fe&46Y=GoTsJ3}^;41DXNNfM!55pc&8%Xa+O`ngPv#WGy|Fe&46Y=GoTsJ3}^;41DXNNfM!55pc&8%Xa+O` zngPv#WGy|Fe&46Y=GoTsJ3}^;41F0~u>uG~M zIqjaGKbe0z`>eBX_n-2Iv2u&CS3CRr%dP1sXW%sxuUUA_#;XV~ljUu6vhs~-EV!}1 z|H^55Ixo*>-T%1!%SKYn4u-Sl?pm64=M5{0*;}0vSKgE?=k}#LS)R9WtaAm`%Yf%+ z9ew)C`u-yNF7`_J#!q=)>9@bSJi-d+U&;!nGnN<5@EA)SEbvANJK0&vUTHks|8hQK zlOJ)jmml%4ryd)}CO>Mi#g7)U4Uf7H99_=Xad7lXcn&+*Xs|pVW94`SeXRSPQ}ROn zf9bw%mwlBtQeT)0A9KsTK0ak%L-UarrWkrNd*7q+niwx*{heQA%thcx^dHX!)_wdd z^`CxwZ$;1N#;|x0@6%I`fsdd1@A?Y;&k+54XimQL*l9+1|Fxgn_u!nHt&BaD{sUj3 z|M=KrUv=z5XQW0o1DXNNfM!55pc&8%Xa+O`nt}f}47}#Ho=;?^buY zclurVD_Ht;FJtLfzUls)&)wbqU-I*wGL97O4-WgB_>}Hc@!=Hhds4K&HAVZb6z$tm zw6FWT{7?y3WV-jT>wH#u$uRZ-n@gV~zg#|*rx<^6iuPYNUS;@fM2h|QyHd;lVwTsy z`phL?bsX+KwycXn$*p z_FXC3x20$wOws<_6z$7Xv@cH4J}*W45h>dDr=_<3-%Zi}l@#rtOVR#diuMnuXy22f z{jDk5ccp0GmZE(yMf-D8w4aN6;2u9)X0X1_Lgv2ei=1!0-=4AC_hcx;%9v3zIDo)zQSPbjF^H$|;FZ3>B%}6jm`>=CN?yLA7_(Obu`by*2OOGyN-5>q)&&Mg`KE=VmKfZUb zn?1Fc;=p&(58ylL2k@Qr1BfYq_@%p+W_qq(I?q}AKUsad5+yGCmJ z$15q?KbNBY!4&NuPSL(6Mf+P*wC_sMzAZ)jV2bukT)%zWNV@)9`^A4xR-R)2#VOk7 zrD#7QMf-l1+WLJrMf+D$w0|x|`-3UkKb)d{Pm1=prfA=lqJ3M6_Q4eG&rQ+3JVpEB z6z%g;v>%b8z1%;mSknG^`xoCoS#MrwE_=T-o&6p6_zx_wSZA7l*Aj!h(Mk8;PIJDud;(sq`@PF?uMmD% zTM0V>y}U*X_Y5tMr!50=q33Yx7=JJB*M8XP0ao^yah4mnyoWbST+hrFWsxXnh;q6p zXNoe<*)P5`{u_Ryf6~71Liac5et?Pl0fT?b{?w4a-)G$)Z@Pt*=Np)h9Vq9IEjX)~ z^@QoUge>QGmPTCV)5fD5Ki67b%s%csgB|Uh2VUlbhXvr^O!nu_h3uWq>p{Q`toOY% z+(Rj2uQdGPTfNn;lHMh!;~oX;{;jvq=&=~P#v8*k`FiQn%xY)47o0q;Ob_hNUVq*5g%+R})?lytd-ijn{U(cHor> zyPdG3c+24P#cx?>WjWtjUh69NxtR5LT0;vlKjV=z4rcvj;Ij`y=gaU9u*Ps-9R4=` zZnd>?7W_K!97cbC(D$vcEnQiU_P)C2y z!wyRX=W*PNpNpJhtSg-92_b)L?PpKiormJP%z- z`Ahc$4feBXhqphO--l;a`ui76W$a`zGw^%}+wfRlSBdW=3p_9N_Ce2o-=qiF(Q=FQ zNw+`G;~R-Jhogw;?Kt{Dj3JE zdSvG>y|xWwS5C3my^qx1Khv7^VScr*^O_ZIw)hcaWF^MD;gJmN8HMbrM}|B5z~_d? zpttu#Uc~{-%NsY2DOh1YgY=kpg?HVQ>U5{K!UZ0F-yeM5`=JT>=yGqTui6;twP1IE z8R>gmj2-J9oKF6?3mLCq`~ePVJB^vG5x^JkM3T<*d+zEPy4KV#8=Q+2Y=UL zjdmYkR*zNtblrh<)xmHHKGPWrF!uVHCj`djYs-eAjj?OWK7}8$|IFd>k&h7q_prXI3~+2X4Sa`l zb)mDbXNk$Wk1=*_p|2zm_@qDh0p%>&-S}zHqWQ#khgF8thyIL0)|a=0`PmYg*VkRo z*AnGyy2w$F^RLU_MJ|2TpLgtpW4c$4C!PJZigJ{%kMu&=?6v)|qg8UP>^|RHIh-aTA;xE5Y{M}g#wyA_-v(>9uY4JCz{l@hAjk3Z>z>R%iZ#y1 z@gCMUtv$ZxOsowL=Ez{vy??;C7@Iz0Bzv#@lm7A#X)H7j=(G3(D1mv^iexlppiJJu)40=qO22hP>6G3H-jFu&E` zzuJf4FG*v8WB1JqR9Y|QVJ zdG>yZ=LmP*;dmnwAJ@sfATfF~ajAQpB1(i5|AV$8Ir~55@r}5_U7MpXv z{`NqR)-s(ZGMs7q7uyZNI;xC~!H(dH(KU9C%f6!n4 z9^wGyF7Jol>L5FLW{_>La6b9KkGa^uHh4F%#bxBfK{@YyeYxqHy{f;z(tGWe+G^+8 z&?;{lwsX(aK!3ll?8E*pn|E;Oqw{Eyh{y0;XU8+cm=Q>4D=LzSF{9U+Fd3{fMa!F_jO9Dg6{NagH|Zq5VBe|Sz@8c^Z-Yk+Zm zTMzoXxRU|8ByjzIWJ>+W833W*XADxc0j~dqN9xy>as4Ahs|)`(j+FXk^SS#DlRjjc}i%Lt1 zPA_3b_Z|$+!E)i)ZM+Gm#&uN1OL8N}{A+aVa1Sd*XbyMU^-wjPY0a%M=ENzK1srGp z21aR{+9S+y&TLd29+uWY(z#r6yOwwxXW;1+hUF&7xx*i%gDBti~9}N zuc$S|#m5cTXC&5fvDa`FkgNKy!@ucy)^MFmwhg@Xh~fGP^&95mQN#5;5;t=3xZ%R% z#XiIJAc;*}JYl%rppKfk*zIuP+KV~y zb8P0~E{7|Zf^5Ch4sxHvHIiJl5s{|nu<62TWsV3}KJ0Yi!wPd;%Ecp2*W)yzC>M`9 zU3XAxI~R{TnVV`f`gE#{;4*b&%LbPpka8|_evEpVZ+%(ZYD#T&~B1$;gZ|6 zfx5kwOCDDn4Q~gR#<|8)+ihI3TrZLIEiM(hD#+Wnx#Y)XF$~8!?!1t?dz}>T;!Vuu zB9}Y4N4^KLRiN;5ab-wYvx+S#xN@fI)~_wP@G(;4Juk8qmS+`t@r zrB6Fk9*{owlHzx{G|u%0>Te&HEEoMw!|^>X6}m1V=|L{}@ks~L_qkM-)=taoA?n%T z3AnaUgg@YIHLiar%^z}Uz3a!+-@{z0bzMTzel9h+-XYB&aVg^3OVW?Iw3RQ*pO9p) zt93Lh2e^oJl}a`FOv8)Z^bfOMB{yiw_=&u+tR;t5zDNMT7SXCoerK+zvLp8*=7pk zSuSFkt)n1+#l`&&*P9g8uetcRgSmSVF1^IcaTxBGV3280C|RV&hP!`>`Y?QIV`WZb z6s~TVYb*LNawr>V&E%1k`vMe9Pp>0wa|1I*)6z0M`-i1%u4l#=GQ!R@jAt>WlUSMA z_rS_1GVFlX10PY0?u{anM|>YXjG{A9W!ZhyN4e2Kj_A!3iG=~!5sq|c|B0ICayLEX z<^vlb%~7?mH_os%a{>g{8%EAeRQa7@WFMmbrrM5;*T|BVh%wa;U^9s3)!Ya(3dtKA zeURFh8pix#GTNoKvfblS(#eg)n6aGNNA*zO)zm&_Cgj{!YC4yi*jO%HU<+WGl*SqJ zD6SU`dAdA7*^5&#t^w@BxDKY{KM?3?Mkw9fv5>2rX4IM)xF^FV{0K2f!zFWhs~-hj zJ{T{+!NeobxDL{!-_Ve(N&jXS1J?+6Zwem(D3c;a@6ms zYVVF?bK5&MGs8}^+!j>$pe7sV5QDE8G75S2UyokDOVJ#{Wmlf<@>LrDD|qG2CAY8s z7A-STvuHYNMPO)V#vAj{WOXLNwFGb6h48%F0cYSt77)oCZ>Uwqo@>&K*jqB_tFgo@-pRJ$T&PxDMjxQ<_AP+ta7F^Hmw;=w1Kli z*>FfG)S`J}9{f_$*?~VUThOCXvzp8)aBBDMpl~SShshb6E_G?f+4~U5L~%*I16sykW>gDN=G~~>g#V4Ul-vk5rne}|MlFD7yiNHxs)qW0 zhpLPf8N=O_pYAvCMz3PR`}3FsmqpO?*O0UEFQCORN(|EQ=TW|&_OT6>M(XRBF|iUx zhG8%78Mr#;PE0oEFJwJ=JRqFTYN3RQ^4lA$_eE^DhB4=t6ihztDCy?m4MHQi(*fPh zP3jK2g3v!b$s_vd=3dy(5T}DZf)K=Y`X2$%b-H9qe%6>pip{Nc%rVSZiFVU|dyUXx zRAo+n5uf%XLBkER1DI<|s09L5OTyn%rlI8sr_p-)_GKQVM6BZMTHF$ z9|btiX@^Mv9K$#k*FVQLJ!#`qbvI)fQ6>EY!p@^A%XkQHay%zQChP>}xP=*XA)EPA z2)kjB^&Bd%pfa33T4iNFgZJ(!BhEt+6LyDbwmMc}MlzcLn~2)80hJrNn5}oa&|}C^ zqqAM=6+>?%>1DA|+a*e4%e_+dBB_crB-Q;w<#DOH^;c5$2B|uXcm9k}p#^Ge zqmPqzpCjy0e*$GTic6}jdzk+_plGjg#w_1vBW+rtv4mnL{yT6dvV%w|q77<>bg+dT& z2Ax;A+hTJ2ePAQV?GmB5gWS$}1zNW2W8`}LLeWUmj1!|{8^8(19_p^#kX;-TN_}Xg z0c4?>_f$?jd9cY$L{66Pg+ye(j{wjeSgZlTNEU#t?q^iC8fzlNT`wzSv z>;>qF?TgkU{4lv~$y*=wz#T>b-VMWeY6yi0BA~gaHglw{M^&TNnPm&T5RSvM)4nV; zehJZwGi4g>aE3`@Mh3)4EXoWgSyn@IjUn4W;e5#8(KU(0vRomuVQx3y;L`ct$?O{x zYy-5!aOP7L#&Q_)8t?bO9Xs%577}0PCR9BRMziQFr8c{YYjWpWTdGHc!{cUYZdVhk zVqbOKMIP)s0PagrHPQ@fH4fq}-5yvPRWs^3HZo(_FQ|&kU-zF-$;`mT{YbkN1GX#J z+xRes{}&YKl}+t=EQ@d7Biw|!S5im#Mjv$}52W*s@)I3RksVEqcT`N;7@;wfj2GC( zDkVGNYY#X#{uQY|a^q%PUoW8Qd%#BJe3J|pw!w*cTi;c=_TUy#pWAWX&BYKFQx_jY z7)`wzt6mb5G+YJk8?|OMukl(qstTYIoSv~E;A;} z%X&8ED2&#^C>L{Z(GL*8<s8w)^rOWdV+JN<`3NMy?ZWhcC~0$;n2Xlu(8?wq60kbVyq82n zf%srkfsS*r-CRr4`aWzYc|=Qmu)cs8%EeHziI^hWd<%s#{*0v3G- z3<&gysvD~{$1t-qGZ$o@nQ7!;{}|3pHwi0p@NEHeLCj8w!))a=sq8k46***;?qw@- zijlh+RKemLZA{Ce25em<4weA+o~SnVY1L zQzV3GSr*!I(H7Sqop8=wkIBU6Ypj$^O!c@TqdZIYO_W?6a0OgWzwsIajA500 z;~IlGGH$EH*e4VjB{{0*#JQ{_#{o96la}O61l5y=bbKdwoR=6J8CjFyamFklJ?VVd$bg0BK}eKaHnH1Y$O!%>4~HG zh>~oGk27S3)8`}fk6C?8{h%e7th?WwAEyTPrR+^xlx6DbX(rD%; zw-a!BqP;wefFTnU^JhW?pI0Zgt3y+)T@%zgO`Eq5a}#e6U~vG;#3(r#RX-Q;$jKfDK3|~cdEVg zeaT}?UQI}LzUoTsEu?@8cT{Fk$frn;MCgeD%ixnzg<^INBrh$I2Nb0%Lr_bLei+|p z+=;A7Ph{GVk&KB?4EEB28>n;Oj+w@NyH2;sNKVW|2Fsl=J;5Z>GZ8TMQ`*6@5;V z$5XOLFsnIqln3rLve z`yt1CW_HXg1t>oO-Jjdac0DfSK15!q#dgSb%v|{9V6NkxG$Y?ga0Mj{h^WqtKb*(!rVB+}a!~s;3NY>WoI}isMw&Bu(QMJWFBsv`42!!rNtDhuU8 z^A9M$2l=m8tv4rFX4o>fSZ4M{v)KX(cqcBVm@P%-xQ%AeDmJ~A`4+Rx_ph?fGN)SR zA=Eco`DSL3*KX?*-;)%LhmKW-gpE;h^7BV~MG+TlQAZUSNWz2lIyZ4Pg44-4WbALY%DoH6-6Z*g%6 z)rFK-H3r}(DY-TCcVx@@TKl;43g*4GzDJ6dOl zwnmCun(K;54z)y@Lg6iE%$wcP+}g3Vcy7_WB7bpnYkf-xek{TwQT)JTBVS4j>pGfS zVzZlD7o#uM9%~3i8!`3ho<<@+#ckAa6}yInlc)kGDO`tb#^3AnF#F=_?mcUSuBVijnBDT;>aGp(7nrgnPUAS^x(& zlC7s@O}0;nG!D5x(6&Oys%%fq-8dH(a54TJ-6|ok&GxLn+i`I=`)>}+61e>KY!*L{ z!jHfDn`X^Tj`iPg-k4T>vr&CFPWiZ0!7DkAT*%w;k_(CIbVyv@$d&O>NjmaY>{?RB zfw-64h)x_^v)Qi@o3xkrQDa=q{{0cz%ln8m0$-JFExFOG{)VIaZf8q2`!)HXL-r@{ z3Knvh`a@?maUO;mS1mF{=KB$0r|QiGz8!ipo8<4HR%Q1ZOK#3-xN&UtH^x-ol)LJi zqwgMPI`I+xH;4WM(QOWG4bm@&l#Czn%cn@Rtv=k|-WCnEH(wTJ^|88OYZMnfLHZV^ zqdn9JtZj276l<<)ZfTBfV@;u!STM4MRO*^z?F>JTiM2(;!B{xDxw$pe5^M;?LTGIa z+YZG^N7Z7HSg^UZA-t7siNxyo2`Shfi+0q}|>_^_P_R=laX6!tmBeINH1!V+plPw`MnzIsM!%7}^qQ zZoxJtrk-tV2{pEhs6(uwE!afAD8vw(5dmg07z@?4U@Bsv`b~BW7y!}P+OZj1VmqcD zc_3JUiG6v&+Cy6sSs{F3?&|78^-W<+{>C4l(4aF5v&_dO@e1R{R5cc>!l^UCES8Z zZN9XF7MwC@Fwq!mVw)Qp;u$NFt-fg!{bHe^Ju02oN8@RRl|@TAF-An)9H|fDe)z_4 zlp)C*SUWNV8m(=#kW1*Tl-}kfuQ47X(t@wJSY1=R3mXYWHny@*3-U3Z9ClVCJw&o% zp#~!zpg9x`Mnj#9E|ic0%`sjRO4?+Y=T+oRY(~h!b$64Lg9X)EKtC zv${}61MwHLYm^E6(xRDenPV%!@ z_90O^S@ddOkCfI6cW!nCt18Gxi$tW?u`K>G2M=AP^yi(%6%*m|+Oq;UDoWf5vDw8Z zt)627`*esliH(c1biqVXrOR4640eI6(vO-rRKqKY_d}v8J4;UlkWk{aJ^{$S4K~Qz z2SVk9D4pz5up^~}A$>7C;BbnddHc>q$9d>Cv{0C?cm zKC0t}F+?tGcD zzLs~Bu;Vqqu#){cn7?O+s4O(ZlLZwBN4z^&Bj%bSakb(aWEzNBexUH#!bp1kEh5+3Yr_!A`Soh;o z=>`Vto-&5&!MdNG%CDs8CSe2iWc48dIa&9$mkk=IYKVb;COc6*q+>o$!I$jhanTv= z+p;cKD=?3&BLnP%^wdN8dPX#0EV3%ihTgaj3xgL#nZdT5a?+%yS`i33k=2-hK-l)d zgvpI%q0mYutVUqcQ*xU+O1Z%#`8j2TVGOF)Qo63Cxo9XA+ni8k4^0 zX99G999flSL(jlq!;mz5JnriP?lkc(eI8Bl(S$$SC+0jYiaNM*`)CLujmUMQtT-6dvSce9g31F@$ks7iphlkBwR(Hj< z*2obgd=ENx3g!59Db248X|2gyO?FGKAq9DF;-4jgoE!uytM|mCx=>d4#G#91^`SU) zp{&Z&zsW8$dZbV&A~V=UvPw^5(SgfEUP-)PA@aFflu)@xRCkHefop?(qMlea=gHIZ zTyYL1wS}U->eS~|x9D3Ap3dg7-Ywd2g?GCQF&@_i9#NHx8d_Tggr85@2cTS0J)D4E z64g%=P=R115NGBBS(TGG#8sf2ibL@@SHC2xeF;d$iAQSf1J@=sqDl`R(E&&jE|~=+ zLzh=4LtNBI?WB2-yVaq%?=`Y|G!C7o?o|d`!$V2DOWy~Cm6P4}%9TA*lHCA(`N|$C z$)1olvU()m>1tWciW5I5{{}l+Be&YO;*JJ|DjmxKy4j`3z6Fyf_DJMd+<4Hko+X;( z{7~Y`dbMbCvddUr{3=;a-w^9(tuSbc_jln|QI#`1gw+u1WWC@h66fl?n5fDR3`1O{ zN=Gtf_?$@ze=xy5kVvvxBOpGFQo1;^ZsN4{C3R$kjeL|LdVy}?>Vix9#a+N4WbG-Pn{^N$ClB#{L@bio) zoXv5xiiakEH~b`V^NWOjuW!v)e^GG z=PZHyMY%+j)uOydl=6x}i1Fh8c7O6LoOO!)`TwoILt_4ppJIOH{1=G!LQ&S7LVtNx z)dH&!f3slvKmW=HzsYRhwi(~upo~R%*(7VR@YWbBiniHb*A+FkL1?dQZ)ZjJTSK_6 zqY+=jgj(@E9xLLa{hf`dhwAF^MU`x^@5zgnjnUBNuxvnYvP$1y2^HxU-|^A6Q}IMf zu`&VnM4A01vh;;}T^z;pk_#osOXon5c_EX1slesa3OmFN0s6Uj@*$^3mebKlb#Xz> zc2R%mf0w+WkZg>)Tak+d275cjRr@mEKm*l&Zo-}`)}l!2zf3NC-pZIIE4-xNjLWek zx5)VWl0nqvI+QT&7em?aSj5rAqopPb99u4xYY=k|4{u>ai!+}`y$_N}L| zKT^x>4=Vwy{9i8Y{R6{f`|7x14}Sied`Ne){5l$CJy~yg6Gx{jgsZx@ox(mMF30I- z{KEOZHyenz4$bDwZ|d{5Z#lYl6torFmqYRf-zE!RAr%QdN= z-{B?sm*+V=&opHJy*s)6QhC9_-NfS-;y*1+scr8k2~`sj%Y7n&QXFP{{SU;Qr@)aM zwa^^oUzs%F%w$S3$8pJu0OB~YGx#tWepNffVKV$^eTc)1-~JicXfphQeTc(k*@I9% z&j#zJ7K~S3fAB~QR#w7sYNlf{Uib|ePc-N^*(lFb!n?^KaN0lUsKm?Gr({aP&k=Z* z@V^Q&9T(wc`w{xW1gPbU`O(*Jc5r}Yb5Zo{_;{3h}H z%K&6L{?&dr*dc-2BHkXti{cCjKhzB!Kf}w8U%`JZ@LmP~qr{6*K|B*t(D5c-Hg6+Q z0WSUjL*M}gr|Vd|Uj?5e@LmNk5;z+*(0{qW@yFE$^m`6)nsk*1+Rp8Mg}&Gp7;Tew z{C@67<^$c}BfMAff3wuj8Q3p9%1rtJ1^0iO0lm00{@R@~zj+do>fm=3; zzY8G!3taMlQu0R=A+c(;OA3cOdr*GT_k2KuMZsWv|f-XZ-f z_}8U>1;0!BA3MibOZr#v&!m3^&&E2p^GCt+ z1kT0}^iPkk+x#eag}}QNe6{qi;Puk~X#@Soq<;m!Uiw$?JEebtQyS5+NBW-tA&H+y zq@dEEw@M!|? z6}TLi{bz=d4{Q>gqF-vJqeAHK5dF${&X)ZOed*_7*{{H5Jk7FS1@9ENeZoS&QvZ7C zpH5^+Jl`e#3tZ~&mHrj|N2UKf?nmlBBmE1!fCh`>d4YEe9HM=^D)3%`OCH`9__Kl^ zkI-khG@*GpBJjBa&$X{-4R%!EQoTgzGYd!(|BD13Q1Dd(?-sa>lb-3e*PXx%;f{{Y z!0Eh@TY>`qNuuKlp>KbXOXB%vfd{-$O2Y3Ic(;N-DDYkd|C#jf8|ded^snH5lKvI^ z9qC`e`=$TsfZJfPrj3%pywPYS$O!Rb#X5ua?@K>wD& z0}5Uu@NR+2^;jwJUIkwxaQoMNNqN{H@Bk%v65b*3ZUz6kz>kAn0iO0mHrj{Md@F`-<1C8Mp4rI z{zLj#@T_#PeieL@zs9dV46gsIf=?3o zVFjNh@FNO-hQN<1c!j`^EBHAA?^E!L1b#xn8wAc2-l76`D|olSJqmt{z{e^0Jp#8B z{6T>iD)>_Z_bWL4ku>7JOu_#fxP6{g^7gMnf4?%1^k>t^kD4d$OpaG8{>KWuM!}~D ze7%Ct6?mpI!Os(TM8RtXzE#271m3OSR|$N(g5M0>vE3N-99R!$kv1eFOJ}=0gvDiKxsik=0b`ni$%CEbtfj?F=a0*IQK1x+SN>x5eRX$2pK1vgOtcxbE4>6Dg8SA27 zi^OX1wW<=8N=9jd4CG%`Y-`+riv!aUUXv1bbwjeWwyrsDyDo~=$?W&wTKl0u83w$r zh$M1;bwf>ZDxTFCN%C<%{s6wTTNkYfM>n30CnY7ax*@rp6EG){9_yMyn-c-84#%)( z#BJBbux-Vq)v+YSSaWb~+xb|t@#Z!3JY#T~{e89UJPAWf+vWiVmDmiWqP^v9iiBQB`f75OC6a5!W<2ORU^^>Q^QuhEE1V$}lSE#L9uq_gAdy-E zP}fZ!SL34{)~GC= zRyUw6+?=ervAG4jY-?=*kDMC}ra9R&o&?9wi}>~IS?!S(t$5nExj_bjDG1vC%?t0C z*hJud(JaIgDK>|wRY<4>lW3_&BLb0*@f3WLBYG$vqI49gZ%%F%qS9K5=cW;Pk^RUr zo>7k!kwVh*{&@JF9&L|5Fl|5noTToTk1od_&j#UOf HOST_LONG_BITS /* temporary fixed-point registers @@ -386,14 +339,11 @@ struct CPUAlphaState { /* Those resources are used only in Qemu core */ CPU_COMMON - uint32_t hflags; - int error_code; uint32_t features; uint32_t amask; int implver; - pal_handler_t *pal_handler; }; #define cpu_init cpu_alpha_init @@ -401,15 +351,11 @@ struct CPUAlphaState { #define cpu_gen_code cpu_alpha_gen_code #define cpu_signal_handler cpu_alpha_signal_handler -/* MMU modes definitions */ -#define MMU_MODE0_SUFFIX _kernel -#define MMU_MODE1_SUFFIX _executive -#define MMU_MODE2_SUFFIX _supervisor -#define MMU_MODE3_SUFFIX _user -#define MMU_USER_IDX 3 +#define CPU_SAVE_VERSION 1 + static inline int cpu_mmu_index (CPUState *env) { - return (env->ps >> 3) & 3; + return (env->ps & PS_USER_MODE) != 0; } #include "cpu-all.h" @@ -422,37 +368,21 @@ enum { }; enum { - EXCP_RESET = 0x0000, - EXCP_MCHK = 0x0020, - EXCP_ARITH = 0x0060, - EXCP_HW_INTERRUPT = 0x00E0, - EXCP_DFAULT = 0x01E0, - EXCP_DTB_MISS_PAL = 0x09E0, - EXCP_ITB_MISS = 0x03E0, - EXCP_ITB_ACV = 0x07E0, - EXCP_DTB_MISS_NATIVE = 0x08E0, - EXCP_UNALIGN = 0x11E0, - EXCP_OPCDEC = 0x13E0, - EXCP_FEN = 0x17E0, - EXCP_CALL_PAL = 0x2000, - EXCP_CALL_PALP = 0x3000, - EXCP_CALL_PALE = 0x4000, - /* Pseudo exception for console */ - EXCP_CONSOLE_DISPATCH = 0x4001, - EXCP_CONSOLE_FIXUP = 0x4002, - EXCP_STL_C = 0x4003, - EXCP_STQ_C = 0x4004, + EXCP_RESET, + EXCP_MCHK, + EXCP_CLK_INTERRUPT, + EXCP_DEV_INTERRUPT, + EXCP_MMFAULT, + EXCP_UNALIGN, + EXCP_OPCDEC, + EXCP_ARITH, + EXCP_FEN, + EXCP_CALL_PAL, + /* For Usermode emulation. */ + EXCP_STL_C, + EXCP_STQ_C, }; -/* Arithmetic exception */ -#define EXC_M_IOV (1<<16) /* Integer Overflow */ -#define EXC_M_INE (1<<15) /* Inexact result */ -#define EXC_M_UNF (1<<14) /* Underflow */ -#define EXC_M_FOV (1<<13) /* Overflow */ -#define EXC_M_DZE (1<<12) /* Division by zero */ -#define EXC_M_INV (1<<11) /* Invalid operation */ -#define EXC_M_SWC (1<<10) /* Software completion */ - enum { IR_V0 = 0, IR_T0 = 1, @@ -502,21 +432,26 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw, #define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault void do_interrupt (CPUState *env); +uint64_t cpu_load_pcc(CPUState *env); uint64_t cpu_alpha_load_fpcr (CPUState *env); void cpu_alpha_store_fpcr (CPUState *env, uint64_t val); -int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); -int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); #if !defined (CONFIG_USER_ONLY) -void pal_init (CPUState *env); -void call_pal (CPUState *env); +void swap_shadow_regs(CPUState *); +void do_unassigned_access(target_phys_addr_t addr, int, int, int, int); #endif +enum { + TB_FLAGS_PAL_MODE = 1, + TB_FLAGS_FEN = 2 +}; + static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, target_ulong *cs_base, int *flags) { *pc = env->pc; *cs_base = 0; - *flags = env->ps; + *flags = ( (env->pal_mode ? TB_FLAGS_PAL_MODE : 0) + | (env->fen ? TB_FLAGS_FEN : 0)); } #if defined(CONFIG_USER_ONLY) diff --git a/target-alpha/exec.h b/target-alpha/exec.h index 6ae96d1..345b017 100644 --- a/target-alpha/exec.h +++ b/target-alpha/exec.h @@ -39,7 +39,12 @@ register struct CPUAlphaState *env asm(AREG0); static inline int cpu_has_work(CPUState *env) { - return (env->interrupt_request & CPU_INTERRUPT_HARD); + /* ??? There's a model-specific mapping between external hardware + interrupt numbers and the Unix PALcode interrupt levels. */ + int req = CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER; + return ((env->interrupt_request & req) + && env->pal_mode == 0 + && (env->ps & 7) == 0); } static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) diff --git a/target-alpha/helper.c b/target-alpha/helper.c index 3ba4478..944676e 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -24,6 +24,14 @@ #include "cpu.h" #include "exec-all.h" #include "softfloat.h" +#include "qemu-timer.h" + + +uint64_t cpu_load_pcc(CPUState *env) +{ + /* ??? This isn't a timer for which we have any rate info. */ + return (uint32_t)cpu_get_real_ticks() - env->pcc_ofs; +} uint64_t cpu_alpha_load_fpcr (CPUState *env) { @@ -160,382 +168,304 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val) } #if defined(CONFIG_USER_ONLY) - int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int mmu_idx, int is_softmmu) { - if (rw == 2) - env->exception_index = EXCP_ITB_MISS; - else - env->exception_index = EXCP_DFAULT; - env->ipr[IPR_EXC_ADDR] = address; - + env->exception_index = EXCP_MMFAULT; + env->trap_arg0 = address; return 1; } - -void do_interrupt (CPUState *env) +#else +/* Returns the OSF/1 entMM failure indication, or -1 on success. */ +static int get_physical_address(CPUState *env, target_ulong addr, + int prot_need, int mmu_idx, + target_ulong *pphys, int *pprot) { - env->exception_index = -1; -} + target_long saddr = addr; + target_ulong phys = 0; + target_ulong L1pte, L2pte, L3pte; + target_ulong pt, index; + int prot = 0; + int ret = MM_K_ACV; + + /* Ensure that the virtual address is properly sign-extended from + the last implemented virtual address bit. */ + if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) { + goto exit; + } -#else + /* Translate the superpage. */ + /* ??? When we do more than emulate Unix PALcode, we'll need to + determine which superpage is actually active. */ + if (saddr < 0 && (saddr >> (TARGET_VIRT_ADDR_SPACE_BITS - 2) & 3) == 2) { + /* User-space cannot access kseg addresses. */ + if (mmu_idx != MMU_KERNEL_IDX) { + goto exit; + } + + phys = saddr & ((1ull << 40) - 1); + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + ret = -1; + goto exit; + } + + /* Interpret the page table exactly like PALcode does. */ + + pt = env->pal_unix.ptbr; + + /* L1 page table read. */ + index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff; + L1pte = ldq_phys(pt + index*8); + + if (unlikely((L1pte & PTE_VALID) == 0)) { + ret = MM_K_TNV; + goto exit; + } + if (unlikely((L1pte & PTE_KRE) == 0)) { + goto exit; + } + pt = L1pte >> 32 << TARGET_PAGE_BITS; + + /* L2 page table read. */ + index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff; + L2pte = ldq_phys(pt + index*8); + + if (unlikely((L2pte & PTE_VALID) == 0)) { + ret = MM_K_TNV; + goto exit; + } + if (unlikely((L2pte & PTE_KRE) == 0)) { + goto exit; + } + pt = L2pte >> 32 << TARGET_PAGE_BITS; + + /* L3 page table read. */ + index = (addr >> TARGET_PAGE_BITS) & 0x3ff; + L3pte = ldq_phys(pt + index*8); + + phys = L3pte >> 32 << TARGET_PAGE_BITS; + if (unlikely((L3pte & PTE_VALID) == 0)) { + ret = MM_K_TNV; + goto exit; + } + +#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4 +# error page bits out of date +#endif + + /* Check access violations. */ + if (L3pte & (PTE_KRE << mmu_idx)) { + prot |= PAGE_READ | PAGE_EXEC; + } + if (L3pte & (PTE_KWE << mmu_idx)) { + prot |= PAGE_WRITE; + } + if (unlikely((prot & prot_need) == 0 && prot_need)) { + goto exit; + } + + /* Check fault-on-operation violations. */ + prot &= ~(L3pte >> 1); + ret = -1; + if (unlikely((prot & prot_need) == 0)) { + ret = (prot_need & PAGE_EXEC ? MM_K_FOE : + prot_need & PAGE_WRITE ? MM_K_FOW : + prot_need & PAGE_READ ? MM_K_FOR : -1); + } + + exit: + *pphys = phys; + *pprot = prot; + return ret; +} target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) { - return -1; + target_ulong phys; + int prot, fail; + + fail = get_physical_address(env, addr, 0, 0, &phys, &prot); + return (fail >= 0 ? -1 : phys); } -int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int mmu_idx, int is_softmmu) +int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw, + int mmu_idx, int is_softmmu) { - uint32_t opc; - - if (rw == 2) { - /* Instruction translation buffer miss */ - env->exception_index = EXCP_ITB_MISS; - } else { - if (env->ipr[IPR_EXC_ADDR] & 1) - env->exception_index = EXCP_DTB_MISS_PAL; - else - env->exception_index = EXCP_DTB_MISS_NATIVE; - opc = (ldl_code(env->pc) >> 21) << 4; - if (rw) { - opc |= 0x9; - } else { - opc |= 0x4; - } - env->ipr[IPR_MM_STAT] = opc; + target_ulong phys; + int prot, fail; + + fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot); + if (unlikely(fail >= 0)) { + env->exception_index = EXCP_MMFAULT; + env->trap_arg0 = addr; + env->trap_arg1 = fail; + env->trap_arg2 = (rw == 2 ? -1 : rw); + return 1; } - return 1; + tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK, + prot, mmu_idx, TARGET_PAGE_SIZE); + return 0; } -int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp) +void swap_shadow_regs(CPUState *env) { - uint64_t hwpcb; - int ret = 0; - - hwpcb = env->ipr[IPR_PCBB]; - switch (iprn) { - case IPR_ASN: - if (env->features & FEATURE_ASN) - *valp = env->ipr[IPR_ASN]; - else - *valp = 0; - break; - case IPR_ASTEN: - *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60; - break; - case IPR_ASTSR: - *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60; - break; - case IPR_DATFX: - /* Write only */ - ret = -1; - break; - case IPR_ESP: - if (env->features & FEATURE_SPS) - *valp = env->ipr[IPR_ESP]; - else - *valp = ldq_raw(hwpcb + 8); - break; - case IPR_FEN: - *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63; - break; - case IPR_IPIR: - /* Write-only */ - ret = -1; - break; - case IPR_IPL: - *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59; - break; - case IPR_KSP: - if (!(env->ipr[IPR_EXC_ADDR] & 1)) { - ret = -1; - } else { - if (env->features & FEATURE_SPS) - *valp = env->ipr[IPR_KSP]; - else - *valp = ldq_raw(hwpcb + 0); - } - break; - case IPR_MCES: - *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59; - break; - case IPR_PERFMON: - /* Implementation specific */ - *valp = 0; - break; - case IPR_PCBB: - *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16; - break; - case IPR_PRBR: - *valp = env->ipr[IPR_PRBR]; - break; - case IPR_PTBR: - *valp = env->ipr[IPR_PTBR]; - break; - case IPR_SCBB: - *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]); - break; - case IPR_SIRR: - /* Write-only */ - ret = -1; - break; - case IPR_SISR: - *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]); - case IPR_SSP: - if (env->features & FEATURE_SPS) - *valp = env->ipr[IPR_SSP]; - else - *valp = ldq_raw(hwpcb + 16); - break; - case IPR_SYSPTBR: - if (env->features & FEATURE_VIRBND) - *valp = env->ipr[IPR_SYSPTBR]; - else - ret = -1; - break; - case IPR_TBCHK: - if ((env->features & FEATURE_TBCHK)) { - /* XXX: TODO */ - *valp = 0; - ret = -1; - } else { - ret = -1; - } - break; - case IPR_TBIA: - /* Write-only */ - ret = -1; - break; - case IPR_TBIAP: - /* Write-only */ - ret = -1; - break; - case IPR_TBIS: - /* Write-only */ - ret = -1; - break; - case IPR_TBISD: - /* Write-only */ - ret = -1; - break; - case IPR_TBISI: - /* Write-only */ - ret = -1; - break; - case IPR_USP: - if (env->features & FEATURE_SPS) - *valp = env->ipr[IPR_USP]; - else - *valp = ldq_raw(hwpcb + 24); - break; - case IPR_VIRBND: - if (env->features & FEATURE_VIRBND) - *valp = env->ipr[IPR_VIRBND]; - else - ret = -1; - break; - case IPR_VPTB: - *valp = env->ipr[IPR_VPTB]; - break; - case IPR_WHAMI: - *valp = env->ipr[IPR_WHAMI]; - break; - default: - /* Invalid */ - ret = -1; - break; - } - - return ret; + uint64_t i0, i1, i2, i3, i4, i5, i6, i7; + + i0 = env->ir[8]; + i1 = env->ir[9]; + i2 = env->ir[10]; + i3 = env->ir[11]; + i4 = env->ir[12]; + i5 = env->ir[13]; + i6 = env->ir[14]; + i7 = env->ir[25]; + + env->ir[8] = env->pal_unix.shadow[0]; + env->ir[9] = env->pal_unix.shadow[1]; + env->ir[10] = env->pal_unix.shadow[2]; + env->ir[11] = env->pal_unix.shadow[3]; + env->ir[12] = env->pal_unix.shadow[4]; + env->ir[13] = env->pal_unix.shadow[5]; + env->ir[14] = env->pal_unix.shadow[6]; + env->ir[25] = env->pal_unix.shadow[7]; + + env->pal_unix.shadow[0] = i0; + env->pal_unix.shadow[1] = i1; + env->pal_unix.shadow[2] = i2; + env->pal_unix.shadow[3] = i3; + env->pal_unix.shadow[4] = i4; + env->pal_unix.shadow[5] = i5; + env->pal_unix.shadow[6] = i6; + env->pal_unix.shadow[7] = i7; } +#endif /* USER_ONLY */ -int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp) +void do_interrupt(CPUState *env) { - uint64_t hwpcb, tmp64; - uint8_t tmp8; - int ret = 0; - - hwpcb = env->ipr[IPR_PCBB]; - switch (iprn) { - case IPR_ASN: - /* Read-only */ - ret = -1; - break; - case IPR_ASTEN: - tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4; - *oldvalp = tmp8; - tmp8 &= val & 0xF; - tmp8 |= (val >> 4) & 0xF; - env->ipr[IPR_ASTEN] &= ~0xF; - env->ipr[IPR_ASTEN] |= tmp8; - ret = 1; - break; - case IPR_ASTSR: - tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4; - *oldvalp = tmp8; - tmp8 &= val & 0xF; - tmp8 |= (val >> 4) & 0xF; - env->ipr[IPR_ASTSR] &= ~0xF; - env->ipr[IPR_ASTSR] |= tmp8; - ret = 1; - case IPR_DATFX: - env->ipr[IPR_DATFX] &= ~0x1; - env->ipr[IPR_DATFX] |= val & 1; - tmp64 = ldq_raw(hwpcb + 56); - tmp64 &= ~0x8000000000000000ULL; - tmp64 |= (val & 1) << 63; - stq_raw(hwpcb + 56, tmp64); - break; - case IPR_ESP: - if (env->features & FEATURE_SPS) - env->ipr[IPR_ESP] = val; - else - stq_raw(hwpcb + 8, val); - break; - case IPR_FEN: - env->ipr[IPR_FEN] = val & 1; - tmp64 = ldq_raw(hwpcb + 56); - tmp64 &= ~1; - tmp64 |= val & 1; - stq_raw(hwpcb + 56, tmp64); - break; - case IPR_IPIR: - /* XXX: TODO: Send IRQ to CPU #ir[16] */ - break; - case IPR_IPL: - *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59; - env->ipr[IPR_IPL] &= ~0x1F; - env->ipr[IPR_IPL] |= val & 0x1F; - /* XXX: may issue an interrupt or ASR _now_ */ - ret = 1; - break; - case IPR_KSP: - if (!(env->ipr[IPR_EXC_ADDR] & 1)) { - ret = -1; - } else { - if (env->features & FEATURE_SPS) - env->ipr[IPR_KSP] = val; - else - stq_raw(hwpcb + 0, val); + int intno = env->exception_index; + + if (qemu_loglevel_mask(CPU_LOG_INT)) { + static int count; + const char *name = ""; + int i, args = 0; + + switch (intno) { + case EXCP_RESET: + name = "reset"; + args = 2; + break; + case EXCP_MCHK: + name = "mchk"; + break; + case EXCP_CLK_INTERRUPT: + name = "clk_interrupt"; + break; + case EXCP_DEV_INTERRUPT: + name = "dev_interrupt"; + break; + case EXCP_MMFAULT: + name = "mmfault"; + args = 2; + break; + case EXCP_UNALIGN: + name = "unalign"; + args = 2; + break; + case EXCP_OPCDEC: + name = "opcdec"; + args = 1; + break; + case EXCP_ARITH: + name = "arith"; + args = 2; + break; + case EXCP_FEN: + name = "fen"; + args = 1; + break; + case EXCP_CALL_PAL: + qemu_log("INT %6d: call_pal %x pc=%016" PRIx64 + " sp=%016" PRIx64 "\n" + " arg0=%016" PRIx64 + " arg1=%016" PRIx64 + " arg2=%016" PRIx64 "\n", + ++count, env->error_code, env->pc, env->ir[IR_SP], + env->ir[16], env->ir[17], env->ir[18]); + goto print_done; + case EXCP_STL_C: + name = "stl_c"; + break; + case EXCP_STQ_C: + name = "stq_c"; + break; } - break; - case IPR_MCES: - env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18); - env->ipr[IPR_MCES] |= val & 0x18; - break; - case IPR_PERFMON: - /* Implementation specific */ - *oldvalp = 0; - ret = 1; - break; - case IPR_PCBB: - /* Read-only */ - ret = -1; - break; - case IPR_PRBR: - env->ipr[IPR_PRBR] = val; - break; - case IPR_PTBR: - /* Read-only */ - ret = -1; - break; - case IPR_SCBB: - env->ipr[IPR_SCBB] = (uint32_t)val; - break; - case IPR_SIRR: - if (val & 0xF) { - env->ipr[IPR_SISR] |= 1 << (val & 0xF); - /* XXX: request a software interrupt _now_ */ + qemu_log("INT %6d: %s pc=%016" PRIx64 " sp=%016" PRIx64 "\n", + ++count, name, env->pc, env->ir[IR_SP]); + for (i = 0; i < args; ++i) { + qemu_log(" arg%d=%016" PRIx64, i, (&env->trap_arg0)[i]); } - break; - case IPR_SISR: - /* Read-only */ - ret = -1; - break; - case IPR_SSP: - if (env->features & FEATURE_SPS) - env->ipr[IPR_SSP] = val; - else - stq_raw(hwpcb + 16, val); - break; - case IPR_SYSPTBR: - if (env->features & FEATURE_VIRBND) - env->ipr[IPR_SYSPTBR] = val; - else - ret = -1; - break; - case IPR_TBCHK: - /* Read-only */ - ret = -1; - break; - case IPR_TBIA: - tlb_flush(env, 1); - break; - case IPR_TBIAP: - tlb_flush(env, 1); - break; - case IPR_TBIS: - tlb_flush_page(env, val); - break; - case IPR_TBISD: - tlb_flush_page(env, val); - break; - case IPR_TBISI: - tlb_flush_page(env, val); - break; - case IPR_USP: - if (env->features & FEATURE_SPS) - env->ipr[IPR_USP] = val; - else - stq_raw(hwpcb + 24, val); - break; - case IPR_VIRBND: - if (env->features & FEATURE_VIRBND) - env->ipr[IPR_VIRBND] = val; - else - ret = -1; - break; - case IPR_VPTB: - env->ipr[IPR_VPTB] = val; - break; - case IPR_WHAMI: - /* Read-only */ - ret = -1; - break; - default: - /* Invalid */ - ret = -1; - break; + print_done:; } - return ret; -} - -void do_interrupt (CPUState *env) -{ - int excp; - env->ipr[IPR_EXC_ADDR] = env->pc | 1; - excp = env->exception_index; env->exception_index = -1; - env->error_code = 0; - /* XXX: disable interrupts and memory mapping */ - if (env->ipr[IPR_PAL_BASE] != -1ULL) { - /* We use native PALcode */ - env->pc = env->ipr[IPR_PAL_BASE] + excp; - } else { - /* We use emulated PALcode */ - call_pal(env); - /* Emulate REI */ - env->pc = env->ipr[IPR_EXC_ADDR] & ~7; - env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1; - /* XXX: re-enable interrupts and memory mapping */ + +#if !defined(CONFIG_USER_ONLY) + { + int offset = -1; + switch (intno) { + case EXCP_RESET: + offset = 0x0000; + break; + case EXCP_MCHK: + offset = 0x0080; + break; + case EXCP_CLK_INTERRUPT: + offset = 0x0100; + break; + case EXCP_DEV_INTERRUPT: + offset = 0x0180; + break; + case EXCP_MMFAULT: + offset = 0x0200; + break; + case EXCP_UNALIGN: + offset = 0x0280; + break; + case EXCP_OPCDEC: + offset = 0x0300; + break; + case EXCP_ARITH: + offset = 0x0380; + break; + case EXCP_FEN: + offset = 0x0400; + break; + case EXCP_CALL_PAL: + offset = env->error_code; + /* There are 64 entry points for both privilaged and unprivlaged, + with bit 0x80 indicating unprivlaged. Each entry point gets + 64 bytes to do its job. */ + if (offset & 0x80) { + offset = 0x2000 + (offset - 0x80) * 64; + } else { + offset = 0x1000 + offset * 64; + } + break; + } + if (offset < 0) { + abort(); + } + env->pal_unix.exc_addr = env->pc | env->pal_mode; + env->pc = env->pal_unix.palbr + offset; + if (!env->pal_mode) { + env->pal_mode = 1; + swap_shadow_regs(env); + } } -} #endif +} void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) @@ -548,8 +478,10 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf, }; int i; - cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n", - env->pc, env->ps); + cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x%s%s\n", + env->pc, env->ps, + env->pal_mode ? " PAL" : "", + env->fen ? " FEN" : ""); for (i = 0; i < 31; i++) { cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i, linux_reg_names[i], env->ir[i]); diff --git a/target-alpha/helper.h b/target-alpha/helper.h index ccf6a2a..ae48d7f 100644 --- a/target-alpha/helper.h +++ b/target-alpha/helper.h @@ -99,28 +99,20 @@ DEF_HELPER_1(ieee_input, i64, i64) DEF_HELPER_1(ieee_input_cmp, i64, i64) DEF_HELPER_1(ieee_input_s, i64, i64) -#if !defined (CONFIG_USER_ONLY) -DEF_HELPER_0(hw_rei, void) +#ifdef CONFIG_PALMODE DEF_HELPER_1(hw_ret, void, i64) -DEF_HELPER_2(mfpr, i64, int, i64) -DEF_HELPER_2(mtpr, void, int, i64) -DEF_HELPER_0(set_alt_mode, void) -DEF_HELPER_0(restore_mode, void) - -DEF_HELPER_1(ld_virt_to_phys, i64, i64) -DEF_HELPER_1(st_virt_to_phys, i64, i64) -DEF_HELPER_2(ldl_raw, void, i64, i64) -DEF_HELPER_2(ldq_raw, void, i64, i64) -DEF_HELPER_2(ldl_l_raw, void, i64, i64) -DEF_HELPER_2(ldq_l_raw, void, i64, i64) -DEF_HELPER_2(ldl_kernel, void, i64, i64) -DEF_HELPER_2(ldq_kernel, void, i64, i64) -DEF_HELPER_2(ldl_data, void, i64, i64) -DEF_HELPER_2(ldq_data, void, i64, i64) -DEF_HELPER_2(stl_raw, void, i64, i64) -DEF_HELPER_2(stq_raw, void, i64, i64) -DEF_HELPER_2(stl_c_raw, i64, i64, i64) -DEF_HELPER_2(stq_c_raw, i64, i64, i64) + +DEF_HELPER_1(ldl_phys, i64, i64) +DEF_HELPER_1(ldq_phys, i64, i64) +DEF_HELPER_1(ldl_l_phys, i64, i64) +DEF_HELPER_1(ldq_l_phys, i64, i64) +DEF_HELPER_2(stl_phys, void, i64, i64) +DEF_HELPER_2(stq_phys, void, i64, i64) +DEF_HELPER_2(stl_c_phys, i64, i64, i64) +DEF_HELPER_2(stq_c_phys, i64, i64, i64) + +DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void) +DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64) #endif #include "def-helper.h" diff --git a/target-alpha/machine.c b/target-alpha/machine.c new file mode 100644 index 0000000..94a695f --- /dev/null +++ b/target-alpha/machine.c @@ -0,0 +1,84 @@ +#include "hw/hw.h" +#include "hw/boards.h" + +static int get_fpcr(QEMUFile *f, void *opaque, size_t size) +{ + CPUAlphaState *env = opaque; + cpu_alpha_store_fpcr(env, qemu_get_be64(f)); + return 0; +} + +static void put_fpcr(QEMUFile *f, void *opaque, size_t size) +{ + CPUAlphaState *env = opaque; + qemu_put_be64(f, cpu_alpha_load_fpcr(env)); +} + +static const VMStateInfo vmstate_fpcr = { + .name = "fpcr", + .get = get_fpcr, + .put = put_fpcr, +}; + +static VMStateField vmstate_cpu_fields[] = { + VMSTATE_UINTTL_ARRAY(ir, CPUState, 31), + VMSTATE_UINTTL_ARRAY(fir, CPUState, 31), + /* Save the architecture value of the fpcr, not the internally + expanded version. Since this architecture value does not + exist in memory to be stored, this requires a but of hoop + jumping. We want OFFSET=0 so that we effectively pass ENV + to the helper functions, and we need to fill in the name by + hand since there's no field of that name. */ + { + .name = "fpcr", + .version_id = 0, + .size = sizeof(uint64_t), + .info = &vmstate_fpcr, + .flags = VMS_SINGLE, + .offset = 0 + }, + VMSTATE_UINTTL(pc, CPUState), + VMSTATE_UINTTL(unique, CPUState), + VMSTATE_UINTTL(lock_addr, CPUState), + VMSTATE_UINTTL(lock_value, CPUState), + /* Note that lock_st_addr is not saved; it is a temporary + used during the execution of the st[lq]_c insns. */ + + VMSTATE_UINT8(ps, CPUState), + VMSTATE_UINT8(intr_flag, CPUState), + VMSTATE_UINT8(fen, CPUState), + VMSTATE_UINT8(pal_mode, CPUState), + + VMSTATE_UINT32(pcc_ofs, CPUState), + VMSTATE_UINTTL(trap_arg0, CPUState), + VMSTATE_UINTTL(trap_arg1, CPUState), + VMSTATE_UINTTL(trap_arg2, CPUState), + + VMSTATE_UINTTL(pal_unix.exc_addr, CPUState), + VMSTATE_UINTTL(pal_unix.palbr, CPUState), + VMSTATE_UINTTL(pal_unix.ptbr, CPUState), + VMSTATE_UINTTL(pal_unix.vptptr, CPUState), + + VMSTATE_UINTTL_ARRAY(pal_unix.shadow, CPUState, 8), + VMSTATE_UINTTL_ARRAY(pal_unix.scratch, CPUState, 24), + + VMSTATE_END_OF_LIST() +}; + +static const VMStateDescription vmstate_cpu = { + .name = "cpu", + .version_id = CPU_SAVE_VERSION, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = vmstate_cpu_fields, +}; + +void cpu_save(QEMUFile *f, void *opaque) +{ + vmstate_save_state(f, &vmstate_cpu, opaque); +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return vmstate_load_state(f, &vmstate_cpu, opaque, version_id); +} diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 6c2ae20..5c3571f 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -21,31 +21,38 @@ #include "host-utils.h" #include "softfloat.h" #include "helper.h" -#include "qemu-timer.h" /*****************************************************************************/ /* Exceptions processing helpers */ -void QEMU_NORETURN helper_excp (int excp, int error) +void QEMU_NORETURN helper_excp(int excp, int error) { env->exception_index = excp; env->error_code = error; cpu_loop_exit(); } +static void QEMU_NORETURN arith_excp(int exc, uint64_t mask) +{ + env->exception_index = EXCP_ARITH; + env->error_code = 0; + env->trap_arg0 = exc; + env->trap_arg1 = mask; + cpu_loop_exit(); +} + uint64_t helper_load_pcc (void) { - /* ??? This isn't a timer for which we have any rate info. */ - return (uint32_t)cpu_get_real_ticks(); + return cpu_load_pcc(env); } uint64_t helper_load_fpcr (void) { - return cpu_alpha_load_fpcr (env); + return cpu_alpha_load_fpcr(env); } void helper_store_fpcr (uint64_t val) { - cpu_alpha_store_fpcr (env, val); + cpu_alpha_store_fpcr(env, val); } uint64_t helper_addqv (uint64_t op1, uint64_t op2) @@ -53,7 +60,7 @@ uint64_t helper_addqv (uint64_t op1, uint64_t op2) uint64_t tmp = op1; op1 += op2; if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) { - helper_excp(EXCP_ARITH, EXC_M_IOV); + arith_excp(EXC_M_IOV, 0); } return op1; } @@ -63,7 +70,7 @@ uint64_t helper_addlv (uint64_t op1, uint64_t op2) uint64_t tmp = op1; op1 = (uint32_t)(op1 + op2); if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) { - helper_excp(EXCP_ARITH, EXC_M_IOV); + arith_excp(EXC_M_IOV, 0); } return op1; } @@ -73,7 +80,7 @@ uint64_t helper_subqv (uint64_t op1, uint64_t op2) uint64_t res; res = op1 - op2; if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) { - helper_excp(EXCP_ARITH, EXC_M_IOV); + arith_excp(EXC_M_IOV, 0); } return res; } @@ -83,7 +90,7 @@ uint64_t helper_sublv (uint64_t op1, uint64_t op2) uint32_t res; res = op1 - op2; if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) { - helper_excp(EXCP_ARITH, EXC_M_IOV); + arith_excp(EXC_M_IOV, 0); } return res; } @@ -93,7 +100,7 @@ uint64_t helper_mullv (uint64_t op1, uint64_t op2) int64_t res = (int64_t)op1 * (int64_t)op2; if (unlikely((int32_t)res != res)) { - helper_excp(EXCP_ARITH, EXC_M_IOV); + arith_excp(EXC_M_IOV, 0); } return (int64_t)((int32_t)res); } @@ -105,7 +112,7 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2) muls64(&tl, &th, op1, op2); /* If th != 0 && th != -1, then we had an overflow */ if (unlikely((th + 1) > 1)) { - helper_excp(EXCP_ARITH, EXC_M_IOV); + arith_excp(EXC_M_IOV, 0); } return tl; } @@ -373,8 +380,6 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno) if (exc) { uint32_t hw_exc = 0; - env->ipr[IPR_EXC_MASK] |= 1ull << regno; - if (exc & float_flag_invalid) { hw_exc |= EXC_M_INV; } @@ -390,7 +395,8 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno) if (exc & float_flag_inexact) { hw_exc |= EXC_M_INE; } - helper_excp(EXCP_ARITH, hw_exc); + + arith_excp(hw_exc, 1ull << regno); } } @@ -420,7 +426,7 @@ uint64_t helper_ieee_input(uint64_t val) if (env->fpcr_dnz) { val &= 1ull << 63; } else { - helper_excp(EXCP_ARITH, EXC_M_UNF); + arith_excp(EXC_M_UNF, 0); } } } else if (exp == 0x7ff) { @@ -428,7 +434,7 @@ uint64_t helper_ieee_input(uint64_t val) /* ??? I'm not sure these exception bit flags are correct. I do know that the Linux kernel, at least, doesn't rely on them and just emulates the insn to figure out what exception to use. */ - helper_excp(EXCP_ARITH, frac ? EXC_M_INV : EXC_M_FOV); + arith_excp(frac ? EXC_M_INV : EXC_M_FOV, 0); } return val; } @@ -445,12 +451,12 @@ uint64_t helper_ieee_input_cmp(uint64_t val) if (env->fpcr_dnz) { val &= 1ull << 63; } else { - helper_excp(EXCP_ARITH, EXC_M_UNF); + arith_excp(EXC_M_UNF, 0); } } } else if (exp == 0x7ff && frac) { /* NaN. */ - helper_excp(EXCP_ARITH, EXC_M_INV); + arith_excp(EXC_M_INV, 0); } return val; } @@ -1154,188 +1160,136 @@ uint64_t helper_cvtqg (uint64_t a) } /* PALcode support special instructions */ -#if !defined (CONFIG_USER_ONLY) -void helper_hw_rei (void) -{ - env->pc = env->ipr[IPR_EXC_ADDR] & ~3; - env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1; - env->intr_flag = 0; - env->lock_addr = -1; - /* XXX: re-enable interrupts and memory mapping */ -} - +#if defined(CONFIG_PALMODE) void helper_hw_ret (uint64_t a) { env->pc = a & ~3; - env->ipr[IPR_EXC_ADDR] = a & 1; env->intr_flag = 0; env->lock_addr = -1; + if ((a & 1) == 0) { + env->pal_mode = 0; + swap_shadow_regs(env); + } /* XXX: re-enable interrupts and memory mapping */ } -uint64_t helper_mfpr (int iprn, uint64_t val) +uint64_t helper_ldl_phys(uint64_t p) { - uint64_t tmp; - - if (cpu_alpha_mfpr(env, iprn, &tmp) == 0) - val = tmp; - - return val; + return (int32_t)ldl_phys(p); } -void helper_mtpr (int iprn, uint64_t val) +uint64_t helper_ldq_phys(uint64_t p) { - cpu_alpha_mtpr(env, iprn, val, NULL); + return ldq_phys(p); } -void helper_set_alt_mode (void) +uint64_t helper_ldl_l_phys(uint64_t p) { - env->saved_mode = env->ps & 0xC; - env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC); + env->lock_addr = p; + return env->lock_value = (int32_t)ldl_phys(p); } -void helper_restore_mode (void) +uint64_t helper_ldq_l_phys(uint64_t p) { - env->ps = (env->ps & ~0xC) | env->saved_mode; -} - -#endif - -/*****************************************************************************/ -/* Softmmu support */ -#if !defined (CONFIG_USER_ONLY) - -/* XXX: the two following helpers are pure hacks. - * Hopefully, we emulate the PALcode, then we should never see - * HW_LD / HW_ST instructions. - */ -uint64_t helper_ld_virt_to_phys (uint64_t virtaddr) -{ - uint64_t tlb_addr, physaddr; - int index, mmu_idx; - void *retaddr; - - mmu_idx = cpu_mmu_index(env); - index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - redo: - tlb_addr = env->tlb_table[mmu_idx][index].addr_read; - if ((virtaddr & TARGET_PAGE_MASK) == - (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend; - } else { - /* the page is not in the TLB : fill it */ - retaddr = GETPC(); - tlb_fill(virtaddr, 0, mmu_idx, retaddr); - goto redo; - } - return physaddr; + env->lock_addr = p; + return env->lock_value = ldq_phys(p); } -uint64_t helper_st_virt_to_phys (uint64_t virtaddr) +void helper_stl_phys(uint64_t p, uint64_t v) { - uint64_t tlb_addr, physaddr; - int index, mmu_idx; - void *retaddr; - - mmu_idx = cpu_mmu_index(env); - index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - redo: - tlb_addr = env->tlb_table[mmu_idx][index].addr_write; - if ((virtaddr & TARGET_PAGE_MASK) == - (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend; - } else { - /* the page is not in the TLB : fill it */ - retaddr = GETPC(); - tlb_fill(virtaddr, 1, mmu_idx, retaddr); - goto redo; - } - return physaddr; + stl_phys(p, v); } -void helper_ldl_raw(uint64_t t0, uint64_t t1) +void helper_stq_phys(uint64_t p, uint64_t v) { - ldl_raw(t1, t0); + stq_phys(p, v); } -void helper_ldq_raw(uint64_t t0, uint64_t t1) +uint64_t helper_stl_c_phys(uint64_t p, uint64_t v) { - ldq_raw(t1, t0); -} + uint64_t ret = 0; -void helper_ldl_l_raw(uint64_t t0, uint64_t t1) -{ - env->lock = t1; - ldl_raw(t1, t0); -} + if (p == env->lock_addr) { + int32_t old = ldl_phys(p); + if (old == (int32_t)env->lock_value) { + stl_phys(p, v); + ret = 1; + } + } + env->lock_addr = -1; -void helper_ldq_l_raw(uint64_t t0, uint64_t t1) -{ - env->lock = t1; - ldl_raw(t1, t0); + return ret; } -void helper_ldl_kernel(uint64_t t0, uint64_t t1) +uint64_t helper_stq_c_phys(uint64_t p, uint64_t v) { - ldl_kernel(t1, t0); -} + uint64_t ret = 0; -void helper_ldq_kernel(uint64_t t0, uint64_t t1) -{ - ldq_kernel(t1, t0); -} + if (p == env->lock_addr) { + uint64_t old = ldq_phys(p); + if (old == env->lock_value) { + stq_phys(p, v); + ret = 1; + } + } + env->lock_addr = -1; -void helper_ldl_data(uint64_t t0, uint64_t t1) -{ - ldl_data(t1, t0); + return ret; } -void helper_ldq_data(uint64_t t0, uint64_t t1) +void helper_tbia(void) { - ldq_data(t1, t0); + tlb_flush(env, 1); } -void helper_stl_raw(uint64_t t0, uint64_t t1) +void helper_tbis(uint64_t p) { - stl_raw(t1, t0); + tlb_flush_page(env, p); } +#endif /* PALMODE */ -void helper_stq_raw(uint64_t t0, uint64_t t1) +/*****************************************************************************/ +/* Softmmu support */ +#if !defined(CONFIG_USER_ONLY) + +static void do_restore_state(void *pc_ptr) { - stq_raw(t1, t0); + TranslationBlock *tb; + unsigned long pc = (unsigned long) pc_ptr; + + tb = tb_find_pc(pc); + if (tb) { + cpu_restore_state(tb, env, pc, NULL); + } } -uint64_t helper_stl_c_raw(uint64_t t0, uint64_t t1) +static void do_unaligned_access(target_ulong addr, int is_write, + int is_user, void *retaddr) { - uint64_t ret; + uint64_t pc; + uint32_t insn; - if (t1 == env->lock) { - stl_raw(t1, t0); - ret = 0; - } else - ret = 1; + do_restore_state(retaddr); - env->lock = 1; + pc = env->pc; + insn = ldl_code(pc); - return ret; + env->trap_arg0 = addr; + env->trap_arg1 = insn >> 26; /* opcode */ + env->trap_arg2 = (insn >> 21) & 31; /* dest regno */ + helper_excp(EXCP_UNALIGN, 0); } -uint64_t helper_stq_c_raw(uint64_t t0, uint64_t t1) +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, + int unused, int size) { - uint64_t ret; - - if (t1 == env->lock) { - stq_raw(t1, t0); - ret = 0; - } else - ret = 1; - - env->lock = 1; - - return ret; + env->trap_arg0 = addr; + env->trap_arg1 = is_write; + helper_excp(EXCP_MCHK, 0); } #define MMUSUFFIX _mmu +#define ALIGNED_ONLY #define SHIFT 0 #include "softmmu_template.h" @@ -1365,7 +1319,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) saved_env = env; env = cpu_single_env; ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); - if (!likely(ret == 0)) { + if (unlikely(ret != 0)) { if (likely(retaddr)) { /* now we have a real cpu fault */ pc = (unsigned long)retaddr; @@ -1381,5 +1335,4 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) } env = saved_env; } - #endif diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 96e922b..ac0217f 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -47,9 +47,6 @@ struct DisasContext { CPUAlphaState *env; uint64_t pc; int mem_idx; -#if !defined (CONFIG_USER_ONLY) - int pal_mode; -#endif uint32_t amask; /* Current rounding mode for this TB. */ @@ -89,9 +86,7 @@ static TCGv cpu_pc; static TCGv cpu_lock_addr; static TCGv cpu_lock_st_addr; static TCGv cpu_lock_value; -#ifdef CONFIG_USER_ONLY static TCGv cpu_uniq; -#endif /* register names */ static char cpu_reg_names[10*4+21*5 + 10*5+21*6]; @@ -134,11 +129,8 @@ static void alpha_translate_init(void) cpu_lock_value = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, lock_value), "lock_value"); - -#ifdef CONFIG_USER_ONLY cpu_uniq = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, unique), "uniq"); -#endif /* register helpers */ #define GEN_HELPER 2 @@ -322,7 +314,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb, #if defined(CONFIG_USER_ONLY) addr = cpu_lock_st_addr; #else - addr = tcg_local_new(); + addr = tcg_temp_local_new(); #endif if (rb != 31) { @@ -345,7 +337,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb, lab_fail = gen_new_label(); lab_done = gen_new_label(); - tcg_gen_brcond(TCG_COND_NE, addr, cpu_lock_addr, lab_fail); + tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail); val = tcg_temp_new(); if (quad) { @@ -353,7 +345,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb, } else { tcg_gen_qemu_ld32s(val, addr, ctx->mem_idx); } - tcg_gen_brcond(TCG_COND_NE, val, cpu_lock_value, lab_fail); + tcg_gen_brcond_i64(TCG_COND_NE, val, cpu_lock_value, lab_fail); if (quad) { tcg_gen_qemu_st64(cpu_ir[ra], addr, ctx->mem_idx); @@ -1464,6 +1456,183 @@ static void gen_rx(int ra, int set) tcg_temp_free_i32(tmp); } +static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) +{ + /* We're emulating OSF/1 PALcode. Many of these are trivial access + to internal cpu registers. */ + + /* Unprivileged PAL call */ + if (palcode >= 0x80 && palcode < 0xC0) { + switch (palcode) { + case 0x86: + /* IMB */ + /* No-op inside QEMU. */ + break; + case 0x9E: + /* RDUNIQUE */ + tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_uniq); + break; + case 0x9F: + /* WRUNIQUE */ + tcg_gen_mov_i64(cpu_uniq, cpu_ir[IR_A0]); + break; + default: + return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xbf); + } + return NO_EXIT; + } + +#ifndef CONFIG_USER_ONLY + /* Privileged PAL code */ + if (palcode < 0x40 && ctx->mem_idx == 0) { + switch (palcode) { + case 0x01: + /* CFLUSH */ + /* No-op inside QEMU. */ + break; + case 0x02: + /* DRAINA */ + /* No-op inside QEMU. */ + break; + case 0x2D: + /* WRVPTPTR */ + tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, + offsetof(CPUAlphaState, pal_unix.vptptr)); + break; + case 0x35: { + /* SWPIPL */ + TCGv tmp; + + /* Note that we already know we're in kernel mode, so we know + that PS only contains the 3 IPL bits. */ + tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, + offsetof(CPUAlphaState, ps)); + + /* But make sure and store only the 3 IPL bits from the user. */ + tmp = tcg_temp_new(); + tcg_gen_andi_i64(tmp, cpu_ir[IR_A0], 7); + tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, ps)); + tcg_temp_free(tmp); + break; + } + + case 0x36: + /* RDPS */ + tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, + offsetof(CPUAlphaState, ps)); + break; + + /* TODO: + 0x31 WrVal + 0x32 RdVal + 0x38 WrUsp + 0x3A RdUsp + 0x3C Whami + These merely need more cooperation in designation of + internal processor registers w/ palcode. These are + currently stored in palcode scratch registers and + should be treated like UNIQUE. */ + + default: + return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3f); + } + return NO_EXIT; + } +#endif + + return gen_invalid(ctx); +} + +#if defined(CONFIG_PALMODE) + +#define PR_BYTE 0x100000 +#define PR_LONG 0x200000 + +static int cpu_pr_data(int pr) +{ + switch (pr) { + case 0: return offsetof(CPUAlphaState, ps) | PR_BYTE; + case 1: return offsetof(CPUAlphaState, fen) | PR_BYTE; + case 2: return offsetof(CPUAlphaState, pcc_ofs) | PR_LONG; + case 3: return offsetof(CPUAlphaState, trap_arg0); + case 4: return offsetof(CPUAlphaState, trap_arg1); + case 5: return offsetof(CPUAlphaState, trap_arg2); + case 6: return offsetof(CPUAlphaState, pal_unix.exc_addr); + case 7: return offsetof(CPUAlphaState, pal_unix.palbr); + case 8: return offsetof(CPUAlphaState, pal_unix.ptbr); + case 9: return offsetof(CPUAlphaState, pal_unix.vptptr); + case 10: return offsetof(CPUAlphaState, unique); + case 11: return offsetof(CPUAlphaState, lock_addr); + + case 32 ... 39: + return offsetof(CPUAlphaState, pal_unix.shadow[pr - 32]); + case 40 ... 63: + return offsetof(CPUAlphaState, pal_unix.scratch[pr - 40]); + } + return 0; +} + +static void gen_mfpr(int ra, int regno) +{ + int data = cpu_pr_data(regno); + + /* In our emulated PALcode, these processor registers have no + side effects from reading. */ + if (ra == 31) { + return; + } + + if (data == 0) { + tcg_gen_movi_i64(cpu_ir[ra], 0); + } else if (data & PR_BYTE) { + tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, data & ~PR_BYTE); + } else if (data & PR_LONG) { + tcg_gen_ld32s_i64(cpu_ir[ra], cpu_env, data & ~PR_LONG); + } else { + tcg_gen_ld_i64(cpu_ir[ra], cpu_env, data); + } +} + +static void gen_mtpr(int rb, int regno) +{ + TCGv tmp; + + if (rb == 31) { + tmp = tcg_const_i64(0); + } else { + tmp = cpu_ir[rb]; + } + + /* These two register numbers perform a TLB cache flush. Thankfully we + can only do this inside PALmode, which means that the current basic + block cannot be affected by the change in mappings. */ + if (regno == 255) { + /* TBIA */ + gen_helper_tbia(); + } else if (regno == 254) { + /* TBIS */ + gen_helper_tbis(tmp); + } else { + /* Otherwise the registers are data only, and unknown registers + are read-zero, write-ignore. */ + int data = cpu_pr_data(regno); + if (data != 0) { + if (data & PR_BYTE) { + tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE); + } else if (data & PR_LONG) { + tcg_gen_st32_i64(tmp, cpu_env, data & ~PR_LONG); + } else { + tcg_gen_st_i64(tmp, cpu_env, data); + } + } + } + + if (rb == 31) { + tcg_temp_free(tmp); + } +} +#endif /* PALMODE */ + static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) { uint32_t palcode; @@ -1499,32 +1668,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) switch (opc) { case 0x00: /* CALL_PAL */ -#ifdef CONFIG_USER_ONLY - if (palcode == 0x9E) { - /* RDUNIQUE */ - tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_uniq); - break; - } else if (palcode == 0x9F) { - /* WRUNIQUE */ - tcg_gen_mov_i64(cpu_uniq, cpu_ir[IR_A0]); - break; - } -#endif - if (palcode >= 0x80 && palcode < 0xC0) { - /* Unprivileged PAL call */ - ret = gen_excp(ctx, EXCP_CALL_PAL + ((palcode & 0x3F) << 6), 0); - break; - } -#ifndef CONFIG_USER_ONLY - if (palcode < 0x40) { - /* Privileged PAL code */ - if (ctx->mem_idx & 1) - goto invalid_opc; - ret = gen_excp(ctx, EXCP_CALL_PALP + ((palcode & 0x3F) << 6), 0); - } -#endif - /* Invalid PAL call */ - goto invalid_opc; + ret = gen_call_pal(ctx, palcode); + break; case 0x01: /* OPC01 */ goto invalid_opc; @@ -2571,18 +2716,13 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) break; case 0x19: /* HW_MFPR (PALcode) */ -#if defined (CONFIG_USER_ONLY) - goto invalid_opc; -#else - if (!ctx->pal_mode) - goto invalid_opc; - if (ra != 31) { - TCGv tmp = tcg_const_i32(insn & 0xFF); - gen_helper_mfpr(cpu_ir[ra], tmp, cpu_ir[ra]); - tcg_temp_free(tmp); +#if defined(CONFIG_PALMODE) + if (ctx->tb->flags & TB_FLAGS_PAL_MODE) { + gen_mfpr(ra, insn & 0xffff); + break; } - break; #endif + goto invalid_opc; case 0x1A: /* JMP, JSR, RET, JSR_COROUTINE. These only differ by the branch prediction stack action, which of course we don't implement. */ @@ -2598,41 +2738,43 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) break; case 0x1B: /* HW_LD (PALcode) */ -#if defined (CONFIG_USER_ONLY) +#if !defined(CONFIG_PALMODE) goto invalid_opc; #else - if (!ctx->pal_mode) + if ((ctx->tb->flags & TB_FLAGS_PAL_MODE) == 0) { goto invalid_opc; + } if (ra != 31) { TCGv addr = tcg_temp_new(); + if (rb != 31) tcg_gen_addi_i64(addr, cpu_ir[rb], disp12); else tcg_gen_movi_i64(addr, disp12); + switch ((insn >> 12) & 0xF) { case 0x0: /* Longword physical access (hw_ldl/p) */ - gen_helper_ldl_raw(cpu_ir[ra], addr); + gen_helper_ldl_phys(cpu_ir[ra], addr); break; case 0x1: /* Quadword physical access (hw_ldq/p) */ - gen_helper_ldq_raw(cpu_ir[ra], addr); + gen_helper_ldq_phys(cpu_ir[ra], addr); break; case 0x2: /* Longword physical access with lock (hw_ldl_l/p) */ - gen_helper_ldl_l_raw(cpu_ir[ra], addr); + gen_helper_ldl_l_phys(cpu_ir[ra], addr); break; case 0x3: /* Quadword physical access with lock (hw_ldq_l/p) */ - gen_helper_ldq_l_raw(cpu_ir[ra], addr); + gen_helper_ldq_l_phys(cpu_ir[ra], addr); break; case 0x4: /* Longword virtual PTE fetch (hw_ldl/v) */ - tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0); - break; + goto invalid_opc; case 0x5: /* Quadword virtual PTE fetch (hw_ldq/v) */ - tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0); + goto invalid_opc; break; case 0x6: /* Incpu_ir[ra]id */ @@ -2641,54 +2783,33 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) /* Incpu_ir[ra]id */ goto invalid_opc; case 0x8: - /* Longword virtual access (hw_ldl) */ - gen_helper_st_virt_to_phys(addr, addr); - gen_helper_ldl_raw(cpu_ir[ra], addr); - break; + /* Longword virtual access (hw_ldl) (no access check) */ + goto invalid_opc; case 0x9: - /* Quadword virtual access (hw_ldq) */ - gen_helper_st_virt_to_phys(addr, addr); - gen_helper_ldq_raw(cpu_ir[ra], addr); - break; + /* Quadword virtual access (hw_ldq) (no access check) */ + goto invalid_opc; case 0xA: /* Longword virtual access with protection check (hw_ldl/w) */ - tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0); - break; + goto invalid_opc; case 0xB: /* Quadword virtual access with protection check (hw_ldq/w) */ - tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0); - break; + goto invalid_opc; case 0xC: /* Longword virtual access with alt access mode (hw_ldl/a)*/ - gen_helper_set_alt_mode(); - gen_helper_st_virt_to_phys(addr, addr); - gen_helper_ldl_raw(cpu_ir[ra], addr); - gen_helper_restore_mode(); - break; + goto invalid_opc; case 0xD: /* Quadword virtual access with alt access mode (hw_ldq/a) */ - gen_helper_set_alt_mode(); - gen_helper_st_virt_to_phys(addr, addr); - gen_helper_ldq_raw(cpu_ir[ra], addr); - gen_helper_restore_mode(); - break; + goto invalid_opc; case 0xE: /* Longword virtual access with alternate access mode and - * protection checks (hw_ldl/wa) - */ - gen_helper_set_alt_mode(); - gen_helper_ldl_data(cpu_ir[ra], addr); - gen_helper_restore_mode(); - break; + protection checks (hw_ldl/wa) */ + goto invalid_opc; case 0xF: /* Quadword virtual access with alternate access mode and - * protection checks (hw_ldq/wa) - */ - gen_helper_set_alt_mode(); - gen_helper_ldq_data(cpu_ir[ra], addr); - gen_helper_restore_mode(); - break; + protection checks (hw_ldq/wa) */ + goto invalid_opc; } + tcg_temp_free(addr); } break; @@ -2870,57 +2991,41 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) break; case 0x1D: /* HW_MTPR (PALcode) */ -#if defined (CONFIG_USER_ONLY) - goto invalid_opc; -#else - if (!ctx->pal_mode) - goto invalid_opc; - else { - TCGv tmp1 = tcg_const_i32(insn & 0xFF); - if (ra != 31) - gen_helper_mtpr(tmp1, cpu_ir[ra]); - else { - TCGv tmp2 = tcg_const_i64(0); - gen_helper_mtpr(tmp1, tmp2); - tcg_temp_free(tmp2); - } - tcg_temp_free(tmp1); - ret = EXIT_PC_STALE; +#if defined(CONFIG_PALMODE) + if (ctx->tb->flags & TB_FLAGS_PAL_MODE) { + gen_mtpr(rb, insn & 0xffff); + break; } - break; #endif + goto invalid_opc; case 0x1E: /* HW_REI (PALcode) */ -#if defined (CONFIG_USER_ONLY) +#if !defined(CONFIG_PALMODE) goto invalid_opc; #else - if (!ctx->pal_mode) + if ((ctx->tb->flags & TB_FLAGS_PAL_MODE) == 0) { goto invalid_opc; + } if (rb == 31) { /* "Old" alpha */ - gen_helper_hw_rei(); - } else { - TCGv tmp; - - if (ra != 31) { - tmp = tcg_temp_new(); - tcg_gen_addi_i64(tmp, cpu_ir[rb], (((int64_t)insn << 51) >> 51)); - } else - tmp = tcg_const_i64(((int64_t)insn << 51) >> 51); + TCGv tmp = tcg_temp_new(); + tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUState, pal_unix.exc_addr)); gen_helper_hw_ret(tmp); tcg_temp_free(tmp); + } else { + gen_helper_hw_ret(cpu_ir[rb]); } ret = EXIT_PC_UPDATED; break; #endif case 0x1F: /* HW_ST (PALcode) */ -#if defined (CONFIG_USER_ONLY) +#if !defined(CONFIG_PALMODE) goto invalid_opc; #else - if (!ctx->pal_mode) + if ((ctx->tb->flags & TB_FLAGS_PAL_MODE) == 0) { goto invalid_opc; - else { + } else { TCGv addr, val; addr = tcg_temp_new(); if (rb != 31) @@ -2936,29 +3041,27 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) switch ((insn >> 12) & 0xF) { case 0x0: /* Longword physical access */ - gen_helper_stl_raw(val, addr); + gen_helper_stl_phys(addr, val); break; case 0x1: /* Quadword physical access */ - gen_helper_stq_raw(val, addr); + gen_helper_stq_phys(addr, val); break; case 0x2: /* Longword physical access with lock */ - gen_helper_stl_c_raw(val, val, addr); + gen_helper_stl_c_phys(val, addr, val); break; case 0x3: /* Quadword physical access with lock */ - gen_helper_stq_c_raw(val, val, addr); + gen_helper_stq_c_phys(val, addr, val); break; case 0x4: - /* Longword virtual access */ - gen_helper_st_virt_to_phys(addr, addr); - gen_helper_stl_raw(val, addr); + /* Longword virtual access (no access check) */ + tcg_gen_qemu_st32(val, addr, 0); break; case 0x5: - /* Quadword virtual access */ - gen_helper_st_virt_to_phys(addr, addr); - gen_helper_stq_raw(val, addr); + /* Quadword virtual access (no access check) */ + tcg_gen_qemu_st64(val, addr, 0); break; case 0x6: /* Invalid */ @@ -2980,18 +3083,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) goto invalid_opc; case 0xC: /* Longword virtual access with alternate access mode */ - gen_helper_set_alt_mode(); - gen_helper_st_virt_to_phys(addr, addr); - gen_helper_stl_raw(val, addr); - gen_helper_restore_mode(); - break; + goto invalid_opc; case 0xD: /* Quadword virtual access with alternate access mode */ - gen_helper_set_alt_mode(); - gen_helper_st_virt_to_phys(addr, addr); - gen_helper_stl_raw(val, addr); - gen_helper_restore_mode(); - break; + goto invalid_opc; case 0xE: /* Invalid */ goto invalid_opc; @@ -3156,12 +3251,7 @@ static inline void gen_intermediate_code_internal(CPUState *env, ctx.env = env; ctx.pc = pc_start; ctx.amask = env->amask; -#if defined (CONFIG_USER_ONLY) - ctx.mem_idx = 0; -#else - ctx.mem_idx = ((env->ps >> 3) & 3); - ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1; -#endif + ctx.mem_idx = cpu_mmu_index(env); /* ??? Every TB begins with unset rounding mode, to be initialized on the first fp insn of the TB. Alternately we could define a proper @@ -3325,43 +3415,17 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) env->implver = implver; env->amask = amask; - env->ps = 0x1F00; -#if defined (CONFIG_USER_ONLY) - env->ps |= 1 << 3; +#if defined(CONFIG_USER_ONLY) cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_UNFD | FPCR_INED | FPCR_DNOD)); + env->ps = PS_USER_MODE; + env->pal_mode = 0; #else - pal_init(env); + env->ps = 7; + env->pal_mode = 1; #endif env->lock_addr = -1; - - /* Initialize IPR */ -#if defined (CONFIG_USER_ONLY) - env->ipr[IPR_EXC_ADDR] = 0; - env->ipr[IPR_EXC_SUM] = 0; - env->ipr[IPR_EXC_MASK] = 0; -#else - { - // uint64_t hwpcb; - // hwpcb = env->ipr[IPR_PCBB]; - env->ipr[IPR_ASN] = 0; - env->ipr[IPR_ASTEN] = 0; - env->ipr[IPR_ASTSR] = 0; - env->ipr[IPR_DATFX] = 0; - /* XXX: fix this */ - // env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8); - // env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0); - // env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16); - // env->ipr[IPR_USP] = ldq_raw(hwpcb + 24); - env->ipr[IPR_FEN] = 0; - env->ipr[IPR_IPL] = 31; - env->ipr[IPR_MCES] = 0; - env->ipr[IPR_PERFMON] = 0; /* Implementation specific */ - // env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32); - env->ipr[IPR_SISR] = 0; - env->ipr[IPR_VIRBND] = -1ULL; - } -#endif + env->fen = 1; qemu_init_vcpu(env); return env;