Improve ddb disassembly for mips (and riscv, cribbed from mips). - use db_read_bytes to get instructions - move the address check logic previously attached only to fetching instructions for disassembly to db_read_bytes (and db_write_bytes) Motivated by related x86 changes this afternoon. Note that the address check logic is not as sophisticated as what the x86 code does, but it's what we had before. (Except that riscv will now also try to fetch usermode instructions instead of just failing.)diff -r1.42 -r1.43 src/sys/arch/mips/mips/db_disasm.c
(dholland)
--- src/sys/arch/mips/mips/db_disasm.c 2021/04/12 11:35:22 1.42
+++ src/sys/arch/mips/mips/db_disasm.c 2021/05/23 23:22:55 1.43
@@ -1,920 +1,911 @@ | @@ -1,920 +1,911 @@ | |||
1 | /* $NetBSD: db_disasm.c,v 1.42 2021/04/12 11:35:22 simonb Exp $ */ | 1 | /* $NetBSD: db_disasm.c,v 1.43 2021/05/23 23:22:55 dholland Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1991, 1993 | 4 | * Copyright (c) 1991, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Ralph Campbell. | 8 | * Ralph Campbell. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | 18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | * | 33 | * | |
34 | * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 | 34 | * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | #include <sys/cdefs.h> | 37 | #include <sys/cdefs.h> | |
38 | __KERNEL_RCSID(0, "$NetBSD: db_disasm.c,v 1.42 2021/04/12 11:35:22 simonb Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: db_disasm.c,v 1.43 2021/05/23 23:22:55 dholland Exp $"); | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/cpu.h> | 41 | #include <sys/cpu.h> | |
42 | #include <sys/systm.h> | 42 | #include <sys/systm.h> | |
43 | 43 | |||
44 | #include <mips/locore.h> | 44 | #include <mips/locore.h> | |
45 | #include <mips/mips_opcode.h> | 45 | #include <mips/mips_opcode.h> | |
46 | #include <mips/reg.h> | 46 | #include <mips/reg.h> | |
47 | 47 | |||
48 | #include <machine/db_machdep.h> | 48 | #include <machine/db_machdep.h> | |
49 | 49 | |||
50 | #include <ddb/db_access.h> | |||
50 | #include <ddb/db_user.h> | 51 | #include <ddb/db_user.h> | |
51 | #include <ddb/db_interface.h> | 52 | #include <ddb/db_interface.h> | |
52 | #include <ddb/db_output.h> | 53 | #include <ddb/db_output.h> | |
53 | #include <ddb/db_extern.h> | 54 | #include <ddb/db_extern.h> | |
54 | #include <ddb/db_sym.h> | 55 | #include <ddb/db_sym.h> | |
55 | 56 | |||
56 | static const char * const op_name[64] = { | 57 | static const char * const op_name[64] = { | |
57 | /* 0 */ "spec", "regimm","j", "jal", "beq", "bne", "blez", "bgtz", | 58 | /* 0 */ "spec", "regimm","j", "jal", "beq", "bne", "blez", "bgtz", | |
58 | /* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui", | 59 | /* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui", | |
59 | /*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl", | 60 | /*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl", | |
60 | /*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37", | 61 | /*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37", | |
61 | /*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", | 62 | /*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", | |
62 | /*40 */ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache", | 63 | /*40 */ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache", | |
63 | #ifdef __OCTEON__ | 64 | #ifdef __OCTEON__ | |
64 | /*48 */ "ll", "lwc1", "bbit0", "lwc3", "lld", "ldc1", "bbit032", "ld", | 65 | /*48 */ "ll", "lwc1", "bbit0", "lwc3", "lld", "ldc1", "bbit032", "ld", | |
65 | /*56 */ "sc", "swc1", "bbit1", "swc3", "scd", "sdc1", "bbit132", "sd" | 66 | /*56 */ "sc", "swc1", "bbit1", "swc3", "scd", "sdc1", "bbit132", "sd" | |
66 | #else | 67 | #else | |
67 | /*48 */ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld", | 68 | /*48 */ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld", | |
68 | /*56 */ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd" | 69 | /*56 */ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd" | |
69 | #endif | 70 | #endif | |
70 | }; | 71 | }; | |
71 | 72 | |||
72 | static const char * const spec_name[64] = { | 73 | static const char * const spec_name[64] = { | |
73 | /* 0 */ "sll", "movc1","srl", "sra", "sllv", "spec05","srlv","srav", | 74 | /* 0 */ "sll", "movc1","srl", "sra", "sllv", "spec05","srlv","srav", | |
74 | /* 8 */ "jr", "jalr", "movz","movn","syscall","break","spec16","sync", | 75 | /* 8 */ "jr", "jalr", "movz","movn","syscall","break","spec16","sync", | |
75 | /*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav", | 76 | /*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav", | |
76 | /*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu", | 77 | /*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu", | |
77 | /*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", | 78 | /*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", | |
78 | /*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu", | 79 | /*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu", | |
79 | /*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67", | 80 | /*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67", | |
80 | /*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32" | 81 | /*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32" | |
81 | }; | 82 | }; | |
82 | 83 | |||
83 | static const char * const spec2_name[64] = { /* QED, MIPS32/64, etc. */ | 84 | static const char * const spec2_name[64] = { /* QED, MIPS32/64, etc. */ | |
84 | [OP_MADD] = "madd", | 85 | [OP_MADD] = "madd", | |
85 | [OP_MADDU] = "maddu", | 86 | [OP_MADDU] = "maddu", | |
86 | [OP_MUL] = "mul", | 87 | [OP_MUL] = "mul", | |
87 | #ifdef __OCTEON__ | 88 | #ifdef __OCTEON__ | |
88 | [OP_CVM_DMUL] = "dmul", | 89 | [OP_CVM_DMUL] = "dmul", | |
89 | #endif | 90 | #endif | |
90 | [OP_MSUB] = "msub", | 91 | [OP_MSUB] = "msub", | |
91 | [OP_MSUBU] = "msubu", | 92 | [OP_MSUBU] = "msubu", | |
92 | [OP_CLZ] = "clz", | 93 | [OP_CLZ] = "clz", | |
93 | [OP_CLO] = "clo", | 94 | [OP_CLO] = "clo", | |
94 | [OP_DCLZ] = "dclz", | 95 | [OP_DCLZ] = "dclz", | |
95 | [OP_DCLO] = "dclo", | 96 | [OP_DCLO] = "dclo", | |
96 | #ifdef __OCTEON__ | 97 | #ifdef __OCTEON__ | |
97 | [OP_CVM_BADDU] = "baddu", | 98 | [OP_CVM_BADDU] = "baddu", | |
98 | [OP_CVM_POP] = "pop", | 99 | [OP_CVM_POP] = "pop", | |
99 | [OP_CVM_DPOP] = "dpop", | 100 | [OP_CVM_DPOP] = "dpop", | |
100 | [OP_CVM_CINS] = "cins", | 101 | [OP_CVM_CINS] = "cins", | |
101 | [OP_CVM_CINS32] = "cins32", | 102 | [OP_CVM_CINS32] = "cins32", | |
102 | [OP_CVM_EXTS] = "exts", | 103 | [OP_CVM_EXTS] = "exts", | |
103 | [OP_CVM_EXTS32] = "exts32", | 104 | [OP_CVM_EXTS32] = "exts32", | |
104 | [OP_CVM_SEQ] = "seq", | 105 | [OP_CVM_SEQ] = "seq", | |
105 | [OP_CVM_SEQI] = "seqi", | 106 | [OP_CVM_SEQI] = "seqi", | |
106 | [OP_CVM_SNE] = "sne", | 107 | [OP_CVM_SNE] = "sne", | |
107 | [OP_CVM_SNEI] = "snei", | 108 | [OP_CVM_SNEI] = "snei", | |
108 | [OP_CVM_SAA] = "saa", | 109 | [OP_CVM_SAA] = "saa", | |
109 | [OP_CVM_SAAD] = "saad", | 110 | [OP_CVM_SAAD] = "saad", | |
110 | #endif | 111 | #endif | |
111 | [OP_SDBBP] = "sdbbp", | 112 | [OP_SDBBP] = "sdbbp", | |
112 | }; | 113 | }; | |
113 | 114 | |||
114 | static const char * const spec3_name[64] = { | 115 | static const char * const spec3_name[64] = { | |
115 | [OP_EXT] = "ext", | 116 | [OP_EXT] = "ext", | |
116 | [OP_DEXTM] = "dextm", | 117 | [OP_DEXTM] = "dextm", | |
117 | [OP_DEXTU] = "dextu", | 118 | [OP_DEXTU] = "dextu", | |
118 | [OP_DEXT] = "dext", | 119 | [OP_DEXT] = "dext", | |
119 | [OP_INS] = "ins", | 120 | [OP_INS] = "ins", | |
120 | [OP_DINSM] = "dinsm", | 121 | [OP_DINSM] = "dinsm", | |
121 | [OP_DINSU] = "dinsu", | 122 | [OP_DINSU] = "dinsu", | |
122 | [OP_DINS] = "dins", | 123 | [OP_DINS] = "dins", | |
123 | [OP_LWLE] = "lwle", | 124 | [OP_LWLE] = "lwle", | |
124 | [OP_LWRE] = "lwre", | 125 | [OP_LWRE] = "lwre", | |
125 | [OP_CACHEE] = "cachee", | 126 | [OP_CACHEE] = "cachee", | |
126 | [OP_SBE] = "sbe", | 127 | [OP_SBE] = "sbe", | |
127 | [OP_SHE] = "she", | 128 | [OP_SHE] = "she", | |
128 | [OP_SCE] = "sce", | 129 | [OP_SCE] = "sce", | |
129 | [OP_SWE] = "swe", | 130 | [OP_SWE] = "swe", | |
130 | [OP_BSHFL] = "bshfl", | 131 | [OP_BSHFL] = "bshfl", | |
131 | [OP_SWLE] = "swle", | 132 | [OP_SWLE] = "swle", | |
132 | [OP_SWRE] = "swre", | 133 | [OP_SWRE] = "swre", | |
133 | [OP_PREFE] = "prefe", | 134 | [OP_PREFE] = "prefe", | |
134 | [OP_DBSHFL] = "dbshfl", | 135 | [OP_DBSHFL] = "dbshfl", | |
135 | [OP_CACHE_R6] = "cache", | 136 | [OP_CACHE_R6] = "cache", | |
136 | [OP_LBUE] = "lbue", | 137 | [OP_LBUE] = "lbue", | |
137 | [OP_LHUE] = "lhue", | 138 | [OP_LHUE] = "lhue", | |
138 | [OP_LBE] = "lbe", | 139 | [OP_LBE] = "lbe", | |
139 | [OP_LHE] = "lhe", | 140 | [OP_LHE] = "lhe", | |
140 | [OP_LLE] = "lle", | 141 | [OP_LLE] = "lle", | |
141 | [OP_LWE] = "lwe", | 142 | [OP_LWE] = "lwe", | |
142 | [OP_RDHWR] = "rdhwr", | 143 | [OP_RDHWR] = "rdhwr", | |
143 | }; | 144 | }; | |
144 | 145 | |||
145 | static const char * const regimm_name[32] = { | 146 | static const char * const regimm_name[32] = { | |
146 | /* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?", | 147 | /* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?", | |
147 | /* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?", | 148 | /* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?", | |
148 | /*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?", | 149 | /*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?", | |
149 | /*24 */ "?", "?", "?", "?", "bposge32", "?", "?", "?", | 150 | /*24 */ "?", "?", "?", "?", "bposge32", "?", "?", "?", | |
150 | }; | 151 | }; | |
151 | 152 | |||
152 | static const char * const cop1_name[64] = { | 153 | static const char * const cop1_name[64] = { | |
153 | /* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", | 154 | /* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", | |
154 | /* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", | 155 | /* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", | |
155 | /*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", | 156 | /*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", | |
156 | /*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", | 157 | /*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", | |
157 | /*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", | 158 | /*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", | |
158 | /*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", | 159 | /*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", | |
159 | /*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", | 160 | /*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", | |
160 | "fcmp.ole","fcmp.ule", | 161 | "fcmp.ole","fcmp.ule", | |
161 | /*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", | 162 | /*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", | |
162 | "fcmp.le","fcmp.ngt" | 163 | "fcmp.le","fcmp.ngt" | |
163 | }; | 164 | }; | |
164 | 165 | |||
165 | static const char * const fmt_name[16] = { | 166 | static const char * const fmt_name[16] = { | |
166 | "s", "d", "e", "fmt3", | 167 | "s", "d", "e", "fmt3", | |
167 | "w", "fmt5", "fmt6", "fmt7", | 168 | "w", "fmt5", "fmt6", "fmt7", | |
168 | "fmt8", "fmt9", "fmta", "fmtb", | 169 | "fmt8", "fmt9", "fmta", "fmtb", | |
169 | "fmtc", "fmtd", "fmte", "fmtf" | 170 | "fmtc", "fmtd", "fmte", "fmtf" | |
170 | }; | 171 | }; | |
171 | 172 | |||
172 | #if defined(__mips_n32) || defined(__mips_n64) | 173 | #if defined(__mips_n32) || defined(__mips_n64) | |
173 | static const char * const reg_name[32] = { | 174 | static const char * const reg_name[32] = { | |
174 | "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", | 175 | "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", | |
175 | "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", | 176 | "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", | |
176 | "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", | 177 | "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", | |
177 | "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" | 178 | "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" | |
178 | }; | 179 | }; | |
179 | #else | 180 | #else | |
180 | static const char * const reg_name[32] = { | 181 | static const char * const reg_name[32] = { | |
181 | "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", | 182 | "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", | |
182 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", | 183 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", | |
183 | "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", | 184 | "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", | |
184 | "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" | 185 | "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" | |
185 | }; | 186 | }; | |
186 | #endif /* __mips_n32 || __mips_n64 */ | 187 | #endif /* __mips_n32 || __mips_n64 */ | |
187 | 188 | |||
188 | static const char * const c0_opname[64] = { | 189 | static const char * const c0_opname[64] = { | |
189 | "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", | 190 | "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", | |
190 | "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", | 191 | "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", | |
191 | "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", | 192 | "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", | |
192 | "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", | 193 | "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", | |
193 | "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", | 194 | "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", | |
194 | "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", | 195 | "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", | |
195 | "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", | 196 | "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", | |
196 | "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", | 197 | "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", | |
197 | }; | 198 | }; | |
198 | 199 | |||
199 | static const char * const c0_reg[32] = { | 200 | static const char * const c0_reg[32] = { | |
200 | "index", "random", "tlblo0", "tlblo1", | 201 | "index", "random", "tlblo0", "tlblo1", | |
201 | "context", "pagemask", "wired", "hwrena", | 202 | "context", "pagemask", "wired", "hwrena", | |
202 | "badvaddr", "count", "tlbhi", "compare", | 203 | "badvaddr", "count", "tlbhi", "compare", | |
203 | "status", "cause", "epc", "prid", | 204 | "status", "cause", "epc", "prid", | |
204 | "config", "lladdr", "watchlo", "watchhi", | 205 | "config", "lladdr", "watchlo", "watchhi", | |
205 | "xcontext", "cp0r21", "osscratch", "debug", | 206 | "xcontext", "cp0r21", "osscratch", "debug", | |
206 | "depc", "perfcnt", "ecc", "cacheerr", | 207 | "depc", "perfcnt", "ecc", "cacheerr", | |
207 | "taglo", "taghi", "errepc", "desave" | 208 | "taglo", "taghi", "errepc", "desave" | |
208 | }; | 209 | }; | |
209 | 210 | |||
210 | static void print_addr(db_addr_t); | 211 | static void print_addr(db_addr_t); | |
211 | 212 | |||
212 | /* | 213 | /* | |
213 | * Disassemble instruction at 'loc'. 'altfmt' specifies an | 214 | * Disassemble instruction at 'loc'. 'altfmt' specifies an | |
214 | * (optional) alternate format (altfmt for vax: don't assume | 215 | * (optional) alternate format (altfmt for vax: don't assume | |
215 | * that each external label is a procedure entry mask). | 216 | * that each external label is a procedure entry mask). | |
216 | * Return address of start of next instruction. | 217 | * Return address of start of next instruction. | |
217 | * Since this function is used by 'examine' and by 'step' | 218 | * Since this function is used by 'examine' and by 'step' | |
218 | * "next instruction" does NOT mean the next instruction to | 219 | * "next instruction" does NOT mean the next instruction to | |
219 | * be executed but the 'linear' next instruction. | 220 | * be executed but the 'linear' next instruction. | |
220 | */ | 221 | */ | |
221 | #ifdef _LP64 | |||
222 | #define DISASM_KERN_START MIPS_XKSEG_START | |||
223 | #else | |||
224 | #define DISASM_KERN_START MIPS_KSEG0_START | |||
225 | #endif | |||
226 | db_addr_t | 222 | db_addr_t | |
227 | db_disasm(db_addr_t loc, bool altfmt) | 223 | db_disasm(db_addr_t loc, bool altfmt) | |
228 | { | 224 | { | |
229 | uint32_t instr; | 225 | uint32_t instr; | |
230 | 226 | |||
231 | /* | 227 | /* | |
232 | * Take some care with addresses to not UTLB here as it | 228 | * Take some care with addresses to not UTLB here as it | |
233 | * loses the current debugging context. KSEG2 and XKSEG | 229 | * loses the current debugging context. KSEG2 and XKSEG | |
234 | * are not checked. | 230 | * are not checked. | |
231 | * Update: db_read_bytes is supposed to do that, and now | |||
232 | * does, so we can use that. | |||
233 | * | |||
234 | * XXX db_read_bytes_can't return failure but instead zeros | |||
235 | * the output. That's ok here, but if ever improved the | |||
236 | * proper thing here on error is to return the original loc. | |||
235 | */ | 237 | */ | |
236 | if (loc < (db_addr_t)DISASM_KERN_START) { | 238 | db_read_bytes(loc, sizeof(instr), (void *)&instr); | |
237 | #ifdef _KERNEL | |||
238 | if (ufetch_32((void *)loc, &instr) != 0) { | |||
239 | db_printf("invalid address.\n"); | |||
240 | return loc; | |||
241 | } | |||
242 | #else | |||
243 | return loc; | |||
244 | #endif | |||
245 | } else { | |||
246 | instr = *(uint32_t *)loc; | |||
247 | } | |||
248 | 239 | |||
249 | return (db_disasm_insn(instr, loc, altfmt)); | 240 | return (db_disasm_insn(instr, loc, altfmt)); | |
250 | } | 241 | } | |
251 | 242 | |||
252 | 243 | |||
253 | /* | 244 | /* | |
254 | * Disassemble instruction 'insn' nominally at 'loc'. | 245 | * Disassemble instruction 'insn' nominally at 'loc'. | |
255 | * 'loc' may in fact contain a breakpoint instruction. | 246 | * 'loc' may in fact contain a breakpoint instruction. | |
256 | */ | 247 | */ | |
257 | db_addr_t | 248 | db_addr_t | |
258 | db_disasm_insn(int insn, db_addr_t loc, bool altfmt) | 249 | db_disasm_insn(int insn, db_addr_t loc, bool altfmt) | |
259 | { | 250 | { | |
260 | bool bdslot = false; | 251 | bool bdslot = false; | |
261 | InstFmt i; | 252 | InstFmt i; | |
262 | 253 | |||
263 | i.word = insn; | 254 | i.word = insn; | |
264 | 255 | |||
265 | switch (i.JType.op) { | 256 | switch (i.JType.op) { | |
266 | case OP_SPECIAL: { | 257 | case OP_SPECIAL: { | |
267 | const char *name = spec_name[i.RType.func]; | 258 | const char *name = spec_name[i.RType.func]; | |
268 | 259 | |||
269 | /* Handle varations of NOPs */ | 260 | /* Handle varations of NOPs */ | |
270 | if ((i.RType.func == OP_SLL) && | 261 | if ((i.RType.func == OP_SLL) && | |
271 | (i.RType.rs == 0) && | 262 | (i.RType.rs == 0) && | |
272 | (i.RType.rt == 0) && | 263 | (i.RType.rt == 0) && | |
273 | (i.RType.rd == 0)) { | 264 | (i.RType.rd == 0)) { | |
274 | switch (i.RType.shamt) { | 265 | switch (i.RType.shamt) { | |
275 | case OP_SLL_NOP: | 266 | case OP_SLL_NOP: | |
276 | db_printf("nop"); | 267 | db_printf("nop"); | |
277 | break; | 268 | break; | |
278 | case OP_SLL_SSNOP: | 269 | case OP_SLL_SSNOP: | |
279 | db_printf("ssnop"); | 270 | db_printf("ssnop"); | |
280 | break; | 271 | break; | |
281 | case OP_SLL_EHB: | 272 | case OP_SLL_EHB: | |
282 | db_printf("ehb"); | 273 | db_printf("ehb"); | |
283 | break; | 274 | break; | |
284 | case OP_SLL_PAUSE: | 275 | case OP_SLL_PAUSE: | |
285 | db_printf("pause"); | 276 | db_printf("pause"); | |
286 | break; | 277 | break; | |
287 | default: | 278 | default: | |
288 | db_printf("nop *"); /* "undefined" NOP */ | 279 | db_printf("nop *"); /* "undefined" NOP */ | |
289 | break; | 280 | break; | |
290 | } | 281 | } | |
291 | break; | 282 | break; | |
292 | } | 283 | } | |
293 | 284 | |||
294 | /* | 285 | /* | |
295 | * The following are equivalents of a "move dst,src": | 286 | * The following are equivalents of a "move dst,src": | |
296 | * addu dst,src,zero (in 32-bit mode) | 287 | * addu dst,src,zero (in 32-bit mode) | |
297 | * daddu dst,src,zero (in 64-bit mode) | 288 | * daddu dst,src,zero (in 64-bit mode) | |
298 | * or dst,src,zero (in 32- and 64-bit modes) | 289 | * or dst,src,zero (in 32- and 64-bit modes) | |
299 | */ | 290 | */ | |
300 | #ifdef __mips_o32 | 291 | #ifdef __mips_o32 | |
301 | #define OP_MOVE_ADDU OP_ADDU | 292 | #define OP_MOVE_ADDU OP_ADDU | |
302 | #else | 293 | #else | |
303 | #define OP_MOVE_ADDU OP_DADDU | 294 | #define OP_MOVE_ADDU OP_DADDU | |
304 | #endif | 295 | #endif | |
305 | if (true && | 296 | if (true && | |
306 | ((i.RType.func == OP_OR) || (i.RType.func == OP_MOVE_ADDU)) | 297 | ((i.RType.func == OP_OR) || (i.RType.func == OP_MOVE_ADDU)) | |
307 | && i.RType.rt == 0) { | 298 | && i.RType.rt == 0) { | |
308 | db_printf("move\t%s,%s", | 299 | db_printf("move\t%s,%s", | |
309 | reg_name[i.RType.rd], | 300 | reg_name[i.RType.rd], | |
310 | reg_name[i.RType.rs]); | 301 | reg_name[i.RType.rs]); | |
311 | break; | 302 | break; | |
312 | } | 303 | } | |
313 | 304 | |||
314 | if ((i.RType.func == OP_SRL || i.RType.func == OP_SRLV) | 305 | if ((i.RType.func == OP_SRL || i.RType.func == OP_SRLV) | |
315 | && i.RType.rs == 1) { | 306 | && i.RType.rs == 1) { | |
316 | name = (i.RType.func == OP_SRL) ? "rotr" : "rotrv"; | 307 | name = (i.RType.func == OP_SRL) ? "rotr" : "rotrv"; | |
317 | } else if ((i.RType.func == OP_DSRL || i.RType.func == OP_DSRLV) | 308 | } else if ((i.RType.func == OP_DSRL || i.RType.func == OP_DSRLV) | |
318 | && i.RType.shamt == 1) { | 309 | && i.RType.shamt == 1) { | |
319 | name = (i.RType.func == OP_DSRL) ? "drotr" : "drotrv"; | 310 | name = (i.RType.func == OP_DSRL) ? "drotr" : "drotrv"; | |
320 | } | 311 | } | |
321 | 312 | |||
322 | db_printf("%s", name); | 313 | db_printf("%s", name); | |
323 | switch (i.RType.func) { | 314 | switch (i.RType.func) { | |
324 | case OP_SLL: | 315 | case OP_SLL: | |
325 | case OP_SRL: | 316 | case OP_SRL: | |
326 | case OP_SRA: | 317 | case OP_SRA: | |
327 | case OP_DSLL: | 318 | case OP_DSLL: | |
328 | case OP_DSRL: | 319 | case OP_DSRL: | |
329 | case OP_DSRA: | 320 | case OP_DSRA: | |
330 | case OP_DSLL32: | 321 | case OP_DSLL32: | |
331 | case OP_DSRL32: | 322 | case OP_DSRL32: | |
332 | case OP_DSRA32: | 323 | case OP_DSRA32: | |
333 | db_printf("\t%s,%s,%d", | 324 | db_printf("\t%s,%s,%d", | |
334 | reg_name[i.RType.rd], | 325 | reg_name[i.RType.rd], | |
335 | reg_name[i.RType.rt], | 326 | reg_name[i.RType.rt], | |
336 | i.RType.shamt); | 327 | i.RType.shamt); | |
337 | break; | 328 | break; | |
338 | 329 | |||
339 | case OP_SLLV: | 330 | case OP_SLLV: | |
340 | case OP_SRLV: | 331 | case OP_SRLV: | |
341 | case OP_SRAV: | 332 | case OP_SRAV: | |
342 | case OP_DSLLV: | 333 | case OP_DSLLV: | |
343 | case OP_DSRLV: | 334 | case OP_DSRLV: | |
344 | case OP_DSRAV: | 335 | case OP_DSRAV: | |
345 | db_printf("\t%s,%s,%s", | 336 | db_printf("\t%s,%s,%s", | |
346 | reg_name[i.RType.rd], | 337 | reg_name[i.RType.rd], | |
347 | reg_name[i.RType.rt], | 338 | reg_name[i.RType.rt], | |
348 | reg_name[i.RType.rs]); | 339 | reg_name[i.RType.rs]); | |
349 | break; | 340 | break; | |
350 | 341 | |||
351 | case OP_MFHI: | 342 | case OP_MFHI: | |
352 | case OP_MFLO: | 343 | case OP_MFLO: | |
353 | db_printf("\t%s", reg_name[i.RType.rd]); | 344 | db_printf("\t%s", reg_name[i.RType.rd]); | |
354 | break; | 345 | break; | |
355 | 346 | |||
356 | case OP_JR: | 347 | case OP_JR: | |
357 | case OP_JALR: | 348 | case OP_JALR: | |
358 | db_printf("\t%s%s", reg_name[i.RType.rs], | 349 | db_printf("\t%s%s", reg_name[i.RType.rs], | |
359 | (insn & __BIT(10)) ? ".hb" : ""); | 350 | (insn & __BIT(10)) ? ".hb" : ""); | |
360 | bdslot = true; | 351 | bdslot = true; | |
361 | break; | 352 | break; | |
362 | case OP_MTLO: | 353 | case OP_MTLO: | |
363 | case OP_MTHI: | 354 | case OP_MTHI: | |
364 | db_printf("\t%s", reg_name[i.RType.rs]); | 355 | db_printf("\t%s", reg_name[i.RType.rs]); | |
365 | break; | 356 | break; | |
366 | 357 | |||
367 | case OP_MULT: | 358 | case OP_MULT: | |
368 | case OP_MULTU: | 359 | case OP_MULTU: | |
369 | case OP_DMULT: | 360 | case OP_DMULT: | |
370 | case OP_DMULTU: | 361 | case OP_DMULTU: | |
371 | case OP_DIV: | 362 | case OP_DIV: | |
372 | case OP_DIVU: | 363 | case OP_DIVU: | |
373 | case OP_DDIV: | 364 | case OP_DDIV: | |
374 | case OP_DDIVU: | 365 | case OP_DDIVU: | |
375 | db_printf("\t%s,%s", | 366 | db_printf("\t%s,%s", | |
376 | reg_name[i.RType.rs], | 367 | reg_name[i.RType.rs], | |
377 | reg_name[i.RType.rt]); | 368 | reg_name[i.RType.rt]); | |
378 | break; | 369 | break; | |
379 | 370 | |||
380 | 371 | |||
381 | case OP_SYSCALL: | 372 | case OP_SYSCALL: | |
382 | break; | 373 | break; | |
383 | case OP_SYNC: | 374 | case OP_SYNC: | |
384 | if (i.RType.shamt != 0) | 375 | if (i.RType.shamt != 0) | |
385 | db_printf("\t%d", i.RType.shamt); | 376 | db_printf("\t%d", i.RType.shamt); | |
386 | break; | 377 | break; | |
387 | 378 | |||
388 | case OP_BREAK: | 379 | case OP_BREAK: | |
389 | db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt); | 380 | db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt); | |
390 | break; | 381 | break; | |
391 | 382 | |||
392 | case OP_TEQ: | 383 | case OP_TEQ: | |
393 | db_printf("\t%s,%s,%#x", | 384 | db_printf("\t%s,%s,%#x", | |
394 | reg_name[i.RType.rs], | 385 | reg_name[i.RType.rs], | |
395 | reg_name[i.RType.rt], | 386 | reg_name[i.RType.rt], | |
396 | (i.RType.rd << 5) | i.RType.shamt); | 387 | (i.RType.rd << 5) | i.RType.shamt); | |
397 | break; | 388 | break; | |
398 | 389 | |||
399 | default: | 390 | default: | |
400 | db_printf("\t%s,%s,%s", | 391 | db_printf("\t%s,%s,%s", | |
401 | reg_name[i.RType.rd], | 392 | reg_name[i.RType.rd], | |
402 | reg_name[i.RType.rs], | 393 | reg_name[i.RType.rs], | |
403 | reg_name[i.RType.rt]); | 394 | reg_name[i.RType.rt]); | |
404 | } | 395 | } | |
405 | break; | 396 | break; | |
406 | } | 397 | } | |
407 | 398 | |||
408 | case OP_SPECIAL2: | 399 | case OP_SPECIAL2: | |
409 | if (spec_name[i.RType.func] == NULL) { | 400 | if (spec_name[i.RType.func] == NULL) { | |
410 | db_printf("spec2#%03o\t%s,%s", | 401 | db_printf("spec2#%03o\t%s,%s", | |
411 | i.RType.func, | 402 | i.RType.func, | |
412 | reg_name[i.RType.rs], | 403 | reg_name[i.RType.rs], | |
413 | reg_name[i.RType.rt]); | 404 | reg_name[i.RType.rt]); | |
414 | break; | 405 | break; | |
415 | } | 406 | } | |
416 | if (i.RType.func == OP_MUL | 407 | if (i.RType.func == OP_MUL | |
417 | #ifdef __OCTEON__ | 408 | #ifdef __OCTEON__ | |
418 | || i.RType.func == OP_CVM_DMUL | 409 | || i.RType.func == OP_CVM_DMUL | |
419 | || i.RType.func == OP_CVM_SEQ | 410 | || i.RType.func == OP_CVM_SEQ | |
420 | || i.RType.func == OP_CVM_SNE | 411 | || i.RType.func == OP_CVM_SNE | |
421 | #endif | 412 | #endif | |
422 | || false) { | 413 | || false) { | |
423 | db_printf("%s\t%s,%s,%s", | 414 | db_printf("%s\t%s,%s,%s", | |
424 | spec2_name[i.RType.func], | 415 | spec2_name[i.RType.func], | |
425 | reg_name[i.RType.rd], | 416 | reg_name[i.RType.rd], | |
426 | reg_name[i.RType.rs], | 417 | reg_name[i.RType.rs], | |
427 | reg_name[i.RType.rt]); | 418 | reg_name[i.RType.rt]); | |
428 | break; | 419 | break; | |
429 | } | 420 | } | |
430 | #ifdef __OCTEON__ | 421 | #ifdef __OCTEON__ | |
431 | if (i.RType.func == OP_CVM_CINS | 422 | if (i.RType.func == OP_CVM_CINS | |
432 | || i.RType.func == OP_CVM_CINS32 | 423 | || i.RType.func == OP_CVM_CINS32 | |
433 | || i.RType.func == OP_CVM_EXTS | 424 | || i.RType.func == OP_CVM_EXTS | |
434 | || i.RType.func == OP_CVM_EXTS32) { | 425 | || i.RType.func == OP_CVM_EXTS32) { | |
435 | db_printf("%s\t%s,%s,%d,%d", | 426 | db_printf("%s\t%s,%s,%d,%d", | |
436 | spec2_name[i.RType.func], | 427 | spec2_name[i.RType.func], | |
437 | reg_name[i.RType.rt], | 428 | reg_name[i.RType.rt], | |
438 | reg_name[i.RType.rs], | 429 | reg_name[i.RType.rs], | |
439 | i.RType.shamt, | 430 | i.RType.shamt, | |
440 | i.RType.rd); | 431 | i.RType.rd); | |
441 | break; | 432 | break; | |
442 | } | 433 | } | |
443 | if (i.RType.func == OP_CVM_SEQI | 434 | if (i.RType.func == OP_CVM_SEQI | |
444 | || i.RType.func == OP_CVM_SNEI) { | 435 | || i.RType.func == OP_CVM_SNEI) { | |
445 | db_printf("%s\t%s,%s,%d", | 436 | db_printf("%s\t%s,%s,%d", | |
446 | spec2_name[i.RType.func], | 437 | spec2_name[i.RType.func], | |
447 | reg_name[i.RType.rs], | 438 | reg_name[i.RType.rs], | |
448 | reg_name[i.RType.rt], | 439 | reg_name[i.RType.rt], | |
449 | (short)i.IType.imm >> 6); | 440 | (short)i.IType.imm >> 6); | |
450 | break; | 441 | break; | |
451 | } | 442 | } | |
452 | if (i.RType.func == OP_CVM_SAA | 443 | if (i.RType.func == OP_CVM_SAA | |
453 | || i.RType.func == OP_CVM_SAAD) { | 444 | || i.RType.func == OP_CVM_SAAD) { | |
454 | db_printf("%s\t%s,(%s)", | 445 | db_printf("%s\t%s,(%s)", | |
455 | spec2_name[i.RType.func], | 446 | spec2_name[i.RType.func], | |
456 | reg_name[i.RType.rt], | 447 | reg_name[i.RType.rt], | |
457 | reg_name[i.RType.rs]); | 448 | reg_name[i.RType.rs]); | |
458 | break; | 449 | break; | |
459 | } | 450 | } | |
460 | #endif | 451 | #endif | |
461 | if (i.RType.func == OP_CLO | 452 | if (i.RType.func == OP_CLO | |
462 | || i.RType.func == OP_DCLO | 453 | || i.RType.func == OP_DCLO | |
463 | #ifdef __OCTEON__ | 454 | #ifdef __OCTEON__ | |
464 | || i.RType.func == OP_CVM_POP | 455 | || i.RType.func == OP_CVM_POP | |
465 | || i.RType.func == OP_CVM_DPOP | 456 | || i.RType.func == OP_CVM_DPOP | |
466 | #endif | 457 | #endif | |
467 | || i.RType.func == OP_CLZ | 458 | || i.RType.func == OP_CLZ | |
468 | || i.RType.func == OP_DCLZ) { | 459 | || i.RType.func == OP_DCLZ) { | |
469 | db_printf("%s\t%s,%s", | 460 | db_printf("%s\t%s,%s", | |
470 | spec2_name[i.RType.func], | 461 | spec2_name[i.RType.func], | |
471 | reg_name[i.RType.rs], | 462 | reg_name[i.RType.rs], | |
472 | reg_name[i.RType.rd]); | 463 | reg_name[i.RType.rd]); | |
473 | break; | 464 | break; | |
474 | } | 465 | } | |
475 | db_printf("%s\t%s,%s", | 466 | db_printf("%s\t%s,%s", | |
476 | spec2_name[i.RType.func], | 467 | spec2_name[i.RType.func], | |
477 | reg_name[i.RType.rs], | 468 | reg_name[i.RType.rs], | |
478 | reg_name[i.RType.rt]); | 469 | reg_name[i.RType.rt]); | |
479 | break; | 470 | break; | |
480 | 471 | |||
481 | case OP_SPECIAL3: | 472 | case OP_SPECIAL3: | |
482 | if (spec3_name[i.RType.func] == NULL) { | 473 | if (spec3_name[i.RType.func] == NULL) { | |
483 | db_printf("spec3#%03o\t%s,%s", | 474 | db_printf("spec3#%03o\t%s,%s", | |
484 | i.RType.func, | 475 | i.RType.func, | |
485 | reg_name[i.RType.rs], | 476 | reg_name[i.RType.rs], | |
486 | reg_name[i.RType.rt]); | 477 | reg_name[i.RType.rt]); | |
487 | break; | 478 | break; | |
488 | } | 479 | } | |
489 | if (i.RType.func <= OP_DINS) { | 480 | if (i.RType.func <= OP_DINS) { | |
490 | int pos = i.RType.shamt; | 481 | int pos = i.RType.shamt; | |
491 | int size = i.RType.rd - pos + 1; | 482 | int size = i.RType.rd - pos + 1; | |
492 | size += (((i.RType.func & 3) == 1) ? 32 : 0); | 483 | size += (((i.RType.func & 3) == 1) ? 32 : 0); | |
493 | pos += (((i.RType.func & 3) == 2) ? 32 : 0); | 484 | pos += (((i.RType.func & 3) == 2) ? 32 : 0); | |
494 | 485 | |||
495 | db_printf("%s\t%s,%s,%d,%d", | 486 | db_printf("%s\t%s,%s,%d,%d", | |
496 | spec3_name[i.RType.func], | 487 | spec3_name[i.RType.func], | |
497 | reg_name[i.RType.rt], | 488 | reg_name[i.RType.rt], | |
498 | reg_name[i.RType.rs], | 489 | reg_name[i.RType.rs], | |
499 | pos, size); | 490 | pos, size); | |
500 | break; | 491 | break; | |
501 | } | 492 | } | |
502 | if (i.RType.func == OP_RDHWR) { | 493 | if (i.RType.func == OP_RDHWR) { | |
503 | db_printf("%s\t%s,$%d", | 494 | db_printf("%s\t%s,$%d", | |
504 | spec3_name[i.RType.func], | 495 | spec3_name[i.RType.func], | |
505 | reg_name[i.RType.rt], | 496 | reg_name[i.RType.rt], | |
506 | i.RType.rd); | 497 | i.RType.rd); | |
507 | break; | 498 | break; | |
508 | } | 499 | } | |
509 | if (i.RType.func == OP_BSHFL) { | 500 | if (i.RType.func == OP_BSHFL) { | |
510 | if (i.RType.shamt == OP_BSHFL_SBH) { | 501 | if (i.RType.shamt == OP_BSHFL_SBH) { | |
511 | db_printf("wsbh\t%s,%s", | 502 | db_printf("wsbh\t%s,%s", | |
512 | reg_name[i.RType.rd], | 503 | reg_name[i.RType.rd], | |
513 | reg_name[i.RType.rt]); | 504 | reg_name[i.RType.rt]); | |
514 | } else if (i.RType.shamt == OP_BSHFL_SEB) { | 505 | } else if (i.RType.shamt == OP_BSHFL_SEB) { | |
515 | db_printf("seb\t%s,%s", | 506 | db_printf("seb\t%s,%s", | |
516 | reg_name[i.RType.rd], | 507 | reg_name[i.RType.rd], | |
517 | reg_name[i.RType.rt]); | 508 | reg_name[i.RType.rt]); | |
518 | } else if (i.RType.shamt == OP_BSHFL_SEH) { | 509 | } else if (i.RType.shamt == OP_BSHFL_SEH) { | |
519 | db_printf("seh\t%s,%s", | 510 | db_printf("seh\t%s,%s", | |
520 | reg_name[i.RType.rd], | 511 | reg_name[i.RType.rd], | |
521 | reg_name[i.RType.rt]); | 512 | reg_name[i.RType.rt]); | |
522 | } else { | 513 | } else { | |
523 | db_printf("bshfl\t%s,%s,%d", | 514 | db_printf("bshfl\t%s,%s,%d", | |
524 | reg_name[i.RType.rd], | 515 | reg_name[i.RType.rd], | |
525 | reg_name[i.RType.rt], | 516 | reg_name[i.RType.rt], | |
526 | i.RType.shamt); | 517 | i.RType.shamt); | |
527 | } | 518 | } | |
528 | break; | 519 | break; | |
529 | } | 520 | } | |
530 | if (i.RType.func == OP_DBSHFL) { | 521 | if (i.RType.func == OP_DBSHFL) { | |
531 | if (i.RType.shamt == OP_BSHFL_SBH) { | 522 | if (i.RType.shamt == OP_BSHFL_SBH) { | |
532 | db_printf("dsbh\t%s,%s", | 523 | db_printf("dsbh\t%s,%s", | |
533 | reg_name[i.RType.rd], | 524 | reg_name[i.RType.rd], | |
534 | reg_name[i.RType.rt]); | 525 | reg_name[i.RType.rt]); | |
535 | } else if (i.RType.shamt == OP_BSHFL_SHD) { | 526 | } else if (i.RType.shamt == OP_BSHFL_SHD) { | |
536 | db_printf("dshd\t%s,%s", | 527 | db_printf("dshd\t%s,%s", | |
537 | reg_name[i.RType.rd], | 528 | reg_name[i.RType.rd], | |
538 | reg_name[i.RType.rt]); | 529 | reg_name[i.RType.rt]); | |
539 | } else { | 530 | } else { | |
540 | db_printf("dbshfl\t%s,%s,%d", | 531 | db_printf("dbshfl\t%s,%s,%d", | |
541 | reg_name[i.RType.rd], | 532 | reg_name[i.RType.rd], | |
542 | reg_name[i.RType.rt], | 533 | reg_name[i.RType.rt], | |
543 | i.RType.shamt); | 534 | i.RType.shamt); | |
544 | } | 535 | } | |
545 | break; | 536 | break; | |
546 | } | 537 | } | |
547 | switch (i.RType.func) { | 538 | switch (i.RType.func) { | |
548 | case OP_LWLE: | 539 | case OP_LWLE: | |
549 | case OP_LWRE: | 540 | case OP_LWRE: | |
550 | case OP_CACHEE: | 541 | case OP_CACHEE: | |
551 | case OP_SBE: | 542 | case OP_SBE: | |
552 | case OP_SHE: | 543 | case OP_SHE: | |
553 | case OP_SCE: | 544 | case OP_SCE: | |
554 | case OP_SWE: | 545 | case OP_SWE: | |
555 | case OP_SWLE: | 546 | case OP_SWLE: | |
556 | case OP_SWRE: | 547 | case OP_SWRE: | |
557 | case OP_PREFE: | 548 | case OP_PREFE: | |
558 | case OP_CACHE_R6: | 549 | case OP_CACHE_R6: | |
559 | case OP_LBUE: | 550 | case OP_LBUE: | |
560 | case OP_LHUE: | 551 | case OP_LHUE: | |
561 | case OP_LBE: | 552 | case OP_LBE: | |
562 | case OP_LHE: | 553 | case OP_LHE: | |
563 | case OP_LLE: | 554 | case OP_LLE: | |
564 | case OP_LWE: | 555 | case OP_LWE: | |
565 | db_printf("%s\t%s,%d(%s)", | 556 | db_printf("%s\t%s,%d(%s)", | |
566 | spec3_name[i.RType.func], | 557 | spec3_name[i.RType.func], | |
567 | reg_name[i.RType.rs], | 558 | reg_name[i.RType.rs], | |
568 | i.S3OType.offset > 255 ? | 559 | i.S3OType.offset > 255 ? | |
569 | -i.S3OType.offset : i.S3OType.offset, | 560 | -i.S3OType.offset : i.S3OType.offset, | |
570 | reg_name[i.RType.rt]); | 561 | reg_name[i.RType.rt]); | |
571 | break; | 562 | break; | |
572 | default: | 563 | default: | |
573 | db_printf("%s\t%s,%s", | 564 | db_printf("%s\t%s,%s", | |
574 | spec3_name[i.RType.func], | 565 | spec3_name[i.RType.func], | |
575 | reg_name[i.RType.rs], | 566 | reg_name[i.RType.rs], | |
576 | reg_name[i.RType.rt]); | 567 | reg_name[i.RType.rt]); | |
577 | } | 568 | } | |
578 | break; | 569 | break; | |
579 | 570 | |||
580 | case OP_REGIMM: | 571 | case OP_REGIMM: | |
581 | db_printf("%s\t%s,", regimm_name[i.IType.rt], | 572 | db_printf("%s\t%s,", regimm_name[i.IType.rt], | |
582 | reg_name[i.IType.rs]); | 573 | reg_name[i.IType.rs]); | |
583 | if (i.IType.rt >= OP_TGEI && i.IType.rt <= OP_TNEI) { | 574 | if (i.IType.rt >= OP_TGEI && i.IType.rt <= OP_TNEI) { | |
584 | db_printf("%d",(int16_t)i.IType.imm); | 575 | db_printf("%d",(int16_t)i.IType.imm); | |
585 | break; | 576 | break; | |
586 | } | 577 | } | |
587 | goto pr_displ; | 578 | goto pr_displ; | |
588 | 579 | |||
589 | case OP_BLEZ: | 580 | case OP_BLEZ: | |
590 | case OP_BLEZL: | 581 | case OP_BLEZL: | |
591 | case OP_BGTZ: | 582 | case OP_BGTZ: | |
592 | case OP_BGTZL: | 583 | case OP_BGTZL: | |
593 | db_printf("%s\t%s,", op_name[i.IType.op], | 584 | db_printf("%s\t%s,", op_name[i.IType.op], | |
594 | reg_name[i.IType.rs]); | 585 | reg_name[i.IType.rs]); | |
595 | goto pr_displ; | 586 | goto pr_displ; | |
596 | 587 | |||
597 | case OP_BEQ: | 588 | case OP_BEQ: | |
598 | case OP_BEQL: | 589 | case OP_BEQL: | |
599 | if (i.IType.rs == 0 && i.IType.rt == 0) { | 590 | if (i.IType.rs == 0 && i.IType.rt == 0) { | |
600 | db_printf("b\t"); | 591 | db_printf("b\t"); | |
601 | goto pr_displ; | 592 | goto pr_displ; | |
602 | } | 593 | } | |
603 | /* FALLTHROUGH */ | 594 | /* FALLTHROUGH */ | |
604 | case OP_BNE: | 595 | case OP_BNE: | |
605 | case OP_BNEL: | 596 | case OP_BNEL: | |
606 | db_printf("%s\t%s,%s,", op_name[i.IType.op], | 597 | db_printf("%s\t%s,%s,", op_name[i.IType.op], | |
607 | reg_name[i.IType.rs], | 598 | reg_name[i.IType.rs], | |
608 | reg_name[i.IType.rt]); | 599 | reg_name[i.IType.rt]); | |
609 | pr_displ: | 600 | pr_displ: | |
610 | print_addr(loc + 4 + ((short)i.IType.imm << 2)); | 601 | print_addr(loc + 4 + ((short)i.IType.imm << 2)); | |
611 | bdslot = true; | 602 | bdslot = true; | |
612 | break; | 603 | break; | |
613 | 604 | |||
614 | case OP_COP0: | 605 | case OP_COP0: | |
615 | switch (i.RType.rs) { | 606 | switch (i.RType.rs) { | |
616 | case OP_BCx: | 607 | case OP_BCx: | |
617 | case OP_BCy: | 608 | case OP_BCy: | |
618 | 609 | |||
619 | db_printf("bc0%c\t", | 610 | db_printf("bc0%c\t", | |
620 | "ft"[i.RType.rt & COPz_BC_TRUE]); | 611 | "ft"[i.RType.rt & COPz_BC_TRUE]); | |
621 | goto pr_displ; | 612 | goto pr_displ; | |
622 | 613 | |||
623 | case OP_MT: | 614 | case OP_MT: | |
624 | db_printf("mtc0\t%s,%s", | 615 | db_printf("mtc0\t%s,%s", | |
625 | reg_name[i.RType.rt], | 616 | reg_name[i.RType.rt], | |
626 | c0_reg[i.RType.rd]); | 617 | c0_reg[i.RType.rd]); | |
627 | break; | 618 | break; | |
628 | 619 | |||
629 | case OP_DMT: | 620 | case OP_DMT: | |
630 | db_printf("dmtc0\t%s,%s", | 621 | db_printf("dmtc0\t%s,%s", | |
631 | reg_name[i.RType.rt], | 622 | reg_name[i.RType.rt], | |
632 | c0_reg[i.RType.rd]); | 623 | c0_reg[i.RType.rd]); | |
633 | break; | 624 | break; | |
634 | 625 | |||
635 | case OP_MF: | 626 | case OP_MF: | |
636 | db_printf("mfc0\t%s,%s", | 627 | db_printf("mfc0\t%s,%s", | |
637 | reg_name[i.RType.rt], | 628 | reg_name[i.RType.rt], | |
638 | c0_reg[i.RType.rd]); | 629 | c0_reg[i.RType.rd]); | |
639 | break; | 630 | break; | |
640 | 631 | |||
641 | case OP_DMF: | 632 | case OP_DMF: | |
642 | db_printf("dmfc0\t%s,%s", | 633 | db_printf("dmfc0\t%s,%s", | |
643 | reg_name[i.RType.rt], | 634 | reg_name[i.RType.rt], | |
644 | c0_reg[i.RType.rd]); | 635 | c0_reg[i.RType.rd]); | |
645 | break; | 636 | break; | |
646 | 637 | |||
647 | case OP_MFM: | 638 | case OP_MFM: | |
648 | if (i.RType.rd == MIPS_COP_0_STATUS | 639 | if (i.RType.rd == MIPS_COP_0_STATUS | |
649 | && i.RType.shamt == 0 | 640 | && i.RType.shamt == 0 | |
650 | && (i.RType.func & 31) == 0) { | 641 | && (i.RType.func & 31) == 0) { | |
651 | db_printf("%s", | 642 | db_printf("%s", | |
652 | i.RType.func & 16 ? "ei" : "di"); | 643 | i.RType.func & 16 ? "ei" : "di"); | |
653 | if (i.RType.rt != 0) { | 644 | if (i.RType.rt != 0) { | |
654 | db_printf("\t%s", | 645 | db_printf("\t%s", | |
655 | reg_name[i.RType.rt]); | 646 | reg_name[i.RType.rt]); | |
656 | } | 647 | } | |
657 | break; | 648 | break; | |
658 | } | 649 | } | |
659 | /* FALLTHROUGH */ | 650 | /* FALLTHROUGH */ | |
660 | 651 | |||
661 | default: | 652 | default: | |
662 | db_printf("%s", c0_opname[i.FRType.func]); | 653 | db_printf("%s", c0_opname[i.FRType.func]); | |
663 | } | 654 | } | |
664 | break; | 655 | break; | |
665 | 656 | |||
666 | case OP_COP1: | 657 | case OP_COP1: | |
667 | switch (i.RType.rs) { | 658 | switch (i.RType.rs) { | |
668 | case OP_BCx: | 659 | case OP_BCx: | |
669 | case OP_BCy: | 660 | case OP_BCy: | |
670 | db_printf("bc1%c\t", | 661 | db_printf("bc1%c\t", | |
671 | "ft"[i.RType.rt & COPz_BC_TRUE]); | 662 | "ft"[i.RType.rt & COPz_BC_TRUE]); | |
672 | goto pr_displ; | 663 | goto pr_displ; | |
673 | 664 | |||
674 | case OP_MT: | 665 | case OP_MT: | |
675 | db_printf("mtc1\t%s,f%d", | 666 | db_printf("mtc1\t%s,f%d", | |
676 | reg_name[i.RType.rt], | 667 | reg_name[i.RType.rt], | |
677 | i.RType.rd); | 668 | i.RType.rd); | |
678 | break; | 669 | break; | |
679 | 670 | |||
680 | case OP_MF: | 671 | case OP_MF: | |
681 | db_printf("mfc1\t%s,f%d", | 672 | db_printf("mfc1\t%s,f%d", | |
682 | reg_name[i.RType.rt], | 673 | reg_name[i.RType.rt], | |
683 | i.RType.rd); | 674 | i.RType.rd); | |
684 | break; | 675 | break; | |
685 | 676 | |||
686 | case OP_CT: | 677 | case OP_CT: | |
687 | db_printf("ctc1\t%s,%d", | 678 | db_printf("ctc1\t%s,%d", | |
688 | reg_name[i.RType.rt], | 679 | reg_name[i.RType.rt], | |
689 | i.RType.rd); | 680 | i.RType.rd); | |
690 | break; | 681 | break; | |
691 | 682 | |||
692 | case OP_CF: | 683 | case OP_CF: | |
693 | db_printf("cfc1\t%s,%d", | 684 | db_printf("cfc1\t%s,%d", | |
694 | reg_name[i.RType.rt], | 685 | reg_name[i.RType.rt], | |
695 | i.RType.rd); | 686 | i.RType.rd); | |
696 | break; | 687 | break; | |
697 | 688 | |||
698 | case OP_DMT: | 689 | case OP_DMT: | |
699 | db_printf("dmtc1\t%s,f%d", | 690 | db_printf("dmtc1\t%s,f%d", | |
700 | reg_name[i.RType.rt], | 691 | reg_name[i.RType.rt], | |
701 | i.RType.rd); | 692 | i.RType.rd); | |
702 | break; | 693 | break; | |
703 | 694 | |||
704 | case OP_DMF: | 695 | case OP_DMF: | |
705 | db_printf("dmfc1\t%s,f%d", | 696 | db_printf("dmfc1\t%s,f%d", | |
706 | reg_name[i.RType.rt], | 697 | reg_name[i.RType.rt], | |
707 | i.RType.rd); | 698 | i.RType.rd); | |
708 | break; | 699 | break; | |
709 | 700 | |||
710 | case OP_MTH: | 701 | case OP_MTH: | |
711 | db_printf("mthc1\t%s,f%d", | 702 | db_printf("mthc1\t%s,f%d", | |
712 | reg_name[i.RType.rt], | 703 | reg_name[i.RType.rt], | |
713 | i.RType.rd); | 704 | i.RType.rd); | |
714 | break; | 705 | break; | |
715 | 706 | |||
716 | case OP_MFH: | 707 | case OP_MFH: | |
717 | db_printf("mfhc1\t%s,f%d", | 708 | db_printf("mfhc1\t%s,f%d", | |
718 | reg_name[i.RType.rt], | 709 | reg_name[i.RType.rt], | |
719 | i.RType.rd); | 710 | i.RType.rd); | |
720 | break; | 711 | break; | |
721 | 712 | |||
722 | default: | 713 | default: | |
723 | db_printf("%s.%s\tf%d,f%d,f%d", | 714 | db_printf("%s.%s\tf%d,f%d,f%d", | |
724 | cop1_name[i.FRType.func], | 715 | cop1_name[i.FRType.func], | |
725 | fmt_name[i.FRType.fmt], | 716 | fmt_name[i.FRType.fmt], | |
726 | i.FRType.fd, i.FRType.fs, i.FRType.ft); | 717 | i.FRType.fd, i.FRType.fs, i.FRType.ft); | |
727 | } | 718 | } | |
728 | break; | 719 | break; | |
729 | 720 | |||
730 | case OP_COP2: | 721 | case OP_COP2: | |
731 | switch (i.RType.rs) { | 722 | switch (i.RType.rs) { | |
732 | case OP_BCx: | 723 | case OP_BCx: | |
733 | case OP_BCy: | 724 | case OP_BCy: | |
734 | db_printf("bc2%c\t", | 725 | db_printf("bc2%c\t", | |
735 | "ft"[i.RType.rt & COPz_BC_TRUE]); | 726 | "ft"[i.RType.rt & COPz_BC_TRUE]); | |
736 | goto pr_displ; | 727 | goto pr_displ; | |
737 | 728 | |||
738 | case OP_MT: | 729 | case OP_MT: | |
739 | db_printf("mtc2\t%s,f%d", | 730 | db_printf("mtc2\t%s,f%d", | |
740 | reg_name[i.RType.rt], | 731 | reg_name[i.RType.rt], | |
741 | i.RType.rd); | 732 | i.RType.rd); | |
742 | break; | 733 | break; | |
743 | 734 | |||
744 | case OP_MF: | 735 | case OP_MF: | |
745 | db_printf("mfc2\t%s,f%d", | 736 | db_printf("mfc2\t%s,f%d", | |
746 | reg_name[i.RType.rt], | 737 | reg_name[i.RType.rt], | |
747 | i.RType.rd); | 738 | i.RType.rd); | |
748 | break; | 739 | break; | |
749 | 740 | |||
750 | case OP_CT: | 741 | case OP_CT: | |
751 | db_printf("ctc2\t%s,f%d", | 742 | db_printf("ctc2\t%s,f%d", | |
752 | reg_name[i.RType.rt], | 743 | reg_name[i.RType.rt], | |
753 | i.RType.rd); | 744 | i.RType.rd); | |
754 | break; | 745 | break; | |
755 | 746 | |||
756 | case OP_CF: | 747 | case OP_CF: | |
757 | db_printf("cfc2\t%s,f%d", | 748 | db_printf("cfc2\t%s,f%d", | |
758 | reg_name[i.RType.rt], | 749 | reg_name[i.RType.rt], | |
759 | i.RType.rd); | 750 | i.RType.rd); | |
760 | break; | 751 | break; | |
761 | 752 | |||
762 | case OP_DMT: | 753 | case OP_DMT: | |
763 | db_printf("dmtc2\t%s,f%d", | 754 | db_printf("dmtc2\t%s,f%d", | |
764 | reg_name[i.RType.rt], | 755 | reg_name[i.RType.rt], | |
765 | i.RType.rd); | 756 | i.RType.rd); | |
766 | break; | 757 | break; | |
767 | 758 | |||
768 | case OP_DMF: | 759 | case OP_DMF: | |
769 | db_printf("dmfc2\t%s,f%d", | 760 | db_printf("dmfc2\t%s,f%d", | |
770 | reg_name[i.RType.rt], | 761 | reg_name[i.RType.rt], | |
771 | i.RType.rd); | 762 | i.RType.rd); | |
772 | break; | 763 | break; | |
773 | 764 | |||
774 | case OP_MTH: | 765 | case OP_MTH: | |
775 | db_printf("mthc2\t%s,f%d", | 766 | db_printf("mthc2\t%s,f%d", | |
776 | reg_name[i.RType.rt], | 767 | reg_name[i.RType.rt], | |
777 | i.RType.rd); | 768 | i.RType.rd); | |
778 | break; | 769 | break; | |
779 | 770 | |||
780 | case OP_MFH: | 771 | case OP_MFH: | |
781 | db_printf("mfhc2\t%s,f%d", | 772 | db_printf("mfhc2\t%s,f%d", | |
782 | reg_name[i.RType.rt], | 773 | reg_name[i.RType.rt], | |
783 | i.RType.rd); | 774 | i.RType.rd); | |
784 | break; | 775 | break; | |
785 | 776 | |||
786 | default: | 777 | default: | |
787 | db_printf("%s\t%s,%s,%d", op_name[i.IType.op], | 778 | db_printf("%s\t%s,%s,%d", op_name[i.IType.op], | |
788 | reg_name[i.IType.rt], | 779 | reg_name[i.IType.rt], | |
789 | reg_name[i.IType.rs], | 780 | reg_name[i.IType.rs], | |
790 | (short)i.IType.imm); | 781 | (short)i.IType.imm); | |
791 | } | 782 | } | |
792 | break; | 783 | break; | |
793 | 784 | |||
794 | case OP_J: | 785 | case OP_J: | |
795 | case OP_JAL: | 786 | case OP_JAL: | |
796 | case OP_JALX: | 787 | case OP_JALX: | |
797 | db_printf("%s\t", op_name[i.JType.op]); | 788 | db_printf("%s\t", op_name[i.JType.op]); | |
798 | print_addr((loc & ~0x0FFFFFFFL) | (i.JType.target << 2)); | 789 | print_addr((loc & ~0x0FFFFFFFL) | (i.JType.target << 2)); | |
799 | bdslot = true; | 790 | bdslot = true; | |
800 | break; | 791 | break; | |
801 | 792 | |||
802 | #ifdef __OCTEON__ | 793 | #ifdef __OCTEON__ | |
803 | case OP_CVM_BBIT0: | 794 | case OP_CVM_BBIT0: | |
804 | case OP_CVM_BBIT032: | 795 | case OP_CVM_BBIT032: | |
805 | case OP_CVM_BBIT1: | 796 | case OP_CVM_BBIT1: | |
806 | case OP_CVM_BBIT132: | 797 | case OP_CVM_BBIT132: | |
807 | db_printf("%s\t%s,%d,", | 798 | db_printf("%s\t%s,%d,", | |
808 | op_name[i.IType.op], | 799 | op_name[i.IType.op], | |
809 | reg_name[i.IType.rs], | 800 | reg_name[i.IType.rs], | |
810 | i.IType.rt); | 801 | i.IType.rt); | |
811 | goto pr_displ; | 802 | goto pr_displ; | |
812 | #else | 803 | #else | |
813 | case OP_LWC2: | 804 | case OP_LWC2: | |
814 | case OP_LDC2: | 805 | case OP_LDC2: | |
815 | case OP_SWC2: | 806 | case OP_SWC2: | |
816 | case OP_SDC2: | 807 | case OP_SDC2: | |
817 | #endif | 808 | #endif | |
818 | 809 | |||
819 | case OP_LWC1: | 810 | case OP_LWC1: | |
820 | case OP_SWC1: | 811 | case OP_SWC1: | |
821 | case OP_LDC1: | 812 | case OP_LDC1: | |
822 | case OP_SDC1: | 813 | case OP_SDC1: | |
823 | db_printf("%s\tf%d,", op_name[i.IType.op], | 814 | db_printf("%s\tf%d,", op_name[i.IType.op], | |
824 | i.IType.rt); | 815 | i.IType.rt); | |
825 | goto loadstore; | 816 | goto loadstore; | |
826 | 817 | |||
827 | case OP_LB: | 818 | case OP_LB: | |
828 | case OP_LH: | 819 | case OP_LH: | |
829 | case OP_LW: | 820 | case OP_LW: | |
830 | case OP_LD: | 821 | case OP_LD: | |
831 | case OP_LBU: | 822 | case OP_LBU: | |
832 | case OP_LHU: | 823 | case OP_LHU: | |
833 | case OP_LWU: | 824 | case OP_LWU: | |
834 | case OP_SB: | 825 | case OP_SB: | |
835 | case OP_SH: | 826 | case OP_SH: | |
836 | case OP_SW: | 827 | case OP_SW: | |
837 | case OP_SD: | 828 | case OP_SD: | |
838 | db_printf("%s\t%s,", op_name[i.IType.op], | 829 | db_printf("%s\t%s,", op_name[i.IType.op], | |
839 | reg_name[i.IType.rt]); | 830 | reg_name[i.IType.rt]); | |
840 | loadstore: | 831 | loadstore: | |
841 | db_printf("%d(%s)", (short)i.IType.imm, | 832 | db_printf("%d(%s)", (short)i.IType.imm, | |
842 | reg_name[i.IType.rs]); | 833 | reg_name[i.IType.rs]); | |
843 | break; | 834 | break; | |
844 | 835 | |||
845 | case OP_ORI: | 836 | case OP_ORI: | |
846 | case OP_XORI: | 837 | case OP_XORI: | |
847 | if (i.IType.rs == 0) { | 838 | if (i.IType.rs == 0) { | |
848 | db_printf("li\t%s,0x%x", | 839 | db_printf("li\t%s,0x%x", | |
849 | reg_name[i.IType.rt], | 840 | reg_name[i.IType.rt], | |
850 | i.IType.imm); | 841 | i.IType.imm); | |
851 | break; | 842 | break; | |
852 | } | 843 | } | |
853 | /* FALLTHROUGH */ | 844 | /* FALLTHROUGH */ | |
854 | case OP_ANDI: | 845 | case OP_ANDI: | |
855 | db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op], | 846 | db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op], | |
856 | reg_name[i.IType.rt], | 847 | reg_name[i.IType.rt], | |
857 | reg_name[i.IType.rs], | 848 | reg_name[i.IType.rs], | |
858 | i.IType.imm); | 849 | i.IType.imm); | |
859 | break; | 850 | break; | |
860 | 851 | |||
861 | case OP_LUI: | 852 | case OP_LUI: | |
862 | db_printf("%s\t%s,0x%x", op_name[i.IType.op], | 853 | db_printf("%s\t%s,0x%x", op_name[i.IType.op], | |
863 | reg_name[i.IType.rt], | 854 | reg_name[i.IType.rt], | |
864 | i.IType.imm); | 855 | i.IType.imm); | |
865 | break; | 856 | break; | |
866 | 857 | |||
867 | case OP_CACHE: | 858 | case OP_CACHE: | |
868 | db_printf("%s\t0x%x,0x%x(%s)", | 859 | db_printf("%s\t0x%x,0x%x(%s)", | |
869 | op_name[i.IType.op], | 860 | op_name[i.IType.op], | |
870 | i.IType.rt, | 861 | i.IType.rt, | |
871 | i.IType.imm, | 862 | i.IType.imm, | |
872 | reg_name[i.IType.rs]); | 863 | reg_name[i.IType.rs]); | |
873 | break; | 864 | break; | |
874 | 865 | |||
875 | case OP_ADDI: | 866 | case OP_ADDI: | |
876 | case OP_DADDI: | 867 | case OP_DADDI: | |
877 | case OP_ADDIU: | 868 | case OP_ADDIU: | |
878 | case OP_DADDIU: | 869 | case OP_DADDIU: | |
879 | if (i.IType.rs == 0) { | 870 | if (i.IType.rs == 0) { | |
880 | db_printf("li\t%s,%d", | 871 | db_printf("li\t%s,%d", | |
881 | reg_name[i.IType.rt], | 872 | reg_name[i.IType.rt], | |
882 | (short)i.IType.imm); | 873 | (short)i.IType.imm); | |
883 | break; | 874 | break; | |
884 | } | 875 | } | |
885 | /* FALLTHROUGH */ | 876 | /* FALLTHROUGH */ | |
886 | default: | 877 | default: | |
887 | db_printf("%s\t%s,%s,%d", op_name[i.IType.op], | 878 | db_printf("%s\t%s,%s,%d", op_name[i.IType.op], | |
888 | reg_name[i.IType.rt], | 879 | reg_name[i.IType.rt], | |
889 | reg_name[i.IType.rs], | 880 | reg_name[i.IType.rs], | |
890 | (short)i.IType.imm); | 881 | (short)i.IType.imm); | |
891 | } | 882 | } | |
892 | db_printf("\n"); | 883 | db_printf("\n"); | |
893 | if (bdslot) { | 884 | if (bdslot) { | |
894 | db_printf("\t\tbdslot:\t"); | 885 | db_printf("\t\tbdslot:\t"); | |
895 | db_disasm(loc+4, false); | 886 | db_disasm(loc+4, false); | |
896 | return (loc + 8); | 887 | return (loc + 8); | |
897 | } | 888 | } | |
898 | return (loc + 4); | 889 | return (loc + 4); | |
899 | } | 890 | } | |
900 | 891 | |||
901 | static void | 892 | static void | |
902 | print_addr(db_addr_t loc) | 893 | print_addr(db_addr_t loc) | |
903 | { | 894 | { | |
904 | db_expr_t diff; | 895 | db_expr_t diff; | |
905 | db_sym_t sym; | 896 | db_sym_t sym; | |
906 | const char *symname; | 897 | const char *symname; | |
907 | 898 | |||
908 | diff = INT_MAX; | 899 | diff = INT_MAX; | |
909 | symname = NULL; | 900 | symname = NULL; | |
910 | sym = db_search_symbol(loc, DB_STGY_ANY, &diff); | 901 | sym = db_search_symbol(loc, DB_STGY_ANY, &diff); | |
911 | db_symbol_values(sym, &symname, 0); | 902 | db_symbol_values(sym, &symname, 0); | |
912 | 903 | |||
913 | db_printf("%#"PRIxVADDR, loc); | 904 | db_printf("%#"PRIxVADDR, loc); | |
914 | if (symname) { | 905 | if (symname) { | |
915 | db_printf(" <%s", symname); | 906 | db_printf(" <%s", symname); | |
916 | if (diff != 0) | 907 | if (diff != 0) | |
917 | db_printf("+%#"DDB_EXPR_FMT"x", diff); | 908 | db_printf("+%#"DDB_EXPR_FMT"x", diff); | |
918 | db_printf(">"); | 909 | db_printf(">"); | |
919 | } | 910 | } | |
920 | } | 911 | } |
--- src/sys/arch/mips/mips/db_interface.c 2021/04/12 02:23:41 1.93
+++ src/sys/arch/mips/mips/db_interface.c 2021/05/23 23:22:55 1.94
@@ -1,1063 +1,1092 @@ | @@ -1,1063 +1,1092 @@ | |||
1 | /* $NetBSD: db_interface.c,v 1.93 2021/04/12 02:23:41 mrg Exp $ */ | 1 | /* $NetBSD: db_interface.c,v 1.94 2021/05/23 23:22:55 dholland Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Mach Operating System | 4 | * Mach Operating System | |
5 | * Copyright (c) 1991,1990 Carnegie Mellon University | 5 | * Copyright (c) 1991,1990 Carnegie Mellon University | |
6 | * All Rights Reserved. | 6 | * All Rights Reserved. | |
7 | * | 7 | * | |
8 | * Permission to use, copy, modify and distribute this software and its | 8 | * Permission to use, copy, modify and distribute this software and its | |
9 | * documentation is hereby granted, provided that both the copyright | 9 | * documentation is hereby granted, provided that both the copyright | |
10 | * notice and this permission notice appear in all copies of the | 10 | * notice and this permission notice appear in all copies of the | |
11 | * software, derivative works or modified versions, and any portions | 11 | * software, derivative works or modified versions, and any portions | |
12 | * thereof, and that both notices appear in supporting documentation. | 12 | * thereof, and that both notices appear in supporting documentation. | |
13 | * | 13 | * | |
14 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | 14 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
15 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | 15 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
16 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | 16 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
17 | * | 17 | * | |
18 | * Carnegie Mellon requests users of this software to return to | 18 | * Carnegie Mellon requests users of this software to return to | |
19 | * | 19 | * | |
20 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | 20 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
21 | * School of Computer Science | 21 | * School of Computer Science | |
22 | * Carnegie Mellon University | 22 | * Carnegie Mellon University | |
23 | * Pittsburgh PA 15213-3890 | 23 | * Pittsburgh PA 15213-3890 | |
24 | * | 24 | * | |
25 | * any improvements or extensions that they make and grant Carnegie Mellon | 25 | * any improvements or extensions that they make and grant Carnegie Mellon | |
26 | * the rights to redistribute these changes. | 26 | * the rights to redistribute these changes. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include <sys/cdefs.h> | 29 | #include <sys/cdefs.h> | |
30 | __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.93 2021/04/12 02:23:41 mrg Exp $"); | 30 | __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.94 2021/05/23 23:22:55 dholland Exp $"); | |
31 | 31 | |||
32 | #ifdef _KERNEL_OPT | 32 | #ifdef _KERNEL_OPT | |
33 | #include "opt_multiprocessor.h" | 33 | #include "opt_multiprocessor.h" | |
34 | #include "opt_cputype.h" /* which mips CPUs do we support? */ | 34 | #include "opt_cputype.h" /* which mips CPUs do we support? */ | |
35 | #include "opt_ddb.h" | 35 | #include "opt_ddb.h" | |
36 | #include "opt_kgdb.h" | 36 | #include "opt_kgdb.h" | |
37 | #endif | 37 | #endif | |
38 | 38 | |||
39 | #define __PMAP_PRIVATE | 39 | #define __PMAP_PRIVATE | |
40 | 40 | |||
41 | #include <sys/types.h> | 41 | #include <sys/types.h> | |
42 | #include <sys/systm.h> | 42 | #include <sys/systm.h> | |
43 | #include <sys/param.h> | 43 | #include <sys/param.h> | |
44 | #include <sys/proc.h> | 44 | #include <sys/proc.h> | |
45 | #include <sys/reboot.h> | 45 | #include <sys/reboot.h> | |
46 | #include <sys/atomic.h> | 46 | #include <sys/atomic.h> | |
47 | #include <sys/cpu.h> | 47 | #include <sys/cpu.h> | |
48 | 48 | |||
49 | #include <uvm/uvm_extern.h> | 49 | #include <uvm/uvm_extern.h> | |
50 | 50 | |||
51 | #include <mips/regnum.h> | 51 | #include <mips/regnum.h> | |
52 | #include <mips/cache.h> | 52 | #include <mips/cache.h> | |
53 | #include <mips/pcb.h> | 53 | #include <mips/pcb.h> | |
54 | #include <mips/pte.h> | 54 | #include <mips/pte.h> | |
55 | #include <mips/locore.h> | 55 | #include <mips/locore.h> | |
56 | #include <mips/mips_opcode.h> | 56 | #include <mips/mips_opcode.h> | |
57 | #include <dev/cons.h> | 57 | #include <dev/cons.h> | |
58 | 58 | |||
59 | #include <machine/int_fmtio.h> | 59 | #include <machine/int_fmtio.h> | |
60 | #include <machine/db_machdep.h> | 60 | #include <machine/db_machdep.h> | |
61 | #include <ddb/db_access.h> | 61 | #include <ddb/db_access.h> | |
62 | #include <ddb/db_user.h> | 62 | #include <ddb/db_user.h> | |
63 | #ifndef KGDB | 63 | #ifndef KGDB | |
64 | #include <ddb/db_command.h> | 64 | #include <ddb/db_command.h> | |
65 | #include <ddb/db_output.h> | 65 | #include <ddb/db_output.h> | |
66 | #include <ddb/db_sym.h> | 66 | #include <ddb/db_sym.h> | |
67 | #include <ddb/db_extern.h> | 67 | #include <ddb/db_extern.h> | |
68 | #include <ddb/db_interface.h> | 68 | #include <ddb/db_interface.h> | |
69 | #include <ddb/db_lex.h> | 69 | #include <ddb/db_lex.h> | |
70 | #include <ddb/db_run.h> /* for db_continue_cmd() proto */ | 70 | #include <ddb/db_run.h> /* for db_continue_cmd() proto */ | |
71 | #endif | 71 | #endif | |
72 | 72 | |||
73 | #define NOCPU ~0 | 73 | #define NOCPU ~0 | |
74 | volatile u_int ddb_cpu = NOCPU; | 74 | volatile u_int ddb_cpu = NOCPU; | |
75 | 75 | |||
76 | int db_active = 0; | 76 | int db_active = 0; | |
77 | #ifdef _KERNEL | 77 | #ifdef _KERNEL | |
78 | db_regs_t ddb_regs; | 78 | db_regs_t ddb_regs; | |
79 | #endif | 79 | #endif | |
80 | 80 | |||
81 | #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 | 81 | #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 | |
82 | static void db_watch_cmd(db_expr_t, bool, db_expr_t, const char *); | 82 | static void db_watch_cmd(db_expr_t, bool, db_expr_t, const char *); | |
83 | static void db_unwatch_cmd(db_expr_t, bool, db_expr_t, const char *); | 83 | static void db_unwatch_cmd(db_expr_t, bool, db_expr_t, const char *); | |
84 | #endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */ | 84 | #endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */ | |
85 | 85 | |||
86 | #ifdef MULTIPROCESSOR | 86 | #ifdef MULTIPROCESSOR | |
87 | static void db_mach_cpu_cmd(db_expr_t, bool, db_expr_t, const char *); | 87 | static void db_mach_cpu_cmd(db_expr_t, bool, db_expr_t, const char *); | |
88 | #endif | 88 | #endif | |
89 | 89 | |||
90 | void db_tlbdump_cmd(db_expr_t, bool, db_expr_t, const char *); | 90 | void db_tlbdump_cmd(db_expr_t, bool, db_expr_t, const char *); | |
91 | void db_kvtophys_cmd(db_expr_t, bool, db_expr_t, const char *); | 91 | void db_kvtophys_cmd(db_expr_t, bool, db_expr_t, const char *); | |
92 | void db_cp0dump_cmd(db_expr_t, bool, db_expr_t, const char *); | 92 | void db_cp0dump_cmd(db_expr_t, bool, db_expr_t, const char *); | |
93 | #ifdef MIPS64_XLS | 93 | #ifdef MIPS64_XLS | |
94 | void db_mfcr_cmd(db_expr_t, bool, db_expr_t, const char *); | 94 | void db_mfcr_cmd(db_expr_t, bool, db_expr_t, const char *); | |
95 | void db_mtcr_cmd(db_expr_t, bool, db_expr_t, const char *); | 95 | void db_mtcr_cmd(db_expr_t, bool, db_expr_t, const char *); | |
96 | #endif | 96 | #endif | |
97 | 97 | |||
98 | paddr_t kvtophys(vaddr_t); | 98 | paddr_t kvtophys(vaddr_t); | |
99 | 99 | |||
100 | #ifdef _KERNEL | 100 | #ifdef _KERNEL | |
101 | CTASSERT(sizeof(ddb_regs) == sizeof(struct reg)); | 101 | CTASSERT(sizeof(ddb_regs) == sizeof(struct reg)); | |
102 | 102 | |||
103 | #ifndef KGDB | 103 | #ifndef KGDB | |
104 | int | 104 | int | |
105 | kdb_trap(int type, struct reg *regs) | 105 | kdb_trap(int type, struct reg *regs) | |
106 | { | 106 | { | |
107 | int s; | 107 | int s; | |
108 | 108 | |||
109 | switch (type) { | 109 | switch (type) { | |
110 | case T_WATCH: /* watchpoint */ | 110 | case T_WATCH: /* watchpoint */ | |
111 | case T_BREAK: /* breakpoint */ | 111 | case T_BREAK: /* breakpoint */ | |
112 | printf("kernel: %s trap\n", trap_names[type & 0x1f]); | 112 | printf("kernel: %s trap\n", trap_names[type & 0x1f]); | |
113 | break; | 113 | break; | |
114 | case -1: /* keyboard interrupt */ | 114 | case -1: /* keyboard interrupt */ | |
115 | printf("kernel: kdbint trap\n"); | 115 | printf("kernel: kdbint trap\n"); | |
116 | break; | 116 | break; | |
117 | default: | 117 | default: | |
118 | printf("kernel: %s trap\n", trap_names[type & 0x1f]); | 118 | printf("kernel: %s trap\n", trap_names[type & 0x1f]); | |
119 | if (db_recover != 0) { | 119 | if (db_recover != 0) { | |
120 | db_error("Faulted in DDB; continuing...\n"); | 120 | db_error("Faulted in DDB; continuing...\n"); | |
121 | /*NOTREACHED*/ | 121 | /*NOTREACHED*/ | |
122 | } | 122 | } | |
123 | break; | 123 | break; | |
124 | } | 124 | } | |
125 | 125 | |||
126 | s = splhigh(); | 126 | s = splhigh(); | |
127 | 127 | |||
128 | #if defined(MULTIPROCESSOR) | 128 | #if defined(MULTIPROCESSOR) | |
129 | bool first_in_ddb = false; | 129 | bool first_in_ddb = false; | |
130 | const u_int cpu_me = cpu_number(); | 130 | const u_int cpu_me = cpu_number(); | |
131 | const u_int old_ddb_cpu = atomic_cas_uint(&ddb_cpu, NOCPU, cpu_me); | 131 | const u_int old_ddb_cpu = atomic_cas_uint(&ddb_cpu, NOCPU, cpu_me); | |
132 | if (old_ddb_cpu == NOCPU) { | 132 | if (old_ddb_cpu == NOCPU) { | |
133 | first_in_ddb = true; | 133 | first_in_ddb = true; | |
134 | cpu_pause_others(); | 134 | cpu_pause_others(); | |
135 | } else { | 135 | } else { | |
136 | if (old_ddb_cpu != cpu_me) { | 136 | if (old_ddb_cpu != cpu_me) { | |
137 | KASSERT(cpu_is_paused(cpu_me)); | 137 | KASSERT(cpu_is_paused(cpu_me)); | |
138 | cpu_pause(regs); | 138 | cpu_pause(regs); | |
139 | splx(s); | 139 | splx(s); | |
140 | return 1; | 140 | return 1; | |
141 | } | 141 | } | |
142 | } | 142 | } | |
143 | KASSERT(! cpu_is_paused(cpu_me)); | 143 | KASSERT(! cpu_is_paused(cpu_me)); | |
144 | #endif | 144 | #endif | |
145 | 145 | |||
146 | ddb_regs = *regs; | 146 | ddb_regs = *regs; | |
147 | db_active++; | 147 | db_active++; | |
148 | cnpollc(1); | 148 | cnpollc(1); | |
149 | db_trap(type & ~T_USER, 0 /*code*/); | 149 | db_trap(type & ~T_USER, 0 /*code*/); | |
150 | cnpollc(0); | 150 | cnpollc(0); | |
151 | db_active--; | 151 | db_active--; | |
152 | *regs = ddb_regs; | 152 | *regs = ddb_regs; | |
153 | 153 | |||
154 | #if defined(MULTIPROCESSOR) | 154 | #if defined(MULTIPROCESSOR) | |
155 | if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me) { | 155 | if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me) { | |
156 | cpu_resume_others(); | 156 | cpu_resume_others(); | |
157 | } else { | 157 | } else { | |
158 | cpu_resume(ddb_cpu); | 158 | cpu_resume(ddb_cpu); | |
159 | if (first_in_ddb) | 159 | if (first_in_ddb) | |
160 | cpu_pause(regs); | 160 | cpu_pause(regs); | |
161 | } | 161 | } | |
162 | #endif | 162 | #endif | |
163 | 163 | |||
164 | splx(s); | 164 | splx(s); | |
165 | return 1; | 165 | return 1; | |
166 | } | 166 | } | |
167 | 167 | |||
168 | void | 168 | void | |
169 | cpu_Debugger(void) | 169 | cpu_Debugger(void) | |
170 | { | 170 | { | |
171 | 171 | |||
172 | __asm("break"); | 172 | __asm("break"); | |
173 | } | 173 | } | |
174 | #endif /* !KGDB */ | 174 | #endif /* !KGDB */ | |
175 | 175 | |||
176 | /* | 176 | /* | |
177 | * Read bytes from kernel address space for debugger. | 177 | * Read bytes from kernel address space for debugger. | |
178 | */ | 178 | */ | |
179 | void | 179 | void | |
180 | db_read_bytes(vaddr_t addr, size_t size, char *data) | 180 | db_read_bytes(vaddr_t addr, size_t size, char *data) | |
181 | { | 181 | { | |
182 | const char *src = (char *)addr; | 182 | const char *src = (char *)addr; | |
183 | int err; | |||
184 | ||||
185 | /* | |||
186 | * If asked to fetch from userspace, do it safely. | |||
187 | * Note that MIPS_KSEG0_START is the proper address for | |||
188 | * both 32-bit and 64-bit kernels. | |||
189 | */ | |||
190 | if (addr < (vaddr_t)MIPS_KSEG0_START) { | |||
191 | err = copyin(src, data, size); | |||
192 | if (err) { | |||
193 | #ifdef DDB | |||
194 | db_printf("address %p is invalid\n", src); | |||
195 | #endif | |||
196 | memset(data, 0, size); | |||
197 | } | |||
198 | return; | |||
199 | } | |||
183 | 200 | |||
184 | if (size <= 8 && (size & (size-1)) == 0 && (addr & (size-1)) == 0 | 201 | if (size <= 8 && (size & (size-1)) == 0 && (addr & (size-1)) == 0 | |
185 | && ((uintptr_t)data & (size-1)) == 0) { | 202 | && ((uintptr_t)data & (size-1)) == 0) { | |
186 | if (size == sizeof(uint8_t)) | 203 | if (size == sizeof(uint8_t)) | |
187 | *(uint8_t *)data = *(const uint8_t *)src; | 204 | *(uint8_t *)data = *(const uint8_t *)src; | |
188 | else if (size == sizeof(uint16_t)) | 205 | else if (size == sizeof(uint16_t)) | |
189 | *(uint16_t *)data = *(const uint16_t *)src; | 206 | *(uint16_t *)data = *(const uint16_t *)src; | |
190 | else if (size == sizeof(uint32_t)) | 207 | else if (size == sizeof(uint32_t)) | |
191 | *(uint32_t *)data = *(const uint32_t *)src; | 208 | *(uint32_t *)data = *(const uint32_t *)src; | |
192 | else | 209 | else | |
193 | *(uint64_t *)data = *(const uint64_t *)src; | 210 | *(uint64_t *)data = *(const uint64_t *)src; | |
194 | return; | 211 | return; | |
195 | } | 212 | } | |
196 | while (size--) | 213 | while (size--) | |
197 | *data++ = *src++; | 214 | *data++ = *src++; | |
198 | } | 215 | } | |
199 | 216 | |||
200 | /* | 217 | /* | |
201 | * Write bytes to kernel address space for debugger. | 218 | * Write bytes to kernel address space for debugger. | |
202 | */ | 219 | */ | |
203 | void | 220 | void | |
204 | db_write_bytes(vaddr_t addr, size_t size, const char *data) | 221 | db_write_bytes(vaddr_t addr, size_t size, const char *data) | |
205 | { | 222 | { | |
206 | char *p = (char *)addr; | 223 | char *p = (char *)addr; | |
207 | size_t n = size; | 224 | size_t n = size; | |
225 | int err; | |||
226 | ||||
227 | /* If asked to fetch from userspace, do it safely */ | |||
228 | if (addr < (vaddr_t)MIPS_KSEG0_START) { | |||
229 | err = copyout(data, p, size); | |||
230 | if (err) { | |||
231 | #ifdef DDB | |||
232 | db_printf("address %p is invalid\n", p); | |||
233 | #endif | |||
234 | } | |||
235 | return; | |||
236 | } | |||
208 | 237 | |||
209 | if (size <= 8 && (size & (size-1)) == 0 && (addr & (size-1)) == 0 | 238 | if (size <= 8 && (size & (size-1)) == 0 && (addr & (size-1)) == 0 | |
210 | && ((uintptr_t)data & (size-1)) == 0) { | 239 | && ((uintptr_t)data & (size-1)) == 0) { | |
211 | if (size == sizeof(uint8_t)) | 240 | if (size == sizeof(uint8_t)) | |
212 | *(uint8_t *)p = *(const uint8_t *)data; | 241 | *(uint8_t *)p = *(const uint8_t *)data; | |
213 | else if (size == sizeof(uint16_t)) | 242 | else if (size == sizeof(uint16_t)) | |
214 | *(uint16_t *)p = *(const uint16_t *)data; | 243 | *(uint16_t *)p = *(const uint16_t *)data; | |
215 | else if (size == sizeof(uint32_t)) | 244 | else if (size == sizeof(uint32_t)) | |
216 | *(uint32_t *)p = *(const uint32_t *)data; | 245 | *(uint32_t *)p = *(const uint32_t *)data; | |
217 | else | 246 | else | |
218 | *(uint64_t *)p = *(const uint64_t *)data; | 247 | *(uint64_t *)p = *(const uint64_t *)data; | |
219 | return; | 248 | return; | |
220 | } | 249 | } | |
221 | while (n--) | 250 | while (n--) | |
222 | *p++ = *data++; | 251 | *p++ = *data++; | |
223 | 252 | |||
224 | wbflush(); | 253 | wbflush(); | |
225 | mips_icache_sync_range(addr, size); | 254 | mips_icache_sync_range(addr, size); | |
226 | } | 255 | } | |
227 | 256 | |||
228 | #ifndef KGDB | 257 | #ifndef KGDB | |
229 | void | 258 | void | |
230 | db_tlbdump_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | 259 | db_tlbdump_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | |
231 | const char *modif) | 260 | const char *modif) | |
232 | { | 261 | { | |
233 | struct tlbmask tlb; | 262 | struct tlbmask tlb; | |
234 | bool valid_only = false; | 263 | bool valid_only = false; | |
235 | 264 | |||
236 | if (modif[0] == 'v') | 265 | if (modif[0] == 'v') | |
237 | valid_only = true; | 266 | valid_only = true; | |
238 | 267 | |||
239 | #ifdef MIPS1 | 268 | #ifdef MIPS1 | |
240 | if (!MIPS_HAS_R4K_MMU) { | 269 | if (!MIPS_HAS_R4K_MMU) { | |
241 | int i; | 270 | int i; | |
242 | 271 | |||
243 | for (i = 0; i < mips_options.mips_num_tlb_entries; i++) { | 272 | for (i = 0; i < mips_options.mips_num_tlb_entries; i++) { | |
244 | tlb_read_entry(i, &tlb); | 273 | tlb_read_entry(i, &tlb); | |
245 | if (valid_only && !(tlb.tlb_lo1 & MIPS1_PG_V)) | 274 | if (valid_only && !(tlb.tlb_lo1 & MIPS1_PG_V)) | |
246 | continue; /* skip invalid TLBs */ | 275 | continue; /* skip invalid TLBs */ | |
247 | db_printf("TLB%c%2d Hi 0x%08x Lo 0x%08x", | 276 | db_printf("TLB%c%2d Hi 0x%08x Lo 0x%08x", | |
248 | (tlb.tlb_lo1 & MIPS1_PG_V) ? ' ' : '*', | 277 | (tlb.tlb_lo1 & MIPS1_PG_V) ? ' ' : '*', | |
249 | i, tlb.tlb_hi, | 278 | i, tlb.tlb_hi, | |
250 | tlb.tlb_lo1 & MIPS1_PG_FRAME); | 279 | tlb.tlb_lo1 & MIPS1_PG_FRAME); | |
251 | db_printf(" %c%c%c\n", | 280 | db_printf(" %c%c%c\n", | |
252 | (tlb.tlb_lo1 & MIPS1_PG_D) ? 'D' : ' ', | 281 | (tlb.tlb_lo1 & MIPS1_PG_D) ? 'D' : ' ', | |
253 | (tlb.tlb_lo1 & MIPS1_PG_G) ? 'G' : ' ', | 282 | (tlb.tlb_lo1 & MIPS1_PG_G) ? 'G' : ' ', | |
254 | (tlb.tlb_lo1 & MIPS1_PG_N) ? 'N' : ' '); | 283 | (tlb.tlb_lo1 & MIPS1_PG_N) ? 'N' : ' '); | |
255 | } | 284 | } | |
256 | } | 285 | } | |
257 | #endif | 286 | #endif | |
258 | #ifdef MIPS3_PLUS | 287 | #ifdef MIPS3_PLUS | |
259 | if (MIPS_HAS_R4K_MMU) { | 288 | if (MIPS_HAS_R4K_MMU) { | |
260 | int i; | 289 | int i; | |
261 | const int tlb_count_width = | 290 | const int tlb_count_width = | |
262 | mips_options.mips_num_tlb_entries > 100 ? 3 : 2; | 291 | mips_options.mips_num_tlb_entries > 100 ? 3 : 2; | |
263 | 292 | |||
264 | for (i = 0; i < mips_options.mips_num_tlb_entries; i++) { | 293 | for (i = 0; i < mips_options.mips_num_tlb_entries; i++) { | |
265 | tlb_read_entry(i, &tlb); | 294 | tlb_read_entry(i, &tlb); | |
266 | if (valid_only && | 295 | if (valid_only && | |
267 | !((tlb.tlb_lo0 | tlb.tlb_lo1) & MIPS3_PG_V)) | 296 | !((tlb.tlb_lo0 | tlb.tlb_lo1) & MIPS3_PG_V)) | |
268 | continue; /* skip invalid TLBs */ | 297 | continue; /* skip invalid TLBs */ | |
269 | 298 | |||
270 | db_printf("TLB%c%*d Hi 0x%08"PRIxVADDR" ", | 299 | db_printf("TLB%c%*d Hi 0x%08"PRIxVADDR" ", | |
271 | (tlb.tlb_lo0 | tlb.tlb_lo1) & MIPS3_PG_V ? ' ' : '*', | 300 | (tlb.tlb_lo0 | tlb.tlb_lo1) & MIPS3_PG_V ? ' ' : '*', | |
272 | tlb_count_width, i, tlb.tlb_hi); | 301 | tlb_count_width, i, tlb.tlb_hi); | |
273 | db_printf("Lo0=0x%09" PRIx64 " %c%c attr %x ", | 302 | db_printf("Lo0=0x%09" PRIx64 " %c%c attr %x ", | |
274 | (uint64_t)mips_tlbpfn_to_paddr(tlb.tlb_lo0), | 303 | (uint64_t)mips_tlbpfn_to_paddr(tlb.tlb_lo0), | |
275 | (tlb.tlb_lo0 & MIPS3_PG_D) ? 'D' : ' ', | 304 | (tlb.tlb_lo0 & MIPS3_PG_D) ? 'D' : ' ', | |
276 | (tlb.tlb_lo0 & MIPS3_PG_G) ? 'G' : ' ', | 305 | (tlb.tlb_lo0 & MIPS3_PG_G) ? 'G' : ' ', | |
277 | (int)(tlb.tlb_lo0 >> 3) & 7); | 306 | (int)(tlb.tlb_lo0 >> 3) & 7); | |
278 | db_printf("Lo1=0x%09" PRIx64 " %c%c attr %x sz=%x\n", | 307 | db_printf("Lo1=0x%09" PRIx64 " %c%c attr %x sz=%x\n", | |
279 | (uint64_t)mips_tlbpfn_to_paddr(tlb.tlb_lo1), | 308 | (uint64_t)mips_tlbpfn_to_paddr(tlb.tlb_lo1), | |
280 | (tlb.tlb_lo1 & MIPS3_PG_D) ? 'D' : ' ', | 309 | (tlb.tlb_lo1 & MIPS3_PG_D) ? 'D' : ' ', | |
281 | (tlb.tlb_lo1 & MIPS3_PG_G) ? 'G' : ' ', | 310 | (tlb.tlb_lo1 & MIPS3_PG_G) ? 'G' : ' ', | |
282 | (int)(tlb.tlb_lo1 >> 3) & 7, | 311 | (int)(tlb.tlb_lo1 >> 3) & 7, | |
283 | tlb.tlb_mask); | 312 | tlb.tlb_mask); | |
284 | } | 313 | } | |
285 | } | 314 | } | |
286 | #endif | 315 | #endif | |
287 | } | 316 | } | |
288 | 317 | |||
289 | void | 318 | void | |
290 | db_kvtophys_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | 319 | db_kvtophys_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | |
291 | const char *modif) | 320 | const char *modif) | |
292 | { | 321 | { | |
293 | 322 | |||
294 | if (!have_addr) | 323 | if (!have_addr) | |
295 | return; | 324 | return; | |
296 | if (VM_MIN_KERNEL_ADDRESS <= addr && addr < VM_MAX_KERNEL_ADDRESS) { | 325 | if (VM_MIN_KERNEL_ADDRESS <= addr && addr < VM_MAX_KERNEL_ADDRESS) { | |
297 | /* | 326 | /* | |
298 | * Cast the physical address -- some platforms, while | 327 | * Cast the physical address -- some platforms, while | |
299 | * being ILP32, may be using 64-bit paddr_t's. | 328 | * being ILP32, may be using 64-bit paddr_t's. | |
300 | */ | 329 | */ | |
301 | db_printf("0x%" DDB_EXPR_FMT "x -> 0x%" PRIx64 "\n", addr, | 330 | db_printf("0x%" DDB_EXPR_FMT "x -> 0x%" PRIx64 "\n", addr, | |
302 | (uint64_t) kvtophys(addr)); | 331 | (uint64_t) kvtophys(addr)); | |
303 | } else | 332 | } else | |
304 | db_printf("not a kernel virtual address\n"); | 333 | db_printf("not a kernel virtual address\n"); | |
305 | } | 334 | } | |
306 | 335 | |||
307 | #define FLDWIDTH 10 | 336 | #define FLDWIDTH 10 | |
308 | 337 | |||
309 | #define SHOW32(reg, name) SHOW32SELECT(reg, 0, name) | 338 | #define SHOW32(reg, name) SHOW32SELECT(reg, 0, name) | |
310 | #define SHOW64(reg, name) SHOW64SELECT(reg, 0, name) | 339 | #define SHOW64(reg, name) SHOW64SELECT(reg, 0, name) | |
311 | #define SHOW32SEL(reg, name) SHOW32SELECT(reg, name) | 340 | #define SHOW32SEL(reg, name) SHOW32SELECT(reg, name) | |
312 | #define SHOW64SEL(reg, name) SHOW64SELECT(reg, name) | 341 | #define SHOW64SEL(reg, name) SHOW64SELECT(reg, name) | |
313 | 342 | |||
314 | #define SHOW32SELECT(num, sel, name) \ | 343 | #define SHOW32SELECT(num, sel, name) \ | |
315 | do { \ | 344 | do { \ | |
316 | uint32_t __val; \ | 345 | uint32_t __val; \ | |
317 | \ | 346 | \ | |
318 | __asm volatile( \ | 347 | __asm volatile( \ | |
319 | ".set push \n\t" \ | 348 | ".set push \n\t" \ | |
320 | ".set mips32 \n\t" \ | 349 | ".set mips32 \n\t" \ | |
321 | "mfc0 %0,$%1,%2 \n\t" \ | 350 | "mfc0 %0,$%1,%2 \n\t" \ | |
322 | ".set pop \n\t" \ | 351 | ".set pop \n\t" \ | |
323 | : "=r"(__val) : "n"(num), "n"(sel)); \ | 352 | : "=r"(__val) : "n"(num), "n"(sel)); \ | |
324 | db_printf(" %s:%*s %#x\n", name, \ | 353 | db_printf(" %s:%*s %#x\n", name, \ | |
325 | FLDWIDTH - (int) strlen(name), "", __val); \ | 354 | FLDWIDTH - (int) strlen(name), "", __val); \ | |
326 | } while (0) | 355 | } while (0) | |
327 | 356 | |||
328 | /* XXX not 64-bit ABI safe! */ | 357 | /* XXX not 64-bit ABI safe! */ | |
329 | #define SHOW64SELECT(num, sel, name) \ | 358 | #define SHOW64SELECT(num, sel, name) \ | |
330 | do { \ | 359 | do { \ | |
331 | uint64_t __val; \ | 360 | uint64_t __val; \ | |
332 | \ | 361 | \ | |
333 | KASSERT (CPUIS64BITS); \ | 362 | KASSERT (CPUIS64BITS); \ | |
334 | __asm volatile( \ | 363 | __asm volatile( \ | |
335 | ".set push \n\t" \ | 364 | ".set push \n\t" \ | |
336 | ".set mips64 \n\t" \ | 365 | ".set mips64 \n\t" \ | |
337 | ".set noat \n\t" \ | 366 | ".set noat \n\t" \ | |
338 | "dmfc0 %0,$%1,%2 \n\t" \ | 367 | "dmfc0 %0,$%1,%2 \n\t" \ | |
339 | ".set pop" \ | 368 | ".set pop" \ | |
340 | : "=r"(__val) : "n"(num), "n"(sel)); \ | 369 | : "=r"(__val) : "n"(num), "n"(sel)); \ | |
341 | db_printf(" %s:%*s %#"PRIx64"\n", name, \ | 370 | db_printf(" %s:%*s %#"PRIx64"\n", name, \ | |
342 | FLDWIDTH - (int) strlen(name), "", __val); \ | 371 | FLDWIDTH - (int) strlen(name), "", __val); \ | |
343 | } while (0) | 372 | } while (0) | |
344 | 373 | |||
345 | #define SET32(reg, name, val) \ | 374 | #define SET32(reg, name, val) \ | |
346 | do { \ | 375 | do { \ | |
347 | \ | 376 | \ | |
348 | __asm volatile("mtc0 %0,$" ___STRING(reg) :: "r"(val)); \ | 377 | __asm volatile("mtc0 %0,$" ___STRING(reg) :: "r"(val)); \ | |
349 | if (name != NULL) \ | 378 | if (name != NULL) \ | |
350 | db_printf(" %s =%*s %#x\n", name, \ | 379 | db_printf(" %s =%*s %#x\n", name, \ | |
351 | FLDWIDTH - (int) strlen(name), "", val); \ | 380 | FLDWIDTH - (int) strlen(name), "", val); \ | |
352 | } while (0) | 381 | } while (0) | |
353 | 382 | |||
354 | #define SET64(reg, name) MIPS64_SET64(reg, 0, name) | 383 | #define SET64(reg, name) MIPS64_SET64(reg, 0, name) | |
355 | 384 | |||
356 | #define MIPS64_SET32(num, sel, name, val) \ | 385 | #define MIPS64_SET32(num, sel, name, val) \ | |
357 | do { \ | 386 | do { \ | |
358 | \ | 387 | \ | |
359 | __asm volatile( \ | 388 | __asm volatile( \ | |
360 | ".set push \n\t" \ | 389 | ".set push \n\t" \ | |
361 | ".set mips32 \n\t" \ | 390 | ".set mips32 \n\t" \ | |
362 | "mtc0 %0,$%1,%2 \n\t" \ | 391 | "mtc0 %0,$%1,%2 \n\t" \ | |
363 | ".set pop \n\t" \ | 392 | ".set pop \n\t" \ | |
364 | :: "r"(val), "n"(num), "n"(sel)); \ | 393 | :: "r"(val), "n"(num), "n"(sel)); \ | |
365 | if (name != NULL) \ | 394 | if (name != NULL) \ | |
366 | db_printf(" %s =%*s %#x\n", name, \ | 395 | db_printf(" %s =%*s %#x\n", name, \ | |
367 | FLDWIDTH - (int) strlen(name), "", val); \ | 396 | FLDWIDTH - (int) strlen(name), "", val); \ | |
368 | } while (0) | 397 | } while (0) | |
369 | 398 | |||
370 | /* XXX not 64-bit ABI safe! */ | 399 | /* XXX not 64-bit ABI safe! */ | |
371 | #define MIPS64_SET64(num, sel, name, val) \ | 400 | #define MIPS64_SET64(num, sel, name, val) \ | |
372 | do { \ | 401 | do { \ | |
373 | \ | 402 | \ | |
374 | KASSERT (CPUIS64BITS); \ | 403 | KASSERT (CPUIS64BITS); \ | |
375 | __asm volatile( \ | 404 | __asm volatile( \ | |
376 | ".set push \n\t" \ | 405 | ".set push \n\t" \ | |
377 | ".set mips64 \n\t" \ | 406 | ".set mips64 \n\t" \ | |
378 | ".set noat \n\t" \ | 407 | ".set noat \n\t" \ | |
379 | "dmtc0 %0,$%1,%2 \n\t" \ | 408 | "dmtc0 %0,$%1,%2 \n\t" \ | |
380 | ".set pop" \ | 409 | ".set pop" \ | |
381 | :: "r"(val), "n"(num), "n"(sel)); \ | 410 | :: "r"(val), "n"(num), "n"(sel)); \ | |
382 | if (name != NULL) \ | 411 | if (name != NULL) \ | |
383 | db_printf(" %s =%*s %#"PRIx64"\n", name, \ | 412 | db_printf(" %s =%*s %#"PRIx64"\n", name, \ | |
384 | FLDWIDTH - (int) strlen(name), "", (uint64_t)val); \ | 413 | FLDWIDTH - (int) strlen(name), "", (uint64_t)val); \ | |
385 | } while (0) | 414 | } while (0) | |
386 | 415 | |||
387 | void | 416 | void | |
388 | db_cp0dump_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | 417 | db_cp0dump_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | |
389 | const char *modif) | 418 | const char *modif) | |
390 | { | 419 | { | |
391 | u_int cp0flags = mips_options.mips_cpu->cpu_cp0flags; | 420 | u_int cp0flags = mips_options.mips_cpu->cpu_cp0flags; | |
392 | 421 | |||
393 | SHOW32(MIPS_COP_0_TLB_INDEX, "index"); | 422 | SHOW32(MIPS_COP_0_TLB_INDEX, "index"); | |
394 | SHOW32(MIPS_COP_0_TLB_RANDOM, "random"); | 423 | SHOW32(MIPS_COP_0_TLB_RANDOM, "random"); | |
395 | 424 | |||
396 | if (!MIPS_HAS_R4K_MMU) { | 425 | if (!MIPS_HAS_R4K_MMU) { | |
397 | SHOW32(MIPS_COP_0_TLB_LOW, "entrylow"); | 426 | SHOW32(MIPS_COP_0_TLB_LOW, "entrylow"); | |
398 | } else { | 427 | } else { | |
399 | if (CPUIS64BITS) { | 428 | if (CPUIS64BITS) { | |
400 | SHOW64(MIPS_COP_0_TLB_LO0, "entrylo0"); | 429 | SHOW64(MIPS_COP_0_TLB_LO0, "entrylo0"); | |
401 | SHOW64(MIPS_COP_0_TLB_LO1, "entrylo1"); | 430 | SHOW64(MIPS_COP_0_TLB_LO1, "entrylo1"); | |
402 | } else { | 431 | } else { | |
403 | SHOW32(MIPS_COP_0_TLB_LO0, "entrylo0"); | 432 | SHOW32(MIPS_COP_0_TLB_LO0, "entrylo0"); | |
404 | SHOW32(MIPS_COP_0_TLB_LO1, "entrylo1"); | 433 | SHOW32(MIPS_COP_0_TLB_LO1, "entrylo1"); | |
405 | } | 434 | } | |
406 | } | 435 | } | |
407 | 436 | |||
408 | if (CPUIS64BITS) { | 437 | if (CPUIS64BITS) { | |
409 | SHOW64(MIPS_COP_0_TLB_CONTEXT, "context"); | 438 | SHOW64(MIPS_COP_0_TLB_CONTEXT, "context"); | |
410 | } else { | 439 | } else { | |
411 | SHOW32(MIPS_COP_0_TLB_CONTEXT, "context"); | 440 | SHOW32(MIPS_COP_0_TLB_CONTEXT, "context"); | |
412 | } | 441 | } | |
413 | 442 | |||
414 | if (MIPS_HAS_R4K_MMU) { | 443 | if (MIPS_HAS_R4K_MMU) { | |
415 | SHOW32(MIPS_COP_0_TLB_PG_MASK, "pagemask"); | 444 | SHOW32(MIPS_COP_0_TLB_PG_MASK, "pagemask"); | |
416 | SHOW32(MIPS_COP_0_TLB_WIRED, "wired"); | 445 | SHOW32(MIPS_COP_0_TLB_WIRED, "wired"); | |
417 | } | 446 | } | |
418 | 447 | |||
419 | if (CPUIS64BITS) { | 448 | if (CPUIS64BITS) { | |
420 | SHOW64(MIPS_COP_0_BAD_VADDR, "badvaddr"); | 449 | SHOW64(MIPS_COP_0_BAD_VADDR, "badvaddr"); | |
421 | } else { | 450 | } else { | |
422 | SHOW32(MIPS_COP_0_BAD_VADDR, "badvaddr"); | 451 | SHOW32(MIPS_COP_0_BAD_VADDR, "badvaddr"); | |
423 | } | 452 | } | |
424 | 453 | |||
425 | if (mips_options.mips_cpu_arch >= CPU_ARCH_MIPS3) { | 454 | if (mips_options.mips_cpu_arch >= CPU_ARCH_MIPS3) { | |
426 | SHOW32(MIPS_COP_0_COUNT, "count"); | 455 | SHOW32(MIPS_COP_0_COUNT, "count"); | |
427 | } | 456 | } | |
428 | 457 | |||
429 | if ((cp0flags & MIPS_CP0FL_USE) != 0) { | 458 | if ((cp0flags & MIPS_CP0FL_USE) != 0) { | |
430 | if ((cp0flags & MIPS_CP0FL_EIRR) != 0) | 459 | if ((cp0flags & MIPS_CP0FL_EIRR) != 0) | |
431 | SHOW64SEL(MIPS_COP_0_EIRR, "eirr"); | 460 | SHOW64SEL(MIPS_COP_0_EIRR, "eirr"); | |
432 | if ((cp0flags & MIPS_CP0FL_EIMR) != 0) | 461 | if ((cp0flags & MIPS_CP0FL_EIMR) != 0) | |
433 | SHOW64SEL(MIPS_COP_0_EIMR, "eimr"); | 462 | SHOW64SEL(MIPS_COP_0_EIMR, "eimr"); | |
434 | } | 463 | } | |
435 | 464 | |||
436 | if (CPUIS64BITS) { | 465 | if (CPUIS64BITS) { | |
437 | SHOW64(MIPS_COP_0_TLB_HI, "entryhi"); | 466 | SHOW64(MIPS_COP_0_TLB_HI, "entryhi"); | |
438 | } else { | 467 | } else { | |
439 | SHOW32(MIPS_COP_0_TLB_HI, "entryhi"); | 468 | SHOW32(MIPS_COP_0_TLB_HI, "entryhi"); | |
440 | } | 469 | } | |
441 | 470 | |||
442 | if (mips_options.mips_cpu_arch >= CPU_ARCH_MIPS3) { | 471 | if (mips_options.mips_cpu_arch >= CPU_ARCH_MIPS3) { | |
443 | SHOW32(MIPS_COP_0_COMPARE, "compare"); | 472 | SHOW32(MIPS_COP_0_COMPARE, "compare"); | |
444 | } | 473 | } | |
445 | 474 | |||
446 | SHOW32(MIPS_COP_0_STATUS, "status"); | 475 | SHOW32(MIPS_COP_0_STATUS, "status"); | |
447 | SHOW32(MIPS_COP_0_CAUSE, "cause"); | 476 | SHOW32(MIPS_COP_0_CAUSE, "cause"); | |
448 | 477 | |||
449 | if (CPUIS64BITS) { | 478 | if (CPUIS64BITS) { | |
450 | SHOW64(MIPS_COP_0_EXC_PC, "epc"); | 479 | SHOW64(MIPS_COP_0_EXC_PC, "epc"); | |
451 | } else { | 480 | } else { | |
452 | SHOW32(MIPS_COP_0_EXC_PC, "epc"); | 481 | SHOW32(MIPS_COP_0_EXC_PC, "epc"); | |
453 | } | 482 | } | |
454 | 483 | |||
455 | SHOW32(MIPS_COP_0_PRID, "prid"); | 484 | SHOW32(MIPS_COP_0_PRID, "prid"); | |
456 | 485 | |||
457 | if ((cp0flags & MIPS_CP0FL_USE) != 0) { | 486 | if ((cp0flags & MIPS_CP0FL_USE) != 0) { | |
458 | if ((cp0flags & MIPS_CP0FL_EBASE) != 0) | 487 | if ((cp0flags & MIPS_CP0FL_EBASE) != 0) | |
459 | SHOW32SEL(MIPS_COP_0_EBASE, "ebase"); | 488 | SHOW32SEL(MIPS_COP_0_EBASE, "ebase"); | |
460 | if ((cp0flags & MIPS_CP0FL_CONFIG) != 0) | 489 | if ((cp0flags & MIPS_CP0FL_CONFIG) != 0) | |
461 | SHOW32(MIPS_COP_0_CONFIG, "config"); | 490 | SHOW32(MIPS_COP_0_CONFIG, "config"); | |
462 | if ((cp0flags & MIPS_CP0FL_CONFIG1) != 0) | 491 | if ((cp0flags & MIPS_CP0FL_CONFIG1) != 0) | |
463 | SHOW32SEL(MIPS_COP_0_CONFIG1, "config1"); | 492 | SHOW32SEL(MIPS_COP_0_CONFIG1, "config1"); | |
464 | if ((cp0flags & MIPS_CP0FL_CONFIG2) != 0) | 493 | if ((cp0flags & MIPS_CP0FL_CONFIG2) != 0) | |
465 | SHOW32SEL(MIPS_COP_0_CONFIG2, "config2"); | 494 | SHOW32SEL(MIPS_COP_0_CONFIG2, "config2"); | |
466 | if ((cp0flags & MIPS_CP0FL_CONFIG3) != 0) | 495 | if ((cp0flags & MIPS_CP0FL_CONFIG3) != 0) | |
467 | SHOW32SEL(MIPS_COP_0_CONFIG3, "config3"); | 496 | SHOW32SEL(MIPS_COP_0_CONFIG3, "config3"); | |
468 | if ((cp0flags & MIPS_CP0FL_CONFIG4) != 0) | 497 | if ((cp0flags & MIPS_CP0FL_CONFIG4) != 0) | |
469 | SHOW32SEL(MIPS_COP_0_CONFIG4, "config4"); | 498 | SHOW32SEL(MIPS_COP_0_CONFIG4, "config4"); | |
470 | if ((cp0flags & MIPS_CP0FL_CONFIG5) != 0) | 499 | if ((cp0flags & MIPS_CP0FL_CONFIG5) != 0) | |
471 | SHOW32SEL(MIPS_COP_0_CONFIG5, "config5"); | 500 | SHOW32SEL(MIPS_COP_0_CONFIG5, "config5"); | |
472 | if ((cp0flags & MIPS_CP0FL_CONFIG6) != 0) | 501 | if ((cp0flags & MIPS_CP0FL_CONFIG6) != 0) | |
473 | SHOW32SEL(MIPS_COP_0_CONFIG6, "config6"); | 502 | SHOW32SEL(MIPS_COP_0_CONFIG6, "config6"); | |
474 | if ((cp0flags & MIPS_CP0FL_CONFIG7) != 0) | 503 | if ((cp0flags & MIPS_CP0FL_CONFIG7) != 0) | |
475 | SHOW32SEL(MIPS_COP_0_CONFIG7, "config7"); | 504 | SHOW32SEL(MIPS_COP_0_CONFIG7, "config7"); | |
476 | if (CPUISMIPSNNR2) | 505 | if (CPUISMIPSNNR2) | |
477 | SHOW32(MIPS_COP_0_HWRENA, "hwrena"); | 506 | SHOW32(MIPS_COP_0_HWRENA, "hwrena"); | |
478 | if (MIPS_HAS_USERLOCAL) | 507 | if (MIPS_HAS_USERLOCAL) | |
479 | SHOW32SEL(MIPS_COP_0_USERLOCAL, "userlocal"); | 508 | SHOW32SEL(MIPS_COP_0_USERLOCAL, "userlocal"); | |
480 | } else { | 509 | } else { | |
481 | SHOW32(MIPS_COP_0_CONFIG, "config"); | 510 | SHOW32(MIPS_COP_0_CONFIG, "config"); | |
482 | #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 | 511 | #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 | |
483 | if (CPUISMIPSNN) { | 512 | if (CPUISMIPSNN) { | |
484 | uint32_t val; | 513 | uint32_t val; | |
485 | 514 | |||
486 | val = mipsNN_cp0_config1_read(); | 515 | val = mipsNN_cp0_config1_read(); | |
487 | db_printf(" config1: %#x\n", val); | 516 | db_printf(" config1: %#x\n", val); | |
488 | } | 517 | } | |
489 | #endif | 518 | #endif | |
490 | } | 519 | } | |
491 | 520 | |||
492 | if (MIPS_HAS_LLSC) { | 521 | if (MIPS_HAS_LLSC) { | |
493 | if (MIPS_HAS_LLADDR) { | 522 | if (MIPS_HAS_LLADDR) { | |
494 | if (CPUIS64BITS) | 523 | if (CPUIS64BITS) | |
495 | SHOW64(MIPS_COP_0_LLADDR, "lladdr"); | 524 | SHOW64(MIPS_COP_0_LLADDR, "lladdr"); | |
496 | else | 525 | else | |
497 | SHOW32(MIPS_COP_0_LLADDR, "lladdr"); | 526 | SHOW32(MIPS_COP_0_LLADDR, "lladdr"); | |
498 | } | 527 | } | |
499 | } | 528 | } | |
500 | 529 | |||
501 | #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 | 530 | #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 | |
502 | for (int i=0; i < curcpu()->ci_cpuwatch_count; i++) { | 531 | for (int i=0; i < curcpu()->ci_cpuwatch_count; i++) { | |
503 | const intptr_t lo = mipsNN_cp0_watchlo_read(i); | 532 | const intptr_t lo = mipsNN_cp0_watchlo_read(i); | |
504 | const uint32_t hi = mipsNN_cp0_watchhi_read(i); | 533 | const uint32_t hi = mipsNN_cp0_watchhi_read(i); | |
505 | db_printf(" %s%d:%*s %#" PRIxPTR "\t", | 534 | db_printf(" %s%d:%*s %#" PRIxPTR "\t", | |
506 | "watchlo", i, FLDWIDTH - 8, "", lo); | 535 | "watchlo", i, FLDWIDTH - 8, "", lo); | |
507 | db_printf(" %s%d:%*s %#" PRIx32 "\n", | 536 | db_printf(" %s%d:%*s %#" PRIx32 "\n", | |
508 | "watchhi", i, FLDWIDTH - 8, "", hi); | 537 | "watchhi", i, FLDWIDTH - 8, "", hi); | |
509 | } | 538 | } | |
510 | #endif | 539 | #endif | |
511 | 540 | |||
512 | if (CPUIS64BITS) { | 541 | if (CPUIS64BITS) { | |
513 | SHOW64(MIPS_COP_0_TLB_XCONTEXT, "xcontext"); | 542 | SHOW64(MIPS_COP_0_TLB_XCONTEXT, "xcontext"); | |
514 | } | 543 | } | |
515 | 544 | |||
516 | if (CPUISMIPSNN) { | 545 | if (CPUISMIPSNN) { | |
517 | if (CPUIS64BITS) { | 546 | if (CPUIS64BITS) { | |
518 | SHOW64(MIPS_COP_0_PERFCNT0_CTL, "perfcnt0ctl"); | 547 | SHOW64(MIPS_COP_0_PERFCNT0_CTL, "perfcnt0ctl"); | |
519 | SHOW64SEL(MIPS_COP_0_PERFCNT0_CNT, "perfcnt0cnt"); | 548 | SHOW64SEL(MIPS_COP_0_PERFCNT0_CNT, "perfcnt0cnt"); | |
520 | } else { | 549 | } else { | |
521 | SHOW32(MIPS_COP_0_PERFCNT0_CTL, "perfcnt0ctl"); | 550 | SHOW32(MIPS_COP_0_PERFCNT0_CTL, "perfcnt0ctl"); | |
522 | SHOW32SEL(MIPS_COP_0_PERFCNT0_CNT, "perfcnt0cnt"); | 551 | SHOW32SEL(MIPS_COP_0_PERFCNT0_CNT, "perfcnt0cnt"); | |
523 | } | 552 | } | |
524 | } | 553 | } | |
525 | 554 | |||
526 | if (((cp0flags & MIPS_CP0FL_USE) == 0) || | 555 | if (((cp0flags & MIPS_CP0FL_USE) == 0) || | |
527 | ((cp0flags & MIPS_CP0FL_ECC) != 0)) | 556 | ((cp0flags & MIPS_CP0FL_ECC) != 0)) | |
528 | SHOW32(MIPS_COP_0_ECC, "ecc"); | 557 | SHOW32(MIPS_COP_0_ECC, "ecc"); | |
529 | 558 | |||
530 | if (((cp0flags & MIPS_CP0FL_USE) == 0) || | 559 | if (((cp0flags & MIPS_CP0FL_USE) == 0) || | |
531 | ((cp0flags & MIPS_CP0FL_CACHE_ERR) != 0)) | 560 | ((cp0flags & MIPS_CP0FL_CACHE_ERR) != 0)) | |
532 | SHOW32(MIPS_COP_0_CACHE_ERR, "cacherr"); | 561 | SHOW32(MIPS_COP_0_CACHE_ERR, "cacherr"); | |
533 | 562 | |||
534 | SHOW32(MIPS_COP_0_TAG_LO, "cachelo"); | 563 | SHOW32(MIPS_COP_0_TAG_LO, "cachelo"); | |
535 | SHOW32(MIPS_COP_0_TAG_HI, "cachehi"); | 564 | SHOW32(MIPS_COP_0_TAG_HI, "cachehi"); | |
536 | 565 | |||
537 | if (CPUIS64BITS) { | 566 | if (CPUIS64BITS) { | |
538 | SHOW64(MIPS_COP_0_ERROR_PC, "errorpc"); | 567 | SHOW64(MIPS_COP_0_ERROR_PC, "errorpc"); | |
539 | } else { | 568 | } else { | |
540 | SHOW32(MIPS_COP_0_ERROR_PC, "errorpc"); | 569 | SHOW32(MIPS_COP_0_ERROR_PC, "errorpc"); | |
541 | } | 570 | } | |
542 | } | 571 | } | |
543 | 572 | |||
544 | #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 | 573 | #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 | |
545 | static void | 574 | static void | |
546 | db_watch_cmd(db_expr_t address, bool have_addr, db_expr_t count, | 575 | db_watch_cmd(db_expr_t address, bool have_addr, db_expr_t count, | |
547 | const char *modif) | 576 | const char *modif) | |
548 | { | 577 | { | |
549 | struct cpu_info * const ci = curcpu(); | 578 | struct cpu_info * const ci = curcpu(); | |
550 | cpu_watchpoint_t *cwp; | 579 | cpu_watchpoint_t *cwp; | |
551 | register_t mask=0; | 580 | register_t mask=0; | |
552 | uint32_t asid; | 581 | uint32_t asid; | |
553 | uint32_t mode; | 582 | uint32_t mode; | |
554 | db_expr_t value; | 583 | db_expr_t value; | |
555 | char str[6]; | 584 | char str[6]; | |
556 | 585 | |||
557 | if (!have_addr) { | 586 | if (!have_addr) { | |
558 | db_printf("%-3s %-5s %-16s %4s %4s\n", | 587 | db_printf("%-3s %-5s %-16s %4s %4s\n", | |
559 | "#", "MODE", "ADDR", "MASK", "ASID"); | 588 | "#", "MODE", "ADDR", "MASK", "ASID"); | |
560 | for (u_int i=0; i < ci->ci_cpuwatch_count; i++) { | 589 | for (u_int i=0; i < ci->ci_cpuwatch_count; i++) { | |
561 | cwp = &ci->ci_cpuwatch_tab[i]; | 590 | cwp = &ci->ci_cpuwatch_tab[i]; | |
562 | mode = cwp->cw_mode; | 591 | mode = cwp->cw_mode; | |
563 | if ((mode & CPUWATCH_RWX) == 0) | 592 | if ((mode & CPUWATCH_RWX) == 0) | |
564 | continue; /* empty/disabled/invalid */ | 593 | continue; /* empty/disabled/invalid */ | |
565 | str[0] = (mode & CPUWATCH_READ) ? 'r' : '-'; | 594 | str[0] = (mode & CPUWATCH_READ) ? 'r' : '-'; | |
566 | str[1] = (mode & CPUWATCH_WRITE) ? 'w' : '-'; | 595 | str[1] = (mode & CPUWATCH_WRITE) ? 'w' : '-'; | |
567 | str[2] = (mode & CPUWATCH_EXEC) ? 'x' : '-'; | 596 | str[2] = (mode & CPUWATCH_EXEC) ? 'x' : '-'; | |
568 | str[3] = (mode & CPUWATCH_MASK) ? 'm' : '-'; | 597 | str[3] = (mode & CPUWATCH_MASK) ? 'm' : '-'; | |
569 | str[4] = (mode & CPUWATCH_ASID) ? 'a' : 'g'; | 598 | str[4] = (mode & CPUWATCH_ASID) ? 'a' : 'g'; | |
570 | str[5] = '\0'; | 599 | str[5] = '\0'; | |
571 | db_printf("%2u: %s %16" PRIxREGISTER | 600 | db_printf("%2u: %s %16" PRIxREGISTER | |
572 | " %4" PRIxREGISTER " %4x\n", | 601 | " %4" PRIxREGISTER " %4x\n", | |
573 | i, str, cwp->cw_addr, cwp->cw_mask, cwp->cw_asid); | 602 | i, str, cwp->cw_addr, cwp->cw_mask, cwp->cw_asid); | |
574 | } | 603 | } | |
575 | db_flush_lex(); | 604 | db_flush_lex(); | |
576 | return; | 605 | return; | |
577 | } | 606 | } | |
578 | 607 | |||
579 | cwp = cpuwatch_alloc(); | 608 | cwp = cpuwatch_alloc(); | |
580 | if (cwp == NULL) { | 609 | if (cwp == NULL) { | |
581 | db_printf("no watchpoint available\n"); | 610 | db_printf("no watchpoint available\n"); | |
582 | db_flush_lex(); | 611 | db_flush_lex(); | |
583 | return; | 612 | return; | |
584 | } | 613 | } | |
585 | 614 | |||
586 | /* | 615 | /* | |
587 | * parse modif to define mode | 616 | * parse modif to define mode | |
588 | */ | 617 | */ | |
589 | KASSERT(modif != NULL); | 618 | KASSERT(modif != NULL); | |
590 | mode = 0; | 619 | mode = 0; | |
591 | for (int i=0; modif[i] != '\0'; i++) { | 620 | for (int i=0; modif[i] != '\0'; i++) { | |
592 | switch(modif[i]) { | 621 | switch(modif[i]) { | |
593 | case 'w': | 622 | case 'w': | |
594 | mode |= CPUWATCH_WRITE; | 623 | mode |= CPUWATCH_WRITE; | |
595 | break; | 624 | break; | |
596 | case 'm': | 625 | case 'm': | |
597 | mode |= CPUWATCH_MASK; | 626 | mode |= CPUWATCH_MASK; | |
598 | break; | 627 | break; | |
599 | case 'r': | 628 | case 'r': | |
600 | mode |= CPUWATCH_READ; | 629 | mode |= CPUWATCH_READ; | |
601 | break; | 630 | break; | |
602 | case 'x': | 631 | case 'x': | |
603 | mode |= CPUWATCH_EXEC; | 632 | mode |= CPUWATCH_EXEC; | |
604 | break; | 633 | break; | |
605 | case 'a': | 634 | case 'a': | |
606 | mode |= CPUWATCH_ASID; | 635 | mode |= CPUWATCH_ASID; | |
607 | break; | 636 | break; | |
608 | } | 637 | } | |
609 | } | 638 | } | |
610 | if (mode == 0) { | 639 | if (mode == 0) { | |
611 | db_printf("mode modifier(s) missing\n"); | 640 | db_printf("mode modifier(s) missing\n"); | |
612 | db_flush_lex(); | 641 | db_flush_lex(); | |
613 | return; | 642 | return; | |
614 | } | 643 | } | |
615 | 644 | |||
616 | /* | 645 | /* | |
617 | * if mask mode is requested get the mask, | 646 | * if mask mode is requested get the mask, | |
618 | */ | 647 | */ | |
619 | if (mode & CPUWATCH_MASK) { | 648 | if (mode & CPUWATCH_MASK) { | |
620 | if (! db_expression(&value)) { | 649 | if (! db_expression(&value)) { | |
621 | db_printf("mask missing\n"); | 650 | db_printf("mask missing\n"); | |
622 | db_flush_lex(); | 651 | db_flush_lex(); | |
623 | return; | 652 | return; | |
624 | } | 653 | } | |
625 | mask = (register_t)(value & __BITS(11, 3)); | 654 | mask = (register_t)(value & __BITS(11, 3)); | |
626 | } | 655 | } | |
627 | 656 | |||
628 | /* | 657 | /* | |
629 | * if asid mode is requested, get the asid; | 658 | * if asid mode is requested, get the asid; | |
630 | * otherwise use global mode (and set asid=0) | 659 | * otherwise use global mode (and set asid=0) | |
631 | */ | 660 | */ | |
632 | if (mode & CPUWATCH_ASID) { | 661 | if (mode & CPUWATCH_ASID) { | |
633 | if (! db_expression(&value)) { | 662 | if (! db_expression(&value)) { | |
634 | db_printf("asid missing\n"); | 663 | db_printf("asid missing\n"); | |
635 | db_flush_lex(); | 664 | db_flush_lex(); | |
636 | return; | 665 | return; | |
637 | } | 666 | } | |
638 | asid = (uint32_t)(value & __BITS(7,0)); | 667 | asid = (uint32_t)(value & __BITS(7,0)); | |
639 | } else { | 668 | } else { | |
640 | asid = 0; | 669 | asid = 0; | |
641 | } | 670 | } | |
642 | 671 | |||
643 | if (mode & (CPUWATCH_MASK|CPUWATCH_ASID)) | 672 | if (mode & (CPUWATCH_MASK|CPUWATCH_ASID)) | |
644 | db_skip_to_eol(); | 673 | db_skip_to_eol(); | |
645 | else | 674 | else | |
646 | db_flush_lex(); | 675 | db_flush_lex(); | |
647 | 676 | |||
648 | /* | 677 | /* | |
649 | * store to the (volatile) table entry | 678 | * store to the (volatile) table entry | |
650 | * other CPUs can see this and load when resuming from pause | 679 | * other CPUs can see this and load when resuming from pause | |
651 | */ | 680 | */ | |
652 | cwp->cw_addr = (register_t)address; | 681 | cwp->cw_addr = (register_t)address; | |
653 | cwp->cw_mask = (register_t)mask; | 682 | cwp->cw_mask = (register_t)mask; | |
654 | cwp->cw_asid = asid; | 683 | cwp->cw_asid = asid; | |
655 | cwp->cw_mode = mode; | 684 | cwp->cw_mode = mode; | |
656 | 685 | |||
657 | /* | 686 | /* | |
658 | * program the CPU watchpoint regs | 687 | * program the CPU watchpoint regs | |
659 | */ | 688 | */ | |
660 | cpuwatch_set(cwp); | 689 | cpuwatch_set(cwp); | |
661 | } | 690 | } | |
662 | 691 | |||
663 | static void | 692 | static void | |
664 | db_unwatch_cmd(db_expr_t address, bool have_addr, db_expr_t count, | 693 | db_unwatch_cmd(db_expr_t address, bool have_addr, db_expr_t count, | |
665 | const char *modif) | 694 | const char *modif) | |
666 | { | 695 | { | |
667 | struct cpu_info * const ci = curcpu(); | 696 | struct cpu_info * const ci = curcpu(); | |
668 | const bool unwatch_all = !have_addr; | 697 | const bool unwatch_all = !have_addr; | |
669 | int n; | 698 | int n; | |
670 | 699 | |||
671 | n = 0; | 700 | n = 0; | |
672 | for (u_int i=0; i < ci->ci_cpuwatch_count; i++) { | 701 | for (u_int i=0; i < ci->ci_cpuwatch_count; i++) { | |
673 | cpu_watchpoint_t * const cwp = &ci->ci_cpuwatch_tab[i]; | 702 | cpu_watchpoint_t * const cwp = &ci->ci_cpuwatch_tab[i]; | |
674 | if (unwatch_all || (cwp->cw_addr == (register_t)address)) { | 703 | if (unwatch_all || (cwp->cw_addr == (register_t)address)) { | |
675 | cpuwatch_free(cwp); | 704 | cpuwatch_free(cwp); | |
676 | n++; | 705 | n++; | |
677 | } | 706 | } | |
678 | } | 707 | } | |
679 | if (n == 0) | 708 | if (n == 0) | |
680 | db_printf("no watch found on address %#" PRIxREGISTER "\n", | 709 | db_printf("no watch found on address %#" PRIxREGISTER "\n", | |
681 | (register_t)address); | 710 | (register_t)address); | |
682 | } | 711 | } | |
683 | #endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */ | 712 | #endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */ | |
684 | 713 | |||
685 | #ifdef MIPS64_XLS | 714 | #ifdef MIPS64_XLS | |
686 | void | 715 | void | |
687 | db_mfcr_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | 716 | db_mfcr_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | |
688 | const char *modif) | 717 | const char *modif) | |
689 | { | 718 | { | |
690 | uint64_t value; | 719 | uint64_t value; | |
691 | 720 | |||
692 | if ((mips_options.mips_cpu->cpu_flags & CPU_MIPS_HAVE_MxCR) == 0) { | 721 | if ((mips_options.mips_cpu->cpu_flags & CPU_MIPS_HAVE_MxCR) == 0) { | |
693 | db_printf("mfcr not implemented on this CPU\n"); | 722 | db_printf("mfcr not implemented on this CPU\n"); | |
694 | return; | 723 | return; | |
695 | } | 724 | } | |
696 | 725 | |||
697 | if (!have_addr) { | 726 | if (!have_addr) { | |
698 | db_printf("Address missing\n"); | 727 | db_printf("Address missing\n"); | |
699 | return; | 728 | return; | |
700 | } | 729 | } | |
701 | 730 | |||
702 | /* value = CR[addr] */ | 731 | /* value = CR[addr] */ | |
703 | __asm volatile( \ | 732 | __asm volatile( \ | |
704 | ".set push \n\t" \ | 733 | ".set push \n\t" \ | |
705 | ".set arch=xlr \n\t" \ | 734 | ".set arch=xlr \n\t" \ | |
706 | ".set noat \n\t" \ | 735 | ".set noat \n\t" \ | |
707 | "mfcr %0,%1 \n\t" \ | 736 | "mfcr %0,%1 \n\t" \ | |
708 | ".set pop \n\t" \ | 737 | ".set pop \n\t" \ | |
709 | : "=r"(value) : "r"(addr)); | 738 | : "=r"(value) : "r"(addr)); | |
710 | 739 | |||
711 | db_printf("control reg 0x%" DDB_EXPR_FMT "x = 0x%" PRIx64 "\n", | 740 | db_printf("control reg 0x%" DDB_EXPR_FMT "x = 0x%" PRIx64 "\n", | |
712 | addr, value); | 741 | addr, value); | |
713 | } | 742 | } | |
714 | 743 | |||
715 | void | 744 | void | |
716 | db_mtcr_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | 745 | db_mtcr_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | |
717 | const char *modif) | 746 | const char *modif) | |
718 | { | 747 | { | |
719 | db_expr_t value; | 748 | db_expr_t value; | |
720 | 749 | |||
721 | if ((mips_options.mips_cpu->cpu_flags & CPU_MIPS_HAVE_MxCR) == 0) { | 750 | if ((mips_options.mips_cpu->cpu_flags & CPU_MIPS_HAVE_MxCR) == 0) { | |
722 | db_printf("mtcr not implemented on this CPU\n"); | 751 | db_printf("mtcr not implemented on this CPU\n"); | |
723 | return; | 752 | return; | |
724 | } | 753 | } | |
725 | 754 | |||
726 | if ((!have_addr) || (! db_expression(&value))) { | 755 | if ((!have_addr) || (! db_expression(&value))) { | |
727 | db_printf("Address missing\n"); | 756 | db_printf("Address missing\n"); | |
728 | db_flush_lex(); | 757 | db_flush_lex(); | |
729 | return; | 758 | return; | |
730 | } | 759 | } | |
731 | db_skip_to_eol(); | 760 | db_skip_to_eol(); | |
732 | 761 | |||
733 | /* CR[addr] = value */ | 762 | /* CR[addr] = value */ | |
734 | __asm volatile( \ | 763 | __asm volatile( \ | |
735 | ".set push \n\t" \ | 764 | ".set push \n\t" \ | |
736 | ".set arch=xlr \n\t" \ | 765 | ".set arch=xlr \n\t" \ | |
737 | ".set noat \n\t" \ | 766 | ".set noat \n\t" \ | |
738 | "mtcr %0,%1 \n\t" \ | 767 | "mtcr %0,%1 \n\t" \ | |
739 | ".set pop \n\t" \ | 768 | ".set pop \n\t" \ | |
740 | :: "r"(value), "r"(addr)); | 769 | :: "r"(value), "r"(addr)); | |
741 | 770 | |||
742 | db_printf("control reg 0x%" DDB_EXPR_FMT "x = 0x%" DDB_EXPR_FMT "x\n", | 771 | db_printf("control reg 0x%" DDB_EXPR_FMT "x = 0x%" DDB_EXPR_FMT "x\n", | |
743 | addr, value); | 772 | addr, value); | |
744 | } | 773 | } | |
745 | #endif /* MIPS64_XLS */ | 774 | #endif /* MIPS64_XLS */ | |
746 | 775 | |||
747 | #ifdef MIPS64_OCTEON | 776 | #ifdef MIPS64_OCTEON | |
748 | #include <mips/cavium/dev/octeon_ciureg.h> | 777 | #include <mips/cavium/dev/octeon_ciureg.h> | |
749 | 778 | |||
750 | #ifdef MULTIPROCESSOR | 779 | #ifdef MULTIPROCESSOR | |
751 | static void | 780 | static void | |
752 | db_mach_nmi_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | 781 | db_mach_nmi_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | |
753 | const char *modif) | 782 | const char *modif) | |
754 | { | 783 | { | |
755 | CPU_INFO_ITERATOR cii; | 784 | CPU_INFO_ITERATOR cii; | |
756 | struct cpu_info *ci; | 785 | struct cpu_info *ci; | |
757 | 786 | |||
758 | if (!have_addr) { | 787 | if (!have_addr) { | |
759 | db_printf("CPU not specific\n"); | 788 | db_printf("CPU not specific\n"); | |
760 | return; | 789 | return; | |
761 | } | 790 | } | |
762 | for (CPU_INFO_FOREACH(cii, ci)) { | 791 | for (CPU_INFO_FOREACH(cii, ci)) { | |
763 | if (cpu_index(ci) == addr) | 792 | if (cpu_index(ci) == addr) | |
764 | break; | 793 | break; | |
765 | } | 794 | } | |
766 | if (ci == NULL) { | 795 | if (ci == NULL) { | |
767 | db_printf("CPU %ld not configured\n", (long)addr); | 796 | db_printf("CPU %ld not configured\n", (long)addr); | |
768 | return; | 797 | return; | |
769 | } | 798 | } | |
770 | if (ci == curcpu()) { | 799 | if (ci == curcpu()) { | |
771 | db_printf("CPU %ld is current cpu; request ignored\n", | 800 | db_printf("CPU %ld is current cpu; request ignored\n", | |
772 | (long)addr); | 801 | (long)addr); | |
773 | return; | 802 | return; | |
774 | } | 803 | } | |
775 | mips3_sd(MIPS_PHYS_TO_XKPHYS_UNCACHED(CIU_NMI), __BIT(ci->ci_cpuid)); | 804 | mips3_sd(MIPS_PHYS_TO_XKPHYS_UNCACHED(CIU_NMI), __BIT(ci->ci_cpuid)); | |
776 | } | 805 | } | |
777 | #endif | 806 | #endif | |
778 | #endif | 807 | #endif | |
779 | 808 | |||
780 | static void | 809 | static void | |
781 | db_mach_reset_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | 810 | db_mach_reset_cmd(db_expr_t addr, bool have_addr, db_expr_t count, | |
782 | const char *modif) | 811 | const char *modif) | |
783 | { | 812 | { | |
784 | 813 | |||
785 | if (cpu_reset_address == NULL) { | 814 | if (cpu_reset_address == NULL) { | |
786 | db_printf("cpu_reset_address is not set\n"); | 815 | db_printf("cpu_reset_address is not set\n"); | |
787 | return; | 816 | return; | |
788 | } | 817 | } | |
789 | 818 | |||
790 | cpu_reset_address(); | 819 | cpu_reset_address(); | |
791 | } | 820 | } | |
792 | 821 | |||
793 | const struct db_command db_machine_command_table[] = { | 822 | const struct db_command db_machine_command_table[] = { | |
794 | #ifdef MULTIPROCESSOR | 823 | #ifdef MULTIPROCESSOR | |
795 | { DDB_ADD_CMD("cpu", db_mach_cpu_cmd, 0, | 824 | { DDB_ADD_CMD("cpu", db_mach_cpu_cmd, 0, | |
796 | "switch to another cpu", "cpu#", NULL) }, | 825 | "switch to another cpu", "cpu#", NULL) }, | |
797 | #endif | 826 | #endif | |
798 | { DDB_ADD_CMD("cp0", db_cp0dump_cmd, 0, | 827 | { DDB_ADD_CMD("cp0", db_cp0dump_cmd, 0, | |
799 | "Dump CP0 registers.", | 828 | "Dump CP0 registers.", | |
800 | NULL, NULL) }, | 829 | NULL, NULL) }, | |
801 | { DDB_ADD_CMD("kvtop", db_kvtophys_cmd, 0, | 830 | { DDB_ADD_CMD("kvtop", db_kvtophys_cmd, 0, | |
802 | "Print the physical address for a given kernel virtual address", | 831 | "Print the physical address for a given kernel virtual address", | |
803 | "address", | 832 | "address", | |
804 | " address:\tvirtual address to look up") }, | 833 | " address:\tvirtual address to look up") }, | |
805 | #ifdef MIPS64_XLS | 834 | #ifdef MIPS64_XLS | |
806 | { DDB_ADD_CMD("mfcr", db_mfcr_cmd, CS_NOREPEAT, | 835 | { DDB_ADD_CMD("mfcr", db_mfcr_cmd, CS_NOREPEAT, | |
807 | "Dump processor control register", | 836 | "Dump processor control register", | |
808 | NULL, NULL) }, | 837 | NULL, NULL) }, | |
809 | { DDB_ADD_CMD("mtcr", db_mtcr_cmd, CS_NOREPEAT|CS_MORE, | 838 | { DDB_ADD_CMD("mtcr", db_mtcr_cmd, CS_NOREPEAT|CS_MORE, | |
810 | "Set processor control register", | 839 | "Set processor control register", | |
811 | NULL, NULL) }, | 840 | NULL, NULL) }, | |
812 | #endif | 841 | #endif | |
813 | #if defined(MIPS64_OCTEON) && defined(MULTIPROCESSOR) | 842 | #if defined(MIPS64_OCTEON) && defined(MULTIPROCESSOR) | |
814 | { DDB_ADD_CMD("nmi", db_mach_nmi_cmd, CS_NOREPEAT, | 843 | { DDB_ADD_CMD("nmi", db_mach_nmi_cmd, CS_NOREPEAT, | |
815 | "Send NMI to processor", | 844 | "Send NMI to processor", | |
816 | "cpu#", NULL) }, | 845 | "cpu#", NULL) }, | |
817 | #endif /* OCTEON + MP */ | 846 | #endif /* OCTEON + MP */ | |
818 | { DDB_ADD_CMD("reset", db_mach_reset_cmd, CS_NOREPEAT, | 847 | { DDB_ADD_CMD("reset", db_mach_reset_cmd, CS_NOREPEAT, | |
819 | "Initiate hardware reset", | 848 | "Initiate hardware reset", | |
820 | NULL, NULL) }, | 849 | NULL, NULL) }, | |
821 | { DDB_ADD_CMD("tlb", db_tlbdump_cmd, 0, | 850 | { DDB_ADD_CMD("tlb", db_tlbdump_cmd, 0, | |
822 | "Print out TLB entries. (only works with options DEBUG)", | 851 | "Print out TLB entries. (only works with options DEBUG)", | |
823 | NULL, NULL) }, | 852 | NULL, NULL) }, | |
824 | #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 | 853 | #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 | |
825 | { DDB_ADD_CMD("watch", db_watch_cmd, CS_MORE, | 854 | { DDB_ADD_CMD("watch", db_watch_cmd, CS_MORE, | |
826 | "set cp0 watchpoint", | 855 | "set cp0 watchpoint", | |
827 | "address <mask> <asid> </rwxma>", NULL) }, | 856 | "address <mask> <asid> </rwxma>", NULL) }, | |
828 | { DDB_ADD_CMD("unwatch",db_unwatch_cmd, 0, | 857 | { DDB_ADD_CMD("unwatch",db_unwatch_cmd, 0, | |
829 | "delete cp0 watchpoint", | 858 | "delete cp0 watchpoint", | |
830 | "address", NULL) }, | 859 | "address", NULL) }, | |
831 | #endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */ | 860 | #endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */ | |
832 | { DDB_END_CMD }, | 861 | { DDB_END_CMD }, | |
833 | }; | 862 | }; | |
834 | #endif /* !KGDB */ | 863 | #endif /* !KGDB */ | |
835 | 864 | |||
836 | /* | 865 | /* | |
837 | * Determine whether the instruction involves a delay slot. | 866 | * Determine whether the instruction involves a delay slot. | |
838 | */ | 867 | */ | |
839 | bool | 868 | bool | |
840 | inst_branch(int inst) | 869 | inst_branch(int inst) | |
841 | { | 870 | { | |
842 | InstFmt i; | 871 | InstFmt i; | |
843 | int delslt; | 872 | int delslt; | |
844 | 873 | |||
845 | i.word = inst; | 874 | i.word = inst; | |
846 | delslt = 0; | 875 | delslt = 0; | |
847 | switch (i.JType.op) { | 876 | switch (i.JType.op) { | |
848 | case OP_REGIMM: | 877 | case OP_REGIMM: | |
849 | case OP_J: | 878 | case OP_J: | |
850 | case OP_JAL: | 879 | case OP_JAL: | |
851 | #if MIPS64_OCTEON | 880 | #if MIPS64_OCTEON | |
852 | case OP_CVM_BBIT0: | 881 | case OP_CVM_BBIT0: | |
853 | case OP_CVM_BBIT032: | 882 | case OP_CVM_BBIT032: | |
854 | case OP_CVM_BBIT1: | 883 | case OP_CVM_BBIT1: | |
855 | case OP_CVM_BBIT132: | 884 | case OP_CVM_BBIT132: | |
856 | #endif | 885 | #endif | |
857 | case OP_BEQ: | 886 | case OP_BEQ: | |
858 | case OP_BNE: | 887 | case OP_BNE: | |
859 | case OP_BLEZ: | 888 | case OP_BLEZ: | |
860 | case OP_BGTZ: | 889 | case OP_BGTZ: | |
861 | case OP_BEQL: | 890 | case OP_BEQL: | |
862 | case OP_BNEL: | 891 | case OP_BNEL: | |
863 | case OP_BLEZL: | 892 | case OP_BLEZL: | |
864 | case OP_BGTZL: | 893 | case OP_BGTZL: | |
865 | delslt = 1; | 894 | delslt = 1; | |
866 | break; | 895 | break; | |
867 | 896 | |||
868 | case OP_COP0: | 897 | case OP_COP0: | |
869 | case OP_COP1: | 898 | case OP_COP1: | |
870 | switch (i.RType.rs) { | 899 | switch (i.RType.rs) { | |
871 | case OP_BCx: | 900 | case OP_BCx: | |
872 | case OP_BCy: | 901 | case OP_BCy: | |
873 | delslt = 1; | 902 | delslt = 1; | |
874 | } | 903 | } | |
875 | break; | 904 | break; | |
876 | 905 | |||
877 | case OP_SPECIAL: | 906 | case OP_SPECIAL: | |
878 | if (i.RType.op == OP_JR || i.RType.op == OP_JALR) | 907 | if (i.RType.op == OP_JR || i.RType.op == OP_JALR) | |
879 | delslt = 1; | 908 | delslt = 1; | |
880 | break; | 909 | break; | |
881 | } | 910 | } | |
882 | return delslt; | 911 | return delslt; | |
883 | } | 912 | } | |
884 | 913 | |||
885 | /* | 914 | /* | |
886 | * Determine whether the instruction calls a function. | 915 | * Determine whether the instruction calls a function. | |
887 | */ | 916 | */ | |
888 | bool | 917 | bool | |
889 | inst_call(int inst) | 918 | inst_call(int inst) | |
890 | { | 919 | { | |
891 | bool call; | 920 | bool call; | |
892 | InstFmt i; | 921 | InstFmt i; | |
893 | 922 | |||
894 | i.word = inst; | 923 | i.word = inst; | |
895 | if (i.JType.op == OP_SPECIAL | 924 | if (i.JType.op == OP_SPECIAL | |
896 | && ((i.RType.func == OP_JR && i.RType.rs != 31) || | 925 | && ((i.RType.func == OP_JR && i.RType.rs != 31) || | |
897 | i.RType.func == OP_JALR)) | 926 | i.RType.func == OP_JALR)) | |
898 | call = 1; | 927 | call = 1; | |
899 | else if (i.JType.op == OP_JAL) | 928 | else if (i.JType.op == OP_JAL) | |
900 | call = 1; | 929 | call = 1; | |
901 | else | 930 | else | |
902 | call = 0; | 931 | call = 0; | |
903 | return call; | 932 | return call; | |
904 | } | 933 | } | |
905 | 934 | |||
906 | /* | 935 | /* | |
907 | * Determine whether the instruction returns from a function (j ra). The | 936 | * Determine whether the instruction returns from a function (j ra). The | |
908 | * compiler can use this construct for other jumps, but usually will not. | 937 | * compiler can use this construct for other jumps, but usually will not. | |
909 | * This lets the ddb "next" command to work (also need inst_trap_return()). | 938 | * This lets the ddb "next" command to work (also need inst_trap_return()). | |
910 | */ | 939 | */ | |
911 | bool | 940 | bool | |
912 | inst_return(int inst) | 941 | inst_return(int inst) | |
913 | { | 942 | { | |
914 | InstFmt i; | 943 | InstFmt i; | |
915 | 944 | |||
916 | i.word = inst; | 945 | i.word = inst; | |
917 | 946 | |||
918 | return (i.JType.op == OP_SPECIAL && i.RType.func == OP_JR && | 947 | return (i.JType.op == OP_SPECIAL && i.RType.func == OP_JR && | |
919 | i.RType.rs == 31); | 948 | i.RType.rs == 31); | |
920 | } | 949 | } | |
921 | 950 | |||
922 | /* | 951 | /* | |
923 | * Determine whether the instruction makes a jump. | 952 | * Determine whether the instruction makes a jump. | |
924 | */ | 953 | */ | |
925 | bool | 954 | bool | |
926 | inst_unconditional_flow_transfer(int inst) | 955 | inst_unconditional_flow_transfer(int inst) | |
927 | { | 956 | { | |
928 | InstFmt i; | 957 | InstFmt i; | |
929 | bool jump; | 958 | bool jump; | |
930 | 959 | |||
931 | i.word = inst; | 960 | i.word = inst; | |
932 | jump = (i.JType.op == OP_J) || | 961 | jump = (i.JType.op == OP_J) || | |
933 | (i.JType.op == OP_SPECIAL && i.RType.func == OP_JR); | 962 | (i.JType.op == OP_SPECIAL && i.RType.func == OP_JR); | |
934 | return jump; | 963 | return jump; | |
935 | } | 964 | } | |
936 | 965 | |||
937 | /* | 966 | /* | |
938 | * Determine whether the instruction is a load/store as appropriate. | 967 | * Determine whether the instruction is a load/store as appropriate. | |
939 | */ | 968 | */ | |
940 | bool | 969 | bool | |
941 | inst_load(int inst) | 970 | inst_load(int inst) | |
942 | { | 971 | { | |
943 | InstFmt i = { .word = inst, }; | 972 | InstFmt i = { .word = inst, }; | |
944 | 973 | |||
945 | /* | 974 | /* | |
946 | * All loads are opcodes 04x or 06x. | 975 | * All loads are opcodes 04x or 06x. | |
947 | */ | 976 | */ | |
948 | if ((i.JType.op & 050) != 040) | 977 | if ((i.JType.op & 050) != 040) | |
949 | return false; | 978 | return false; | |
950 | 979 | |||
951 | /* | 980 | /* | |
952 | * Except these this opcode is not a load. | 981 | * Except these this opcode is not a load. | |
953 | */ | 982 | */ | |
954 | return i.JType.op != OP_PREF; | 983 | return i.JType.op != OP_PREF; | |
955 | } | 984 | } | |
956 | 985 | |||
957 | bool | 986 | bool | |
958 | inst_store(int inst) | 987 | inst_store(int inst) | |
959 | { | 988 | { | |
960 | InstFmt i = { .word = inst, }; | 989 | InstFmt i = { .word = inst, }; | |
961 | 990 | |||
962 | /* | 991 | /* | |
963 | * All stores are opcodes 05x or 07x. | 992 | * All stores are opcodes 05x or 07x. | |
964 | */ | 993 | */ | |
965 | if ((i.JType.op & 050) != 050) | 994 | if ((i.JType.op & 050) != 050) | |
966 | return false; | 995 | return false; | |
967 | 996 | |||
968 | /* | 997 | /* | |
969 | * Except these two opcodes are not stores. | 998 | * Except these two opcodes are not stores. | |
970 | */ | 999 | */ | |
971 | return i.JType.op != OP_RSVD073 && i.JType.op != OP_CACHE; | 1000 | return i.JType.op != OP_RSVD073 && i.JType.op != OP_CACHE; | |
972 | } | 1001 | } | |
973 | 1002 | |||
974 | /* | 1003 | /* | |
975 | * Return the next pc if the given branch is taken. | 1004 | * Return the next pc if the given branch is taken. | |
976 | * mips_emul_branch() runs analysis for branch delay slot. | 1005 | * mips_emul_branch() runs analysis for branch delay slot. | |
977 | */ | 1006 | */ | |
978 | db_addr_t | 1007 | db_addr_t | |
979 | branch_taken(int inst, db_addr_t pc, db_regs_t *regs) | 1008 | branch_taken(int inst, db_addr_t pc, db_regs_t *regs) | |
980 | { | 1009 | { | |
981 | struct pcb * const pcb = lwp_getpcb(curlwp); | 1010 | struct pcb * const pcb = lwp_getpcb(curlwp); | |
982 | const uint32_t fpucsr = PCB_FSR(pcb); | 1011 | const uint32_t fpucsr = PCB_FSR(pcb); | |
983 | vaddr_t ra; | 1012 | vaddr_t ra; | |
984 | 1013 | |||
985 | ra = mips_emul_branch((struct trapframe *)regs, pc, fpucsr, false); | 1014 | ra = mips_emul_branch((struct trapframe *)regs, pc, fpucsr, false); | |
986 | return ra; | 1015 | return ra; | |
987 | } | 1016 | } | |
988 | 1017 | |||
989 | /* | 1018 | /* | |
990 | * Return the next pc of an arbitrary instruction. | 1019 | * Return the next pc of an arbitrary instruction. | |
991 | */ | 1020 | */ | |
992 | db_addr_t | 1021 | db_addr_t | |
993 | next_instr_address(db_addr_t pc, bool bd) | 1022 | next_instr_address(db_addr_t pc, bool bd) | |
994 | { | 1023 | { | |
995 | uint32_t ins; | 1024 | uint32_t ins; | |
996 | 1025 | |||
997 | if (bd == false) | 1026 | if (bd == false) | |
998 | return (pc + 4); | 1027 | return (pc + 4); | |
999 | 1028 | |||
1000 | if (pc < MIPS_KSEG0_START) | 1029 | if (pc < MIPS_KSEG0_START) | |
1001 | ins = mips_ufetch32((void *)pc); | 1030 | ins = mips_ufetch32((void *)pc); | |
1002 | else | 1031 | else | |
1003 | ins = *(uint32_t *)pc; | 1032 | ins = *(uint32_t *)pc; | |
1004 | 1033 | |||
1005 | if (inst_branch(ins) || inst_call(ins) || inst_return(ins)) | 1034 | if (inst_branch(ins) || inst_call(ins) || inst_return(ins)) | |
1006 | return (pc + 4); | 1035 | return (pc + 4); | |
1007 | 1036 | |||
1008 | return (pc); | 1037 | return (pc); | |
1009 | } | 1038 | } | |
1010 | 1039 | |||
1011 | #ifdef MULTIPROCESSOR | 1040 | #ifdef MULTIPROCESSOR | |
1012 | 1041 | |||
1013 | bool | 1042 | bool | |
1014 | ddb_running_on_this_cpu_p(void) | 1043 | ddb_running_on_this_cpu_p(void) | |
1015 | { | 1044 | { | |
1016 | return ddb_cpu == cpu_number(); | 1045 | return ddb_cpu == cpu_number(); | |
1017 | } | 1046 | } | |
1018 | 1047 | |||
1019 | bool | 1048 | bool | |
1020 | ddb_running_on_any_cpu_p(void) | 1049 | ddb_running_on_any_cpu_p(void) | |
1021 | { | 1050 | { | |
1022 | return ddb_cpu != NOCPU; | 1051 | return ddb_cpu != NOCPU; | |
1023 | } | 1052 | } | |
1024 | 1053 | |||
1025 | void | 1054 | void | |
1026 | db_resume_others(void) | 1055 | db_resume_others(void) | |
1027 | { | 1056 | { | |
1028 | u_int cpu_me = cpu_number(); | 1057 | u_int cpu_me = cpu_number(); | |
1029 | 1058 | |||
1030 | if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me) | 1059 | if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me) | |
1031 | cpu_resume_others(); | 1060 | cpu_resume_others(); | |
1032 | } | 1061 | } | |
1033 | 1062 | |||
1034 | static void | 1063 | static void | |
1035 | db_mach_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | 1064 | db_mach_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) | |
1036 | { | 1065 | { | |
1037 | CPU_INFO_ITERATOR cii; | 1066 | CPU_INFO_ITERATOR cii; | |
1038 | struct cpu_info *ci; | 1067 | struct cpu_info *ci; | |
1039 | 1068 | |||
1040 | if (!have_addr) { | 1069 | if (!have_addr) { | |
1041 | cpu_debug_dump(); | 1070 | cpu_debug_dump(); | |
1042 | return; | 1071 | return; | |
1043 | } | 1072 | } | |
1044 | for (CPU_INFO_FOREACH(cii, ci)) { | 1073 | for (CPU_INFO_FOREACH(cii, ci)) { | |
1045 | if (cpu_index(ci) == addr) | 1074 | if (cpu_index(ci) == addr) | |
1046 | break; | 1075 | break; | |
1047 | } | 1076 | } | |
1048 | if (ci == NULL) { | 1077 | if (ci == NULL) { | |
1049 | db_printf("CPU %ld not configured\n", (long)addr); | 1078 | db_printf("CPU %ld not configured\n", (long)addr); | |
1050 | return; | 1079 | return; | |
1051 | } | 1080 | } | |
1052 | if (ci != curcpu()) { | 1081 | if (ci != curcpu()) { | |
1053 | if (!cpu_is_paused(cpu_index(ci))) { | 1082 | if (!cpu_is_paused(cpu_index(ci))) { | |
1054 | db_printf("CPU %ld not paused\n", (long)addr); | 1083 | db_printf("CPU %ld not paused\n", (long)addr); | |
1055 | return; | 1084 | return; | |
1056 | } | 1085 | } | |
1057 | (void)atomic_cas_uint(&ddb_cpu, cpu_number(), cpu_index(ci)); | 1086 | (void)atomic_cas_uint(&ddb_cpu, cpu_number(), cpu_index(ci)); | |
1058 | db_continue_cmd(0, false, 0, ""); | 1087 | db_continue_cmd(0, false, 0, ""); | |
1059 | } | 1088 | } | |
1060 | } | 1089 | } | |
1061 | #endif /* MULTIPROCESSOR */ | 1090 | #endif /* MULTIPROCESSOR */ | |
1062 | 1091 | |||
1063 | #endif /* _KERNEL */ | 1092 | #endif /* _KERNEL */ |
--- src/sys/arch/riscv/riscv/db_disasm.c 2021/05/01 06:48:51 1.7
+++ src/sys/arch/riscv/riscv/db_disasm.c 2021/05/23 23:22:55 1.8
@@ -1,1503 +1,1497 @@ | @@ -1,1503 +1,1497 @@ | |||
1 | /* $NetBSD: db_disasm.c,v 1.7 2021/05/01 06:48:51 skrll Exp $ */ | 1 | /* $NetBSD: db_disasm.c,v 1.8 2021/05/23 23:22:55 dholland Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Matt Thomas of 3am Software Foundry. | 8 | * by Matt Thomas of 3am Software Foundry. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | 33 | |||
34 | __RCSID("$NetBSD: db_disasm.c,v 1.7 2021/05/01 06:48:51 skrll Exp $"); | 34 | __RCSID("$NetBSD: db_disasm.c,v 1.8 2021/05/23 23:22:55 dholland Exp $"); | |
35 | 35 | |||
36 | #include <sys/param.h> | 36 | #include <sys/param.h> | |
37 | #include <sys/systm.h> | 37 | #include <sys/systm.h> | |
38 | 38 | |||
39 | #include <riscv/db_machdep.h> | 39 | #include <riscv/db_machdep.h> | |
40 | #include <riscv/insn.h> | 40 | #include <riscv/insn.h> | |
41 | 41 | |||
42 | #include <ddb/db_access.h> | |||
42 | #include <ddb/db_user.h> | 43 | #include <ddb/db_user.h> | |
43 | #include <ddb/db_interface.h> | 44 | #include <ddb/db_interface.h> | |
44 | #include <ddb/db_output.h> | 45 | #include <ddb/db_output.h> | |
45 | #include <ddb/db_extern.h> | 46 | #include <ddb/db_extern.h> | |
46 | #include <ddb/db_sym.h> | 47 | #include <ddb/db_sym.h> | |
47 | 48 | |||
48 | //////////////////////////////////////////////////////////// | 49 | //////////////////////////////////////////////////////////// | |
49 | // registers | 50 | // registers | |
50 | 51 | |||
51 | static const char *riscv_registers[32] = { | 52 | static const char *riscv_registers[32] = { | |
52 | "zero", "ra", "sp", "gp", "tp", | 53 | "zero", "ra", "sp", "gp", "tp", | |
53 | "t0", "t1", "t2", | 54 | "t0", "t1", "t2", | |
54 | "s0", "s1", | 55 | "s0", "s1", | |
55 | "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", | 56 | "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", | |
56 | "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", | 57 | "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", | |
57 | "t3", "t4", "t5", "t6" | 58 | "t3", "t4", "t5", "t6" | |
58 | }; | 59 | }; | |
59 | 60 | |||
60 | /* XXX this should be in MI ddb */ | 61 | /* XXX this should be in MI ddb */ | |
61 | static void | 62 | static void | |
62 | db_print_addr(db_addr_t loc) | 63 | db_print_addr(db_addr_t loc) | |
63 | { | 64 | { | |
64 | db_expr_t diff; | 65 | db_expr_t diff; | |
65 | db_sym_t sym; | 66 | db_sym_t sym; | |
66 | const char *symname; | 67 | const char *symname; | |
67 | 68 | |||
68 | /* hack for testing since the test program is ASLR'd */ | 69 | /* hack for testing since the test program is ASLR'd */ | |
69 | #ifndef _KERNEL | 70 | #ifndef _KERNEL | |
70 | loc &= 0xfff; | 71 | loc &= 0xfff; | |
71 | #endif | 72 | #endif | |
72 | 73 | |||
73 | diff = INT_MAX; | 74 | diff = INT_MAX; | |
74 | symname = NULL; | 75 | symname = NULL; | |
75 | sym = db_search_symbol(loc, DB_STGY_ANY, &diff); | 76 | sym = db_search_symbol(loc, DB_STGY_ANY, &diff); | |
76 | db_symbol_values(sym, &symname, 0); | 77 | db_symbol_values(sym, &symname, 0); | |
77 | 78 | |||
78 | if (symname) { | 79 | if (symname) { | |
79 | if (diff == 0) | 80 | if (diff == 0) | |
80 | db_printf("%s", symname); | 81 | db_printf("%s", symname); | |
81 | else | 82 | else | |
82 | db_printf("<%s+%"DDB_EXPR_FMT"x>", symname, diff); | 83 | db_printf("<%s+%"DDB_EXPR_FMT"x>", symname, diff); | |
83 | db_printf("\t[addr:%#"PRIxVADDR"]", loc); | 84 | db_printf("\t[addr:%#"PRIxVADDR"]", loc); | |
84 | } else { | 85 | } else { | |
85 | db_printf("%#"PRIxVADDR, loc); | 86 | db_printf("%#"PRIxVADDR, loc); | |
86 | } | 87 | } | |
87 | } | 88 | } | |
88 | 89 | |||
89 | //////////////////////////////////////////////////////////// | 90 | //////////////////////////////////////////////////////////// | |
90 | // 16-bit instructions | 91 | // 16-bit instructions | |
91 | 92 | |||
92 | /* | 93 | /* | |
93 | * This is too tightly wedged in to make it worth trying to make it | 94 | * This is too tightly wedged in to make it worth trying to make it | |
94 | * table-driven. But I'm going to hack it up to use a 1-level switch. | 95 | * table-driven. But I'm going to hack it up to use a 1-level switch. | |
95 | * | 96 | * | |
96 | * Note that quite a few instructions depend on the architecture word | 97 | * Note that quite a few instructions depend on the architecture word | |
97 | * size. I've used the #defines for that to conditionalize it, on the | 98 | * size. I've used the #defines for that to conditionalize it, on the | |
98 | * grounds that ddb is disassembling itself so the build machine | 99 | * grounds that ddb is disassembling itself so the build machine | |
99 | * version is the target machine version. This is not true for crash | 100 | * version is the target machine version. This is not true for crash | |
100 | * necessarily but I don't think | 101 | * necessarily but I don't think | |
101 | */ | 102 | */ | |
102 | 103 | |||
103 | #define COMBINE(op, q) (((op) << 2) | (q)) | 104 | #define COMBINE(op, q) (((op) << 2) | (q)) | |
104 | 105 | |||
105 | #define IN_Q0(op) COMBINE(op, OPCODE16_Q0) | 106 | #define IN_Q0(op) COMBINE(op, OPCODE16_Q0) | |
106 | #define IN_Q1(op) COMBINE(op, OPCODE16_Q1) | 107 | #define IN_Q1(op) COMBINE(op, OPCODE16_Q1) | |
107 | #define IN_Q2(op) COMBINE(op, OPCODE16_Q2) | 108 | #define IN_Q2(op) COMBINE(op, OPCODE16_Q2) | |
108 | 109 | |||
109 | /* | 110 | /* | |
110 | * All the 16-bit immediate bit-wrangling is done in uint32_t, which | 111 | * All the 16-bit immediate bit-wrangling is done in uint32_t, which | |
111 | * is sufficient, but on RV64 the resulting values should be printed | 112 | * is sufficient, but on RV64 the resulting values should be printed | |
112 | * as 64-bit. Continuing the assumption that we're disassembling for | 113 | * as 64-bit. Continuing the assumption that we're disassembling for | |
113 | * the size we're built on, do nothing for RV32 and sign-extend from | 114 | * the size we're built on, do nothing for RV32 and sign-extend from | |
114 | * 32 to 64 for RV64. (And bail on RV128 since it's not clear what | 115 | * 32 to 64 for RV64. (And bail on RV128 since it's not clear what | |
115 | * the C type sizes are going to be there anyway...) | 116 | * the C type sizes are going to be there anyway...) | |
116 | */ | 117 | */ | |
117 | static unsigned long | 118 | static unsigned long | |
118 | maybe_signext64(uint32_t x) | 119 | maybe_signext64(uint32_t x) | |
119 | { | 120 | { | |
120 | #if __riscv_xlen == 32 | 121 | #if __riscv_xlen == 32 | |
121 | return x; | 122 | return x; | |
122 | #elif __riscv_xlen == 64 | 123 | #elif __riscv_xlen == 64 | |
123 | uint64_t xx; | 124 | uint64_t xx; | |
124 | 125 | |||
125 | xx = ((x & 0x80000000) ? 0xffffffff00000000 : 0) | x; | 126 | xx = ((x & 0x80000000) ? 0xffffffff00000000 : 0) | x; | |
126 | return xx; | 127 | return xx; | |
127 | #else | 128 | #else | |
128 | #error Oops. | 129 | #error Oops. | |
129 | #endif | 130 | #endif | |
130 | } | 131 | } | |
131 | 132 | |||
132 | static int | 133 | static int | |
133 | db_disasm_16(db_addr_t loc, uint32_t insn, bool altfmt) | 134 | db_disasm_16(db_addr_t loc, uint32_t insn, bool altfmt) | |
134 | { | 135 | { | |
135 | /* note: insn needs to be uint32_t for immediate computations */ | 136 | /* note: insn needs to be uint32_t for immediate computations */ | |
136 | 137 | |||
137 | uint32_t imm; | 138 | uint32_t imm; | |
138 | unsigned rd, rs1, rs2; | 139 | unsigned rd, rs1, rs2; | |
139 | 140 | |||
140 | //warnx("toot 0x%x", insn); | 141 | //warnx("toot 0x%x", insn); | |
141 | switch (COMBINE(INSN16_FUNCT3(insn), INSN16_QUADRANT(insn))) { | 142 | switch (COMBINE(INSN16_FUNCT3(insn), INSN16_QUADRANT(insn))) { | |
142 | case IN_Q0(Q0_ADDI4SPN): | 143 | case IN_Q0(Q0_ADDI4SPN): | |
143 | rd = INSN16_RS2x(insn); | 144 | rd = INSN16_RS2x(insn); | |
144 | imm = INSN16_IMM_CIW(insn); | 145 | imm = INSN16_IMM_CIW(insn); | |
145 | if (imm == 0) { | 146 | if (imm == 0) { | |
146 | /* reserved (all bits 0 -> invalid) */ | 147 | /* reserved (all bits 0 -> invalid) */ | |
147 | return EINVAL; | 148 | return EINVAL; | |
148 | } | 149 | } | |
149 | db_printf("c.addi4spn %s, 0x%x\n", riscv_registers[rd], imm); | 150 | db_printf("c.addi4spn %s, 0x%x\n", riscv_registers[rd], imm); | |
150 | break; | 151 | break; | |
151 | case IN_Q0(Q0_FLD_LQ): | 152 | case IN_Q0(Q0_FLD_LQ): | |
152 | rs1 = INSN16_RS1x(insn); | 153 | rs1 = INSN16_RS1x(insn); | |
153 | rd = INSN16_RS2x(insn); | 154 | rd = INSN16_RS2x(insn); | |
154 | #if __riscv_xlen < 128 | 155 | #if __riscv_xlen < 128 | |
155 | imm = INSN16_IMM_CL_D(insn); | 156 | imm = INSN16_IMM_CL_D(insn); | |
156 | db_printf("c.fld f%d, %d(%s)\n", rd, (int32_t)imm, | 157 | db_printf("c.fld f%d, %d(%s)\n", rd, (int32_t)imm, | |
157 | riscv_registers[rs1]); | 158 | riscv_registers[rs1]); | |
158 | #else | 159 | #else | |
159 | imm = INSN16_IMM_CL_Q(insn); | 160 | imm = INSN16_IMM_CL_Q(insn); | |
160 | db_printf("c.lq %s, %d(%s)\n", riscv_registers[rd], | 161 | db_printf("c.lq %s, %d(%s)\n", riscv_registers[rd], | |
161 | (int32_t)imm, riscv_registers[rs1]); | 162 | (int32_t)imm, riscv_registers[rs1]); | |
162 | #endif | 163 | #endif | |
163 | break; | 164 | break; | |
164 | case IN_Q0(Q0_LW): | 165 | case IN_Q0(Q0_LW): | |
165 | rs1 = INSN16_RS1x(insn); | 166 | rs1 = INSN16_RS1x(insn); | |
166 | rd = INSN16_RS2x(insn); | 167 | rd = INSN16_RS2x(insn); | |
167 | imm = INSN16_IMM_CL_W(insn); | 168 | imm = INSN16_IMM_CL_W(insn); | |
168 | db_printf("c.lw %s, %d(%s)\n", riscv_registers[rd], | 169 | db_printf("c.lw %s, %d(%s)\n", riscv_registers[rd], | |
169 | (int32_t)imm, riscv_registers[rs1]); | 170 | (int32_t)imm, riscv_registers[rs1]); | |
170 | break; | 171 | break; | |
171 | case IN_Q0(Q0_FLW_LD): | 172 | case IN_Q0(Q0_FLW_LD): | |
172 | rs1 = INSN16_RS1x(insn); | 173 | rs1 = INSN16_RS1x(insn); | |
173 | rd = INSN16_RS2x(insn); | 174 | rd = INSN16_RS2x(insn); | |
174 | #if __riscv_xlen == 32 | 175 | #if __riscv_xlen == 32 | |
175 | imm = INSN16_IMM_CL_W(insn); | 176 | imm = INSN16_IMM_CL_W(insn); | |
176 | db_printf("c.flw f%d, %d(%s)\n", rd, (int32_t)imm, | 177 | db_printf("c.flw f%d, %d(%s)\n", rd, (int32_t)imm, | |
177 | riscv_registers[rs1]); | 178 | riscv_registers[rs1]); | |
178 | #else | 179 | #else | |
179 | imm = INSN16_IMM_CL_D(insn); | 180 | imm = INSN16_IMM_CL_D(insn); | |
180 | db_printf("c.ld %s, %d(%s)\n", riscv_registers[rd], | 181 | db_printf("c.ld %s, %d(%s)\n", riscv_registers[rd], | |
181 | (int32_t)imm, riscv_registers[rs1]); | 182 | (int32_t)imm, riscv_registers[rs1]); | |
182 | #endif | 183 | #endif | |
183 | break; | 184 | break; | |
184 | case IN_Q0(Q0_FSD_SQ): | 185 | case IN_Q0(Q0_FSD_SQ): | |
185 | rs1 = INSN16_RS1x(insn); | 186 | rs1 = INSN16_RS1x(insn); | |
186 | rs2 = INSN16_RS2x(insn); | 187 | rs2 = INSN16_RS2x(insn); | |
187 | #if __riscv_xlen < 128 | 188 | #if __riscv_xlen < 128 | |
188 | imm = INSN16_IMM_CS_D(insn); | 189 | imm = INSN16_IMM_CS_D(insn); | |
189 | db_printf("c.fsd f%d, %d(%s)\n", rs2, (int32_t)imm, | 190 | db_printf("c.fsd f%d, %d(%s)\n", rs2, (int32_t)imm, | |
190 | riscv_registers[rs1]); | 191 | riscv_registers[rs1]); | |
191 | #else | 192 | #else | |
192 | imm = INSN16_IMM_CS_Q(insn); | 193 | imm = INSN16_IMM_CS_Q(insn); | |
193 | db_printf("c.sq %s, %d(%s)\n", riscv_registers[rs2], | 194 | db_printf("c.sq %s, %d(%s)\n", riscv_registers[rs2], | |
194 | (int32_t)imm, riscv_registers[rs1]); | 195 | (int32_t)imm, riscv_registers[rs1]); | |
195 | #endif | 196 | #endif | |
196 | break; | 197 | break; | |
197 | case IN_Q0(Q0_SW): | 198 | case IN_Q0(Q0_SW): | |
198 | rs1 = INSN16_RS1x(insn); | 199 | rs1 = INSN16_RS1x(insn); | |
199 | rs2 = INSN16_RS2x(insn); | 200 | rs2 = INSN16_RS2x(insn); | |
200 | imm = INSN16_IMM_CS_W(insn); | 201 | imm = INSN16_IMM_CS_W(insn); | |
201 | db_printf("c.sw %s, %d(%s)\n", riscv_registers[rs2], | 202 | db_printf("c.sw %s, %d(%s)\n", riscv_registers[rs2], | |
202 | (int32_t)imm, riscv_registers[rs1]); | 203 | (int32_t)imm, riscv_registers[rs1]); | |
203 | break; | 204 | break; | |
204 | case IN_Q0(Q0_FSW_SD): | 205 | case IN_Q0(Q0_FSW_SD): | |
205 | rs1 = INSN16_RS1x(insn); | 206 | rs1 = INSN16_RS1x(insn); | |
206 | rs2 = INSN16_RS2x(insn); | 207 | rs2 = INSN16_RS2x(insn); | |
207 | #if __riscv_xlen == 32 | 208 | #if __riscv_xlen == 32 | |
208 | imm = INSN16_IMM_CS_W(insn); | 209 | imm = INSN16_IMM_CS_W(insn); | |
209 | db_printf("c.fsw f%d, %d(%s)\n", rs2, (int32_t)imm, | 210 | db_printf("c.fsw f%d, %d(%s)\n", rs2, (int32_t)imm, | |
210 | riscv_registers[rs1]); | 211 | riscv_registers[rs1]); | |
211 | #else | 212 | #else | |
212 | imm = INSN16_IMM_CS_D(insn); | 213 | imm = INSN16_IMM_CS_D(insn); | |
213 | db_printf("c.sd %s, %d(%s)\n", riscv_registers[rs2], | 214 | db_printf("c.sd %s, %d(%s)\n", riscv_registers[rs2], | |
214 | (int32_t)imm, riscv_registers[rs1]); | 215 | (int32_t)imm, riscv_registers[rs1]); | |
215 | #endif | 216 | #endif | |
216 | break; | 217 | break; | |
217 | case IN_Q1(Q1_NOP_ADDI): | 218 | case IN_Q1(Q1_NOP_ADDI): | |
218 | rd = INSN16_RS1(insn); | 219 | rd = INSN16_RS1(insn); | |
219 | imm = INSN16_IMM_CI_K(insn); | 220 | imm = INSN16_IMM_CI_K(insn); | |
220 | if (rd == 0 && imm == 0) { | 221 | if (rd == 0 && imm == 0) { | |
221 | db_printf("c.nop\n"); | 222 | db_printf("c.nop\n"); | |
222 | } else if (rd == 0 && imm != 0) { | 223 | } else if (rd == 0 && imm != 0) { | |
223 | /* undefined hint */ | 224 | /* undefined hint */ | |
224 | return EINVAL; | 225 | return EINVAL; | |
225 | } else if (rd != 0 && imm == 0) { | 226 | } else if (rd != 0 && imm == 0) { | |
226 | /* undefined hint */ | 227 | /* undefined hint */ | |
227 | return EINVAL; | 228 | return EINVAL; | |
228 | } else { | 229 | } else { | |
229 | db_printf("c.addi %s, %s, 0x%lx\n", | 230 | db_printf("c.addi %s, %s, 0x%lx\n", | |
230 | riscv_registers[rd], | 231 | riscv_registers[rd], | |
231 | riscv_registers[rd], | 232 | riscv_registers[rd], | |
232 | maybe_signext64(imm)); | 233 | maybe_signext64(imm)); | |
233 | } | 234 | } | |
234 | break; | 235 | break; | |
235 | case IN_Q1(Q1_JAL_ADDIW): | 236 | case IN_Q1(Q1_JAL_ADDIW): | |
236 | #if __riscv_xlen == 32 | 237 | #if __riscv_xlen == 32 | |
237 | imm = INSN16_IMM_CJ(insn); | 238 | imm = INSN16_IMM_CJ(insn); | |
238 | db_printf("c.jal "); | 239 | db_printf("c.jal "); | |
239 | db_print_addr(loc + (int32_t)imm); | 240 | db_print_addr(loc + (int32_t)imm); | |
240 | db_printf("\n"); | 241 | db_printf("\n"); | |
241 | #else | 242 | #else | |
242 | rd = INSN16_RS1(insn); | 243 | rd = INSN16_RS1(insn); | |
243 | imm = INSN16_IMM_CI_K(insn); | 244 | imm = INSN16_IMM_CI_K(insn); | |
244 | db_printf("c.addiw %s, %s, 0x%lx\n", riscv_registers[rd], | 245 | db_printf("c.addiw %s, %s, 0x%lx\n", riscv_registers[rd], | |
245 | riscv_registers[rd], maybe_signext64(imm)); | 246 | riscv_registers[rd], maybe_signext64(imm)); | |
246 | #endif | 247 | #endif | |
247 | break; | 248 | break; | |
248 | case IN_Q1(Q1_LI): | 249 | case IN_Q1(Q1_LI): | |
249 | rd = INSN16_RS1(insn); | 250 | rd = INSN16_RS1(insn); | |
250 | imm = INSN16_IMM_CI_K(insn); | 251 | imm = INSN16_IMM_CI_K(insn); | |
251 | db_printf("c.li %s, 0x%lx\n", riscv_registers[rd], | 252 | db_printf("c.li %s, 0x%lx\n", riscv_registers[rd], | |
252 | maybe_signext64(imm)); | 253 | maybe_signext64(imm)); | |
253 | break; | 254 | break; | |
254 | case IN_Q1(Q1_ADDI16SP_LUI): | 255 | case IN_Q1(Q1_ADDI16SP_LUI): | |
255 | rd = INSN16_RS1(insn); | 256 | rd = INSN16_RS1(insn); | |
256 | if (rd == 2/*sp*/) { | 257 | if (rd == 2/*sp*/) { | |
257 | imm = INSN16_IMM_CI_K4(insn); | 258 | imm = INSN16_IMM_CI_K4(insn); | |
258 | db_printf("c.add16sp sp, 0x%lx\n", | 259 | db_printf("c.add16sp sp, 0x%lx\n", | |
259 | maybe_signext64(imm)); | 260 | maybe_signext64(imm)); | |
260 | } | 261 | } | |
261 | else { | 262 | else { | |
262 | imm = INSN16_IMM_CI_K12(insn); | 263 | imm = INSN16_IMM_CI_K12(insn); | |
263 | db_printf("c.lui %s, 0x%lx\n", riscv_registers[rd], | 264 | db_printf("c.lui %s, 0x%lx\n", riscv_registers[rd], | |
264 | maybe_signext64(imm)); | 265 | maybe_signext64(imm)); | |
265 | } | 266 | } | |
266 | break; | 267 | break; | |
267 | case IN_Q1(Q1_MISC): | 268 | case IN_Q1(Q1_MISC): | |
268 | imm = INSN16_IMM_CI_K(insn); | 269 | imm = INSN16_IMM_CI_K(insn); | |
269 | rd = INSN16_RS1x(insn); | 270 | rd = INSN16_RS1x(insn); | |
270 | switch (INSN16_FUNCT2a(insn)) { | 271 | switch (INSN16_FUNCT2a(insn)) { | |
271 | case Q1MISC_SRLI: | 272 | case Q1MISC_SRLI: | |
272 | case Q1MISC_SRAI: | 273 | case Q1MISC_SRAI: | |
273 | #if __riscv_xlen == 32 | 274 | #if __riscv_xlen == 32 | |
274 | if (imm > 31) { | 275 | if (imm > 31) { | |
275 | /* reserved */ | 276 | /* reserved */ | |
276 | return EINVAL; | 277 | return EINVAL; | |
277 | } | 278 | } | |
278 | #elif __riscv_xlen == 64 | 279 | #elif __riscv_xlen == 64 | |
279 | /* drop the sign-extension */ | 280 | /* drop the sign-extension */ | |
280 | imm &= 63; | 281 | imm &= 63; | |
281 | #elif __riscv_xlen == 128 | 282 | #elif __riscv_xlen == 128 | |
282 | if (imm == 0) { | 283 | if (imm == 0) { | |
283 | imm = 64; | 284 | imm = 64; | |
284 | } | 285 | } | |
285 | else { | 286 | else { | |
286 | imm &= 127; | 287 | imm &= 127; | |
287 | } | 288 | } | |
288 | #endif | 289 | #endif | |
289 | db_printf("c.%s %s, %d\n", | 290 | db_printf("c.%s %s, %d\n", | |
290 | INSN16_FUNCT2a(insn) == Q1MISC_SRLI ? | 291 | INSN16_FUNCT2a(insn) == Q1MISC_SRLI ? | |
291 | "srli" : "srai", | 292 | "srli" : "srai", | |
292 | riscv_registers[rd], imm); | 293 | riscv_registers[rd], imm); | |
293 | break; | 294 | break; | |
294 | case Q1MISC_ANDI: | 295 | case Q1MISC_ANDI: | |
295 | db_printf("c.andi %s, 0x%lx\n", riscv_registers[rd], | 296 | db_printf("c.andi %s, 0x%lx\n", riscv_registers[rd], | |
296 | maybe_signext64(imm)); | 297 | maybe_signext64(imm)); | |
297 | break; | 298 | break; | |
298 | case Q1MISC_MORE: | 299 | case Q1MISC_MORE: | |
299 | rs2 = INSN16_RS2x(insn); | 300 | rs2 = INSN16_RS2x(insn); | |
300 | switch (INSN16_FUNCT3c(insn)) { | 301 | switch (INSN16_FUNCT3c(insn)) { | |
301 | case Q1MORE_SUB: | 302 | case Q1MORE_SUB: | |
302 | db_printf("c.sub"); | 303 | db_printf("c.sub"); | |
303 | break; | 304 | break; | |
304 | case Q1MORE_XOR: | 305 | case Q1MORE_XOR: | |
305 | db_printf("c.xor"); | 306 | db_printf("c.xor"); | |
306 | break; | 307 | break; | |
307 | case Q1MORE_OR: | 308 | case Q1MORE_OR: | |
308 | db_printf("c.or"); | 309 | db_printf("c.or"); | |
309 | break; | 310 | break; | |
310 | case Q1MORE_AND: | 311 | case Q1MORE_AND: | |
311 | db_printf("c.and"); | 312 | db_printf("c.and"); | |
312 | break; | 313 | break; | |
313 | case Q1MORE_SUBW: | 314 | case Q1MORE_SUBW: | |
314 | db_printf("c.subw"); | 315 | db_printf("c.subw"); | |
315 | break; | 316 | break; | |
316 | case Q1MORE_ADDW: | 317 | case Q1MORE_ADDW: | |
317 | db_printf("c.addw"); | 318 | db_printf("c.addw"); | |
318 | break; | 319 | break; | |
319 | default: | 320 | default: | |
320 | return EINVAL; | 321 | return EINVAL; | |
321 | } | 322 | } | |
322 | db_printf(" %s, %s, %s\n", riscv_registers[rd], | 323 | db_printf(" %s, %s, %s\n", riscv_registers[rd], | |
323 | riscv_registers[rd], riscv_registers[rs2]); | 324 | riscv_registers[rd], riscv_registers[rs2]); | |
324 | break; | 325 | break; | |
325 | } | 326 | } | |
326 | break; | 327 | break; | |
327 | case IN_Q1(Q1_J): | 328 | case IN_Q1(Q1_J): | |
328 | imm = INSN16_IMM_CJ(insn); | 329 | imm = INSN16_IMM_CJ(insn); | |
329 | db_printf("c.j "); | 330 | db_printf("c.j "); | |
330 | db_print_addr(loc + (int32_t)imm); | 331 | db_print_addr(loc + (int32_t)imm); | |
331 | db_printf("\n"); | 332 | db_printf("\n"); | |
332 | break; | 333 | break; | |
333 | case IN_Q1(Q1_BEQZ): | 334 | case IN_Q1(Q1_BEQZ): | |
334 | rs1 = INSN16_RS1x(insn); | 335 | rs1 = INSN16_RS1x(insn); | |
335 | imm = INSN16_IMM_CB(insn); | 336 | imm = INSN16_IMM_CB(insn); | |
336 | db_printf("c.beqz %s, ", riscv_registers[rs1]); | 337 | db_printf("c.beqz %s, ", riscv_registers[rs1]); | |
337 | db_print_addr(loc + (int32_t)imm); | 338 | db_print_addr(loc + (int32_t)imm); | |
338 | db_printf("\n"); | 339 | db_printf("\n"); | |
339 | break; | 340 | break; | |
340 | case IN_Q1(Q1_BNEZ): | 341 | case IN_Q1(Q1_BNEZ): | |
341 | rs1 = INSN16_RS1x(insn); | 342 | rs1 = INSN16_RS1x(insn); | |
342 | imm = INSN16_IMM_CB(insn); | 343 | imm = INSN16_IMM_CB(insn); | |
343 | db_printf("c.bnez %s, ", riscv_registers[rs1]); | 344 | db_printf("c.bnez %s, ", riscv_registers[rs1]); | |
344 | db_print_addr(loc + (int32_t)imm); | 345 | db_print_addr(loc + (int32_t)imm); | |
345 | db_printf("\n"); | 346 | db_printf("\n"); | |
346 | break; | 347 | break; | |
347 | case IN_Q2(Q2_SLLI): | 348 | case IN_Q2(Q2_SLLI): | |
348 | rd = INSN16_RS1(insn); | 349 | rd = INSN16_RS1(insn); | |
349 | imm = INSN16_IMM_CI_K(insn); | 350 | imm = INSN16_IMM_CI_K(insn); | |
350 | #if __riscv_xlen == 32 | 351 | #if __riscv_xlen == 32 | |
351 | if (imm > 31) { | 352 | if (imm > 31) { | |
352 | /* reserved */ | 353 | /* reserved */ | |
353 | return EINVAL; | 354 | return EINVAL; | |
354 | } | 355 | } | |
355 | #elif __riscv_xlen == 64 | 356 | #elif __riscv_xlen == 64 | |
356 | /* drop the sign-extension */ | 357 | /* drop the sign-extension */ | |
357 | imm &= 63; | 358 | imm &= 63; | |
358 | #elif __riscv_xlen == 128 | 359 | #elif __riscv_xlen == 128 | |
359 | if (imm == 0) { | 360 | if (imm == 0) { | |
360 | imm = 64; | 361 | imm = 64; | |
361 | } | 362 | } | |
362 | else { | 363 | else { | |
363 | /* | 364 | /* | |
364 | * XXX the manual is not clear on | 365 | * XXX the manual is not clear on | |
365 | * whether this is like c.srli/c.srai | 366 | * whether this is like c.srli/c.srai | |
366 | * or truncates to 6 bits. I'm assuming | 367 | * or truncates to 6 bits. I'm assuming | |
367 | * the former. | 368 | * the former. | |
368 | */ | 369 | */ | |
369 | imm &= 127; | 370 | imm &= 127; | |
370 | } | 371 | } | |
371 | #endif | 372 | #endif | |
372 | db_printf("c.slli %s, %d\n", riscv_registers[rd], imm); | 373 | db_printf("c.slli %s, %d\n", riscv_registers[rd], imm); | |
373 | break; | 374 | break; | |
374 | case IN_Q2(Q2_FLDSP_LQSP): | 375 | case IN_Q2(Q2_FLDSP_LQSP): | |
375 | rd = INSN16_RS1(insn); | 376 | rd = INSN16_RS1(insn); | |
376 | #if __riscv_xlen < 128 | 377 | #if __riscv_xlen < 128 | |
377 | imm = INSN16_IMM_CI_D(insn); | 378 | imm = INSN16_IMM_CI_D(insn); | |
378 | db_printf("c.fldsp f%d, %d(sp)\n", rd, imm); | 379 | db_printf("c.fldsp f%d, %d(sp)\n", rd, imm); | |
379 | #else | 380 | #else | |
380 | if (rd == 0) { | 381 | if (rd == 0) { | |
381 | /* reserved */ | 382 | /* reserved */ | |
382 | return EINVAL; | 383 | return EINVAL; | |
383 | } | 384 | } | |
384 | imm = INSN16_IMM_CI_Q(insn); | 385 | imm = INSN16_IMM_CI_Q(insn); | |
385 | db_printf("c.lqsp %s, %d(sp)\n", riscv_registers[rd], imm); | 386 | db_printf("c.lqsp %s, %d(sp)\n", riscv_registers[rd], imm); | |
386 | #endif | 387 | #endif | |
387 | break; | 388 | break; | |
388 | case IN_Q2(Q2_LWSP): | 389 | case IN_Q2(Q2_LWSP): | |
389 | rd = INSN16_RS1(insn); | 390 | rd = INSN16_RS1(insn); | |
390 | if (rd == 0) { | 391 | if (rd == 0) { | |
391 | /* reserved */ | 392 | /* reserved */ | |
392 | return EINVAL; | 393 | return EINVAL; | |
393 | } | 394 | } | |
394 | imm = INSN16_IMM_CI_W(insn); | 395 | imm = INSN16_IMM_CI_W(insn); | |
395 | db_printf("c.lwsp %s, %d(sp)\n", riscv_registers[rd], imm); | 396 | db_printf("c.lwsp %s, %d(sp)\n", riscv_registers[rd], imm); | |
396 | break; | 397 | break; | |
397 | case IN_Q2(Q2_FLWSP_LDSP): | 398 | case IN_Q2(Q2_FLWSP_LDSP): | |
398 | rd = INSN16_RS1(insn); | 399 | rd = INSN16_RS1(insn); | |
399 | #if __riscv_xlen == 32 | 400 | #if __riscv_xlen == 32 | |
400 | imm = INSN16_IMM_CI_W(insn); | 401 | imm = INSN16_IMM_CI_W(insn); | |
401 | db_printf("c.flwsp f%d, %d(sp)\n", rd, imm); | 402 | db_printf("c.flwsp f%d, %d(sp)\n", rd, imm); | |
402 | #else | 403 | #else | |
403 | if (rd == 0) { | 404 | if (rd == 0) { | |
404 | /* reserved */ | 405 | /* reserved */ | |
405 | return EINVAL; | 406 | return EINVAL; | |
406 | } | 407 | } | |
407 | imm = INSN16_IMM_CI_D(insn); | 408 | imm = INSN16_IMM_CI_D(insn); | |
408 | db_printf("c.ldsp %s, %d(sp)\n", riscv_registers[rd], imm); | 409 | db_printf("c.ldsp %s, %d(sp)\n", riscv_registers[rd], imm); | |
409 | #endif | 410 | #endif | |
410 | break; | 411 | break; | |
411 | case IN_Q2(Q2_MISC): | 412 | case IN_Q2(Q2_MISC): | |
412 | rs1 = INSN16_RS1(insn); | 413 | rs1 = INSN16_RS1(insn); | |
413 | rs2 = INSN16_RS2(insn); | 414 | rs2 = INSN16_RS2(insn); | |
414 | switch (INSN16_FUNCT1b(insn)) { | 415 | switch (INSN16_FUNCT1b(insn)) { | |
415 | case Q2MISC_JR_MV: | 416 | case Q2MISC_JR_MV: | |
416 | if (rs1 == 0) { | 417 | if (rs1 == 0) { | |
417 | return EINVAL; | 418 | return EINVAL; | |
418 | } else if (rs2 == 0) { | 419 | } else if (rs2 == 0) { | |
419 | db_printf("c.jr %s\n", riscv_registers[rs1]); | 420 | db_printf("c.jr %s\n", riscv_registers[rs1]); | |
420 | } else { | 421 | } else { | |
421 | db_printf("c.mv %s, %s\n", | 422 | db_printf("c.mv %s, %s\n", | |
422 | riscv_registers[rs1], | 423 | riscv_registers[rs1], | |
423 | riscv_registers[rs2]); | 424 | riscv_registers[rs2]); | |
424 | } | 425 | } | |
425 | break; | 426 | break; | |
426 | case Q2MISC_EBREAK_JALR_ADD: | 427 | case Q2MISC_EBREAK_JALR_ADD: | |
427 | if (rs1 == 0 && rs2 == 0) { | 428 | if (rs1 == 0 && rs2 == 0) { | |
428 | db_printf("c.ebreak\n"); | 429 | db_printf("c.ebreak\n"); | |
429 | } else if (rs2 == 0) { | 430 | } else if (rs2 == 0) { | |
430 | db_printf("c.jalr %s\n", riscv_registers[rs1]); | 431 | db_printf("c.jalr %s\n", riscv_registers[rs1]); | |
431 | } else if (rs1 == 0) { | 432 | } else if (rs1 == 0) { | |
432 | return EINVAL; | 433 | return EINVAL; | |
433 | } else { | 434 | } else { | |
434 | db_printf("c.add %s, %s, %s\n", | 435 | db_printf("c.add %s, %s, %s\n", | |
435 | riscv_registers[rs1], | 436 | riscv_registers[rs1], | |
436 | riscv_registers[rs1], | 437 | riscv_registers[rs1], | |
437 | riscv_registers[rs2]); | 438 | riscv_registers[rs2]); | |
438 | } | 439 | } | |
439 | break; | 440 | break; | |
440 | } | 441 | } | |
441 | break; | 442 | break; | |
442 | case IN_Q2(Q2_FSDSP_SQSP): | 443 | case IN_Q2(Q2_FSDSP_SQSP): | |
443 | rs2 = INSN16_RS2(insn); | 444 | rs2 = INSN16_RS2(insn); | |
444 | #if __riscv_xlen < 128 | 445 | #if __riscv_xlen < 128 | |
445 | imm = INSN16_IMM_CSS_D(insn); | 446 | imm = INSN16_IMM_CSS_D(insn); | |
446 | db_printf("c.fsdsp f%d, %d(sp)\n", rs2, imm); | 447 | db_printf("c.fsdsp f%d, %d(sp)\n", rs2, imm); | |
447 | #else | 448 | #else | |
448 | imm = INSN16_IMM_CSS_Q(insn); | 449 | imm = INSN16_IMM_CSS_Q(insn); | |
449 | db_printf("c.sqsp %s, %d(sp)\n", riscv_registers[rs2], imm); | 450 | db_printf("c.sqsp %s, %d(sp)\n", riscv_registers[rs2], imm); | |
450 | #endif | 451 | #endif | |
451 | break; | 452 | break; | |
452 | case IN_Q2(Q2_SWSP): | 453 | case IN_Q2(Q2_SWSP): | |
453 | rs2 = INSN16_RS2(insn); | 454 | rs2 = INSN16_RS2(insn); | |
454 | imm = INSN16_IMM_CSS_W(insn); | 455 | imm = INSN16_IMM_CSS_W(insn); | |
455 | db_printf("c.swsp %s, %d(sp)\n", riscv_registers[rs2], imm); | 456 | db_printf("c.swsp %s, %d(sp)\n", riscv_registers[rs2], imm); | |
456 | break; | 457 | break; | |
457 | case IN_Q2(Q2_FSWSP_SDSP): | 458 | case IN_Q2(Q2_FSWSP_SDSP): | |
458 | rs2 = INSN16_RS2(insn); | 459 | rs2 = INSN16_RS2(insn); | |
459 | #if __riscv_xlen == 32 | 460 | #if __riscv_xlen == 32 | |
460 | imm = INSN16_IMM_CSS_W(insn); | 461 | imm = INSN16_IMM_CSS_W(insn); | |
461 | db_printf("c.fswsp f%d, %d(sp)\n", rs2, imm); | 462 | db_printf("c.fswsp f%d, %d(sp)\n", rs2, imm); | |
462 | #else | 463 | #else | |
463 | imm = INSN16_IMM_CSS_D(insn); | 464 | imm = INSN16_IMM_CSS_D(insn); | |
464 | db_printf("c.sdsp %s, %d(sp)\n", riscv_registers[rs2], imm); | 465 | db_printf("c.sdsp %s, %d(sp)\n", riscv_registers[rs2], imm); | |
465 | #endif | 466 | #endif | |
466 | break; | 467 | break; | |
467 | default: | 468 | default: | |
468 | /* 0b11 marks 32-bit instructions and shouldn't come here */ | 469 | /* 0b11 marks 32-bit instructions and shouldn't come here */ | |
469 | KASSERT(INSN16_QUADRANT(insn) != 0b11); | 470 | KASSERT(INSN16_QUADRANT(insn) != 0b11); | |
470 | return EINVAL; | 471 | return EINVAL; | |
471 | } | 472 | } | |
472 | return 0; | 473 | return 0; | |
473 | } | 474 | } | |
474 | 475 | |||
475 | //////////////////////////////////////////////////////////// | 476 | //////////////////////////////////////////////////////////// | |
476 | // 32-bit instructions | 477 | // 32-bit instructions | |
477 | 478 | |||
478 | /* match flags */ | 479 | /* match flags */ | |
479 | #define CHECK_F3 0x0001 /* check funct3 field */ | 480 | #define CHECK_F3 0x0001 /* check funct3 field */ | |
480 | #define CHECK_F7 0x0002 /* check funct7 field */ | 481 | #define CHECK_F7 0x0002 /* check funct7 field */ | |
481 | #define CHECK_F5 0x0004 /* check tpo of funct7 field only */ | 482 | #define CHECK_F5 0x0004 /* check tpo of funct7 field only */ | |
482 | #define CHECK_RS2 0x0008 /* check rs2 as quaternary opcode */ | 483 | #define CHECK_RS2 0x0008 /* check rs2 as quaternary opcode */ | |
483 | #define SHIFT32 0x0010 /* 32-bit immediate shift */ | 484 | #define SHIFT32 0x0010 /* 32-bit immediate shift */ | |
484 | #define SHIFT64 0x0020 /* 64-bit immediate shift */ | 485 | #define SHIFT64 0x0020 /* 64-bit immediate shift */ | |
485 | #define RD_0 0x0040 /* rd field should be 0 */ | 486 | #define RD_0 0x0040 /* rd field should be 0 */ | |
486 | #define RS1_0 0x0080 /* rs1 field should be 0 */ | 487 | #define RS1_0 0x0080 /* rs1 field should be 0 */ | |
487 | #define RS2_0 0x0100 /* rs2 field should be 0 */ | 488 | #define RS2_0 0x0100 /* rs2 field should be 0 */ | |
488 | #define IMM_0 0x0200 /* immediate value should be 0 */ | 489 | #define IMM_0 0x0200 /* immediate value should be 0 */ | |
489 | #define F3AMO 0x0400 /* expect amo size in funct3 */ | 490 | #define F3AMO 0x0400 /* expect amo size in funct3 */ | |
490 | #define F3ROUND 0x0800 /* expect fp rounding mode in funct3 */ | 491 | #define F3ROUND 0x0800 /* expect fp rounding mode in funct3 */ | |
491 | #define F7SIZE 0x1000 /* expect fp size in funct7:0-1 */ | 492 | #define F7SIZE 0x1000 /* expect fp size in funct7:0-1 */ | |
492 | #define RS2_FSIZE 0x2000 /* expect fp size in rs2 */ | 493 | #define RS2_FSIZE 0x2000 /* expect fp size in rs2 */ | |
493 | #define RS2_FSIZE_INT 0x4000 /* expect fp size in rs2 */ | 494 | #define RS2_FSIZE_INT 0x4000 /* expect fp size in rs2 */ | |
494 | #define FENCEFM 0x8000 /* fence mode in top 4 bits of imm */ | 495 | #define FENCEFM 0x8000 /* fence mode in top 4 bits of imm */ | |
495 | /* do not add more without increasing the field size below */ | 496 | /* do not add more without increasing the field size below */ | |
496 | 497 | |||
497 | #ifdef _LP64 /* disassembling ourself so can use our build flags... */ | 498 | #ifdef _LP64 /* disassembling ourself so can use our build flags... */ | |
498 | #define SHIFTNATIVE SHIFT64 | 499 | #define SHIFTNATIVE SHIFT64 | |
499 | #else | 500 | #else | |
500 | #define SHIFTNATIVE SHIFT32 | 501 | #define SHIFTNATIVE SHIFT32 | |
501 | #endif | 502 | #endif | |
502 | 503 | |||
503 | /* print flags */ | 504 | /* print flags */ | |
504 | #define MEMORYIMM 0x001 /* print immediate as 0(reg) */ | 505 | #define MEMORYIMM 0x001 /* print immediate as 0(reg) */ | |
505 | #define FENCEIMM 0x002 /* print fence instruction codes */ | 506 | #define FENCEIMM 0x002 /* print fence instruction codes */ | |
506 | #define DECIMM 0x004 /* print immediate in decimal */ | 507 | #define DECIMM 0x004 /* print immediate in decimal */ | |
507 | #define BRANCHIMM 0x008 /* print immediate as branch target */ | 508 | #define BRANCHIMM 0x008 /* print immediate as branch target */ | |
508 | #define CSRIMM 0x010 /* immediate is csr number */ | 509 | #define CSRIMM 0x010 /* immediate is csr number */ | |
509 | #define CSRIIMM 0x020 /* ... also an immediate in rs1 */ | 510 | #define CSRIIMM 0x020 /* ... also an immediate in rs1 */ | |
510 | #define AMOAQRL 0x040 /* print acquire/release bits of amo */ | 511 | #define AMOAQRL 0x040 /* print acquire/release bits of amo */ | |
511 | #define RS2SIZE_FIRST 0x080 /* print rs2 size before funct7 size */ | 512 | #define RS2SIZE_FIRST 0x080 /* print rs2 size before funct7 size */ | |
512 | #define RD_FREG 0x100 /* rd is a fpu reg */ | 513 | #define RD_FREG 0x100 /* rd is a fpu reg */ | |
513 | #define RS1_FREG 0x200 /* rs1 is a fpu reg */ | 514 | #define RS1_FREG 0x200 /* rs1 is a fpu reg */ | |
514 | #define RS2_FREG 0x400 /* rs2 is a fpu reg */ | 515 | #define RS2_FREG 0x400 /* rs2 is a fpu reg */ | |
515 | #define ISCVT 0x800 /* is an fpu conversion op */ | 516 | #define ISCVT 0x800 /* is an fpu conversion op */ | |
516 | /* do not add more without increasing the field size below */ | 517 | /* do not add more without increasing the field size below */ | |
517 | 518 | |||
518 | #define ALL_FREG (RD_FREG | RS1_FREG | RS2_FREG) | 519 | #define ALL_FREG (RD_FREG | RS1_FREG | RS2_FREG) | |
519 | #define RS12_FREG (RS1_FREG | RS2_FREG) | 520 | #define RS12_FREG (RS1_FREG | RS2_FREG) | |
520 | 521 | |||
521 | /* entries for matching within a major opcode */ | 522 | /* entries for matching within a major opcode */ | |
522 | struct riscv_disasm_insn { | 523 | struct riscv_disasm_insn { | |
523 | const char *name; | 524 | const char *name; | |
524 | unsigned int matchflags: 16, | 525 | unsigned int matchflags: 16, | |
525 | funct3: 3, | 526 | funct3: 3, | |
526 | funct7: 7, | 527 | funct7: 7, | |
527 | rs2: 5; | 528 | rs2: 5; | |
528 | unsigned int printflags: 12; | 529 | unsigned int printflags: 12; | |
529 | }; | 530 | }; | |
530 | 531 | |||
531 | /* format codes */ | 532 | /* format codes */ | |
532 | #define FMT_R 0 | 533 | #define FMT_R 0 | |
533 | #define FMT_R4 1 | 534 | #define FMT_R4 1 | |
534 | #define FMT_I 2 | 535 | #define FMT_I 2 | |
535 | #define FMT_In 3 | 536 | #define FMT_In 3 | |
536 | #define FMT_S 4 | 537 | #define FMT_S 4 | |
537 | #define FMT_B 5 | 538 | #define FMT_B 5 | |
538 | #define FMT_U 6 | 539 | #define FMT_U 6 | |
539 | #define FMT_J 7 | 540 | #define FMT_J 7 | |
540 | #define FMT_UNKNOWN 8 | 541 | #define FMT_UNKNOWN 8 | |
541 | #define FMT_ASSERT 9 | 542 | #define FMT_ASSERT 9 | |
542 | 543 | |||
543 | /* top-level opcode dispatch */ | 544 | /* top-level opcode dispatch */ | |
544 | struct riscv_disasm32_entry { | 545 | struct riscv_disasm32_entry { | |
545 | uint8_t fmt; | 546 | uint8_t fmt; | |
546 | union { | 547 | union { | |
547 | // R4, In, U, J | 548 | // R4, In, U, J | |
548 | const char *name; | 549 | const char *name; | |
549 | // R, I, S, B | 550 | // R, I, S, B | |
550 | struct { | 551 | struct { | |
551 | const struct riscv_disasm_insn *v; | 552 | const struct riscv_disasm_insn *v; | |
552 | unsigned n; | 553 | unsigned n; | |
553 | } entries; | 554 | } entries; | |
554 | } u; | 555 | } u; | |
555 | }; | 556 | }; | |
556 | 557 | |||
557 | #define INSN_F3(n, f3, moretests, pflags) \ | 558 | #define INSN_F3(n, f3, moretests, pflags) \ | |
558 | { \ | 559 | { \ | |
559 | .name = n, \ | 560 | .name = n, \ | |
560 | .matchflags = CHECK_F3 | moretests, \ | 561 | .matchflags = CHECK_F3 | moretests, \ | |
561 | .funct3 = f3, .funct7 = 0, .rs2 = 0, \ | 562 | .funct3 = f3, .funct7 = 0, .rs2 = 0, \ | |
562 | .printflags = pflags, \ | 563 | .printflags = pflags, \ | |
563 | } | 564 | } | |
564 | 565 | |||
565 | #define INSN_F5(n, f5, moretests, pflags) \ | 566 | #define INSN_F5(n, f5, moretests, pflags) \ | |
566 | { \ | 567 | { \ | |
567 | .name = n, \ | 568 | .name = n, \ | |
568 | .matchflags = CHECK_F7 | CHECK_F5 | moretests, \ | 569 | .matchflags = CHECK_F7 | CHECK_F5 | moretests, \ | |
569 | .funct3 = 0, .funct7 = f5 << 2, .rs2 = 0, \ | 570 | .funct3 = 0, .funct7 = f5 << 2, .rs2 = 0, \ | |
570 | .printflags = pflags, \ | 571 | .printflags = pflags, \ | |
571 | } | 572 | } | |
572 | 573 | |||
573 | #define INSN_F53(n, f5, f3, moretests, pflags) \ | 574 | #define INSN_F53(n, f5, f3, moretests, pflags) \ | |
574 | { \ | 575 | { \ | |
575 | .name = n, \ | 576 | .name = n, \ | |
576 | .matchflags = CHECK_F7 | CHECK_F5 | CHECK_F3 | moretests, \ | 577 | .matchflags = CHECK_F7 | CHECK_F5 | CHECK_F3 | moretests, \ | |
577 | .funct3 = f3, .funct7 = f5 << 2, .rs2 = 0, \ | 578 | .funct3 = f3, .funct7 = f5 << 2, .rs2 = 0, \ | |
578 | .printflags = pflags, \ | 579 | .printflags = pflags, \ | |
579 | } | 580 | } | |
580 | 581 | |||
581 | #define INSN_F7(n, f7, moretests, pflags) \ | 582 | #define INSN_F7(n, f7, moretests, pflags) \ | |
582 | { \ | 583 | { \ | |
583 | .name = n, \ | 584 | .name = n, \ | |
584 | .matchflags = CHECK_F7 | moretests, \ | 585 | .matchflags = CHECK_F7 | moretests, \ | |
585 | .funct3 = 0, .funct7 = f7, .rs2 = 0, \ | 586 | .funct3 = 0, .funct7 = f7, .rs2 = 0, \ | |
586 | .printflags = pflags, \ | 587 | .printflags = pflags, \ | |
587 | } | 588 | } | |
588 | 589 | |||
589 | #define INSN_F73(n, f7, f3, moretests, pflags) \ | 590 | #define INSN_F73(n, f7, f3, moretests, pflags) \ | |
590 | { \ | 591 | { \ | |
591 | .name = n, \ | 592 | .name = n, \ | |
592 | .matchflags = CHECK_F7 | CHECK_F3 | moretests, \ | 593 | .matchflags = CHECK_F7 | CHECK_F3 | moretests, \ | |
593 | .funct3 = f3, .funct7 = f7, .rs2 = 0, \ | 594 | .funct3 = f3, .funct7 = f7, .rs2 = 0, \ | |
594 | .printflags = pflags, \ | 595 | .printflags = pflags, \ | |
595 | } | 596 | } | |
596 | 597 | |||
597 | #define INSN_F37(n, f3, f7, moretests, pflags) \ | 598 | #define INSN_F37(n, f3, f7, moretests, pflags) \ | |
598 | INSN_F73(n, f7, f3, moretests, pflags) | 599 | INSN_F73(n, f7, f3, moretests, pflags) | |
599 | 600 | |||
600 | #define INSN_USER(n, rs2val, moretests, pflags) \ | 601 | #define INSN_USER(n, rs2val, moretests, pflags) \ | |
601 | { \ | 602 | { \ | |
602 | .name = n, \ | 603 | .name = n, \ | |
603 | .matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \ | 604 | .matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \ | |
604 | .funct3 = SYSTEM_PRIV, .funct7 = PRIV_USER, \ | 605 | .funct3 = SYSTEM_PRIV, .funct7 = PRIV_USER, \ | |
605 | .rs2 = rs2val, \ | 606 | .rs2 = rs2val, \ | |
606 | .printflags = pflags, \ | 607 | .printflags = pflags, \ | |
607 | } | 608 | } | |
608 | 609 | |||
609 | #define INSN_SYSTEM(n, rs2val, moretests, pflags) \ | 610 | #define INSN_SYSTEM(n, rs2val, moretests, pflags) \ | |
610 | { \ | 611 | { \ | |
611 | .name = n, \ | 612 | .name = n, \ | |
612 | .matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \ | 613 | .matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \ | |
613 | .funct3 = SYSTEM_PRIV, .funct7 = PRIV_SYSTEM, \ | 614 | .funct3 = SYSTEM_PRIV, .funct7 = PRIV_SYSTEM, \ | |
614 | .rs2 = rs2val, \ | 615 | .rs2 = rs2val, \ | |
615 | .printflags = pflags, \ | 616 | .printflags = pflags, \ | |
616 | } | 617 | } | |
617 | 618 | |||
618 | #define INSN_MACHINE(n, rs2val, moretests, pflags) \ | 619 | #define INSN_MACHINE(n, rs2val, moretests, pflags) \ | |
619 | { \ | 620 | { \ | |
620 | .name = n, \ | 621 | .name = n, \ | |
621 | .matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \ | 622 | .matchflags = CHECK_F7 | CHECK_F3 | CHECK_RS2 | moretests, \ | |
622 | .funct3 = SYSTEM_PRIV, .funct7 = PRIV_MACHINE, \ | 623 | .funct3 = SYSTEM_PRIV, .funct7 = PRIV_MACHINE, \ | |
623 | .rs2 = rs2val, \ | 624 | .rs2 = rs2val, \ | |
624 | .printflags = pflags, \ | 625 | .printflags = pflags, \ | |
625 | } | 626 | } | |
626 | 627 | |||
627 | static const struct riscv_disasm_insn riscv_disasm_miscmem[] = { | 628 | static const struct riscv_disasm_insn riscv_disasm_miscmem[] = { | |
628 | INSN_F3("fence", MISCMEM_FENCE, RD_0 | RS1_0 | FENCEFM, FENCEIMM), | 629 | INSN_F3("fence", MISCMEM_FENCE, RD_0 | RS1_0 | FENCEFM, FENCEIMM), | |
629 | INSN_F3("fence.i", MISCMEM_FENCEI, RD_0 | RS1_0 | IMM_0, 0), | 630 | INSN_F3("fence.i", MISCMEM_FENCEI, RD_0 | RS1_0 | IMM_0, 0), | |
630 | }; | 631 | }; | |
631 | 632 | |||
632 | static const struct riscv_disasm_insn riscv_disasm_load[] = { | 633 | static const struct riscv_disasm_insn riscv_disasm_load[] = { | |
633 | INSN_F3("lb", LOAD_LB, 0, MEMORYIMM), | 634 | INSN_F3("lb", LOAD_LB, 0, MEMORYIMM), | |
634 | INSN_F3("lh", LOAD_LH, 0, MEMORYIMM), | 635 | INSN_F3("lh", LOAD_LH, 0, MEMORYIMM), | |
635 | INSN_F3("lw", LOAD_LW, 0, MEMORYIMM), | 636 | INSN_F3("lw", LOAD_LW, 0, MEMORYIMM), | |
636 | INSN_F3("ld", LOAD_LD, 0, MEMORYIMM), | 637 | INSN_F3("ld", LOAD_LD, 0, MEMORYIMM), | |
637 | INSN_F3("lbu", LOAD_LBU, 0, MEMORYIMM), | 638 | INSN_F3("lbu", LOAD_LBU, 0, MEMORYIMM), | |
638 | INSN_F3("lhu", LOAD_LHU, 0, MEMORYIMM), | 639 | INSN_F3("lhu", LOAD_LHU, 0, MEMORYIMM), | |
639 | INSN_F3("lwu", LOAD_LWU, 0, MEMORYIMM), | 640 | INSN_F3("lwu", LOAD_LWU, 0, MEMORYIMM), | |
640 | }; | 641 | }; | |
641 | 642 | |||
642 | static const struct riscv_disasm_insn riscv_disasm_loadfp[] = { | 643 | static const struct riscv_disasm_insn riscv_disasm_loadfp[] = { | |
643 | INSN_F3("flw", LOADFP_FLW, 0, MEMORYIMM | RD_FREG), | 644 | INSN_F3("flw", LOADFP_FLW, 0, MEMORYIMM | RD_FREG), | |
644 | INSN_F3("fld", LOADFP_FLD, 0, MEMORYIMM | RD_FREG), | 645 | INSN_F3("fld", LOADFP_FLD, 0, MEMORYIMM | RD_FREG), | |
645 | INSN_F3("flq", LOADFP_FLQ, 0, MEMORYIMM | RD_FREG), | 646 | INSN_F3("flq", LOADFP_FLQ, 0, MEMORYIMM | RD_FREG), | |
646 | }; | 647 | }; | |
647 | 648 | |||
648 | static const struct riscv_disasm_insn riscv_disasm_opimm[] = { | 649 | static const struct riscv_disasm_insn riscv_disasm_opimm[] = { | |
649 | INSN_F3("nop", OP_ADDSUB, RD_0 | RS1_0 | IMM_0, 0), | 650 | INSN_F3("nop", OP_ADDSUB, RD_0 | RS1_0 | IMM_0, 0), | |
650 | INSN_F3("addi", OP_ADDSUB, 0, 0), | 651 | INSN_F3("addi", OP_ADDSUB, 0, 0), | |
651 | INSN_F3("slti", OP_SLT, 0, 0), | 652 | INSN_F3("slti", OP_SLT, 0, 0), | |
652 | INSN_F3("sltiu", OP_SLTU, 0, 0), | 653 | INSN_F3("sltiu", OP_SLTU, 0, 0), | |
653 | INSN_F3("xori", OP_XOR, 0, 0), | 654 | INSN_F3("xori", OP_XOR, 0, 0), | |
654 | INSN_F3("ori", OP_OR, 0, 0), | 655 | INSN_F3("ori", OP_OR, 0, 0), | |
655 | INSN_F3("andi", OP_AND, 0, 0), | 656 | INSN_F3("andi", OP_AND, 0, 0), | |
656 | INSN_F37("slli", OP_SLL, OP_ARITH, SHIFTNATIVE, DECIMM), | 657 | INSN_F37("slli", OP_SLL, OP_ARITH, SHIFTNATIVE, DECIMM), | |
657 | INSN_F37("srli", OP_SRX, OP_ARITH, SHIFTNATIVE, DECIMM), | 658 | INSN_F37("srli", OP_SRX, OP_ARITH, SHIFTNATIVE, DECIMM), | |
658 | INSN_F37("srai", OP_SRX, OP_NARITH, SHIFTNATIVE, DECIMM), | 659 | INSN_F37("srai", OP_SRX, OP_NARITH, SHIFTNATIVE, DECIMM), | |
659 | }; | 660 | }; | |
660 | 661 | |||
661 | static const struct riscv_disasm_insn riscv_disasm_opimm32[] = { | 662 | static const struct riscv_disasm_insn riscv_disasm_opimm32[] = { | |
662 | INSN_F3("addiw", OP_ADDSUB, 0, 0), | 663 | INSN_F3("addiw", OP_ADDSUB, 0, 0), | |
663 | INSN_F37("slliw", OP_SLL, OP_ARITH, SHIFT32, DECIMM), | 664 | INSN_F37("slliw", OP_SLL, OP_ARITH, SHIFT32, DECIMM), | |
664 | INSN_F37("srliw", OP_SRX, OP_ARITH, SHIFT32, DECIMM), | 665 | INSN_F37("srliw", OP_SRX, OP_ARITH, SHIFT32, DECIMM), | |
665 | INSN_F37("sraiw", OP_SRX, OP_NARITH, SHIFT32, DECIMM), | 666 | INSN_F37("sraiw", OP_SRX, OP_NARITH, SHIFT32, DECIMM), | |
666 | }; | 667 | }; | |
667 | 668 | |||
668 | static const struct riscv_disasm_insn riscv_disasm_store[] = { | 669 | static const struct riscv_disasm_insn riscv_disasm_store[] = { | |
669 | INSN_F3("sb", STORE_SB, 0, MEMORYIMM), | 670 | INSN_F3("sb", STORE_SB, 0, MEMORYIMM), | |
670 | INSN_F3("sh", STORE_SH, 0, MEMORYIMM), | 671 | INSN_F3("sh", STORE_SH, 0, MEMORYIMM), | |
671 | INSN_F3("sw", STORE_SW, 0, MEMORYIMM), | 672 | INSN_F3("sw", STORE_SW, 0, MEMORYIMM), | |
672 | INSN_F3("sd", STORE_SD, 0, MEMORYIMM), | 673 | INSN_F3("sd", STORE_SD, 0, MEMORYIMM), | |
673 | }; | 674 | }; | |
674 | 675 | |||
675 | static const struct riscv_disasm_insn riscv_disasm_storefp[] = { | 676 | static const struct riscv_disasm_insn riscv_disasm_storefp[] = { | |
676 | INSN_F3("fsw", STOREFP_FSW, 0, MEMORYIMM | RS2_FREG), | 677 | INSN_F3("fsw", STOREFP_FSW, 0, MEMORYIMM | RS2_FREG), | |
677 | INSN_F3("fsd", STOREFP_FSD, 0, MEMORYIMM | RS2_FREG), | 678 | INSN_F3("fsd", STOREFP_FSD, 0, MEMORYIMM | RS2_FREG), | |
678 | INSN_F3("fsq", STOREFP_FSQ, 0, MEMORYIMM | RS2_FREG), | 679 | INSN_F3("fsq", STOREFP_FSQ, 0, MEMORYIMM | RS2_FREG), | |
679 | }; | 680 | }; | |
680 | 681 | |||
681 | static const struct riscv_disasm_insn riscv_disasm_branch[] = { | 682 | static const struct riscv_disasm_insn riscv_disasm_branch[] = { | |
682 | INSN_F3("beq", BRANCH_BEQ, 0, BRANCHIMM), | 683 | INSN_F3("beq", BRANCH_BEQ, 0, BRANCHIMM), | |
683 | INSN_F3("bne", BRANCH_BNE, 0, BRANCHIMM), | 684 | INSN_F3("bne", BRANCH_BNE, 0, BRANCHIMM), | |
684 | INSN_F3("blt", BRANCH_BLT, 0, BRANCHIMM), | 685 | INSN_F3("blt", BRANCH_BLT, 0, BRANCHIMM), | |
685 | INSN_F3("bge", BRANCH_BGE, 0, BRANCHIMM), | 686 | INSN_F3("bge", BRANCH_BGE, 0, BRANCHIMM), | |
686 | INSN_F3("bltu", BRANCH_BLTU, 0, BRANCHIMM), | 687 | INSN_F3("bltu", BRANCH_BLTU, 0, BRANCHIMM), | |
687 | INSN_F3("bgeu", BRANCH_BGEU, 0, BRANCHIMM), | 688 | INSN_F3("bgeu", BRANCH_BGEU, 0, BRANCHIMM), | |
688 | }; | 689 | }; | |
689 | 690 | |||
690 | static const struct riscv_disasm_insn riscv_disasm_system[] = { | 691 | static const struct riscv_disasm_insn riscv_disasm_system[] = { | |
691 | INSN_F3("csrw", SYSTEM_CSRRW, RD_0, CSRIMM), | 692 | INSN_F3("csrw", SYSTEM_CSRRW, RD_0, CSRIMM), | |
692 | INSN_F3("csrrw", SYSTEM_CSRRW, 0, CSRIMM), | 693 | INSN_F3("csrrw", SYSTEM_CSRRW, 0, CSRIMM), | |
693 | INSN_F3("csrr", SYSTEM_CSRRS, RS1_0, CSRIMM), | 694 | INSN_F3("csrr", SYSTEM_CSRRS, RS1_0, CSRIMM), | |
694 | INSN_F3("csrrs", SYSTEM_CSRRS, 0, CSRIMM), | 695 | INSN_F3("csrrs", SYSTEM_CSRRS, 0, CSRIMM), | |
695 | INSN_F3("csrrc", SYSTEM_CSRRC, 0, CSRIMM), | 696 | INSN_F3("csrrc", SYSTEM_CSRRC, 0, CSRIMM), | |
696 | INSN_F3("csrwi", SYSTEM_CSRRWI, RD_0, CSRIIMM), | 697 | INSN_F3("csrwi", SYSTEM_CSRRWI, RD_0, CSRIIMM), | |
697 | INSN_F3("csrrwi", SYSTEM_CSRRWI, 0, CSRIIMM), | 698 | INSN_F3("csrrwi", SYSTEM_CSRRWI, 0, CSRIIMM), | |
698 | INSN_F3("csrrsi", SYSTEM_CSRRSI, 0, CSRIIMM), | 699 | INSN_F3("csrrsi", SYSTEM_CSRRSI, 0, CSRIIMM), | |
699 | INSN_F3("csrrci", SYSTEM_CSRRCI, 0, CSRIIMM), | 700 | INSN_F3("csrrci", SYSTEM_CSRRCI, 0, CSRIIMM), | |
700 | INSN_F37("sfence.vma", SYSTEM_PRIV, PRIV_SFENCE_VMA, RD_0, 0), | 701 | INSN_F37("sfence.vma", SYSTEM_PRIV, PRIV_SFENCE_VMA, RD_0, 0), | |
701 | INSN_F37("hfence.bvma", SYSTEM_PRIV, PRIV_HFENCE_BVMA, 0, 0), | 702 | INSN_F37("hfence.bvma", SYSTEM_PRIV, PRIV_HFENCE_BVMA, 0, 0), | |
702 | INSN_F37("hfence.gvma", SYSTEM_PRIV, PRIV_HFENCE_GVMA, 0, 0), | 703 | INSN_F37("hfence.gvma", SYSTEM_PRIV, PRIV_HFENCE_GVMA, 0, 0), | |
703 | INSN_USER("ecall", USER_ECALL, RD_0 | RS1_0, 0), | 704 | INSN_USER("ecall", USER_ECALL, RD_0 | RS1_0, 0), | |
704 | INSN_USER("ebreak", USER_EBREAK, RD_0 | RS1_0, 0), | 705 | INSN_USER("ebreak", USER_EBREAK, RD_0 | RS1_0, 0), | |
705 | INSN_USER("uret", USER_URET, RD_0 | RS1_0, 0), | 706 | INSN_USER("uret", USER_URET, RD_0 | RS1_0, 0), | |
706 | INSN_SYSTEM("sret", SYSTEM_SRET, RD_0 | RS1_0, 0), | 707 | INSN_SYSTEM("sret", SYSTEM_SRET, RD_0 | RS1_0, 0), | |
707 | INSN_SYSTEM("wfi", SYSTEM_WFI, RD_0 | RS1_0, 0), | 708 | INSN_SYSTEM("wfi", SYSTEM_WFI, RD_0 | RS1_0, 0), | |
708 | INSN_MACHINE("mret", MACHINE_MRET, RD_0 | RS1_0, 0), | 709 | INSN_MACHINE("mret", MACHINE_MRET, RD_0 | RS1_0, 0), | |
709 | }; | 710 | }; | |
710 | 711 | |||
711 | static const struct riscv_disasm_insn riscv_disasm_amo[] = { | 712 | static const struct riscv_disasm_insn riscv_disasm_amo[] = { | |
712 | INSN_F5("amoadd", AMO_ADD, F3AMO, AMOAQRL), | 713 | INSN_F5("amoadd", AMO_ADD, F3AMO, AMOAQRL), | |
713 | INSN_F5("amoswap", AMO_SWAP, F3AMO, AMOAQRL), | 714 | INSN_F5("amoswap", AMO_SWAP, F3AMO, AMOAQRL), | |
714 | INSN_F5("lr", AMO_LR, F3AMO | RS2_0, AMOAQRL), | 715 | INSN_F5("lr", AMO_LR, F3AMO | RS2_0, AMOAQRL), | |
715 | INSN_F5("sc", AMO_SC, F3AMO, AMOAQRL), | 716 | INSN_F5("sc", AMO_SC, F3AMO, AMOAQRL), | |
716 | INSN_F5("amoxor", AMO_XOR, F3AMO, AMOAQRL), | 717 | INSN_F5("amoxor", AMO_XOR, F3AMO, AMOAQRL), | |
717 | INSN_F5("amoor", AMO_OR, F3AMO, AMOAQRL), | 718 | INSN_F5("amoor", AMO_OR, F3AMO, AMOAQRL), | |
718 | INSN_F5("amoand", AMO_AND, F3AMO, AMOAQRL), | 719 | INSN_F5("amoand", AMO_AND, F3AMO, AMOAQRL), | |
719 | INSN_F5("amomin", AMO_MIN, F3AMO, AMOAQRL), | 720 | INSN_F5("amomin", AMO_MIN, F3AMO, AMOAQRL), | |
720 | INSN_F5("amomax", AMO_MAX, F3AMO, AMOAQRL), | 721 | INSN_F5("amomax", AMO_MAX, F3AMO, AMOAQRL), | |
721 | INSN_F5("amominu", AMO_MINU, F3AMO, AMOAQRL), | 722 | INSN_F5("amominu", AMO_MINU, F3AMO, AMOAQRL), | |
722 | INSN_F5("amomaxu", AMO_MAXU, F3AMO, AMOAQRL), | 723 | INSN_F5("amomaxu", AMO_MAXU, F3AMO, AMOAQRL), | |
723 | }; | 724 | }; | |
724 | 725 | |||
725 | static const struct riscv_disasm_insn riscv_disasm_op[] = { | 726 | static const struct riscv_disasm_insn riscv_disasm_op[] = { | |
726 | INSN_F37("add", OP_ADDSUB, OP_ARITH, 0, 0), | 727 | INSN_F37("add", OP_ADDSUB, OP_ARITH, 0, 0), | |
727 | INSN_F37("sub", OP_ADDSUB, OP_NARITH, 0, 0), | 728 | INSN_F37("sub", OP_ADDSUB, OP_NARITH, 0, 0), | |
728 | INSN_F37("sll", OP_SLL, OP_ARITH, 0, 0), | 729 | INSN_F37("sll", OP_SLL, OP_ARITH, 0, 0), | |
729 | INSN_F37("slt", OP_SLT, OP_ARITH, 0, 0), | 730 | INSN_F37("slt", OP_SLT, OP_ARITH, 0, 0), | |
730 | INSN_F37("sltu", OP_SLTU, OP_ARITH, 0, 0), | 731 | INSN_F37("sltu", OP_SLTU, OP_ARITH, 0, 0), | |
731 | INSN_F37("xor", OP_XOR, OP_ARITH, 0, 0), | 732 | INSN_F37("xor", OP_XOR, OP_ARITH, 0, 0), | |
732 | INSN_F37("srl", OP_SRX, OP_ARITH, 0, 0), | 733 | INSN_F37("srl", OP_SRX, OP_ARITH, 0, 0), | |
733 | INSN_F37("sra", OP_SRX, OP_NARITH, 0, 0), | 734 | INSN_F37("sra", OP_SRX, OP_NARITH, 0, 0), | |
734 | INSN_F37("or", OP_OR, OP_ARITH, 0, 0), | 735 | INSN_F37("or", OP_OR, OP_ARITH, 0, 0), | |
735 | INSN_F37("and", OP_AND, OP_ARITH, 0, 0), | 736 | INSN_F37("and", OP_AND, OP_ARITH, 0, 0), | |
736 | INSN_F37("mul", OP_MUL, OP_MULDIV, 0, 0), | 737 | INSN_F37("mul", OP_MUL, OP_MULDIV, 0, 0), | |
737 | INSN_F37("mulh", OP_MULH, OP_MULDIV, 0, 0), | 738 | INSN_F37("mulh", OP_MULH, OP_MULDIV, 0, 0), | |
738 | INSN_F37("mulhsu", OP_MULHSU, OP_MULDIV, 0, 0), | 739 | INSN_F37("mulhsu", OP_MULHSU, OP_MULDIV, 0, 0), | |
739 | INSN_F37("mulhu", OP_MULHU, OP_MULDIV, 0, 0), | 740 | INSN_F37("mulhu", OP_MULHU, OP_MULDIV, 0, 0), | |
740 | INSN_F37("div", OP_DIV, OP_MULDIV, 0, 0), | 741 | INSN_F37("div", OP_DIV, OP_MULDIV, 0, 0), | |
741 | INSN_F37("divu", OP_DIVU, OP_MULDIV, 0, 0), | 742 | INSN_F37("divu", OP_DIVU, OP_MULDIV, 0, 0), | |
742 | INSN_F37("rem", OP_REM, OP_MULDIV, 0, 0), | 743 | INSN_F37("rem", OP_REM, OP_MULDIV, 0, 0), | |
743 | INSN_F37("remu", OP_REMU, OP_MULDIV, 0, 0), | 744 | INSN_F37("remu", OP_REMU, OP_MULDIV, 0, 0), | |
744 | }; | 745 | }; | |
745 | 746 | |||
746 | static const struct riscv_disasm_insn riscv_disasm_op32[] = { | 747 | static const struct riscv_disasm_insn riscv_disasm_op32[] = { | |
747 | INSN_F37("addw", OP_ADDSUB, OP_ARITH, 0, 0), | 748 | INSN_F37("addw", OP_ADDSUB, OP_ARITH, 0, 0), | |
748 | INSN_F37("subw", OP_ADDSUB, OP_NARITH, 0, 0), | 749 | INSN_F37("subw", OP_ADDSUB, OP_NARITH, 0, 0), | |
749 | INSN_F37("sllw", OP_SLL, OP_ARITH, 0, 0), | 750 | INSN_F37("sllw", OP_SLL, OP_ARITH, 0, 0), | |
750 | INSN_F37("srlw", OP_SRX, OP_ARITH, 0, 0), | 751 | INSN_F37("srlw", OP_SRX, OP_ARITH, 0, 0), | |
751 | INSN_F37("sraw", OP_SRX, OP_NARITH, 0, 0), | 752 | INSN_F37("sraw", OP_SRX, OP_NARITH, 0, 0), | |
752 | INSN_F37("mulw", OP_MUL, OP_MULDIV, 0, 0), | 753 | INSN_F37("mulw", OP_MUL, OP_MULDIV, 0, 0), | |
753 | INSN_F37("divw", OP_DIV, OP_MULDIV, 0, 0), | 754 | INSN_F37("divw", OP_DIV, OP_MULDIV, 0, 0), | |
754 | INSN_F37("divuw", OP_DIVU, OP_MULDIV, 0, 0), | 755 | INSN_F37("divuw", OP_DIVU, OP_MULDIV, 0, 0), | |
755 | INSN_F37("remw", OP_REM, OP_MULDIV, 0, 0), | 756 | INSN_F37("remw", OP_REM, OP_MULDIV, 0, 0), | |
756 | INSN_F37("remuw", OP_REMU, OP_MULDIV, 0, 0), | 757 | INSN_F37("remuw", OP_REMU, OP_MULDIV, 0, 0), | |
757 | }; | 758 | }; | |
758 | 759 | |||
759 | static const struct riscv_disasm_insn riscv_disasm_opfp[] = { | 760 | static const struct riscv_disasm_insn riscv_disasm_opfp[] = { | |
760 | INSN_F5("fadd", OPFP_ADD, F7SIZE|F3ROUND, ALL_FREG), | 761 | INSN_F5("fadd", OPFP_ADD, F7SIZE|F3ROUND, ALL_FREG), | |
761 | INSN_F5("fsub", OPFP_SUB, F7SIZE|F3ROUND, ALL_FREG), | 762 | INSN_F5("fsub", OPFP_SUB, F7SIZE|F3ROUND, ALL_FREG), | |
762 | INSN_F5("fmul", OPFP_MUL, F7SIZE|F3ROUND, ALL_FREG), | 763 | INSN_F5("fmul", OPFP_MUL, F7SIZE|F3ROUND, ALL_FREG), | |
763 | INSN_F5("fdiv", OPFP_DIV, F7SIZE|F3ROUND, ALL_FREG), | 764 | INSN_F5("fdiv", OPFP_DIV, F7SIZE|F3ROUND, ALL_FREG), | |
764 | INSN_F53("fsgnj", OPFP_SGNJ, SGN_SGNJ, F7SIZE, ALL_FREG), | 765 | INSN_F53("fsgnj", OPFP_SGNJ, SGN_SGNJ, F7SIZE, ALL_FREG), | |
765 | INSN_F53("fsgnjn", OPFP_SGNJ, SGN_SGNJN, F7SIZE, ALL_FREG), | 766 | INSN_F53("fsgnjn", OPFP_SGNJ, SGN_SGNJN, F7SIZE, ALL_FREG), | |
766 | INSN_F53("fsgnjx", OPFP_SGNJ, SGN_SGNJX, F7SIZE, ALL_FREG), | 767 | INSN_F53("fsgnjx", OPFP_SGNJ, SGN_SGNJX, F7SIZE, ALL_FREG), | |
767 | INSN_F53("fmin", OPFP_MINMAX, MINMAX_MIN, F7SIZE, ALL_FREG), | 768 | INSN_F53("fmin", OPFP_MINMAX, MINMAX_MIN, F7SIZE, ALL_FREG), | |
768 | INSN_F53("fmax", OPFP_MINMAX, MINMAX_MAX, F7SIZE, ALL_FREG), | 769 | INSN_F53("fmax", OPFP_MINMAX, MINMAX_MAX, F7SIZE, ALL_FREG), | |
769 | INSN_F5("fcvt", OPFP_CVTFF, F7SIZE|F3ROUND|RS2_FSIZE, | 770 | INSN_F5("fcvt", OPFP_CVTFF, F7SIZE|F3ROUND|RS2_FSIZE, | |
770 | ISCVT | ALL_FREG), | 771 | ISCVT | ALL_FREG), | |
771 | INSN_F5("fsqrt", OPFP_SQRT, F7SIZE|F3ROUND|RS2_0, ALL_FREG), | 772 | INSN_F5("fsqrt", OPFP_SQRT, F7SIZE|F3ROUND|RS2_0, ALL_FREG), | |
772 | INSN_F53("fle", OPFP_CMP, CMP_LE, F7SIZE, RS12_FREG), | 773 | INSN_F53("fle", OPFP_CMP, CMP_LE, F7SIZE, RS12_FREG), | |
773 | INSN_F53("flt", OPFP_CMP, CMP_LT, F7SIZE, RS12_FREG), | 774 | INSN_F53("flt", OPFP_CMP, CMP_LT, F7SIZE, RS12_FREG), | |
774 | INSN_F53("feq", OPFP_CMP, CMP_EQ, F7SIZE, RS12_FREG), | 775 | INSN_F53("feq", OPFP_CMP, CMP_EQ, F7SIZE, RS12_FREG), | |
775 | INSN_F5("fcvt", OPFP_CVTIF, F7SIZE|F3ROUND|RS2_FSIZE|RS2_FSIZE_INT, | 776 | INSN_F5("fcvt", OPFP_CVTIF, F7SIZE|F3ROUND|RS2_FSIZE|RS2_FSIZE_INT, | |
776 | ISCVT | RS2SIZE_FIRST | RS1_FREG), | 777 | ISCVT | RS2SIZE_FIRST | RS1_FREG), | |
777 | INSN_F5("fcvt", OPFP_CVTFI, F7SIZE|F3ROUND|RS2_FSIZE|RS2_FSIZE_INT, | 778 | INSN_F5("fcvt", OPFP_CVTFI, F7SIZE|F3ROUND|RS2_FSIZE|RS2_FSIZE_INT, | |
778 | ISCVT | RD_FREG), | 779 | ISCVT | RD_FREG), | |
779 | INSN_F53("fclass", OPFP_MVFI_CLASS, MVFI_CLASS_CLASS, F7SIZE|RS2_0, | 780 | INSN_F53("fclass", OPFP_MVFI_CLASS, MVFI_CLASS_CLASS, F7SIZE|RS2_0, | |
780 | RS1_FREG), | 781 | RS1_FREG), | |
781 | INSN_F73("fmv.x.w", (OPFP_MVFI_CLASS << 2) | OPFP_S, MVFI_CLASS_MVFI, | 782 | INSN_F73("fmv.x.w", (OPFP_MVFI_CLASS << 2) | OPFP_S, MVFI_CLASS_MVFI, | |
782 | RS2_0, RS1_FREG), | 783 | RS2_0, RS1_FREG), | |
783 | INSN_F73("fmv.w.x", (OPFP_MVIF << 2) | OPFP_S, 0, | 784 | INSN_F73("fmv.w.x", (OPFP_MVIF << 2) | OPFP_S, 0, | |
784 | RS2_0, RD_FREG), | 785 | RS2_0, RD_FREG), | |
785 | INSN_F73("fmv.x.d", (OPFP_MVFI_CLASS << 2) | OPFP_D, MVFI_CLASS_MVFI, | 786 | INSN_F73("fmv.x.d", (OPFP_MVFI_CLASS << 2) | OPFP_D, MVFI_CLASS_MVFI, | |
786 | RS2_0, RS1_FREG), | 787 | RS2_0, RS1_FREG), | |
787 | INSN_F73("fmv.d.x", (OPFP_MVIF << 2) | OPFP_D, 0, | 788 | INSN_F73("fmv.d.x", (OPFP_MVIF << 2) | OPFP_D, 0, | |
788 | RS2_0, RD_FREG), | 789 | RS2_0, RD_FREG), | |
789 | }; | 790 | }; | |
790 | 791 | |||
791 | #define TABLE(table) \ | 792 | #define TABLE(table) \ | |
792 | .u.entries.v = table, .u.entries.n = __arraycount(table) | 793 | .u.entries.v = table, .u.entries.n = __arraycount(table) | |
793 | 794 | |||
794 | static const struct riscv_disasm32_entry riscv_disasm32[32] = { | 795 | static const struct riscv_disasm32_entry riscv_disasm32[32] = { | |
795 | [OPCODE_AUIPC] = { .fmt = FMT_U, .u.name = "auipc" }, | 796 | [OPCODE_AUIPC] = { .fmt = FMT_U, .u.name = "auipc" }, | |
796 | [OPCODE_LUI] = { .fmt = FMT_U, .u.name = "lui" }, | 797 | [OPCODE_LUI] = { .fmt = FMT_U, .u.name = "lui" }, | |
797 | [OPCODE_JAL] = { .fmt = FMT_J, .u.name = "jal" }, | 798 | [OPCODE_JAL] = { .fmt = FMT_J, .u.name = "jal" }, | |
798 | [OPCODE_JALR] = { .fmt = FMT_In, .u.name = "jalr" }, | 799 | [OPCODE_JALR] = { .fmt = FMT_In, .u.name = "jalr" }, | |
799 | [OPCODE_MISCMEM] = { .fmt = FMT_I, TABLE(riscv_disasm_miscmem) }, | 800 | [OPCODE_MISCMEM] = { .fmt = FMT_I, TABLE(riscv_disasm_miscmem) }, | |
800 | [OPCODE_LOAD] = { .fmt = FMT_I, TABLE(riscv_disasm_load) }, | 801 | [OPCODE_LOAD] = { .fmt = FMT_I, TABLE(riscv_disasm_load) }, | |
801 | [OPCODE_LOADFP] = { .fmt = FMT_I, TABLE(riscv_disasm_loadfp) }, | 802 | [OPCODE_LOADFP] = { .fmt = FMT_I, TABLE(riscv_disasm_loadfp) }, | |
802 | [OPCODE_OPIMM] = { .fmt = FMT_I, TABLE(riscv_disasm_opimm) }, | 803 | [OPCODE_OPIMM] = { .fmt = FMT_I, TABLE(riscv_disasm_opimm) }, | |
803 | [OPCODE_OPIMM32] = { .fmt = FMT_I, TABLE(riscv_disasm_opimm32) }, | 804 | [OPCODE_OPIMM32] = { .fmt = FMT_I, TABLE(riscv_disasm_opimm32) }, | |
804 | [OPCODE_STORE] = { .fmt = FMT_S, TABLE(riscv_disasm_store) }, | 805 | [OPCODE_STORE] = { .fmt = FMT_S, TABLE(riscv_disasm_store) }, | |
805 | [OPCODE_STOREFP] = { .fmt = FMT_S, TABLE(riscv_disasm_storefp) }, | 806 | [OPCODE_STOREFP] = { .fmt = FMT_S, TABLE(riscv_disasm_storefp) }, | |
806 | [OPCODE_BRANCH] = { .fmt = FMT_B, TABLE(riscv_disasm_branch) }, | 807 | [OPCODE_BRANCH] = { .fmt = FMT_B, TABLE(riscv_disasm_branch) }, | |
807 | [OPCODE_SYSTEM] = { .fmt = FMT_R, TABLE(riscv_disasm_system) }, | 808 | [OPCODE_SYSTEM] = { .fmt = FMT_R, TABLE(riscv_disasm_system) }, | |
808 | [OPCODE_AMO] = { .fmt = FMT_R, TABLE(riscv_disasm_amo) }, | 809 | [OPCODE_AMO] = { .fmt = FMT_R, TABLE(riscv_disasm_amo) }, | |
809 | [OPCODE_OP] = { .fmt = FMT_R, TABLE(riscv_disasm_op) }, | 810 | [OPCODE_OP] = { .fmt = FMT_R, TABLE(riscv_disasm_op) }, | |
810 | [OPCODE_OP32] = { .fmt = FMT_R, TABLE(riscv_disasm_op32) }, | 811 | [OPCODE_OP32] = { .fmt = FMT_R, TABLE(riscv_disasm_op32) }, | |
811 | [OPCODE_OPFP] = { .fmt = FMT_R, TABLE(riscv_disasm_opfp) }, | 812 | [OPCODE_OPFP] = { .fmt = FMT_R, TABLE(riscv_disasm_opfp) }, | |
812 | [OPCODE_MADD] = { .fmt = FMT_R4, .u.name = "fmadd" }, | 813 | [OPCODE_MADD] = { .fmt = FMT_R4, .u.name = "fmadd" }, | |
813 | [OPCODE_MSUB] = { .fmt = FMT_R4, .u.name = "fmsub" }, | 814 | [OPCODE_MSUB] = { .fmt = FMT_R4, .u.name = "fmsub" }, | |
814 | [OPCODE_NMADD] = { .fmt = FMT_R4, .u.name = "fnmadd" }, | 815 | [OPCODE_NMADD] = { .fmt = FMT_R4, .u.name = "fnmadd" }, | |
815 | [OPCODE_NMSUB] = { .fmt = FMT_R4, .u.name = "fnmsub" }, | 816 | [OPCODE_NMSUB] = { .fmt = FMT_R4, .u.name = "fnmsub" }, | |
816 | [OPCODE_CUSTOM0] = { .fmt = FMT_UNKNOWN }, | 817 | [OPCODE_CUSTOM0] = { .fmt = FMT_UNKNOWN }, | |
817 | [OPCODE_CUSTOM1] = { .fmt = FMT_UNKNOWN }, | 818 | [OPCODE_CUSTOM1] = { .fmt = FMT_UNKNOWN }, | |
818 | [OPCODE_CUSTOM2] = { .fmt = FMT_UNKNOWN }, | 819 | [OPCODE_CUSTOM2] = { .fmt = FMT_UNKNOWN }, | |
819 | [OPCODE_CUSTOM3] = { .fmt = FMT_UNKNOWN }, | 820 | [OPCODE_CUSTOM3] = { .fmt = FMT_UNKNOWN }, | |
820 | [OPCODE_rsvd21] = { .fmt = FMT_UNKNOWN }, | 821 | [OPCODE_rsvd21] = { .fmt = FMT_UNKNOWN }, | |
821 | [OPCODE_rsvd26] = { .fmt = FMT_UNKNOWN }, | 822 | [OPCODE_rsvd26] = { .fmt = FMT_UNKNOWN }, | |
822 | [OPCODE_rsvd29] = { .fmt = FMT_UNKNOWN }, | 823 | [OPCODE_rsvd29] = { .fmt = FMT_UNKNOWN }, | |
823 | [OPCODE_X48a] = { .fmt = FMT_ASSERT }, | 824 | [OPCODE_X48a] = { .fmt = FMT_ASSERT }, | |
824 | [OPCODE_X48b] = { .fmt = FMT_ASSERT }, | 825 | [OPCODE_X48b] = { .fmt = FMT_ASSERT }, | |
825 | [OPCODE_X64] = { .fmt = FMT_ASSERT }, | 826 | [OPCODE_X64] = { .fmt = FMT_ASSERT }, | |
826 | [OPCODE_X80] = { .fmt = FMT_ASSERT }, | 827 | [OPCODE_X80] = { .fmt = FMT_ASSERT }, | |
827 | }; | 828 | }; | |
828 | 829 | |||
829 | static const struct riscv_disasm_insn * | 830 | static const struct riscv_disasm_insn * | |
830 | riscv_disasm_match(const struct riscv_disasm_insn *table, unsigned num, | 831 | riscv_disasm_match(const struct riscv_disasm_insn *table, unsigned num, | |
831 | uint32_t insn, uint32_t imm) | 832 | uint32_t insn, uint32_t imm) | |
832 | { | 833 | { | |
833 | unsigned i, f3, f7, testf7; | 834 | unsigned i, f3, f7, testf7; | |
834 | const struct riscv_disasm_insn *info; | 835 | const struct riscv_disasm_insn *info; | |
835 | 836 | |||
836 | f3 = INSN_FUNCT3(insn); | 837 | f3 = INSN_FUNCT3(insn); | |
837 | f7 = INSN_FUNCT7(insn); | 838 | f7 = INSN_FUNCT7(insn); | |
838 | for (i=0; i<num; i++) { | 839 | for (i=0; i<num; i++) { | |
839 | info = &table[i]; | 840 | info = &table[i]; | |
840 | 841 | |||
841 | /* always check funct3 first */ | 842 | /* always check funct3 first */ | |
842 | if (info->matchflags & CHECK_F3) { | 843 | if (info->matchflags & CHECK_F3) { | |
843 | if (info->funct3 != f3) { | 844 | if (info->funct3 != f3) { | |
844 | continue; | 845 | continue; | |
845 | } | 846 | } | |
846 | } | 847 | } | |
847 | 848 | |||
848 | /* now funct7 */ | 849 | /* now funct7 */ | |
849 | testf7 = f7; | 850 | testf7 = f7; | |
850 | if (info->matchflags & SHIFT64) { | 851 | if (info->matchflags & SHIFT64) { | |
851 | /* shift count leaks into the bottom bit of funct7 */ | 852 | /* shift count leaks into the bottom bit of funct7 */ | |
852 | testf7 &= 0b1111110; | 853 | testf7 &= 0b1111110; | |
853 | } | 854 | } | |
854 | if (info->matchflags & CHECK_F5) { | 855 | if (info->matchflags & CHECK_F5) { | |
855 | /* other stuff in the bottom two bits, don't look */ | 856 | /* other stuff in the bottom two bits, don't look */ | |
856 | testf7 &= 0b1111100; | 857 | testf7 &= 0b1111100; | |
857 | } | 858 | } | |
858 | if (info->matchflags & CHECK_F7) { | 859 | if (info->matchflags & CHECK_F7) { | |
859 | if (info->funct7 != testf7) { | 860 | if (info->funct7 != testf7) { | |
860 | continue; | 861 | continue; | |
861 | } | 862 | } | |
862 | } | 863 | } | |
863 | 864 | |||
864 | /* finally rs2 as the 4th opcode field */ | 865 | /* finally rs2 as the 4th opcode field */ | |
865 | if (info->matchflags & CHECK_RS2) { | 866 | if (info->matchflags & CHECK_RS2) { | |
866 | if (info->rs2 != INSN_RS2(insn)) { | 867 | if (info->rs2 != INSN_RS2(insn)) { | |
867 | continue; | 868 | continue; | |
868 | } | 869 | } | |
869 | } | 870 | } | |
870 | 871 | |||
871 | /* check fields that are supposed to be 0 */ | 872 | /* check fields that are supposed to be 0 */ | |
872 | if (info->matchflags & RD_0) { | 873 | if (info->matchflags & RD_0) { | |
873 | if (INSN_RD(insn) != 0) { | 874 | if (INSN_RD(insn) != 0) { | |
874 | continue; | 875 | continue; | |
875 | } | 876 | } | |
876 | } | 877 | } | |
877 | if (info->matchflags & RS1_0) { | 878 | if (info->matchflags & RS1_0) { | |
878 | if (INSN_RS1(insn) != 0) { | 879 | if (INSN_RS1(insn) != 0) { | |
879 | continue; | 880 | continue; | |
880 | } | 881 | } | |
881 | } | 882 | } | |
882 | if (info->matchflags & RS2_0) { | 883 | if (info->matchflags & RS2_0) { | |
883 | /* this could be folded into CHECK_RS2 */ | 884 | /* this could be folded into CHECK_RS2 */ | |
884 | /* (but would make the initializations uglier) */ | 885 | /* (but would make the initializations uglier) */ | |
885 | if (INSN_RS2(insn) != 0) { | 886 | if (INSN_RS2(insn) != 0) { | |
886 | continue; | 887 | continue; | |
887 | } | 888 | } | |
888 | } | 889 | } | |
889 | if (info->matchflags & IMM_0) { | 890 | if (info->matchflags & IMM_0) { | |
890 | if (imm != 0) { | 891 | if (imm != 0) { | |
891 | continue; | 892 | continue; | |
892 | } | 893 | } | |
893 | } | 894 | } | |
894 | 895 | |||
895 | /* other checks */ | 896 | /* other checks */ | |
896 | if (info->matchflags & F3AMO) { | 897 | if (info->matchflags & F3AMO) { | |
897 | if (f3 != AMO_W && f3 != AMO_D) { | 898 | if (f3 != AMO_W && f3 != AMO_D) { | |
898 | continue; | 899 | continue; | |
899 | } | 900 | } | |
900 | } | 901 | } | |
901 | if (info->matchflags & F3ROUND) { | 902 | if (info->matchflags & F3ROUND) { | |
902 | switch (f3) { | 903 | switch (f3) { | |
903 | case ROUND_RNE: | 904 | case ROUND_RNE: | |
904 | case ROUND_RTZ: | 905 | case ROUND_RTZ: | |
905 | case ROUND_RDN: | 906 | case ROUND_RDN: | |
906 | case ROUND_RUP: | 907 | case ROUND_RUP: | |
907 | case ROUND_RMM: | 908 | case ROUND_RMM: | |
908 | case ROUND_DYN: | 909 | case ROUND_DYN: | |
909 | break; | 910 | break; | |
910 | default: | 911 | default: | |
911 | continue; | 912 | continue; | |
912 | } | 913 | } | |
913 | } | 914 | } | |
914 | if (info->matchflags & F7SIZE) { | 915 | if (info->matchflags & F7SIZE) { | |
915 | /* fpu size bits at bottom of funct7 */ | 916 | /* fpu size bits at bottom of funct7 */ | |
916 | /* always floating sizes */ | 917 | /* always floating sizes */ | |
917 | switch (f7 & 3) { | 918 | switch (f7 & 3) { | |
918 | case OPFP_S: | 919 | case OPFP_S: | |
919 | case OPFP_D: | 920 | case OPFP_D: | |
920 | case OPFP_Q: | 921 | case OPFP_Q: | |
921 | break; | 922 | break; | |
922 | default: | 923 | default: | |
923 | continue; | 924 | continue; | |
924 | } | 925 | } | |
925 | } | 926 | } | |
926 | if (info->matchflags & RS2_FSIZE) { | 927 | if (info->matchflags & RS2_FSIZE) { | |
927 | /* fpu size bits in rs2 field */ | 928 | /* fpu size bits in rs2 field */ | |
928 | if (info->matchflags & RS2_FSIZE_INT) { | 929 | if (info->matchflags & RS2_FSIZE_INT) { | |
929 | /* integer sizes */ | 930 | /* integer sizes */ | |
930 | switch (INSN_RS2(insn)) { | 931 | switch (INSN_RS2(insn)) { | |
931 | case OPFP_W: | 932 | case OPFP_W: | |
932 | case OPFP_WU: | 933 | case OPFP_WU: | |
933 | case OPFP_L: | 934 | case OPFP_L: | |
934 | case OPFP_LU: | 935 | case OPFP_LU: | |
935 | break; | 936 | break; | |
936 | default: | 937 | default: | |
937 | continue; | 938 | continue; | |
938 | } | 939 | } | |
939 | } | 940 | } | |
940 | else { | 941 | else { | |
941 | /* floating sizes */ | 942 | /* floating sizes */ | |
942 | switch (INSN_RS2(insn)) { | 943 | switch (INSN_RS2(insn)) { | |
943 | case OPFP_S: | 944 | case OPFP_S: | |
944 | case OPFP_D: | 945 | case OPFP_D: | |
945 | case OPFP_Q: | 946 | case OPFP_Q: | |
946 | break; | 947 | break; | |
947 | default: | 948 | default: | |
948 | continue; | 949 | continue; | |
949 | } | 950 | } | |
950 | } | 951 | } | |
951 | } | 952 | } | |
952 | if (info->matchflags & FENCEFM) { | 953 | if (info->matchflags & FENCEFM) { | |
953 | /* imm is 12 bits, upper 4 are a fence mode */ | 954 | /* imm is 12 bits, upper 4 are a fence mode */ | |
954 | switch (imm >> 8) { | 955 | switch (imm >> 8) { | |
955 | case FENCE_FM_NORMAL: | 956 | case FENCE_FM_NORMAL: | |
956 | case FENCE_FM_TSO: | 957 | case FENCE_FM_TSO: | |
957 | break; | 958 | break; | |
958 | default: | 959 | default: | |
959 | continue; | 960 | continue; | |
960 | } | 961 | } | |
961 | } | 962 | } | |
962 | 963 | |||
963 | /* passed all tests */ | 964 | /* passed all tests */ | |
964 | return info; | 965 | return info; | |
965 | } | 966 | } | |
966 | /* no match */ | 967 | /* no match */ | |
967 | return NULL; | 968 | return NULL; | |
968 | } | 969 | } | |
969 | 970 | |||
970 | static void | 971 | static void | |
971 | db_print_riscv_fencebits(unsigned bits) | 972 | db_print_riscv_fencebits(unsigned bits) | |
972 | { | 973 | { | |
973 | if (bits == 0) { | 974 | if (bits == 0) { | |
974 | db_printf("0"); | 975 | db_printf("0"); | |
975 | } | 976 | } | |
976 | else { | 977 | else { | |
977 | db_printf("%s%s%s%s", | 978 | db_printf("%s%s%s%s", | |
978 | (bits & FENCE_INPUT) ? "i" : "", | 979 | (bits & FENCE_INPUT) ? "i" : "", | |
979 | (bits & FENCE_OUTPUT) ? "o" : "", | 980 | (bits & FENCE_OUTPUT) ? "o" : "", | |
980 | (bits & FENCE_READ) ? "r" : "", | 981 | (bits & FENCE_READ) ? "r" : "", | |
981 | (bits & FENCE_WRITE) ? "w" : ""); | 982 | (bits & FENCE_WRITE) ? "w" : ""); | |
982 | } | 983 | } | |
983 | } | 984 | } | |
984 | 985 | |||
985 | static void | 986 | static void | |
986 | db_print_riscv_reg(unsigned reg, bool isfreg) | 987 | db_print_riscv_reg(unsigned reg, bool isfreg) | |
987 | { | 988 | { | |
988 | if (isfreg) { | 989 | if (isfreg) { | |
989 | db_printf("f%d", reg); | 990 | db_printf("f%d", reg); | |
990 | } | 991 | } | |
991 | else { | 992 | else { | |
992 | db_printf("%s", riscv_registers[reg]); | 993 | db_printf("%s", riscv_registers[reg]); | |
993 | } | 994 | } | |
994 | } | 995 | } | |
995 | 996 | |||
996 | static const char * | 997 | static const char * | |
997 | riscv_int_size(unsigned fpsize) | 998 | riscv_int_size(unsigned fpsize) | |
998 | { | 999 | { | |
999 | switch (fpsize) { | 1000 | switch (fpsize) { | |
1000 | case OPFP_W: return ".w"; | 1001 | case OPFP_W: return ".w"; | |
1001 | case OPFP_WU: return ".wu"; | 1002 | case OPFP_WU: return ".wu"; | |
1002 | case OPFP_L: return ".l"; | 1003 | case OPFP_L: return ".l"; | |
1003 | case OPFP_LU: return ".lu"; | 1004 | case OPFP_LU: return ".lu"; | |
1004 | default: | 1005 | default: | |
1005 | /* matching should prevent it coming here */ | 1006 | /* matching should prevent it coming here */ | |
1006 | KASSERT(0); | 1007 | KASSERT(0); | |
1007 | return ".?"; | 1008 | return ".?"; | |
1008 | } | 1009 | } | |
1009 | } | 1010 | } | |
1010 | 1011 | |||
1011 | static const char * | 1012 | static const char * | |
1012 | riscv_fp_size(unsigned fpsize) | 1013 | riscv_fp_size(unsigned fpsize) | |
1013 | { | 1014 | { | |
1014 | switch (fpsize) { | 1015 | switch (fpsize) { | |
1015 | case OPFP_S: return ".s"; | 1016 | case OPFP_S: return ".s"; | |
1016 | case OPFP_D: return ".d"; | 1017 | case OPFP_D: return ".d"; | |
1017 | case OPFP_Q: return ".q"; | 1018 | case OPFP_Q: return ".q"; | |
1018 | default: | 1019 | default: | |
1019 | /* matching should prevent it coming here */ | 1020 | /* matching should prevent it coming here */ | |
1020 | KASSERT(0); | 1021 | KASSERT(0); | |
1021 | return ".?"; | 1022 | return ".?"; | |
1022 | } | 1023 | } | |
1023 | } | 1024 | } | |
1024 | 1025 | |||
1025 | static bool | 1026 | static bool | |
1026 | larger_f_i(unsigned sz1, unsigned sz2) | 1027 | larger_f_i(unsigned sz1, unsigned sz2) | |
1027 | { | 1028 | { | |
1028 | switch (sz1) { | 1029 | switch (sz1) { | |
1029 | case OPFP_S: | 1030 | case OPFP_S: | |
1030 | break; | 1031 | break; | |
1031 | case OPFP_D: | 1032 | case OPFP_D: | |
1032 | switch (sz2) { | 1033 | switch (sz2) { | |
1033 | case OPFP_W: | 1034 | case OPFP_W: | |
1034 | case OPFP_WU: | 1035 | case OPFP_WU: | |
1035 | return true; | 1036 | return true; | |
1036 | default: | 1037 | default: | |
1037 | break; | 1038 | break; | |
1038 | } | 1039 | } | |
1039 | break; | 1040 | break; | |
1040 | case OPFP_Q: | 1041 | case OPFP_Q: | |
1041 | switch (sz2) { | 1042 | switch (sz2) { | |
1042 | case OPFP_W: | 1043 | case OPFP_W: | |
1043 | case OPFP_WU: | 1044 | case OPFP_WU: | |
1044 | case OPFP_L: | 1045 | case OPFP_L: | |
1045 | case OPFP_LU: | 1046 | case OPFP_LU: | |
1046 | return true; | 1047 | return true; | |
1047 | default: | 1048 | default: | |
1048 | break; | 1049 | break; | |
1049 | } | 1050 | } | |
1050 | break; | 1051 | break; | |
1051 | default: | 1052 | default: | |
1052 | /* matching should keep it from coming here */ | 1053 | /* matching should keep it from coming here */ | |
1053 | KASSERT(0); | 1054 | KASSERT(0); | |
1054 | break; | 1055 | break; | |
1055 | } | 1056 | } | |
1056 | return false; | 1057 | return false; | |
1057 | } | 1058 | } | |
1058 | 1059 | |||
1059 | static bool | 1060 | static bool | |
1060 | larger_f_f(unsigned sz1, unsigned sz2) | 1061 | larger_f_f(unsigned sz1, unsigned sz2) | |
1061 | { | 1062 | { | |
1062 | switch (sz1) { | 1063 | switch (sz1) { | |
1063 | case OPFP_S: | 1064 | case OPFP_S: | |
1064 | break; | 1065 | break; | |
1065 | case OPFP_D: | 1066 | case OPFP_D: | |
1066 | switch (sz2) { | 1067 | switch (sz2) { | |
1067 | case OPFP_S: | 1068 | case OPFP_S: | |
1068 | return true; | 1069 | return true; | |
1069 | default: | 1070 | default: | |
1070 | break; | 1071 | break; | |
1071 | } | 1072 | } | |
1072 | break; | 1073 | break; | |
1073 | case OPFP_Q: | 1074 | case OPFP_Q: | |
1074 | switch (sz2) { | 1075 | switch (sz2) { | |
1075 | case OPFP_S: | 1076 | case OPFP_S: | |
1076 | case OPFP_D: | 1077 | case OPFP_D: | |
1077 | return true; | 1078 | return true; | |
1078 | default: | 1079 | default: | |
1079 | break; | 1080 | break; | |
1080 | } | 1081 | } | |
1081 | break; | 1082 | break; | |
1082 | default: | 1083 | default: | |
1083 | /* matching should keep it from coming here */ | 1084 | /* matching should keep it from coming here */ | |
1084 | KASSERT(0); | 1085 | KASSERT(0); | |
1085 | break; | 1086 | break; | |
1086 | } | 1087 | } | |
1087 | return false; | 1088 | return false; | |
1088 | } | 1089 | } | |
1089 | 1090 | |||
1090 | static void | 1091 | static void | |
1091 | db_print_riscv_fpround(const char *sep, unsigned round) | 1092 | db_print_riscv_fpround(const char *sep, unsigned round) | |
1092 | { | 1093 | { | |
1093 | switch (round) { | 1094 | switch (round) { | |
1094 | case ROUND_RNE: db_printf("%srne", sep); break; | 1095 | case ROUND_RNE: db_printf("%srne", sep); break; | |
1095 | case ROUND_RTZ: db_printf("%srtz", sep); break; | 1096 | case ROUND_RTZ: db_printf("%srtz", sep); break; | |
1096 | case ROUND_RDN: db_printf("%srdn", sep); break; | 1097 | case ROUND_RDN: db_printf("%srdn", sep); break; | |
1097 | case ROUND_RUP: db_printf("%srup", sep); break; | 1098 | case ROUND_RUP: db_printf("%srup", sep); break; | |
1098 | case ROUND_RMM: db_printf("%srmm", sep); break; | 1099 | case ROUND_RMM: db_printf("%srmm", sep); break; | |
1099 | case ROUND_DYN: break; | 1100 | case ROUND_DYN: break; | |
1100 | default: | 1101 | default: | |
1101 | /* matching should prevent it coming here */ | 1102 | /* matching should prevent it coming here */ | |
1102 | KASSERT(0); | 1103 | KASSERT(0); | |
1103 | db_printf("%s<unknown-rounding-mode>", sep); | 1104 | db_printf("%s<unknown-rounding-mode>", sep); | |
1104 | break; | 1105 | break; | |
1105 | } | 1106 | } | |
1106 | } | 1107 | } | |
1107 | 1108 | |||
1108 | 1109 | |||
1109 | static void | 1110 | static void | |
1110 | db_print_riscv_insnname(uint32_t insn, const struct riscv_disasm_insn *info) | 1111 | db_print_riscv_insnname(uint32_t insn, const struct riscv_disasm_insn *info) | |
1111 | { | 1112 | { | |
1112 | db_printf("%s", info->name); | 1113 | db_printf("%s", info->name); | |
1113 | 1114 | |||
1114 | /* accumulated mode cruft on the name */ | 1115 | /* accumulated mode cruft on the name */ | |
1115 | if (info->matchflags & F3AMO) { | 1116 | if (info->matchflags & F3AMO) { | |
1116 | db_printf("%s", INSN_FUNCT3(insn) == AMO_W ? ".w" : ".d"); | 1117 | db_printf("%s", INSN_FUNCT3(insn) == AMO_W ? ".w" : ".d"); | |
1117 | } | 1118 | } | |
1118 | if ((info->matchflags & RS2_FSIZE) && | 1119 | if ((info->matchflags & RS2_FSIZE) && | |
1119 | (info->printflags & RS2SIZE_FIRST)) { | 1120 | (info->printflags & RS2SIZE_FIRST)) { | |
1120 | if (info->matchflags & RS2_FSIZE_INT) { | 1121 | if (info->matchflags & RS2_FSIZE_INT) { | |
1121 | db_printf("%s", riscv_int_size(INSN_RS2(insn))); | 1122 | db_printf("%s", riscv_int_size(INSN_RS2(insn))); | |
1122 | } | 1123 | } | |
1123 | else { | 1124 | else { | |
1124 | db_printf("%s", riscv_fp_size(INSN_RS2(insn))); | 1125 | db_printf("%s", riscv_fp_size(INSN_RS2(insn))); | |
1125 | } | 1126 | } | |
1126 | } | 1127 | } | |
1127 | if (info->matchflags & F7SIZE) { | 1128 | if (info->matchflags & F7SIZE) { | |
1128 | db_printf("%s", riscv_fp_size(INSN_FUNCT7(insn) & 3)); | 1129 | db_printf("%s", riscv_fp_size(INSN_FUNCT7(insn) & 3)); | |
1129 | } | 1130 | } | |
1130 | if ((info->matchflags & RS2_FSIZE) && | 1131 | if ((info->matchflags & RS2_FSIZE) && | |
1131 | (info->printflags & RS2SIZE_FIRST) == 0) { | 1132 | (info->printflags & RS2SIZE_FIRST) == 0) { | |
1132 | if (info->matchflags & RS2_FSIZE_INT) { | 1133 | if (info->matchflags & RS2_FSIZE_INT) { | |
1133 | db_printf("%s", riscv_int_size(INSN_RS2(insn))); | 1134 | db_printf("%s", riscv_int_size(INSN_RS2(insn))); | |
1134 | } | 1135 | } | |
1135 | else { | 1136 | else { | |
1136 | db_printf("%s", riscv_fp_size(INSN_RS2(insn))); | 1137 | db_printf("%s", riscv_fp_size(INSN_RS2(insn))); | |
1137 | } | 1138 | } | |
1138 | } | 1139 | } | |
1139 | if (info->matchflags & FENCEFM) { | 1140 | if (info->matchflags & FENCEFM) { | |
1140 | /* | 1141 | /* | |
1141 | * The fence mode is the top 4 bits of the instruction, | 1142 | * The fence mode is the top 4 bits of the instruction, | |
1142 | * which is the top 4 bits of funct7, so get it from | 1143 | * which is the top 4 bits of funct7, so get it from | |
1143 | * there. Elsewhere in this file it's defined in terms | 1144 | * there. Elsewhere in this file it's defined in terms | |
1144 | * of the immediate though. XXX tidy up | 1145 | * of the immediate though. XXX tidy up | |
1145 | */ | 1146 | */ | |
1146 | if ((INSN_FUNCT7(insn) >> 3) == FENCE_FM_TSO) { | 1147 | if ((INSN_FUNCT7(insn) >> 3) == FENCE_FM_TSO) { | |
1147 | db_printf(".tso"); | 1148 | db_printf(".tso"); | |
1148 | } | 1149 | } | |
1149 | } | 1150 | } | |
1150 | if (info->printflags & AMOAQRL) { | 1151 | if (info->printflags & AMOAQRL) { | |
1151 | db_printf("%s%s", | 1152 | db_printf("%s%s", | |
1152 | INSN_FUNCT7(insn) & AMO_AQ ? ".aq" : "", | 1153 | INSN_FUNCT7(insn) & AMO_AQ ? ".aq" : "", | |
1153 | INSN_FUNCT7(insn) & AMO_RL ? ".rl" : ""); | 1154 | INSN_FUNCT7(insn) & AMO_RL ? ".rl" : ""); | |
1154 | } | 1155 | } | |
1155 | } | 1156 | } | |
1156 | 1157 | |||
1157 | static int | 1158 | static int | |
1158 | db_disasm_32(db_addr_t loc, uint32_t insn, bool altfmt) | 1159 | db_disasm_32(db_addr_t loc, uint32_t insn, bool altfmt) | |
1159 | { | 1160 | { | |
1160 | unsigned opcode; | 1161 | unsigned opcode; | |
1161 | const struct riscv_disasm32_entry *d; | 1162 | const struct riscv_disasm32_entry *d; | |
1162 | unsigned numtable; | 1163 | unsigned numtable; | |
1163 | const struct riscv_disasm_insn *table, *info; | 1164 | const struct riscv_disasm_insn *table, *info; | |
1164 | const char *sep = " "; | 1165 | const char *sep = " "; | |
1165 | uint32_t imm; | 1166 | uint32_t imm; | |
1166 | 1167 | |||
1167 | opcode = INSN_OPCODE32(insn); | 1168 | opcode = INSN_OPCODE32(insn); | |
1168 | d = &riscv_disasm32[opcode]; | 1169 | d = &riscv_disasm32[opcode]; | |
1169 | switch (d->fmt) { | 1170 | switch (d->fmt) { | |
1170 | case FMT_R: | 1171 | case FMT_R: | |
1171 | /* register ops */ | 1172 | /* register ops */ | |
1172 | table = d->u.entries.v; | 1173 | table = d->u.entries.v; | |
1173 | numtable = d->u.entries.n; | 1174 | numtable = d->u.entries.n; | |
1174 | info = riscv_disasm_match(table, numtable, insn, 0); | 1175 | info = riscv_disasm_match(table, numtable, insn, 0); | |
1175 | if (info == NULL) { | 1176 | if (info == NULL) { | |
1176 | return EINVAL; | 1177 | return EINVAL; | |
1177 | } | 1178 | } | |
1178 | 1179 | |||
1179 | /* name */ | 1180 | /* name */ | |
1180 | db_print_riscv_insnname(insn, info); | 1181 | db_print_riscv_insnname(insn, info); | |
1181 | 1182 | |||
1182 | /* rd */ | 1183 | /* rd */ | |
1183 | if ((info->matchflags & RD_0) == 0) { | 1184 | if ((info->matchflags & RD_0) == 0) { | |
1184 | db_printf("%s", sep); | 1185 | db_printf("%s", sep); | |
1185 | db_print_riscv_reg(INSN_RD(insn), | 1186 | db_print_riscv_reg(INSN_RD(insn), | |
1186 | info->printflags & RD_FREG); | 1187 | info->printflags & RD_FREG); | |
1187 | sep = ", "; | 1188 | sep = ", "; | |
1188 | } | 1189 | } | |
1189 | 1190 | |||
1190 | if (info->printflags & CSRIMM) { | 1191 | if (info->printflags & CSRIMM) { | |
1191 | /* | 1192 | /* | |
1192 | * CSR instruction; these appear under a major | 1193 | * CSR instruction; these appear under a major | |
1193 | * opcode with register format, but they | 1194 | * opcode with register format, but they | |
1194 | * actually use the I format. Sigh. The | 1195 | * actually use the I format. Sigh. The | |
1195 | * immediate field contains the CSR number and | 1196 | * immediate field contains the CSR number and | |
1196 | * prints _before_ rs1. | 1197 | * prints _before_ rs1. | |
1197 | */ | 1198 | */ | |
1198 | imm = INSN_IMM_I(insn); | 1199 | imm = INSN_IMM_I(insn); | |
1199 | db_printf("%s0x%x, ", sep, (int32_t)imm); | 1200 | db_printf("%s0x%x, ", sep, (int32_t)imm); | |
1200 | db_print_riscv_reg(INSN_RS1(insn), | 1201 | db_print_riscv_reg(INSN_RS1(insn), | |
1201 | info->printflags & RS1_FREG); | 1202 | info->printflags & RS1_FREG); | |
1202 | } else if (info->printflags & CSRIIMM) { | 1203 | } else if (info->printflags & CSRIIMM) { | |
1203 | /* | 1204 | /* | |
1204 | * CSR instruction with immediate; the CSR | 1205 | * CSR instruction with immediate; the CSR | |
1205 | * number is in the immediate fiel and the RS1 | 1206 | * number is in the immediate fiel and the RS1 | |
1206 | * field contains the immediate. Bleck. | 1207 | * field contains the immediate. Bleck. | |
1207 | */ | 1208 | */ | |
1208 | imm = INSN_IMM_I(insn); | 1209 | imm = INSN_IMM_I(insn); | |
1209 | db_printf("%s0x%x, %d", sep, (int32_t)imm, | 1210 | db_printf("%s0x%x, %d", sep, (int32_t)imm, | |
1210 | INSN_RS1(insn)); | 1211 | INSN_RS1(insn)); | |
1211 | } | 1212 | } | |
1212 | else { | 1213 | else { | |
1213 | /* rs1 */ | 1214 | /* rs1 */ | |
1214 | if ((info->matchflags & RS1_0) == 0) { | 1215 | if ((info->matchflags & RS1_0) == 0) { | |
1215 | db_printf("%s", sep); | 1216 | db_printf("%s", sep); | |
1216 | db_print_riscv_reg(INSN_RS1(insn), | 1217 | db_print_riscv_reg(INSN_RS1(insn), | |
1217 | info->printflags & RS1_FREG); | 1218 | info->printflags & RS1_FREG); | |
1218 | sep = ", "; | 1219 | sep = ", "; | |
1219 | } | 1220 | } | |
1220 | 1221 | |||
1221 | /* rs2 */ | 1222 | /* rs2 */ | |
1222 | if ((info->matchflags & RS2_0) == 0 && | 1223 | if ((info->matchflags & RS2_0) == 0 && | |
1223 | (info->matchflags & CHECK_RS2) == 0 && | 1224 | (info->matchflags & CHECK_RS2) == 0 && | |
1224 | (info->matchflags & RS2_FSIZE) == 0) { | 1225 | (info->matchflags & RS2_FSIZE) == 0) { | |
1225 | db_printf("%s", sep); | 1226 | db_printf("%s", sep); | |
1226 | db_print_riscv_reg(INSN_RS2(insn), | 1227 | db_print_riscv_reg(INSN_RS2(insn), | |
1227 | info->printflags & RS2_FREG); | 1228 | info->printflags & RS2_FREG); | |
1228 | } | 1229 | } | |
1229 | } | 1230 | } | |
1230 | 1231 | |||
1231 | if (info->matchflags & F3ROUND) { | 1232 | if (info->matchflags & F3ROUND) { | |
1232 | /* | 1233 | /* | |
1233 | * Suppress rounding mode print for insns that | 1234 | * Suppress rounding mode print for insns that | |
1234 | * never round, because gas encodes it as 0 | 1235 | * never round, because gas encodes it as 0 | |
1235 | * ("rup") rather than the normal default | 1236 | * ("rup") rather than the normal default | |
1236 | * ("dyn"). | 1237 | * ("dyn"). | |
1237 | * | 1238 | * | |
1238 | * These are: convert float to larger float, | 1239 | * These are: convert float to larger float, | |
1239 | * convert int to float larger than the float. | 1240 | * convert int to float larger than the float. | |
1240 | */ | 1241 | */ | |
1241 | bool suppress; | 1242 | bool suppress; | |
1242 | 1243 | |||
1243 | if (info->printflags & ISCVT) { | 1244 | if (info->printflags & ISCVT) { | |
1244 | KASSERT(info->matchflags & F7SIZE); | 1245 | KASSERT(info->matchflags & F7SIZE); | |
1245 | KASSERT(info->matchflags & RS2_FSIZE); | 1246 | KASSERT(info->matchflags & RS2_FSIZE); | |
1246 | if (info->matchflags & RS2SIZE_FIRST) { | 1247 | if (info->matchflags & RS2SIZE_FIRST) { | |
1247 | /* convert to int */ | 1248 | /* convert to int */ | |
1248 | suppress = false; | 1249 | suppress = false; | |
1249 | } | 1250 | } | |
1250 | else if (info->matchflags & RS2_FSIZE_INT) { | 1251 | else if (info->matchflags & RS2_FSIZE_INT) { | |
1251 | /* convert from int */ | 1252 | /* convert from int */ | |
1252 | suppress = larger_f_i( | 1253 | suppress = larger_f_i( | |
1253 | INSN_FUNCT7(insn) & 3, | 1254 | INSN_FUNCT7(insn) & 3, | |
1254 | INSN_RS2(insn)); | 1255 | INSN_RS2(insn)); | |
1255 | } | 1256 | } | |
1256 | else { | 1257 | else { | |
1257 | /* convert from float */ | 1258 | /* convert from float */ | |
1258 | suppress = larger_f_f( | 1259 | suppress = larger_f_f( | |
1259 | INSN_FUNCT7(insn) & 3, | 1260 | INSN_FUNCT7(insn) & 3, | |
1260 | INSN_RS2(insn)); | 1261 | INSN_RS2(insn)); | |
1261 | } | 1262 | } | |
1262 | } | 1263 | } | |
1263 | else { | 1264 | else { | |
1264 | suppress = false; | 1265 | suppress = false; | |
1265 | } | 1266 | } | |
1266 | 1267 | |||
1267 | if (!suppress) { | 1268 | if (!suppress) { | |
1268 | db_print_riscv_fpround(sep, INSN_FUNCT3(insn)); | 1269 | db_print_riscv_fpround(sep, INSN_FUNCT3(insn)); | |
1269 | } | 1270 | } | |
1270 | } | 1271 | } | |
1271 | 1272 | |||
1272 | db_printf("\n"); | 1273 | db_printf("\n"); | |
1273 | break; | 1274 | break; | |
1274 | case FMT_R4: | 1275 | case FMT_R4: | |
1275 | db_printf("%s%s f%d, f%d, f%d, f%d", d->u.name, | 1276 | db_printf("%s%s f%d, f%d, f%d, f%d", d->u.name, | |
1276 | riscv_fp_size(INSN_FUNCT7(insn) & 3), | 1277 | riscv_fp_size(INSN_FUNCT7(insn) & 3), | |
1277 | INSN_RD(insn), | 1278 | INSN_RD(insn), | |
1278 | INSN_RS1(insn), | 1279 | INSN_RS1(insn), | |
1279 | INSN_RS2(insn), | 1280 | INSN_RS2(insn), | |
1280 | INSN_FUNCT7(insn) >> 2); | 1281 | INSN_FUNCT7(insn) >> 2); | |
1281 | db_print_riscv_fpround(", ", INSN_FUNCT3(insn)); | 1282 | db_print_riscv_fpround(", ", INSN_FUNCT3(insn)); | |
1282 | db_printf("\n"); | 1283 | db_printf("\n"); | |
1283 | break; | 1284 | break; | |
1284 | case FMT_I: | 1285 | case FMT_I: | |
1285 | /* immediates */ | 1286 | /* immediates */ | |
1286 | imm = INSN_IMM_I(insn); | 1287 | imm = INSN_IMM_I(insn); | |
1287 | 1288 | |||
1288 | table = d->u.entries.v; | 1289 | table = d->u.entries.v; | |
1289 | numtable = d->u.entries.n; | 1290 | numtable = d->u.entries.n; | |
1290 | info = riscv_disasm_match(table, numtable, insn, imm); | 1291 | info = riscv_disasm_match(table, numtable, insn, imm); | |
1291 | if (info == NULL) { | 1292 | if (info == NULL) { | |
1292 | return EINVAL; | 1293 | return EINVAL; | |
1293 | } | 1294 | } | |
1294 | 1295 | |||
1295 | if (info->matchflags & SHIFT32) { | 1296 | if (info->matchflags & SHIFT32) { | |
1296 | imm &= 31; | 1297 | imm &= 31; | |
1297 | } else if (info->matchflags & SHIFT64) { | 1298 | } else if (info->matchflags & SHIFT64) { | |
1298 | imm &= 63; | 1299 | imm &= 63; | |
1299 | } | 1300 | } | |
1300 | 1301 | |||
1301 | /* name */ | 1302 | /* name */ | |
1302 | db_print_riscv_insnname(insn, info); | 1303 | db_print_riscv_insnname(insn, info); | |
1303 | 1304 | |||
1304 | /* rd */ | 1305 | /* rd */ | |
1305 | if ((info->matchflags & RD_0) == 0) { | 1306 | if ((info->matchflags & RD_0) == 0) { | |
1306 | db_printf("%s", sep); | 1307 | db_printf("%s", sep); | |
1307 | db_print_riscv_reg(INSN_RD(insn), | 1308 | db_print_riscv_reg(INSN_RD(insn), | |
1308 | info->printflags & RD_FREG); | 1309 | info->printflags & RD_FREG); | |
1309 | sep = ", "; | 1310 | sep = ", "; | |
1310 | } | 1311 | } | |
1311 | 1312 | |||
1312 | if (info->printflags & MEMORYIMM) { | 1313 | if (info->printflags & MEMORYIMM) { | |
1313 | db_printf("%s", sep); | 1314 | db_printf("%s", sep); | |
1314 | db_printf("%d(", (int32_t)imm); | 1315 | db_printf("%d(", (int32_t)imm); | |
1315 | db_print_riscv_reg(INSN_RS1(insn), | 1316 | db_print_riscv_reg(INSN_RS1(insn), | |
1316 | info->printflags & RS1_FREG); | 1317 | info->printflags & RS1_FREG); | |
1317 | db_printf(")"); | 1318 | db_printf(")"); | |
1318 | } | 1319 | } | |
1319 | else { | 1320 | else { | |
1320 | /* rs1 */ | 1321 | /* rs1 */ | |
1321 | if ((info->matchflags & RS1_0) == 0) { | 1322 | if ((info->matchflags & RS1_0) == 0) { | |
1322 | db_printf("%s", sep); | 1323 | db_printf("%s", sep); | |
1323 | db_print_riscv_reg(INSN_RS1(insn), | 1324 | db_print_riscv_reg(INSN_RS1(insn), | |
1324 | info->printflags & RS1_FREG); | 1325 | info->printflags & RS1_FREG); | |
1325 | sep = ", "; | 1326 | sep = ", "; | |
1326 | } | 1327 | } | |
1327 | 1328 | |||
1328 | /* imm */ | 1329 | /* imm */ | |
1329 | if (info->matchflags & IMM_0) { | 1330 | if (info->matchflags & IMM_0) { | |
1330 | /* nothing */ | 1331 | /* nothing */ | |
1331 | } else if (info->printflags & FENCEIMM) { | 1332 | } else if (info->printflags & FENCEIMM) { | |
1332 | unsigned pred, succ; | 1333 | unsigned pred, succ; | |
1333 | 1334 | |||
1334 | /* fm is part of the name, doesn't go here */ | 1335 | /* fm is part of the name, doesn't go here */ | |
1335 | pred = (imm >> 4) & 0xf; | 1336 | pred = (imm >> 4) & 0xf; | |
1336 | succ = imm & 0xf; | 1337 | succ = imm & 0xf; | |
1337 | db_printf("%s", sep); | 1338 | db_printf("%s", sep); | |
1338 | db_print_riscv_fencebits(pred); | 1339 | db_print_riscv_fencebits(pred); | |
1339 | db_printf(", "); | 1340 | db_printf(", "); | |
1340 | db_print_riscv_fencebits(succ); | 1341 | db_print_riscv_fencebits(succ); | |
1341 | } else if (info->printflags & BRANCHIMM) { | 1342 | } else if (info->printflags & BRANCHIMM) { | |
1342 | /* should be B format and not come here */ | 1343 | /* should be B format and not come here */ | |
1343 | KASSERT(0); | 1344 | KASSERT(0); | |
1344 | } else if (info->printflags & DECIMM) { | 1345 | } else if (info->printflags & DECIMM) { | |
1345 | db_printf("%s%d", sep, (int32_t)imm); | 1346 | db_printf("%s%d", sep, (int32_t)imm); | |
1346 | } else { | 1347 | } else { | |
1347 | db_printf("%s0x%x", sep, imm); | 1348 | db_printf("%s0x%x", sep, imm); | |
1348 | } | 1349 | } | |
1349 | } | 1350 | } | |
1350 | db_printf("\n"); | 1351 | db_printf("\n"); | |
1351 | break; | 1352 | break; | |
1352 | case FMT_In: | 1353 | case FMT_In: | |
1353 | /* same as I but funct3 should be 0 so just one case */ | 1354 | /* same as I but funct3 should be 0 so just one case */ | |
1354 | if (INSN_FUNCT3(insn) != 0) { | 1355 | if (INSN_FUNCT3(insn) != 0) { | |
1355 | return EINVAL; | 1356 | return EINVAL; | |
1356 | } | 1357 | } | |
1357 | db_printf("%s %s, %s, 0x%x\n", | 1358 | db_printf("%s %s, %s, 0x%x\n", | |
1358 | d->u.name, | 1359 | d->u.name, | |
1359 | riscv_registers[INSN_RD(insn)], | 1360 | riscv_registers[INSN_RD(insn)], | |
1360 | riscv_registers[INSN_RS1(insn)], | 1361 | riscv_registers[INSN_RS1(insn)], | |
1361 | INSN_IMM_I(insn)); | 1362 | INSN_IMM_I(insn)); | |
1362 | break; | 1363 | break; | |
1363 | case FMT_S: | 1364 | case FMT_S: | |
1364 | /* stores */ | 1365 | /* stores */ | |
1365 | imm = INSN_IMM_S(insn); | 1366 | imm = INSN_IMM_S(insn); | |
1366 | 1367 | |||
1367 | table = d->u.entries.v; | 1368 | table = d->u.entries.v; | |
1368 | numtable = d->u.entries.n; | 1369 | numtable = d->u.entries.n; | |
1369 | info = riscv_disasm_match(table, numtable, insn, imm); | 1370 | info = riscv_disasm_match(table, numtable, insn, imm); | |
1370 | if (info == NULL) { | 1371 | if (info == NULL) { | |
1371 | return EINVAL; | 1372 | return EINVAL; | |
1372 | } | 1373 | } | |
1373 | 1374 | |||
1374 | KASSERT((info->matchflags & (RS1_0 | RS2_0 | CHECK_RS2)) == 0); | 1375 | KASSERT((info->matchflags & (RS1_0 | RS2_0 | CHECK_RS2)) == 0); | |
1375 | KASSERT(info->printflags & MEMORYIMM); | 1376 | KASSERT(info->printflags & MEMORYIMM); | |
1376 | 1377 | |||
1377 | /* name */ | 1378 | /* name */ | |
1378 | db_print_riscv_insnname(insn, info); | 1379 | db_print_riscv_insnname(insn, info); | |
1379 | db_printf(" "); | 1380 | db_printf(" "); | |
1380 | 1381 | |||
1381 | db_print_riscv_reg(INSN_RS2(insn), | 1382 | db_print_riscv_reg(INSN_RS2(insn), | |
1382 | info->printflags & RS2_FREG); | 1383 | info->printflags & RS2_FREG); | |
1383 | db_printf("%s", sep); | 1384 | db_printf("%s", sep); | |
1384 | 1385 | |||
1385 | db_printf("%d(", (int32_t)imm); | 1386 | db_printf("%d(", (int32_t)imm); | |
1386 | db_print_riscv_reg(INSN_RS1(insn), | 1387 | db_print_riscv_reg(INSN_RS1(insn), | |
1387 | info->printflags & RS1_FREG); | 1388 | info->printflags & RS1_FREG); | |
1388 | db_printf(")\n"); | 1389 | db_printf(")\n"); | |
1389 | break; | 1390 | break; | |
1390 | case FMT_B: | 1391 | case FMT_B: | |
1391 | /* branches */ | 1392 | /* branches */ | |
1392 | imm = INSN_IMM_B(insn); | 1393 | imm = INSN_IMM_B(insn); | |
1393 | 1394 | |||
1394 | table = d->u.entries.v; | 1395 | table = d->u.entries.v; | |
1395 | numtable = d->u.entries.n; | 1396 | numtable = d->u.entries.n; | |
1396 | info = riscv_disasm_match(table, numtable, insn, imm); | 1397 | info = riscv_disasm_match(table, numtable, insn, imm); | |
1397 | if (info == NULL) { | 1398 | if (info == NULL) { | |
1398 | return EINVAL; | 1399 | return EINVAL; | |
1399 | } | 1400 | } | |
1400 | 1401 | |||
1401 | KASSERT((info->matchflags & (RS1_0 | RS2_0 | CHECK_RS2)) == 0); | 1402 | KASSERT((info->matchflags & (RS1_0 | RS2_0 | CHECK_RS2)) == 0); | |
1402 | KASSERT(info->printflags & BRANCHIMM); | 1403 | KASSERT(info->printflags & BRANCHIMM); | |
1403 | 1404 | |||
1404 | /* name */ | 1405 | /* name */ | |
1405 | db_print_riscv_insnname(insn, info); | 1406 | db_print_riscv_insnname(insn, info); | |
1406 | db_printf(" "); | 1407 | db_printf(" "); | |
1407 | 1408 | |||
1408 | db_print_riscv_reg(INSN_RS1(insn), | 1409 | db_print_riscv_reg(INSN_RS1(insn), | |
1409 | info->printflags & RS1_FREG); | 1410 | info->printflags & RS1_FREG); | |
1410 | db_printf(", "); | 1411 | db_printf(", "); | |
1411 | 1412 | |||
1412 | db_print_riscv_reg(INSN_RS2(insn), | 1413 | db_print_riscv_reg(INSN_RS2(insn), | |
1413 | info->printflags & RS2_FREG); | 1414 | info->printflags & RS2_FREG); | |
1414 | db_printf(", "); | 1415 | db_printf(", "); | |
1415 | db_print_addr(loc + (int32_t)imm); | 1416 | db_print_addr(loc + (int32_t)imm); | |
1416 | db_printf("\n"); | 1417 | db_printf("\n"); | |
1417 | break; | 1418 | break; | |
1418 | case FMT_U: | 1419 | case FMT_U: | |
1419 | /* large immediates */ | 1420 | /* large immediates */ | |
1420 | db_printf("%s %s, 0x%x\n", | 1421 | db_printf("%s %s, 0x%x\n", | |
1421 | d->u.name, | 1422 | d->u.name, | |
1422 | riscv_registers[INSN_RD(insn)], | 1423 | riscv_registers[INSN_RD(insn)], | |
1423 | INSN_IMM_U(insn)); | 1424 | INSN_IMM_U(insn)); | |
1424 | break; | 1425 | break; | |
1425 | case FMT_J: | 1426 | case FMT_J: | |
1426 | /* jal */ | 1427 | /* jal */ | |
1427 | db_printf("%s %s, ", | 1428 | db_printf("%s %s, ", | |
1428 | d->u.name, | 1429 | d->u.name, | |
1429 | riscv_registers[INSN_RD(insn)]); | 1430 | riscv_registers[INSN_RD(insn)]); | |
1430 | db_print_addr(loc + (int32_t)INSN_IMM_J(insn)); | 1431 | db_print_addr(loc + (int32_t)INSN_IMM_J(insn)); | |
1431 | db_printf("\n"); | 1432 | db_printf("\n"); | |
1432 | break; | 1433 | break; | |
1433 | case FMT_UNKNOWN: | 1434 | case FMT_UNKNOWN: | |
1434 | /* reserved, custom, etc. */ | 1435 | /* reserved, custom, etc. */ | |
1435 | return EINVAL; | 1436 | return EINVAL; | |
1436 | case FMT_ASSERT: | 1437 | case FMT_ASSERT: | |
1437 | /* shouldn't have come here */ | 1438 | /* shouldn't have come here */ | |
1438 | KASSERTMSG(false, "db_disasm_32: non-32-bit instruction"); | 1439 | KASSERTMSG(false, "db_disasm_32: non-32-bit instruction"); | |
1439 | return EINVAL; | 1440 | return EINVAL; | |
1440 | } | 1441 | } | |
1441 | return 0; | 1442 | return 0; | |
1442 | } | 1443 | } | |
1443 | 1444 | |||
1444 | //////////////////////////////////////////////////////////// | 1445 | //////////////////////////////////////////////////////////// | |
1445 | 1446 | |||
1446 | static void | 1447 | static void | |
1447 | db_disasm_unknown(const uint16_t *insn, unsigned n) | 1448 | db_disasm_unknown(const uint16_t *insn, unsigned n) | |
1448 | { | 1449 | { | |
1449 | unsigned i; | 1450 | unsigned i; | |
1450 | 1451 | |||
1451 | db_printf(".insn%u 0x", n*16); | 1452 | db_printf(".insn%u 0x", n*16); | |
1452 | for (i=n; i-- > 0; ) { | 1453 | for (i=n; i-- > 0; ) { | |
1453 | db_printf("%02x", insn[i]); | 1454 | db_printf("%02x", insn[i]); | |
1454 | } | 1455 | } | |
1455 | db_printf("\n"); | 1456 | db_printf("\n"); | |
1456 | } | 1457 | } | |
1457 | 1458 | |||
1458 | db_addr_t | 1459 | db_addr_t | |
1459 | db_disasm(db_addr_t loc, bool altfmt) | 1460 | db_disasm(db_addr_t loc, bool altfmt) | |
1460 | { | 1461 | { | |
1461 | /* instructions are up to 5 halfwords */ | 1462 | /* instructions are up to 5 halfwords */ | |
1462 | uint16_t insn[5]; | 1463 | uint16_t insn[5]; | |
1463 | unsigned n, i; | 1464 | unsigned n, i; | |
1464 | uint32_t insn32; | 1465 | uint32_t insn32; | |
1465 | 1466 | |||
1466 | #ifdef _KERNEL | |||
1467 | if ((intptr_t) loc >= 0) { | |||
1468 | db_printf("%s: %#"PRIxVADDR" is not a kernel address\n", | |||
1469 | __func__, loc); | |||
1470 | return loc; | |||
1471 | } | |||
1472 | #endif | |||
1473 | ||||
1474 | /* | 1467 | /* | |
1475 | * Fetch the instruction. The first halfword tells us how many | 1468 | * Fetch the instruction. The first halfword tells us how many | |
1476 | * more there are, and they're always in little-endian order. | 1469 | * more there are, and they're always in little-endian order. | |
1477 | */ | 1470 | */ | |
1478 | insn[0] = ((const uint16_t *)loc)[0]; | 1471 | db_read_bytes(loc, sizeof(insn[0]), (void *)&insn[0]); | |
1479 | n = INSN_HALFWORDS(insn[0]); | 1472 | n = INSN_HALFWORDS(insn[0]); | |
1480 | KASSERT(n > 0 && n <= 5); | 1473 | KASSERT(n > 0 && n <= 5); | |
1481 | for (i = 1; i < n; i++) { | 1474 | for (i = 1; i < n; i++) { | |
1482 | insn[i] = ((const uint16_t *)loc)[i]; | 1475 | db_read_bytes(loc + i * sizeof(insn[i]), sizeof(insn[i]), | |
1476 | (void *)&insn[i]); | |||
1483 | } | 1477 | } | |
1484 | 1478 | |||
1485 | switch (n) { | 1479 | switch (n) { | |
1486 | case 1: | 1480 | case 1: | |
1487 | if (db_disasm_16(loc, insn[0], altfmt) != 0) { | 1481 | if (db_disasm_16(loc, insn[0], altfmt) != 0) { | |
1488 | db_disasm_unknown(insn, n); | 1482 | db_disasm_unknown(insn, n); | |
1489 | } | 1483 | } | |
1490 | break; | 1484 | break; | |
1491 | case 2: | 1485 | case 2: | |
1492 | insn32 = ((uint32_t)insn[1] << 16) | insn[0]; | 1486 | insn32 = ((uint32_t)insn[1] << 16) | insn[0]; | |
1493 | if (db_disasm_32(loc, insn32, altfmt) != 0) { | 1487 | if (db_disasm_32(loc, insn32, altfmt) != 0) { | |
1494 | db_disasm_unknown(insn, n); | 1488 | db_disasm_unknown(insn, n); | |
1495 | } | 1489 | } | |
1496 | break; | 1490 | break; | |
1497 | default: | 1491 | default: | |
1498 | /* no standard instructions of size 3+ */ | 1492 | /* no standard instructions of size 3+ */ | |
1499 | db_disasm_unknown(insn, n); | 1493 | db_disasm_unknown(insn, n); | |
1500 | break; | 1494 | break; | |
1501 | } | 1495 | } | |
1502 | return loc + n * sizeof(uint16_t); | 1496 | return loc + n * sizeof(uint16_t); | |
1503 | } | 1497 | } |
--- src/sys/arch/riscv/riscv/db_machdep.c 2021/04/14 06:32:20 1.7
+++ src/sys/arch/riscv/riscv/db_machdep.c 2021/05/23 23:22:55 1.8
@@ -1,253 +1,281 @@ | @@ -1,253 +1,281 @@ | |||
1 | /* $NetBSD: db_machdep.c,v 1.7 2021/04/14 06:32:20 dholland Exp $ */ | 1 | /* $NetBSD: db_machdep.c,v 1.8 2021/05/23 23:22:55 dholland Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2014 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Matt Thomas of 3am Software Foundry. | 8 | * by Matt Thomas of 3am Software Foundry. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | 33 | |||
34 | __RCSID("$NetBSD: db_machdep.c,v 1.7 2021/04/14 06:32:20 dholland Exp $"); | 34 | __RCSID("$NetBSD: db_machdep.c,v 1.8 2021/05/23 23:22:55 dholland Exp $"); | |
35 | 35 | |||
36 | #include <sys/param.h> | 36 | #include <sys/param.h> | |
37 | 37 | |||
38 | #include <riscv/insn.h> | 38 | #include <riscv/insn.h> | |
39 | #include <riscv/db_machdep.h> | 39 | #include <riscv/db_machdep.h> | |
40 | 40 | |||
41 | #include <ddb/db_access.h> | 41 | #include <ddb/db_access.h> | |
42 | #include <ddb/db_interface.h> | 42 | #include <ddb/db_interface.h> | |
43 | #include <ddb/db_extern.h> | 43 | #include <ddb/db_extern.h> | |
44 | #include <ddb/db_variables.h> | 44 | #include <ddb/db_variables.h> | |
45 | #include <ddb/db_output.h> | |||
45 | 46 | |||
46 | int db_active = 0; | 47 | int db_active = 0; | |
47 | 48 | |||
48 | static int db_rw_ddbreg(const struct db_variable *, db_expr_t *, int); | 49 | static int db_rw_ddbreg(const struct db_variable *, db_expr_t *, int); | |
49 | 50 | |||
50 | const struct db_variable db_regs[] = { | 51 | const struct db_variable db_regs[] = { | |
51 | { "ra", (void *)offsetof(struct trapframe, tf_ra), db_rw_ddbreg, NULL }, | 52 | { "ra", (void *)offsetof(struct trapframe, tf_ra), db_rw_ddbreg, NULL }, | |
52 | { "sp", (void *)offsetof(struct trapframe, tf_sp), db_rw_ddbreg, NULL }, | 53 | { "sp", (void *)offsetof(struct trapframe, tf_sp), db_rw_ddbreg, NULL }, | |
53 | { "gp", (void *)offsetof(struct trapframe, tf_gp), db_rw_ddbreg, NULL }, | 54 | { "gp", (void *)offsetof(struct trapframe, tf_gp), db_rw_ddbreg, NULL }, | |
54 | { "tp", (void *)offsetof(struct trapframe, tf_tp), db_rw_ddbreg, NULL }, | 55 | { "tp", (void *)offsetof(struct trapframe, tf_tp), db_rw_ddbreg, NULL }, | |
55 | { "s0", (void *)offsetof(struct trapframe, tf_s0), db_rw_ddbreg, NULL }, | 56 | { "s0", (void *)offsetof(struct trapframe, tf_s0), db_rw_ddbreg, NULL }, | |
56 | { "s1", (void *)offsetof(struct trapframe, tf_s1), db_rw_ddbreg, NULL }, | 57 | { "s1", (void *)offsetof(struct trapframe, tf_s1), db_rw_ddbreg, NULL }, | |
57 | { "s2", (void *)offsetof(struct trapframe, tf_s2), db_rw_ddbreg, NULL }, | 58 | { "s2", (void *)offsetof(struct trapframe, tf_s2), db_rw_ddbreg, NULL }, | |
58 | { "s3", (void *)offsetof(struct trapframe, tf_s3), db_rw_ddbreg, NULL }, | 59 | { "s3", (void *)offsetof(struct trapframe, tf_s3), db_rw_ddbreg, NULL }, | |
59 | { "s4", (void *)offsetof(struct trapframe, tf_s4), db_rw_ddbreg, NULL }, | 60 | { "s4", (void *)offsetof(struct trapframe, tf_s4), db_rw_ddbreg, NULL }, | |
60 | { "s5", (void *)offsetof(struct trapframe, tf_s5), db_rw_ddbreg, NULL }, | 61 | { "s5", (void *)offsetof(struct trapframe, tf_s5), db_rw_ddbreg, NULL }, | |
61 | { "s6", (void *)offsetof(struct trapframe, tf_s6), db_rw_ddbreg, NULL }, | 62 | { "s6", (void *)offsetof(struct trapframe, tf_s6), db_rw_ddbreg, NULL }, | |
62 | { "s7", (void *)offsetof(struct trapframe, tf_s7), db_rw_ddbreg, NULL }, | 63 | { "s7", (void *)offsetof(struct trapframe, tf_s7), db_rw_ddbreg, NULL }, | |
63 | { "s8", (void *)offsetof(struct trapframe, tf_s8), db_rw_ddbreg, NULL }, | 64 | { "s8", (void *)offsetof(struct trapframe, tf_s8), db_rw_ddbreg, NULL }, | |
64 | { "s9", (void *)offsetof(struct trapframe, tf_s9), db_rw_ddbreg, NULL }, | 65 | { "s9", (void *)offsetof(struct trapframe, tf_s9), db_rw_ddbreg, NULL }, | |
65 | { "s10", (void *)offsetof(struct trapframe, tf_s10), db_rw_ddbreg, NULL }, | 66 | { "s10", (void *)offsetof(struct trapframe, tf_s10), db_rw_ddbreg, NULL }, | |
66 | { "s11", (void *)offsetof(struct trapframe, tf_s11), db_rw_ddbreg, NULL }, | 67 | { "s11", (void *)offsetof(struct trapframe, tf_s11), db_rw_ddbreg, NULL }, | |
67 | { "a0", (void *)offsetof(struct trapframe, tf_a0), db_rw_ddbreg, NULL }, | 68 | { "a0", (void *)offsetof(struct trapframe, tf_a0), db_rw_ddbreg, NULL }, | |
68 | { "a1", (void *)offsetof(struct trapframe, tf_a1), db_rw_ddbreg, NULL }, | 69 | { "a1", (void *)offsetof(struct trapframe, tf_a1), db_rw_ddbreg, NULL }, | |
69 | { "a2", (void *)offsetof(struct trapframe, tf_a2), db_rw_ddbreg, NULL }, | 70 | { "a2", (void *)offsetof(struct trapframe, tf_a2), db_rw_ddbreg, NULL }, | |
70 | { "a3", (void *)offsetof(struct trapframe, tf_a3), db_rw_ddbreg, NULL }, | 71 | { "a3", (void *)offsetof(struct trapframe, tf_a3), db_rw_ddbreg, NULL }, | |
71 | { "a4", (void *)offsetof(struct trapframe, tf_a4), db_rw_ddbreg, NULL }, | 72 | { "a4", (void *)offsetof(struct trapframe, tf_a4), db_rw_ddbreg, NULL }, | |
72 | { "a5", (void *)offsetof(struct trapframe, tf_a5), db_rw_ddbreg, NULL }, | 73 | { "a5", (void *)offsetof(struct trapframe, tf_a5), db_rw_ddbreg, NULL }, | |
73 | { "a6", (void *)offsetof(struct trapframe, tf_a6), db_rw_ddbreg, NULL }, | 74 | { "a6", (void *)offsetof(struct trapframe, tf_a6), db_rw_ddbreg, NULL }, | |
74 | { "a7", (void *)offsetof(struct trapframe, tf_a7), db_rw_ddbreg, NULL }, | 75 | { "a7", (void *)offsetof(struct trapframe, tf_a7), db_rw_ddbreg, NULL }, | |
75 | { "t0", (void *)offsetof(struct trapframe, tf_t0), db_rw_ddbreg, NULL }, | 76 | { "t0", (void *)offsetof(struct trapframe, tf_t0), db_rw_ddbreg, NULL }, | |
76 | { "t1", (void *)offsetof(struct trapframe, tf_t1), db_rw_ddbreg, NULL }, | 77 | { "t1", (void *)offsetof(struct trapframe, tf_t1), db_rw_ddbreg, NULL }, | |
77 | { "t2", (void *)offsetof(struct trapframe, tf_t2), db_rw_ddbreg, NULL }, | 78 | { "t2", (void *)offsetof(struct trapframe, tf_t2), db_rw_ddbreg, NULL }, | |
78 | { "t3", (void *)offsetof(struct trapframe, tf_t3), db_rw_ddbreg, NULL }, | 79 | { "t3", (void *)offsetof(struct trapframe, tf_t3), db_rw_ddbreg, NULL }, | |
79 | { "t4", (void *)offsetof(struct trapframe, tf_t4), db_rw_ddbreg, NULL }, | 80 | { "t4", (void *)offsetof(struct trapframe, tf_t4), db_rw_ddbreg, NULL }, | |
80 | { "t5", (void *)offsetof(struct trapframe, tf_t5), db_rw_ddbreg, NULL }, | 81 | { "t5", (void *)offsetof(struct trapframe, tf_t5), db_rw_ddbreg, NULL }, | |
81 | { "t6", (void *)offsetof(struct trapframe, tf_t6), db_rw_ddbreg, NULL }, | 82 | { "t6", (void *)offsetof(struct trapframe, tf_t6), db_rw_ddbreg, NULL }, | |
82 | { "pc", (void *)offsetof(struct trapframe, tf_pc), db_rw_ddbreg, NULL }, | 83 | { "pc", (void *)offsetof(struct trapframe, tf_pc), db_rw_ddbreg, NULL }, | |
83 | { "status", (void *)offsetof(struct trapframe, tf_sr), db_rw_ddbreg, "i" }, | 84 | { "status", (void *)offsetof(struct trapframe, tf_sr), db_rw_ddbreg, "i" }, | |
84 | { "cause", (void *)offsetof(struct trapframe, tf_cause), db_rw_ddbreg, "i" }, | 85 | { "cause", (void *)offsetof(struct trapframe, tf_cause), db_rw_ddbreg, "i" }, | |
85 | { "tval", (void *)offsetof(struct trapframe, tf_tval), db_rw_ddbreg, NULL }, | 86 | { "tval", (void *)offsetof(struct trapframe, tf_tval), db_rw_ddbreg, NULL }, | |
86 | }; | 87 | }; | |
87 | const struct db_variable * const db_eregs = db_regs + __arraycount(db_regs); | 88 | const struct db_variable * const db_eregs = db_regs + __arraycount(db_regs); | |
88 | 89 | |||
89 | int | 90 | int | |
90 | db_rw_ddbreg(const struct db_variable *vp, db_expr_t *valp, int rw) | 91 | db_rw_ddbreg(const struct db_variable *vp, db_expr_t *valp, int rw) | |
91 | { | 92 | { | |
92 | struct trapframe * const tf = curcpu()->ci_ddb_regs; | 93 | struct trapframe * const tf = curcpu()->ci_ddb_regs; | |
93 | KASSERT(db_regs <= vp && vp < db_regs + __arraycount(db_regs)); | 94 | KASSERT(db_regs <= vp && vp < db_regs + __arraycount(db_regs)); | |
94 | const uintptr_t addr = (uintptr_t)tf + (uintptr_t)vp->valuep; | 95 | const uintptr_t addr = (uintptr_t)tf + (uintptr_t)vp->valuep; | |
95 | if (vp->modif != NULL && vp->modif[0] == 'i') { | 96 | if (vp->modif != NULL && vp->modif[0] == 'i') { | |
96 | if (rw == DB_VAR_GET) { | 97 | if (rw == DB_VAR_GET) { | |
97 | *valp = *(const uint32_t *)addr; | 98 | *valp = *(const uint32_t *)addr; | |
98 | } else { | 99 | } else { | |
99 | *(uint32_t *)addr = *valp; | 100 | *(uint32_t *)addr = *valp; | |
100 | } | 101 | } | |
101 | } else { | 102 | } else { | |
102 | if (rw == DB_VAR_GET) { | 103 | if (rw == DB_VAR_GET) { | |
103 | *valp = *(const register_t *)addr; | 104 | *valp = *(const register_t *)addr; | |
104 | } else { | 105 | } else { | |
105 | *(register_t *)addr = *valp; | 106 | *(register_t *)addr = *valp; | |
106 | } | 107 | } | |
107 | } | 108 | } | |
108 | return 0; | 109 | return 0; | |
109 | } | 110 | } | |
110 | 111 | |||
111 | // These are for the software implementation of single-stepping. | 112 | // These are for the software implementation of single-stepping. | |
112 | // | 113 | // | |
113 | // XXX none of this checks for 16-bit instructions; it should all be | 114 | // XXX none of this checks for 16-bit instructions; it should all be | |
114 | // converted to the newer decoding macros. Also, XXX it does not look | 115 | // converted to the newer decoding macros. Also, XXX it does not look | |
115 | // like the MI parts in ddb is going to work in the presence of 16-bit | 116 | // like the MI parts in ddb is going to work in the presence of 16-bit | |
116 | // instructions anyway. | 117 | // instructions anyway. | |
117 | // | 118 | // | |
118 | // returns true is the instruction might branch | 119 | // returns true is the instruction might branch | |
119 | bool | 120 | bool | |
120 | inst_branch(uint32_t insn) | 121 | inst_branch(uint32_t insn) | |
121 | { | 122 | { | |
122 | return OPCODE_P(insn, BRANCH); | 123 | return OPCODE_P(insn, BRANCH); | |
123 | } | 124 | } | |
124 | 125 | |||
125 | // returns true is the instruction might branch | 126 | // returns true is the instruction might branch | |
126 | bool | 127 | bool | |
127 | inst_call(uint32_t insn) | 128 | inst_call(uint32_t insn) | |
128 | { | 129 | { | |
129 | const union riscv_insn ri = { .val = insn }; | 130 | const union riscv_insn ri = { .val = insn }; | |
130 | return (OPCODE_P(insn, JAL) && ri.type_u.u_rd == 1) | 131 | return (OPCODE_P(insn, JAL) && ri.type_u.u_rd == 1) | |
131 | || (OPCODE_P(insn, JALR) && ri.type_i.i_rd == 1); | 132 | || (OPCODE_P(insn, JALR) && ri.type_i.i_rd == 1); | |
132 | } | 133 | } | |
133 | 134 | |||
134 | // return true if the instructon is an uncondition branch/jump. | 135 | // return true if the instructon is an uncondition branch/jump. | |
135 | bool | 136 | bool | |
136 | inst_unconditional_flow_transfer(uint32_t insn) | 137 | inst_unconditional_flow_transfer(uint32_t insn) | |
137 | { | 138 | { | |
138 | // we should check for beq xN,xN but why use that instead of jal x0,... | 139 | // we should check for beq xN,xN but why use that instead of jal x0,... | |
139 | return OPCODE_P(insn, JAL) || OPCODE_P(insn, JALR); | 140 | return OPCODE_P(insn, JAL) || OPCODE_P(insn, JALR); | |
140 | } | 141 | } | |
141 | 142 | |||
142 | bool | 143 | bool | |
143 | inst_return(uint32_t insn) | 144 | inst_return(uint32_t insn) | |
144 | { | 145 | { | |
145 | const union riscv_insn ri = { .val = insn }; | 146 | const union riscv_insn ri = { .val = insn }; | |
146 | return OPCODE_P(insn, JALR) && ri.type_i.i_rs1 == 1; | 147 | return OPCODE_P(insn, JALR) && ri.type_i.i_rs1 == 1; | |
147 | } | 148 | } | |
148 | 149 | |||
149 | bool | 150 | bool | |
150 | inst_load(uint32_t insn) | 151 | inst_load(uint32_t insn) | |
151 | { | 152 | { | |
152 | return OPCODE_P(insn, LOAD) || OPCODE_P(insn, LOADFP); | 153 | return OPCODE_P(insn, LOAD) || OPCODE_P(insn, LOADFP); | |
153 | } | 154 | } | |
154 | 155 | |||
155 | bool | 156 | bool | |
156 | inst_store(uint32_t insn) | 157 | inst_store(uint32_t insn) | |
157 | { | 158 | { | |
158 | return OPCODE_P(insn, STORE) || OPCODE_P(insn, STOREFP); | 159 | return OPCODE_P(insn, STORE) || OPCODE_P(insn, STOREFP); | |
159 | } | 160 | } | |
160 | 161 | |||
161 | static inline register_t | 162 | static inline register_t | |
162 | get_reg_value(const db_regs_t *tf, u_int regno) | 163 | get_reg_value(const db_regs_t *tf, u_int regno) | |
163 | { | 164 | { | |
164 | return (regno == 0 ? 0 : tf->tf_reg[regno - 1]); | 165 | return (regno == 0 ? 0 : tf->tf_reg[regno - 1]); | |
165 | } | 166 | } | |
166 | 167 | |||
167 | db_addr_t | 168 | db_addr_t | |
168 | branch_taken(uint32_t insn, db_addr_t pc, db_regs_t *tf) | 169 | branch_taken(uint32_t insn, db_addr_t pc, db_regs_t *tf) | |
169 | { | 170 | { | |
170 | const union riscv_insn i = { .val = insn }; | 171 | const union riscv_insn i = { .val = insn }; | |
171 | intptr_t displacement; | 172 | intptr_t displacement; | |
172 | 173 | |||
173 | if (OPCODE_P(insn, JALR)) { | 174 | if (OPCODE_P(insn, JALR)) { | |
174 | return i.type_i.i_imm11to0 + get_reg_value(tf, i.type_i.i_rs1); | 175 | return i.type_i.i_imm11to0 + get_reg_value(tf, i.type_i.i_rs1); | |
175 | } | 176 | } | |
176 | if (OPCODE_P(insn, JAL)) { | 177 | if (OPCODE_P(insn, JAL)) { | |
177 | displacement = i.type_j.j_imm20 << 20; | 178 | displacement = i.type_j.j_imm20 << 20; | |
178 | displacement |= i.type_j.j_imm19to12 << 12; | 179 | displacement |= i.type_j.j_imm19to12 << 12; | |
179 | displacement |= i.type_j.j_imm11 << 11; | 180 | displacement |= i.type_j.j_imm11 << 11; | |
180 | displacement |= i.type_j.j_imm10to1 << 1; | 181 | displacement |= i.type_j.j_imm10to1 << 1; | |
181 | } else { | 182 | } else { | |
182 | KASSERT(OPCODE_P(insn, BRANCH)); | 183 | KASSERT(OPCODE_P(insn, BRANCH)); | |
183 | register_t rs1 = get_reg_value(tf, i.type_b.b_rs1); | 184 | register_t rs1 = get_reg_value(tf, i.type_b.b_rs1); | |
184 | register_t rs2 = get_reg_value(tf, i.type_b.b_rs2); | 185 | register_t rs2 = get_reg_value(tf, i.type_b.b_rs2); | |
185 | bool branch_p; // = false; | 186 | bool branch_p; // = false; | |
186 | switch (i.type_b.b_funct3 & 0b110U) { | 187 | switch (i.type_b.b_funct3 & 0b110U) { | |
187 | case 0b000U: | 188 | case 0b000U: | |
188 | branch_p = (rs1 == rs2); | 189 | branch_p = (rs1 == rs2); | |
189 | break; | 190 | break; | |
190 | case 0b010U: | 191 | case 0b010U: | |
191 | branch_p = ((rs1 & (1 << (i.type_b.b_rs2))) != 0); | 192 | branch_p = ((rs1 & (1 << (i.type_b.b_rs2))) != 0); | |
192 | break; | 193 | break; | |
193 | case 0b100U: | 194 | case 0b100U: | |
194 | branch_p = (rs1 < rs2); | 195 | branch_p = (rs1 < rs2); | |
195 | break; | 196 | break; | |
196 | default: // stupid gcc | 197 | default: // stupid gcc | |
197 | case 0b110U: | 198 | case 0b110U: | |
198 | branch_p = ((uregister_t)rs1 < (uregister_t)rs2); | 199 | branch_p = ((uregister_t)rs1 < (uregister_t)rs2); | |
199 | break; | 200 | break; | |
200 | } | 201 | } | |
201 | 202 | |||
202 | if (i.type_b.b_funct3 & 1) | 203 | if (i.type_b.b_funct3 & 1) | |
203 | branch_p = !branch_p; | 204 | branch_p = !branch_p; | |
204 | 205 | |||
205 | if (!branch_p) { | 206 | if (!branch_p) { | |
206 | displacement = 4; | 207 | displacement = 4; | |
207 | } else { | 208 | } else { | |
208 | displacement = i.type_b.b_imm12 << 12; | 209 | displacement = i.type_b.b_imm12 << 12; | |
209 | displacement |= i.type_b.b_imm11 << 11; | 210 | displacement |= i.type_b.b_imm11 << 11; | |
210 | displacement |= i.type_b.b_imm10to5 << 5; | 211 | displacement |= i.type_b.b_imm10to5 << 5; | |
211 | displacement |= i.type_b.b_imm4to1 << 1; | 212 | displacement |= i.type_b.b_imm4to1 << 1; | |
212 | } | 213 | } | |
213 | } | 214 | } | |
214 | 215 | |||
215 | return pc + displacement; | 216 | return pc + displacement; | |
216 | } | 217 | } | |
217 | 218 | |||
218 | db_addr_t | 219 | db_addr_t | |
219 | next_instr_address(db_addr_t pc, bool bdslot_p) | 220 | next_instr_address(db_addr_t pc, bool bdslot_p) | |
220 | { | 221 | { | |
221 | return pc + (bdslot_p ? 0 : 4); | 222 | return pc + (bdslot_p ? 0 : 4); | |
222 | } | 223 | } | |
223 | 224 | |||
224 | void | 225 | void | |
225 | db_read_bytes(db_addr_t addr, size_t len, char *data) | 226 | db_read_bytes(db_addr_t addr, size_t len, char *data) | |
226 | { | 227 | { | |
227 | const char *src = (char *)addr; | 228 | const char *src = (char *)addr; | |
229 | int err; | |||
230 | ||||
231 | /* If asked to fetch from userspace, do it safely */ | |||
232 | if ((intptr_t)addr >= 0) { | |||
233 | err = copyin(src, data, len); | |||
234 | if (err) { | |||
235 | #ifdef DDB | |||
236 | db_printf("address %p is invalid\n", src); | |||
237 | #endif | |||
238 | memset(data, 0, len); | |||
239 | } | |||
240 | return; | |||
241 | } | |||
228 | 242 | |||
229 | while (len--) { | 243 | while (len--) { | |
230 | *data++ = *src++; | 244 | *data++ = *src++; | |
231 | } | 245 | } | |
232 | } | 246 | } | |
233 | 247 | |||
234 | /* | 248 | /* | |
235 | * Write bytes to kernel address space for debugger. | 249 | * Write bytes to kernel address space for debugger. | |
236 | */ | 250 | */ | |
237 | void | 251 | void | |
238 | db_write_bytes(vaddr_t addr, size_t len, const char *data) | 252 | db_write_bytes(vaddr_t addr, size_t len, const char *data) | |
239 | { | 253 | { | |
254 | int err; | |||
255 | ||||
256 | /* If asked to fetch from userspace, do it safely */ | |||
257 | if ((intptr_t)addr >= 0) { | |||
258 | err = copyout(data, (char *)addr, len); | |||
259 | if (err) { | |||
260 | #ifdef DDB | |||
261 | db_printf("address %p is invalid\n", (char *)addr); | |||
262 | #endif | |||
263 | } | |||
264 | return; | |||
265 | } | |||
266 | ||||
240 | if (len == 8) { | 267 | if (len == 8) { | |
241 | *(uint64_t *)addr = *(const uint64_t *) data; | 268 | *(uint64_t *)addr = *(const uint64_t *) data; | |
242 | } else if (len == 4) { | 269 | } else if (len == 4) { | |
243 | *(uint32_t *)addr = *(const uint32_t *) data; | 270 | *(uint32_t *)addr = *(const uint32_t *) data; | |
244 | } else if (len == 2) { | 271 | } else if (len == 2) { | |
245 | *(uint16_t *)addr = *(const uint16_t *) data; | 272 | *(uint16_t *)addr = *(const uint16_t *) data; | |
246 | } else { | 273 | } else { | |
274 | KASSERT(len == 1); | |||
247 | *(uint8_t *)addr = *(const uint8_t *) data; | 275 | *(uint8_t *)addr = *(const uint8_t *) data; | |
248 | } | 276 | } | |
249 | __asm("fence rw,rw; fence.i"); | 277 | __asm("fence rw,rw; fence.i"); | |
250 | } | 278 | } | |
251 | 279 | |||
252 | 280 | |||
253 | 281 |