From patchwork Wed Dec 20 16:25:38 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500339 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 861DCC3DA6E for ; Wed, 20 Dec 2023 16:27:23 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzP5-0000RN-GY; Wed, 20 Dec 2023 11:26:39 -0500 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 1rFzOx-0000Mr-EP for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:31 -0500 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 1rFzOr-0004Ur-LI for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:30 -0500 Received: (qmail 15075 invoked by uid 484); 20 Dec 2023 16:26:03 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.35455 secs); 20 Dec 2023 16:26:03 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:02 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 01/18] gdbstub, mcdstub: file and build structure adapted to accomodate for the mcdstub Date: Wed, 20 Dec 2023 17:25:38 +0100 Message-Id: <20231220162555.19545-2-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@lauterbach.com> MIME-Version: 1.0 Received-SPF: pass client-ip=62.154.241.196; envelope-from=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 mcdstub files created including the shared header between the mcd shared library and the mcdstub. MAINTAINERS file updated Reviewed-by: Alex Bennée --- MAINTAINERS | 11 +- debug/common/debug.c | 18 ++++ debug/common/meson.build | 0 {gdbstub => debug/gdbstub}/gdbstub.c | 0 {gdbstub => debug/gdbstub}/internals.h | 0 {gdbstub => debug/gdbstub}/meson.build | 0 {gdbstub => debug/gdbstub}/syscalls.c | 0 {gdbstub => debug/gdbstub}/system.c | 0 {gdbstub => debug/gdbstub}/trace-events | 0 debug/gdbstub/trace.h | 1 + {gdbstub => debug/gdbstub}/user-target.c | 0 {gdbstub => debug/gdbstub}/user.c | 0 debug/mcdstub/arm_mcdstub.c | 18 ++++ debug/mcdstub/mcdstub.c | 18 ++++ debug/mcdstub/meson.build | 0 debug/meson.build | 1 + gdbstub/trace.h | 1 - include/mcdstub/arm_mcdstub.h | 18 ++++ include/mcdstub/mcd_shared_defines.h | 132 +++++++++++++++++++++++ include/mcdstub/mcdstub.h | 18 ++++ include/mcdstub/mcdstub_common.h | 18 ++++ include/qemu/debug.h | 18 ++++ meson.build | 4 +- 23 files changed, 272 insertions(+), 4 deletions(-) create mode 100644 debug/common/debug.c create mode 100644 debug/common/meson.build rename {gdbstub => debug/gdbstub}/gdbstub.c (100%) rename {gdbstub => debug/gdbstub}/internals.h (100%) rename {gdbstub => debug/gdbstub}/meson.build (100%) rename {gdbstub => debug/gdbstub}/syscalls.c (100%) rename {gdbstub => debug/gdbstub}/system.c (100%) rename {gdbstub => debug/gdbstub}/trace-events (100%) create mode 100644 debug/gdbstub/trace.h rename {gdbstub => debug/gdbstub}/user-target.c (100%) rename {gdbstub => debug/gdbstub}/user.c (100%) create mode 100644 debug/mcdstub/arm_mcdstub.c create mode 100644 debug/mcdstub/mcdstub.c create mode 100644 debug/mcdstub/meson.build create mode 100644 debug/meson.build delete mode 100644 gdbstub/trace.h create mode 100644 include/mcdstub/arm_mcdstub.h create mode 100644 include/mcdstub/mcd_shared_defines.h create mode 100644 include/mcdstub/mcdstub.h create mode 100644 include/mcdstub/mcdstub_common.h create mode 100644 include/qemu/debug.h diff --git a/MAINTAINERS b/MAINTAINERS index 695e0bd34f..467da56a38 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2955,7 +2955,7 @@ M: Alex Bennée R: Philippe Mathieu-Daudé S: Maintained F: docs/system/gdb.rst -F: gdbstub/* +F: debug/gdbstub/* F: include/exec/gdbstub.h F: include/gdbstub/* F: gdb-xml/ @@ -2963,6 +2963,15 @@ F: tests/tcg/multiarch/gdbstub/* F: scripts/feature_to_c.py F: scripts/probe-gdb-support.py +MCD stub +M: Nicolas Eder +R: Alex Bennée +S: Maintained +F: debug/mcdstub/* +F: debug/common/* +F: include/mcdstub/* +F: include/qemu/debug.h + Memory API M: Paolo Bonzini M: Peter Xu diff --git a/debug/common/debug.c b/debug/common/debug.c new file mode 100644 index 0000000000..c24aaf1202 --- /dev/null +++ b/debug/common/debug.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Nicolas Eder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * SPDX-License-Identifier: LGPL-2.0+ + */ diff --git a/debug/common/meson.build b/debug/common/meson.build new file mode 100644 index 0000000000..e69de29bb2 diff --git a/gdbstub/gdbstub.c b/debug/gdbstub/gdbstub.c similarity index 100% rename from gdbstub/gdbstub.c rename to debug/gdbstub/gdbstub.c diff --git a/gdbstub/internals.h b/debug/gdbstub/internals.h similarity index 100% rename from gdbstub/internals.h rename to debug/gdbstub/internals.h diff --git a/gdbstub/meson.build b/debug/gdbstub/meson.build similarity index 100% rename from gdbstub/meson.build rename to debug/gdbstub/meson.build diff --git a/gdbstub/syscalls.c b/debug/gdbstub/syscalls.c similarity index 100% rename from gdbstub/syscalls.c rename to debug/gdbstub/syscalls.c diff --git a/gdbstub/system.c b/debug/gdbstub/system.c similarity index 100% rename from gdbstub/system.c rename to debug/gdbstub/system.c diff --git a/gdbstub/trace-events b/debug/gdbstub/trace-events similarity index 100% rename from gdbstub/trace-events rename to debug/gdbstub/trace-events diff --git a/debug/gdbstub/trace.h b/debug/gdbstub/trace.h new file mode 100644 index 0000000000..ca6f0e8d29 --- /dev/null +++ b/debug/gdbstub/trace.h @@ -0,0 +1 @@ +#include "trace/trace-debug_gdbstub.h" diff --git a/gdbstub/user-target.c b/debug/gdbstub/user-target.c similarity index 100% rename from gdbstub/user-target.c rename to debug/gdbstub/user-target.c diff --git a/gdbstub/user.c b/debug/gdbstub/user.c similarity index 100% rename from gdbstub/user.c rename to debug/gdbstub/user.c diff --git a/debug/mcdstub/arm_mcdstub.c b/debug/mcdstub/arm_mcdstub.c new file mode 100644 index 0000000000..c24aaf1202 --- /dev/null +++ b/debug/mcdstub/arm_mcdstub.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Nicolas Eder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * SPDX-License-Identifier: LGPL-2.0+ + */ diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c new file mode 100644 index 0000000000..c24aaf1202 --- /dev/null +++ b/debug/mcdstub/mcdstub.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Nicolas Eder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * SPDX-License-Identifier: LGPL-2.0+ + */ diff --git a/debug/mcdstub/meson.build b/debug/mcdstub/meson.build new file mode 100644 index 0000000000..e69de29bb2 diff --git a/debug/meson.build b/debug/meson.build new file mode 100644 index 0000000000..a5b093f31e --- /dev/null +++ b/debug/meson.build @@ -0,0 +1 @@ +subdir('gdbstub') diff --git a/gdbstub/trace.h b/gdbstub/trace.h deleted file mode 100644 index dee87b1238..0000000000 --- a/gdbstub/trace.h +++ /dev/null @@ -1 +0,0 @@ -#include "trace/trace-gdbstub.h" diff --git a/include/mcdstub/arm_mcdstub.h b/include/mcdstub/arm_mcdstub.h new file mode 100644 index 0000000000..c24aaf1202 --- /dev/null +++ b/include/mcdstub/arm_mcdstub.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Nicolas Eder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * SPDX-License-Identifier: LGPL-2.0+ + */ diff --git a/include/mcdstub/mcd_shared_defines.h b/include/mcdstub/mcd_shared_defines.h new file mode 100644 index 0000000000..b6f2d81c34 --- /dev/null +++ b/include/mcdstub/mcd_shared_defines.h @@ -0,0 +1,132 @@ +/* + * MIT License + * + * Copyright (c) 2023 Lauterbach GmbH, Nicolas Eder + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + *this file is shared between the mcd dll and the mcd stub. + *it has to be kept exectly the same! + */ + +#ifndef MCD_SHARED_DEFINES +#define MCD_SHARED_DEFINES + +/* default tcp port */ +#define MCD_DEFAULT_TCP_PORT "1235" + +/* tcp data characters */ +#define TCP_CHAR_OPEN_SERVER 'I' +#define TCP_CHAR_OPEN_CORE 'i' +#define TCP_CHAR_GO 'C' +#define TCP_CHAR_STEP 'c' +#define TCP_CHAR_BREAK 'b' +#define TCP_CHAR_QUERY 'q' +#define TCP_CHAR_CLOSE_SERVER 'D' +#define TCP_CHAR_CLOSE_CORE 'd' +#define TCP_CHAR_KILLQEMU 'k' +#define TCP_CHAR_RESET 'r' +#define TCP_CHAR_READ_REGISTER 'p' +#define TCP_CHAR_WRITE_REGISTER 'P' +#define TCP_CHAR_READ_MEMORY 'm' +#define TCP_CHAR_WRITE_MEMORY 'M' +#define TCP_CHAR_BREAKPOINT_INSERT 't' +#define TCP_CHAR_BREAKPOINT_REMOVE 'T' + +/* tcp protocol chars */ +#define TCP_ACKNOWLEDGED '+' +#define TCP_NOT_ACKNOWLEDGED '-' +#define TCP_COMMAND_START '$' +#define TCP_COMMAND_END '#' +#define TCP_WAS_LAST '|' +#define TCP_WAS_NOT_LAST '~' +#define TCP_HANDSHAKE_SUCCESS "shaking your hand" +#define TCP_EXECUTION_SUCCESS "success" +#define TCP_EXECUTION_ERROR "error" + +/* tcp query arguments */ +#define QUERY_FIRST "f" +#define QUERY_CONSEQUTIVE "c" +#define QUERY_END_INDEX "!" + +#define QUERY_ARG_SYSTEM "system" +#define QUERY_ARG_CORES "cores" +#define QUERY_ARG_RESET "reset" +#define QUERY_ARG_TRIGGER "trigger" +#define QUERY_ARG_MEMORY "memory" +#define QUERY_ARG_REGGROUP "reggroup" +#define QUERY_ARG_REG "reg" +#define QUERY_ARG_STATE "state" + +/* tcp query packet argument list */ +#define TCP_ARGUMENT_NAME "name" +#define TCP_ARGUMENT_DATA "data" +#define TCP_ARGUMENT_ID "id" +#define TCP_ARGUMENT_TYPE "type" +#define TCP_ARGUMENT_BITS_PER_MAU "bpm" +#define TCP_ARGUMENT_INVARIANCE "i" +#define TCP_ARGUMENT_ENDIAN "e" +#define TCP_ARGUMENT_MIN "min" +#define TCP_ARGUMENT_MAX "max" +#define TCP_ARGUMENT_SUPPORTED_ACCESS_OPTIONS "sao" +#define TCP_ARGUMENT_REGGROUPID "reggroupid" +#define TCP_ARGUMENT_MEMSPACEID "memspaceid" +#define TCP_ARGUMENT_SIZE "size" +#define TCP_ARGUMENT_THREAD "thread" +#define TCP_ARGUMENT_ADDRESS "address" +#define TCP_ARGUMENT_STOP_STRING "stop_str" +#define TCP_ARGUMENT_INFO_STRING "info_str" +#define TCP_ARGUMENT_STATE "state" +#define TCP_ARGUMENT_EVENT "event" +#define TCP_ARGUMENT_DEVICE "device" +#define TCP_ARGUMENT_CORE "core" +#define TCP_ARGUMENT_AMOUNT_CORE "nr_cores" +#define TCP_ARGUMENT_AMOUNT_TRIGGER "nr_trigger" +#define TCP_ARGUMENT_OPTION "option" +#define TCP_ARGUMENT_ACTION "action" +#define TCP_ARGUMENT_OPCODE "opcode" + +/* for packets sent to qemu */ +#define ARGUMENT_SEPARATOR ';' +#define NEGATIVE_FLAG 0 +#define POSITIVE_FLAG 1 + +/* core states */ +#define CORE_STATE_RUNNING "running" +#define CORE_STATE_HALTED "halted" +#define CORE_STATE_DEBUG "debug" +#define CORE_STATE_UNKNOWN "unknown" + +/* breakpoint types */ +#define MCD_BREAKPOINT_HW 1 +#define MCD_BREAKPOINT_READ 2 +#define MCD_BREAKPOINT_WRITE 3 +#define MCD_BREAKPOINT_RW 4 + +/* trigger data */ +#define MCD_TRIG_ACT_BREAK "check_data_value" +#define MCD_TRIG_OPT_VALUE "break_on_trigger" + +/* register mem space key words */ +#define MCD_GRP_KEYWORD "GPR" +#define MCD_CP_KEYWORD "CP" + +#endif diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h new file mode 100644 index 0000000000..c24aaf1202 --- /dev/null +++ b/include/mcdstub/mcdstub.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Nicolas Eder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * SPDX-License-Identifier: LGPL-2.0+ + */ diff --git a/include/mcdstub/mcdstub_common.h b/include/mcdstub/mcdstub_common.h new file mode 100644 index 0000000000..c24aaf1202 --- /dev/null +++ b/include/mcdstub/mcdstub_common.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Nicolas Eder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * SPDX-License-Identifier: LGPL-2.0+ + */ diff --git a/include/qemu/debug.h b/include/qemu/debug.h new file mode 100644 index 0000000000..c24aaf1202 --- /dev/null +++ b/include/qemu/debug.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Nicolas Eder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * SPDX-License-Identifier: LGPL-2.0+ + */ diff --git a/meson.build b/meson.build index d2c4c2adb3..2e1a7048e9 100644 --- a/meson.build +++ b/meson.build @@ -3263,7 +3263,7 @@ trace_events_subdirs = [ 'qom', 'monitor', 'util', - 'gdbstub', + 'debug/gdbstub', ] if have_linux_user trace_events_subdirs += [ 'linux-user' ] @@ -3389,7 +3389,7 @@ subdir('authz') subdir('crypto') subdir('ui') subdir('hw') -subdir('gdbstub') +subdir('debug') if enable_modules libmodulecommon = static_library('module-common', files('module-common.c') + genh, pic: true, c_args: '-DBUILD_DSO') From patchwork Wed Dec 20 16:25:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500353 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 8D946C46CD2 for ; Wed, 20 Dec 2023 16:29:50 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzP1-0000Ol-7N; Wed, 20 Dec 2023 11:26:35 -0500 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 1rFzOx-0000Mu-Es for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:31 -0500 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 1rFzOr-0004Wi-LI for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:30 -0500 Received: (qmail 15097 invoked by uid 484); 20 Dec 2023 16:26:04 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.074878 secs); 20 Dec 2023 16:26:04 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:03 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 02/18] gdbstub: hex conversion functions moved to cutils.h Date: Wed, 20 Dec 2023 17:25:39 +0100 Message-Id: <20231220162555.19545-3-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/gdbstub/gdbstub.c | 19 ++++++++++--------- debug/gdbstub/internals.h | 26 -------------------------- include/qemu/cutils.h | 30 ++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 35 deletions(-) Reviewed-by: Alex Bennée diff --git a/debug/gdbstub/gdbstub.c b/debug/gdbstub/gdbstub.c index 46d752bbc2..f43d4355c0 100644 --- a/debug/gdbstub/gdbstub.c +++ b/debug/gdbstub/gdbstub.c @@ -80,8 +80,8 @@ void gdb_memtohex(GString *buf, const uint8_t *mem, int len) int i, c; for(i = 0; i < len; i++) { c = mem[i]; - g_string_append_c(buf, tohex(c >> 4)); - g_string_append_c(buf, tohex(c & 0xf)); + g_string_append_c(buf, nibble_to_hexchar(c >> 4)); + g_string_append_c(buf, nibble_to_hexchar(c & 0xf)); } g_string_append_c(buf, '\0'); } @@ -91,7 +91,8 @@ void gdb_hextomem(GByteArray *mem, const char *buf, int len) int i; for(i = 0; i < len; i++) { - guint8 byte = fromhex(buf[0]) << 4 | fromhex(buf[1]); + guint8 byte = hexchar_to_nibble(buf[0]) << 4 | + hexchar_to_nibble(buf[1]); g_byte_array_append(mem, &byte, 1); buf += 2; } @@ -118,8 +119,8 @@ static void hexdump(const char *buf, int len, if (i < len) { char value = buf[i]; - line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF); - line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF); + line_buffer[hex_col + 0] = nibble_to_hexchar((value >> 4) & 0xF); + line_buffer[hex_col + 1] = nibble_to_hexchar((value >> 0) & 0xF); line_buffer[txt_col + 0] = (value >= ' ' && value < 127) ? value : '.'; @@ -151,8 +152,8 @@ int gdb_put_packet_binary(const char *buf, int len, bool dump) csum += buf[i]; } footer[0] = '#'; - footer[1] = tohex((csum >> 4) & 0xf); - footer[2] = tohex((csum) & 0xf); + footer[1] = nibble_to_hexchar((csum >> 4) & 0xf); + footer[2] = nibble_to_hexchar((csum) & 0xf); g_byte_array_append(gdbserver_state.last_packet, footer, 3); gdb_put_buffer(gdbserver_state.last_packet->data, @@ -2267,7 +2268,7 @@ void gdb_read_byte(uint8_t ch) break; } gdbserver_state.line_buf[gdbserver_state.line_buf_index] = '\0'; - gdbserver_state.line_csum = fromhex(ch) << 4; + gdbserver_state.line_csum = hexchar_to_nibble(ch) << 4; gdbserver_state.state = RS_CHKSUM2; break; case RS_CHKSUM2: @@ -2277,7 +2278,7 @@ void gdb_read_byte(uint8_t ch) gdbserver_state.state = RS_GETLINE; break; } - gdbserver_state.line_csum |= fromhex(ch); + gdbserver_state.line_csum |= hexchar_to_nibble(ch); if (gdbserver_state.line_csum != (gdbserver_state.line_sum & 0xff)) { trace_gdbstub_err_checksum_incorrect(gdbserver_state.line_sum, gdbserver_state.line_csum); diff --git a/debug/gdbstub/internals.h b/debug/gdbstub/internals.h index 5c0c725e54..4b67adfeda 100644 --- a/debug/gdbstub/internals.h +++ b/debug/gdbstub/internals.h @@ -75,32 +75,6 @@ typedef struct GDBState { /* lives in main gdbstub.c */ extern GDBState gdbserver_state; -/* - * Inline utility function, convert from int to hex and back - */ - -static inline int fromhex(int v) -{ - if (v >= '0' && v <= '9') { - return v - '0'; - } else if (v >= 'A' && v <= 'F') { - return v - 'A' + 10; - } else if (v >= 'a' && v <= 'f') { - return v - 'a' + 10; - } else { - return 0; - } -} - -static inline int tohex(int v) -{ - if (v < 10) { - return v + '0'; - } else { - return v - 10 + 'a'; - } -} - /* * Connection helpers for both system and user backends */ diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index 92c927a6a3..5ab1a4ffb0 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -267,4 +267,34 @@ void qemu_hexdump_line(char *line, unsigned int b, const void *bufptr, void qemu_hexdump(FILE *fp, const char *prefix, const void *bufptr, size_t size); + +/** + * hexchar_to_nibble() - Converts hex character to nibble. + */ +static inline int hexchar_to_nibble(int v) +{ + if (v >= '0' && v <= '9') { + return v - '0'; + } else if (v >= 'A' && v <= 'F') { + return v - 'A' + 10; + } else if (v >= 'a' && v <= 'f') { + return v - 'a' + 10; + } else { + g_assert_not_reached(); + } +} + +/** + * nibble_to_hexchar() - Converts nibble to hex character. + */ +static inline int nibble_to_hexchar(int v) +{ + g_assert(v <= 0xf); + if (v < 10) { + return v + '0'; + } else { + return v - 10 + 'a'; + } +} + #endif From patchwork Wed Dec 20 16:25:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500356 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 ECE31C3DA6E for ; Wed, 20 Dec 2023 16:30:23 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzP6-0000Sb-JH; Wed, 20 Dec 2023 11:26:40 -0500 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 1rFzP1-0000P9-G3 for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:36 -0500 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 1rFzOx-0004cr-8D for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:34 -0500 Received: (qmail 15122 invoked by uid 484); 20 Dec 2023 16:26:06 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.090129 secs); 20 Dec 2023 16:26:06 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:05 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 03/18] gdbstub: GDBRegisterState moved to gdbstub.h so it can be used outside of the gdbstub Date: Wed, 20 Dec 2023 17:25:40 +0100 Message-Id: <20231220162555.19545-4-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/gdbstub/gdbstub.c | 8 -------- include/exec/gdbstub.h | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/debug/gdbstub/gdbstub.c b/debug/gdbstub/gdbstub.c index f43d4355c0..5df7841878 100644 --- a/debug/gdbstub/gdbstub.c +++ b/debug/gdbstub/gdbstub.c @@ -45,14 +45,6 @@ #include "internals.h" -typedef struct GDBRegisterState { - int base_reg; - int num_regs; - gdb_get_reg_cb get_reg; - gdb_set_reg_cb set_reg; - const char *xml; -} GDBRegisterState; - GDBState gdbserver_state; void gdb_init_gdbserver_state(void) diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index d8a3c56fa2..cdbad65930 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -27,6 +27,14 @@ typedef struct GDBFeatureBuilder { typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg); typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg); +typedef struct GDBRegisterState { + int base_reg; + int num_regs; + gdb_get_reg_cb get_reg; + gdb_set_reg_cb set_reg; + const char *xml; +} GDBRegisterState; + /** * gdb_register_coprocessor() - register a supplemental set of registers * @cpu - the CPU associated with registers From patchwork Wed Dec 20 16:25:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500355 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 A2E19C3DA6E for ; Wed, 20 Dec 2023 16:29:59 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzP8-0000TQ-3k; Wed, 20 Dec 2023 11:26:42 -0500 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 1rFzP3-0000PZ-F5 for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:37 -0500 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 1rFzOz-0004hS-Ap for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:36 -0500 Received: (qmail 15145 invoked by uid 484); 20 Dec 2023 16:26:07 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.070998 secs); 20 Dec 2023 16:26:07 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:06 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 04/18] gdbstub: DebugClass added to system mode. Date: Wed, 20 Dec 2023 17:25:41 +0100 Message-Id: <20231220162555.19545-5-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 This class is used to abstract debug features between different debuggers --- debug/common/debug.c | 33 +++++++++++++++++++++++++++++++++ debug/common/meson.build | 1 + debug/gdbstub/system.c | 18 ++++++++++++++++++ debug/meson.build | 1 + include/hw/boards.h | 1 + include/qemu/debug.h | 20 ++++++++++++++++++++ include/qemu/typedefs.h | 2 ++ system/cpus.c | 9 ++++++++- 8 files changed, 84 insertions(+), 1 deletion(-) diff --git a/debug/common/debug.c b/debug/common/debug.c index c24aaf1202..476c969c98 100644 --- a/debug/common/debug.c +++ b/debug/common/debug.c @@ -16,3 +16,36 @@ * * SPDX-License-Identifier: LGPL-2.0+ */ + +#include "qemu/osdep.h" +#include "qemu/debug.h" +#include "qom/object_interfaces.h" + +static void debug_instance_init(Object *obj) +{ +} + +static void debug_finalize(Object *obj) +{ +} + +static void debug_class_init(ObjectClass *oc, void *data) +{ +} + +static const TypeInfo debug_info = { + .name = TYPE_DEBUG, + .parent = TYPE_OBJECT, + .instance_size = sizeof(DebugState), + .instance_init = debug_instance_init, + .instance_finalize = debug_finalize, + .class_size = sizeof(DebugClass), + .class_init = debug_class_init +}; + +static void debug_register_types(void) +{ + type_register_static(&debug_info); +} + +type_init(debug_register_types); diff --git a/debug/common/meson.build b/debug/common/meson.build index e69de29bb2..815cb6f0fc 100644 --- a/debug/common/meson.build +++ b/debug/common/meson.build @@ -0,0 +1 @@ +system_ss.add(files('debug.c')) diff --git a/debug/gdbstub/system.c b/debug/gdbstub/system.c index 83fd452800..06bc580147 100644 --- a/debug/gdbstub/system.c +++ b/debug/gdbstub/system.c @@ -14,6 +14,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/cutils.h" +#include "qemu/debug.h" #include "exec/gdbstub.h" #include "gdbstub/syscalls.h" #include "exec/hwaddr.h" @@ -46,6 +47,20 @@ static void reset_gdbserver_state(void) gdbserver_state.allow_stop_reply = false; } +/** + * gdb_init_debug_class() - initialize gdb-specific DebugClass + */ +static void gdb_init_debug_class(void) +{ + Object *obj; + obj = object_new(TYPE_DEBUG); + DebugState *ds = DEBUG(obj); + DebugClass *dc = DEBUG_GET_CLASS(ds); + dc->set_stop_cpu = gdb_set_stop_cpu; + MachineState *ms = MACHINE(qdev_get_machine()); + ms->debug_state = ds; +} + /* * Return the GDB index for a given vCPU state. * @@ -405,6 +420,9 @@ int gdbserver_start(const char *device) gdbserver_system_state.mon_chr = mon_chr; gdb_syscall_reset(); + /* create new debug object */ + gdb_init_debug_class(); + return 0; } diff --git a/debug/meson.build b/debug/meson.build index a5b093f31e..f46ab14af9 100644 --- a/debug/meson.build +++ b/debug/meson.build @@ -1 +1,2 @@ +subdir('common') subdir('gdbstub') diff --git a/include/hw/boards.h b/include/hw/boards.h index da85f86efb..2e28913afc 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -400,6 +400,7 @@ struct MachineState { CpuTopology smp; struct NVDIMMState *nvdimms_state; struct NumaState *numa_state; + DebugState *debug_state; }; #define DEFINE_MACHINE(namestr, machine_initfn) \ diff --git a/include/qemu/debug.h b/include/qemu/debug.h index c24aaf1202..9526f9fb48 100644 --- a/include/qemu/debug.h +++ b/include/qemu/debug.h @@ -16,3 +16,23 @@ * * SPDX-License-Identifier: LGPL-2.0+ */ + +#ifndef QEMU_DEBUG_H +#define QEMU_DEBUG_H + +#include "qom/object.h" +#include "qemu/typedefs.h" + +struct DebugClass { + ObjectClass parent_class; + void (*set_stop_cpu)(CPUState *cpu); +}; + +struct DebugState { + Object parent_obj; +}; + +#define TYPE_DEBUG "debug" +OBJECT_DECLARE_TYPE(DebugState, DebugClass, DEBUG) + +#endif /* QEMU_DEBUG_H */ diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 5abdbc3874..e48b544173 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -46,6 +46,8 @@ typedef struct CpuInfoFast CpuInfoFast; typedef struct CPUJumpCache CPUJumpCache; typedef struct CPUState CPUState; typedef struct CPUTLBEntryFull CPUTLBEntryFull; +typedef struct DebugClass DebugClass; +typedef struct DebugState DebugState; typedef struct DeviceListener DeviceListener; typedef struct DeviceState DeviceState; typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot; diff --git a/system/cpus.c b/system/cpus.c index a444a747f0..7a7fff14bc 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include "monitor/monitor.h" #include "qemu/coroutine-tls.h" +#include "qemu/debug.h" #include "qapi/error.h" #include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-misc.h" @@ -313,7 +314,13 @@ void cpu_handle_guest_debug(CPUState *cpu) cpu_single_step(cpu, 0); } } else { - gdb_set_stop_cpu(cpu); + MachineState *ms = MACHINE(qdev_get_machine()); + DebugState *ds = ms->debug_state; + DebugClass *dc = DEBUG_GET_CLASS(ds); + + if (dc->set_stop_cpu) { + dc->set_stop_cpu(cpu); + } qemu_system_debug_request(); cpu->stopped = true; } From patchwork Wed Dec 20 16:25:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500340 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 08AABC46CD2 for ; Wed, 20 Dec 2023 16:27:23 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzP5-0000Rh-Fu; Wed, 20 Dec 2023 11:26:39 -0500 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 1rFzP3-0000Pa-Ex for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:37 -0500 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 1rFzOz-0004ht-A1 for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:36 -0500 Received: (qmail 15166 invoked by uid 484); 20 Dec 2023 16:26:08 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.07155 secs); 20 Dec 2023 16:26:08 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:07 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 05/18] mcdstub: memory helper functions added Date: Wed, 20 Dec 2023 17:25:42 +0100 Message-Id: <20231220162555.19545-6-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- include/exec/cpu-common.h | 3 +++ include/exec/memory.h | 9 +++++++++ system/memory.c | 11 +++++++++++ system/physmem.c | 26 ++++++++++++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 41115d8919..dd989b5ab2 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -182,6 +182,9 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length); int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, void *ptr, size_t len, bool is_write); +int cpu_memory_get_physical_address(CPUState *cpu, vaddr *addr, size_t *len); + + /* vl.c */ void list_cpus(void); diff --git a/include/exec/memory.h b/include/exec/memory.h index 831f7c996d..174de807d5 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -3142,6 +3142,15 @@ bool ram_block_discard_is_disabled(void); */ bool ram_block_discard_is_required(void); +/* + * mcd_find_address_space() - Find the address spaces with the corresponding + * name. + * + * Currently only used by the mcd debugger. + * @as_name: Name to look for. + */ +AddressSpace *mcd_find_address_space(const char *as_name); + #endif #endif diff --git a/system/memory.c b/system/memory.c index 798b6c0a17..9a8fa79e0c 100644 --- a/system/memory.c +++ b/system/memory.c @@ -3562,6 +3562,17 @@ void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled) } } +AddressSpace *mcd_find_address_space(const char *as_name) +{ + AddressSpace *as; + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + if (strcmp(as->name, as_name) == 0) { + return as; + } + } + return NULL; +} + void memory_region_init_ram(MemoryRegion *mr, Object *owner, const char *name, diff --git a/system/physmem.c b/system/physmem.c index a63853a7bc..70733c67c7 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -3422,6 +3422,32 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, return 0; } +int cpu_memory_get_physical_address(CPUState *cpu, vaddr *addr, size_t *len) +{ + hwaddr phys_addr; + vaddr l, page; + + cpu_synchronize_state(cpu); + MemTxAttrs attrs; + + page = *addr & TARGET_PAGE_MASK; + phys_addr = cpu_get_phys_page_attrs_debug(cpu, page, &attrs); + /* if no physical page mapped, return an error */ + if (phys_addr == -1) { + return -1; + } + l = (page + TARGET_PAGE_SIZE) - *addr; + if (l > *len) { + l = *len; + } + phys_addr += (*addr & ~TARGET_PAGE_MASK); + + /* set output values */ + *addr = phys_addr; + *len = l; + return 0; +} + /* * Allows code that needs to deal with migration bitmaps etc to still be built * target independent. From patchwork Wed Dec 20 16:25:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500343 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 B0ACDC46CD3 for ; Wed, 20 Dec 2023 16:27:42 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzPB-0000Ty-FF; Wed, 20 Dec 2023 11:26:45 -0500 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 1rFzP5-0000Qy-3j for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:39 -0500 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 1rFzOz-0004i9-BB for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:38 -0500 Received: (qmail 15190 invoked by uid 484); 20 Dec 2023 16:26:10 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.153183 secs); 20 Dec 2023 16:26:10 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:09 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 06/18] mcdstub: -mcd start option added, mcd specific defines added Date: Wed, 20 Dec 2023 17:25:43 +0100 Message-Id: <20231220162555.19545-7-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/mcdstub.c | 203 +++++++++++++++++++++++++++++++ debug/mcdstub/meson.build | 12 ++ debug/meson.build | 1 + include/mcdstub/mcdstub.h | 152 +++++++++++++++++++++++ include/mcdstub/mcdstub_common.h | 46 +++++++ qemu-options.hx | 18 +++ system/vl.c | 13 ++ 7 files changed, 445 insertions(+) diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index c24aaf1202..4d8d5d956a 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -16,3 +16,206 @@ * * SPDX-License-Identifier: LGPL-2.0+ */ + +#include "qemu/osdep.h" +#include "qemu/ctype.h" +#include "qemu/cutils.h" +#include "qemu/module.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "chardev/char.h" +#include "chardev/char-fe.h" +#include "sysemu/cpus.h" +#include "sysemu/hw_accel.h" +#include "sysemu/runstate.h" + +#include "mcdstub/mcd_shared_defines.h" +#include "mcdstub/mcdstub.h" + +typedef struct { + CharBackend chr; +} MCDSystemState; + +MCDSystemState mcdserver_system_state; + +MCDState mcdserver_state; + +/** + * mcd_supports_guest_debug() - Returns true if debugging the selected + * accelerator is supported. + */ +static bool mcd_supports_guest_debug(void) +{ + const AccelOpsClass *ops = cpus_get_accel(); + if (ops->supports_guest_debug) { + return ops->supports_guest_debug(); + } + return false; +} + +#ifndef _WIN32 +static void mcd_sigterm_handler(int signal) +{ + if (runstate_is_running()) { + vm_stop(RUN_STATE_PAUSED); + } +} +#endif + +/** + * mcd_vm_state_change() - Handles a state change of the QEMU VM. + * + * This function is called when the QEMU VM goes through a state transition. + * It stores the runstate the CPU is in to the cpu_state and when in + * RUN_STATE_DEBUG it collects additional data on what watchpoint was hit. + * This function also resets the singlestep behavior. + * @running: True if he VM is running. + * @state: The new (and active) VM run state. + */ +static void mcd_vm_state_change(void *opaque, bool running, RunState state) +{ +} + +/** + * mcd_chr_can_receive() - Returns the maximum packet length of a TCP packet. + */ +static int mcd_chr_can_receive(void *opaque) +{ + return MAX_PACKET_LENGTH; +} + +/** + * mcd_chr_receive() - Handles receiving a TCP packet. + * + * This function gets called by QEMU when a TCP packet is received. + * It iterates over that packet an calls :c:func:`mcd_read_byte` for each char + * of the packet. + * @buf: Content of the packet. + * @size: Length of the packet. + */ +static void mcd_chr_receive(void *opaque, const uint8_t *buf, int size) +{ +} + +/** + * mcd_chr_event() - Handles a TCP client connect. + * + * This function gets called by QEMU when a TCP cliet connects to the opened + * TCP port. It attaches the first process. From here on TCP packets can be + * exchanged. + * @event: Type of event. + */ +static void mcd_chr_event(void *opaque, QEMUChrEvent event) +{ +} + +/** + * mcd_init_mcdserver_state() - Initializes the mcdserver_state struct. + * + * This function allocates memory for the mcdserver_state struct and sets + * all of its members to their inital values. This includes setting the + * cpu_state to halted and initializing the query functions with + * :c:func:`init_query_cmds_table`. + */ +static void mcd_init_mcdserver_state(void) +{ +} + +/** + * reset_mcdserver_state() - Resets the mcdserver_state struct. + * + * This function deletes all processes connected to the mcdserver_state. + */ +static void reset_mcdserver_state(void) +{ +} + +/** + * create_processes() - Sorts all processes and calls + * :c:func:`mcd_create_default_process`. + * + * This function sorts all connected processes with the qsort function. + * Afterwards, it creates a new process with + * :c:func:`mcd_create_default_process`. + * @s: A MCDState object. + */ +static void create_processes(MCDState *s) +{ +} + +int mcdserver_start(const char *device) +{ + char mcd_device_config[TCP_CONFIG_STRING_LENGTH]; + char mcd_tcp_port[TCP_CONFIG_STRING_LENGTH]; + Chardev *chr = NULL; + + if (!first_cpu) { + error_report("mcdstub: meaningless to attach to a " + "machine without any CPU."); + return -1; + } + + if (!mcd_supports_guest_debug()) { + error_report("mcdstub: current accelerator doesn't " + "support guest debugging"); + return -1; + } + + if (!device) { + return -1; + } + + /* if device == default -> set tcp_port = tcp:: */ + if (strcmp(device, "default") == 0) { + snprintf(mcd_tcp_port, sizeof(mcd_tcp_port), "tcp::%s", + MCD_DEFAULT_TCP_PORT); + device = mcd_tcp_port; + } + + if (strcmp(device, "none") != 0) { + if (strstart(device, "tcp:", NULL)) { + /* enforce required TCP attributes */ + if (snprintf(mcd_device_config, sizeof(mcd_device_config), + "%s,wait=off,nodelay=on,server=on", device) < 0) { + g_assert_not_reached(); + } + device = mcd_device_config; + } +#ifndef _WIN32 + else if (strcmp(device, "stdio") == 0) { + struct sigaction act; + + memset(&act, 0, sizeof(act)); + act.sa_handler = mcd_sigterm_handler; + sigaction(SIGINT, &act, NULL); + strcpy(mcd_device_config, device); + } +#endif + chr = qemu_chr_new_noreplay("mcd", device, true, NULL); + if (!chr) { + return -1; + } + } + + if (!mcdserver_state.init) { + mcd_init_mcdserver_state(); + + qemu_add_vm_change_state_handler(mcd_vm_state_change, NULL); + } else { + qemu_chr_fe_deinit(&mcdserver_system_state.chr, true); + reset_mcdserver_state(); + } + + create_processes(&mcdserver_state); + + if (chr) { + qemu_chr_fe_init(&mcdserver_system_state.chr, chr, &error_abort); + qemu_chr_fe_set_handlers(&mcdserver_system_state.chr, + mcd_chr_can_receive, + mcd_chr_receive, mcd_chr_event, + NULL, &mcdserver_state, NULL, true); + } + mcdserver_state.state = chr ? RS_IDLE : RS_INACTIVE; + + return 0; +} diff --git a/debug/mcdstub/meson.build b/debug/mcdstub/meson.build index e69de29bb2..7e5ae878b0 100644 --- a/debug/mcdstub/meson.build +++ b/debug/mcdstub/meson.build @@ -0,0 +1,12 @@ +# only system emulation is supported over mcd +mcd_system_ss = ss.source_set() +mcd_system_ss.add(files('mcdstub.c')) +mcd_system_ss = mcd_system_ss.apply(config_host, strict: false) + +libmcd_system = static_library('mcd_system', + mcd_system_ss.sources() + genh, + name_suffix: 'fa', + build_by_default: have_system) + +mcd_system = declare_dependency(link_whole: libmcd_system) +system_ss.add(mcd_system) diff --git a/debug/meson.build b/debug/meson.build index f46ab14af9..97c80d7406 100644 --- a/debug/meson.build +++ b/debug/meson.build @@ -1,2 +1,3 @@ subdir('common') subdir('gdbstub') +subdir('mcdstub') diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h index c24aaf1202..26aa33c0e3 100644 --- a/include/mcdstub/mcdstub.h +++ b/include/mcdstub/mcdstub.h @@ -16,3 +16,155 @@ * * SPDX-License-Identifier: LGPL-2.0+ */ + +#ifndef MCDSTUB_H +#define MCDSTUB_H + +#include "mcdstub_common.h" + +#define MAX_PACKET_LENGTH 1024 + +/* trigger defines */ +#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008 +#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001 + +/* schema defines */ +#define ARG_SCHEMA_QRYHANDLE 'q' +#define ARG_SCHEMA_STRING 's' +#define ARG_SCHEMA_INT 'd' +#define ARG_SCHEMA_UINT64_T 'l' +#define ARG_SCHEMA_CORENUM 'c' +#define ARG_SCHEMA_HEXDATA 'h' + +/* resets */ +#define RESET_SYSTEM "full_system_reset" +#define RESET_GPR "gpr_reset" +#define RESET_MEMORY "memory_reset" + +/* misc */ +#define QUERY_TOTAL_NUMBER 12 +#define CMD_SCHEMA_LENGTH 6 +#define MCD_SYSTEM_NAME "qemu-system" + +/* supported architectures */ +#define MCDSTUB_ARCH_ARM "arm" + +/* tcp query packet values templates */ +#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device" + +/* state strings */ +#define STATE_STR_UNKNOWN(d) "cpu " #d " in unknown state" +#define STATE_STR_DEBUG(d) "cpu " #d " in debug state" +#define STATE_STR_RUNNING(d) "cpu " #d " running" +#define STATE_STR_HALTED(d) "cpu " #d " currently halted" +#define STATE_STR_INIT_HALTED "vm halted since boot" +#define STATE_STR_INIT_RUNNING "vm running since boot" +#define STATE_STR_BREAK_HW "stopped beacuse of HW breakpoint" +#define STATE_STEP_PERFORMED "stopped beacuse of single step" +#define STATE_STR_BREAK_READ(d) "stopped beacuse of read access at " #d +#define STATE_STR_BREAK_WRITE(d) "stopped beacuse of write access at " #d +#define STATE_STR_BREAK_RW(d) "stopped beacuse of read or write access at " #d +#define STATE_STR_BREAK_UNKNOWN "stopped for unknown reason" + +typedef struct MCDProcess { + uint32_t pid; + bool attached; +} MCDProcess; + +typedef void (*MCDCmdHandler)(GArray *params, void *user_ctx); +typedef struct MCDCmdParseEntry { + MCDCmdHandler handler; + char cmd[ARGUMENT_STRING_LENGTH]; + char schema[CMD_SCHEMA_LENGTH]; +} MCDCmdParseEntry; + +typedef union MCDCmdVariant { + const char *data; + uint32_t data_uint32_t; + uint64_t data_uint64_t; + uint32_t query_handle; + uint32_t cpu_id; +} MCDCmdVariant; + +#define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i)) + +enum RSState { + RS_INACTIVE, + RS_IDLE, + RS_GETLINE, + RS_DATAEND, +}; + +typedef struct breakpoint_st { + uint32_t type; + uint64_t address; + uint32_t id; +} breakpoint_st; + +typedef struct mcd_trigger_into_st { + char type[ARGUMENT_STRING_LENGTH]; + char option[ARGUMENT_STRING_LENGTH]; + char action[ARGUMENT_STRING_LENGTH]; + uint32_t nr_trigger; +} mcd_trigger_into_st; + +typedef struct mcd_cpu_state_st { + const char *state; + bool memory_changed; + bool registers_changed; + bool target_was_stopped; + uint32_t bp_type; + uint64_t bp_address; + const char *stop_str; + const char *info_str; +} mcd_cpu_state_st; + +typedef struct MCDState { + bool init; + CPUState *c_cpu; + enum RSState state; + char line_buf[MAX_PACKET_LENGTH]; + int line_buf_index; + int line_sum; + int line_csum; + GByteArray *last_packet; + int signal; + + MCDProcess *processes; + int process_num; + GString *str_buf; + GByteArray *mem_buf; + int sstep_flags; + int supported_sstep_flags; + + uint32_t query_cpu_id; + GList *all_memspaces; + GList *all_reggroups; + GList *all_registers; + GList *all_breakpoints; + GArray *resets; + mcd_trigger_into_st trigger; + mcd_cpu_state_st cpu_state; + MCDCmdParseEntry mcd_query_cmds_table[QUERY_TOTAL_NUMBER]; +} MCDState; + +/* lives in mcdstub.c */ +extern MCDState mcdserver_state; + +typedef struct xml_attrib { + char argument[ARGUMENT_STRING_LENGTH]; + char value[ARGUMENT_STRING_LENGTH]; +} xml_attrib; + +typedef struct mcd_reset_st { + const char *name; + uint8_t id; +} mcd_reset_st; + +/** + * mcdserver_start() - initializes the mcdstub and opens a TCP port + * @device: TCP port (e.g. tcp::1235) + */ +int mcdserver_start(const char *device); + +#endif /* MCDSTUB_H */ diff --git a/include/mcdstub/mcdstub_common.h b/include/mcdstub/mcdstub_common.h index c24aaf1202..b64748c080 100644 --- a/include/mcdstub/mcdstub_common.h +++ b/include/mcdstub/mcdstub_common.h @@ -16,3 +16,49 @@ * * SPDX-License-Identifier: LGPL-2.0+ */ + +#ifndef MCDSTUB_COMMON_H +#define MCDSTUB_COMMON_H + +#define ARGUMENT_STRING_LENGTH 64 +#define TCP_CONFIG_STRING_LENGTH 128 + +typedef struct mcd_mem_space_st { + const char *name; + uint32_t id; + uint32_t type; + uint32_t bits_per_mau; + uint8_t invariance; + uint32_t endian; + uint64_t min_addr; + uint64_t max_addr; + uint32_t supported_access_options; + /* internal */ + bool is_secure; + bool is_physical; +} mcd_mem_space_st; + +typedef struct mcd_reg_st { + /* xml info */ + char name[ARGUMENT_STRING_LENGTH]; + char group[ARGUMENT_STRING_LENGTH]; + char type[ARGUMENT_STRING_LENGTH]; + uint32_t bitsize; + uint32_t id; /* id used by the mcd interface */ + uint32_t internal_id; /* id inside reg type */ + uint8_t reg_type; + /* mcd metadata */ + uint32_t mcd_reg_group_id; + uint32_t mcd_mem_space_id; + uint32_t mcd_reg_type; + uint32_t mcd_hw_thread_id; + /* data for op-code */ + uint32_t opcode; +} mcd_reg_st; + +typedef struct mcd_reg_group_st { + const char *name; + uint32_t id; +} mcd_reg_group_st; + +#endif /* MCDSTUB_COMMON_H */ diff --git a/qemu-options.hx b/qemu-options.hx index 42fd09e4de..b60df3463c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4444,6 +4444,24 @@ SRST (see the :ref:`GDB usage` chapter in the System Emulation Users Guide). ERST +DEF("mcd", HAS_ARG, QEMU_OPTION_mcd, \ + "-mcd dev accept mcd connection on 'dev'. (QEMU defaults to starting\n" + " the guest without waiting for a mcd client to connect; use -S too\n" + " if you want it to not start execution.)\n" + " To use the default Port write '-mcd default'\n", + QEMU_ARCH_ALL) +SRST +``-mcd dev`` + Accept a mcd connection on device dev. Note that this option does not pause QEMU + execution -- if you want QEMU to not start the guest until you + connect with mcd and issue a ``run`` command, you will need to + also pass the ``-S`` option to QEMU. + + The most usual configuration is to listen on a local TCP socket:: + + -mcd tcp::1235 +ERST + DEF("d", HAS_ARG, QEMU_OPTION_d, \ "-d item1,... enable logging of specified items (use '-d help' for a list of log items)\n", QEMU_ARCH_ALL) diff --git a/system/vl.c b/system/vl.c index 2bcd9efb9a..2c4610c19f 100644 --- a/system/vl.c +++ b/system/vl.c @@ -68,6 +68,7 @@ #include "sysemu/numa.h" #include "sysemu/hostmem.h" #include "exec/gdbstub.h" +#include "mcdstub/mcdstub.h" #include "qemu/timer.h" #include "chardev/char.h" #include "qemu/bitmap.h" @@ -1271,6 +1272,7 @@ struct device_config { DEV_PARALLEL, /* -parallel */ DEV_DEBUGCON, /* -debugcon */ DEV_GDB, /* -gdb, -s */ + DEV_MCD, /* -mcd */ DEV_SCLP, /* s390 sclp */ } type; const char *cmdline; @@ -2686,6 +2688,12 @@ static void qemu_machine_creation_done(void) if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) { exit(1); } + if (foreach_device_config(DEV_MCD, mcdserver_start) < 0) { + /* + * starts the mcdserver if the mcd option was set + */ + exit(1); + } if (!vga_interface_created && !default_vga && vga_interface_type != VGA_NONE) { warn_report("A -vga option was passed but this machine " @@ -3041,6 +3049,11 @@ void qemu_init(int argc, char **argv) case QEMU_OPTION_gdb: add_device_config(DEV_GDB, optarg); break; +#if !defined(CONFIG_USER_ONLY) + case QEMU_OPTION_mcd: + add_device_config(DEV_MCD, optarg); + break; +#endif case QEMU_OPTION_L: if (is_help_option(optarg)) { list_data_dirs = true; From patchwork Wed Dec 20 16:25:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500342 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 54540C3DA6E for ; Wed, 20 Dec 2023 16:27:40 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzP5-0000R9-Ct; Wed, 20 Dec 2023 11:26:39 -0500 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 1rFzP4-0000Qc-Bf for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:38 -0500 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 1rFzOz-0004iX-B9 for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:38 -0500 Received: (qmail 15224 invoked by uid 484); 20 Dec 2023 16:26:12 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.071925 secs); 20 Dec 2023 16:26:12 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:10 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 07/18] mcdstub: mcdserver initialization functions added Date: Wed, 20 Dec 2023 17:25:44 +0100 Message-Id: <20231220162555.19545-8-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/mcdstub.c | 154 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index 4d8d5d956a..0df436719e 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -22,9 +22,12 @@ #include "qemu/cutils.h" #include "qemu/module.h" #include "qemu/error-report.h" +#include "qemu/debug.h" #include "qapi/error.h" #include "chardev/char.h" #include "chardev/char-fe.h" +#include "hw/cpu/cluster.h" +#include "hw/boards.h" #include "sysemu/cpus.h" #include "sysemu/hw_accel.h" #include "sysemu/runstate.h" @@ -109,6 +112,39 @@ static void mcd_chr_event(void *opaque, QEMUChrEvent event) { } +/** + * init_query_cmds_table() - Initializes all query functions. + * + * This function adds all query functions to the mcd_query_cmds_table. This + * includes their command string, handler function and parameter schema. + * @mcd_query_cmds_table: Lookup table with all query commands. + */ +static void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table) +{} + +/** + * mcd_set_stop_cpu() - Sets c_cpu to the just stopped CPU. + * + * @cpu: The CPU state. + */ +static void mcd_set_stop_cpu(CPUState *cpu) +{ + mcdserver_state.c_cpu = cpu; +} + +/** + * mcd_init_debug_class() - initialize mcd-specific DebugClass + */ +static void mcd_init_debug_class(void){ + Object *obj; + obj = object_new(TYPE_DEBUG); + DebugState *ds = DEBUG(obj); + DebugClass *dc = DEBUG_GET_CLASS(ds); + dc->set_stop_cpu = mcd_set_stop_cpu; + MachineState *ms = MACHINE(qdev_get_machine()); + ms->debug_state = ds; +} + /** * mcd_init_mcdserver_state() - Initializes the mcdserver_state struct. * @@ -119,6 +155,35 @@ static void mcd_chr_event(void *opaque, QEMUChrEvent event) */ static void mcd_init_mcdserver_state(void) { + g_assert(!mcdserver_state.init); + memset(&mcdserver_state, 0, sizeof(MCDState)); + mcdserver_state.init = true; + mcdserver_state.str_buf = g_string_new(NULL); + mcdserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH); + mcdserver_state.last_packet = g_byte_array_sized_new(MAX_PACKET_LENGTH + 4); + + /* + * What single-step modes are supported is accelerator dependent. + * By default try to use no IRQs and no timers while single + * stepping so as to make single stepping like a typical ICE HW step. + */ + mcdserver_state.supported_sstep_flags = + accel_supported_gdbstub_sstep_flags(); + mcdserver_state.sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; + mcdserver_state.sstep_flags &= mcdserver_state.supported_sstep_flags; + + /* init query table */ + init_query_cmds_table(mcdserver_state.mcd_query_cmds_table); + + /* at this time the cpu hans't been started! -> set cpu_state */ + mcd_cpu_state_st cpu_state = { + .state = CORE_STATE_HALTED, + .info_str = STATE_STR_INIT_HALTED, + }; + mcdserver_state.cpu_state = cpu_state; + + /* create new debug object */ + mcd_init_debug_class(); } /** @@ -128,6 +193,84 @@ static void mcd_init_mcdserver_state(void) */ static void reset_mcdserver_state(void) { + g_free(mcdserver_state.processes); + mcdserver_state.processes = NULL; + mcdserver_state.process_num = 0; +} + +/** + * mcd_create_default_process() - Creates a default process for debugging. + * + * This function creates a new, not yet attached, process with an ID one above + * the previous maximum ID. + * @s: A MCDState object. + */ +static void mcd_create_default_process(MCDState *s) +{ + MCDProcess *process; + int max_pid = 0; + + if (mcdserver_state.process_num) { + max_pid = s->processes[s->process_num - 1].pid; + } + + s->processes = g_renew(MCDProcess, s->processes, ++s->process_num); + process = &s->processes[s->process_num - 1]; + + /* We need an available PID slot for this process */ + assert(max_pid < UINT32_MAX); + + process->pid = max_pid + 1; + process->attached = false; +} + +/** + * find_cpu_clusters() - Returns the CPU cluster of the child object. + * + * @param[in] child Object with unknown CPU cluster. + * @param[in] opaque Pointer to an MCDState object. + */ +static int find_cpu_clusters(Object *child, void *opaque) +{ + if (object_dynamic_cast(child, TYPE_CPU_CLUSTER)) { + MCDState *s = (MCDState *) opaque; + CPUClusterState *cluster = CPU_CLUSTER(child); + MCDProcess *process; + + s->processes = g_renew(MCDProcess, s->processes, ++s->process_num); + + process = &s->processes[s->process_num - 1]; + assert(cluster->cluster_id != UINT32_MAX); + process->pid = cluster->cluster_id + 1; + process->attached = false; + + return 0; + } + + return object_child_foreach(child, find_cpu_clusters, opaque); +} + +/** + * pid_order() - Compares process IDs. + * + * This function returns -1 if process "a" has a ower process ID than "b". + * If "b" has a lower ID than "a" 1 is returned and if they are qual 0 is + * returned. + * @a: Process a. + * @b: Process b. + */ +static int pid_order(const void *a, const void *b) +{ + MCDProcess *pa = (MCDProcess *) a; + MCDProcess *pb = (MCDProcess *) b; + + if (pa->pid < pb->pid) { + return -1; + } else if (pa->pid > pb->pid) { + return 1; + } else { + return 0; + } } /** @@ -141,6 +284,17 @@ static void reset_mcdserver_state(void) */ static void create_processes(MCDState *s) { + object_child_foreach(object_get_root(), find_cpu_clusters, s); + + if (mcdserver_state.processes) { + /* Sort by PID */ + qsort(mcdserver_state.processes, + mcdserver_state.process_num, + sizeof(mcdserver_state.processes[0]), + pid_order); + } + + mcd_create_default_process(s); } int mcdserver_start(const char *device) From patchwork Wed Dec 20 16:25:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500344 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 51B6DC3DA6E for ; Wed, 20 Dec 2023 16:27:51 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzP7-0000TC-Rv; Wed, 20 Dec 2023 11:26:41 -0500 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 1rFzP5-0000Qz-4u for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:39 -0500 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 1rFzP3-0004j1-8v for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:38 -0500 Received: (qmail 15252 invoked by uid 484); 20 Dec 2023 16:26:15 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.180907 secs); 20 Dec 2023 16:26:15 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:12 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 08/18] cutils: qemu_strtou32 function added Date: Wed, 20 Dec 2023 17:25:45 +0100 Message-Id: <20231220162555.19545-9-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- include/qemu/cutils.h | 2 ++ util/cutils.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index 5ab1a4ffb0..14f492ba61 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -158,6 +158,8 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, unsigned long *result); int qemu_strtoi64(const char *nptr, const char **endptr, int base, int64_t *result); +int qemu_strtou32(const char *nptr, const char **endptr, int base, + uint32_t *result); int qemu_strtou64(const char *nptr, const char **endptr, int base, uint64_t *result); int qemu_strtod(const char *nptr, const char **endptr, double *result); diff --git a/util/cutils.c b/util/cutils.c index 42364039a5..5e00a4ec14 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -665,6 +665,36 @@ int qemu_strtoi64(const char *nptr, const char **endptr, int base, return check_strtox_error(nptr, ep, endptr, *result == 0, errno); } +/** + * Convert string @nptr to an uint32_t. + * + * Works like qemu_strtoul(), except it stores UINT32_MAX on overflow. + * (If you want to prohibit negative numbers that wrap around to + * positive, use parse_uint()). + */ +int qemu_strtou32(const char *nptr, const char **endptr, int base, + uint32_t *result) +{ + char *ep; + + assert((unsigned) base <= 36 && base != 1); + if (!nptr) { + *result = 0; + if (endptr) { + *endptr = nptr; + } + return -EINVAL; + } + + errno = 0; + *result = strtoul(nptr, &ep, base); + /* Windows returns 1 for negative out-of-range values. */ + if (errno == ERANGE) { + *result = -1; + } + return check_strtox_error(nptr, ep, endptr, *result == 0, errno); +} + /** * Convert string @nptr to an uint64_t. * From patchwork Wed Dec 20 16:25:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500341 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 E750FC3DA6E for ; Wed, 20 Dec 2023 16:27:35 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzP9-0000TT-Q3; Wed, 20 Dec 2023 11:26:44 -0500 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 1rFzP6-0000Sm-Of for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:40 -0500 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 1rFzP4-0004jL-AM for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:40 -0500 Received: (qmail 15281 invoked by uid 484); 20 Dec 2023 16:26:16 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.136501 secs); 20 Dec 2023 16:26:16 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:15 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 09/18] mcdstub: TCP packet plumbing added Date: Wed, 20 Dec 2023 17:25:46 +0100 Message-Id: <20231220162555.19545-10-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/mcdstub.c | 422 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 422 insertions(+) diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index 0df436719e..642f3c2826 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -87,6 +87,320 @@ static int mcd_chr_can_receive(void *opaque) return MAX_PACKET_LENGTH; } +/** + * mcd_put_buffer() - Sends the buf as TCP packet with qemu_chr_fe_write_all. + * + * @buf: TCP packet data. + * @len: TCP packet length. + */ +static void mcd_put_buffer(const uint8_t *buf, int len) +{ + qemu_chr_fe_write_all(&mcdserver_system_state.chr, buf, len); +} + +/** + * mcd_put_packet_binary() - Adds footer and header to the TCP packet data in + * buf. + * + * Besides adding header and footer, this function also stores the complete TCP + * packet in the last_packet member of the mcdserver_state. Then the packet + * gets send with the :c:func:`mcd_put_buffer` function. + * @buf: TCP packet data. + * @len: TCP packet length. + */ +static int mcd_put_packet_binary(const char *buf, int len) +{ + g_byte_array_set_size(mcdserver_state.last_packet, 0); + g_byte_array_append(mcdserver_state.last_packet, + (const uint8_t *) (char[2]) { TCP_COMMAND_START, '\0' }, 1); + g_byte_array_append(mcdserver_state.last_packet, + (const uint8_t *) buf, len); + g_byte_array_append(mcdserver_state.last_packet, + (const uint8_t *) (char[2]) { TCP_COMMAND_END, '\0' }, 1); + g_byte_array_append(mcdserver_state.last_packet, + (const uint8_t *) (char[2]) { TCP_WAS_LAST, '\0' }, 1); + + mcd_put_buffer(mcdserver_state.last_packet->data, + mcdserver_state.last_packet->len); + return 0; +} + +/** + * mcd_put_packet() - Calls :c:func:`mcd_put_packet_binary` with buf and length + * of buf. + * + * @buf: TCP packet data. + */ +static int mcd_put_packet(const char *buf) +{ + return mcd_put_packet_binary(buf, strlen(buf)); +} + +/** + * cmd_parse_params() - Extracts all parameters from a TCP packet. + * + * This function uses the schema parameter to determine which type of parameter + * to expect. It then extracts that parameter from the data and stores it in + * the params GArray. + * @data: TCP packet data. + * @schema: List of expected parameters for the packet. + * @params: GArray with all extracted parameters. + */ +static int cmd_parse_params(const char *data, const char *schema, + GArray *params) +{ + char data_buffer[64] = {0}; + const char *remaining_data = data; + + for (int i = 0; i < strlen(schema); i++) { + /* get correct part of data */ + char *separator = strchr(remaining_data, ARGUMENT_SEPARATOR); + + if (separator) { + /* multiple arguments */ + int seperator_index = (int)(separator - remaining_data); + strncpy(data_buffer, remaining_data, seperator_index); + data_buffer[seperator_index] = 0; + } else { + strncpy(data_buffer, remaining_data, 63); + data_buffer[strlen(remaining_data)] = 0; + } + + /* store right data */ + MCDCmdVariant this_param; + switch (schema[i]) { + case ARG_SCHEMA_STRING: + /* this has to be the last argument */ + this_param.data = remaining_data; + g_array_append_val(params, this_param); + break; + case ARG_SCHEMA_HEXDATA: + g_string_printf(mcdserver_state.str_buf, "%s", data_buffer); + break; + case ARG_SCHEMA_INT: + if (qemu_strtou32(remaining_data, &remaining_data, 10, + (uint32_t *)&this_param.data_uint32_t)) { + return -1; + } + g_array_append_val(params, this_param); + break; + case ARG_SCHEMA_UINT64_T: + if (qemu_strtou64(remaining_data, &remaining_data, 10, + (uint64_t *)&this_param.data_uint64_t)) { + return -1; + } + g_array_append_val(params, this_param); + break; + case ARG_SCHEMA_QRYHANDLE: + if (qemu_strtou32(remaining_data, &remaining_data, 10, + (uint32_t *)&this_param.query_handle)) { + return -1; + } + g_array_append_val(params, this_param); + break; + case ARG_SCHEMA_CORENUM: + if (qemu_strtou32(remaining_data, &remaining_data, 10, + (uint32_t *)&this_param.cpu_id)) { + return -1; + } + g_array_append_val(params, this_param); + break; + default: + return -1; + } + /* update remaining data for the next run */ + remaining_data = &(remaining_data[1]); + } + return 0; +} + +/** + * process_string_cmd() - Collects all parameters from the data and calls the + * correct handler. + * + * The parameters are extracted with the :c:func:`cmd_parse_params function. + * This function selects the command in the cmds array, which fits the start of + * the data string. This way the correct commands is selected. + * @data: TCP packet data. + * @cmds: Array of possible commands. + * @num_cmds: Number of commands in the cmds array. + */ +static int process_string_cmd(void *user_ctx, const char *data, + const MCDCmdParseEntry *cmds, int num_cmds) +{ + int i; + g_autoptr(GArray) params = g_array_new(false, true, sizeof(MCDCmdVariant)); + + if (!cmds) { + return -1; + } + + for (i = 0; i < num_cmds; i++) { + const MCDCmdParseEntry *cmd = &cmds[i]; + g_assert(cmd->handler && cmd->cmd); + + /* continue if data and command are different */ + if (strncmp(data, cmd->cmd, strlen(cmd->cmd))) { + continue; + } + + if (strlen(cmd->schema)) { + /* extract data for parameters */ + if (cmd_parse_params(&data[strlen(cmd->cmd)], cmd->schema, params)) + { + return -1; + } + } + + /* call handler */ + cmd->handler(params, user_ctx); + return 0; + } + + return -1; +} + +/** + * run_cmd_parser() - Prepares the mcdserver_state before executing TCP packet + * functions. + * + * This function empties the str_buf and mem_buf of the mcdserver_state and + * then calls :c:func:`process_string_cmd`. In case this function fails, an + * empty TCP packet is sent back the MCD Shared Library. + * @data: TCP packet data. + * @cmd: Handler function (can be an array of functions). + */ +static void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd) +{ + if (!data) { + return; + } + + g_string_set_size(mcdserver_state.str_buf, 0); + g_byte_array_set_size(mcdserver_state.mem_buf, 0); + + if (process_string_cmd(NULL, data, cmd, 1)) { + mcd_put_packet(""); + } +} + +/** + * mcd_handle_packet() - Evaluates the type of received packet and chooses the + * correct handler. + * + * This function takes the first character of the line_buf to determine the + * type of packet. Then it selects the correct handler function and parameter + * schema. With this info it calls :c:func:`run_cmd_parser`. + * @line_buf: TCP packet data. + */ +static int mcd_handle_packet(const char *line_buf) +{ + /* + * decides what function (handler) to call depending on + * the first character in the line_buf + */ + const MCDCmdParseEntry *cmd_parser = NULL; + + switch (line_buf[0]) { + default: + /* command not supported */ + mcd_put_packet(""); + break; + } + + if (cmd_parser) { + /* parse commands and run the selected handler function */ + run_cmd_parser(line_buf, cmd_parser); + } + + return RS_IDLE; +} + +/** + * mcd_read_byte() - Resends the last packet if not acknowledged and extracts + * the data from a received TCP packet. + * + * In case the last sent packet was not acknowledged from the mcdstub, + * this function resends it. + * If it was acknowledged this function parses the incoming packet + * byte by byte. + * It extracts the data in the packet and sends an + * acknowledging response when finished. Then :c:func:`mcd_handle_packet` gets + * called. + * @ch: Character of the received TCP packet, which should be parsed. + */ +static void mcd_read_byte(uint8_t ch) +{ + uint8_t reply; + + if (mcdserver_state.last_packet->len) { + if (ch == TCP_NOT_ACKNOWLEDGED) { + /* the previous packet was not akcnowledged */ + mcd_put_buffer(mcdserver_state.last_packet->data, + mcdserver_state.last_packet->len); + } else if (ch == TCP_ACKNOWLEDGED) { + /* the previous packet was acknowledged */ + } + + if (ch == TCP_ACKNOWLEDGED || ch == TCP_COMMAND_START) { + /* + * either acknowledged or a new communication starts + * -> discard previous packet + */ + g_byte_array_set_size(mcdserver_state.last_packet, 0); + } + if (ch != TCP_COMMAND_START) { + /* skip to the next char */ + return; + } + } + + switch (mcdserver_state.state) { + case RS_IDLE: + if (ch == TCP_COMMAND_START) { + /* start of command packet */ + mcdserver_state.line_buf_index = 0; + mcdserver_state.line_sum = 0; + mcdserver_state.state = RS_GETLINE; + } + break; + case RS_GETLINE: + if (ch == TCP_COMMAND_END) { + /* end of command */ + mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = 0; + mcdserver_state.state = RS_DATAEND; + } else if (mcdserver_state.line_buf_index >= + sizeof(mcdserver_state.line_buf) - 1) { + /* the input string is too long for the linebuffer! */ + mcdserver_state.state = RS_IDLE; + } else { + /* copy the content to the line_buf */ + mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = ch; + mcdserver_state.line_sum += ch; + } + break; + case RS_DATAEND: + if (ch == TCP_WAS_NOT_LAST) { + reply = TCP_ACKNOWLEDGED; + mcd_put_buffer(&reply, 1); + mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf); + } else if (ch == TCP_WAS_LAST) { + reply = TCP_ACKNOWLEDGED; + mcd_put_buffer(&reply, 1); + mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf); + } else { + /* not acknowledged! */ + reply = TCP_NOT_ACKNOWLEDGED; + mcd_put_buffer(&reply, 1); + /* waiting for package to get resent */ + mcdserver_state.state = RS_IDLE; + } + break; + default: + abort(); + } +} + /** * mcd_chr_receive() - Handles receiving a TCP packet. * @@ -98,6 +412,99 @@ static int mcd_chr_can_receive(void *opaque) */ static void mcd_chr_receive(void *opaque, const uint8_t *buf, int size) { + int i; + + for (i = 0; i < size; i++) { + mcd_read_byte(buf[i]); + if (buf[i] == 0) { + break; + } + } +} + +/** + * mcd_get_process() - Returns the process of the provided pid. + * + * @pid: The process ID. + */ +static MCDProcess *mcd_get_process(uint32_t pid) +{ + int i; + + if (!pid) { + /* 0 means any process, we take the first one */ + return &mcdserver_state.processes[0]; + } + + for (i = 0; i < mcdserver_state.process_num; i++) { + if (mcdserver_state.processes[i].pid == pid) { + return &mcdserver_state.processes[i]; + } + } + + return NULL; +} + +/** + * mcd_get_cpu_pid() - Returns the process ID of the provided CPU. + * + * @cpu: The CPU state. + */ +static uint32_t mcd_get_cpu_pid(CPUState *cpu) +{ + if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) { + /* Return the default process' PID */ + int index = mcdserver_state.process_num - 1; + return mcdserver_state.processes[index].pid; + } + return cpu->cluster_index + 1; +} + +/** + * mcd_get_cpu_process() - Returns the process of the provided CPU. + * + * @cpu: The CPU state. + */ +static MCDProcess *mcd_get_cpu_process(CPUState *cpu) +{ + return mcd_get_process(mcd_get_cpu_pid(cpu)); +} + +/** + * mcd_next_attached_cpu() - Returns the first CPU with an attached process + * starting after the + * provided cpu. + * + * @cpu: The CPU to start from. + */ +static CPUState *mcd_next_attached_cpu(CPUState *cpu) +{ + cpu = CPU_NEXT(cpu); + + while (cpu) { + if (mcd_get_cpu_process(cpu)->attached) { + break; + } + + cpu = CPU_NEXT(cpu); + } + + return cpu; +} + +/** + * mcd_first_attached_cpu() - Returns the first CPU with an attached process. + */ +static CPUState *mcd_first_attached_cpu(void) +{ + CPUState *cpu = first_cpu; + MCDProcess *process = mcd_get_cpu_process(cpu); + + if (!process->attached) { + return mcd_next_attached_cpu(cpu); + } + + return cpu; } /** @@ -110,6 +517,21 @@ static void mcd_chr_receive(void *opaque, const uint8_t *buf, int size) */ static void mcd_chr_event(void *opaque, QEMUChrEvent event) { + int i; + MCDState *s = (MCDState *) opaque; + + switch (event) { + case CHR_EVENT_OPENED: + /* Start with first process attached, others detached */ + for (i = 0; i < s->process_num; i++) { + s->processes[i].attached = !i; + } + + s->c_cpu = mcd_first_attached_cpu(); + break; + default: + break; + } } /** From patchwork Wed Dec 20 16:25:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500350 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 697AFC3DA6E for ; Wed, 20 Dec 2023 16:29:04 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzP4-0000Q2-1B; Wed, 20 Dec 2023 11:26:38 -0500 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 1rFzOx-0000Mq-EB for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:31 -0500 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 1rFzOr-0004jn-LO for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:29 -0500 Received: (qmail 15324 invoked by uid 484); 20 Dec 2023 16:26:19 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 5e-06 secs); 20 Dec 2023 16:26:19 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:17 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 10/18] mcdstub: open and close server functions added Date: Wed, 20 Dec 2023 17:25:47 +0100 Message-Id: <20231220162555.19545-11-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/mcdstub.c | 299 ++++++++++++++++++++++++++++------------ 1 file changed, 214 insertions(+), 85 deletions(-) diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index 642f3c2826..45daa38689 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -65,6 +65,91 @@ static void mcd_sigterm_handler(int signal) } #endif +/** + * mcd_get_process() - Returns the process of the provided pid. + * + * @pid: The process ID. + */ +static MCDProcess *mcd_get_process(uint32_t pid) +{ + int i; + + if (!pid) { + /* 0 means any process, we take the first one */ + return &mcdserver_state.processes[0]; + } + + for (i = 0; i < mcdserver_state.process_num; i++) { + if (mcdserver_state.processes[i].pid == pid) { + return &mcdserver_state.processes[i]; + } + } + + return NULL; +} + +/** + * mcd_get_cpu_pid() - Returns the process ID of the provided CPU. + * + * @cpu: The CPU state. + */ +static uint32_t mcd_get_cpu_pid(CPUState *cpu) +{ + if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) { + /* Return the default process' PID */ + int index = mcdserver_state.process_num - 1; + return mcdserver_state.processes[index].pid; + } + return cpu->cluster_index + 1; +} + +/** + * mcd_get_cpu_process() - Returns the process of the provided CPU. + * + * @cpu: The CPU state. + */ +static MCDProcess *mcd_get_cpu_process(CPUState *cpu) +{ + return mcd_get_process(mcd_get_cpu_pid(cpu)); +} + +/** + * mcd_next_attached_cpu() - Returns the first CPU with an attached process + * starting after the + * provided cpu. + * + * @cpu: The CPU to start from. + */ +static CPUState *mcd_next_attached_cpu(CPUState *cpu) +{ + cpu = CPU_NEXT(cpu); + + while (cpu) { + if (mcd_get_cpu_process(cpu)->attached) { + break; + } + + cpu = CPU_NEXT(cpu); + } + + return cpu; +} + +/** + * mcd_first_attached_cpu() - Returns the first CPU with an attached process. + */ +static CPUState *mcd_first_attached_cpu(void) +{ + CPUState *cpu = first_cpu; + MCDProcess *process = mcd_get_cpu_process(cpu); + + if (!process->attached) { + return mcd_next_attached_cpu(cpu); + } + + return cpu; +} + /** * mcd_vm_state_change() - Handles a state change of the QEMU VM. * @@ -284,6 +369,117 @@ static void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd) } } +/** + * init_resets() - Initializes the resets info. + * + * This function currently only adds all theoretical possible resets to the + * resets GArray. None of the resets work at the moment. The resets are: + * "full_system_reset", "gpr_reset" and "memory_reset". + * @resets: GArray with possible resets. + */ +static int init_resets(GArray *resets) +{ + mcd_reset_st system_reset = { .id = 0, .name = RESET_SYSTEM}; + mcd_reset_st gpr_reset = { .id = 1, .name = RESET_GPR}; + mcd_reset_st memory_reset = { .id = 2, .name = RESET_MEMORY}; + g_array_append_vals(resets, (gconstpointer)&system_reset, 1); + g_array_append_vals(resets, (gconstpointer)&gpr_reset, 1); + g_array_append_vals(resets, (gconstpointer)&memory_reset, 1); + return 0; +} + +/** + * init_trigger() - Initializes the trigger info. + * + * This function adds the types of trigger, their possible options and actions + * to the trigger struct. + * @trigger: Struct with all trigger info. + */ +static int init_trigger(mcd_trigger_into_st *trigger) +{ + snprintf(trigger->type, sizeof(trigger->type), + "%d,%d,%d,%d", MCD_BREAKPOINT_HW, MCD_BREAKPOINT_READ, + MCD_BREAKPOINT_WRITE, MCD_BREAKPOINT_RW); + snprintf(trigger->option, sizeof(trigger->option), + "%s", MCD_TRIG_OPT_VALUE); + snprintf(trigger->action, sizeof(trigger->action), + "%s", MCD_TRIG_ACT_BREAK); + /* there can be 16 breakpoints and 16 watchpoints each */ + trigger->nr_trigger = 16; + return 0; +} + +/** + * handle_open_server() - Handler for opening the MCD server. + * + * This is the first function that gets called from the MCD Shared Library. + * It initializes core indepent data with the :c:func:`init_resets` and + * \reg init_trigger functions. It also send the TCP_HANDSHAKE_SUCCESS + * packet back to the library to confirm the mcdstub is ready for further + * communication. + * @params: GArray with all TCP packet parameters. + */ +static void handle_open_server(GArray *params, void *user_ctx) +{ + /* initialize core-independent data */ + int return_value = 0; + mcdserver_state.resets = g_array_new(false, true, sizeof(mcd_reset_st)); + return_value = init_resets(mcdserver_state.resets); + if (return_value != 0) { + g_assert_not_reached(); + } + return_value = init_trigger(&mcdserver_state.trigger); + if (return_value != 0) { + g_assert_not_reached(); + } + + mcd_put_packet(TCP_HANDSHAKE_SUCCESS); +} + +/** + * mcd_vm_start() - Starts all CPUs with the vm_start function. + */ +static void mcd_vm_start(void) +{ + if (!runstate_needs_reset() && !runstate_is_running()) { + vm_start(); + } +} + +/** + * handle_close_server() - Handler for closing the MCD server. + * + * This function detaches the debugger (process) and frees up memory. + * Then it start the QEMU VM with :c:func:`mcd_vm_start`. + * @params: GArray with all TCP packet parameters. + */ +static void handle_close_server(GArray *params, void *user_ctx) +{ + uint32_t pid = 1; + MCDProcess *process = mcd_get_process(pid); + + /* + * 1. free memory + * TODO: do this only if there are no processes attached anymore! + */ + g_list_free(mcdserver_state.all_memspaces); + g_list_free(mcdserver_state.all_reggroups); + g_list_free(mcdserver_state.all_registers); + g_array_free(mcdserver_state.resets, TRUE); + + /* 2. detach */ + process->attached = false; + + /* 3. reset process */ + if (pid == mcd_get_cpu_pid(mcdserver_state.c_cpu)) { + mcdserver_state.c_cpu = mcd_first_attached_cpu(); + } + if (!mcdserver_state.c_cpu) { + /* no more processes attached */ + mcd_vm_start(); + } +} + /** * mcd_handle_packet() - Evaluates the type of received packet and chooses the * correct handler. @@ -302,6 +498,24 @@ static int mcd_handle_packet(const char *line_buf) const MCDCmdParseEntry *cmd_parser = NULL; switch (line_buf[0]) { + case TCP_CHAR_OPEN_SERVER: + { + static MCDCmdParseEntry open_server_cmd_desc = { + .handler = handle_open_server, + .cmd = {TCP_CHAR_OPEN_SERVER, '\0'}, + }; + cmd_parser = &open_server_cmd_desc; + } + break; + case TCP_CHAR_CLOSE_SERVER: + { + static MCDCmdParseEntry close_server_cmd_desc = { + .handler = handle_close_server, + .cmd = {TCP_CHAR_CLOSE_SERVER, '\0'}, + }; + cmd_parser = &close_server_cmd_desc; + } + break; default: /* command not supported */ mcd_put_packet(""); @@ -422,91 +636,6 @@ static void mcd_chr_receive(void *opaque, const uint8_t *buf, int size) } } -/** - * mcd_get_process() - Returns the process of the provided pid. - * - * @pid: The process ID. - */ -static MCDProcess *mcd_get_process(uint32_t pid) -{ - int i; - - if (!pid) { - /* 0 means any process, we take the first one */ - return &mcdserver_state.processes[0]; - } - - for (i = 0; i < mcdserver_state.process_num; i++) { - if (mcdserver_state.processes[i].pid == pid) { - return &mcdserver_state.processes[i]; - } - } - - return NULL; -} - -/** - * mcd_get_cpu_pid() - Returns the process ID of the provided CPU. - * - * @cpu: The CPU state. - */ -static uint32_t mcd_get_cpu_pid(CPUState *cpu) -{ - if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) { - /* Return the default process' PID */ - int index = mcdserver_state.process_num - 1; - return mcdserver_state.processes[index].pid; - } - return cpu->cluster_index + 1; -} - -/** - * mcd_get_cpu_process() - Returns the process of the provided CPU. - * - * @cpu: The CPU state. - */ -static MCDProcess *mcd_get_cpu_process(CPUState *cpu) -{ - return mcd_get_process(mcd_get_cpu_pid(cpu)); -} - -/** - * mcd_next_attached_cpu() - Returns the first CPU with an attached process - * starting after the - * provided cpu. - * - * @cpu: The CPU to start from. - */ -static CPUState *mcd_next_attached_cpu(CPUState *cpu) -{ - cpu = CPU_NEXT(cpu); - - while (cpu) { - if (mcd_get_cpu_process(cpu)->attached) { - break; - } - - cpu = CPU_NEXT(cpu); - } - - return cpu; -} - -/** - * mcd_first_attached_cpu() - Returns the first CPU with an attached process. - */ -static CPUState *mcd_first_attached_cpu(void) -{ - CPUState *cpu = first_cpu; - MCDProcess *process = mcd_get_cpu_process(cpu); - - if (!process->attached) { - return mcd_next_attached_cpu(cpu); - } - - return cpu; -} - /** * mcd_chr_event() - Handles a TCP client connect. * From patchwork Wed Dec 20 16:25:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500354 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 73E23C3DA6E for ; Wed, 20 Dec 2023 16:29:49 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzP1-0000Ok-8L; Wed, 20 Dec 2023 11:26:35 -0500 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 1rFzOx-0000Mt-EW for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:31 -0500 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 1rFzOr-0004lG-LJ for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:30 -0500 Received: (qmail 15354 invoked by uid 484); 20 Dec 2023 16:26:20 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.073577 secs); 20 Dec 2023 16:26:20 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:19 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 11/18] mcdstub: system and core queries added Date: Wed, 20 Dec 2023 17:25:48 +0100 Message-Id: <20231220162555.19545-12-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/arm_mcdstub.c | 243 ++++++++++++++++++++ debug/mcdstub/mcdstub.c | 370 ++++++++++++++++++++++++++++++- debug/mcdstub/meson.build | 2 +- include/mcdstub/arm_mcdstub.h | 85 +++++++ include/mcdstub/mcdstub.h | 5 - include/mcdstub/mcdstub_common.h | 19 ++ 6 files changed, 717 insertions(+), 7 deletions(-) diff --git a/debug/mcdstub/arm_mcdstub.c b/debug/mcdstub/arm_mcdstub.c index c24aaf1202..ce5264a617 100644 --- a/debug/mcdstub/arm_mcdstub.c +++ b/debug/mcdstub/arm_mcdstub.c @@ -16,3 +16,246 @@ * * SPDX-License-Identifier: LGPL-2.0+ */ + +#include "qemu/osdep.h" +#include "mcdstub/arm_mcdstub.h" + +int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces) +{ + int nr_address_spaces = cpu->num_ases; + uint32_t mem_space_id = 0; + + mem_space_id++; + mcd_mem_space_st non_secure = { + .name = "Non Secure", + .id = mem_space_id, + .type = 34, + .bits_per_mau = 8, + .invariance = 1, + .endian = 1, + .min_addr = 0, + .max_addr = -1, + .supported_access_options = 0, + .is_secure = false, + .is_physical = false, + }; + g_array_append_vals(memspaces, (gconstpointer)&non_secure, 1); + mem_space_id++; + mcd_mem_space_st phys_non_secure = { + .name = "Physical (Non Secure)", + .id = mem_space_id, + .type = 18, + .bits_per_mau = 8, + .invariance = 1, + .endian = 1, + .min_addr = 0, + .max_addr = -1, + .supported_access_options = 0, + .is_secure = false, + .is_physical = true, + }; + g_array_append_vals(memspaces, (gconstpointer)&phys_non_secure, 1); + if (nr_address_spaces > 1) { + mem_space_id++; + mcd_mem_space_st secure = { + .name = "Secure", + .id = mem_space_id, + .type = 34, + .bits_per_mau = 8, + .invariance = 1, + .endian = 1, + .min_addr = 0, + .max_addr = -1, + .supported_access_options = 0, + .is_secure = true, + .is_physical = false, + }; + g_array_append_vals(memspaces, (gconstpointer)&secure, 1); + mem_space_id++; + mcd_mem_space_st phys_secure = { + .name = "Physical (Secure)", + .id = mem_space_id, + .type = 18, + .bits_per_mau = 8, + .invariance = 1, + .endian = 1, + .min_addr = 0, + .max_addr = -1, + .supported_access_options = 0, + .is_secure = true, + .is_physical = true, + }; + g_array_append_vals(memspaces, (gconstpointer)&phys_secure, 1); + } + mem_space_id++; + mcd_mem_space_st gpr = { + .name = "GPR Registers", + .id = mem_space_id, + .type = 1, + .bits_per_mau = 8, + .invariance = 1, + .endian = 1, + .min_addr = 0, + .max_addr = -1, + .supported_access_options = 0, + }; + g_array_append_vals(memspaces, (gconstpointer)&gpr, 1); + mem_space_id++; + mcd_mem_space_st cpr = { + .name = "CP15 Registers", + .id = mem_space_id, + .type = 1, + .bits_per_mau = 8, + .invariance = 1, + .endian = 1, + .min_addr = 0, + .max_addr = -1, + .supported_access_options = 0, + }; + g_array_append_vals(memspaces, (gconstpointer)&cpr, 1); + return 0; +} + +int arm_mcd_parse_core_xml_file(CPUClass *cc, GArray *reggroups, + GArray *registers, int *current_group_id) +{ + const char *xml_filename = NULL; + const char *current_xml_filename = NULL; + const char *xml_content = NULL; + int i = 0; + + /* 1. get correct file */ + xml_filename = cc->gdb_core_xml_file; + for (i = 0; ; i++) { + current_xml_filename = gdb_static_features[i].xmlname; + if (!current_xml_filename || (strncmp(current_xml_filename, + xml_filename, strlen(xml_filename)) == 0 + && strlen(current_xml_filename) == strlen(xml_filename))) + break; + } + /* without gpr registers we can do nothing */ + if (!current_xml_filename) { + return -1; + } + + /* 2. add group for gpr registers */ + mcd_reg_group_st gprregs = { + .name = "GPR Registers", + .id = *current_group_id + }; + g_array_append_vals(reggroups, (gconstpointer)&gprregs, 1); + *current_group_id = *current_group_id + 1; + + /* 3. parse xml */ + /* the offset for gpr is always zero */ + xml_content = gdb_static_features[i].xml; + parse_reg_xml(xml_content, strlen(xml_content), registers, + MCD_ARM_REG_TYPE_GPR, 0); + return 0; +} + +int arm_mcd_parse_general_xml_files(CPUState *cpu, GArray *reggroups, + GArray *registers, int *current_group_id) { + const char *xml_filename = NULL; + const char *current_xml_filename = NULL; + const char *xml_content = NULL; + uint8_t reg_type = 0; + CPUClass *cc = CPU_GET_CLASS(cpu); + + /* iterate over all gdb xml files*/ + GDBRegisterState *r; + for (guint i = 0; i < cpu->gdb_regs->len; i++) { + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); + + xml_filename = r->xml; + xml_content = NULL; + + /* 1. get xml content */ + if (cc->gdb_get_dynamic_xml) { + xml_content = cc->gdb_get_dynamic_xml(cpu, xml_filename); + } + if (xml_content) { + if (strcmp(xml_filename, "system-registers.xml") == 0) { + /* these are the coprocessor register */ + mcd_reg_group_st corprocessorregs = { + .name = "CP15 Registers", + .id = *current_group_id + }; + g_array_append_vals(reggroups, + (gconstpointer)&corprocessorregs, 1); + *current_group_id = *current_group_id + 1; + reg_type = MCD_ARM_REG_TYPE_CPR; + } + } else { + /* its not a coprocessor xml -> it is a static xml file */ + int j = 0; + for (j = 0; ; j++) { + current_xml_filename = gdb_static_features[j].xmlname; + if (!current_xml_filename || (strncmp(current_xml_filename, + xml_filename, strlen(xml_filename)) == 0 + && strlen(current_xml_filename) == strlen(xml_filename))) + break; + } + if (current_xml_filename) { + xml_content = gdb_static_features[j].xml; + /* select correct reg_type */ + if (strcmp(current_xml_filename, "arm-vfp.xml") == 0) { + reg_type = MCD_ARM_REG_TYPE_VFP; + } else if (strcmp(current_xml_filename, "arm-vfp3.xml") == 0) { + reg_type = MCD_ARM_REG_TYPE_VFP; + } else if (strcmp(current_xml_filename, + "arm-vfp-sysregs.xml") == 0) { + reg_type = MCD_ARM_REG_TYPE_VFP_SYS; + } else if (strcmp(current_xml_filename, + "arm-neon.xml") == 0) { + reg_type = MCD_ARM_REG_TYPE_VFP; + } else if (strcmp(current_xml_filename, + "arm-m-profile-mve.xml") == 0) { + reg_type = MCD_ARM_REG_TYPE_MVE; + } + } else { + continue; + } + } + /* 2. parse xml */ + parse_reg_xml(xml_content, strlen(xml_content), registers, reg_type, + r->base_reg); + } + return 0; +} + +int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers, + CPUState *cpu) +{ + mcd_reg_st *current_register; + uint32_t i = 0; + + /* iterate over all registers */ + for (i = 0; i < registers->len; i++) { + current_register = &(g_array_index(registers, mcd_reg_st, i)); + /* add mcd_reg_group_id and mcd_mem_space_id */ + if (strcmp(current_register->group, "cp_regs") == 0) { + /* coprocessor registers */ + current_register->mcd_reg_group_id = 2; + current_register->mcd_mem_space_id = 6; + /* + * get info for opcode + * for 32bit the opcode is only 16 bit long + * for 64bit it is 32 bit long + */ + current_register->opcode |= + arm_mcd_get_opcode(cpu, current_register->internal_id); + } else { + /* gpr register */ + current_register->mcd_reg_group_id = 1; + current_register->mcd_mem_space_id = 5; + } + } + return 0; +} + +uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n) +{ + /* TODO: not working with current build structure */ + return 0; +} diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index 45daa38689..4095b3f8ce 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -34,6 +34,7 @@ #include "mcdstub/mcd_shared_defines.h" #include "mcdstub/mcdstub.h" +#include "mcdstub/arm_mcdstub.h" typedef struct { CharBackend chr; @@ -150,6 +151,25 @@ static CPUState *mcd_first_attached_cpu(void) return cpu; } +/** + * mcd_get_cpu() - Returns the CPU the index i_cpu_index. + * + * @cpu_index: Index of the desired CPU. + */ +static CPUState *mcd_get_cpu(uint32_t cpu_index) +{ + CPUState *cpu = first_cpu; + + while (cpu) { + if (cpu->cpu_index == cpu_index) { + return cpu; + } + cpu = mcd_next_attached_cpu(cpu); + } + + return cpu; +} + /** * mcd_vm_state_change() - Handles a state change of the QEMU VM. * @@ -221,6 +241,15 @@ static int mcd_put_packet(const char *buf) return mcd_put_packet_binary(buf, strlen(buf)); } +/** + * mcd_put_strbuf() - Calls :c:func:`mcd_put_packet` with the str_buf of the + * mcdserver_state. + */ +static void mcd_put_strbuf(void) +{ + mcd_put_packet(mcdserver_state.str_buf->str); +} + /** * cmd_parse_params() - Extracts all parameters from a TCP packet. * @@ -480,6 +509,134 @@ static void handle_close_server(GArray *params, void *user_ctx) } } +/** + * handle_gen_query() - Handler for all TCP query packets. + * + * Calls :c:func:`process_string_cmd` with all query functions in the + * mcd_query_cmds_table. :c:func:`process_string_cmd` then selects the correct + * one. This function just passes on the TCP packet data string from the + * parameters. + * @params: GArray with all TCP packet parameters. + */ +static void handle_gen_query(GArray *params, void *user_ctx) +{ + if (!params->len) { + return; + } + /* iterate over all possible query functions and execute the right one */ + if (process_string_cmd(NULL, get_param(params, 0)->data, + mcdserver_state.mcd_query_cmds_table, + ARRAY_SIZE(mcdserver_state.mcd_query_cmds_table))) { + mcd_put_packet(""); + } +} + +/** + * handle_open_core() - Handler for opening a core. + * + * This function initializes all data for the core with the ID provided in + * the first parameter. In has a swtich case for different architectures. + * Currently only 32-Bit ARM is supported. The data includes memory spaces, + * register groups and registers themselves. They get stored into GLists where + * every entry in the list corresponds to one opened core. + * @params: GArray with all TCP packet parameters. + */ +static void handle_open_core(GArray *params, void *user_ctx) +{ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + CPUState *cpu = mcd_get_cpu(cpu_id); + mcdserver_state.c_cpu = cpu; + CPUClass *cc = CPU_GET_CLASS(cpu); + const gchar *arch = cc->gdb_arch_name(cpu); + int return_value = 0; + + /* prepare data strucutures */ + GArray *memspaces = g_array_new(false, true, sizeof(mcd_mem_space_st)); + GArray *reggroups = g_array_new(false, true, sizeof(mcd_reg_group_st)); + GArray *registers = g_array_new(false, true, sizeof(mcd_reg_st)); + + if (strcmp(arch, MCDSTUB_ARCH_ARM) == 0) { + /* TODO: make group and memspace ids dynamic */ + int current_group_id = 1; + /* 1. store mem spaces */ + return_value = arm_mcd_store_mem_spaces(cpu, memspaces); + if (return_value != 0) { + g_assert_not_reached(); + } + /* 2. parse core xml */ + return_value = arm_mcd_parse_core_xml_file(cc, reggroups, + registers, ¤t_group_id); + if (return_value != 0) { + g_assert_not_reached(); + } + /* 3. parse other xmls */ + return_value = arm_mcd_parse_general_xml_files(cpu, reggroups, + registers, ¤t_group_id); + if (return_value != 0) { + g_assert_not_reached(); + } + /* 4. add additional data the the regs from the xmls */ + return_value = arm_mcd_get_additional_register_info(reggroups, + registers, cpu); + if (return_value != 0) { + g_assert_not_reached(); + } + /* 5. store all found data */ + if (g_list_nth(mcdserver_state.all_memspaces, cpu_id)) { + GList *memspaces_ptr = + g_list_nth(mcdserver_state.all_memspaces, cpu_id); + memspaces_ptr->data = memspaces; + } else { + mcdserver_state.all_memspaces = + g_list_insert(mcdserver_state.all_memspaces, memspaces, cpu_id); + } + if (g_list_nth(mcdserver_state.all_reggroups, cpu_id)) { + GList *reggroups_ptr = + g_list_nth(mcdserver_state.all_reggroups, cpu_id); + reggroups_ptr->data = reggroups; + } else { + mcdserver_state.all_reggroups = + g_list_insert(mcdserver_state.all_reggroups, reggroups, cpu_id); + } + if (g_list_nth(mcdserver_state.all_registers, cpu_id)) { + GList *registers_ptr = + g_list_nth(mcdserver_state.all_registers, cpu_id); + registers_ptr->data = registers; + } else { + mcdserver_state.all_registers = + g_list_insert(mcdserver_state.all_registers, registers, cpu_id); + } + } else { + /* we don't support other architectures */ + g_assert_not_reached(); + } +} + +/** + * handle_close_core() - Handler for closing a core. + * + * Frees all memory allocated for core specific information. This includes + * memory spaces, register groups and registers. + * @params: GArray with all TCP packet parameters. + */ +static void handle_close_core(GArray *params, void *user_ctx) +{ + /* free memory for correct core */ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + GArray *memspaces = g_list_nth_data(mcdserver_state.all_memspaces, cpu_id); + mcdserver_state.all_memspaces = + g_list_remove(mcdserver_state.all_memspaces, memspaces); + g_array_free(memspaces, TRUE); + GArray *reggroups = g_list_nth_data(mcdserver_state.all_reggroups, cpu_id); + mcdserver_state.all_reggroups = + g_list_remove(mcdserver_state.all_reggroups, reggroups); + g_array_free(reggroups, TRUE); + GArray *registers = g_list_nth_data(mcdserver_state.all_registers, cpu_id); + mcdserver_state.all_registers = + g_list_remove(mcdserver_state.all_registers, registers); + g_array_free(registers, TRUE); +} + /** * mcd_handle_packet() - Evaluates the type of received packet and chooses the * correct handler. @@ -516,6 +673,36 @@ static int mcd_handle_packet(const char *line_buf) cmd_parser = &close_server_cmd_desc; } break; + case TCP_CHAR_QUERY: + { + static MCDCmdParseEntry query_cmd_desc = { + .handler = handle_gen_query, + .cmd = {TCP_CHAR_QUERY, '\0'}, + .schema = {ARG_SCHEMA_STRING, '\0'}, + }; + cmd_parser = &query_cmd_desc; + } + break; + case TCP_CHAR_OPEN_CORE: + { + static MCDCmdParseEntry open_core_cmd_desc = { + .handler = handle_open_core, + .cmd = {TCP_CHAR_OPEN_CORE, '\0'}, + .schema = {ARG_SCHEMA_CORENUM, '\0'}, + }; + cmd_parser = &open_core_cmd_desc; + } + break; + case TCP_CHAR_CLOSE_CORE: + { + static MCDCmdParseEntry close_core_cmd_desc = { + .handler = handle_close_core, + .cmd = {TCP_CHAR_CLOSE_CORE, '\0'}, + .schema = {ARG_SCHEMA_CORENUM, '\0'}, + }; + cmd_parser = &close_core_cmd_desc; + } + break; default: /* command not supported */ mcd_put_packet(""); @@ -663,6 +850,49 @@ static void mcd_chr_event(void *opaque, QEMUChrEvent event) } } +/** + * handle_query_system() - Handler for the system query. + * + * Sends the system name, which is "qemu-system". + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_system(GArray *params, void *user_ctx) +{ + mcd_put_packet(MCD_SYSTEM_NAME); +} + +/** + * handle_query_cores() - Handler for the core query. + * + * This function sends the type of core and number of cores currently + * simulated by QEMU. It also sends a device name for the MCD data structure. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_cores(GArray *params, void *user_ctx) +{ + /* get first cpu */ + CPUState *cpu = mcd_first_attached_cpu(); + if (!cpu) { + return; + } + + ObjectClass *oc = object_get_class(OBJECT(cpu)); + const char *cpu_model = object_class_get_name(oc); + + CPUClass *cc = CPU_GET_CLASS(cpu); + const gchar *arch = cc->gdb_arch_name(cpu); + + uint32_t nr_cores = cpu->nr_cores; + char device_name[ARGUMENT_STRING_LENGTH] = {0}; + if (arch) { + snprintf(device_name, sizeof(device_name), "qemu-%s-device", arch); + } + g_string_printf(mcdserver_state.str_buf, "%s=%s.%s=%s.%s=%u.", + TCP_ARGUMENT_DEVICE, device_name, TCP_ARGUMENT_CORE, cpu_model, + TCP_ARGUMENT_AMOUNT_CORE, nr_cores); + mcd_put_strbuf(); +} + /** * init_query_cmds_table() - Initializes all query functions. * @@ -671,7 +901,24 @@ static void mcd_chr_event(void *opaque, QEMUChrEvent event) * @mcd_query_cmds_table: Lookup table with all query commands. */ static void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table) -{} +{ + /* initalizes a list of all query commands */ + int cmd_number = 0; + + MCDCmdParseEntry query_system = { + .handler = handle_query_system, + .cmd = QUERY_ARG_SYSTEM, + }; + mcd_query_cmds_table[cmd_number] = query_system; + cmd_number++; + + MCDCmdParseEntry query_cores = { + .handler = handle_query_cores, + .cmd = QUERY_ARG_CORES, + }; + mcd_query_cmds_table[cmd_number] = query_cores; + cmd_number++; +} /** * mcd_set_stop_cpu() - Sets c_cpu to the just stopped CPU. @@ -924,3 +1171,124 @@ int mcdserver_start(const char *device) return 0; } + +void parse_reg_xml(const char *xml, int size, GArray* registers, + uint8_t reg_type, uint32_t reg_id_offset) +{ + /* iterates over the complete xml file */ + int i, j; + uint32_t current_reg_id = reg_id_offset; + uint32_t internal_id = 0; + int still_to_skip = 0; + char argument[64] = {0}; + char value[64] = {0}; + bool is_reg = false; + bool is_argument = false; + bool is_value = false; + GArray *reg_data = NULL; + + char c; + char *c_ptr; + + xml_attrib attribute_j; + const char *argument_j; + const char *value_j; + + for (i = 0; i < size; i++) { + c = xml[i]; + c_ptr = &c; + + if (still_to_skip > 0) { + /* skip unwanted chars */ + still_to_skip--; + continue; + } + + if (strncmp(&xml[i], "", 2) == 0) { + /* end of register info */ + still_to_skip = 1; + is_reg = false; + + /* create empty register */ + mcd_reg_st my_register = (const struct mcd_reg_st){ 0 }; + + /* add found attribtues */ + for (j = 0; j < reg_data->len; j++) { + attribute_j = g_array_index(reg_data, xml_attrib, j); + + argument_j = attribute_j.argument; + value_j = attribute_j.value; + + if (strcmp(argument_j, "name") == 0) { + strcpy(my_register.name, value_j); + } else if (strcmp(argument_j, "regnum") == 0) { + my_register.id = atoi(value_j); + } else if (strcmp(argument_j, "bitsize") == 0) { + my_register.bitsize = atoi(value_j); + } else if (strcmp(argument_j, "type") == 0) { + strcpy(my_register.type, value_j); + } else if (strcmp(argument_j, "group") == 0) { + strcpy(my_register.group, value_j); + } + } + /* add reg_type, internal_id and id*/ + my_register.reg_type = reg_type; + my_register.internal_id = internal_id; + internal_id++; + if (!my_register.id) { + my_register.id = current_reg_id; + current_reg_id++; + } else { + /* set correct ID for the next register */ + current_reg_id = my_register.id + 1; + } + /* store register */ + g_array_append_vals(registers, (gconstpointer)&my_register, 1); + /* free memory */ + g_array_free(reg_data, false); + } else { + /* store info for register */ + switch (c) { + case ' ': + break; + case '=': + is_argument = false; + break; + case '"': + if (is_value) { + /* end of value reached */ + is_value = false; + /* store arg-val combo */ + xml_attrib current_attribute; + strcpy(current_attribute.argument, argument); + strcpy(current_attribute.value, value); + g_array_append_vals(reg_data, + (gconstpointer)¤t_attribute, 1); + memset(argument, 0, sizeof(argument)); + memset(value, 0, sizeof(value)); + } else { + /*start of value */ + is_value = true; + } + break; + default: + if (is_argument) { + strncat(argument, c_ptr, 1); + } else if (is_value) { + strncat(value, c_ptr, 1); + } else { + is_argument = true; + strncat(argument, c_ptr, 1); + } + break; + } + } + } + } +} diff --git a/debug/mcdstub/meson.build b/debug/mcdstub/meson.build index 7e5ae878b0..3051a4e731 100644 --- a/debug/mcdstub/meson.build +++ b/debug/mcdstub/meson.build @@ -1,6 +1,6 @@ # only system emulation is supported over mcd mcd_system_ss = ss.source_set() -mcd_system_ss.add(files('mcdstub.c')) +mcd_system_ss.add(files('mcdstub.c', 'arm_mcdstub.c')) mcd_system_ss = mcd_system_ss.apply(config_host, strict: false) libmcd_system = static_library('mcd_system', diff --git a/include/mcdstub/arm_mcdstub.h b/include/mcdstub/arm_mcdstub.h index c24aaf1202..9961145f07 100644 --- a/include/mcdstub/arm_mcdstub.h +++ b/include/mcdstub/arm_mcdstub.h @@ -16,3 +16,88 @@ * * SPDX-License-Identifier: LGPL-2.0+ */ + +#ifndef ARM_MCDSTUB_H +#define ARM_MCDSTUB_H + +#include "hw/core/cpu.h" +#include "mcdstub_common.h" +/* just used for the register xml files */ +#include "exec/gdbstub.h" + +/* ids for each different type of register */ +enum { + MCD_ARM_REG_TYPE_GPR, + MCD_ARM_REG_TYPE_VFP, + MCD_ARM_REG_TYPE_VFP_SYS, + MCD_ARM_REG_TYPE_MVE, + MCD_ARM_REG_TYPE_CPR, +}; + +/** + * arm_mcd_store_mem_spaces() - Stores all 32-Bit ARM specific memory spaces. + * + * This function stores the memory spaces into the memspaces GArray. + * It only stores secure memory spaces if the CPU has more than one address + * space. It also stores a GPR and a CP15 register memory space. + * @memspaces: GArray of memory spaces. + * @cpu: CPU state. + */ +int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces); + +/** + * arm_mcd_parse_core_xml_file() - Parses the GPR registers. + * + * This function parses the core XML file, which includes the GPR registers. + * The regsters get stored in a GArray and a GPR register group is stored in a + * second GArray. + * @reggroups: GArray of register groups. + * @registers: GArray of registers. + * @cc: The CPU class. + * @current_group_id: The current group ID. It increases after + * each group. + */ +int arm_mcd_parse_core_xml_file(CPUClass *cc, GArray *reggroups, + GArray *registers, int *current_group_id); + +/** + * arm_mcd_parse_general_xml_files() - Parses all but the GPR registers. + * + * This function parses all XML files except for the core XML file. + * The regsters get stored in a GArray and if the system-registers.xml file is + * parsed, it also adds a CP15 register group. + * @reggroups: GArray of register groups. + * @registers: GArray of registers. + * @cpu: The CPU state. + * @current_group_id: The current group ID. It increases after + * each added group. + */ +int arm_mcd_parse_general_xml_files(CPUState *cpu, GArray* reggroups, + GArray *registers, int *current_group_id); + +/** + * arm_mcd_get_additional_register_info() - Adds additional data to parsed + * registers. + * + * This function is called, after :c:func:`arm_mcd_parse_core_xml_file` and + * :c:func:`arm_mcd_parse_general_xml_files`. It adds additional data for all + * already parsed registers. The registers get a correct ID, group, memory + * space and opcode, if they are CP15 registers. + * @reggroups: GArray of register groups. + * @registers: GArray of registers. + * @cpu: The CPU state. + */ +int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers, + CPUState *cpu); + +/** + * arm_mcd_get_opcode() - Returns the opcode for a coprocessor register. + * + * This function uses the opc1, opc2, crm and crn members of the register to + * create the opcode. The formular for creating the opcode is determined by ARM. + * @n: The register ID of the CP register. + * @cs: CPU state. + */ +uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n); + +#endif /* ARM_MCDSTUB_H */ diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h index 26aa33c0e3..ac14b2cda8 100644 --- a/include/mcdstub/mcdstub.h +++ b/include/mcdstub/mcdstub.h @@ -151,11 +151,6 @@ typedef struct MCDState { /* lives in mcdstub.c */ extern MCDState mcdserver_state; -typedef struct xml_attrib { - char argument[ARGUMENT_STRING_LENGTH]; - char value[ARGUMENT_STRING_LENGTH]; -} xml_attrib; - typedef struct mcd_reset_st { const char *name; uint8_t id; diff --git a/include/mcdstub/mcdstub_common.h b/include/mcdstub/mcdstub_common.h index b64748c080..d6ff55005e 100644 --- a/include/mcdstub/mcdstub_common.h +++ b/include/mcdstub/mcdstub_common.h @@ -61,4 +61,23 @@ typedef struct mcd_reg_group_st { uint32_t id; } mcd_reg_group_st; +typedef struct xml_attrib { + char argument[ARGUMENT_STRING_LENGTH]; + char value[ARGUMENT_STRING_LENGTH]; +} xml_attrib; + +/** + * parse_reg_xml() - Parses a GDB register XML file + * + * This fuction extracts all registers from the provided xml file and stores + * them into the registers GArray. It extracts the register name, bitsize, type + * and group if they are set. + * @xml: String with contents of the XML file. + * @registers: GArray with stored registers. + * @reg_type: Register type (depending on file). + * @size: Number of characters in the xml string. + */ +void parse_reg_xml(const char *xml, int size, GArray* registers, + uint8_t reg_type, uint32_t reg_id_offset); + #endif /* MCDSTUB_COMMON_H */ From patchwork Wed Dec 20 16:25:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500347 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 E46E7C3DA6E for ; Wed, 20 Dec 2023 16:28:42 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzPE-0000VC-JY; Wed, 20 Dec 2023 11:26:48 -0500 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 1rFzP5-0000SF-Sg for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:39 -0500 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 1rFzP3-0004lU-8z for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:39 -0500 Received: (qmail 15377 invoked by uid 484); 20 Dec 2023 16:26:23 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.162234 secs); 20 Dec 2023 16:26:23 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:21 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 12/18] mcdstub: all core specific queries added Date: Wed, 20 Dec 2023 17:25:49 +0100 Message-Id: <20231220162555.19545-13-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/mcdstub.c | 365 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 365 insertions(+) diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index 4095b3f8ce..e90fc81814 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -893,6 +893,301 @@ static void handle_query_cores(GArray *params, void *user_ctx) mcd_put_strbuf(); } +/** + * handle_query_reset_f() - Handler for the first reset query. + * + * This function sends the first reset name and ID. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_reset_f(GArray *params, void *user_ctx) +{ + /* 1. check length */ + int nb_resets = mcdserver_state.resets->len; + if (nb_resets == 1) { + /* indicates this is the last packet */ + g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX); + } else { + g_string_printf(mcdserver_state.str_buf, "1%s", QUERY_END_INDEX); + } + /* 2. send data */ + mcd_reset_st reset = g_array_index(mcdserver_state.resets, mcd_reset_st, 0); + g_string_append_printf(mcdserver_state.str_buf, "%s=%s.%s=%u.", + TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id); + mcd_put_strbuf(); +} + +/** + * handle_query_reset_c() - Handler for all consecutive reset queries. + * + * This functions sends all consecutive reset names and IDs. It uses the + * query_index parameter to determine which reset is queried next. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_reset_c(GArray *params, void *user_ctx) +{ + /* reset options are the same for every cpu! */ + uint32_t query_index = get_param(params, 0)->query_handle; + + /* 1. check weather this was the last mem space */ + int nb_groups = mcdserver_state.resets->len; + if (query_index + 1 == nb_groups) { + /* indicates this is the last packet */ + g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX); + } else { + g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1); + } + + /* 2. send data */ + mcd_reset_st reset = g_array_index(mcdserver_state.resets, + mcd_reset_st, query_index); + g_string_append_printf(mcdserver_state.str_buf, "%s=%s.%s=%u.", + TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id); + mcd_put_strbuf(); +} + +/** + * handle_query_trigger() - Handler for trigger query. + * + * Sends data on the different types of trigger and their options and actions. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_trigger(GArray *params, void *user_ctx) +{ + mcd_trigger_into_st trigger = mcdserver_state.trigger; + g_string_printf(mcdserver_state.str_buf, "%s=%u.%s=%s.%s=%s.%s=%s.", + TCP_ARGUMENT_AMOUNT_TRIGGER, trigger.nr_trigger, + TCP_ARGUMENT_TYPE, trigger.type, + TCP_ARGUMENT_OPTION, trigger.option, + TCP_ARGUMENT_ACTION, trigger.action); + mcd_put_strbuf(); +} + +/** + * handle_query_mem_spaces_f() Handler for the first memory space query. + * + * This function sends the first memory space name, ID, type and accessing + * options. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_mem_spaces_f(GArray *params, void *user_ctx) +{ + /* 1. get correct memspaces and set the query_cpu */ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + mcdserver_state.query_cpu_id = cpu_id; + GArray *memspaces = g_list_nth_data(mcdserver_state.all_memspaces, cpu_id); + + /* 2. check length */ + int nb_groups = memspaces->len; + if (nb_groups == 1) { + /* indicates this is the last packet */ + g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX); + } else { + g_string_printf(mcdserver_state.str_buf, "1%s", QUERY_END_INDEX); + } + + /* 3. send data */ + mcd_mem_space_st space = g_array_index(memspaces, mcd_mem_space_st, 0); + g_string_append_printf(mcdserver_state.str_buf, + "%s=%s.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.%s=%ld.%s=%ld.%s=%u.", + TCP_ARGUMENT_NAME, space.name, + TCP_ARGUMENT_ID, space.id, + TCP_ARGUMENT_TYPE, space.type, + TCP_ARGUMENT_BITS_PER_MAU, space.bits_per_mau, + TCP_ARGUMENT_INVARIANCE, space.invariance, + TCP_ARGUMENT_ENDIAN, space.endian, + TCP_ARGUMENT_MIN, space.min_addr, + TCP_ARGUMENT_MAX, space.max_addr, + TCP_ARGUMENT_SUPPORTED_ACCESS_OPTIONS, space.supported_access_options); + mcd_put_strbuf(); +} + +/** + * handle_query_mem_spaces_c() - Handler for all consecutive memory space + * queries. + * + * This function sends all consecutive memory space names, IDs, types and + * accessing options. + * It uses the query_index parameter to determine + * which memory space is queried next. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_mem_spaces_c(GArray *params, void *user_ctx) +{ + /* + * this funcitons send all mem spaces except for the first + * 1. get parameter and memspace + */ + uint32_t query_index = get_param(params, 0)->query_handle; + uint32_t cpu_id = mcdserver_state.query_cpu_id; + GArray *memspaces = g_list_nth_data(mcdserver_state.all_memspaces, cpu_id); + + /* 2. check weather this was the last mem space */ + int nb_groups = memspaces->len; + if (query_index + 1 == nb_groups) { + /* indicates this is the last packet */ + g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX); + } else { + g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1); + } + + /* 3. send the correct memspace */ + mcd_mem_space_st space = g_array_index(memspaces, + mcd_mem_space_st, query_index); + g_string_append_printf(mcdserver_state.str_buf, + "%s=%s.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.%s=%ld.%s=%ld.%s=%u.", + TCP_ARGUMENT_NAME, space.name, + TCP_ARGUMENT_ID, space.id, + TCP_ARGUMENT_TYPE, space.type, + TCP_ARGUMENT_BITS_PER_MAU, space.bits_per_mau, + TCP_ARGUMENT_INVARIANCE, space.invariance, + TCP_ARGUMENT_ENDIAN, space.endian, + TCP_ARGUMENT_MIN, space.min_addr, + TCP_ARGUMENT_MAX, space.max_addr, + TCP_ARGUMENT_SUPPORTED_ACCESS_OPTIONS, space.supported_access_options); + mcd_put_strbuf(); +} + +/** + * handle_query_reg_groups_f() - Handler for the first register group query. + * + * This function sends the first register group name and ID. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_reg_groups_f(GArray *params, void *user_ctx) +{ + /* 1. get correct reggroups and set the query_cpu */ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + mcdserver_state.query_cpu_id = cpu_id; + GArray *reggroups = g_list_nth_data(mcdserver_state.all_reggroups, cpu_id); + + /* 2. check length */ + int nb_groups = reggroups->len; + if (nb_groups == 1) { + /* indicates this is the last packet */ + g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX); + } else { + g_string_printf(mcdserver_state.str_buf, "1%s", QUERY_END_INDEX); + } + /* 3. send data */ + mcd_reg_group_st group = g_array_index(reggroups, mcd_reg_group_st, 0); + g_string_append_printf(mcdserver_state.str_buf, "%s=%u.%s=%s.", + TCP_ARGUMENT_ID, group.id, TCP_ARGUMENT_NAME, group.name); + mcd_put_strbuf(); +} + +/** + * handle_query_reg_groups_c() - Handler for all consecutive register group + * queries. + * + * This function sends all consecutive register group names and IDs. It uses + * the query_index parameter to determine which register group is queried next. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_reg_groups_c(GArray *params, void *user_ctx) +{ + /* + * this funcitons send all reg groups except for the first + * 1. get parameter and memspace + */ + uint32_t query_index = get_param(params, 0)->query_handle; + uint32_t cpu_id = mcdserver_state.query_cpu_id; + GArray *reggroups = g_list_nth_data(mcdserver_state.all_reggroups, cpu_id); + + /* 2. check weather this was the last reg group */ + int nb_groups = reggroups->len; + if (query_index + 1 == nb_groups) { + /* indicates this is the last packet */ + g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX); + } else { + g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1); + } + + /* 3. send the correct reggroup */ + mcd_reg_group_st group = g_array_index(reggroups, mcd_reg_group_st, + query_index); + g_string_append_printf(mcdserver_state.str_buf, "%s=%u.%s=%s.", + TCP_ARGUMENT_ID, group.id, TCP_ARGUMENT_NAME, group.name); + mcd_put_strbuf(); +} + +/** + * handle_query_regs_f() - Handler for the first register query. + * + * This function sends the first register with all its information. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_regs_f(GArray *params, void *user_ctx) +{ + /* 1. get correct registers and set the query_cpu */ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + mcdserver_state.query_cpu_id = cpu_id; + GArray *registers = g_list_nth_data(mcdserver_state.all_registers, cpu_id); + + /* 2. check length */ + int nb_regs = registers->len; + if (nb_regs == 1) { + /* indicates this is the last packet */ + g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX); + } else { + g_string_printf(mcdserver_state.str_buf, "1%s", QUERY_END_INDEX); + } + /* 3. send data */ + mcd_reg_st my_register = g_array_index(registers, mcd_reg_st, 0); + g_string_append_printf(mcdserver_state.str_buf, + "%s=%u.%s=%s.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.", + TCP_ARGUMENT_ID, my_register.id, + TCP_ARGUMENT_NAME, my_register.name, + TCP_ARGUMENT_SIZE, my_register.bitsize, + TCP_ARGUMENT_REGGROUPID, my_register.mcd_reg_group_id, + TCP_ARGUMENT_MEMSPACEID, my_register.mcd_mem_space_id, + TCP_ARGUMENT_TYPE, my_register.mcd_reg_type, + TCP_ARGUMENT_THREAD, my_register.mcd_hw_thread_id, + TCP_ARGUMENT_OPCODE, my_register.opcode); + mcd_put_strbuf(); +} + +/** + * handle_query_regs_c() - Handler for all consecutive register queries. + * + * This function sends all consecutive registers with all their information. + * It uses the query_index parameter to determine + * which register is queried next. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_regs_c(GArray *params, void *user_ctx) +{ + /* + * this funcitons send all regs except for the first + * 1. get parameter and registers + */ + uint32_t query_index = get_param(params, 0)->query_handle; + uint32_t cpu_id = mcdserver_state.query_cpu_id; + GArray *registers = g_list_nth_data(mcdserver_state.all_registers, cpu_id); + + /* 2. check weather this was the last register */ + int nb_regs = registers->len; + if (query_index + 1 == nb_regs) { + /* indicates this is the last packet */ + g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX); + } else { + g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1); + } + + /* 3. send the correct register */ + mcd_reg_st my_register = g_array_index(registers, mcd_reg_st, query_index); + g_string_append_printf(mcdserver_state.str_buf, + "%s=%u.%s=%s.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.", + TCP_ARGUMENT_ID, my_register.id, + TCP_ARGUMENT_NAME, my_register.name, + TCP_ARGUMENT_SIZE, my_register.bitsize, + TCP_ARGUMENT_REGGROUPID, my_register.mcd_reg_group_id, + TCP_ARGUMENT_MEMSPACEID, my_register.mcd_mem_space_id, + TCP_ARGUMENT_TYPE, my_register.mcd_reg_type, + TCP_ARGUMENT_THREAD, my_register.mcd_hw_thread_id, + TCP_ARGUMENT_OPCODE, my_register.opcode); + mcd_put_strbuf(); +} + /** * init_query_cmds_table() - Initializes all query functions. * @@ -918,6 +1213,76 @@ static void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table) }; mcd_query_cmds_table[cmd_number] = query_cores; cmd_number++; + + MCDCmdParseEntry query_reset_f = { + .handler = handle_query_reset_f, + .cmd = QUERY_ARG_RESET QUERY_FIRST, + }; + mcd_query_cmds_table[cmd_number] = query_reset_f; + cmd_number++; + + MCDCmdParseEntry query_reset_c = { + .handler = handle_query_reset_c, + .cmd = QUERY_ARG_RESET QUERY_CONSEQUTIVE, + }; + strcpy(query_reset_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' }); + mcd_query_cmds_table[cmd_number] = query_reset_c; + cmd_number++; + + MCDCmdParseEntry query_trigger = { + .handler = handle_query_trigger, + .cmd = QUERY_ARG_TRIGGER, + }; + mcd_query_cmds_table[cmd_number] = query_trigger; + cmd_number++; + + MCDCmdParseEntry query_mem_spaces_f = { + .handler = handle_query_mem_spaces_f, + .cmd = QUERY_ARG_MEMORY QUERY_FIRST, + }; + strcpy(query_mem_spaces_f.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' }); + mcd_query_cmds_table[cmd_number] = query_mem_spaces_f; + cmd_number++; + + MCDCmdParseEntry query_mem_spaces_c = { + .handler = handle_query_mem_spaces_c, + .cmd = QUERY_ARG_MEMORY QUERY_CONSEQUTIVE, + }; + strcpy(query_mem_spaces_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' }); + mcd_query_cmds_table[cmd_number] = query_mem_spaces_c; + cmd_number++; + + MCDCmdParseEntry query_reg_groups_f = { + .handler = handle_query_reg_groups_f, + .cmd = QUERY_ARG_REGGROUP QUERY_FIRST, + }; + strcpy(query_reg_groups_f.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' }); + mcd_query_cmds_table[cmd_number] = query_reg_groups_f; + cmd_number++; + + MCDCmdParseEntry query_reg_groups_c = { + .handler = handle_query_reg_groups_c, + .cmd = QUERY_ARG_REGGROUP QUERY_CONSEQUTIVE, + }; + strcpy(query_reg_groups_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' }); + mcd_query_cmds_table[cmd_number] = query_reg_groups_c; + cmd_number++; + + MCDCmdParseEntry query_regs_f = { + .handler = handle_query_regs_f, + .cmd = QUERY_ARG_REG QUERY_FIRST, + }; + strcpy(query_regs_f.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' }); + mcd_query_cmds_table[cmd_number] = query_regs_f; + cmd_number++; + + MCDCmdParseEntry query_regs_c = { + .handler = handle_query_regs_c, + .cmd = QUERY_ARG_REG QUERY_CONSEQUTIVE, + }; + strcpy(query_regs_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' }); + mcd_query_cmds_table[cmd_number] = query_regs_c; + cmd_number++; } /** From patchwork Wed Dec 20 16:25:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500352 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 1DBEEC3DA6E for ; Wed, 20 Dec 2023 16:29:23 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzPH-0000Wg-Nh; Wed, 20 Dec 2023 11:26:51 -0500 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 1rFzP9-0000TW-GQ for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:43 -0500 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 1rFzP7-0004mS-8o for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:43 -0500 Received: (qmail 15502 invoked by uid 484); 20 Dec 2023 16:26:26 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 1.8e-05 secs); 20 Dec 2023 16:26:26 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:23 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 13/18] mcdstub: go, step and break added Date: Wed, 20 Dec 2023 17:25:50 +0100 Message-Id: <20231220162555.19545-14-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/mcdstub.c | 218 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index e90fc81814..ee52830a2c 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -28,6 +28,7 @@ #include "chardev/char-fe.h" #include "hw/cpu/cluster.h" #include "hw/boards.h" +#include "exec/tb-flush.h" #include "sysemu/cpus.h" #include "sysemu/hw_accel.h" #include "sysemu/runstate.h" @@ -182,6 +183,96 @@ static CPUState *mcd_get_cpu(uint32_t cpu_index) */ static void mcd_vm_state_change(void *opaque, bool running, RunState state) { + CPUState *cpu = mcdserver_state.c_cpu; + + if (mcdserver_state.state == RS_INACTIVE) { + return; + } + + if (cpu == NULL) { + if (running) { + /* + * this is the case if qemu starts the vm + * before a mcd client is connected + */ + const char *mcd_state; + mcd_state = CORE_STATE_RUNNING; + const char *info_str; + info_str = STATE_STR_INIT_RUNNING; + mcdserver_state.cpu_state.state = mcd_state; + mcdserver_state.cpu_state.info_str = info_str; + } + return; + } + + const char *mcd_state; + const char *stop_str; + const char *info_str; + uint32_t bp_type = 0; + uint64_t bp_address = 0; + switch (state) { + case RUN_STATE_RUNNING: + mcd_state = CORE_STATE_RUNNING; + info_str = STATE_STR_RUNNING(cpu->cpu_index); + stop_str = ""; + break; + case RUN_STATE_DEBUG: + mcd_state = CORE_STATE_DEBUG; + info_str = STATE_STR_DEBUG(cpu->cpu_index); + if (cpu->watchpoint_hit) { + switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) { + case BP_MEM_READ: + bp_type = MCD_BREAKPOINT_READ; + stop_str = STATE_STR_BREAK_READ(cpu->watchpoint_hit->hitaddr); + break; + case BP_MEM_WRITE: + bp_type = MCD_BREAKPOINT_WRITE; + stop_str = STATE_STR_BREAK_WRITE(cpu->watchpoint_hit->hitaddr); + break; + case BP_MEM_ACCESS: + bp_type = MCD_BREAKPOINT_RW; + stop_str = STATE_STR_BREAK_RW(cpu->watchpoint_hit->hitaddr); + break; + default: + stop_str = STATE_STR_BREAK_UNKNOWN; + break; + } + bp_address = cpu->watchpoint_hit->hitaddr; + cpu->watchpoint_hit = NULL; + } else if (cpu->singlestep_enabled) { + /* we land here when a single step is performed */ + stop_str = STATE_STEP_PERFORMED; + } else { + bp_type = MCD_BREAKPOINT_HW; + stop_str = STATE_STR_BREAK_HW; + tb_flush(cpu); + } + /* deactivate single step */ + cpu_single_step(cpu, 0); + break; + case RUN_STATE_PAUSED: + info_str = STATE_STR_HALTED(cpu->cpu_index); + mcd_state = CORE_STATE_HALTED; + stop_str = ""; + break; + case RUN_STATE_WATCHDOG: + info_str = STATE_STR_UNKNOWN(cpu->cpu_index); + mcd_state = CORE_STATE_UNKNOWN; + stop_str = ""; + break; + default: + info_str = STATE_STR_UNKNOWN(cpu->cpu_index); + mcd_state = CORE_STATE_UNKNOWN; + stop_str = ""; + break; + } + + /* set state for c_cpu */ + mcdserver_state.cpu_state.state = mcd_state; + mcdserver_state.cpu_state.bp_type = bp_type; + mcdserver_state.cpu_state.bp_address = bp_address; + mcdserver_state.cpu_state.stop_str = stop_str; + mcdserver_state.cpu_state.info_str = info_str; } /** @@ -637,6 +728,104 @@ static void handle_close_core(GArray *params, void *user_ctx) g_array_free(registers, TRUE); } +/** + * mcd_cpu_start() - Starts the selected CPU with the cpu_resume function. + * + * @cpu: The CPU about to be started. + */ +static void mcd_cpu_start(CPUState *cpu) +{ + if (!runstate_needs_reset() && !runstate_is_running() && + !vm_prepare_start(false)) { + mcdserver_state.c_cpu = cpu; + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); + cpu_resume(cpu); + } +} + +/** + * mcd_cpu_sstep() - Performes a step on the selected CPU. + * + * This function first sets the correct single step flags for the CPU with + * cpu_single_step and then starts the CPU with cpu_resume. + * @cpu: The CPU about to be stepped. + */ +static int mcd_cpu_sstep(CPUState *cpu) +{ + mcdserver_state.c_cpu = cpu; + cpu_single_step(cpu, mcdserver_state.sstep_flags); + if (!runstate_needs_reset() && !runstate_is_running() && + !vm_prepare_start(true)) { + qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true); + cpu_resume(cpu); + } + return 0; +} + +/** + * mcd_vm_stop() - Brings all CPUs in debug state with the vm_stop function. + */ +static void mcd_vm_stop(void) +{ + if (runstate_is_running()) { + vm_stop(RUN_STATE_DEBUG); + } +} + +/** + * handle_vm_start() - Handler for the VM start TCP packet. + * + * Evaluates whether all cores or just a perticular core should get started and + * calls :c:func:`mcd_vm_start` or :c:func:`mcd_cpu_start` respectively. + * @params: GArray with all TCP packet parameters. + */ +static void handle_vm_start(GArray *params, void *user_ctx) +{ + uint32_t global = get_param(params, 0)->data_uint32_t; + if (global == 1) { + mcd_vm_start(); + } else{ + uint32_t cpu_id = get_param(params, 1)->cpu_id; + CPUState *cpu = mcd_get_cpu(cpu_id); + mcd_cpu_start(cpu); + } +} + +/** + * handle_vm_step() - Handler for the VM step TCP packet. + * + * Calls :c:func:`mcd_cpu_sstep` for the CPU which sould be stepped. + * Stepping all CPUs is currently not supported. + * @params: GArray with all TCP packet parameters. + */ +static void handle_vm_step(GArray *params, void *user_ctx) +{ + uint32_t global = get_param(params, 0)->data_uint32_t; + if (global == 1) { + /* TODO: add multicore support */ + } else{ + uint32_t cpu_id = get_param(params, 1)->cpu_id; + CPUState *cpu = mcd_get_cpu(cpu_id); + int return_value = mcd_cpu_sstep(cpu); + if (return_value != 0) { + g_assert_not_reached(); + } + } +} + +/** + * handle_vm_stop() - Handler for the VM stop TCP packet. + * + * Always calls :c:func:`mcd_vm_stop` and stops all cores. Stopping individual + * cores is currently not supported. + * @params: GArray with all TCP packet parameters. + */ +static void handle_vm_stop(GArray *params, void *user_ctx) +{ + /* TODO: add core dependant break option */ + mcd_vm_stop(); +} + /** * mcd_handle_packet() - Evaluates the type of received packet and chooses the * correct handler. @@ -703,6 +892,35 @@ static int mcd_handle_packet(const char *line_buf) cmd_parser = &close_core_cmd_desc; } break; + case TCP_CHAR_GO: + { + static MCDCmdParseEntry go_cmd_desc = { + .handler = handle_vm_start, + .cmd = {TCP_CHAR_GO, '\0'}, + .schema = {ARG_SCHEMA_INT, ARG_SCHEMA_CORENUM, '\0'}, + }; + cmd_parser = &go_cmd_desc; + } + break; + case TCP_CHAR_STEP: + { + static MCDCmdParseEntry step_cmd_desc = { + .handler = handle_vm_step, + .cmd = {TCP_CHAR_STEP, '\0'}, + .schema = {ARG_SCHEMA_INT, ARG_SCHEMA_CORENUM, '\0'}, + }; + cmd_parser = &step_cmd_desc; + } + break; + case TCP_CHAR_BREAK: + { + static MCDCmdParseEntry break_cmd_desc = { + .handler = handle_vm_stop, + .cmd = {TCP_CHAR_BREAK, '\0'}, + }; + cmd_parser = &break_cmd_desc; + } + break; default: /* command not supported */ mcd_put_packet(""); From patchwork Wed Dec 20 16:25:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500348 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 5368EC46CD2 for ; Wed, 20 Dec 2023 16:28:45 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzPI-0000Wm-Ow; Wed, 20 Dec 2023 11:26:52 -0500 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 1rFzPC-0000UI-F5 for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:46 -0500 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 1rFzPA-0004ml-AH for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:46 -0500 Received: (qmail 15531 invoked by uid 484); 20 Dec 2023 16:26:29 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.089016 secs); 20 Dec 2023 16:26:29 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:26 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 14/18] mcdstub: state query added Date: Wed, 20 Dec 2023 17:25:51 +0100 Message-Id: <20231220162555.19545-15-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/mcdstub.c | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index ee52830a2c..fb13958108 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -1406,6 +1406,43 @@ static void handle_query_regs_c(GArray *params, void *user_ctx) mcd_put_strbuf(); } +/** + * handle_query_state() - Handler for the state query. + * + * This function collects all data stored in the + * cpu_state member of the mcdserver_state and formats and sends it to the + * library. + * @params: GArray with all TCP packet parameters. + */ +static void handle_query_state(GArray *params, void *user_ctx) +{ + /* + * TODO: multicore support + * get state info + */ + mcd_cpu_state_st state_info = mcdserver_state.cpu_state; + /* TODO: add event information */ + uint32_t event = 0; + /* send data */ + g_string_printf(mcdserver_state.str_buf, + "%s=%s.%s=%u.%s=%u.%s=%u.%s=%lu.%s=%s.%s=%s.", + TCP_ARGUMENT_STATE, state_info.state, + TCP_ARGUMENT_EVENT, event, TCP_ARGUMENT_THREAD, 0, + TCP_ARGUMENT_TYPE, state_info.bp_type, + TCP_ARGUMENT_ADDRESS, state_info.bp_address, + TCP_ARGUMENT_STOP_STRING, state_info.stop_str, + TCP_ARGUMENT_INFO_STRING, state_info.info_str); + mcd_put_strbuf(); + + /* reset debug info after first query */ + if (strcmp(state_info.state, CORE_STATE_DEBUG) == 0) { + mcdserver_state.cpu_state.stop_str = ""; + mcdserver_state.cpu_state.info_str = ""; + mcdserver_state.cpu_state.bp_type = 0; + mcdserver_state.cpu_state.bp_address = 0; + } +} + /** * init_query_cmds_table() - Initializes all query functions. * @@ -1501,6 +1538,13 @@ static void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table) strcpy(query_regs_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' }); mcd_query_cmds_table[cmd_number] = query_regs_c; cmd_number++; + + MCDCmdParseEntry query_state = { + .handler = handle_query_state, + .cmd = QUERY_ARG_STATE, + }; + strcpy(query_state.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' }); + mcd_query_cmds_table[cmd_number] = query_state; } /** From patchwork Wed Dec 20 16:25:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500346 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 9335EC3DA6E for ; Wed, 20 Dec 2023 16:28:24 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzPF-0000VZ-BJ; Wed, 20 Dec 2023 11:26:49 -0500 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 1rFzPC-0000UE-7U for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:46 -0500 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 1rFzPA-0004nY-CW for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:45 -0500 Received: (qmail 15563 invoked by uid 484); 20 Dec 2023 16:26:32 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.073401 secs); 20 Dec 2023 16:26:32 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:29 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 15/18] mcdstub: skeleton for reset handling added Date: Wed, 20 Dec 2023 17:25:52 +0100 Message-Id: <20231220162555.19545-16-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/mcdstub.c | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index fb13958108..df97eca65b 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -826,6 +826,37 @@ static void handle_vm_stop(GArray *params, void *user_ctx) mcd_vm_stop(); } +/** + * mcd_exit() - Terminates QEMU. + * + * If the mcdserver_state has not been initialized the function exits before + * terminating QEMU. Terminting is done with the qemu_chr_fe_deinit function. + * @code: An exitcode, which can be used in the future. + */ +static void mcd_exit(int code) +{ + /* terminate qemu */ + if (!mcdserver_state.init) { + return; + } + + qemu_chr_fe_deinit(&mcdserver_system_state.chr, true); +} + +/** + * handle_reset() - Handler for performing resets. + * + * This function is currently not in use. + * @params: GArray with all TCP packet parameters. + */ +static void handle_reset(GArray *params, void *user_ctx) +{ + /* + * int reset_id = get_param(params, 0)->data_int; + * TODO: implement resets + */ +} + /** * mcd_handle_packet() - Evaluates the type of received packet and chooses the * correct handler. @@ -921,6 +952,21 @@ static int mcd_handle_packet(const char *line_buf) cmd_parser = &break_cmd_desc; } break; + case TCP_CHAR_KILLQEMU: + /* kill qemu completely */ + error_report("QEMU: Terminated via MCDstub"); + mcd_exit(0); + exit(0); + case TCP_CHAR_RESET: + { + static MCDCmdParseEntry reset_cmd_desc = { + .handler = handle_reset, + .cmd = {TCP_CHAR_RESET, '\0'}, + .schema = {ARG_SCHEMA_INT, '\0'}, + }; + cmd_parser = &reset_cmd_desc; + } + break; default: /* command not supported */ mcd_put_packet(""); From patchwork Wed Dec 20 16:25:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500351 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 41547C3DA6E for ; Wed, 20 Dec 2023 16:29:20 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzPG-0000WE-PG; Wed, 20 Dec 2023 11:26:50 -0500 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 1rFzPD-0000Uq-NV for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:47 -0500 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 1rFzPB-0004ns-9l for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:47 -0500 Received: (qmail 15586 invoked by uid 484); 20 Dec 2023 16:26:33 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 0.072786 secs); 20 Dec 2023 16:26:33 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:32 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 16/18] mcdstub: register access added Date: Wed, 20 Dec 2023 17:25:53 +0100 Message-Id: <20231220162555.19545-17-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/mcdstub.c | 161 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index df97eca65b..df98453558 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -857,6 +857,146 @@ static void handle_reset(GArray *params, void *user_ctx) */ } +/** + * mcd_memtohex() - Converts a byte array into a hex string. + * + * @mem: Pointer to byte array. + * @buf: Pointer to hex string. + * @len: Number of bytes. + */ +static void mcd_memtohex(GString *buf, const uint8_t *mem, int len) +{ + int i, c; + for (i = 0; i < len; i++) { + c = mem[i]; + g_string_append_c(buf, nibble_to_hexchar(c >> 4)); + g_string_append_c(buf, nibble_to_hexchar(c & 0xf)); + } + g_string_append_c(buf, '\0'); +} + +/** + * mcd_hextomem() - Converts a hex string into a byte array. + * + * @mem: Pointer to byte array. + * @buf: Pointer to hex string. + * @len: Number of bytes. + */ +static void mcd_hextomem(GByteArray *mem, const char *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) { + guint8 byte = hexchar_to_nibble(buf[0]) << 4 | + hexchar_to_nibble(buf[1]); + g_byte_array_append(mem, &byte, 1); + buf += 2; + } +} + +/** + * mcd_read_register() - Reads a registers data and stores it into the buf. + * + * This function collects the register type and internal ID + * (depending on the XML file). Then it calls the architecture specific + * read function. For ARM this is :c:func:`arm_mcd_read_register`. + * @cpu: CPU to which the register belongs. + * @buf: Byte array with register data. + * @reg: General ID of the register. + */ +static int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + CPUArchState *env = cpu_env(cpu); + GDBRegisterState *r; + + if (reg < cc->gdb_num_core_regs) { + return cc->gdb_read_register(cpu, buf, reg); + } + + for (guint i = 0; i < cpu->gdb_regs->len; i++) { + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); + if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { + return r->get_reg(env, buf, reg - r->base_reg); + } + } + return 0; +} + +/** + * mcd_write_register() - Writes data from the buf to a register. + * + * This function collects the register type and internal ID + * (depending on the XML file). Then it calls the architecture specific + * write function. For ARM this is :c:func:`arm_mcd_write_register`. + * @cpu: CPU to which the register belongs. + * @mem_buf: Byte array with register data. + * @reg: General ID of the register. + */ +static int mcd_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + CPUArchState *env = cpu_env(cpu); + GDBRegisterState *r; + + if (reg < cc->gdb_num_core_regs) { + return cc->gdb_write_register(cpu, mem_buf, reg); + } + + for (guint i = 0; i < cpu->gdb_regs->len; i++) { + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); + if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { + return r->set_reg(env, mem_buf, reg - r->base_reg); + } + } + return 0; +} + +/** + * handle_read_register() - Handler for reading a register. + * + * This function calls :c:func:`mcd_read_register` to read a register. The + * register data gets stored in the mem_buf byte array. The data then gets + * converted into a hex string with :c:func:`mcd_memtohex` and then send. + * @params: GArray with all TCP packet parameters. + */ +static void handle_read_register(GArray *params, void *user_ctx) +{ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + uint64_t reg_num = get_param(params, 1)->data_uint64_t; + int reg_size; + + CPUState *cpu = mcd_get_cpu(cpu_id); + reg_size = mcd_read_register(cpu, mcdserver_state.mem_buf, reg_num); + mcd_memtohex(mcdserver_state.str_buf, + mcdserver_state.mem_buf->data, reg_size); + mcd_put_strbuf(); +} + +/** + * handle_write_register() - Handler for writing a register. + * + * This function converts the incoming hex string data into a byte array with + * :c:func:`mcd_hextomem`. Then it calls :c:func:`mcd_write_register` to write + * to the register. + * @params: GArray with all TCP packet parameters. + */ +static void handle_write_register(GArray *params, void *user_ctx) +{ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + uint64_t reg_num = get_param(params, 1)->data_uint64_t; + uint32_t reg_size = get_param(params, 2)->data_uint32_t; + + CPUState *cpu = mcd_get_cpu(cpu_id); + mcd_hextomem(mcdserver_state.mem_buf, + mcdserver_state.str_buf->str, reg_size); + if (mcd_write_register(cpu, mcdserver_state.mem_buf->data, reg_num) == 0) { + mcd_put_packet(TCP_EXECUTION_ERROR); + } else { + mcd_put_packet(TCP_EXECUTION_SUCCESS); + } +} + /** * mcd_handle_packet() - Evaluates the type of received packet and chooses the * correct handler. @@ -967,6 +1107,27 @@ static int mcd_handle_packet(const char *line_buf) cmd_parser = &reset_cmd_desc; } break; + case TCP_CHAR_READ_REGISTER: + { + static MCDCmdParseEntry read_reg_cmd_desc = { + .handler = handle_read_register, + .cmd = {TCP_CHAR_READ_REGISTER, '\0'}, + .schema = {ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T, '\0'}, + }; + cmd_parser = &read_reg_cmd_desc; + } + break; + case TCP_CHAR_WRITE_REGISTER: + { + static MCDCmdParseEntry write_reg_cmd_desc = { + .handler = handle_write_register, + .cmd = {TCP_CHAR_WRITE_REGISTER, '\0'}, + .schema = {ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T, + ARG_SCHEMA_INT, ARG_SCHEMA_HEXDATA, '\0'}, + }; + cmd_parser = &write_reg_cmd_desc; + } + break; default: /* command not supported */ mcd_put_packet(""); From patchwork Wed Dec 20 16:25:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500345 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 8439CC3DA6E for ; Wed, 20 Dec 2023 16:28:01 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzPJ-0000Wy-R0; Wed, 20 Dec 2023 11:26:53 -0500 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 1rFzPF-0000Vp-Pg for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:49 -0500 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 1rFzPD-0004oE-A9 for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:49 -0500 Received: (qmail 15607 invoked by uid 484); 20 Dec 2023 16:26:34 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 4e-06 secs); 20 Dec 2023 16:26:34 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:33 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 17/18] mcdstub: memory access added Date: Wed, 20 Dec 2023 17:25:54 +0100 Message-Id: <20231220162555.19545-18-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/arm_mcdstub.c | 28 +++++ debug/mcdstub/mcdstub.c | 203 ++++++++++++++++++++++++++++++++++ include/mcdstub/arm_mcdstub.h | 15 +++ 3 files changed, 246 insertions(+) diff --git a/debug/mcdstub/arm_mcdstub.c b/debug/mcdstub/arm_mcdstub.c index ce5264a617..6eaf2d754f 100644 --- a/debug/mcdstub/arm_mcdstub.c +++ b/debug/mcdstub/arm_mcdstub.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "exec/memory.h" #include "mcdstub/arm_mcdstub.h" int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces) @@ -259,3 +260,30 @@ uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n) /* TODO: not working with current build structure */ return 0; } + +AddressSpace *arm_mcd_get_address_space(uint32_t cpu_id, + mcd_mem_space_st mem_space) +{ + /* get correct address space name */ + char as_name[ARGUMENT_STRING_LENGTH] = {0}; + if (mem_space.is_secure) { + sprintf(as_name, "cpu-secure-memory-%u", cpu_id); + } else { + sprintf(as_name, "cpu-memory-%u", cpu_id); + } + /* return correct address space */ + AddressSpace *as = mcd_find_address_space(as_name); + return as; +} + +MemTxAttrs arm_mcd_get_memtxattrs(mcd_mem_space_st mem_space) +{ + MemTxAttrs attributes = {0}; + if (mem_space.is_secure) { + attributes.secure = 1; + attributes.space = 2; + } else { + attributes.space = 1; + } + return attributes; +} diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index df98453558..954d06c0b7 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -997,6 +997,186 @@ static void handle_write_register(GArray *params, void *user_ctx) } } +/** + * mcd_read_write_physical_memory() - Reades or writes from/to a logical + * memory address. + * @address_space: Desired QEMU address space (e.g. secure/non-secure) + * @attributes: Access attributes + * @addr: (physical) memory address + * @buf: Buffer for memory data + * @len: Length of the memory access + * @is_write: True for writing and false for reading + */ +static int mcd_read_write_physical_memory(AddressSpace *address_space, + MemTxAttrs attributes, hwaddr addr, uint8_t *buf, int len, bool is_write) +{ + if (is_write) { + return address_space_write_rom(address_space, addr, attributes, buf, + len); + } else { + return address_space_read_full(address_space, addr, attributes, buf, + len); + } +} + +/** + * mcd_read_write_memory() - Reades or writes from/to a logical memory address. + * @cpu: CPUState + * @address_space: Desired QEMU address space (e.g. secure/non-secure) + * @attributes: Access attributes + * @addr: (logical) memory address + * @buf: Buffer for memory data + * @len: Length of the memory access + * @is_write: True for writing and false for reading + */ +static int mcd_read_write_memory(CPUState *cpu, AddressSpace *address_space, + MemTxAttrs attributes, vaddr addr, uint8_t *buf, uint64_t len, + bool is_write) +{ + /* get physical address */ + if (cpu_memory_get_physical_address(cpu, &addr, &len) != 0) { + return -1; + } + /* read memory */ + return mcd_read_write_physical_memory(address_space, attributes, addr, buf, + len, is_write); +} + +/** + * mcd_get_address_space() - Returnes the correct QEMU address space name + * @cpu: CPUState + * @cpu_id: Correct CPU ID + * @mem_space: Desired mcd specific memory space. + */ +static AddressSpace *mcd_get_address_space(CPUState *cpu, uint32_t cpu_id, + mcd_mem_space_st mem_space) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + const gchar *arch = cc->gdb_arch_name(cpu); + if (strcmp(arch, MCDSTUB_ARCH_ARM) == 0) { + return arm_mcd_get_address_space(cpu_id, mem_space); + } else { + g_assert_not_reached(); + } +} + +/** + * mcd_get_memtxattrs() - Returnes the correct QEMU address space access + * attributes + * @cpu: CPUState + * @mem_space: Desired mcd specific memory space. + */ +static MemTxAttrs mcd_get_memtxattrs(CPUState *cpu, mcd_mem_space_st mem_space) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + const gchar *arch = cc->gdb_arch_name(cpu); + if (strcmp(arch, MCDSTUB_ARCH_ARM) == 0) { + return arm_mcd_get_memtxattrs(mem_space); + } else { + g_assert_not_reached(); + } +} + +/** + * handle_read_memory() - Handler for reading memory. + * + * First, this function checks whether reading a secure memory space is + * requested and changes the access mode with :c:func:`arm_mcd_set_scr`. + * Then it calls :c:func:`mcd_read_memory` to read memory. The collected + * data gets stored in the mem_buf byte array. The data then gets converted + * into a hex string with :c:func:`mcd_memtohex` and then send. + * @params: GArray with all TCP packet parameters. + */ +static void handle_read_memory(GArray *params, void *user_ctx) +{ + /* read input parameters */ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + uint32_t mem_space_id = get_param(params, 1)->data_uint32_t; + uint64_t mem_address = get_param(params, 2)->data_uint64_t; + uint32_t len = get_param(params, 3)->data_uint32_t; + /* check which memory space was requested */ + CPUState *cpu = mcd_get_cpu(cpu_id); + GArray *memspaces = + g_list_nth_data(mcdserver_state.all_memspaces, cpu_id); + mcd_mem_space_st space = g_array_index(memspaces, mcd_mem_space_st, + mem_space_id - 1); + /* get data in the QEMU address space and access attributes */ + AddressSpace *address_space = mcd_get_address_space(cpu, cpu_id, space); + MemTxAttrs attributes = mcd_get_memtxattrs(cpu, space); + /* read memory data */ + g_byte_array_set_size(mcdserver_state.mem_buf, len); + if (space.is_physical) { + /* physical memory */ + if (mcd_read_write_physical_memory(address_space, attributes, + mem_address, mcdserver_state.mem_buf->data, + mcdserver_state.mem_buf->len, false) != 0) { + mcd_put_packet(TCP_EXECUTION_ERROR); + return; + } + } else { + /* user space memory */ + if (mcd_read_write_memory(cpu, address_space, attributes, mem_address, + mcdserver_state.mem_buf->data, mcdserver_state.mem_buf->len, + false) != 0) { + mcd_put_packet(TCP_EXECUTION_ERROR); + return; + } + } + /* send data */ + mcd_memtohex(mcdserver_state.str_buf, mcdserver_state.mem_buf->data, + mcdserver_state.mem_buf->len); + mcd_put_strbuf(); +} + +/** + * handle_write_memory() - Handler for writing memory. + * + * First, this function checks whether reading a secure memory space is + * requested and changes the access mode with :c:func:`arm_mcd_set_scr`. + * Then it converts the incoming hex string data into a byte array with + * :c:func:`mcd_hextomem`. Then it calls :c:func:`mcd_write_memory` to write to + * the register. + * @params: GArray with all TCP packet parameters. + */ +static void handle_write_memory(GArray *params, void *user_ctx) +{ + /* read input parameters */ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + uint32_t mem_space_id = get_param(params, 1)->data_uint32_t; + uint64_t mem_address = get_param(params, 2)->data_uint64_t; + uint32_t len = get_param(params, 3)->data_uint32_t; + /* check which memory space was requested */ + CPUState *cpu = mcd_get_cpu(cpu_id); + GArray *memspaces = + g_list_nth_data(mcdserver_state.all_memspaces, cpu_id); + mcd_mem_space_st space = g_array_index(memspaces, mcd_mem_space_st, + mem_space_id - 1); + /* get data in the QEMU address space and access attributes */ + AddressSpace *address_space = mcd_get_address_space(cpu, cpu_id, space); + MemTxAttrs attributes = mcd_get_memtxattrs(cpu, space); + /* write memory data */ + mcd_hextomem(mcdserver_state.mem_buf, mcdserver_state.str_buf->str, len); + if (space.is_physical) { + /* physical memory */ + if (mcd_read_write_physical_memory(address_space, attributes, + mem_address, mcdserver_state.mem_buf->data, + mcdserver_state.mem_buf->len, true) != 0) { + mcd_put_packet(TCP_EXECUTION_ERROR); + return; + } + } else { + /* user space memory */ + if (mcd_read_write_memory(cpu, address_space, attributes, mem_address, + mcdserver_state.mem_buf->data, mcdserver_state.mem_buf->len, + true) != 0) { + mcd_put_packet(TCP_EXECUTION_ERROR); + return; + } + } + /* send acknowledge */ + mcd_put_packet(TCP_EXECUTION_SUCCESS); +} + /** * mcd_handle_packet() - Evaluates the type of received packet and chooses the * correct handler. @@ -1128,6 +1308,29 @@ static int mcd_handle_packet(const char *line_buf) cmd_parser = &write_reg_cmd_desc; } break; + case TCP_CHAR_READ_MEMORY: + { + static MCDCmdParseEntry read_mem_cmd_desc = { + .handler = handle_read_memory, + .cmd = {TCP_CHAR_READ_MEMORY, '\0'}, + .schema = {ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, + ARG_SCHEMA_UINT64_T, ARG_SCHEMA_INT, '\0'}, + }; + cmd_parser = &read_mem_cmd_desc; + } + break; + case TCP_CHAR_WRITE_MEMORY: + { + static MCDCmdParseEntry write_mem_cmd_desc = { + .handler = handle_write_memory, + .cmd = {TCP_CHAR_WRITE_MEMORY, '\0'}, + .schema = {ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, + ARG_SCHEMA_UINT64_T, ARG_SCHEMA_INT, + ARG_SCHEMA_HEXDATA, '\0'}, + }; + cmd_parser = &write_mem_cmd_desc; + } + break; default: /* command not supported */ mcd_put_packet(""); diff --git a/include/mcdstub/arm_mcdstub.h b/include/mcdstub/arm_mcdstub.h index 9961145f07..69f6e2d487 100644 --- a/include/mcdstub/arm_mcdstub.h +++ b/include/mcdstub/arm_mcdstub.h @@ -100,4 +100,19 @@ int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers, */ uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n); +/** + * arm_mcd_get_address_space() - Returnes the correct QEMU address space name + * @cpu_id: Correct CPU ID + * @mem_space: Desired mcd specific memory space. + */ +AddressSpace *arm_mcd_get_address_space(uint32_t cpu_id, + mcd_mem_space_st mem_space); + +/** + * arm_mcd_get_memtxattrs() - Returnes the correct QEMU address space access + * attributes + * @mem_space: Desired mcd specific memory space. + */ +MemTxAttrs arm_mcd_get_memtxattrs(mcd_mem_space_st mem_space); + #endif /* ARM_MCDSTUB_H */ From patchwork Wed Dec 20 16:25:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "nicolas.eder@lauterbach.com" X-Patchwork-Id: 13500338 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 C530BC46CD3 for ; Wed, 20 Dec 2023 16:27:23 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rFzPN-0000XZ-U5; Wed, 20 Dec 2023 11:26:58 -0500 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 1rFzPM-0000XQ-P5 for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:56 -0500 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 1rFzPK-0004pw-RB for qemu-devel@nongnu.org; Wed, 20 Dec 2023 11:26:56 -0500 Received: (qmail 15722 invoked by uid 484); 20 Dec 2023 16:26:42 -0000 X-Qmail-Scanner-Diagnostics: from nedpc1.intern.lauterbach.com 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.11.92):. Processed in 6e-06 secs); 20 Dec 2023 16:26:42 -0000 Received: from nedpc1.intern.lauterbach.com (Authenticated_SSL:neder@[10.2.11.92]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with TLS_AES_256_GCM_SHA384 encrypted SMTP for ; 20 Dec 2023 16:26:35 -0000 From: Nicolas Eder To: qemu-devel@nongnu.org Cc: =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?Philipp?= =?utf-8?q?e_Mathieu-Daud=C3=A9?= , "Christian Boenig" , "Nicolas Eder" Subject: [PATCH v5 18/18] mcdstub: break/watchpoints added Date: Wed, 20 Dec 2023 17:25:55 +0100 Message-Id: <20231220162555.19545-19-nicolas.eder@lauterbach.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231220162555.19545-1-nicolas.eder@lauterbach.com> References: <20231220162555.19545-1-nicolas.eder@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=nicolas.eder@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, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-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 --- debug/mcdstub/mcdstub.c | 150 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/debug/mcdstub/mcdstub.c b/debug/mcdstub/mcdstub.c index 954d06c0b7..d2c505c0d6 100644 --- a/debug/mcdstub/mcdstub.c +++ b/debug/mcdstub/mcdstub.c @@ -1177,6 +1177,134 @@ static void handle_write_memory(GArray *params, void *user_ctx) mcd_put_packet(TCP_EXECUTION_SUCCESS); } +/** + * mcd_breakpoint_insert() - Inserts a break- or watchpoint. + * + * This function evaluates the received breakpoint type and translates it + * to a known GDB breakpoint type. + * Then it calls cpu_breakpoint_insert or cpu_watchpoint_insert depending on + * the type. + * @cpu: CPU to which the breakpoint should be added. + * @addr: Address of the breakpoint. + * @type: Breakpoint type. + */ +static int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr) +{ + /* translate the type to known gdb types and function call*/ + int bp_type = 0; + CPUClass *cc = CPU_GET_CLASS(cpu); + if (cc->gdb_stop_before_watchpoint) { + /* bp_type |= BP_STOP_BEFORE_ACCESS; */ + } + int return_value = 0; + switch (type) { + case MCD_BREAKPOINT_HW: + return_value = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL); + return return_value; + case MCD_BREAKPOINT_READ: + bp_type |= BP_GDB | BP_MEM_READ; + return_value = cpu_watchpoint_insert(cpu, addr, 4, bp_type, NULL); + return return_value; + case MCD_BREAKPOINT_WRITE: + bp_type |= BP_GDB | BP_MEM_WRITE; + return_value = cpu_watchpoint_insert(cpu, addr, 4, bp_type, NULL); + return return_value; + case MCD_BREAKPOINT_RW: + bp_type |= BP_GDB | BP_MEM_ACCESS; + return_value = cpu_watchpoint_insert(cpu, addr, 4, bp_type, NULL); + return return_value; + default: + return -ENOSYS; + } +} + +/** + * mcd_breakpoint_remove() - Removes a break- or watchpoint. + * + * This function evaluates the received breakpoint type and translates it + * to a known GDB breakpoint type. + * Then it calls cpu_breakpoint_remove or cpu_watchpoint_remove depending on + * the type. + * @cpu: CPU from which the breakpoint should be removed. + * @addr: Address of the breakpoint. + * @type: Breakpoint type. + */ +static int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr) +{ + /* translate the type to known gdb types and function call*/ + int bp_type = 0; + CPUClass *cc = CPU_GET_CLASS(cpu); + if (cc->gdb_stop_before_watchpoint) { + /* bp_type |= BP_STOP_BEFORE_ACCESS; */ + } + int return_value = 0; + switch (type) { + case MCD_BREAKPOINT_HW: + return_value = cpu_breakpoint_remove(cpu, addr, BP_GDB); + return return_value; + case MCD_BREAKPOINT_READ: + bp_type |= BP_GDB | BP_MEM_READ; + return_value = cpu_watchpoint_remove(cpu, addr, 4, bp_type); + return return_value; + case MCD_BREAKPOINT_WRITE: + bp_type |= BP_GDB | BP_MEM_WRITE; + return_value = cpu_watchpoint_remove(cpu, addr, 4, bp_type); + return return_value; + case MCD_BREAKPOINT_RW: + bp_type |= BP_GDB | BP_MEM_ACCESS; + return_value = cpu_watchpoint_remove(cpu, addr, 4, bp_type); + return return_value; + default: + return -ENOSYS; + } +} + +/** + * handle_breakpoint_insert() - Handler for inserting a break- or watchpoint. + * + * This function extracts the CPU, breakpoint type and address from the + * parameters and calls :c:func:`mcd_breakpoint_insert` to insert the + * breakpoint. + * @params: GArray with all TCP packet parameters. + */ +static void handle_breakpoint_insert(GArray *params, void *user_ctx) +{ + /* 1. get parameter data */ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + uint32_t type = get_param(params, 1)->data_uint32_t; + uint64_t address = get_param(params, 2)->data_uint64_t; + /* 2. insert breakpoint and send reply */ + CPUState *cpu = mcd_get_cpu(cpu_id); + if (mcd_breakpoint_insert(cpu, type, address) != 0) { + mcd_put_packet(TCP_EXECUTION_ERROR); + } else { + mcd_put_packet(TCP_EXECUTION_SUCCESS); + } +} + +/** + * handle_breakpoint_remove() - Handler for inserting a break- or watchpoint. + * + * This function extracts the CPU, breakpoint type and address from the + * parameters and calls :c:func:`mcd_breakpoint_remove` to insert the + * breakpoint. + * @params: GArray with all TCP packet parameters. + */ +static void handle_breakpoint_remove(GArray *params, void *user_ctx) +{ + /* 1. get parameter data */ + uint32_t cpu_id = get_param(params, 0)->cpu_id; + uint32_t type = get_param(params, 1)->data_uint32_t; + uint64_t address = get_param(params, 2)->data_uint64_t; + /* 2. remove breakpoint and send reply */ + CPUState *cpu = mcd_get_cpu(cpu_id); + if (mcd_breakpoint_remove(cpu, type, address) != 0) { + mcd_put_packet(TCP_EXECUTION_ERROR); + } else { + mcd_put_packet(TCP_EXECUTION_SUCCESS); + } +} + /** * mcd_handle_packet() - Evaluates the type of received packet and chooses the * correct handler. @@ -1331,6 +1459,28 @@ static int mcd_handle_packet(const char *line_buf) cmd_parser = &write_mem_cmd_desc; } break; + case TCP_CHAR_BREAKPOINT_INSERT: + { + static MCDCmdParseEntry handle_breakpoint_insert_cmd_desc = { + .handler = handle_breakpoint_insert, + .cmd = {TCP_CHAR_BREAKPOINT_INSERT, '\0'}, + .schema = {ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, + ARG_SCHEMA_UINT64_T, '\0'}, + }; + cmd_parser = &handle_breakpoint_insert_cmd_desc; + } + break; + case TCP_CHAR_BREAKPOINT_REMOVE: + { + static MCDCmdParseEntry handle_breakpoint_remove_cmd_desc = { + .handler = handle_breakpoint_remove, + .cmd = {TCP_CHAR_BREAKPOINT_REMOVE, '\0'}, + .schema = {ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, + ARG_SCHEMA_UINT64_T, '\0'}, + }; + cmd_parser = &handle_breakpoint_remove_cmd_desc; + } + break; default: /* command not supported */ mcd_put_packet("");