From patchwork Wed Jul 29 20:24:36 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 501822 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 8CF4814030C for ; Thu, 30 Jul 2015 06:26:07 +1000 (AEST) Received: from localhost ([::1]:36914 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZKXvR-0006NJ-Nb for incoming@patchwork.ozlabs.org; Wed, 29 Jul 2015 16:26:05 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55178) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZKXuK-0004We-Di for qemu-devel@nongnu.org; Wed, 29 Jul 2015 16:24:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZKXuA-0002Ui-Ue for qemu-devel@nongnu.org; Wed, 29 Jul 2015 16:24:56 -0400 Received: from mail-bn1bon0090.outbound.protection.outlook.com ([157.56.111.90]:53952 helo=na01-bn1-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZKXuA-0002Tg-MP for qemu-devel@nongnu.org; Wed, 29 Jul 2015 16:24:46 -0400 Received: from BY2FFO11OLC009.protection.gbl (10.1.14.30) by BY2FFO11HUB046.protection.gbl (10.1.14.86) with Microsoft SMTP Server (TLS) id 15.1.231.11; Wed, 29 Jul 2015 20:24:44 +0000 Authentication-Results: spf=fail (sender IP is 149.199.60.96) smtp.mailfrom=xilinx.com; suse.de; dkim=none (message not signed) header.d=none; Received-SPF: Fail (protection.outlook.com: domain of xilinx.com does not designate 149.199.60.96 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.60.96; helo=xsj-tvapsmtpgw01; Received: from xsj-tvapsmtpgw01 (149.199.60.96) by BY2FFO11OLC009.mail.protection.outlook.com (10.1.15.0) with Microsoft SMTP Server (TLS) id 15.1.231.11 via Frontend Transport; Wed, 29 Jul 2015 20:24:44 +0000 Received: from 172-16-1-203.xilinx.com ([172.16.1.203]:49634 helo=xsj-tvapsmtp02.xilinx.com) by xsj-tvapsmtpgw01 with esmtp (Exim 4.63) (envelope-from ) id 1ZKXu7-0003Zo-Qs; Wed, 29 Jul 2015 13:24:43 -0700 Received: from [127.0.0.1] (port=39033 helo=tsj-smtp-dlp1.xlnx.xilinx.com) by xsj-tvapsmtp02.xilinx.com with esmtp (Exim 4.63) (envelope-from ) id 1ZKXu7-0004S2-Lv; Wed, 29 Jul 2015 13:24:43 -0700 Received: from xsj-tvapsmtp02 (xsj-tvapsmtp02.xilinx.com [172.16.1.203]) by tsj-smtp-dlp1.xlnx.xilinx.com (8.13.8/8.13.1) with ESMTP id t6TKK1YD010126; Wed, 29 Jul 2015 13:20:02 -0700 Received: from [172.19.5.153] (port=49419 helo=xsjrdevl46.xilinx.com) by xsj-tvapsmtp02 with esmtp (Exim 4.63) (envelope-from ) id 1ZKXu1-0004Rq-0V; Wed, 29 Jul 2015 13:24:37 -0700 From: Alistair Francis To: Date: Wed, 29 Jul 2015 13:24:36 -0700 Message-ID: <9b14a6062370daa861eb82d9fdc9f5c7489995a9.1438200827.git.alistair.francis@xilinx.com> X-Mailer: git-send-email 2.1.1 In-Reply-To: References: X-RCIS-Action: ALLOW X-TM-AS-MML: disable X-TM-AS-Product-Ver: IMSS-7.1.0.1679-8.0.0.1202-21710.005 X-TM-AS-Result: No--18.712-7.0-31-10 X-imss-scan-details: No--18.712-7.0-31-10 X-TMASE-MatchedRID: ihLZuK09RcT/uyguzMmOKARH1Nr7oERdjxcjD6EuBs+67Q3uPo9KIzCH Bv5Fitn/0LqCaNlK8HJ6G6AL0FZqL2mqpgBD4nq5joyKzEmtrEczc8FC0MEwT0dmDSBYfnJRKSy Ml4Bp7a7s1fZuShlORrLt1t7uCIbaisUdOYwWFvfqsFlQXzLr6B0PsyMp50OO8ayRINFASnA7QY 7O2lBJhNafdb8k4ITVAEjOD2KPH1PhfwdYxI1fupEbNXwHGDRxFRVzane0XL5xoL3YvJLZdEZMO 3oWMNTyWRXM1BNPHVM8qHVkKaIEhvzYctv/oCAEydRN/Yyg4ph6zDxGcFEbCtHOIxsF5Mj5tn2P 53ro+JNpWCw8jpYXDxyw4hptc7XXfU9pW8KI0q/IOn6NK8S1a+LTTDK9VdnFYjjBDVir93T2wtJ dngDYbSD0PwU0Y/hfH/DHUeW7+Tth44VlLBLudBcanaCAqviGVNyumldWne3ny/syo1tPDyUctK Y3q+DsfWTrndUleuDnU7CCEjbK3xZK05xEkCkCQ16yrdVRtxx9/z2DYqHY7cSiwizsgluQQxt1j 3x9x3hQt+pbl5nznrQTHgp2KOvwIVYGYkaCAUxLc5N+0s1+DVPgO2JKQydYYe1mzp7dkwceBo3q eJi8bVkvX5/Fh8kHULQAqSG9Qd64aCSQ7hdJ72MGiV639iF0OFrEjYh/1F74JyR+b5tvoOXoAzg BreAWXT/VjIWHsSyUcK7jAZJCQhp7fC7WQET3VU3yVpaj3QxmEl4mTr2Jj7V5fSMRD1zql9+Zxp HSoIvi8zVgXoAltsZfJcPORGlUC24oEZ6SpSk+Mqg+CyrtwA== X-EOPAttributedMessage: 0 X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11OLC009; 1:k6NYNsMfCE9LpAphkP9tlw2SH/xOa3cpXkJmXD1GeIgTSwuMBlMltZxMOmKFC+KkluKLaY2tmWaUUqm7ILcWEX0vdxNmZ8AQVkJMUKfeQGHcbL5zUp+lDB2Ap1CLkXWvKb1bANWgN7U3P0p+w/qgVy/1P6/x64qM+NDEiBnKZNfmlnUc338wpJRjbWkHjtH9H4A2f2MqN1zjRhUjqrxUbnpVgbEA1n3MBmZwh8YgeZixPnYbILbaqHtVigevT6XwHKgucgCf3vMn+oztFs85J6lG6a/NKiBXAtSMwn1DWyzxL5lGED1LDvXm/J0iah6N X-Forefront-Antispam-Report: CIP:149.199.60.96; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(2980300002)(339900001)(189002)(199003)(51444003)(2950100001)(76176999)(50986999)(106466001)(77096005)(71366001)(92566002)(50226001)(46102003)(5003940100001)(62966003)(33646002)(77156002)(64026002)(6806004)(19580395003)(36756003)(105606002)(19580405001)(50466002)(2351001)(229853001)(5003600100002)(48376002)(110136002)(189998001)(87936001)(5001920100001)(118296001)(85426001)(5001960100002)(47776003)(86362001)(107986001); DIR:OUT; SFP:1101; SCL:1; SRVR:BY2FFO11HUB046; H:xsj-tvapsmtpgw01; FPR:; SPF:Fail; MLV:nov; MX:1; A:1; PTR:unknown-60-96.xilinx.com; LANG:en; MIME-Version: 1.0 X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11HUB046; 2:W5TO/i9gbUErxiZViqD84048HevfdWqBtr/2YeE+g8Q7zm6u9OWiAxSYlVMnIXNS6U4oSoo83o3zMiP7JlyoPtg1SrVUJwx2qJHzrvzktPHOWHpAoK+V0mDhbGm9Mns05NFo832fWp76EFDIrjhKd/Vz28LBtJY0l3XKdhbDxoQ=; 3:8qSCbyf7TQqqGMddQrYjk4Af/rVBCis2OcPTJB/9kD2joMRTdve/QV+42lvnFmPZKozOjw220OtrPHMzvyRJG2Jk5bEoU0xBsNY9BqMmDvOLzTt9tYosdIkBesIgcZr8IzDHjvt46IMIp00Us0NkWpEGAidZZgtYEYusK+bjtIquzKeKXTKFkJWn0GQAFwVYZpHruCQFjRASRRbkcVVLX2G/frH8TJI4pQNU+oWa/AM=; 25:ddhuAWUxUqi6Y3BvoNszhiX2nOrNTGcrPXyF36zWIJTL1wml1mihLeVueObWuQTZWrlu8H9KpblzRji7+U1hCvvVVHyRDl78seuLfVE4l3b4Zu8upMnwowl3D+95QBacfY3bOnlWqKMOrQhRbjmSJDd6AhK3lJzeWSPu4fTlWeC7XTOggjlELZL+6H2La3LW68tTzoMjSyZSOqD9K5EXelzFdAF8PnAzYH2yMrRpTIgcJ/+lbqFpzf9rUI7Kg1xwdauFzJrZDG8fa8JWFf4GtA== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2FFO11HUB046; X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11HUB046; 20:miuycf66r5rlW/8x+tnyNMx40cKvbWW5QoXb+10ZJZOFpdGZtmo/K+sEyYE6ox6UuFC9ZLz92g4V+LwcTT4UYMDUsPbPx0XKCpBr9nevTpRleP+bYcTVOMA7dgbHSTsg1SSHnBN1ViuL4cnOayA2wRbRebH15ExVXXhapK0GHyQDn1OETtnx/C1slRj1fmyvMXPFYVyzQ5R/g4nKn0TvwVMLk6tHF/p7teJ5SP8kOy34igIAa9aI3Wx3k9jBmEPVUH2a9UyQ6oJM8Zb7f0DZryeaVuQeSOPIbDxxJFBYlci3hy3IZfFaJqWUcjExz2FtDEyAJUascx/+WNdNg8NSXX0gW/a+UiMMQmDP3OS7A40jtupr7N2IZx4/rCyjD1JS8y4TJJTU9R/iLSLYc2FmC/qcQZ6BB+juseLG3MQrXCu7khUGy3cM2NJqUHei4x8oVjulUkq/FBT2ZFwXWc6FOZr7/mw1EnK0CqAotf8x5FL4uWVvZxBTgFkuAqtzrwkD; 4:ctg2TMwS7qZ2Th/pnC/B5+b3GEyFHtzkq0X1mi/BQdur/QByniNOmMU2HWJwAmKTDs/Yhi61tAQAnxnr8aJk+C2FeWJJ3uKycDdbVBKbKhII9j4n7ZNgCDA0Gr+u76OlebcH9rXvcLDea2bimQ95m9HcgadjVNpUeDjzIU6AiECaoMD0nFWHRwkht3oL9y8t9CyeCH8wqA2jxMGXFl2QOjXLjw74ruvvRKYK9k9gRZ8gO3L9rrPOLNgGMCZTGLzVdIYzesq8ecQ3LzR5jv2/RtT9Umd09H9rXX4wiEkvR5E= BY2FFO11HUB046: X-MS-Exchange-Organization-RulesExecuted X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(5005006)(3002001); SRVR:BY2FFO11HUB046; BCL:0; PCL:0; RULEID:; SRVR:BY2FFO11HUB046; X-Forefront-PRVS: 0652EA5565 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BY2FFO11HUB046; 23:cqN9xzmz/KsxVd+PrSiw00w+O63Mzs6/U+5gFiCR?= =?us-ascii?Q?GcCt+j9iiVnwqNmytcqzJ2vn4Qprt4Bsyt7C4aJ3IAKou50MJ4+C8pxU2Jya?= =?us-ascii?Q?Jkw/r0E8uvl3NG7W/jX17ACjwewx3qLLSgGUGs/SAbHxsR3FWSn/ohmNKxrf?= =?us-ascii?Q?1mo5Nlt5KmZ3tcU2HXkxvb24vgMJFDqp/5y3kj+yojCUKgHKTy0aKujhToJM?= =?us-ascii?Q?G7O56huieL4c5asaXR2Z1JcSGKlfsN1fjh4EjSIsQF+XVbSEi9Wt0NXS+mN1?= =?us-ascii?Q?BLJmYBnHJ8nzVdx8vXc+ukxsKWURThossE7MCMiZaa+7XX2VSDSLwT3TtOQu?= =?us-ascii?Q?FFYWDMor/TD5y+NrySv5NMWPwbxjnTHChQQcaXKlxk5eB1i5zZbMmGrQAS8b?= =?us-ascii?Q?oebWVyo6UQfda1wfNWamwRmnVi1780bu3jcF8SRUGJBl/rdhionYk/wFbv0t?= =?us-ascii?Q?J34KxTwiIfgxAoTSHPDNry6MCs6+xqL8+XGRcgih2CKSax0bXZ1q0bGiN0Yz?= =?us-ascii?Q?elyk7+6qoSuFWwkF4+U6Myo9anq6BUaoYQfBiigzhCiGnSd6DdaelK58rXL+?= =?us-ascii?Q?AXLfJ2xNYeesYTsyriFu2zyhmj8yVZKLSLyWT5Y2mhrR46SZBzj+MHZ1FRj7?= =?us-ascii?Q?ev0vL7K20FNx6x1BuPA8+x0kJd0Sui1G4mpVXpCc3a6T6KxNpjRqdzvAfJlH?= =?us-ascii?Q?Gf12F4Iti53vAMmsVSgE4RC0rdPPZgwGtIqN8bLFLtSGJe7PxUNVNyDhhxMe?= =?us-ascii?Q?m6PTcoXqgmvEF4IIBFwlQRP6M/7KveOg6SrIf04Y0DFfpcdThIrLlfeW9EPs?= =?us-ascii?Q?hVHo3yGLHlAvDrTat4V0u+Qm2Ep/MkTlVfyR/duIZKM4JUyMF2MlTqeO3IK8?= =?us-ascii?Q?a11v4NStttQZ434ulL7isufqSnv4FiDgEAocb/0cYdJrMbSkhflgPAIdKoIT?= =?us-ascii?Q?V+zZ5h0lso2U2YZtxpKzROwYr0jFVARA4RyvS/F8BLb3difLJ/2jnESpzdHs?= =?us-ascii?Q?ZyEKmozfWy1Lepa7yJPVb1QC82KWFTzs/gaoaQ1Djl7cL6ao37HUknyIPaJL?= =?us-ascii?Q?KML1b0w0N7C2n69B/rfXZw5hcjOP?= X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11HUB046; 5:pHaCpaEQo0BgaZEyQ/LgMbbO/d2eAI8zJzTuKrezSCesCOYlm1V0hWNx7x2EfAd6BXSsF+aL4q2shF6DhBvYvbm7XkyXPf7kk95Yn4EYKIgblo046WEeG+1rnFv7LTiRLf6n8GaUIvcK23j5ONvC7g==; 24:CYyym/HDK3o6Yox8jz6GWd7lxVL5SomudsO+sPa3NBq8MwViiZ8Y6xh4Bgkn2nx2XEBFqqRifGJb+2yxWfIlG/str+cIuLgWYWIiOrNq50U= X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Jul 2015 20:24:44.2194 (UTC) X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.60.96]; Helo=[xsj-tvapsmtpgw01] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2FFO11HUB046 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x (barebone) [generic] [fuzzy] X-Received-From: 157.56.111.90 Cc: edgar.iglesias@xilinx.com, peter.maydell@linaro.org, alistair.francis@xilinx.com, crosthwaitepeter@gmail.com, edgar.iglesias@gmail.com, afaerber@suse.de Subject: [Qemu-devel] [PATCH v1 01/15] register: Add Register API X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Peter Crosthwaite This API provides some encapsulation of registers and factors our some common functionality to common code. Bits of device state (usually MMIO registers), often have all sorts of access restrictions and semantics associated with them. This API allow you to define what those restrictions are on a bit-by-bit basis. Helper functions are then used to access the register which observe the semantics defined by the RegisterAccessInfo struct. Some features: Bits can be marked as read_only (ro field) Bits can be marked as write-1-clear (w1c field) Bits can be marked as reserved (rsvd field) Reset values can be defined (reset) Bits can throw guest errors when written certain values (ge0, ge1) Bits can throw unimp errors when written certain values (ui0, ui1) Bits can be marked clear on read (cor) Pre and post action callbacks can be added to read and write ops Verbose debugging info can be enabled/disabled Useful for defining device register spaces in a data driven way. Cuts down on a lot of the verbosity and repetition in the switch-case blocks in the standard foo_mmio_read/write functions. Also useful for automated generation of device models from hardware design sources. Signed-off-by: Peter Crosthwaite --- changed from v2: Simplified! Removed pre-read, nwx, wo Removed byte loops (Gerd Review) Made data pointer optional Added fast paths for simple registers Moved into hw/core and include/hw (Paolo Review) changed from v1: Rebranded as the "Register API" - I think thats probably what it is. Near total rewrite of implementation. De-arrayified reset (this is client/Memory APIs job). Moved out of bitops into its own file (Blue review) Added debug, the register pointer, and prefix to a struct (Blue Review) Made 64-bit to play friendlier with memory API (Blue review) Made backend storage uint8_t (MST review) Added read/write callbacks (Blue review) Added ui0, ui1 (Blue review) Moved re-purposed width (now byte width defining actual storage size) Arrayified ge0, ge1 (ui0, ui1 too) and added .reason Added wo field (not an April fools joke - this has genuine meaning here) Added we mask to write accessor hw/core/Makefile.objs | 1 + hw/core/register.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/register.h | 132 ++++++++++++++++++++++++++++++++++ 3 files changed, 319 insertions(+), 0 deletions(-) create mode 100644 hw/core/register.c create mode 100644 include/hw/register.h diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index abb3560..bf95db5 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -14,4 +14,5 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o common-obj-$(CONFIG_SOFTMMU) += null-machine.o common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o +common-obj-$(CONFIG_SOFTMMU) += register.o common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o diff --git a/hw/core/register.c b/hw/core/register.c new file mode 100644 index 0000000..02a4376 --- /dev/null +++ b/hw/core/register.c @@ -0,0 +1,186 @@ +/* + * Register Definition API + * + * Copyright (c) 2013 Xilinx Inc. + * Copyright (c) 2013 Peter Crosthwaite + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include "hw/register.h" +#include "qemu/log.h" + +static inline void register_write_log(RegisterInfo *reg, int dir, uint64_t val, + int mask, const char *msg, + const char *reason) +{ + qemu_log_mask(mask, "%s:%s bits %#" PRIx64 " %s write of %d%s%s\n", + reg->prefix, reg->access->name, val, msg, dir, + reason ? ": " : "", reason ? reason : ""); +} + +static inline void register_write_val(RegisterInfo *reg, uint64_t val) +{ + if (!reg->data) { + return; + } + switch (reg->data_size) { + case 1: + *(uint8_t *)reg->data = val; + break; + case 2: + *(uint16_t *)reg->data = val; + break; + case 4: + *(uint32_t *)reg->data = val; + break; + case 8: + *(uint64_t *)reg->data = val; + break; + default: + abort(); + } +} + +static inline uint64_t register_read_val(RegisterInfo *reg) +{ + switch (reg->data_size) { + case 1: + return *(uint8_t *)reg->data; + case 2: + return *(uint16_t *)reg->data; + case 4: + return *(uint32_t *)reg->data; + case 8: + return *(uint64_t *)reg->data; + default: + abort(); + } + return 0; /* unreachable */ +} + +void register_write(RegisterInfo *reg, uint64_t val, uint64_t we) +{ + uint64_t old_val, new_val, test, no_w_mask; + const RegisterAccessInfo *ac; + const RegisterAccessError *rae; + + assert(reg); + + ac = reg->access; + old_val = reg->data ? register_read_val(reg) : ac->reset; + if (reg->write_lite && !~we) { /* fast path!! */ + new_val = val; + goto register_write_fast; + } + + if (!ac || !ac->name) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state " + "(written value: %#" PRIx64 ")\n", reg->prefix, val); + return; + } + + no_w_mask = ac->ro | ac->w1c | ~we; + + if (reg->debug) { + qemu_log("%s:%s: write of value %#" PRIx64 "\n", reg->prefix, ac->name, + val); + } + + if (qemu_loglevel_mask(LOG_GUEST_ERROR)) { + test = (old_val ^ val) & ac->rsvd; + if (test) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: change of value in reserved bit" + "fields: %#" PRIx64 ")\n", reg->prefix, test); + } + for (rae = ac->ge1; rae && rae->mask; rae++) { + test = val & rae->mask; + if (test) { + register_write_log(reg, 1, test, LOG_GUEST_ERROR, + "invalid", rae->reason); + } + } + for (rae = ac->ge0; rae && rae->mask; rae++) { + test = ~val & rae->mask; + if (test) { + register_write_log(reg, 0, test, LOG_GUEST_ERROR, + "invalid", rae->reason); + } + } + } + + if (qemu_loglevel_mask(LOG_UNIMP)) { + for (rae = ac->ui1; rae && rae->mask; rae++) { + test = val & rae->mask; + if (test) { + register_write_log(reg, 1, test, LOG_GUEST_ERROR, + "unimplmented", rae->reason); + } + } + for (rae = ac->ui0; rae && rae->mask; rae++) { + test = ~val & rae->mask; + if (test) { + register_write_log(reg, 0, test, LOG_GUEST_ERROR, + "unimplemented", rae->reason); + } + } + } + + new_val = (val & ~no_w_mask) | (old_val & no_w_mask); + new_val &= ~(val & ac->w1c); + + if (ac->pre_write) { + new_val = ac->pre_write(reg, new_val); + } +register_write_fast: + register_write_val(reg, new_val); + if (ac->post_write) { + ac->post_write(reg, new_val); + } +} + +uint64_t register_read(RegisterInfo *reg) +{ + uint64_t ret; + const RegisterAccessInfo *ac; + + assert(reg); + + ac = reg->access; + if (!ac || !ac->name) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: read from undefined device state\n", + reg->prefix); + return 0; + } + + ret = reg->data ? register_read_val(reg) : ac->reset; + + if (!reg->read_lite) { + register_write_val(reg, ret & ~ac->cor); + } + + if (ac->post_read) { + ret = ac->post_read(reg, ret); + } + + if (!reg->read_lite) { + if (reg->debug) { + qemu_log("%s:%s: read of value %#" PRIx64 "\n", reg->prefix, + ac->name, ret); + } + } + + return ret; +} + +void register_reset(RegisterInfo *reg) +{ + assert(reg); + + if (!reg->data || !reg->access) { + return; + } + + register_write_val(reg, reg->access->reset); +} diff --git a/include/hw/register.h b/include/hw/register.h new file mode 100644 index 0000000..249f458 --- /dev/null +++ b/include/hw/register.h @@ -0,0 +1,132 @@ +/* + * Register Definition API + * + * Copyright (c) 2013 Xilinx Inc. + * Copyright (c) 2013 Peter Crosthwaite + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef REGISTER_H +#define REGISTER_H + +#include "exec/memory.h" + +typedef struct RegisterInfo RegisterInfo; +typedef struct RegisterAccessInfo RegisterAccessInfo; + +/** + * A register access error message + * @mask: Bits in the register the error applies to + * @reason: Reason why this access is an error + */ + +typedef struct RegisterAccessError { + uint64_t mask; + const char *reason; +} RegisterAccessError; + +/** + * Access description for a register that is part of guest accessible device + * state. + * + * @name: String name of the register + * @ro: whether or not the bit is read-only + * @w1c: bits with the common write 1 to clear semantic. + * @reset: reset value. + * @cor: Bits that are clear on read + * @rsvd: Bits that are reserved and should not be changed + * + * @ge1: Bits that when written 1 indicate a guest error + * @ge0: Bits that when written 0 indicate a guest error + * @ui1: Bits that when written 1 indicate use of an unimplemented feature + * @ui0: Bits that when written 0 indicate use of an unimplemented feature + * + * @pre_write: Pre write callback. Passed the value that's to be written, + * immediately before the actual write. The returned value is what is written, + * giving the handler a chance to modify the written value. + * @post_write: Post write callback. Passed the written value. Most write side + * effects should be implemented here. + * + * @post_read: Post read callback. Passes the value that is about to be returned + * for a read. The return value from this function is what is ultimately read, + * allowing this function to modify the value before return to the client. + */ + +struct RegisterAccessInfo { + const char *name; + uint64_t ro; + uint64_t w1c; + uint64_t reset; + uint64_t cor; + uint64_t rsvd; + + const RegisterAccessError *ge0; + const RegisterAccessError *ge1; + const RegisterAccessError *ui0; + const RegisterAccessError *ui1; + + uint64_t (*pre_write)(RegisterInfo *reg, uint64_t val); + void (*post_write)(RegisterInfo *reg, uint64_t val); + + uint64_t (*post_read)(RegisterInfo *reg, uint64_t val); +}; + +/** + * A register that is part of guest accessible state + * @data: pointer to the register data. Will be cast + * to the relevant uint type depending on data_size. + * @data_size: Size of the register in bytes. Must be + * 1, 2, 4 or 8 + * + * @access: Access desciption of this register + * + * @debug: Whether or not verbose debug is enabled + * @prefix: String prefix for log and debug messages + * + * @opaque: Opaque data for the register + */ + +struct RegisterInfo { + void *data; + int data_size; + + const RegisterAccessInfo *access; + + bool debug; + const char *prefix; + + void *opaque; + + /*< private >*/ + + bool read_lite; + bool write_lite; +}; + +/** + * write a value to a register, subject to its restrictions + * @reg: register to write to + * @val: value to write + * @we: write enable mask + */ + +void register_write(RegisterInfo *reg, uint64_t val, uint64_t we); + +/** + * read a value from a register, subject to its restrictions + * @reg: register to read from + * returns: value read + */ + +uint64_t register_read(RegisterInfo *reg); + +/** + * reset a register + * @reg: register to reset + */ + +void register_reset(RegisterInfo *reg); + +#endif