From nobody Mon Apr 29 00:24:57 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517311082954712.0258970180921; Tue, 30 Jan 2018 03:18:02 -0800 (PST) Received: from localhost ([::1]:58329 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egTvL-00057V-PG for importer@patchew.org; Tue, 30 Jan 2018 06:17:59 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44369) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egTuD-0004aJ-2D for qemu-devel@nongnu.org; Tue, 30 Jan 2018 06:16:55 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egTu1-0006rN-Rv for qemu-devel@nongnu.org; Tue, 30 Jan 2018 06:16:49 -0500 Received: from smtp1.lauterbach.com ([62.154.241.196]:53961) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egTu1-0006Wx-Bm for qemu-devel@nongnu.org; Tue, 30 Jan 2018 06:16:37 -0500 Received: (qmail 14319 invoked by uid 484); 30 Jan 2018 11:16:19 -0000 Received: from unknown (HELO [192.168.187.23]) (Authenticated_SSL:abouassida@[41.224.44.126]) (envelope-sender ) by smtp1.lauterbach.com (qmail-ldap-1.03) with ECDHE-RSA-AES256-GCM-SHA384 encrypted SMTP for ; 30 Jan 2018 11:16:18 -0000 X-Qmail-Scanner-Diagnostics: from 41.224.44.126 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(41.224.44.126):. Processed in 0.338676 secs); 30 Jan 2018 11:16:19 -0000 From: Abdallah Bouassida To: qemu-arm , Peter Maydell Message-ID: Date: Tue, 30 Jan 2018 12:16:16 +0100 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.5.2 MIME-Version: 1.0 Content-Language: en-US X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 62.154.241.196 Content-Type: text/plain; charset="utf-8"; format="flowed" Content-Transfer-Encoding: quoted-printable X-Content-Filtered-By: Mailman/MimeDel 2.1.21 Subject: [Qemu-devel] [PATCH V2] target-arm:Add a dynamic XML-description of the cp-registers to GDB X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Khaled Jmal , QEMU Developers Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 [PATCH V2] target-arm:Add a dynamic XML-description of the cp-registers=20 to GDB This patch offers to GDB the ability to read/write all the coprocessor registers for ARM and ARM64 by generating dynamically an XML-description for these registers. Signed-off-by: Abdallah Bouassida --- Hello Peter, Thanks for reviewing the previous version of this patch! =C2=A0=C2=A0=C2=A0 http://patchwork.ozlabs.org/patch/861374/ >> *For the ARM64, should I differentiate the registers that have two views= (32 >> and 64) >> Maybe by adding in the XML description a "32" tag for the registers name= for >> the >> 32bit view and a "64" for the 64bit view. >> *How to properly handle the secure and the non secure views? > I think it might be useful to approach it from the other end -- what > are we trying to achieve? > > For 32 vs 64 bit, it depends on what interface we're showing to the > debugger. If we're saying "this is a 64 bit CPU" then we should just > present the 64-bit sysregs, in the same way we only present the 64-bit > GPRs. If a 32-bit CPU, present the coprocessor regs only. (It's not > currently possible to have gdb switch between 32 and 64 bit views > as a 64-bit CPU changes from aarch32 to aarch64, though upstream gdb > are working on it.) > > For secure vs non-secure, follow how the architecture does it: > * for a 64-bit CPU, there are no banked sysregs like this, so you > just expose 1 register > * for a 32-bit CPU, maybe banked registers should be exposed as 2 regis= ters > > ...but this depends on what you're trying to do, and whether there's > existing practice in for instance how JTAG debugging presents these > sysregs to gdb. So, in this new patch I have did the following: - If the CPU is on the AARCH64 state (when connecting to GDB stub), I=20 only take the 64bit view of cpregs. - If we are on the AARCH32, I only take the 32bit view of cpregs and in=20 the XML description I add the tag "_S" to the cpreg's name if it is the secure view of that=20 register. > I'm pretty hesitant about allowing the user to modify system registers > in the debugger, that is unlikely to work in quite a lot of cases. > I'd rather we just made these registers all readonly. Some of our customers need to connect to Qemu using our tool TRACE32=C2=AE=20 via GDB, and for some use case they need to have write access to some particular=20 cpregs. So, it will be nice to have this capability! Usually, a user won't modify these registers unless he knows what he is=20 doing! > What does the UI in gdb look like? What gdb commands display > the list of and values of system registers now? (Are there any > commands that used to be useful and are now swamped by lists of > hundreds of system registers?) To read a given register: =C2=A0=C2=A0 (gdb)=C2=A0 print/x $ To write on a given register =C2=A0=C2=A0 (gdb) set $=3D To get the list of all registers: =C2=A0=C2=A0 (gdb) info registers all =C2=A0=C2=A0=C2=A0 with this command the user get all the registers includ= ing the=20 cpregs that has been =C2=A0=C2=A0=C2=A0 described dynamically. =C2=A0=C2=A0=C2=A0 This command shows the registers page by page (dependin= g on the=20 terminal window size) =C2=A0=C2=A0=C2=A0 and the cpregs goes at the end of the list so if user i= s really=20 interested on these cpregs he =C2=A0=C2=A0=C2=A0 should continue to read the register list or he simply = type "q" to=20 quit. In the previous patch, the command "info registers" (without the option=20 "all") was swamped by the new big list. So, I fixed that by assigning these registers (in=20 the XML ) to a special group (group=3D"cp_regs") and with that the cpregs won't appear with this=20 command. Otherwise, I don't think that there is another GDB command that could be=20 affected by this patch. > Don't we run into problems where this XML exceeds our gdbstub > MAX_PACKET_LENGTH (which is only 4K) ? > > This is a pre-existing bug (https://bugs.launchpad.net/qemu/+bug/1703147) > but I would expect that if we start autogenerating xml for all the > coprocessor registers we're going to hit the packet limit pretty > quickly. No, indeed I don't think that (https://bugs.launchpad.net/qemu/+bug/1703147) is a bug! However, when the gdb request to get an XML description, it sends the=20 packet: qXfer:features:read::, for the first packet, the offset=3D0 and the length in our case is 0xFFB (=3D MAX_PACKET_LENGTH - 5) When the GDB stub gets this packet, it will send the corresponding XML=20 description and: - if the size of the XML is bigger than the length requested by qXfer,=20 GDB stub will add 'm' at the beginning of the response to inform GDB=C2=A0 that there is=20 still more data to be sent. - else, it will add 'l' which mean there is no more data. =C2=A0=C2=A0=C2=A0 if (len < total_len - addr) { =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 buf[0] =3D 'm'; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 len =3D memtox(buf + 1, xml + a= ddr, len); =C2=A0=C2=A0=C2=A0 } else { =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 buf[0] =3D 'l'; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 len =3D memtox(buf + 1, xml + a= ddr, total_len - addr); =C2=A0=C2=A0=C2=A0 } When GBD gets an answer with the header "m" it will send another qXfer=20 and this time the will be equal to (old_offset + the size of the data read=20 previously) With this, the XML description won't be truncated even if it is longer=20 than 2045. >> /** >> + * XMLDynamicDescription: >> + * @desc: Contains the XML descriptions. >> + * @num_cpregs: Number of the Coprocessor registers seen by GDB. >> + * @xml_cpregs_ordred_keys: Array that contains the corresponding Key of >> + * a given cpreg with the same order of the cpreg in the XML descriptio= n. >> + */ >> +typedef struct XMLDynamicDescription { >> + char * desc; >> + int num_cpregs; >> + uint32_t *xml_cpregs_ordred_keys; >> +} XMLDynamicDescription; > cpregs are an arm-specific concept so this data structure doesn't > belong in the for-all-cpus header. I moved this to /target/arm/cpu.h . >> + char * (*get_feature_xml_dynamically)(CPUState *cpu); >> + int (*gdb_read_cpregister)(CPUState *cpu, uint8_t *buf, int reg); >> + int (*gdb_write_cpregister)(CPUState *cpu, uint8_t *buf, int reg); > Do we really need a new set of functions rather than just being > able to use the existing gdb_read_register/gdb_write_register ? > The API seems to be the same, so I was expecting to just have > the same functions be called, with the register number distinguishing > the existing regs from the new coprocessor ones. I'm using now the gdb_read_register/gdb_write_register instead. Best regards, Abdallah =C2=A0gdbstub.c=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 | 18 +++++++++++ =C2=A0include/qom/cpu.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0 3 ++ =C2=A0target/arm/cpu.c=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0 3 ++ =C2=A0target/arm/cpu.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 | 18 +++++++++++ =C2=A0target/arm/gdbstub.c=C2=A0=C2=A0 | 87=20 ++++++++++++++++++++++++++++++++++++++++++++++++++ =C2=A0target/arm/gdbstub64.c | 25 +++++++++++++++ =C2=A0target/arm/helper.c=C2=A0=C2=A0=C2=A0 |=C2=A0 3 +- =C2=A07 files changed, 155 insertions(+), 2 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index f1d5148..f54053f 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -670,10 +670,20 @@ static const char *get_feature_xml(const char *p,=20 const char **newp, =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 pstrcat(target_xml, sizeof(target_xml), r->xml); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 pstrcat(target_xml, sizeof(target_xml), "\"/>"); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (cc-= >has_dynamic_xml) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 cc->gen_dynamic_xml(cpu); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 pstrcat(target_xml, sizeof(target_xml), ""); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 p= strcat(target_xml, sizeof(target_xml), ""); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return target_xml; =C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 if (strncmp(p, "dynamic_desc.xml", len) =3D=3D 0) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 CPUState *cpu =3D first_cpu; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return cc->get_dynamic_xml(cpu); +=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 for (i =3D 0; ; i++) { =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 name =3D xml_builtin[i][0= ]; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (!name || (strncmp(nam= e, p, len) =3D=3D 0 && strlen(name) =3D=3D len)) @@ -697,6 +707,10 @@ static int gdb_read_register(CPUState *cpu, uint8_t=20 *mem_buf, int reg) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 r= eturn r->get_reg(env, mem_buf, reg - r->base_reg); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 if (cc->has_dynamic_xml) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return cc->gdb_read_register(cp= u, mem_buf, reg); +=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 return 0; =C2=A0} @@ -715,6 +729,10 @@ static int gdb_write_register(CPUState *cpu,=20 uint8_t *mem_buf, int reg) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 r= eturn r->set_reg(env, mem_buf, reg - r->base_reg); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 if (cc->has_dynamic_xml) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return cc->gdb_write_register(c= pu, mem_buf, reg); +=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 return 0; =C2=A0} diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 93bd546..a3105c0 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -197,6 +197,9 @@ typedef struct CPUClass { =C2=A0=C2=A0=C2=A0=C2=A0 const struct VMStateDescription *vmsd; =C2=A0=C2=A0=C2=A0=C2=A0 const char *gdb_core_xml_file; =C2=A0=C2=A0=C2=A0=C2=A0 gchar * (*gdb_arch_name)(CPUState *cpu); +=C2=A0=C2=A0=C2=A0 bool has_dynamic_xml; +=C2=A0=C2=A0=C2=A0 void (*gen_dynamic_xml)(CPUState *cpu); +=C2=A0=C2=A0=C2=A0 char *(*get_dynamic_xml)(CPUState *cpu); =C2=A0=C2=A0=C2=A0=C2=A0 void (*cpu_exec_enter)(CPUState *cpu); =C2=A0=C2=A0=C2=A0=C2=A0 void (*cpu_exec_exit)(CPUState *cpu); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index cc1856c..410e250 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1752,6 +1752,9 @@ static void arm_cpu_class_init(ObjectClass *oc,=20 void *data) =C2=A0=C2=A0=C2=A0=C2=A0 cc->gdb_num_core_regs =3D 26; =C2=A0=C2=A0=C2=A0=C2=A0 cc->gdb_core_xml_file =3D "arm-core.xml"; =C2=A0=C2=A0=C2=A0=C2=A0 cc->gdb_arch_name =3D arm_gdb_arch_name; +=C2=A0=C2=A0=C2=A0 cc->has_dynamic_xml =3D true; +=C2=A0=C2=A0=C2=A0 cc->gen_dynamic_xml =3D arm_gen_dynamic_xml; +=C2=A0=C2=A0=C2=A0 cc->get_dynamic_xml =3D arm_get_dynamic_xml; =C2=A0=C2=A0=C2=A0=C2=A0 cc->gdb_stop_before_watchpoint =3D true; =C2=A0=C2=A0=C2=A0=C2=A0 cc->debug_excp_handler =3D arm_debug_excp_handler; =C2=A0=C2=A0=C2=A0=C2=A0 cc->debug_check_watchpoint =3D arm_debug_check_wa= tchpoint; diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 9631670..bcb567b 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -135,6 +135,19 @@ enum { =C2=A0=C2=A0=C2=A0 s<2n+1> maps to the most significant half of d =C2=A0 */ +/** + * XMLDynamicDescription: + * @desc: Contains the XML descriptions. + * @num_cpregs: Number of the Coprocessor registers seen by GDB. + * @cpregs_keys: Array that contains the corresponding Key of + * a given cpreg with the same order of the cpreg in the XML description. + */ +typedef struct XMLDynamicDescription { +=C2=A0=C2=A0=C2=A0 char *desc; +=C2=A0=C2=A0=C2=A0 int num_cpregs; +=C2=A0=C2=A0=C2=A0 uint32_t *cpregs_keys; +} XMLDynamicDescription; + =C2=A0/* CPU state for each instance of a generic timer (in cp15 c14) */ =C2=A0typedef struct ARMGenericTimer { =C2=A0=C2=A0=C2=A0=C2=A0 uint64_t cval; /* Timer CompareValue register */ @@ -633,6 +646,8 @@ struct ARMCPU { =C2=A0=C2=A0=C2=A0=C2=A0 uint64_t *cpreg_vmstate_values; =C2=A0=C2=A0=C2=A0=C2=A0 int32_t cpreg_vmstate_array_len; +=C2=A0=C2=A0=C2=A0 XMLDynamicDescription dyn_xml; + =C2=A0=C2=A0=C2=A0=C2=A0 /* Timers used by the generic (architected) timer= */ =C2=A0=C2=A0=C2=A0=C2=A0 QEMUTimer *gt_timer[NUM_GTIMERS]; =C2=A0=C2=A0=C2=A0=C2=A0 /* GPIO outputs for generic timer */ @@ -797,6 +812,8 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState=20 *cpu, vaddr addr, =C2=A0int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); =C2=A0int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +void arm_gen_dynamic_xml(CPUState *cpu); +char *arm_get_dynamic_xml(CPUState *cpu); =C2=A0int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0 int cpuid, void *opaque); @@ -2005,6 +2022,7 @@ static inline bool cp_access_ok(int current_el, =C2=A0/* Raw read of a coprocessor register (as needed for migration, etc)= */ =C2=A0uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri); +void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,=20 uint64_t v); =C2=A0/** =C2=A0 * write_list_to_cpustate diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index 04c1208..7cffe87 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -56,6 +56,17 @@ int arm_cpu_gdb_read_register(CPUState *cs, uint8_t=20 *mem_buf, int n) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 /* CPSR */ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return gdb_get_reg32(mem_= buf, cpsr_read(env)); =C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 if (n >=3D cs->gdb_num_regs && +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n < cs->gdb_num_regs + cpu->dyn= _xml.num_cpregs) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 const ARMCPRegInfo *ri; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 uint32_t key; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 key =3D cpu->dyn_xml.cpregs_key= s[n - cs->gdb_num_regs]; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ri =3D get_arm_cp_reginfo(arm_e= nv_get_cpu(env)->cp_regs, key); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (ri) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = gdb_get_reg32(mem_buf,=20 (uint32_t)read_raw_cp_reg(env, ri)); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 /* Unknown register.=C2=A0 */ =C2=A0=C2=A0=C2=A0=C2=A0 return 0; =C2=A0} @@ -98,6 +109,82 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t=20 *mem_buf, int n) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 cpsr_write(env, tmp, 0xff= ffffff, CPSRWriteByGDBStub); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return 4; =C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 if (n >=3D cs->gdb_num_regs && +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n < cs->gdb_num_regs + cpu->dyn= _xml.num_cpregs) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 const ARMCPRegInfo *ri; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 uint32_t key; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 key =3D cpu->dyn_xml.cpregs_key= s[n - cs->gdb_num_regs]; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ri =3D get_arm_cp_reginfo(arm_e= nv_get_cpu(env)->cp_regs, key); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (ri) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (!(r= i->type & ARM_CP_CONST)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 write_raw_cp_reg(env, ri, tmp); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 return 4; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 /* Unknown register.=C2=A0 */ =C2=A0=C2=A0=C2=A0=C2=A0 return 0; =C2=A0} + +static void arm_gen_xml_reg(gpointer key, gpointer value, gpointer cs) +{ +=C2=A0=C2=A0=C2=A0 ARMCPU *cpu =3D ARM_CPU(cs); +=C2=A0=C2=A0=C2=A0 XMLDynamicDescription *dyn_xml =3D &cpu->dyn_xml; +=C2=A0=C2=A0=C2=A0 ARMCPRegInfo *ri =3D value; +=C2=A0=C2=A0=C2=A0 uint32_t ri_key =3D *(uint32_t *)key; +=C2=A0=C2=A0=C2=A0 CPUARMState *env =3D &cpu->env; +=C2=A0=C2=A0=C2=A0 char **target_xml =3D (char **)&(dyn_xml->desc); +=C2=A0=C2=A0=C2=A0 char *tmp_xml =3D *target_xml; + +=C2=A0=C2=A0=C2=A0 if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (env->aarch64) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (cpr= eg_field_is_64bit(ri)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 *target_xml =3D g_strconcat(*target_xml, +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 "name, "\" ", +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 "bitsize=3D\"64\"=20 group=3D\"cp_regs\"/>", +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 NULL); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } else { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 return; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } else { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (ri-= >secure & ARM_CP_SECSTATE_S) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 *target_xml =3D g_strconcat(*target_xml, +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 "name,=20 "_S\" ", +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 "bitsize=3D\"32\"=20 group=3D\"cp_regs\"/>", +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 NULL); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } else { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 *target_xml =3D g_strconcat(*target_xml, +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 "name, "\" ", +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 "bitsize=3D\"32\"=20 group=3D\"cp_regs\"/>", +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 NULL); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 g_free(tmp_xml); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 dyn_xml->num_cpregs++; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 dyn_xml->cpregs_keys =3D g_rene= w(uint32_t, +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 dyn_xml->cpregs_keys, +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 dyn_xml->num_cpregs); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 dyn_xml->cpregs_keys[dyn_xml->n= um_cpregs - 1] =3D ri_key; +=C2=A0=C2=A0=C2=A0 } +} + +void arm_gen_dynamic_xml(CPUState *cs) +{ +=C2=A0=C2=A0=C2=A0 ARMCPU *cpu =3D ARM_CPU(cs); + +=C2=A0=C2=A0=C2=A0 cpu->dyn_xml.num_cpregs =3D 0; +=C2=A0=C2=A0=C2=A0 cpu->dyn_xml.desc =3D g_strconcat("", +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "", +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "", +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 NULL); +=C2=A0=C2=A0=C2=A0 g_hash_table_foreach(cpu->cp_regs, arm_gen_xml_reg, cs); +=C2=A0=C2=A0=C2=A0 cpu->dyn_xml.desc =3D g_strconcat(cpu->dyn_xml.desc, "<= /feature>", NULL); +} + +char *arm_get_dynamic_xml(CPUState *cs) +{ +=C2=A0=C2=A0=C2=A0 ARMCPU *cpu =3D ARM_CPU(cs); + +=C2=A0=C2=A0=C2=A0 return cpu->dyn_xml.desc; +} diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c index 49bc3fc..6cf302f 100644 --- a/target/arm/gdbstub64.c +++ b/target/arm/gdbstub64.c @@ -38,6 +38,17 @@ int aarch64_cpu_gdb_read_register(CPUState *cs,=20 uint8_t *mem_buf, int n) =C2=A0=C2=A0=C2=A0=C2=A0 case 33: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return gdb_get_reg32(mem_= buf, pstate_read(env)); =C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 if (n >=3D cs->gdb_num_regs && +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n < cs->gdb_num_regs + cpu->dyn= _xml.num_cpregs) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 const ARMCPRegInfo *ri; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 uint32_t key; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 key =3D cpu->dyn_xml.cpregs_key= s[n - cs->gdb_num_regs]; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ri =3D get_arm_cp_reginfo(arm_e= nv_get_cpu(env)->cp_regs, key); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (ri) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = gdb_get_reg64(mem_buf,=20 (uint64_t)read_raw_cp_reg(env, ri)); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 /* Unknown register.=C2=A0 */ =C2=A0=C2=A0=C2=A0=C2=A0 return 0; =C2=A0} @@ -67,6 +78,20 @@ int aarch64_cpu_gdb_write_register(CPUState *cs,=20 uint8_t *mem_buf, int n) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 pstate_write(env, tmp); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return 4; =C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 if (n >=3D cs->gdb_num_regs && +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n < cs->gdb_num_regs + cpu->dyn= _xml.num_cpregs) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 const ARMCPRegInfo *ri; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 uint32_t key; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 key =3D cpu->dyn_xml.cpregs_key= s[n - cs->gdb_num_regs]; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ri =3D get_arm_cp_reginfo(arm_e= nv_get_cpu(env)->cp_regs, key); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (ri) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (!(r= i->type & ARM_CP_CONST)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 write_raw_cp_reg(env, ri, tmp); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 return 8; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 /* Unknown register.=C2=A0 */ =C2=A0=C2=A0=C2=A0=C2=A0 return 0; =C2=A0} diff --git a/target/arm/helper.c b/target/arm/helper.c index c83c901..223372f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -191,8 +191,7 @@ uint64_t read_raw_cp_reg(CPUARMState *env, const=20 ARMCPRegInfo *ri) =C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0} -static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri, -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 uint64_t v) +void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t v) =C2=A0{ =C2=A0=C2=A0=C2=A0=C2=A0 /* Raw write of a coprocessor register (as needed= for migration, etc). =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 * Note that constant registers are treated = as write-ignored; the --=20 1.9.1