From patchwork Sun Mar 3 06:13:02 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Crosthwaite X-Patchwork-Id: 224533 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 82CCC2C02FC for ; Sun, 3 Mar 2013 17:15:12 +1100 (EST) Received: from localhost ([::1]:41939 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UC2CT-0000Gd-Ie for incoming@patchwork.ozlabs.org; Sun, 03 Mar 2013 01:15:09 -0500 Received: from eggs.gnu.org ([208.118.235.92]:52561) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UC2C9-0000EU-SY for qemu-devel@nongnu.org; Sun, 03 Mar 2013 01:14:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UC2C8-0001lY-42 for qemu-devel@nongnu.org; Sun, 03 Mar 2013 01:14:49 -0500 Received: from mail-da0-f45.google.com ([209.85.210.45]:55515) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UC2C7-0001lS-RK for qemu-devel@nongnu.org; Sun, 03 Mar 2013 01:14:48 -0500 Received: by mail-da0-f45.google.com with SMTP id v40so2035679dad.32 for ; Sat, 02 Mar 2013 22:14:47 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:sender:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:in-reply-to:references:x-gm-message-state; bh=uvxMVZ7+duGpXtDOnOBwYK5yDLwV2N+1xxRoKaIHGqU=; b=RmyfHx5TvmoJMS/+kZEGgWB6ERW9nPMBk1tBIIZX3NGmbfccAYat9NtGUemHCz7I24 Au4VG2O8Bj/NcOsLF9NjSHuErsWQ9u2MtvKGUNWhRb2uo2bQKRIht1R4/s1OHpG54zD+ WjM69rRr5XSb8tGuIuAEZXgijjrwqX1kYuUjVBvd/DV40i3Lxfnk3noR7HHZ7fLyrNnM EYRDbjeDetWkN0NmIvvFO0DQ7zIsnNn01lLTUgFKfUGxmhjNEYjdw7e54R37i1cpi6Pr bnEszwtL4L1AxCZXKtmQcbVRR2MFTDuqye6j3X1uymHexf+a1tzRE8SUVuATLAoAZ5Cu ZkRQ== X-Received: by 10.66.146.99 with SMTP id tb3mr26112563pab.99.1362291287034; Sat, 02 Mar 2013 22:14:47 -0800 (PST) Received: from localhost ([149.199.62.254]) by mx.google.com with ESMTPS id j7sm19165540pay.10.2013.03.02.22.14.43 (version=TLSv1.1 cipher=RC4-SHA bits=128/128); Sat, 02 Mar 2013 22:14:46 -0800 (PST) From: Peter Crosthwaite To: qemu-devel@nongnu.org Date: Sun, 3 Mar 2013 16:13:02 +1000 Message-Id: <11e3c93f4c64bda4ef46ec9de8dd8b4fa88b3ec5.1362290776.git.peter.crosthwaite@xilinx.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: References: In-Reply-To: References: X-Gm-Message-State: ALoCoQlUZ4gH50yl+wkeWUM4/PBPsZ5KPkO/XnTtCWSao00OwRjtZN//7xN4JYf/ygi7yAevpAsg X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 209.85.210.45 Cc: peter.maydell@linaro.org, Peter Crosthwaite , kraxel@redhat.com Subject: [Qemu-devel] [RFC PATCH v1 2/4] bitops: Add UInt32StateInfo and helper functions 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 This struct and functions provide some encapsulation of the uint32_t type to make it more friendly for use as guest accessible device state. Bits of device state (usually MMIO registers), often have all sorts of access restrictions and semantics associated with them. This struct allow you to define what whose restrictions are on a bit-by-bit basis. Helper functions are then used to access the uint32_t which observe the semantics defined by the UInt32StateInfo 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 sticky (nw0 and nw1) Reset values can be defined (reset) Bits can be marked to throw guest errors when written certain values (ge0, ge1) Bits can be marked clear on read (cor) Regsiters can be truncated in width (width) 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. Signed-off-by: Peter Crosthwaite --- include/qemu/bitops.h | 59 ++++++++++++++++++++++++++++++++++++++++ util/bitops.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 0 deletions(-) diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index affcc96..8ad0290 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -273,4 +273,63 @@ static inline uint64_t deposit64(uint64_t value, int start, int length, return (value & ~mask) | ((fieldval << start) & mask); } +/** + * A descriptor for a Uint32 that is part of guest accessible device state + * @ro: whether or not the bit is read-only state comming out of reset + * @w1c: bits with the common write 1 to clear semantic. + * @nw0: bits that cant be written with a 0 by the guest (sticky 1) + * @nw1: bits that cant be written with a 1 by the guest (sticky 0) + * @reset: reset value. + * @ge1: Bits that when written 1 indicate a guest error + * @ge0: Bits that when written 0 indicate a guest error + * @cor: Bits that are clear on read + * @width: width of the uint32t. Only the @width least significant bits are + * valid. All others are silent Read-as-reset/WI. + */ + +typedef struct UInt32StateInfo { + const char *name; + uint32_t ro; + uint32_t w1c; + uint32_t nw0; + uint32_t nw1; + uint32_t reset; + uint32_t ge1; + uint32_t ge0; + uint32_t cor; + int width; +} UInt32StateInfo; + +/** + * reset an array of u32s + * @array: array of u32s to reset + * @info: corresponding array of UInt32StateInfos to get reset values from + * @num: number of values to reset + */ + +void uint32_array_reset(uint32_t *array, const UInt32StateInfo *info, int num); + +/** + * write a value to a uint32_t subject to its restrictions + * @state: Pointer to location to be written + * @info: Definition of variable + * @val: value to write + * @prefix: Debug and error message prefix + * @debug: Turn on noisy debug printfery + */ + +void uint32_write(uint32_t *state, const UInt32StateInfo *info, uint32_t val, + const char *prefix, bool debug); + +/** + * write a value from a uint32_t subject to its restrictions + * @state: Pointer to location to be read + * @info: Definition of variable + * @prefix: Debug and error message prefix + * @debug: Turn on noisy debug printfery + */ + +uint32_t uint32_read(uint32_t *state, const UInt32StateInfo *info, + const char *prefix, bool debug); + #endif diff --git a/util/bitops.c b/util/bitops.c index e72237a..51db476 100644 --- a/util/bitops.c +++ b/util/bitops.c @@ -11,6 +11,8 @@ * 2 of the License, or (at your option) any later version. */ +#include "qemu-common.h" +#include "qemu/log.h" #include "qemu/bitops.h" #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) @@ -140,3 +142,72 @@ unsigned long find_last_bit(const unsigned long *addr, unsigned long size) /* Not found */ return size; } +void uint32_array_reset(uint32_t *state, const UInt32StateInfo *info, int num) +{ + int i = 0; + + for (i = 0; i < num; ++i) { + state[i] = info[i].reset; + } +} + +void uint32_write(uint32_t *state, const UInt32StateInfo *info, uint32_t val, + const char *prefix, bool debug) +{ + int i; + uint32_t new_val; + int width = info->width ? info->width : 32; + + uint32_t no_w0_mask = info->ro | info->w1c | info->nw0 | + ~((1ull << width) - 1); + uint32_t no_w1_mask = info->ro | info->w1c | info->nw1 | + ~((1ull << width) - 1); + + if (!info->name) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state " + "(written value: %#08x)\n", prefix, val); + return; + } + + if (debug) { + fprintf(stderr, "%s:%s: write of value %08x\n", prefix, info->name, + val); + } + + /*FIXME: skip over if no LOG_GUEST_ERROR */ + for (i = 0; i <= 1; ++i) { + uint32_t test = (val ^ (i ? 0 : ~0)) & (i ? info->ge1 : info->ge0); + if (test) { + qemu_log_mask(LOG_GUEST_ERROR, "%s:%s bits %#08x may not be written" + " to %d\n", prefix, info->name, test, i); + } + } + + new_val = val & ~(no_w1_mask & val); + new_val |= no_w1_mask & *state & val; + new_val |= no_w0_mask & *state & ~val; + new_val &= ~(val & info->w1c); + *state = new_val; +} + +uint32_t uint32_read(uint32_t *state, const UInt32StateInfo *info, + const char *prefix, bool debug) +{ + uint32_t ret = *state; + + /* clear on read */ + ret &= ~info->cor; + *state = ret; + + if (!info->name) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: read from undefined device state " + "(read value: %#08x)\n", prefix, ret); + return ret; + } + + if (debug) { + fprintf(stderr, "%s:%s: read of value %08x\n", prefix, info->name, ret); + } + + return ret; +}