From patchwork Mon Jun 27 18:53:18 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 9201103 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A7DA96075F for ; Mon, 27 Jun 2016 18:54:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 99397285B9 for ; Mon, 27 Jun 2016 18:54:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8E052285BB; Mon, 27 Jun 2016 18:54:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id A2B8E285B9 for ; Mon, 27 Jun 2016 18:54:24 +0000 (UTC) Received: from localhost ([::1]:60453 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bHbfr-0003sB-NR for patchwork-qemu-devel@patchwork.kernel.org; Mon, 27 Jun 2016 14:54:23 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56475) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bHbfG-0003pR-9s for qemu-devel@nongnu.org; Mon, 27 Jun 2016 14:53:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bHbfB-0006BI-TW for qemu-devel@nongnu.org; Mon, 27 Jun 2016 14:53:45 -0400 Received: from mail-bl2nam02on0071.outbound.protection.outlook.com ([104.47.38.71]:19350 helo=NAM02-BL2-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bHbfB-0006BC-Nf for qemu-devel@nongnu.org; Mon, 27 Jun 2016 14:53:41 -0400 Received: from BL2NAM02FT019.eop-nam02.prod.protection.outlook.com (10.152.76.51) by BL2NAM02HT150.eop-nam02.prod.protection.outlook.com (10.152.76.197) with Microsoft SMTP Server (TLS) id 15.1.523.9; Mon, 27 Jun 2016 18:53:39 +0000 Authentication-Results: spf=fail (sender IP is 149.199.60.96) smtp.mailfrom=xilinx.com; linaro.org; dkim=none (message not signed) header.d=none; linaro.org; dmarc=none action=none header.from=xilinx.com; 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 BL2NAM02FT019.mail.protection.outlook.com (10.152.77.166) with Microsoft SMTP Server (TLS) id 15.1.523.9 via Frontend Transport; Mon, 27 Jun 2016 18:53:39 +0000 Received: from 172-16-1-203.xilinx.com ([172.16.1.203]:39813 helo=xsj-tvapsmtp02.xilinx.com) by xsj-tvapsmtpgw01 with esmtp (Exim 4.63) (envelope-from ) id 1bHbf9-0006I7-0Y; Mon, 27 Jun 2016 11:53:39 -0700 Received: from [127.0.0.1] (port=48654 helo=tsj-smtp-dlp1.xlnx.xilinx.com) by xsj-tvapsmtp02.xilinx.com with esmtp (Exim 4.63) (envelope-from ) id 1bHbf8-0006XD-UI; Mon, 27 Jun 2016 11:53:38 -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 u5RIl5Ou022939; Mon, 27 Jun 2016 11:47:05 -0700 Received: from [172.19.74.182] (port=60368 helo=xsjalistai50.xilinx.com) by xsj-tvapsmtp02 with esmtp (Exim 4.63) (envelope-from ) id 1bHbf8-0006XA-2Q; Mon, 27 Jun 2016 11:53:38 -0700 From: Alistair Francis To: , Date: Mon, 27 Jun 2016 11:53:18 -0700 Message-ID: <40d62c7e1bf6e63bb4193ec46b15092a7d981e59.1467053537.git.alistair.francis@xilinx.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: MIME-Version: 1.0 X-RCIS-Action: ALLOW X-TM-AS-MML: disable X-TM-AS-Product-Ver: IMSS-7.1.0.1679-8.0.0.1202-22416.006 X-TM-AS-Result: No--15.405-7.0-31-10 X-imss-scan-details: No--15.405-7.0-31-10 X-TMASE-MatchedRID: DuLmukcnql83AywPeXaPsy2taMI32X8Wc3ewuwbSaG5+YesuCgkiXBte FaJq8mkjzAH8Lwk1uQLaspLkRXRDK7MywGOaB4QQwVaayvK71l+7nrAU9KQxUavM+zzl/BSTt9z UwxhckREtkxfCWkuZ8yLycPkZDpLE64dDeOHpGHAlAj6R+xEl2k+4kuSJytt6LzNBnatH86nA4C 9G/+bRm90V3crzLnk8Otvu50ejSKQ6lAbfYjpbk5Y9D0/NRxoqtZN20SHV1TQOkJQR4QWbsMeti vb6XlQxWGfm6ffYK9DHG+BsUZTTom8LdPkpremHFxqdoICq+IZU3K6aV1ad7efL+zKjW08PJRy0 pjer4Ox9ZOud1SV64OdTsIISNsrfSb33LHGWcKiEwZM25BMds4PfQve7FwfAGiJD6+TqBuUu7K3 kCTZ3O7pUJwN0ZtHiUi43GA8Sjd8GlwKxlQJO5vsgrpDX6v2e7f6JAS2hKPikZrfnHo/JxbwaMR aJSfpgM24ESlEwlq6t0xD7NVaaRX7savaFQtEKRlqShqb35p4hotH7bEpEMvqh2SbpugCfdnXHJ 0U7XkK4qMQaURTY6hYC4jP1GnU/JcygH/wggoRsG7r4Qh7N3HUh2OMdFI0J4aROJEypr9zQRyTL sMcWDBkuLwmeZorT0Iftga7pJ0phjejNb4SeB1VN8laWo90MpVeDgRl9APEiKK6SKh8JW4sZZeG +LsUw585VzGMOFzA9wJeM2pSaRbxAi7jPoeEQftwZ3X11IV0= X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-Forefront-Antispam-Report: CIP:149.199.60.96; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(7916002)(2980300002)(1109001)(1110001)(339900001)(189002)(199003)(81166006)(8676002)(23676002)(586003)(8936002)(81156014)(11100500001)(7846002)(305945005)(356003)(76176999)(86362001)(50466002)(106466001)(5001770100001)(5820100001)(47776003)(229853001)(2870700001)(64026002)(71366001)(2906002)(189998001)(50986999)(19580395003)(19580405001)(36756003)(33646002)(6806005)(87936001)(7696003)(105606002)(2950100001)(85426001)(5003600100003)(50226002)(92566002)(9786002)(77096005)(118296001)(4326007)(107986001)(2004002); DIR:OUT; SFP:1101; SCL:1; SRVR:BL2NAM02HT150; H:xsj-tvapsmtpgw01; FPR:; SPF:Fail; PTR:unknown-60-96.xilinx.com; MX:1; A:1; CAT:NONE; LANG:en; CAT:NONE; X-MS-Office365-Filtering-Correlation-Id: 292bb54e-ab67-409e-d075-08d39ebc5a87 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BL2NAM02HT150; X-Microsoft-Antispam-PRVS: <969c2234d9d04c94ad1d2e985957a277@BL2NAM02HT150.eop-nam02.prod.protection.outlook.com> X-Exchange-Antispam-Report-Test: UriScan:(190756311086443)(192813158149592); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(13023025)(8121501046)(13018025)(13024025)(13015025)(5005006)(13017025)(3002001)(10201501046)(6055026); SRVR:BL2NAM02HT150; BCL:0; PCL:0; RULEID:; SRVR:BL2NAM02HT150; X-Forefront-PRVS: 09860C2161 X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 27 Jun 2016 18:53:39.6137 (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: BL2NAM02HT150 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 104.47.38.71 Subject: [Qemu-devel] [PATCH v9 2/8] register: Add Register API X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: edgar.iglesias@xilinx.com, alistair.francis@xilinx.com, crosthwaitepeter@gmail.com, edgar.iglesias@gmail.com, alex.bennee@linaro.org, afaerber@suse.de, fred.konrad@greensocs.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP This API provides some encapsulation of registers and factors out 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 allows 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 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 Signed-off-by: Alistair Francis Reviewed-by: Alex Bennée Reviewed-by: Peter Maydell --- V9: - Fixup read enable mask logic V8: - Add read enable mask V5: - Convert to using only one memory region V4: - Rebase - Remove the guest error masking - Simplify the unimplemented masking - Use the reserved value in the write calculations - Remove read_lite and write_lite - General fixes to asserts and log printing V3: - Address some comments from Fred hw/core/Makefile.objs | 1 + hw/core/register.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/register.h | 112 +++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) 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 82a9ef8..cfd4840 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -15,4 +15,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..033b03c --- /dev/null +++ b/hw/core/register.c @@ -0,0 +1,160 @@ +/* + * Register Definition API + * + * Copyright (c) 2016 Xilinx Inc. + * Copyright (c) 2013 Peter Crosthwaite + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "qemu/osdep.h" +#include "hw/register.h" +#include "hw/qdev.h" +#include "qemu/log.h" + +static inline void register_write_val(RegisterInfo *reg, uint64_t val) +{ + g_assert(reg->data); + + 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: + g_assert_not_reached(); + } +} + +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: + g_assert_not_reached(); + } + return 0; /* unreachable */ +} + +void register_write(RegisterInfo *reg, uint64_t val, uint64_t we, + const char *prefix, bool debug) +{ + uint64_t old_val, new_val, test, no_w_mask; + const RegisterAccessInfo *ac; + + assert(reg); + + ac = reg->access; + + if (!ac || !ac->name) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state " + "(written value: %#" PRIx64 ")\n", prefix, val); + return; + } + + old_val = reg->data ? register_read_val(reg) : ac->reset; + + test = (old_val ^ val) & ac->rsvd; + if (test) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: change of value in reserved bit" + "fields: %#" PRIx64 ")\n", prefix, test); + } + + test = val & ac->unimp; + if (test) { + qemu_log_mask(LOG_UNIMP, + "%s:%s writing %#" PRIx64 " to unimplemented bits:" \ + " %#" PRIx64 "", + prefix, reg->access->name, val, ac->unimp); + } + + /* Create the no write mask based on the read only, write to clear and + * reserved bit masks. + */ + no_w_mask = ac->ro | ac->w1c | ac->rsvd | ~we; + 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); + } + + if (debug) { + qemu_log("%s:%s: write of value %#" PRIx64 "\n", prefix, ac->name, + new_val); + } + + register_write_val(reg, new_val); + + if (ac->post_write) { + ac->post_write(reg, new_val); + } +} + +uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix, + bool debug) +{ + 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", + prefix); + return 0; + } + + ret = reg->data ? register_read_val(reg) : ac->reset; + + register_write_val(reg, ret & ~(ac->cor & re)); + + /* Mask based on the read enable size */ + ret &= re; + + if (ac->post_read) { + ret = ac->post_read(reg, ret); + } + + if (debug) { + qemu_log("%s:%s: read of value %#" PRIx64 "\n", prefix, + ac->name, ret); + } + + return ret; +} + +void register_reset(RegisterInfo *reg) +{ + g_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..6a2bc75 --- /dev/null +++ b/include/hw/register.h @@ -0,0 +1,112 @@ +/* + * Register Definition API + * + * Copyright (c) 2016 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; + +/** + * 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 + * + * @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; + uint64_t unimp; + + 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 description 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; + + void *opaque; +}; + +/** + * write a value to a register, subject to its restrictions + * @reg: register to write to + * @val: value to write + * @we: write enable mask + * @prefix: The device prefix that should be printed before the register name + * @debug: Should the write operation debug information be printed? + */ + +void register_write(RegisterInfo *reg, uint64_t val, uint64_t we, + const char *prefix, bool debug); + +/** + * read a value from a register, subject to its restrictions + * @reg: register to read from + * @re: read enable mask + * @prefix: The device prefix that should be printed before the register name + * @debug: Should the read operation debug information be printed? + * returns: value read + */ + +uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix, + bool debug); + +/** + * reset a register + * @reg: register to reset + */ + +void register_reset(RegisterInfo *reg); + +#endif