From patchwork Mon Mar 10 15:04:55 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010297 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D49BAC282EC for ; Mon, 10 Mar 2025 15:18:15 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1trenq-0002Lf-JW; Mon, 10 Mar 2025 11:12:27 -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 1tren3-00025F-2v for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:37 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremu-0007fN-OG for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:36 -0400 Received: (qmail 30619 invoked by uid 484); 10 Mar 2025 15:11:09 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.28661 secs); 10 Mar 2025 15:11:09 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:08 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann Subject: [PATCH 01/16] mcd: Introduce Multi-Core Debug (MCD) API Date: Mon, 10 Mar 2025 16:04:55 +0100 Message-Id: <20250310150510.200607-2-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Formatting changes to mcd_api.h to compily with QEMU's coding style guidelines: * limit line width to 80 * convert Doxygen to kernel-doc comments * avoid architecture specific defines The original MCD API version can be found at: https://repo.lauterbach.com/sprint_mcd_api_v1_0.zip Signed-off-by: Mario Fleischmann --- MAINTAINERS | 6 + docs/interop/index.rst | 1 + docs/interop/mcd.rst | 44 + mcd/mcd_api.h | 3963 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 4014 insertions(+) create mode 100644 docs/interop/mcd.rst create mode 100644 mcd/mcd_api.h diff --git a/MAINTAINERS b/MAINTAINERS index 618d75f087..448fb55a09 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3101,6 +3101,12 @@ F: scripts/feature_to_c.py F: scripts/probe-gdb-support.py T: git https://gitlab.com/stsquad/qemu gdbstub/next +MCD +M: Mario Fleischmann +S: Maintained +F: mcd/* +F: docs/interop/mcd.rst + Memory API M: Paolo Bonzini M: Peter Xu diff --git a/docs/interop/index.rst b/docs/interop/index.rst index 999e44eae1..3644b8efb2 100644 --- a/docs/interop/index.rst +++ b/docs/interop/index.rst @@ -14,6 +14,7 @@ are useful for making QEMU interoperate with other software. dbus-vmstate dbus-display live-block-operations + mcd nbd parallels prl-xml diff --git a/docs/interop/mcd.rst b/docs/interop/mcd.rst new file mode 100644 index 0000000000..9587cfb010 --- /dev/null +++ b/docs/interop/mcd.rst @@ -0,0 +1,44 @@ +.. + Copyright (c) 2025 Lauterbach GmbH + SPDX-License-Identifier: GPL-2.0-or-later + + +========================== +Multi-Core Debug (MCD) API +========================== + +The Multi-Core Debug (MCD) API is a debug interface which is commonly provided +by emulators alongside other interfaces such as GDB and is specifically designed +for machine-level debugging. + +For instance, to allow physical memory access through the GDB interface, QEMU +introduced a custom maintenance packet, as explained in :doc:`/system/gdb`. +With MCD, multiple memory spaces can be made available, which can be accessed +from a given CPU. In addition to ``MCD_MEM_SPACE_IS_REGISTERS`` and +``MCD_MEM_SPACE_IS_LOGICAL``, the types also include +``MCD_MEM_SPACE_IS_PHYSICAL``. Each memory and register accessed is initiated +through a transaction. Depending on the memory space identifier in the address, +the transaction accesses registers, logical memory (with MMU), or physical +memory. + +Operations like accessing memory or registers, and controlling the execution +flow, are all performed with respect to an open core connection. As the +following diagram shows, cores are part of a hierarchical system structure which +can be directly mapped to QEMU's options: + +.. code-block:: bash + + $ qemu-system-* -machine * -cpu * -smp * (...) + +The resulting system can be visualized as follows:: + + +----------------+ +----------+ +------+ + | System | 1 1 | Device | 1 -smp | Core | + | |------| |-----------| | + | qemu-system-* | | -machine | | -cpu | + +----------------+ +----------+ +------+ + +API Reference +------------- + +.. kernel-doc:: mcd/mcd_api.h diff --git a/mcd/mcd_api.h b/mcd/mcd_api.h new file mode 100644 index 0000000000..8c893538f8 --- /dev/null +++ b/mcd/mcd_api.h @@ -0,0 +1,3963 @@ +/* + * Copyright (c) 2008, ARM Ltd., Infineon Technologies, NXP Semiconductors, + * Lauterbach, STMicroelectronics and TIMA Laboratory. + * All rights reserved. + * + * PREAMBLE + * + * The MCD API (Multi-Core Debug) has been designed as an interface between + * software development tools and simulated or real systems with multi-core + * SoCs. The target is to allow consistent software tooling throughout the + * whole SoC development flow. + * The MCD API (the "SOFTWARE") has been developed jointly by ARM Ltd., + * Infineon Technologies, NXP Semiconductors, Lauterbach, + * STMicroelectronics and TIMA Laboratory as part of the SPRINT project + * (www.sprint-project.net). + * The SPRINT project has been funded by the European Commission. + * + * LICENSE + * + * Any redistribution and use of the SOFTWARE in source and binary forms, + * with or without modification constitutes the full acceptance of the + * following disclaimer as well as of the license herein and is permitted + * provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer detailed below. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the disclaimer detailed below in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of its copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from the + * Software without specific prior written permission. + * - Modification of any or all of the source code, documentation and other + * materials provided under this license are subject to acknowledgement of + * the modification(s) by including a prominent notice on the modification(s) + * stating the change(s) to the file(s), identifying the date of such change + * and stating the name of the publisher of any such modification(s). + * + * DISCLAIMER OF WARRANTY AND LIABILITY + * + * THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE, + * MISREPRESENTATION OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * VERSION HISTORY + * + * 1.0 "SPRINT Release" : SPRINT reference version + * + * 1.1 "Lauterbach Release" : + * - forces all boolean types to 8-bit on Linux and Mac-OS-X, + * but 32-bit on all other OS forces 32-bit enumeration types + * - additional memory spaces MCD_MEM_SPACE_IS_PHYSICAL, + * MCD_MEM_SPACE_IS_LOGICAL, MCD_MEM_SPACE_IS_AUX + * - changed type of 2nd argument of mcd_qry_input_handle_f from "int" to + * "uint32_t" + * - changed type of element "data" of of mcd_tx_st from "unsigned char" to + * "uint8_t" + * - specifying the calling convention for MS Windows (x86) to __cdecl + * + * 1.2 "QEMU Release" : + * - changes formatting to accommodate QEMU's coding style guidelines + * - includes qemu/osdep.h instead of mcd_types.h + */ + + +/** + * DOC: Using the MCD API + * + * The MCD API has been captured in a single header file and all API users have + * to include this header file in their source code. The following has to be + * noted when including this header file: + * + * - The MCD API extensively utilizes standard fixed size integer types as + * defined by ISO. These types can be found in the system library header named + * . In case this file is not provided with the used platform and/or + * build environment, suitable definitions for the required types need to be + * created. In most cases it should be possible to find definitions of these + * platform-specific types on the internet. + * + * The MCD API is composed of two distinct parts: + * + * - An API in order to allow tools to access debug targets in a uniform way + * (ToolsAPI). + * - An API in order to allow the MCD framework to access target components in a + * standard way (TargetAPI). + * + * The following naming conventions have been introduced for the definition of + * the various data structures and function calls of the MCD API: + * + * - All data structures begin with the prefix 'mcd'. This stands for + * "Multi-Core Debugging". + * - All data structures used by the API functions that are C Enumerations end + * in the suffix '_et'. This stands for "Enumeration Type". With version 1.1 + * of the API all enumeration types are defined as 32-bit unsigned integers. + * - All data structures used by the API functions that are C Structures end in + * the suffix '_st'. This stands for "Structure Type". + * - All API function names begin with the prefix 'mcd'. This stands for + * "Multi-Core Debugging". + * - All API function names end in the suffix '_f'. This stands for "Function". + * + * In addition to this, the following convention is assumed to be applied to all + * implementations: + * + * - All strings are terminated by a zero character. + * - All member of a structure must be aligned to their size E.g. members must + * of type uint64_t must be aligned to an offset divisible by 8. + * - The calling convention for implementations on MS Windows for x86 CPUs is + * __cdecl + * + * If MCD API extensions are needed, it is strongly recommended to add them + * outside of this header file for compatibility reasons. If this is not + * possible it is mandatory to modify the MCD_API_VER_AUTHOR to a different + * string than "SPRINT Release". New versions of the "SPRINT Release" may only + * be created by the copyright holders listed in the license text. + */ + + +/* + * mcd_api.h + * The Multi-Core Debug (MCD) API defined as a part of the SPRINT Project + * This is the definition of the Multi-Core Debug API as defined by SPRINT. + */ + + +#ifndef MCD_API_H +#define MCD_API_H + +#include "qemu/osdep.h" + + +/** + * DOC: Definitions of Constant + * + * This is a list of constant values as defined for the utilization by data + * structures of the MCD API. + */ + + +/** + * define MCD_API_VER_MAJOR - Major revision number of this API. + */ +#define MCD_API_VER_MAJOR 1 + +/** + * define MCD_API_VER_MINOR - Minor revision number of this API. + * + * Version 1.2 only introduced formatting changes + */ +#define MCD_API_VER_MINOR 1 + +/** + * define MCD_API_VER_AUTHOR - Author of this API + * + * Version 1.2 introduces MCD into QEMU + * Version 1.1 extends 1.0 "SPRINT Release" by fixed types + * Version 1.0 "SPRINT Release" is the SPRINT reference version + */ +#define MCD_API_VER_AUTHOR "QEMU Release" + +/** + * define MCD_API_VER_BUILD - Build revision number of this API. + * + * SVN revision not applicable to QEMU. + */ +#define MCD_API_VER_BUILD 0 + +/** + * define MCD_HOSTNAME_LEN - Maximum length of the host's name which runs the + * debug server (incl. terminating zero). + */ +#define MCD_HOSTNAME_LEN 64 /* Maximum length of the host's name */ + +/** + * define MCD_REG_NAME_LEN - Maximum length of a register name + * (incl. terminating zero). + */ +#define MCD_REG_NAME_LEN 32 + +/** + * define MCD_MEM_SPACE_NAME_LEN - Maximum length of a memory space name + * (incl. terminating zero). + */ +#define MCD_MEM_SPACE_NAME_LEN 32 + +/** + * define MCD_MEM_BLOCK_NAME_LEN - Maximum length of a memory block name + * (incl. terminating zero). + */ +#define MCD_MEM_BLOCK_NAME_LEN 32 + +/** + * define MCD_MEM_BLOCK_NOPARENT - Parent ID to be assigned to a memory block + * at root level. + */ +#define MCD_MEM_BLOCK_NOPARENT 0 + +/** + * define MCD_MEM_AUSIZE_NUM - Maximum number of supported Addressable Unit + * sizes. + */ +#define MCD_MEM_AUSIZE_NUM 8 + +/** + * define MCD_INFO_STR_LEN - Maximum length of an info string + * (incl. terminating zero). + */ +#define MCD_INFO_STR_LEN 256 + +/** + * define MCD_KEY_LEN - Maximum length of keys (incl. terminating zero). + */ +#define MCD_KEY_LEN 64 + +/** + * define MCD_UNIQUE_NAME_LEN - Maximum length of a unique name string + * (incl. terminating zero). + */ +#define MCD_UNIQUE_NAME_LEN 64 + +/** + * define MCD_MAX_TRIGS - Maximum number of triggers supported per core. + */ +#define MCD_MAX_TRIGS 32 + +/** + * define MCD_API_IMP_VENDOR_LEN - Maximum name length of the API implementation + * vendor (incl. terminating zero). + */ +#define MCD_API_IMP_VENDOR_LEN 32 + +/** + * define MCD_CHL_NUM_MAX - Maximum number of supported communication channels. + */ +#define MCD_CHL_NUM_MAX 32 + +/** + * define MCD_CHL_LOWEST_PRIORITY - Lowest channel priority + * [Range: 0 (highest) to 15 (lowest)]. + */ +#define MCD_CHL_LOWEST_PRIORITY 15 + +/** + * define MCD_TX_NUM_MAX - Maximum number of transactions supported per + * transaction list. + */ +#define MCD_TX_NUM_MAX 64 + +/** + * define MCD_GUARANTEED_MIN_PAYLOAD - Minimum payload guaranteed per + * transaction list (in bytes). + */ +#define MCD_GUARANTEED_MIN_PAYLOAD 16384 + +/** + * define MCD_CORE_MODE_NAME_LEN - Maximum name length of a core mode, e.g. + * user, supervisor, secure + * (incl. terminating zero). + */ +#define MCD_CORE_MODE_NAME_LEN 32 + + +/** + * DOC: Definition of Enumerations + * + * This is a list of enumeration values as defined for the utilization + * by data structures of the MCD API. + */ + + +/** + * typedef mcd_return_et - Enumeration type defining the action a calling + * function has to take after an MCD API function call. + * + * The calling function has to evaluate the return value of an MCD API function + * call in order to check its success. If the function returned with an error an + * appropriate action has to be taken as defined by the return value. All MCD + * API functions return a value of type mcd_return_et. The calling function has + * to decide the further proceeding based on it. + * + * A few return codes have been reserved for future API use and must not be + * used. Any further value can be used for customized actions. All of these user + * defined actions need to have values between %MCD_RET_ACT_CUSTOM_LO and + * %MCD_RET_ACT_CUSTOM_HI. + * + * * %MCD_RET_ACT_NONE - No special action required. + * * %MCD_RET_ACT_AGAIN - Try to call the function again. + * * %MCD_RET_ACT_HANDLE_EVENT - Handle the event or events. + * * %MCD_RET_ACT_HANDLE_ERROR - Handle the error. + * * %MCD_RET_ACT_RESERVED_LO - Begin Range: Action reserved for future API use. + * * %MCD_RET_ACT_RESERVED_HI - End Range: Action reserved for future API use. + * * %MCD_RET_ACT_CUSTOM_LO - Begin Range: For user defined actions. + * * %MCD_RET_ACT_CUSTOM_HI - End Range: For user defined actions. + */ +typedef uint32_t mcd_return_et; +enum { + MCD_RET_ACT_NONE = 0x00000000, + MCD_RET_ACT_AGAIN = 0x00000001, + MCD_RET_ACT_HANDLE_EVENT = 0x00000002, + MCD_RET_ACT_HANDLE_ERROR = 0x00000003, + MCD_RET_ACT_RESERVED_LO = 0x00000004, + MCD_RET_ACT_RESERVED_HI = 0x00008000, + MCD_RET_ACT_CUSTOM_LO = 0x00010000, + MCD_RET_ACT_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_error_code_et - Enumeration type defining the detailed error + * codes that can be returned by an MCD API function + * call. + * + * The calling function has to evaluate the return value of an MCD API function + * call in order to check its success. If the function returned with an error an + * appropriate action has to be taken as defined by the return value. All MCD + * API functions return a value of type mcd_return_et. If the returned value + * indicates an error, the user has to retrieve the detailed information on the + * occurred error by calling mcd_qry_error_info_f(). The following enumeration + * is part of this information and describes the detailed error codes. + * + * The enumeration's values can be subdivided into the following categories: + * + * - GENERAL (0x0000-0x0FFF) : These errors can be returned by any + * MCD API function call. + * - API_SPECIFIC (0x1000-0x10000000) : These errors are specific to + * certain MCD API function calls. Some of them may be valid for multiple MCD + * API function calls. + * - CUSTOM (0x10000000-0x7FFFFFFF) : These error codes can be defined by + * the user and carry user defined semantics. + * + * * %MCD_ERR_NONE - No error. + * * %MCD_ERR_FN_UNIMPLEMENTED - Called function is not implemented. + * * %MCD_ERR_USAGE - MCD API not correctly used. + * * %MCD_ERR_PARAM - Passed invalid parameter. + * * %MCD_ERR_CONNECTION - Server connection error. + * * %MCD_ERR_TIMED_OUT - Function call timed out. + * * %MCD_ERR_GENERAL - General error. + * * %MCD_ERR_RESULT_TOO_LONG - String to return is longer than the provided + * character array. + * * %MCD_ERR_COULD_NOT_START_SERVER - Could not start server. + * * %MCD_ERR_SERVER_LOCKED - Server is locked. + * * %MCD_ERR_NO_MEM_SPACES - No memory spaces defined. + * * %MCD_ERR_NO_MEM_BLOCKS - No memory blocks defined for the requested memory + * space. + * * %MCD_ERR_MEM_SPACE_ID - No memory space with requested ID exists. + * * %MCD_ERR_NO_REG_GROUPS - No register groups defined. + * * %MCD_ERR_REG_GROUP_ID - No register group with requested ID exists. + * * %MCD_ERR_REG_NOT_COMPOUND - Register is not a compound register. + * * %MCD_ERR_OVERLAYS - Error retrieving overlay information. + * * %MCD_ERR_DEVICE_ACCESS - Cannot access device (power-down, reset active, + * etc.). + * * %MCD_ERR_DEVICE_LOCKED - Device is locked. + * * %MCD_ERR_TXLIST_READ - Read transaction of transaction list has failed. + * * %MCD_ERR_TXLIST_WRITE - Write transaction of transaction list has failed. + * * %MCD_ERR_TXLIST_TX - Other error (no R/W failure) for a transaction of the + * transaction list. + * * %MCD_ERR_CHL_TYPE_NOT_SUPPORTED - Requested channel type is not supported + * by the implementation. + * * %MCD_ERR_CHL_TARGET_NOT_SUPPORTED - Addressed target does not support + * communication channels. + * * %MCD_ERR_CHL_SETUP - Channel setup is invalid or contains unsupported + * attributes. + * * %MCD_ERR_CHL_MESSAGE_FAILED - Sending or receiving of the last message has + * failed. + * * %MCD_ERR_TRIG_CREATE - Trigger could not be created. + * * %MCD_ERR_TRIG_ACCESS - Error during trigger information access. + * * %MCD_ERR_CUSTOM_LO - Begin Range: For user defined errors. + * * %MCD_ERR_CUSTOM_HI - End Range: For user defined errors. + */ +typedef uint32_t mcd_error_code_et; +enum { + + MCD_ERR_NONE = 0, + + MCD_ERR_FN_UNIMPLEMENTED = 0x0100, + MCD_ERR_USAGE = 0x0101, + MCD_ERR_PARAM = 0x0102, + MCD_ERR_CONNECTION = 0x0200, + MCD_ERR_TIMED_OUT = 0x0201, + + MCD_ERR_GENERAL = 0x0F00, + + MCD_ERR_RESULT_TOO_LONG = 0x1000, + + MCD_ERR_COULD_NOT_START_SERVER = 0x1100, + MCD_ERR_SERVER_LOCKED = 0x1101, + + MCD_ERR_NO_MEM_SPACES = 0x1401, + MCD_ERR_NO_MEM_BLOCKS = 0x1402, + MCD_ERR_MEM_SPACE_ID = 0x1410, + MCD_ERR_NO_REG_GROUPS = 0x1440, + MCD_ERR_REG_GROUP_ID = 0x1441, + MCD_ERR_REG_NOT_COMPOUND = 0x1442, + + MCD_ERR_OVERLAYS = 0x1500, + + MCD_ERR_DEVICE_ACCESS = 0x1900, + MCD_ERR_DEVICE_LOCKED = 0x1901, + + MCD_ERR_TXLIST_READ = 0x2100, + MCD_ERR_TXLIST_WRITE = 0x2101, + MCD_ERR_TXLIST_TX = 0x2102, + + MCD_ERR_CHL_TYPE_NOT_SUPPORTED = 0x3100, + MCD_ERR_CHL_TARGET_NOT_SUPPORTED = 0x3101, + MCD_ERR_CHL_SETUP = 0x3102, + MCD_ERR_CHL_MESSAGE_FAILED = 0x3140, + + MCD_ERR_TRIG_CREATE = 0x3200, + MCD_ERR_TRIG_ACCESS = 0x3201, + + MCD_ERR_CUSTOM_LO = 0x10000000, + MCD_ERR_CUSTOM_HI = 0x7FFFFFFF, +}; + + +/** + * typedef mcd_error_event_et - Enumeration type defining the error events that + * can be returned by an MCD API function call. + * + * The calling function has to evaluate the return value of an MCD API function + * call in order to check its success. If the function returned with an error an + * appropriate action has to be taken as defined by the return value. All MCD + * API functions return a value of type mcd_return_et. If the returned value + * indicates an event, the user has to retrieve the detailed information on the + * occurred error by calling mcd_qry_error_info_f(). The following enumeration + * is part of this information and describes the detailed event codes. + * + * Event codes are bitwise exclusive. This allows 32 different event codes. User + * defined event codes need to have values between %MCD_ERR_EVT_CUSTOM_LO and + * %MCD_ERR_EVT_CUSTOM_HI. Reserved error event codes must not be used. + * + * * %MCD_ERR_EVT_NONE - No action required due to an event. + * * %MCD_ERR_EVT_RESET - Target has been reset. + * * %MCD_ERR_EVT_PWRDN - Target has been a powered down. + * * %MCD_ERR_EVT_HWFAILURE - There has been a target hardware failure. + * * %MCD_ERR_EVT_RESERVED_LO - Begin Range: Events reserved for future API use. + * * %MCD_ERR_EVT_RESERVED_HI - End Range: Events reserved for future API use. + * * %MCD_ERR_EVT_CUSTOM_LO - Begin Range: User defined events. + * * %MCD_ERR_EVT_CUSTOM_HI - End Range: User defined events. + */ +typedef uint32_t mcd_error_event_et; +enum { + MCD_ERR_EVT_NONE = 0x00000000, + MCD_ERR_EVT_RESET = 0x00000001, + MCD_ERR_EVT_PWRDN = 0x00000002, + MCD_ERR_EVT_HWFAILURE = 0x00000004, + MCD_ERR_EVT_RESERVED_LO = 0x00000008, + MCD_ERR_EVT_RESERVED_HI = 0x00008000, + MCD_ERR_EVT_CUSTOM_LO = 0x00010000, + MCD_ERR_EVT_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_addr_space_type_et - Enumeration type defining the type of an + * address space ID. + * + * The type of the address space ID defines the interpretation of an address + * space ID. This type refers to the addr_space_id member of mcd_addr_st which + * is used to further extend the address information. + * + * * %MCD_NOTUSED_ID - Address space ID is not used. + * * %MCD_OVERLAY_ID - Address space ID represents the memory overlay the + * address is valid in. + * * %MCD_MEMBANK_ID - Address space ID represents the memory bank the address + * is valid in. + * * %MCD_PROCESS_ID - Address space ID represents the process the address is + * valid in. + * * %MCD_HW_THREAD_ID - Address space ID represents the hardware thread the + * address is valid in. + */ +typedef uint32_t mcd_addr_space_type_et; +enum { + + MCD_NOTUSED_ID = 0, + MCD_OVERLAY_ID = 1, + MCD_MEMBANK_ID = 2, + MCD_PROCESS_ID = 3, + MCD_HW_THREAD_ID = 4, +}; + + +/** + * typedef mcd_mem_type_et - Enumeration type defining the type of a memory + * space. + * + * Different types of memory spaces are possible. This enumeration type + * describes them. The type values %MCD_MEM_SPACE_IS_REGISTERS, + * %MCD_MEM_SPACE_IS_PROGRAM, %MCD_MEM_SPACE_IS_VIRTUAL and + * %MCD_MEM_SPACE_IS_CACHE are bitwise mutually exclusive. + * %MCD_MEM_SPACE_IS_PHYSICAL or %MCD_MEM_SPACE_IS_LOGICAL should be set when + * the target contains a memory management unit (MMU) that translates memory + * addresses between core and memory. User defined memory space types need to + * have values between %MCD_MEMSPACE_CUSTOM_HI and %MCD_MEMSPACE_CUSTOM_HI. + * Reserved memory space types must not be used. + * + * * %MCD_MEM_SPACE_DEFAULT - The memory space is of none of the types below. + * * %MCD_MEM_SPACE_IS_REGISTERS - The memory space contains only registers. + * * %MCD_MEM_SPACE_IS_PROGRAM - The memory space is a program memory. + * * %MCD_MEM_SPACE_IS_VIRTUAL - The memory space is virtual (resource not + * existing in target). + * * %MCD_MEM_SPACE_IS_CACHE - The memory space is a cache. + * * %MCD_MEM_SPACE_IS_PHYSICAL - The memory space is physical memory (not + * translated by MMU). + * * %MCD_MEM_SPACE_IS_LOGICAL - The memory space is logical memory (translated + * by MMU). + * * %MCD_MEM_SPACE_RESERVED_LO - Begin Range: Reserved for future API use. + * * %MCD_MEM_SPACE_RESERVED_HI - End Range: Reserved for future API use. + * * %MCD_MEM_SPACE_CUSTOM_LO - Begin Range: User defined memory types. + * * %MCD_MEM_SPACE_CUSTOM_HI - End Range: User defined memory types. + */ +typedef uint32_t mcd_mem_type_et; +enum { + MCD_MEM_SPACE_DEFAULT = 0x00000000, + MCD_MEM_SPACE_IS_REGISTERS = 0x00000001, + MCD_MEM_SPACE_IS_PROGRAM = 0x00000002, + MCD_MEM_SPACE_IS_VIRTUAL = 0x00000004, + MCD_MEM_SPACE_IS_CACHE = 0x00000008, + MCD_MEM_SPACE_IS_PHYSICAL = 0x00000010, + MCD_MEM_SPACE_IS_LOGICAL = 0x00000020, + MCD_MEM_SPACE_RESERVED_LO = 0x00000040, + MCD_MEM_SPACE_RESERVED_HI = 0x00008000, + MCD_MEM_SPACE_CUSTOM_LO = 0x00010000, + MCD_MEM_SPACE_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_endian_et - Enumeration type defining the endianness of a memory + * space or a memory block. + * + * The endianness of a memory can be either Little Endian or Big Endian. This + * enumeration type describes the two possible values of endianness and is used + * to set the corresponding property of a memory space and a memory block + * description. If memory blocks are supported, the value of a memory block + * overrides the one for the memory space it is part of. + * + * * %MCD_ENDIAN_DEFAULT - Endianness as defined by the target architecture or + * parent module (if available). + * * %MCD_ENDIAN_LITTLE - Little Endian data representation. + * * %MCD_ENDIAN_BIG - Big Endian data representation. + */ +typedef uint32_t mcd_endian_et; +enum { + MCD_ENDIAN_DEFAULT = 0, + MCD_ENDIAN_LITTLE = 1, + MCD_ENDIAN_BIG = 2, +}; + + +/** + * typedef mcd_reg_type_et - Enumeration type defining the allowed register + * types. + * + * A register can be a simple register, a compound register or a partial + * register. This enumeration type describes the three register types. + * + * * %MCD_REG_TYPE_SIMPLE - Simple register. + * * %MCD_REG_TYPE_COMPOUND - Compound register composed more than one simple + * register. + * * %MCD_REG_TYPE_PARTIAL - Register that is part of a simple register. + */ +typedef uint32_t mcd_reg_type_et; +enum { + MCD_REG_TYPE_SIMPLE = 0, + MCD_REG_TYPE_COMPOUND = 1, + MCD_REG_TYPE_PARTIAL = 2, +}; + + +/** + * typedef mcd_trig_type_et - Enumeration type defining the type of a trigger. + * + * This enumeration type describes the possible types of triggers for the + * target. The type values are bitwise mutually exclusive and a member of type + * mcd_trig_type_et may be a combination of several of them. The type + * %MCD_TRIG_TYPE_CUSTOM refers to a custom trigger (not a custom trigger type) + * using the standard format as defined by mcd_trig_custom_st. User defined + * trigger types need to have values between %MCD_TRIG_TYPE_CUSTOM_LO and + * %MCD_TRIG_TYPE_CUSTOM_HI. + * + * * %MCD_TRIG_TYPE_UNDEFINED - Undefined trigger type. + * * %MCD_TRIG_TYPE_IP - Trigger on a changing instruction pointer. + * * %MCD_TRIG_TYPE_READ - Trigger on a read data access to a specific address + * or address range. + * * %MCD_TRIG_TYPE_WRITE - Trigger on a write data access to a specific address + * or address range. + * * %MCD_TRIG_TYPE_RW - Trigger on a read or a write data access to a specific + * address or address range. + * * %MCD_TRIG_TYPE_NOCYCLE - Trigger on core information other than an IP or + * data compare trigger. + * * %MCD_TRIG_TYPE_TRIG_BUS - Trigger on a trigger bus combination. + * * %MCD_TRIG_TYPE_COUNTER - Trigger on an elapsed trigger counter. + * * %MCD_TRIG_TYPE_CUSTOM - Custom trigger using standard format as defined by + * mcd_trig_custom_st. + * * %MCD_TRIG_TYPE_CUSTOM_LO - Begin Range: User defined trigger types. + * * %MCD_TRIG_TYPE_CUSTOM_HI - End Range: User defined trigger types. + */ +typedef uint32_t mcd_trig_type_et; +enum { + MCD_TRIG_TYPE_UNDEFINED = 0x00000000, + MCD_TRIG_TYPE_IP = 0x00000001, + MCD_TRIG_TYPE_READ = 0x00000002, + MCD_TRIG_TYPE_WRITE = 0x00000004, + MCD_TRIG_TYPE_RW = 0x00000008, + MCD_TRIG_TYPE_NOCYCLE = 0x00000010, + MCD_TRIG_TYPE_TRIG_BUS = 0x00000020, + MCD_TRIG_TYPE_COUNTER = 0x00000040, + MCD_TRIG_TYPE_CUSTOM = 0x00000080, + MCD_TRIG_TYPE_CUSTOM_LO = 0x00010000, + MCD_TRIG_TYPE_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_trig_opt_et - Enumeration type defining additional options for a + * trigger. + * + * This enumeration type describes the additionally possible options for + * triggers in a target. The type values are bitwise mutually exclusive and a + * member of type mcd_trig_opt_et may be a combination of several of them. User + * defined trigger options need to have values between %MCD_TRIG_OPT_CUSTOM_LO + * and %MCD_TRIG_OPT_CUSTOM_HI. + * + * * %MCD_TRIG_OPT_DEFAULT - Default trigger options, e.g. chosen by the + * platform. + * * %MCD_TRIG_OPT_IMPL_HARDWARE - The trigger shall be implemented by hardware. + * * %MCD_TRIG_OPT_IMPL_SOFTWARE - The trigger shall be implemented by software + * (code substitution). + * * %MCD_TRIG_OPT_OUT_OF_RANGE - The trigger is activated when a data access is + * performed outside the specified range. + * * %MCD_TRIG_OPT_DATA_IS_CONDITION - The value of a data access is part of the + * trigger condition. + * * %MCD_TRIG_OPT_DATASIZE_IS_CONDITION - The size of a data access is part of + * the trigger condition. + * * %MCD_TRIG_OPT_NOT_DATA - The data comparison done in a trigger condition is + * negated. + * * %MCD_TRIG_OPT_SIGNED_DATA - The data values are considered as signed for + * the trigger condition. This usually requires the setting of + * %MCD_TRIG_OPT_DATASIZE_IS_CONDITION. + * * %MCD_TRIG_OPT_HW_THREAD_IS_CONDITION - The hardware thread ID is part of + * the trigger condition. + * * %MCD_TRIG_OPT_NOT_HW_THREAD - The comparison of the hardware thread ID is + * negated. + * * %MCD_TRIG_OPT_SW_THREAD_IS_CONDITION - The software thread ID is part of + * the trigger condition. + * * %MCD_TRIG_OPT_NOT_SW_THREAD - The comparison of the software thread ID is + * negated. + * * %MCD_TRIG_OPT_DATA_MUST_CHANGE - The data value of the cycle must change + * the value of the target location. This applies only to triggers on write + * cycles. The data_mask field defines which bits are considered for the + * comparison. + * * %MCD_TRIG_OPT_CORE_MODE_IS_CONDITION - The core mode as defined by the + * member core_mode_mask of a mcd_trig_complex_core_st is part of the trigger + * condition. Each set bit prevents the related core mode from activating the + * trigger. + * * %MCD_TRIG_OPT_STATE_IS_CONDITION - The state of the trigger set's state + * machine is part of the trigger condition. + * * %MCD_TRIG_OPT_NOT - The trigger condition is negated, i.e. action is taken + * if the whole trigger condition is NOT met. This should not be mixed up with + * %MCD_TRIG_OPT_OUT_OF_RANGE which inverts just the address range. + * * %MCD_TRIG_OPT_CUSTOM_LO - Begin Range: User defined trigger options. + * * %MCD_TRIG_OPT_CUSTOM_HI - End Range: User defined trigger options. + */ +typedef uint32_t mcd_trig_opt_et; +enum { + MCD_TRIG_OPT_DEFAULT = 0x00000000, + MCD_TRIG_OPT_IMPL_HARDWARE = 0x00000001, + MCD_TRIG_OPT_IMPL_SOFTWARE = 0x00000002, + MCD_TRIG_OPT_OUT_OF_RANGE = 0x00000004, + MCD_TRIG_OPT_DATA_IS_CONDITION = 0x00000008, + MCD_TRIG_OPT_DATASIZE_IS_CONDITION = 0x00000010, + MCD_TRIG_OPT_NOT_DATA = 0x00000020, + MCD_TRIG_OPT_SIGNED_DATA = 0x00000040, + MCD_TRIG_OPT_HW_THREAD_IS_CONDITION = 0x00000080, + MCD_TRIG_OPT_NOT_HW_THREAD = 0x00000100, + MCD_TRIG_OPT_SW_THREAD_IS_CONDITION = 0x00000200, + MCD_TRIG_OPT_NOT_SW_THREAD = 0x00000400, + MCD_TRIG_OPT_DATA_MUST_CHANGE = 0x00000800, + MCD_TRIG_OPT_CORE_MODE_IS_CONDITION = 0x00020000, + MCD_TRIG_OPT_STATE_IS_CONDITION = 0x00040000, + MCD_TRIG_OPT_NOT = 0x00080000, + MCD_TRIG_OPT_CUSTOM_LO = 0x00100000, + MCD_TRIG_OPT_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_trig_action_et - Enumeration type defining the trigger action + * types. + * + * This enumeration type describes the possible actions for triggers in a + * target. The type values are bitwise mutually exclusive and a member of type + * mcd_trig_action_et may be a combination of several of them. User defined + * trigger actions need to have values between %MCD_TRIG_ACTION_CUSTOM_LO and + * %MCD_TRIG_ACTION_CUSTOM_HI. + * + * * %MCD_TRIG_ACTION_DEFAULT - No action has to be taken except from setting + * the trigger to be captured. + * * %MCD_TRIG_ACTION_DBG_DEBUG - Stop this core and bring it into debug mode. + * * %MCD_TRIG_ACTION_DBG_GLOBAL - Stop all cores and bring them into debug + * mode. + * * %MCD_TRIG_ACTION_DBG_MONITOR - Issue an exception (monitor interrupt) on + * this core in order to execute the monitor code. + * * %MCD_TRIG_ACTION_TRIG_BUS_EVENT - Signal the according event on the trigger + * bus (for the duration of one core cycle). The corresponding bitmask is + * specified by the member action_param of the used trigger data structure. + * * %MCD_TRIG_ACTION_TRIG_BUS_SET - Set bits on the trigger bus. The + * corresponding bitmask is specified by the member action_param of the used + * trigger data structure. + * * %MCD_TRIG_ACTION_TRIG_BUS_CLEAR - Clear bits on the trigger bus. The + * corresponding bitmask is specified by the member action_param of the used + * trigger data structure. + * * %MCD_TRIG_ACTION_TRACE_QUALIFY - Trace this cycle. + * * %MCD_TRIG_ACTION_TRACE_QUALIFY_PROGRAM - Trace this cycle, affects program + * trace only. + * * %MCD_TRIG_ACTION_TRACE_QUALIFY_DATA - Trace this cycle, affects data trace + * only. + * * %MCD_TRIG_ACTION_TRACE_START - Start tracing. + * * %MCD_TRIG_ACTION_TRACE_STOP - Stop tracing. + * * %MCD_TRIG_ACTION_TRACE_TRIGGER - Trigger trace unit. + * * %MCD_TRIG_ACTION_ANA_START_PERFM - Start performance analysis or profiling. + * * %MCD_TRIG_ACTION_ANA_STOP_PERFM - Stop performance analysis or profiling. + * * %MCD_TRIG_ACTION_STATE_CHANGE - Set the trigger set's state machine to a + * new state. The corresponding state is specified by the member action_param + * of the used trigger data structure. + * * %MCD_TRIG_ACTION_COUNT_QUALIFY - Increment the counter specified by the + * member action_param of the used trigger data structure. + * * %MCD_TRIG_ACTION_COUNT_START - Start the counter specified by the member + * action_param of the used trigger data structure. + * * %MCD_TRIG_ACTION_COUNT_STOP - Stop the counter specified by the member + * action_param of the used trigger data structure. + * * %MCD_TRIG_ACTION_COUNT_RESTART - Restart the counter specified by the + * member action_param of the used trigger data structure. + * * %MCD_TRIG_ACTION_CUSTOM_LO - Begin Range: User defined trigger actions. + * * %MCD_TRIG_ACTION_CUSTOM_HI - End Range: User defined trigger actions. + */ +typedef uint32_t mcd_trig_action_et; +enum { + MCD_TRIG_ACTION_DEFAULT = 0x00000000, + MCD_TRIG_ACTION_DBG_DEBUG = 0x00000001, + MCD_TRIG_ACTION_DBG_GLOBAL = 0x00000002, + MCD_TRIG_ACTION_DBG_MONITOR = 0x00000004, + MCD_TRIG_ACTION_TRIG_BUS_EVENT = 0x00000010, + MCD_TRIG_ACTION_TRIG_BUS_SET = 0x00000020, + MCD_TRIG_ACTION_TRIG_BUS_CLEAR = 0x00000040, + MCD_TRIG_ACTION_TRACE_QUALIFY = 0x00000100, + MCD_TRIG_ACTION_TRACE_QUALIFY_PROGRAM = 0x00000200, + MCD_TRIG_ACTION_TRACE_QUALIFY_DATA = 0x00000400, + MCD_TRIG_ACTION_TRACE_START = 0x00000800, + MCD_TRIG_ACTION_TRACE_STOP = 0x00001000, + MCD_TRIG_ACTION_TRACE_TRIGGER = 0x00002000, + MCD_TRIG_ACTION_ANA_START_PERFM = 0x00010000, + MCD_TRIG_ACTION_ANA_STOP_PERFM = 0x00020000, + MCD_TRIG_ACTION_STATE_CHANGE = 0x00040000, + MCD_TRIG_ACTION_COUNT_QUALIFY = 0x00080000, + MCD_TRIG_ACTION_COUNT_START = 0x00100000, + MCD_TRIG_ACTION_COUNT_STOP = 0x00200000, + MCD_TRIG_ACTION_COUNT_RESTART = 0x00400000, + MCD_TRIG_ACTION_CUSTOM_LO = 0x01000000, + MCD_TRIG_ACTION_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_tx_access_type_et - Enumeration type defining access types for + * transactions of transaction lists. + * + * This enumeration type describes the four possible access types for + * transaction of a transaction list. + * + * * %MCD_TX_AT_R - Read access transaction. + * * %MCD_TX_AT_W - Write access transaction. + * * %MCD_TX_AT_RW - Read then write access transaction (atomic swap). + * * %MCD_TX_AT_WR - Write then read access transaction (write and verify). + */ +typedef uint32_t mcd_tx_access_type_et; +enum { + MCD_TX_AT_R = 0x00000001, + MCD_TX_AT_W = 0x00000002, + MCD_TX_AT_RW = 0x00000003, + MCD_TX_AT_WR = 0x00000004, +}; + + +/** + * typedef mcd_tx_access_opt_et - Enumeration type defining access options for + * transactions of transaction lists. + * + * This enumeration type describes the possible access options for transactions + * of a transaction list. The type values are bitwise mutually exclusive and a + * member of type mcd_tx_access_opt_et may be a combination of several of them. + * User defined access options need to have values between %MCD_TX_OPT_CUSTOM_LO + * and %MCD_TX_OPT_CUSTOM_HI. Reserved access options must not be used. + * + * Marking the last transaction of a transaction list with + * %MCD_TX_OPT_ATOMIC_WITH_NEXT causes it to be atomic with the first + * transaction of the next list to be executed for this core connection. + * + * * %MCD_TX_OPT_DEFAULT - MCD implementation decides on applied access options. + * * %MCD_TX_OPT_SIDE_EFFECTS - Trigger side effects for the access. + * * %MCD_TX_OPT_NO_SIDE_EFFECTS - Omit side effects for the access. + * * %MCD_TX_OPT_BURST_ACCESSES - Perform burst accesses if possible. + * * %MCD_TX_OPT_NO_BURST_ACCESSES - Avoid burst accesses if possible. + * * %MCD_TX_OPT_ALTERNATE_PATH - Dual port or DAP memory access. + * * %MCD_TX_OPT_PRIORITY_ACCESS - High priority access. + * * %MCD_TX_OPT_DCACHE_WRITE_THRU - Force D-cache and unified caches to be + * write-through. + * * %MCD_TX_OPT_CACHE_BYPASS - Bypass caches and read/write directly to the + * memory. + * * %MCD_TX_OPT_NOINCREMENT - Do not increment address after each cycle. Useful + * for reading or writing to FIFOs. + * * %MCD_TX_OPT_ATOMIC_WITH_NEXT - Transaction is executed atomic with the next + * one. + * * %MCD_TX_OPT_RESERVED_LO - Begin Range: Reserved for future API use. + * * %MCD_TX_OPT_RESERVED_HI - End Range: Reserved for future API use. + * * %MCD_TX_OPT_CUSTOM_LO - Begin Range: User defined access options. + * * %MCD_TX_OPT_CUSTOM_HI - End Range: User defined access options. + */ +typedef uint32_t mcd_tx_access_opt_et; +enum { + MCD_TX_OPT_DEFAULT = 0x00000000, + MCD_TX_OPT_SIDE_EFFECTS = 0x00000001, + MCD_TX_OPT_NO_SIDE_EFFECTS = 0x00000002, + MCD_TX_OPT_BURST_ACCESSES = 0x00000004, + MCD_TX_OPT_NO_BURST_ACCESSES = 0x00000008, + MCD_TX_OPT_ALTERNATE_PATH = 0x00000010, + MCD_TX_OPT_PRIORITY_ACCESS = 0x00000020, + MCD_TX_OPT_DCACHE_WRITE_THRU = 0x00000040, + MCD_TX_OPT_CACHE_BYPASS = 0x00000080, + MCD_TX_OPT_NOINCREMENT = 0x00000100, + MCD_TX_OPT_ATOMIC_WITH_NEXT = 0x00000200, + MCD_TX_OPT_RESERVED_LO = 0x00000400, + MCD_TX_OPT_RESERVED_HI = 0x00008000, + MCD_TX_OPT_CUSTOM_LO = 0x00010000, + MCD_TX_OPT_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_core_step_type_et - Enumeration type defining step types for a + * target core. + * + * This enumeration type describes the possible step types for a target core. + * The step type depends on the core type. A programmable core can be for + * example stepped in terms of cycles or instructions. User defined step types + * need to have values between %MCD_CORE_STEP_TYPE_CUSTOM_LO and + * %MCD_CORE_STEP_TYPE_CUSTOM_HI. They for example can be based on + * specifications provided by the IP developer of a core. The step type values + * %MCD_CORE_STEP_TYPE_RESERVED_LO to %MCD_CORE_STEP_TYPE_RESERVED_HI are + * reserved for future API extensions and must not be used. + * + * * %MCD_CORE_STEP_TYPE_CYCLES - Step the core for core specific cycles. + * * %MCD_CORE_STEP_TYPE_INSTR - Step the core for core specific instructions. + * * %MCD_CORE_STEP_TYPE_RESERVED_LO - Begin Range: Reserved for future API use. + * * %MCD_CORE_STEP_TYPE_RESERVED_HI - End Range: Reserved for future API use. + * * %MCD_CORE_STEP_TYPE_CUSTOM_LO - Begin Range: User defined step types. + * * %MCD_CORE_STEP_TYPE_CUSTOM_HI - End Range: User defined step types. + * * %MCD_CORE_STEP_TYPE_MAX_TYPES - Maximum number of supported step types. + */ +typedef uint32_t mcd_core_step_type_et; +enum { + MCD_CORE_STEP_TYPE_CYCLES = 0x00000001, + MCD_CORE_STEP_TYPE_INSTR = 0x00000002, + MCD_CORE_STEP_TYPE_RESERVED_LO = 0x00000004, + MCD_CORE_STEP_TYPE_RESERVED_HI = 0x000000FF, + MCD_CORE_STEP_TYPE_CUSTOM_LO = 0x00000100, + MCD_CORE_STEP_TYPE_CUSTOM_HI = 0x00000F00, + MCD_CORE_STEP_TYPE_MAX_TYPES = 0x7FFFFFFF +}; + + +/** + * typedef mcd_core_state_et - Enumeration type defining the execution states of + * a target core. + * + * This enumeration type describes the possible execution states of a target + * core from a debugger perspective. The HALTED state is defined to differ from + * the DEBUG state by the fact that a core in debug mode is under debugger + * control. In contrast to this a core in HALTED state is not under the + * execution control of the debugger but in a state from which the debugger can + * only push it to DEBUG state. The same applies to the RUNNING state. User + * defined core states need to have values between %MCD_CORE_STATE_CUSTOM_LO and + * %MCD_CORE_STATE_CUSTOM_HI. + * + * * %MCD_CORE_STATE_UNKNOWN - Target core state is unknown. + * * %MCD_CORE_STATE_RUNNING - Target core is running. + * * %MCD_CORE_STATE_HALTED - Target core is halted. + * * %MCD_CORE_STATE_DEBUG - Target core is in debug mode. + * * %MCD_CORE_STATE_CUSTOM_LO - Begin Range: User defined core states. + * * %MCD_CORE_STATE_CUSTOM_HI - End Range: User defined core states. + * * %MCD_CORE_STATE_MAX_STATES - Maximum number of supported core states. + */ +typedef uint32_t mcd_core_state_et; +enum { + MCD_CORE_STATE_UNKNOWN = 0x00000000, + MCD_CORE_STATE_RUNNING = 0x00000001, + MCD_CORE_STATE_HALTED = 0x00000002, + MCD_CORE_STATE_DEBUG = 0x00000003, + MCD_CORE_STATE_CUSTOM_LO = 0x00000100, + MCD_CORE_STATE_CUSTOM_HI = 0x00000800, + MCD_CORE_STATE_MAX_STATES = 0x7FFFFFFF +}; + + +/** + * typedef mcd_core_event_et - Enumeration type defining the possible events for + * a target core. + * + * This enumeration type describes the possible core events for a target core + * from a debugger perspective. These allow to optimize the polling of specific + * target information and to support multiple clients connected to one target + * core. Some core events may be reported just once. User defined core events + * need to have values between %MCD_CORE_EVENT_CUSTOM_LO and + * %MCD_CORE_EVENT_CUSTOM_HI. + * + * * %MCD_CORE_EVENT_NONE - No since the last poll. + * * %MCD_CORE_EVENT_MEMORY_CHANGE - Memory content has changed. + * * %MCD_CORE_EVENT_REGISTER_CHANGE - Register contents have changed. + * * %MCD_CORE_EVENT_TRACE_CHANGE - Trace contents or states have changed. + * * %MCD_CORE_EVENT_TRIGGER_CHANGE - Triggers or trigger states have changed. + * * %MCD_CORE_EVENT_STOPPED - Target was stopped at least once since the last + * poll, it may already be running again. + * * %MCD_CORE_EVENT_CHL_PENDING - A target communication channel request from + * the target is pending. + * * %MCD_CORE_EVENT_CUSTOM_LO - Begin Range: User defined core events. + * * %MCD_CORE_EVENT_CUSTOM_HI - End Range: User defined core events. + */ +typedef uint32_t mcd_core_event_et; +enum { + MCD_CORE_EVENT_NONE = 0x00000000, + MCD_CORE_EVENT_MEMORY_CHANGE = 0x00000001, + MCD_CORE_EVENT_REGISTER_CHANGE = 0x00000002, + MCD_CORE_EVENT_TRACE_CHANGE = 0x00000004, + MCD_CORE_EVENT_TRIGGER_CHANGE = 0x00000008, + MCD_CORE_EVENT_STOPPED = 0x00000010, + MCD_CORE_EVENT_CHL_PENDING = 0x00000020, + MCD_CORE_EVENT_CUSTOM_LO = 0x00010000, + MCD_CORE_EVENT_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_chl_type_et - Enumeration type defining the communication channel + * types. + * + * There can be different types of communication channels between a host side + * tool and the target. This enumeration describes these possible types of + * communication channels. User defined communication channel types need to have + * values between %MCD_CHL_TYPE_CUSTOM_LO and %MCD_CHL_TYPE_CUSTOM_HI. + * + * * %MCD_CHL_TYPE_COMMON - Common communication channel to the target. + * * %MCD_CHL_TYPE_CONFIG - Communication channel for configuration purposes, + * e.g. to configure the analysis setup. + * * %MCD_CHL_TYPE_APPLI - Communication channel to an application running on + * the target, e.g. for semi-hosting purposes. + * * %MCD_CHL_TYPE_CUSTOM_LO - Begin Range: User defined communication channel + * types. + * * %MCD_CHL_TYPE_CUSTOM_HI - End Range: User defined communication channel + * types. + */ +typedef uint32_t mcd_chl_type_et; +enum { + MCD_CHL_TYPE_COMMON = 0x00000001, + MCD_CHL_TYPE_CONFIG = 0x00000002, + MCD_CHL_TYPE_APPLI = 0x00000003, + MCD_CHL_TYPE_CUSTOM_LO = 0x00000100, + MCD_CHL_TYPE_CUSTOM_HI = 0x00000F00, +}; + + +/** + * typedef mcd_chl_attributes_et - Enumeration type defining communication + * channel attributes. + * + * A communication channel can be defined with several attributes concerning the + * channel's direction, accessibility and priority. This enumeration type + * describes them. The type values are bitwise mutually exclusive and a member + * of type mcd_chl_attributes_et may be a combination of several of them. + * + * * %MCD_CHL_AT_RCV - Receive channel. + * * %MCD_CHL_AT_SND - Send channel. + * * %MCD_CHL_AT_MEM_MAPPED - Channel is memory mapped. + * * %MCD_CHL_AT_HAS_PRIO - Channel has a defined priority. + */ +typedef uint32_t mcd_chl_attributes_et; +enum { + MCD_CHL_AT_RCV = 0x00000001, + MCD_CHL_AT_SND = 0x00000002, + MCD_CHL_AT_MEM_MAPPED = 0x00000040, + MCD_CHL_AT_HAS_PRIO = 0x00000800, +}; + + +/** + * typedef mcd_trace_type_et - Enumeration type defining basic trace types. + * + * This enumeration type describes the type of a trace source. The type values + * are bitwise mutually exclusive. User defined trace types need to have values + * between %MCD_TRACE_TYPE_CUSTOM_LO and %MCD_TRACE_TYPE_CUSTOM_HI. + * + * * %MCD_TRACE_TYPE_UNKNOWN - Unknown trace source. + * * %MCD_TRACE_TYPE_CORE - Traces the instruction and (optional) data trace + * stream as seen from the core. + * * %MCD_TRACE_TYPE_BUS - Traces a bus that is not related to the program flow. + * * %MCD_TRACE_TYPE_EVENT - Traces logical signals (can include buses) that + * have an asynchronous nature. + * * %MCD_TRACE_TYPE_STAT - Traces statistical or profiling information. + * * %MCD_TRACE_TYPE_CUSTOM_LO - Begin Range: User defined trace types. + * * %MCD_TRACE_TYPE_CUSTOM_HI - End Range: User defined trace types. + */ +typedef uint32_t mcd_trace_type_et; +enum { + MCD_TRACE_TYPE_UNKNOWN = 0x00000000, + MCD_TRACE_TYPE_CORE = 0x00000001, + MCD_TRACE_TYPE_BUS = 0x00000002, + MCD_TRACE_TYPE_EVENT = 0x00000004, + MCD_TRACE_TYPE_STAT = 0x00000008, + MCD_TRACE_TYPE_CUSTOM_LO = 0x00000100, + MCD_TRACE_TYPE_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_trace_format_et - Enumeration type defining trace data formats. + * + * This enumeration type describes the format of the trace data. Each trace + * source can deliver data in exactly one format, only. Standard formats should + * be used whenever possible. User defined trace types need to have values + * between %MCD_TRACE_FORMAT_CUSTOM_LO and %MCD_TRACE_FORMAT_CUSTOM_HI. + * + * * %MCD_TRACE_FORMAT_UNKNOWN - Trace data format not readable via API. + * * %MCD_TRACE_FORMAT_CORE_FETCH - Execution trace extracted from bus fetch + * cycles (use struct mcd_trace_data_core_st for this format). + * * %MCD_TRACE_FORMAT_CORE_EXECUTE - Execution trace (use struct + * mcd_trace_data_core_st for this format) + * * %MCD_TRACE_FORMAT_CORE_FLOW_ICOUNT - Flowtrace data format similar to NEXUS + * traces, instruction count (use struct mcd_trace_data_core_st for this + * format). + * * %MCD_TRACE_FORMAT_CORE_FLOW_BCOUNT - Flowtrace data format similar to NEXUS + * traces, bytes count (use struct mcd_trace_data_core_st for this format). + * * %MCD_TRACE_FORMAT_CORE_FLOW_IPREDICATE - Flowtrace data format with + * predicates and instruction count (use struct mcd_trace_data_core_st for + * this format). + * * %MCD_TRACE_FORMAT_EVENT - Logic and system event trace (use struct + * mcd_trace_data_event_st for this format). + * * %MCD_TRACE_FORMAT_STAT - Statistics trace (use struct + * mcd_trace_data_stat_st for this format). + * * %MCD_TRACE_FORMAT_CUSTOM_LO - Begin Range: User defined trace data formats. + * * %MCD_TRACE_FORMAT_CUSTOM_HI - End Range: User defined trace data formats. + */ +typedef uint32_t mcd_trace_format_et; +enum { + MCD_TRACE_FORMAT_UNKNOWN = 0x00000000, + MCD_TRACE_FORMAT_CORE_FETCH = 0x00000001, + MCD_TRACE_FORMAT_CORE_EXECUTE = 0x00000002, + MCD_TRACE_FORMAT_CORE_FLOW_ICOUNT = 0x00000003, + MCD_TRACE_FORMAT_CORE_FLOW_BCOUNT = 0x00000004, + MCD_TRACE_FORMAT_CORE_FLOW_IPREDICATE = 0x00000005, + MCD_TRACE_FORMAT_EVENT = 0x00000010, + MCD_TRACE_FORMAT_STAT = 0x00000020, + MCD_TRACE_FORMAT_CUSTOM_LO = 0x00000100, + MCD_TRACE_FORMAT_CUSTOM_HI = 0x7FFFFFFF, +}; + + +/** + * typedef mcd_trace_mode_et - Enumeration type defining operation modes of a + * trace buffer. + * + * This enumeration type describes the possible operation modes of a trace + * buffer. The type values are bitwise mutually exclusive. User defined + * operation modes need to have values between %MCD_TRACE_MODE_CUSTOM_LO and + * %MCD_TRACE_MODE_CUSTOM_HI. + * + * * %MCD_TRACE_MODE_NOCHANGE - Do not change trace buffer mode. + * * %MCD_TRACE_MODE_FIFO - Circular trace buffer. + * * %MCD_TRACE_MODE_STACK - Trace stops when buffer is full. + * * %MCD_TRACE_MODE_LEACH - Target is stopped (brought into debug state) when + * buffer is almost full. + * * %MCD_TRACE_MODE_PIPE - Trace data are continuously streamed through API, + * buffer is a FIFO for temporary storage. + * * %MCD_TRACE_MODE_CUSTOM_LO - Begin Range: User defined operation modes. + * * %MCD_TRACE_MODE_CUSTOM_HI - End Range: User defined operation modes. + */ +typedef uint32_t mcd_trace_mode_et; +enum { + MCD_TRACE_MODE_NOCHANGE = 0x00000000, + MCD_TRACE_MODE_FIFO = 0x00000001, + MCD_TRACE_MODE_STACK = 0x00000002, + MCD_TRACE_MODE_LEACH = 0x00000004, + MCD_TRACE_MODE_PIPE = 0x00000008, + MCD_TRACE_MODE_CUSTOM_LO = 0x00000100, + MCD_TRACE_MODE_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_trace_state_et - Enumeration type defining trace states. + * + * This enumeration type describes the possible states of a trace. User defined + * trace states need to have values between %MCD_TRACE_STATE_CUSTOM_LO and + * %MCD_TRACE_STATE_CUSTOM_HI. + * + * * %MCD_TRACE_STATE_NOCHANGE - Do not change state (only for + * mcd_set_trace_state_f()). + * * %MCD_TRACE_STATE_DISABLE - Trace is disabled and no resources are + * allocated. + * * %MCD_TRACE_STATE_OFF - Trace is off and does not trace data, but is ready + * for tracing. + * * %MCD_TRACE_STATE_ARM - Trace is armed. + * * %MCD_TRACE_STATE_TRIGGER - Trace is triggered and waits for the post + * trigger delay. + * * %MCD_TRACE_STATE_STOP - Trace has stopped (after trigger and post trigger + * delay have elapsed). + * * %MCD_TRACE_STATE_INIT - Clears trace buffer and goes into OFF state (only + * for mcd_set_trace_state_f()). + * * %MCD_TRACE_STATE_CUSTOM_LO - Begin Range: User defined trace states. + * * %MCD_TRACE_STATE_CUSTOM_HI - End Range: User defined trace states. + */ +typedef uint32_t mcd_trace_state_et; +enum { + + MCD_TRACE_STATE_NOCHANGE = 0x00000000, + MCD_TRACE_STATE_DISABLE = 0x00000001, + MCD_TRACE_STATE_OFF = 0x00000002, + MCD_TRACE_STATE_ARM = 0x00000003, + MCD_TRACE_STATE_TRIGGER = 0x00000004, + MCD_TRACE_STATE_STOP = 0x00000005, + MCD_TRACE_STATE_INIT = 0x00000010, + MCD_TRACE_STATE_CUSTOM_LO = 0x00000100, + MCD_TRACE_STATE_CUSTOM_HI = 0x7FFFFFFF, +}; + + +/** + * typedef mcd_trace_marker_et - Enumeration type defining trace markers. + * + * This enumeration type describes markers associated with a single trace frame. + * The type values are bitwise mutually exclusive and a member of type + * mcd_trace_marker_et may be a combination of several of them. User defined + * trace markers need to have values between %MCD_TRACE_MARKER_CUSTOM_LO and + * %MCD_TRACE_MARKER_CUSTOM_HI. + * + * * %MCD_TRACE_MARKER_NONE - No marker set. + * * %MCD_TRACE_MARKER_RUN - Core has started execution in this trace frame + * (first cycle). + * * %MCD_TRACE_MARKER_DEBUG - Core has stopped execution in this trace frame + * (last cycle). + * * %MCD_TRACE_MARKER_START - Tracing has started in this trace frame + * (controlled by trigger). + * * %MCD_TRACE_MARKER_STOP - Tracing has stopped in this trace frame + * (controlled by trigger). + * * %MCD_TRACE_MARKER_ERROR - Error marker (hardware failure or program flow + * reconstruction error). + * * %MCD_TRACE_MARKER_GAP - Gap in trace (caused by bandwidth limitation on + * trace port). + * * %MCD_TRACE_MARKER_CUSTOM_LO - Begin Range: User defined trace markers. + * * %MCD_TRACE_MARKER_CUSTOM_HI - End Range: User defined trace markers. + */ +typedef uint32_t mcd_trace_marker_et; +enum { + MCD_TRACE_MARKER_NONE = 0x00000000, + MCD_TRACE_MARKER_RUN = 0x00000001, + MCD_TRACE_MARKER_DEBUG = 0x00000002, + MCD_TRACE_MARKER_START = 0x00000004, + MCD_TRACE_MARKER_STOP = 0x00000008, + MCD_TRACE_MARKER_ERROR = 0x00000010, + MCD_TRACE_MARKER_GAP = 0x00000020, + MCD_TRACE_MARKER_CUSTOM_LO = 0x00000100, + MCD_TRACE_MARKER_CUSTOM_HI = 0x40000000, +}; + + +/** + * typedef mcd_trace_cycle_et - Enumeration type defining basic trace cycles. + * + * This enumeration type describes the basic trace cycle types for bus and core + * traces. User defined trace cycle types need to have values between + * %MCD_TRACE_CYCLE_CUSTOM_LO and %MCD_TRACE_CYCLE_CUSTOM_HI. + * + * * %MCD_TRACE_CYCLE_UNKNOWN - Trace cycle contains no valid data for this + * core. + * * %MCD_TRACE_CYCLE_NONE - No trace cycle, control information (marker, + * timestamp) is valid. + * * %MCD_TRACE_CYCLE_EXECUTE - Program execution cycle, marks the execution of + * one instruction. For a program flow trace this marks the execution of a + * block which is ended with a taken branch. + * * %MCD_TRACE_CYCLE_NOTEXECUTE - Program execution cycle, marks the execution + * of one conditional instruction with a "failing" condition code. For a + * program flow trace this marks the execution of a block which is ended + * without a branch. + * * %MCD_TRACE_CYCLE_FETCH - Program fetch cycle, the instruction related to + * the cycle may just be prefetched. + * * %MCD_TRACE_CYCLE_READ - Data read cycle. + * * %MCD_TRACE_CYCLE_WRITE - Data write cycle. + * * %MCD_TRACE_CYCLE_OWNERSHIP - Ownership change cycle, usually indicates a + * change of the executed software thread. + * * %MCD_TRACE_CYCLE_CUSTOM_LO - Begin Range: User defined trace cycles. + * * %MCD_TRACE_CYCLE_CUSTOM_HI - End Range: User defined trace cycles. + */ +typedef uint32_t mcd_trace_cycle_et; +enum { + MCD_TRACE_CYCLE_UNKNOWN = 0x00000000, + MCD_TRACE_CYCLE_NONE = 0x00000001, + MCD_TRACE_CYCLE_EXECUTE = 0x00000002, + MCD_TRACE_CYCLE_NOTEXECUTE = 0x00000003, + MCD_TRACE_CYCLE_FETCH = 0x00000004, + MCD_TRACE_CYCLE_READ = 0x00000005, + MCD_TRACE_CYCLE_WRITE = 0x00000006, + MCD_TRACE_CYCLE_OWNERSHIP = 0x00000007, + MCD_TRACE_CYCLE_CUSTOM_LO = 0x00000100, + MCD_TRACE_CYCLE_CUSTOM_HI = 0x7FFFFFFF, +}; + + +/** + * DOC: Definition of Structures + * + * This is the list of data structures exchanged by the functions of the MCD + * API. + */ + + +/** + * struct mcd_api_version_st - Structure type containing the MCD API version + * information of the tool. + * + * @v_api_major: API major version. + * @v_api_minor: API minor version. + * @author: API name of the author of this MCD API version. + * + * This structure type contains version information about the MCD API + * implementation of the tool. Reference version at end of SPRINT project is: + * + * * @v_api_major = 1 + * * @v_api_minor = 0 + * * @author = "SPRINT Release" + */ +typedef struct mcd_api_version_st { + uint16_t v_api_major; + uint16_t v_api_minor; + char author[MCD_API_IMP_VENDOR_LEN]; +} mcd_api_version_st; + + +/** + * struct mcd_impl_version_info_st - Structure type containing the MCD API + * implementation information. + * + * @v_api: Implemented API version. + * @v_imp_major: Major version number of this implementation. + * @v_imp_minor: Minor version number of this implementation. + * @v_imp_build: Build number of this implementation. + * @vendor: Name of vendor of the implementation. + * @date: String from __DATE__ macro at compile time. + * + * This structure type contains important information about the particular + * implementation of the MCD API. + */ +typedef struct mcd_impl_version_info_st { + mcd_api_version_st v_api; + uint16_t v_imp_major; + uint16_t v_imp_minor; + uint16_t v_imp_build; + char vendor[MCD_API_IMP_VENDOR_LEN]; + char date[16]; +} mcd_impl_version_info_st; + + +/** + * struct mcd_error_info_st - Structure type containing the error status and + * error event notification. + * + * @return_status: Return status from the last API call. + * @error_code: Detailed error code from the last API call. + * @error_events: Detailed event code from the last API call. + * @error_str: Detailed error text string from the last API call. + * + * All API functions return a value of type mcd_return_et. If this value + * indicates an error or an error event that has happened during the last API + * call, the calling function has to handle it appropriately. This can be + * achieved by asking for more information about the occurred error or error + * event. This structure type contains all the required details about the error + * and/or the error event as reported by the target. + */ +typedef struct mcd_error_info_st { + mcd_return_et return_status; + mcd_error_code_et error_code; + mcd_error_event_et error_events; + char error_str[MCD_INFO_STR_LEN]; +} mcd_error_info_st; + + +/** + * struct mcd_server_info_st - Structure type containing the server information. + * + * @server: String containing the server name. + * @system_instance: String containing the unique system instance identifier. + * @acc_hw: String containing the unique device access hardware name. + * + * This structure type contains the information about a running or an installed + * server. + * + * @server contains a string with the server name. For a running simulation + * server, @system_instance has the same value as @system_instance in + * mcd_core_con_info_st, and @acc_hw contains an empty string. For a real + * hardware server it is the other way around. + */ +typedef struct mcd_server_info_st { + char server[MCD_UNIQUE_NAME_LEN]; + char system_instance[MCD_UNIQUE_NAME_LEN]; + char acc_hw[MCD_UNIQUE_NAME_LEN]; +} mcd_server_info_st; + + +/** + * struct mcd_server_st - Structure type containing the server connection + * instance. + * + * @instance: Server connection instance of an implementation at lower level. + * @host: String containing the host name. + * @config_string: Server configuration information. + * + * This structure type contains a server connection instance. + * + * For the MCD API a server provides the capability to connect to a system, its + * devices and/or cores. A server can arrange connections to several systems. A + * system again consists of devices and cores, where devices may subsume + * several cores, e.g. a SoC on a real hardware board. Consequently, a + * multi-core simulation is a system with several processor cores. + */ +typedef struct mcd_server_st { + void *instance; + const char *host; + const char *config_string; +} mcd_server_st; + + +/** + * struct mcd_core_con_info_st - Structure type containing the core connection + * information. + * + * @host: String containing the IP host name. + * @server_port: Port number of the server. + * @server_key: String containing the server key as provided by + * mcd_open_server_f(). + * @system_key: String containing the system key as provided by + * mcd_open_server_f(). + * @device_key: String containing the device key, optional for + * mcd_open_core_f(). + * @system: String containing the system name. Predefined value is + * "Real HW" for physical devices. Note that in case of "Real + * HW" the @acc_hw always needs to be defined. + * @system_instance: String containing the unique system instance identifier. + * Allows to differentiate between several system instances + * with the same name. A typical use case is a simulator where + * different instances can be distinguished by their process + * ID. (For example @system_instance could be: "Process ID: + * 1234") + * @acc_hw: String containing the unique device access hardware name. + * @device_type: Device type identifier (IEEE 1149.1 device ID) + * @device: String containing the system unique device instance name. + * For Real HW this is usually the sales name of the device. + * If the access hardware operates a multi device target + * system (e.g. over IEEE1149.7), this device string can + * contain an index to differentiate between several devices + * of the same type. + * @device_id: Unique device ID. + * @core: String containing the device unique core name. + * @core_type: Core type identifier (taken from ELF predefined + * architecture) + * @core_id: Unique core ID representing the core version. + * + * The MCD hierarchy's top-level is a system. The next level are devices and + * followed by cores at the lowest level are cores. The MCD API is core centric, + * i.e. connections are established to specific cores and not to a device or a + * system. The core connection information is used to open this connection with + * mcd_open_core_f(). In order to establish a core connection, the core + * connection information does not have to complete but it has to be + * unambiguous. A set of hierarchical query functions, starting at system level, + * allows to parse each system top down. It is recommended to exclude + * unnecessary and redundant hierarchy information from @core and @device. + * @device needs to be readable and unambiguous within a @system. @core again + * has to be readable and unambiguous within its superior @device instance. + * + * This structure type contains all information required to establish a core + * connection. + */ +typedef struct mcd_core_con_info_st { + char host[MCD_HOSTNAME_LEN]; + uint32_t server_port; + char server_key[MCD_KEY_LEN]; + char system_key[MCD_KEY_LEN]; + char device_key[MCD_KEY_LEN]; + char system[MCD_UNIQUE_NAME_LEN]; + char system_instance[MCD_UNIQUE_NAME_LEN]; + char acc_hw[MCD_UNIQUE_NAME_LEN]; + uint32_t device_type; + char device[MCD_UNIQUE_NAME_LEN]; + uint32_t device_id; + char core[MCD_UNIQUE_NAME_LEN]; + uint32_t core_type; + uint32_t core_id; +} mcd_core_con_info_st; + + +/** + * struct mcd_core_st - Structure type containing the core connection instance. + * + * @instance: Core connection instance of an implementation at lower level. + * This void pointer must not be null except from function calls + * concerning communication channels. For these calls, null + * pointers are allowed in order to address hierarchical levels + * higher than core level. + * @core_con_info: Core connection information of the core instance. + * + * This structure type contains a core connection instance. + */ +typedef struct mcd_core_st { + void *instance; + const mcd_core_con_info_st *core_con_info; +} mcd_core_st; + + +/** + * struct mcd_core_mode_info_st - Structure type containing information about a + * core mode. + * + * @core_mode: Contains one of the 32 possible core modes, + * values can be 1 to 32. + * @name: The name of this core mode. + * + * This structure type contains information about a specific core mode. Most + * cores have for example "supervisor" or "user" operation modes. @core_mode can + * be a value within the range of 1 to 32. Some API structures contain bitmasks + * of which each bit corresponds to @core_mode of exactly one core mode (bit 0 + * corresponds to core mode 1). Core mode 0 is used to define a default core + * mode - usually the most permissive core mode. + */ +typedef struct mcd_core_mode_info_st { + uint8_t core_mode; + char name[MCD_CORE_MODE_NAME_LEN]; +} mcd_core_mode_info_st; + + +/** + * struct mcd_addr_st - Structure type containing a completely resolved logical + * or physical memory address. + * + * @address: Address value within a memory space, expressed in bytes. + * @mem_space_id: ID of the memory space associated with this address, e.g. a + * program memory, a data memory or registers . + * @addr_space_id: ID of the address space in which this address is valid. + * @addr_space_type: Type of the address space in which this address is valid. + * + * This structure type contains a completely resolved logical or physical memory + * address. The @address is always expressed in bytes, even if the minimum + * access unit (MAU) size is larger than a byte. The + * @addr_space_id can be used for different purposes as defined by + * @addr_space_type. + */ +typedef struct mcd_addr_st { + uint64_t address; + uint32_t mem_space_id; + uint32_t addr_space_id; + mcd_addr_space_type_et addr_space_type; +} mcd_addr_st; + + +/** + * struct mcd_memspace_st - Structure type containing information about a memory + * space. + * + * @mem_space_id: ID of this memory space, ID 0 is reserved. + * @mem_space_name: Unique name of the memory space. + * @mem_type: Type of the memory space. + * @bits_per_mau: Bits per minimum addressable unit (MAU). The + * minimum addressable unit of a memory is defined as + * the size in bits of its basic block that may have + * a unique address. For example for a byte + * addressable memory this value would be set to '8' + * according to the 8 bits of a byte block. + * @invariance: The total number of bytes in a memory word, which + * is @bits_per_mau divided by 8, consists of groups + * of "invariant" bytes. These groups can be arranged + * in Big Endian or Little Endian order. + * For example an @invariance of '2' and '64' + * @bits_per_mau, a Little Endian word are + * represented as b0 b1 b2 b3 b4 b5 b6 b7. + * In contrast to this, a Big Endian word is + * represented as b6 b7 b4 b5 b2 b3 b0 b1. + * @endian: Endianness of this memory space. Can be overriden + * by @endian of a mcd_memblock_st. + * @min_addr: Minimum address of this memory space. + * @max_addr: Maximum address of this memory space. + * @num_mem_blocks: Number of memory blocks in this memory space. Each + * memory space may have a certain number of memory + * blocks. Memory blocks contain additional + * information pertaining to the intended purpose of + * the memory. This information may be used as a hint + * for memory data representation within a tool's + * memory view. This field specifies the number of + * memory blocks present in this memory space. + * @supported_access_options: Supported memory access options (OR'ed bitmask). + * Can be overriden by @supported_access_options of a + * mcd_memblock_st. + * @core_mode_mask_read: Mask of core modes for which read accesses are + * impossible. A set bit indicates that read accesses + * are denied in this mode. Bit 0 represents core + * mode '1', bit 31 represents core mode '32'. Can be + * overriden by + * @core_mode_mask_read of a mcd_memblock_st. + * @core_mode_mask_write: Mask of core modes for which write accesses are + * impossible; a set bit indicates that write + * accesses are denied in this mode. Bit 0 represents + * core mode '1', bit 31 represents core mode '32'. + * Can be overriden by + * @core_mode_mask_write of a mcd_memblock_st. + * + * This structure type contains information about a memory space. of a target + * core. A memory space defines a region of memory used in different processor + * architectures, e.g. "program" and "data" memory of a Harvard architecture or + * "P"/"X"/"Y"/"Z" of a DSP architecture. + * + * Users must note that the sematics used in order to access a cache memory are + * the same as for accessing regular memory. On the target side, each cache + * memory implementation must be provided as a different memory space with a + * unique memory space ID. All accesses to such a memory space must be + * understood by the target as debug access to the cache. + */ +typedef struct mcd_memspace_st { + uint32_t mem_space_id; + char mem_space_name[MCD_MEM_SPACE_NAME_LEN]; + mcd_mem_type_et mem_type; + uint32_t bits_per_mau; + uint8_t invariance; + mcd_endian_et endian; + uint64_t min_addr; + uint64_t max_addr; + uint32_t num_mem_blocks; + mcd_tx_access_opt_et supported_access_options; + uint32_t core_mode_mask_read; + uint32_t core_mode_mask_write; +} mcd_memspace_st; + + +/** + * struct mcd_memblock_st - Structure type containing information about a memory + * block. + * + * @mem_block_id: ID of this memory block, ID 0 is reserved. + * @mem_block_name: Memory block name. + * @has_children: Indicating that this block has children. + * @parent_id: ID of this block's parent (%MCD_MEM_BLOCK_NOPARENT + * if no parent exists). Memory blocks by definition + * can be hierarchical. This field describes the ID + * of the parent memory block. In case this memory + * block is at root level (and therefore has no + * parent) the @parent_id field has to be set to + * %MCD_MEM_BLOCK_NOPARENT. + * @start_addr: Start address of this block. + * @end_addr: End address of this block. + * @endian: Endianness of this memory block. Overrides @endian + * of the corresponding mcd_memspace_st. + * @supported_au_sizes: This array has a maximum of %MCD_MEM_AUSIZE_NUM + * entries. Each entry different from '0' indicates + * the permissible size of an addressable memory unit + * in bits. All entries represent an allowed multiple + * of the @bits_per_mau field in the corresponding + * mcd_memspace_st data structure. For example, the + * supported addressable unit sizes for a memory + * block in a memory space with '32' bits_per_mau + * would be {32, 64, 96, 128}. This array field would + * then contain the values {1, 2, 3, 4}. + * @supported_access_options: Supported memory access options (OR'ed bitmask). + * Overrides @supported_access_options of the + * corresponding mcd_memspace_st. + * @core_mode_mask_read: Mask of core modes for which read accesses are + * impossible. A set bit indicates that read accesses + * are denied in this mode. Bit 0 represents core + * mode '1', bit 31 represents core mode '32'. + * Overrides @core_mode_mask_read of the + * corresponding mcd_memspace_st. + * @core_mode_mask_write: Mask of core modes for which write accesses are + * impossible. A set bit indicates that write + * accesses are denied in this mode. Bit 0 represents + * core mode '1', bit 31 represents core mode '32'. + * Overrides @core_mode_mask_write of the + * corresponding mcd_memspace_st. + * + * This structure type contains information about a memory block. A memory + * block is defined as a continuous range of memory addresses with same + * properties. A memory block is owned by a memory space. + */ +typedef struct mcd_memblock_st { + uint32_t mem_block_id; + char mem_block_name[MCD_MEM_BLOCK_NAME_LEN]; + bool has_children; + uint32_t parent_id; + uint64_t start_addr; + uint64_t end_addr; + mcd_endian_et endian; + uint32_t supported_au_sizes[MCD_MEM_AUSIZE_NUM]; + mcd_tx_access_opt_et supported_access_options; + uint32_t core_mode_mask_read; + uint32_t core_mode_mask_write; +} mcd_memblock_st; + + +/** + * struct mcd_register_group_st - Structure type containing register group + * information. + * + * @reg_group_id: Contains the ID of this register group. A register group ID + * must be unique within the scope of a target core. ID '0' is + * reserved. + * @reg_group_name: The name of a register group. A register group name cannot + * be longer than %MCD_REG_NAME_LEN characters (use + * representative names). + * @n_registers: Number of registers part of this group. + * + * This structure type contains the properties of a register group of a target + * core. + */ +typedef struct mcd_register_group_st { + uint32_t reg_group_id; + char reg_group_name[MCD_REG_NAME_LEN]; + uint32_t n_registers; +} mcd_register_group_st; + + +/** + * struct mcd_register_info_st - Structure type containing register information + * for a single register. + * + * @addr: Either the address of a memory mapped register or + * the register address in a dedicated "register memory + * space" + * @reg_group_id: ID of the group this register belongs to. + * @regname: The name of a register. A register name cannot be + * longer than %MCD_REG_NAME_LEN characters (use + * representative names). + * @regsize: Register size in bits. + * @core_mode_mask_read: Mask of core modes for which read accesses are + * impossible. A set bit indicates that read accesses + * are denied in this mode. Bit 0 represents core mode + * '1', bit 31 represents core mode 32. Overrides + * @core_mode_mask_read of the corresponding + * mcd_memspace_st. + * @core_mode_mask_write: Mask of core modes for which write accesses are + * impossible. A set bit indicates that write accesses + * are denied in this mode. Bit 0 represents core mode + * '1', bit 31 represents core mode '32'. Overrides + * @core_mode_mask_write of the corresponding + * mcd_memspace_st. + * @has_side_effects_read: Reading this register can trigger side effects. + * @has_side_effects_write: Writing this register can trigger side effects. + * @reg_type: Register type (simple, compound or partial) + * @hw_thread_id: Hardware thread ID this register belongs to. The ID + * must be set to '0' if the register is not assigned + * to a hardware thread. + * + * This structure contains the properties of a single register of a target + * core. + */ +typedef struct mcd_register_info_st { + mcd_addr_st addr; + uint32_t reg_group_id; + char regname[MCD_REG_NAME_LEN]; + uint32_t regsize; + uint32_t core_mode_mask_read; + uint32_t core_mode_mask_write; + bool has_side_effects_read; + bool has_side_effects_write; + mcd_reg_type_et reg_type; + uint32_t hw_thread_id; +} mcd_register_info_st; + + +/** + * struct mcd_trig_info_st - Structure type containing information about trigger + * capabilities. + * + * @type: Supported trigger types (OR'ed bitmask). + * @option: Supported trigger options (OR'ed bitmask). + * @action: Supported trigger actions (OR'ed bitmask). + * @trig_number: Number of usable triggers (or 0 if number not known). + * @state_number: Number of states of the trigger set's state machine (or 0 if + * not known). + * @counter_number: Number of usable counters (or 0 if not known) + * @sw_breakpoints: True if software breakpoints via code patch are available. + * + * This structure type contains information about the trigger capabilities of a + * target. + * + * Note: @trig_number, @state_number and @counter_number should NOT be used to + * determine if the appropriate trigger resource is available. It can just + * provide hints about the maximum number. The availability should be checked + * evaluating @action. + */ +typedef struct mcd_trig_info_st { + mcd_trig_type_et type; + mcd_trig_opt_et option; + mcd_trig_action_et action; + uint32_t trig_number; + uint32_t state_number; + uint32_t counter_number; + bool sw_breakpoints; +} mcd_trig_info_st; + + +/** + * struct mcd_ctrig_info_st - Structure type containing information about a + * custom trigger. + * + * @ctrig_id: Custom trigger ID, ID 0 is reserved. + * @info_str: Description of the custom trigger. + * + * This structure type contains information about a custom trigger. These custom + * triggers can be used via the mcd_trig_custom_st structure type. + * + * Note: This is NOT related to custom trigger formats - they use a format not + * defined by the MCD API. + */ +typedef struct mcd_ctrig_info_st { + uint32_t ctrig_id; + char info_str[MCD_INFO_STR_LEN]; +} mcd_ctrig_info_st; + + +/** + * struct mcd_trig_complex_core_st - Structure type containing information about + * a complex core trigger condition. + * + * @struct_size: Size of this structure in bytes. + * @type: Trigger type, for this structure type it must be one of: + * + * - %MCD_TRIG_TYPE_IP + * - %MCD_TRIG_TYPE_READ + * - %MCD_TRIG_TYPE_WRITE + * - %MCD_TRIG_TYPE_RW + * - %MCD_TRIG_TYPE_NOCYCLE + * + * @option: Adds further qualifiers to the trigger or overrides the + * behaviour (multiple options possible) + * @action: Action to be taken on trigger. Only one per trigger allowed. + * @action_param: Parameter for action - depends on the selected action. + * @modified: Set to "TRUE" on return of mcd_create_trig_f() if trigger + * was modified by implementation, untouched otherwise. + * @state_mask: Set bits indicate that this trigger is inactive when + * reaching the corresponding state of the state machine. Bit 0 + * represents state '1' of the state machine. Only to be + * considered if %MCD_TRIG_OPT_STATE_IS_CONDITION is set in + * @option. + * @addr_start: Start address for the address range the trigger shall be + * activated for. + * @addr_range: Size of the address range for the trigger (in bytes). If it + * is set to '0', the trigger is activated by an access to a + * single address. If it is set to '1', the range of addresses + * is two (@addr_start + 1). The address range can be + * "inverted" if %MCD_TRIG_OPT_OUT_OF_RANGE is set in @option. + * @data_start: Data comparison value of the trigger. Only considered if + * %MCD_TRIG_OPT_DATA_IS_CONDITION is set in @option. Setting + * option %MCD_TRIG_OPT_NOT_DATA activates the trigger on a + * data mismatch. + * @data_range: Size of the data value range for the trigger. If it is set + * to '0', the trigger is activated on a match with a single + * value. If it is set to '1', the range of values is two + * (@data_range + 1). Option %MCD_TRIG_OPT_SIGNED_DATA may be + * set in @option if the data shall be interpreted as signed. + * This usually also requires the option + * %MCD_TRIG_OPT_DATASIZE_IS_CONDITION to be set in @option. + * @data_mask: Only value bits are considered for which the mask is set to + * '0' + * @data_size: Size of the access in bytes. If set to '0' the size shall + * not be considered. Shall be only considered if + * %MCD_TRIG_OPT_DATASIZE_IS_CONDITION is set in @option. + * @hw_thread_id: ID of the hardware thread this trigger is associated with. + * @sw_thread_id: ID of the software thread this trigger is associated with. + * @core_mode_mask: Mask of core modes for which the trigger shall not be + * activated. A set bit disables the trigger for the + * corresponding mode. Bit 0 represents core mode '1', bit 31 + * represents core mode '32'. + * + * This structure type contains information about a complex core based trigger + * of the target system. + */ +typedef struct mcd_trig_complex_core_st { + uint32_t struct_size; + mcd_trig_type_et type; + mcd_trig_opt_et option; + mcd_trig_action_et action; + uint32_t action_param; + bool modified; + uint32_t state_mask; + mcd_addr_st addr_start; + uint64_t addr_range; + uint64_t data_start; + uint64_t data_range; + uint64_t data_mask; + uint32_t data_size; + uint32_t hw_thread_id; + uint64_t sw_thread_id; + uint32_t core_mode_mask; +} mcd_trig_complex_core_st; + + +/** + * struct mcd_trig_simple_core_st - Structure type containing information about + * a simple core trigger condition. + * @struct_size: Size of this structure in bytes. + * @type: Trigger type, for this structure type it must be one of: + * + * - %MCD_TRIG_TYPE_IP + * - %MCD_TRIG_TYPE_READ + * - %MCD_TRIG_TYPE_WRITE + * - %MCD_TRIG_TYPE_RW + * - %MCD_TRIG_TYPE_NOCYCLE + * + * @option: Adds further qualifiers to the trigger or overrides the + * behaviour (multiple options possible) + * @action: Action to be taken on trigger. Only one per trigger allowed. + * @action_param: Parameter for action - depends on the selected action. + * @modified: Set to "TRUE" on return of mcd_create_trig_f() if trigger + * was modified by implementation, untouched otherwise. + * @state_mask: Set bits indicate that this trigger is inactive when + * reaching the corresponding state of the state machine. Bit 0 + * represents state '1' of the state machine. Only to be + * considered if %MCD_TRIG_OPT_STATE_IS_CONDITION is set in + * @option. + * @addr_start: Start address for the address range the trigger shall be + * activated for. + * @addr_range: Size of the address range for the trigger (in bytes). If it + * is set to '0', the trigger is activated by an access to a + * single address. If it is set to '1', the range of addresses + * is two (@addr_start + 1). The address range can be + * "inverted" if %MCD_TRIG_OPT_OUT_OF_RANGE is set in @option. + * + * This structure type contains information about a simple core based trigger of + * the target system. It is a subset of mcd_trig_complex_core_st. + */ +typedef struct mcd_trig_simple_core_st { + uint32_t struct_size; + mcd_trig_type_et type; + mcd_trig_opt_et option; + mcd_trig_action_et action; + uint32_t action_param; + bool modified; + uint32_t state_mask; + mcd_addr_st addr_start; + uint64_t addr_range; +} mcd_trig_simple_core_st; + + +/** + * struct mcd_trig_trig_bus_st - Structure type containing information about a + * trigger bus based trigger condition. + * + * @struct_size: Size of this structure in bytes. + * @type: Trigger type, for this structure type it must be + * %MCD_TRIG_TYPE_TRIG_BUS. + * @option: Trigger options, for this structure the following are + * allowed: + * + * - %MCD_TRIG_OPT_NOT + * - %MCD_TRIG_OPT_STATE_IS_CONDITION + * + * @action: Action to be taken on trigger. Only one per trigger allowed. + * @action_param: Parameter for action - depends on the selected action. + * @modified: Set to "TRUE" on return of mcd_create_trig_f() if trigger + * was modified by implementation, untouched otherwise. + * @state_mask: Set bits indicate that this trigger is inactive when + * reaching the corresponding state of the state machine. Bit 0 + * represents state '1' of the state machine. Only to be + * considered if %MCD_TRIG_OPT_STATE_IS_CONDITION is set in + * @option. + * @trig_bus_value: Trigger bus value. + * @trig_bus_mask: Only value bits are considered for which the bitmask is set + * to '0'. + * + * Trigger buses exist that can be optionally activated. This structure type + * contains information about a trigger on the target system based on such a + * trigger bus. + * + * A trigger bus is split into a core local trigger (bits 0 to 15) and a global + * trigger (bits 16 to 31). On real silicon some bits of the trigger bus may + * also be available on device pins. + */ +typedef struct mcd_trig_trig_bus_st { + uint32_t struct_size; + mcd_trig_type_et type; + mcd_trig_opt_et option; + mcd_trig_action_et action; + uint32_t action_param; + bool modified; + uint32_t state_mask; + uint32_t trig_bus_value; + uint32_t trig_bus_mask; + +} mcd_trig_trig_bus_st; + + +/** + * struct mcd_trig_counter_st - Structure type containing information about a + * trigger counter on the target. + * + * @struct_size: Size of this s tructure in bytes. + * @type: Trigger type, for this structure type it must be + * %MCD_TRIG_TYPE_TRIG_COUNTER. + * @option: Trigger options, for this structure the following are + * allowed: + * + * - %MCD_TRIG_OPT_NOT + * - %MCD_TRIG_OPT_STATE_IS_CONDITION + * + * @action: Action to be taken on trigger. Only one per trigger allowed. + * @action_param: Parameter for action - depends on the selected action. + * @modified: Set to "TRUE" on return of mcd_create_trig_f() if trigger + * was modified by implementation, untouched otherwise. + * @state_mask: Set bits indicate that this trigger is inactive when + * reaching the corresponding state of the state machine. Bit 0 + * represents state '1' of the state machine. Only to be + * considered if %MCD_TRIG_OPT_STATE_IS_CONDITION is set in + * @option. + * @count_value: Current value of counter. + * @reload_value: Reload value of counter. + * + * This structure type contains information about a trigger counter on the + * target system. + */ +typedef struct mcd_trig_counter_st { + uint32_t struct_size; + mcd_trig_type_et type; + mcd_trig_opt_et option; + mcd_trig_action_et action; + uint32_t action_param; + bool modified; + uint32_t state_mask; + uint64_t count_value; + uint64_t reload_value; +} mcd_trig_counter_st; + + +/** + * struct mcd_trig_custom_st - Structure type containing information about a + * custom trigger on the target. + * + * @struct_size: Size of this structure in bytes. + * @type: Trigger type, for this structure type it must be + * %MCD_TRIG_TYPE_CUSTOM. + * @option: Trigger options, for this structure the following are + * allowed: + * + * - %MCD_TRIG_OPT_NOT + * - %MCD_TRIG_OPT_STATE_IS_CONDITION + * + * @action: Action to be taken on trigger. Only one per trigger allowed. + * @action_param: Parameter for action - depends on the selected action. + * @modified: Set to "TRUE" on return of mcd_create_trig_f() if trigger + * was modified by implementation, untouched otherwise. + * @state_mask: Set bits indicate that this trigger is inactive when + * reaching the corresponding state of the state machine. Bit 0 + * represents state '1' of the state machine. Only to be + * considered if %MCD_TRIG_OPT_STATE_IS_CONDITION is set in + * @option. + * @ctrig_id: Custom trigger ID. + * @ctrig_args: Custom trigger arguments. + * + * This structure type contains information about a custom trigger on the target + * system. + */ +typedef struct mcd_trig_custom_st { + uint32_t struct_size; + mcd_trig_type_et type; + mcd_trig_opt_et option; + mcd_trig_action_et action; + uint32_t action_param; + bool modified; + uint32_t state_mask; + uint32_t ctrig_id; + uint32_t ctrig_args[4]; +} mcd_trig_custom_st; + + +/** + * struct mcd_trig_state_st - Structure type containing a trigger state. + * + * @active: Was active at the point of time the trigger set was + * uploaded. + * @captured: Activated at least once after trigger got downloaded to the + * target. + * @captured_valid: The information in @captured is valid. + * @count_value: Current value of the counter (for counter triggers). + * @count_valid: The information in @count_value is valid. + * + * This structure type contains the state of a single trigger on the target + * system. + */ +typedef struct mcd_trig_state_st { + bool active; + bool captured; + bool captured_valid; + uint64_t count_value; + bool count_valid; +} mcd_trig_state_st; + + +/** + * struct mcd_trig_set_state_st - Structure type containing a trigger set state. + * + * @active: Set if the trigger set is currently active. + * @state: Current state of the trigger set's state machine. + * @state_valid: Current state is valid. + * @trig_bus: Current state of trigger bus. + * @trig_bus_valid: Current state of trig_bus is valid. + * @trace: Current state of trace start/stop. + * @trace_valid: Current state is valid. + * @analysis: Current state of performance analysis start/stop. + * @analysis_valid: Current state is valid. + * + * This structure type contains the state of the trigger set of the target + * system. + */ +typedef struct mcd_trig_set_state_st { + bool active; + uint32_t state; + bool state_valid; + uint32_t trig_bus; + bool trig_bus_valid; + bool trace; + bool trace_valid; + bool analysis; + bool analysis_valid; +} mcd_trig_set_state_st; + + +/** + * struct mcd_tx_st - Structure type containing information about a single + * transaction. + * + * @addr: The address of the first memory cell/register. + * @access_type: Type of access: Read/Write/Read+Write/Write+Verify. + * @options: Access options: burst, side-effects, alternate path, cache, + * etc. + * @access_width: Access size in bytes (or 0 if access size does not matter). + * @core_mode: The core mode in which the access should be performed (or 0 + * for most permissive mode). + * @data: Byte array of size @num_bytes storing the access data. + * @num_bytes: Size of the memory/register access. The buffer @data needs to + * be of this size. + * @num_bytes_ok: Number of successfully received/sent bytes. + * + * This structure type contains all information required for a single + * transaction. The transaction itself can be a memory read/write operation or a + * register read/write operation. + * + * For memory access transactions, the data is stored to the buffer in the + * target's endianess format. For register access transaction, the data is + * stored to the buffer in Little Endian format. Targets need to read/fill the + * buffer, accordingly. + */ +typedef struct mcd_tx_st { + mcd_addr_st addr; + mcd_tx_access_type_et access_type; + mcd_tx_access_opt_et options; + uint8_t access_width; + uint8_t core_mode; + uint8_t *data; + uint32_t num_bytes; + uint32_t num_bytes_ok; +} mcd_tx_st; + + +/** + * struct mcd_txlist_st - Structure type containing a transaction list. + * + * @tx: Array of size @num_tx storing the transactions. + * @num_tx: Number of transactions. + * @num_tx_ok: Number of transactions which succeeded without any errors. + * + * This structure type contains a transaction list. + */ +typedef struct mcd_txlist_st { + mcd_tx_st *tx; + uint32_t num_tx; + uint32_t num_tx_ok; +} mcd_txlist_st; + + +/** + * struct mcd_core_state_st - Structure type containing the state of a core. + * + * @state: Core state. + * @event: Core events (OR'ed bitmask) + * @hw_thread_id: ID of the hardware thread that caused the core to stop. + * @trig_id: ID of the trigger that caused the core to stop. + * @stop_str: Detailed description of a special stop reason. + * @info_str: Detailed description of the core state. + * + * This structure type contains information about the state of a core. + * + * Note that the additional information provided in @info_str is not a + * repetition of the general core state provided by @state. + */ +typedef struct mcd_core_state_st { + mcd_core_state_et state; + mcd_core_event_et event; + uint32_t hw_thread_id; + uint32_t trig_id; + char stop_str[MCD_INFO_STR_LEN]; + char info_str[MCD_INFO_STR_LEN]; +} mcd_core_state_st; + + +/** + * struct mcd_rst_info_st - Structure type containing information about a + * particular reset class. + * + * @class_vector: Reset class vector which issues this reset. Exactly one bit + * may be set. + * @info_str: Description of the reset class. + * + * This structure type contains information about a particular reset class. Only + * a single bit of the 32 bit field @class_vector can be '1'. It represents the + * reset class for this particular reset. At target system level, there cannot + * be two objects of type mcd_rst_info_st bound to the same reset class. + */ +typedef struct mcd_rst_info_st { + uint32_t class_vector; + char info_str[MCD_INFO_STR_LEN]; +} mcd_rst_info_st; + + +/** + * struct mcd_chl_st - Structure type containing information about + * communication channels. + * + * @chl_id: Channel ID. + * @type: Type of the requested channel. + * @attributes: Attributes the requested channel has to provide. + * @max_msg_len: Maximum message length (e.g. size of the message buffer as + * specified by @msg_buffer_addr). + * @msg_buffer_addr: Address of the message buffer for memory mapped channels. + * @prio: Channel priority for a prioritized channel. Range is from 0 + * (highest priority) to %MCD_CHL_LOWEST_PRIORITY. + * + * This structure type contains information about the setup of a communication + * channel and about its properties. + */ +typedef struct mcd_chl_st { + uint32_t chl_id; + mcd_chl_type_et type; + mcd_chl_attributes_et attributes; + uint32_t max_msg_len; + mcd_addr_st msg_buffer_addr; + uint8_t prio; +} mcd_chl_st; + + +/** + * struct mcd_trace_info_st - Structure type containing information about a + * trace. + * + * @trace_id: ID of this trace source, ID 0 is reserved. This ID is + * used to identify the trace by all trace related f + * @trace_name: Trace source name. + * @trace_type: Type of this trace. + * @trace_format: Used trace data format. + * @trace_modes: Possible modes of this trace (OR'ed bitmask). + * @trace_no_timestamps: Is set if the target has no global "time" concept. It + * may still provide clock cycle information. + * @trace_shared: Is set if the trace buffer used by this trace is shared + * with other traces. + * @trace_size_is_bytes: Is set when the tracebuffer size (in + * mcd_trace_state_st) is defined in bytes instead of + * frames. + * + * This structure type contains information about a trace. + */ +typedef struct mcd_trace_info_st { + uint32_t trace_id; + char trace_name[MCD_INFO_STR_LEN]; + mcd_trace_type_et trace_type; + mcd_trace_format_et trace_format; + mcd_trace_mode_et trace_modes; + bool trace_no_timestamps; + bool trace_shared; + bool trace_size_is_bytes; +} mcd_trace_info_st; + + +/** + * struct mcd_trace_state_st - Structure type containing the trace state. + * + * @state: Trace state. + * @mode: Trace buffer mode. + * @autoarm: Trace's ARM/OFF state follows core run state. + * @wraparound: Set if the frame counter has wrapped around (in FIFO + * mode) or overflowed (in PIPE mode). + * @frames: Number of valid trace frames in the buffer. + * @count: Counts frames, but is not reset due to a wraparound if + * running in FIFO mode (serves as progress indicator). + * @size: Maximum size of trace (frames or bytes). + * @trigger_delay: Trigger delay. Input has the same unit as @size (frames + * or bytes). Output is the actually elapsed number of + * frames. + * @timestamp_accuracy: Accuracy of timestamping in percent (0 to 100). Higher + * values indicate more accurate timestamps. + * @timestamp_is_time: Set when timestamp is a time value (in picoseconds). + * Otherwise it represents clock cycles. + * @options: Implementation specific options. + * @modified: Set on return from mcd_set_trace_state_f when + * implementation could not exactly match requests.. + * @info_str: Additional information about the trace (only special + * state information). + * + * This structure type contains information about the trace state. + * + * Note that the additional information provided by @info_str is no repetition + * of the general trace state provided by @state. + */ +typedef struct mcd_trace_state_st { + mcd_trace_state_et state; + mcd_trace_mode_et mode; + bool autoarm; + bool wraparound; + uint64_t frames; + uint64_t count; + uint64_t size; + uint64_t trigger_delay; + uint8_t timestamp_accuracy; + bool timestamp_is_time; + uint32_t options; + bool modified; + char info_str[MCD_INFO_STR_LEN]; +} mcd_trace_state_st; + + +/** + * struct mcd_trace_data_core_st - Structure type containing simple core trace + * data. + * + * @timestamp: Timestamp of this cycle (picoseconds or clock cycles). + * @marker: Markers for this cycle. + * @cycle: Basic cycle type. + * @addr: Address. + * @data: Data (code length for program flow). + * @data_width: Width of data (in bytes), zero if @data_mask is used. + * @data_mask: Data bitmask, set bits indicate that the related byte in @data + * is valid. Zero if @data_width is used. + * @source: Additional source information (hardware thread ID, bus + * initiator, etc. + * @aux_info: Auxiliary information, e.g. endianess, burst information or core + * execution mode. + * + * This structure type contains simple trace data of cores and buses. + */ +typedef struct mcd_trace_data_core_st { + uint64_t timestamp; + mcd_trace_marker_et marker; + mcd_trace_cycle_et cycle; + mcd_addr_st addr; + uint64_t data; + uint8_t data_width; + uint8_t data_mask; + uint16_t source; + uint32_t aux_info; +} mcd_trace_data_core_st; + + +/** + * struct mcd_trace_data_event_st - Structure type containing logic analyzer + * trace data. + * @timestamp: Timestamp of this cycle (either picoseconds or clock cycles). + * @marker: Markers for this cycle. + * @data: User data, array of 256 bits. + * LSB of data[0] represents channel0. + * + * This structure type contains "logic analyzer"-like trace data (256 channels). + */ +typedef struct mcd_trace_data_event_st { + uint64_t timestamp; + mcd_trace_marker_et marker; + uint32_t data[8]; +} mcd_trace_data_event_st; + + +/** + * struct - Structure type containing statistic counter data. + * + * @timestamp: Timestamp of this cycle (either picoseconds or clock cycles). + * @marker: Markers for this cycle. + * @count: Array of 8 statistic counters ('-1' represents an invalid value). + * + * This structure type contains "logic analyzer"-like trace data (8 channels). + */ +typedef struct mcd_trace_data_stat_st { + uint64_t timestamp; + mcd_trace_marker_et marker; + uint64_t count[8]; +} mcd_trace_data_stat_st; + + +/** + * DOC: Target Initialization API + * + * API initialization functions are dedicated to Target interface initialization + * and closure. They allow to initialize the interaction between a tool and a + * target, as well as clean-up connections before closure. + */ + + +/** + * mcd_initialize_f() - Function initializing the interaction between a + * tool-side implementation and target-side implementation. + * + * @version_req: [in] MCD API version as requested by an upper layer. + * @impl_info: [out] Information about the implementation of the MCD API + * implementation. + * + * This function returns the version and vendor information for a particular + * implementation of the MCD API in order to initialize the interaction between + * a tool and a target-side implementation. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if target implementation is incompatible. + */ +mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, + mcd_impl_version_info_st *impl_info); + + +/** + * mcd_exit_f() - Function cleaning up all core and server connections from a + * tool. + * + * This function allows to perform some cleanup functionality for all core + * connections to a particular debugger before closing the connections. + */ +void mcd_exit_f(void); + + +/** + * DOC: Server Connection API + * + * Server-connection API functions are used to setup a connection between a tool + * and a target through a target server. They allow to locate a target server + * open or close a connection to a target server. They also allow to retrieve + * and change a target server configuration. + */ + + +/** + * mcd_qry_servers_f() - Function returning a list of available servers. + * + * @host: [in] String containing the host name. + * @running: [in] Selects between running and installed servers. + * @start_index: [in] Start index of the queried servers. This refers to an + * internal list of the target side implementation. + * @num_servers: + * * [in] The number of queried servers starting from the defined + * @start_index. If it is set to '0', no server descriptions are returned but + * the number of all available servers. + * * [out] The number of returned servers. In case the input value of + * @num_servers is '0', this is the number of all available servers. + * @server_info: [out] Server information. This is an array allocated by the + * calling function. + * + * This function returns a list of available (running or installed) servers. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if @start_index is equal or larger than the number of + * available servers. + * - %MCD_ERR_CONNECTION if query failed. + */ +mcd_return_et mcd_qry_servers_f(const char *host, bool running, + uint32_t start_index, uint32_t *num_servers, + mcd_server_info_st *server_info); + + +/** + * mcd_open_server_f() - Function opening the connection to a server on a host + * computer. + * + * @config_string: [in] Allows the configuration of the server connection by a + * character string. Delimiters are blanks, tabs and line + * breaks. Value strings are always enclosed with "double + * quotes". Bool values can be "TRUE" or "FALSE" (both in + * small letters). + * @system_key: [in] A server is claimed by this key when being opened. + * @server: [out] Pointer to the server connection instance. In contrast + * to the MCD API's usual calling scheme, the target has to + * allocate the object the pointer refers to. + * + * Pre-defined @config_string string parameters: + * + * - McdHostName= : Optional host name. Default value is + * "localhost". + * - McdServerName= : Name of the server to connect to. + * - McdSystemInstance= : Name of the simulation system instance this + * server is associated with. + * - McdServerKey= : Static key for this specific server. + * - McdExitIfLastClient : If mcd_close_server_f() is called for the + * last client connection, the server will terminate. + * + * Additional pre-defined string parameters for real hardware: + * + * - McdAccHw= : Restricts this server to connect to + * devices via a specific access hardware as determined by the string. + * - McdAccHw.Frequency= : Decimal (32 bit) value setting the + * frequency of the physical I/F (e.g. according to IEEE 1149.1) + * - McdAccHw.PostRstDelay= : Delay [microseconds] after reset before + * first interaction with the device is allowed. + * - McdAccHw.Device="" : Description of connected device. + * - McdAccHw.DeviceId= : Device ID (e.g. IEEE 1149.1 ID) of + * connected device. + * - McdAccHw.AutoDetect= : If set to "TRUE" the access HW detects + * the device (DeviceId and Device will be ignored). + * + * Interactive Server Connection Setup + * + * If a server(s) is running, mcd_open_server_f() can be called with an empty or + * NULL pointer @config_string. Then it connects to the first possible + * simulation system or, for real hardware, access hardware path. A second call + * (while the first server is still open) will open the second possible + * simulation system or access hardware path and so on. In order to restrict the + * potential list of connections to a server, "McdServerName" (and + * "McdServerKey") can be optionally provided with @config_string. + * + * mcd_qry_server_config_f() returns the complete configuration string for a + * server/device connection. This allows storing this configuration to avoid an + * interactive server connection setup for the next debug session. This is in + * particular useful for Real HW multi device systems in order to connect the + * devices step by step. + * + * Server and System Keys + * + * A server can optionally require a key for access (\c config_string parameter + * "McdServerKey"). This allows for example to prevent an unauthorized access to + * a test stand which might cause damage. A system key additionally allows to + * dynamically claim a server or to prevent several users from unintentionally + * accessing the same system at the same time through a specific set of servers. + * + * A key can be a password string or a sequence of decimal or hexadecimal + * numbers separated by whitespaces. + * + * This function opens the connection to a server on a host computer and updates + * the internal core information data base. It contains the information about + * all cores of devices which are simulated on the host computer or which are + * accessible on real silicon through a specific tool access hardware to the + * host. This data base can then be queried at system, device and core level. + * + * For real hardware devices, a server connection needs to be opened for each + * access hardware. This allows individual control of the access parameters. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_CONNECTION if server connection failed. + */ +mcd_return_et mcd_open_server_f(const char *system_key, + const char *config_string, + mcd_server_st **server); + + +/** + * mcd_close_server_f() - Function closing the connection to a debug server on a + * host computer. + * + * @server: [in] Pointer to the server connection instance of the opened server. + * + * This function closes the connection to an opened debug server on a host + * computer. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_CONNECTION if closing the server connection failed. + */ +mcd_return_et mcd_close_server_f(const mcd_server_st *server); + + +/** + * mcd_set_server_config_f() - Function changing the configuration of an open + * debug server. + * + * @server: [in] Pointer to the server connection instance of the + * opened server. + * @config_string: [in] String to configure the server or access hardware + * device. + * + * This function allows to change the configuration of an open server. Note that + * McdHostName, McdServerName and McdSystemInstance can't be changed with this + * function. When the @config_string contains such parameter which can't be + * changed or parameters which can't be changed to the requested value (e.g. new + * McdAccHw.Frequency not supported by the Access HW), these parameters will be + * ignored or e.g. the closest possible value will be chosen by the + * implementation. This behavior allows to use the same config strings/files for + * mcd_set_server_config_f() as for mcd_open_server_f(). The tool should always + * read back the actual config parameter values with mcd_qry_server_config_f(). + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_CONNECTION if configuration of the server or access hardware + * device failed. + */ +mcd_return_et mcd_set_server_config_f(const mcd_server_st *server, + const char *config_string); + + +/** + * mcd_qry_server_config_f() - Function retrieving the configuration string of + * a debug server. + * + * @server: [in] Pointer to the server connection instance. + * @max_len: + * * [in] Maximum length of @config_string (as allocated by the calling + * function). + * * [out] Actual length required by the returned configuration string. + * @config_string: [out] String describing the configuration of the server or + * the access hardware device. + * + * This function retrieves the configuration string of an opened + * debug server. + * + * The string can be used to retrieve the configuration of a server + * for the following cases: + * - Server has been opened without setting "McdServerName" via @config_string. + * - Server has been configured with a server specific proprietary tool. + * + * Calling mcd_qry_server_config_f() with @max_len being a NULL pointer returns + * the required string length for @config_string. The returned length includes + * the terminating zero. This retrieved configuration can be stored by an MCD + * based tool in order to configure the server connection of the next session. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_CONNECTION if server connection could not be accessed. + * - %MCD_ERR_RESULT_TOO_LONG if requested configuration string is longer than + * @max_len. + */ +mcd_return_et mcd_qry_server_config_f(const mcd_server_st *server, + uint32_t *max_len, + char *config_string); + + +/** + * DOC: Target System Features API + * + * Target System Features API functions allow to query the core connection + * information according to several cases: for a specified number of systems; + * for a specified number of devices of a particular system or for a specified + * number of cores of a system (or device). This API subset also allows querying + * the available modes of a specific core. + */ + + +/** + * mcd_qry_systems_f() - Function querying the core connection information of a + * specified number of systems. + * + * @start_index: [in] Start index of the queried systems. This refers to an + * internal list of the target side implementation. + * @num_systems: + * * [in] The number of queried systems starting from the defined @start_index. + * If it is set to '0', no core connection information is returned but the + * number of available systems. + * * [out] : The number of systems the core connection info was returned for. In + * case the input value of @num_systems is '0', this is the number of all + * available systems. + * @system_con_info: [out] Core connection information of the requested systems. + * This is an array allocated by the calling function. + * + * This function queries for the core connection information of a specified + * number of systems. The returned core_con_info data are distinguished for + * different systems only by the name of the system. If @num_systems is set to + * '0', the function call returns the number of all available systems. + * + * Only the following information of @system_con_info shall be set by the + * target: + * + * - system_key + * - system + * - system_instance + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if @start_index is equal or larger than the number of + * available systems. + * - %MCD_ERR_GENERAL on any other error. + */ +mcd_return_et mcd_qry_systems_f(uint32_t start_index, uint32_t *num_systems, + mcd_core_con_info_st *system_con_info); + + +/** + * mcd_qry_devices_f() - Function querying the core connection information of a + * specified number of devices of a system. + * + * @system_con_info: [in] Core connection information of the system the devices + * are queried from. + * @start_index: [in] Start index of the requested devices. This refers to + * an internal list of the target side implementation. + * @num_devices: + * * [in] The number of queried devices (e.g. simulated on or connected to this + * host computer) starting from the defined @start_index. If it is set to '0', + * no core connection information is returned but the number of all available + * devices. + * * [out] The number of devices the core connection information was returned + * for. In case the input value of @num_devices is '0', this is the number of + * all available devices for the selected system. + * @device_con_info: [out] Core connection information of the requested devices. + * This is an array allocated by the calling function. + * + * This function queries for the core connection information of a specified + * number of devices of a particular system. If @num_devices is set to '0', the + * function call returns the number of all available devices for the system. + * + * Only the system and system_instance information of system_con_info are used + * for system selection. + * + * Only the following information of @device_con_info shall be set by the + * target: + * + * - host + * - server_port + * - system_key + * - device_key (zero length string if no device key) + * - system + * - system_instance (zero length string for Real HW) + * - acc_hw (for Real HW) + * - device_type + * - device + * - device_id + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if @start_index is equal or larger than the number of + * available devices. + * - %MCD_ERR_GENERAL on any other error. + */ +mcd_return_et mcd_qry_devices_f(const mcd_core_con_info_st *system_con_info, + uint32_t start_index, uint32_t *num_devices, + mcd_core_con_info_st *device_con_info); + + +/** + * mcd_qry_cores_f() - Function querying the core connection information of a + * specified number of cores of a system/device. + * + * @connection_info: [in] Core connection information of the system or device + * the cores are queried from. + * @start_index: [in] Start index of the requested cores. This refers to an + * internal list of the target side implementation. + * @num_cores: + * * [in] The number of queried cores starting from the defined @start_index. If + * it is set to '0', no core connection information is returned but the number + * of all available cores. + * * [out] The number of cores the core connection information is returned for. + * In case the input value of @num_cores is '0', this is the number of all + * available cores for the selected system or device. + * @core_con_info: [out] Core connection information of the requested cores. + * This is an array allocated by the calling function. + * + * This function queries the core connection information of a specified number + * of cores of a system/device. + * + * Only the system and system_instance information of connection_info are used + * for system selection. + * + * For selecting a specific device, the following information of + * @connection_info is used: + * + * - host + * - server_port + * - system_key + * - device_key (zero length string if no device key) + * - system + * - system_instance (zero length string for Real HW) + * - acc_hw (for Real HW) + * - device_type + * - device + * - device_id + * + * If device and acc_hw are given for Real HW, only the cores of this specific + * device will be returned. + * + * The output parameter @core_con_info shall contain the complete + * mcd_core_con_info_st information except from device_key. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if @start_index is equal or larger than the number of + * available cores. + * - %MCD_ERR_GENERAL on any other error. + */ +mcd_return_et mcd_qry_cores_f(const mcd_core_con_info_st *connection_info, + uint32_t start_index, uint32_t *num_cores, + mcd_core_con_info_st *core_con_info); + + +/** + * mcd_qry_core_modes_f() - Function querying the available modes of a core. + * + * @core: [in] A reference to the core the calling function addresses. + * @start_index: [in] Start index of the requested modes. This refers to an + * internal list of the target side implementation. + * @num_modes: + * * [in] The number of queried core modes starting from the defined + * @start_index. If it is set to '0', no core modes are returned but the + * number of all available core modes. + * * [out] : The number of returned core modes. In case the input value of + * @num_modes is '0', this is the number of all available core modes for the + * selected core. + * @core_mode_info: [out] : Core mode information of the requested core. This is + * an array allocated by the calling function. + * + * This function queries the available modes of a specific core. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if @start_index is equal or larger than the number of + * available core modes. + * - %MCD_ERR_GENERAL on any other error. + */ +mcd_return_et mcd_qry_core_modes_f(const mcd_core_st *core, + uint32_t start_index, uint32_t *num_modes, + mcd_core_mode_info_st *core_mode_info); + + +/** + * DOC: Core Connection API + * + * Core Connection API functions allow the management of a connection to a core, + * such as: opening or closing a specific core connection ; retrieving detailed + * error and/or event information after an API call ; as well as querying + * payload size for a transaction list. + */ + + +/** + * mcd_open_core_f() - Function opening a core connection. + * + * @core_con_info: [in] Unambiguous core information (e.g. from + * mcd_qry_cores_f()). + * @core: [out] Pointer to the requested core connection instance (In + * contrast to the API's usual scheme, the target has to + * allocate the object the pointer refers to). + * + * Note that device_key needs to be set in core_con_info in case of opening a + * locked device. + * + * This function opens a specific core connection. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if @core_con_info is ambiguous. + * - %MCD_ERR_DEVICE_LOCKED if the requested device is locked. + * - %MCD_ERR_CONNECTION if opening the core connection failed. + */ +mcd_return_et mcd_open_core_f(const mcd_core_con_info_st *core_con_info, + mcd_core_st **core); + + +/** + * mcd_close_core_f() - Function closing a core connection. + * + * @core: [in] Pointer to the core connection instance of the core to close. + * + * This function closes a specific core connection. + * + * Allowed error codes: + * + * * - %MCD_ERR_NONE if successful. + * * - %MCD_ERR_CONNECTION if closing the core connection failed. + */ +mcd_return_et mcd_close_core_f(const mcd_core_st *core); + + +/** + * mcd_qry_error_info_f() - Function allowing the access to detailed error + * and/or event information after an API call. + * + * @core: [in] A reference to the core the calling function addresses. + * This parameter can be NULL if the error occurred at a function + * without a parameter of type mcd_core_st. + * @error_info: [out] Pointer to a structure containing the detailed error/event + * information. + * + * Almost all MCD API functions return a value of type mcd_return_et. This is an + * enumeration type informing the calling function how to react on the API + * function call's results. If an error occurred, the calling function has to + * call this function in order to obtain details about the error and/or event + * which occurred during the previous call and in order to gain further details + * on it. + * + */ +void mcd_qry_error_info_f(const mcd_core_st *core, + mcd_error_info_st *error_info); + + +/** + * mcd_qry_device_description_f () - Function retrieving the file information of + * an IP-XACT description of the addressed + * component. + * + * @core: [in] A reference to the core the calling function addresses. + * @url: [out] A pointer to the string containing the URL pointing to the + * IP-XACT description is returned through this parameter. Space + * for the URL must be reserved by the caller. The string returned + * must be null terminated except if it is too large to fit the + * buffer. If called with a null pointer then the required buffer + * size will be returned in the url_length parameter. + * @url_length: [in] Pointing to the size of the buffer allocated by the caller. + * @url_length: [out] Pointing to the size of the URL returned excluding the + * terminating '\\0' character. When called with url=0 returns the + * size of the buffer required including the terminating '\\0' + * character. + * + * This functions can be used to request the URL where an IP-XACT + * description describing a system can be acquired. The most common for + * is to use a URL starting with "file://..." referring to a local + * file where the description is stored in the local filesystem. This + * is also the only mandatory URI scheme ("protocol") which must be + * supported in every tool. Other possible options are URLs starting + * with "http://..." or "ftp://...". URLs might either point to the + * MCD server itself, but could also point to locations on other + * servers. + * + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if URL could not be provided. + */ +mcd_return_et mcd_qry_device_description_f(const mcd_core_st *core, + char *url, uint32_t *url_length); + + +/** + * mcd_qry_max_payload_size_f() - Function querying the maximum payload size + * for a transaction list. + * + * @core: [in] A reference to the core the calling function addresses. + * @max_payload: [out] Maximum (and optimum) supported payload size for a + * transaction list. + * + * Different systems will support a different maximum in transaction list + * payload sizes. The payload is the net number of bytes that are read or + * written. This function queries the maximum payload size for a transaction + * list. Since a tool needs to be able to deal with smaller payload sizes, the + * only reason to use larger payloads is an improved performance. In order to + * achieve this performance, it is recommended that @max_payload is equal to the + * payload allowing the optimum performance. + * @max_payload then should be obeyed by the sent transaction lists. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL on any other error. + */ +mcd_return_et mcd_qry_max_payload_size_f(const mcd_core_st *core, + uint32_t *max_payload); + + +/** + * mcd_qry_input_handle_f() - Function querying the input handle for the + * connection. + * + * @core: [in] A reference to the core the calling function addresses. + * @input_handle: [out] Input handle or -1 if handle not defined. + * + * Fast and efficient reaction on target system events with a single threaded + * application requires that the application can wait for user input or + * asynchronous activity from the target. Obtaining the handle used for the + * communication to the target (usually a socket) allows the application to wait + * for activity there without frequent polling. If the communication is not done + * by sockets then there may be no such handle. + * + * Allowed error codes: + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL on any other error. + */ +mcd_return_et mcd_qry_input_handle_f(const mcd_core_st *core, + uint32_t *input_handle); + + +/** + * DOC: Target Memory Access API + * + * Target Memory Access API functions are related to the configuration + * of memories. They allow retrieving memory spaces for a particular component, + * or memory blocks of a specified memory space. + */ + + +/** + * mcd_qry_mem_spaces_f() - Function querying the available memory spaces for a + * particular component. + * + * @core: [in] A reference to the core the calling function addresses. + * @start_index: [in] Start index of the requested memory spaces. This refers to + * an internal list of the target side implementation. + * @num_mem_spaces: + * * [in] Number of memory spaces, information is requested of. If it is set to + * '0', no memory space information is returned but the number of all + * available memory spaces for the selected core. + * * [out] : The number of returned memory spaces. In case the input value of + * @num_mem_spaces is '0', this is the number of all available memory spaces + * for the selected core. + * @mem_spaces: [out] Memory space information. This is an array allocated by + * the calling function. + * + * There can be various memory spaces visible to a core depending on its + * architecture. For Harvard architectures these can be "program" and "data", + * for DSP architecture these can be "P"/"X"/"Y", etc. This function queries all + * memory spaces available for a particular target core. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_NO_MEM_SPACES if no memory spaces are defined for this core. + */ +mcd_return_et mcd_qry_mem_spaces_f(const mcd_core_st *core, + uint32_t start_index, + uint32_t *num_mem_spaces, + mcd_memspace_st *mem_spaces); + +/** + * mcd_qry_mem_blocks_f() - Function querying the available memory blocks of a + * specified memory space. + * + * @core: [in] A reference to the core the calling function addresses. + * @mem_space_id: [in] The ID of the memory space the calling function queries + * the memory block information from. + * @start_index: [in] Start index of the requested memory blocks. This refers + * to an internal list of the target side implementation. + * @num_mem_blocks: + * * [in] Number of memory blocks, information is requested of. If it is set to + * '0', no memory block information is returned but the number of all + * available memory blocks for the selected memory. + * * [out] : Number of returned memory blocks. In case the input value of + * @num_mem_blocks is '0', this is the number of all available memory blocks + * for the selected memory space. + * @mem_blocks: [out] Memory block information. This is an array allocated by + * the calling function. + * + * There can be various memory blocks within a particular memory space of a + * core. The memory blocks define the layout of the memory space. Memory blocks + * can be hierarchical in nature, and this query function returns information + * about all available memory blocks in the memory space. Memory blocks with the + * same parent must not overlap. This call returns existing memory blocks only. + * If a target side implementation supports memory block descriptions, the + * calling function may assume that memory which does not belong to any memory + * block is not addressable. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_NO_MEM_BLOCKS if no memory blocks are defined for this memory + * space. + */ +mcd_return_et mcd_qry_mem_blocks_f(const mcd_core_st *core, + uint32_t mem_space_id, uint32_t start_index, + uint32_t *num_mem_blocks, + mcd_memblock_st *mem_blocks); + +/** + * mcd_qry_active_overlays_f() - Function querying the active (swapped-in) + * overlays at the current time. + * + * @core: [in] A reference to the core the calling function + * addresses. + * @start_index: [in] Start index of the requested active memory + * overlays. This refers to an internal list of the target + * side implementation. + * @num_active_overlays: + * * [in] Number of active memory overlays, information is requested of. If it + * is set to '0', no active memory overlay information is returned but the + * number of all available active memory overlays for the selected core. + * * [out] Number of returned active memory overlays. In case the input value of + * @num_active_overlays is '0', this is the number of all available active + * memory overlays for the selected core. + * @active_overlays: [out] Active memory overlay information. This is an array + * allocated by the calling function. + * + * This function is called when the caller wants to retrieve the list of active + * memory overlays. This is typically done when a breakpoint is hit. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_OVERLAYS if retrieving active memory overlay information failed. + */ +mcd_return_et mcd_qry_active_overlays_f(const mcd_core_st *core, + uint32_t start_index, + uint32_t *num_active_overlays, + uint32_t *active_overlays); + + +/** + * DOC: Target Register Access API + * + * Target Register Access API functions are related to the access and + * configuration of registers. Registers in an IP may be of the following two + * types: + * + * - Internal IP registers: These registers are internal to an IP and cannot be + * accessed by other system components connected to the bus. Special means + * must be provided in order to make these registers visible to the external + * tools such as debugging and profiling tools. An example of a mechanism + * commonly used to expose such internal registers of an IP to external tools + * is the use of scan chains and an IP specific TAP controller whose data + * registers are mapped to a few of these internal registers. These registers + * must be accessed by the debugging and profiling tools using their ID, which + * need to be unique within the scope of a particular instance of an IP. + * + * - Memory Mapped registers: These registers are mapped to memory addresses + * which are an offset to a base address belonging to that IP. They can + * therefore be accessed via the bus infrastructure using common memory + * addressing mechanisms. These registers may be accessed by the debugging and + * profiling tools using their ID, which must be unique within the scope of a + * particular instance of an IP. Alternatively, they may be accessed by + * external tools using their memory mapped addresses via the memory bus. + */ + + +/** + * mcd_qry_reg_groups_f() - Function querying the register groups defined for a + * particular component. + * + * @core: [in] A reference to the core the calling function addresses. + * @start_index: [in] Start index of the requested register groups. This refers + * to an internal list of the target side implementation. + * @num_reg_groups: + * * [in] Number of register groups, information is requested of. If it is set + * to '0', no register groups information is returned but the number of all + * available register groups for the selected core. + * * [out] Number of returned register groups. In case the input value of + * @num_reg_groups is '0', this is the number of all available register groups + * for the selected core. + * @reg_groups: [out] Register group information. This is an array allocated by + * the calling function. + * + * There can be various register groups defined for a core depending on its + * architecture. This function queries information about these register groups. + * + * The parameter @num_reg_groups is used as an input/output parameter. + * As input parameter it is set to the desired number of register groups. As + * output parameter it set to the actual number of register groups information + * is returned for in @reg_groups. + * If the target does not define any register groups, it is assumed that a + * virtual register group with ID 0 exists which contains all registers of the + * corresponding component. Then the information about this default 'virtual' + * register group has to be sent back as only register group information. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_NO_REG_GROUPS if no register groups are defined for this core. + */ +mcd_return_et mcd_qry_reg_groups_f(const mcd_core_st *core, + uint32_t start_index, + uint32_t *num_reg_groups, + mcd_register_group_st *reg_groups); + + +/** + * mcd_qry_reg_map_f() - Function querying the register information of a + * particular register group. + * + * @core: [in] A reference to the core the calling function addresses. + * @reg_group_id: [in] ID of the register group detailed register information is + * requested for. + * @start_index: [in] Start index of the requested registers. This refers to an + * internal list of the target side implementation. + * @num_regs: + * * [in] Number of registers, information is requested of. If it is set to '0', + * no register information is returned but the number of all available + * registers within for the selected register group. + * * [out] Number of returned registers. In case the input value of @num_regs is + * '0', this is the number of all available register for the selected register + * group. + * @reg_info: [out] Register information. This is an array allocated by the + * calling function. + * + * There can be various register groups defined for a core depending on its + * architecture. Within each register group there can be many registers. This + * function allows the user to query information about the registers contained + * within a register group. Information all registers which have to be exposed + * to the debug environment have to be returned as a result of such a query. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_REG_GROUP_ID if no register group with this ID is available + * for this core. + */ +mcd_return_et mcd_qry_reg_map_f(const mcd_core_st *core, uint32_t reg_group_id, + uint32_t start_index, uint32_t *num_regs, + mcd_register_info_st *reg_info); + + +/** + * mcd_qry_reg_compound_f() - Function querying the component registers of a + * compound register + * + * @core: [in] A reference to the core the calling function + * addresses. + * @compound_reg_id: [in] ID of the compound register component register IDs are + * queried for. + * @start_index: [in] Start index of the requested component registers. This + * refers to an internal list of the target side + * implementation. + * @num_reg_ids: + * * [in] Number of component registers the ID is requested of. If it is set to + * '0', no component register IDs are returned but the number of all available + * component register for the selected compound register. + * * [out] : Number of returned component registers. In case the input value of + * @num_reg_ids is '0', this is the number of all available component + * registers for the selected compound register. + * @reg_id_array: [out] Component register IDs. This is an array allocated by + * the calling function. + * + * Registers within a target component may be composed of several simple + * registers. These are by definition called "compound registers". This function + * allows a user to query information about the registers contained within a + * particular compound register. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_REG_NOT_COMPOUND if no compound register with this ID is available + * for this core. + */ +mcd_return_et mcd_qry_reg_compound_f(const mcd_core_st *core, + uint32_t compound_reg_id, + uint32_t start_index, + uint32_t *num_reg_ids, + uint32_t *reg_id_array); + + +/** + * DOC: Target Trigger Setup API + * + * Target Trigger Setup API functions allow management of triggers, such as + * creation, activation, deletion or trigger status inquiry. Typical triggers + * are breakpoints, but the API allows definition of complex triggers, as well + * as complex trigger conditions. Triggers can be managed individually but also + * as a trigger set defined for a core. + */ + + +/** + * mcd_qry_trig_info_f() - Function querying information about trigger + * capabilities. + * + * @core: [in] A reference to the core the calling function addresses. + * @trig_info: [out] Information about supported triggers. + * + * This function queries information about trigger capabilities implemented + * in a target. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if trigger capabilities could not be retrieved. + */ +mcd_return_et mcd_qry_trig_info_f(const mcd_core_st *core, + mcd_trig_info_st *trig_info); + + +/** + * mcd_qry_ctrigs_f() - Function querying information about custom triggers. + * + * @core: [in] A reference to the core the calling function addresses. + * @start_index: [in] Start index of the requested custom triggers. This refers + * to an internal list of the target side implementation. + * @num_ctrigs: + * * [in] Number of custom triggers, information is requested of. If it is set + * to '0', no custom trigger information is returned but the number of all + * available custom triggers for the selected core. + * * [out] : Number of returned custom triggers. In case the input value of + * @num_ctrigs is '0', this is the number of all available custom triggers for + * the selected core. + * @ctrig_info: [out] Custom trigger information. This is an array allocated by + * the calling function. + * + * This function queries information about custom triggers of a component as + * well as the number of available custom triggers. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if custom trigger ID does not exist. + */ +mcd_return_et mcd_qry_ctrigs_f(const mcd_core_st *core, uint32_t start_index, + uint32_t *num_ctrigs, + mcd_ctrig_info_st *ctrig_info); + +/** + * mcd_create_trig_f() - Function allowing the creation of a new trigger. + * + * @core: [in] A reference to the core the calling function addresses. + * @trig: + * * [in] Pointer to the structure containing information about the trigger + * object to be created. + * * [out] : Members of the structure may be modified by the function. In this + * case the modified member of the trigger structure as well as the modified + * members are set. + * @trig_id: [out] Unique ID for the newly created trigger returned by the API + * implementation. A value of '0' indicates that the breakpoint is + * set, but cannot be identified by an ID. Removing such breakpoints + * is only possible by calling mcd_remove_trig_set_f(). + * + * This function allows a user to create a new trigger. If the exact trigger + * cannot be created, an approximate trigger is created instead and the modified + * member of the trigger structure is set. + * + * The void pointer @trig usually points to a standard trigger structure like + * mcd_trig_simple_core_st or mcd_trig_complex_core_st. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_TRIG_CREATE if trigger could not be created. + */ +mcd_return_et mcd_create_trig_f(const mcd_core_st *core, void *trig, + uint32_t *trig_id); + + +/** + * mcd_qry_trig_f() - Function querying the contents of a trigger. + * + * @core: [in] A reference to the core the calling function addresses. + * @trig_id: [in] ID of the trigger the user queries. + * @max_trig_size: [in] Maximum size of the structure in bytes as expected by + * the calling function. + * @trig: [out] Pointer to the structure receiving the information about + * the trigger object. The structure is allocated by the calling + * function. + * + * This function allows the user to query the contents of a trigger. + * The @max_trig_size parameter is set to the maximum size of + * the trigger structure the user expects in bytes. + * + * The void pointer trig usually points to a standard trigger + * structure like mcd_trig_simple_core_st or mcd_trig_complex_core_st. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_RESULT_TOO_LONG if requested trigger is larger than + * @max_trig_size. + * - %MCD_ERR_TRIG_ACCESS if trigger could not be returned for any other + * reason. + */ +mcd_return_et mcd_qry_trig_f(const mcd_core_st *core, uint32_t trig_id, + uint32_t max_trig_size, void *trig); + + +/** + * mcd_remove_trig_f() - Function allowing a user to delete a particular trigger + * from a trigger set. + * + * @core: [in] A reference to the core the calling function addresses. + * @trig_id: [in] ID of the trigger the user wants to delete. + * + * This function allows the user to delete a particular trigger from a trigger + * set. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_TRIG_ACCESS if trigger could not be accessed for deletion. + */ +mcd_return_et mcd_remove_trig_f(const mcd_core_st *core, uint32_t trig_id); + + +/** + * mcd_qry_trig_state_f() - Function allowing a user to query the trigger states + * from the target. + * + * @core: [in] A reference to the core the calling function addresses. + * @trig_id: [in] ID of the trigger, the tool queries the state for. + * @trig_state: [out] Queried Trigger state. The structure is allocated by the + * calling function. + * + * This function allows a user to query the status of a single trigger. + * Note that mcd_qry_trig_set_state_f() needs to be called before to sample + * the trigger state. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_TRIG_ACCESS if trigger could not be accessed. + */ +mcd_return_et mcd_qry_trig_state_f(const mcd_core_st *core, uint32_t trig_id, + mcd_trig_state_st *trig_state); + + +/** + * mcd_activate_trig_set_f() - Function allowing a user to activate a trigger + * set on the target. + * + * @core: [in] A reference to the core the calling function addresses. + * + * This function downloads the current trigger set to the hardware in order to + * activate it. If the trigger set is unchanged since the last call of this + * function, it will just arm the triggers again. + * + * This function is only needed to activate triggers on the fly (while the + * target is running) and in a consistent way - if supported by the target. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_TRIG_ACCESS if trigger set could not be activated. + */ +mcd_return_et mcd_activate_trig_set_f(const mcd_core_st *core); + + +/** + * mcd_remove_trig_set_f() - Function allowing a user to delete a trigger set. + * + * @core: [in] A reference to the core the calling function addresses. + * + * This function allows a user to delete a trigger set for a particular core. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_TRIG_ACCESS if trigger set could not be removed. + */ +mcd_return_et mcd_remove_trig_set_f(const mcd_core_st *core); + + +/** + * mcd_qry_trig_set_f() - Function querying the contents of a trigger set. + * + * @core: [in] A reference to the core the calling function addresses. + * @start_index: [in] Start index of the requested triggers. This refers to an + * internal list of the target side implementation. + * @num_trigs: + * * [in] The number of queried triggers starting from the defined + * @start_index. If it is set to '0', no triggers are returned but the number + * of all available triggers of the trigger set. + * * [out] The number of returned triggers. In case the input value of + * @num_trigs is '0', this is the number of all available triggers of this + * core's trigger set. + * @trig_ids: [out] List of trigger IDs set in the target. This is an array + * allocated by the calling function. + * + * This function queries information about the current state of the trigger set + * of a target core. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_TRIG_ACCESS if trigger set could not be queried. + */ +mcd_return_et mcd_qry_trig_set_f(const mcd_core_st *core, uint32_t start_index, + uint32_t *num_trigs, uint32_t *trig_ids); + + +/** + * mcd_qry_trig_set_state_f() - Function querying the state of a trigger set. + * + * @core: [in] A reference to the core the calling function addresses. + * @trig_state: [out] Information about the current state of the trigger set. + * + * This function queries information about the current state of the trigger set + * of a target core. It will consistently sample the state of all triggers in + * the set. This is in particular necessary for Real HW targets. The individual + * triggers can then be queried with \ref mcd_qry_trig_state_f(). + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_TRIG_ACCESS if state of the trigger set could not be queried. + */ +mcd_return_et mcd_qry_trig_set_state_f(const mcd_core_st *core, + mcd_trig_set_state_st *trig_state); + + +/** + * DOC: Target Execution Control API + * + * Target Execution Control API functions allow control of the execution, such + * as run, stop and step. They allow querying the state of a core as well as the + * execution time of the target. The API also allows execution of commands + * grouped as transaction lists. + * + */ + + +/** + * mcd_execute_txlist_f() - Function executing a transaction list on the target. + * + * @core: [in] A reference to the core the calling function addresses. + * @txlist: [in] A pointer to the transaction list for execution. + * + * This function sends a transaction list to the target for execution and + * retrieves the result. It is blocking, so it is the responsibility of the tool + * to make sure that the execution time will be reasonable by creating a + * transaction list with an appropriate payload size. + * + * Note that multiple tools can issue transaction lists requests to the same + * core at the same time. + * + * In case of an error, the execution of the transaction list is immediately + * aborted. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_TXLIST_READ if execution of the transaction list aborted due to a + * specific read access. + * - %MCD_ERR_TXLIST_WRITE if execution of the transaction list aborted due to a + * specific write access. + * - %MCD_ERR_TXLIST_TX if execution of the transaction list aborted due to + * any other reason. + */ +mcd_return_et mcd_execute_txlist_f(const mcd_core_st *core, + mcd_txlist_st *txlist); + + +/** + * mcd_run_f() - Function starting execution on a particular core. + * + * @core: [in] A reference to the core the calling function addresses. + * @global: [in] Set to "TRUE" if all cores of a system shall start execution. + * Otherwise, starting execution of selected core only. + * + * This function causes the corresponding target core to begin execution. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if starting execution failed. + */ +mcd_return_et mcd_run_f(const mcd_core_st *core, bool global); + + +/** + * mcd_stop_f() - Function stopping execution on a particular core. + * + * @core: [in] A reference to the core the calling function addresses. + * @global: [in] Set to "TRUE" if all cores of a system shall stop + * execution. Otherwise, stopping execution of selected + * core only. + * + * This function causes the corresponding target core to stop execution. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if stopping execution failed. + */ +mcd_return_et mcd_stop_f(const mcd_core_st *core, bool global); + + +/** + * mcd_stop_f() - Function running a particular core until a defined time. + * + * @core: [in] A reference to the core the calling function addresses. + * @global: [in] Set to "TRUE" if all cores of a system shall start + * execution. Otherwise, starting execution of selected core + * only. + * @absolute_time: [in] Boolean value indicating whether the time parameter is + * absolute or not. + * @run_until_time: [in] The number of time units (picoseconds) until which the + * target core shall run. + * + * This function causes the corresponding target core to run for a defined time + * before it stops. If @absolute_time is "FALSE", @run_until_time is the value + * of the system timer that is associated with this core. This means it starts + * again from '0' for certain reset types, and it needs to be scaled depending + * on the crystal and PLL settings in order to determine a time value. If + * @absolute_time is "TRUE", @run_until_time is an absolute time in seconds. + * Usually, a simulation model can only support this case. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if execution failed. + */ +mcd_return_et mcd_run_until_f(const mcd_core_st *core, bool global, + bool absolute_time, uint64_t run_until_time); + +/** + * mcd_qry_current_time_f() - Function querying the current time of execution + * from the target system. + * + * @core: [in] A reference to the core the calling function addresses. + * @current_time: [out] The current number of time units (picoseconds) the + * target system has been running. + * + * This function returns the current execution time of the target. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if querying for the time failed. + */ +mcd_return_et mcd_qry_current_time_f(const mcd_core_st *core, + uint64_t *current_time); + +/** + * mcd_step_f() - Function stepping a target core based on the particular step + * type. + * + * @core: [in] A reference to the core the calling function addresses. + * @global: [in] Set to "TRUE" if all cores of a system shall start + * execution. Otherwise, starting execution of selected core only. + * @step_type: [in] The unit, the stepping of the target core is based on. + * @n_steps: [in] The number of steps, the target core is stepped for. + * + * This function causes the corresponding target core to step based on the + * provided step type. + * + * Note that the function is blocking. It is the responsibility of the tool to + * call it with a reasonable number of steps. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if stepping the target core failed. + */ +mcd_return_et mcd_step_f(const mcd_core_st *core, bool global, + mcd_core_step_type_et step_type, uint32_t n_steps); + + +/** + * mcd_set_global_f() - Function enabling/disabling global stop and run + * activities on this core. + * + * @core: [in] A reference to the core the calling function addresses. + * @enable: [in] Set to "TRUE" if this core should perform global run or stop + * activities. + * + * This function enables or disables the effect of a global run and stop on this + * core. The default state is target specific. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful.\n + * - %MCD_ERR_GENERAL if enabling/disabling the global effect of execution + * functions failed. + */ +mcd_return_et mcd_set_global_f(const mcd_core_st *core, bool enable); + + +/** + * mcd_qry_state_f() - Function querying the execution state of a target core. + * + * @core: [in] A reference to the core the calling function addresses. + * @state: [out] The current execution state of the target core. + * + * This function queries the current execution state of a particular target + * core. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful.\n + * - %MCD_ERR_GENERAL if querying the execution state failed. + */ +mcd_return_et mcd_qry_state_f(const mcd_core_st *core, + mcd_core_state_st *state); + + +/** + * mcd_execute_command_f() - Function executing a command on the target + * platform. + * + * @core: [in] A reference to the core the calling function + * addresses. + * @command_string: [in] The command string. This is implementation + * specific. + * @result_string_size: [in] The maximum size of the result string. + * @result_string: [out] The result string allocated by the calling + * function. + * + * This function sends a command to the target platform and retrieves the result + * in the form of a string. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if executing the command failed. + */ +mcd_return_et mcd_execute_command_f(const mcd_core_st *core, + const char *command_string, + uint32_t result_string_size, + char *result_string); + + +/** + * DOC: Reset Control API + * + * Reset Control API functions allow querying information about the reset + * classes supported by the target system, as well as triggering one or more + * reset signals in parallel on the target system. + * + */ + + +/** + * mcd_qry_rst_classes_f() - Function querying information about reset classes + * supported by the target system. + * @core: [in] A reference to the core the calling function + * addresses. + * @rst_class_vector: [out] A 32 bit vector that defines the available reset + * classes. + * + * This function queries all available reset classes of the target system. Each + * bit of @rst_class_vector represents an available reset class. + * + * It is recommended that the strongest reset (e.g. power-on reset) is of class + * '0'. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if querying the reset classes failed. + */ +mcd_return_et mcd_qry_rst_classes_f(const mcd_core_st *core, + uint32_t *rst_class_vector); + + +/** + * mcd_qry_rst_class_info_f() - Function querying information about a particular + * reset class supported by the target system. + * + * @core: [in] A reference to the core the calling function addresses. + * @rst_class: [in] Reset class ID which refers to a bit in the 32-bit reset + * class vector as obtained by mcd_qry_rst_classes_f(). + * @rst_info: [out] Reference to an object of type mcd_rst_info_st containing + * detailed information about this reset class. + * + * This function queries more detailed information about a particular reset + * class of the target system. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if reset class does not exist. + * - %MCD_ERR_GENERAL if any other error occurred. + */ +mcd_return_et mcd_qry_rst_class_info_f(const mcd_core_st *core, + uint8_t rst_class, + mcd_rst_info_st *rst_info); + + +/** + * mcd_rst_f() - Function triggering one or more reset signals in parallel on + * the target system. + * + * @core: [in] A reference to the core the calling function + * addresses. + * @rst_class_vector: [in] Reset vector specifying the resets which shall be + * issued. + * @rst_and_halt: [in] Optionally halting the core if the reset changes the + * core state. + * + * This function triggers one or more reset signals in parallel on the target + * system. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if one or several reset classes do not exist. + * - %MCD_ERR_GENERAL if any other error occurred. + */ +mcd_return_et mcd_rst_f(const mcd_core_st *core, uint32_t rst_class_vector, + bool rst_and_halt); + + +/** + * DOC: Communication Channel API + * + * Communication channels allow the exchange of data between a tool and the + * target. A channel requested by the tool is specified by mcd_chl_st. This + * structure type contains information on the channel type and its attributes. + * The number of channels for each server of the MCD API is limited to + * MCD_CHL_NUM_MAX. A channel can be both uni- and bi-directional. It also may + * be memory-mapped and prioritized. In the latter case, the channel priority + * determines the sequence of communication transfers between the target and the + * connected tools. + * + * Note that there must never be two or more open channels of the same priority + * to a single target. In case of conflicts the channel will get the closest + * free priority. + */ + + +/** + * mcd_chl_open_f() - Function opening a communication channel between the host + * tool and the target. + * + * @core: [in] A reference to the targeted system, device or core. Here, member + * instance is allowed to be a null pointer for levels higher than core + * level. + * @channel: + * * [in] Requested channel setup. + * * [out] Accepted and at least for chl_id modified channel setup. Note that + * max_msg_len and prio can be changed as well if the requested values are not + * possible. + * + * This function opens a defined communication channel between a host side tool + * and a target. The addressed target is identified by a core reference. This + * function call allows to establish a communication channel between the host + * side tool and any hierarchical level of the targeted system (i.e. at system + * level, at device level or at core level). For this reason, this function call + * accepts core structures which have their member instance set to a null + * pointer for levels higher than core level. The target implementation actually + * needs to determine the targeted hierarchical level based on the member + * core_con_info of the core structure. The established channel is described by + * channel. Only a single debugger may be attached to a communication channel at + * a time. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_CHL_TYPE_NOT_SUPPORTED if unsupported channel type was + * requested. + * - %MCD_ERR_CHL_TARGET_NOT_SUPPORTED if addressed target does not support + * communication channels. + * - %MCD_ERR_CHL_SETUP if channel setup is invalid or contains + * unsupported attributes. + */ +mcd_return_et mcd_chl_open_f(const mcd_core_st *core, mcd_chl_st *channel); + + +/** + * mcd_send_msg_f() - Function send a message using a specified communication + * channel. + * + * @core: [in] A reference to the targeted system, device or core. Here, + * member instance is allowed to be a null pointer for levels higher + * than core level. + * @channel: [in] Description of the addressed communication channel. + * @msg_len: [in] The number of bytes sent with this message. + * @msg: [in] Message buffer. + * + * This function sends a message using a defined communication channel between + * the host and the target. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_CHL_MESSAGE_FAILED if sending the message failed. + */ +mcd_return_et mcd_send_msg_f(const mcd_core_st *core, const mcd_chl_st *channel, + uint32_t msg_len, const uint8_t *msg); + + +/** + * mcd_receive_msg_f() - Function receiving a message using a specified + * communication channel. + * + * @core: [in] A reference to the targeted system, device or core. Here, for + * member instance is allowed to be a null pointer for levels higher + * than core level. + * @channel: [in] Description of the addressed communication channel. + * @timeout: [in] Number of time units (milliseconds) until function call times + * out. + * @msg_len: [in] Maximum number of bytes that can be fetched with this call. + * @msg_len: [out] Number of bytes that have been actually fetched with this + * call. + * @msg: [out] Message buffer. + * + * This function receives a message using a defined communication channel + * between the host and the target. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_CHL_MESSAGE_FAILED if receiving of the message failed. + */ +mcd_return_et mcd_receive_msg_f(const mcd_core_st *core, + const mcd_chl_st *channel, uint32_t timeout, + uint32_t *msg_len, uint8_t *msg); + +/** + * mcd_chl_reset_f() - Function resetting a specified communication channel. + * + * @core: [in] : A reference to the targeted system, device or core. Here, + * member instance is allowed to be a null pointer for levels higher + * than core level. + * @channel: [in] : Description of the addressed communication channel. + * + * This function resets a communication channel between the host and the target. + * This allows the communication to be setup again e.g. if the communication + * hangs. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if resetting the communication channel failed. + */ +mcd_return_et mcd_chl_reset_f(const mcd_core_st *core, + const mcd_chl_st *channel); + + +/** + * mcd_chl_close_f() - Function closing a specified communication channel. + * + * @core: [in] : A reference to the targeted system, device or core. + * Here, member instance is allowed to be a null + * pointer for levels higher than core level. + * @channel: [in] : Description of the addressed communication channel. + * + * This function closes a communication channel between the host and the target. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_GENERAL if closing the communication channel failed. + */ +mcd_return_et mcd_chl_close_f(const mcd_core_st *core, + const mcd_chl_st *channel); + + +/** + * DOC: Trace API + * + * Traces allow information to be captured from a running target system or + * platform. A target may contain different trace sources and sinks. A trace + * source is generating trace data (e.g. a core trace or a bus trace unit), + * whereas a trace sink is storing the trace data until it is retrieved via the + * MCD API (e.g. an on-chip or off-chip trace buffer). The MCD API does not + * differentiate between source and sink. Consequently, there needs to be a + * "Trace" for each combination. + */ + + +/** + * mcd_qry_traces_f() - Function querying information about available traces for + * a core. + * + * @core: [in] A reference to the core of which the traces are + * requested. + * @start_index: [in] Start index of the requested traces. This refers to an + * internal list of the target side implementation. + * @num_traces: + * * [in] The number of queried traces starting from the defined + * @start_index. If it is set to '0', no traces are returned but the number of + * all available traces. + * * [out] The number of returned traces. In case the input value of + * @num_traces is '0', this is the number of all available traces for the + * selected core. + * @trace_info: [out] Trace information of the requested traces. This is an + * array allocated by the calling function. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if @trace_index is equal or larger than the number of + * traces. + * - %MCD_ERR_GENERAL on any other error. + */ +mcd_return_et mcd_qry_traces_f(const mcd_core_st *core, uint32_t start_index, + uint32_t *num_traces, + mcd_trace_info_st *trace_info); + + +/** + * mcd_qry_trace_state_f() - Function querying the status of a trace. + * + * @core: [in] A reference to the core to which the trace belongs. + * @trace_id: [in] ID to which this trace refers to. + * @state: [out] The current state of the trace. + * + * This function queries the current status of a particular trace source. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if @trace_id is not a valid trace ID. + * - %MCD_ERR_GENERAL on any other error. + */ +mcd_return_et mcd_qry_trace_state_f(const mcd_core_st *core, uint32_t trace_id, + mcd_trace_state_st *state); + + +/** + * mcd_set_trace_state_f() - Function setting the state and mode of a trace. + * + * This function sets the state and mode of a particular trace source. + * + * @core: [in] A reference to the core to which the trace belongs. + * @trace_id: [in] ID of the trace which is referenced. + * @state: + * * [in] The trace settings to be applied. + * * [out] Returns the current state of the trace. Member @modified is set if a + * member has changed. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if @trace_id is not a valid trace ID. + * - %MCD_ERR_GENERAL on any other error. + */ +mcd_return_et mcd_set_trace_state_f(const mcd_core_st *core, uint32_t trace_id, + mcd_trace_state_st *state); + + +/** + * mcd_read_trace_f () - Function reading trace data from a trace. + * + * @core: [in] A reference to the core to which the trace belongs. + * @trace_id: [in] ID of the trace which is referenced. + * @start_index: [in] Start index of frame to read (0 = oldest frame). This + * refers to an internal list of the target implementation + * which stores the trace frames. + * @num_frames: + * * [in] The number of queried trace frames starting from the defined + * @start_index. If it is set to '0', no trace data is returned but the number + * of all currently available trace frames. + * * [out] The number of read trace frames. In case the input value of + * @num_frames is '0', this is the number of all currently available trace + * frames. + * @trace_data_size: [in] Size of one trace data frame in bytes (for type + * checking). + * @trace_data: [out] Array of trace data structures filled by this + * function. The format depends on the trace source. Standard + * formats are mcd_trace_data_core_st, mcd_trace_data_event_st + * and mcd_trace_data_stat_st. + * + * This function reads trace data from a particular trace source. + * + * Allowed error codes: + * + * - %MCD_ERR_NONE if successful. + * - %MCD_ERR_PARAM if @trace_id is not a valid trace ID, or if start_index is + * larger than the number of available trace frames. + * - %MCD_ERR_GENERAL on any other error. + */ +mcd_return_et mcd_read_trace_f(const mcd_core_st *core, uint32_t trace_id, + uint64_t start_index, uint32_t *num_frames, + uint32_t trace_data_size, void *trace_data); + + +#endif /* MCD_API_H */ From patchwork Mon Mar 10 15:04:56 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010265 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 8FE5FC282EC for ; Mon, 10 Mar 2025 15:13:20 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tren1-00022q-A4; Mon, 10 Mar 2025 11:11:35 -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 1tremz-000220-35 for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:33 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremu-0007fU-OE for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:32 -0400 Received: (qmail 30644 invoked by uid 484); 10 Mar 2025 15:11:09 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.257821 secs); 10 Mar 2025 15:11:09 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:09 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Paolo Bonzini , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , Michael Roth Subject: [PATCH 02/16] mcd: Introduce MCD server Date: Mon, 10 Mar 2025 16:04:56 +0100 Message-Id: <20250310150510.200607-3-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org The MCD implementation follows a remote procedure call approach and uses QMP as the communication protocol: * mcdserver implements the MCD API * mcd.json and mcdstub_qapi.c declare and implement the server stub Our client stub supporting QMP can be found at: https://gitlab.com/lauterbach/mcdrefsrv Signed-off-by: Mario Fleischmann --- MAINTAINERS | 1 + docs/interop/mcd.rst | 14 ++ mcd/mcdserver.c | 431 ++++++++++++++++++++++++++++++++++++++++++ mcd/mcdstub_qapi.c | 13 ++ mcd/meson.build | 12 ++ meson.build | 1 + qapi/mcd.json | 6 + qapi/meson.build | 1 + qapi/qapi-schema.json | 1 + 9 files changed, 480 insertions(+) create mode 100644 mcd/mcdserver.c create mode 100644 mcd/mcdstub_qapi.c create mode 100644 mcd/meson.build create mode 100644 qapi/mcd.json diff --git a/MAINTAINERS b/MAINTAINERS index 448fb55a09..58d94b392f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3106,6 +3106,7 @@ M: Mario Fleischmann S: Maintained F: mcd/* F: docs/interop/mcd.rst +F: qapi/mcd.json Memory API M: Paolo Bonzini diff --git a/docs/interop/mcd.rst b/docs/interop/mcd.rst index 9587cfb010..de7b7a8d5c 100644 --- a/docs/interop/mcd.rst +++ b/docs/interop/mcd.rst @@ -38,6 +38,20 @@ The resulting system can be visualized as follows:: | qemu-system-* | | -machine | | -cpu | +----------------+ +----------+ +------+ + +Debugging via QMP +----------------- + +Since the MCD API does not define a communication protocol, the QEMU Machine +Protocol (QMP) is utilized to implement a remote procedure call mechanism. +Each function within the API corresponds to one QMP command, ensuring a +one-to-one mapping between the API's functions and the QMP commands. + +If you are not familiar with QMP, see the :doc:`qmp-spec` for the +protocol, and the :doc:`qemu-qmp-ref` for a full reference of all +commands. + + API Reference ------------- diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c new file mode 100644 index 0000000000..a20708db1b --- /dev/null +++ b/mcd/mcdserver.c @@ -0,0 +1,431 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * mcdserver - Multi-Core Debug (MCD) API implementation + * + * Copyright (c) 2025 Lauterbach GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "mcd_api.h" + +static const mcd_error_info_st MCD_ERROR_NOT_IMPLEMENTED = { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_FN_UNIMPLEMENTED, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "", +}; + +static const mcd_error_info_st MCD_ERROR_NONE = { + .return_status = MCD_RET_ACT_NONE, + .error_code = MCD_ERR_NONE, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "", +}; + +/** + * struct mcdserver_state - State of the MCD server + * + * @last_error: Error info of most recent executed function. + */ +typedef struct mcdserver_state { + const mcd_error_info_st *last_error; +} mcdserver_state; + +static mcdserver_state g_server_state = { + .last_error = &MCD_ERROR_NONE, +}; + +mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, + mcd_impl_version_info_st *impl_info) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +void mcd_exit_f(void) +{ + return; +} + +mcd_return_et mcd_qry_servers_f(const char *host, bool running, + uint32_t start_index, uint32_t *num_servers, + mcd_server_info_st *server_info) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_open_server_f(const char *system_key, + const char *config_string, + mcd_server_st **server) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_close_server_f(const mcd_server_st *server) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_set_server_config_f(const mcd_server_st *server, + const char *config_string) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_server_config_f(const mcd_server_st *server, + uint32_t *max_len, + char *config_string) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_systems_f(uint32_t start_index, uint32_t *num_systems, + mcd_core_con_info_st *system_con_info) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_devices_f(const mcd_core_con_info_st *system_con_info, + uint32_t start_index, uint32_t *num_devices, + mcd_core_con_info_st *device_con_info) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_cores_f(const mcd_core_con_info_st *connection_info, + uint32_t start_index, uint32_t *num_cores, + mcd_core_con_info_st *core_con_info) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_core_modes_f(const mcd_core_st *core, + uint32_t start_index, uint32_t *num_modes, + mcd_core_mode_info_st *core_mode_info) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_open_core_f(const mcd_core_con_info_st *core_con_info, + mcd_core_st **core) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_close_core_f(const mcd_core_st *core) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +void mcd_qry_error_info_f(const mcd_core_st *core, + mcd_error_info_st *error_info) +{ + if (error_info) { + *error_info = *g_server_state.last_error; + } +} + +mcd_return_et mcd_qry_device_description_f(const mcd_core_st *core, char *url, + uint32_t *url_length) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_max_payload_size_f(const mcd_core_st *core, + uint32_t *max_payload) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_input_handle_f(const mcd_core_st *core, + uint32_t *input_handle) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_mem_spaces_f(const mcd_core_st *core, + uint32_t start_index, + uint32_t *num_mem_spaces, + mcd_memspace_st *mem_spaces) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_mem_blocks_f(const mcd_core_st *core, + uint32_t mem_space_id, uint32_t start_index, + uint32_t *num_mem_blocks, + mcd_memblock_st *mem_blocks) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_active_overlays_f(const mcd_core_st *core, + uint32_t start_index, + uint32_t *num_active_overlays, + uint32_t *active_overlays) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_reg_groups_f(const mcd_core_st *core, + uint32_t start_index, + uint32_t *num_reg_groups, + mcd_register_group_st *reg_groups) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_reg_map_f(const mcd_core_st *core, uint32_t reg_group_id, + uint32_t start_index, uint32_t *num_regs, + mcd_register_info_st *reg_info) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_reg_compound_f(const mcd_core_st *core, + uint32_t compound_reg_id, + uint32_t start_index, + uint32_t *num_reg_ids, + uint32_t *reg_id_array) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_trig_info_f(const mcd_core_st *core, + mcd_trig_info_st *trig_info) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_ctrigs_f(const mcd_core_st *core, uint32_t start_index, + uint32_t *num_ctrigs, + mcd_ctrig_info_st *ctrig_info) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_create_trig_f(const mcd_core_st *core, void *trig, + uint32_t *trig_id) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_trig_f(const mcd_core_st *core, uint32_t trig_id, + uint32_t max_trig_size, void *trig) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_remove_trig_f(const mcd_core_st *core, uint32_t trig_id) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_trig_state_f(const mcd_core_st *core, uint32_t trig_id, + mcd_trig_state_st *trig_state) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_activate_trig_set_f(const mcd_core_st *core) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_remove_trig_set_f(const mcd_core_st *core) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_trig_set_f(const mcd_core_st *core, uint32_t start_index, + uint32_t *num_trigs, uint32_t *trig_ids) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_trig_set_state_f(const mcd_core_st *core, + mcd_trig_set_state_st *trig_state) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_execute_txlist_f(const mcd_core_st *core, + mcd_txlist_st *txlist) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_run_f(const mcd_core_st *core, bool global) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_stop_f(const mcd_core_st *core, bool global) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_run_until_f(const mcd_core_st *core, bool global, + bool absolute_time, uint64_t run_until_time) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_current_time_f(const mcd_core_st *core, + uint64_t *current_time) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_step_f(const mcd_core_st *core, bool global, + mcd_core_step_type_et step_type, uint32_t n_steps) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_set_global_f(const mcd_core_st *core, bool enable) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_state_f(const mcd_core_st *core, mcd_core_state_st *state) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_execute_command_f(const mcd_core_st *core, + const char *command_string, + uint32_t result_string_size, + char *result_string) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_rst_classes_f(const mcd_core_st *core, + uint32_t *rst_class_vector) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_rst_class_info_f(const mcd_core_st *core, + uint8_t rst_class, + mcd_rst_info_st *rst_info) +{ + + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_rst_f(const mcd_core_st *core, uint32_t rst_class_vector, + bool rst_and_halt) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_chl_open_f(const mcd_core_st *core, mcd_chl_st *channel) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_send_msg_f(const mcd_core_st *core, const mcd_chl_st *channel, + uint32_t msg_len, const uint8_t *msg) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_receive_msg_f(const mcd_core_st *core, + const mcd_chl_st *channel, uint32_t timeout, + uint32_t *msg_len, uint8_t *msg) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_chl_reset_f(const mcd_core_st *core, + const mcd_chl_st *channel) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_chl_close_f(const mcd_core_st *core, + const mcd_chl_st *channel) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_traces_f(const mcd_core_st *core, uint32_t start_index, + uint32_t *num_traces, + mcd_trace_info_st *trace_info) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_qry_trace_state_f(const mcd_core_st *core, uint32_t trace_id, + mcd_trace_state_st *state) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_set_trace_state_f(const mcd_core_st *core, uint32_t trace_id, + mcd_trace_state_st *state) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} + +mcd_return_et mcd_read_trace_f(const mcd_core_st *core, uint32_t trace_id, + uint64_t start_index, uint32_t *num_frames, + uint32_t trace_data_size, void *trace_data) +{ + g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + return g_server_state.last_error->return_status; +} diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c new file mode 100644 index 0000000000..6f79ae38a9 --- /dev/null +++ b/mcd/mcdstub_qapi.c @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * MCD server stub using QMP + * + * see qapi/mcd.json for the declarations of the (un)marshalling functions + * + * Copyright (c) 2025 Lauterbach GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "mcd_api.h" diff --git a/mcd/meson.build b/mcd/meson.build new file mode 100644 index 0000000000..bc783dae54 --- /dev/null +++ b/mcd/meson.build @@ -0,0 +1,12 @@ +# MCD is only supported in system emulation +mcd_system_ss = ss.source_set() + +mcd_system_ss.add(files('mcdserver.c', 'mcdstub_qapi.c')) +mcd_system_ss = mcd_system_ss.apply({}) + +libmcd_system = static_library('mcd_system', + mcd_system_ss.sources() + genh, + build_by_default: false) + +mcd_system = declare_dependency(objects: libmcd_system.extract_all_objects(recursive: false)) +system_ss.add(mcd_system) diff --git a/meson.build b/meson.build index 4899d896de..5e1b4865f7 100644 --- a/meson.build +++ b/meson.build @@ -3685,6 +3685,7 @@ subdir('authz') subdir('crypto') subdir('ui') subdir('gdbstub') +subdir('mcd') if have_system subdir('hw') else diff --git a/qapi/mcd.json b/qapi/mcd.json new file mode 100644 index 0000000000..701fd03ece --- /dev/null +++ b/qapi/mcd.json @@ -0,0 +1,6 @@ +# -*- Mode: Python -*- +# vim: filetype=python + +## +# = Multi-Core Debug (MCD) API +## diff --git a/qapi/meson.build b/qapi/meson.build index eadde4db30..d05f17fe95 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -40,6 +40,7 @@ qapi_all_modules = [ 'machine-common', 'machine', 'machine-target', + 'mcd', 'migration', 'misc', 'misc-target', diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index 2877aff73d..07907b0a53 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -82,3 +82,4 @@ { 'include': 'cryptodev.json' } { 'include': 'cxl.json' } { 'include': 'uefi.json' } +{ 'include': 'mcd.json' } From patchwork Mon Mar 10 15:04:57 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010269 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3DE19C282EC for ; Mon, 10 Mar 2025 15:14:20 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tren4-00026h-2z; Mon, 10 Mar 2025 11:11:38 -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 1tremz-00021y-2v for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:33 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremu-0007fk-F6 for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:32 -0400 Received: (qmail 30673 invoked by uid 484); 10 Mar 2025 15:11:09 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.013291 secs); 10 Mar 2025 15:11:09 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:09 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake , Fabiano Rosas , Laurent Vivier , Paolo Bonzini Subject: [PATCH 03/16] mcd: Implement target initialization API Date: Mon, 10 Mar 2025 16:04:57 +0100 Message-Id: <20250310150510.200607-4-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org The target initialization API ensures that the requested and provided MCD versions are compatible. * implement mcd_initialize_f and mcd_qry_error_info_f in mcdserver * implement QMP stub functionality * add QTest Thanks to the QMP integration in QTest, function arguments and results can be (de)serialized automatically. Signed-off-by: Mario Fleischmann --- MAINTAINERS | 2 + mcd/libmcd_qapi.c | 66 ++++++++++++++ mcd/libmcd_qapi.h | 26 ++++++ mcd/mcdserver.c | 44 ++++++++- mcd/mcdstub_qapi.c | 35 ++++++++ mcd/meson.build | 2 +- qapi/mcd.json | 183 ++++++++++++++++++++++++++++++++++++++ tests/qtest/libmcd-test.c | 88 ++++++++++++++++++ tests/qtest/libmcd-test.h | 23 +++++ tests/qtest/mcd-test.c | 93 +++++++++++++++++++ tests/qtest/meson.build | 2 + 11 files changed, 562 insertions(+), 2 deletions(-) create mode 100644 mcd/libmcd_qapi.c create mode 100644 mcd/libmcd_qapi.h create mode 100644 tests/qtest/libmcd-test.c create mode 100644 tests/qtest/libmcd-test.h create mode 100644 tests/qtest/mcd-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 58d94b392f..0687a6baef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3107,6 +3107,8 @@ S: Maintained F: mcd/* F: docs/interop/mcd.rst F: qapi/mcd.json +F: tests/qtest/libmcd-test.* +F: tests/qtest/mcd-test.c Memory API M: Paolo Bonzini diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c new file mode 100644 index 0000000000..bc147072a1 --- /dev/null +++ b/mcd/libmcd_qapi.c @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QAPI marshalling helpers for structures of the MCD API + * + * Copyright (c) 2025 Lauterbach GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libmcd_qapi.h" + +MCDAPIVersion *marshal_mcd_api_version(const mcd_api_version_st *api_version) +{ + MCDAPIVersion *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDAPIVersion) { + .v_api_major = api_version->v_api_major, + .v_api_minor = api_version->v_api_minor, + .author = g_strdup(api_version->author), + }; + + return marshal; +} + +mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version) +{ + mcd_api_version_st unmarshal = { + .v_api_major = api_version->v_api_major, + .v_api_minor = api_version->v_api_minor, + }; + strncpy(unmarshal.author, api_version->author, MCD_API_IMP_VENDOR_LEN - 1); + return unmarshal; +} + +MCDImplVersionInfo *marshal_mcd_impl_version_info( + const mcd_impl_version_info_st *impl_info) +{ + MCDImplVersionInfo *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDImplVersionInfo) { + .v_api = marshal_mcd_api_version(&impl_info->v_api), + .v_imp_major = impl_info->v_imp_major, + .v_imp_minor = impl_info->v_imp_minor, + .v_imp_build = impl_info->v_imp_build, + .vendor = g_strdup(impl_info->vendor), + .date = g_strdup(impl_info->date), + }; + + return marshal; +} + +MCDErrorInfo *marshal_mcd_error_info(const mcd_error_info_st *error_info) +{ + MCDErrorInfo *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDErrorInfo) { + .return_status = error_info->return_status, + .error_code = error_info->error_code, + .error_events = error_info->error_events, + .error_str = g_strdup(error_info->error_str), + }; + + return marshal; +} diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h new file mode 100644 index 0000000000..fc7436bf65 --- /dev/null +++ b/mcd/libmcd_qapi.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QAPI marshalling helpers for structures of the MCD API + * + * Copyright (c) 2025 Lauterbach GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef LIBMCD_QAPI_H +#define LIBMCD_QAPI_H + +#include "mcd_api.h" +#include "qapi-types-mcd.h" + +MCDAPIVersion *marshal_mcd_api_version(const mcd_api_version_st *api_version); + +MCDImplVersionInfo *marshal_mcd_impl_version_info( + const mcd_impl_version_info_st *impl_info); + +MCDErrorInfo *marshal_mcd_error_info(const mcd_error_info_st *error_info); + +mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version); + +#endif /* LIBMCD_QAPI_H */ diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index a20708db1b..6e941f0531 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -8,6 +8,7 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "mcd_api.h" static const mcd_error_info_st MCD_ERROR_NOT_IMPLEMENTED = { @@ -17,6 +18,13 @@ static const mcd_error_info_st MCD_ERROR_NOT_IMPLEMENTED = { .error_str = "", }; +static const mcd_error_info_st MCD_ERROR_INVALID_NULL_PARAM = { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "null was invalidly passed as a parameter", +}; + static const mcd_error_info_st MCD_ERROR_NONE = { .return_status = MCD_RET_ACT_NONE, .error_code = MCD_ERR_NONE, @@ -24,6 +32,9 @@ static const mcd_error_info_st MCD_ERROR_NONE = { .error_str = "", }; +/* reserves memory for custom errors */ +static mcd_error_info_st custom_mcd_error; + /** * struct mcdserver_state - State of the MCD server * @@ -40,12 +51,43 @@ static mcdserver_state g_server_state = { mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, mcd_impl_version_info_st *impl_info) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + if (!version_req || !impl_info) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + *impl_info = (mcd_impl_version_info_st) { + .v_api = (mcd_api_version_st) { + .v_api_major = MCD_API_VER_MAJOR, + .v_api_minor = MCD_API_VER_MINOR, + .author = MCD_API_VER_AUTHOR, + }, + .v_imp_major = QEMU_VERSION_MAJOR, + .v_imp_minor = QEMU_VERSION_MINOR, + .v_imp_build = 0, + .vendor = "QEMU", + .date = __DATE__, + }; + + if (version_req->v_api_major == MCD_API_VER_MAJOR && + version_req->v_api_minor <= MCD_API_VER_MINOR) { + g_server_state.last_error = &MCD_ERROR_NONE; + } else { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_GENERAL, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "incompatible versions", + }; + g_server_state.last_error = &custom_mcd_error; + } + return g_server_state.last_error->return_status; } void mcd_exit_f(void) { + g_server_state.last_error = &MCD_ERROR_NONE; return; } diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index 6f79ae38a9..a76d2d081f 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -10,4 +10,39 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "mcd_api.h" +#include "libmcd_qapi.h" +#include "qapi/qapi-commands-mcd.h" + +MCDInitializeResult *qmp_mcd_initialize(MCDAPIVersion *version_req, + Error **errp) +{ + mcd_impl_version_info_st impl_info; + MCDInitializeResult *result = g_malloc0(sizeof(*result)); + mcd_api_version_st version_req_unmarshalled = + unmarshal_mcd_api_version(version_req); + + result->return_status = mcd_initialize_f(&version_req_unmarshalled, + &impl_info); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->impl_info = marshal_mcd_impl_version_info(&impl_info); + } + + return result; +} + +void qmp_mcd_exit(Error **errp) +{ + mcd_exit_f(); +} + +MCDErrorInfo *qmp_mcd_qry_error_info(Error **errp) +{ + MCDErrorInfo *result; + mcd_error_info_st error_info; + mcd_qry_error_info_f(NULL, &error_info); + result = marshal_mcd_error_info(&error_info); + return result; +} diff --git a/mcd/meson.build b/mcd/meson.build index bc783dae54..90d1c6be67 100644 --- a/mcd/meson.build +++ b/mcd/meson.build @@ -1,7 +1,7 @@ # MCD is only supported in system emulation mcd_system_ss = ss.source_set() -mcd_system_ss.add(files('mcdserver.c', 'mcdstub_qapi.c')) +mcd_system_ss.add(files('mcdserver.c', 'mcdstub_qapi.c', 'libmcd_qapi.c')) mcd_system_ss = mcd_system_ss.apply({}) libmcd_system = static_library('mcd_system', diff --git a/qapi/mcd.json b/qapi/mcd.json index 701fd03ece..7b42a74036 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -4,3 +4,186 @@ ## # = Multi-Core Debug (MCD) API ## + + +## +# == Definition of Structures +## + + +## +# @MCDAPIVersion: +# +# Structure type containing the MCD API version information of the tool. +# +# @v-api-major: API major version. +# @v-api-minor: API minor version. +# @author: API name of the author of this MCD API version. +# +# Since: 9.1 +## +{ 'struct': 'MCDAPIVersion', + 'data': { + 'v-api-major': 'uint16', + 'v-api-minor': 'uint16', + 'author': 'str' } } + + +## +# @MCDImplVersionInfo: +# +# Structure type containing the MCD API implementation information. +# +# @v-api: Implemented API version. +# @v-imp-major: Major version number of this implementation. +# @v-imp-minor: Minor version number of this implementation. +# @v-imp-build: Build number of this implementation. +# @vendor: Name of vendor of the implementation. +# @date: String from __DATE__ macro at compile time. +# +# Since: 9.1 +## +{ 'struct': 'MCDImplVersionInfo', + 'data': { + 'v-api' : 'MCDAPIVersion', + 'v-imp-major': 'uint16', + 'v-imp-minor': 'uint16', + 'v-imp-build': 'uint16', + 'vendor' : 'str', + 'date' : 'str' } } + + +## +# @MCDErrorInfo: +# +# Structure type containing the error status and error event notification. +# +# @return-status: Return status from the last API call. +# @error-code: Detailed error code from the last API call. +# @error-events: Detailed event code from the last API call. +# @error-str: Detailed error text string from the last API call. +# +# Since: 9.1 +## +{ 'struct': 'MCDErrorInfo', + 'data': { + 'return-status': 'uint32', + 'error-code' : 'uint32', + 'error-events' : 'uint32', + 'error-str' : 'str' }} + + +## +# == Target Initialization API +## + + +## +# @MCDInitializeResult: +# +# Return value of @mcd-initialize. +# +# @return-status: Return code. +# +# @impl-info: Information about the QEMU build, its version and the version of +# the implemented MCD API. +# +# Since: 9.1 +## +{ 'struct': 'MCDInitializeResult', + 'data': { + 'return-status': 'uint32', + '*impl-info' : 'MCDImplVersionInfo' } } + + +## +# @mcd-initialize: +# +# Function initializing the interaction between a tool-side implementation and +# target-side implementation. +# +# @version-req: MCD API version as requested by an upper layer. +# +# Returns: @MCDInitializeResult +# +# Since: 9.1 +# +# .. qmp-example:: +# :title: Check compatibility with MCD server +# +# -> { "execute": "mcd-initialize", +# "arguments": { "version-req": { "v-api-major": 1, +# "v-api-minor": 1, +# "author": "" } } } +# <- { +# "return": { +# "impl-info": { +# "v-api": { +# "v-api-minor": 1, +# "v-api-major": 1, +# "author": "QEMU Release" +# }, +# "vendor": "QEMU", +# "v-imp-minor": 2, +# "v-imp-major": 9, +# "v-imp-build": 0, +# "date": "Dec 18 2024" +# }, +# "return-status": 0 +# } +# } +## +{ 'command': 'mcd-initialize', + 'data': { 'version-req': 'MCDAPIVersion' }, + 'returns': 'MCDInitializeResult' } + + +## +# @mcd-exit: +# +# Function cleaning up all core and server connections from a tool. +# +# Since: 9.1 +## +{ 'command': 'mcd-exit' } + + +## +# == Core Connection API +## + + +## +# @mcd-qry-error-info: +# +# Function allowing the access to detailed error and/or event information after +# an API call. +# +# Returns: @MCDErrorInfo +# +# Since: 9.1 +# +# .. qmp-example:: +# :title: Incompatible MCD versions +# +# -> { "execute": "mcd-initialize", +# "arguments": { "version-req": { "v-api-major": 2, +# "v-api-minor": 0, +# "author": "" } } } +# <- { +# "return": { +# "return-status": 3 +# } +# } +# -> { "execute": "mcd-qry-error-info" } +# <- { +# "return": { +# "error-str": "incompatible versions", +# "error-code": 3840, +# "error-events": 0, +# "return-status": 3 +# } +# } +## +{ 'command': 'mcd-qry-error-info', + 'returns': 'MCDErrorInfo' } diff --git a/tests/qtest/libmcd-test.c b/tests/qtest/libmcd-test.c new file mode 100644 index 0000000000..597ebec9b5 --- /dev/null +++ b/tests/qtest/libmcd-test.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QTest helpers for functions of the MCD API + * + * Copyright (c) 2025 Lauterbach GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libmcd-test.h" +#include "mcd/mcd_api.h" +#include "mcd/libmcd_qapi.h" +#include "qobject/qdict.h" +#include "qobject/qlist.h" +#include "qobject/qjson.h" +#include "qapi/qapi-commands-mcd.h" +#include "qapi/qapi-visit-mcd.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/compat-policy.h" + +/* + * We can use the %p format specifier of qtest_qmp() to automatically + * serialize the arguments into JSON. + * The serialization works only after the arguments have been converted into + * a QDict. + */ + + #define MARSHAL_ARGS(type) do { \ + v = qobject_output_visitor_new_qmp(&marshal); \ + ok = visit_start_struct(v, NULL, (void **)&args, \ + sizeof(type), NULL); \ + g_assert(ok); \ + ok = visit_type_##type##_members(v, args, NULL); \ + g_assert(ok); \ + ok = visit_check_struct(v, NULL); \ + g_assert(ok); \ + visit_end_struct(v, (void **)&args); \ + visit_complete(v, &marshal); \ + visit_free(v); \ + arg = qobject_to(QDict, marshal); \ +} while (0) + +#define UNMARSHAL_RESULT(type) do { \ + ret = qdict_get(resp, "return"); \ + g_assert(ret); \ + v = qobject_input_visitor_new(ret); \ + ok = visit_type_##type(v, NULL, &unmarshal, NULL); \ + g_assert(ok); \ + visit_free(v); \ + qobject_unref(resp); \ +} while (0) + +MCDInitializeResult *qtest_mcd_initialize(QTestState *qts, + q_obj_mcd_initialize_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDInitializeResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_initialize_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-initialize'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDInitializeResult); + + return unmarshal; +} + +MCDErrorInfo *qtest_mcd_qry_error_info(QTestState *qts) +{ + Visitor *v; + QDict *resp; + QObject *ret; + bool ok; + MCDErrorInfo *unmarshal; + + resp = qtest_qmp(qts, "{'execute': 'mcd-qry-error-info'}"); + + UNMARSHAL_RESULT(MCDErrorInfo); + + return unmarshal; +} diff --git a/tests/qtest/libmcd-test.h b/tests/qtest/libmcd-test.h new file mode 100644 index 0000000000..1c5da9de62 --- /dev/null +++ b/tests/qtest/libmcd-test.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QTest helpers for functions of the MCD API + * + * Copyright (c) 2025 Lauterbach GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef LIBMCD_TEST_H +#define LIBMCD_TEST_H + +#include "libqtest.h" +#include "mcd/mcd_api.h" +#include "qapi/qapi-visit-mcd.h" + +MCDInitializeResult *qtest_mcd_initialize(QTestState *qts, + q_obj_mcd_initialize_arg *args); + +MCDErrorInfo *qtest_mcd_qry_error_info(QTestState *qts); + +#endif /* LIBMCD_TEST_H */ diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c new file mode 100644 index 0000000000..275fb46aaa --- /dev/null +++ b/tests/qtest/mcd-test.c @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Architecture independent QTests for the MCD server with QAPI stub + * + * Copyright (c) 2025 Lauterbach GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "mcd/mcd_api.h" +#include "mcd/libmcd_qapi.h" +#include "qapi/qapi-visit-mcd.h" +#include "qapi/qapi-types-mcd.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/compat-policy.h" +#include "libmcd-test.h" + +#define QEMU_EXTRA_ARGS "" + +static bool verbose; + +static void test_initialize(void) +{ + QTestState *qts = qtest_init(QEMU_EXTRA_ARGS); + MCDErrorInfo *error_info; + + mcd_api_version_st version_req = { + .v_api_major = MCD_API_VER_MAJOR, + .v_api_minor = MCD_API_VER_MINOR, + .author = "", + }; + + q_obj_mcd_initialize_arg qapi_args = { + .version_req = marshal_mcd_api_version(&version_req), + }; + + MCDInitializeResult *result = qtest_mcd_initialize(qts, &qapi_args); + g_assert(result->return_status == MCD_RET_ACT_NONE); + + if (verbose) { + fprintf(stderr, "[INFO]\tAPI v%d.%d (%s)\n", + result->impl_info->v_api->v_api_major, + result->impl_info->v_api->v_api_minor, + result->impl_info->v_api->author); + fprintf(stderr, "[INFO]\tImplementation v%d.%d.%d %s (%s)\n", + result->impl_info->v_imp_major, + result->impl_info->v_imp_minor, + result->impl_info->v_imp_build, + result->impl_info->date, + result->impl_info->vendor); + } + + qapi_free_MCDAPIVersion(qapi_args.version_req); + qapi_free_MCDInitializeResult(result); + + /* Incompatible version */ + version_req = (mcd_api_version_st) { + .v_api_major = MCD_API_VER_MAJOR, + .v_api_minor = MCD_API_VER_MINOR + 1, + .author = "", + }; + + qapi_args.version_req = marshal_mcd_api_version(&version_req); + result = qtest_mcd_initialize(qts, &qapi_args); + g_assert(result->return_status != MCD_RET_ACT_NONE); + + error_info = qtest_mcd_qry_error_info(qts); + g_assert(error_info->error_code == MCD_ERR_GENERAL); + + if (verbose) { + fprintf(stderr, "[INFO]\tInitialization with newer API failed " + "successfully: %s\n", error_info->error_str); + } + + qapi_free_MCDAPIVersion(qapi_args.version_req); + qapi_free_MCDInitializeResult(result); + qapi_free_MCDErrorInfo(error_info); + + qtest_quit(qts); +} + +int main(int argc, char *argv[]) +{ + char *v_env = getenv("V"); + verbose = v_env && atoi(v_env) >= 1; + g_test_init(&argc, &argv, NULL); + + qtest_add_func("mcd/initialize", test_initialize); + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 8a6243382a..1e39a7191b 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -30,6 +30,7 @@ qtests_generic = [ 'qos-test', 'readconfig-test', 'netdev-socket', + 'mcd-test', ] if enable_modules qtests_generic += [ 'modules-test' ] @@ -383,6 +384,7 @@ qtests = { 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'), 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'), 'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'), + 'mcd-test': files('mcd-test.c', 'libmcd-test.c', '../../mcd/libmcd_qapi.c'), } if vnc.found() From patchwork Mon Mar 10 15:04:58 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010262 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 73B51C282DE for ; Mon, 10 Mar 2025 15:12:26 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tren0-00022W-7c; Mon, 10 Mar 2025 11:11:34 -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 1tremx-000204-UK for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:31 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremu-0007g1-F6 for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:31 -0400 Received: (qmail 30701 invoked by uid 484); 10 Mar 2025 15:11:10 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.013713 secs); 10 Mar 2025 15:11:10 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:10 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake , Fabiano Rosas , Laurent Vivier , Paolo Bonzini Subject: [PATCH 04/16] mcd: Implement server connection API Date: Mon, 10 Mar 2025 16:04:58 +0100 Message-Id: <20250310150510.200607-5-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This commit implements the necessary operations required to establish a connection with the MCD server: * query information about the server * connect to " * disconnect from " Signed-off-by: Mario Fleischmann --- mcd/libmcd_qapi.c | 13 +++ mcd/libmcd_qapi.h | 2 + mcd/mcdserver.c | 110 +++++++++++++++++++- mcd/mcdstub_qapi.c | 98 ++++++++++++++++++ qapi/mcd.json | 205 ++++++++++++++++++++++++++++++++++++++ tests/qtest/libmcd-test.c | 60 +++++++++++ tests/qtest/libmcd-test.h | 9 ++ tests/qtest/mcd-test.c | 96 ++++++++++++++++++ 8 files changed, 588 insertions(+), 5 deletions(-) diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c index bc147072a1..44adb04c76 100644 --- a/mcd/libmcd_qapi.c +++ b/mcd/libmcd_qapi.c @@ -64,3 +64,16 @@ MCDErrorInfo *marshal_mcd_error_info(const mcd_error_info_st *error_info) return marshal; } + +MCDServerInfo *marshal_mcd_server_info(const mcd_server_info_st *server_info) +{ + MCDServerInfo *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDServerInfo) { + .server = g_strdup(server_info->server), + .system_instance = g_strdup(server_info->system_instance), + .acc_hw = g_strdup(server_info->acc_hw), + }; + + return marshal; +} diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h index fc7436bf65..6fc99edc93 100644 --- a/mcd/libmcd_qapi.h +++ b/mcd/libmcd_qapi.h @@ -21,6 +21,8 @@ MCDImplVersionInfo *marshal_mcd_impl_version_info( MCDErrorInfo *marshal_mcd_error_info(const mcd_error_info_st *error_info); +MCDServerInfo *marshal_mcd_server_info(const mcd_server_info_st *server_info); + mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version); #endif /* LIBMCD_QAPI_H */ diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index 6e941f0531..4d06c255f2 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -38,14 +38,17 @@ static mcd_error_info_st custom_mcd_error; /** * struct mcdserver_state - State of the MCD server * - * @last_error: Error info of most recent executed function. + * @last_error: Error info of most recent executed function. + * @open_server: Open server instance as allocated in mcd_open_server_f(). */ typedef struct mcdserver_state { const mcd_error_info_st *last_error; + mcd_server_st *open_server; } mcdserver_state; static mcdserver_state g_server_state = { .last_error = &MCD_ERROR_NONE, + .open_server = NULL, }; mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, @@ -87,7 +90,10 @@ mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, void mcd_exit_f(void) { - g_server_state.last_error = &MCD_ERROR_NONE; + if (g_server_state.open_server) { + mcd_close_server_f(g_server_state.open_server); + } + return; } @@ -95,7 +101,51 @@ mcd_return_et mcd_qry_servers_f(const char *host, bool running, uint32_t start_index, uint32_t *num_servers, mcd_server_info_st *server_info) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + if (start_index >= 1) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "QEMU only has one MCD server", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + if (!num_servers) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + if (!running) { + /* MCD server is always running */ + *num_servers = 0; + g_server_state.last_error = &MCD_ERROR_NONE; + return g_server_state.last_error->return_status; + } + + if (*num_servers == 0) { + *num_servers = 1; + g_server_state.last_error = &MCD_ERROR_NONE; + return g_server_state.last_error->return_status; + } + + /* num_servers != 0 => return server information */ + + if (!server_info) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + *server_info = (mcd_server_info_st) { + .server = "QEMU" + }; + snprintf(server_info->system_instance, MCD_UNIQUE_NAME_LEN, + "Process ID: %d", (int) getpid()); + + *num_servers = 1; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } @@ -103,13 +153,63 @@ mcd_return_et mcd_open_server_f(const char *system_key, const char *config_string, mcd_server_st **server) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + if (g_server_state.open_server) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_CONNECTION, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "server already open", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + if (!server) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + g_server_state.open_server = g_malloc(sizeof(mcd_server_st)); + *g_server_state.open_server = (mcd_server_st) { + .instance = NULL, + .host = "QEMU", + .config_string = "", + }; + + *server = g_server_state.open_server; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } mcd_return_et mcd_close_server_f(const mcd_server_st *server) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + if (!g_server_state.open_server) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_CONNECTION, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "server not open", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + if (server != g_server_state.open_server) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_CONNECTION, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "unknown server", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + g_free(g_server_state.open_server); + g_server_state.open_server = NULL; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index a76d2d081f..425bcacd00 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -15,6 +15,39 @@ #include "libmcd_qapi.h" #include "qapi/qapi-commands-mcd.h" +/** + * struct mcdstub_state - State of the MCD server stub + * + * @open_server: Open server instance as allocated in mcd_open_server_f(). + * @open_server_uid: Unique identifier of the open server. + */ +typedef struct mcdstub_state { + mcd_server_st *open_server; + uint32_t open_server_uid; +} mcdstub_state; + + +static mcdstub_state g_stub_state = { + .open_server = NULL, + .open_server_uid = 0, +}; + +static uint32_t store_open_server(mcd_server_st *server) +{ + g_stub_state.open_server = server; + g_stub_state.open_server_uid++; + return g_stub_state.open_server_uid; +} + +static mcd_server_st *retrieve_open_server(uint32_t server_uid) +{ + if (server_uid == g_stub_state.open_server_uid) { + return g_stub_state.open_server; + } else { + return NULL; + } +} + MCDInitializeResult *qmp_mcd_initialize(MCDAPIVersion *version_req, Error **errp) { @@ -38,6 +71,71 @@ void qmp_mcd_exit(Error **errp) mcd_exit_f(); } +MCDQryServersResult *qmp_mcd_qry_servers(const char *host, bool running, + uint32_t start_index, + uint32_t num_servers, Error **errp) +{ + MCDServerInfoList **tailp; + MCDServerInfo *info; + mcd_server_info_st *server_info = NULL; + bool query_num_only = num_servers == 0; + MCDQryServersResult *result = g_malloc0(sizeof(*result)); + + if (!query_num_only) { + server_info = g_malloc0(num_servers * sizeof(*server_info)); + } + + result->return_status = mcd_qry_servers_f(host, running, start_index, + &num_servers, server_info); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_num_servers = true; + result->num_servers = num_servers; + if (!query_num_only) { + result->has_server_info = true; + tailp = &(result->server_info); + for (uint32_t i = 0; i < num_servers; i++) { + info = marshal_mcd_server_info(server_info + i); + QAPI_LIST_APPEND(tailp, info); + } + } + } + + if (!query_num_only) { + g_free(server_info); + } + + return result; +} + +MCDOpenServerResult *qmp_mcd_open_server(const char *system_key, + const char *config_string, + Error **errp) +{ + MCDOpenServerResult *result = g_malloc0(sizeof(*result)); + mcd_server_st *server; + + result->return_status = mcd_open_server_f(system_key, config_string, + &server); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_server_uid = true; + result->server_uid = store_open_server(server); + result->host = g_strdup(server->host); + result->config_string = g_strdup(server->config_string); + } + + return result; +} + +MCDCloseServerResult *qmp_mcd_close_server(uint32_t server_uid, Error **errp) +{ + MCDCloseServerResult *result = g_malloc0(sizeof(*result)); + mcd_server_st *server = retrieve_open_server(server_uid); + result->return_status = mcd_close_server_f(server); + return result; +} + MCDErrorInfo *qmp_mcd_qry_error_info(Error **errp) { MCDErrorInfo *result; diff --git a/qapi/mcd.json b/qapi/mcd.json index 7b42a74036..3cdfd5dc29 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -73,6 +73,24 @@ 'error-str' : 'str' }} +## +# @MCDServerInfo: +# +# Structure type containing the server information. +# +# @server: String containing the server name. +# @system-instance: String containing the unique system instance identifier. +# @acc-hw: String containing the unique device access hardware name. +# +# Since: 9.1 +## +{ 'struct': 'MCDServerInfo', + 'data': { + 'server' : 'str', + 'system-instance': 'str', + 'acc-hw' : 'str' } } + + ## # == Target Initialization API ## @@ -148,6 +166,193 @@ { 'command': 'mcd-exit' } +## +# == Server Connection API +## + + +## +# @MCDQryServersResult: +# +# Return value of @mcd-qry-servers. +# +# @return-status: Return code. +# @num-servers: The number of returned servers. In case the input value of +# @num-servers is '0', this is the number of all available +# servers. +# @server-info: Server information. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryServersResult', + 'data': { + 'return-status': 'uint32', + '*num-servers' : 'uint32', + '*server-info' : [ 'MCDServerInfo' ] }} + + +## +# @mcd-qry-servers: +# +# Function returning a list of available servers. +# +# @host: String containing the host name. +# @running: Selects between running and installed servers. +# @start-index: Start index of the queried servers. This refers to an +# internal list of the target side implementation. +# @num-servers: The number of queried servers starting from the defined +# @start-index. If it is set to '0', no server descriptions are +# returned but the number of all available servers. +# +# Returns: @MCDQryServersResult +# +# Since: 9.1 +# +# .. qmp-example:: +# +# -> { "execute": "mcd-qry-servers", +# "arguments": { "host": "", +# "running": true, +# "start-index": 0, +# "num-servers": 0 } } +# <- { +# "return": { +# "num-servers": 1, +# "return-status": 0 +# } +# } +# +# -> { "execute": "mcd-qry-servers", +# "arguments": { "host": "", +# "running": true, +# "start-index": 0, +# "num-servers": 1 } } +# <- { +# "return": { +# "num-servers": 1, +# "server-info": [ +# { +# "system-instance": "Process ID: 44801", +# "acc-hw": "", +# "server": "QEMU" +# } +# ], +# "return-status": 0 +# } +# } +## +{ 'command': 'mcd-qry-servers', + 'data': { + 'host' : 'str', + 'running' : 'bool', + 'start-index': 'uint32', + 'num-servers': 'uint32' }, + 'returns': 'MCDQryServersResult' } + + +## +# @MCDOpenServerResult: +# +# Return value of @mcd-open-server. +# +# @return-status: Return code. +# @server-uid: Unique identifier of the server instance. +# @host: String containing the host name. +# @config-string: Server configuration information. +# +# Since: 9.1 +## +{ 'struct': 'MCDOpenServerResult', + 'data': { + 'return-status' : 'uint32', + '*server-uid' : 'uint32', + '*host' : 'str', + '*config-string': 'str' } } + + +## +# @mcd-open-server: +# +# Function opening the connection to a server on a host computer. +# +# @system-key: A server is claimed by this key when being opened. +# @config-string: Allows the configuration of the server connection by a +# character string. Delimiters are blanks, tabs and line +# breaks. Value strings are always enclosed with "double +# quotes". Bool values can be "TRUE" or "FALSE" (both in +# small letters). +# +# Returns: @MCDOpenServerResult +# +# Since: 9.1 +# +# .. qmp-example:: +# +# -> { "execute": "mcd-open-server", +# "arguments": { "system-key": "", +# "config-string": "" } } +# <- { +# "return": { +# "config-string": "", +# "host": "QEMU", +# "server-uid": 1, +# "return-status": 0 +# } +# } +# -> { "execute": "mcd-open-server", +# "arguments": { "system-key": "", +# "config-string": "" } } +# <- { +# "return": { +# "return-status": 3 +# } +# } +# -> { "execute": "mcd-qry-error-info" } +# <- { +# "return": { +# "error-str": "server already open", +# "error-code": 512, +# "error-events": 0, +# "return-status": 3 +# } +# } +## +{ 'command': 'mcd-open-server', + 'data': { + 'system-key' : 'str', + 'config-string': 'str' }, + 'returns': 'MCDOpenServerResult' } + + +## +# @MCDCloseServerResult: +# +# Return value of @mcd-close-server. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDCloseServerResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-close-server: +# +# Function closing the connection to a debug server on a host computer. +# +# @server-uid: Unique identifier of the open server as returned by +# @mcd-open-server. +# +# Returns: @MCDCloseServerResult. +# +# Since: 9.1 +## +{ 'command': 'mcd-close-server', + 'data': { 'server-uid': 'uint32' }, + 'returns': 'MCDCloseServerResult' } + + ## # == Core Connection API ## diff --git a/tests/qtest/libmcd-test.c b/tests/qtest/libmcd-test.c index 597ebec9b5..043ac09cad 100644 --- a/tests/qtest/libmcd-test.c +++ b/tests/qtest/libmcd-test.c @@ -86,3 +86,63 @@ MCDErrorInfo *qtest_mcd_qry_error_info(QTestState *qts) return unmarshal; } + +MCDQryServersResult *qtest_mcd_qry_servers(QTestState *qts, + q_obj_mcd_qry_servers_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDQryServersResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_qry_servers_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-qry-servers'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDQryServersResult); + + return unmarshal; +} + +MCDOpenServerResult *qtest_mcd_open_server(QTestState *qts, + q_obj_mcd_open_server_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDOpenServerResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_open_server_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-open-server'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDOpenServerResult); + + return unmarshal; +} + +MCDCloseServerResult *qtest_mcd_close_server(QTestState *qts, + q_obj_mcd_close_server_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDCloseServerResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_close_server_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-close-server'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDCloseServerResult); + + return unmarshal; +} diff --git a/tests/qtest/libmcd-test.h b/tests/qtest/libmcd-test.h index 1c5da9de62..473416f99f 100644 --- a/tests/qtest/libmcd-test.h +++ b/tests/qtest/libmcd-test.h @@ -20,4 +20,13 @@ MCDInitializeResult *qtest_mcd_initialize(QTestState *qts, MCDErrorInfo *qtest_mcd_qry_error_info(QTestState *qts); +MCDQryServersResult *qtest_mcd_qry_servers(QTestState *qts, + q_obj_mcd_qry_servers_arg *args); + +MCDOpenServerResult *qtest_mcd_open_server(QTestState *qts, + q_obj_mcd_open_server_arg *args); + +MCDCloseServerResult *qtest_mcd_close_server(QTestState *qts, + q_obj_mcd_close_server_arg *args); + #endif /* LIBMCD_TEST_H */ diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c index 275fb46aaa..a0a7cbba46 100644 --- a/tests/qtest/mcd-test.c +++ b/tests/qtest/mcd-test.c @@ -82,6 +82,100 @@ static void test_initialize(void) qtest_quit(qts); } +static void test_qry_servers(void) +{ + QTestState *qts = qtest_init(QEMU_EXTRA_ARGS); + + char host[] = ""; + + q_obj_mcd_qry_servers_arg qapi_args = { + .host = host, + .running = true, + .start_index = 0, + .num_servers = 0, + }; + + MCDQryServersResult *result = qtest_mcd_qry_servers(qts, &qapi_args); + g_assert(result->return_status == MCD_RET_ACT_NONE); + g_assert(result->has_num_servers); + g_assert(result->num_servers == 1); + g_assert(result->has_server_info == false); + + qapi_args.num_servers = result->num_servers; + qapi_free_MCDQryServersResult(result); + + result = qtest_mcd_qry_servers(qts, &qapi_args); + + g_assert(result->return_status == MCD_RET_ACT_NONE); + g_assert(result->has_num_servers); + g_assert(result->num_servers == 1); + g_assert(result->has_server_info); + + if (verbose) { + MCDServerInfo *server_info = result->server_info->value; + fprintf(stderr, "[INFO]\tServer info: %s (%s)\n", + server_info->server, + server_info->system_instance); + } + + qapi_free_MCDQryServersResult(result); + qtest_quit(qts); +} + +static void test_open_server(void) +{ + QTestState *qts = qtest_init(QEMU_EXTRA_ARGS); + + char empty_string[] = ""; + + q_obj_mcd_open_server_arg open_server_args = { + .system_key = empty_string, + .config_string = empty_string, + }; + + q_obj_mcd_close_server_arg close_server_args; + + MCDOpenServerResult *open_server_result; + MCDCloseServerResult *close_server_result; + + open_server_result = qtest_mcd_open_server(qts, &open_server_args); + g_assert(open_server_result->return_status == MCD_RET_ACT_NONE); + g_assert(open_server_result->has_server_uid); + + close_server_args.server_uid = open_server_result->server_uid; + qapi_free_MCDOpenServerResult(open_server_result); + + /* Check that server cannot be opened twice */ + open_server_result = qtest_mcd_open_server(qts, &open_server_args); + g_assert(open_server_result->return_status != MCD_RET_ACT_NONE); + + if (verbose) { + MCDErrorInfo *error_info = qtest_mcd_qry_error_info(qts); + fprintf(stderr, "[INFO]\tServer cannot be opened twice: %s\n", + error_info->error_str); + qapi_free_MCDErrorInfo(error_info); + } + + qapi_free_MCDOpenServerResult(open_server_result); + close_server_result = qtest_mcd_close_server(qts, &close_server_args); + g_assert(close_server_result->return_status == MCD_RET_ACT_NONE); + qapi_free_MCDCloseServerResult(close_server_result); + + /* Check that server cannot be closed twice */ + close_server_result = qtest_mcd_close_server(qts, &close_server_args); + g_assert(close_server_result->return_status != MCD_RET_ACT_NONE); + + if (verbose) { + MCDErrorInfo *error_info = qtest_mcd_qry_error_info(qts); + fprintf(stderr, "[INFO]\tServer cannot be closed twice: %s\n", + error_info->error_str); + qapi_free_MCDErrorInfo(error_info); + } + + qapi_free_MCDCloseServerResult(close_server_result); + qtest_quit(qts); +} + int main(int argc, char *argv[]) { char *v_env = getenv("V"); @@ -89,5 +183,7 @@ int main(int argc, char *argv[]) g_test_init(&argc, &argv, NULL); qtest_add_func("mcd/initialize", test_initialize); + qtest_add_func("mcd/qry-servers", test_qry_servers); + qtest_add_func("mcd/open-server", test_open_server); return g_test_run(); } From patchwork Mon Mar 10 15:04:59 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010264 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A8E59C282DE for ; Mon, 10 Mar 2025 15:13:00 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tren6-000284-Pa; Mon, 10 Mar 2025 11:11:41 -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 1tren1-00023V-IJ for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:35 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremv-0007gG-6H for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:35 -0400 Received: (qmail 30725 invoked by uid 484); 10 Mar 2025 15:11:10 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.01316 secs); 10 Mar 2025 15:11:10 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:10 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake , Fabiano Rosas , Laurent Vivier , Paolo Bonzini Subject: [PATCH 05/16] mcd: Implement target system query Date: Mon, 10 Mar 2025 16:04:59 +0100 Message-Id: <20250310150510.200607-6-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org In MCD, the target system is divided into system, devices and cores: [ system ] 1-* [ devices ] 1-* [cores] This commit implements the necessary functions to query information about the target system. Signed-off-by: Mario Fleischmann --- mcd/libmcd_qapi.c | 48 +++++ mcd/libmcd_qapi.h | 4 + mcd/mcdserver.c | 165 +++++++++++++++++- mcd/mcdstub_qapi.c | 116 +++++++++++++ qapi/mcd.json | 356 ++++++++++++++++++++++++++++++++++++++ tests/qtest/libmcd-test.c | 66 +++++++ tests/qtest/libmcd-test.h | 11 ++ tests/qtest/mcd-test.c | 83 +++++++++ 8 files changed, 846 insertions(+), 3 deletions(-) diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c index 44adb04c76..cb65643110 100644 --- a/mcd/libmcd_qapi.c +++ b/mcd/libmcd_qapi.c @@ -77,3 +77,51 @@ MCDServerInfo *marshal_mcd_server_info(const mcd_server_info_st *server_info) return marshal; } + +MCDCoreConInfo *marshal_mcd_core_con_info(const mcd_core_con_info_st *con_info) +{ + MCDCoreConInfo *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDCoreConInfo) { + .host = g_strdup(con_info->host), + .server_port = con_info->server_port, + .server_key = g_strdup(con_info->server_key), + .system_key = g_strdup(con_info->system_key), + .device_key = g_strdup(con_info->device_key), + .system = g_strdup(con_info->system), + .system_instance = g_strdup(con_info->system_instance), + .acc_hw = g_strdup(con_info->acc_hw), + .device_type = con_info->device_type, + .device = g_strdup(con_info->device), + .device_id = con_info->device_id, + .core = g_strdup(con_info->core), + .core_type = con_info->core_type, + .core_id = con_info->core_id, + }; + + return marshal; +} + +mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info) +{ + mcd_core_con_info_st unmarshal = { + .server_port = con_info->server_port, + .device_type = con_info->device_type, + .device_id = con_info->device_id, + .core_type = con_info->core_type, + .core_id = con_info->core_id, + }; + + strncpy(unmarshal.host, con_info->host, MCD_HOSTNAME_LEN - 1); + strncpy(unmarshal.server_key, con_info->server_key, MCD_KEY_LEN - 1); + strncpy(unmarshal.system_key, con_info->system_key, MCD_KEY_LEN - 1); + strncpy(unmarshal.device_key, con_info->device_key, MCD_KEY_LEN - 1); + strncpy(unmarshal.system, con_info->system, MCD_UNIQUE_NAME_LEN - 1); + strncpy(unmarshal.system_instance, con_info->system_instance, + MCD_UNIQUE_NAME_LEN - 1); + strncpy(unmarshal.acc_hw, con_info->acc_hw, MCD_UNIQUE_NAME_LEN - 1); + strncpy(unmarshal.device, con_info->device, MCD_UNIQUE_NAME_LEN - 1); + strncpy(unmarshal.core, con_info->core, MCD_UNIQUE_NAME_LEN - 1); + + return unmarshal; +} diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h index 6fc99edc93..ceb4b438bb 100644 --- a/mcd/libmcd_qapi.h +++ b/mcd/libmcd_qapi.h @@ -23,6 +23,10 @@ MCDErrorInfo *marshal_mcd_error_info(const mcd_error_info_st *error_info); MCDServerInfo *marshal_mcd_server_info(const mcd_server_info_st *server_info); +MCDCoreConInfo *marshal_mcd_core_con_info(const mcd_core_con_info_st *con_info); + mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version); +mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info); + #endif /* LIBMCD_QAPI_H */ diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index 4d06c255f2..9cc7ec0362 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -9,7 +9,9 @@ */ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include "mcd_api.h" +#include "hw/boards.h" static const mcd_error_info_st MCD_ERROR_NOT_IMPLEMENTED = { .return_status = MCD_RET_ACT_HANDLE_ERROR, @@ -25,6 +27,13 @@ static const mcd_error_info_st MCD_ERROR_INVALID_NULL_PARAM = { .error_str = "null was invalidly passed as a parameter", }; +static const mcd_error_info_st MCD_ERROR_SERVER_NOT_OPEN = { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_CONNECTION, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "server is not open", +}; + static const mcd_error_info_st MCD_ERROR_NONE = { .return_status = MCD_RET_ACT_NONE, .error_code = MCD_ERR_NONE, @@ -40,15 +49,21 @@ static mcd_error_info_st custom_mcd_error; * * @last_error: Error info of most recent executed function. * @open_server: Open server instance as allocated in mcd_open_server_f(). + * @system_key: System key as provided in mcd_open_server_f() + * @cores: Internal core information database. */ typedef struct mcdserver_state { const mcd_error_info_st *last_error; mcd_server_st *open_server; + char system_key[MCD_KEY_LEN]; + GArray *cores; } mcdserver_state; static mcdserver_state g_server_state = { .last_error = &MCD_ERROR_NONE, .open_server = NULL, + .system_key = "", + .cores = NULL, }; mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, @@ -153,6 +168,8 @@ mcd_return_et mcd_open_server_f(const char *system_key, const char *config_string, mcd_server_st **server) { + CPUState *cpu; + if (g_server_state.open_server) { custom_mcd_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, @@ -178,6 +195,23 @@ mcd_return_et mcd_open_server_f(const char *system_key, *server = g_server_state.open_server; + if (system_key) { + pstrcpy(g_server_state.system_key, MCD_KEY_LEN, system_key); + } + + /* update the internal core information data base */ + g_server_state.cores = g_array_new(false, true, + sizeof(mcd_core_con_info_st)); + CPU_FOREACH(cpu) { + ObjectClass *oc = object_get_class(OBJECT(cpu)); + const char *cpu_model = object_class_get_name(oc); + mcd_core_con_info_st info = { + .core_id = g_server_state.cores->len, + }; + pstrcpy(info.core, MCD_UNIQUE_NAME_LEN, cpu_model); + g_array_append_val(g_server_state.cores, info); + } + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } @@ -206,8 +240,10 @@ mcd_return_et mcd_close_server_f(const mcd_server_st *server) return g_server_state.last_error->return_status; } + g_array_free(g_server_state.cores, true); g_free(g_server_state.open_server); g_server_state.open_server = NULL; + g_server_state.system_key[0] = '\0'; g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; @@ -231,7 +267,45 @@ mcd_return_et mcd_qry_server_config_f(const mcd_server_st *server, mcd_return_et mcd_qry_systems_f(uint32_t start_index, uint32_t *num_systems, mcd_core_con_info_st *system_con_info) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + if (!num_systems) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + if (*num_systems == 0) { + *num_systems = 1; + g_server_state.last_error = &MCD_ERROR_NONE; + return g_server_state.last_error->return_status; + } + + if (start_index >= 1) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "QEMU only emulates one system", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + /* num_systems != 0 => return system information */ + + if (!system_con_info) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + *system_con_info = (mcd_core_con_info_st) {}; + pstrcpy(system_con_info->system, MCD_UNIQUE_NAME_LEN, g_get_prgname()); + pstrcpy(system_con_info->system_key, MCD_KEY_LEN, + g_server_state.system_key); + snprintf(system_con_info->system_instance, MCD_UNIQUE_NAME_LEN , + "Process ID: %d", (int) getpid()); + + *num_systems = 1; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } @@ -239,7 +313,41 @@ mcd_return_et mcd_qry_devices_f(const mcd_core_con_info_st *system_con_info, uint32_t start_index, uint32_t *num_devices, mcd_core_con_info_st *device_con_info) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + MachineClass *mc = MACHINE_GET_CLASS(current_machine); + + if (!system_con_info || !num_devices) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + if (*num_devices == 0) { + *num_devices = 1; + g_server_state.last_error = &MCD_ERROR_NONE; + return g_server_state.last_error->return_status; + } + + if (start_index >= 1) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "QEMU only emulates one machine", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + if (!device_con_info) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + *device_con_info = *system_con_info; + pstrcpy(device_con_info->device, MCD_UNIQUE_NAME_LEN, mc->name); + + *num_devices = 1; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } @@ -247,7 +355,58 @@ mcd_return_et mcd_qry_cores_f(const mcd_core_con_info_st *connection_info, uint32_t start_index, uint32_t *num_cores, mcd_core_con_info_st *core_con_info) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + uint32_t i; + + if (!g_server_state.open_server) { + g_server_state.last_error = &MCD_ERROR_SERVER_NOT_OPEN; + return g_server_state.last_error->return_status; + } + + if (!connection_info || !num_cores) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + /* array is allocated during core database update in mcd_server_open_f */ + g_assert(g_server_state.cores); + + if (*num_cores == 0) { + *num_cores = g_server_state.cores->len; + g_server_state.last_error = &MCD_ERROR_NONE; + return g_server_state.last_error->return_status; + } + + if (start_index >= g_server_state.cores->len) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "start_index exceeds the number of cores", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + if (!core_con_info) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + for (i = 0; + i < *num_cores && start_index + i < g_server_state.cores->len; + i++) { + + mcd_core_con_info_st *info = &g_array_index(g_server_state.cores, + mcd_core_con_info_st, + start_index + i); + core_con_info[i] = *connection_info; + core_con_info[i].core_id = info->core_id; + pstrcpy(core_con_info[i].core, MCD_UNIQUE_NAME_LEN, info->core); + } + + *num_cores = i; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index 425bcacd00..f4573bc77c 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -136,6 +136,122 @@ MCDCloseServerResult *qmp_mcd_close_server(uint32_t server_uid, Error **errp) return result; } +MCDQrySystemsResult *qmp_mcd_qry_systems(uint32_t start_index, + uint32_t num_systems, Error **errp) +{ + MCDCoreConInfoList **tailp; + MCDCoreConInfo *info; + mcd_core_con_info_st *system_con_info = NULL; + bool query_num_only = num_systems == 0; + MCDQrySystemsResult *result = g_malloc0(sizeof(*result)); + + if (!query_num_only) { + system_con_info = g_malloc0(num_systems * sizeof(*system_con_info)); + } + + result->return_status = mcd_qry_systems_f(start_index, &num_systems, + system_con_info); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_num_systems = true; + result->num_systems = num_systems; + if (!query_num_only) { + result->has_system_con_info = true; + tailp = &(result->system_con_info); + for (uint32_t i = 0; i < num_systems; i++) { + info = marshal_mcd_core_con_info(system_con_info + i); + QAPI_LIST_APPEND(tailp, info); + } + } + } + + if (!query_num_only) { + g_free(system_con_info); + } + + return result; +} + +MCDQryDevicesResult *qmp_mcd_qry_devices(MCDCoreConInfo *system_con_info, + uint32_t start_index, + uint32_t num_devices, Error **errp) +{ + MCDCoreConInfoList **tailp; + MCDCoreConInfo *info; + mcd_core_con_info_st *device_con_info = NULL; + bool query_num_only = num_devices == 0; + MCDQryDevicesResult *result = g_malloc0(sizeof(*result)); + mcd_core_con_info_st system_con_info_unmarshalled = + unmarshal_mcd_core_con_info(system_con_info); + + if (!query_num_only) { + device_con_info = g_malloc0(num_devices * sizeof(*device_con_info)); + } + + result->return_status = mcd_qry_devices_f(&system_con_info_unmarshalled, + start_index, &num_devices, + device_con_info); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_num_devices = true; + result->num_devices = num_devices; + if (!query_num_only) { + result->has_device_con_info = true; + tailp = &(result->device_con_info); + for (uint32_t i = 0; i < num_devices; i++) { + info = marshal_mcd_core_con_info(device_con_info + i); + QAPI_LIST_APPEND(tailp, info); + } + } + } + + if (!query_num_only) { + g_free(device_con_info); + } + + return result; +} + +MCDQryCoresResult *qmp_mcd_qry_cores(MCDCoreConInfo *connection_info, + uint32_t start_index, uint32_t num_cores, + Error **errp) +{ + MCDCoreConInfoList **tailp; + MCDCoreConInfo *info; + mcd_core_con_info_st *core_con_info = NULL; + bool query_num_only = num_cores == 0; + MCDQryCoresResult *result = g_malloc0(sizeof(*result)); + mcd_core_con_info_st connection_info_unmarshalled = + unmarshal_mcd_core_con_info(connection_info); + + if (!query_num_only) { + core_con_info = g_malloc0(num_cores * sizeof(*core_con_info)); + } + + result->return_status = mcd_qry_cores_f(&connection_info_unmarshalled, + start_index, &num_cores, + core_con_info); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_num_cores = true; + result->num_cores = num_cores; + if (!query_num_only) { + result->has_core_con_info = true; + tailp = &(result->core_con_info); + for (uint32_t i = 0; i < num_cores; i++) { + info = marshal_mcd_core_con_info(core_con_info + i); + QAPI_LIST_APPEND(tailp, info); + } + } + } + + if (!query_num_only) { + g_free(core_con_info); + } + + return result; +} + MCDErrorInfo *qmp_mcd_qry_error_info(Error **errp) { MCDErrorInfo *result; diff --git a/qapi/mcd.json b/qapi/mcd.json index 3cdfd5dc29..2d581b9d89 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -91,6 +91,62 @@ 'acc-hw' : 'str' } } +## +# @MCDCoreConInfo: +# +# Structure type containing the core connection information. +# +# @host: String containing the IP host name. +# @server-port: Port number of the server. +# @server-key: String containing the server key as provided by +# mcd_open_server_f(). +# @system-key: String containing the system key as provided by +# mcd_open_server_f(). +# @device-key: String containing the device key, optional for +# mcd_open_core_f(). +# @system: String containing the system name. Predefined value is +# "Real HW" for physical devices. Note that in case of "Real +# HW" the @acc-hw always needs to be defined. +# @system-instance: String containing the unique system instance identifier. +# Allows to differentiate between several system instances +# with the same name. A typical use case is a simulator where +# different instances can be distinguished by their process +# ID. (For example @system-instance could be: "Process ID: +# 1234") +# @acc-hw: String containing the unique device access hardware name. +# @device-type: Device type identifier (IEEE 1149.1 device ID) +# @device: String containing the system unique device instance name. +# For Real HW this is usually the sales name of the device. +# If the access hardware operates a multi device target +# system (e.g. over IEEE1149.7), this device string can +# contain an index to differentiate between several devices +# of the same type. +# @device-id: Unique device ID. +# @core: String containing the device unique core name. +# @core-type: Core type identifier (taken from ELF predefined +# architecture) +# @core-id: Unique core ID representing the core version. +# +# Since: 9.1 +## +{ 'struct': 'MCDCoreConInfo', + 'data': { + 'host' : 'str', + 'server-port' : 'uint32', + 'server-key' : 'str', + 'system-key' : 'str', + 'device-key' : 'str', + 'system' : 'str', + 'system-instance': 'str', + 'acc-hw' : 'str', + 'device-type' : 'uint32', + 'device' : 'str', + 'device-id' : 'uint32', + 'core' : 'str', + 'core-type' : 'uint32', + 'core-id' : 'uint32' } } + + ## # == Target Initialization API ## @@ -353,6 +409,306 @@ 'returns': 'MCDCloseServerResult' } +## +# == Target System Features API +## + + +## +# @MCDQrySystemsResult: +# +# Return value of @mcd-qry-systems. +# +# @return-status: Return code. +# @num-systems: The number of systems the core connection info was returned +# for. In case the input value of @num-systems is '0', this is +# the number of all available systems. +# @system-con-info: Core connection information of the requested systems. +# +# Since: 9.1 +## +{ 'struct': 'MCDQrySystemsResult', + 'data': { + 'return-status' : 'uint32', + '*num-systems' : 'uint32', + '*system-con-info': [ 'MCDCoreConInfo' ] }} + + +## +# @mcd-qry-systems: +# +# Function querying the core connection information of a specified number of +# systems. +# +# @start-index: Start index of the queried systems. This refers to an +# internal list of the target side implementation. +# @num-systems: The number of queried systems starting from the defined +# @start-index. If it is set to '0', no core connection +# information is returned but the number of available systems. +# +# Returns: @MCDQrySystemsResult +# +# Since: 9.1 +# +# .. qmp-example:: +# +# -> { "execute": "mcd-qry-systems", +# "arguments": { "start-index": 0, +# "num-systems": 1 } } +# <- { +# "return": { +# "num-systems": 1, +# "system-con-info": [ +# { +# "core-id": 0, +# "device": "", +# "device-id": 0, +# "device-key": "", +# "system": "qemu-system-aarch64", +# "core": "", +# "host": "", +# "system-key": "", +# "system-instance": "Process ID: 21591", +# "acc-hw": "", +# "core-type": 0, +# "device-type": 0, +# "server-key": "", +# "server-port": 0 +# } +# ], +# "return-status": 0 +# } +# } +## +{ 'command': 'mcd-qry-systems', + 'data': { + 'start-index': 'uint32', + 'num-systems': 'uint32' }, + 'returns': 'MCDQrySystemsResult' } + + +## +# @MCDQryDevicesResult: +# +# Return value of @mcd-qry-devices. +# +# @return-status: Return code. +# @num-devices: The number of devices the core connection information was +# returned for. In case the input value of @num-devices is +# '0', this is the number of all available devices for the +# selected system. +# @device-con-info: Core connection information of the requested devices. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryDevicesResult', + 'data': { + 'return-status' : 'uint32', + '*num-devices' : 'uint32', + '*device-con-info': [ 'MCDCoreConInfo' ] }} + + +## +# @mcd-qry-devices: +# +# Function querying the core connection information of a specified number of +# devices of a system. +# +# @system-con-info: Core connection information of the system the devices +# are queried from. +# @start-index: Start index of the requested devices. This refers to +# an internal list of the target side implementation. +# @num-devices: The number of queried devices (e.g. simulated on or +# connected to this host computer) starting from the defined +# @start-index. If it is set to '0', no core connection +# information is returned but the number of all available +# devices. +# +# Returns: @MCDQryDevicesResult +# +# Since: 9.1 +# +# .. qmp-example:: +# +# -> { "execute": "mcd-qry-devices", +# "arguments": { +# "start-index": 0, +# "num-devices": 1, +# "system-con-info": { +# "core-id": 0, +# "device": "", +# "device-id": 0, +# "device-key": "", +# "system": "qemu-system-aarch64", +# "core": "", +# "host": "", +# "system-key": "", +# "system-instance": "", +# "acc-hw": "", +# "core-type": 0, +# "device-type": 0, +# "server-key": "", +# "server-port": 0 } } } +# <- { +# "return": { +# "return-status": 0, +# "num-devices": 1, +# "device-con-info": [ +# { +# "core-id": 0, +# "device": "virt-10.0", +# "device-id": 0, +# "device-key": "", +# "system": "qemu-system-aarch64", +# "core": "", +# "host": "", +# "system-key": "", +# "system-instance": "", +# "acc-hw": "", +# "core-type": 0, +# "device-type": 0, +# "server-key": "", +# "server-port": 0 +# } +# ] +# } +# } +## +{ 'command': 'mcd-qry-devices', + 'data': { + 'system-con-info': 'MCDCoreConInfo', + 'start-index' : 'uint32', + 'num-devices' : 'uint32' }, + 'returns': 'MCDQryDevicesResult' } + + +## +# @MCDQryCoresResult: +# +# Return value of @mcd-qry-cores. +# +# @return-status: Return code. +# +# @num-cores: The number of cores the core connection information +# is returned for. In case the input value of @num-cores is '0', +# this is the number of all available cores for the selected +# system or device. +# @core-con-info: Core connection information of the requested cores. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryCoresResult', + 'data': { + 'return-status' : 'uint32', + '*num-cores' : 'uint32', + '*core-con-info': [ 'MCDCoreConInfo' ] }} + + +## +# @mcd-qry-cores: +# +# Function querying the core connection information of a specified number of +# cores of a system/device. +# +# @connection-info: Core connection information of the system or device +# the cores are queried from. +# @start-index: Start index of the requested cores. This refers to an +# internal list of the target side implementation. +# @num-cores: The number of queried cores starting from the defined +# @start-index. If it is set to '0', no core connection +# information is returned but the number of all available +# cores. +# +# Returns: @MCDQryCoresResult +# +# Since: 9.1 +# +# .. qmp-example:: +# :title: Multicore +# +# -> { "execute": "mcd-qry-cores", +# "arguments": { +# "start-index": 0, +# "num-cores": 3, +# "connection-info": { +# "core-id": 0, +# "device": "virt-10.0", +# "device-id": 0, +# "device-key": "", +# "system": "", +# "core": "", +# "host": "", +# "system-key": "qemu-system-aarch64", +# "system-instance": "", +# "acc-hw": "", +# "core-type": 0, +# "device-type": 0, +# "server-key": "", +# "server-port": 0 } } } +# <- { +# "return": { +# "num-cores": 3, +# "core-con-info": [ +# { +# "core-id": 0, +# "device": "virt-10.0", +# "device-id": 0, +# "device-key": "", +# "system": "", +# "core": "cortex-a53-arm-cpu", +# "host": "", +# "system-key": "qemu-system-aarch64", +# "system-instance": "", +# "acc-hw": "", +# "core-type": 0, +# "device-type": 0, +# "server-key": "", +# "server-port": 0 +# }, +# { +# "core-id": 1, +# "device": "virt-10.0", +# "device-id": 0, +# "device-key": "", +# "system": "", +# "core": "cortex-a53-arm-cpu", +# "host": "", +# "system-key": "qemu-system-aarch64", +# "system-instance": "", +# "acc-hw": "", +# "core-type": 0, +# "device-type": 0, +# "server-key": "", +# "server-port": 0 +# }, +# { +# "core-id": 2, +# "device": "virt-10.0", +# "device-id": 0, +# "device-key": "", +# "system": "", +# "core": "cortex-a53-arm-cpu", +# "host": "", +# "system-key": "qemu-system-aarch64", +# "system-instance": "", +# "acc-hw": "", +# "core-type": 0, +# "device-type": 0, +# "server-key": "", +# "server-port": 0 +# } +# ], +# "return-status": 0 +# } +# } +## +{ 'command': 'mcd-qry-cores', + 'data': { + 'connection-info': 'MCDCoreConInfo', + 'start-index' : 'uint32', + 'num-cores' : 'uint32' }, + 'returns': 'MCDQryCoresResult' } + ## # == Core Connection API ## diff --git a/tests/qtest/libmcd-test.c b/tests/qtest/libmcd-test.c index 043ac09cad..0874a0eb4c 100644 --- a/tests/qtest/libmcd-test.c +++ b/tests/qtest/libmcd-test.c @@ -87,6 +87,12 @@ MCDErrorInfo *qtest_mcd_qry_error_info(QTestState *qts) return unmarshal; } +void qtest_mcd_exit(QTestState *qts) +{ + QDict *resp = qtest_qmp(qts, "{'execute': 'mcd-exit' }"); + qobject_unref(resp); +} + MCDQryServersResult *qtest_mcd_qry_servers(QTestState *qts, q_obj_mcd_qry_servers_arg *args) { @@ -146,3 +152,63 @@ MCDCloseServerResult *qtest_mcd_close_server(QTestState *qts, return unmarshal; } + +MCDQrySystemsResult *qtest_mcd_qry_systems(QTestState *qts, + q_obj_mcd_qry_systems_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDQrySystemsResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_qry_systems_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-qry-systems'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDQrySystemsResult); + + return unmarshal; +} + +MCDQryDevicesResult *qtest_mcd_qry_devices(QTestState *qts, + q_obj_mcd_qry_devices_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDQryDevicesResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_qry_devices_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-qry-devices'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDQryDevicesResult); + + return unmarshal; +} + +MCDQryCoresResult *qtest_mcd_qry_cores(QTestState *qts, + q_obj_mcd_qry_cores_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDQryCoresResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_qry_cores_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-qry-cores'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDQryCoresResult); + + return unmarshal; +} diff --git a/tests/qtest/libmcd-test.h b/tests/qtest/libmcd-test.h index 473416f99f..baeaf57419 100644 --- a/tests/qtest/libmcd-test.h +++ b/tests/qtest/libmcd-test.h @@ -20,6 +20,8 @@ MCDInitializeResult *qtest_mcd_initialize(QTestState *qts, MCDErrorInfo *qtest_mcd_qry_error_info(QTestState *qts); +void qtest_mcd_exit(QTestState *qts); + MCDQryServersResult *qtest_mcd_qry_servers(QTestState *qts, q_obj_mcd_qry_servers_arg *args); @@ -29,4 +31,13 @@ MCDOpenServerResult *qtest_mcd_open_server(QTestState *qts, MCDCloseServerResult *qtest_mcd_close_server(QTestState *qts, q_obj_mcd_close_server_arg *args); +MCDQrySystemsResult *qtest_mcd_qry_systems(QTestState *qts, + q_obj_mcd_qry_systems_arg *args); + +MCDQryDevicesResult *qtest_mcd_qry_devices(QTestState *qts, + q_obj_mcd_qry_devices_arg *args); + +MCDQryCoresResult *qtest_mcd_qry_cores(QTestState *qts, + q_obj_mcd_qry_cores_arg *args); + #endif /* LIBMCD_TEST_H */ diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c index a0a7cbba46..2e61867c8d 100644 --- a/tests/qtest/mcd-test.c +++ b/tests/qtest/mcd-test.c @@ -176,6 +176,88 @@ static void test_open_server(void) qtest_quit(qts); } +static void test_qry_cores(void) +{ + QTestState *qts = qtest_init(QEMU_EXTRA_ARGS); + + char empty_string[] = ""; + + q_obj_mcd_open_server_arg open_server_args = { + .system_key = empty_string, + .config_string = empty_string, + }; + + q_obj_mcd_qry_systems_arg qry_systems_args = { + .start_index = 0, + .num_systems = 1, + }; + + q_obj_mcd_qry_devices_arg qry_devices_args = { + .start_index = 0, + .num_devices = 1, + }; + + q_obj_mcd_qry_cores_arg qry_cores_args = { + .start_index = 0, + /* first, only query the number of cores */ + .num_cores = 0, + }; + + MCDOpenServerResult *open_server_result; + MCDQrySystemsResult *qry_systems_result; + MCDQryDevicesResult *qry_devices_result; + MCDQryCoresResult *qry_cores_result; + + open_server_result = qtest_mcd_open_server(qts, &open_server_args); + g_assert(open_server_result->return_status == MCD_RET_ACT_NONE); + g_assert(open_server_result->has_server_uid); + qapi_free_MCDOpenServerResult(open_server_result); + + qry_systems_result = qtest_mcd_qry_systems(qts, &qry_systems_args); + g_assert(qry_systems_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_systems_result->has_system_con_info); + + qry_devices_args.system_con_info = + qry_systems_result->system_con_info->value; + + qry_devices_result = qtest_mcd_qry_devices(qts, &qry_devices_args); + g_assert(qry_devices_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_devices_result->has_device_con_info); + qapi_free_MCDQrySystemsResult(qry_systems_result); + + qry_cores_args.connection_info = + qry_devices_result->device_con_info->value; + + qry_cores_result = qtest_mcd_qry_cores(qts, &qry_cores_args); + g_assert(qry_cores_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_cores_result->has_num_cores); + g_assert(qry_cores_result->num_cores > 0); + qry_cores_args.num_cores = qry_cores_result->num_cores; + qapi_free_MCDQryCoresResult(qry_cores_result); + qry_cores_result = qtest_mcd_qry_cores(qts, &qry_cores_args); + qapi_free_MCDQryDevicesResult(qry_devices_result); + + if (verbose) { + MCDCoreConInfoList *core_head = qry_cores_result->core_con_info; + for (uint32_t c = 0; c < qry_cores_result->num_cores; c++) { + MCDCoreConInfo *core_con = core_head->value; + if (verbose) { + fprintf(stderr, "[INFO]\tSystem: %s\n" + "\tDevice: %s\n" + "\tCore: %s (#%d)\n", + core_con->system, + core_con->device, + core_con->core, core_con->core_id); + } + core_head = core_head->next; + } + } + + qapi_free_MCDQryCoresResult(qry_cores_result); + qtest_mcd_exit(qts); + qtest_quit(qts); +} + int main(int argc, char *argv[]) { char *v_env = getenv("V"); @@ -185,5 +267,6 @@ int main(int argc, char *argv[]) qtest_add_func("mcd/initialize", test_initialize); qtest_add_func("mcd/qry-servers", test_qry_servers); qtest_add_func("mcd/open-server", test_open_server); + qtest_add_func("mcd/qry-cores", test_qry_cores); return g_test_run(); } From patchwork Mon Mar 10 15:05:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010303 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7390BC35FF1 for ; Mon, 10 Mar 2025 15:20:43 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tren7-00028c-0i; Mon, 10 Mar 2025 11:11:41 -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 1tren1-00023b-It for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:35 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremw-0007gS-LA for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:35 -0400 Received: (qmail 30747 invoked by uid 484); 10 Mar 2025 15:11:10 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.013263 secs); 10 Mar 2025 15:11:10 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:10 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake , Fabiano Rosas , Laurent Vivier , Paolo Bonzini Subject: [PATCH 06/16] mcd: Implement core connection control Date: Mon, 10 Mar 2025 16:05:00 +0100 Message-Id: <20250310150510.200607-7-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org In MCD, core-specific operations require an open connection to the core. This commit implements the necessary operations to open and close the connection to cores. Signed-off-by: Mario Fleischmann --- mcd/mcdserver.c | 176 ++++++++++++++++++++++++++++--- mcd/mcdstub_qapi.c | 116 ++++++++++++++++++++- qapi/mcd.json | 132 +++++++++++++++++++++++- tests/qtest/libmcd-test.c | 52 +++++++++- tests/qtest/libmcd-test.h | 9 +- tests/qtest/mcd-test.c | 212 +++++++++++++++++++++++++++----------- 6 files changed, 613 insertions(+), 84 deletions(-) diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index 9cc7ec0362..83ffa4f097 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -34,6 +34,13 @@ static const mcd_error_info_st MCD_ERROR_SERVER_NOT_OPEN = { .error_str = "server is not open", }; +static const mcd_error_info_st MCD_ERROR_UNKNOWN_CORE = { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "specified core is unknown to server", +}; + static const mcd_error_info_st MCD_ERROR_NONE = { .return_status = MCD_RET_ACT_NONE, .error_code = MCD_ERR_NONE, @@ -44,6 +51,24 @@ static const mcd_error_info_st MCD_ERROR_NONE = { /* reserves memory for custom errors */ static mcd_error_info_st custom_mcd_error; +/** + * struct mcdcore_state - State of a core. + * + * @last_error: Error info of most recent executed function. + * @info: Core connection information. + * @open_core: Open core instance as allocated in mcd_open_core_f(). + * + * MCD is mainly being used on the core level: + * After the initial query functions, a core connection is opened in + * mcd_open_core_f(). The allocated mcd_core_st instance is then the basis + * of subsequent operations. + */ +typedef struct mcdcore_state { + const mcd_error_info_st *last_error; + mcd_core_con_info_st info; + mcd_core_st *open_core; +} mcdcore_state; + /** * struct mcdserver_state - State of the MCD server * @@ -66,6 +91,24 @@ static mcdserver_state g_server_state = { .cores = NULL, }; +static mcdcore_state *find_core(const mcd_core_con_info_st *core_con_info) +{ + uint32_t core_id; + mcdcore_state *core; + + if (!core_con_info || !g_server_state.cores) { + return NULL; + } + + core_id = core_con_info->core_id; + if (core_id > g_server_state.cores->len) { + return NULL; + } + + core = &g_array_index(g_server_state.cores, mcdcore_state, core_id); + return core; +} + mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, mcd_impl_version_info_st *impl_info) { @@ -200,16 +243,19 @@ mcd_return_et mcd_open_server_f(const char *system_key, } /* update the internal core information data base */ - g_server_state.cores = g_array_new(false, true, - sizeof(mcd_core_con_info_st)); + g_server_state.cores = g_array_new(false, true, sizeof(mcdcore_state)); CPU_FOREACH(cpu) { ObjectClass *oc = object_get_class(OBJECT(cpu)); const char *cpu_model = object_class_get_name(oc); - mcd_core_con_info_st info = { - .core_id = g_server_state.cores->len, + mcdcore_state c = { + .info = (mcd_core_con_info_st) { + .core_id = g_server_state.cores->len, + }, + .last_error = &MCD_ERROR_NONE, + .open_core = NULL, }; - pstrcpy(info.core, MCD_UNIQUE_NAME_LEN, cpu_model); - g_array_append_val(g_server_state.cores, info); + pstrcpy(c.info.core, MCD_UNIQUE_NAME_LEN, cpu_model); + g_array_append_val(g_server_state.cores, c); } g_server_state.last_error = &MCD_ERROR_NONE; @@ -240,6 +286,14 @@ mcd_return_et mcd_close_server_f(const mcd_server_st *server) return g_server_state.last_error->return_status; } + for (int i = 0; i < g_server_state.cores->len; i++) { + mcdcore_state *c = &g_array_index(g_server_state.cores, + mcdcore_state, i); + if (c->open_core) { + mcd_close_core_f(c->open_core); + } + } + g_array_free(g_server_state.cores, true); g_free(g_server_state.open_server); g_server_state.open_server = NULL; @@ -396,12 +450,11 @@ mcd_return_et mcd_qry_cores_f(const mcd_core_con_info_st *connection_info, i < *num_cores && start_index + i < g_server_state.cores->len; i++) { - mcd_core_con_info_st *info = &g_array_index(g_server_state.cores, - mcd_core_con_info_st, - start_index + i); + mcdcore_state *c = &g_array_index(g_server_state.cores, mcdcore_state, + start_index + i); core_con_info[i] = *connection_info; - core_con_info[i].core_id = info->core_id; - pstrcpy(core_con_info[i].core, MCD_UNIQUE_NAME_LEN, info->core); + core_con_info[i].core_id = c->info.core_id; + pstrcpy(core_con_info[i].core, MCD_UNIQUE_NAME_LEN, c->info.core); } *num_cores = i; @@ -421,21 +474,116 @@ mcd_return_et mcd_qry_core_modes_f(const mcd_core_st *core, mcd_return_et mcd_open_core_f(const mcd_core_con_info_st *core_con_info, mcd_core_st **core) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + uint32_t core_id; + mcdcore_state *core_state; + mcd_core_con_info_st *info; + + if (!g_server_state.open_server) { + g_server_state.last_error = &MCD_ERROR_SERVER_NOT_OPEN; + return g_server_state.last_error->return_status; + } + + if (!core_con_info || !core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_id = core_con_info->core_id; + if (core_id > g_server_state.cores->len) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "specified core index exceeds the number of cores", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + core_state = &g_array_index(g_server_state.cores, mcdcore_state, core_id); + if (core_state->open_core) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_CONNECTION, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "core already open", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + *core = g_malloc(sizeof(mcd_core_st)); + info = g_malloc(sizeof(mcd_core_con_info_st)); + *info = *core_con_info; + (*core)->core_con_info = info; + (*core)->instance = NULL; + core_state->open_core = *core; + core_state->last_error = &MCD_ERROR_NONE; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } mcd_return_et mcd_close_core_f(const mcd_core_st *core) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + mcdcore_state *core_state; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (core_state->open_core != core) { + custom_mcd_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_CONNECTION, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "core not open", + }; + g_server_state.last_error = &custom_mcd_error; + return g_server_state.last_error->return_status; + } + + g_free((void *)core->core_con_info); + g_free((void *)core); + core_state->open_core = NULL; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } void mcd_qry_error_info_f(const mcd_core_st *core, mcd_error_info_st *error_info) { - if (error_info) { + mcdcore_state *core_state; + + if (!error_info) { + return; + } + + if (!core) { *error_info = *g_server_state.last_error; + return; + } + + core_state = find_core(core->core_con_info); + if (!core_state) { + *error_info = MCD_ERROR_UNKNOWN_CORE; + } else if (core_state->open_core != core) { + *error_info = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_CONNECTION, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "core not open", + }; + } else { + *error_info = *core_state->last_error; } } diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index f4573bc77c..51292d239d 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -18,18 +18,27 @@ /** * struct mcdstub_state - State of the MCD server stub * - * @open_server: Open server instance as allocated in mcd_open_server_f(). - * @open_server_uid: Unique identifier of the open server. + * @open_server: Open server instance as allocated in + * mcd_open_server_f(). + * @open_server_uid: Unique identifier of the open server. + * @open_cores: Array of open cores. + * @custom_error: Last error which occurred in the server stub. + * @on_error_ask_server: Call mcd_qry_error_info_f() when asked for most recent + * error. */ typedef struct mcdstub_state { mcd_server_st *open_server; uint32_t open_server_uid; + GPtrArray *open_cores; + mcd_error_info_st custom_error; + bool on_error_ask_server; } mcdstub_state; static mcdstub_state g_stub_state = { .open_server = NULL, .open_server_uid = 0, + .on_error_ask_server = true, }; static uint32_t store_open_server(mcd_server_st *server) @@ -48,6 +57,50 @@ static mcd_server_st *retrieve_open_server(uint32_t server_uid) } } +static uint32_t store_open_core(mcd_core_st *core) +{ + /* core_uid 0 is reserved */ + uint32_t core_uid = core->core_con_info->core_id + 1; + mcd_core_st **core_p; + + if (!g_stub_state.open_cores) { + g_stub_state.open_cores = g_ptr_array_new(); + } + + if (core_uid > g_stub_state.open_cores->len) { + g_ptr_array_set_size(g_stub_state.open_cores, core_uid); + } + + core_p = (mcd_core_st **) &g_ptr_array_index(g_stub_state.open_cores, + core_uid - 1); + *core_p = core; + return core_uid; +} + +static mcd_return_et retrieve_open_core(uint32_t core_uid, mcd_core_st **core) +{ + if (core_uid > 0 && + (!g_stub_state.open_cores || core_uid > g_stub_state.open_cores->len)) { + g_stub_state.custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "stub: core UID not found", + }; + return g_stub_state.custom_error.return_status; + } + + g_assert(core); + + if (!core_uid) { + *core = NULL; + } else { + *core = g_ptr_array_index(g_stub_state.open_cores, core_uid - 1); + } + + return MCD_RET_ACT_NONE; +} + MCDInitializeResult *qmp_mcd_initialize(MCDAPIVersion *version_req, Error **errp) { @@ -63,6 +116,7 @@ MCDInitializeResult *qmp_mcd_initialize(MCDAPIVersion *version_req, result->impl_info = marshal_mcd_impl_version_info(&impl_info); } + g_stub_state.on_error_ask_server = true; return result; } @@ -105,6 +159,7 @@ MCDQryServersResult *qmp_mcd_qry_servers(const char *host, bool running, g_free(server_info); } + g_stub_state.on_error_ask_server = true; return result; } @@ -125,6 +180,7 @@ MCDOpenServerResult *qmp_mcd_open_server(const char *system_key, result->config_string = g_strdup(server->config_string); } + g_stub_state.on_error_ask_server = true; return result; } @@ -169,6 +225,7 @@ MCDQrySystemsResult *qmp_mcd_qry_systems(uint32_t start_index, g_free(system_con_info); } + g_stub_state.on_error_ask_server = true; return result; } @@ -209,6 +266,7 @@ MCDQryDevicesResult *qmp_mcd_qry_devices(MCDCoreConInfo *system_con_info, g_free(device_con_info); } + g_stub_state.on_error_ask_server = true; return result; } @@ -249,14 +307,64 @@ MCDQryCoresResult *qmp_mcd_qry_cores(MCDCoreConInfo *connection_info, g_free(core_con_info); } + g_stub_state.on_error_ask_server = true; return result; } -MCDErrorInfo *qmp_mcd_qry_error_info(Error **errp) +MCDOpenCoreResult *qmp_mcd_open_core(MCDCoreConInfo *core_con_info, + Error **errp) +{ + MCDOpenCoreResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core; + mcd_core_con_info_st core_con_info_unmarshalled = + unmarshal_mcd_core_con_info(core_con_info); + + result->return_status = mcd_open_core_f(&core_con_info_unmarshalled, + &core); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_core_uid = true; + result->core_uid = store_open_core(core); + result->core_con_info = marshal_mcd_core_con_info(core->core_con_info); + } + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDCloseCoreResult *qmp_mcd_close_core(uint32_t core_uid, Error **errp) +{ + MCDCloseCoreResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_close_core_f(core); + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDErrorInfo *qmp_mcd_qry_error_info(uint32_t core_uid, Error **errp) { MCDErrorInfo *result; + mcd_core_st *core = NULL; mcd_error_info_st error_info; - mcd_qry_error_info_f(NULL, &error_info); + + if (retrieve_open_core(core_uid, &core) != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + } + + if (g_stub_state.on_error_ask_server) { + mcd_qry_error_info_f(core, &error_info); + } else { + error_info = g_stub_state.custom_error; + } + result = marshal_mcd_error_info(&error_info); return result; } diff --git a/qapi/mcd.json b/qapi/mcd.json index 2d581b9d89..7219056464 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -713,6 +713,133 @@ # == Core Connection API ## +## +# @MCDOpenCoreResult: +# +# Return value of @mcd-open-core. +# +# @return-status: Return code. +# @core-uid: Unique identifier of the core instance. +# @core-con-info: Core connection information of the core instance. +# +# Since: 9.1 +## +{ 'struct': 'MCDOpenCoreResult', + 'data': { + 'return-status' : 'uint32', + '*core-uid' : 'uint32', + '*core-con-info': 'MCDCoreConInfo' }} + + +## +# @mcd-open-core: +# +# Function opening a core connection. +# +# @core-con-info: Unambiguous core information (e.g. from @mcd-qry-cores). +# +# Returns: @MCDOpenCoreResult +# +# Since: 9.1 +# +# .. qmp-example:: +# +# -> { "execute": "mcd-open-core", +# "arguments": { +# "core-con-info": { +# "core-id": 0, +# "device": "virt-10.0", +# "device-id": 0, +# "device-key": "", +# "system": "", +# "core": "cortex-a53-arm-cpu", +# "host": "", +# "system-key": "qemu-system-aarch64", +# "system-instance": "", +# "acc-hw": "", +# "core-type": 0, +# "device-type": 0, +# "server-key": "", +# "server-port": 0 } } } +# <- { +# "return": { +# "core-con-info": { +# "core-id": 0, +# "device": "virt-10.0", +# "device-id": 0, +# "device-key": "", +# "system": "", +# "core": "cortex-a53-arm-cpu", +# "host": "", +# "system-key": "qemu-system-aarch64", +# "system-instance": "", +# "acc-hw": "", +# "core-type": 0, +# "device-type": 0, +# "server-key": "", +# "server-port": 0 +# }, +# "return-status": 0, +# "core-uid": 1 +# } +# } +## +{ 'command': 'mcd-open-core', + 'data': { 'core-con-info': 'MCDCoreConInfo' }, + 'returns': 'MCDOpenCoreResult' } + + +## +# @MCDCloseCoreResult: +# +# Return value of @mcd-close-core. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDCloseCoreResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-close-core: +# +# Function closing a core connection. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# +# Returns: @MCDCloseCoreResult +# +# Since: 9.1 +# +# .. qmp-example:: +# +# -> { "execute": "mcd-close-core", "arguments": { "core-uid": 1 } } +# <- { +# "return": { +# "return-status": 0 +# } +# } +# -> { "execute": "mcd-close-core", "arguments": { "core-uid": 1 } } +# <- { +# "return": { +# "return-status": 3 +# } +# } +# -> { "execute": "mcd-qry-error-info", "arguments": { "core-uid": 1 } } +# <- { +# "return": { +# "error-str": "core not open", +# "error-code": 512, +# "error-events": 0, +# "return-status": 3 +# } +# } +## +{ 'command': 'mcd-close-core', + 'data': { 'core-uid': 'uint32' }, + 'returns': 'MCDCloseCoreResult' } + ## # @mcd-qry-error-info: @@ -720,6 +847,8 @@ # Function allowing the access to detailed error and/or event information after # an API call. # +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# # Returns: @MCDErrorInfo # # Since: 9.1 @@ -736,7 +865,7 @@ # "return-status": 3 # } # } -# -> { "execute": "mcd-qry-error-info" } +# -> { "execute": "mcd-qry-error-info", "arguments": { "core-uid": 0 }} # <- { # "return": { # "error-str": "incompatible versions", @@ -747,4 +876,5 @@ # } ## { 'command': 'mcd-qry-error-info', + 'data': { 'core-uid': 'uint32' }, 'returns': 'MCDErrorInfo' } diff --git a/tests/qtest/libmcd-test.c b/tests/qtest/libmcd-test.c index 0874a0eb4c..c976eb1bed 100644 --- a/tests/qtest/libmcd-test.c +++ b/tests/qtest/libmcd-test.c @@ -72,21 +72,27 @@ MCDInitializeResult *qtest_mcd_initialize(QTestState *qts, return unmarshal; } -MCDErrorInfo *qtest_mcd_qry_error_info(QTestState *qts) +MCDErrorInfo *qtest_mcd_qry_error_info(QTestState *qts, + q_obj_mcd_qry_error_info_arg *args) { Visitor *v; - QDict *resp; + QObject *marshal; + QDict *arg, *resp; QObject *ret; bool ok; MCDErrorInfo *unmarshal; - resp = qtest_qmp(qts, "{'execute': 'mcd-qry-error-info'}"); + MARSHAL_ARGS(q_obj_mcd_qry_error_info_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-qry-error-info'," + "'arguments': %p}", arg); UNMARSHAL_RESULT(MCDErrorInfo); return unmarshal; } + void qtest_mcd_exit(QTestState *qts) { QDict *resp = qtest_qmp(qts, "{'execute': 'mcd-exit' }"); @@ -212,3 +218,43 @@ MCDQryCoresResult *qtest_mcd_qry_cores(QTestState *qts, return unmarshal; } + +MCDOpenCoreResult *qtest_mcd_open_core(QTestState *qts, + q_obj_mcd_open_core_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDOpenCoreResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_open_core_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-open-core'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDOpenCoreResult); + + return unmarshal; +} + +MCDCloseCoreResult *qtest_mcd_close_core(QTestState *qts, + q_obj_mcd_close_core_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDCloseCoreResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_close_core_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-close-core'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDCloseCoreResult); + + return unmarshal; +} diff --git a/tests/qtest/libmcd-test.h b/tests/qtest/libmcd-test.h index baeaf57419..323458785e 100644 --- a/tests/qtest/libmcd-test.h +++ b/tests/qtest/libmcd-test.h @@ -18,7 +18,8 @@ MCDInitializeResult *qtest_mcd_initialize(QTestState *qts, q_obj_mcd_initialize_arg *args); -MCDErrorInfo *qtest_mcd_qry_error_info(QTestState *qts); +MCDErrorInfo *qtest_mcd_qry_error_info(QTestState *qts, + q_obj_mcd_qry_error_info_arg *args); void qtest_mcd_exit(QTestState *qts); @@ -40,4 +41,10 @@ MCDQryDevicesResult *qtest_mcd_qry_devices(QTestState *qts, MCDQryCoresResult *qtest_mcd_qry_cores(QTestState *qts, q_obj_mcd_qry_cores_arg *args); +MCDOpenCoreResult *qtest_mcd_open_core(QTestState *qts, + q_obj_mcd_open_core_arg *args); + +MCDCloseCoreResult *qtest_mcd_close_core(QTestState *qts, + q_obj_mcd_close_core_arg *args); + #endif /* LIBMCD_TEST_H */ diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c index 2e61867c8d..8a7e04c5cf 100644 --- a/tests/qtest/mcd-test.c +++ b/tests/qtest/mcd-test.c @@ -22,6 +22,71 @@ static bool verbose; +static MCDQryCoresResult *open_server_query_cores(QTestState *qts) +{ + char empty_string[] = ""; + + q_obj_mcd_open_server_arg open_server_args = { + .system_key = empty_string, + .config_string = empty_string, + }; + + q_obj_mcd_qry_systems_arg qry_systems_args = { + .start_index = 0, + .num_systems = 1, + }; + + q_obj_mcd_qry_devices_arg qry_devices_args = { + .start_index = 0, + .num_devices = 1, + }; + + /* first for num_cores only */ + q_obj_mcd_qry_cores_arg qry_cores_args = { + .start_index = 0, + .num_cores = 0, + }; + + MCDOpenServerResult *open_server_result; + MCDQrySystemsResult *qry_systems_result; + MCDQryDevicesResult *qry_devices_result; + MCDQryCoresResult *qry_cores_result; + + open_server_result = qtest_mcd_open_server(qts, &open_server_args); + g_assert(open_server_result->return_status == MCD_RET_ACT_NONE); + g_assert(open_server_result->has_server_uid); + qapi_free_MCDOpenServerResult(open_server_result); + + qry_systems_result = qtest_mcd_qry_systems(qts, &qry_systems_args); + g_assert(qry_systems_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_systems_result->has_system_con_info); + + qry_devices_args.system_con_info = + qry_systems_result->system_con_info->value; + + qry_devices_result = qtest_mcd_qry_devices(qts, &qry_devices_args); + g_assert(qry_devices_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_devices_result->has_device_con_info); + qapi_free_MCDQrySystemsResult(qry_systems_result); + + qry_cores_args.connection_info = + qry_devices_result->device_con_info->value; + + qry_cores_result = qtest_mcd_qry_cores(qts, &qry_cores_args); + g_assert(qry_cores_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_cores_result->has_num_cores); + g_assert(qry_cores_result->num_cores > 0); + qry_cores_args.num_cores = qry_cores_result->num_cores; + qapi_free_MCDQryCoresResult(qry_cores_result); + qry_cores_result = qtest_mcd_qry_cores(qts, &qry_cores_args); + g_assert(qry_cores_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_cores_result->has_num_cores); + g_assert(qry_cores_result->num_cores > 0); + qapi_free_MCDQryDevicesResult(qry_devices_result); + + return qry_cores_result; +} + static void test_initialize(void) { QTestState *qts = qtest_init(QEMU_EXTRA_ARGS); @@ -37,6 +102,8 @@ static void test_initialize(void) .version_req = marshal_mcd_api_version(&version_req), }; + q_obj_mcd_qry_error_info_arg qry_error_info_args = { .core_uid = 0 }; + MCDInitializeResult *result = qtest_mcd_initialize(qts, &qapi_args); g_assert(result->return_status == MCD_RET_ACT_NONE); @@ -67,7 +134,7 @@ static void test_initialize(void) result = qtest_mcd_initialize(qts, &qapi_args); g_assert(result->return_status != MCD_RET_ACT_NONE); - error_info = qtest_mcd_qry_error_info(qts); + error_info = qtest_mcd_qry_error_info(qts, &qry_error_info_args); g_assert(error_info->error_code == MCD_ERR_GENERAL); if (verbose) { @@ -150,7 +217,9 @@ static void test_open_server(void) g_assert(open_server_result->return_status != MCD_RET_ACT_NONE); if (verbose) { - MCDErrorInfo *error_info = qtest_mcd_qry_error_info(qts); + q_obj_mcd_qry_error_info_arg qry_error_info_args = { .core_uid = 0 }; + MCDErrorInfo *error_info = qtest_mcd_qry_error_info(qts, + &qry_error_info_args); fprintf(stderr, "[INFO]\tServer cannot be opened twice: %s\n", error_info->error_str); qapi_free_MCDErrorInfo(error_info); @@ -166,7 +235,9 @@ static void test_open_server(void) g_assert(close_server_result->return_status != MCD_RET_ACT_NONE); if (verbose) { - MCDErrorInfo *error_info = qtest_mcd_qry_error_info(qts); + q_obj_mcd_qry_error_info_arg qry_error_info_args = { .core_uid = 0 }; + MCDErrorInfo *error_info = qtest_mcd_qry_error_info(qts, + &qry_error_info_args); fprintf(stderr, "[INFO]\tServer cannot be closed twice: %s\n", error_info->error_str); qapi_free_MCDErrorInfo(error_info); @@ -179,64 +250,7 @@ static void test_open_server(void) static void test_qry_cores(void) { QTestState *qts = qtest_init(QEMU_EXTRA_ARGS); - - char empty_string[] = ""; - - q_obj_mcd_open_server_arg open_server_args = { - .system_key = empty_string, - .config_string = empty_string, - }; - - q_obj_mcd_qry_systems_arg qry_systems_args = { - .start_index = 0, - .num_systems = 1, - }; - - q_obj_mcd_qry_devices_arg qry_devices_args = { - .start_index = 0, - .num_devices = 1, - }; - - q_obj_mcd_qry_cores_arg qry_cores_args = { - .start_index = 0, - /* first, only query the number of cores */ - .num_cores = 0, - }; - - MCDOpenServerResult *open_server_result; - MCDQrySystemsResult *qry_systems_result; - MCDQryDevicesResult *qry_devices_result; - MCDQryCoresResult *qry_cores_result; - - open_server_result = qtest_mcd_open_server(qts, &open_server_args); - g_assert(open_server_result->return_status == MCD_RET_ACT_NONE); - g_assert(open_server_result->has_server_uid); - qapi_free_MCDOpenServerResult(open_server_result); - - qry_systems_result = qtest_mcd_qry_systems(qts, &qry_systems_args); - g_assert(qry_systems_result->return_status == MCD_RET_ACT_NONE); - g_assert(qry_systems_result->has_system_con_info); - - qry_devices_args.system_con_info = - qry_systems_result->system_con_info->value; - - qry_devices_result = qtest_mcd_qry_devices(qts, &qry_devices_args); - g_assert(qry_devices_result->return_status == MCD_RET_ACT_NONE); - g_assert(qry_devices_result->has_device_con_info); - qapi_free_MCDQrySystemsResult(qry_systems_result); - - qry_cores_args.connection_info = - qry_devices_result->device_con_info->value; - - qry_cores_result = qtest_mcd_qry_cores(qts, &qry_cores_args); - g_assert(qry_cores_result->return_status == MCD_RET_ACT_NONE); - g_assert(qry_cores_result->has_num_cores); - g_assert(qry_cores_result->num_cores > 0); - qry_cores_args.num_cores = qry_cores_result->num_cores; - qapi_free_MCDQryCoresResult(qry_cores_result); - qry_cores_result = qtest_mcd_qry_cores(qts, &qry_cores_args); - qapi_free_MCDQryDevicesResult(qry_devices_result); - + MCDQryCoresResult *qry_cores_result = open_server_query_cores(qts); if (verbose) { MCDCoreConInfoList *core_head = qry_cores_result->core_con_info; for (uint32_t c = 0; c < qry_cores_result->num_cores; c++) { @@ -258,6 +272,81 @@ static void test_qry_cores(void) qtest_quit(qts); } +static void test_open_core(void) +{ + QTestState *qts = qtest_init(QEMU_EXTRA_ARGS); + MCDQryCoresResult *cores_query = open_server_query_cores(qts); + + MCDCoreConInfoList *core_head = cores_query->core_con_info; + for (uint32_t c = 0; c < cores_query->num_cores; c++) { + q_obj_mcd_close_core_arg close_core_args; + MCDCloseCoreResult *close_core_result; + + MCDCoreConInfo *core_con_info = core_head->value; + q_obj_mcd_open_core_arg open_core_args = { + .core_con_info = core_con_info, + }; + + q_obj_mcd_qry_error_info_arg error_info_args = { + .core_uid = 0, + }; + MCDErrorInfo *last_server_error; + + MCDOpenCoreResult *open_core_result = + qtest_mcd_open_core(qts, &open_core_args); + g_assert(open_core_result->return_status == MCD_RET_ACT_NONE); + g_assert(open_core_result->has_core_uid); + + if (verbose) { + fprintf(stderr, "[INFO]\tCore #%d open with UID %d\n", + core_con_info->core_id, + open_core_result->core_uid); + } + + close_core_args.core_uid = open_core_result->core_uid; + + /* Verify that core cannot be opened twice */ + qapi_free_MCDOpenCoreResult(open_core_result); + open_core_result = qtest_mcd_open_core(qts, &open_core_args); + g_assert(open_core_result->return_status != MCD_RET_ACT_NONE); + + last_server_error = qtest_mcd_qry_error_info(qts, &error_info_args); + if (verbose) { + fprintf(stderr, "[INFO]\tCore cannot be opened twice: %s\n", + last_server_error->error_str); + } + qapi_free_MCDErrorInfo(last_server_error); + + close_core_result = qtest_mcd_close_core(qts, &close_core_args); + g_assert(close_core_result->return_status == MCD_RET_ACT_NONE); + + if (verbose) { + fprintf(stderr, "[INFO]\tCore with UID %d closed\n", + close_core_args.core_uid); + } + + /* Check that core cannot be closed twice */ + qapi_free_MCDCloseCoreResult(close_core_result); + close_core_result = qtest_mcd_close_core(qts, &close_core_args); + g_assert(close_core_result->return_status != MCD_RET_ACT_NONE); + + last_server_error = qtest_mcd_qry_error_info(qts, &error_info_args); + if (verbose) { + fprintf(stderr, "[INFO]\tCore cannot be closed twice: %s\n", + last_server_error->error_str); + } + qapi_free_MCDErrorInfo(last_server_error); + + qapi_free_MCDCloseCoreResult(close_core_result); + qapi_free_MCDOpenCoreResult(open_core_result); + core_head = core_head->next; + } + + qapi_free_MCDQryCoresResult(cores_query); + qtest_mcd_exit(qts); + qtest_quit(qts); +} + int main(int argc, char *argv[]) { char *v_env = getenv("V"); @@ -268,5 +357,6 @@ int main(int argc, char *argv[]) qtest_add_func("mcd/qry-servers", test_qry_servers); qtest_add_func("mcd/open-server", test_open_server); qtest_add_func("mcd/qry-cores", test_qry_cores); + qtest_add_func("mcd/open-core", test_open_core); return g_test_run(); } From patchwork Mon Mar 10 15:05:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010301 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E6BCFC282EC for ; Mon, 10 Mar 2025 15:20:40 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tren7-00029E-6A; Mon, 10 Mar 2025 11:11:41 -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 1tren2-00024I-7r for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:36 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremw-0007gY-Me for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:35 -0400 Received: (qmail 30771 invoked by uid 484); 10 Mar 2025 15:11:11 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.013161 secs); 10 Mar 2025 15:11:11 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:11 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake , Fabiano Rosas , Laurent Vivier , Paolo Bonzini Subject: [PATCH 07/16] mcd: Implement memory space query Date: Mon, 10 Mar 2025 16:05:01 +0100 Message-Id: <20250310150510.200607-8-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Support three main memory space types: * Physical memory * Logical memory (MMU) * GDB Registers Use custom memory type to mark memory spaces as secure V=1 QTEST_QEMU_BINARY="./qemu-system-arm -M virt,secure=on -cpu cortex-a15" tests/qtest/mcd-test Signed-off-by: Mario Fleischmann --- mcd/libmcd_qapi.c | 22 +++++ mcd/libmcd_qapi.h | 2 + mcd/mcdserver.c | 199 +++++++++++++++++++++++++++++++------- mcd/mcdstub_qapi.c | 44 +++++++++ qapi/mcd.json | 199 ++++++++++++++++++++++++++++++++++++++ tests/qtest/libmcd-test.c | 20 ++++ tests/qtest/libmcd-test.h | 3 + tests/qtest/mcd-test.c | 79 +++++++++++++++ 8 files changed, 534 insertions(+), 34 deletions(-) diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c index cb65643110..0421152705 100644 --- a/mcd/libmcd_qapi.c +++ b/mcd/libmcd_qapi.c @@ -125,3 +125,25 @@ mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info) return unmarshal; } + +MCDMemspace *marshal_mcd_memspace(const mcd_memspace_st *mem_space) +{ + MCDMemspace *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDMemspace) { + .mem_space_id = mem_space->mem_space_id, + .mem_space_name = g_strdup(mem_space->mem_space_name), + .mem_type = mem_space->mem_type, + .bits_per_mau = mem_space->bits_per_mau, + .invariance = mem_space->invariance, + .endian = mem_space->endian, + .min_addr = mem_space->min_addr, + .max_addr = mem_space->max_addr, + .num_mem_blocks = mem_space->num_mem_blocks, + .supported_access_options = mem_space->supported_access_options, + .core_mode_mask_read = mem_space->core_mode_mask_read, + .core_mode_mask_write = mem_space->core_mode_mask_write, + }; + + return marshal; +} diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h index ceb4b438bb..7e874dec25 100644 --- a/mcd/libmcd_qapi.h +++ b/mcd/libmcd_qapi.h @@ -25,6 +25,8 @@ MCDServerInfo *marshal_mcd_server_info(const mcd_server_info_st *server_info); MCDCoreConInfo *marshal_mcd_core_con_info(const mcd_core_con_info_st *con_info); +MCDMemspace *marshal_mcd_memspace(const mcd_memspace_st *mem_space); + mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version); mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info); diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index 83ffa4f097..f924bf3799 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -12,6 +12,10 @@ #include "qemu/cutils.h" #include "mcd_api.h" #include "hw/boards.h" +#include "exec/tswap.h" + +/* Custom memory space type */ +static const mcd_mem_type_et MCD_MEM_SPACE_IS_SECURE = 0x00010000; static const mcd_error_info_st MCD_ERROR_NOT_IMPLEMENTED = { .return_status = MCD_RET_ACT_HANDLE_ERROR, @@ -48,37 +52,45 @@ static const mcd_error_info_st MCD_ERROR_NONE = { .error_str = "", }; -/* reserves memory for custom errors */ -static mcd_error_info_st custom_mcd_error; - /** * struct mcdcore_state - State of a core. * - * @last_error: Error info of most recent executed function. - * @info: Core connection information. - * @open_core: Open core instance as allocated in mcd_open_core_f(). + * @last_error: Error info of most recent executed core-related function. + * @custom_error: Reserves memory for custom MCD errors. + * @info: Core connection information. + * @open_core: Open core instance as allocated in mcd_open_core_f(). + * @cpu: QEMU's internal CPU handle. + * @memory_spaces: Memory spaces as queried by mcd_qry_mem_spaces_f(). * * MCD is mainly being used on the core level: * After the initial query functions, a core connection is opened in * mcd_open_core_f(). The allocated mcd_core_st instance is then the basis * of subsequent operations. + * + * @cpu is the internal CPU handle through which core specific debug + * functions are implemented. */ typedef struct mcdcore_state { const mcd_error_info_st *last_error; + mcd_error_info_st custom_error; mcd_core_con_info_st info; mcd_core_st *open_core; + CPUState *cpu; + GArray *memory_spaces; } mcdcore_state; /** * struct mcdserver_state - State of the MCD server * - * @last_error: Error info of most recent executed function. - * @open_server: Open server instance as allocated in mcd_open_server_f(). - * @system_key: System key as provided in mcd_open_server_f() - * @cores: Internal core information database. + * @last_error: Error info of most recent executed function. + * @custom_error: Reserves memory for custom MCD errors. + * @open_server: Open server instance as allocated in mcd_open_server_f(). + * @system_key: System key as provided in mcd_open_server_f() + * @cores: Internal core information database. */ typedef struct mcdserver_state { const mcd_error_info_st *last_error; + mcd_error_info_st custom_error; mcd_server_st *open_server; char system_key[MCD_KEY_LEN]; GArray *cores; @@ -134,13 +146,13 @@ mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, version_req->v_api_minor <= MCD_API_VER_MINOR) { g_server_state.last_error = &MCD_ERROR_NONE; } else { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_GENERAL, .error_events = MCD_ERR_EVT_NONE, .error_str = "incompatible versions", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; } return g_server_state.last_error->return_status; @@ -160,13 +172,13 @@ mcd_return_et mcd_qry_servers_f(const char *host, bool running, mcd_server_info_st *server_info) { if (start_index >= 1) { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_PARAM, .error_events = MCD_ERR_EVT_NONE, .error_str = "QEMU only has one MCD server", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; return g_server_state.last_error->return_status; } @@ -214,13 +226,13 @@ mcd_return_et mcd_open_server_f(const char *system_key, CPUState *cpu; if (g_server_state.open_server) { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_CONNECTION, .error_events = MCD_ERR_EVT_NONE, .error_str = "server already open", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; return g_server_state.last_error->return_status; } @@ -253,6 +265,8 @@ mcd_return_et mcd_open_server_f(const char *system_key, }, .last_error = &MCD_ERROR_NONE, .open_core = NULL, + .cpu = cpu, + .memory_spaces = g_array_new(false, true, sizeof(mcd_memspace_st)), }; pstrcpy(c.info.core, MCD_UNIQUE_NAME_LEN, cpu_model); g_array_append_val(g_server_state.cores, c); @@ -265,24 +279,24 @@ mcd_return_et mcd_open_server_f(const char *system_key, mcd_return_et mcd_close_server_f(const mcd_server_st *server) { if (!g_server_state.open_server) { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_CONNECTION, .error_events = MCD_ERR_EVT_NONE, .error_str = "server not open", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; return g_server_state.last_error->return_status; } if (server != g_server_state.open_server) { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_CONNECTION, .error_events = MCD_ERR_EVT_NONE, .error_str = "unknown server", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; return g_server_state.last_error->return_status; } @@ -333,13 +347,13 @@ mcd_return_et mcd_qry_systems_f(uint32_t start_index, uint32_t *num_systems, } if (start_index >= 1) { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_PARAM, .error_events = MCD_ERR_EVT_NONE, .error_str = "QEMU only emulates one system", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; return g_server_state.last_error->return_status; } @@ -381,13 +395,13 @@ mcd_return_et mcd_qry_devices_f(const mcd_core_con_info_st *system_con_info, } if (start_index >= 1) { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_PARAM, .error_events = MCD_ERR_EVT_NONE, .error_str = "QEMU only emulates one machine", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; return g_server_state.last_error->return_status; } @@ -431,13 +445,13 @@ mcd_return_et mcd_qry_cores_f(const mcd_core_con_info_st *connection_info, } if (start_index >= g_server_state.cores->len) { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_PARAM, .error_events = MCD_ERR_EVT_NONE, .error_str = "start_index exceeds the number of cores", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; return g_server_state.last_error->return_status; } @@ -471,6 +485,59 @@ mcd_return_et mcd_qry_core_modes_f(const mcd_core_st *core, return g_server_state.last_error->return_status; } +static mcd_return_et query_memspaces(mcdcore_state *core_state) +{ + g_array_set_size(core_state->memory_spaces, 0); + + mcd_endian_et endian = target_words_bigendian() + ? MCD_ENDIAN_BIG : MCD_ENDIAN_LITTLE; + + for (uint32_t i = 0; i < core_state->cpu->num_ases; i++) { + AddressSpace *as = cpu_get_address_space(core_state->cpu, i); + + int secure_flag = 0; + if (core_state->cpu->num_ases > 1) { + int sid = cpu_asidx_from_attrs(core_state->cpu, + (MemTxAttrs) { .secure = 1 }); + if (i == sid) { + secure_flag = MCD_MEM_SPACE_IS_SECURE; + } + } + + const char *as_name = as->name; + const char *mr_name = as->root->name; + + mcd_memspace_st physical = { + /* mem space ID 0 is reserved */ + .mem_space_id = core_state->memory_spaces->len + 1, + .mem_type = MCD_MEM_SPACE_IS_PHYSICAL | secure_flag, + .endian = endian, + }; + strncpy(physical.mem_space_name, mr_name, MCD_MEM_SPACE_NAME_LEN - 1); + + g_array_append_val(core_state->memory_spaces, physical); + + mcd_memspace_st logical = { + .mem_space_id = core_state->memory_spaces->len + 1, + .mem_type = MCD_MEM_SPACE_IS_LOGICAL | secure_flag, + .endian = endian, + }; + strncpy(logical.mem_space_name, as_name, MCD_MEM_SPACE_NAME_LEN - 1); + + g_array_append_val(core_state->memory_spaces, logical); + } + + mcd_memspace_st gdb_registers = { + .mem_space_id = core_state->memory_spaces->len + 1, + .mem_space_name = "GDB Registers", + .mem_type = MCD_MEM_SPACE_IS_REGISTERS, + .endian = endian, + }; + g_array_append_val(core_state->memory_spaces, gdb_registers); + + return MCD_RET_ACT_NONE; +} + mcd_return_et mcd_open_core_f(const mcd_core_con_info_st *core_con_info, mcd_core_st **core) { @@ -490,25 +557,29 @@ mcd_return_et mcd_open_core_f(const mcd_core_con_info_st *core_con_info, core_id = core_con_info->core_id; if (core_id > g_server_state.cores->len) { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_PARAM, .error_events = MCD_ERR_EVT_NONE, .error_str = "specified core index exceeds the number of cores", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; return g_server_state.last_error->return_status; } core_state = &g_array_index(g_server_state.cores, mcdcore_state, core_id); if (core_state->open_core) { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_CONNECTION, .error_events = MCD_ERR_EVT_NONE, .error_str = "core already open", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; + return g_server_state.last_error->return_status; + } + + if (query_memspaces(core_state) != MCD_RET_ACT_NONE) { return g_server_state.last_error->return_status; } @@ -540,19 +611,21 @@ mcd_return_et mcd_close_core_f(const mcd_core_st *core) } if (core_state->open_core != core) { - custom_mcd_error = (mcd_error_info_st) { + g_server_state.custom_error = (mcd_error_info_st) { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_CONNECTION, .error_events = MCD_ERR_EVT_NONE, .error_str = "core not open", }; - g_server_state.last_error = &custom_mcd_error; + g_server_state.last_error = &g_server_state.custom_error; return g_server_state.last_error->return_status; } g_free((void *)core->core_con_info); g_free((void *)core); core_state->open_core = NULL; + core_state->cpu = NULL; + g_array_set_size(core_state->memory_spaces, 0); g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; @@ -613,8 +686,66 @@ mcd_return_et mcd_qry_mem_spaces_f(const mcd_core_st *core, uint32_t *num_mem_spaces, mcd_memspace_st *mem_spaces) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + uint32_t i; + mcdcore_state *core_state; + + if (!core || !num_mem_spaces) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + g_assert(core_state->memory_spaces); + + if (core_state->memory_spaces->len == 0) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_NO_MEM_SPACES, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (*num_mem_spaces == 0) { + *num_mem_spaces = core_state->memory_spaces->len; + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; + } + + if (start_index >= core_state->memory_spaces->len) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "start_index exceeds the number of memory spaces", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (!mem_spaces) { + core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return core_state->last_error->return_status; + } + + for (i = 0; i < *num_mem_spaces && + start_index + i < core_state->memory_spaces->len; i++) { + + mem_spaces[i] = g_array_index(core_state->memory_spaces, + mcd_memspace_st, start_index + i); + } + + *num_mem_spaces = i; + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_qry_mem_blocks_f(const mcd_core_st *core, diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index 51292d239d..437d2c2e3e 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -368,3 +368,47 @@ MCDErrorInfo *qmp_mcd_qry_error_info(uint32_t core_uid, Error **errp) result = marshal_mcd_error_info(&error_info); return result; } + +MCDQryMemSpacesResult *qmp_mcd_qry_mem_spaces(uint32_t core_uid, + uint32_t start_index, + uint32_t num_mem_spaces, + Error **errp) +{ + MCDMemspaceList **tailp; + MCDMemspace *ms; + mcd_memspace_st *memspaces = NULL; + bool query_num_only = num_mem_spaces == 0; + MCDQryMemSpacesResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + if (retrieve_open_core(core_uid, &core) != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + } + + if (!query_num_only) { + memspaces = g_malloc0(num_mem_spaces * sizeof(*memspaces)); + } + + result->return_status = mcd_qry_mem_spaces_f(core, start_index, + &num_mem_spaces, memspaces); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_num_mem_spaces = true; + result->num_mem_spaces = num_mem_spaces; + if (!query_num_only) { + result->has_mem_spaces = true; + tailp = &(result->mem_spaces); + for (uint32_t i = 0; i < num_mem_spaces; i++) { + ms = marshal_mcd_memspace(memspaces + i); + QAPI_LIST_APPEND(tailp, ms); + } + } + } + + if (!query_num_only) { + g_free(memspaces); + } + + g_stub_state.on_error_ask_server = true; + return result; +} diff --git a/qapi/mcd.json b/qapi/mcd.json index 7219056464..214933e279 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -147,6 +147,74 @@ 'core-id' : 'uint32' } } +## +# @MCDMemspace: +# +# Structure type containing information about a memory space. +# +# @mem-space-id: ID of this memory space, ID 0 is reserved. +# @mem-space-name: Unique name of the memory space. +# @mem-type: Type of the memory space. +# @bits-per-mau: Bits per minimum addressable unit (MAU). The +# minimum addressable unit of a memory is defined as +# the size in bits of its basic block that may have +# a unique address. For example for a byte +# addressable memory this value would be set to '8' +# according to the 8 bits of a byte block. +# @invariance: The total number of bytes in a memory word, which +# is @bits-per-mau divided by 8, consists of groups +# of "invariant" bytes. These groups can be arranged +# in Big Endian or Little Endian order. +# For example an @invariance of '2' and '64' +# @bits-per-mau, a Little Endian word are +# represented as b0 b1 b2 b3 b4 b5 b6 b7. +# In contrast to this, a Big Endian word is +# represented as b6 b7 b4 b5 b2 b3 b0 b1. +# @endian: Endianness of this memory space. Can be overriden +# by @endian of a MCDMemblock. +# @min-addr: Minimum address of this memory space. +# @max-addr: Maximum address of this memory space. +# @num-mem-blocks: Number of memory blocks in this memory space. Each +# memory space may have a certain number of memory +# blocks. Memory blocks contain additional +# information pertaining to the intended purpose of +# the memory. This information may be used as a hint +# for memory data representation within a tool's +# memory view. This field specifies the number of +# memory blocks present in this memory space. +# @supported-access-options: Supported memory access options (OR'ed bitmask). +# Can be overriden by @supported-access-options of a +# MCDMemblock. +# @core-mode-mask-read: Mask of core modes for which read accesses are +# impossible. A set bit indicates that read accesses +# are denied in this mode. Bit 0 represents core +# mode '1', bit 31 represents core mode '32'. Can be +# overriden by @core-mode-mask-read of a MCDMemblock. +# @core-mode-mask-write: Mask of core modes for which write accesses are +# impossible; a set bit indicates that write +# accesses are denied in this mode. Bit 0 represents +# core mode '1', bit 31 represents core mode '32'. +# Can be overriden by +# @core-mode-mask-write of a MCDMemblock. +# +# Since: 9.1 +## +{ 'struct': 'MCDMemspace', + 'data': { + 'mem-space-id' : 'uint32', + 'mem-space-name' : 'str', + 'mem-type' : 'uint32', + 'bits-per-mau' : 'uint32', + 'invariance' : 'uint8', + 'endian' : 'uint32', + 'min-addr' : 'uint64', + 'max-addr' : 'uint64', + 'num-mem-blocks' : 'uint32', + 'supported-access-options': 'uint32', + 'core-mode-mask-read' : 'uint32', + 'core-mode-mask-write' : 'uint32' } } + + ## # == Target Initialization API ## @@ -878,3 +946,134 @@ { 'command': 'mcd-qry-error-info', 'data': { 'core-uid': 'uint32' }, 'returns': 'MCDErrorInfo' } + + +## +# @MCDQryMemSpacesResult: +# +# Return value of @mcd-qry-mem-spaces. +# +# @return-status: Return code. +# @num-mem-spaces: The number of returned memory spaces. In case the input value +# of @num-mem-spaces is '0', this is the number of all +# available memory spaces for the selected core. +# @mem-spaces: Memory space information. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryMemSpacesResult', + 'data': { + 'return-status' : 'uint32', + '*num-mem-spaces': 'uint32', + '*mem-spaces' : [ 'MCDMemspace' ] }} + +## +# @mcd-qry-mem-spaces: +# +# Function querying the available memory spaces for a particular component. +# +# @core-uid: Unique identifier of the open core as returned by +# @mcd-open-core. +# @start-index: Start index of the requested memory spaces. This refers to +# an internal list of the target side implementation. +# @num-mem-spaces: Number of memory spaces, information is requested of. If it +# is set to '0', no memory space information is returned but +# the number of all available memory spaces for the selected +# core. +# +# Returns: @MCDQryMemSpacesResult +# +# Since: 9.1 +# +# .. qmp-example:: +# :title: Arm TrustZone +# +# -> { "execute": "mcd-qry-mem-spaces", +# "arguments": { "core-uid": 1, +# "start-index": 0, +# "num-mem-spaces": 20 } } +# <- { +# "return": { +# "mem-spaces": [ +# { +# "mem-space-id": 1, +# "bits-per-mau": 0, +# "mem-space-name": "system", +# "endian": 0, +# "max-addr": 0, +# "mem-type": 16, +# "core-mode-mask-write": 0, +# "core-mode-mask-read": 0, +# "supported-access-options": 0, +# "invariance": 0, +# "num-mem-blocks": 0, +# "min-addr": 0 +# }, +# { +# "mem-space-id": 2, +# "bits-per-mau": 0, +# "mem-space-name": "cpu-memory-0", +# "endian": 0, +# "max-addr": 0, +# "mem-type": 32, +# "core-mode-mask-write": 0, +# "core-mode-mask-read": 0, +# "supported-access-options": 0, +# "invariance": 0, +# "num-mem-blocks": 0, +# "min-addr": 0 +# }, +# { +# "mem-space-id": 3, +# "bits-per-mau": 0, +# "mem-space-name": "secure-memory", +# "endian": 0, +# "max-addr": 0, +# "mem-type": 65552, +# "core-mode-mask-write": 0, +# "core-mode-mask-read": 0, +# "supported-access-options": 0, +# "invariance": 0, +# "num-mem-blocks": 0, +# "min-addr": 0 +# }, +# { +# "mem-space-id": 4, +# "bits-per-mau": 0, +# "mem-space-name": "cpu-secure-memory-0", +# "endian": 0, +# "max-addr": 0, +# "mem-type": 65568, +# "core-mode-mask-write": 0, +# "core-mode-mask-read": 0, +# "supported-access-options": 0, +# "invariance": 0, +# "num-mem-blocks": 0, +# "min-addr": 0 +# }, +# { +# "mem-space-id": 5, +# "bits-per-mau": 0, +# "mem-space-name": "GDB Registers", +# "endian": 0, +# "max-addr": 0, +# "mem-type": 1, +# "core-mode-mask-write": 0, +# "core-mode-mask-read": 0, +# "supported-access-options": 0, +# "invariance": 0, +# "num-mem-blocks": 0, +# "min-addr": 0 +# } +# ], +# "return-status": 0, +# "num-mem-spaces": 5 +# } +# } +## +{ 'command': 'mcd-qry-mem-spaces', + 'data': { + 'core-uid' : 'uint32', + 'start-index' : 'uint32', + 'num-mem-spaces': 'uint32' }, + 'returns': 'MCDQryMemSpacesResult' } diff --git a/tests/qtest/libmcd-test.c b/tests/qtest/libmcd-test.c index c976eb1bed..9e41a0218f 100644 --- a/tests/qtest/libmcd-test.c +++ b/tests/qtest/libmcd-test.c @@ -258,3 +258,23 @@ MCDCloseCoreResult *qtest_mcd_close_core(QTestState *qts, return unmarshal; } + +MCDQryMemSpacesResult *qtest_mcd_qry_mem_spaces( + QTestState *qts, q_obj_mcd_qry_mem_spaces_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDQryMemSpacesResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_qry_mem_spaces_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-qry-mem-spaces'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDQryMemSpacesResult); + + return unmarshal; +} diff --git a/tests/qtest/libmcd-test.h b/tests/qtest/libmcd-test.h index 323458785e..26f35b8931 100644 --- a/tests/qtest/libmcd-test.h +++ b/tests/qtest/libmcd-test.h @@ -47,4 +47,7 @@ MCDOpenCoreResult *qtest_mcd_open_core(QTestState *qts, MCDCloseCoreResult *qtest_mcd_close_core(QTestState *qts, q_obj_mcd_close_core_arg *args); +MCDQryMemSpacesResult *qtest_mcd_qry_mem_spaces(QTestState *qts, + q_obj_mcd_qry_mem_spaces_arg *args); + #endif /* LIBMCD_TEST_H */ diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c index 8a7e04c5cf..7deca39f93 100644 --- a/tests/qtest/mcd-test.c +++ b/tests/qtest/mcd-test.c @@ -347,6 +347,84 @@ static void test_open_core(void) qtest_quit(qts); } +static void test_qry_core_info(void) +{ + QTestState *qts = qtest_init(QEMU_EXTRA_ARGS); + MCDQryCoresResult *cores_query = open_server_query_cores(qts); + + MCDCoreConInfoList *core_head = cores_query->core_con_info; + for (uint32_t c = 0; c < cores_query->num_cores; c++) { + q_obj_mcd_qry_mem_spaces_arg qry_mem_spaces_args; + q_obj_mcd_close_core_arg close_core_args; + MCDQryMemSpacesResult *qry_mem_spaces_result; + MCDCloseCoreResult *close_core_result; + + MCDCoreConInfo *core_con_info = core_head->value; + q_obj_mcd_open_core_arg open_core_args = { + .core_con_info = core_con_info, + }; + MCDOpenCoreResult *open_core_result = + qtest_mcd_open_core(qts, &open_core_args); + g_assert(open_core_result->return_status == MCD_RET_ACT_NONE); + g_assert(open_core_result->has_core_uid); + + if (verbose) { + fprintf(stderr, "[INFO]\tCore %s #%d\n", + core_con_info->core, + core_con_info->core_id); + } + + qry_mem_spaces_args = (q_obj_mcd_qry_mem_spaces_arg) { + .core_uid = open_core_result->core_uid, + .start_index = 0, + .num_mem_spaces = 0, + }; + + qry_mem_spaces_result = qtest_mcd_qry_mem_spaces(qts, + &qry_mem_spaces_args); + g_assert(qry_mem_spaces_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_mem_spaces_result->has_num_mem_spaces); + g_assert(qry_mem_spaces_result->num_mem_spaces > 0); + + qry_mem_spaces_args.num_mem_spaces = + qry_mem_spaces_result->num_mem_spaces; + qapi_free_MCDQryMemSpacesResult(qry_mem_spaces_result); + qry_mem_spaces_result = qtest_mcd_qry_mem_spaces(qts, + &qry_mem_spaces_args); + g_assert(qry_mem_spaces_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_mem_spaces_result->has_num_mem_spaces); + + if (verbose) { + MCDMemspaceList *ms_head = qry_mem_spaces_result->mem_spaces; + for (uint32_t i = 0; + i < qry_mem_spaces_result->num_mem_spaces; i++) { + MCDMemspace *ms = ms_head->value; + if (verbose) { + fprintf(stderr, "\tMemory Space: %s (#%d)\n" + "\t Type: 0x%x\n", + ms->mem_space_name, + ms->mem_space_id, + ms->mem_type); + } + ms_head = ms_head->next; + } + } + + qapi_free_MCDQryMemSpacesResult(qry_mem_spaces_result); + close_core_args.core_uid = open_core_result->core_uid; + close_core_result = qtest_mcd_close_core(qts, &close_core_args); + g_assert(close_core_result->return_status == MCD_RET_ACT_NONE); + + qapi_free_MCDCloseCoreResult(close_core_result); + qapi_free_MCDOpenCoreResult(open_core_result); + core_head = core_head->next; + } + + qapi_free_MCDQryCoresResult(cores_query); + qtest_mcd_exit(qts); + qtest_quit(qts); +} + int main(int argc, char *argv[]) { char *v_env = getenv("V"); @@ -358,5 +436,6 @@ int main(int argc, char *argv[]) qtest_add_func("mcd/open-server", test_open_server); qtest_add_func("mcd/qry-cores", test_qry_cores); qtest_add_func("mcd/open-core", test_open_core); + qtest_add_func("mcd/qry-core-info", test_qry_core_info); return g_test_run(); } From patchwork Mon Mar 10 15:05:02 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010268 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 22721C282DE for ; Mon, 10 Mar 2025 15:13:29 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1treo2-0002vB-9E; Mon, 10 Mar 2025 11:12:38 -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 1tren6-00028v-LB for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:40 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremx-0007gl-Qr for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:40 -0400 Received: (qmail 30796 invoked by uid 484); 10 Mar 2025 15:11:11 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.013247 secs); 10 Mar 2025 15:11:11 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:11 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann Subject: [PATCH 08/16] gdbstub: Expose GDBRegisterState Date: Mon, 10 Mar 2025 16:05:02 +0100 Message-Id: <20250310150510.200607-9-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, T_SPF_TEMPERROR=0.01 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Signed-off-by: Mario Fleischmann --- gdbstub/gdbstub.c | 7 ------- include/exec/gdbstub.h | 8 +++++++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 282e13e163..8166510f06 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -48,13 +48,6 @@ #include "internals.h" -typedef struct GDBRegisterState { - int base_reg; - gdb_get_reg_cb get_reg; - gdb_set_reg_cb set_reg; - const GDBFeature *feature; -} GDBRegisterState; - GDBState gdbserver_state; void gdb_init_gdbserver_state(void) diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 0675b0b646..c2941e5c10 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -16,11 +16,17 @@ typedef struct GDBFeatureBuilder { int base_reg; } GDBFeatureBuilder; - /* Get or set a register. Returns the size of the register. */ typedef int (*gdb_get_reg_cb)(CPUState *cpu, GByteArray *buf, int reg); typedef int (*gdb_set_reg_cb)(CPUState *cpu, uint8_t *buf, int reg); +typedef struct GDBRegisterState { + int base_reg; + gdb_get_reg_cb get_reg; + gdb_set_reg_cb set_reg; + const GDBFeature *feature; +} GDBRegisterState; + /** * gdb_init_cpu(): Initialize the CPU for gdbstub. * @cpu: The CPU to be initialized. From patchwork Mon Mar 10 15:05:03 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010271 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 61930C282DE for ; Mon, 10 Mar 2025 15:15:28 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1trens-0002Z1-Kx; Mon, 10 Mar 2025 11:12:28 -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 1trenE-0002D6-4V for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:58 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tren9-0007h3-TT for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:47 -0400 Received: (qmail 30817 invoked by uid 484); 10 Mar 2025 15:11:11 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.013285 secs); 10 Mar 2025 15:11:11 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:11 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake , Fabiano Rosas , Laurent Vivier , Paolo Bonzini Subject: [PATCH 09/16] mcd: Implement register query Date: Mon, 10 Mar 2025 16:05:03 +0100 Message-Id: <20250310150510.200607-10-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Directly map MCD register groups to GDB features lists Signed-off-by: Mario Fleischmann --- mcd/libmcd_qapi.c | 48 +++++++ mcd/libmcd_qapi.h | 8 ++ mcd/mcdserver.c | 237 ++++++++++++++++++++++++++++-- mcd/mcdstub_qapi.c | 93 ++++++++++++ qapi/mcd.json | 296 ++++++++++++++++++++++++++++++++++++++ tests/qtest/libmcd-test.c | 40 ++++++ tests/qtest/libmcd-test.h | 6 + tests/qtest/mcd-test.c | 85 +++++++++++ 8 files changed, 803 insertions(+), 10 deletions(-) diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c index 0421152705..99177b2fd2 100644 --- a/mcd/libmcd_qapi.c +++ b/mcd/libmcd_qapi.c @@ -147,3 +147,51 @@ MCDMemspace *marshal_mcd_memspace(const mcd_memspace_st *mem_space) return marshal; } + +MCDRegisterGroup *marshal_mcd_register_group( + const mcd_register_group_st *reg_group) +{ + MCDRegisterGroup *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDRegisterGroup) { + .reg_group_id = reg_group->reg_group_id, + .reg_group_name = g_strdup(reg_group->reg_group_name), + .n_registers = reg_group->n_registers, + }; + + return marshal; +} + +MCDAddr *marshal_mcd_addr(const mcd_addr_st *addr) +{ + MCDAddr *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDAddr) { + .address = addr->address, + .mem_space_id = addr->mem_space_id, + .addr_space_id = addr->addr_space_id, + .addr_space_type = addr->addr_space_type, + }; + + return marshal; +} + +MCDRegisterInfo *marshal_mcd_register_info(const mcd_register_info_st *reg_info) +{ + MCDRegisterInfo *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDRegisterInfo) { + .addr = marshal_mcd_addr(®_info->addr), + .reg_group_id = reg_info->reg_group_id, + .regname = g_strdup(reg_info->regname), + .regsize = reg_info->regsize, + .core_mode_mask_read = reg_info->core_mode_mask_read, + .core_mode_mask_write = reg_info->core_mode_mask_write, + .side_effects_read = reg_info->has_side_effects_read, + .side_effects_write = reg_info->has_side_effects_write, + .reg_type = reg_info->reg_type, + .hw_thread_id = reg_info->hw_thread_id, + }; + + return marshal; +} diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h index 7e874dec25..edcc6d0b7c 100644 --- a/mcd/libmcd_qapi.h +++ b/mcd/libmcd_qapi.h @@ -27,6 +27,14 @@ MCDCoreConInfo *marshal_mcd_core_con_info(const mcd_core_con_info_st *con_info); MCDMemspace *marshal_mcd_memspace(const mcd_memspace_st *mem_space); +MCDRegisterGroup *marshal_mcd_register_group( + const mcd_register_group_st *reg_group); + +MCDAddr *marshal_mcd_addr(const mcd_addr_st *addr); + +MCDRegisterInfo *marshal_mcd_register_info( + const mcd_register_info_st *reg_info); + mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version); mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info); diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index f924bf3799..f0cda23981 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -13,6 +13,7 @@ #include "mcd_api.h" #include "hw/boards.h" #include "exec/tswap.h" +#include "exec/gdbstub.h" /* Custom memory space type */ static const mcd_mem_type_et MCD_MEM_SPACE_IS_SECURE = 0x00010000; @@ -55,12 +56,14 @@ static const mcd_error_info_st MCD_ERROR_NONE = { /** * struct mcdcore_state - State of a core. * - * @last_error: Error info of most recent executed core-related function. - * @custom_error: Reserves memory for custom MCD errors. - * @info: Core connection information. - * @open_core: Open core instance as allocated in mcd_open_core_f(). - * @cpu: QEMU's internal CPU handle. - * @memory_spaces: Memory spaces as queried by mcd_qry_mem_spaces_f(). + * @last_error: Error info of most recent executed core-related function. + * @custom_error: Reserves memory for custom MCD errors. + * @info: Core connection information. + * @open_core: Open core instance as allocated in mcd_open_core_f(). + * @cpu: QEMU's internal CPU handle. + * @memory_spaces: Memory spaces as queried by mcd_qry_mem_spaces_f(). + * @register_groups: Register groups as queried by mcd_qry_reg_groups_f(). + * @registers: Registers as queried by mcd_qry_reg_map_f(). * * MCD is mainly being used on the core level: * After the initial query functions, a core connection is opened in @@ -77,6 +80,8 @@ typedef struct mcdcore_state { mcd_core_st *open_core; CPUState *cpu; GArray *memory_spaces; + GArray *register_groups; + GArray *registers; } mcdcore_state; /** @@ -267,6 +272,10 @@ mcd_return_et mcd_open_server_f(const char *system_key, .open_core = NULL, .cpu = cpu, .memory_spaces = g_array_new(false, true, sizeof(mcd_memspace_st)), + .register_groups = g_array_new(false, true, + sizeof(mcd_register_group_st)), + .registers = g_array_new(false, true, + sizeof(mcd_register_info_st)), }; pstrcpy(c.info.core, MCD_UNIQUE_NAME_LEN, cpu_model); g_array_append_val(g_server_state.cores, c); @@ -306,6 +315,10 @@ mcd_return_et mcd_close_server_f(const mcd_server_st *server) if (c->open_core) { mcd_close_core_f(c->open_core); } + + g_array_free(c->memory_spaces, true); + g_array_free(c->register_groups, true); + g_array_free(c->registers, true); } g_array_free(g_server_state.cores, true); @@ -538,6 +551,59 @@ static mcd_return_et query_memspaces(mcdcore_state *core_state) return MCD_RET_ACT_NONE; } +static mcd_return_et query_registers(mcdcore_state *core_state) +{ + GArray *gdb_regs = core_state->cpu->gdb_regs; + assert(gdb_regs); + + g_array_set_size(core_state->register_groups, 0); + g_array_set_size(core_state->registers, 0); + + for (int feature_id = 0; feature_id < gdb_regs->len; feature_id++) { + GDBRegisterState *f = &g_array_index(gdb_regs, GDBRegisterState, + feature_id); + /* register group ID 0 is reserved */ + uint32_t group_id = feature_id + 1; + uint32_t num_regs = 0; + + GByteArray *mem_buf = g_byte_array_new(); + for (int i = 0; i < f->feature->num_regs; i++) { + const char *name = f->feature->regs[i]; + if (name) { + int reg_id = f->base_reg + i; + int bitsize = gdb_read_register(core_state->cpu, + mem_buf, reg_id) * 8; + mcd_register_info_st r = { + .addr = { + .address = (uint64_t) reg_id, + /* memory space "GDB Registers" */ + .mem_space_id = core_state->memory_spaces->len, + .addr_space_type = MCD_NOTUSED_ID, + }, + .reg_group_id = group_id, + .regsize = (uint32_t) bitsize, + .reg_type = MCD_REG_TYPE_SIMPLE, + /* ID 0 reserved */ + .hw_thread_id = core_state->info.core_id + 1, + }; + strncpy(r.regname, name, MCD_REG_NAME_LEN - 1); + g_array_append_val(core_state->registers, r); + num_regs++; + } + } + g_byte_array_free(mem_buf, true); + + mcd_register_group_st rg = { + .reg_group_id = group_id, + .n_registers = num_regs, + }; + strncpy(rg.reg_group_name, f->feature->name, MCD_REG_NAME_LEN - 1); + g_array_append_val(core_state->register_groups, rg); + } + + return MCD_RET_ACT_NONE; +} + mcd_return_et mcd_open_core_f(const mcd_core_con_info_st *core_con_info, mcd_core_st **core) { @@ -583,6 +649,10 @@ mcd_return_et mcd_open_core_f(const mcd_core_con_info_st *core_con_info, return g_server_state.last_error->return_status; } + if (query_registers(core_state) != MCD_RET_ACT_NONE) { + return g_server_state.last_error->return_status; + } + *core = g_malloc(sizeof(mcd_core_st)); info = g_malloc(sizeof(mcd_core_con_info_st)); *info = *core_con_info; @@ -626,6 +696,8 @@ mcd_return_et mcd_close_core_f(const mcd_core_st *core) core_state->open_core = NULL; core_state->cpu = NULL; g_array_set_size(core_state->memory_spaces, 0); + g_array_set_size(core_state->register_groups, 0); + g_array_set_size(core_state->registers, 0); g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; @@ -771,16 +843,161 @@ mcd_return_et mcd_qry_reg_groups_f(const mcd_core_st *core, uint32_t *num_reg_groups, mcd_register_group_st *reg_groups) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + uint32_t i; + mcdcore_state *core_state; + + if (!core || !num_reg_groups) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + g_assert(core_state->register_groups); + + if (core_state->register_groups->len == 0) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_NO_REG_GROUPS, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (*num_reg_groups == 0) { + *num_reg_groups = core_state->register_groups->len; + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; + } + + if (start_index >= core_state->register_groups->len) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "start_index exceeds the number of register groups", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (!reg_groups) { + core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return core_state->last_error->return_status; + } + + for (i = 0; i < *num_reg_groups && + start_index + i < core_state->register_groups->len; i++) { + + reg_groups[i] = g_array_index(core_state->register_groups, + mcd_register_group_st, start_index + i); + } + + *num_reg_groups = i; + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_qry_reg_map_f(const mcd_core_st *core, uint32_t reg_group_id, uint32_t start_index, uint32_t *num_regs, mcd_register_info_st *reg_info) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + bool query_all_regs = reg_group_id == 0; + bool query_num_only; + + if (!core || !num_regs) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + query_num_only = *num_regs == 0; + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (core_state->register_groups->len == 0 || + reg_group_id > core_state->register_groups->len) { + + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_REG_GROUP_ID, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + /* + * Depending on reg_group_id, start_index refers either to the total list of + * register or a single register group. + */ + + if (query_all_regs) { + if (start_index >= core_state->registers->len) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "start_index exceeds the number of registers", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + }; + + if (*num_regs == 0) { + *num_regs = core_state->registers->len; + } else if (*num_regs > core_state->registers->len - start_index) { + *num_regs = core_state->registers->len - start_index; + } + } else { + mcd_register_group_st *rg = &g_array_index(core_state->register_groups, + mcd_register_group_st, reg_group_id - 1); + + if (start_index > rg->n_registers) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "start_index exceeds the number of registers", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (*num_regs == 0) { + *num_regs = rg->n_registers; + } else if (*num_regs > rg->n_registers - start_index) { + *num_regs = rg->n_registers - start_index; + } + + for (uint32_t rg_id = 0; rg_id < reg_group_id - 1; rg_id++) { + mcd_register_group_st *prev_rg = &g_array_index( + core_state->register_groups, mcd_register_group_st, rg_id); + start_index += prev_rg->n_registers; + } + } + + if (!query_num_only) { + for (uint32_t i = 0; i < *num_regs; i++) { + reg_info[i] = g_array_index( + core_state->registers, mcd_register_info_st, start_index + i); + } + } + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_qry_reg_compound_f(const mcd_core_st *core, diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index 437d2c2e3e..6aa72b025c 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -412,3 +412,96 @@ MCDQryMemSpacesResult *qmp_mcd_qry_mem_spaces(uint32_t core_uid, g_stub_state.on_error_ask_server = true; return result; } + +MCDQryRegGroupsResult *qmp_mcd_qry_reg_groups(uint32_t core_uid, + uint32_t start_index, + uint32_t num_reg_groups, + Error **errp) +{ + MCDRegisterGroupList **tailp; + MCDRegisterGroup *rg; + mcd_register_group_st *reg_groups = NULL; + bool query_num_only = num_reg_groups == 0; + MCDQryRegGroupsResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + if (!query_num_only) { + reg_groups = g_malloc0(num_reg_groups * sizeof(*reg_groups)); + } + + result->return_status = mcd_qry_reg_groups_f(core, start_index, + &num_reg_groups, reg_groups); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_num_reg_groups = true; + result->num_reg_groups = num_reg_groups; + if (!query_num_only) { + result->has_reg_groups = true; + tailp = &(result->reg_groups); + for (uint32_t i = 0; i < num_reg_groups; i++) { + rg = marshal_mcd_register_group(reg_groups + i); + QAPI_LIST_APPEND(tailp, rg); + } + } + } + + if (!query_num_only) { + g_free(reg_groups); + } + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDQryRegMapResult *qmp_mcd_qry_reg_map(uint32_t core_uid, + uint32_t reg_group_id, + uint32_t start_index, uint32_t num_regs, + Error **errp) +{ + MCDRegisterInfoList **tailp; + MCDRegisterInfo *r; + mcd_register_info_st *regs = NULL; + bool query_num_only = num_regs == 0; + MCDQryRegMapResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + if (!query_num_only) { + regs = g_malloc0(num_regs * sizeof(*regs)); + } + + result->return_status = mcd_qry_reg_map_f(core, reg_group_id, + start_index, &num_regs, + regs); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_num_regs = true; + result->num_regs = num_regs; + if (!query_num_only) { + result->has_reg_info = true; + tailp = &(result->reg_info); + for (uint32_t i = 0; i < num_regs; i++) { + r = marshal_mcd_register_info(regs + i); + QAPI_LIST_APPEND(tailp, r); + } + } + } + + if (!query_num_only) { + g_free(regs); + } + + g_stub_state.on_error_ask_server = true; + return result; +} diff --git a/qapi/mcd.json b/qapi/mcd.json index 214933e279..936016de45 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -215,6 +215,98 @@ 'core-mode-mask-write' : 'uint32' } } +## +# @MCDRegisterGroup: +# +# Structure type containing register group information. +# +# @reg-group-id: Contains the ID of this register group. A register group ID +# must be unique within the scope of a target core. ID '0' is +# reserved. +# @reg-group-name: The name of a register group. A register group name cannot +# be longer than MCD_REG_NAME_LEN characters (use +# representative names). +# @n-registers: Number of registers part of this group. +# +# Since: 9.1 +## +{ 'struct': 'MCDRegisterGroup', + 'data': { + 'reg-group-id' : 'uint32', + 'reg-group-name': 'str', + 'n-registers' : 'uint32' } } + + +## +# @MCDAddr: +# +# Structure type containing a completely resolved logical or physical memory +# address. +# +# @address: Address value within a memory space, expressed in bytes. +# @mem-space-id: ID of the memory space associated with this address, e.g. a +# program memory, a data memory or registers . +# @addr-space-id: ID of the address space in which this address is valid. +# @addr-space-type: Type of the address space in which this address is valid. +# +# Since: 9.1 +## +{ 'struct': 'MCDAddr', + 'data': { + 'address' : 'uint64', + 'mem-space-id' : 'uint32', + 'addr-space-id' : 'uint32', + 'addr-space-type': 'uint32' } } + + +## +# @MCDRegisterInfo: +# +# Structure type containing register information for a single register. +# +# @addr: Either the address of a memory mapped register or +# the register address in a dedicated +# "register memory space" +# @reg-group-id: ID of the group this register belongs to. +# @regname: The name of a register. A register name cannot be +# longer than MCD_REG_NAME_LEN characters (use +# representative names). +# @regsize: Register size in bits. +# @core-mode-mask-read: Mask of core modes for which read accesses are +# impossible. A set bit indicates that read accesses +# are denied in this mode. Bit 0 represents core mode +# '1', bit 31 represents core mode 32. Overrides +# @core-mode-mask-read of the corresponding +# mcd_memspace_st. +# @core-mode-mask-write: Mask of core modes for which write accesses are +# impossible. A set bit indicates that write accesses +# are denied in this mode. Bit 0 represents core mode +# '1', bit 31 represents core mode '32'. Overrides +# @core-mode-mask-write of the corresponding +# mcd_memspace_st. +# @side-effects-read: Reading this register can trigger side effects. +# @side-effects-write: Writing this register can trigger side effects. +# @reg-type: Register type (simple, compound or partial) +# @hw-thread-id: Hardware thread ID this register belongs to. The ID +# must be set to '0' if the register is not assigned +# to a hardware thread. +# +# Since: 9.1 +## +{ 'struct': 'MCDRegisterInfo', + 'data': { + 'addr' : 'MCDAddr', + 'reg-group-id' : 'uint32', + 'regname' : 'str', + 'regsize' : 'uint32', + 'core-mode-mask-read' : 'uint32', + 'core-mode-mask-write': 'uint32', + 'side-effects-read' : 'bool', + 'side-effects-write' : 'bool', + 'reg-type' : 'uint32', + 'hw-thread-id' : 'uint32' } } + + ## # == Target Initialization API ## @@ -1077,3 +1169,207 @@ 'start-index' : 'uint32', 'num-mem-spaces': 'uint32' }, 'returns': 'MCDQryMemSpacesResult' } + + +## +# @MCDQryRegGroupsResult: +# +# Return value of @mcd-qry-reg-groups. +# +# @return-status: Return code. +# @num-reg-groups: Number of returned register groups. In case the input value +# of @num-reg-groups is '0', this is the number of all +# available register groups for the selected core. +# @reg-groups: Register group information. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryRegGroupsResult', + 'data': { + 'return-status' : 'uint32', + '*num-reg-groups': 'uint32', + '*reg-groups' : [ 'MCDRegisterGroup' ] }} + + +## +# @mcd-qry-reg-groups: +# +# Function querying the register groups defined for a particular component. +# +# @core-uid: Unique ID of the core the calling function addresses. +# @start-index: Start index of the requested register groups. This refers +# to an internal list of the target side implementation. +# @num-reg-groups: Number of register groups, information is requested of. If +# it is set to '0', no register groups information is returned +# but the number of all available register groups for the +# selected core. +# +# Returns: @MCDQryRegGroupsResult +# +# Since: 9.1 +## +{ 'command': 'mcd-qry-reg-groups', + 'data': { + 'core-uid' : 'uint32', + 'start-index' : 'uint32', + 'num-reg-groups': 'uint32' }, + 'returns': 'MCDQryRegGroupsResult' } + + +## +# @MCDQryRegMapResult: +# +# Return value of @mcd-qry-reg-map. +# +# @return-status: Return code. +# @num-regs: Number of returned registers. In case the input value of +# @num-regs is '0', this is the number of all available register +# for the selected register group. +# @reg-info: Register information. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryRegMapResult', + 'data': { + 'return-status': 'uint32', + '*num-regs' : 'uint32', + '*reg-info' : [ 'MCDRegisterInfo' ] }} + +## +# @mcd-qry-reg-map: +# +# Function querying the register information of a particular register group. +# +# @core-uid: Unique ID of the core the calling function addresses. +# @reg-group-id: ID of the register group detailed register information is +# requested for. +# @start-index: Start index of the requested registers. This refers to an +# internal list of the target side implementation. +# @num-regs: Number of registers, information is requested of. If it +# is set to '0', no register information is returned but the +# number of all available registers within for the selected +# register group. +# +# Returns: @MCDQryRegMapResult +# +# Since: 9.1 +# +# .. qmp-example:: +# +# -> { "execute": "mcd-qry-reg-groups", +# "arguments": { "core-uid": 1, +# "start-index": 0, +# "num-reg-groups": 3 } } +# <- { +# "return": { +# "reg-groups": [ +# { +# "reg-group-id": 1, +# "reg-group-name": "org.gnu.gdb.aarch64.core", +# "n-registers": 34 +# }, +# { +# "reg-group-id": 2, +# "reg-group-name": "org.gnu.gdb.aarch64.fpu", +# "n-registers": 34 +# }, +# { +# "reg-group-id": 3, +# "reg-group-name": "org.qemu.gdb.arm.sys.regs", +# "n-registers": 210 +# } +# ], +# "return-status": 0, +# "num-reg-groups": 3 +# } +# } +# -> { "execute": "mcd-qry-reg-map", +# "arguments": { "core-uid": 1, +# "reg-group-id": 1, +# "start-index": 0, +# "num-regs": 34 } } +# <- { +# "return": { +# "reg-info": [ +# { +# "reg-group-id": 1, +# "regname": "x0", +# "side-effects-read": false, +# "addr": { +# "mem-space-id": 5, +# "addr-space-id": 0, +# "address": 0, +# "addr-space-type": 0 +# }, +# "reg-type": 0, +# "core-mode-mask-write": 0, +# "core-mode-mask-read": 0, +# "regsize": 64, +# "hw-thread-id": 0, +# "side-effects-write": false +# }, +# { +# "reg-group-id": 1, +# "regname": "x1", +# "side-effects-read": false, +# "addr": { +# "mem-space-id": 5, +# "addr-space-id": 0, +# "address": 1, +# "addr-space-type": 0 +# }, +# "reg-type": 0, +# "core-mode-mask-write": 0, +# "core-mode-mask-read": 0, +# "regsize": 64, +# "hw-thread-id": 0, +# "side-effects-write": false +# }, +# { +# "reg-group-id": 1, +# "regname": "x2", +# "side-effects-read": false, +# "addr": { +# "mem-space-id": 5, +# "addr-space-id": 0, +# "address": 2, +# "addr-space-type": 0 +# }, +# "reg-type": 0, +# "core-mode-mask-write": 0, +# "core-mode-mask-read": 0, +# "regsize": 64, +# "hw-thread-id": 0, +# "side-effects-write": false +# }, +# { +# "reg-group-id": 1, +# "regname": "x3", +# "side-effects-read": false, +# "addr": { +# "mem-space-id": 5, +# "addr-space-id": 0, +# "address": 3, +# "addr-space-type": 0 +# }, +# "reg-type": 0, +# "core-mode-mask-write": 0, +# "core-mode-mask-read": 0, +# "regsize": 64, +# "hw-thread-id": 0, +# "side-effects-write": false +# }, +# ... +# ], +# "return-status": 0, +# "num-regs": 34 +# } +# } +## +{ 'command': 'mcd-qry-reg-map', + 'data': { + 'core-uid': 'uint32', + 'reg-group-id': 'uint32', + 'start-index': 'uint32', + 'num-regs': 'uint32' }, + 'returns': 'MCDQryRegMapResult' } diff --git a/tests/qtest/libmcd-test.c b/tests/qtest/libmcd-test.c index 9e41a0218f..82a39366b2 100644 --- a/tests/qtest/libmcd-test.c +++ b/tests/qtest/libmcd-test.c @@ -278,3 +278,43 @@ MCDQryMemSpacesResult *qtest_mcd_qry_mem_spaces( return unmarshal; } + +MCDQryRegGroupsResult *qtest_mcd_qry_reg_groups( + QTestState *qts, q_obj_mcd_qry_reg_groups_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDQryRegGroupsResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_qry_reg_groups_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-qry-reg-groups'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDQryRegGroupsResult); + + return unmarshal; +} + +MCDQryRegMapResult *qtest_mcd_qry_reg_map(QTestState *qts, + q_obj_mcd_qry_reg_map_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDQryRegMapResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_qry_reg_map_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-qry-reg-map'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDQryRegMapResult); + + return unmarshal; +} diff --git a/tests/qtest/libmcd-test.h b/tests/qtest/libmcd-test.h index 26f35b8931..266b6fe854 100644 --- a/tests/qtest/libmcd-test.h +++ b/tests/qtest/libmcd-test.h @@ -50,4 +50,10 @@ MCDCloseCoreResult *qtest_mcd_close_core(QTestState *qts, MCDQryMemSpacesResult *qtest_mcd_qry_mem_spaces(QTestState *qts, q_obj_mcd_qry_mem_spaces_arg *args); +MCDQryRegGroupsResult *qtest_mcd_qry_reg_groups(QTestState *qts, + q_obj_mcd_qry_reg_groups_arg *args); + +MCDQryRegMapResult *qtest_mcd_qry_reg_map(QTestState *qts, + q_obj_mcd_qry_reg_map_arg *args); + #endif /* LIBMCD_TEST_H */ diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c index 7deca39f93..820408a9a9 100644 --- a/tests/qtest/mcd-test.c +++ b/tests/qtest/mcd-test.c @@ -355,8 +355,12 @@ static void test_qry_core_info(void) MCDCoreConInfoList *core_head = cores_query->core_con_info; for (uint32_t c = 0; c < cores_query->num_cores; c++) { q_obj_mcd_qry_mem_spaces_arg qry_mem_spaces_args; + q_obj_mcd_qry_reg_groups_arg qry_reg_groups_args; + q_obj_mcd_qry_reg_map_arg qry_reg_map_args; q_obj_mcd_close_core_arg close_core_args; MCDQryMemSpacesResult *qry_mem_spaces_result; + MCDQryRegGroupsResult *qry_reg_groups_result; + MCDQryRegMapResult *qry_reg_map_result; MCDCloseCoreResult *close_core_result; MCDCoreConInfo *core_con_info = core_head->value; @@ -374,6 +378,8 @@ static void test_qry_core_info(void) core_con_info->core_id); } + /* Memory Space Query */ + qry_mem_spaces_args = (q_obj_mcd_qry_mem_spaces_arg) { .core_uid = open_core_result->core_uid, .start_index = 0, @@ -411,6 +417,85 @@ static void test_qry_core_info(void) } qapi_free_MCDQryMemSpacesResult(qry_mem_spaces_result); + + /* Register Query */ + + qry_reg_groups_args = (q_obj_mcd_qry_reg_groups_arg) { + .core_uid = open_core_result->core_uid, + .start_index = 0, + .num_reg_groups = 0, /* query only number of register groups */ + }; + + qry_reg_groups_result = qtest_mcd_qry_reg_groups(qts, + &qry_reg_groups_args); + g_assert(qry_reg_groups_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_reg_groups_result->has_num_reg_groups); + + if (qry_reg_groups_result->num_reg_groups == 0) { + fprintf(stderr, "[WARN]\tTNo register groups!\n"); + } + + qry_reg_groups_args.num_reg_groups = + qry_reg_groups_result->num_reg_groups; + + qapi_free_MCDQryRegGroupsResult(qry_reg_groups_result); + qry_reg_groups_result = qtest_mcd_qry_reg_groups(qts, + &qry_reg_groups_args); + g_assert(qry_reg_groups_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_reg_groups_result->has_num_reg_groups); + + if (verbose) { + MCDRegisterGroupList *rg_head = qry_reg_groups_result->reg_groups; + for (uint32_t i = 0; + i < qry_reg_groups_result->num_reg_groups; i++) { + MCDRegisterGroup *rg = rg_head->value; + if (verbose) { + fprintf(stderr, "\tRegister Group: %s (#%d) with " + "%d registers\n", + rg->reg_group_name, + rg->reg_group_id, + rg->n_registers); + } + rg_head = rg_head->next; + } + } + + qapi_free_MCDQryRegGroupsResult(qry_reg_groups_result); + + qry_reg_map_args = (q_obj_mcd_qry_reg_map_arg) { + .core_uid = open_core_result->core_uid, + .reg_group_id = 0, + .start_index = 0, + .num_regs = 0, /* query only number of registers */ + }; + + qry_reg_map_result = qtest_mcd_qry_reg_map(qts, &qry_reg_map_args); + g_assert(qry_reg_map_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_reg_map_result->has_num_regs); + + if (verbose) { + fprintf(stderr, "\t%d registers found\n", + qry_reg_map_result->num_regs); + } + + qry_reg_map_args.num_regs = qry_reg_map_result->num_regs; + qapi_free_MCDQryRegMapResult(qry_reg_map_result); + + qry_reg_map_result = qtest_mcd_qry_reg_map(qts, &qry_reg_map_args); + g_assert(qry_reg_map_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_reg_map_result->has_num_regs); + if (verbose) { + MCDRegisterInfoList *r_head = qry_reg_map_result->reg_info; + for (uint32_t i = 0; + i < qry_reg_map_result->num_regs; i++) { + MCDRegisterInfo *r = r_head->value; + fprintf(stderr, "\tRegister: %s (#%lx)\n", + r->regname, r->addr->address); + r_head = r_head->next; + } + } + qapi_free_MCDQryRegMapResult(qry_reg_map_result); + close_core_args.core_uid = open_core_result->core_uid; close_core_result = qtest_mcd_close_core(qts, &close_core_args); g_assert(close_core_result->return_status == MCD_RET_ACT_NONE); From patchwork Mon Mar 10 15:05:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010270 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C4411C28B2E for ; Mon, 10 Mar 2025 15:14:22 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tren3-00024a-LI; Mon, 10 Mar 2025 11:11:37 -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 1tremy-00020g-Ag for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:32 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremu-0007hV-Nq for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:32 -0400 Received: (qmail 30843 invoked by uid 484); 10 Mar 2025 15:11:12 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.013133 secs); 10 Mar 2025 15:11:12 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:11 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake Subject: [PATCH 10/16] mcd: Implement runstate control Date: Mon, 10 Mar 2025 16:05:04 +0100 Message-Id: <20250310150510.200607-11-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Currently, only global stop is implemented Signed-off-by: Mario Fleischmann --- mcd/mcdserver.c | 74 +++++++++++++++++++++++++++++++-- mcd/mcdstub_qapi.c | 52 +++++++++++++++++++++++ qapi/mcd.json | 100 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+), 4 deletions(-) diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index f0cda23981..9e46ea5fa5 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -14,6 +14,8 @@ #include "hw/boards.h" #include "exec/tswap.h" #include "exec/gdbstub.h" +#include "hw/core/cpu.h" +#include "system/runstate.h" /* Custom memory space type */ static const mcd_mem_type_et MCD_MEM_SPACE_IS_SECURE = 0x00010000; @@ -1087,13 +1089,53 @@ mcd_return_et mcd_execute_txlist_f(const mcd_core_st *core, mcd_return_et mcd_run_f(const mcd_core_st *core, bool global) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + + if (g_server_state.cores->len > 1 && global) { + vm_start(); + g_server_state.last_error = &MCD_ERROR_NONE; + return g_server_state.last_error->return_status; + } + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (!runstate_needs_reset() && !runstate_is_running() && + !vm_prepare_start(false)) { + cpu_resume(core_state->cpu); + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); + } + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_stop_f(const mcd_core_st *core, bool global) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + if (g_server_state.cores->len > 1 && !global) { + g_server_state.custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_FN_UNIMPLEMENTED, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "core-specific stop not implemented", + }; + g_server_state.last_error = &g_server_state.custom_error; + return g_server_state.last_error->return_status; + } + + if (runstate_is_running()) { + vm_stop(RUN_STATE_DEBUG); + } + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } @@ -1120,7 +1162,31 @@ mcd_return_et mcd_step_f(const mcd_core_st *core, bool global, mcd_return_et mcd_set_global_f(const mcd_core_st *core, bool enable) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + mcdcore_state *core_state; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (!enable) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_GENERAL, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "global stop activities cannot be disabled", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index 6aa72b025c..635f95181b 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -505,3 +505,55 @@ MCDQryRegMapResult *qmp_mcd_qry_reg_map(uint32_t core_uid, g_stub_state.on_error_ask_server = true; return result; } + +MCDRunResult *qmp_mcd_run(uint32_t core_uid, bool global, Error **errp) +{ + MCDRunResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_run_f(core, global); + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDStopResult *qmp_mcd_stop(uint32_t core_uid, bool global, Error **errp) +{ + MCDStopResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_stop_f(core, global); + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDSetGlobalResult *qmp_mcd_set_global(uint32_t core_uid, bool enable, + Error **errp) +{ + MCDSetGlobalResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_set_global_f(core, enable); + + g_stub_state.on_error_ask_server = true; + return result; +} diff --git a/qapi/mcd.json b/qapi/mcd.json index 936016de45..c8b82e7f82 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -1373,3 +1373,103 @@ 'start-index': 'uint32', 'num-regs': 'uint32' }, 'returns': 'MCDQryRegMapResult' } + + +## +# == Target Execution Control API +## + + +## +# @MCDRunResult: +# +# Return value of @MCDRunResult. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDRunResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-run: +# +# Function starting execution on a particular core. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# @global: Set to "TRUE" if all cores of a system shall start execution. +# Otherwise, starting execution of selected core only. +# +# Returns: @MCDRunResult +# +# Since: 9.1 +## +{ 'command': 'mcd-run', + 'data': { + 'core-uid': 'uint32', + 'global' : 'bool' }, + 'returns': 'MCDRunResult' } + + +## +# @MCDStopResult: +# +# Return value of @mcd-stop. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDStopResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-stop: +# +# Function stopping execution on a particular core. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# @global: Set to "TRUE" if all cores of a system shall stop execution. +# Otherwise, stopping execution of selected core only. +# +# Returns: @MCDStopResult +# +# Since: 9.1 +## +{ 'command': 'mcd-stop', + 'data': { + 'core-uid': 'uint32', + 'global' : 'bool' }, + 'returns': 'MCDStopResult' } + +## +# @MCDSetGlobalResult: +# +# Return value of @mcd-set-global. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDSetGlobalResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-set-global: +# +# Function enabling/disabling global stop and run activities on this core. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# @enable: Set to "TRUE" if this core should perform global run or stop +# activities. +# +# Returns: @MCDSetGlobalResult +# +# Since: 9.1 +## +{ 'command': 'mcd-set-global', + 'data': { + 'core-uid': 'uint32', + 'enable' : 'bool' }, + 'returns': 'MCDSetGlobalResult' } From patchwork Mon Mar 10 15:05:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010298 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C9F72C28B2E for ; Mon, 10 Mar 2025 15:18:40 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1trenW-0002GM-Ea; Mon, 10 Mar 2025 11:12:06 -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 1tren3-00026Z-Qo for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:37 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremy-0007hx-Do for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:37 -0400 Received: (qmail 30868 invoked by uid 484); 10 Mar 2025 15:11:12 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.012867 secs); 10 Mar 2025 15:11:12 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:12 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake , Fabiano Rosas , Laurent Vivier , Paolo Bonzini Subject: [PATCH 11/16] mcd test: Implement core state query Date: Mon, 10 Mar 2025 16:05:05 +0100 Message-Id: <20250310150510.200607-12-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Depending on the VM and CPU state, core states can be queried: * MCD_CORE_STATE_DEBUG: VM halted or CPU artifically stopped * MCD_CORE_STATE_RUNNING: VM and CPU running * MCD_CORE_STATE_HALTED: CPU suspended Signed-off-by: Mario Fleischmann --- mcd/libmcd_qapi.c | 16 +++++ mcd/libmcd_qapi.h | 2 + mcd/mcdserver.c | 48 ++++++++++++++- mcd/mcdstub_qapi.c | 21 +++++++ qapi/mcd.json | 55 +++++++++++++++++ tests/qtest/libmcd-test.c | 59 +++++++++++++++++++ tests/qtest/libmcd-test.h | 9 +++ tests/qtest/mcd-test.c | 120 +++++++++++++++++++++++++++++++++++++- 8 files changed, 328 insertions(+), 2 deletions(-) diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c index 99177b2fd2..44fc9bd6b4 100644 --- a/mcd/libmcd_qapi.c +++ b/mcd/libmcd_qapi.c @@ -195,3 +195,19 @@ MCDRegisterInfo *marshal_mcd_register_info(const mcd_register_info_st *reg_info) return marshal; } + +MCDCoreState *marshal_mcd_core_state(const mcd_core_state_st *state) +{ + MCDCoreState *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDCoreState) { + .state = state->state, + .event = state->event, + .hw_thread_id = state->hw_thread_id, + .trig_id = state->trig_id, + .stop_str = g_strdup(state->stop_str), + .info_str = g_strdup(state->info_str), + }; + + return marshal; +} diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h index edcc6d0b7c..7d68d60f02 100644 --- a/mcd/libmcd_qapi.h +++ b/mcd/libmcd_qapi.h @@ -35,6 +35,8 @@ MCDAddr *marshal_mcd_addr(const mcd_addr_st *addr); MCDRegisterInfo *marshal_mcd_register_info( const mcd_register_info_st *reg_info); +MCDCoreState *marshal_mcd_core_state(const mcd_core_state_st *state); + mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version); mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info); diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index 9e46ea5fa5..116fbfaa30 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -16,6 +16,7 @@ #include "exec/gdbstub.h" #include "hw/core/cpu.h" #include "system/runstate.h" +#include "system/hw_accel.h" /* Custom memory space type */ static const mcd_mem_type_et MCD_MEM_SPACE_IS_SECURE = 0x00010000; @@ -1192,7 +1193,52 @@ mcd_return_et mcd_set_global_f(const mcd_core_st *core, bool enable) mcd_return_et mcd_qry_state_f(const mcd_core_st *core, mcd_core_state_st *state) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + mcdcore_state *core_state; + RunState rs; + + if (!core || !state) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + *state = (mcd_core_state_st) { + .stop_str = "", + .info_str = "", + }; + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + cpu_synchronize_state(core_state->cpu); + rs = runstate_get(); + switch (rs) { + case RUN_STATE_PRELAUNCH: + case RUN_STATE_DEBUG: + case RUN_STATE_PAUSED: + state->state = MCD_CORE_STATE_DEBUG; + pstrcpy(state->stop_str, MCD_INFO_STR_LEN, "RUN_STATE_PAUSED"); + break; + case RUN_STATE_RUNNING: + if (core_state->cpu->running) { + state->state = MCD_CORE_STATE_RUNNING; + } else if (core_state->cpu->stopped) { + state->state = MCD_CORE_STATE_DEBUG; + } else if (core_state->cpu->halted) { + state->state = MCD_CORE_STATE_HALTED; + pstrcpy(state->info_str, MCD_INFO_STR_LEN, "halted"); + } else { + state->state = MCD_CORE_STATE_UNKNOWN; + } + break; + default: + state->state = MCD_CORE_STATE_UNKNOWN; + break; + } + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index 635f95181b..e1bde14b47 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -557,3 +557,24 @@ MCDSetGlobalResult *qmp_mcd_set_global(uint32_t core_uid, bool enable, g_stub_state.on_error_ask_server = true; return result; } + +MCDQryStateResult *qmp_mcd_qry_state(uint32_t core_uid, Error **errp) +{ + MCDQryStateResult *result = g_malloc0(sizeof(*result)); + mcd_core_state_st state; + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_qry_state_f(core, &state); + if (result->return_status == MCD_RET_ACT_NONE) { + result->state = marshal_mcd_core_state(&state); + } + + g_stub_state.on_error_ask_server = true; + return result; +} diff --git a/qapi/mcd.json b/qapi/mcd.json index c8b82e7f82..3560658451 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -307,6 +307,29 @@ 'hw-thread-id' : 'uint32' } } +## +# @MCDCoreState: +# +# Structure type containing the state of a core. +# +# @state: Core state. +# @event: Core events (OR'ed bitmask) +# @hw-thread-id: ID of the hardware thread that caused the core to stop. +# @trig-id: ID of the trigger that caused the core to stop. +# @stop-str: Detailed description of a special stop reason. +# @info-str: Detailed description of the core state. +# +# Since: 9.1 +## +{ 'struct': 'MCDCoreState', + 'data': { + 'state' : 'uint32', + 'event' : 'uint32', + 'hw-thread-id': 'uint32', + 'trig-id' : 'uint32', + 'stop-str' : 'str', + 'info-str' : 'str' } } + ## # == Target Initialization API ## @@ -1473,3 +1496,35 @@ 'core-uid': 'uint32', 'enable' : 'bool' }, 'returns': 'MCDSetGlobalResult' } + + +## +# @MCDQryStateResult: +# +# Return value of @mcd-qry-state. +# +# @return-status: Return code. +# @state: The current execution state of the target core. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryStateResult', + 'data': { + 'return-status': 'uint32', + '*state': 'MCDCoreState' }} + + +## +# @mcd-qry-state: +# +# Function querying the execution state of a target core. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# +# Returns: @MCDQryStateResult +# +# Since: 9.1 +## +{ 'command': 'mcd-qry-state', + 'data': { 'core-uid': 'uint32' }, + 'returns': 'MCDQryStateResult' } diff --git a/tests/qtest/libmcd-test.c b/tests/qtest/libmcd-test.c index 82a39366b2..52f3ffcaa1 100644 --- a/tests/qtest/libmcd-test.c +++ b/tests/qtest/libmcd-test.c @@ -316,5 +316,64 @@ MCDQryRegMapResult *qtest_mcd_qry_reg_map(QTestState *qts, UNMARSHAL_RESULT(MCDQryRegMapResult); + return unmarshal; + +} + +MCDRunResult *qtest_mcd_run(QTestState *qts, q_obj_mcd_run_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDRunResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_run_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-run'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDRunResult); + + return unmarshal; +} + +MCDStopResult *qtest_mcd_stop(QTestState *qts, q_obj_mcd_stop_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDStopResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_stop_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-stop'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDStopResult); + + return unmarshal; +} + +MCDQryStateResult *qtest_mcd_qry_state(QTestState *qts, + q_obj_mcd_qry_state_arg *args) +{ + Visitor *v; + QObject *marshal; + QDict *arg, *resp; + QObject *ret; + bool ok; + MCDQryStateResult *unmarshal; + + MARSHAL_ARGS(q_obj_mcd_qry_state_arg); + + resp = qtest_qmp(qts, "{'execute': 'mcd-qry-state'," + "'arguments': %p}", arg); + + UNMARSHAL_RESULT(MCDQryStateResult); + return unmarshal; } diff --git a/tests/qtest/libmcd-test.h b/tests/qtest/libmcd-test.h index 266b6fe854..e45386847d 100644 --- a/tests/qtest/libmcd-test.h +++ b/tests/qtest/libmcd-test.h @@ -56,4 +56,13 @@ MCDQryRegGroupsResult *qtest_mcd_qry_reg_groups(QTestState *qts, MCDQryRegMapResult *qtest_mcd_qry_reg_map(QTestState *qts, q_obj_mcd_qry_reg_map_arg *args); +MCDRunResult *qtest_mcd_run(QTestState *qts, + q_obj_mcd_run_arg *args); + +MCDStopResult *qtest_mcd_stop(QTestState *qts, + q_obj_mcd_stop_arg *args); + +MCDQryStateResult *qtest_mcd_qry_state(QTestState *qts, + q_obj_mcd_qry_state_arg *args); + #endif /* LIBMCD_TEST_H */ diff --git a/tests/qtest/mcd-test.c b/tests/qtest/mcd-test.c index 820408a9a9..9ab6b8e675 100644 --- a/tests/qtest/mcd-test.c +++ b/tests/qtest/mcd-test.c @@ -18,7 +18,7 @@ #include "qapi/compat-policy.h" #include "libmcd-test.h" -#define QEMU_EXTRA_ARGS "" +#define QEMU_EXTRA_ARGS "-accel tcg" static bool verbose; @@ -87,6 +87,45 @@ static MCDQryCoresResult *open_server_query_cores(QTestState *qts) return qry_cores_result; } +static mcd_core_state_et check_core_state(QTestState *qts, uint32_t core_uid) +{ + mcd_core_state_et state; + + q_obj_mcd_qry_state_arg qry_state_args = { + .core_uid = core_uid, + }; + + MCDQryStateResult *qry_state_result = qtest_mcd_qry_state(qts, + &qry_state_args); + + g_assert(qry_state_result->return_status == MCD_RET_ACT_NONE); + g_assert(qry_state_result->state); + state = qry_state_result->state->state; + + if (verbose) { + fprintf(stderr, "[INFO]\tCore state: "); + switch (qry_state_result->state->state) { + case MCD_CORE_STATE_RUNNING: + fprintf(stderr, "running\n"); + break; + case MCD_CORE_STATE_HALTED: + fprintf(stderr, "halted\n"); + break; + case MCD_CORE_STATE_DEBUG: + fprintf(stderr, "debug\n"); + break; + case MCD_CORE_STATE_UNKNOWN: + fprintf(stderr, "unknown\n"); + break; + default: + g_assert_not_reached(); + } + } + + qapi_free_MCDQryStateResult(qry_state_result); + return state; +} + static void test_initialize(void) { QTestState *qts = qtest_init(QEMU_EXTRA_ARGS); @@ -510,6 +549,84 @@ static void test_qry_core_info(void) qtest_quit(qts); } +static void test_go_stop(void) +{ + QTestState *qts = qtest_init(QEMU_EXTRA_ARGS); + mcd_core_state_et core_state; + MCDQryCoresResult *cores_query = open_server_query_cores(qts); + + MCDCoreConInfoList *core_head = cores_query->core_con_info; + for (uint32_t c = 0; c < cores_query->num_cores; c++) { + q_obj_mcd_stop_arg stop_args = { + .global = true, /* only global stops currently supported */ + }; + + q_obj_mcd_run_arg run_args = { + .global = true, + }; + + q_obj_mcd_close_core_arg close_core_args; + + MCDRunResult *run_result; + MCDStopResult *stop_result; + MCDOpenCoreResult *open_core_result; + MCDCloseCoreResult *close_core_result; + + MCDCoreConInfo *core_con_info = core_head->value; + q_obj_mcd_open_core_arg open_core_args = { + .core_con_info = core_con_info, + }; + + if (verbose) { + fprintf(stderr, "[INFO]\tTesting core %s (#%d)...\n", + core_con_info->core, + core_con_info->core_id); + } + + open_core_result = qtest_mcd_open_core(qts, &open_core_args); + g_assert(open_core_result->return_status == MCD_RET_ACT_NONE); + g_assert(open_core_result->has_core_uid); + + check_core_state(qts, open_core_result->core_uid); + + if (verbose) { + fprintf(stderr, "[INFO]\tStop core\n"); + } + + stop_args.core_uid = open_core_result->core_uid; + stop_result = qtest_mcd_stop(qts, &stop_args); + g_assert(stop_result->return_status == MCD_RET_ACT_NONE); + qapi_free_MCDStopResult(stop_result); + + core_state = check_core_state(qts, open_core_result->core_uid); + g_assert(core_state == MCD_CORE_STATE_DEBUG); + + if (verbose) { + fprintf(stderr, "[INFO]\tResume core\n"); + } + + run_args.core_uid = open_core_result->core_uid; + run_result = qtest_mcd_run(qts, &run_args); + g_assert(run_result->return_status == MCD_RET_ACT_NONE); + qapi_free_MCDRunResult(run_result); + + core_state = check_core_state(qts, open_core_result->core_uid); + g_assert(core_state == MCD_CORE_STATE_RUNNING); + + close_core_args.core_uid = open_core_result->core_uid; + close_core_result = qtest_mcd_close_core(qts, &close_core_args); + g_assert(close_core_result->return_status == MCD_RET_ACT_NONE); + + qapi_free_MCDCloseCoreResult(close_core_result); + qapi_free_MCDOpenCoreResult(open_core_result); + core_head = core_head->next; + } + + qapi_free_MCDQryCoresResult(cores_query); + qtest_mcd_exit(qts); + qtest_quit(qts); +} + int main(int argc, char *argv[]) { char *v_env = getenv("V"); @@ -522,5 +639,6 @@ int main(int argc, char *argv[]) qtest_add_func("mcd/qry-cores", test_qry_cores); qtest_add_func("mcd/open-core", test_open_core); qtest_add_func("mcd/qry-core-info", test_qry_core_info); + qtest_add_func("mcd/go-stop", test_go_stop); return g_test_run(); } From patchwork Mon Mar 10 15:05:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010263 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E116AC282EC for ; Mon, 10 Mar 2025 15:12:35 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1trenb-0002JT-Eh; Mon, 10 Mar 2025 11:12:11 -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 1tren3-00025c-DB for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:37 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremy-0007gz-O1 for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:36 -0400 Received: (qmail 30892 invoked by uid 484); 10 Mar 2025 15:11:12 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.013116 secs); 10 Mar 2025 15:11:12 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:12 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann Subject: [PATCH 12/16] gdbstub: Expose gdb_write_register Date: Mon, 10 Mar 2025 16:05:06 +0100 Message-Id: <20250310150510.200607-13-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Signed-off-by: Mario Fleischmann --- gdbstub/gdbstub.c | 2 +- include/exec/gdbstub.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 8166510f06..830854ef72 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -527,7 +527,7 @@ int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) return 0; } -static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) +int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) { GDBRegisterState *r; diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index c2941e5c10..e2d848806b 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -130,6 +130,16 @@ const GDBFeature *gdb_find_static_feature(const char *xmlname); */ int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); +/** + * gdb_write_register() - Write a register associated with a CPU. + * @cpu: The CPU associated with the register. + * @mem_buf: The buffer that the register will be written from. + * @reg: The register's number returned by gdb_find_feature_register(). + * + * Return: The number of written bytes. + */ +int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg); + /** * typedef GDBRegDesc - a register description from gdbstub */ From patchwork Mon Mar 10 15:05:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010302 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3C436C282DE for ; Mon, 10 Mar 2025 15:20:44 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1trenv-0002iq-It; Mon, 10 Mar 2025 11:12:31 -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 1trenD-0002Cx-NA for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:58 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1trenA-0007hH-89 for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:46 -0400 Received: (qmail 30914 invoked by uid 484); 10 Mar 2025 15:11:12 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.012888 secs); 10 Mar 2025 15:11:12 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:12 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake Subject: [PATCH 13/16] mcd: Implement register/memory access Date: Mon, 10 Mar 2025 16:05:07 +0100 Message-Id: <20250310150510.200607-14-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org In MCD, all accesses to register or memory are issued over transaction lists. This commit implements three types of transactions: * register access * logical memory access (with MMU) * physical memory access (no MMU) Signed-off-by: Mario Fleischmann --- mcd/libmcd_qapi.c | 128 +++++++++++++++++++++++++++++++++ mcd/libmcd_qapi.h | 14 ++++ mcd/mcdserver.c | 176 ++++++++++++++++++++++++++++++++++++++++++++- mcd/mcdstub_qapi.c | 26 +++++++ qapi/mcd.json | 83 +++++++++++++++++++++ 5 files changed, 425 insertions(+), 2 deletions(-) diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c index 44fc9bd6b4..8088a9eed2 100644 --- a/mcd/libmcd_qapi.c +++ b/mcd/libmcd_qapi.c @@ -176,6 +176,18 @@ MCDAddr *marshal_mcd_addr(const mcd_addr_st *addr) return marshal; } +mcd_addr_st unmarshal_mcd_addr(MCDAddr *addr) +{ + mcd_addr_st unmarshal = { + .address = addr->address, + .mem_space_id = addr->mem_space_id, + .addr_space_id = addr->addr_space_id, + .addr_space_type = addr->addr_space_type, + }; + + return unmarshal; +} + MCDRegisterInfo *marshal_mcd_register_info(const mcd_register_info_st *reg_info) { MCDRegisterInfo *marshal = g_malloc0(sizeof(*marshal)); @@ -211,3 +223,119 @@ MCDCoreState *marshal_mcd_core_state(const mcd_core_state_st *state) return marshal; } + +MCDTx *marshal_mcd_tx(const mcd_tx_st *tx) +{ + MCDTx *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDTx) { + .addr = marshal_mcd_addr(&tx->addr), + .access_type = tx->access_type, + .options = tx->options, + .access_width = tx->access_width, + .core_mode = tx->core_mode, + .num_bytes = tx->num_bytes, + .num_bytes_ok = tx->num_bytes_ok, + }; + + if (tx->num_bytes == 0) { + return marshal; + } + + g_assert(tx->data); + + uint8List *head = marshal->data; + for (int i = tx->num_bytes - 1; i >= 0; i--) { + QAPI_LIST_PREPEND(head, tx->data[i]); + } + marshal->data = head; + return marshal; +} + +mcd_tx_st unmarshal_mcd_tx(MCDTx *tx) +{ + mcd_tx_st unmarshal = { + .addr = unmarshal_mcd_addr(tx->addr), + .access_type = tx->access_type, + .options = tx->options, + .access_width = tx->access_width, + .core_mode = tx->core_mode, + .data = NULL, + .num_bytes = tx->num_bytes, + .num_bytes_ok = tx->num_bytes_ok, + }; + + if (tx->num_bytes == 0) { + return unmarshal; + } + + unmarshal.data = g_malloc(tx->num_bytes); + uint8List *current_data = tx->data; + for (uint32_t i = 0; i < tx->num_bytes; i++) { + g_assert(current_data); + unmarshal.data[i] = current_data->value; + current_data = current_data->next; + } + + return unmarshal; +} + +void free_mcd_tx(mcd_tx_st *tx) +{ + g_free(tx->data); +} + +MCDTxlist *marshal_mcd_txlist(const mcd_txlist_st *txlist) +{ + MCDTxlist *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDTxlist) { + .num_tx = txlist->num_tx, + .num_tx_ok = txlist->num_tx_ok, + }; + + if (txlist->num_tx == 0) { + return marshal; + } + + g_assert(txlist->tx); + + MCDTxList **tailp = &(marshal->tx); + for (uint32_t i = 0; i < txlist->num_tx; i++) { + MCDTx *tx = marshal_mcd_tx(txlist->tx + i); + QAPI_LIST_APPEND(tailp, tx); + } + + return marshal; +} + +mcd_txlist_st unmarshal_mcd_txlist(MCDTxlist *txlist) +{ + mcd_txlist_st unmarshal = { + .tx = g_malloc(txlist->num_tx * sizeof(mcd_tx_st)), + .num_tx = txlist->num_tx, + .num_tx_ok = txlist->num_tx_ok, + }; + + MCDTxList *current_tx = txlist->tx; + for (uint32_t i = 0; i < txlist->num_tx; i++) { + g_assert(current_tx); + unmarshal.tx[i] = unmarshal_mcd_tx(current_tx->value); + current_tx = current_tx->next; + } + + return unmarshal; +} + +void free_mcd_txlist(mcd_txlist_st *txlist) +{ + if (!txlist->tx) { + return; + } + + for (uint32_t i = 0; i < txlist->num_tx; i++) { + free_mcd_tx(txlist->tx + i); + } + + g_free(txlist->tx); +} diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h index 7d68d60f02..27bb945db5 100644 --- a/mcd/libmcd_qapi.h +++ b/mcd/libmcd_qapi.h @@ -37,8 +37,22 @@ MCDRegisterInfo *marshal_mcd_register_info( MCDCoreState *marshal_mcd_core_state(const mcd_core_state_st *state); +MCDTx *marshal_mcd_tx(const mcd_tx_st *tx); + +MCDTxlist *marshal_mcd_txlist(const mcd_txlist_st *txlist); + mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version); mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info); +mcd_addr_st unmarshal_mcd_addr(MCDAddr *addr); + +mcd_tx_st unmarshal_mcd_tx(MCDTx *tx); + +mcd_txlist_st unmarshal_mcd_txlist(MCDTxlist *txlist); + +void free_mcd_tx(mcd_tx_st *tx); + +void free_mcd_txlist(mcd_txlist_st *txlist); + #endif /* LIBMCD_QAPI_H */ diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index 116fbfaa30..837c0276e7 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -1081,11 +1081,183 @@ mcd_return_et mcd_qry_trig_set_state_f(const mcd_core_st *core, return g_server_state.last_error->return_status; } +static mcd_return_et execute_memory_tx(mcdcore_state *core_state, mcd_tx_st *tx, + mcd_mem_type_et type) +{ + MemTxResult result; + + /* each address space has one physical and one virtual memory */ + int address_space_id = (tx->addr.mem_space_id - 1) / 2; + AddressSpace *as = cpu_get_address_space(core_state->cpu, address_space_id); + + hwaddr addr = tx->addr.address; + hwaddr len = tx->num_bytes; + void *buf = tx->data; + bool is_write; + + if (tx->access_type == MCD_TX_AT_R) { + is_write = false; + } else if (tx->access_type == MCD_TX_AT_W) { + is_write = true; + } else { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TXLIST_TX, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "tx access type not supported", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (type & MCD_MEM_SPACE_IS_PHYSICAL) { + MemTxAttrs attrs = { + .secure = !!(type & MCD_MEM_SPACE_IS_SECURE), + .space = address_space_id, + }; + result = address_space_rw(as, addr, attrs, buf, len, is_write); + } else if (type & MCD_MEM_SPACE_IS_LOGICAL) { + int ret = cpu_memory_rw_debug(core_state->cpu, addr, buf, len, + is_write); + result = (ret == 0) ? MEMTX_OK : MEMTX_ERROR; + } else { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TXLIST_TX, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "unknown mem space type", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (result != MEMTX_OK) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = is_write ? MCD_ERR_TXLIST_WRITE : MCD_ERR_TXLIST_READ, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "", + }; + snprintf(core_state->custom_error.error_str, MCD_INFO_STR_LEN, + "Memory tx failed with error code %d", result); + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + tx->num_bytes_ok = tx->num_bytes; + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; +} + +static mcd_return_et execute_register_tx(mcdcore_state *core_state, + mcd_tx_st *tx) +{ + if (tx->access_type == MCD_TX_AT_R) { + GByteArray *mem_buf = g_byte_array_new(); + int read_bytes = gdb_read_register(core_state->cpu, mem_buf, + tx->addr.address); + if (read_bytes > tx->num_bytes) { + g_byte_array_free(mem_buf, true); + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TXLIST_READ, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "too many bytes read", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + memcpy(tx->data, mem_buf->data, read_bytes); + g_byte_array_free(mem_buf, true); + tx->num_bytes_ok = read_bytes; + } else if (tx->access_type == MCD_TX_AT_W) { + int written_bytes = gdb_write_register(core_state->cpu, tx->data, + tx->addr.address); + if (written_bytes > tx->num_bytes) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TXLIST_READ, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "too many bytes written", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + tx->num_bytes_ok = written_bytes; + } else { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TXLIST_TX, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "tx access type not supported", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; +} + +static mcd_return_et execute_tx(mcdcore_state *core_state, mcd_tx_st *tx) +{ + mcd_memspace_st *ms; + + uint32_t ms_id = tx->addr.mem_space_id; + if (ms_id == 0 || ms_id > core_state->memory_spaces->len) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "unknown memory space ID", + }; + } + + ms = &g_array_index(core_state->memory_spaces, mcd_memspace_st, ms_id - 1); + if (ms->mem_type & MCD_MEM_SPACE_IS_PHYSICAL || + ms->mem_type & MCD_MEM_SPACE_IS_LOGICAL) { + return execute_memory_tx(core_state, tx, ms->mem_type); + } else if (ms->mem_type & MCD_MEM_SPACE_IS_REGISTERS) { + return execute_register_tx(core_state, tx); + } else { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TXLIST_TX, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "unknown memory space type", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } +} + mcd_return_et mcd_execute_txlist_f(const mcd_core_st *core, mcd_txlist_st *txlist) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + + if (!core || !txlist) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + for (uint32_t i = 0; i < txlist->num_tx; i++) { + mcd_tx_st *tx = txlist->tx + i; + if (execute_tx(core_state, tx) != MCD_RET_ACT_NONE) { + return core_state->last_error->return_status; + } else { + txlist->num_tx_ok++; + } + } + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_run_f(const mcd_core_st *core, bool global) diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index e1bde14b47..724b7ff7ea 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -506,6 +506,32 @@ MCDQryRegMapResult *qmp_mcd_qry_reg_map(uint32_t core_uid, return result; } +MCDExecuteTxlistResult *qmp_mcd_execute_txlist(uint32_t core_uid, + MCDTxlist *txlist, + Error **errp) +{ + MCDExecuteTxlistResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + mcd_txlist_st txlist_unmarshalled = unmarshal_mcd_txlist(txlist); + + result->return_status = mcd_execute_txlist_f(core, &txlist_unmarshalled); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->txlist = marshal_mcd_txlist(&txlist_unmarshalled); + } + + free_mcd_txlist(&txlist_unmarshalled); + g_stub_state.on_error_ask_server = true; + return result; +} + MCDRunResult *qmp_mcd_run(uint32_t core_uid, bool global, Error **errp) { MCDRunResult *result = g_malloc0(sizeof(*result)); diff --git a/qapi/mcd.json b/qapi/mcd.json index 3560658451..fabb3eea89 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -306,6 +306,54 @@ 'reg-type' : 'uint32', 'hw-thread-id' : 'uint32' } } +## +# @MCDTx: +# +# Structure type containing information about a single transaction. +# +# @addr: The address of the first memory cell/register. +# @access-type: Type of access: Read/Write/Read+Write/Write+Verify. +# @options: Access options: burst, side-effects, alternate path, cache, +# etc. +# @access-width: Access size in bytes (or 0 if access size does not matter). +# @core-mode: The core mode in which the access should be performed (or 0 +# for most permissive mode). +# @data: Byte array of size @num-bytes storing the access data. +# @num-bytes: Size of the memory/register access. The buffer @data needs to +# be of this size. +# @num-bytes-ok: Number of successfully received/sent bytes. +# +# Since: 9.1 +## +{ 'struct': 'MCDTx', + 'data': { + 'addr' : 'MCDAddr', + 'access-type' : 'uint32', + 'options' : 'uint32', + 'access-width': 'uint8', + 'core-mode' : 'uint8', + 'data' : ['uint8'], + 'num-bytes' : 'uint32', + 'num-bytes-ok': 'uint32' } } + + +## +# @MCDTxlist: +# +# Structure type containing a transaction list. +# +# @tx: Array of size @num-tx storing the transactions. +# @num-tx: Number of transactions. +# @num-tx-ok: Number of transactions which succeeded without any errors. +# +# Since: 9.1 +## +{ 'struct': 'MCDTxlist', + 'data': { + 'tx' : ['MCDTx'], + 'num-tx' : 'uint32', + 'num-tx-ok': 'uint32' } } + ## # @MCDCoreState: @@ -1403,6 +1451,41 @@ ## +## +# @MCDExecuteTxlistResult: +# +# Return value of @mcd-execute-txlist. +# +# @return-status: Return code. +# @txlist: Transaction list after execution. +# +# Since: 9.1 +## +{ 'struct': 'MCDExecuteTxlistResult', + 'data': { + 'return-status': 'uint32', + '*txlist' : 'MCDTxlist' }} + + +## +# @mcd-execute-txlist: +# +# Function executing a transaction list on the target. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# @txlist: Transaction list for execution. +# +# Returns: @MCDExecuteTxlistResult +# +# Since: 9.1 +## +{ 'command': 'mcd-execute-txlist', + 'data': { + 'core-uid': 'uint32', + 'txlist' : 'MCDTxlist' }, + 'returns': 'MCDExecuteTxlistResult' } + + ## # @MCDRunResult: # From patchwork Mon Mar 10 15:05:08 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010300 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 6F819C282EC for ; Mon, 10 Mar 2025 15:19:07 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1trenW-0002GP-EX; Mon, 10 Mar 2025 11:12:06 -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 1tren4-00026v-2C for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:38 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tremz-0007i7-Tz for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:37 -0400 Received: (qmail 30940 invoked by uid 484); 10 Mar 2025 15:11:13 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.012684 secs); 10 Mar 2025 15:11:13 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:13 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake Subject: [PATCH 14/16] mcd: Implement single stepping Date: Mon, 10 Mar 2025 16:05:08 +0100 Message-Id: <20250310150510.200607-15-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org gdbstub: abort gdb_set_stop_cpu when step is issued by mcdserver Signed-off-by: Mario Fleischmann --- gdbstub/gdbstub.c | 6 ++- mcd/mcdserver.c | 115 +++++++++++++++++++++++++++++++++++++++++---- mcd/mcdstub_qapi.c | 17 +++++++ qapi/mcd.json | 38 ++++++++++++++- 4 files changed, 164 insertions(+), 12 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 830854ef72..3821ebc0ba 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -226,6 +226,10 @@ GDBProcess *gdb_get_process(uint32_t pid) static GDBProcess *gdb_get_cpu_process(CPUState *cpu) { + if (!gdbserver_state.processes) { + return NULL; + } + return gdb_get_process(gdb_get_cpu_pid(cpu)); } @@ -2272,7 +2276,7 @@ void gdb_set_stop_cpu(CPUState *cpu) { GDBProcess *p = gdb_get_cpu_process(cpu); - if (!p->attached) { + if (!p || !p->attached) { /* * Having a stop CPU corresponding to a process that is not attached * confuses GDB. So we ignore the request. diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index 837c0276e7..bdb4767060 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -59,14 +59,19 @@ static const mcd_error_info_st MCD_ERROR_NONE = { /** * struct mcdcore_state - State of a core. * - * @last_error: Error info of most recent executed core-related function. - * @custom_error: Reserves memory for custom MCD errors. - * @info: Core connection information. - * @open_core: Open core instance as allocated in mcd_open_core_f(). - * @cpu: QEMU's internal CPU handle. - * @memory_spaces: Memory spaces as queried by mcd_qry_mem_spaces_f(). - * @register_groups: Register groups as queried by mcd_qry_reg_groups_f(). - * @registers: Registers as queried by mcd_qry_reg_map_f(). + * @last_error: Error info of most recent executed core-related + * function. + * @custom_error: Reserves memory for custom MCD errors. + * @info: Core connection information. + * @open_core: Open core instance as allocated in + * mcd_open_core_f(). + * @cpu: QEMU's internal CPU handle. + * @memory_spaces: Memory spaces as queried by + * mcd_qry_mem_spaces_f(). + * @register_groups: Register groups as queried by + * mcd_qry_reg_groups_f(). + * @registers: Registers as queried by mcd_qry_reg_map_f(). + * @vm_state_change_handler: State change handler. * * MCD is mainly being used on the core level: * After the initial query functions, a core connection is opened in @@ -85,6 +90,7 @@ typedef struct mcdcore_state { GArray *memory_spaces; GArray *register_groups; GArray *registers; + VMChangeStateEntry *vm_state_change_handler; } mcdcore_state; /** @@ -129,6 +135,16 @@ static mcdcore_state *find_core(const mcd_core_con_info_st *core_con_info) return core; } +static void mcd_handle_vm_state_change(void *opaque, bool running, + RunState state) +{ + mcdcore_state *core_state = (mcdcore_state *)opaque; + CPUState *cpu = core_state->cpu; + + /* disable single step if it was enabled */ + cpu_single_step(cpu, 0); +} + mcd_return_et mcd_initialize_f(const mcd_api_version_st *version_req, mcd_impl_version_info_st *impl_info) { @@ -279,6 +295,7 @@ mcd_return_et mcd_open_server_f(const char *system_key, sizeof(mcd_register_group_st)), .registers = g_array_new(false, true, sizeof(mcd_register_info_st)), + .vm_state_change_handler = NULL, }; pstrcpy(c.info.core, MCD_UNIQUE_NAME_LEN, cpu_model); g_array_append_val(g_server_state.cores, c); @@ -663,6 +680,8 @@ mcd_return_et mcd_open_core_f(const mcd_core_con_info_st *core_con_info, (*core)->instance = NULL; core_state->open_core = *core; core_state->last_error = &MCD_ERROR_NONE; + core_state->vm_state_change_handler = qemu_add_vm_change_state_handler( + mcd_handle_vm_state_change, core_state); g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; @@ -694,6 +713,8 @@ mcd_return_et mcd_close_core_f(const mcd_core_st *core) return g_server_state.last_error->return_status; } + qemu_del_vm_change_state_handler(core_state->vm_state_change_handler); + core_state->vm_state_change_handler = NULL; g_free((void *)core->core_con_info); g_free((void *)core); core_state->open_core = NULL; @@ -1329,8 +1350,82 @@ mcd_return_et mcd_qry_current_time_f(const mcd_core_st *core, mcd_return_et mcd_step_f(const mcd_core_st *core, bool global, mcd_core_step_type_et step_type, uint32_t n_steps) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + int supported_step_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; + + if (global) { + g_server_state.custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_FN_UNIMPLEMENTED, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "global step not implemented", + }; + g_server_state.last_error = &g_server_state.custom_error; + return g_server_state.last_error->return_status; + } + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (n_steps != 1) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "only single step supported", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (runstate_needs_reset()) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_GENERAL, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "internal error: runstate needs reset", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (vm_prepare_start(true) != 0) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_GENERAL, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "internal error: vm_prepare_start failed", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (step_type != MCD_CORE_STEP_TYPE_INSTR) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TXLIST_TX, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "step type not supported", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + supported_step_flags &= accel_supported_gdbstub_sstep_flags(); + cpu_single_step(core_state->cpu, supported_step_flags); + cpu_resume(core_state->cpu); + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_set_global_f(const mcd_core_st *core, bool enable) diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index 724b7ff7ea..872fb7c9da 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -566,6 +566,23 @@ MCDStopResult *qmp_mcd_stop(uint32_t core_uid, bool global, Error **errp) return result; } +MCDStepResult *qmp_mcd_step(uint32_t core_uid, bool global, uint32_t step_type, + uint32_t n_steps, Error **errp) +{ + MCDStepResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + result->return_status = mcd_step_f(core, global, step_type, n_steps); + + g_stub_state.on_error_ask_server = true; + return result; +} + MCDSetGlobalResult *qmp_mcd_set_global(uint32_t core_uid, bool enable, Error **errp) { diff --git a/qapi/mcd.json b/qapi/mcd.json index fabb3eea89..b4f21995e3 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -1549,6 +1549,43 @@ 'global' : 'bool' }, 'returns': 'MCDStopResult' } + +## +# @MCDStepResult: +# +# Return value of @mcd-step. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDStepResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-step: +# +# Function stepping a target core based on the particular step type. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# @global: Set to "TRUE" if all cores of a system shall start +# execution. Otherwise, starting execution of selected core only. +# @step-type: The unit, the stepping of the target core is based on. +# @n-steps: The number of steps, the target core is stepped for. +# +# Returns: @MCDStepResult +# +# Since: 9.1 +## +{ 'command': 'mcd-step', + 'data': { + 'core-uid' : 'uint32', + 'global' : 'bool', + 'step-type': 'uint32', + 'n-steps' : 'uint32' }, + 'returns': 'MCDStepResult' } + + ## # @MCDSetGlobalResult: # @@ -1580,7 +1617,6 @@ 'enable' : 'bool' }, 'returns': 'MCDSetGlobalResult' } - ## # @MCDQryStateResult: # From patchwork Mon Mar 10 15:05:09 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010272 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DBADBC28B2E for ; Mon, 10 Mar 2025 15:15:28 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1trenu-0002ie-NG; Mon, 10 Mar 2025 11:12:30 -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 1tren6-00029H-SG for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:40 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tren0-0007iC-EP for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:40 -0400 Received: (qmail 30961 invoked by uid 484); 10 Mar 2025 15:11:13 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.012861 secs); 10 Mar 2025 15:11:13 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:13 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake Subject: [PATCH 15/16] mcd: Implement trigger control Date: Mon, 10 Mar 2025 16:05:09 +0100 Message-Id: <20250310150510.200607-16-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org MCD's trigger API functions support multiple triggers by expecting a pointer to the trigger instance. Each trigger structure reserves the first four bytes for its size. To get the specific structure, read a uint32_t at passed pointer and compare it to the sizes of known trigger structures. This approach does not work for serialization. The sizes might vary between host machines and pointers cannot be sent over the network anyway. Therefore, we define a MCDTrig structure which explicitly lists all supported trigger types as optional fields: * mcd_trig_simple_core_st: mcd-trig-simple-core * mcd_trig_complex_core_st: mcd-trig-complex-core Signed-off-by: Mario Fleischmann --- mcd/libmcd_qapi.c | 155 +++++++++++- mcd/libmcd_qapi.h | 21 ++ mcd/mcdserver.c | 585 ++++++++++++++++++++++++++++++++++++++++++-- mcd/mcdstub_qapi.c | 290 ++++++++++++++++++++++ qapi/mcd.json | 588 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1619 insertions(+), 20 deletions(-) diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c index 8088a9eed2..db3d11d3e5 100644 --- a/mcd/libmcd_qapi.c +++ b/mcd/libmcd_qapi.c @@ -188,7 +188,8 @@ mcd_addr_st unmarshal_mcd_addr(MCDAddr *addr) return unmarshal; } -MCDRegisterInfo *marshal_mcd_register_info(const mcd_register_info_st *reg_info) +MCDRegisterInfo *marshal_mcd_register_info( + const mcd_register_info_st *reg_info) { MCDRegisterInfo *marshal = g_malloc0(sizeof(*marshal)); @@ -224,6 +225,158 @@ MCDCoreState *marshal_mcd_core_state(const mcd_core_state_st *state) return marshal; } +MCDTrigInfo *marshal_mcd_trig_info(const mcd_trig_info_st *trig_info) +{ + MCDTrigInfo *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDTrigInfo) { + .type = trig_info->type, + .option = trig_info->option, + .action = trig_info->action, + .trig_number = trig_info->trig_number, + .state_number = trig_info->state_number, + .counter_number = trig_info->counter_number, + .sw_breakpoints = trig_info->sw_breakpoints, + }; + + return marshal; +} + +MCDCtrigInfo *marshal_mcd_ctrig_info(const mcd_ctrig_info_st *trig_info) +{ + MCDCtrigInfo *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDCtrigInfo) { + .ctrig_id = trig_info->ctrig_id, + .info_str = g_strdup(trig_info->info_str), + }; + + return marshal; +} + +MCDTrigSimpleCore *marshal_mcd_trig_simple_core( + mcd_trig_simple_core_st const *trig_simple_core) +{ + MCDTrigSimpleCore *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDTrigSimpleCore) { + .type = trig_simple_core->type, + .option = trig_simple_core->option, + .action = trig_simple_core->action, + .action_param = trig_simple_core->action_param, + .modified = trig_simple_core->modified, + .state_mask = trig_simple_core->state_mask, + .addr_start = marshal_mcd_addr(&trig_simple_core->addr_start), + .addr_range = trig_simple_core->addr_range, + }; + + return marshal; +} + +mcd_trig_simple_core_st unmarshal_mcd_trig_simple_core( + MCDTrigSimpleCore *trig_simple_core) +{ + mcd_trig_simple_core_st unmarshal = { + .struct_size = sizeof(mcd_trig_simple_core_st), + .type = trig_simple_core->type, + .option = trig_simple_core->option, + .action = trig_simple_core->action, + .action_param = trig_simple_core->action_param, + .modified = trig_simple_core->modified, + .state_mask = trig_simple_core->state_mask, + .addr_start = unmarshal_mcd_addr(trig_simple_core->addr_start), + .addr_range = trig_simple_core->addr_range, + }; + + return unmarshal; +} + +MCDTrigComplexCore *marshal_mcd_trig_complex_core( + mcd_trig_complex_core_st const *trig_complex_core) +{ + MCDTrigComplexCore *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDTrigComplexCore) { + .type = trig_complex_core->type, + .option = trig_complex_core->option, + .action = trig_complex_core->action, + .action_param = trig_complex_core->action_param, + .modified = trig_complex_core->modified, + .state_mask = trig_complex_core->state_mask, + .addr_start = marshal_mcd_addr(&trig_complex_core->addr_start), + .addr_range = trig_complex_core->addr_range, + .data_start = trig_complex_core->data_start, + .data_range = trig_complex_core->data_range, + .data_mask = trig_complex_core->data_mask, + .data_size = trig_complex_core->data_size, + .hw_thread_id = trig_complex_core->hw_thread_id, + .sw_thread_id = trig_complex_core->sw_thread_id, + .core_mode_mask = trig_complex_core->core_mode_mask, + }; + + return marshal; +} + +mcd_trig_complex_core_st unmarshal_mcd_trig_complex_core( + MCDTrigComplexCore *trig_complex_core) +{ + mcd_trig_complex_core_st unmarshal = { + .struct_size = sizeof(mcd_trig_complex_core_st), + .type = trig_complex_core->type, + .option = trig_complex_core->option, + .action = trig_complex_core->action, + .action_param = trig_complex_core->action_param, + .modified = trig_complex_core->modified, + .state_mask = trig_complex_core->state_mask, + .addr_start = unmarshal_mcd_addr(trig_complex_core->addr_start), + .addr_range = trig_complex_core->addr_range, + .data_start = trig_complex_core->data_start, + .data_range = trig_complex_core->data_range, + .data_mask = trig_complex_core->data_mask, + .data_size = trig_complex_core->data_size, + .hw_thread_id = trig_complex_core->hw_thread_id, + .sw_thread_id = trig_complex_core->sw_thread_id, + .core_mode_mask = trig_complex_core->core_mode_mask, + }; + + return unmarshal; +} + +MCDTrigState *marshal_mcd_trig_state(const mcd_trig_state_st *trig_info) +{ + MCDTrigState *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDTrigState) { + .active = trig_info->active, + .captured = trig_info->captured, + .captured_valid = trig_info->captured_valid, + .count_value = trig_info->count_value, + .count_valid = trig_info->count_valid, + }; + + return marshal; +} + +MCDTrigSetState *marshal_mcd_trig_set_state( + const mcd_trig_set_state_st *trig_state) +{ + MCDTrigSetState *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDTrigSetState) { + .active = trig_state->active, + .state = trig_state->state, + .state_valid = trig_state->state_valid, + .trig_bus = trig_state->trig_bus, + .trig_bus_valid = trig_state->trig_bus_valid, + .trace = trig_state->trace, + .trace_valid = trig_state->trace_valid, + .analysis = trig_state->analysis, + .analysis_valid = trig_state->analysis_valid, + }; + + return marshal; +} + MCDTx *marshal_mcd_tx(const mcd_tx_st *tx) { MCDTx *marshal = g_malloc0(sizeof(*marshal)); diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h index 27bb945db5..133dfbf9d3 100644 --- a/mcd/libmcd_qapi.h +++ b/mcd/libmcd_qapi.h @@ -37,6 +37,21 @@ MCDRegisterInfo *marshal_mcd_register_info( MCDCoreState *marshal_mcd_core_state(const mcd_core_state_st *state); +MCDTrigInfo *marshal_mcd_trig_info(const mcd_trig_info_st *trig_info); + +MCDCtrigInfo *marshal_mcd_ctrig_info(const mcd_ctrig_info_st *trig_info); + +MCDTrigSimpleCore *marshal_mcd_trig_simple_core( + const mcd_trig_simple_core_st *trig_simple_core); + +MCDTrigComplexCore *marshal_mcd_trig_complex_core( + const mcd_trig_complex_core_st *trig_complex_core); + +MCDTrigState *marshal_mcd_trig_state(const mcd_trig_state_st *trig_info); + +MCDTrigSetState *marshal_mcd_trig_set_state( + const mcd_trig_set_state_st *trig_state); + MCDTx *marshal_mcd_tx(const mcd_tx_st *tx); MCDTxlist *marshal_mcd_txlist(const mcd_txlist_st *txlist); @@ -47,6 +62,12 @@ mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info); mcd_addr_st unmarshal_mcd_addr(MCDAddr *addr); +mcd_trig_simple_core_st unmarshal_mcd_trig_simple_core( + MCDTrigSimpleCore *trig_simple_core); + +mcd_trig_complex_core_st unmarshal_mcd_trig_complex_core( + MCDTrigComplexCore *trig_complex_core); + mcd_tx_st unmarshal_mcd_tx(MCDTx *tx); mcd_txlist_st unmarshal_mcd_txlist(MCDTxlist *txlist); diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index bdb4767060..649c4d387b 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -71,7 +71,10 @@ static const mcd_error_info_st MCD_ERROR_NONE = { * @register_groups: Register groups as queried by * mcd_qry_reg_groups_f(). * @registers: Registers as queried by mcd_qry_reg_map_f(). + * @triggers: Triggers as created in mcd_create_trig_f(). * @vm_state_change_handler: State change handler. + * @num_created_triggers: Total amount of created triggers since last + * mcd_open_server_f(). * * MCD is mainly being used on the core level: * After the initial query functions, a core connection is opened in @@ -91,6 +94,8 @@ typedef struct mcdcore_state { GArray *register_groups; GArray *registers; VMChangeStateEntry *vm_state_change_handler; + GArray *triggers; + uint32_t num_created_triggers; } mcdcore_state; /** @@ -101,6 +106,8 @@ typedef struct mcdcore_state { * @open_server: Open server instance as allocated in mcd_open_server_f(). * @system_key: System key as provided in mcd_open_server_f() * @cores: Internal core information database. + * @bp_cpu: CPU hitting the most recent break-/watchpoint. + * @bp_addr: Address of the most recent break-/watchpoint. */ typedef struct mcdserver_state { const mcd_error_info_st *last_error; @@ -108,6 +115,8 @@ typedef struct mcdserver_state { mcd_server_st *open_server; char system_key[MCD_KEY_LEN]; GArray *cores; + CPUState const *bp_cpu; + vaddr bp_addr; } mcdserver_state; static mcdserver_state g_server_state = { @@ -115,8 +124,24 @@ static mcdserver_state g_server_state = { .open_server = NULL, .system_key = "", .cores = NULL, + .bp_cpu = NULL, }; +/** + * struct mcd_active_trigger - Identifiable active trigger + * + * @trig: Trigger instance as created in mcd_create_trig_f(). + * @id: Unique trigger identifier. + * + * Currently, only mcd_trig_simple_core_st is supported. + */ +typedef struct mcd_active_trigger { + mcd_trig_simple_core_st trig; + uint32_t id; + bool captured; +} mcd_active_trigger; + + static mcdcore_state *find_core(const mcd_core_con_info_st *core_con_info) { uint32_t core_id; @@ -140,6 +165,16 @@ static void mcd_handle_vm_state_change(void *opaque, bool running, { mcdcore_state *core_state = (mcdcore_state *)opaque; CPUState *cpu = core_state->cpu; + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (state == RUN_STATE_DEBUG && cpu->watchpoint_hit) { + g_server_state.bp_cpu = cpu; + g_server_state.bp_addr = cpu->watchpoint_hit->vaddr; + cpu->watchpoint_hit = NULL; + } else if (cpu_breakpoint_test(cpu, cc->get_pc(cpu), BP_GDB)) { + g_server_state.bp_cpu = cpu; + g_server_state.bp_addr = cc->get_pc(cpu); + } /* disable single step if it was enabled */ cpu_single_step(cpu, 0); @@ -295,7 +330,9 @@ mcd_return_et mcd_open_server_f(const char *system_key, sizeof(mcd_register_group_st)), .registers = g_array_new(false, true, sizeof(mcd_register_info_st)), + .triggers = g_array_new(false, true, sizeof(mcd_active_trigger)), .vm_state_change_handler = NULL, + .num_created_triggers = 0, }; pstrcpy(c.info.core, MCD_UNIQUE_NAME_LEN, cpu_model); g_array_append_val(g_server_state.cores, c); @@ -339,6 +376,7 @@ mcd_return_et mcd_close_server_f(const mcd_server_st *server) g_array_free(c->memory_spaces, true); g_array_free(c->register_groups, true); g_array_free(c->registers, true); + g_array_free(c->triggers, true); } g_array_free(g_server_state.cores, true); @@ -682,6 +720,8 @@ mcd_return_et mcd_open_core_f(const mcd_core_con_info_st *core_con_info, core_state->last_error = &MCD_ERROR_NONE; core_state->vm_state_change_handler = qemu_add_vm_change_state_handler( mcd_handle_vm_state_change, core_state); + g_array_set_size(core_state->triggers, 0); + core_state->num_created_triggers = 0; g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; @@ -722,6 +762,8 @@ mcd_return_et mcd_close_core_f(const mcd_core_st *core) g_array_set_size(core_state->memory_spaces, 0); g_array_set_size(core_state->register_groups, 0); g_array_set_size(core_state->registers, 0); + g_array_set_size(core_state->triggers, 0); + core_state->num_created_triggers = 0; g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; @@ -1037,68 +1079,553 @@ mcd_return_et mcd_qry_reg_compound_f(const mcd_core_st *core, mcd_return_et mcd_qry_trig_info_f(const mcd_core_st *core, mcd_trig_info_st *trig_info) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (!trig_info) { + core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return core_state->last_error->return_status; + } + + *trig_info = (mcd_trig_info_st){ + .type = MCD_TRIG_TYPE_IP | + MCD_TRIG_TYPE_READ | + MCD_TRIG_TYPE_WRITE | + MCD_TRIG_TYPE_RW, + .option = MCD_TRIG_OPT_DEFAULT, + .action = MCD_TRIG_ACTION_DBG_DEBUG, + .trig_number = 0, + .state_number = 0, + .counter_number = 0, + .sw_breakpoints = false, + }; + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_qry_ctrigs_f(const mcd_core_st *core, uint32_t start_index, uint32_t *num_ctrigs, mcd_ctrig_info_st *ctrig_info) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + + if (!core || !num_ctrigs) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (*num_ctrigs == 0) { + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; + } + + if (start_index > 0) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "custom triggers are currently not supported", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + *num_ctrigs = 0; + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; +} + +static mcd_return_et mcd_create_trig_simple_core(mcdcore_state *core_state, + mcd_trig_simple_core_st *trig) +{ + uint32_t ms_id = trig->addr_start.mem_space_id; + const mcd_memspace_st *ms; + int ret_val; + + /* memory space ID 0 is reserved */ + if (ms_id == 0 || ms_id > core_state->memory_spaces->len) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "unknown memory space ID", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + ms = &g_array_index(core_state->memory_spaces, mcd_memspace_st, ms_id - 1); + if (!(ms->mem_type & MCD_MEM_SPACE_IS_LOGICAL)) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "only logical trigger addresses are supported", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + switch (trig->type) { + case MCD_TRIG_TYPE_IP: + ret_val = cpu_breakpoint_insert(core_state->cpu, + trig->addr_start.address, + BP_GDB, NULL); + break; + case MCD_TRIG_TYPE_WRITE: + ret_val = cpu_watchpoint_insert(core_state->cpu, + trig->addr_start.address, 4, + BP_GDB | BP_MEM_WRITE, NULL); + break; + case MCD_TRIG_TYPE_READ: + ret_val = cpu_watchpoint_insert(core_state->cpu, + trig->addr_start.address, 4, + BP_GDB | BP_MEM_READ, NULL); + break; + case MCD_TRIG_TYPE_RW: + ret_val = cpu_watchpoint_insert(core_state->cpu, + trig->addr_start.address, 4, + BP_GDB | BP_MEM_ACCESS, NULL); + break; + default: + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TRIG_CREATE, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "unknown trigger type", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (ret_val != 0) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TRIG_CREATE, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "trigger could not be created", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + return MCD_RET_ACT_NONE; } mcd_return_et mcd_create_trig_f(const mcd_core_st *core, void *trig, uint32_t *trig_id) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + uint32_t struct_size; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (!trig || !trig_id) { + core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return core_state->last_error->return_status; + } + + struct_size = *((uint32_t *)trig); + if (struct_size == (uint32_t) sizeof(mcd_trig_simple_core_st) || + struct_size == (uint32_t) sizeof(mcd_trig_complex_core_st)) + { + /* only trig_simple_cores are currently supported */ + mcd_trig_simple_core_st *simple_trig = (mcd_trig_simple_core_st *)trig; + + if (mcd_create_trig_simple_core(core_state, simple_trig) != + MCD_RET_ACT_NONE) { + return core_state->last_error->return_status; + } + + *trig_id = ++core_state->num_created_triggers; + mcd_active_trigger t = { + .trig = *simple_trig, + .id = *trig_id, + .captured = false, + }; + g_array_append_val(core_state->triggers, t); + } else { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TRIG_CREATE, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "trigger with struct_size not supported", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; +} + +/* + * find_trig() - Searches for a trigger with trig_id in the core-internal + * trigger list. If found, the trigger as well as (optionally) + * its index in the internal list are returned. + */ +static mcd_active_trigger *find_trig(mcdcore_state *core_state, + uint32_t trig_id, + uint32_t *trig_array_index) +{ + g_assert(core_state->triggers); + for (uint32_t i = 0; i < core_state->triggers->len; i++) { + mcd_active_trigger *t = &g_array_index(core_state->triggers, + mcd_active_trigger, i); + if (t->id == trig_id) { + if (trig_array_index) { + *trig_array_index = i; + } + return t; + } + } + + return NULL; } mcd_return_et mcd_qry_trig_f(const mcd_core_st *core, uint32_t trig_id, uint32_t max_trig_size, void *trig) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + mcd_active_trigger *active_trig; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (max_trig_size < sizeof(*active_trig)) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_RESULT_TOO_LONG, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (!trig) { + core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return core_state->last_error->return_status; + } + + active_trig = find_trig(core_state, trig_id, NULL); + if (!active_trig) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TRIG_ACCESS, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "trigger with trig_id not found", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + memcpy(trig, &active_trig->trig, sizeof(active_trig->trig)); + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; +} + +static mcd_return_et mcd_remove_trig_simple_core(mcdcore_state *core_state, + mcd_trig_simple_core_st *trig) +{ + int ret_val; + + switch (trig->type) { + case MCD_TRIG_TYPE_IP: + ret_val = cpu_breakpoint_remove(core_state->cpu, + trig->addr_start.address, + BP_GDB); + break; + case MCD_TRIG_TYPE_WRITE: + ret_val = cpu_watchpoint_remove(core_state->cpu, + trig->addr_start.address, 4, + BP_GDB | BP_MEM_WRITE); + break; + case MCD_TRIG_TYPE_READ: + ret_val = cpu_watchpoint_remove(core_state->cpu, + trig->addr_start.address, 4, + BP_GDB | BP_MEM_READ); + break; + case MCD_TRIG_TYPE_RW: + ret_val = cpu_watchpoint_remove(core_state->cpu, + trig->addr_start.address, 4, + BP_GDB | BP_MEM_ACCESS); + break; + default: + g_assert_not_reached(); + } + + if (ret_val != 0) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TRIG_CREATE, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "trigger could not be removed", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + return MCD_RET_ACT_NONE; } mcd_return_et mcd_remove_trig_f(const mcd_core_st *core, uint32_t trig_id) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + mcd_active_trigger *trig; + uint32_t trig_index; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + trig = find_trig(core_state, trig_id, &trig_index); + if (!trig) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TRIG_ACCESS, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "trigger with trig_id not found", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (mcd_remove_trig_simple_core(core_state, &trig->trig) + != MCD_RET_ACT_NONE) { + return core_state->last_error->return_status; + } + + g_array_remove_index(core_state->triggers, trig_index); + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_qry_trig_state_f(const mcd_core_st *core, uint32_t trig_id, mcd_trig_state_st *trig_state) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + mcd_active_trigger *trig; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (!trig_state) { + core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return core_state->last_error->return_status; + } + + trig = find_trig(core_state, trig_id, NULL); + if (!trig) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_TRIG_ACCESS, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "trigger with trig_id not found", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + /* triggers are always active */ + *trig_state = (mcd_trig_state_st) { + .active = true, + .captured = trig->captured, + .captured_valid = true, + .count_valid = false, + }; + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_activate_trig_set_f(const mcd_core_st *core) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + /* Triggers are already activated when being created */ + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_remove_trig_set_f(const mcd_core_st *core) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + g_assert(core_state->triggers); + + while (core_state->triggers->len > 0) { + uint32_t len = core_state->triggers->len; + mcd_active_trigger *trig = &g_array_index(core_state->triggers, + mcd_active_trigger, 0); + if (mcd_remove_trig_f(core, trig->id) != MCD_RET_ACT_NONE) { + return core_state->last_error->return_status; + } + g_assert(core_state->triggers->len == len - 1); + } + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_qry_trig_set_f(const mcd_core_st *core, uint32_t start_index, uint32_t *num_trigs, uint32_t *trig_ids) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + uint32_t i; + mcdcore_state *core_state; + + if (!core || !num_trigs) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + g_assert(core_state->triggers); + + if (*num_trigs == 0) { + *num_trigs = core_state->triggers->len; + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; + } + + if (start_index >= core_state->triggers->len) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "start_index exceeds the number of triggers", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (!trig_ids) { + core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return core_state->last_error->return_status; + } + + for (i = 0; i < *num_trigs && + start_index + i < core_state->triggers->len; i++) { + + mcd_active_trigger *t = &g_array_index(core_state->triggers, + mcd_active_trigger, + start_index + i); + trig_ids[i] = t->id; + } + + *num_trigs = i; + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_qry_trig_set_state_f(const mcd_core_st *core, mcd_trig_set_state_st *trig_state) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + mcdcore_state *core_state; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (!trig_state) { + core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return core_state->last_error->return_status; + } + + *trig_state = (mcd_trig_set_state_st) { + .active = true, + .state_valid = false, + .trig_bus_valid = false, + .trace_valid = false, + .analysis_valid = false, + }; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } @@ -1505,6 +2032,26 @@ mcd_return_et mcd_qry_state_f(const mcd_core_st *core, mcd_core_state_st *state) break; } + if (state->state == MCD_CORE_STATE_DEBUG && g_server_state.bp_cpu) { + if (g_server_state.bp_cpu == core_state->cpu) { + state->event = MCD_CORE_EVENT_TRIGGER_CHANGE; + GArray *trigs = core_state->triggers; + for (int i = 0; i < trigs->len; i++) { + mcd_active_trigger *t = &g_array_index(trigs, + mcd_active_trigger, i); + if (g_server_state.bp_addr >= t->trig.addr_start.address + && g_server_state.bp_addr <= t->trig.addr_start.address + + t->trig.addr_range) { + state->trig_id = t->id; + t->captured = true; + } + } + g_server_state.bp_cpu = NULL; + } else { + state->state = MCD_CORE_STATE_HALTED; + } + } + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index 872fb7c9da..a1d5cbc5d9 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -621,3 +621,293 @@ MCDQryStateResult *qmp_mcd_qry_state(uint32_t core_uid, Error **errp) g_stub_state.on_error_ask_server = true; return result; } + +MCDQryTrigInfoResult *qmp_mcd_qry_trig_info(uint32_t core_uid, Error **errp) +{ + MCDQryTrigInfoResult *result = g_malloc0(sizeof(*result)); + mcd_trig_info_st trig_info; + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_qry_trig_info_f(core, &trig_info); + if (result->return_status == MCD_RET_ACT_NONE) { + result->trig_info = marshal_mcd_trig_info(&trig_info); + } + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDQryCtrigsResult *qmp_mcd_qry_ctrigs(uint32_t core_uid, uint32_t start_index, + uint32_t num_ctrigs, Error **errp) +{ + MCDCtrigInfoList **tailp; + MCDCtrigInfo *info; + MCDQryCtrigsResult *result = g_malloc0(sizeof(*result)); + mcd_ctrig_info_st *ctrig_info = NULL; + bool query_num_only = num_ctrigs == 0; + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + if (!query_num_only) { + ctrig_info = g_malloc0(num_ctrigs * sizeof(*ctrig_info)); + } + + result->return_status = mcd_qry_ctrigs_f(core, start_index, &num_ctrigs, + ctrig_info); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_num_ctrigs = true; + result->num_ctrigs = num_ctrigs; + if (!query_num_only) { + result->has_ctrig_info = true; + tailp = &(result->ctrig_info); + for (uint32_t i = 0; i < num_ctrigs; i++) { + info = marshal_mcd_ctrig_info(ctrig_info + i); + QAPI_LIST_APPEND(tailp, info); + } + } + } + + if (!query_num_only) { + g_free(ctrig_info); + } + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDCreateTrigResult *qmp_mcd_create_trig(uint32_t core_uid, MCDTrig *trig, + Error **errp) +{ + MCDCreateTrigResult *result = g_malloc0(sizeof(*result)); + mcd_trig_simple_core_st trig_simple; + mcd_trig_complex_core_st trig_complex; + void *trig_p; + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + + if (trig->trig_simple_core) { + trig_simple = unmarshal_mcd_trig_simple_core(trig->trig_simple_core); + trig_p = (void *) &trig_simple; + } else if (trig->trig_complex_core) { + trig_complex = unmarshal_mcd_trig_complex_core(trig->trig_complex_core); + trig_p = (void *) &trig_complex; + } else { + g_assert_not_reached(); + } + + uint32_t trig_id; + result->return_status = mcd_create_trig_f(core, trig_p, &trig_id); + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_trig_id = true; + result->trig_id = trig_id; + result->trig = g_malloc0(sizeof(*result->trig)); + if (trig_p == &trig_simple) { + result->trig->trig_simple_core = + marshal_mcd_trig_simple_core(&trig_simple); + result->trig->trig_complex_core = NULL; + } else if (trig_p == &trig_complex) { + result->trig->trig_complex_core = + marshal_mcd_trig_complex_core(&trig_complex); + result->trig->trig_simple_core = NULL; + } else { + g_assert_not_reached(); + } + } + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDQryTrigResult *qmp_mcd_qry_trig(uint32_t core_uid, uint32_t trig_id, + Error **errp) +{ + MCDQryTrigResult *result = g_malloc0(sizeof(*result)); + /* Currently, only trig simple and complex cores are supported */ + mcd_trig_complex_core_st trig; + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_qry_trig_f(core, trig_id, sizeof(trig), &trig); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->trig = g_malloc0(sizeof(*result->trig)); + if (trig.struct_size == sizeof(mcd_trig_complex_core_st)) { + result->trig->trig_complex_core = + marshal_mcd_trig_complex_core(&trig); + } else if (trig.struct_size == sizeof(mcd_trig_simple_core_st)) { + mcd_trig_simple_core_st *trig_simple = + (mcd_trig_simple_core_st *) &trig; + result->trig->trig_simple_core = + marshal_mcd_trig_simple_core(trig_simple); + } else { + g_assert_not_reached(); + } + } + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDRemoveTrigResult *qmp_mcd_remove_trig(uint32_t core_uid, uint32_t trig_id, + Error **errp) +{ + MCDRemoveTrigResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_remove_trig_f(core, trig_id); + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDQryTrigStateResult *qmp_mcd_qry_trig_state(uint32_t core_uid, + uint32_t trig_id, Error **errp) +{ + MCDQryTrigStateResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + mcd_trig_state_st trig_state; + result->return_status = mcd_qry_trig_state_f(core, trig_id, &trig_state); + if (result->return_status == MCD_RET_ACT_NONE) { + result->trig_state = marshal_mcd_trig_state(&trig_state); + } + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDActivateTrigSetResult *qmp_mcd_activate_trig_set(uint32_t core_uid, + Error **errp) +{ + MCDActivateTrigSetResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_activate_trig_set_f(core); + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDActivateTrigSetResult *qmp_mcd_remove_trig_set(uint32_t core_uid, + Error **errp) +{ + MCDActivateTrigSetResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_remove_trig_set_f(core); + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDQryTrigSetResult *qmp_mcd_qry_trig_set(uint32_t core_uid, + uint32_t start_index, + uint32_t num_trigs, Error **errp) +{ + uint32List **tailp; + MCDQryTrigSetResult *result = g_malloc0(sizeof(*result)); + uint32_t *trig_ids = NULL; + bool query_num_only = num_trigs == 0; + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + if (!query_num_only) { + trig_ids = g_malloc0(num_trigs * sizeof(*trig_ids)); + } + + result->return_status = mcd_qry_trig_set_f(core, start_index, &num_trigs, + trig_ids); + + if (result->return_status == MCD_RET_ACT_NONE) { + result->has_num_trigs = true; + result->num_trigs = num_trigs; + if (!query_num_only) { + result->has_trig_ids = true; + tailp = &(result->trig_ids); + for (uint32_t i = 0; i < num_trigs; i++) { + QAPI_LIST_APPEND(tailp, trig_ids[i]); + } + } + } + + if (!query_num_only) { + g_free(trig_ids); + } + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDQryTrigSetStateResult *qmp_mcd_qry_trig_set_state(uint32_t core_uid, + Error **errp) +{ + MCDQryTrigSetStateResult *result = g_malloc0(sizeof(*result)); + mcd_trig_set_state_st trig_state; + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_qry_trig_set_state_f(core, &trig_state); + if (result->return_status == MCD_RET_ACT_NONE) { + result->trig_state = marshal_mcd_trig_set_state(&trig_state); + } + + g_stub_state.on_error_ask_server = true; + return result; +} diff --git a/qapi/mcd.json b/qapi/mcd.json index b4f21995e3..8934d2d057 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -306,6 +306,238 @@ 'reg-type' : 'uint32', 'hw-thread-id' : 'uint32' } } + +## +# @MCDTrigInfo: +# +# Structure type containing information about trigger capabilities. +# +# @type: Supported trigger types (OR'ed bitmask). +# @option: Supported trigger options (OR'ed bitmask). +# @action: Supported trigger actions (OR'ed bitmask). +# @trig-number: Number of usable triggers (or 0 if number not known). +# @state-number: Number of states of the trigger set's state machine (or 0 if +# not known). +# @counter-number: Number of usable counters (or 0 if not known) +# @sw-breakpoints: True if software breakpoints via code patch are available. +# +# Since: 9.1 +## +{ 'struct': 'MCDTrigInfo', + 'data': { + 'type' : 'uint32', + 'option' : 'uint32', + 'action' : 'uint32', + 'trig-number' : 'uint32', + 'state-number' : 'uint32', + 'counter-number': 'uint32', + 'sw-breakpoints': 'bool' } } + + +## +# @MCDCtrigInfo: +# +# Structure type containing information about a custom trigger. +# +# @ctrig-id: Custom trigger ID, ID 0 is reserved. +# @info-str: Description of the custom trigger. +# +# Since: 9.1 +## +{ 'struct': 'MCDCtrigInfo', + 'data': { + 'ctrig-id': 'uint32', + 'info-str': 'str' } } + + +## +# @MCDTrigSimpleCore: +# +# Structure type containing information about a simple core trigger condition. +# +# @type: Trigger type, for this structure type it must be one of: +# - %MCD_TRIG_TYPE_IP +# - %MCD_TRIG_TYPE_READ +# - %MCD_TRIG_TYPE_WRITE +# - %MCD_TRIG_TYPE_RW +# - %MCD_TRIG_TYPE_NOCYCLE +# @option: Adds further qualifiers to the trigger or overrides the +# behaviour (multiple options possible) +# @action: Action to be taken on trigger. Only one per trigger allowed. +# @action-param: Parameter for action - depends on the selected action. +# @modified: Set to "TRUE" on return of @mcd-create-trig if trigger +# was modified by implementation, untouched otherwise. +# @state-mask: Set bits indicate that this trigger is inactive when +# reaching the corresponding state of the state machine. Bit 0 +# represents state '1' of the state machine. Only to be +# considered if %MCD_TRIG_OPT_STATE_IS_CONDITION is set in +# @option. +# @addr-start: Start address for the address range the trigger shall be +# activated for. +# @addr-range: Size of the address range for the trigger (in bytes). If it +# is set to '0', the trigger is activated by an access to a +# single address. If it is set to '1', the range of addresses +# is two (@addr_start + 1). The address range can be +# "inverted" if %MCD_TRIG_OPT_OUT_OF_RANGE is set in @option. +# +# Since: 9.1 +## +{ 'struct': 'MCDTrigSimpleCore', + 'data': { + 'type' : 'uint32', + 'option' : 'uint32', + 'action' : 'uint32', + 'action-param': 'uint32', + 'modified' : 'bool', + 'state-mask' : 'uint32', + 'addr-start' : 'MCDAddr', + 'addr-range' : 'uint64' }} + + +## +# @MCDTrigComplexCore: +# +# Structure type containing information about a complex core trigger condition. +# +# @type: Trigger type, for this structure type it must be one of: +# - %MCD_TRIG_TYPE_IP +# - %MCD_TRIG_TYPE_READ +# - %MCD_TRIG_TYPE_WRITE +# - %MCD_TRIG_TYPE_RW +# - %MCD_TRIG_TYPE_NOCYCLE +# @option: Adds further qualifiers to the trigger or overrides the +# behaviour (multiple options possible) +# @action: Action to be taken on trigger. Only one per trigger allowed. +# @action-param: Parameter for action - depends on the selected action. +# @modified: Set to "TRUE" on return of @mcd-create-trig if trigger +# was modified by implementation, untouched otherwise. +# @state-mask: Set bits indicate that this trigger is inactive when +# reaching the corresponding state of the state machine. Bit 0 +# represents state '1' of the state machine. Only to be +# considered if %MCD_TRIG_OPT_STATE_IS_CONDITION is set in +# @option. +# @addr-start: Start address for the address range the trigger shall be +# activated for. +# @addr-range: Size of the address range for the trigger (in bytes). If it +# is set to '0', the trigger is activated by an access to a +# single address. If it is set to '1', the range of addresses +# is two (@addr_start + 1). The address range can be +# "inverted" if %MCD_TRIG_OPT_OUT_OF_RANGE is set in @option. +# @data-start: Data comparison value of the trigger. Only considered if +# %MCD_TRIG_OPT_DATA_IS_CONDITION is set in @option. Setting +# option %MCD_TRIG_OPT_NOT_DATA activates the trigger on a +# data mismatch. +# @data-range: Size of the data value range for the trigger. If it is set +# to '0', the trigger is activated on a match with a single +# value. If it is set to '1', the range of values is two +# (@data_range + 1). Option %MCD_TRIG_OPT_SIGNED_DATA may be +# set in @option if the data shall be interpreted as signed. +# This usually also requires the option +# %MCD_TRIG_OPT_DATASIZE_IS_CONDITION to be set in @option. +# @data-mask: Only value bits are considered for which the mask is set to +# '0' +# @data-size: Size of the access in bytes. If set to '0' the size shall +# not be considered. Shall be only considered if +# %MCD_TRIG_OPT_DATASIZE_IS_CONDITION is set in @option. +# @hw-thread-id: ID of the hardware thread this trigger is associated with. +# @sw-thread-id: ID of the software thread this trigger is associated with. +# @core-mode-mask: Mask of core modes for which the trigger shall not be +# activated. A set bit disables the trigger for the +# corresponding mode. Bit 0 represents core mode '1', bit 31 +# represents core mode '32'. +# +# Since: 9.1 +## +{ 'struct': 'MCDTrigComplexCore', + 'data': { + 'type' : 'uint32', + 'option' : 'uint32', + 'action' : 'uint32', + 'action-param' : 'uint32', + 'modified' : 'bool', + 'state-mask' : 'uint32', + 'addr-start' : 'MCDAddr', + 'addr-range' : 'uint64', + 'data-start' : 'uint64', + 'data-range' : 'uint64', + 'data-mask' : 'uint64', + 'data-size' : 'uint32', + 'hw-thread-id' : 'uint32', + 'sw-thread-id' : 'uint64', + 'core-mode-mask': 'uint32' }} + + +## +# @MCDTrig: +# +# Compound structure which can be set to every supported trigger type. +# Only one member is supposed to be set at once. +# +# @trig-simple-core: Simple core trigger condition. +# @trig-complex-core: Complex core trigger condition. +# +# Since: 9.1 +## +{ 'struct': 'MCDTrig', + 'data': { + '*trig-simple-core': 'MCDTrigSimpleCore', + '*trig-complex-core': 'MCDTrigComplexCore' } } + + +## +# @MCDTrigState: +# +# Structure type containing a trigger state. +# +# @active: Was active at the point of time the trigger set was +# uploaded. +# @captured: Activated at least once after trigger got downloaded to the +# target. +# @captured-valid: The information in @captured is valid. +# @count-value: Current value of the counter (for counter triggers). +# @count-valid: The information in @count-value is valid. +# +# Since: 9.1 +## +{ 'struct': 'MCDTrigState', + 'data': { + 'active' : 'bool', + 'captured' : 'bool', + 'captured-valid': 'bool', + 'count-value' : 'uint64', + 'count-valid' : 'bool' } } + + +## +# @MCDTrigSetState: +# +# Structure type containing a trigger state. +# +# @active: Set if the trigger set is currently active. +# @state: Current state of the trigger set's state machine. +# @state-valid: Current state is valid. +# @trig-bus: Current state of trigger bus. +# @trig-bus-valid: Current state of trig-bus is valid. +# @trace: Current state of trace start/stop. +# @trace-valid: Current state is valid. +# @analysis: Current state of performance analysis start/stop. +# @analysis-valid: Current state is valid. +# +# Since: 9.1 +## +{ 'struct': 'MCDTrigSetState', + 'data': { + 'active' : 'bool', + 'state' : 'uint32', + 'state-valid' : 'bool', + 'trig-bus' : 'uint32', + 'trig-bus-valid': 'bool', + 'trace' : 'bool', + 'trace-valid' : 'bool', + 'analysis' : 'bool', + 'analysis-valid': 'bool' } } + + ## # @MCDTx: # @@ -1647,3 +1879,359 @@ { 'command': 'mcd-qry-state', 'data': { 'core-uid': 'uint32' }, 'returns': 'MCDQryStateResult' } + + +## +# == Target Trigger Setup API +## + + +## +# @MCDQryTrigInfoResult: +# +# Return value of @mcd-qry-trig-info. +# +# @return-status: Return code. +# @trig-info: Information about supported triggers. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryTrigInfoResult', + 'data': { + 'return-status': 'uint32', + '*trig-info' : 'MCDTrigInfo' }} + + +## +# @mcd-qry-trig-info: +# +# Function querying information about trigger capabilities. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# +# Returns: @MCDQryTrigInfoResult +# +# Since: 9.1 +## +{ 'command': 'mcd-qry-trig-info', + 'data': { 'core-uid': 'uint32' }, + 'returns': 'MCDQryTrigInfoResult' } + + +## +# @MCDQryCtrigsResult: +# +# Return value of @mcd-qry-ctrigs. +# +# @return-status: Return code. +# @num-ctrigs: Number of returned custom triggers. In case the input value of +# @num_ctrigs is '0', this is the number of all available custom +# triggers for the selected core. +# @ctrig-info: Custom trigger information. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryCtrigsResult', + 'data': { + 'return-status': 'uint32', + '*num-ctrigs' : 'uint32', + '*ctrig-info' : [ 'MCDCtrigInfo' ] }} + + +## +# @mcd-qry-ctrigs: +# +# Function querying information about custom triggers. +# +# @core-uid: Unique identifier of the open core as returned by +# @mcd-open-core. +# @start-index: Start index of the requested custom triggers. This refers +# to an internal list of the target side implementation. +# @num-ctrigs: Number of custom triggers, information is requested of. If it is +# set to '0', no custom trigger information is returned but the +# number of all available custom triggers for the selected core. +# +# Returns: @MCDQryCtrigsResult +# +# Since: 9.1 +## +{ 'command': 'mcd-qry-ctrigs', + 'data': { + 'core-uid' : 'uint32', + 'start-index': 'uint32', + 'num-ctrigs' : 'uint32' }, + 'returns': 'MCDQryCtrigsResult' } + + +## +# @MCDCreateTrigResult: +# +# Return value of @mcd-create-trig. +# +# @return-status: Return code. +# @trig: Information about the created trigger object. +# @trig-id: Unique ID for the newly created trigger returned by the API +# implementation. A value of '0' indicates that the breakpoint +# is set, but cannot be identified by an ID. Removing such +# breakpoints is only possible by calling @mcd-remove-trig-set. +# +# Since: 9.1 +## +{ 'struct': 'MCDCreateTrigResult', + 'data': { + 'return-status': 'uint32', + '*trig' : 'MCDTrig', + '*trig-id' : 'uint32' }} + + +## +# @mcd-create-trig: +# +# Function allowing the creation of a new trigger. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# @trig: Information about the trigger object to be created. +# +# Returns: @MCDCreateTrigResult +# +# Since: 9.1 +## +{ 'command': 'mcd-create-trig', + 'data': { + 'core-uid': 'uint32', + 'trig' : 'MCDTrig' }, + 'returns': 'MCDCreateTrigResult' } + + +## +# @MCDQryTrigResult: +# +# Return value of @mcd-qry-trig. +# +# @return-status: Return code. +# @trig: Information about the trigger object. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryTrigResult', + 'data': { + 'return-status': 'uint32', + '*trig' : 'MCDTrig' }} + + +## +# @mcd-qry-trig: +# +# Function querying the contents of a trigger. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# @trig-id: ID of the trigger the user queries. +# +# Returns: @MCDQryTrigResult +# +# Since: 9.1 +## +{ 'command': 'mcd-qry-trig', + 'data': { + 'core-uid': 'uint32', + 'trig-id' : 'uint32'}, + 'returns': 'MCDQryTrigResult' } + + +## +# @MCDRemoveTrigResult: +# +# Return value of @mcd-remove-trig. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDRemoveTrigResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-remove-trig: +# +# Function allowing a user to delete a particular trigger from a trigger set. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# @trig-id: ID of the trigger the user wants to delete. +# +# Returns: @MCDRemoveTrigResult +# +# Since: 9.1 +## +{ 'command': 'mcd-remove-trig', + 'data': { + 'core-uid': 'uint32', + 'trig-id' : 'uint32' }, + 'returns': 'MCDRemoveTrigResult' } + + +## +# @MCDQryTrigStateResult: +# +# Return value of @mcd-qry-trig-state. +# +# @return-status: Return code. +# @trig-state: Queried Trigger state. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryTrigStateResult', + 'data': { + 'return-status': 'uint32', + '*trig-state' : 'MCDTrigState' }} + + +## +# @mcd-qry-trig-state: +# +# Function allowing a user to query the trigger states from the target. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# @trig-id: ID of the trigger, the tool queries the state for. +# +# Returns: @MCDQryTrigStateResult +# +# Since: 9.1 +## +{ 'command': 'mcd-qry-trig-state', + 'data': { + 'core-uid': 'uint32', + 'trig-id' : 'uint32' }, + 'returns': 'MCDQryTrigStateResult' } + + +## +# @MCDActivateTrigSetResult: +# +# Return value of @mcd-activate-trig-set. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDActivateTrigSetResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-activate-trig-set: +# +# Function allowing a user to activate a trigger set on the target. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# +# Returns: @MCDActivateTrigSetResult +# +# Since: 9.1 +## +{ 'command': 'mcd-activate-trig-set', + 'data': { 'core-uid': 'uint32' }, + 'returns': 'MCDActivateTrigSetResult' } + + +## +# @MCDRemoveTrigSetResult: +# +# Return value of @mcd-remove-trig-set. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDRemoveTrigSetResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-remove-trig-set: +# +# Function allowing a user to delete a trigger set. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# +# Returns: @MCDActivateTrigSetResult +# +# Since: 9.1 +## +{ 'command': 'mcd-remove-trig-set', + 'data': { 'core-uid': 'uint32' }, + 'returns': 'MCDActivateTrigSetResult' } + + +## +# @MCDQryTrigSetResult: +# +# Return value of @mcd-qry-trig-set. +# +# @return-status: Return code. +# @num-trigs: The number of returned triggers. In case the input value of +# @num_trigs is '0', this is the number of all available triggers +# of this core's trigger set. +# @trig-ids: List of trigger IDs set in the target. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryTrigSetResult', + 'data': { + 'return-status': 'uint32', + '*num-trigs' : 'uint32', + '*trig-ids' : [ 'uint32' ] }} + + +## +# @mcd-qry-trig-set: +# +# Function querying the contents of a trigger set. +# +# @core-uid: Unique identifier of the open core as returned by +# @mcd-open-core. +# @start-index: Start index of the requested triggers. This refers to an +# internal list of the target side implementation. +# @num-trigs: The number of queried triggers starting from the defined +# @start-index. If it is set to '0', no triggers are returned but +# the number of all available triggers of the trigger set. +# +# Returns: @MCDQryTrigSetResult +# +# Since: 9.1 +## +{ 'command': 'mcd-qry-trig-set', + 'data': { + 'core-uid' : 'uint32', + 'start-index': 'uint32', + 'num-trigs' : 'uint32' }, + 'returns': 'MCDQryTrigSetResult' } + + +## +# @MCDQryTrigSetStateResult: +# +# Return value of @mcd-qry-trig-set-state. +# +# @return-status: Return code. +# @trig-state: Information about the current state of the trigger set. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryTrigSetStateResult', + 'data': { + 'return-status': 'uint32', + '*trig-state' : 'MCDTrigSetState' }} + + +## +# @mcd-qry-trig-set-state: +# +# Function querying the state of a trigger set. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# +# Returns: @MCDQryTrigSetStateResult +# +# Since: 9.1 +## +{ 'command': 'mcd-qry-trig-set-state', + 'data': { 'core-uid': 'uint32' }, + 'returns': 'MCDQryTrigSetStateResult' } From patchwork Mon Mar 10 15:05:10 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Fleischmann X-Patchwork-Id: 14010267 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 13EF2C282EC for ; Mon, 10 Mar 2025 15:13:26 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1trena-0002JS-Tg; Mon, 10 Mar 2025 11:12:11 -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 1tren8-0002A8-Ca for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:43 -0400 Received: from smtp1.lauterbach.com ([62.154.241.196]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tren2-0007iJ-0R for qemu-devel@nongnu.org; Mon, 10 Mar 2025 11:11:42 -0400 Received: (qmail 30984 invoked by uid 484); 10 Mar 2025 15:11:14 -0000 X-Qmail-Scanner-Diagnostics: from 10.2.13.100 by smtp1.lauterbach.com (envelope-from , uid 484) with qmail-scanner-2.11 (mhr: 1.0. clamdscan: 0.99/21437. spamassassin: 3.4.0. Clear:RC:1(10.2.13.100):. Processed in 0.248327 secs); 10 Mar 2025 15:11:14 -0000 Received: from unknown (HELO mflpc1.LTB.LAN) (Authenticated_SSL:mfleischmann@[10.2.13.100]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 10 Mar 2025 15:11:13 -0000 From: Mario Fleischmann To: qemu-devel@nongnu.org Cc: alex.bennee@linaro.org, philmd@linaro.org, armbru@redhat.com, christian.boenig@lauterbach.com, Mario Fleischmann , Eric Blake Subject: [PATCH 16/16] mcd: Implement reset control Date: Mon, 10 Mar 2025 16:05:10 +0100 Message-Id: <20250310150510.200607-17-mario.fleischmann@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> References: <20250310150510.200607-1-mario.fleischmann@lauterbach.com> MIME-Version: 1.0 X-Qmail-Scanner-2.11: added fake Content-Type header Received-SPF: pass client-ip=62.154.241.196; envelope-from=mario.fleischmann@lauterbach.com; helo=smtp1.lauterbach.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_PASS=-0.001, T_SPF_HELO_TEMPERROR=0.01 autolearn=ham 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Provide a system reset vector and handle it similar to hmp_system_reset We don't use a QMP related shutdown reason because the mcdserver is implemented independent of the used communication protocol. (In fact, another communication protocol implementation for MCD already exists and can be found at https://gitlab.com/lauterbach/mcdrefsrv) Signed-off-by: Mario Fleischmann --- mcd/libmcd_qapi.c | 12 +++++ mcd/libmcd_qapi.h | 2 + mcd/mcdserver.c | 98 ++++++++++++++++++++++++++++++++-- mcd/mcdstub_qapi.c | 61 +++++++++++++++++++++ qapi/mcd.json | 129 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 297 insertions(+), 5 deletions(-) diff --git a/mcd/libmcd_qapi.c b/mcd/libmcd_qapi.c index db3d11d3e5..888a92dcb8 100644 --- a/mcd/libmcd_qapi.c +++ b/mcd/libmcd_qapi.c @@ -492,3 +492,15 @@ void free_mcd_txlist(mcd_txlist_st *txlist) g_free(txlist->tx); } + +MCDRstInfo *marshal_mcd_rst_info(const mcd_rst_info_st *rst_info) +{ + MCDRstInfo *marshal = g_malloc0(sizeof(*marshal)); + + *marshal = (MCDRstInfo) { + .class_vector = rst_info->class_vector, + .info_str = g_strdup(rst_info->info_str), + }; + + return marshal; +} diff --git a/mcd/libmcd_qapi.h b/mcd/libmcd_qapi.h index 133dfbf9d3..220698c957 100644 --- a/mcd/libmcd_qapi.h +++ b/mcd/libmcd_qapi.h @@ -56,6 +56,8 @@ MCDTx *marshal_mcd_tx(const mcd_tx_st *tx); MCDTxlist *marshal_mcd_txlist(const mcd_txlist_st *txlist); +MCDRstInfo *marshal_mcd_rst_info(const mcd_rst_info_st *rst_info); + mcd_api_version_st unmarshal_mcd_api_version(MCDAPIVersion *api_version); mcd_core_con_info_st unmarshal_mcd_core_con_info(MCDCoreConInfo *con_info); diff --git a/mcd/mcdserver.c b/mcd/mcdserver.c index 649c4d387b..a5995ae09e 100644 --- a/mcd/mcdserver.c +++ b/mcd/mcdserver.c @@ -21,6 +21,8 @@ /* Custom memory space type */ static const mcd_mem_type_et MCD_MEM_SPACE_IS_SECURE = 0x00010000; +#define MCD_RST_CLASS_SYSTEM_RESET 0 + static const mcd_error_info_st MCD_ERROR_NOT_IMPLEMENTED = { .return_status = MCD_RET_ACT_HANDLE_ERROR, .error_code = MCD_ERR_FN_UNIMPLEMENTED, @@ -2068,24 +2070,110 @@ mcd_return_et mcd_execute_command_f(const mcd_core_st *core, mcd_return_et mcd_qry_rst_classes_f(const mcd_core_st *core, uint32_t *rst_class_vector) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (!rst_class_vector) { + core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return core_state->last_error->return_status; + } + + *rst_class_vector = (1 << MCD_RST_CLASS_SYSTEM_RESET); + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_qry_rst_class_info_f(const mcd_core_st *core, uint8_t rst_class, mcd_rst_info_st *rst_info) { + mcdcore_state *core_state; - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (rst_class != MCD_RST_CLASS_SYSTEM_RESET) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "unknown reset class", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (!rst_info) { + core_state->last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return core_state->last_error->return_status; + } + + *rst_info = (mcd_rst_info_st) { + .class_vector = (1 << MCD_RST_CLASS_SYSTEM_RESET), + .info_str = "System Reset", + }; + + g_server_state.last_error = &MCD_ERROR_NONE; return g_server_state.last_error->return_status; } mcd_return_et mcd_rst_f(const mcd_core_st *core, uint32_t rst_class_vector, bool rst_and_halt) { - g_server_state.last_error = &MCD_ERROR_NOT_IMPLEMENTED; - return g_server_state.last_error->return_status; + mcdcore_state *core_state; + + if (!core) { + g_server_state.last_error = &MCD_ERROR_INVALID_NULL_PARAM; + return g_server_state.last_error->return_status; + } + + core_state = find_core(core->core_con_info); + if (!core_state || core_state->open_core != core) { + g_server_state.last_error = &MCD_ERROR_UNKNOWN_CORE; + return g_server_state.last_error->return_status; + } + + if (rst_class_vector != (1 << MCD_RST_CLASS_SYSTEM_RESET)) { + core_state->custom_error = (mcd_error_info_st) { + .return_status = MCD_RET_ACT_HANDLE_ERROR, + .error_code = MCD_ERR_PARAM, + .error_events = MCD_ERR_EVT_NONE, + .error_str = "unknown reset class", + }; + core_state->last_error = &core_state->custom_error; + return core_state->last_error->return_status; + } + + if (rst_and_halt) { + mcd_return_et ret = mcd_stop_f(core, true); + if (ret != MCD_RET_ACT_NONE) { + return ret; + } + } + + qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_UI); + + core_state->last_error = &MCD_ERROR_NONE; + return core_state->last_error->return_status; } mcd_return_et mcd_chl_open_f(const mcd_core_st *core, mcd_chl_st *channel) diff --git a/mcd/mcdstub_qapi.c b/mcd/mcdstub_qapi.c index a1d5cbc5d9..224a8d2b50 100644 --- a/mcd/mcdstub_qapi.c +++ b/mcd/mcdstub_qapi.c @@ -622,6 +622,67 @@ MCDQryStateResult *qmp_mcd_qry_state(uint32_t core_uid, Error **errp) return result; } +MCDQryRstClassesResult *qmp_mcd_qry_rst_classes(uint32_t core_uid, Error **errp) +{ + MCDQryRstClassesResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_qry_rst_classes_f(core, + &result->rst_class_vector); + result->has_rst_class_vector = result->return_status == MCD_RET_ACT_NONE; + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDQryRstClassInfoResult *qmp_mcd_qry_rst_class_info(uint32_t core_uid, + uint8_t rst_class, + Error **errp) +{ + MCDQryRstClassInfoResult *result = g_malloc0(sizeof(*result)); + mcd_rst_info_st rst_info; + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_qry_rst_class_info_f(core, rst_class, + &rst_info); + if (result->return_status == MCD_RET_ACT_NONE) { + result->rst_info = marshal_mcd_rst_info(&rst_info); + } + + g_stub_state.on_error_ask_server = true; + return result; +} + +MCDRstResult *qmp_mcd_rst(uint32_t core_uid, uint32_t rst_class_vector, + bool rst_and_halt, Error **errp) +{ + MCDRstResult *result = g_malloc0(sizeof(*result)); + mcd_core_st *core = NULL; + + result->return_status = retrieve_open_core(core_uid, &core); + if (result->return_status != MCD_RET_ACT_NONE) { + g_stub_state.on_error_ask_server = false; + return result; + } + + result->return_status = mcd_rst_f(core, rst_class_vector, rst_and_halt); + + g_stub_state.on_error_ask_server = true; + return result; +} + MCDQryTrigInfoResult *qmp_mcd_qry_trig_info(uint32_t core_uid, Error **errp) { MCDQryTrigInfoResult *result = g_malloc0(sizeof(*result)); diff --git a/qapi/mcd.json b/qapi/mcd.json index 8934d2d057..b90cdfab03 100644 --- a/qapi/mcd.json +++ b/qapi/mcd.json @@ -610,6 +610,24 @@ 'stop-str' : 'str', 'info-str' : 'str' } } + +## +# @MCDRstInfo: +# +# Structure type containing information about a particular reset class. +# +# @class-vector: Reset class vector which issues this reset. Exactly one bit +# may be set. +# @info-str: Description of the reset class. +# +# Since: 9.1 +## +{ 'struct': 'MCDRstInfo', + 'data': { + 'class-vector': 'uint32', + 'info-str' : 'str' } } + + ## # == Target Initialization API ## @@ -1881,6 +1899,117 @@ 'returns': 'MCDQryStateResult' } +## +# == Reset Control API +## + + +## +# @MCDQryRstClassesResult: +# +# Return value of @mcd-qry-rst-classes. +# +# @return-status: Return code. +# @rst-class-vector: A 32 bit vector that defines the available reset classes. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryRstClassesResult', + 'data': { + 'return-status': 'uint32', + '*rst-class-vector': 'uint32' }} + + +## +# @mcd-qry-rst-classes: +# +# Function querying information about reset classes supported by the target +# system. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# +# Returns: @MCDQryRstClassesResult +# +# Since: 9.1 +## +{ 'command': 'mcd-qry-rst-classes', + 'data': { 'core-uid': 'uint32' }, + 'returns': 'MCDQryRstClassesResult' } + + +## +# @MCDQryRstClassInfoResult: +# +# Return value of @mcd-qry-rst-class-info. +# +# @return-status: Return code. +# @rst-info: Detailed information about the reset class. +# +# Since: 9.1 +## +{ 'struct': 'MCDQryRstClassInfoResult', + 'data': { + 'return-status': 'uint32', + '*rst-info': 'MCDRstInfo' }} + + +## +# @mcd-qry-rst-class-info: +# +# Function querying information about a particular reset class supported by the +# target system. +# +# @core-uid: Unique identifier of the open core as returned by @mcd-open-core. +# @rst-class: Reset class ID which refers to a bit in the 32-bit reset class +# vector as obtained by @mcd-qry-rst-classes. +# +# Returns: @MCDQryRstClassInfoResult +# +# Since: 9.1 +## +{ 'command': 'mcd-qry-rst-class-info', + 'data': { + 'core-uid' : 'uint32', + 'rst-class': 'uint8'}, + 'returns': 'MCDQryRstClassInfoResult' } + + +## +# @MCDRstResult: +# +# Return value of @mcd-rst. +# +# @return-status: Return code. +# +# Since: 9.1 +## +{ 'struct': 'MCDRstResult', 'data': { 'return-status': 'uint32' } } + + +## +# @mcd-rst: +# +# Function triggering one or more reset signals in parallel on the target +# system. +# +# @core-uid: Unique identifier of the open core as returned by +# @mcd-open-core. +# @rst-class-vector: Reset vector specifying the resets which shall be issued. +# @rst-and-halt: Optionally halting the core if the reset changes the core +# state. +# +# Returns: @MCDRstResult +# +# Since: 9.1 +## +{ 'command': 'mcd-rst', + 'data': { + 'core-uid' : 'uint32', + 'rst-class-vector': 'uint32', + 'rst-and-halt' : 'bool'}, + 'returns': 'MCDRstResult' } + + ## # == Target Trigger Setup API ##