From nobody Sat Dec 13 22:59:31 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1751902952; cv=none; d=zohomail.com; s=zohoarc; b=QGnb6/2XBTA0Z2Ya7WIggZybHkS1WWfCBDCwx0O3hC6q3bLZedlnAFFA9pGDAGKfCpswmGE6bt//rBNc91BK180082gZsqN8FC6Buoa5cL/VboXtXjI9hv0MgCuZT5Xz+oN9CyxOCHQnaKDo7Cvji9Eew+YB6drqw4PZr5FvRGA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1751902952; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=bI3cu7GDszasTfxVkgNgSTZnwpreTUViKPsKKclbv5c=; b=QHPoofPPL/pJTcnKS6/DoDYSjgmNWXHXCh0Bfpz9m2j54tZvkqRfeG3EuyevxsObYLJqxyVHxe0+aNjoKMqyqpxpQ/9RkP7qG1slvoG/UmPgQGW75IePyc2LNmWRthUVcOL76SasQO/r82x+xARXT6uTVjPjeGcGK8YA6asUeDk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1751902952411434.10496588737226; Mon, 7 Jul 2025 08:42:32 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uYnyZ-00057e-Pi; Mon, 07 Jul 2025 11:41:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uYnZS-000575-6P for qemu-devel@nongnu.org; Mon, 07 Jul 2025 11:15:54 -0400 Received: from mail-oa1-x31.google.com ([2001:4860:4864:20::31]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uYnZQ-00024k-Cg for qemu-devel@nongnu.org; Mon, 07 Jul 2025 11:15:53 -0400 Received: by mail-oa1-x31.google.com with SMTP id 586e51a60fabf-2da3c572a0bso2954514fac.3 for ; Mon, 07 Jul 2025 08:15:51 -0700 (PDT) Received: from localhost.localdomain (fixed-187-189-51-143.totalplay.net. [187.189.51.143]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-2f7902d65f6sm2236393fac.46.2025.07.07.08.15.49 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Jul 2025 08:15:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1751901351; x=1752506151; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=bI3cu7GDszasTfxVkgNgSTZnwpreTUViKPsKKclbv5c=; b=QXR+gbPtnJe8QsoIqc1IEsha8IJ5q6rmTZiTYVDbNflibzmKJ0NMZK+BqboW2IIC48 IRd2hV7fxtluE+LdwAY9cTOqAg3CyrGYeTB6caONlP/LRCzrSq7Y3Sy61ab3X1E46N26 /W5T9xNg7sTaErcHt4xt/vJdZM6eM7xMHYMGsI6FtggzFvoWMIJgcTrYaw7wsbpShlCC Faiyr4cgotbL6+pluhf5Klbv6NhZtbASWf2Xv49SKrEhgsZcYWjTyk4HlIyri++xqsFQ sq+mQByUgq6K0n96PGkDgpU1Qontkt3nw6/9Co4+dRFSK8PKCAvYrns4A/JDWtSZyKiP YWcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751901351; x=1752506151; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=bI3cu7GDszasTfxVkgNgSTZnwpreTUViKPsKKclbv5c=; b=g/JlIq3w+T3LO9dLOLS7Pz7J3BaEUx8rnhyNgeoujF0IF9OojPGv+KLm+AZjgbnCyK SljHV/05cwbY8wdcPmQYLRkOAge+bRfwIEfFcZZ4QAK9t+E6bFXL1GIaWdxWZDxk9LQ4 ORnrpIhH/RvUPZWetxrCypBuX3Hscg1bJbMr7ZMPFt3mO2pGXg79SlnYZh/1vEgMhdaZ yjobFlZmLwTaW9FM2Cs47/SYk0CImWql+71c8Kb6hFkCrxCwpaWh5QiXPbMOIW9bRzyN v8Y9BlM9SqC7c8JtS+qDcPMValnfyUz7NhTPMpw4HdHjUOoTPRP+h2PVEPfbTfuPV4oJ Yjhw== X-Gm-Message-State: AOJu0Yx/PSaFQIwYqbDqV5bnhV7VH3KIKNYaeLByRKgBKFvHETvq1jEH ptRtQ7qLN7BX17nPkVh9Awks/8R8RlWPZ+URuUy7UnyKLbL4qVz/Kuh1bVfWLXn3vsIm1JwSnuX J6DLZwiM= X-Gm-Gg: ASbGncs4HwtueFGz9MsGknoBk+/9R3lAcGaA5OTMfYPf9PJQZEdZKTVdcbGylNPko1f K3qFaUbX5tdV6PNa2vgyohq/5xLYAo70ur2dIaBKNYVwOUfe4tj2TXi39/GsAzk9pFkqEaWUTC7 stkBdCnpJtVG8IQJYsGFnRlV5ArMmMf6zRh8rkSOhxTnqswWGAgPo9aT+tFtTEEw77wi1z1NAuD KjKifTNBettHW9dRSllJQqUrnzw3gftGzhFuokvo5OucIfCxsGqywDZt53HIUWr1JbpznZ64vee uudXnXeM/n9h4YECqvZrSMyIZKg6pZdTfWks6T386WvNA8T7r37ZTLPKVeBtVuj0b8OdHxEfEeo c61nUfRqMBkDXuBVZfQakW02W30R6KH9tDRmBRoc9W7dymkwQqe7gofM1vN0= X-Google-Smtp-Source: AGHT+IHid/1s77zFJznhPNtc4waNTG6ZiwAd6BjuxaThkEm9l34a9d2/7WGISJrTmjJTUY4La420HQ== X-Received: by 2002:a05:6870:37d1:b0:2ea:83e7:d525 with SMTP id 586e51a60fabf-2f7afdb198emr7208169fac.16.1751901350380; Mon, 07 Jul 2025 08:15:50 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Subject: [PATCH 1/3] target/arm: Drop stub for define_tlb_insn_regs Date: Mon, 7 Jul 2025 09:15:45 -0600 Message-ID: <20250707151547.196393-2-richard.henderson@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250707151547.196393-1-richard.henderson@linaro.org> References: <20250707151547.196393-1-richard.henderson@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2001:4860:4864:20::31; envelope-from=richard.henderson@linaro.org; helo=mail-oa1-x31.google.com X-Spam_score_int: 12 X-Spam_score: 1.2 X-Spam_bar: + X-Spam_report: (1.2 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1751902953950116600 Content-Type: text/plain; charset="utf-8" Allow the call to be compiled out by protecting it with tcg_enabled. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- target/arm/helper.c | 4 +++- target/arm/tcg-stubs.c | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index c311d2df21..be84954360 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7767,7 +7767,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) } =20 #ifndef CONFIG_USER_ONLY - define_tlb_insn_regs(cpu); + if (tcg_enabled()) { + define_tlb_insn_regs(cpu); + } #endif =20 if (arm_feature(env, ARM_FEATURE_V6)) { diff --git a/target/arm/tcg-stubs.c b/target/arm/tcg-stubs.c index 5e5166c049..aac99b2672 100644 --- a/target/arm/tcg-stubs.c +++ b/target/arm/tcg-stubs.c @@ -22,11 +22,6 @@ void raise_exception_ra(CPUARMState *env, uint32_t excp,= uint32_t syndrome, g_assert_not_reached(); } =20 -/* TLBI insns are only used by TCG, so we don't need to do anything for KV= M */ -void define_tlb_insn_regs(ARMCPU *cpu) -{ -} - /* With KVM, we never use float_status, so these can be no-ops */ void arm_set_default_fp_behaviours(float_status *s) { --=20 2.43.0 From nobody Sat Dec 13 22:59:31 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1751903014; cv=none; d=zohomail.com; s=zohoarc; b=SW+V2kVYt1ukaPDoIj907xGyj3Tpcj9rcII+dEpRWMTDa3AqiO//hMLr6jso9NoB3CXsmeMvcPWBJ65ZutZuXX4JgQdeKXxWNSAvZX/1TUAvbZ64XrcOCdk9mE9VDb19xwa1UurujFIa5Qioak/VdnED3ZsQRWlo6sFx4zRQViQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1751903014; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=Txmz76/Hnq+QxxqJNujReBz9uNPDe4gjMekOoFvc9ik=; b=ArE52xX6zak8irPuBVHY2xJDNE0CkVTK2/wRjtIEIXzfEVuD9nWM/NvCU58rA6RYZiQePAsVY0Dyvfzb9fZNThfvCMq8d4MFUJqVy/m+95aiHz43MlotMU28LTtaa7/9y7uVwbT11fMIqPosOtJCyqef8uCagsdp1O8t2ZhO20o= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1751903014401991.2437146840695; Mon, 7 Jul 2025 08:43:34 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uYnzq-0006VB-Sw; Mon, 07 Jul 2025 11:43:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uYneR-00073X-Q7 for qemu-devel@nongnu.org; Mon, 07 Jul 2025 11:21:05 -0400 Received: from mail-qv1-xf29.google.com ([2607:f8b0:4864:20::f29]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uYneM-0002s4-GH for qemu-devel@nongnu.org; Mon, 07 Jul 2025 11:21:02 -0400 Received: by mail-qv1-xf29.google.com with SMTP id 6a1803df08f44-6faf66905baso48326766d6.2 for ; Mon, 07 Jul 2025 08:20:57 -0700 (PDT) Received: from localhost.localdomain (fixed-187-189-51-143.totalplay.net. [187.189.51.143]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-2f7902d65f6sm2236393fac.46.2025.07.07.08.15.50 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Jul 2025 08:15:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1751901657; x=1752506457; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=Txmz76/Hnq+QxxqJNujReBz9uNPDe4gjMekOoFvc9ik=; b=rCX5LK+67jJ29ZhpjuVDYQ0syp/XfqEJYlkRsNoX6q9Io+lCTjqjdVsO461wBgTr9D lnVTU2S3W1JFZeAY4Id7ClTTyNC1MaX4CTq9i8r63ocK4J56n6qcNPyvsn1MQr8ic9QC FuEg3He8dcPEdTdx/pL7wkwO9TFKhDlOJzTYnKTlXyIFSLkOjdqkPlhsnWwQEmF5K0Do vSH8xIy/eL9VTdcX3V5W70ksZx8VljnEeaCgg4H5SZ4RCDLxnMX+Sr+tB7puv1KLmo/F S0fHJCD4guUPNW5ollsuqQxif46KK4A5oID/6zI9E9pxtnTRBDBaQWi6P2sLNPZ5VCQ3 HNWQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751901657; x=1752506457; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Txmz76/Hnq+QxxqJNujReBz9uNPDe4gjMekOoFvc9ik=; b=Yec88/kZdd0X/Xl3G/gSMXUhx1YZGX9vOgbz4BeJ3j8KBH/pY/CZmSPgnYjxB6UCkM A8RfZEi2LOuumkSuxuGT4Bb85T1TukGDeAwBZCV6qwoKHVoggCh2lCXCQyMfBkTfBrzU D+o4R6UWulgQmxbv3wojHj+HpnhuBl4UN3x9IMY8x2odJmgfVmG/1UpmIgNGJZligY4j ys1+QVpRCczT4wOEsfMca/Qrq2iP+r37+A1ssJT7oWMBNrOQrEKjQFlUDujDTkbV3C4L qsVQURnjc0KM9mmAHdCBWX0I761H9+SuZdYIDT5tKXUroZbcP7pOLYgYr/9dlENCPVSk JOlQ== X-Gm-Message-State: AOJu0Yx7xMCooZht3EwoZE/mdZiVT+p/1druNMcicbNeGvvnHv5R7VTC fv7AVgjzEjk8uDpYllwHzWk0XKPnRtXC1P7sp6Rpwdb11E5N0ZEJFWf4bRTesY/qouEdgwNZ5sP SebYLFXE= X-Gm-Gg: ASbGncvcByYK5ZjhXZX+siYmwvM7+L8WsPFhl3cCO6qprc5dZInnc5ASLONfUJXrB38 Z+1tziEuOaNJxg99t9GDY1D9JEhXhbcwt62pgbCpxF3S+iT+prMoBWMW0bZ/g7UxMiggEebalwA L91W5LkSUbxXJ2MQG53AJY/n1dtUBrgtqv+40T7dENlwv4u8TbqPabVSkzCO5eaCteXcz16PWSc 7eX9+rOTvbmQq2wiYL85sU4zHZgYDdx+uTMFOZDoXf/dGM5nRtJWc0+mhr8fgGpWJRsh1AlzR2v /WI7CVU3OvSqQ9fHc3eyA9xzZWoQ6O304KsMAv8mUzrVYSJvQatmp20i7zLmESAjDi967+iSx5k HD25v7XmdW2026ZaqveELA+Dy0v5iILVjeL2QcxaFdDySmQIv X-Google-Smtp-Source: AGHT+IH7U81bjlNSYxwVeG53Juu2x5FaaJrnRMRYTFipwhp091X/HDkB8VrUd8YS54x+X0tW45tH3w== X-Received: by 2002:a05:6870:a44f:b0:2c1:5fe3:22eb with SMTP id 586e51a60fabf-2f796adb1b5mr8638636fac.15.1751901351310; Mon, 07 Jul 2025 08:15:51 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Subject: [PATCH 2/3] target/arm: Split out AT insns to tcg/cpregs-at.c Date: Mon, 7 Jul 2025 09:15:46 -0600 Message-ID: <20250707151547.196393-3-richard.henderson@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250707151547.196393-1-richard.henderson@linaro.org> References: <20250707151547.196393-1-richard.henderson@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::f29; envelope-from=richard.henderson@linaro.org; helo=mail-qv1-xf29.google.com X-Spam_score_int: 12 X-Spam_score: 1.2 X-Spam_bar: + X-Spam_report: (1.2 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1751903016287116600 Content-Type: text/plain; charset="utf-8" Split out all "system instructions for address translation". While mapped into "cpregs", these are instructions, and thus are handled in hardware by virtualization. They are all priviledged, and thus not reachable for user-only. Signed-off-by: Richard Henderson --- target/arm/internals.h | 3 + target/arm/helper.c | 514 +----------------------------------- target/arm/tcg/cpregs-at.c | 519 +++++++++++++++++++++++++++++++++++++ target/arm/tcg/meson.build | 1 + 4 files changed, 525 insertions(+), 512 deletions(-) create mode 100644 target/arm/tcg/cpregs-at.c diff --git a/target/arm/internals.h b/target/arm/internals.h index 21a8d67edd..bcaf8965fc 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1871,6 +1871,8 @@ void define_debug_regs(ARMCPU *cpu); =20 /* Add the cpreg definitions for TLBI instructions */ void define_tlb_insn_regs(ARMCPU *cpu); +/* Add the cpreg definitions for AT instructions */ +void define_at_insn_regs(ARMCPU *cpu); =20 /* Effective value of MDCR_EL2 */ static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env) @@ -1981,5 +1983,6 @@ void vfp_clear_float_status_exc_flags(CPUARMState *en= v); * specified by mask changing to the values in val. */ void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask); +bool arm_pan_enabled(CPUARMState *env); =20 #endif diff --git a/target/arm/helper.c b/target/arm/helper.c index be84954360..9680136b3d 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -270,7 +270,7 @@ void init_cpreg_list(ARMCPU *cpu) g_list_free(keys); } =20 -static bool arm_pan_enabled(CPUARMState *env) +bool arm_pan_enabled(CPUARMState *env) { if (is_a64(env)) { if ((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) =3D=3D (HCR_NV | H= CR_NV1)) { @@ -3448,402 +3448,6 @@ static void par_write(CPUARMState *env, const ARMCP= RegInfo *ri, uint64_t value) } } =20 -#ifndef CONFIG_USER_ONLY -/* get_phys_addr() isn't present for user-mode-only targets */ - -static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) -{ - if (ri->opc2 & 4) { - /* - * The ATS12NSO* operations must trap to EL3 or EL2 if executed in - * Secure EL1 (which can only happen if EL3 is AArch64). - * They are simply UNDEF if executed from NS EL1. - * They function normally from EL2 or EL3. - */ - if (arm_current_el(env) =3D=3D 1) { - if (arm_is_secure_below_el3(env)) { - if (env->cp15.scr_el3 & SCR_EEL2) { - return CP_ACCESS_TRAP_EL2; - } - return CP_ACCESS_TRAP_EL3; - } - return CP_ACCESS_UNDEFINED; - } - } - return CP_ACCESS_OK; -} - -#ifdef CONFIG_TCG -static int par_el1_shareability(GetPhysAddrResult *res) -{ - /* - * The PAR_EL1.SH field must be 0b10 for Device or Normal-NC - * memory -- see pseudocode PAREncodeShareability(). - */ - if (((res->cacheattrs.attrs & 0xf0) =3D=3D 0) || - res->cacheattrs.attrs =3D=3D 0x44 || res->cacheattrs.attrs =3D=3D = 0x40) { - return 2; - } - return res->cacheattrs.shareability; -} - -static uint64_t do_ats_write(CPUARMState *env, uint64_t value, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - ARMSecuritySpace ss) -{ - bool ret; - uint64_t par64; - bool format64 =3D false; - ARMMMUFaultInfo fi =3D {}; - GetPhysAddrResult res =3D {}; - - /* - * I_MXTJT: Granule protection checks are not performed on the final - * address of a successful translation. This is a translation not a - * memory reference, so "memop =3D none =3D 0". - */ - ret =3D get_phys_addr_with_space_nogpc(env, value, access_type, 0, - mmu_idx, ss, &res, &fi); - - /* - * ATS operations only do S1 or S1+S2 translations, so we never - * have to deal with the ARMCacheAttrs format for S2 only. - */ - assert(!res.cacheattrs.is_s2_format); - - if (ret) { - /* - * Some kinds of translation fault must cause exceptions rather - * than being reported in the PAR. - */ - int current_el =3D arm_current_el(env); - int target_el; - uint32_t syn, fsr, fsc; - bool take_exc =3D false; - - if (fi.s1ptw && current_el =3D=3D 1 - && arm_mmu_idx_is_stage1_of_2(mmu_idx)) { - /* - * Synchronous stage 2 fault on an access made as part of the - * translation table walk for AT S1E0* or AT S1E1* insn - * executed from NS EL1. If this is a synchronous external abo= rt - * and SCR_EL3.EA =3D=3D 1, then we take a synchronous externa= l abort - * to EL3. Otherwise the fault is taken as an exception to EL2, - * and HPFAR_EL2 holds the faulting IPA. - */ - if (fi.type =3D=3D ARMFault_SyncExternalOnWalk && - (env->cp15.scr_el3 & SCR_EA)) { - target_el =3D 3; - } else { - env->cp15.hpfar_el2 =3D extract64(fi.s2addr, 12, 47) << 4; - if (arm_is_secure_below_el3(env) && fi.s1ns) { - env->cp15.hpfar_el2 |=3D HPFAR_NS; - } - target_el =3D 2; - } - take_exc =3D true; - } else if (fi.type =3D=3D ARMFault_SyncExternalOnWalk) { - /* - * Synchronous external aborts during a translation table walk - * are taken as Data Abort exceptions. - */ - if (fi.stage2) { - if (current_el =3D=3D 3) { - target_el =3D 3; - } else { - target_el =3D 2; - } - } else { - target_el =3D exception_target_el(env); - } - take_exc =3D true; - } - - if (take_exc) { - /* Construct FSR and FSC using same logic as arm_deliver_fault= () */ - if (target_el =3D=3D 2 || arm_el_is_aa64(env, target_el) || - arm_s1_regime_using_lpae_format(env, mmu_idx)) { - fsr =3D arm_fi_to_lfsc(&fi); - fsc =3D extract32(fsr, 0, 6); - } else { - fsr =3D arm_fi_to_sfsc(&fi); - fsc =3D 0x3f; - } - /* - * Report exception with ESR indicating a fault due to a - * translation table walk for a cache maintenance instruction. - */ - syn =3D syn_data_abort_no_iss(current_el =3D=3D target_el, 0, - fi.ea, 1, fi.s1ptw, 1, fsc); - env->exception.vaddress =3D value; - env->exception.fsr =3D fsr; - raise_exception(env, EXCP_DATA_ABORT, syn, target_el); - } - } - - if (is_a64(env)) { - format64 =3D true; - } else if (arm_feature(env, ARM_FEATURE_LPAE)) { - /* - * ATS1Cxx: - * * TTBCR.EAE determines whether the result is returned using the - * 32-bit or the 64-bit PAR format - * * Instructions executed in Hyp mode always use the 64bit format - * - * ATS1S2NSOxx uses the 64bit format if any of the following is tr= ue: - * * The Non-secure TTBCR.EAE bit is set to 1 - * * The implementation includes EL2, and the value of HCR.VM is 1 - * - * (Note that HCR.DC makes HCR.VM behave as if it is 1.) - * - * ATS1Hx always uses the 64bit format. - */ - format64 =3D arm_s1_regime_using_lpae_format(env, mmu_idx); - - if (arm_feature(env, ARM_FEATURE_EL2)) { - if (mmu_idx =3D=3D ARMMMUIdx_E10_0 || - mmu_idx =3D=3D ARMMMUIdx_E10_1 || - mmu_idx =3D=3D ARMMMUIdx_E10_1_PAN) { - format64 |=3D env->cp15.hcr_el2 & (HCR_VM | HCR_DC); - } else { - format64 |=3D arm_current_el(env) =3D=3D 2; - } - } - } - - if (format64) { - /* Create a 64-bit PAR */ - par64 =3D (1 << 11); /* LPAE bit always set */ - if (!ret) { - par64 |=3D res.f.phys_addr & ~0xfffULL; - if (!res.f.attrs.secure) { - par64 |=3D (1 << 9); /* NS */ - } - par64 |=3D (uint64_t)res.cacheattrs.attrs << 56; /* ATTR */ - par64 |=3D par_el1_shareability(&res) << 7; /* SH */ - } else { - uint32_t fsr =3D arm_fi_to_lfsc(&fi); - - par64 |=3D 1; /* F */ - par64 |=3D (fsr & 0x3f) << 1; /* FS */ - if (fi.stage2) { - par64 |=3D (1 << 9); /* S */ - } - if (fi.s1ptw) { - par64 |=3D (1 << 8); /* PTW */ - } - } - } else { - /* - * fsr is a DFSR/IFSR value for the short descriptor - * translation table format (with WnR always clear). - * Convert it to a 32-bit PAR. - */ - if (!ret) { - /* We do not set any attribute bits in the PAR */ - if (res.f.lg_page_size =3D=3D 24 - && arm_feature(env, ARM_FEATURE_V7)) { - par64 =3D (res.f.phys_addr & 0xff000000) | (1 << 1); - } else { - par64 =3D res.f.phys_addr & 0xfffff000; - } - if (!res.f.attrs.secure) { - par64 |=3D (1 << 9); /* NS */ - } - } else { - uint32_t fsr =3D arm_fi_to_sfsc(&fi); - - par64 =3D ((fsr & (1 << 10)) >> 5) | ((fsr & (1 << 12)) >> 6) | - ((fsr & 0xf) << 1) | 1; - } - } - return par64; -} -#endif /* CONFIG_TCG */ - -static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t v= alue) -{ -#ifdef CONFIG_TCG - MMUAccessType access_type =3D ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA= _LOAD; - uint64_t par64; - ARMMMUIdx mmu_idx; - int el =3D arm_current_el(env); - ARMSecuritySpace ss =3D arm_security_space(env); - - switch (ri->opc2 & 6) { - case 0: - /* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP= */ - switch (el) { - case 3: - if (ri->crm =3D=3D 9 && arm_pan_enabled(env)) { - mmu_idx =3D ARMMMUIdx_E30_3_PAN; - } else { - mmu_idx =3D ARMMMUIdx_E3; - } - break; - case 2: - g_assert(ss !=3D ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit o= nly */ - /* fall through */ - case 1: - if (ri->crm =3D=3D 9 && arm_pan_enabled(env)) { - mmu_idx =3D ARMMMUIdx_Stage1_E1_PAN; - } else { - mmu_idx =3D ARMMMUIdx_Stage1_E1; - } - break; - default: - g_assert_not_reached(); - } - break; - case 2: - /* stage 1 current state PL0: ATS1CUR, ATS1CUW */ - switch (el) { - case 3: - mmu_idx =3D ARMMMUIdx_E30_0; - break; - case 2: - g_assert(ss !=3D ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit o= nly */ - mmu_idx =3D ARMMMUIdx_Stage1_E0; - break; - case 1: - mmu_idx =3D ARMMMUIdx_Stage1_E0; - break; - default: - g_assert_not_reached(); - } - break; - case 4: - /* stage 1+2 NonSecure PL1: ATS12NSOPR, ATS12NSOPW */ - mmu_idx =3D ARMMMUIdx_E10_1; - ss =3D ARMSS_NonSecure; - break; - case 6: - /* stage 1+2 NonSecure PL0: ATS12NSOUR, ATS12NSOUW */ - mmu_idx =3D ARMMMUIdx_E10_0; - ss =3D ARMSS_NonSecure; - break; - default: - g_assert_not_reached(); - } - - par64 =3D do_ats_write(env, value, access_type, mmu_idx, ss); - - A32_BANKED_CURRENT_REG_SET(env, par, par64); -#else - /* Handled by hardware accelerator. */ - g_assert_not_reached(); -#endif /* CONFIG_TCG */ -} - -static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ -#ifdef CONFIG_TCG - MMUAccessType access_type =3D ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA= _LOAD; - uint64_t par64; - - /* There is no SecureEL2 for AArch32. */ - par64 =3D do_ats_write(env, value, access_type, ARMMMUIdx_E2, - ARMSS_NonSecure); - - A32_BANKED_CURRENT_REG_SET(env, par, par64); -#else - /* Handled by hardware accelerator. */ - g_assert_not_reached(); -#endif /* CONFIG_TCG */ -} - -static CPAccessResult at_e012_access(CPUARMState *env, const ARMCPRegInfo = *ri, - bool isread) -{ - /* - * R_NYXTL: instruction is UNDEFINED if it applies to an Exception lev= el - * lower than EL3 and the combination SCR_EL3.{NSE,NS} is reserved. Th= is can - * only happen when executing at EL3 because that combination also cau= ses an - * illegal exception return. We don't need to check FEAT_RME either, b= ecause - * scr_write() ensures that the NSE bit is not set otherwise. - */ - if ((env->cp15.scr_el3 & (SCR_NSE | SCR_NS)) =3D=3D SCR_NSE) { - return CP_ACCESS_UNDEFINED; - } - return CP_ACCESS_OK; -} - -static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo = *ri, - bool isread) -{ - if (arm_current_el(env) =3D=3D 3 && - !(env->cp15.scr_el3 & (SCR_NS | SCR_EEL2))) { - return CP_ACCESS_UNDEFINED; - } - return at_e012_access(env, ri, isread); -} - -static CPAccessResult at_s1e01_access(CPUARMState *env, const ARMCPRegInfo= *ri, - bool isread) -{ - if (arm_current_el(env) =3D=3D 1 && (arm_hcr_el2_eff(env) & HCR_AT)) { - return CP_ACCESS_TRAP_EL2; - } - return at_e012_access(env, ri, isread); -} - -static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ -#ifdef CONFIG_TCG - MMUAccessType access_type =3D ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA= _LOAD; - ARMMMUIdx mmu_idx; - uint64_t hcr_el2 =3D arm_hcr_el2_eff(env); - bool regime_e20 =3D (hcr_el2 & (HCR_E2H | HCR_TGE)) =3D=3D (HCR_E2H | = HCR_TGE); - bool for_el3 =3D false; - ARMSecuritySpace ss; - - switch (ri->opc2 & 6) { - case 0: - switch (ri->opc1) { - case 0: /* AT S1E1R, AT S1E1W, AT S1E1RP, AT S1E1WP */ - if (ri->crm =3D=3D 9 && arm_pan_enabled(env)) { - mmu_idx =3D regime_e20 ? - ARMMMUIdx_E20_2_PAN : ARMMMUIdx_Stage1_E1_PAN; - } else { - mmu_idx =3D regime_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_Stage= 1_E1; - } - break; - case 4: /* AT S1E2R, AT S1E2W */ - mmu_idx =3D hcr_el2 & HCR_E2H ? ARMMMUIdx_E20_2 : ARMMMUIdx_E2; - break; - case 6: /* AT S1E3R, AT S1E3W */ - mmu_idx =3D ARMMMUIdx_E3; - for_el3 =3D true; - break; - default: - g_assert_not_reached(); - } - break; - case 2: /* AT S1E0R, AT S1E0W */ - mmu_idx =3D regime_e20 ? ARMMMUIdx_E20_0 : ARMMMUIdx_Stage1_E0; - break; - case 4: /* AT S12E1R, AT S12E1W */ - mmu_idx =3D regime_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_E10_1; - break; - case 6: /* AT S12E0R, AT S12E0W */ - mmu_idx =3D regime_e20 ? ARMMMUIdx_E20_0 : ARMMMUIdx_E10_0; - break; - default: - g_assert_not_reached(); - } - - ss =3D for_el3 ? arm_security_space(env) : arm_security_space_below_el= 3(env); - env->cp15.par_el[1] =3D do_ats_write(env, value, access_type, mmu_idx,= ss); -#else - /* Handled by hardware accelerator. */ - g_assert_not_reached(); -#endif /* CONFIG_TCG */ -} -#endif - /* Return basic MPU access permission bits. */ static uint32_t simple_mpu_ap_bits(uint32_t val) { @@ -5094,53 +4698,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] =3D { .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 14, .opc2 =3D 2, .fgt =3D FGT_DCCISW, .access =3D PL1_W, .accessfn =3D access_tsw, .type =3D ARM_CP_NOP }, -#ifndef CONFIG_USER_ONLY - /* 64 bit address translation operations */ - { .name =3D "AT_S1E1R", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 8, .opc2 =3D 0, - .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .fgt =3D FGT_ATS1E1R, - .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, - { .name =3D "AT_S1E1W", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 8, .opc2 =3D 1, - .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .fgt =3D FGT_ATS1E1W, - .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, - { .name =3D "AT_S1E0R", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 8, .opc2 =3D 2, - .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .fgt =3D FGT_ATS1E0R, - .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, - { .name =3D "AT_S1E0W", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 8, .opc2 =3D 3, - .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .fgt =3D FGT_ATS1E0W, - .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, - { .name =3D "AT_S12E1R", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 4, - .access =3D PL2_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .accessfn =3D at_e012_access, .writefn =3D ats_write64 }, - { .name =3D "AT_S12E1W", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 5, - .access =3D PL2_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .accessfn =3D at_e012_access, .writefn =3D ats_write64 }, - { .name =3D "AT_S12E0R", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 6, - .access =3D PL2_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .accessfn =3D at_e012_access, .writefn =3D ats_write64 }, - { .name =3D "AT_S12E0W", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 7, - .access =3D PL2_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .accessfn =3D at_e012_access, .writefn =3D ats_write64 }, - /* AT S1E2* are elsewhere as they UNDEF from EL3 if EL2 is not present= */ - { .name =3D "AT_S1E3R", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 6, .crn =3D 7, .crm =3D 8, .opc2 =3D 0, - .access =3D PL3_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .writefn =3D ats_write64 }, - { .name =3D "AT_S1E3W", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 6, .crn =3D 7, .crm =3D 8, .opc2 =3D 1, - .access =3D PL3_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .writefn =3D ats_write64 }, { .name =3D "PAR_EL1", .state =3D ARM_CP_STATE_AA64, .type =3D ARM_CP_ALIAS, .opc0 =3D 3, .opc1 =3D 0, .crn =3D 7, .crm =3D 4, .opc2 =3D 0, @@ -5148,7 +4705,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] =3D { .fgt =3D FGT_PAR_EL1, .fieldoffset =3D offsetof(CPUARMState, cp15.par_el[1]), .writefn =3D par_write }, -#endif /* 32 bit cache operations */ { .name =3D "ICIALLUIS", .cp =3D 15, .opc1 =3D 0, .crn =3D 7, .crm =3D= 1, .opc2 =3D 0, .type =3D ARM_CP_NOP, .access =3D PL1_W, .accessfn =3D access_ticab = }, @@ -5751,33 +5307,6 @@ static const ARMCPRegInfo el2_cp_reginfo[] =3D { .access =3D PL2_RW, .type =3D ARM_CP_64BIT | ARM_CP_ALIAS, .fieldoffset =3D offsetof(CPUARMState, cp15.ttbr0_el[2]) }, #ifndef CONFIG_USER_ONLY - /* - * Unlike the other EL2-related AT operations, these must - * UNDEF from EL3 if EL2 is not implemented, which is why we - * define them here rather than with the rest of the AT ops. - */ - { .name =3D "AT_S1E2R", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 0, - .access =3D PL2_W, .accessfn =3D at_s1e2_access, - .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDE= F, - .writefn =3D ats_write64 }, - { .name =3D "AT_S1E2W", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 1, - .access =3D PL2_W, .accessfn =3D at_s1e2_access, - .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDE= F, - .writefn =3D ats_write64 }, - /* - * The AArch32 ATS1H* operations are CONSTRAINED UNPREDICTABLE - * if EL2 is not implemented; we choose to UNDEF. Behaviour at EL3 - * with SCR.NS =3D=3D 0 outside Monitor mode is UNPREDICTABLE; we choo= se - * to behave as if SCR.NS was 1. - */ - { .name =3D "ATS1HR", .cp =3D 15, .opc1 =3D 4, .crn =3D 7, .crm =3D 8,= .opc2 =3D 0, - .access =3D PL2_W, - .writefn =3D ats1h_write, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EX= C }, - { .name =3D "ATS1HW", .cp =3D 15, .opc1 =3D 4, .crn =3D 7, .crm =3D 8,= .opc2 =3D 1, - .access =3D PL2_W, - .writefn =3D ats1h_write, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EX= C }, { .name =3D "CNTHCTL_EL2", .state =3D ARM_CP_STATE_BOTH, .opc0 =3D 3, .opc1 =3D 4, .crn =3D 14, .crm =3D 1, .opc2 =3D 0, /* @@ -7700,32 +7229,6 @@ static const ARMCPRegInfo vhe_reginfo[] =3D { #endif }; =20 -#ifndef CONFIG_USER_ONLY -static const ARMCPRegInfo ats1e1_reginfo[] =3D { - { .name =3D "AT_S1E1RP", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 9, .opc2 =3D 0, - .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .fgt =3D FGT_ATS1E1RP, - .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, - { .name =3D "AT_S1E1WP", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 9, .opc2 =3D 1, - .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .fgt =3D FGT_ATS1E1WP, - .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, -}; - -static const ARMCPRegInfo ats1cp_reginfo[] =3D { - { .name =3D "ATS1CPRP", - .cp =3D 15, .opc1 =3D 0, .crn =3D 7, .crm =3D 9, .opc2 =3D 0, - .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .writefn =3D ats_write }, - { .name =3D "ATS1CPWP", - .cp =3D 15, .opc1 =3D 0, .crn =3D 7, .crm =3D 9, .opc2 =3D 1, - .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, - .writefn =3D ats_write }, -}; -#endif - /* * ACTLR2 and HACTLR2 map to ACTLR_EL1[63:32] and * ACTLR_EL2[63:32]. They exist only if the ID_MMFR4.AC2 field @@ -7769,6 +7272,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) #ifndef CONFIG_USER_ONLY if (tcg_enabled()) { define_tlb_insn_regs(cpu); + define_at_insn_regs(cpu); } #endif =20 @@ -8502,12 +8006,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .bank_fieldoffsets =3D { offsetoflow32(CPUARMState, cp15.par= _s), offsetoflow32(CPUARMState, cp15.par_n= s) }, .writefn =3D par_write}, -#ifndef CONFIG_USER_ONLY - /* This underdecoding is safe because the reginfo is NO_RAW. */ - { .name =3D "ATS", .cp =3D 15, .crn =3D 7, .crm =3D 8, .opc1 = =3D 0, .opc2 =3D CP_ANY, - .access =3D PL1_W, .accessfn =3D ats_access, - .writefn =3D ats_write, .type =3D ARM_CP_NO_RAW | ARM_CP_RAI= SES_EXC }, -#endif }; =20 /* @@ -8913,14 +8411,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (cpu_isar_feature(aa64_pan, cpu)) { define_one_arm_cp_reg(cpu, &pan_reginfo); } -#ifndef CONFIG_USER_ONLY - if (cpu_isar_feature(aa64_ats1e1, cpu)) { - define_arm_cp_regs(cpu, ats1e1_reginfo); - } - if (cpu_isar_feature(aa32_ats1e1, cpu)) { - define_arm_cp_regs(cpu, ats1cp_reginfo); - } -#endif if (cpu_isar_feature(aa64_uao, cpu)) { define_one_arm_cp_reg(cpu, &uao_reginfo); } diff --git a/target/arm/tcg/cpregs-at.c b/target/arm/tcg/cpregs-at.c new file mode 100644 index 0000000000..398a61d398 --- /dev/null +++ b/target/arm/tcg/cpregs-at.c @@ -0,0 +1,519 @@ +/* + * System instructions for address translation + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "cpu-features.h" +#include "internals.h" +#include "cpregs.h" + + +static int par_el1_shareability(GetPhysAddrResult *res) +{ + /* + * The PAR_EL1.SH field must be 0b10 for Device or Normal-NC + * memory -- see pseudocode PAREncodeShareability(). + */ + if (((res->cacheattrs.attrs & 0xf0) =3D=3D 0) || + res->cacheattrs.attrs =3D=3D 0x44 || res->cacheattrs.attrs =3D=3D = 0x40) { + return 2; + } + return res->cacheattrs.shareability; +} + +static uint64_t do_ats_write(CPUARMState *env, uint64_t value, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + ARMSecuritySpace ss) +{ + bool ret; + uint64_t par64; + bool format64 =3D false; + ARMMMUFaultInfo fi =3D {}; + GetPhysAddrResult res =3D {}; + + /* + * I_MXTJT: Granule protection checks are not performed on the final + * address of a successful translation. This is a translation not a + * memory reference, so "memop =3D none =3D 0". + */ + ret =3D get_phys_addr_with_space_nogpc(env, value, access_type, 0, + mmu_idx, ss, &res, &fi); + + /* + * ATS operations only do S1 or S1+S2 translations, so we never + * have to deal with the ARMCacheAttrs format for S2 only. + */ + assert(!res.cacheattrs.is_s2_format); + + if (ret) { + /* + * Some kinds of translation fault must cause exceptions rather + * than being reported in the PAR. + */ + int current_el =3D arm_current_el(env); + int target_el; + uint32_t syn, fsr, fsc; + bool take_exc =3D false; + + if (fi.s1ptw && current_el =3D=3D 1 + && arm_mmu_idx_is_stage1_of_2(mmu_idx)) { + /* + * Synchronous stage 2 fault on an access made as part of the + * translation table walk for AT S1E0* or AT S1E1* insn + * executed from NS EL1. If this is a synchronous external abo= rt + * and SCR_EL3.EA =3D=3D 1, then we take a synchronous externa= l abort + * to EL3. Otherwise the fault is taken as an exception to EL2, + * and HPFAR_EL2 holds the faulting IPA. + */ + if (fi.type =3D=3D ARMFault_SyncExternalOnWalk && + (env->cp15.scr_el3 & SCR_EA)) { + target_el =3D 3; + } else { + env->cp15.hpfar_el2 =3D extract64(fi.s2addr, 12, 47) << 4; + if (arm_is_secure_below_el3(env) && fi.s1ns) { + env->cp15.hpfar_el2 |=3D HPFAR_NS; + } + target_el =3D 2; + } + take_exc =3D true; + } else if (fi.type =3D=3D ARMFault_SyncExternalOnWalk) { + /* + * Synchronous external aborts during a translation table walk + * are taken as Data Abort exceptions. + */ + if (fi.stage2) { + if (current_el =3D=3D 3) { + target_el =3D 3; + } else { + target_el =3D 2; + } + } else { + target_el =3D exception_target_el(env); + } + take_exc =3D true; + } + + if (take_exc) { + /* Construct FSR and FSC using same logic as arm_deliver_fault= () */ + if (target_el =3D=3D 2 || arm_el_is_aa64(env, target_el) || + arm_s1_regime_using_lpae_format(env, mmu_idx)) { + fsr =3D arm_fi_to_lfsc(&fi); + fsc =3D extract32(fsr, 0, 6); + } else { + fsr =3D arm_fi_to_sfsc(&fi); + fsc =3D 0x3f; + } + /* + * Report exception with ESR indicating a fault due to a + * translation table walk for a cache maintenance instruction. + */ + syn =3D syn_data_abort_no_iss(current_el =3D=3D target_el, 0, + fi.ea, 1, fi.s1ptw, 1, fsc); + env->exception.vaddress =3D value; + env->exception.fsr =3D fsr; + raise_exception(env, EXCP_DATA_ABORT, syn, target_el); + } + } + + if (is_a64(env)) { + format64 =3D true; + } else if (arm_feature(env, ARM_FEATURE_LPAE)) { + /* + * ATS1Cxx: + * * TTBCR.EAE determines whether the result is returned using the + * 32-bit or the 64-bit PAR format + * * Instructions executed in Hyp mode always use the 64bit format + * + * ATS1S2NSOxx uses the 64bit format if any of the following is tr= ue: + * * The Non-secure TTBCR.EAE bit is set to 1 + * * The implementation includes EL2, and the value of HCR.VM is 1 + * + * (Note that HCR.DC makes HCR.VM behave as if it is 1.) + * + * ATS1Hx always uses the 64bit format. + */ + format64 =3D arm_s1_regime_using_lpae_format(env, mmu_idx); + + if (arm_feature(env, ARM_FEATURE_EL2)) { + if (mmu_idx =3D=3D ARMMMUIdx_E10_0 || + mmu_idx =3D=3D ARMMMUIdx_E10_1 || + mmu_idx =3D=3D ARMMMUIdx_E10_1_PAN) { + format64 |=3D env->cp15.hcr_el2 & (HCR_VM | HCR_DC); + } else { + format64 |=3D arm_current_el(env) =3D=3D 2; + } + } + } + + if (format64) { + /* Create a 64-bit PAR */ + par64 =3D (1 << 11); /* LPAE bit always set */ + if (!ret) { + par64 |=3D res.f.phys_addr & ~0xfffULL; + if (!res.f.attrs.secure) { + par64 |=3D (1 << 9); /* NS */ + } + par64 |=3D (uint64_t)res.cacheattrs.attrs << 56; /* ATTR */ + par64 |=3D par_el1_shareability(&res) << 7; /* SH */ + } else { + uint32_t fsr =3D arm_fi_to_lfsc(&fi); + + par64 |=3D 1; /* F */ + par64 |=3D (fsr & 0x3f) << 1; /* FS */ + if (fi.stage2) { + par64 |=3D (1 << 9); /* S */ + } + if (fi.s1ptw) { + par64 |=3D (1 << 8); /* PTW */ + } + } + } else { + /* + * fsr is a DFSR/IFSR value for the short descriptor + * translation table format (with WnR always clear). + * Convert it to a 32-bit PAR. + */ + if (!ret) { + /* We do not set any attribute bits in the PAR */ + if (res.f.lg_page_size =3D=3D 24 + && arm_feature(env, ARM_FEATURE_V7)) { + par64 =3D (res.f.phys_addr & 0xff000000) | (1 << 1); + } else { + par64 =3D res.f.phys_addr & 0xfffff000; + } + if (!res.f.attrs.secure) { + par64 |=3D (1 << 9); /* NS */ + } + } else { + uint32_t fsr =3D arm_fi_to_sfsc(&fi); + + par64 =3D ((fsr & (1 << 10)) >> 5) | ((fsr & (1 << 12)) >> 6) | + ((fsr & 0xf) << 1) | 1; + } + } + return par64; +} + +static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t v= alue) +{ + MMUAccessType access_type =3D ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA= _LOAD; + uint64_t par64; + ARMMMUIdx mmu_idx; + int el =3D arm_current_el(env); + ARMSecuritySpace ss =3D arm_security_space(env); + + switch (ri->opc2 & 6) { + case 0: + /* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP= */ + switch (el) { + case 3: + if (ri->crm =3D=3D 9 && arm_pan_enabled(env)) { + mmu_idx =3D ARMMMUIdx_E30_3_PAN; + } else { + mmu_idx =3D ARMMMUIdx_E3; + } + break; + case 2: + g_assert(ss !=3D ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit o= nly */ + /* fall through */ + case 1: + if (ri->crm =3D=3D 9 && arm_pan_enabled(env)) { + mmu_idx =3D ARMMMUIdx_Stage1_E1_PAN; + } else { + mmu_idx =3D ARMMMUIdx_Stage1_E1; + } + break; + default: + g_assert_not_reached(); + } + break; + case 2: + /* stage 1 current state PL0: ATS1CUR, ATS1CUW */ + switch (el) { + case 3: + mmu_idx =3D ARMMMUIdx_E30_0; + break; + case 2: + g_assert(ss !=3D ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit o= nly */ + mmu_idx =3D ARMMMUIdx_Stage1_E0; + break; + case 1: + mmu_idx =3D ARMMMUIdx_Stage1_E0; + break; + default: + g_assert_not_reached(); + } + break; + case 4: + /* stage 1+2 NonSecure PL1: ATS12NSOPR, ATS12NSOPW */ + mmu_idx =3D ARMMMUIdx_E10_1; + ss =3D ARMSS_NonSecure; + break; + case 6: + /* stage 1+2 NonSecure PL0: ATS12NSOUR, ATS12NSOUW */ + mmu_idx =3D ARMMMUIdx_E10_0; + ss =3D ARMSS_NonSecure; + break; + default: + g_assert_not_reached(); + } + + par64 =3D do_ats_write(env, value, access_type, mmu_idx, ss); + + A32_BANKED_CURRENT_REG_SET(env, par, par64); +} + +static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + MMUAccessType access_type =3D ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA= _LOAD; + uint64_t par64; + + /* There is no SecureEL2 for AArch32. */ + par64 =3D do_ats_write(env, value, access_type, ARMMMUIdx_E2, + ARMSS_NonSecure); + + A32_BANKED_CURRENT_REG_SET(env, par, par64); +} + +static CPAccessResult at_e012_access(CPUARMState *env, const ARMCPRegInfo = *ri, + bool isread) +{ + /* + * R_NYXTL: instruction is UNDEFINED if it applies to an Exception lev= el + * lower than EL3 and the combination SCR_EL3.{NSE,NS} is reserved. Th= is can + * only happen when executing at EL3 because that combination also cau= ses an + * illegal exception return. We don't need to check FEAT_RME either, b= ecause + * scr_write() ensures that the NSE bit is not set otherwise. + */ + if ((env->cp15.scr_el3 & (SCR_NSE | SCR_NS)) =3D=3D SCR_NSE) { + return CP_ACCESS_UNDEFINED; + } + return CP_ACCESS_OK; +} + +static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo = *ri, + bool isread) +{ + if (arm_current_el(env) =3D=3D 3 && + !(env->cp15.scr_el3 & (SCR_NS | SCR_EEL2))) { + return CP_ACCESS_UNDEFINED; + } + return at_e012_access(env, ri, isread); +} + +static CPAccessResult at_s1e01_access(CPUARMState *env, const ARMCPRegInfo= *ri, + bool isread) +{ + if (arm_current_el(env) =3D=3D 1 && (arm_hcr_el2_eff(env) & HCR_AT)) { + return CP_ACCESS_TRAP_EL2; + } + return at_e012_access(env, ri, isread); +} + +static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + MMUAccessType access_type =3D ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA= _LOAD; + ARMMMUIdx mmu_idx; + uint64_t hcr_el2 =3D arm_hcr_el2_eff(env); + bool regime_e20 =3D (hcr_el2 & (HCR_E2H | HCR_TGE)) =3D=3D (HCR_E2H | = HCR_TGE); + bool for_el3 =3D false; + ARMSecuritySpace ss; + + switch (ri->opc2 & 6) { + case 0: + switch (ri->opc1) { + case 0: /* AT S1E1R, AT S1E1W, AT S1E1RP, AT S1E1WP */ + if (ri->crm =3D=3D 9 && arm_pan_enabled(env)) { + mmu_idx =3D regime_e20 ? + ARMMMUIdx_E20_2_PAN : ARMMMUIdx_Stage1_E1_PAN; + } else { + mmu_idx =3D regime_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_Stage= 1_E1; + } + break; + case 4: /* AT S1E2R, AT S1E2W */ + mmu_idx =3D hcr_el2 & HCR_E2H ? ARMMMUIdx_E20_2 : ARMMMUIdx_E2; + break; + case 6: /* AT S1E3R, AT S1E3W */ + mmu_idx =3D ARMMMUIdx_E3; + for_el3 =3D true; + break; + default: + g_assert_not_reached(); + } + break; + case 2: /* AT S1E0R, AT S1E0W */ + mmu_idx =3D regime_e20 ? ARMMMUIdx_E20_0 : ARMMMUIdx_Stage1_E0; + break; + case 4: /* AT S12E1R, AT S12E1W */ + mmu_idx =3D regime_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_E10_1; + break; + case 6: /* AT S12E0R, AT S12E0W */ + mmu_idx =3D regime_e20 ? ARMMMUIdx_E20_0 : ARMMMUIdx_E10_0; + break; + default: + g_assert_not_reached(); + } + + ss =3D for_el3 ? arm_security_space(env) : arm_security_space_below_el= 3(env); + env->cp15.par_el[1] =3D do_ats_write(env, value, access_type, mmu_idx,= ss); +} + +static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (ri->opc2 & 4) { + /* + * The ATS12NSO* operations must trap to EL3 or EL2 if executed in + * Secure EL1 (which can only happen if EL3 is AArch64). + * They are simply UNDEF if executed from NS EL1. + * They function normally from EL2 or EL3. + */ + if (arm_current_el(env) =3D=3D 1) { + if (arm_is_secure_below_el3(env)) { + if (env->cp15.scr_el3 & SCR_EEL2) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_UNDEFINED; + } + } + return CP_ACCESS_OK; +} + +static const ARMCPRegInfo vapa_ats_reginfo[] =3D { + /* This underdecoding is safe because the reginfo is NO_RAW. */ + { .name =3D "ATS", .cp =3D 15, .crn =3D 7, .crm =3D 8, .opc1 =3D 0, .o= pc2 =3D CP_ANY, + .access =3D PL1_W, .accessfn =3D ats_access, + .writefn =3D ats_write, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC = }, +}; + +static const ARMCPRegInfo v8_ats_reginfo[] =3D { + /* 64 bit address translation operations */ + { .name =3D "AT_S1E1R", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 8, .opc2 =3D 0, + .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt =3D FGT_ATS1E1R, + .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, + { .name =3D "AT_S1E1W", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 8, .opc2 =3D 1, + .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt =3D FGT_ATS1E1W, + .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, + { .name =3D "AT_S1E0R", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 8, .opc2 =3D 2, + .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt =3D FGT_ATS1E0R, + .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, + { .name =3D "AT_S1E0W", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 8, .opc2 =3D 3, + .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt =3D FGT_ATS1E0W, + .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, + { .name =3D "AT_S12E1R", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 4, + .access =3D PL2_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .accessfn =3D at_e012_access, .writefn =3D ats_write64 }, + { .name =3D "AT_S12E1W", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 5, + .access =3D PL2_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .accessfn =3D at_e012_access, .writefn =3D ats_write64 }, + { .name =3D "AT_S12E0R", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 6, + .access =3D PL2_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .accessfn =3D at_e012_access, .writefn =3D ats_write64 }, + { .name =3D "AT_S12E0W", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 7, + .access =3D PL2_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .accessfn =3D at_e012_access, .writefn =3D ats_write64 }, + /* AT S1E2* are elsewhere as they UNDEF from EL3 if EL2 is not present= */ + { .name =3D "AT_S1E3R", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 6, .crn =3D 7, .crm =3D 8, .opc2 =3D 0, + .access =3D PL3_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn =3D ats_write64 }, + { .name =3D "AT_S1E3W", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 6, .crn =3D 7, .crm =3D 8, .opc2 =3D 1, + .access =3D PL3_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn =3D ats_write64 }, +}; + +static const ARMCPRegInfo el2_ats_reginfo[] =3D { + /* + * Unlike the other EL2-related AT operations, these must + * UNDEF from EL3 if EL2 is not implemented, which is why we + * define them here rather than with the rest of the AT ops. + */ + { .name =3D "AT_S1E2R", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 0, + .access =3D PL2_W, .accessfn =3D at_s1e2_access, + .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDE= F, + .writefn =3D ats_write64 }, + { .name =3D "AT_S1E2W", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 4, .crn =3D 7, .crm =3D 8, .opc2 =3D 1, + .access =3D PL2_W, .accessfn =3D at_s1e2_access, + .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDE= F, + .writefn =3D ats_write64 }, + /* + * The AArch32 ATS1H* operations are CONSTRAINED UNPREDICTABLE + * if EL2 is not implemented; we choose to UNDEF. Behaviour at EL3 + * with SCR.NS =3D=3D 0 outside Monitor mode is UNPREDICTABLE; we choo= se + * to behave as if SCR.NS was 1. + */ + { .name =3D "ATS1HR", .cp =3D 15, .opc1 =3D 4, .crn =3D 7, .crm =3D 8,= .opc2 =3D 0, + .access =3D PL2_W, + .writefn =3D ats1h_write, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EX= C }, + { .name =3D "ATS1HW", .cp =3D 15, .opc1 =3D 4, .crn =3D 7, .crm =3D 8,= .opc2 =3D 1, + .access =3D PL2_W, + .writefn =3D ats1h_write, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EX= C }, +}; + +static const ARMCPRegInfo ats1e1_reginfo[] =3D { + { .name =3D "AT_S1E1RP", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 9, .opc2 =3D 0, + .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt =3D FGT_ATS1E1RP, + .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, + { .name =3D "AT_S1E1WP", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 1, .opc1 =3D 0, .crn =3D 7, .crm =3D 9, .opc2 =3D 1, + .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .fgt =3D FGT_ATS1E1WP, + .accessfn =3D at_s1e01_access, .writefn =3D ats_write64 }, +}; + +static const ARMCPRegInfo ats1cp_reginfo[] =3D { + { .name =3D "ATS1CPRP", + .cp =3D 15, .opc1 =3D 0, .crn =3D 7, .crm =3D 9, .opc2 =3D 0, + .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn =3D ats_write }, + { .name =3D "ATS1CPWP", + .cp =3D 15, .opc1 =3D 0, .crn =3D 7, .crm =3D 9, .opc2 =3D 1, + .access =3D PL1_W, .type =3D ARM_CP_NO_RAW | ARM_CP_RAISES_EXC, + .writefn =3D ats_write }, +}; + +void define_at_insn_regs(ARMCPU *cpu) +{ + CPUARMState *env =3D &cpu->env; + + if (arm_feature(env, ARM_FEATURE_VAPA)) { + define_arm_cp_regs(cpu, vapa_ats_reginfo); + } + if (arm_feature(env, ARM_FEATURE_V8)) { + define_arm_cp_regs(cpu, v8_ats_reginfo); + } + if (arm_feature(env, ARM_FEATURE_EL2) + || (arm_feature(env, ARM_FEATURE_EL3) + && arm_feature(env, ARM_FEATURE_V8))) { + define_arm_cp_regs(cpu, el2_ats_reginfo); + } + if (cpu_isar_feature(aa64_ats1e1, cpu)) { + define_arm_cp_regs(cpu, ats1e1_reginfo); + } + if (cpu_isar_feature(aa32_ats1e1, cpu)) { + define_arm_cp_regs(cpu, ats1cp_reginfo); + } +} diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index c59f0f03a1..895facdc30 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -64,6 +64,7 @@ arm_common_ss.add(files( )) =20 arm_common_system_ss.add(files( + 'cpregs-at.c', 'hflags.c', 'iwmmxt_helper.c', 'neon_helper.c', --=20 2.43.0 From nobody Sat Dec 13 22:59:31 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1751902959; cv=none; d=zohomail.com; s=zohoarc; b=EmqzJqDQRRRBRkj8avWMkNm2b09jQBWPeylstd9gnyKWSm/SnelP87Kdj78EBemR5MnaOWIjmIpNbtN7hcZShuHPrZ+4N+vzXJyk+54PyYOqxFmjpggcSCNm+U5Gnbg8MKlmHNeO1zMN1EGsFxa0AwYkEGXbJY8q5G1rEP6ktYY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1751902959; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=8vr0HEGnq99PEHxJemHmUVpMzgiAEnbt5GwsNBJweOM=; b=J5bZ6QQv79pbXorehmsdRpVf2xMopVWG+gH5XcMIdt/5WySxE7qLrQdjb3J5pY0EVv2L+rXR1pi49Z8s5X3aDQDqwCEVsMnuKjDRqJPc4m7ef2QO/eDsiG1TnN7Hy8jxv4hR0UR+PB+bzybt8UNJsvc1NmLD/9Prz2D+oTm8/0M= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1751902954628653.9637501038292; Mon, 7 Jul 2025 08:42:34 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uYnyc-0005DG-RP; Mon, 07 Jul 2025 11:41:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uYnZZ-0005C7-1a for qemu-devel@nongnu.org; Mon, 07 Jul 2025 11:16:03 -0400 Received: from mail-ot1-x32f.google.com ([2607:f8b0:4864:20::32f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uYnZT-00025D-C3 for qemu-devel@nongnu.org; Mon, 07 Jul 2025 11:16:00 -0400 Received: by mail-ot1-x32f.google.com with SMTP id 46e09a7af769-73a43d327d6so1890976a34.2 for ; Mon, 07 Jul 2025 08:15:54 -0700 (PDT) Received: from localhost.localdomain (fixed-187-189-51-143.totalplay.net. [187.189.51.143]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-2f7902d65f6sm2236393fac.46.2025.07.07.08.15.51 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Jul 2025 08:15:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1751901354; x=1752506154; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=8vr0HEGnq99PEHxJemHmUVpMzgiAEnbt5GwsNBJweOM=; b=IFTO8Ix0cp+ZHvNshXxnq+rKDbrDI8mJn64sZLdaOyNdQ/95W71voVOGypWwQ0o+bS Qnc3e5py5L11NFLKEwXm1rDdBQwlgOAepGZF+497Vu101tceWb0O185E0RloAkwEt+0W Lczm9G9AUG1hsAoYaAbU1Ljq/ZPzAya5T9D0+/3KTxjszQV3Bf84yvlEDZMghqJS/is7 rBpS8KzH+o1ToflvA9iMps3KQ19OWKbhF8NsAiLkZkjtg2UMjf2FYC2bxlCqrg1HXcPT hR0+mTn74S05Xseja2XzMQ83OG0L5pDEVTCgd0WwFjSY5Qn6VF2SbCRXS+CxFIWXM630 9QAQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751901354; x=1752506154; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=8vr0HEGnq99PEHxJemHmUVpMzgiAEnbt5GwsNBJweOM=; b=IFd0FJoJFexvDYGLd7t7t3NkhYNuVY+vcUDlYT156+j64fsW4rw3M8qwOnfkxPQC6d xDCbvQmKMdWBpvupl18oOMYTTpxCvJukeHeBsKkoNfvOAEq59AHbmP/jG8C/DRtzcUdX WuOBEkh6TvnQcfiW9VAO/U38+5xNPXELL6yUMJYExpcYN8QZBbOxxGHxLQrfey/5tGgO DLPQuxGAeFHCK8tLWPl3XHOSVYtH5pzTCwmYRtHB1C0mG9oF851q0o9WWyVpC1vV2rD1 L2FqAbycp8PYq1FmJEd745wf/XBUMdJj4vOiSpMsA70hlAqDBWTWbJsEaXCoqtc0A/oB mswg== X-Gm-Message-State: AOJu0YwSSK3wtya24lXLY+UWtp7JjNiFpDdVAXSvicjcjbpMZky+ovuE N9z6owG5KEaBBdVtGKpNh5TJDhGSkBmEBZMINISAP+5cmvj5ovjqI68xcSC57xS8Jy1JZAPY9vy xF3tA55o= X-Gm-Gg: ASbGnctItaJukoSZMtOkpF6b/71qshu845Kj6Nfv91DjwiobZCR65FLDyD+508JyHuT RVpkENXRcKQwDKIs4qZILFzzEAPjPmvK35FOPEdhXTI+Hg82kKM/9p7tfm9Vj9RKRfiirdQziGW KQ14b0H5FoNOnYxGuh6ghqg2K04AyVIrDIGQUtWbQFu1cO0rMhU/BcMOMIDzMXikVSzAa7l1Wal 6sZTNdf+ZKuroGNFQ/SIywaSTv3KzTZHbpOyyMxnIYRBkPoEMmKMfzs0pS3vjopo+RoxZPQnn8q ADSzP9xyzJrFZVa6rU84pCswWEXfvEqO8BD3Ddit1s3EugoK+FvkRstullRy9cM7A8CZZWTLzHY 4oMYqXHe6/GXmg4avNF7gzG0ziwfaFIGhnpZR4mpKTW2ZoANo X-Google-Smtp-Source: AGHT+IErgeNPH9z29hjyO/h6PNx9TjDFDdXN/Hanu19wESfoUj7/j35azPlZimqbchjG54QM6aHT1g== X-Received: by 2002:a05:6871:203:b0:296:bbc8:4a82 with SMTP id 586e51a60fabf-2f796d075f8mr9961827fac.27.1751901352296; Mon, 07 Jul 2025 08:15:52 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Subject: [PATCH 3/3] target/arm: Split out performance monitor regs to cpregs-pmu.c Date: Mon, 7 Jul 2025 09:15:47 -0600 Message-ID: <20250707151547.196393-4-richard.henderson@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250707151547.196393-1-richard.henderson@linaro.org> References: <20250707151547.196393-1-richard.henderson@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::32f; envelope-from=richard.henderson@linaro.org; helo=mail-ot1-x32f.google.com X-Spam_score_int: 12 X-Spam_score: 1.2 X-Spam_bar: + X-Spam_report: (1.2 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linaro.org) X-ZM-MESSAGEID: 1751902962284116600 Content-Type: text/plain; charset="utf-8" Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- target/arm/cpregs.h | 3 + target/arm/internals.h | 2 + target/arm/cpregs-pmu.c | 1309 +++++++++++++++++++++++++++++++++++++++ target/arm/helper.c | 1287 +------------------------------------- target/arm/meson.build | 2 + 5 files changed, 1319 insertions(+), 1284 deletions(-) create mode 100644 target/arm/cpregs-pmu.c diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index c1a7ae3735..c9506aa6d5 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -1065,6 +1065,9 @@ void arm_cp_write_ignore(CPUARMState *env, const ARMC= PRegInfo *ri, /* CPReadFn that can be used for read-as-zero behaviour */ uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri); =20 +/* CPReadFn that just reads the value from ri->fieldoffset */ +uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri); + /* CPWriteFn that just writes the value to ri->fieldoffset */ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value); =20 diff --git a/target/arm/internals.h b/target/arm/internals.h index bcaf8965fc..c4765e4489 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1873,6 +1873,8 @@ void define_debug_regs(ARMCPU *cpu); void define_tlb_insn_regs(ARMCPU *cpu); /* Add the cpreg definitions for AT instructions */ void define_at_insn_regs(ARMCPU *cpu); +/* Add the cpreg definitions for PM cpregs */ +void define_pm_cpregs(ARMCPU *cpu); =20 /* Effective value of MDCR_EL2 */ static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env) diff --git a/target/arm/cpregs-pmu.c b/target/arm/cpregs-pmu.c new file mode 100644 index 0000000000..0f295b1376 --- /dev/null +++ b/target/arm/cpregs-pmu.c @@ -0,0 +1,1309 @@ +/* + * QEMU ARM CP Register PMU insns + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/timer.h" +#include "exec/icount.h" +#include "hw/irq.h" +#include "cpu.h" +#include "cpu-features.h" +#include "cpregs.h" +#include "internals.h" + + +#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ + +/* + * Check for traps to performance monitor registers, which are controlled + * by MDCR_EL2.TPM for EL2 and MDCR_EL3.TPM for EL3. + */ +static CPAccessResult access_tpm(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + int el =3D arm_current_el(env); + uint64_t mdcr_el2 =3D arm_mdcr_el2_eff(env); + + if (el < 2 && (mdcr_el2 & MDCR_TPM)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TPM)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; +} + +typedef struct pm_event { + uint16_t number; /* PMEVTYPER.evtCount is 16 bits wide */ + /* If the event is supported on this CPU (used to generate PMCEID[01])= */ + bool (*supported)(CPUARMState *); + /* + * Retrieve the current count of the underlying event. The programmed + * counters hold a difference from the return value from this function + */ + uint64_t (*get_count)(CPUARMState *); + /* + * Return how many nanoseconds it will take (at a minimum) for count e= vents + * to occur. A negative value indicates the counter will never overflo= w, or + * that the counter has otherwise arranged for the overflow bit to be = set + * and the PMU interrupt to be raised on overflow. + */ + int64_t (*ns_per_count)(uint64_t); +} pm_event; + +static bool event_always_supported(CPUARMState *env) +{ + return true; +} + +static uint64_t swinc_get_count(CPUARMState *env) +{ + /* + * SW_INCR events are written directly to the pmevcntr's by writes to + * PMSWINC, so there is no underlying count maintained by the PMU itse= lf + */ + return 0; +} + +static int64_t swinc_ns_per(uint64_t ignored) +{ + return -1; +} + +/* + * Return the underlying cycle count for the PMU cycle counters. If we're = in + * usermode, simply return 0. + */ +static uint64_t cycles_get_count(CPUARMState *env) +{ +#ifndef CONFIG_USER_ONLY + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + ARM_CPU_FREQ, NANOSECONDS_PER_SECOND); +#else + return cpu_get_host_ticks(); +#endif +} + +#ifndef CONFIG_USER_ONLY +static int64_t cycles_ns_per(uint64_t cycles) +{ + return (ARM_CPU_FREQ / NANOSECONDS_PER_SECOND) * cycles; +} + +static bool instructions_supported(CPUARMState *env) +{ + /* Precise instruction counting */ + return icount_enabled() =3D=3D ICOUNT_PRECISE; +} + +static uint64_t instructions_get_count(CPUARMState *env) +{ + assert(icount_enabled() =3D=3D ICOUNT_PRECISE); + return (uint64_t)icount_get_raw(); +} + +static int64_t instructions_ns_per(uint64_t icount) +{ + assert(icount_enabled() =3D=3D ICOUNT_PRECISE); + return icount_to_ns((int64_t)icount); +} +#endif + +static bool pmuv3p1_events_supported(CPUARMState *env) +{ + /* For events which are supported in any v8.1 PMU */ + return cpu_isar_feature(any_pmuv3p1, env_archcpu(env)); +} + +static bool pmuv3p4_events_supported(CPUARMState *env) +{ + /* For events which are supported in any v8.1 PMU */ + return cpu_isar_feature(any_pmuv3p4, env_archcpu(env)); +} + +static uint64_t zero_event_get_count(CPUARMState *env) +{ + /* For events which on QEMU never fire, so their count is always zero = */ + return 0; +} + +static int64_t zero_event_ns_per(uint64_t cycles) +{ + /* An event which never fires can never overflow */ + return -1; +} + +static const pm_event pm_events[] =3D { + { .number =3D 0x000, /* SW_INCR */ + .supported =3D event_always_supported, + .get_count =3D swinc_get_count, + .ns_per_count =3D swinc_ns_per, + }, +#ifndef CONFIG_USER_ONLY + { .number =3D 0x008, /* INST_RETIRED, Instruction architecturally exec= uted */ + .supported =3D instructions_supported, + .get_count =3D instructions_get_count, + .ns_per_count =3D instructions_ns_per, + }, + { .number =3D 0x011, /* CPU_CYCLES, Cycle */ + .supported =3D event_always_supported, + .get_count =3D cycles_get_count, + .ns_per_count =3D cycles_ns_per, + }, +#endif + { .number =3D 0x023, /* STALL_FRONTEND */ + .supported =3D pmuv3p1_events_supported, + .get_count =3D zero_event_get_count, + .ns_per_count =3D zero_event_ns_per, + }, + { .number =3D 0x024, /* STALL_BACKEND */ + .supported =3D pmuv3p1_events_supported, + .get_count =3D zero_event_get_count, + .ns_per_count =3D zero_event_ns_per, + }, + { .number =3D 0x03c, /* STALL */ + .supported =3D pmuv3p4_events_supported, + .get_count =3D zero_event_get_count, + .ns_per_count =3D zero_event_ns_per, + }, +}; + +/* + * Note: Before increasing MAX_EVENT_ID beyond 0x3f into the 0x40xx range = of + * events (i.e. the statistical profiling extension), this implementation + * should first be updated to something sparse instead of the current + * supported_event_map[] array. + */ +#define MAX_EVENT_ID 0x3c +#define UNSUPPORTED_EVENT UINT16_MAX +static uint16_t supported_event_map[MAX_EVENT_ID + 1]; + +/* + * Called upon CPU initialization to initialize PMCEID[01]_EL0 and build a= map + * of ARM event numbers to indices in our pm_events array. + * + * Note: Events in the 0x40XX range are not currently supported. + */ +void pmu_init(ARMCPU *cpu) +{ + unsigned int i; + + /* + * Empty supported_event_map and cpu->pmceid[01] before adding support= ed + * events to them + */ + for (i =3D 0; i < ARRAY_SIZE(supported_event_map); i++) { + supported_event_map[i] =3D UNSUPPORTED_EVENT; + } + cpu->pmceid0 =3D 0; + cpu->pmceid1 =3D 0; + + for (i =3D 0; i < ARRAY_SIZE(pm_events); i++) { + const pm_event *cnt =3D &pm_events[i]; + assert(cnt->number <=3D MAX_EVENT_ID); + /* We do not currently support events in the 0x40xx range */ + assert(cnt->number <=3D 0x3f); + + if (cnt->supported(&cpu->env)) { + supported_event_map[cnt->number] =3D i; + uint64_t event_mask =3D 1ULL << (cnt->number & 0x1f); + if (cnt->number & 0x20) { + cpu->pmceid1 |=3D event_mask; + } else { + cpu->pmceid0 |=3D event_mask; + } + } + } +} + +/* + * Check at runtime whether a PMU event is supported for the current machi= ne + */ +static bool event_supported(uint16_t number) +{ + if (number > MAX_EVENT_ID) { + return false; + } + return supported_event_map[number] !=3D UNSUPPORTED_EVENT; +} + +static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *r= i, + bool isread) +{ + /* + * Performance monitor registers user accessibility is controlled + * by PMUSERENR. MDCR_EL2.TPM and MDCR_EL3.TPM allow configurable + * trapping to EL2 or EL3 for other accesses. + */ + int el =3D arm_current_el(env); + uint64_t mdcr_el2 =3D arm_mdcr_el2_eff(env); + + if (el =3D=3D 0 && !(env->cp15.c9_pmuserenr & 1)) { + return CP_ACCESS_TRAP_EL1; + } + if (el < 2 && (mdcr_el2 & MDCR_TPM)) { + return CP_ACCESS_TRAP_EL2; + } + if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TPM)) { + return CP_ACCESS_TRAP_EL3; + } + + return CP_ACCESS_OK; +} + +static CPAccessResult pmreg_access_xevcntr(CPUARMState *env, + const ARMCPRegInfo *ri, + bool isread) +{ + /* ER: event counter read trap control */ + if (arm_feature(env, ARM_FEATURE_V8) + && arm_current_el(env) =3D=3D 0 + && (env->cp15.c9_pmuserenr & (1 << 3)) !=3D 0 + && isread) { + return CP_ACCESS_OK; + } + + return pmreg_access(env, ri, isread); +} + +static CPAccessResult pmreg_access_swinc(CPUARMState *env, + const ARMCPRegInfo *ri, + bool isread) +{ + /* SW: software increment write trap control */ + if (arm_feature(env, ARM_FEATURE_V8) + && arm_current_el(env) =3D=3D 0 + && (env->cp15.c9_pmuserenr & (1 << 1)) !=3D 0 + && !isread) { + return CP_ACCESS_OK; + } + + return pmreg_access(env, ri, isread); +} + +static CPAccessResult pmreg_access_selr(CPUARMState *env, + const ARMCPRegInfo *ri, + bool isread) +{ + /* ER: event counter read trap control */ + if (arm_feature(env, ARM_FEATURE_V8) + && arm_current_el(env) =3D=3D 0 + && (env->cp15.c9_pmuserenr & (1 << 3)) !=3D 0) { + return CP_ACCESS_OK; + } + + return pmreg_access(env, ri, isread); +} + +static CPAccessResult pmreg_access_ccntr(CPUARMState *env, + const ARMCPRegInfo *ri, + bool isread) +{ + /* CR: cycle counter read trap control */ + if (arm_feature(env, ARM_FEATURE_V8) + && arm_current_el(env) =3D=3D 0 + && (env->cp15.c9_pmuserenr & (1 << 2)) !=3D 0 + && isread) { + return CP_ACCESS_OK; + } + + return pmreg_access(env, ri, isread); +} + +/* + * Returns true if the counter (pass 31 for PMCCNTR) should count events u= sing + * the current EL, security state, and register configuration. + */ +static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter) +{ + uint64_t filter; + bool e, p, u, nsk, nsu, nsh, m; + bool enabled, prohibited =3D false, filtered; + bool secure =3D arm_is_secure(env); + int el =3D arm_current_el(env); + uint64_t mdcr_el2; + uint8_t hpmn; + + /* + * We might be called for M-profile cores where MDCR_EL2 doesn't + * exist and arm_mdcr_el2_eff() will assert, so this early-exit check + * must be before we read that value. + */ + if (!arm_feature(env, ARM_FEATURE_PMU)) { + return false; + } + + mdcr_el2 =3D arm_mdcr_el2_eff(env); + hpmn =3D mdcr_el2 & MDCR_HPMN; + + if (!arm_feature(env, ARM_FEATURE_EL2) || + (counter < hpmn || counter =3D=3D 31)) { + e =3D env->cp15.c9_pmcr & PMCRE; + } else { + e =3D mdcr_el2 & MDCR_HPME; + } + enabled =3D e && (env->cp15.c9_pmcnten & (1 << counter)); + + /* Is event counting prohibited? */ + if (el =3D=3D 2 && (counter < hpmn || counter =3D=3D 31)) { + prohibited =3D mdcr_el2 & MDCR_HPMD; + } + if (secure) { + prohibited =3D prohibited || !(env->cp15.mdcr_el3 & MDCR_SPME); + } + + if (counter =3D=3D 31) { + /* + * The cycle counter defaults to running. PMCR.DP says "disable + * the cycle counter when event counting is prohibited". + * Some MDCR bits disable the cycle counter specifically. + */ + prohibited =3D prohibited && env->cp15.c9_pmcr & PMCRDP; + if (cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { + if (secure) { + prohibited =3D prohibited || (env->cp15.mdcr_el3 & MDCR_SC= CD); + } + if (el =3D=3D 2) { + prohibited =3D prohibited || (mdcr_el2 & MDCR_HCCD); + } + } + } + + if (counter =3D=3D 31) { + filter =3D env->cp15.pmccfiltr_el0; + } else { + filter =3D env->cp15.c14_pmevtyper[counter]; + } + + p =3D filter & PMXEVTYPER_P; + u =3D filter & PMXEVTYPER_U; + nsk =3D arm_feature(env, ARM_FEATURE_EL3) && (filter & PMXEVTYPER_NSK); + nsu =3D arm_feature(env, ARM_FEATURE_EL3) && (filter & PMXEVTYPER_NSU); + nsh =3D arm_feature(env, ARM_FEATURE_EL2) && (filter & PMXEVTYPER_NSH); + m =3D arm_el_is_aa64(env, 1) && + arm_feature(env, ARM_FEATURE_EL3) && (filter & PMXEVTYPER_M); + + if (el =3D=3D 0) { + filtered =3D secure ? u : u !=3D nsu; + } else if (el =3D=3D 1) { + filtered =3D secure ? p : p !=3D nsk; + } else if (el =3D=3D 2) { + filtered =3D !nsh; + } else { /* EL3 */ + filtered =3D m !=3D p; + } + + if (counter !=3D 31) { + /* + * If not checking PMCCNTR, ensure the counter is setup to an even= t we + * support + */ + uint16_t event =3D filter & PMXEVTYPER_EVTCOUNT; + if (!event_supported(event)) { + return false; + } + } + + return enabled && !prohibited && !filtered; +} + +static void pmu_update_irq(CPUARMState *env) +{ + ARMCPU *cpu =3D env_archcpu(env); + qemu_set_irq(cpu->pmu_interrupt, (env->cp15.c9_pmcr & PMCRE) && + (env->cp15.c9_pminten & env->cp15.c9_pmovsr)); +} + +static bool pmccntr_clockdiv_enabled(CPUARMState *env) +{ + /* + * Return true if the clock divider is enabled and the cycle counter + * is supposed to tick only once every 64 clock cycles. This is + * controlled by PMCR.D, but if PMCR.LC is set to enable the long + * (64-bit) cycle counter PMCR.D has no effect. + */ + return (env->cp15.c9_pmcr & (PMCRD | PMCRLC)) =3D=3D PMCRD; +} + +static bool pmevcntr_is_64_bit(CPUARMState *env, int counter) +{ + /* Return true if the specified event counter is configured to be 64 b= it */ + + /* This isn't intended to be used with the cycle counter */ + assert(counter < 31); + + if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { + return false; + } + + if (arm_feature(env, ARM_FEATURE_EL2)) { + /* + * MDCR_EL2.HLP still applies even when EL2 is disabled in the + * current security state, so we don't use arm_mdcr_el2_eff() here. + */ + bool hlp =3D env->cp15.mdcr_el2 & MDCR_HLP; + int hpmn =3D env->cp15.mdcr_el2 & MDCR_HPMN; + + if (counter >=3D hpmn) { + return hlp; + } + } + return env->cp15.c9_pmcr & PMCRLP; +} + +/* + * Ensure c15_ccnt is the guest-visible count so that operations such as + * enabling/disabling the counter or filtering, modifying the count itself, + * etc. can be done logically. This is essentially a no-op if the counter = is + * not enabled at the time of the call. + */ +static void pmccntr_op_start(CPUARMState *env) +{ + uint64_t cycles =3D cycles_get_count(env); + + if (pmu_counter_enabled(env, 31)) { + uint64_t eff_cycles =3D cycles; + if (pmccntr_clockdiv_enabled(env)) { + eff_cycles /=3D 64; + } + + uint64_t new_pmccntr =3D eff_cycles - env->cp15.c15_ccnt_delta; + + uint64_t overflow_mask =3D env->cp15.c9_pmcr & PMCRLC ? \ + 1ull << 63 : 1ull << 31; + if (env->cp15.c15_ccnt & ~new_pmccntr & overflow_mask) { + env->cp15.c9_pmovsr |=3D (1ULL << 31); + pmu_update_irq(env); + } + + env->cp15.c15_ccnt =3D new_pmccntr; + } + env->cp15.c15_ccnt_delta =3D cycles; +} + +/* + * If PMCCNTR is enabled, recalculate the delta between the clock and the + * guest-visible count. A call to pmccntr_op_finish should follow every ca= ll to + * pmccntr_op_start. + */ +static void pmccntr_op_finish(CPUARMState *env) +{ + if (pmu_counter_enabled(env, 31)) { +#ifndef CONFIG_USER_ONLY + /* Calculate when the counter will next overflow */ + uint64_t remaining_cycles =3D -env->cp15.c15_ccnt; + if (!(env->cp15.c9_pmcr & PMCRLC)) { + remaining_cycles =3D (uint32_t)remaining_cycles; + } + int64_t overflow_in =3D cycles_ns_per(remaining_cycles); + + if (overflow_in > 0) { + int64_t overflow_at; + + if (!sadd64_overflow(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + overflow_in, &overflow_at)) { + ARMCPU *cpu =3D env_archcpu(env); + timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); + } + } +#endif + + uint64_t prev_cycles =3D env->cp15.c15_ccnt_delta; + if (pmccntr_clockdiv_enabled(env)) { + prev_cycles /=3D 64; + } + env->cp15.c15_ccnt_delta =3D prev_cycles - env->cp15.c15_ccnt; + } +} + +static void pmevcntr_op_start(CPUARMState *env, uint8_t counter) +{ + + uint16_t event =3D env->cp15.c14_pmevtyper[counter] & PMXEVTYPER_EVTCO= UNT; + uint64_t count =3D 0; + if (event_supported(event)) { + uint16_t event_idx =3D supported_event_map[event]; + count =3D pm_events[event_idx].get_count(env); + } + + if (pmu_counter_enabled(env, counter)) { + uint64_t new_pmevcntr =3D count - env->cp15.c14_pmevcntr_delta[cou= nter]; + uint64_t overflow_mask =3D pmevcntr_is_64_bit(env, counter) ? + 1ULL << 63 : 1ULL << 31; + + if (env->cp15.c14_pmevcntr[counter] & ~new_pmevcntr & overflow_mas= k) { + env->cp15.c9_pmovsr |=3D (1 << counter); + pmu_update_irq(env); + } + env->cp15.c14_pmevcntr[counter] =3D new_pmevcntr; + } + env->cp15.c14_pmevcntr_delta[counter] =3D count; +} + +static void pmevcntr_op_finish(CPUARMState *env, uint8_t counter) +{ + if (pmu_counter_enabled(env, counter)) { +#ifndef CONFIG_USER_ONLY + uint16_t event =3D env->cp15.c14_pmevtyper[counter] & PMXEVTYPER_E= VTCOUNT; + uint16_t event_idx =3D supported_event_map[event]; + uint64_t delta =3D -(env->cp15.c14_pmevcntr[counter] + 1); + int64_t overflow_in; + + if (!pmevcntr_is_64_bit(env, counter)) { + delta =3D (uint32_t)delta; + } + overflow_in =3D pm_events[event_idx].ns_per_count(delta); + + if (overflow_in > 0) { + int64_t overflow_at; + + if (!sadd64_overflow(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + overflow_in, &overflow_at)) { + ARMCPU *cpu =3D env_archcpu(env); + timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); + } + } +#endif + + env->cp15.c14_pmevcntr_delta[counter] -=3D + env->cp15.c14_pmevcntr[counter]; + } +} + +void pmu_op_start(CPUARMState *env) +{ + unsigned int i; + pmccntr_op_start(env); + for (i =3D 0; i < pmu_num_counters(env); i++) { + pmevcntr_op_start(env, i); + } +} + +void pmu_op_finish(CPUARMState *env) +{ + unsigned int i; + pmccntr_op_finish(env); + for (i =3D 0; i < pmu_num_counters(env); i++) { + pmevcntr_op_finish(env, i); + } +} + +void pmu_pre_el_change(ARMCPU *cpu, void *ignored) +{ + pmu_op_start(&cpu->env); +} + +void pmu_post_el_change(ARMCPU *cpu, void *ignored) +{ + pmu_op_finish(&cpu->env); +} + +void arm_pmu_timer_cb(void *opaque) +{ + ARMCPU *cpu =3D opaque; + + /* + * Update all the counter values based on the current underlying count= s, + * triggering interrupts to be raised, if necessary. pmu_op_finish() a= lso + * has the effect of setting the cpu->pmu_timer to the next earliest t= ime a + * counter may expire. + */ + pmu_op_start(&cpu->env); + pmu_op_finish(&cpu->env); +} + +static void pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + pmu_op_start(env); + + if (value & PMCRC) { + /* The counter has been reset */ + env->cp15.c15_ccnt =3D 0; + } + + if (value & PMCRP) { + unsigned int i; + for (i =3D 0; i < pmu_num_counters(env); i++) { + env->cp15.c14_pmevcntr[i] =3D 0; + } + } + + env->cp15.c9_pmcr &=3D ~PMCR_WRITABLE_MASK; + env->cp15.c9_pmcr |=3D (value & PMCR_WRITABLE_MASK); + + pmu_op_finish(env); +} + +static uint64_t pmcr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + uint64_t pmcr =3D env->cp15.c9_pmcr; + + /* + * If EL2 is implemented and enabled for the current security state, r= eads + * of PMCR.N from EL1 or EL0 return the value of MDCR_EL2.HPMN or HDCR= .HPMN. + */ + if (arm_current_el(env) <=3D 1 && arm_is_el2_enabled(env)) { + pmcr &=3D ~PMCRN_MASK; + pmcr |=3D (env->cp15.mdcr_el2 & MDCR_HPMN) << PMCRN_SHIFT; + } + + return pmcr; +} + +static void pmswinc_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + unsigned int i; + uint64_t overflow_mask, new_pmswinc; + + for (i =3D 0; i < pmu_num_counters(env); i++) { + /* Increment a counter's count iff: */ + if ((value & (1 << i)) && /* counter's bit is set */ + /* counter is enabled and not filtered */ + pmu_counter_enabled(env, i) && + /* counter is SW_INCR */ + (env->cp15.c14_pmevtyper[i] & PMXEVTYPER_EVTCOUNT) =3D=3D = 0x0) { + pmevcntr_op_start(env, i); + + /* + * Detect if this write causes an overflow since we can't pred= ict + * PMSWINC overflows like we can for other events + */ + new_pmswinc =3D env->cp15.c14_pmevcntr[i] + 1; + + overflow_mask =3D pmevcntr_is_64_bit(env, i) ? + 1ULL << 63 : 1ULL << 31; + + if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & overflow_mask) { + env->cp15.c9_pmovsr |=3D (1 << i); + pmu_update_irq(env); + } + + env->cp15.c14_pmevcntr[i] =3D new_pmswinc; + + pmevcntr_op_finish(env, i); + } + } +} + +static uint64_t pmccntr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + uint64_t ret; + pmccntr_op_start(env); + ret =3D env->cp15.c15_ccnt; + pmccntr_op_finish(env); + return ret; +} + +static void pmselr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* + * The value of PMSELR.SEL affects the behavior of PMXEVTYPER and + * PMXEVCNTR. We allow [0..31] to be written to PMSELR here; in the + * meanwhile, we check PMSELR.SEL when PMXEVTYPER and PMXEVCNTR are + * accessed. + */ + env->cp15.c9_pmselr =3D value & 0x1f; +} + +static void pmccntr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + pmccntr_op_start(env); + env->cp15.c15_ccnt =3D value; + pmccntr_op_finish(env); +} + +static void pmccntr_write32(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + uint64_t cur_val =3D pmccntr_read(env, NULL); + + pmccntr_write(env, ri, deposit64(cur_val, 0, 32, value)); +} + +static void pmccfiltr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + pmccntr_op_start(env); + env->cp15.pmccfiltr_el0 =3D value & PMCCFILTR_EL0; + pmccntr_op_finish(env); +} + +static void pmccfiltr_write_a32(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + pmccntr_op_start(env); + /* M is not accessible from AArch32 */ + env->cp15.pmccfiltr_el0 =3D (env->cp15.pmccfiltr_el0 & PMCCFILTR_M) | + (value & PMCCFILTR); + pmccntr_op_finish(env); +} + +static uint64_t pmccfiltr_read_a32(CPUARMState *env, const ARMCPRegInfo *r= i) +{ + /* M is not visible in AArch32 */ + return env->cp15.pmccfiltr_el0 & PMCCFILTR; +} + +static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + pmu_op_start(env); + value &=3D pmu_counter_mask(env); + env->cp15.c9_pmcnten |=3D value; + pmu_op_finish(env); +} + +static void pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + pmu_op_start(env); + value &=3D pmu_counter_mask(env); + env->cp15.c9_pmcnten &=3D ~value; + pmu_op_finish(env); +} + +static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + value &=3D pmu_counter_mask(env); + env->cp15.c9_pmovsr &=3D ~value; + pmu_update_irq(env); +} + +static void pmovsset_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + value &=3D pmu_counter_mask(env); + env->cp15.c9_pmovsr |=3D value; + pmu_update_irq(env); +} + +static void pmevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value, const uint8_t counter) +{ + if (counter =3D=3D 31) { + pmccfiltr_write(env, ri, value); + } else if (counter < pmu_num_counters(env)) { + pmevcntr_op_start(env, counter); + + /* + * If this counter's event type is changing, store the current + * underlying count for the new type in c14_pmevcntr_delta[counter= ] so + * pmevcntr_op_finish has the correct baseline when it converts ba= ck to + * a delta. + */ + uint16_t old_event =3D env->cp15.c14_pmevtyper[counter] & + PMXEVTYPER_EVTCOUNT; + uint16_t new_event =3D value & PMXEVTYPER_EVTCOUNT; + if (old_event !=3D new_event) { + uint64_t count =3D 0; + if (event_supported(new_event)) { + uint16_t event_idx =3D supported_event_map[new_event]; + count =3D pm_events[event_idx].get_count(env); + } + env->cp15.c14_pmevcntr_delta[counter] =3D count; + } + + env->cp15.c14_pmevtyper[counter] =3D value & PMXEVTYPER_MASK; + pmevcntr_op_finish(env, counter); + } + /* + * Attempts to access PMXEVTYPER are CONSTRAINED UNPREDICTABLE when + * PMSELR value is equal to or greater than the number of implemented + * counters, but not equal to 0x1f. We opt to behave as a RAZ/WI. + */ +} + +static uint64_t pmevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri, + const uint8_t counter) +{ + if (counter =3D=3D 31) { + return env->cp15.pmccfiltr_el0; + } else if (counter < pmu_num_counters(env)) { + return env->cp15.c14_pmevtyper[counter]; + } else { + /* + * We opt to behave as a RAZ/WI when attempts to access PMXEVTYPER + * are CONSTRAINED UNPREDICTABLE. See comments in pmevtyper_write(). + */ + return 0; + } +} + +static void pmevtyper_writefn(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + pmevtyper_write(env, ri, value, counter); +} + +static void pmevtyper_rawwrite(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + env->cp15.c14_pmevtyper[counter] =3D value; + + /* + * pmevtyper_rawwrite is called between a pair of pmu_op_start and + * pmu_op_finish calls when loading saved state for a migration. Becau= se + * we're potentially updating the type of event here, the value writte= n to + * c14_pmevcntr_delta by the preceding pmu_op_start call may be for a + * different counter type. Therefore, we need to set this value to the + * current count for the counter type we're writing so that pmu_op_fin= ish + * has the correct count for its calculation. + */ + uint16_t event =3D value & PMXEVTYPER_EVTCOUNT; + if (event_supported(event)) { + uint16_t event_idx =3D supported_event_map[event]; + env->cp15.c14_pmevcntr_delta[counter] =3D + pm_events[event_idx].get_count(env); + } +} + +static uint64_t pmevtyper_readfn(CPUARMState *env, const ARMCPRegInfo *ri) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + return pmevtyper_read(env, ri, counter); +} + +static void pmxevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + pmevtyper_write(env, ri, value, env->cp15.c9_pmselr & 31); +} + +static uint64_t pmxevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return pmevtyper_read(env, ri, env->cp15.c9_pmselr & 31); +} + +static void pmevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value, uint8_t counter) +{ + if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { + /* Before FEAT_PMUv3p5, top 32 bits of event counters are RES0 */ + value &=3D MAKE_64BIT_MASK(0, 32); + } + if (counter < pmu_num_counters(env)) { + pmevcntr_op_start(env, counter); + env->cp15.c14_pmevcntr[counter] =3D value; + pmevcntr_op_finish(env, counter); + } + /* + * We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR + * are CONSTRAINED UNPREDICTABLE. + */ +} + +static uint64_t pmevcntr_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint8_t counter) +{ + if (counter < pmu_num_counters(env)) { + uint64_t ret; + pmevcntr_op_start(env, counter); + ret =3D env->cp15.c14_pmevcntr[counter]; + pmevcntr_op_finish(env, counter); + if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { + /* Before FEAT_PMUv3p5, top 32 bits of event counters are RES0= */ + ret &=3D MAKE_64BIT_MASK(0, 32); + } + return ret; + } else { + /* + * We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR + * are CONSTRAINED UNPREDICTABLE. + */ + return 0; + } +} + +static void pmevcntr_writefn(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + pmevcntr_write(env, ri, value, counter); +} + +static uint64_t pmevcntr_readfn(CPUARMState *env, const ARMCPRegInfo *ri) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + return pmevcntr_read(env, ri, counter); +} + +static void pmevcntr_rawwrite(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + assert(counter < pmu_num_counters(env)); + env->cp15.c14_pmevcntr[counter] =3D value; + pmevcntr_write(env, ri, value, counter); +} + +static uint64_t pmevcntr_rawread(CPUARMState *env, const ARMCPRegInfo *ri) +{ + uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); + assert(counter < pmu_num_counters(env)); + return env->cp15.c14_pmevcntr[counter]; +} + +static void pmxevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + pmevcntr_write(env, ri, value, env->cp15.c9_pmselr & 31); +} + +static uint64_t pmxevcntr_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return pmevcntr_read(env, ri, env->cp15.c9_pmselr & 31); +} + +static void pmuserenr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + if (arm_feature(env, ARM_FEATURE_V8)) { + env->cp15.c9_pmuserenr =3D value & 0xf; + } else { + env->cp15.c9_pmuserenr =3D value & 1; + } +} + +static void pmintenset_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* We have no event counters so only the C bit can be changed */ + value &=3D pmu_counter_mask(env); + env->cp15.c9_pminten |=3D value; + pmu_update_irq(env); +} + +static void pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + value &=3D pmu_counter_mask(env); + env->cp15.c9_pminten &=3D ~value; + pmu_update_irq(env); +} + +static const ARMCPRegInfo v7_pm_reginfo[] =3D { + /* + * Performance monitors are implementation defined in v7, + * but with an ARM recommended set of registers, which we + * follow. + * + * Performance registers fall into three categories: + * (a) always UNDEF in PL0, RW in PL1 (PMINTENSET, PMINTENCLR) + * (b) RO in PL0 (ie UNDEF on write), RW in PL1 (PMUSERENR) + * (c) UNDEF in PL0 if PMUSERENR.EN=3D=3D0, otherwise accessible (all= others) + * For the cases controlled by PMUSERENR we must set .access to PL0_RW + * or PL0_RO as appropriate and then check PMUSERENR in the helper fn. + */ + { .name =3D "PMCNTENSET", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 = =3D 0, .opc2 =3D 1, + .access =3D PL0_RW, .type =3D ARM_CP_ALIAS | ARM_CP_IO, + .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmcnten), + .writefn =3D pmcntenset_write, + .accessfn =3D pmreg_access, + .fgt =3D FGT_PMCNTEN, + .raw_writefn =3D raw_write }, + { .name =3D "PMCNTENSET_EL0", .state =3D ARM_CP_STATE_AA64, .type =3D = ARM_CP_IO, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 1, + .access =3D PL0_RW, .accessfn =3D pmreg_access, + .fgt =3D FGT_PMCNTEN, + .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmcnten), .resetvalue= =3D 0, + .writefn =3D pmcntenset_write, .raw_writefn =3D raw_write }, + { .name =3D "PMCNTENCLR", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 = =3D 0, .opc2 =3D 2, + .access =3D PL0_RW, + .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmcnten), + .accessfn =3D pmreg_access, + .fgt =3D FGT_PMCNTEN, + .writefn =3D pmcntenclr_write, .raw_writefn =3D raw_write, + .type =3D ARM_CP_ALIAS | ARM_CP_IO }, + { .name =3D "PMCNTENCLR_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 2, + .access =3D PL0_RW, .accessfn =3D pmreg_access, + .fgt =3D FGT_PMCNTEN, + .type =3D ARM_CP_ALIAS | ARM_CP_IO, + .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmcnten), + .writefn =3D pmcntenclr_write, .raw_writefn =3D raw_write }, + { .name =3D "PMOVSR", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 =3D 0= , .opc2 =3D 3, + .access =3D PL0_RW, .type =3D ARM_CP_IO, + .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmovsr), + .accessfn =3D pmreg_access, + .fgt =3D FGT_PMOVS, + .writefn =3D pmovsr_write, + .raw_writefn =3D raw_write }, + { .name =3D "PMOVSCLR_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 3, + .access =3D PL0_RW, .accessfn =3D pmreg_access, + .fgt =3D FGT_PMOVS, + .type =3D ARM_CP_ALIAS | ARM_CP_IO, + .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmovsr), + .writefn =3D pmovsr_write, + .raw_writefn =3D raw_write }, + { .name =3D "PMSWINC", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 =3D = 0, .opc2 =3D 4, + .access =3D PL0_W, .accessfn =3D pmreg_access_swinc, + .fgt =3D FGT_PMSWINC_EL0, + .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .writefn =3D pmswinc_write }, + { .name =3D "PMSWINC_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 4, + .access =3D PL0_W, .accessfn =3D pmreg_access_swinc, + .fgt =3D FGT_PMSWINC_EL0, + .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .writefn =3D pmswinc_write }, + { .name =3D "PMSELR", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 =3D 0= , .opc2 =3D 5, + .access =3D PL0_RW, .type =3D ARM_CP_ALIAS, + .fgt =3D FGT_PMSELR_EL0, + .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmselr), + .accessfn =3D pmreg_access_selr, .writefn =3D pmselr_write, + .raw_writefn =3D raw_write}, + { .name =3D "PMSELR_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 5, + .access =3D PL0_RW, .accessfn =3D pmreg_access_selr, + .fgt =3D FGT_PMSELR_EL0, + .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmselr), + .writefn =3D pmselr_write, .raw_writefn =3D raw_write, }, + { .name =3D "PMCCNTR", .cp =3D 15, .crn =3D 9, .crm =3D 13, .opc1 =3D = 0, .opc2 =3D 0, + .access =3D PL0_RW, .resetvalue =3D 0, .type =3D ARM_CP_ALIAS | ARM_= CP_IO, + .fgt =3D FGT_PMCCNTR_EL0, + .readfn =3D pmccntr_read, .writefn =3D pmccntr_write32, + .accessfn =3D pmreg_access_ccntr }, + { .name =3D "PMCCNTR_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 13, .opc2 =3D 0, + .access =3D PL0_RW, .accessfn =3D pmreg_access_ccntr, + .fgt =3D FGT_PMCCNTR_EL0, + .type =3D ARM_CP_IO, + .fieldoffset =3D offsetof(CPUARMState, cp15.c15_ccnt), + .readfn =3D pmccntr_read, .writefn =3D pmccntr_write, + .raw_readfn =3D raw_read, .raw_writefn =3D raw_write, }, + { .name =3D "PMCCFILTR", .cp =3D 15, .opc1 =3D 0, .crn =3D 14, .crm = =3D 15, .opc2 =3D 7, + .writefn =3D pmccfiltr_write_a32, .readfn =3D pmccfiltr_read_a32, + .access =3D PL0_RW, .accessfn =3D pmreg_access, + .fgt =3D FGT_PMCCFILTR_EL0, + .type =3D ARM_CP_ALIAS | ARM_CP_IO, + .resetvalue =3D 0, }, + { .name =3D "PMCCFILTR_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 14, .crm =3D 15, .opc2 =3D 7, + .writefn =3D pmccfiltr_write, .raw_writefn =3D raw_write, + .access =3D PL0_RW, .accessfn =3D pmreg_access, + .fgt =3D FGT_PMCCFILTR_EL0, + .type =3D ARM_CP_IO, + .fieldoffset =3D offsetof(CPUARMState, cp15.pmccfiltr_el0), + .resetvalue =3D 0, }, + { .name =3D "PMXEVTYPER", .cp =3D 15, .crn =3D 9, .crm =3D 13, .opc1 = =3D 0, .opc2 =3D 1, + .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .accessfn =3D pmreg_access, + .fgt =3D FGT_PMEVTYPERN_EL0, + .writefn =3D pmxevtyper_write, .readfn =3D pmxevtyper_read }, + { .name =3D "PMXEVTYPER_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 13, .opc2 =3D 1, + .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .accessfn =3D pmreg_access, + .fgt =3D FGT_PMEVTYPERN_EL0, + .writefn =3D pmxevtyper_write, .readfn =3D pmxevtyper_read }, + { .name =3D "PMXEVCNTR", .cp =3D 15, .crn =3D 9, .crm =3D 13, .opc1 = =3D 0, .opc2 =3D 2, + .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .accessfn =3D pmreg_access_xevcntr, + .fgt =3D FGT_PMEVCNTRN_EL0, + .writefn =3D pmxevcntr_write, .readfn =3D pmxevcntr_read }, + { .name =3D "PMXEVCNTR_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 13, .opc2 =3D 2, + .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, + .accessfn =3D pmreg_access_xevcntr, + .fgt =3D FGT_PMEVCNTRN_EL0, + .writefn =3D pmxevcntr_write, .readfn =3D pmxevcntr_read }, + { .name =3D "PMUSERENR", .cp =3D 15, .crn =3D 9, .crm =3D 14, .opc1 = =3D 0, .opc2 =3D 0, + .access =3D PL0_R | PL1_RW, .accessfn =3D access_tpm, + .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmuserenr), + .resetvalue =3D 0, + .writefn =3D pmuserenr_write, .raw_writefn =3D raw_write }, + { .name =3D "PMUSERENR_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 14, .opc2 =3D 0, + .access =3D PL0_R | PL1_RW, .accessfn =3D access_tpm, .type =3D ARM_= CP_ALIAS, + .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmuserenr), + .resetvalue =3D 0, + .writefn =3D pmuserenr_write, .raw_writefn =3D raw_write }, + { .name =3D "PMINTENSET", .cp =3D 15, .crn =3D 9, .crm =3D 14, .opc1 = =3D 0, .opc2 =3D 1, + .access =3D PL1_RW, .accessfn =3D access_tpm, + .fgt =3D FGT_PMINTEN, + .type =3D ARM_CP_ALIAS | ARM_CP_IO, + .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pminten), + .resetvalue =3D 0, + .writefn =3D pmintenset_write, .raw_writefn =3D raw_write }, + { .name =3D "PMINTENSET_EL1", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 0, .crn =3D 9, .crm =3D 14, .opc2 =3D 1, + .access =3D PL1_RW, .accessfn =3D access_tpm, + .fgt =3D FGT_PMINTEN, + .type =3D ARM_CP_IO, + .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pminten), + .writefn =3D pmintenset_write, .raw_writefn =3D raw_write, + .resetvalue =3D 0x0 }, + { .name =3D "PMINTENCLR", .cp =3D 15, .crn =3D 9, .crm =3D 14, .opc1 = =3D 0, .opc2 =3D 2, + .access =3D PL1_RW, .accessfn =3D access_tpm, + .fgt =3D FGT_PMINTEN, + .type =3D ARM_CP_ALIAS | ARM_CP_IO, + .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pminten), + .writefn =3D pmintenclr_write, .raw_writefn =3D raw_write }, + { .name =3D "PMINTENCLR_EL1", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 0, .crn =3D 9, .crm =3D 14, .opc2 =3D 2, + .access =3D PL1_RW, .accessfn =3D access_tpm, + .fgt =3D FGT_PMINTEN, + .type =3D ARM_CP_ALIAS | ARM_CP_IO, + .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pminten), + .writefn =3D pmintenclr_write, .raw_writefn =3D raw_write }, +}; + +static const ARMCPRegInfo pmovsset_cp_reginfo[] =3D { + /* PMOVSSET is not implemented in v7 before v7ve */ + { .name =3D "PMOVSSET", .cp =3D 15, .opc1 =3D 0, .crn =3D 9, .crm =3D = 14, .opc2 =3D 3, + .access =3D PL0_RW, .accessfn =3D pmreg_access, + .fgt =3D FGT_PMOVS, + .type =3D ARM_CP_ALIAS | ARM_CP_IO, + .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmovsr), + .writefn =3D pmovsset_write, + .raw_writefn =3D raw_write }, + { .name =3D "PMOVSSET_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 14, .opc2 =3D 3, + .access =3D PL0_RW, .accessfn =3D pmreg_access, + .fgt =3D FGT_PMOVS, + .type =3D ARM_CP_ALIAS | ARM_CP_IO, + .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmovsr), + .writefn =3D pmovsset_write, + .raw_writefn =3D raw_write }, +}; + +void define_pm_cpregs(ARMCPU *cpu) +{ + CPUARMState *env =3D &cpu->env; + + if (arm_feature(env, ARM_FEATURE_V7)) { + /* + * v7 performance monitor control register: same implementor + * field as main ID register, and we implement four counters in + * addition to the cycle count register. + */ + static const ARMCPRegInfo pmcr =3D { + .name =3D "PMCR", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 = =3D 0, .opc2 =3D 0, + .access =3D PL0_RW, + .fgt =3D FGT_PMCR_EL0, + .type =3D ARM_CP_IO | ARM_CP_ALIAS, + .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmcr), + .accessfn =3D pmreg_access, + .readfn =3D pmcr_read, .raw_readfn =3D raw_read, + .writefn =3D pmcr_write, .raw_writefn =3D raw_write, + }; + const ARMCPRegInfo pmcr64 =3D { + .name =3D "PMCR_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 0, + .access =3D PL0_RW, .accessfn =3D pmreg_access, + .fgt =3D FGT_PMCR_EL0, + .type =3D ARM_CP_IO, + .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmcr), + .resetvalue =3D cpu->isar.reset_pmcr_el0, + .readfn =3D pmcr_read, .raw_readfn =3D raw_read, + .writefn =3D pmcr_write, .raw_writefn =3D raw_write, + }; + + define_one_arm_cp_reg(cpu, &pmcr); + define_one_arm_cp_reg(cpu, &pmcr64); + define_arm_cp_regs(cpu, v7_pm_reginfo); + + for (unsigned i =3D 0, pmcrn =3D pmu_num_counters(env); i < pmcrn;= i++) { + g_autofree char *pmevcntr_name =3D g_strdup_printf("PMEVCNTR%d= ", i); + g_autofree char *pmevcntr_el0_name =3D g_strdup_printf("PMEVCN= TR%d_EL0", i); + g_autofree char *pmevtyper_name =3D g_strdup_printf("PMEVTYPER= %d", i); + g_autofree char *pmevtyper_el0_name =3D g_strdup_printf("PMEVT= YPER%d_EL0", i); + + ARMCPRegInfo pmev_regs[] =3D { + { .name =3D pmevcntr_name, .cp =3D 15, .crn =3D 14, + .crm =3D 8 | (3 & (i >> 3)), .opc1 =3D 0, .opc2 =3D i & = 7, + .access =3D PL0_RW, .type =3D ARM_CP_IO | ARM_CP_ALIAS, + .fgt =3D FGT_PMEVCNTRN_EL0, + .readfn =3D pmevcntr_readfn, .writefn =3D pmevcntr_write= fn, + .accessfn =3D pmreg_access_xevcntr }, + { .name =3D pmevcntr_el0_name, .state =3D ARM_CP_STATE_AA6= 4, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 14, .crm =3D 8 | (3 &= (i >> 3)), + .opc2 =3D i & 7, .access =3D PL0_RW, .accessfn =3D pmreg= _access_xevcntr, + .type =3D ARM_CP_IO, + .fgt =3D FGT_PMEVCNTRN_EL0, + .readfn =3D pmevcntr_readfn, .writefn =3D pmevcntr_write= fn, + .raw_readfn =3D pmevcntr_rawread, + .raw_writefn =3D pmevcntr_rawwrite }, + { .name =3D pmevtyper_name, .cp =3D 15, .crn =3D 14, + .crm =3D 12 | (3 & (i >> 3)), .opc1 =3D 0, .opc2 =3D i &= 7, + .access =3D PL0_RW, .type =3D ARM_CP_IO | ARM_CP_ALIAS, + .fgt =3D FGT_PMEVTYPERN_EL0, + .readfn =3D pmevtyper_readfn, .writefn =3D pmevtyper_wri= tefn, + .accessfn =3D pmreg_access }, + { .name =3D pmevtyper_el0_name, .state =3D ARM_CP_STATE_AA= 64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 14, .crm =3D 12 | (3 = & (i >> 3)), + .opc2 =3D i & 7, .access =3D PL0_RW, .accessfn =3D pmreg= _access, + .fgt =3D FGT_PMEVTYPERN_EL0, + .type =3D ARM_CP_IO, + .readfn =3D pmevtyper_readfn, .writefn =3D pmevtyper_wri= tefn, + .raw_writefn =3D pmevtyper_rawwrite }, + }; + define_arm_cp_regs(cpu, pmev_regs); + } + } + if (arm_feature(env, ARM_FEATURE_V7VE)) { + define_arm_cp_regs(cpu, pmovsset_cp_reginfo); + } + + if (arm_feature(env, ARM_FEATURE_V8)) { + const ARMCPRegInfo v8_pm_reginfo[] =3D { + { .name =3D "PMCEID0", .state =3D ARM_CP_STATE_AA32, + .cp =3D 15, .opc1 =3D 0, .crn =3D 9, .crm =3D 12, .opc2 =3D = 6, + .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, + .fgt =3D FGT_PMCEIDN_EL0, + .resetvalue =3D extract64(cpu->pmceid0, 0, 32) }, + { .name =3D "PMCEID0_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D= 6, + .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, + .fgt =3D FGT_PMCEIDN_EL0, + .resetvalue =3D cpu->pmceid0 }, + { .name =3D "PMCEID1", .state =3D ARM_CP_STATE_AA32, + .cp =3D 15, .opc1 =3D 0, .crn =3D 9, .crm =3D 12, .opc2 =3D = 7, + .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, + .fgt =3D FGT_PMCEIDN_EL0, + .resetvalue =3D extract64(cpu->pmceid1, 0, 32) }, + { .name =3D "PMCEID1_EL0", .state =3D ARM_CP_STATE_AA64, + .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D= 7, + .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, + .fgt =3D FGT_PMCEIDN_EL0, + .resetvalue =3D cpu->pmceid1 }, + }; + define_arm_cp_regs(cpu, v8_pm_reginfo); + } + + if (cpu_isar_feature(aa32_pmuv3p1, cpu)) { + ARMCPRegInfo v81_pmu_regs[] =3D { + { .name =3D "PMCEID2", .state =3D ARM_CP_STATE_AA32, + .cp =3D 15, .opc1 =3D 0, .crn =3D 9, .crm =3D 14, .opc2 =3D = 4, + .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, + .fgt =3D FGT_PMCEIDN_EL0, + .resetvalue =3D extract64(cpu->pmceid0, 32, 32) }, + { .name =3D "PMCEID3", .state =3D ARM_CP_STATE_AA32, + .cp =3D 15, .opc1 =3D 0, .crn =3D 9, .crm =3D 14, .opc2 =3D = 5, + .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, + .fgt =3D FGT_PMCEIDN_EL0, + .resetvalue =3D extract64(cpu->pmceid1, 32, 32) }, + }; + define_arm_cp_regs(cpu, v81_pmu_regs); + } + + if (cpu_isar_feature(any_pmuv3p4, cpu)) { + static const ARMCPRegInfo v84_pmmir =3D { + .name =3D "PMMIR_EL1", .state =3D ARM_CP_STATE_BOTH, + .opc0 =3D 3, .opc1 =3D 0, .crn =3D 9, .crm =3D 14, .opc2 =3D 6, + .access =3D PL1_R, .accessfn =3D pmreg_access, .type =3D ARM_C= P_CONST, + .fgt =3D FGT_PMMIR_EL1, + .resetvalue =3D 0 + }; + define_one_arm_cp_reg(cpu, &v84_pmmir); + } +} diff --git a/target/arm/helper.c b/target/arm/helper.c index 9680136b3d..bd3ecce3bd 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -38,11 +38,9 @@ #define HELPER_H "tcg/helper.h" #include "exec/helper-proto.h.inc" =20 -#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ - static void switch_mode(CPUARMState *env, int mode); =20 -static uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri) +uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri) { assert(ri->fieldoffset); if (cpreg_field_is_64bit(ri)) { @@ -319,25 +317,6 @@ static CPAccessResult access_trap_aa32s_el1(CPUARMStat= e *env, return CP_ACCESS_UNDEFINED; } =20 -/* - * Check for traps to performance monitor registers, which are controlled - * by MDCR_EL2.TPM for EL2 and MDCR_EL3.TPM for EL3. - */ -static CPAccessResult access_tpm(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) -{ - int el =3D arm_current_el(env); - uint64_t mdcr_el2 =3D arm_mdcr_el2_eff(env); - - if (el < 2 && (mdcr_el2 & MDCR_TPM)) { - return CP_ACCESS_TRAP_EL2; - } - if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TPM)) { - return CP_ACCESS_TRAP_EL3; - } - return CP_ACCESS_OK; -} - /* Check for traps from EL1 due to HCR_EL2.TVM and HCR_EL2.TRVM. */ CPAccessResult access_tvm_trvm(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) @@ -681,283 +660,6 @@ static const ARMCPRegInfo v6_cp_reginfo[] =3D { .resetfn =3D cpacr_reset, .writefn =3D cpacr_write, .readfn =3D cpac= r_read }, }; =20 -typedef struct pm_event { - uint16_t number; /* PMEVTYPER.evtCount is 16 bits wide */ - /* If the event is supported on this CPU (used to generate PMCEID[01])= */ - bool (*supported)(CPUARMState *); - /* - * Retrieve the current count of the underlying event. The programmed - * counters hold a difference from the return value from this function - */ - uint64_t (*get_count)(CPUARMState *); - /* - * Return how many nanoseconds it will take (at a minimum) for count e= vents - * to occur. A negative value indicates the counter will never overflo= w, or - * that the counter has otherwise arranged for the overflow bit to be = set - * and the PMU interrupt to be raised on overflow. - */ - int64_t (*ns_per_count)(uint64_t); -} pm_event; - -static bool event_always_supported(CPUARMState *env) -{ - return true; -} - -static uint64_t swinc_get_count(CPUARMState *env) -{ - /* - * SW_INCR events are written directly to the pmevcntr's by writes to - * PMSWINC, so there is no underlying count maintained by the PMU itse= lf - */ - return 0; -} - -static int64_t swinc_ns_per(uint64_t ignored) -{ - return -1; -} - -/* - * Return the underlying cycle count for the PMU cycle counters. If we're = in - * usermode, simply return 0. - */ -static uint64_t cycles_get_count(CPUARMState *env) -{ -#ifndef CONFIG_USER_ONLY - return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), - ARM_CPU_FREQ, NANOSECONDS_PER_SECOND); -#else - return cpu_get_host_ticks(); -#endif -} - -#ifndef CONFIG_USER_ONLY -static int64_t cycles_ns_per(uint64_t cycles) -{ - return (ARM_CPU_FREQ / NANOSECONDS_PER_SECOND) * cycles; -} - -static bool instructions_supported(CPUARMState *env) -{ - /* Precise instruction counting */ - return icount_enabled() =3D=3D ICOUNT_PRECISE; -} - -static uint64_t instructions_get_count(CPUARMState *env) -{ - assert(icount_enabled() =3D=3D ICOUNT_PRECISE); - return (uint64_t)icount_get_raw(); -} - -static int64_t instructions_ns_per(uint64_t icount) -{ - assert(icount_enabled() =3D=3D ICOUNT_PRECISE); - return icount_to_ns((int64_t)icount); -} -#endif - -static bool pmuv3p1_events_supported(CPUARMState *env) -{ - /* For events which are supported in any v8.1 PMU */ - return cpu_isar_feature(any_pmuv3p1, env_archcpu(env)); -} - -static bool pmuv3p4_events_supported(CPUARMState *env) -{ - /* For events which are supported in any v8.1 PMU */ - return cpu_isar_feature(any_pmuv3p4, env_archcpu(env)); -} - -static uint64_t zero_event_get_count(CPUARMState *env) -{ - /* For events which on QEMU never fire, so their count is always zero = */ - return 0; -} - -static int64_t zero_event_ns_per(uint64_t cycles) -{ - /* An event which never fires can never overflow */ - return -1; -} - -static const pm_event pm_events[] =3D { - { .number =3D 0x000, /* SW_INCR */ - .supported =3D event_always_supported, - .get_count =3D swinc_get_count, - .ns_per_count =3D swinc_ns_per, - }, -#ifndef CONFIG_USER_ONLY - { .number =3D 0x008, /* INST_RETIRED, Instruction architecturally exec= uted */ - .supported =3D instructions_supported, - .get_count =3D instructions_get_count, - .ns_per_count =3D instructions_ns_per, - }, - { .number =3D 0x011, /* CPU_CYCLES, Cycle */ - .supported =3D event_always_supported, - .get_count =3D cycles_get_count, - .ns_per_count =3D cycles_ns_per, - }, -#endif - { .number =3D 0x023, /* STALL_FRONTEND */ - .supported =3D pmuv3p1_events_supported, - .get_count =3D zero_event_get_count, - .ns_per_count =3D zero_event_ns_per, - }, - { .number =3D 0x024, /* STALL_BACKEND */ - .supported =3D pmuv3p1_events_supported, - .get_count =3D zero_event_get_count, - .ns_per_count =3D zero_event_ns_per, - }, - { .number =3D 0x03c, /* STALL */ - .supported =3D pmuv3p4_events_supported, - .get_count =3D zero_event_get_count, - .ns_per_count =3D zero_event_ns_per, - }, -}; - -/* - * Note: Before increasing MAX_EVENT_ID beyond 0x3f into the 0x40xx range = of - * events (i.e. the statistical profiling extension), this implementation - * should first be updated to something sparse instead of the current - * supported_event_map[] array. - */ -#define MAX_EVENT_ID 0x3c -#define UNSUPPORTED_EVENT UINT16_MAX -static uint16_t supported_event_map[MAX_EVENT_ID + 1]; - -/* - * Called upon CPU initialization to initialize PMCEID[01]_EL0 and build a= map - * of ARM event numbers to indices in our pm_events array. - * - * Note: Events in the 0x40XX range are not currently supported. - */ -void pmu_init(ARMCPU *cpu) -{ - unsigned int i; - - /* - * Empty supported_event_map and cpu->pmceid[01] before adding support= ed - * events to them - */ - for (i =3D 0; i < ARRAY_SIZE(supported_event_map); i++) { - supported_event_map[i] =3D UNSUPPORTED_EVENT; - } - cpu->pmceid0 =3D 0; - cpu->pmceid1 =3D 0; - - for (i =3D 0; i < ARRAY_SIZE(pm_events); i++) { - const pm_event *cnt =3D &pm_events[i]; - assert(cnt->number <=3D MAX_EVENT_ID); - /* We do not currently support events in the 0x40xx range */ - assert(cnt->number <=3D 0x3f); - - if (cnt->supported(&cpu->env)) { - supported_event_map[cnt->number] =3D i; - uint64_t event_mask =3D 1ULL << (cnt->number & 0x1f); - if (cnt->number & 0x20) { - cpu->pmceid1 |=3D event_mask; - } else { - cpu->pmceid0 |=3D event_mask; - } - } - } -} - -/* - * Check at runtime whether a PMU event is supported for the current machi= ne - */ -static bool event_supported(uint16_t number) -{ - if (number > MAX_EVENT_ID) { - return false; - } - return supported_event_map[number] !=3D UNSUPPORTED_EVENT; -} - -static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *r= i, - bool isread) -{ - /* - * Performance monitor registers user accessibility is controlled - * by PMUSERENR. MDCR_EL2.TPM and MDCR_EL3.TPM allow configurable - * trapping to EL2 or EL3 for other accesses. - */ - int el =3D arm_current_el(env); - uint64_t mdcr_el2 =3D arm_mdcr_el2_eff(env); - - if (el =3D=3D 0 && !(env->cp15.c9_pmuserenr & 1)) { - return CP_ACCESS_TRAP_EL1; - } - if (el < 2 && (mdcr_el2 & MDCR_TPM)) { - return CP_ACCESS_TRAP_EL2; - } - if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TPM)) { - return CP_ACCESS_TRAP_EL3; - } - - return CP_ACCESS_OK; -} - -static CPAccessResult pmreg_access_xevcntr(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) -{ - /* ER: event counter read trap control */ - if (arm_feature(env, ARM_FEATURE_V8) - && arm_current_el(env) =3D=3D 0 - && (env->cp15.c9_pmuserenr & (1 << 3)) !=3D 0 - && isread) { - return CP_ACCESS_OK; - } - - return pmreg_access(env, ri, isread); -} - -static CPAccessResult pmreg_access_swinc(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) -{ - /* SW: software increment write trap control */ - if (arm_feature(env, ARM_FEATURE_V8) - && arm_current_el(env) =3D=3D 0 - && (env->cp15.c9_pmuserenr & (1 << 1)) !=3D 0 - && !isread) { - return CP_ACCESS_OK; - } - - return pmreg_access(env, ri, isread); -} - -static CPAccessResult pmreg_access_selr(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) -{ - /* ER: event counter read trap control */ - if (arm_feature(env, ARM_FEATURE_V8) - && arm_current_el(env) =3D=3D 0 - && (env->cp15.c9_pmuserenr & (1 << 3)) !=3D 0) { - return CP_ACCESS_OK; - } - - return pmreg_access(env, ri, isread); -} - -static CPAccessResult pmreg_access_ccntr(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) -{ - /* CR: cycle counter read trap control */ - if (arm_feature(env, ARM_FEATURE_V8) - && arm_current_el(env) =3D=3D 0 - && (env->cp15.c9_pmuserenr & (1 << 2)) !=3D 0 - && isread) { - return CP_ACCESS_OK; - } - - return pmreg_access(env, ri, isread); -} - /* * Bits in MDCR_EL2 and MDCR_EL3 which pmu_counter_enabled() looks at. * We use these to decide whether we need to wrap a write to MDCR_EL2 @@ -967,684 +669,6 @@ static CPAccessResult pmreg_access_ccntr(CPUARMState = *env, (MDCR_HPME | MDCR_HPMD | MDCR_HPMN | MDCR_HCCD | MDCR_HLP) #define MDCR_EL3_PMU_ENABLE_BITS (MDCR_SPME | MDCR_SCCD) =20 -/* - * Returns true if the counter (pass 31 for PMCCNTR) should count events u= sing - * the current EL, security state, and register configuration. - */ -static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter) -{ - uint64_t filter; - bool e, p, u, nsk, nsu, nsh, m; - bool enabled, prohibited =3D false, filtered; - bool secure =3D arm_is_secure(env); - int el =3D arm_current_el(env); - uint64_t mdcr_el2; - uint8_t hpmn; - - /* - * We might be called for M-profile cores where MDCR_EL2 doesn't - * exist and arm_mdcr_el2_eff() will assert, so this early-exit check - * must be before we read that value. - */ - if (!arm_feature(env, ARM_FEATURE_PMU)) { - return false; - } - - mdcr_el2 =3D arm_mdcr_el2_eff(env); - hpmn =3D mdcr_el2 & MDCR_HPMN; - - if (!arm_feature(env, ARM_FEATURE_EL2) || - (counter < hpmn || counter =3D=3D 31)) { - e =3D env->cp15.c9_pmcr & PMCRE; - } else { - e =3D mdcr_el2 & MDCR_HPME; - } - enabled =3D e && (env->cp15.c9_pmcnten & (1 << counter)); - - /* Is event counting prohibited? */ - if (el =3D=3D 2 && (counter < hpmn || counter =3D=3D 31)) { - prohibited =3D mdcr_el2 & MDCR_HPMD; - } - if (secure) { - prohibited =3D prohibited || !(env->cp15.mdcr_el3 & MDCR_SPME); - } - - if (counter =3D=3D 31) { - /* - * The cycle counter defaults to running. PMCR.DP says "disable - * the cycle counter when event counting is prohibited". - * Some MDCR bits disable the cycle counter specifically. - */ - prohibited =3D prohibited && env->cp15.c9_pmcr & PMCRDP; - if (cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { - if (secure) { - prohibited =3D prohibited || (env->cp15.mdcr_el3 & MDCR_SC= CD); - } - if (el =3D=3D 2) { - prohibited =3D prohibited || (mdcr_el2 & MDCR_HCCD); - } - } - } - - if (counter =3D=3D 31) { - filter =3D env->cp15.pmccfiltr_el0; - } else { - filter =3D env->cp15.c14_pmevtyper[counter]; - } - - p =3D filter & PMXEVTYPER_P; - u =3D filter & PMXEVTYPER_U; - nsk =3D arm_feature(env, ARM_FEATURE_EL3) && (filter & PMXEVTYPER_NSK); - nsu =3D arm_feature(env, ARM_FEATURE_EL3) && (filter & PMXEVTYPER_NSU); - nsh =3D arm_feature(env, ARM_FEATURE_EL2) && (filter & PMXEVTYPER_NSH); - m =3D arm_el_is_aa64(env, 1) && - arm_feature(env, ARM_FEATURE_EL3) && (filter & PMXEVTYPER_M); - - if (el =3D=3D 0) { - filtered =3D secure ? u : u !=3D nsu; - } else if (el =3D=3D 1) { - filtered =3D secure ? p : p !=3D nsk; - } else if (el =3D=3D 2) { - filtered =3D !nsh; - } else { /* EL3 */ - filtered =3D m !=3D p; - } - - if (counter !=3D 31) { - /* - * If not checking PMCCNTR, ensure the counter is setup to an even= t we - * support - */ - uint16_t event =3D filter & PMXEVTYPER_EVTCOUNT; - if (!event_supported(event)) { - return false; - } - } - - return enabled && !prohibited && !filtered; -} - -static void pmu_update_irq(CPUARMState *env) -{ - ARMCPU *cpu =3D env_archcpu(env); - qemu_set_irq(cpu->pmu_interrupt, (env->cp15.c9_pmcr & PMCRE) && - (env->cp15.c9_pminten & env->cp15.c9_pmovsr)); -} - -static bool pmccntr_clockdiv_enabled(CPUARMState *env) -{ - /* - * Return true if the clock divider is enabled and the cycle counter - * is supposed to tick only once every 64 clock cycles. This is - * controlled by PMCR.D, but if PMCR.LC is set to enable the long - * (64-bit) cycle counter PMCR.D has no effect. - */ - return (env->cp15.c9_pmcr & (PMCRD | PMCRLC)) =3D=3D PMCRD; -} - -static bool pmevcntr_is_64_bit(CPUARMState *env, int counter) -{ - /* Return true if the specified event counter is configured to be 64 b= it */ - - /* This isn't intended to be used with the cycle counter */ - assert(counter < 31); - - if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { - return false; - } - - if (arm_feature(env, ARM_FEATURE_EL2)) { - /* - * MDCR_EL2.HLP still applies even when EL2 is disabled in the - * current security state, so we don't use arm_mdcr_el2_eff() here. - */ - bool hlp =3D env->cp15.mdcr_el2 & MDCR_HLP; - int hpmn =3D env->cp15.mdcr_el2 & MDCR_HPMN; - - if (counter >=3D hpmn) { - return hlp; - } - } - return env->cp15.c9_pmcr & PMCRLP; -} - -/* - * Ensure c15_ccnt is the guest-visible count so that operations such as - * enabling/disabling the counter or filtering, modifying the count itself, - * etc. can be done logically. This is essentially a no-op if the counter = is - * not enabled at the time of the call. - */ -static void pmccntr_op_start(CPUARMState *env) -{ - uint64_t cycles =3D cycles_get_count(env); - - if (pmu_counter_enabled(env, 31)) { - uint64_t eff_cycles =3D cycles; - if (pmccntr_clockdiv_enabled(env)) { - eff_cycles /=3D 64; - } - - uint64_t new_pmccntr =3D eff_cycles - env->cp15.c15_ccnt_delta; - - uint64_t overflow_mask =3D env->cp15.c9_pmcr & PMCRLC ? \ - 1ull << 63 : 1ull << 31; - if (env->cp15.c15_ccnt & ~new_pmccntr & overflow_mask) { - env->cp15.c9_pmovsr |=3D (1ULL << 31); - pmu_update_irq(env); - } - - env->cp15.c15_ccnt =3D new_pmccntr; - } - env->cp15.c15_ccnt_delta =3D cycles; -} - -/* - * If PMCCNTR is enabled, recalculate the delta between the clock and the - * guest-visible count. A call to pmccntr_op_finish should follow every ca= ll to - * pmccntr_op_start. - */ -static void pmccntr_op_finish(CPUARMState *env) -{ - if (pmu_counter_enabled(env, 31)) { -#ifndef CONFIG_USER_ONLY - /* Calculate when the counter will next overflow */ - uint64_t remaining_cycles =3D -env->cp15.c15_ccnt; - if (!(env->cp15.c9_pmcr & PMCRLC)) { - remaining_cycles =3D (uint32_t)remaining_cycles; - } - int64_t overflow_in =3D cycles_ns_per(remaining_cycles); - - if (overflow_in > 0) { - int64_t overflow_at; - - if (!sadd64_overflow(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), - overflow_in, &overflow_at)) { - ARMCPU *cpu =3D env_archcpu(env); - timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); - } - } -#endif - - uint64_t prev_cycles =3D env->cp15.c15_ccnt_delta; - if (pmccntr_clockdiv_enabled(env)) { - prev_cycles /=3D 64; - } - env->cp15.c15_ccnt_delta =3D prev_cycles - env->cp15.c15_ccnt; - } -} - -static void pmevcntr_op_start(CPUARMState *env, uint8_t counter) -{ - - uint16_t event =3D env->cp15.c14_pmevtyper[counter] & PMXEVTYPER_EVTCO= UNT; - uint64_t count =3D 0; - if (event_supported(event)) { - uint16_t event_idx =3D supported_event_map[event]; - count =3D pm_events[event_idx].get_count(env); - } - - if (pmu_counter_enabled(env, counter)) { - uint64_t new_pmevcntr =3D count - env->cp15.c14_pmevcntr_delta[cou= nter]; - uint64_t overflow_mask =3D pmevcntr_is_64_bit(env, counter) ? - 1ULL << 63 : 1ULL << 31; - - if (env->cp15.c14_pmevcntr[counter] & ~new_pmevcntr & overflow_mas= k) { - env->cp15.c9_pmovsr |=3D (1 << counter); - pmu_update_irq(env); - } - env->cp15.c14_pmevcntr[counter] =3D new_pmevcntr; - } - env->cp15.c14_pmevcntr_delta[counter] =3D count; -} - -static void pmevcntr_op_finish(CPUARMState *env, uint8_t counter) -{ - if (pmu_counter_enabled(env, counter)) { -#ifndef CONFIG_USER_ONLY - uint16_t event =3D env->cp15.c14_pmevtyper[counter] & PMXEVTYPER_E= VTCOUNT; - uint16_t event_idx =3D supported_event_map[event]; - uint64_t delta =3D -(env->cp15.c14_pmevcntr[counter] + 1); - int64_t overflow_in; - - if (!pmevcntr_is_64_bit(env, counter)) { - delta =3D (uint32_t)delta; - } - overflow_in =3D pm_events[event_idx].ns_per_count(delta); - - if (overflow_in > 0) { - int64_t overflow_at; - - if (!sadd64_overflow(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), - overflow_in, &overflow_at)) { - ARMCPU *cpu =3D env_archcpu(env); - timer_mod_anticipate_ns(cpu->pmu_timer, overflow_at); - } - } -#endif - - env->cp15.c14_pmevcntr_delta[counter] -=3D - env->cp15.c14_pmevcntr[counter]; - } -} - -void pmu_op_start(CPUARMState *env) -{ - unsigned int i; - pmccntr_op_start(env); - for (i =3D 0; i < pmu_num_counters(env); i++) { - pmevcntr_op_start(env, i); - } -} - -void pmu_op_finish(CPUARMState *env) -{ - unsigned int i; - pmccntr_op_finish(env); - for (i =3D 0; i < pmu_num_counters(env); i++) { - pmevcntr_op_finish(env, i); - } -} - -void pmu_pre_el_change(ARMCPU *cpu, void *ignored) -{ - pmu_op_start(&cpu->env); -} - -void pmu_post_el_change(ARMCPU *cpu, void *ignored) -{ - pmu_op_finish(&cpu->env); -} - -void arm_pmu_timer_cb(void *opaque) -{ - ARMCPU *cpu =3D opaque; - - /* - * Update all the counter values based on the current underlying count= s, - * triggering interrupts to be raised, if necessary. pmu_op_finish() a= lso - * has the effect of setting the cpu->pmu_timer to the next earliest t= ime a - * counter may expire. - */ - pmu_op_start(&cpu->env); - pmu_op_finish(&cpu->env); -} - -static void pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - pmu_op_start(env); - - if (value & PMCRC) { - /* The counter has been reset */ - env->cp15.c15_ccnt =3D 0; - } - - if (value & PMCRP) { - unsigned int i; - for (i =3D 0; i < pmu_num_counters(env); i++) { - env->cp15.c14_pmevcntr[i] =3D 0; - } - } - - env->cp15.c9_pmcr &=3D ~PMCR_WRITABLE_MASK; - env->cp15.c9_pmcr |=3D (value & PMCR_WRITABLE_MASK); - - pmu_op_finish(env); -} - -static uint64_t pmcr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - uint64_t pmcr =3D env->cp15.c9_pmcr; - - /* - * If EL2 is implemented and enabled for the current security state, r= eads - * of PMCR.N from EL1 or EL0 return the value of MDCR_EL2.HPMN or HDCR= .HPMN. - */ - if (arm_current_el(env) <=3D 1 && arm_is_el2_enabled(env)) { - pmcr &=3D ~PMCRN_MASK; - pmcr |=3D (env->cp15.mdcr_el2 & MDCR_HPMN) << PMCRN_SHIFT; - } - - return pmcr; -} - -static void pmswinc_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - unsigned int i; - uint64_t overflow_mask, new_pmswinc; - - for (i =3D 0; i < pmu_num_counters(env); i++) { - /* Increment a counter's count iff: */ - if ((value & (1 << i)) && /* counter's bit is set */ - /* counter is enabled and not filtered */ - pmu_counter_enabled(env, i) && - /* counter is SW_INCR */ - (env->cp15.c14_pmevtyper[i] & PMXEVTYPER_EVTCOUNT) =3D=3D = 0x0) { - pmevcntr_op_start(env, i); - - /* - * Detect if this write causes an overflow since we can't pred= ict - * PMSWINC overflows like we can for other events - */ - new_pmswinc =3D env->cp15.c14_pmevcntr[i] + 1; - - overflow_mask =3D pmevcntr_is_64_bit(env, i) ? - 1ULL << 63 : 1ULL << 31; - - if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & overflow_mask) { - env->cp15.c9_pmovsr |=3D (1 << i); - pmu_update_irq(env); - } - - env->cp15.c14_pmevcntr[i] =3D new_pmswinc; - - pmevcntr_op_finish(env, i); - } - } -} - -static uint64_t pmccntr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - uint64_t ret; - pmccntr_op_start(env); - ret =3D env->cp15.c15_ccnt; - pmccntr_op_finish(env); - return ret; -} - -static void pmselr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - /* - * The value of PMSELR.SEL affects the behavior of PMXEVTYPER and - * PMXEVCNTR. We allow [0..31] to be written to PMSELR here; in the - * meanwhile, we check PMSELR.SEL when PMXEVTYPER and PMXEVCNTR are - * accessed. - */ - env->cp15.c9_pmselr =3D value & 0x1f; -} - -static void pmccntr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - pmccntr_op_start(env); - env->cp15.c15_ccnt =3D value; - pmccntr_op_finish(env); -} - -static void pmccntr_write32(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - uint64_t cur_val =3D pmccntr_read(env, NULL); - - pmccntr_write(env, ri, deposit64(cur_val, 0, 32, value)); -} - -static void pmccfiltr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - pmccntr_op_start(env); - env->cp15.pmccfiltr_el0 =3D value & PMCCFILTR_EL0; - pmccntr_op_finish(env); -} - -static void pmccfiltr_write_a32(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - pmccntr_op_start(env); - /* M is not accessible from AArch32 */ - env->cp15.pmccfiltr_el0 =3D (env->cp15.pmccfiltr_el0 & PMCCFILTR_M) | - (value & PMCCFILTR); - pmccntr_op_finish(env); -} - -static uint64_t pmccfiltr_read_a32(CPUARMState *env, const ARMCPRegInfo *r= i) -{ - /* M is not visible in AArch32 */ - return env->cp15.pmccfiltr_el0 & PMCCFILTR; -} - -static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - pmu_op_start(env); - value &=3D pmu_counter_mask(env); - env->cp15.c9_pmcnten |=3D value; - pmu_op_finish(env); -} - -static void pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - pmu_op_start(env); - value &=3D pmu_counter_mask(env); - env->cp15.c9_pmcnten &=3D ~value; - pmu_op_finish(env); -} - -static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - value &=3D pmu_counter_mask(env); - env->cp15.c9_pmovsr &=3D ~value; - pmu_update_irq(env); -} - -static void pmovsset_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - value &=3D pmu_counter_mask(env); - env->cp15.c9_pmovsr |=3D value; - pmu_update_irq(env); -} - -static void pmevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value, const uint8_t counter) -{ - if (counter =3D=3D 31) { - pmccfiltr_write(env, ri, value); - } else if (counter < pmu_num_counters(env)) { - pmevcntr_op_start(env, counter); - - /* - * If this counter's event type is changing, store the current - * underlying count for the new type in c14_pmevcntr_delta[counter= ] so - * pmevcntr_op_finish has the correct baseline when it converts ba= ck to - * a delta. - */ - uint16_t old_event =3D env->cp15.c14_pmevtyper[counter] & - PMXEVTYPER_EVTCOUNT; - uint16_t new_event =3D value & PMXEVTYPER_EVTCOUNT; - if (old_event !=3D new_event) { - uint64_t count =3D 0; - if (event_supported(new_event)) { - uint16_t event_idx =3D supported_event_map[new_event]; - count =3D pm_events[event_idx].get_count(env); - } - env->cp15.c14_pmevcntr_delta[counter] =3D count; - } - - env->cp15.c14_pmevtyper[counter] =3D value & PMXEVTYPER_MASK; - pmevcntr_op_finish(env, counter); - } - /* - * Attempts to access PMXEVTYPER are CONSTRAINED UNPREDICTABLE when - * PMSELR value is equal to or greater than the number of implemented - * counters, but not equal to 0x1f. We opt to behave as a RAZ/WI. - */ -} - -static uint64_t pmevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri, - const uint8_t counter) -{ - if (counter =3D=3D 31) { - return env->cp15.pmccfiltr_el0; - } else if (counter < pmu_num_counters(env)) { - return env->cp15.c14_pmevtyper[counter]; - } else { - /* - * We opt to behave as a RAZ/WI when attempts to access PMXEVTYPER - * are CONSTRAINED UNPREDICTABLE. See comments in pmevtyper_write(). - */ - return 0; - } -} - -static void pmevtyper_writefn(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); - pmevtyper_write(env, ri, value, counter); -} - -static void pmevtyper_rawwrite(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); - env->cp15.c14_pmevtyper[counter] =3D value; - - /* - * pmevtyper_rawwrite is called between a pair of pmu_op_start and - * pmu_op_finish calls when loading saved state for a migration. Becau= se - * we're potentially updating the type of event here, the value writte= n to - * c14_pmevcntr_delta by the preceding pmu_op_start call may be for a - * different counter type. Therefore, we need to set this value to the - * current count for the counter type we're writing so that pmu_op_fin= ish - * has the correct count for its calculation. - */ - uint16_t event =3D value & PMXEVTYPER_EVTCOUNT; - if (event_supported(event)) { - uint16_t event_idx =3D supported_event_map[event]; - env->cp15.c14_pmevcntr_delta[counter] =3D - pm_events[event_idx].get_count(env); - } -} - -static uint64_t pmevtyper_readfn(CPUARMState *env, const ARMCPRegInfo *ri) -{ - uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); - return pmevtyper_read(env, ri, counter); -} - -static void pmxevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - pmevtyper_write(env, ri, value, env->cp15.c9_pmselr & 31); -} - -static uint64_t pmxevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - return pmevtyper_read(env, ri, env->cp15.c9_pmselr & 31); -} - -static void pmevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value, uint8_t counter) -{ - if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { - /* Before FEAT_PMUv3p5, top 32 bits of event counters are RES0 */ - value &=3D MAKE_64BIT_MASK(0, 32); - } - if (counter < pmu_num_counters(env)) { - pmevcntr_op_start(env, counter); - env->cp15.c14_pmevcntr[counter] =3D value; - pmevcntr_op_finish(env, counter); - } - /* - * We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR - * are CONSTRAINED UNPREDICTABLE. - */ -} - -static uint64_t pmevcntr_read(CPUARMState *env, const ARMCPRegInfo *ri, - uint8_t counter) -{ - if (counter < pmu_num_counters(env)) { - uint64_t ret; - pmevcntr_op_start(env, counter); - ret =3D env->cp15.c14_pmevcntr[counter]; - pmevcntr_op_finish(env, counter); - if (!cpu_isar_feature(any_pmuv3p5, env_archcpu(env))) { - /* Before FEAT_PMUv3p5, top 32 bits of event counters are RES0= */ - ret &=3D MAKE_64BIT_MASK(0, 32); - } - return ret; - } else { - /* - * We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR - * are CONSTRAINED UNPREDICTABLE. - */ - return 0; - } -} - -static void pmevcntr_writefn(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); - pmevcntr_write(env, ri, value, counter); -} - -static uint64_t pmevcntr_readfn(CPUARMState *env, const ARMCPRegInfo *ri) -{ - uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); - return pmevcntr_read(env, ri, counter); -} - -static void pmevcntr_rawwrite(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); - assert(counter < pmu_num_counters(env)); - env->cp15.c14_pmevcntr[counter] =3D value; - pmevcntr_write(env, ri, value, counter); -} - -static uint64_t pmevcntr_rawread(CPUARMState *env, const ARMCPRegInfo *ri) -{ - uint8_t counter =3D ((ri->crm & 3) << 3) | (ri->opc2 & 7); - assert(counter < pmu_num_counters(env)); - return env->cp15.c14_pmevcntr[counter]; -} - -static void pmxevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - pmevcntr_write(env, ri, value, env->cp15.c9_pmselr & 31); -} - -static uint64_t pmxevcntr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - return pmevcntr_read(env, ri, env->cp15.c9_pmselr & 31); -} - -static void pmuserenr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - if (arm_feature(env, ARM_FEATURE_V8)) { - env->cp15.c9_pmuserenr =3D value & 0xf; - } else { - env->cp15.c9_pmuserenr =3D value & 1; - } -} - -static void pmintenset_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - /* We have no event counters so only the C bit can be changed */ - value &=3D pmu_counter_mask(env); - env->cp15.c9_pminten |=3D value; - pmu_update_irq(env); -} - -static void pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - value &=3D pmu_counter_mask(env); - env->cp15.c9_pminten &=3D ~value; - pmu_update_irq(env); -} - static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { @@ -1874,171 +898,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] =3D { /* the old v6 WFI, UNPREDICTABLE in v7 but we choose to NOP */ { .name =3D "NOP", .cp =3D 15, .crn =3D 7, .crm =3D 0, .opc1 =3D 0, .o= pc2 =3D 4, .access =3D PL1_W, .type =3D ARM_CP_NOP }, - /* - * Performance monitors are implementation defined in v7, - * but with an ARM recommended set of registers, which we - * follow. - * - * Performance registers fall into three categories: - * (a) always UNDEF in PL0, RW in PL1 (PMINTENSET, PMINTENCLR) - * (b) RO in PL0 (ie UNDEF on write), RW in PL1 (PMUSERENR) - * (c) UNDEF in PL0 if PMUSERENR.EN=3D=3D0, otherwise accessible (all= others) - * For the cases controlled by PMUSERENR we must set .access to PL0_RW - * or PL0_RO as appropriate and then check PMUSERENR in the helper fn. - */ - { .name =3D "PMCNTENSET", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 = =3D 0, .opc2 =3D 1, - .access =3D PL0_RW, .type =3D ARM_CP_ALIAS | ARM_CP_IO, - .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmcnten), - .writefn =3D pmcntenset_write, - .accessfn =3D pmreg_access, - .fgt =3D FGT_PMCNTEN, - .raw_writefn =3D raw_write }, - { .name =3D "PMCNTENSET_EL0", .state =3D ARM_CP_STATE_AA64, .type =3D = ARM_CP_IO, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 1, - .access =3D PL0_RW, .accessfn =3D pmreg_access, - .fgt =3D FGT_PMCNTEN, - .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmcnten), .resetvalue= =3D 0, - .writefn =3D pmcntenset_write, .raw_writefn =3D raw_write }, - { .name =3D "PMCNTENCLR", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 = =3D 0, .opc2 =3D 2, - .access =3D PL0_RW, - .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmcnten), - .accessfn =3D pmreg_access, - .fgt =3D FGT_PMCNTEN, - .writefn =3D pmcntenclr_write, .raw_writefn =3D raw_write, - .type =3D ARM_CP_ALIAS | ARM_CP_IO }, - { .name =3D "PMCNTENCLR_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 2, - .access =3D PL0_RW, .accessfn =3D pmreg_access, - .fgt =3D FGT_PMCNTEN, - .type =3D ARM_CP_ALIAS | ARM_CP_IO, - .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmcnten), - .writefn =3D pmcntenclr_write, .raw_writefn =3D raw_write }, - { .name =3D "PMOVSR", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 =3D 0= , .opc2 =3D 3, - .access =3D PL0_RW, .type =3D ARM_CP_IO, - .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmovsr), - .accessfn =3D pmreg_access, - .fgt =3D FGT_PMOVS, - .writefn =3D pmovsr_write, - .raw_writefn =3D raw_write }, - { .name =3D "PMOVSCLR_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 3, - .access =3D PL0_RW, .accessfn =3D pmreg_access, - .fgt =3D FGT_PMOVS, - .type =3D ARM_CP_ALIAS | ARM_CP_IO, - .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmovsr), - .writefn =3D pmovsr_write, - .raw_writefn =3D raw_write }, - { .name =3D "PMSWINC", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 =3D = 0, .opc2 =3D 4, - .access =3D PL0_W, .accessfn =3D pmreg_access_swinc, - .fgt =3D FGT_PMSWINC_EL0, - .type =3D ARM_CP_NO_RAW | ARM_CP_IO, - .writefn =3D pmswinc_write }, - { .name =3D "PMSWINC_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 4, - .access =3D PL0_W, .accessfn =3D pmreg_access_swinc, - .fgt =3D FGT_PMSWINC_EL0, - .type =3D ARM_CP_NO_RAW | ARM_CP_IO, - .writefn =3D pmswinc_write }, - { .name =3D "PMSELR", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 =3D 0= , .opc2 =3D 5, - .access =3D PL0_RW, .type =3D ARM_CP_ALIAS, - .fgt =3D FGT_PMSELR_EL0, - .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmselr), - .accessfn =3D pmreg_access_selr, .writefn =3D pmselr_write, - .raw_writefn =3D raw_write}, - { .name =3D "PMSELR_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 5, - .access =3D PL0_RW, .accessfn =3D pmreg_access_selr, - .fgt =3D FGT_PMSELR_EL0, - .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmselr), - .writefn =3D pmselr_write, .raw_writefn =3D raw_write, }, - { .name =3D "PMCCNTR", .cp =3D 15, .crn =3D 9, .crm =3D 13, .opc1 =3D = 0, .opc2 =3D 0, - .access =3D PL0_RW, .resetvalue =3D 0, .type =3D ARM_CP_ALIAS | ARM_= CP_IO, - .fgt =3D FGT_PMCCNTR_EL0, - .readfn =3D pmccntr_read, .writefn =3D pmccntr_write32, - .accessfn =3D pmreg_access_ccntr }, - { .name =3D "PMCCNTR_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 13, .opc2 =3D 0, - .access =3D PL0_RW, .accessfn =3D pmreg_access_ccntr, - .fgt =3D FGT_PMCCNTR_EL0, - .type =3D ARM_CP_IO, - .fieldoffset =3D offsetof(CPUARMState, cp15.c15_ccnt), - .readfn =3D pmccntr_read, .writefn =3D pmccntr_write, - .raw_readfn =3D raw_read, .raw_writefn =3D raw_write, }, - { .name =3D "PMCCFILTR", .cp =3D 15, .opc1 =3D 0, .crn =3D 14, .crm = =3D 15, .opc2 =3D 7, - .writefn =3D pmccfiltr_write_a32, .readfn =3D pmccfiltr_read_a32, - .access =3D PL0_RW, .accessfn =3D pmreg_access, - .fgt =3D FGT_PMCCFILTR_EL0, - .type =3D ARM_CP_ALIAS | ARM_CP_IO, - .resetvalue =3D 0, }, - { .name =3D "PMCCFILTR_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 14, .crm =3D 15, .opc2 =3D 7, - .writefn =3D pmccfiltr_write, .raw_writefn =3D raw_write, - .access =3D PL0_RW, .accessfn =3D pmreg_access, - .fgt =3D FGT_PMCCFILTR_EL0, - .type =3D ARM_CP_IO, - .fieldoffset =3D offsetof(CPUARMState, cp15.pmccfiltr_el0), - .resetvalue =3D 0, }, - { .name =3D "PMXEVTYPER", .cp =3D 15, .crn =3D 9, .crm =3D 13, .opc1 = =3D 0, .opc2 =3D 1, - .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, - .accessfn =3D pmreg_access, - .fgt =3D FGT_PMEVTYPERN_EL0, - .writefn =3D pmxevtyper_write, .readfn =3D pmxevtyper_read }, - { .name =3D "PMXEVTYPER_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 13, .opc2 =3D 1, - .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, - .accessfn =3D pmreg_access, - .fgt =3D FGT_PMEVTYPERN_EL0, - .writefn =3D pmxevtyper_write, .readfn =3D pmxevtyper_read }, - { .name =3D "PMXEVCNTR", .cp =3D 15, .crn =3D 9, .crm =3D 13, .opc1 = =3D 0, .opc2 =3D 2, - .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, - .accessfn =3D pmreg_access_xevcntr, - .fgt =3D FGT_PMEVCNTRN_EL0, - .writefn =3D pmxevcntr_write, .readfn =3D pmxevcntr_read }, - { .name =3D "PMXEVCNTR_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 13, .opc2 =3D 2, - .access =3D PL0_RW, .type =3D ARM_CP_NO_RAW | ARM_CP_IO, - .accessfn =3D pmreg_access_xevcntr, - .fgt =3D FGT_PMEVCNTRN_EL0, - .writefn =3D pmxevcntr_write, .readfn =3D pmxevcntr_read }, - { .name =3D "PMUSERENR", .cp =3D 15, .crn =3D 9, .crm =3D 14, .opc1 = =3D 0, .opc2 =3D 0, - .access =3D PL0_R | PL1_RW, .accessfn =3D access_tpm, - .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmuserenr), - .resetvalue =3D 0, - .writefn =3D pmuserenr_write, .raw_writefn =3D raw_write }, - { .name =3D "PMUSERENR_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 14, .opc2 =3D 0, - .access =3D PL0_R | PL1_RW, .accessfn =3D access_tpm, .type =3D ARM_= CP_ALIAS, - .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmuserenr), - .resetvalue =3D 0, - .writefn =3D pmuserenr_write, .raw_writefn =3D raw_write }, - { .name =3D "PMINTENSET", .cp =3D 15, .crn =3D 9, .crm =3D 14, .opc1 = =3D 0, .opc2 =3D 1, - .access =3D PL1_RW, .accessfn =3D access_tpm, - .fgt =3D FGT_PMINTEN, - .type =3D ARM_CP_ALIAS | ARM_CP_IO, - .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pminten), - .resetvalue =3D 0, - .writefn =3D pmintenset_write, .raw_writefn =3D raw_write }, - { .name =3D "PMINTENSET_EL1", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 0, .crn =3D 9, .crm =3D 14, .opc2 =3D 1, - .access =3D PL1_RW, .accessfn =3D access_tpm, - .fgt =3D FGT_PMINTEN, - .type =3D ARM_CP_IO, - .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pminten), - .writefn =3D pmintenset_write, .raw_writefn =3D raw_write, - .resetvalue =3D 0x0 }, - { .name =3D "PMINTENCLR", .cp =3D 15, .crn =3D 9, .crm =3D 14, .opc1 = =3D 0, .opc2 =3D 2, - .access =3D PL1_RW, .accessfn =3D access_tpm, - .fgt =3D FGT_PMINTEN, - .type =3D ARM_CP_ALIAS | ARM_CP_IO, - .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pminten), - .writefn =3D pmintenclr_write, .raw_writefn =3D raw_write }, - { .name =3D "PMINTENCLR_EL1", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 0, .crn =3D 9, .crm =3D 14, .opc2 =3D 2, - .access =3D PL1_RW, .accessfn =3D access_tpm, - .fgt =3D FGT_PMINTEN, - .type =3D ARM_CP_ALIAS | ARM_CP_IO, - .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pminten), - .writefn =3D pmintenclr_write, .raw_writefn =3D raw_write }, { .name =3D "CCSIDR", .state =3D ARM_CP_STATE_BOTH, .opc0 =3D 3, .crn =3D 0, .crm =3D 0, .opc1 =3D 1, .opc2 =3D 0, .access =3D PL1_R, @@ -2121,25 +980,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] =3D { .type =3D ARM_CP_NO_RAW, .access =3D PL1_R, .readfn =3D isr_read }, }; =20 -static const ARMCPRegInfo pmovsset_cp_reginfo[] =3D { - /* PMOVSSET is not implemented in v7 before v7ve */ - { .name =3D "PMOVSSET", .cp =3D 15, .opc1 =3D 0, .crn =3D 9, .crm =3D = 14, .opc2 =3D 3, - .access =3D PL0_RW, .accessfn =3D pmreg_access, - .fgt =3D FGT_PMOVS, - .type =3D ARM_CP_ALIAS | ARM_CP_IO, - .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmovsr), - .writefn =3D pmovsset_write, - .raw_writefn =3D raw_write }, - { .name =3D "PMOVSSET_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 14, .opc2 =3D 3, - .access =3D PL0_RW, .accessfn =3D pmreg_access, - .fgt =3D FGT_PMOVS, - .type =3D ARM_CP_ALIAS | ARM_CP_IO, - .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmovsr), - .writefn =3D pmovsset_write, - .raw_writefn =3D raw_write }, -}; - static void teecr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { @@ -6352,105 +5192,6 @@ static const ARMCPRegInfo nmi_reginfo[] =3D { .resetfn =3D arm_cp_reset_ignore }, }; =20 -static void define_pmu_regs(ARMCPU *cpu) -{ - /* - * v7 performance monitor control register: same implementor - * field as main ID register, and we implement four counters in - * addition to the cycle count register. - */ - unsigned int i, pmcrn =3D pmu_num_counters(&cpu->env); - ARMCPRegInfo pmcr =3D { - .name =3D "PMCR", .cp =3D 15, .crn =3D 9, .crm =3D 12, .opc1 =3D 0= , .opc2 =3D 0, - .access =3D PL0_RW, - .fgt =3D FGT_PMCR_EL0, - .type =3D ARM_CP_IO | ARM_CP_ALIAS, - .fieldoffset =3D offsetoflow32(CPUARMState, cp15.c9_pmcr), - .accessfn =3D pmreg_access, - .readfn =3D pmcr_read, .raw_readfn =3D raw_read, - .writefn =3D pmcr_write, .raw_writefn =3D raw_write, - }; - ARMCPRegInfo pmcr64 =3D { - .name =3D "PMCR_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D 0, - .access =3D PL0_RW, .accessfn =3D pmreg_access, - .fgt =3D FGT_PMCR_EL0, - .type =3D ARM_CP_IO, - .fieldoffset =3D offsetof(CPUARMState, cp15.c9_pmcr), - .resetvalue =3D cpu->isar.reset_pmcr_el0, - .readfn =3D pmcr_read, .raw_readfn =3D raw_read, - .writefn =3D pmcr_write, .raw_writefn =3D raw_write, - }; - - define_one_arm_cp_reg(cpu, &pmcr); - define_one_arm_cp_reg(cpu, &pmcr64); - for (i =3D 0; i < pmcrn; i++) { - char *pmevcntr_name =3D g_strdup_printf("PMEVCNTR%d", i); - char *pmevcntr_el0_name =3D g_strdup_printf("PMEVCNTR%d_EL0", i); - char *pmevtyper_name =3D g_strdup_printf("PMEVTYPER%d", i); - char *pmevtyper_el0_name =3D g_strdup_printf("PMEVTYPER%d_EL0", i); - ARMCPRegInfo pmev_regs[] =3D { - { .name =3D pmevcntr_name, .cp =3D 15, .crn =3D 14, - .crm =3D 8 | (3 & (i >> 3)), .opc1 =3D 0, .opc2 =3D i & 7, - .access =3D PL0_RW, .type =3D ARM_CP_IO | ARM_CP_ALIAS, - .fgt =3D FGT_PMEVCNTRN_EL0, - .readfn =3D pmevcntr_readfn, .writefn =3D pmevcntr_writefn, - .accessfn =3D pmreg_access_xevcntr }, - { .name =3D pmevcntr_el0_name, .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 14, .crm =3D 8 | (3 & (i = >> 3)), - .opc2 =3D i & 7, .access =3D PL0_RW, .accessfn =3D pmreg_acc= ess_xevcntr, - .type =3D ARM_CP_IO, - .fgt =3D FGT_PMEVCNTRN_EL0, - .readfn =3D pmevcntr_readfn, .writefn =3D pmevcntr_writefn, - .raw_readfn =3D pmevcntr_rawread, - .raw_writefn =3D pmevcntr_rawwrite }, - { .name =3D pmevtyper_name, .cp =3D 15, .crn =3D 14, - .crm =3D 12 | (3 & (i >> 3)), .opc1 =3D 0, .opc2 =3D i & 7, - .access =3D PL0_RW, .type =3D ARM_CP_IO | ARM_CP_ALIAS, - .fgt =3D FGT_PMEVTYPERN_EL0, - .readfn =3D pmevtyper_readfn, .writefn =3D pmevtyper_writefn, - .accessfn =3D pmreg_access }, - { .name =3D pmevtyper_el0_name, .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 14, .crm =3D 12 | (3 & (i= >> 3)), - .opc2 =3D i & 7, .access =3D PL0_RW, .accessfn =3D pmreg_acc= ess, - .fgt =3D FGT_PMEVTYPERN_EL0, - .type =3D ARM_CP_IO, - .readfn =3D pmevtyper_readfn, .writefn =3D pmevtyper_writefn, - .raw_writefn =3D pmevtyper_rawwrite }, - }; - define_arm_cp_regs(cpu, pmev_regs); - g_free(pmevcntr_name); - g_free(pmevcntr_el0_name); - g_free(pmevtyper_name); - g_free(pmevtyper_el0_name); - } - if (cpu_isar_feature(aa32_pmuv3p1, cpu)) { - ARMCPRegInfo v81_pmu_regs[] =3D { - { .name =3D "PMCEID2", .state =3D ARM_CP_STATE_AA32, - .cp =3D 15, .opc1 =3D 0, .crn =3D 9, .crm =3D 14, .opc2 =3D = 4, - .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, - .fgt =3D FGT_PMCEIDN_EL0, - .resetvalue =3D extract64(cpu->pmceid0, 32, 32) }, - { .name =3D "PMCEID3", .state =3D ARM_CP_STATE_AA32, - .cp =3D 15, .opc1 =3D 0, .crn =3D 9, .crm =3D 14, .opc2 =3D = 5, - .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, - .fgt =3D FGT_PMCEIDN_EL0, - .resetvalue =3D extract64(cpu->pmceid1, 32, 32) }, - }; - define_arm_cp_regs(cpu, v81_pmu_regs); - } - if (cpu_isar_feature(any_pmuv3p4, cpu)) { - static const ARMCPRegInfo v84_pmmir =3D { - .name =3D "PMMIR_EL1", .state =3D ARM_CP_STATE_BOTH, - .opc0 =3D 3, .opc1 =3D 0, .crn =3D 9, .crm =3D 14, .opc2 =3D 6, - .access =3D PL1_R, .accessfn =3D pmreg_access, .type =3D ARM_C= P_CONST, - .fgt =3D FGT_PMMIR_EL1, - .resetvalue =3D 0 - }; - define_one_arm_cp_reg(cpu, &v84_pmmir); - } -} - #ifndef CONFIG_USER_ONLY /* * We don't know until after realize whether there's a GICv3 @@ -7381,9 +6122,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_V6K)) { define_arm_cp_regs(cpu, v6k_cp_reginfo); } - if (arm_feature(env, ARM_FEATURE_V7VE)) { - define_arm_cp_regs(cpu, pmovsset_cp_reginfo); - } if (arm_feature(env, ARM_FEATURE_V7)) { ARMCPRegInfo clidr =3D { .name =3D "CLIDR", .state =3D ARM_CP_STATE_BOTH, @@ -7396,7 +6134,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_one_arm_cp_reg(cpu, &clidr); define_arm_cp_regs(cpu, v7_cp_reginfo); define_debug_regs(cpu); - define_pmu_regs(cpu); } else { define_arm_cp_regs(cpu, not_v7_cp_reginfo); } @@ -7652,26 +6389,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access =3D PL1_R, .type =3D ARM_CP_CONST, .accessfn =3D access_aa64_tid3, .resetvalue =3D 0 }, - { .name =3D "PMCEID0", .state =3D ARM_CP_STATE_AA32, - .cp =3D 15, .opc1 =3D 0, .crn =3D 9, .crm =3D 12, .opc2 =3D = 6, - .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, - .fgt =3D FGT_PMCEIDN_EL0, - .resetvalue =3D extract64(cpu->pmceid0, 0, 32) }, - { .name =3D "PMCEID0_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D= 6, - .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, - .fgt =3D FGT_PMCEIDN_EL0, - .resetvalue =3D cpu->pmceid0 }, - { .name =3D "PMCEID1", .state =3D ARM_CP_STATE_AA32, - .cp =3D 15, .opc1 =3D 0, .crn =3D 9, .crm =3D 12, .opc2 =3D = 7, - .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, - .fgt =3D FGT_PMCEIDN_EL0, - .resetvalue =3D extract64(cpu->pmceid1, 0, 32) }, - { .name =3D "PMCEID1_EL0", .state =3D ARM_CP_STATE_AA64, - .opc0 =3D 3, .opc1 =3D 3, .crn =3D 9, .crm =3D 12, .opc2 =3D= 7, - .access =3D PL0_R, .accessfn =3D pmreg_access, .type =3D ARM= _CP_CONST, - .fgt =3D FGT_PMCEIDN_EL0, - .resetvalue =3D cpu->pmceid1 }, }; #ifdef CONFIG_USER_ONLY static const ARMCPRegUserSpaceInfo v8_user_idregs[] =3D { @@ -8510,6 +7227,8 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, ccsidr2_reginfo); } =20 + define_pm_cpregs(cpu); + #ifndef CONFIG_USER_ONLY /* * Register redirections and aliases must be done last, diff --git a/target/arm/meson.build b/target/arm/meson.build index 7aa81e30ab..07d9271aa4 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -22,6 +22,7 @@ arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files( 'cpu32-stubs.c', )) arm_user_ss.add(files( + 'cpregs-pmu.c', 'debug_helper.c', 'helper.c', 'vfp_fpscr.c', @@ -36,6 +37,7 @@ arm_common_system_ss.add(files( 'arch_dump.c', 'arm-powerctl.c', 'cortex-regs.c', + 'cpregs-pmu.c', 'debug_helper.c', 'helper.c', 'machine.c', --=20 2.43.0